@sapudex/web-components 2.60.0 → 2.62.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 (385) hide show
  1. package/cypress/specs/AccordionSpotlight.cy.tsx +43 -2
  2. package/cypress/specs/Carousel.cy.tsx +134 -0
  3. package/cypress/specs/CountrySelector.cy.tsx +233 -6
  4. package/cypress/specs/FilterMenu.cy.tsx +39 -45
  5. package/cypress/specs/List.cy.tsx +624 -10
  6. package/cypress/specs/ListItem.cy.tsx +50 -0
  7. package/cypress/specs/SecondaryNavigationDesktop.cy.tsx +52 -3
  8. package/cypress/specs/SelectBox.cy.tsx +276 -136
  9. package/cypress/specs/SelectBoxAccessibility.cy.tsx +3109 -0
  10. package/cypress/specs/SideNavigation.cy.tsx +509 -0
  11. package/cypress/specs/Table.cy.tsx +90 -0
  12. package/cypress/specs/TagGroup.cy.tsx +168 -0
  13. package/cypress/support/component-imports.instrumented.ts +6 -0
  14. package/cypress/support/component-imports.src.ts +6 -0
  15. package/dist/AccordionSpotlight.d.ts +7 -2
  16. package/dist/AccordionSpotlight.js +31 -6
  17. package/dist/AccordionSpotlight.js.map +1 -1
  18. package/dist/AccordionSpotlightItem.d.ts +3 -1
  19. package/dist/AccordionSpotlightItem.js +3 -1
  20. package/dist/AccordionSpotlightItem.js.map +1 -1
  21. package/dist/Carousel.d.ts +2 -0
  22. package/dist/Carousel.js +35 -4
  23. package/dist/Carousel.js.map +1 -1
  24. package/dist/CountrySelector.js +1 -3
  25. package/dist/CountrySelector.js.map +1 -1
  26. package/dist/List.d.ts +2 -0
  27. package/dist/List.js +22 -4
  28. package/dist/List.js.map +1 -1
  29. package/dist/ListGroupHeader.js +5 -1
  30. package/dist/ListGroupHeader.js.map +1 -1
  31. package/dist/ListGroupHeaderBase.d.ts +2 -0
  32. package/dist/ListGroupHeaderBase.js +15 -2
  33. package/dist/ListGroupHeaderBase.js.map +1 -1
  34. package/dist/ListGroupHeaderTemplate.js +14 -22
  35. package/dist/ListGroupHeaderTemplate.js.map +1 -1
  36. package/dist/ListItem.d.ts +1 -2
  37. package/dist/ListItem.js +14 -12
  38. package/dist/ListItem.js.map +1 -1
  39. package/dist/ListItemBase.d.ts +5 -0
  40. package/dist/ListItemBase.js +11 -1
  41. package/dist/ListItemBase.js.map +1 -1
  42. package/dist/ListItemTemplate.js +1 -1
  43. package/dist/ListItemTemplate.js.map +1 -1
  44. package/dist/ListSelectAllTemplate.js +1 -1
  45. package/dist/ListSelectAllTemplate.js.map +1 -1
  46. package/dist/ListTemplate.js +2 -1
  47. package/dist/ListTemplate.js.map +1 -1
  48. package/dist/Pagination.d.ts +0 -1
  49. package/dist/Pagination.js +2 -2
  50. package/dist/Pagination.js.map +1 -1
  51. package/dist/Search.d.ts +13 -3
  52. package/dist/Search.js +36 -11
  53. package/dist/Search.js.map +1 -1
  54. package/dist/SearchableListBase.d.ts +2 -0
  55. package/dist/SearchableListBase.js +13 -3
  56. package/dist/SearchableListBase.js.map +1 -1
  57. package/dist/SearchableListBaseTemplate.js +42 -34
  58. package/dist/SearchableListBaseTemplate.js.map +1 -1
  59. package/dist/SecondaryNavigation.d.ts +2 -1
  60. package/dist/SecondaryNavigation.js.map +1 -1
  61. package/dist/SecondaryNavigationItem.js +12 -6
  62. package/dist/SecondaryNavigationItem.js.map +1 -1
  63. package/dist/SecondaryNavigationTemplate.js +1 -2
  64. package/dist/SecondaryNavigationTemplate.js.map +1 -1
  65. package/dist/SelectBase.d.ts +18 -33
  66. package/dist/SelectBase.js +125 -140
  67. package/dist/SelectBase.js.map +1 -1
  68. package/dist/SelectBox.d.ts +3 -0
  69. package/dist/SelectBox.js +19 -7
  70. package/dist/SelectBox.js.map +1 -1
  71. package/dist/SelectBoxTemplate.js +3 -3
  72. package/dist/SelectBoxTemplate.js.map +1 -1
  73. package/dist/SideNavigation.d.ts +23 -0
  74. package/dist/SideNavigation.js +39 -0
  75. package/dist/SideNavigation.js.map +1 -1
  76. package/dist/SideNavigationItem.d.ts +10 -0
  77. package/dist/SideNavigationItem.js +69 -0
  78. package/dist/SideNavigationItem.js.map +1 -1
  79. package/dist/SideNavigationItemTemplate.d.ts +2 -0
  80. package/dist/SideNavigationItemTemplate.js +15 -0
  81. package/dist/SideNavigationItemTemplate.js.map +1 -0
  82. package/dist/SideNavigationMobile.js +1 -2
  83. package/dist/SideNavigationMobile.js.map +1 -1
  84. package/dist/SideNavigationMobileTemplate.js +1 -1
  85. package/dist/SideNavigationMobileTemplate.js.map +1 -1
  86. package/dist/SideNavigationSubItem.d.ts +23 -0
  87. package/dist/SideNavigationSubItem.js +105 -1
  88. package/dist/SideNavigationSubItem.js.map +1 -1
  89. package/dist/SideNavigationSubItemTemplate.d.ts +2 -0
  90. package/dist/SideNavigationSubItemTemplate.js +9 -0
  91. package/dist/SideNavigationSubItemTemplate.js.map +1 -0
  92. package/dist/Table.js +1 -1
  93. package/dist/Table.js.map +1 -1
  94. package/dist/TableCell.d.ts +8 -2
  95. package/dist/TableCell.js +13 -11
  96. package/dist/TableCell.js.map +1 -1
  97. package/dist/TableCellBase.d.ts +2 -1
  98. package/dist/TableCellBase.js +9 -0
  99. package/dist/TableCellBase.js.map +1 -1
  100. package/dist/TableHeaderCell.d.ts +0 -1
  101. package/dist/TableHeaderCell.js +0 -4
  102. package/dist/TableHeaderCell.js.map +1 -1
  103. package/dist/TableRow.d.ts +10 -0
  104. package/dist/TableRow.js +23 -0
  105. package/dist/TableRow.js.map +1 -1
  106. package/dist/TagGroup.d.ts +3 -0
  107. package/dist/TagGroup.js +31 -0
  108. package/dist/TagGroup.js.map +1 -1
  109. package/dist/TagGroupTemplate.js +1 -1
  110. package/dist/TagGroupTemplate.js.map +1 -1
  111. package/dist/UploadItem.js +3 -4
  112. package/dist/UploadItem.js.map +1 -1
  113. package/dist/assets/{InputSuggestions-DyNcKgip.js → InputSuggestions-BPKrPqPb.js} +1 -1
  114. package/dist/assets/{ListItemStandardExpandableTextTemplate-qdKPzaOQ.js → ListItemStandardExpandableTextTemplate-DkdOcCxC.js} +1 -1
  115. package/dist/assets/{bundle.esm-sUYwSJOp.js → bundle.esm-17Yt5gDr.js} +234 -235
  116. package/dist/css/themes/AccordionSpotlight.css +1 -1
  117. package/dist/css/themes/Contact.css +1 -1
  118. package/dist/css/themes/EventRibbon.css +1 -1
  119. package/dist/css/themes/Feed.css +1 -1
  120. package/dist/css/themes/HeroBanner.css +1 -1
  121. package/dist/css/themes/ImageGridCloud.css +1 -1
  122. package/dist/css/themes/ImageGridTicker.css +1 -1
  123. package/dist/css/themes/ImageGridTickerItem.css +1 -1
  124. package/dist/css/themes/LinkList.css +1 -1
  125. package/dist/css/themes/ListGroupHeader.css +1 -1
  126. package/dist/css/themes/MastheadCountrySelector.css +1 -1
  127. package/dist/css/themes/MastheadItem.css +1 -1
  128. package/dist/css/themes/MastheadMenu.css +1 -1
  129. package/dist/css/themes/MastheadMenuItem.css +1 -1
  130. package/dist/css/themes/MastheadMobileMenu.css +1 -1
  131. package/dist/css/themes/MastheadProfileMenu.css +1 -1
  132. package/dist/css/themes/MastheadShell.css +1 -1
  133. package/dist/css/themes/MessageStrip.css +1 -1
  134. package/dist/css/themes/Modal.css +1 -1
  135. package/dist/css/themes/PromoTile.css +1 -1
  136. package/dist/css/themes/Quote.css +1 -1
  137. package/dist/css/themes/Review.css +1 -1
  138. package/dist/css/themes/ReviewItem.css +1 -1
  139. package/dist/css/themes/SecondaryNavigation.css +1 -1
  140. package/dist/css/themes/SecondaryNavigationItem.css +1 -1
  141. package/dist/css/themes/SelectBase.css +1 -1
  142. package/dist/css/themes/SideNavigation.css +1 -1
  143. package/dist/css/themes/SideNavigationItem.css +1 -1
  144. package/dist/css/themes/SideNavigationMobile.css +1 -1
  145. package/dist/css/themes/SideNavigationSubItem.css +1 -1
  146. package/dist/css/themes/TabNavigation.css +1 -1
  147. package/dist/css/themes/Table.css +1 -1
  148. package/dist/css/themes/TableCellBase.css +1 -1
  149. package/dist/css/themes/Upload.css +1 -1
  150. package/dist/css/themes/UploadItem.css +1 -1
  151. package/dist/custom-elements-internal.json +162 -19
  152. package/dist/custom-elements.json +151 -26
  153. package/dist/generated/i18n/i18n-defaults.d.ts +2 -1
  154. package/dist/generated/i18n/i18n-defaults.js +2 -1
  155. package/dist/generated/i18n/i18n-defaults.js.map +1 -1
  156. package/dist/generated/themes/AccordionSpotlight.css.d.ts +1 -1
  157. package/dist/generated/themes/AccordionSpotlight.css.js +1 -1
  158. package/dist/generated/themes/AccordionSpotlight.css.js.map +1 -1
  159. package/dist/generated/themes/Contact.css.d.ts +1 -1
  160. package/dist/generated/themes/Contact.css.js +1 -1
  161. package/dist/generated/themes/Contact.css.js.map +1 -1
  162. package/dist/generated/themes/EventRibbon.css.d.ts +1 -1
  163. package/dist/generated/themes/EventRibbon.css.js +1 -1
  164. package/dist/generated/themes/EventRibbon.css.js.map +1 -1
  165. package/dist/generated/themes/Feed.css.d.ts +1 -1
  166. package/dist/generated/themes/Feed.css.js +1 -1
  167. package/dist/generated/themes/Feed.css.js.map +1 -1
  168. package/dist/generated/themes/HeroBanner.css.d.ts +1 -1
  169. package/dist/generated/themes/HeroBanner.css.js +1 -1
  170. package/dist/generated/themes/HeroBanner.css.js.map +1 -1
  171. package/dist/generated/themes/ImageGridCloud.css.d.ts +1 -1
  172. package/dist/generated/themes/ImageGridCloud.css.js +1 -1
  173. package/dist/generated/themes/ImageGridCloud.css.js.map +1 -1
  174. package/dist/generated/themes/ImageGridTicker.css.d.ts +1 -1
  175. package/dist/generated/themes/ImageGridTicker.css.js +1 -1
  176. package/dist/generated/themes/ImageGridTicker.css.js.map +1 -1
  177. package/dist/generated/themes/ImageGridTickerItem.css.d.ts +1 -1
  178. package/dist/generated/themes/ImageGridTickerItem.css.js +1 -1
  179. package/dist/generated/themes/ImageGridTickerItem.css.js.map +1 -1
  180. package/dist/generated/themes/LinkList.css.d.ts +1 -1
  181. package/dist/generated/themes/LinkList.css.js +1 -1
  182. package/dist/generated/themes/LinkList.css.js.map +1 -1
  183. package/dist/generated/themes/ListGroupHeader.css.d.ts +1 -1
  184. package/dist/generated/themes/ListGroupHeader.css.js +1 -1
  185. package/dist/generated/themes/ListGroupHeader.css.js.map +1 -1
  186. package/dist/generated/themes/MastheadCountrySelector.css.d.ts +1 -1
  187. package/dist/generated/themes/MastheadCountrySelector.css.js +1 -1
  188. package/dist/generated/themes/MastheadCountrySelector.css.js.map +1 -1
  189. package/dist/generated/themes/MastheadItem.css.d.ts +1 -1
  190. package/dist/generated/themes/MastheadItem.css.js +1 -1
  191. package/dist/generated/themes/MastheadItem.css.js.map +1 -1
  192. package/dist/generated/themes/MastheadMenu.css.d.ts +1 -1
  193. package/dist/generated/themes/MastheadMenu.css.js +1 -1
  194. package/dist/generated/themes/MastheadMenu.css.js.map +1 -1
  195. package/dist/generated/themes/MastheadMenuItem.css.d.ts +1 -1
  196. package/dist/generated/themes/MastheadMenuItem.css.js +1 -1
  197. package/dist/generated/themes/MastheadMenuItem.css.js.map +1 -1
  198. package/dist/generated/themes/MastheadMobileMenu.css.d.ts +1 -1
  199. package/dist/generated/themes/MastheadMobileMenu.css.js +1 -1
  200. package/dist/generated/themes/MastheadMobileMenu.css.js.map +1 -1
  201. package/dist/generated/themes/MastheadProfileMenu.css.d.ts +1 -1
  202. package/dist/generated/themes/MastheadProfileMenu.css.js +1 -1
  203. package/dist/generated/themes/MastheadProfileMenu.css.js.map +1 -1
  204. package/dist/generated/themes/MastheadShell.css.d.ts +1 -1
  205. package/dist/generated/themes/MastheadShell.css.js +1 -1
  206. package/dist/generated/themes/MastheadShell.css.js.map +1 -1
  207. package/dist/generated/themes/MessageStrip.css.d.ts +1 -1
  208. package/dist/generated/themes/MessageStrip.css.js +1 -1
  209. package/dist/generated/themes/MessageStrip.css.js.map +1 -1
  210. package/dist/generated/themes/Modal.css.d.ts +1 -1
  211. package/dist/generated/themes/Modal.css.js +1 -1
  212. package/dist/generated/themes/Modal.css.js.map +1 -1
  213. package/dist/generated/themes/PromoTile.css.d.ts +1 -1
  214. package/dist/generated/themes/PromoTile.css.js +1 -1
  215. package/dist/generated/themes/PromoTile.css.js.map +1 -1
  216. package/dist/generated/themes/Quote.css.d.ts +1 -1
  217. package/dist/generated/themes/Quote.css.js +1 -1
  218. package/dist/generated/themes/Quote.css.js.map +1 -1
  219. package/dist/generated/themes/Review.css.d.ts +1 -1
  220. package/dist/generated/themes/Review.css.js +1 -1
  221. package/dist/generated/themes/Review.css.js.map +1 -1
  222. package/dist/generated/themes/ReviewItem.css.d.ts +1 -1
  223. package/dist/generated/themes/ReviewItem.css.js +1 -1
  224. package/dist/generated/themes/ReviewItem.css.js.map +1 -1
  225. package/dist/generated/themes/SecondaryNavigation.css.d.ts +1 -1
  226. package/dist/generated/themes/SecondaryNavigation.css.js +1 -1
  227. package/dist/generated/themes/SecondaryNavigation.css.js.map +1 -1
  228. package/dist/generated/themes/SecondaryNavigationItem.css.d.ts +1 -1
  229. package/dist/generated/themes/SecondaryNavigationItem.css.js +1 -1
  230. package/dist/generated/themes/SecondaryNavigationItem.css.js.map +1 -1
  231. package/dist/generated/themes/SelectBase.css.d.ts +1 -1
  232. package/dist/generated/themes/SelectBase.css.js +1 -1
  233. package/dist/generated/themes/SelectBase.css.js.map +1 -1
  234. package/dist/generated/themes/SideNavigation.css.d.ts +1 -1
  235. package/dist/generated/themes/SideNavigation.css.js +1 -1
  236. package/dist/generated/themes/SideNavigation.css.js.map +1 -1
  237. package/dist/generated/themes/SideNavigationItem.css.d.ts +1 -1
  238. package/dist/generated/themes/SideNavigationItem.css.js +1 -1
  239. package/dist/generated/themes/SideNavigationItem.css.js.map +1 -1
  240. package/dist/generated/themes/SideNavigationMobile.css.d.ts +1 -1
  241. package/dist/generated/themes/SideNavigationMobile.css.js +1 -1
  242. package/dist/generated/themes/SideNavigationMobile.css.js.map +1 -1
  243. package/dist/generated/themes/SideNavigationSubItem.css.d.ts +1 -1
  244. package/dist/generated/themes/SideNavigationSubItem.css.js +1 -1
  245. package/dist/generated/themes/SideNavigationSubItem.css.js.map +1 -1
  246. package/dist/generated/themes/TabNavigation.css.d.ts +1 -1
  247. package/dist/generated/themes/TabNavigation.css.js +1 -1
  248. package/dist/generated/themes/TabNavigation.css.js.map +1 -1
  249. package/dist/generated/themes/Table.css.d.ts +1 -1
  250. package/dist/generated/themes/Table.css.js +1 -1
  251. package/dist/generated/themes/Table.css.js.map +1 -1
  252. package/dist/generated/themes/TableCellBase.css.d.ts +1 -1
  253. package/dist/generated/themes/TableCellBase.css.js +1 -1
  254. package/dist/generated/themes/TableCellBase.css.js.map +1 -1
  255. package/dist/generated/themes/Upload.css.d.ts +1 -1
  256. package/dist/generated/themes/Upload.css.js +1 -1
  257. package/dist/generated/themes/Upload.css.js.map +1 -1
  258. package/dist/generated/themes/UploadItem.css.d.ts +1 -1
  259. package/dist/generated/themes/UploadItem.css.js +1 -1
  260. package/dist/generated/themes/UploadItem.css.js.map +1 -1
  261. package/dist/messagebundle.properties +3 -0
  262. package/dist/types/Table.d.ts +6 -2
  263. package/dist/types/Table.js +7 -2
  264. package/dist/types/Table.js.map +1 -1
  265. package/dist/vscode.html-custom-data.json +48 -7
  266. package/dist/web-types.json +88 -14
  267. package/package.json +1 -1
  268. package/run-cypress.js +8 -1
  269. package/src/AccordionSpotlight.ts +35 -6
  270. package/src/AccordionSpotlightItem.ts +3 -1
  271. package/src/Carousel.ts +39 -4
  272. package/src/CountrySelector.ts +1 -3
  273. package/src/List.ts +21 -4
  274. package/src/ListGroupHeader.ts +5 -1
  275. package/src/ListGroupHeaderBase.ts +16 -2
  276. package/src/ListGroupHeaderTemplate.tsx +29 -47
  277. package/src/ListItem.ts +14 -13
  278. package/src/ListItemBase.ts +14 -1
  279. package/src/ListItemTemplate.tsx +4 -4
  280. package/src/ListSelectAllTemplate.tsx +10 -8
  281. package/src/ListTemplate.tsx +14 -10
  282. package/src/Pagination.ts +2 -3
  283. package/src/Search.ts +48 -13
  284. package/src/SearchableListBase.ts +15 -3
  285. package/src/SearchableListBaseTemplate.tsx +51 -37
  286. package/src/SecondaryNavigation.ts +2 -1
  287. package/src/SecondaryNavigationItem.ts +14 -6
  288. package/src/SecondaryNavigationTemplate.tsx +4 -6
  289. package/src/SelectBase.ts +131 -145
  290. package/src/SelectBox.ts +21 -7
  291. package/src/SelectBoxTemplate.tsx +10 -9
  292. package/src/SideNavigation.ts +35 -0
  293. package/src/SideNavigationItem.ts +77 -0
  294. package/src/SideNavigationItemTemplate.tsx +97 -0
  295. package/src/SideNavigationMobile.ts +1 -2
  296. package/src/SideNavigationMobileTemplate.tsx +2 -1
  297. package/src/SideNavigationSubItem.ts +119 -2
  298. package/src/SideNavigationSubItemTemplate.tsx +57 -0
  299. package/src/Table.ts +1 -2
  300. package/src/TableCell.ts +9 -12
  301. package/src/TableCellBase.ts +10 -1
  302. package/src/TableHeaderCell.ts +0 -5
  303. package/src/TableRow.ts +20 -0
  304. package/src/TagGroup.ts +32 -0
  305. package/src/TagGroupTemplate.tsx +1 -1
  306. package/src/UploadItem.ts +3 -5
  307. package/src/generated/i18n/i18n-defaults.ts +2 -2
  308. package/src/generated/themes/AccordionSpotlight.css.ts +1 -1
  309. package/src/generated/themes/Contact.css.ts +1 -1
  310. package/src/generated/themes/EventRibbon.css.ts +1 -1
  311. package/src/generated/themes/Feed.css.ts +1 -1
  312. package/src/generated/themes/HeroBanner.css.ts +1 -1
  313. package/src/generated/themes/ImageGridCloud.css.ts +1 -1
  314. package/src/generated/themes/ImageGridTicker.css.ts +1 -1
  315. package/src/generated/themes/ImageGridTickerItem.css.ts +1 -1
  316. package/src/generated/themes/LinkList.css.ts +1 -1
  317. package/src/generated/themes/ListGroupHeader.css.ts +1 -1
  318. package/src/generated/themes/MastheadCountrySelector.css.ts +1 -1
  319. package/src/generated/themes/MastheadItem.css.ts +1 -1
  320. package/src/generated/themes/MastheadMenu.css.ts +1 -1
  321. package/src/generated/themes/MastheadMenuItem.css.ts +1 -1
  322. package/src/generated/themes/MastheadMobileMenu.css.ts +1 -1
  323. package/src/generated/themes/MastheadProfileMenu.css.ts +1 -1
  324. package/src/generated/themes/MastheadShell.css.ts +1 -1
  325. package/src/generated/themes/MessageStrip.css.ts +1 -1
  326. package/src/generated/themes/Modal.css.ts +1 -1
  327. package/src/generated/themes/PromoTile.css.ts +1 -1
  328. package/src/generated/themes/Quote.css.ts +1 -1
  329. package/src/generated/themes/Review.css.ts +1 -1
  330. package/src/generated/themes/ReviewItem.css.ts +1 -1
  331. package/src/generated/themes/SecondaryNavigation.css.ts +1 -1
  332. package/src/generated/themes/SecondaryNavigationItem.css.ts +1 -1
  333. package/src/generated/themes/SelectBase.css.ts +1 -1
  334. package/src/generated/themes/SideNavigation.css.ts +1 -1
  335. package/src/generated/themes/SideNavigationItem.css.ts +1 -1
  336. package/src/generated/themes/SideNavigationMobile.css.ts +1 -1
  337. package/src/generated/themes/SideNavigationSubItem.css.ts +1 -1
  338. package/src/generated/themes/TabNavigation.css.ts +1 -1
  339. package/src/generated/themes/Table.css.ts +1 -1
  340. package/src/generated/themes/TableCellBase.css.ts +1 -1
  341. package/src/generated/themes/Upload.css.ts +1 -1
  342. package/src/generated/themes/UploadItem.css.ts +1 -1
  343. package/src/i18n/messagebundle.properties +3 -0
  344. package/src/themes/AccordionSpotlight.css +11 -8
  345. package/src/themes/Contact.css +1 -1
  346. package/src/themes/EventRibbon.css +4 -4
  347. package/src/themes/Feed.css +2 -2
  348. package/src/themes/HeroBanner.css +3 -3
  349. package/src/themes/ImageGridCloud.css +1 -1
  350. package/src/themes/ImageGridTicker.css +1 -1
  351. package/src/themes/ImageGridTickerItem.css +1 -1
  352. package/src/themes/LinkList.css +4 -4
  353. package/src/themes/ListGroupHeader.css +2 -43
  354. package/src/themes/MastheadCountrySelector.css +1 -1
  355. package/src/themes/MastheadItem.css +4 -4
  356. package/src/themes/MastheadMenu.css +1 -1
  357. package/src/themes/MastheadMenuItem.css +1 -1
  358. package/src/themes/MastheadMobileMenu.css +2 -2
  359. package/src/themes/MastheadProfileMenu.css +1 -1
  360. package/src/themes/MastheadShell.css +4 -4
  361. package/src/themes/MessageStrip.css +7 -2
  362. package/src/themes/Modal.css +1 -1
  363. package/src/themes/PromoTile.css +4 -3
  364. package/src/themes/Quote.css +2 -2
  365. package/src/themes/Review.css +2 -2
  366. package/src/themes/ReviewItem.css +2 -2
  367. package/src/themes/SecondaryNavigation.css +1 -2
  368. package/src/themes/SecondaryNavigationItem.css +3 -6
  369. package/src/themes/SelectBase.css +1 -1
  370. package/src/themes/SideNavigation.css +31 -8
  371. package/src/themes/SideNavigationItem.css +100 -22
  372. package/src/themes/SideNavigationMobile.css +65 -20
  373. package/src/themes/SideNavigationSubItem.css +15 -54
  374. package/src/themes/TabNavigation.css +2 -2
  375. package/src/themes/Table.css +7 -2
  376. package/src/themes/TableCellBase.css +8 -0
  377. package/src/themes/Upload.css +1 -1
  378. package/src/themes/UploadItem.css +1 -1
  379. package/src/types/Table.ts +6 -2
  380. package/dist/css/themes/SideNavigationMobileDropdown.css +0 -1
  381. package/dist/generated/themes/SideNavigationMobileDropdown.css.d.ts +0 -2
  382. package/dist/generated/themes/SideNavigationMobileDropdown.css.js +0 -8
  383. package/dist/generated/themes/SideNavigationMobileDropdown.css.js.map +0 -1
  384. package/src/generated/themes/SideNavigationMobileDropdown.css.ts +0 -9
  385. package/src/themes/SideNavigationMobileDropdown.css +0 -29
@@ -253,6 +253,16 @@ describe("AccordionSpotlight — autoPlay", () => {
253
253
  });
254
254
 
255
255
  it("clicking the play button toggles the icon between pause and play", () => {
256
+ // Force reduced-motion off so autoPlay starts and the icon begins as "pause".
257
+ // The Cypress runner otherwise reports prefers-reduced-motion: reduce, which
258
+ // makes the component start paused.
259
+ cy.window().then((win) => {
260
+ cy.stub(win, "matchMedia")
261
+ .callThrough()
262
+ .withArgs("(prefers-reduced-motion: reduce)")
263
+ .returns({ matches: false, addEventListener() {}, removeEventListener() {} });
264
+ });
265
+
256
266
  cy.mount(
257
267
  <UDExAccordionSpotlight id="accordion-spotlight-toggle" autoPlay>
258
268
  <UDExAccordionSpotlightItem heading="Item 1" subheading="Sub 1" selected>
@@ -272,7 +282,7 @@ describe("AccordionSpotlight — autoPlay", () => {
272
282
  cy.get("[udex-accordion-spotlight]")
273
283
  .shadow()
274
284
  .find(".udex-accordion-spotlight__play-button")
275
- .click();
285
+ .realClick();
276
286
 
277
287
  cy.get("[udex-accordion-spotlight]")
278
288
  .shadow()
@@ -282,7 +292,7 @@ describe("AccordionSpotlight — autoPlay", () => {
282
292
  cy.get("[udex-accordion-spotlight]")
283
293
  .shadow()
284
294
  .find(".udex-accordion-spotlight__play-button")
285
- .click();
295
+ .realClick();
286
296
 
287
297
  cy.get("[udex-accordion-spotlight]")
288
298
  .shadow()
@@ -399,4 +409,35 @@ describe("AccordionSpotlight — accessibility", () => {
399
409
  .eq(0)
400
410
  .should("not.have.attr", "aria-hidden");
401
411
  });
412
+
413
+ it("setting item.selected = true activates that item", () => {
414
+ cy.mount(defaultAccordionSpotlight);
415
+
416
+ cy.get("[udex-accordion-spotlight-item]").eq(1).then(($item) => {
417
+ ($item[0] as any).selected = true;
418
+ });
419
+
420
+ cy.get("[udex-accordion-spotlight]")
421
+ .shadow()
422
+ .find(".udex-accordion-spotlight-item__button")
423
+ .eq(1)
424
+ .should("have.class", "udex-accordion-spotlight-item__button--active")
425
+ .and("have.attr", "aria-expanded", "true");
426
+ });
427
+
428
+ it("setting item.selected = true deactivates the previously active item", () => {
429
+ cy.mount(defaultAccordionSpotlight);
430
+
431
+ cy.get("[udex-accordion-spotlight-item]").eq(2).then(($item) => {
432
+ ($item[0] as any).selected = true;
433
+ });
434
+
435
+ cy.get("[udex-accordion-spotlight]")
436
+ .shadow()
437
+ .find(".udex-accordion-spotlight-item__button")
438
+ .eq(0)
439
+ .should("not.have.class", "udex-accordion-spotlight-item__button--active")
440
+ .and("have.attr", "aria-expanded", "false");
441
+ });
402
442
  });
443
+
@@ -103,6 +103,94 @@ describe("UDExCarousel component", () => {
103
103
  cy.get("@next").should("have.attr", "disabled");
104
104
  });
105
105
 
106
+ it("keeps focus on the next button after clicking it instead of moving focus to the slide", () => {
107
+ cy.mount(
108
+ <UDExCarousel id="carousel" navigation-placement="bottom">
109
+ <div>slide 1</div>
110
+ <div>slide 2</div>
111
+ <div>slide 3</div>
112
+ </UDExCarousel>
113
+ );
114
+
115
+ // Wait for the carousel to settle (navigation buttons rendered + enabled) so the
116
+ // realClick lands on a stable target.
117
+ cy.get("[udex-carousel]").shadow().find("[data-ui5-arrow-forward]").should("not.have.attr", "disabled");
118
+
119
+ // realClick (a genuine browser click) is required to faithfully exercise focus
120
+ // behaviour; Cypress' synthetic .click() does not manage focus for these custom
121
+ // elements the same way a real user click does.
122
+ cy.get("[udex-carousel]").shadow().find("[data-ui5-arrow-forward]").realClick();
123
+
124
+ // The next arrow is a udex-button, so focus lands on that host element inside
125
+ // the carousel's shadow root (not on the newly shown slide). The assertion is
126
+ // wrapped in a retryable .should() because the carousel re-renders after the
127
+ // click (disabled-state recalculation) and focus settles on the button.
128
+ cy.get("[udex-carousel]").should(($carousel) => {
129
+ const carousel = $carousel[0];
130
+ const nextButton = carousel.shadowRoot!.querySelector("[data-ui5-arrow-forward]");
131
+ expect(carousel.shadowRoot!.activeElement).to.eq(nextButton);
132
+ });
133
+ });
134
+
135
+ it("keeps focus on the previous button after clicking it instead of moving focus to the slide", () => {
136
+ cy.mount(
137
+ <UDExCarousel id="carousel" navigation-placement="bottom">
138
+ <div>slide 1</div>
139
+ <div>slide 2</div>
140
+ <div>slide 3</div>
141
+ </UDExCarousel>
142
+ );
143
+
144
+ // Navigate forward to the last page first so that, after one click back, the
145
+ // previous button is still enabled (landing on page 0 would disable it and a
146
+ // disabled button cannot retain focus).
147
+ cy.get("[udex-carousel]").shadow().find("[data-ui5-arrow-forward]").should("not.have.attr", "disabled");
148
+ cy.get("[udex-carousel]").shadow().find("[data-ui5-arrow-forward]").realClick();
149
+ cy.get("[udex-carousel]").shadow().find("[data-ui5-arrow-forward]").should("not.have.attr", "disabled");
150
+ cy.get("[udex-carousel]").shadow().find("[data-ui5-arrow-forward]").realClick();
151
+ cy.get("[udex-carousel]").shadow().find("[data-ui5-arrow-back]").should("not.have.attr", "disabled");
152
+
153
+ cy.get("[udex-carousel]").shadow().find("[data-ui5-arrow-back]").realClick();
154
+
155
+ cy.get("[udex-carousel]").should(($carousel) => {
156
+ const carousel = $carousel[0];
157
+ const prevButton = carousel.shadowRoot!.querySelector("[data-ui5-arrow-back]");
158
+ expect(carousel.shadowRoot!.activeElement).to.eq(prevButton);
159
+ });
160
+ });
161
+
162
+ it("advances the current page on next click while retaining focus on the next button", () => {
163
+ cy.mount(
164
+ <UDExCarousel id="carousel" navigation-placement="bottom">
165
+ <div>slide 1</div>
166
+ <div>slide 2</div>
167
+ <div>slide 3</div>
168
+ </UDExCarousel>
169
+ );
170
+
171
+ // Starts on the first page: next enabled, prev disabled.
172
+ cy.get("[udex-carousel]").shadow().find("[data-ui5-arrow-forward]").should("not.have.attr", "disabled");
173
+ cy.get("[udex-carousel]").shadow().find("[data-ui5-arrow-back]").should("have.attr", "disabled");
174
+
175
+ cy.get("[udex-carousel]").shadow().find("[data-ui5-arrow-forward]").realClick();
176
+
177
+ // Navigation still works: the current page advances (0 -> 1) and, as a
178
+ // user-observable consequence, the previous button becomes enabled.
179
+ cy.get("[udex-carousel]").should(($carousel) => {
180
+ const carousel = $carousel[0];
181
+ const inner = carousel.shadowRoot!.querySelector("[ui5-carousel]") as unknown as { _currentPageIndex: number };
182
+ expect(inner._currentPageIndex).to.eq(1);
183
+ });
184
+ cy.get("[udex-carousel]").shadow().find("[data-ui5-arrow-back]").should("not.have.attr", "disabled");
185
+
186
+ // ...and focus is retained on the triggering button.
187
+ cy.get("[udex-carousel]").should(($carousel) => {
188
+ const carousel = $carousel[0];
189
+ const nextButton = carousel.shadowRoot!.querySelector("[data-ui5-arrow-forward]");
190
+ expect(carousel.shadowRoot!.activeElement).to.eq(nextButton);
191
+ });
192
+ });
193
+
106
194
  it("tests navigation buttons are hidden when all items fit on one page", () => {
107
195
  cy.mount(
108
196
  <UDExCarousel id="carousel" items-per-page="S3 M3 L3 XL3" navigation-placement="bottom">
@@ -139,4 +227,50 @@ describe("UDExCarousel component", () => {
139
227
  .find(".udex-carousel__navigation-wrapper")
140
228
  .should("exist");
141
229
  });
230
+
231
+ it("re-enables the next button when a resize reduces items-per-page while on the last page", () => {
232
+ // Regression test: when on the last page with N items per page and the carousel
233
+ // shrinks across a breakpoint so fewer items fit per page, there are now items
234
+ // beyond the current view, so "next" must no longer be disabled.
235
+ // Both configs still have "many pages", so _hasManyPages does not change and the
236
+ // fix relies on _onResize recalculating the disabled state after the inner UI5
237
+ // carousel processes its own resize.
238
+ //
239
+ // The inner carousel advances by 1 item per click (overlapping-page behaviour), so
240
+ // the number of reachable positions = items - ipp + 1. With 4 slides and ipp=3
241
+ // at the L breakpoint that is exactly 2 positions — one click reaches the last one
242
+ // (hasNext = false). After shrinking to the M breakpoint (ipp=2) there are
243
+ // 3 reachable positions so hasNext becomes true again.
244
+ cy.viewport(1280, 900);
245
+ cy.mount(
246
+ <UDExCarousel id="carousel" items-per-page="S2 M2 L3 XL3" navigation-placement="bottom">
247
+ <div>slide 1</div>
248
+ <div>slide 2</div>
249
+ <div>slide 3</div>
250
+ <div>slide 4</div>
251
+ </UDExCarousel>
252
+ );
253
+
254
+ // L breakpoint (1024-1439px) -> 3 items per page -> 2 reachable positions.
255
+ // One click reaches the last position where hasNext = false.
256
+ cy.get("[udex-carousel]")
257
+ .shadow()
258
+ .find("[data-ui5-arrow-forward]")
259
+ .click();
260
+
261
+ // At the last reachable position the next button is disabled.
262
+ cy.get("[udex-carousel]")
263
+ .shadow()
264
+ .find("[data-ui5-arrow-forward]")
265
+ .should("have.attr", "disabled");
266
+
267
+ // Shrink to M breakpoint (600-1023px) -> 2 items per page -> 3 reachable positions.
268
+ // The remaining slide(s) become reachable again, so next must no longer be disabled.
269
+ cy.viewport(800, 900);
270
+
271
+ cy.get("[udex-carousel]")
272
+ .shadow()
273
+ .find("[data-ui5-arrow-forward]")
274
+ .should("not.have.attr", "disabled");
275
+ });
142
276
  });
@@ -1,4 +1,5 @@
1
1
  import { UDExCountrySelector } from "../support/component-imports.js";
2
+ import type { UDExSearchableListBaseSelectionChangeEventDetail } from "../../src/SearchableListBase.js";
2
3
 
3
4
  const defaultCountrySelector = <div style={{ width: "300px" }}><UDExCountrySelector
4
5
  id="default"
@@ -20,6 +21,27 @@ const countrySelectorWithSupportingText = <UDExCountrySelector
20
21
  </UDExCountrySelector>
21
22
 
22
23
  describe("CountrySelector component", () => {
24
+ // Updated: unfiltered first opening includes expanded in the shared template's single status.
25
+ function UDExAssertFirstCountryActive() {
26
+ cy.get("@dropdownPopover").should("have.attr", "open");
27
+ cy.get("@defaultCountrySelector").find("[_active-descendant]").should($active => {
28
+ expect($active).to.have.length(1);
29
+ expect($active).to.have.attr("data-token-id", "AF");
30
+ expect($active).to.have.class("_udex-active-descendant");
31
+ });
32
+ cy.get("@defaultCountrySelector").find("._udex-active-descendant").should("have.length", 1);
33
+ cy.get("@defaultCountrySelector").find('[udex-list-item][data-token-id="AF"]').then($country => {
34
+ cy.get("@searchInput").should("have.attr", "aria-activedescendant", $country[0].id);
35
+ });
36
+ cy.get("@searchInput").should("have.attr", "aria-expanded", "true");
37
+ cy.get("@searchInput").should("be.focused").should($input => {
38
+ const UDExRoot = $input[0].getRootNode() as ShadowRoot;
39
+ expect($input[0].ownerDocument.activeElement).to.equal(UDExRoot.host);
40
+ expect(UDExRoot.activeElement).to.equal($input[0]);
41
+ });
42
+ cy.get("@defaultCountrySelector").find('[aria-live="polite"]').should("have.length", 1).and("have.text", "expanded");
43
+ }
44
+
23
45
  beforeEach(() => {
24
46
  cy.mount(defaultCountrySelector);
25
47
  cy.get("#default").shadow().as("defaultCountrySelector");
@@ -115,9 +137,10 @@ describe("CountrySelector component", () => {
115
137
  cy.get("@dropdownPopover").find("udex-list-item").first().should("have.attr", "data-token-id", "AF");
116
138
  });
117
139
 
118
- it("opens the dropdown on trigger click", () => {
140
+ // Updated: pointer first opening must announce expanded as well as establishing the active country.
141
+ it("opens the dropdown on pointer click with the first country active and exact expanded status", () => {
119
142
  cy.get("@searchInput").click();
120
- cy.get("@dropdownPopover").should("have.attr", "open");
143
+ UDExAssertFirstCountryActive();
121
144
  });
122
145
 
123
146
  it("closes the dropdown on trigger click", () => {
@@ -170,19 +193,29 @@ describe("CountrySelector component", () => {
170
193
  cy.get("@defaultCountrySelector").find(".udex-text-field__text-holder").should("have.text", "Afghanistan (افغانستان)");
171
194
  });
172
195
 
196
+ // Updated: keyboard opening immediately highlights the first country without moving DOM focus.
173
197
  it("open dropdown press `ArrowDown` key on search", () => {
174
- cy.get("@searchInput").click().realPress("{downarrow}");
175
- cy.get("@dropdownPopover").should("have.attr", "open");
198
+ cy.get("@searchInput").focus().realPress("ArrowDown");
199
+ UDExAssertFirstCountryActive();
176
200
  });
177
201
 
202
+ // Updated: Enter selects the country highlighted by opening, with no extra ArrowDown.
178
203
  it("set active country item on `Enter` press", () => {
179
- cy.get("@searchInput").click().realPress("{downarrow}").realPress("{enter}");
204
+ cy.get("@searchInput").focus().realPress("ArrowDown");
205
+ UDExAssertFirstCountryActive();
206
+ cy.realPress("Enter");
180
207
  cy.get("@defaultCountrySelector").find(".udex-text-field__text-holder").should("have.text", "Afghanistan (افغانستان)");
181
208
  });
182
209
 
210
+ // Updated: Escape closes a genuinely keyboard-opened popup with an immediately active country.
183
211
  it("close dropdown press `Escape` key on search", () => {
184
- cy.get("@searchInput").click().realPress("{downarrow}").realPress("Escape");
212
+ cy.get("@searchInput").focus().realPress("ArrowDown");
213
+ UDExAssertFirstCountryActive();
214
+ cy.realPress("Escape");
185
215
  cy.get("@dropdownPopover").should("not.have.attr", "open");
216
+ cy.get("@searchInput").should("be.focused").and("have.attr", "aria-expanded", "false");
217
+ cy.get("@searchInput").should("not.have.attr", "aria-activedescendant");
218
+ cy.get("@defaultCountrySelector").find("[_active-descendant], ._udex-active-descendant").should("not.exist");
186
219
  });
187
220
 
188
221
  it("emits before-open event when dropdown is about to open", () => {
@@ -257,3 +290,197 @@ describe("CountrySelector component", () => {
257
290
  });
258
291
  });
259
292
  });
293
+
294
+ describe("CountrySelector keyboard accessibility regressions", () => {
295
+ const UDExCombobox = () => cy.get("[udex-country-selector]").shadow().find('input[role="combobox"]');
296
+ const UDExPopover = () => cy.get("[udex-country-selector]").shadow().find("[ui5-popover]");
297
+ const UDExList = () => cy.get("[udex-country-selector]").shadow().find("[udex-list]");
298
+ const UDExCountryOption = (UDExCode: string) => UDExList().find(`[udex-list-item][data-token-id="${UDExCode}"]`);
299
+ const UDExStatus = () => cy.get("[udex-country-selector]").shadow().find('[aria-live="polite"]');
300
+
301
+ function UDExAssertNativeInputFocus() {
302
+ UDExCombobox().should("be.focused").should($input => {
303
+ const UDExRoot = $input[0].getRootNode() as ShadowRoot;
304
+ expect($input[0].ownerDocument.activeElement).to.equal(UDExRoot.host);
305
+ expect(UDExRoot.activeElement).to.equal($input[0]);
306
+ });
307
+ }
308
+
309
+ function UDExAssertDescription(UDExExpected: string) {
310
+ UDExCombobox().should($input => {
311
+ const UDExIds = $input.attr("aria-describedby")!.split(/\s+/);
312
+ const UDExRoot = $input[0].getRootNode() as ShadowRoot;
313
+ expect(UDExIds).to.have.length(1);
314
+ const UDExDescription = UDExRoot.getElementById(UDExIds[0]);
315
+ expect(UDExDescription, "description resolves in the input's own shadow root").not.to.equal(null);
316
+ expect(UDExDescription!.textContent).to.equal(UDExExpected);
317
+ });
318
+ }
319
+
320
+ function UDExMountKeyboardCountrySelector(UDExPreselectedCountry?: string) {
321
+ // Observe errors without returning false: Cypress must still fail on any uncaught TypeError.
322
+ cy.on("uncaught:exception", cy.stub().as("countryUncaughtException"));
323
+ cy.mount(
324
+ <div id="country-selector-keyboard-fixture">
325
+ <button id="before-country-selector">Previous</button>
326
+ <UDExCountrySelector accessibleName="Country" supportingText="Choose a country" height="400px"
327
+ preselectedCountry={UDExPreselectedCountry}>
328
+ </UDExCountrySelector>
329
+ </div>
330
+ );
331
+ cy.get("#country-selector-keyboard-fixture").then($fixture => {
332
+ $fixture[0].addEventListener("selection-change", cy.stub().as("countrySelectionChange"));
333
+ });
334
+ cy.get("[udex-country-selector]").then($host => {
335
+ $host[0].addEventListener("close", cy.stub().as("countryDropdownClosed"));
336
+ });
337
+ UDExPopover().then($popover => {
338
+ $popover[0].addEventListener("ui5-open", cy.stub().as("countryPopoverOpened"));
339
+ });
340
+ UDExCombobox().then($input => {
341
+ $input[0].addEventListener("blur", cy.stub().as("countryComboboxBlur"));
342
+ });
343
+ cy.get("#before-country-selector").realClick();
344
+ cy.realPress("Tab");
345
+ UDExAssertNativeInputFocus();
346
+ UDExPopover().should("not.have.attr", "open");
347
+ UDExCombobox().should("have.attr", "aria-expanded", "false");
348
+ }
349
+
350
+ function UDExAssertActiveCountry(UDExCode: string) {
351
+ UDExCountryOption(UDExCode).should($country => {
352
+ expect($country).to.have.length(1);
353
+ expect($country).to.have.attr("_active-descendant");
354
+ expect($country).to.have.class("_udex-active-descendant");
355
+ }).then($country => {
356
+ UDExList().find("[_active-descendant]").should("have.length", 1).and($active => {
357
+ expect($active[0]).to.equal($country[0]);
358
+ });
359
+ UDExList().find("._udex-active-descendant").should("have.length", 1).and($highlight => {
360
+ expect($highlight[0]).to.equal($country[0]);
361
+ });
362
+ UDExCombobox().should("have.attr", "aria-activedescendant", $country[0].id);
363
+ });
364
+ UDExCountryOption(UDExCode).should("not.be.focused");
365
+ UDExAssertNativeInputFocus();
366
+ }
367
+
368
+ function UDExOpenWithActiveCountry(UDExOpenCount: number, UDExCode = "AF") {
369
+ cy.realPress("ArrowDown");
370
+ cy.get("@countryPopoverOpened").should("have.callCount", UDExOpenCount);
371
+ UDExPopover().should("have.attr", "open");
372
+ UDExCombobox().should("have.attr", "aria-expanded", "true");
373
+ UDExAssertActiveCountry(UDExCode);
374
+ // Updated: opening announces expanded; flat country navigation remains silent.
375
+ UDExStatus().should("have.length", 1).and("have.text", "expanded");
376
+ UDExAssertNativeInputFocus();
377
+ }
378
+
379
+ // Updated: opening announces expanded with the first country active; the next ArrowDown moves silently to the second.
380
+ it("opens with the first country active, advances on ArrowDown and selects a plain-data country with persistent close feedback and no blur or TypeError", () => {
381
+ const UDExName = "Afghanistan (افغانستان)";
382
+ UDExMountKeyboardCountrySelector();
383
+ cy.get("[udex-country-selector]").shadow().find('label[for="search-input"]').should("not.exist");
384
+ UDExCombobox().should("have.attr", "aria-label", "Country");
385
+ UDExCombobox().should("have.attr", "aria-haspopup", "listbox");
386
+ UDExList().should("have.attr", "role", "listbox");
387
+ UDExList().then($list => {
388
+ UDExCombobox().should("have.attr", "aria-controls", $list[0].id);
389
+ });
390
+ UDExAssertDescription("Choose a country");
391
+
392
+ UDExOpenWithActiveCountry(1);
393
+ cy.get("@countrySelectionChange").should("not.have.been.called");
394
+ UDExList().find("[_active-descendant]").should("have.length", 1);
395
+ UDExList().find("[udex-list-item]").first().should("have.attr", "data-token-id", "AF");
396
+ UDExCountryOption("AF").should("have.attr", "_active-descendant");
397
+ UDExCountryOption("AF").should("have.attr", "role", "option");
398
+ UDExCountryOption("AF").should("have.attr", "aria-label", UDExName);
399
+ UDExCountryOption("AF").should("have.attr", "aria-selected", "false");
400
+ UDExCountryOption("AF").then($country => {
401
+ UDExCombobox().should("have.attr", "aria-activedescendant", $country[0].id);
402
+ });
403
+ UDExAssertNativeInputFocus();
404
+ UDExAssertDescription("Choose a country");
405
+ UDExStatus().should("have.text", "expanded");
406
+ cy.get("@countrySelectionChange").should("not.have.been.called");
407
+ cy.get("@countryComboboxBlur").should("not.have.been.called");
408
+
409
+ cy.realPress("ArrowDown");
410
+ UDExAssertActiveCountry("AL");
411
+ UDExCountryOption("AF").should("not.have.attr", "_active-descendant");
412
+ UDExCountryOption("AL").should("have.attr", "aria-selected", "false");
413
+ UDExStatus().should("have.text", "");
414
+ cy.get("@countrySelectionChange").should("not.have.been.called");
415
+ cy.get("@countryComboboxBlur").should("not.have.been.called");
416
+ cy.realPress("ArrowUp");
417
+ UDExAssertActiveCountry("AF");
418
+
419
+ cy.realPress("Enter");
420
+ cy.get("@countrySelectionChange").should("have.been.calledOnce")
421
+ .its("lastCall.args.0").should((UDExEvent: CustomEvent<UDExSearchableListBaseSelectionChangeEventDetail>) => {
422
+ expect(UDExEvent.bubbles).to.equal(true);
423
+ expect(UDExEvent.detail.item).to.include({ _id: "AF", label: UDExName, selected: true });
424
+ expect(UDExEvent.detail.item).not.to.have.property("getAttribute");
425
+ expect(UDExEvent.detail.selectedItems).to.deep.equal([UDExEvent.detail.item]);
426
+ });
427
+ cy.get("@countryDropdownClosed").should("have.been.calledOnce");
428
+ UDExPopover().should("not.have.attr", "open");
429
+ UDExCombobox().should("have.attr", "aria-expanded", "false");
430
+ UDExCombobox().should("not.have.attr", "aria-activedescendant");
431
+ UDExList().find("[_active-descendant]").should("not.exist");
432
+ cy.get("[udex-country-selector]").should("have.prop", "selectedCountryName", UDExName);
433
+ cy.get("[udex-country-selector]").shadow().find(".udex-text-field__text-holder").should("have.text", UDExName);
434
+ UDExCountryOption("AF").should("have.attr", "aria-selected", "true");
435
+ UDExAssertDescription(`Choose a country ${UDExName}`);
436
+ UDExAssertNativeInputFocus();
437
+ // Assert after the complete close lifecycle, not just the selection handler.
438
+ UDExStatus().should("have.attr", "aria-atomic", "true");
439
+ UDExStatus().should("have.text", `${UDExName}, Selected`);
440
+ cy.get("@countryComboboxBlur").should("not.have.been.called");
441
+ cy.get("@countryUncaughtException").should("not.have.been.called");
442
+ });
443
+
444
+ // Updated: initial opening and Escape reopening announce expanded and immediately restore the selected country.
445
+ it("restores the preselected country immediately on initial opening and Escape reopening, then advances on ArrowDown", () => {
446
+ const UDExName = "Poland (Polska)";
447
+ UDExMountKeyboardCountrySelector("PL");
448
+ cy.get("[udex-country-selector]").should("have.prop", "selectedCountryName", UDExName);
449
+
450
+ [1, 2].forEach(UDExCycle => {
451
+ UDExOpenWithActiveCountry(UDExCycle, "PL");
452
+ UDExList().find("[_active-descendant]").should("have.length", 1);
453
+ UDExCountryOption("PL").should("have.attr", "_active-descendant");
454
+ UDExCountryOption("PL").should("have.attr", "aria-selected", "true");
455
+ UDExCountryOption("PL").should("have.attr", "aria-label", UDExName);
456
+ UDExCountryOption("AF").should("not.have.attr", "_active-descendant");
457
+ UDExCountryOption("PL").then($country => {
458
+ UDExCombobox().should("have.attr", "aria-activedescendant", $country[0].id);
459
+ });
460
+ UDExAssertNativeInputFocus();
461
+ UDExAssertDescription("Choose a country");
462
+ UDExStatus().should("have.text", "expanded");
463
+
464
+ cy.realPress("ArrowDown");
465
+ UDExAssertActiveCountry("PT");
466
+ UDExCountryOption("PL").should("not.have.attr", "_active-descendant");
467
+ UDExCountryOption("PL").should("have.attr", "aria-selected", "true");
468
+ UDExCountryOption("PT").should("have.attr", "aria-selected", "false");
469
+ UDExAssertDescription("Choose a country");
470
+ UDExStatus().should("have.text", "");
471
+
472
+ cy.realPress("Escape");
473
+ cy.get("@countryDropdownClosed").should("have.callCount", UDExCycle);
474
+ UDExPopover().should("not.have.attr", "open");
475
+ UDExCombobox().should("have.attr", "aria-expanded", "false");
476
+ UDExCombobox().should("not.have.attr", "aria-activedescendant");
477
+ UDExList().find("[_active-descendant]").should("not.exist");
478
+ UDExStatus().should("have.text", "");
479
+ UDExAssertNativeInputFocus();
480
+ cy.get("[udex-country-selector]").should("have.prop", "selectedCountryName", UDExName);
481
+ cy.get("@countrySelectionChange").should("not.have.been.called");
482
+ cy.get("@countryComboboxBlur").should("not.have.been.called");
483
+ cy.get("@countryUncaughtException").should("not.have.been.called");
484
+ });
485
+ });
486
+ });
@@ -1837,8 +1837,8 @@ describe("Filter Menu component", () => {
1837
1837
  // - the list host still activates tree/treeitem semantics
1838
1838
  // - aria-multiselectable is NOT set (SingleSelect distinction)
1839
1839
  // - leaf items expose aria-selected (not aria-checked)
1840
- // - header renders via the udex-list-item partial (useListItemHeader === true)
1841
- // and exposes aria-expanded on [part=item]
1840
+ // - header renders as a header-only div treeitem (useListItemHeader === false)
1841
+ // with aria-expanded and ownership of a same-shadow sibling group
1842
1842
  describe("SingleSelect + collapsible groups", () => {
1843
1843
  beforeEach(() => {
1844
1844
  cy.mount(filterMenuSingleSelectGroupCollapsible);
@@ -1891,33 +1891,32 @@ describe("Filter Menu component", () => {
1891
1891
  .should("have.attr", "role", "treeitem");
1892
1892
  });
1893
1893
 
1894
- it("nests the content region (role=\"group\") inside the treeitem div (conformant tree)", () => {
1895
- // Conformant nesting: the role="group" content region is a DESCENDANT of the
1896
- // .udex-list__group-content treeitem, so screen readers count children per group
1897
- // natively (no author aria-posinset needed — matches the List component). This is
1898
- // what restores JAWS per-item counting under arrow navigation.
1894
+ // Updated: the header owns a same-shadow sibling group without nesting its leaves.
1895
+ it("owns the sibling content group without nesting its slot inside the header treeitem", () => {
1899
1896
  cy.get("#filter-menu-single-tree-collapsible").shadow()
1900
- .find("udex-list-group-header").shadow()
1901
- .find(".udex-list__group-list > .udex-list__group-content--nested[role='treeitem']").should("exist");
1902
-
1903
- cy.get("#filter-menu-single-tree-collapsible").shadow()
1904
- .find("udex-list-group-header").shadow()
1905
- .find(".udex-list__group-content--nested[role='treeitem'] .udex-list__group-list__content[role='group']").should("exist");
1906
-
1907
- // The content region is no longer emitted as a sibling of the treeitem.
1908
- cy.get("#filter-menu-single-tree-collapsible").shadow()
1909
- .find("udex-list-group-header").shadow()
1910
- .find(".udex-list__group-list > .udex-list__group-list__content[role='group']").should("not.exist");
1911
-
1912
- // The visible header row wrapper now sits inside the treeitem (ring/layout target).
1913
- cy.get("#filter-menu-single-tree-collapsible").shadow()
1914
- .find("udex-list-group-header").shadow()
1915
- .find(".udex-list__group-content--nested[role='treeitem'] > .udex-list__group-header-row").should("exist");
1897
+ .find("[udex-list-group-header]").shadow()
1898
+ .find(".udex-list__group-list > .udex-list__group-content.udex-list__group-header-wrap[role='treeitem']")
1899
+ .should(UDExHeader => {
1900
+ expect(UDExHeader).to.have.length(1);
1901
+ const UDExRow = UDExHeader[0];
1902
+ const UDExShadow = UDExRow.getRootNode() as ShadowRoot;
1903
+ const UDExOwnedId = UDExRow.getAttribute("aria-owns");
1904
+ expect(UDExOwnedId).to.match(/^\S+$/);
1905
+ expect(UDExRow.getAttribute("aria-controls")).to.equal(UDExOwnedId);
1906
+ const UDExGroups = UDExShadow.querySelectorAll(`[id="${UDExOwnedId}"]`);
1907
+ expect(UDExGroups).to.have.length(1);
1908
+ const UDExGroup = UDExGroups[0];
1909
+ expect(UDExGroup.matches(".udex-list__group-list__content[role=group]")).to.equal(true);
1910
+ expect(UDExGroup.getRootNode()).to.equal(UDExShadow);
1911
+ expect(UDExGroup.parentElement).to.equal(UDExRow.parentElement);
1912
+ expect(UDExRow.nextElementSibling).to.equal(UDExGroup);
1913
+ expect(UDExRow.querySelector("slot, [role=group], [udex-list-item]")).to.equal(null);
1914
+ expect(UDExGroup.querySelector("slot")!.assignedElements()).to.have.length(3);
1915
+ });
1916
1916
  });
1917
1917
 
1918
1918
  it("emits explicit aria-posinset/aria-setsize on single-select child treeitems (forces JAWS re-announcement)", () => {
1919
- // Conformant nesting makes the structural count match the explicit values, so
1920
- // JAWS trusts and re-announces on every arrow step — not just on group entry.
1919
+ // Explicit per-group positions preserve child counts with the owned sibling group.
1921
1920
  cy.get("#filter-menu-single-tree-collapsible").shadow()
1922
1921
  .find("udex-list-group-header")
1923
1922
  .find("udex-list-item").eq(0).shadow()
@@ -2073,12 +2072,12 @@ describe("Filter Menu component", () => {
2073
2072
 
2074
2073
  // Updated: the header is now a plain <div>. Clicking its body does nothing at all
2075
2074
  // (no @click handler is wired on the div). This asserts no child gets selected.
2076
- // Full click/Enter/Space + collapse coverage is in the dedicated
2077
- // "activation collapses only, never selects" describe below.
2075
+ // Additional activation/collapse coverage is in the dedicated
2076
+ // "never selectable, collapses via arrows/arrow-button only" describe below.
2078
2077
  it("clicking the header body does NOT select any child", () => {
2079
2078
  cy.get("#filter-menu-single-tree-collapsible").shadow()
2080
- .find("udex-list-group-header").shadow()
2081
- .find(".udex-list__group-header-row").click();
2079
+ .find("[udex-list-group-header]").shadow()
2080
+ .find(".udex-list__group-content.udex-list__group-header-wrap").realClick();
2082
2081
 
2083
2082
  cy.get("#filter-menu-single-tree-collapsible").shadow()
2084
2083
  .find("udex-list-group-header")
@@ -2150,20 +2149,12 @@ describe("Filter Menu component", () => {
2150
2149
  openMenu("filter-menu-single-tree-collapsible");
2151
2150
  });
2152
2151
 
2152
+ // The treeitem is header-only; its children live in the owned sibling group.
2153
+ // Native clicks at its centre therefore target the header body, not a child item.
2153
2154
  const headerDiv = () =>
2154
2155
  cy.get("#filter-menu-single-tree-collapsible").shadow()
2155
- .find("udex-list-group-header").shadow()
2156
- .find(".udex-list__group-content");
2157
-
2158
- // The visible header body. In the conformant nested tree the treeitem div
2159
- // (.udex-list__group-content) wraps the whole subtree, so its geometric centre is
2160
- // over a child item — clicking it is "covered". The header row is the actual body
2161
- // (it sits above the children), so clicks target it while attribute assertions stay
2162
- // on the treeitem div above.
2163
- const headerRow = () =>
2164
- cy.get("#filter-menu-single-tree-collapsible").shadow()
2165
- .find("udex-list-group-header").shadow()
2166
- .find(".udex-list__group-header-row");
2156
+ .find("[udex-list-group-header]").shadow()
2157
+ .find(".udex-list__group-content.udex-list__group-header-wrap");
2167
2158
 
2168
2159
  const arrowButton = () =>
2169
2160
  cy.get("#filter-menu-single-tree-collapsible").shadow()
@@ -2185,14 +2176,15 @@ describe("Filter Menu component", () => {
2185
2176
  headerDiv().should("not.have.attr", "aria-selected");
2186
2177
  headerDiv().should("not.have.attr", "aria-checked");
2187
2178
 
2188
- headerRow().click();
2179
+ headerDiv().realClick();
2189
2180
 
2190
2181
  headerDiv().should("not.have.attr", "aria-selected");
2191
2182
  headerDiv().should("not.have.attr", "aria-checked");
2192
2183
  });
2193
2184
 
2185
+ // Updated: click the current header-only treeitem with native pointer events.
2194
2186
  it("clicking the header body does NOT set the selected property on the host group header", () => {
2195
- headerRow().click();
2187
+ headerDiv().realClick();
2196
2188
 
2197
2189
  cy.get("#filter-menu-single-tree-collapsible").shadow()
2198
2190
  .find("udex-list-group-header").then($gh => {
@@ -2200,8 +2192,9 @@ describe("Filter Menu component", () => {
2200
2192
  });
2201
2193
  });
2202
2194
 
2195
+ // Updated: click the current header-only treeitem with native pointer events.
2203
2196
  it("clicking the header body does NOT select any child item", () => {
2204
- headerRow().click();
2197
+ headerDiv().realClick();
2205
2198
 
2206
2199
  childItems().each($item => {
2207
2200
  cy.wrap($item).shadow()
@@ -2211,10 +2204,11 @@ describe("Filter Menu component", () => {
2211
2204
 
2212
2205
  // 2) Clicking the header body must NOT collapse the group either — there is no
2213
2206
  // @click handler on the div in the new implementation.
2207
+ // Updated: click the current header-only treeitem with native pointer events.
2214
2208
  it("clicking the header body does NOT collapse the group", () => {
2215
2209
  headerDiv().should("have.attr", "aria-expanded", "true");
2216
2210
 
2217
- headerRow().click();
2211
+ headerDiv().realClick();
2218
2212
 
2219
2213
  headerDiv().should("have.attr", "aria-expanded", "true");
2220
2214
  cy.get("#filter-menu-single-tree-collapsible").shadow()