@sapudex/web-components 2.33.0 → 2.35.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 (175) hide show
  1. package/cypress/specs/FilterMenu.cy.tsx +53 -0
  2. package/cypress/specs/ListItem.cy.tsx +73 -21
  3. package/cypress/specs/MastheadMenu.cy.tsx +645 -0
  4. package/cypress/specs/MastheadMobileMenu.cy.tsx +573 -0
  5. package/cypress/specs/MastheadShell.cy.tsx +79 -0
  6. package/cypress/specs/SecondaryNavigationDesktop.cy.tsx +14 -0
  7. package/cypress/specs/SelectBox.cy.tsx +229 -1
  8. package/cypress/support/component-imports.instrumented.ts +2 -0
  9. package/cypress/support/component-imports.src.ts +2 -0
  10. package/dist/CountrySelector.d.ts +1 -0
  11. package/dist/CountrySelector.js +3 -0
  12. package/dist/CountrySelector.js.map +1 -1
  13. package/dist/FilterMenu.d.ts +1 -0
  14. package/dist/FilterMenu.js +3 -0
  15. package/dist/FilterMenu.js.map +1 -1
  16. package/dist/ListItem.d.ts +3 -0
  17. package/dist/ListItem.js +10 -1
  18. package/dist/ListItem.js.map +1 -1
  19. package/dist/ListItemBase.d.ts +31 -0
  20. package/dist/ListItemBase.js +28 -0
  21. package/dist/ListItemBase.js.map +1 -1
  22. package/dist/MastheadItem.d.ts +12 -1
  23. package/dist/MastheadItem.js +33 -1
  24. package/dist/MastheadItem.js.map +1 -1
  25. package/dist/MastheadMenu.d.ts +5 -1
  26. package/dist/MastheadMenu.js +16 -6
  27. package/dist/MastheadMenu.js.map +1 -1
  28. package/dist/SearchableListBase.d.ts +3 -1
  29. package/dist/SearchableListBase.js +7 -1
  30. package/dist/SearchableListBase.js.map +1 -1
  31. package/dist/SecondaryNavigationItem.d.ts +5 -1
  32. package/dist/SecondaryNavigationItem.js +35 -5
  33. package/dist/SecondaryNavigationItem.js.map +1 -1
  34. package/dist/SelectBase.js +14 -3
  35. package/dist/SelectBase.js.map +1 -1
  36. package/dist/SelectBox.d.ts +1 -0
  37. package/dist/SelectBox.js +3 -0
  38. package/dist/SelectBox.js.map +1 -1
  39. package/dist/assets/{InputSuggestions-B_Dl2L6w.js → InputSuggestions-CrSNIz-l.js} +1 -1
  40. package/dist/assets/{ListItemStandardExpandableTextTemplate-9Z-aZmJx.js → ListItemStandardExpandableTextTemplate-BUgxFxi7.js} +1 -1
  41. package/dist/assets/{bundle-DbTEs-Za.css → bundle-JYo3bV8v.css} +1 -1
  42. package/dist/assets/{bundle.esm-BlIxH9k1.js → bundle.esm-BZJm6rNI.js} +633 -219
  43. package/dist/css/themes/Breadcrumbs.css +1 -1
  44. package/dist/css/themes/BreadcrumbsPopover.css +1 -1
  45. package/dist/css/themes/FilterMenu.css +1 -1
  46. package/dist/css/themes/ListGroupHeader.css +1 -1
  47. package/dist/css/themes/ListItem.css +1 -1
  48. package/dist/css/themes/MastheadItem.css +1 -1
  49. package/dist/css/themes/MastheadMenu.css +1 -1
  50. package/dist/css/themes/MastheadMobileMenu.css +1 -1
  51. package/dist/css/themes/RatingIndicator.css +1 -1
  52. package/dist/css/themes/SearchableList.css +1 -1
  53. package/dist/css/themes/SecondaryNavigation.css +1 -1
  54. package/dist/css/themes/SecondaryNavigationItem.css +1 -1
  55. package/dist/css/themes/SelectBase.css +1 -1
  56. package/dist/css/themes/Slider.css +1 -1
  57. package/dist/custom-elements-internal.json +1125 -35
  58. package/dist/custom-elements.json +1126 -36
  59. package/dist/generated/templates/ListGroupHeaderTemplate.lit.js +16 -12
  60. package/dist/generated/templates/ListGroupHeaderTemplate.lit.js.map +1 -1
  61. package/dist/generated/templates/ListItemTemplate.lit.js +40 -32
  62. package/dist/generated/templates/ListItemTemplate.lit.js.map +1 -1
  63. package/dist/generated/templates/MastheadItemTemplate.lit.js +2 -2
  64. package/dist/generated/templates/MastheadItemTemplate.lit.js.map +1 -1
  65. package/dist/generated/templates/MastheadMenuTemplate.lit.js +8 -1
  66. package/dist/generated/templates/MastheadMenuTemplate.lit.js.map +1 -1
  67. package/dist/generated/templates/MastheadMobileMenuTemplate.lit.js +10 -4
  68. package/dist/generated/templates/MastheadMobileMenuTemplate.lit.js.map +1 -1
  69. package/dist/generated/templates/MastheadShellTemplate.lit.js +3 -3
  70. package/dist/generated/templates/MastheadShellTemplate.lit.js.map +1 -1
  71. package/dist/generated/templates/SearchableListBaseTemplate.lit.js +4 -4
  72. package/dist/generated/templates/SearchableListBaseTemplate.lit.js.map +1 -1
  73. package/dist/generated/templates/SelectBoxTemplate.lit.js +12 -10
  74. package/dist/generated/templates/SelectBoxTemplate.lit.js.map +1 -1
  75. package/dist/generated/themes/Breadcrumbs.css.d.ts +1 -1
  76. package/dist/generated/themes/Breadcrumbs.css.js +1 -1
  77. package/dist/generated/themes/Breadcrumbs.css.js.map +1 -1
  78. package/dist/generated/themes/BreadcrumbsPopover.css.d.ts +1 -1
  79. package/dist/generated/themes/BreadcrumbsPopover.css.js +1 -1
  80. package/dist/generated/themes/BreadcrumbsPopover.css.js.map +1 -1
  81. package/dist/generated/themes/FilterMenu.css.d.ts +1 -1
  82. package/dist/generated/themes/FilterMenu.css.js +1 -1
  83. package/dist/generated/themes/FilterMenu.css.js.map +1 -1
  84. package/dist/generated/themes/ListGroupHeader.css.d.ts +1 -1
  85. package/dist/generated/themes/ListGroupHeader.css.js +1 -1
  86. package/dist/generated/themes/ListGroupHeader.css.js.map +1 -1
  87. package/dist/generated/themes/ListItem.css.d.ts +1 -1
  88. package/dist/generated/themes/ListItem.css.js +1 -1
  89. package/dist/generated/themes/ListItem.css.js.map +1 -1
  90. package/dist/generated/themes/MastheadItem.css.d.ts +1 -1
  91. package/dist/generated/themes/MastheadItem.css.js +1 -1
  92. package/dist/generated/themes/MastheadItem.css.js.map +1 -1
  93. package/dist/generated/themes/MastheadMenu.css.d.ts +1 -1
  94. package/dist/generated/themes/MastheadMenu.css.js +1 -1
  95. package/dist/generated/themes/MastheadMenu.css.js.map +1 -1
  96. package/dist/generated/themes/MastheadMobileMenu.css.d.ts +1 -1
  97. package/dist/generated/themes/MastheadMobileMenu.css.js +1 -1
  98. package/dist/generated/themes/MastheadMobileMenu.css.js.map +1 -1
  99. package/dist/generated/themes/RatingIndicator.css.d.ts +1 -1
  100. package/dist/generated/themes/RatingIndicator.css.js +1 -1
  101. package/dist/generated/themes/RatingIndicator.css.js.map +1 -1
  102. package/dist/generated/themes/SearchableList.css.d.ts +1 -1
  103. package/dist/generated/themes/SearchableList.css.js +1 -1
  104. package/dist/generated/themes/SearchableList.css.js.map +1 -1
  105. package/dist/generated/themes/SecondaryNavigation.css.d.ts +1 -1
  106. package/dist/generated/themes/SecondaryNavigation.css.js +1 -1
  107. package/dist/generated/themes/SecondaryNavigation.css.js.map +1 -1
  108. package/dist/generated/themes/SecondaryNavigationItem.css.d.ts +1 -1
  109. package/dist/generated/themes/SecondaryNavigationItem.css.js +1 -1
  110. package/dist/generated/themes/SecondaryNavigationItem.css.js.map +1 -1
  111. package/dist/generated/themes/SelectBase.css.d.ts +1 -1
  112. package/dist/generated/themes/SelectBase.css.js +1 -1
  113. package/dist/generated/themes/SelectBase.css.js.map +1 -1
  114. package/dist/generated/themes/Slider.css.d.ts +1 -1
  115. package/dist/generated/themes/Slider.css.js +1 -1
  116. package/dist/generated/themes/Slider.css.js.map +1 -1
  117. package/dist/types/List.d.ts +2 -0
  118. package/dist/types/List.js +2 -0
  119. package/dist/types/List.js.map +1 -1
  120. package/dist/vscode.html-custom-data.json +292 -12
  121. package/dist/web-types.json +431 -21
  122. package/package.json +1 -1
  123. package/src/CountrySelector.ts +3 -0
  124. package/src/FilterMenu.ts +3 -0
  125. package/src/ListGroupHeader.hbs +11 -7
  126. package/src/ListItem.hbs +28 -2
  127. package/src/ListItem.ts +12 -1
  128. package/src/ListItemBase.ts +48 -0
  129. package/src/MastheadItem.hbs +2 -0
  130. package/src/MastheadItem.ts +37 -2
  131. package/src/MastheadMenu.hbs +35 -0
  132. package/src/MastheadMenu.ts +21 -7
  133. package/src/MastheadMobileMenu.hbs +40 -9
  134. package/src/MastheadShell.hbs +3 -0
  135. package/src/SearchableListBase.hbs +21 -1
  136. package/src/SearchableListBase.ts +11 -2
  137. package/src/SecondaryNavigationItem.ts +37 -5
  138. package/src/SelectBase.ts +15 -3
  139. package/src/SelectBox.hbs +13 -5
  140. package/src/SelectBox.ts +3 -0
  141. package/src/generated/templates/ListGroupHeaderTemplate.lit.ts +16 -12
  142. package/src/generated/templates/ListItemTemplate.lit.ts +40 -32
  143. package/src/generated/templates/MastheadItemTemplate.lit.ts +2 -2
  144. package/src/generated/templates/MastheadMenuTemplate.lit.ts +8 -1
  145. package/src/generated/templates/MastheadMobileMenuTemplate.lit.ts +10 -4
  146. package/src/generated/templates/MastheadShellTemplate.lit.ts +3 -3
  147. package/src/generated/templates/SearchableListBaseTemplate.lit.ts +4 -4
  148. package/src/generated/templates/SelectBoxTemplate.lit.ts +12 -10
  149. package/src/generated/themes/Breadcrumbs.css.ts +1 -1
  150. package/src/generated/themes/BreadcrumbsPopover.css.ts +1 -1
  151. package/src/generated/themes/FilterMenu.css.ts +1 -1
  152. package/src/generated/themes/ListGroupHeader.css.ts +1 -1
  153. package/src/generated/themes/ListItem.css.ts +1 -1
  154. package/src/generated/themes/MastheadItem.css.ts +1 -1
  155. package/src/generated/themes/MastheadMenu.css.ts +1 -1
  156. package/src/generated/themes/MastheadMobileMenu.css.ts +1 -1
  157. package/src/generated/themes/RatingIndicator.css.ts +1 -1
  158. package/src/generated/themes/SearchableList.css.ts +1 -1
  159. package/src/generated/themes/SecondaryNavigation.css.ts +1 -1
  160. package/src/generated/themes/SecondaryNavigationItem.css.ts +1 -1
  161. package/src/generated/themes/SelectBase.css.ts +1 -1
  162. package/src/generated/themes/Slider.css.ts +1 -1
  163. package/src/themes/Breadcrumbs.css +16 -2
  164. package/src/themes/BreadcrumbsPopover.css +18 -3
  165. package/src/themes/FilterMenu.css +4 -9
  166. package/src/themes/ListGroupHeader.css +11 -0
  167. package/src/themes/ListItem.css +6 -4
  168. package/src/themes/MastheadItem.css +41 -9
  169. package/src/themes/MastheadMenu.css +45 -0
  170. package/src/themes/MastheadMobileMenu.css +45 -0
  171. package/src/themes/SearchableList.css +18 -3
  172. package/src/themes/SecondaryNavigation.css +1 -1
  173. package/src/themes/SecondaryNavigationItem.css +5 -2
  174. package/src/themes/SelectBase.css +0 -9
  175. package/src/types/List.ts +2 -0
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@sapudex/web-components",
4
- "version": "2.33.0",
4
+ "version": "2.35.0",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"
7
7
  },
@@ -6,6 +6,8 @@ import "@ui5/webcomponents-icons/dist/navigation-down-arrow.js";
6
6
  import "@ui5/webcomponents-icons/dist/navigation-up-arrow.js";
7
7
  import type { Country } from "./data/CountryListISO3166.js";
8
8
  import { CountryListDB } from "./data/CountryListISO3166.js";
9
+ import IllustratedMessage from "@ui5/webcomponents-fiori/dist/IllustratedMessage.js";
10
+ import "@ui5/webcomponents-fiori/dist/illustrations/NoSearchResults.js";
9
11
  import UDExSearch from "./Search.js";
10
12
  import UDExDropdown from "./Dropdown.js";
11
13
  import UDExList from "./List.js";
@@ -63,6 +65,7 @@ type UDExCountrySelectorChangeSearchEventDetail = {
63
65
  UDExDropdown,
64
66
  UDExTextField,
65
67
  UDExStatusMessage,
68
+ IllustratedMessage,
66
69
  ],
67
70
  })
68
71
 
package/src/FilterMenu.ts CHANGED
@@ -11,6 +11,8 @@ import PopupAccessibleRole from "@ui5/webcomponents/dist/types/PopupAccessibleRo
11
11
  import Popover from "@ui5/webcomponents/dist/Popover.js";
12
12
  import UDExBusyIndicator from "./BusyIndicator.js";
13
13
  import Icon from "@ui5/webcomponents/dist/Icon.js";
14
+ import IllustratedMessage from "@ui5/webcomponents-fiori/dist/IllustratedMessage.js";
15
+ import "@ui5/webcomponents-fiori/dist/illustrations/NoSearchResults.js";
14
16
  import UDExList from "./List.js";
15
17
  import UDExListItem from "./ListItem.js";
16
18
  import UDExListGroupHeader from "./ListGroupHeader.js";
@@ -80,6 +82,7 @@ type UDExFilterMenuResetClickEventDetail = {
80
82
  styles: [FilterMenuCss, SearchableListCss, getEffectiveScrollbarStyle()],
81
83
  template: FilterMenuTemplate,
82
84
  dependencies: [
85
+ IllustratedMessage,
83
86
  Popover,
84
87
  Icon,
85
88
  UDExBusyIndicator,
@@ -125,6 +125,8 @@
125
125
 
126
126
  {{#*inline "single-group-header"}}
127
127
  <div class="udex-list__group-content udex-list__group-header-wrap {{sizeClass}}" part="group-item">
128
+ {{#if typeNumber}}<span class="udex-list__number">{{numberOfItem}}.</span>{{/if}}
129
+ {{#if typeCircle}}<span class="udex-list__circle">&#x2022;</span>{{/if}}
128
130
  {{#if typeIcon}}
129
131
  <ui5-icon
130
132
  class="udex-list__icon"
@@ -145,13 +147,15 @@
145
147
 
146
148
  {{#*inline "single-group-header-collapsible"}}
147
149
  <div class="udex-list__group-content udex-list__group-header-wrap {{sizeClass}}" part="group-item"
148
- id="{{this._id}}_group-content__focusable"
149
- role="button"
150
- tabindex="0"
151
- @keydown="{{handleKeyDown}}"
152
- _tab-index="{{_effectiveTabIndex}}"
153
- aria-expanded="{{expanded}}"
154
- aria-controls="{{ariaControlsId}}">
150
+ id="{{this._id}}_group-content__focusable"
151
+ role="button"
152
+ tabindex="0"
153
+ @keydown="{{handleKeyDown}}"
154
+ _tab-index="{{_effectiveTabIndex}}"
155
+ aria-expanded="{{expanded}}"
156
+ aria-controls="{{ariaControlsId}}">
157
+ {{#if typeNumber}}<span class="udex-list__number">{{numberOfItem}}.</span>{{/if}}
158
+ {{#if typeCircle}}<span class="udex-list__circle">&#x2022;</span>{{/if}}
155
159
  {{#if typeIcon}}
156
160
  <ui5-icon
157
161
  class="udex-list__icon"
package/src/ListItem.hbs CHANGED
@@ -56,6 +56,8 @@
56
56
  <span class="udex-list__flag" style="background-position: {{flagPosition}}"></span>
57
57
  </div>
58
58
  {{/if}}
59
+ {{#if typeNumber}}<span class="udex-list__number">{{numberOfItem}}.</span>{{/if}}
60
+ {{#if typeCircle}}<span class="udex-list__circle">&#x2022;</span>{{/if}}
59
61
  {{#if typeIcon}}
60
62
  <ui5-icon
61
63
  class="udex-list__icon"
@@ -89,6 +91,18 @@
89
91
  <span class="udex-list__supporting-text" part="supporting">{{supportingText}}</span>
90
92
  {{/if}}
91
93
  <slot part="content"></slot>
94
+ {{#if hasRating}}
95
+ <udex-rating-indicator
96
+ aria-label="{{ratingAriaLabel}}"
97
+ value="{{rating}}"
98
+ rating-count="{{ratingCount}}"
99
+ total-count="{{totalCount}}"
100
+ max="{{ratingMax}}"
101
+ display="{{_displayRating}}"
102
+ disabled
103
+ readonly>
104
+ </udex-rating-indicator>
105
+ {{/if}}
92
106
  </div>
93
107
  {{#if additionalText}}<div class="udex-list__add-text" part="additional-text">{{additionalText}}</div>{{/if}}
94
108
  <div class="udex-list__btn-wrap">
@@ -103,6 +117,18 @@
103
117
  <div class="udex-list__text-holder">
104
118
  <slot part="content"></slot>
105
119
  {{#if supportingText}}<span class="udex-list__supporting-text" part="supporting">{{supportingText}}</span>{{/if}}
120
+ {{#if hasRating}}
121
+ <udex-rating-indicator
122
+ aria-label="{{ratingAriaLabel}}"
123
+ value="{{rating}}"
124
+ rating-count="{{ratingCount}}"
125
+ total-count="{{totalCount}}"
126
+ max="{{ratingMax}}"
127
+ display="{{_displayRating}}"
128
+ disabled
129
+ readonly>
130
+ </udex-rating-indicator>
131
+ {{/if}}
106
132
  </div>
107
133
  {{#if additionalText}}<div class="udex-list__add-text" part="additional-text">{{additionalText}}</div>{{/if}}
108
134
  <div class="udex-list__btn-wrap">
@@ -130,7 +156,7 @@
130
156
  </div>
131
157
  {{/if}}
132
158
  </div>
133
- <div class="hidden" id="{{this._id}}-invisibleText">{{accessibleListItemName}}</div>
134
- <div class="hidden" id="{{this._id}}-invisibleText-describedby">{{itemState}}</div>
159
+ <div class="hidden" id="{{this._id}}-invisibleText">{{accessibleListItemName}}</div>
160
+ <div class="hidden" id="{{this._id}}-invisibleText-describedby">{{itemState}}</div>
135
161
  </div>
136
162
  {{/inline}}
package/src/ListItem.ts CHANGED
@@ -13,13 +13,14 @@ import type UDExListGroupHeaderBase from "./ListGroupHeaderBase.js";
13
13
  import UDExAvatar, { UDExAvatarShape, UDExAvatarSize } from "./Avatar.js";
14
14
  import UDExButton from "./Button.js";
15
15
  import UDExStatusBadge from "./StatusBadge.js";
16
+ import UDExRatingIndicator, { UDExDisplayType } from "./RatingIndicator.js";
16
17
  import type UDExStatusBadgeValueState from "./types/StatusBadgeValueState.js";
17
18
  import { UDExListItemSize, UDExListMode, UDExAdditionalTextState } from "./types/List.js";
18
19
  import UDExRadioButton from "./RadioButton.js";
19
20
  import i18n from "@ui5/webcomponents-base/dist/decorators/i18n.js";
20
21
  import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js";
21
22
  import {
22
- INDETERMINATE, SELECTED, UNSELECTED,
23
+ INDETERMINATE, SELECTED, UNSELECTED, RATING_INDICATOR_TEXT, RATING_COUNT_TITLE, TOTAL,
23
24
  } from "./generated/i18n/i18n-defaults.js";
24
25
  import translate from "./utils/translate.js";
25
26
 
@@ -71,6 +72,7 @@ type UDExListItemItemPressEventDetail = {
71
72
  UDExRadioButton,
72
73
  UDExCheckbox,
73
74
  UDExStatusBadge,
75
+ UDExRatingIndicator,
74
76
  Icon,
75
77
  ],
76
78
  })
@@ -235,6 +237,8 @@ class UDExListItem extends UDExListItemBase {
235
237
  @property({ type: String })
236
238
  _additionalClassName!: string;
237
239
 
240
+ _displayRating: UDExDisplayType = UDExDisplayType.Desktop;
241
+
238
242
  deactivate: () => void;
239
243
 
240
244
  @i18n("@sapudex/web-components")
@@ -402,6 +406,13 @@ class UDExListItem extends UDExListItemBase {
402
406
  get itemState(): string {
403
407
  return this.selected ? "Selected" : "Not selected";
404
408
  }
409
+
410
+ get ratingAriaLabel(): string {
411
+ const ratingText = this.ratingCount ? `${translate(UDExListItem, RATING_COUNT_TITLE)} ${this.ratingCount}` : "";
412
+ const totalText = this.totalCount ? `${translate(UDExListItem, TOTAL)} ${this.totalCount}` : "";
413
+ const ratingTitleText = translate(UDExListItem, RATING_INDICATOR_TEXT);
414
+ return [...[ratingText, totalText].filter(Boolean), `${ratingTitleText} ${this.rating} of ${this.ratingMax}`].join(", ");
415
+ }
405
416
  }
406
417
 
407
418
  UDExListItem.define();
@@ -70,6 +70,42 @@ type UDExListItemBaseAccordionClickEventDetail = {
70
70
  class UDExListItemBase extends UI5Element {
71
71
  eventDetails!: UDExListItemBaseEvents;
72
72
 
73
+ /**
74
+ * Defines the number of displayed rating symbols.
75
+ *
76
+ * @default 5
77
+ * @public
78
+ */
79
+ @property({ type: Number })
80
+ ratingMax: number = 5;
81
+
82
+ /**
83
+ * Defines the value of the rating.
84
+ * Use for rating indicator to represent aggregated review scores within list items
85
+ *
86
+ * @public
87
+ */
88
+ @property({ type: String })
89
+ rating?: string;
90
+
91
+ /**
92
+ * Defines the number of the rating.
93
+ * Use for the rating indicator
94
+ *
95
+ * @public
96
+ */
97
+ @property({ type: String })
98
+ ratingCount?: string;
99
+
100
+ /**
101
+ * The number of total votes.
102
+ * Use for the rating indicator
103
+ *
104
+ * @public
105
+ */
106
+ @property({ type: String })
107
+ totalCount?: string;
108
+
73
109
  /**
74
110
  * Defines the <code>label</code> for the item.
75
111
  *
@@ -298,6 +334,14 @@ class UDExListItemBase extends UI5Element {
298
334
  return this.modeMultiSelect || this.modeRadioGroup;
299
335
  }
300
336
 
337
+ get typeNumber(): boolean {
338
+ return this.type === UDExListStyleType.Number;
339
+ }
340
+
341
+ get typeCircle(): boolean {
342
+ return this.type === UDExListStyleType.Circle;
343
+ }
344
+
301
345
  get typeIcon(): boolean {
302
346
  return this.type === UDExListStyleType.Icon;
303
347
  }
@@ -313,6 +357,10 @@ class UDExListItemBase extends UI5Element {
313
357
  get expanded(): boolean {
314
358
  return !this.collapsed;
315
359
  }
360
+
361
+ get hasRating(): boolean {
362
+ return !!this.rating;
363
+ }
316
364
  }
317
365
 
318
366
  export default UDExListItemBase;
@@ -24,6 +24,7 @@
24
24
  <button
25
25
  id="{{this._id}}"
26
26
  class="udex-masthead-item__btn udex-masthead-item__profile-btn {{additionalClass}}"
27
+ tabindex="0"
27
28
  aria-expanded="{{buttonAriaExpanded}}"
28
29
  aria-describedby="{{ariaDescribedBy}}"
29
30
  aria-controls="{{this._id}}_dropdown"
@@ -41,6 +42,7 @@
41
42
  role="{{accessibleRoleName}}"
42
43
  id="{{this._id}}"
43
44
  class="udex-masthead-item__btn {{additionalClass}}"
45
+ tabindex="0"
44
46
  aria-expanded="{{buttonAriaExpanded}}"
45
47
  aria-controls="{{this._id}}_dropdown"
46
48
  aria-describedby="{{ariaDescribedBy}}"
@@ -8,7 +8,7 @@ import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js";
8
8
  import UI5Icon from "@ui5/webcomponents/dist/Icon.js";
9
9
  import "@ui5/webcomponents-icons/dist/search.js";
10
10
  import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js";
11
- import { isEscape } from "@ui5/webcomponents-base/dist/Keys.js";
11
+ import { isEscape, isTabNext } from "@ui5/webcomponents-base/dist/Keys.js";
12
12
  import { isDesktop } from "@ui5/webcomponents-base/dist/Device.js";
13
13
  import {
14
14
  OPENS_IN_A_NEW_WINDOW, PROFILE, CART, COUNTRY_SELECTOR, SUPPORT, SEARCH,
@@ -44,8 +44,9 @@ export interface IMastheadItem {
44
44
 
45
45
  export type CategoryItem = {
46
46
  title: string;
47
- url: string;
47
+ url?: string;
48
48
  externalLink: boolean;
49
+ subItems?: CategoryItem[];
49
50
  };
50
51
 
51
52
  export type SubMenuLinkItem = {
@@ -323,6 +324,14 @@ class UDExMastheadItem extends UI5Element implements IMastheadItem {
323
324
  @property({ type: Boolean })
324
325
  _imageLoadError = false;
325
326
 
327
+ /**
328
+ * Defines if the item has the dropdown with four columns menu
329
+ *
330
+ * @private
331
+ */
332
+ @property({ type: Boolean })
333
+ _hasFourColumnsMenu = false;
334
+
326
335
  @i18n("@sapudex/web-components")
327
336
  static i18nBundle: I18nBundle;
328
337
 
@@ -337,6 +346,9 @@ class UDExMastheadItem extends UI5Element implements IMastheadItem {
337
346
 
338
347
  onBeforeRendering(): void {
339
348
  this.label = this.eventItemTitle;
349
+ if (this.hasFourColumnsMenu && !this.isExploreBtn) {
350
+ this._hasFourColumnsMenu = true;
351
+ }
340
352
  }
341
353
 
342
354
  onAfterRendering(): void {
@@ -397,6 +409,20 @@ class UDExMastheadItem extends UI5Element implements IMastheadItem {
397
409
  this.handleKeyEscape();
398
410
  }
399
411
  }
412
+ if (isTabNext(e) && this.isDropdownOpened) {
413
+ const button = this.getDomElement(".udex-masthead-item__btn, .udex-masthead-item__profile-btn");
414
+ if (button && e.currentTarget === button) {
415
+ this.handleTabIntoDropdown(e);
416
+ }
417
+ }
418
+ }
419
+
420
+ handleTabIntoDropdown(e: KeyboardEvent): void {
421
+ const menu = this.getSlottedNodes<UDExMastheadMenu>("dropdown")[0];
422
+ if (menu && typeof menu.focusFirstItem === "function") {
423
+ e.preventDefault();
424
+ menu.focusFirstItem();
425
+ }
400
426
  }
401
427
 
402
428
  handleKeyEscape(): void {
@@ -703,6 +729,15 @@ class UDExMastheadItem extends UI5Element implements IMastheadItem {
703
729
  get imageLoadError(): boolean {
704
730
  return this._imageLoadError && this.isCountrySelectorBtn;
705
731
  }
732
+
733
+ get dropdownMenu(): UDExMastheadMenu | undefined {
734
+ return this.getSlottedNodes<UDExMastheadMenu>("dropdown")
735
+ .find(el => el instanceof UDExMastheadMenu);
736
+ }
737
+
738
+ get hasFourColumnsMenu(): boolean {
739
+ return !!this.dropdownMenu?.hasFourColumns;
740
+ }
706
741
  }
707
742
 
708
743
  UDExMastheadItem.define();
@@ -77,6 +77,41 @@
77
77
  <li>
78
78
  {{#if this.isDivider}}
79
79
  <udex-divider class="udex-masthead-menu__item-divider"></udex-divider>
80
+ {{else if this.subItems}}
81
+ {{#if this.url}}
82
+ <udex-masthead-menu-item
83
+ part="menu-item"
84
+ accessible-role="link"
85
+ exportparts="menu-item"
86
+ @click="{{../../../handleMenuItemClick}}"
87
+ url="{{this.url}}"
88
+ label="{{this.title}}"
89
+ class="udex-masthead-menu__sub-category">
90
+ </udex-masthead-menu-item>
91
+ {{else}}
92
+ <span class="udex-masthead-menu__sub-category">{{this.title}}</span>
93
+ {{/if}}
94
+ <ul class="udex-masthead-menu__sub-list" aria-label="{{this.title}}">
95
+ {{#each this.subItems}}
96
+ <li>
97
+ {{#if this.isDivider}}
98
+ <udex-divider class="udex-masthead-menu__item-divider"></udex-divider>
99
+ {{else}}
100
+ <udex-masthead-menu-item
101
+ part="menu-item"
102
+ accessible-role="link"
103
+ exportparts="menu-item"
104
+ exportparts="badge"
105
+ @click="{{../../../../handleMenuItemClick}}"
106
+ badge="{{this.badge}}"
107
+ ?external-link="{{this.externalLink}}"
108
+ url="{{this.url}}"
109
+ label="{{this.title}}">
110
+ </udex-masthead-menu-item>
111
+ {{/if}}
112
+ </li>
113
+ {{/each}}
114
+ </ul>
80
115
  {{else}}
81
116
  <udex-masthead-menu-item
82
117
  part="menu-item"
@@ -29,9 +29,10 @@ const rowClass = "udex-masthead-menu_with-one-column";
29
29
 
30
30
  export type Item = {
31
31
  title: string;
32
- url: string;
32
+ url?: string;
33
33
  externalLink: boolean;
34
34
  isDivider?: boolean;
35
+ subItems?: Item[];
35
36
  };
36
37
 
37
38
  export type SubMenuLinkItem = {
@@ -155,14 +156,12 @@ class UDExMastheadMenu extends UI5Element {
155
156
 
156
157
  handleHomeKey(e: KeyboardEvent): void {
157
158
  e.preventDefault();
158
- const firstItem = this.links[0];
159
- firstItem.focus();
159
+ this.focusInnerElement(this.links[0]);
160
160
  }
161
161
 
162
162
  handleEndKey(e: KeyboardEvent): void {
163
163
  e.preventDefault();
164
- const lastItem = this.links[this.links.length - 1];
165
- lastItem.focus();
164
+ this.focusInnerElement(this.links[this.links.length - 1]);
166
165
  }
167
166
 
168
167
  handlePreviousItemFocus(e: KeyboardEvent): void {
@@ -207,7 +206,7 @@ class UDExMastheadMenu extends UI5Element {
207
206
  if (this._scrollIntoView) {
208
207
  this.scrollToItem(this.links[previousSelectIndex]);
209
208
  }
210
- this.links[previousSelectIndex].focus();
209
+ this.focusInnerElement(this.links[previousSelectIndex]);
211
210
  }
212
211
 
213
212
  focusNextItem(item: UDExMastheadMenuItem): void {
@@ -216,13 +215,24 @@ class UDExMastheadMenu extends UI5Element {
216
215
  if (this._scrollIntoView) {
217
216
  this.scrollToItem(this.links[nextSelectIndex]);
218
217
  }
219
- this.links[nextSelectIndex].focus();
218
+ this.focusInnerElement(this.links[nextSelectIndex]);
220
219
  }
221
220
 
222
221
  getCurrentIndex(item: UDExMastheadMenuItem): number {
223
222
  return this.links.indexOf(item);
224
223
  }
225
224
 
225
+ focusFirstItem(): void {
226
+ const firstItem = this.links[0];
227
+ if (firstItem) {
228
+ this.focusInnerElement(firstItem);
229
+ }
230
+ }
231
+
232
+ private focusInnerElement(item: UDExMastheadMenuItem): void {
233
+ item.shadowRoot?.querySelector<HTMLElement>(".udex-masthead-menu-item")?.focus();
234
+ }
235
+
226
236
  scrollToItem(item: UDExMastheadMenuItem): void {
227
237
  item.scrollIntoView({ block: this._scrollIntoView?.toLowerCase() as ScrollLogicalPosition });
228
238
  }
@@ -260,6 +270,10 @@ class UDExMastheadMenu extends UI5Element {
260
270
  get overviewHeaderLinkText(): string {
261
271
  return translate(UDExMastheadMenu, OVERVIEW);
262
272
  }
273
+
274
+ get hasFourColumns(): boolean {
275
+ return this.itemsList.some(item => item.subMenuLinkItems.length === 4);
276
+ }
263
277
  }
264
278
 
265
279
  UDExMastheadMenu.define();
@@ -205,17 +205,48 @@
205
205
  </li>
206
206
  {{/if}}
207
207
  {{#each _category.items}}
208
- {{#if this.url}}
208
+ {{#if this.subItems}}
209
209
  <li class="udex-masthead-mobile-menu__list-item" role="none">
210
- <udex-masthead-menu-item
211
- part="menu-item"
212
- @click="{{../handleMobileCategoryItemEvent}}"
213
- label="{{this.title}}"
214
- url="{{this.url}}"
215
- third-level
216
- has-border>
217
- </udex-masthead-menu-item>
210
+ {{#if this.url}}
211
+ <udex-masthead-menu-item
212
+ part="menu-item"
213
+ @click="{{../handleMobileCategoryItemEvent}}"
214
+ label="{{this.title}}"
215
+ url="{{this.url}}"
216
+ class="udex-masthead-mobile-menu__sub-category"
217
+ third-level>
218
+ </udex-masthead-menu-item>
219
+ {{else}}
220
+ <span class="udex-masthead-mobile-menu__sub-category">{{this.title}}</span>
221
+ {{/if}}
222
+ <ul class="udex-masthead-mobile-menu__sub-list" aria-label="{{this.title}}">
223
+ {{#each this.subItems}}
224
+ {{#if this.url}}
225
+ <li class="udex-masthead-mobile-menu__list-item" role="none">
226
+ <udex-masthead-menu-item
227
+ part="menu-item"
228
+ @click="{{../../handleMobileCategoryItemEvent}}"
229
+ label="{{this.title}}"
230
+ url="{{this.url}}"
231
+ third-level>
232
+ </udex-masthead-menu-item>
233
+ </li>
234
+ {{/if}}
235
+ {{/each}}
236
+ </ul>
218
237
  </li>
238
+ {{else}}
239
+ {{#if this.url}}
240
+ <li class="udex-masthead-mobile-menu__list-item" role="none">
241
+ <udex-masthead-menu-item
242
+ part="menu-item"
243
+ @click="{{../handleMobileCategoryItemEvent}}"
244
+ label="{{this.title}}"
245
+ url="{{this.url}}"
246
+ third-level>
247
+ </udex-masthead-menu-item>
248
+ </li>
249
+ {{/if}}
219
250
  {{/if}}
220
251
  {{/each}}
221
252
  {{/inline}}
@@ -151,6 +151,7 @@
151
151
  @click="{{handleLogoClick}}"
152
152
  role="link"
153
153
  href="{{homeUrl}}"
154
+ tabindex="0"
154
155
  title="{{logoTitle}}"
155
156
  target="_self"
156
157
  aria-label="{{homepageAriaLabel}}"
@@ -178,6 +179,7 @@
178
179
  @click="{{handleSiteLabelClick}}"
179
180
  role="link"
180
181
  href="{{siteLabelUrl}}"
182
+ tabindex="0"
181
183
  title="{{siteLabelTitle}}"
182
184
  target="_self"
183
185
  aria-label="{{siteLabelAriaLabel}}"
@@ -196,6 +198,7 @@
196
198
  class="udex-masthead-shell__co-brand-link"
197
199
  @click="{{handleCoBrandClick}}"
198
200
  href="{{coBrandUrl}}"
201
+ tabindex="0"
199
202
  title="{{coBrandTitle}}"
200
203
  aria-label="{{coBrandAriaLabel}}"
201
204
  target="_self"
@@ -16,7 +16,15 @@
16
16
  </span>
17
17
  {{/if}}
18
18
  {{#if isListEmpty}}
19
- <div class="udex-no-result"><span>{{getNoResultText}}</span></div>
19
+ <div class="udex-no-result">
20
+ <ui5-illustrated-message
21
+ name="NoSearchResults"
22
+ design="Dot"
23
+ title-text=" "
24
+ subtitle-text=" ">
25
+ </ui5-illustrated-message>
26
+ <span>{{getNoResultText}}</span>
27
+ </div>
20
28
  {{else if busy}}
21
29
  <udex-busy-indicator
22
30
  class="udex-busy-indicator"
@@ -62,6 +70,10 @@
62
70
  ?divider="{{this.divider}}"
63
71
  ?disabled="{{this.disabled}}"
64
72
  ?selected="{{this.selected}}"
73
+ rating="{{this.rating}}"
74
+ total-count="{{this.totalCount}}"
75
+ rating-count="{{this.ratingCount}}"
76
+ rating-max="{{this.ratingMax}}"
65
77
  label="{{this.label}}">
66
78
  {{{this.innerHTML}}}
67
79
  </udex-list-item>
@@ -99,6 +111,10 @@
99
111
  ?divider="{{this.divider}}"
100
112
  ?disabled="{{this.disabled}}"
101
113
  ?selected="{{this.selected}}"
114
+ rating="{{this.rating}}"
115
+ total-count="{{this.totalCount}}"
116
+ rating-count="{{this.ratingCount}}"
117
+ rating-max="{{this.ratingMax}}"
102
118
  label="{{this.label}}">
103
119
  {{{this.innerHTML}}}
104
120
  </udex-list-item>
@@ -118,6 +134,10 @@
118
134
  ?controlled="{{this.controlled}}"
119
135
  ?divider="{{this.divider}}"
120
136
  ?selected="{{this.item.selected}}"
137
+ rating="{{this.item.rating}}"
138
+ total-count="{{this.item.totalCount}}"
139
+ rating-count="{{this.item.ratingCount}}"
140
+ rating-max="{{this.item.ratingMax}}"
121
141
  label="{{this.item.label}}"
122
142
  accessible-role="{{../listItemRole}}">
123
143
  {{{this.item.innerHTML}}}
@@ -14,8 +14,9 @@ import type UDExListGroupHeaderBase from "./ListGroupHeaderBase.js";
14
14
  import type UDExList from "./List.js";
15
15
  import type UDExListItem from "./ListItem.js";
16
16
  import type UDExFilterMenuItem from "./FilterMenuItem.js";
17
+ import type UDExSelectBoxItem from "./SelectBoxItem.js";
17
18
  import { SHOW_SEARCH_AFTER_COUNT, UDExPopoverPart } from "./types/SearchableListBase.js";
18
- import { NO_MATCHES_FOUND, RESULT_RETURNED } from "./generated/i18n/i18n-defaults.js";
19
+ import { NO_MATCHES_FOUND, RESULT_RETURNED, STARS } from "./generated/i18n/i18n-defaults.js";
19
20
  import translate from "./utils/translate.js";
20
21
 
21
22
  export type UDExItemFromList = UDExListItemBase | UDExListGroupHeaderBase | null | undefined;
@@ -403,6 +404,10 @@ class UDExSearchableListBase extends UI5Element {
403
404
  }
404
405
 
405
406
  checkAndUpdateLabel(item: UDExListItemBase | UDExListGroupHeaderBase, str: string): boolean {
407
+ if (item.ratingCount) {
408
+ return this.isIncludes(item.ratingCount, str);
409
+ }
410
+
406
411
  if (!item.label) {
407
412
  console.warn("A label property is required for the item");
408
413
  return false;
@@ -597,7 +602,7 @@ class UDExSearchableListBase extends UI5Element {
597
602
  content.style.maxHeight = this.height || "";
598
603
  }
599
604
 
600
- _setItemsModeAndControl(items: Array<UDExFilterMenuItem>) {
605
+ _setItemsModeAndControl(items: Array<UDExFilterMenuItem | UDExSelectBoxItem>) {
601
606
  items.forEach(item => {
602
607
  item.mode = this.mode;
603
608
  item.controlled = this.isControlled;
@@ -617,6 +622,10 @@ class UDExSearchableListBase extends UI5Element {
617
622
  return translate(UDExSearchableListBase, RESULT_RETURNED);
618
623
  }
619
624
 
625
+ get startsText(): string {
626
+ return translate(UDExSearchableListBase, STARS);
627
+ }
628
+
620
629
  get isListEmpty(): boolean {
621
630
  return this._filteredItems.length === 0;
622
631
  }