@sapudex/web-components 2.1.1 → 2.2.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 (264) hide show
  1. package/cypress/specs/ListItem.cy.tsx +4 -4
  2. package/cypress/specs/SecondaryNavigationDesktop.cy.tsx +28 -37
  3. package/cypress/specs/Slider.cy.tsx +4 -3
  4. package/dist/Badge.d.ts +2 -2
  5. package/dist/Badge.js +4 -4
  6. package/dist/Badge.js.map +1 -1
  7. package/dist/Breadcrumbs.d.ts +1 -0
  8. package/dist/Breadcrumbs.js +11 -1
  9. package/dist/Breadcrumbs.js.map +1 -1
  10. package/dist/Button.d.ts +12 -1
  11. package/dist/Button.js +12 -1
  12. package/dist/Button.js.map +1 -1
  13. package/dist/Checkbox.d.ts +1 -0
  14. package/dist/Checkbox.js +3 -0
  15. package/dist/Checkbox.js.map +1 -1
  16. package/dist/ControlButton.d.ts +2 -1
  17. package/dist/ControlButton.js +2 -1
  18. package/dist/ControlButton.js.map +1 -1
  19. package/dist/DatePicker.d.ts +2 -2
  20. package/dist/DatePicker.js.map +1 -1
  21. package/dist/InputGroup.d.ts +5 -2
  22. package/dist/InputGroup.js +6 -0
  23. package/dist/InputGroup.js.map +1 -1
  24. package/dist/ListItem.d.ts +3 -2
  25. package/dist/ListItem.js +2 -2
  26. package/dist/ListItem.js.map +1 -1
  27. package/dist/MastheadItem.js +1 -1
  28. package/dist/MastheadItem.js.map +1 -1
  29. package/dist/MediaPlayer.d.ts +2 -1
  30. package/dist/MediaPlayer.js.map +1 -1
  31. package/dist/MediaPlayerYoutube.d.ts +2 -1
  32. package/dist/MediaPlayerYoutube.js.map +1 -1
  33. package/dist/Pagination.d.ts +1 -1
  34. package/dist/Pagination.js.map +1 -1
  35. package/dist/PhoneNumberField.d.ts +5 -2
  36. package/dist/PhoneNumberField.js +7 -1
  37. package/dist/PhoneNumberField.js.map +1 -1
  38. package/dist/ProgressBar.d.ts +2 -2
  39. package/dist/ProgressBar.js +6 -6
  40. package/dist/ProgressBar.js.map +1 -1
  41. package/dist/RadioButton.d.ts +2 -2
  42. package/dist/RadioButton.js +6 -6
  43. package/dist/RadioButton.js.map +1 -1
  44. package/dist/Search.d.ts +0 -1
  45. package/dist/Search.js +1 -3
  46. package/dist/Search.js.map +1 -1
  47. package/dist/SecondaryNavigation.d.ts +4 -1
  48. package/dist/SecondaryNavigation.js +38 -10
  49. package/dist/SecondaryNavigation.js.map +1 -1
  50. package/dist/SecondaryNavigationItem.d.ts +10 -0
  51. package/dist/SecondaryNavigationItem.js +19 -0
  52. package/dist/SecondaryNavigationItem.js.map +1 -1
  53. package/dist/SecondaryNavigationItemBase.d.ts +1 -0
  54. package/dist/SecondaryNavigationItemBase.js +4 -0
  55. package/dist/SecondaryNavigationItemBase.js.map +1 -1
  56. package/dist/SecondaryNavigationSubItem.d.ts +0 -1
  57. package/dist/SecondaryNavigationSubItem.js +0 -4
  58. package/dist/SecondaryNavigationSubItem.js.map +1 -1
  59. package/dist/SegmentedButton.d.ts +1 -1
  60. package/dist/SegmentedButton.js +1 -1
  61. package/dist/SegmentedButton.js.map +1 -1
  62. package/dist/SegmentedButtonItem.d.ts +1 -1
  63. package/dist/SegmentedButtonItem.js +2 -2
  64. package/dist/SegmentedButtonItem.js.map +1 -1
  65. package/dist/StatusBadge.d.ts +8 -3
  66. package/dist/StatusBadge.js +9 -1
  67. package/dist/StatusBadge.js.map +1 -1
  68. package/dist/StepInput.d.ts +3 -3
  69. package/dist/StepInput.js.map +1 -1
  70. package/dist/TableCellBase.d.ts +2 -2
  71. package/dist/TableCellBase.js.map +1 -1
  72. package/dist/Tag.d.ts +2 -2
  73. package/dist/Tag.js +4 -4
  74. package/dist/Tag.js.map +1 -1
  75. package/dist/TextArea.d.ts +2 -2
  76. package/dist/TextArea.js +9 -9
  77. package/dist/TextArea.js.map +1 -1
  78. package/dist/TextField.d.ts +2 -2
  79. package/dist/TextField.js +5 -5
  80. package/dist/TextField.js.map +1 -1
  81. package/dist/Toast.js +1 -1
  82. package/dist/Toast.js.map +1 -1
  83. package/dist/Upload.d.ts +1 -1
  84. package/dist/Upload.js +1 -1
  85. package/dist/Upload.js.map +1 -1
  86. package/dist/UploadItem.d.ts +3 -3
  87. package/dist/UploadItem.js +9 -9
  88. package/dist/UploadItem.js.map +1 -1
  89. package/dist/assets/InputSuggestions-KGCQrV_T.js +2 -0
  90. package/dist/assets/{ListItemStandardExpandableTextTemplate-CLBtdbBK.js → ListItemStandardExpandableTextTemplate-D4zLIdLd.js} +2 -2
  91. package/dist/assets/bundle.esm-Diw1zQ-o.js +384 -0
  92. package/dist/assets/parameters-bundle.css-1GGBOW8m.js +2 -0
  93. package/dist/assets/parameters-bundle.css-A9eeRg2R.js +2 -0
  94. package/dist/assets/parameters-bundle.css-COBI_9-U.js +2 -0
  95. package/dist/assets/parameters-bundle.css-CgAoZ-Ir.js +2 -0
  96. package/dist/assets/parameters-bundle.css-DuFHHRNK.js +2 -0
  97. package/dist/assets/parameters-bundle.css-Pf68NO0T.js +2 -0
  98. package/dist/assets/parameters-bundle.css-aX_t_-9o.js +2 -0
  99. package/dist/assets/parameters-bundle.css-rNSryFKH.js +2 -0
  100. package/dist/css/themes/Breadcrumbs.css +1 -1
  101. package/dist/css/themes/Button.css +1 -1
  102. package/dist/css/themes/ListItem.css +1 -1
  103. package/dist/css/themes/MastheadShell.css +1 -1
  104. package/dist/css/themes/Modal.css +1 -1
  105. package/dist/css/themes/RatingIndicator.css +1 -1
  106. package/dist/css/themes/Search.css +1 -1
  107. package/dist/css/themes/SideNavigationItem.css +1 -1
  108. package/dist/css/themes/SideNavigationSubItem.css +1 -1
  109. package/dist/css/themes/Slider.css +1 -1
  110. package/dist/custom-elements-internal.json +129 -37
  111. package/dist/custom-elements.json +101 -35
  112. package/dist/generated/json-imports/Themes-node.d.ts +1 -0
  113. package/dist/generated/json-imports/Themes-node.js +19 -0
  114. package/dist/generated/json-imports/Themes-node.js.map +1 -0
  115. package/dist/generated/json-imports/i18n-node.d.ts +1 -0
  116. package/dist/generated/json-imports/i18n-node.js +82 -0
  117. package/dist/generated/json-imports/i18n-node.js.map +1 -0
  118. package/dist/generated/templates/BreadcrumbsPopoverTemplate.lit.js +1 -1
  119. package/dist/generated/templates/BreadcrumbsPopoverTemplate.lit.js.map +1 -1
  120. package/dist/generated/templates/BreadcrumbsTemplate.lit.js +1 -1
  121. package/dist/generated/templates/BreadcrumbsTemplate.lit.js.map +1 -1
  122. package/dist/generated/templates/SearchTemplate.lit.js +3 -3
  123. package/dist/generated/templates/SearchTemplate.lit.js.map +1 -1
  124. package/dist/generated/templates/SecondaryNavigationItemTemplate.lit.js +2 -2
  125. package/dist/generated/templates/SecondaryNavigationItemTemplate.lit.js.map +1 -1
  126. package/dist/generated/templates/SecondaryNavigationTemplate.lit.js +1 -1
  127. package/dist/generated/templates/SecondaryNavigationTemplate.lit.js.map +1 -1
  128. package/dist/generated/themes/Breadcrumbs.css.d.ts +1 -1
  129. package/dist/generated/themes/Breadcrumbs.css.js +1 -1
  130. package/dist/generated/themes/Breadcrumbs.css.js.map +1 -1
  131. package/dist/generated/themes/Button.css.d.ts +1 -1
  132. package/dist/generated/themes/Button.css.js +1 -1
  133. package/dist/generated/themes/Button.css.js.map +1 -1
  134. package/dist/generated/themes/ListItem.css.d.ts +1 -1
  135. package/dist/generated/themes/ListItem.css.js +1 -1
  136. package/dist/generated/themes/ListItem.css.js.map +1 -1
  137. package/dist/generated/themes/MastheadShell.css.d.ts +1 -1
  138. package/dist/generated/themes/MastheadShell.css.js +1 -1
  139. package/dist/generated/themes/MastheadShell.css.js.map +1 -1
  140. package/dist/generated/themes/Modal.css.d.ts +1 -1
  141. package/dist/generated/themes/Modal.css.js +1 -1
  142. package/dist/generated/themes/Modal.css.js.map +1 -1
  143. package/dist/generated/themes/RatingIndicator.css.d.ts +1 -1
  144. package/dist/generated/themes/RatingIndicator.css.js +1 -1
  145. package/dist/generated/themes/RatingIndicator.css.js.map +1 -1
  146. package/dist/generated/themes/Search.css.d.ts +1 -1
  147. package/dist/generated/themes/Search.css.js +1 -1
  148. package/dist/generated/themes/Search.css.js.map +1 -1
  149. package/dist/generated/themes/SideNavigationItem.css.d.ts +1 -1
  150. package/dist/generated/themes/SideNavigationItem.css.js +1 -1
  151. package/dist/generated/themes/SideNavigationItem.css.js.map +1 -1
  152. package/dist/generated/themes/SideNavigationSubItem.css.d.ts +1 -1
  153. package/dist/generated/themes/SideNavigationSubItem.css.js +1 -1
  154. package/dist/generated/themes/SideNavigationSubItem.css.js.map +1 -1
  155. package/dist/generated/themes/Slider.css.d.ts +1 -1
  156. package/dist/generated/themes/Slider.css.js +1 -1
  157. package/dist/generated/themes/Slider.css.js.map +1 -1
  158. package/dist/types/ButtonAccessibleRole.d.ts +8 -0
  159. package/dist/types/ButtonAccessibleRole.js +10 -0
  160. package/dist/types/ButtonAccessibleRole.js.map +1 -0
  161. package/dist/types/{Button.d.ts → ButtonDesign.d.ts} +1 -15
  162. package/dist/types/ButtonDesign.js +16 -0
  163. package/dist/types/ButtonDesign.js.map +1 -0
  164. package/dist/types/ButtonSize.d.ts +6 -0
  165. package/dist/types/ButtonSize.js +8 -0
  166. package/dist/types/ButtonSize.js.map +1 -0
  167. package/dist/types/ControlButtonDesign.d.ts +10 -0
  168. package/dist/types/ControlButtonDesign.js +12 -0
  169. package/dist/types/ControlButtonDesign.js.map +1 -0
  170. package/dist/types/ProgressBar.d.ts +1 -1
  171. package/dist/types/ProgressBar.js +1 -1
  172. package/dist/types/ProgressBar.js.map +1 -1
  173. package/dist/types/common.d.ts +1 -1
  174. package/dist/types/common.js +1 -1
  175. package/dist/types/common.js.map +1 -1
  176. package/dist/vscode.html-custom-data.json +11 -10
  177. package/dist/web-types.json +10 -13
  178. package/package.json +8 -8
  179. package/src/Badge.ts +4 -4
  180. package/src/Breadcrumbs.hbs +7 -10
  181. package/src/Breadcrumbs.ts +14 -1
  182. package/src/BreadcrumbsPopover.hbs +3 -1
  183. package/src/Button.ts +12 -1
  184. package/src/Checkbox.ts +4 -0
  185. package/src/ControlButton.ts +2 -1
  186. package/src/DatePicker.ts +2 -2
  187. package/src/InputGroup.ts +5 -2
  188. package/src/ListItem.ts +4 -4
  189. package/src/MastheadItem.ts +1 -1
  190. package/src/MediaPlayer.ts +3 -1
  191. package/src/MediaPlayerYoutube.ts +4 -2
  192. package/src/Pagination.ts +1 -1
  193. package/src/PhoneNumberField.ts +6 -3
  194. package/src/ProgressBar.ts +6 -6
  195. package/src/RadioButton.ts +6 -6
  196. package/src/Search.hbs +3 -2
  197. package/src/Search.ts +1 -3
  198. package/src/SecondaryNavigation.hbs +1 -0
  199. package/src/SecondaryNavigation.ts +41 -12
  200. package/src/SecondaryNavigationItem.hbs +2 -1
  201. package/src/SecondaryNavigationItem.ts +31 -0
  202. package/src/SecondaryNavigationItemBase.ts +3 -0
  203. package/src/SecondaryNavigationSubItem.ts +0 -3
  204. package/src/SegmentedButton.ts +1 -1
  205. package/src/SegmentedButtonItem.ts +2 -2
  206. package/src/StatusBadge.ts +8 -3
  207. package/src/StepInput.ts +3 -3
  208. package/src/TableCellBase.ts +2 -2
  209. package/src/Tag.ts +4 -4
  210. package/src/TextArea.ts +9 -9
  211. package/src/TextField.ts +5 -5
  212. package/src/Toast.ts +1 -1
  213. package/src/Upload.ts +1 -1
  214. package/src/UploadItem.ts +9 -9
  215. package/src/generated/json-imports/Themes-node.ts +21 -0
  216. package/src/generated/json-imports/i18n-node.ts +85 -0
  217. package/src/generated/templates/BreadcrumbsPopoverTemplate.lit.ts +1 -1
  218. package/src/generated/templates/BreadcrumbsTemplate.lit.ts +1 -1
  219. package/src/generated/templates/SearchTemplate.lit.ts +3 -3
  220. package/src/generated/templates/SecondaryNavigationItemTemplate.lit.ts +2 -2
  221. package/src/generated/templates/SecondaryNavigationTemplate.lit.ts +1 -1
  222. package/src/generated/themes/Breadcrumbs.css.ts +1 -1
  223. package/src/generated/themes/Button.css.ts +1 -1
  224. package/src/generated/themes/ListItem.css.ts +1 -1
  225. package/src/generated/themes/MastheadShell.css.ts +1 -1
  226. package/src/generated/themes/Modal.css.ts +1 -1
  227. package/src/generated/themes/RatingIndicator.css.ts +1 -1
  228. package/src/generated/themes/Search.css.ts +1 -1
  229. package/src/generated/themes/SideNavigationItem.css.ts +1 -1
  230. package/src/generated/themes/SideNavigationSubItem.css.ts +1 -1
  231. package/src/generated/themes/Slider.css.ts +1 -1
  232. package/src/themes/Breadcrumbs.css +3 -0
  233. package/src/themes/Button.css +2 -2
  234. package/src/themes/ListItem.css +4 -0
  235. package/src/themes/MastheadShell.css +2 -1
  236. package/src/themes/Modal.css +2 -1
  237. package/src/themes/Search.css +8 -1
  238. package/src/themes/SideNavigationItem.css +9 -1
  239. package/src/themes/SideNavigationSubItem.css +7 -0
  240. package/src/types/ButtonAccessibleRole.ts +9 -0
  241. package/src/types/{Button.ts → ButtonDesign.ts} +1 -17
  242. package/src/types/ButtonSize.ts +7 -0
  243. package/src/types/ControlButtonDesign.ts +11 -0
  244. package/src/types/ProgressBar.ts +1 -1
  245. package/src/types/common.ts +1 -1
  246. package/dist/assets/InputSuggestions-CP3cBQsh.js +0 -2
  247. package/dist/assets/bundle.esm-jHcdiVfj.js +0 -380
  248. package/dist/assets/parameters-bundle.css-BU4Bi-ho.js +0 -2
  249. package/dist/assets/parameters-bundle.css-Beilb2gS.js +0 -2
  250. package/dist/assets/parameters-bundle.css-BzQMaZUt.js +0 -2
  251. package/dist/assets/parameters-bundle.css-Bzfv_Fox.js +0 -2
  252. package/dist/assets/parameters-bundle.css-CLwmjytB.js +0 -2
  253. package/dist/assets/parameters-bundle.css-CU3plTdF.js +0 -2
  254. package/dist/assets/parameters-bundle.css-DRX-o-Cb.js +0 -2
  255. package/dist/assets/parameters-bundle.css-DhFMZJhW.js +0 -2
  256. package/dist/css/themes/overrides/@ui5/webcomponents/sap_glow/parameters-bundle.css +0 -1
  257. package/dist/generated/assets/themes/overrides/@ui5/webcomponents/sap_glow/parameters-bundle.css.json +0 -1
  258. package/dist/generated/themes/overrides/@ui5/webcomponents/sap_glow/parameters-bundle.css.d.ts +0 -2
  259. package/dist/generated/themes/overrides/@ui5/webcomponents/sap_glow/parameters-bundle.css.js +0 -3
  260. package/dist/generated/themes/overrides/@ui5/webcomponents/sap_glow/parameters-bundle.css.js.map +0 -1
  261. package/dist/types/Button.js +0 -33
  262. package/dist/types/Button.js.map +0 -1
  263. package/src/generated/themes/overrides/@ui5/webcomponents/sap_glow/parameters-bundle.css.ts +0 -2
  264. package/src/themes/overrides/@ui5/webcomponents/sap_glow/parameters-bundle.css +0 -195
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@sapudex/web-components",
4
- "version": "2.1.1",
4
+ "version": "2.2.0",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"
7
7
  },
@@ -32,19 +32,19 @@
32
32
  },
33
33
  "dependencies": {
34
34
  "@types/vimeo__player": "^2.18.3",
35
- "@types/youtube": "^0.1.0",
36
- "@ui5/webcomponents": "2.10.0",
37
- "@ui5/webcomponents-base": "2.10.0",
38
- "@ui5/webcomponents-fiori": "2.10.0",
39
- "@ui5/webcomponents-icons": "2.10.0",
40
- "@ui5/webcomponents-theming": "2.10.0",
35
+ "@types/youtube": "^0.1.2",
36
+ "@ui5/webcomponents": "2.12.0",
37
+ "@ui5/webcomponents-base": "2.12.0",
38
+ "@ui5/webcomponents-fiori": "2.12.0",
39
+ "@ui5/webcomponents-icons": "2.12.0",
40
+ "@ui5/webcomponents-theming": "2.12.0",
41
41
  "@vimeo/player": "^2.24.0",
42
42
  "cypress-real-events": "^1.14.0",
43
43
  "video.js": "8.22.0"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@ui5/cypress-ct-ui5-webc": "^0.0.4",
47
- "@ui5/webcomponents-tools": "2.10.0",
47
+ "@ui5/webcomponents-tools": "2.12.0",
48
48
  "chromedriver": "138.0.1",
49
49
  "cross-env": "^7.0.3",
50
50
  "cypress": "^14.3.3",
package/src/Badge.ts CHANGED
@@ -9,7 +9,7 @@ import BadgeTemplate from "./generated/templates/BadgeTemplate.lit.js";
9
9
 
10
10
  // Styles
11
11
  import BadgeCss from "./generated/themes/Badge.css.js";
12
- import IconPlacement from "./types/IconPlacement.js";
12
+ import UDExIconPlacement from "./types/IconPlacement.js";
13
13
 
14
14
  import {
15
15
  UDExNumberBadgeDesign, UDExSizeBadgeDesign, UDExTextBadgeDesign, UDExTypeBadgeDesign,
@@ -81,7 +81,7 @@ class UDExBadge extends UI5Element {
81
81
  * @public
82
82
  */
83
83
  @property()
84
- iconPlacement: `${IconPlacement}` = IconPlacement.End;
84
+ iconPlacement: `${UDExIconPlacement}` = UDExIconPlacement.End;
85
85
  /**
86
86
  * Defines icon name
87
87
  *
@@ -100,11 +100,11 @@ class UDExBadge extends UI5Element {
100
100
  default!: Array<Node>;
101
101
 
102
102
  get startIcon(): boolean {
103
- return !!this.icon && this.iconPlacement === IconPlacement.Start;
103
+ return !!this.icon && this.iconPlacement === UDExIconPlacement.Start;
104
104
  }
105
105
 
106
106
  get endIcon(): boolean {
107
- return !!this.icon && this.iconPlacement === IconPlacement.End;
107
+ return !!this.icon && this.iconPlacement === UDExIconPlacement.End;
108
108
  }
109
109
 
110
110
  get textClasses(): string {
@@ -3,19 +3,16 @@
3
3
  aria-label="{{_accessibleNameText}}">
4
4
  <ol @focusin="{{_onfocusin}}">
5
5
  <li class="udex-breadcrumbs__arrow-wrapper ui5-breadcrumbs-dropdown-arrow-link-wrapper">
6
- <button
6
+ <udex-link
7
7
  id="udex-{{this._id}}-breadcrumbs__opener"
8
8
  @click="{{_toggleDropdown}}"
9
9
  class="udex-breadcrumbs__trigger {{_triggerClass}}"
10
- accessible-role="button"
11
- aria-label="{{_dropdownArrowAccessibleNameText}}"
12
- aria-haspopup="true">
13
- <ui5-icon
14
- name="slim-arrow-down"
15
- mode="Decorative"
16
- title="{{_dropdownArrowAccessibleNameText}}">
17
- </ui5-icon>
18
- </button>
10
+ accessible-role="button"
11
+ aria-label="{{_dropdownArrowAccessibleNameText}}"
12
+ icon="slim-arrow-down"
13
+ icon-placement="Start"
14
+ aria-haspopup="true">
15
+ </udex-link>
19
16
  </li>
20
17
  {{#each _linksData}}
21
18
  <li
@@ -122,6 +122,7 @@ class UDExBreadcrumbs extends UI5Element {
122
122
 
123
123
  _responsivePopover?: UDExDropdown;
124
124
  _itemNavigation?: ItemNavigation;
125
+ _shouldFocusFirstVisibleItem!: boolean;
125
126
 
126
127
  onBeforeRendering(): void {
127
128
  this._preprocessItems();
@@ -130,7 +131,13 @@ class UDExBreadcrumbs extends UI5Element {
130
131
  onAfterRendering(): void {
131
132
  this._responsivePopover = this._getResponsePopover();
132
133
  this._initItemNavigation();
134
+ this._dropdownArrowLink.forcedTabIndex = "0";
133
135
  this._handleOutsideClick();
136
+
137
+ if (this._shouldFocusFirstVisibleItem) {
138
+ this._getFocusableItems()[1].focus();
139
+ this._shouldFocusFirstVisibleItem = false;
140
+ }
134
141
  }
135
142
 
136
143
  _preprocessItems(): void {
@@ -236,6 +243,12 @@ class UDExBreadcrumbs extends UI5Element {
236
243
  const isLastItem = itemIndex === (this.items.length - 2).toString();
237
244
  const isFirstItem = itemIndex === "0";
238
245
 
246
+ if (isTabNext(e) && isLastItem) {
247
+ this._shouldFocusFirstVisibleItem = true;
248
+ this._toggleDropdown();
249
+ return;
250
+ }
251
+
239
252
  if ((isTabNext(e) && isLastItem) || (isTabPrevious(e) && isFirstItem) || isEscape(e)) {
240
253
  this._toggleDropdown();
241
254
  }
@@ -267,7 +280,7 @@ class UDExBreadcrumbs extends UI5Element {
267
280
  * Getter for the list of links corresponding to the abstract breadcrumb items
268
281
  */
269
282
  get _links(): Array<UDExLink> {
270
- return Array.from(this.shadowRoot!.querySelectorAll<UDExLink>(".udex-breadcrumbs__link-wrapper [ui5-link]"));
283
+ return Array.from(this.shadowRoot!.querySelectorAll<UDExLink>(".udex-breadcrumbs__link-wrapper [udex-link]"));
271
284
  }
272
285
 
273
286
  /**
@@ -4,7 +4,9 @@
4
4
  class="udex-breadcrumbs__popover ui5-breadcrumbs-popover"
5
5
  placement="Bottom"
6
6
  horizontal-align="Start"
7
- @keydown="{{_handleKeydown}}">
7
+ @keydown="{{_handleKeydown}}"
8
+ @close="{{_afterDropdownClose}}"
9
+ @open="{{_afterDropdownOpen}}">
8
10
  <div class="udex-breadcrumbs__popover-content">
9
11
  {{#each _dropdownItems}}
10
12
  {{#if this.icon}}
package/src/Button.ts CHANGED
@@ -8,7 +8,8 @@ import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js";
8
8
  import {
9
9
  BUTTON_ARIA_ATTENTION, BUTTON_ARIA_DEFAULT, BUTTON_ARIA_EMPHASIZED, BUTTON_ARIA_TRANSPARENT, BUTTON_ARIA_TYPE_NEGATIVE, BUTTON_ARIA_TYPE_POSITIVE, BUTTON_ARIA_TYPE_PRIMARY, BUTTON_ARIA_TYPE_SECONDARY, BUTTON_ARIA_TYPE_TERTIARY, BUTTON_ARIA_TYPE_WARNING, TOGGLED,
10
10
  } from "./generated/i18n/i18n-defaults.js";
11
- import { UDExButtonDesign, UDExButtonSize } from "./types/Button.js";
11
+ import UDExButtonSize from "./types/ButtonSize.js";
12
+ import UDExButtonDesign from "./types/ButtonDesign.js";
12
13
 
13
14
  // Styles
14
15
  import ButtonCss from "./generated/themes/Button.css.js";
@@ -16,6 +17,16 @@ import ButtonCss from "./generated/themes/Button.css.js";
16
17
  /**
17
18
  * @class
18
19
  *
20
+ * <h3 class="comment-api-title">Overview</h3>
21
+ *
22
+ *
23
+ * <h3>Usage</h3>
24
+ *
25
+ * For the <code>udex-button</code>
26
+ * <h3>ES6 Module Import</h3>
27
+ *
28
+ * <code>import "@sapudex/web-components/dist/Button.js";</code>
29
+ *
19
30
  * @constructor
20
31
  * @extends Button
21
32
  * @tagname udex-button
package/src/Checkbox.ts CHANGED
@@ -74,6 +74,10 @@ class UDExCheckbox extends CheckBox {
74
74
  ResizeHandler.register(this, this._handleResizeBound);
75
75
  }
76
76
 
77
+ onAfterRendering() {
78
+ this.shadowRoot?.querySelector(".ui5-checkbox-label")?.removeAttribute("required");
79
+ }
80
+
77
81
  onExitDOM(): void {
78
82
  ResizeHandler.deregister(this, this._handleResizeBound);
79
83
  }
@@ -5,7 +5,8 @@ import Button from "@ui5/webcomponents/dist/Button.js";
5
5
  // Styles
6
6
  import property from "@ui5/webcomponents-base/dist/decorators/property.js";
7
7
  import ControlButtonCss from "./generated/themes/ControlButton.css.js";
8
- import { UDExButtonSize, UDExControlButtonDesign } from "./types/Button.js";
8
+ import UDExButtonSize from "./types/ButtonSize.js";
9
+ import UDExControlButtonDesign from "./types/ControlButtonDesign.js";
9
10
 
10
11
  /**
11
12
  * @class
package/src/DatePicker.ts CHANGED
@@ -28,13 +28,13 @@ export enum UDExDatePickerSelectionMode {
28
28
  Range = "Range",
29
29
  }
30
30
 
31
- type UDExDatePickerSelectionChangeEventDetail = {
31
+ export type UDExDatePickerSelectionChangeEventDetail = {
32
32
  selectedValues: Array<string>;
33
33
  selectedDates: Array<number | undefined>;
34
34
  timestamp: number | undefined;
35
35
  };
36
36
 
37
- type UDExDatePickerValueStateChangeEventDetail = {
37
+ export type UDExDatePickerValueStateChangeEventDetail = {
38
38
  valueState: `${UDExValueState}`,
39
39
  valid: boolean
40
40
  }
package/src/InputGroup.ts CHANGED
@@ -15,12 +15,15 @@ import {
15
15
  VALUE_STATE_ERROR,
16
16
  VALUE_STATE_SUCCESS,
17
17
  } from "./generated/i18n/i18n-defaults.js";
18
- import type UDExValueState from "./types/common.js";
19
18
 
20
19
  // Styles
21
20
  import InputGroupCss from "./generated/themes/InputGroup.css.js";
22
21
 
23
- export type UDExGroupValueState = Exclude<UDExValueState, "Warning">
22
+ export enum UDExGroupValueState {
23
+ Standard = "Standard",
24
+ Error = "Error",
25
+ Success = "Success",
26
+ }
24
27
 
25
28
  export enum UDExOrientation {
26
29
  Vertical = "Vertical",
package/src/ListItem.ts CHANGED
@@ -196,16 +196,16 @@ class UDExListItem extends UDExListItemBase {
196
196
  * @slot
197
197
  * @public
198
198
  */
199
- @slot()
200
- firstIcon!: Array<HTMLElement>;
199
+ @slot({ type: UDExButton })
200
+ firstIcon!: Array<UDExButton>;
201
201
  /**
202
202
  * Slot for second icon.
203
203
  *
204
204
  * @slot
205
205
  * @public
206
206
  */
207
- @slot()
208
- secondIcon!: Array<HTMLElement>;
207
+ @slot({ type: UDExButton })
208
+ secondIcon!: Array<UDExButton>;
209
209
 
210
210
  /**
211
211
  * Defines the role attribute of component
@@ -549,7 +549,7 @@ class UDExMastheadItem extends UI5Element implements IMastheadItem {
549
549
  }
550
550
 
551
551
  get isMobile(): boolean {
552
- return BreakpointUtils.isBelow("M") || this.mastheadShell?._isMobileMode;
552
+ return BreakpointUtils.isAtMost("M") || this.mastheadShell?._isMobileMode;
553
553
  }
554
554
 
555
555
  get isTargetBlank(): boolean {
@@ -19,6 +19,8 @@ import MediaPlayerTemplate from "./generated/templates/MediaPlayerTemplate.lit.j
19
19
  // Styles
20
20
  import MediaPlayerCss from "./generated/themes/MediaPlayer.css.js";
21
21
 
22
+ export type YoutubePlayer = YT.Player;
23
+
22
24
  declare global {
23
25
  interface Window {
24
26
  videojs: any;
@@ -352,7 +354,7 @@ class UDExMediaPlayer extends UI5Element {
352
354
  * Returns video element
353
355
  * @public
354
356
  */
355
- getPlayer(): HTMLVideoElement | HTMLAudioElement | YT.Player | VimeoPlayer | null {
357
+ getPlayer(): HTMLVideoElement | HTMLAudioElement | YoutubePlayer | VimeoPlayer | null {
356
358
  if (this._youtubeSrc) {
357
359
  const player = this.shadowRoot?.querySelector("[udex-media-player-youtube]") as UDExMediaPlayerYoutube;
358
360
  return player?.getPlayer() || null;
@@ -3,13 +3,13 @@ import customElement from "@ui5/webcomponents-base/dist/decorators/customElement
3
3
  import property from "@ui5/webcomponents-base/dist/decorators/property.js";
4
4
  import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js";
5
5
  import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js";
6
+ import type { UDExAspectRatio } from "./MediaPlayer.js";
6
7
 
7
8
  import MediaPlayerYoutubeTemplate from "./generated/templates/MediaPlayerYoutubeTemplate.lit.js";
8
9
 
9
10
  // Styles
10
11
  import MediaPlayerYoutubeCss from "./generated/themes/MediaPlayerYoutube.css.js";
11
12
  import MediaPlayerCss from "./generated/themes/MediaPlayer.css.js";
12
- import type { UDExAspectRatio } from "./MediaPlayer.js";
13
13
 
14
14
  const MATCH_NOCOOKIE = /youtube-nocookie\.com/;
15
15
  const MATCH_URL_YOUTUBE = /(?:youtu\.be\/|youtube(?:-nocookie|education)?\.com\/(?:embed\/|v\/|watch\/|watch\?v=|watch\?.+&v=|shorts\/|live\/))((\w|-){11})|youtube\.com\/playlist\?list=|youtube\.com\/user\//;
@@ -22,6 +22,8 @@ const MATCH_END_QUERY = /[?&#]end=([0-9hms]+)/;
22
22
  const MATCH_START_STAMP = /(\d+)(h|m|s)/g;
23
23
  const MATCH_NUMERIC = /^\d+$/;
24
24
 
25
+ export type YoutubePlayer = YT.Player;
26
+
25
27
  declare global {
26
28
  interface Window {
27
29
  onYouTubeIframeAPIReady: () => void;
@@ -293,7 +295,7 @@ class UDExMediaPlayerYoutube extends UI5Element {
293
295
  * Returns video element
294
296
  * @public
295
297
  */
296
- getPlayer(): YT.Player | null {
298
+ getPlayer(): YoutubePlayer | null {
297
299
  return this.youtubePlayer || null;
298
300
  }
299
301
 
package/src/Pagination.ts CHANGED
@@ -46,7 +46,7 @@ export enum UDExDisplayType {
46
46
  mobile = "mobile"
47
47
  }
48
48
 
49
- type UDExPaginationChangeEventDetail = {
49
+ export type UDExPaginationChangeEventDetail = {
50
50
  currentPage: number,
51
51
  }
52
52
 
@@ -24,7 +24,6 @@ import "@ui5/webcomponents-icons/dist/slim-arrow-up.js";
24
24
  import "@ui5/webcomponents-icons/dist/slim-arrow-down.js";
25
25
 
26
26
  import PhoneNumberFieldTemplate from "./generated/templates/PhoneNumberFieldTemplate.lit.js";
27
- import type UDExValueState from "./types/common.js";
28
27
 
29
28
  // Styles
30
29
  import PhoneNumberFieldCss from "./generated/themes/PhoneNumberField.css.js";
@@ -39,7 +38,11 @@ export enum UDExOpenButtonIcon {
39
38
  iconDown = "slim-arrow-down",
40
39
  }
41
40
 
42
- export type UDExPhoneNumberFieldValueState = Exclude<UDExValueState, "Warning">
41
+ export enum UDExPhoneNumberFieldValueState {
42
+ Standard = "Standard",
43
+ Error = "Error",
44
+ Success = "Success",
45
+ }
43
46
 
44
47
  const initialPlaceholder: string = "+X XXX-XXX-XXXX";
45
48
  /**
@@ -101,7 +104,7 @@ class UDExPhoneNumberField extends UI5Element {
101
104
  * @public
102
105
  */
103
106
  @property()
104
- valueState: `${UDExPhoneNumberFieldValueState}` = "Standard";
107
+ valueState: `${UDExPhoneNumberFieldValueState}` = UDExPhoneNumberFieldValueState.Standard;
105
108
 
106
109
  /**
107
110
  * Defines supporting text under the input field.
@@ -7,7 +7,7 @@ import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js";
7
7
  import {
8
8
  VALUE_STATE_ERROR, VALUE_STATE_SUCCESS, VALUE_STATE_WARNING, VALUE_STATE_INFORMATION,
9
9
  } from "./generated/i18n/i18n-defaults.js";
10
- import ProgressBarValueState from "./types/ProgressBar.js";
10
+ import UDExProgressBarValueState from "./types/ProgressBar.js";
11
11
 
12
12
  // Styles
13
13
  import ProgressBarCss from "./generated/themes/ProgressBar.css.js";
@@ -47,17 +47,17 @@ class UDExProgressBar extends ProgressIndicator {
47
47
  */
48
48
  @property()
49
49
  /** @ts-expect-error */
50
- valueState!: `${ProgressBarValueState}` = ProgressBarValueState.None;
50
+ valueState!: `${UDExProgressBarValueState}` = UDExProgressBarValueState.None;
51
51
 
52
52
  @i18n("@sapudex/web-components")
53
53
  static i18nBundle: I18nBundle;
54
54
 
55
55
  valueStateTextMappings(): Record<string, string> {
56
56
  return {
57
- [ProgressBarValueState.Error]: UDExProgressBar.i18nBundle.getText(VALUE_STATE_ERROR),
58
- [ProgressBarValueState.Warning]: UDExProgressBar.i18nBundle.getText(VALUE_STATE_WARNING),
59
- [ProgressBarValueState.Success]: UDExProgressBar.i18nBundle.getText(VALUE_STATE_SUCCESS),
60
- [ProgressBarValueState.Information]: UDExProgressBar.i18nBundle.getText(VALUE_STATE_INFORMATION),
57
+ [UDExProgressBarValueState.Error]: UDExProgressBar.i18nBundle.getText(VALUE_STATE_ERROR),
58
+ [UDExProgressBarValueState.Warning]: UDExProgressBar.i18nBundle.getText(VALUE_STATE_WARNING),
59
+ [UDExProgressBarValueState.Success]: UDExProgressBar.i18nBundle.getText(VALUE_STATE_SUCCESS),
60
+ [UDExProgressBarValueState.Information]: UDExProgressBar.i18nBundle.getText(VALUE_STATE_INFORMATION),
61
61
  };
62
62
  }
63
63
  }
@@ -7,7 +7,7 @@ import {
7
7
  } from "./generated/i18n/i18n-defaults.js";
8
8
  import RadioButton from "@ui5/webcomponents/dist/RadioButton.js";
9
9
  import property from "@ui5/webcomponents-base/dist/decorators/property.js";
10
- import RadioButtonValueState from "./types/RadioButton.js";
10
+ import UDExRadioButtonValueState from "./types/RadioButton.js";
11
11
 
12
12
  // Styles
13
13
  import RadioButtonCss from "./generated/themes/RadioButton.css.js";
@@ -53,7 +53,7 @@ class UDExRadioButton extends RadioButton {
53
53
  */
54
54
  @property()
55
55
  /** @ts-expect-error */
56
- valueState!: `${RadioButtonValueState}` = RadioButtonValueState.None;
56
+ valueState!: `${UDExRadioButtonValueState}` = UDExRadioButtonValueState.None;
57
57
 
58
58
  @i18n("@sapudex/web-components")
59
59
  static i18nBundle: I18nBundle;
@@ -65,13 +65,13 @@ class UDExRadioButton extends RadioButton {
65
65
 
66
66
  get valueStateText(): string {
67
67
  switch (this.valueState) {
68
- case RadioButtonValueState.Error:
68
+ case UDExRadioButtonValueState.Error:
69
69
  return RadioButton.i18nBundle.getText(VALUE_STATE_ERROR);
70
- case RadioButtonValueState.Success:
70
+ case UDExRadioButtonValueState.Success:
71
71
  return RadioButton.i18nBundle.getText(VALUE_STATE_SUCCESS);
72
- case RadioButtonValueState.Information:
72
+ case UDExRadioButtonValueState.Information:
73
73
  return RadioButton.i18nBundle.getText(VALUE_STATE_INFORMATION);
74
- case RadioButtonValueState.Warning:
74
+ case UDExRadioButtonValueState.Warning:
75
75
  return RadioButton.i18nBundle.getText(VALUE_STATE_WARNING);
76
76
  default:
77
77
  return "";
package/src/Search.hbs CHANGED
@@ -73,8 +73,8 @@
73
73
  @click="{{handleInputClick}}"
74
74
  />
75
75
  {{/if}}
76
- {{#if accInfo.ariaDescription}}
77
- <span role="status" id="search-description" class="hidden" aria-hidden="true">{{accInfo.ariaDescription}}</span>
76
+ {{#if open}}
77
+ <span aria-live="polite" aria-atomic="true" id="search-description" class="hidden" aria-hidden="true">{{suggestionsDescription}}</span>
78
78
  {{/if}}
79
79
  <div class="udex-search__icons">
80
80
  {{#if isShowHomeResetButton}}
@@ -123,6 +123,7 @@
123
123
  class="udex-search__icon"
124
124
  aria-hidden="true"
125
125
  accessible-name="{{accInfo.accessibleNameSearchIcon}}"
126
+ show-tooltip
126
127
  name="search">
127
128
  </ui5-icon>
128
129
  {{/if}}
package/src/Search.ts CHANGED
@@ -710,7 +710,6 @@ class UDExSearch extends UI5Element {
710
710
 
711
711
  getTextWithSuggestion(text: string): string {
712
712
  const escapedValue = this.escapeRegExp(this.value);
713
- console.warn(escapedValue);
714
713
  const search = new RegExp(escapedValue, "i");
715
714
  return text.replace(search, "<b>$&</b>");
716
715
  }
@@ -1285,14 +1284,13 @@ class UDExSearch extends UI5Element {
1285
1284
  get accInfo() {
1286
1285
  return {
1287
1286
  "ariaLabel": this.accessibleName || undefined,
1288
- "ariaDescription": this.open ? this.suggestionsDescription : undefined,
1289
1287
  "accessibleNameResetIcon": this.accessibleNameResetIcon || UDExSearch.i18nBundle.getText(ACCESSIBLE_NAME_RESET_ICON),
1290
1288
  "accessibleNameSearchIcon": this.accessibleNameSearchIcon || UDExSearch.i18nBundle.getText(ACCESSIBLE_NAME_SEARCH_ICON),
1291
1289
  };
1292
1290
  }
1293
1291
 
1294
1292
  get suggestionsDescription(): string {
1295
- return this.hasPopoverContent ? `${this.suggestedList.length} ${this._suggestionLabel}, ${this.recommendedList.length} ${this._recommendLabel}` : `${this.noResultText}`;
1293
+ return !this.showNoResultMessage ? `${this.suggestedList.length} ${this._suggestionLabel}, ${this.recommendedList.length} ${this._recommendLabel}` : `${this.noResultMessage}`;
1296
1294
  }
1297
1295
 
1298
1296
  get tooltipInfo() {
@@ -66,6 +66,7 @@
66
66
  label="{{heading}}"
67
67
  mobile-link-title="{{title}}"
68
68
  @ui5-sub-item-click="{{handleSubItemClick}}"
69
+ _is-mobile-menu-opener
69
70
  .subItems="{{this.parsedItems}}">
70
71
  {{#if hasMobileButtonsSlot}}
71
72
  {{>buttons}}
@@ -145,7 +145,8 @@ class UDExSecondaryNavigation extends UI5Element {
145
145
  _mobileBtnExpanded = false;
146
146
 
147
147
  _navItems!: Array<NavItem>;
148
- _showMoreButton: boolean;
148
+ _showMoreButton: boolean = true;
149
+ _shouldFocusFirstItem: boolean = true;
149
150
  _rootHolder!: HTMLElement | null | undefined;
150
151
  _clickedNavItem!: UDExSecondaryNavigationItem;
151
152
  _boundReflowItems: () => void;
@@ -155,7 +156,6 @@ class UDExSecondaryNavigation extends UI5Element {
155
156
 
156
157
  constructor() {
157
158
  super();
158
- this._showMoreButton = true;
159
159
  this._boundReflowItems = this._handleResize.bind(this);
160
160
  }
161
161
 
@@ -171,13 +171,6 @@ class UDExSecondaryNavigation extends UI5Element {
171
171
  ResizeHandler.deregister(this, this._boundReflowItems);
172
172
  }
173
173
 
174
- _handleResize() {
175
- this.reflowItems();
176
- if (this._clickedNavItem && this.isDesktopScreen) {
177
- this._clickedNavItem.closeDropdown();
178
- }
179
- }
180
-
181
174
  onInvalidation(changeInfo: ChangeInfo): void {
182
175
  if (changeInfo.name === "navItems") {
183
176
  this.reflowItems();
@@ -186,6 +179,12 @@ class UDExSecondaryNavigation extends UI5Element {
186
179
 
187
180
  onAfterRendering(): void {
188
181
  this._rootHolder = this.rootHolder;
182
+ if (!this._overflowItems.length) {
183
+ this._showMoreButton = true;
184
+ }
185
+ if (this._shouldFocusFirstItem && this.isDesktopScreen) {
186
+ this.domNavItems[0]._tabIndex = "0";
187
+ }
189
188
  this.handleOutsideClick();
190
189
  }
191
190
 
@@ -193,6 +192,16 @@ class UDExSecondaryNavigation extends UI5Element {
193
192
  this._requestRender = !this._requestRender;
194
193
  }
195
194
 
195
+ _handleResize() {
196
+ this.reflowItems();
197
+ if (this.isDesktopScreen) {
198
+ this.resetTabIndex();
199
+ }
200
+ if (this._clickedNavItem && this.isDesktopScreen) {
201
+ this._clickedNavItem.closeDropdown();
202
+ }
203
+ }
204
+
196
205
  reflowItems(): void {
197
206
  const availableWidth = this.rootHolder.offsetWidth - (this.headingHolder?.offsetWidth || 0) - (this.optionalButtons?.offsetWidth || 0);
198
207
  const moreButtonWidth = this.getMoreButtonWidth();
@@ -243,9 +252,12 @@ class UDExSecondaryNavigation extends UI5Element {
243
252
  const item = e.target as UDExSecondaryNavigationItem;
244
253
  const currentSelectedIndex = this.getCurrentIndex(item);
245
254
  const previousSelectIndex = currentSelectedIndex - 1;
255
+ const previousItem = this.domNavItems[previousSelectIndex];
246
256
  if (currentSelectedIndex > 0) {
247
257
  e.preventDefault();
248
- this.domNavItems[previousSelectIndex]?.focus();
258
+ this.domNavItems[currentSelectedIndex]._tabIndex = "-1";
259
+ previousItem._tabIndex = "0";
260
+ previousItem?.focus();
249
261
  }
250
262
  }
251
263
 
@@ -254,9 +266,12 @@ class UDExSecondaryNavigation extends UI5Element {
254
266
  const currentSelectedIndex = this.getCurrentIndex(item);
255
267
  const lastItemIndex = this.domNavItems.length - 1;
256
268
  const nextSelectIndex = currentSelectedIndex + 1;
269
+ const nextItem = this.domNavItems[nextSelectIndex];
257
270
  if (nextSelectIndex < lastItemIndex) {
258
271
  e.preventDefault();
259
- this.domNavItems[nextSelectIndex].focus();
272
+ this.domNavItems[currentSelectedIndex]._tabIndex = "-1";
273
+ nextItem._tabIndex = "0";
274
+ nextItem.focus();
260
275
  }
261
276
  }
262
277
 
@@ -305,6 +320,8 @@ class UDExSecondaryNavigation extends UI5Element {
305
320
  }
306
321
 
307
322
  this._clickedNavItem = clickedItem;
323
+ this._shouldFocusFirstItem = false;
324
+ this.setTabIndexById(_id);
308
325
  this.closePrevDropdown(_id);
309
326
 
310
327
  if (!subItems.length) {
@@ -401,7 +418,7 @@ class UDExSecondaryNavigation extends UI5Element {
401
418
 
402
419
  closePrevDropdown(clickedItemId: string): void {
403
420
  this.domNavItems.forEach(item => {
404
- if (clickedItemId !== item._id) {
421
+ if (item.isOpen && item._id !== clickedItemId) {
405
422
  item.closeDropdown();
406
423
  }
407
424
  });
@@ -411,6 +428,18 @@ class UDExSecondaryNavigation extends UI5Element {
411
428
  return string ? JSON.parse(string) as T[] : [];
412
429
  }
413
430
 
431
+ resetTabIndex(): void {
432
+ this.domNavItems.forEach((item, index) => {
433
+ item._tabIndex = index === 0 ? "0" : "-1";
434
+ });
435
+ }
436
+
437
+ setTabIndexById(id: string): void {
438
+ this.domNavItems.forEach(item => {
439
+ item._tabIndex = id === item._id ? "0" : "-1";
440
+ });
441
+ }
442
+
414
443
  get domNavItems(): Array<UDExSecondaryNavigationItem> {
415
444
  const items = this.shadowRoot?.querySelectorAll<UDExSecondaryNavigationItem>("[udex-secondary-navigation-item]");
416
445
  return items ? Array.from(items) : [];
@@ -5,6 +5,7 @@
5
5
  ?active="{{isActive}}"
6
6
  href="{{path}}"
7
7
  target="{{target}}"
8
+ tabindex="{{_tabIndex}}"
8
9
  aria-current="{{ariaCurrent}}"
9
10
  @keydown="{{handleItemLinkKeyDown}}"
10
11
  @click="{{fireNavItemClickEvent}}">
@@ -14,7 +15,7 @@
14
15
  <button
15
16
  class="udex-secondary-navigation__item"
16
17
  role="{{itemRole}}"
17
- tabindex="0"
18
+ tabindex="{{menuOpenerTabIndex}}"
18
19
  ?active="{{isActive}}"
19
20
  aria-haspopup="{{hasNestedItems}}"
20
21
  aria-expanded="{{isOpen}}"