@sapudex/web-components 2.25.0 → 2.26.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 (136) hide show
  1. package/cypress/fixtures/profile-menu.ts +2 -1
  2. package/cypress/specs/MastheadProfileMenu.cy.tsx +21 -6
  3. package/dist/Badge.js.map +1 -1
  4. package/dist/List.d.ts +9 -0
  5. package/dist/List.js +33 -2
  6. package/dist/List.js.map +1 -1
  7. package/dist/MastheadCountrySelector.d.ts +11 -0
  8. package/dist/MastheadCountrySelector.js +71 -14
  9. package/dist/MastheadCountrySelector.js.map +1 -1
  10. package/dist/MastheadItem.d.ts +2 -0
  11. package/dist/MastheadItem.js +14 -1
  12. package/dist/MastheadItem.js.map +1 -1
  13. package/dist/MastheadMenu.d.ts +14 -0
  14. package/dist/MastheadMenu.js +55 -15
  15. package/dist/MastheadMenu.js.map +1 -1
  16. package/dist/MastheadMobileMenu.d.ts +1 -0
  17. package/dist/MastheadMobileMenu.js +6 -0
  18. package/dist/MastheadMobileMenu.js.map +1 -1
  19. package/dist/MastheadProfileMenu.d.ts +33 -3
  20. package/dist/MastheadProfileMenu.js +93 -5
  21. package/dist/MastheadProfileMenu.js.map +1 -1
  22. package/dist/MastheadShell.d.ts +5 -0
  23. package/dist/MastheadShell.js +25 -7
  24. package/dist/MastheadShell.js.map +1 -1
  25. package/dist/Pagination.d.ts +2 -0
  26. package/dist/Pagination.js +31 -6
  27. package/dist/Pagination.js.map +1 -1
  28. package/dist/PaginationTemplate.js +6 -5
  29. package/dist/PaginationTemplate.js.map +1 -1
  30. package/dist/Tag.js +7 -0
  31. package/dist/Tag.js.map +1 -1
  32. package/dist/Tooltip.js +3 -5
  33. package/dist/Tooltip.js.map +1 -1
  34. package/dist/TooltipTemplate.d.ts +2 -0
  35. package/dist/TooltipTemplate.js +7 -0
  36. package/dist/TooltipTemplate.js.map +1 -0
  37. package/dist/assets/{InputSuggestions-DF_pzCn9.js → InputSuggestions-CG5owMFQ.js} +1 -1
  38. package/dist/assets/{ListItemStandardExpandableTextTemplate-DOYL5Szm.js → ListItemStandardExpandableTextTemplate-DpVr7qdn.js} +1 -1
  39. package/dist/assets/{bundle.esm-CWBg8c5Q.js → bundle.esm-CTkLMr6f.js} +216 -216
  40. package/dist/css/themes/MastheadCountrySelector.css +1 -1
  41. package/dist/css/themes/MastheadItem.css +1 -1
  42. package/dist/css/themes/MastheadMenu.css +1 -1
  43. package/dist/css/themes/MastheadMenuItem.css +1 -1
  44. package/dist/css/themes/MastheadProfileMenu.css +1 -1
  45. package/dist/css/themes/Quote.css +1 -1
  46. package/dist/css/themes/RatingIndicator.css +1 -1
  47. package/dist/css/themes/Search.css +1 -1
  48. package/dist/css/themes/Slider.css +1 -1
  49. package/dist/custom-elements-internal.json +10 -2
  50. package/dist/custom-elements.json +6 -2
  51. package/dist/generated/templates/MastheadCountrySelectorTemplate.lit.js +1 -1
  52. package/dist/generated/templates/MastheadCountrySelectorTemplate.lit.js.map +1 -1
  53. package/dist/generated/templates/MastheadItemTemplate.lit.js +1 -1
  54. package/dist/generated/templates/MastheadItemTemplate.lit.js.map +1 -1
  55. package/dist/generated/templates/MastheadMenuTemplate.lit.js +9 -7
  56. package/dist/generated/templates/MastheadMenuTemplate.lit.js.map +1 -1
  57. package/dist/generated/templates/MastheadProfileMenuTemplate.lit.js +7 -5
  58. package/dist/generated/templates/MastheadProfileMenuTemplate.lit.js.map +1 -1
  59. package/dist/generated/themes/MastheadCountrySelector.css.d.ts +1 -1
  60. package/dist/generated/themes/MastheadCountrySelector.css.js +1 -1
  61. package/dist/generated/themes/MastheadCountrySelector.css.js.map +1 -1
  62. package/dist/generated/themes/MastheadItem.css.d.ts +1 -1
  63. package/dist/generated/themes/MastheadItem.css.js +1 -1
  64. package/dist/generated/themes/MastheadItem.css.js.map +1 -1
  65. package/dist/generated/themes/MastheadMenu.css.d.ts +1 -1
  66. package/dist/generated/themes/MastheadMenu.css.js +1 -1
  67. package/dist/generated/themes/MastheadMenu.css.js.map +1 -1
  68. package/dist/generated/themes/MastheadMenuItem.css.d.ts +1 -1
  69. package/dist/generated/themes/MastheadMenuItem.css.js +1 -1
  70. package/dist/generated/themes/MastheadMenuItem.css.js.map +1 -1
  71. package/dist/generated/themes/MastheadProfileMenu.css.d.ts +1 -1
  72. package/dist/generated/themes/MastheadProfileMenu.css.js +1 -1
  73. package/dist/generated/themes/MastheadProfileMenu.css.js.map +1 -1
  74. package/dist/generated/themes/Quote.css.d.ts +1 -1
  75. package/dist/generated/themes/Quote.css.js +1 -1
  76. package/dist/generated/themes/Quote.css.js.map +1 -1
  77. package/dist/generated/themes/RatingIndicator.css.d.ts +1 -1
  78. package/dist/generated/themes/RatingIndicator.css.js +1 -1
  79. package/dist/generated/themes/RatingIndicator.css.js.map +1 -1
  80. package/dist/generated/themes/Search.css.d.ts +1 -1
  81. package/dist/generated/themes/Search.css.js +1 -1
  82. package/dist/generated/themes/Search.css.js.map +1 -1
  83. package/dist/generated/themes/Slider.css.d.ts +1 -1
  84. package/dist/generated/themes/Slider.css.js +1 -1
  85. package/dist/generated/themes/Slider.css.js.map +1 -1
  86. package/dist/types/List.d.ts +6 -0
  87. package/dist/types/List.js +7 -0
  88. package/dist/types/List.js.map +1 -1
  89. package/dist/vscode.html-custom-data.json +1 -1
  90. package/dist/web-types.json +4 -6
  91. package/package.json +1 -1
  92. package/src/Badge.ts +5 -2
  93. package/src/List.ts +41 -2
  94. package/src/MastheadCountrySelector.hbs +20 -16
  95. package/src/MastheadCountrySelector.ts +83 -16
  96. package/src/MastheadItem.hbs +1 -1
  97. package/src/MastheadItem.ts +16 -1
  98. package/src/MastheadMenu.hbs +33 -12
  99. package/src/MastheadMenu.ts +67 -13
  100. package/src/MastheadMobileMenu.ts +9 -1
  101. package/src/MastheadProfileMenu.hbs +43 -26
  102. package/src/MastheadProfileMenu.ts +124 -7
  103. package/src/MastheadShell.ts +29 -7
  104. package/src/Pagination.ts +32 -6
  105. package/src/PaginationTemplate.tsx +19 -16
  106. package/src/Tag.ts +1 -1
  107. package/src/Tooltip.ts +7 -6
  108. package/src/TooltipTemplate.tsx +29 -0
  109. package/src/generated/templates/MastheadCountrySelectorTemplate.lit.ts +1 -1
  110. package/src/generated/templates/MastheadItemTemplate.lit.ts +1 -1
  111. package/src/generated/templates/MastheadMenuTemplate.lit.ts +9 -7
  112. package/src/generated/templates/MastheadProfileMenuTemplate.lit.ts +7 -5
  113. package/src/generated/themes/MastheadCountrySelector.css.ts +1 -1
  114. package/src/generated/themes/MastheadItem.css.ts +1 -1
  115. package/src/generated/themes/MastheadMenu.css.ts +1 -1
  116. package/src/generated/themes/MastheadMenuItem.css.ts +1 -1
  117. package/src/generated/themes/MastheadProfileMenu.css.ts +1 -1
  118. package/src/generated/themes/Quote.css.ts +1 -1
  119. package/src/generated/themes/RatingIndicator.css.ts +1 -1
  120. package/src/generated/themes/Search.css.ts +1 -1
  121. package/src/generated/themes/Slider.css.ts +1 -1
  122. package/src/themes/Badge.css +0 -1
  123. package/src/themes/MastheadCountrySelector.css +70 -10
  124. package/src/themes/MastheadItem.css +0 -1
  125. package/src/themes/MastheadMenu.css +1 -2
  126. package/src/themes/MastheadMenuItem.css +1 -0
  127. package/src/themes/MastheadProfileMenu.css +113 -17
  128. package/src/themes/Quote.css +1 -1
  129. package/src/themes/Search.css +2 -3
  130. package/src/types/List.ts +7 -0
  131. package/cypress/downloads/downloads.html +0 -0
  132. package/dist/generated/templates/TooltipTemplate.lit.d.ts +0 -3
  133. package/dist/generated/templates/TooltipTemplate.lit.js +0 -8
  134. package/dist/generated/templates/TooltipTemplate.lit.js.map +0 -1
  135. package/src/Tooltip.hbs +0 -22
  136. package/src/generated/templates/TooltipTemplate.lit.ts +0 -12
@@ -22,18 +22,39 @@
22
22
  {{#*inline "header"}}
23
23
  <div class="udex-masthead-menu__header">
24
24
  {{#if this.url}}
25
- <udex-masthead-menu-item
26
- id="category-{{categoryId}}"
27
- type="Heading"
28
- part="menu-item"
29
- exportparts="menu-item"
30
- accessible-role="link"
31
- @click="{{../../handleMenuItemClick}}"
32
- url="{{this.url}}"
33
- label="{{this.category}}"
34
- icon-end
35
- has-border>
36
- </udex-masthead-menu-item>
25
+ {{#if ../_isMobileMode}}
26
+ <udex-masthead-menu-item
27
+ id="category-{{categoryId}}"
28
+ type="Heading"
29
+ part="menu-item"
30
+ exportparts="menu-item"
31
+ label="{{this.category}}"
32
+ has-border>
33
+ </udex-masthead-menu-item>
34
+ <udex-masthead-menu-item
35
+ part="menu-item"
36
+ accessible-role="link"
37
+ exportparts="menu-item"
38
+ part="menu-item"
39
+ exportparts="menu-item"
40
+ label="{{../overviewHeaderLinkText}}"
41
+ url="{{this.url}}"
42
+ has-border>
43
+ </udex-masthead-menu-item>
44
+ {{else}}
45
+ <udex-masthead-menu-item
46
+ id="category-{{categoryId}}"
47
+ type="Heading"
48
+ part="menu-item"
49
+ exportparts="menu-item"
50
+ accessible-role="link"
51
+ @click="{{../../handleMenuItemClick}}"
52
+ url="{{this.url}}"
53
+ label="{{this.category}}"
54
+ icon-end
55
+ has-border>
56
+ </udex-masthead-menu-item>
57
+ {{/if}}
37
58
  {{else}}
38
59
  <udex-masthead-menu-item
39
60
  id="category-{{categoryId}}"
@@ -2,11 +2,15 @@ import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js";
2
2
  import customElement from "@ui5/webcomponents-base/dist/decorators/customElement.js";
3
3
  import property from "@ui5/webcomponents-base/dist/decorators/property.js";
4
4
  import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js";
5
+ import i18n from "@ui5/webcomponents-base/dist/decorators/i18n.js";
6
+ import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js";
5
7
  import Icon from "@ui5/webcomponents/dist/Icon.js";
6
8
  import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js";
7
9
  import "@ui5/webcomponents-icons/dist/slim-arrow-right.js";
8
10
  import "@ui5/webcomponents-icons/dist/action.js";
9
- import { isUp, isDown } from "@ui5/webcomponents-base/dist/Keys.js";
11
+ import {
12
+ isUp, isDown, isTabNext, isTabPrevious, isHome, isEnd,
13
+ } from "@ui5/webcomponents-base/dist/Keys.js";
10
14
  import UDExBadge from "./Badge.js";
11
15
  import UDExMastheadMenuItem, { UDExItemType } from "./MastheadMenuItem.js";
12
16
  import type UDExMastheadItem from "./MastheadItem.js";
@@ -14,6 +18,9 @@ import UDExDivider from "./Divider.js";
14
18
  import MastheadMenuTemplate from "./generated/templates/MastheadMenuTemplate.lit.js";
15
19
  import parseArrayFromString from "./utils/parseArrayFromString.js";
16
20
  import AnalyticsName from "./types/AnalyticsName.js";
21
+ import { OVERVIEW } from "./generated/i18n/i18n-defaults.js";
22
+ import type { UDExScrollIntoViewOptions } from "./types/List.js";
23
+ import translate from "./utils/translate.js";
17
24
 
18
25
  // Styles
19
26
  import MastheadMenuCss from "./generated/themes/MastheadMenu.css.js";
@@ -116,25 +123,58 @@ class UDExMastheadMenu extends UI5Element {
116
123
  @property({ type: Boolean })
117
124
  _isMobileMode!: boolean;
118
125
 
126
+ /**
127
+ * Defines the scroll behavior for the items of the component.
128
+ *
129
+ * @default undefined
130
+ * @private
131
+ */
132
+ @property()
133
+ _scrollIntoView?: `${UDExScrollIntoViewOptions}`;
134
+
135
+ @i18n("@sapudex/web-components")
136
+ static i18nBundle: I18nBundle;
137
+
119
138
  handleKeyDown(e: KeyboardEvent): void {
120
- this.handleUpArrow(e);
121
- this.handleDownArrow(e);
139
+ const isFirstItem = e.target === this.links[0];
140
+ const isLastItem = e.target === this.links[this.links.length - 1];
141
+
142
+ if (isUp(e) || (isTabPrevious(e) && !isFirstItem)) {
143
+ this.handleUpArrow(e);
144
+ }
145
+ if (isDown(e) || (isTabNext(e) && !isLastItem)) {
146
+ this.handleDownArrow(e);
147
+ }
148
+ if (isHome(e)) {
149
+ this.handleHomeKey(e);
150
+ }
151
+ if (isEnd(e)) {
152
+ this.handleEndKey(e);
153
+ }
154
+ }
155
+
156
+ handleHomeKey(e: KeyboardEvent): void {
157
+ e.preventDefault();
158
+ const firstItem = this.links[0];
159
+ firstItem.focus();
160
+ }
161
+
162
+ handleEndKey(e: KeyboardEvent): void {
163
+ e.preventDefault();
164
+ const lastItem = this.links[this.links.length - 1];
165
+ lastItem.focus();
122
166
  }
123
167
 
124
168
  handleUpArrow(e: KeyboardEvent): void {
125
- if (isUp(e)) {
126
- e.preventDefault();
127
- const currentItem = e.target as UDExMastheadMenuItem;
128
- this.focusPreviousItem(currentItem);
129
- }
169
+ e.preventDefault();
170
+ const currentItem = e.target as UDExMastheadMenuItem;
171
+ this.focusPreviousItem(currentItem);
130
172
  }
131
173
 
132
174
  handleDownArrow(e: KeyboardEvent): void {
133
- if (isDown(e)) {
134
- e.preventDefault();
135
- const currentItem = e.target as UDExMastheadMenuItem;
136
- this.focusNextItem(currentItem);
137
- }
175
+ e.preventDefault();
176
+ const currentItem = e.target as UDExMastheadMenuItem;
177
+ this.focusNextItem(currentItem);
138
178
  }
139
179
 
140
180
  handleMenuItemClick(e: PointerEvent): void {
@@ -164,12 +204,18 @@ class UDExMastheadMenu extends UI5Element {
164
204
  const currentSelectedIndex = this.getCurrentIndex(item);
165
205
  const lastItemIndex = this.links.length - 1;
166
206
  const previousSelectIndex = currentSelectedIndex - 1 < 0 ? lastItemIndex : currentSelectedIndex - 1;
207
+ if (this._scrollIntoView) {
208
+ this.scrollToItem(this.links[previousSelectIndex]);
209
+ }
167
210
  this.links[previousSelectIndex].focus();
168
211
  }
169
212
 
170
213
  focusNextItem(item: UDExMastheadMenuItem): void {
171
214
  const currentSelectedIndex = this.getCurrentIndex(item);
172
215
  const nextSelectIndex = currentSelectedIndex + 1 > this.links.length - 1 ? 0 : currentSelectedIndex + 1;
216
+ if (this._scrollIntoView) {
217
+ this.scrollToItem(this.links[nextSelectIndex]);
218
+ }
173
219
  this.links[nextSelectIndex].focus();
174
220
  }
175
221
 
@@ -177,6 +223,10 @@ class UDExMastheadMenu extends UI5Element {
177
223
  return this.links.indexOf(item);
178
224
  }
179
225
 
226
+ scrollToItem(item: UDExMastheadMenuItem): void {
227
+ item.scrollIntoView({ block: this._scrollIntoView?.toLowerCase() as ScrollLogicalPosition });
228
+ }
229
+
180
230
  get links(): Array<UDExMastheadMenuItem> {
181
231
  const menuItems: Array<UDExMastheadMenuItem> = Array.from(this.shadowRoot!.querySelectorAll("[udex-masthead-menu-item]"));
182
232
  return menuItems.filter(({ url }) => url && url.length > 0);
@@ -205,6 +255,10 @@ class UDExMastheadMenu extends UI5Element {
205
255
  const hasOneColumn = this.itemsList.length === 1 && this.itemsList[0].subMenuLinkItems.length === 1;
206
256
  return hasOneColumn ? rowClass : "";
207
257
  }
258
+
259
+ get overviewHeaderLinkText(): string {
260
+ return translate(UDExMastheadMenu, OVERVIEW);
261
+ }
208
262
  }
209
263
 
210
264
  UDExMastheadMenu.define();
@@ -11,6 +11,7 @@ import {
11
11
  } from "@ui5/webcomponents-base/dist/Keys.js";
12
12
  import type { MenuItem, SubMenuLinkItem } from "./MastheadItem.js";
13
13
  import type UDExMastheadItem from "./MastheadItem.js";
14
+ import type UDExSearch from "./Search.js";
14
15
  import UDExMastheadMenuItem, { UDExItemType } from "./MastheadMenuItem.js";
15
16
  import { OVERVIEW } from "./generated/i18n/i18n-defaults.js";
16
17
  import AnalyticsName from "./types/AnalyticsName.js";
@@ -551,7 +552,14 @@ class UDExMastheadMobileMenu extends UI5Element {
551
552
  return analyticsPath;
552
553
  }
553
554
 
554
- closeMenu():void {
555
+ resetSearch(): void {
556
+ const search = this.search[0] as UDExSearch;
557
+ if (search && search.value) {
558
+ search.value = "";
559
+ }
560
+ }
561
+
562
+ closeMenu(): void {
555
563
  this._mastheadShell.closeMobileMenu();
556
564
  this._mastheadShell.mobileBtn?.focus();
557
565
  }
@@ -14,7 +14,8 @@
14
14
  <udex-avatar
15
15
  aria-hidden="true"
16
16
  size="L"
17
- initials="{{userData.avatarInitials}}">
17
+ initials="{{userData.avatarInitials}}"
18
+ fallback-icon="{{userData.fallbackIcon}}">
18
19
  {{#if userData.avatarUrl}}
19
20
  <img src="{{userData.avatarUrl}}" alt="avatar"/>
20
21
  {{/if}}
@@ -40,25 +41,39 @@
40
41
  <slot name="message"></slot>
41
42
  </div>
42
43
  {{/if}}
43
- <div class="udex-masthead-profile-menu__links">
44
- <udex-masthead-menu
45
- exportparts="badge, menu-item"
46
- part="menu"
47
- sub-items='{{linksList}}'
48
- @ui5-menu-item-click="{{handleProfileMenuItemClick}}">
49
- </udex-masthead-menu>
50
- {{#if logoutLink}}
51
- <div class="udex-masthead-profile-menu__actions">
52
- <udex-masthead-menu-item
53
- @click="{{handleUserLogoutItemClick}}"
54
- label="{{logoutText}}"
55
- url="{{logoutUrl}}">
56
- </udex-masthead-menu-item>
44
+ <div class="udex-masthead-profile-menu__content">
45
+ <div
46
+ class="udex-masthead-profile-menu__links"
47
+ @scroll="{{handleProfileMenuShadowVisible}}">
48
+ <udex-masthead-menu
49
+ exportparts="badge, menu-item"
50
+ part="menu"
51
+ sub-items='{{linksList}}'
52
+ @ui5-menu-item-click="{{handleProfileMenuItemClick}}"
53
+ _scroll-into-view="Center">
54
+ </udex-masthead-menu>
57
55
  </div>
58
- {{/if}}
59
56
  </div>
57
+ {{#if hasActionButton}}
58
+ <div class="udex-masthead-profile-menu__actions">
59
+ {{#if hasLogoutButton}}
60
+ <div class="udex-masthead-profile-menu__btn">
61
+ <slot name="logoutButton"></slot>
62
+ </div>
63
+ {{else}}
64
+ <udex-link
65
+ @click="{{handleUserLogoutClick}}"
66
+ end-icon="action"
67
+ design="Default"
68
+ accessible-role="Link"
69
+ href="{{logoutUrl}}">
70
+ {{logoutText}}
71
+ </udex-link>
72
+ {{/if}}
73
+ </div>
74
+ {{/if}}
60
75
  {{/inline}}
61
-
76
+
62
77
  {{#*inline "account-indetities"}}
63
78
  <div class="udex-masthead-profile-menu__header-wrap back-btn">
64
79
  <udex-masthead-menu-item
@@ -70,13 +85,15 @@
70
85
  </udex-masthead-menu-item>
71
86
  <span class="udex-masthead-profile-menu__switcher-title">{{switcherAccountText}}</span>
72
87
  </div>
88
+ <span class="udex-masthead-profile-menu__identities-list-title">{{listTitleText}}</span>
73
89
  <div class="udex-masthead-profile-menu__identities-list-wrap">
74
- <span class="udex-masthead-profile-menu__identities-list-title">{{listTitleText}}</span>
75
90
  {{#if identitiesList.length}}
76
91
  <udex-list
77
92
  class="udex-masthead-profile-menu__identities-list"
78
93
  mode="SingleSelect"
79
94
  accessible-name="{{listTitleText}}"
95
+ @scroll="{{handleIdentitiesListShadowVisible}}"
96
+ _scroll-into-view="Center"
80
97
  controlled>
81
98
  {{#each identitiesList}}
82
99
  <udex-list-item
@@ -92,13 +109,13 @@
92
109
  {{/each}}
93
110
  </udex-list>
94
111
  {{/if}}
95
- <udex-button
96
- @click="{{fireEventAddOrRemoveAccountClick}}"
97
- class="udex-masthead-profile-menu__add-remove-btn"
98
- design="Primary"
99
- end-icon="action"
100
- size="Large">
101
- {{addOrRemoveAccountText}}
102
- </udex-button>
103
112
  </div>
113
+ <udex-button
114
+ @click="{{fireEventAddOrRemoveAccountClick}}"
115
+ class="udex-masthead-profile-menu__add-remove-btn"
116
+ design="Primary"
117
+ end-icon="action"
118
+ size="Large">
119
+ {{addOrRemoveAccountText}}
120
+ </udex-button>
104
121
  {{/inline}}
@@ -5,6 +5,7 @@ import slot from "@ui5/webcomponents-base/dist/decorators/slot.js";
5
5
  import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js";
6
6
  import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js";
7
7
  import i18n from "@ui5/webcomponents-base/dist/decorators/i18n.js";
8
+ import { isDesktop } from "@ui5/webcomponents-base/dist/Device.js";
8
9
  import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js";
9
10
  import {
10
11
  LOGOUT, SWITCH_ACCOUNT, BACK, OTHER_IDENTITIES, ADD_OR_REMOVE_ACCOUNT,
@@ -13,6 +14,7 @@ import { isEscape } from "@ui5/webcomponents-base/Keys.js";
13
14
  import UDExMastheadMenu from "./MastheadMenu.js";
14
15
  import UDExButton from "./Button.js";
15
16
  import UDExList from "./List.js";
17
+ import UDExLink from "./Link.js";
16
18
  import UDExListItem from "./ListItem.js";
17
19
  import UDExMastheadMenuItem from "./MastheadMenuItem.js";
18
20
  import MastheadProfileMenuTemplate from "./generated/templates/MastheadProfileMenuTemplate.lit.js";
@@ -37,6 +39,7 @@ export interface UserData {
37
39
  email?: string,
38
40
  avatarUrl?: string,
39
41
  avatarInitials?: string
42
+ fallbackIcon?: string,
40
43
  }
41
44
 
42
45
  export interface UserIdentity {
@@ -96,6 +99,7 @@ type UDExMastheadProfileMenuAddOrRemoveClickEventDetail = {
96
99
  UDExListItem,
97
100
  UDExButton,
98
101
  UDExList,
102
+ UDExLink,
99
103
  ],
100
104
  })
101
105
 
@@ -198,13 +202,29 @@ class UDExMastheadProfileMenu extends UI5Element {
198
202
  _openIdentities: boolean = false;
199
203
 
200
204
  /**
201
- * Placeholder for message strip.
205
+ * Defines the request render state
206
+ *
207
+ * @private
208
+ */
209
+ @property({ type: Boolean, noAttribute: true })
210
+ _requestRender = false;
211
+
212
+ /**
213
+ * Slot for message strip.
202
214
  *
203
215
  * @public
204
216
  */
205
217
  @slot({ type: Node, "default": false })
206
218
  message!: Array<Node>;
207
219
 
220
+ /**
221
+ * Slot for logout button.
222
+ *
223
+ * @public
224
+ */
225
+ @slot({ type: HTMLElement })
226
+ logoutButton!: Array<Node>;
227
+
208
228
  @i18n("@sapudex/web-components")
209
229
  static i18nBundle: I18nBundle;
210
230
 
@@ -212,6 +232,8 @@ class UDExMastheadProfileMenu extends UI5Element {
212
232
  _handleResizeBound: ResizeObserverCallback;
213
233
  _shouldFocusBackBtn!: boolean;
214
234
  _shouldFocusSwitchBtn!: boolean;
235
+ _identitiesListClassName = "udex-masthead-profile-menu__identities-list";
236
+ _profileMenuLinksClassName = "udex-masthead-profile-menu__links";
215
237
 
216
238
  constructor() {
217
239
  super();
@@ -223,10 +245,14 @@ class UDExMastheadProfileMenu extends UI5Element {
223
245
  this.updateFocusState(this._shouldFocusBackBtn, this.focusBackBtn.bind(this));
224
246
  this.updateFocusState(this._shouldFocusSwitchBtn, this.focusSwitchBtn.bind(this));
225
247
  this.setMenuItemsMobileMode();
248
+ this.checkScrollableElements();
226
249
  }
227
250
 
228
251
  onEnterDOM(): void {
229
252
  ResizeHandler.register(this, this._handleResizeBound);
253
+ if (isDesktop()) {
254
+ this.setAttribute("desktop", "");
255
+ }
230
256
  }
231
257
 
232
258
  onExitDOM(): void {
@@ -239,6 +265,8 @@ class UDExMastheadProfileMenu extends UI5Element {
239
265
  if (this.profileMenuLinks) {
240
266
  this.profileMenuLinks._isMobileMode = this.isMobile;
241
267
  }
268
+
269
+ this.checkScrollableElements();
242
270
  }
243
271
 
244
272
  handleSwitcherClick(): void {
@@ -247,8 +275,8 @@ class UDExMastheadProfileMenu extends UI5Element {
247
275
  this._shouldFocusSwitchBtn = !this._openIdentities;
248
276
  }
249
277
 
250
- handleUserLogoutItemClick(e: PointerEvent): void {
251
- this.fireLogoutItemClick(e);
278
+ handleUserLogoutClick(e: PointerEvent): void {
279
+ this.fireLogoutClick(e);
252
280
  if (this._isMobileMode) {
253
281
  this.closeMenu();
254
282
  }
@@ -318,15 +346,18 @@ class UDExMastheadProfileMenu extends UI5Element {
318
346
  }
319
347
  }
320
348
 
321
- fireLogoutItemClick(e: PointerEvent): void {
349
+ fireLogoutClick(e: PointerEvent): void {
322
350
  const item = e.target as UDExMastheadMenuItem;
323
-
324
- this.fireDecoratorEvent("logout", {
351
+ const executeEvent = this.fireDecoratorEvent("logout", {
325
352
  item,
326
- sourceNode: item.shadowRoot?.querySelector(".udex-masthead-menu-item") as HTMLElement,
353
+ sourceNode: item.shadowRoot?.querySelector("a") as HTMLElement,
327
354
  originalEvent: e,
328
355
  analyticsName: AnalyticsName.Header,
329
356
  });
357
+
358
+ if (!executeEvent) {
359
+ e.preventDefault();
360
+ }
330
361
  }
331
362
 
332
363
  fireMenuItemClick(e: CustomEvent): void {
@@ -340,6 +371,84 @@ class UDExMastheadProfileMenu extends UI5Element {
340
371
  });
341
372
  }
342
373
 
374
+ checkScrollableElements(): void {
375
+ if (this._openIdentities) {
376
+ this.checkScrollableElement(this.identitiesHTMLElement, this._identitiesListClassName);
377
+ }
378
+
379
+ if (this.isMobile) {
380
+ this.checkScrollableElement(this.profileMenuHTMLElement, this._profileMenuLinksClassName);
381
+ }
382
+ }
383
+
384
+ checkScrollableElement(element: HTMLElement, className: string): void {
385
+ if (element) {
386
+ requestAnimationFrame(() => {
387
+ if (this.isScrollableElement(element)) {
388
+ element.classList.add(`${className}_scrollable`);
389
+ }
390
+ });
391
+ }
392
+ }
393
+
394
+ scrollToTopProfileMenu(): void {
395
+ setTimeout(() => {
396
+ this.profileMenuHTMLElement.scrollTop = 0;
397
+ }, 0);
398
+ }
399
+
400
+ isScrollableElement(element: HTMLElement): boolean {
401
+ return element.scrollHeight > element.clientHeight;
402
+ }
403
+
404
+ handleProfileMenuShadowVisible(): void {
405
+ this.toggleScrollableClass(
406
+ this.profileMenuHTMLElement,
407
+ this._profileMenuLinksClassName,
408
+ this.scrollBottomProfileMenu,
409
+ );
410
+ }
411
+
412
+ handleIdentitiesListShadowVisible(): void {
413
+ this.toggleScrollableClass(
414
+ this.identitiesHTMLElement,
415
+ this._identitiesListClassName,
416
+ this.scrollBottomIdentitiesList,
417
+ );
418
+ }
419
+
420
+ toggleScrollableClass(el: HTMLElement, className: string, scrollBottom: number): void {
421
+ if (scrollBottom === 0) {
422
+ el.classList.remove(`${className}_scrollable`);
423
+ } else {
424
+ el.classList.add(`${className}_scrollable`);
425
+ }
426
+ }
427
+
428
+ get scrollBottomIdentitiesList(): number {
429
+ return this.calculateScrollBottom(this.identitiesHTMLElement);
430
+ }
431
+
432
+ get scrollBottomProfileMenu(): number {
433
+ return this.calculateScrollBottom(this.profileMenuHTMLElement);
434
+ }
435
+
436
+ calculateScrollBottom(element: HTMLElement): number {
437
+ return element.scrollHeight - element.scrollTop - element.clientHeight;
438
+ }
439
+
440
+ get profileMenuHTMLElement(): HTMLElement {
441
+ return this.getElementByClassName(this._profileMenuLinksClassName);
442
+ }
443
+
444
+ get identitiesHTMLElement(): HTMLElement {
445
+ return this.getElementByClassName(this._identitiesListClassName);
446
+ }
447
+
448
+ getElementByClassName(className: string): HTMLElement {
449
+ return this.shadowRoot?.querySelector<HTMLElement>(`.${className}`) as HTMLElement;
450
+ }
451
+
343
452
  closeMenu():void {
344
453
  this._mastheadShell.closeMobileMenu();
345
454
  this._mastheadShell.mobileBtn?.focus();
@@ -381,6 +490,10 @@ class UDExMastheadProfileMenu extends UI5Element {
381
490
  return !!this.message.length;
382
491
  }
383
492
 
493
+ get hasLogoutButton(): boolean {
494
+ return !!this.logoutButton.length;
495
+ }
496
+
384
497
  get logoutLink(): boolean {
385
498
  return !!this.logoutUrl?.length;
386
499
  }
@@ -425,6 +538,10 @@ class UDExMastheadProfileMenu extends UI5Element {
425
538
  get isMobile(): boolean {
426
539
  return this.isAtMostBreakpointSizeM || this.mastheadShell?.isMobileMenuMode;
427
540
  }
541
+
542
+ get hasActionButton(): boolean {
543
+ return this.logoutLink || this.hasLogoutButton;
544
+ }
428
545
  }
429
546
 
430
547
  UDExMastheadProfileMenu.define();
@@ -543,6 +543,7 @@ class UDExMastheadShell extends UI5Element {
543
543
  static i18nBundle: I18nBundle;
544
544
 
545
545
  _searchOpener!: UDExMastheadItem | null | undefined;
546
+ _desktopSearch!: UDExSearch | null | undefined;
546
547
  _mobileMenu!: UDExMastheadMobileMenu | null | undefined;
547
548
  _handleResizeBound: ResizeObserverCallback;
548
549
  _rootHolder!: HTMLElement | null | undefined;
@@ -563,9 +564,10 @@ class UDExMastheadShell extends UI5Element {
563
564
  onAfterRendering() {
564
565
  this._rootHolder = this.mastheadHolder;
565
566
  this._searchOpener = this.searchOpener;
567
+ this._desktopSearch = this.desktopSearchSlot;
566
568
  this._mobileMenu = this.mastheadMobileMenu;
567
569
 
568
- if (this._isSearchOpened) {
570
+ if (this._isSearchOpened && this._desktopSearch) {
569
571
  this.focusSearchInput();
570
572
  }
571
573
 
@@ -701,16 +703,19 @@ class UDExMastheadShell extends UI5Element {
701
703
  handleCartClick(e: PointerEvent): void {
702
704
  e.stopPropagation();
703
705
  this.fireMastheadEvent("cart-click", e);
706
+ this.mobileMenuReset();
704
707
  }
705
708
 
706
709
  handleJouleClick(e: PointerEvent): void {
707
710
  e.stopPropagation();
708
711
  this.fireMastheadEvent("joule-click", e);
712
+ this.mobileMenuReset();
709
713
  }
710
714
 
711
715
  handleProfileClick(e: PointerEvent): void {
712
716
  e.stopPropagation();
713
717
  this.fireMastheadEvent("profile-click", e);
718
+ this.mobileMenuReset();
714
719
  }
715
720
 
716
721
  handleSupportClick(e: PointerEvent): void {
@@ -721,6 +726,7 @@ class UDExMastheadShell extends UI5Element {
721
726
  handleCountrySelectorClick(e: PointerEvent): void {
722
727
  e.stopPropagation();
723
728
  this.fireMastheadEvent("country-selector-click", e);
729
+ this.mobileMenuReset();
724
730
  }
725
731
 
726
732
  handleOpenMobileMenu(): void {
@@ -743,6 +749,7 @@ class UDExMastheadShell extends UI5Element {
743
749
  this._closeBtnClicked = true;
744
750
  this.fireMastheadEvent("search-close-click", e);
745
751
  this.closeSearch();
752
+ this.resetSearch();
746
753
  }
747
754
 
748
755
  handleEnterAndSpaceOnCloseBtn(e: KeyboardEvent): void {
@@ -754,11 +761,8 @@ class UDExMastheadShell extends UI5Element {
754
761
  }
755
762
 
756
763
  focusSearchInput(): void {
757
- const searchSlot = this.querySelector<UDExSearch>("[udex-search]");
758
- if (searchSlot) {
759
- const input = searchSlot.shadowRoot!.querySelector<HTMLElement>("input");
760
- input?.focus();
761
- }
764
+ const input = this._desktopSearch?.shadowRoot!.querySelector<HTMLElement>("input");
765
+ input?.focus();
762
766
  }
763
767
 
764
768
  focusPreviousMenuItem(item: UDExMastheadItem): void {
@@ -787,6 +791,12 @@ class UDExMastheadShell extends UI5Element {
787
791
  });
788
792
  }
789
793
 
794
+ resetSearch(): void {
795
+ if (this._desktopSearch) {
796
+ this._desktopSearch.value = "";
797
+ }
798
+ }
799
+
790
800
  setSelectedItem(e: CustomEvent): void {
791
801
  const clickedItem: UDExMastheadItem = e.detail.item;
792
802
  if (clickedItem) {
@@ -967,6 +977,13 @@ class UDExMastheadShell extends UI5Element {
967
977
  this.fireDecoratorEvent(eventName, eventDetails);
968
978
  }
969
979
 
980
+ mobileMenuReset(): void {
981
+ if (this._isMobileMenuOpen) {
982
+ this._mobileMenu?.showFirstLevelMenu();
983
+ this._mobileMenu?.resetSearch();
984
+ }
985
+ }
986
+
970
987
  /**
971
988
  * Close the search panel.
972
989
  * @public
@@ -1023,6 +1040,7 @@ class UDExMastheadShell extends UI5Element {
1023
1040
  (this.mobileBtn as UDExMastheadItem).selected = false;
1024
1041
  this._isMobileMenuOpen = false;
1025
1042
  this._mobileMenu?.showFirstLevelMenu();
1043
+ this._mobileMenu?.resetSearch();
1026
1044
 
1027
1045
  if (this.bodyOverflow) {
1028
1046
  this.removeOverflowBody();
@@ -1043,6 +1061,10 @@ class UDExMastheadShell extends UI5Element {
1043
1061
  ];
1044
1062
  }
1045
1063
 
1064
+ get desktopSearchSlot(): UDExSearch | null {
1065
+ return this.querySelector<UDExSearch>("[udex-search]");
1066
+ }
1067
+
1046
1068
  get searchOpener(): MastheadItemType {
1047
1069
  return this.shadowRoot?.querySelector(".udex-masthead-shell__search-btn");
1048
1070
  }
@@ -1152,7 +1174,7 @@ class UDExMastheadShell extends UI5Element {
1152
1174
  }
1153
1175
 
1154
1176
  get openSearchButtonAccessibleNameText(): string {
1155
- return this.openSearchButtonAccessibleName || UDExMastheadShell.i18nBundle.getText(SEARCH);
1177
+ return this.openSearchButtonAccessibleName || translate(UDExMastheadShell, SEARCH);
1156
1178
  }
1157
1179
 
1158
1180
  get mainNavigationAriaLabel(): string {