@sapudex/web-components 2.32.1 → 2.34.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 (159) hide show
  1. package/cypress/fixtures/masthead-shell.ts +281 -0
  2. package/cypress/specs/Breadcrumbs.cy.tsx +196 -1
  3. package/cypress/specs/FilterMenu.cy.tsx +53 -0
  4. package/cypress/specs/ListItem.cy.tsx +48 -0
  5. package/cypress/specs/MastheadMenu.cy.tsx +564 -0
  6. package/cypress/specs/MastheadMobileMenu.cy.tsx +573 -0
  7. package/cypress/specs/MastheadShell.cy.tsx +645 -0
  8. package/cypress/specs/SecondaryNavigationDesktop.cy.tsx +289 -95
  9. package/cypress/specs/SecondaryNavigationMobile.cy.tsx +42 -0
  10. package/cypress/specs/SelectBox.cy.tsx +63 -0
  11. package/cypress/specs/TabNavigation.cy.tsx +431 -10
  12. package/cypress/support/component-imports.instrumented.ts +14 -0
  13. package/cypress/support/component-imports.src.ts +10 -0
  14. package/dist/Breadcrumbs.d.ts +12 -0
  15. package/dist/Breadcrumbs.js +30 -6
  16. package/dist/Breadcrumbs.js.map +1 -1
  17. package/dist/BreadcrumbsPopoverTemplate.js +10 -1
  18. package/dist/BreadcrumbsPopoverTemplate.js.map +1 -1
  19. package/dist/BreadcrumbsTemplate.js +1 -1
  20. package/dist/BreadcrumbsTemplate.js.map +1 -1
  21. package/dist/ListItem.d.ts +3 -0
  22. package/dist/ListItem.js +10 -1
  23. package/dist/ListItem.js.map +1 -1
  24. package/dist/ListItemBase.d.ts +29 -0
  25. package/dist/ListItemBase.js +22 -0
  26. package/dist/ListItemBase.js.map +1 -1
  27. package/dist/MastheadItem.d.ts +2 -1
  28. package/dist/MastheadItem.js.map +1 -1
  29. package/dist/MastheadMenu.d.ts +2 -1
  30. package/dist/MastheadMenu.js.map +1 -1
  31. package/dist/SearchableListBase.d.ts +3 -1
  32. package/dist/SearchableListBase.js +7 -1
  33. package/dist/SearchableListBase.js.map +1 -1
  34. package/dist/SecondaryNavigation.d.ts +1 -6
  35. package/dist/SecondaryNavigation.js +6 -59
  36. package/dist/SecondaryNavigation.js.map +1 -1
  37. package/dist/SecondaryNavigationItem.d.ts +5 -12
  38. package/dist/SecondaryNavigationItem.js +34 -65
  39. package/dist/SecondaryNavigationItem.js.map +1 -1
  40. package/dist/SecondaryNavigationItemBase.d.ts +0 -1
  41. package/dist/SecondaryNavigationItemBase.js +0 -4
  42. package/dist/SecondaryNavigationItemBase.js.map +1 -1
  43. package/dist/SelectBase.js +4 -2
  44. package/dist/SelectBase.js.map +1 -1
  45. package/dist/Tab.d.ts +19 -0
  46. package/dist/Tab.js +22 -0
  47. package/dist/Tab.js.map +1 -1
  48. package/dist/TabNavigation.d.ts +9 -1
  49. package/dist/TabNavigation.js +25 -7
  50. package/dist/TabNavigation.js.map +1 -1
  51. package/dist/assets/{InputSuggestions-DeXhpK0F.js → InputSuggestions-Bz7HZXUc.js} +1 -1
  52. package/dist/assets/{ListItemStandardExpandableTextTemplate-jMEdrC07.js → ListItemStandardExpandableTextTemplate-CjE7hAvu.js} +1 -1
  53. package/dist/assets/{bundle-S1uYREqT.css → bundle-JYo3bV8v.css} +1 -1
  54. package/dist/assets/{bundle.esm-CwJAt93x.js → bundle.esm-mAR7ytdB.js} +217 -217
  55. package/dist/css/themes/Breadcrumbs.css +1 -1
  56. package/dist/css/themes/BreadcrumbsPopover.css +1 -1
  57. package/dist/css/themes/ListItem.css +1 -1
  58. package/dist/css/themes/MastheadMenu.css +1 -1
  59. package/dist/css/themes/MastheadMobileMenu.css +1 -1
  60. package/dist/css/themes/RatingIndicator.css +1 -1
  61. package/dist/css/themes/Slider.css +1 -1
  62. package/dist/css/themes/TabNavigation.css +1 -1
  63. package/dist/custom-elements-internal.json +1357 -212
  64. package/dist/custom-elements.json +1342 -197
  65. package/dist/generated/templates/ListItemTemplate.lit.js +32 -28
  66. package/dist/generated/templates/ListItemTemplate.lit.js.map +1 -1
  67. package/dist/generated/templates/MastheadMenuTemplate.lit.js +8 -1
  68. package/dist/generated/templates/MastheadMenuTemplate.lit.js.map +1 -1
  69. package/dist/generated/templates/MastheadMobileMenuTemplate.lit.js +10 -4
  70. package/dist/generated/templates/MastheadMobileMenuTemplate.lit.js.map +1 -1
  71. package/dist/generated/templates/SearchableListBaseTemplate.lit.js +3 -3
  72. package/dist/generated/templates/SearchableListBaseTemplate.lit.js.map +1 -1
  73. package/dist/generated/templates/SecondaryNavigationItemTemplate.lit.js +4 -4
  74. package/dist/generated/templates/SecondaryNavigationItemTemplate.lit.js.map +1 -1
  75. package/dist/generated/templates/SecondaryNavigationSubItemTemplate.lit.js +3 -3
  76. package/dist/generated/templates/SecondaryNavigationSubItemTemplate.lit.js.map +1 -1
  77. package/dist/generated/templates/SecondaryNavigationTemplate.lit.js +5 -5
  78. package/dist/generated/templates/SecondaryNavigationTemplate.lit.js.map +1 -1
  79. package/dist/generated/templates/SelectBoxTemplate.lit.js +12 -10
  80. package/dist/generated/templates/SelectBoxTemplate.lit.js.map +1 -1
  81. package/dist/generated/templates/TabHeaderTemplate.lit.js +40 -24
  82. package/dist/generated/templates/TabHeaderTemplate.lit.js.map +1 -1
  83. package/dist/generated/templates/TabNavigationTemplate.lit.js +1 -1
  84. package/dist/generated/templates/TabNavigationTemplate.lit.js.map +1 -1
  85. package/dist/generated/themes/Breadcrumbs.css.d.ts +1 -1
  86. package/dist/generated/themes/Breadcrumbs.css.js +1 -1
  87. package/dist/generated/themes/Breadcrumbs.css.js.map +1 -1
  88. package/dist/generated/themes/BreadcrumbsPopover.css.d.ts +1 -1
  89. package/dist/generated/themes/BreadcrumbsPopover.css.js +1 -1
  90. package/dist/generated/themes/BreadcrumbsPopover.css.js.map +1 -1
  91. package/dist/generated/themes/ListItem.css.d.ts +1 -1
  92. package/dist/generated/themes/ListItem.css.js +1 -1
  93. package/dist/generated/themes/ListItem.css.js.map +1 -1
  94. package/dist/generated/themes/MastheadMenu.css.d.ts +1 -1
  95. package/dist/generated/themes/MastheadMenu.css.js +1 -1
  96. package/dist/generated/themes/MastheadMenu.css.js.map +1 -1
  97. package/dist/generated/themes/MastheadMobileMenu.css.d.ts +1 -1
  98. package/dist/generated/themes/MastheadMobileMenu.css.js +1 -1
  99. package/dist/generated/themes/MastheadMobileMenu.css.js.map +1 -1
  100. package/dist/generated/themes/RatingIndicator.css.d.ts +1 -1
  101. package/dist/generated/themes/RatingIndicator.css.js +1 -1
  102. package/dist/generated/themes/RatingIndicator.css.js.map +1 -1
  103. package/dist/generated/themes/Slider.css.d.ts +1 -1
  104. package/dist/generated/themes/Slider.css.js +1 -1
  105. package/dist/generated/themes/Slider.css.js.map +1 -1
  106. package/dist/generated/themes/TabNavigation.css.d.ts +1 -1
  107. package/dist/generated/themes/TabNavigation.css.js +1 -1
  108. package/dist/generated/themes/TabNavigation.css.js.map +1 -1
  109. package/dist/vscode.html-custom-data.json +236 -1
  110. package/dist/web-types.json +393 -3
  111. package/package.json +1 -1
  112. package/src/Breadcrumbs.ts +26 -7
  113. package/src/BreadcrumbsPopoverTemplate.tsx +53 -41
  114. package/src/BreadcrumbsTemplate.tsx +35 -21
  115. package/src/ListItem.hbs +42 -14
  116. package/src/ListItem.ts +12 -1
  117. package/src/ListItemBase.ts +40 -0
  118. package/src/MastheadItem.ts +2 -1
  119. package/src/MastheadMenu.hbs +35 -0
  120. package/src/MastheadMenu.ts +2 -1
  121. package/src/MastheadMobileMenu.hbs +40 -9
  122. package/src/SearchableListBase.hbs +12 -0
  123. package/src/SearchableListBase.ts +11 -2
  124. package/src/SecondaryNavigation.hbs +6 -6
  125. package/src/SecondaryNavigation.ts +7 -66
  126. package/src/SecondaryNavigationItem.hbs +4 -6
  127. package/src/SecondaryNavigationItem.ts +40 -83
  128. package/src/SecondaryNavigationItemBase.ts +0 -3
  129. package/src/SecondaryNavigationSubItem.hbs +3 -7
  130. package/src/SelectBase.ts +4 -2
  131. package/src/SelectBox.hbs +13 -5
  132. package/src/Tab.ts +32 -0
  133. package/src/TabHeader.hbs +40 -19
  134. package/src/TabNavigation.hbs +5 -9
  135. package/src/TabNavigation.ts +25 -8
  136. package/src/generated/templates/ListItemTemplate.lit.ts +32 -28
  137. package/src/generated/templates/MastheadMenuTemplate.lit.ts +8 -1
  138. package/src/generated/templates/MastheadMobileMenuTemplate.lit.ts +10 -4
  139. package/src/generated/templates/SearchableListBaseTemplate.lit.ts +3 -3
  140. package/src/generated/templates/SecondaryNavigationItemTemplate.lit.ts +4 -4
  141. package/src/generated/templates/SecondaryNavigationSubItemTemplate.lit.ts +3 -3
  142. package/src/generated/templates/SecondaryNavigationTemplate.lit.ts +5 -5
  143. package/src/generated/templates/SelectBoxTemplate.lit.ts +12 -10
  144. package/src/generated/templates/TabHeaderTemplate.lit.ts +40 -24
  145. package/src/generated/templates/TabNavigationTemplate.lit.ts +1 -1
  146. package/src/generated/themes/Breadcrumbs.css.ts +1 -1
  147. package/src/generated/themes/BreadcrumbsPopover.css.ts +1 -1
  148. package/src/generated/themes/ListItem.css.ts +1 -1
  149. package/src/generated/themes/MastheadMenu.css.ts +1 -1
  150. package/src/generated/themes/MastheadMobileMenu.css.ts +1 -1
  151. package/src/generated/themes/RatingIndicator.css.ts +1 -1
  152. package/src/generated/themes/Slider.css.ts +1 -1
  153. package/src/generated/themes/TabNavigation.css.ts +1 -1
  154. package/src/themes/Breadcrumbs.css +6 -0
  155. package/src/themes/BreadcrumbsPopover.css +12 -2
  156. package/src/themes/ListItem.css +12 -5
  157. package/src/themes/MastheadMenu.css +45 -0
  158. package/src/themes/MastheadMobileMenu.css +45 -0
  159. package/src/themes/TabNavigation.css +58 -73
@@ -1,6 +1,25 @@
1
1
  import UDExTabNavigation, { UDExTabNavigationOrientation, UDExTabNavigationPlacement, UDExTabNavigationVerticalAlignment } from "../../src/TabNavigation.js";
2
2
  import UDExTab from "../../src/Tab.js";
3
3
 
4
+ // ─── Process Tab fixtures ─────────────────────────────────────────────────────
5
+
6
+ const processTabNavigation = (
7
+ <UDExTabNavigation id="process-tab-navigation" processTab>
8
+ <UDExTab text="Step 1" icon="home" itemCountText="1 of 4" selected>
9
+ <div>Step 1 Content</div>
10
+ </UDExTab>
11
+ <UDExTab text="Step 2" icon="action" itemCountText="2 of 4">
12
+ <div>Step 2 Content</div>
13
+ </UDExTab>
14
+ <UDExTab text="Step 3" icon="add" itemCountText="3 of 4">
15
+ <div>Step 3 Content</div>
16
+ </UDExTab>
17
+ <UDExTab text="Step 4" icon="delete">
18
+ <div>Step 4 Content</div>
19
+ </UDExTab>
20
+ </UDExTabNavigation>
21
+ );
22
+
4
23
  // Test fixtures
5
24
  const verticalTabNavigation = (
6
25
  <UDExTabNavigation orientation="Vertical" id="verticalTabNav">
@@ -167,20 +186,28 @@ describe("Tab Navigation component", () => {
167
186
  * that don't work reliably in the component test environment. The overflow logic
168
187
  * triggers when tab widths exceed the container width, but in isolated component tests
169
188
  * the dimensions aren't calculated the same way as in a full page context.
170
- *
171
- * The original WebDriver.io tests (TabNavigation.spec.js) that run in full page context
172
- * successfully test the overflow behavior including:
173
- * - More button visibility
174
- * - Dropdown opening/closing
175
- * - Keyboard navigation in dropdown (Arrow keys, Home, End, Enter, Escape, Tab, Shift+Tab)
176
- *
177
- * These tests remain in the WebDriver.io suite and provide coverage for overflow functionality.
189
+ *
190
+ * When implementing overflow tests in the future, note that the More button is now a
191
+ * <udex-button class="udex-tab-navigation__button-more"> (not a native <button>).
192
+ * Key assertions should use:
193
+ * - selector: `.udex-tab-navigation__button-more` (class-only, works for udex-button)
194
+ * - visibility: the element's `hidden` attribute controls show/hide
195
+ * - toggled state: check the `toggled` boolean property/attribute on the udex-button
196
+ * element (not a CSS class like `udex-tab-navigation__button-more--toggled`, which
197
+ * was removed when the button was converted to udex-button)
198
+ * - design/size: assert `design="Tertiary"` and `size="Medium"` on the udex-button
199
+ * - icon: the down-arrow icon is now supplied via the `end-icon` prop on udex-button,
200
+ * not a separate `.udex-tab-navigation__button-more-icon` element (which was removed)
201
+ *
202
+ * Overflow behaviour is covered by the WebDriver.io fixture in test/pages/tab-navigation.html
203
+ * (the #tab-navigation-overflow element with 20 tabs). WebdriverIO specs for overflow have
204
+ * not yet been written; when added they should live in test/specs/TabNavigation.spec.js.
178
205
  */
179
- describe.skip("Horizontal Tabs - Overflow Behavior (tested in WebDriver.io)", () => {
206
+ describe.skip("Horizontal Tabs - Overflow Behavior", () => {
180
207
  // Tests skipped - see note above
181
208
  });
182
209
 
183
- describe.skip("Overflow Tabs - Accessibility Keyboard Navigation (tested in WebDriver.io)", () => {
210
+ describe.skip("Overflow Tabs - Accessibility Keyboard Navigation", () => {
184
211
  // Tests skipped - see note above
185
212
  });
186
213
 
@@ -1585,4 +1612,398 @@ describe("Tab Navigation component", () => {
1585
1612
  .should("contain.text", "Tab 10");
1586
1613
  });
1587
1614
  });
1615
+
1616
+ // ── Process Tab variant ──────────────────────────────────────────────────────
1617
+
1618
+ describe("TabNavigation - Process Tab variant", () => {
1619
+ describe("Propagation of _isProcessTab", () => {
1620
+ it("sets the process-tab attribute on the host when processTab is true", () => {
1621
+ cy.mount(processTabNavigation);
1622
+
1623
+ cy.get("[udex-tab-navigation]")
1624
+ .should("have.attr", "process-tab");
1625
+ });
1626
+
1627
+ it("applies .udex-tab-navigation__button-tab--process class to every tab button when processTab is active", () => {
1628
+ cy.mount(processTabNavigation);
1629
+
1630
+ cy.get("[udex-tab-navigation]")
1631
+ .shadow()
1632
+ .find("button[role='tab']")
1633
+ .should("have.length", 4)
1634
+ .each($btn => {
1635
+ cy.wrap($btn).should("have.class", "udex-tab-navigation__button-tab--process");
1636
+ });
1637
+ });
1638
+
1639
+ it("does NOT apply .udex-tab-navigation__button-tab--process when processTab is false", () => {
1640
+ cy.mount(
1641
+ <UDExTabNavigation>
1642
+ <UDExTab text="Tab 1" selected><div>Content 1</div></UDExTab>
1643
+ <UDExTab text="Tab 2"><div>Content 2</div></UDExTab>
1644
+ </UDExTabNavigation>
1645
+ );
1646
+
1647
+ cy.get("[udex-tab-navigation]")
1648
+ .shadow()
1649
+ .find("button[role='tab']")
1650
+ .should("not.have.class", "udex-tab-navigation__button-tab--process");
1651
+ });
1652
+ });
1653
+
1654
+ describe("Text block wrapper rendering", () => {
1655
+ it("wraps label in .udex-tab-navigation__button-text-block when processTab is active", () => {
1656
+ cy.mount(processTabNavigation);
1657
+
1658
+ cy.get("[udex-tab-navigation]")
1659
+ .shadow()
1660
+ .find("button[role='tab']")
1661
+ .each($btn => {
1662
+ cy.wrap($btn).find(".udex-tab-navigation__button-text-block").should("exist");
1663
+ });
1664
+ });
1665
+
1666
+ it("does NOT render .udex-tab-navigation__button-text-block when processTab is false", () => {
1667
+ cy.mount(
1668
+ <UDExTabNavigation>
1669
+ <UDExTab text="Tab 1" selected><div>Content 1</div></UDExTab>
1670
+ <UDExTab text="Tab 2"><div>Content 2</div></UDExTab>
1671
+ </UDExTabNavigation>
1672
+ );
1673
+
1674
+ cy.get("[udex-tab-navigation]")
1675
+ .shadow()
1676
+ .find(".udex-tab-navigation__button-text-block")
1677
+ .should("not.exist");
1678
+ });
1679
+ });
1680
+
1681
+ describe("Item count text rendering", () => {
1682
+ it("renders .udex-tab-navigation__button-item-count inside the text block when itemCountText is set", () => {
1683
+ cy.mount(processTabNavigation);
1684
+
1685
+ // First three tabs have itemCountText set
1686
+ cy.get("[udex-tab-navigation]")
1687
+ .shadow()
1688
+ .find("button[role='tab']")
1689
+ .eq(0)
1690
+ .find(".udex-tab-navigation__button-text-block .udex-tab-navigation__button-item-count")
1691
+ .should("exist")
1692
+ .and("have.text", "1 of 4");
1693
+
1694
+ cy.get("[udex-tab-navigation]")
1695
+ .shadow()
1696
+ .find("button[role='tab']")
1697
+ .eq(1)
1698
+ .find(".udex-tab-navigation__button-item-count")
1699
+ .should("have.text", "2 of 4");
1700
+
1701
+ cy.get("[udex-tab-navigation]")
1702
+ .shadow()
1703
+ .find("button[role='tab']")
1704
+ .eq(2)
1705
+ .find(".udex-tab-navigation__button-item-count")
1706
+ .should("have.text", "3 of 4");
1707
+ });
1708
+
1709
+ // Updated: item count span is now always rendered for process tabs; tabs without
1710
+ // itemCountText show "0" via effectiveItemCountText (hasItemCountText no longer drives rendering).
1711
+ it("renders .udex-tab-navigation__button-item-count with text '0' when itemCountText is absent but processTab is active", () => {
1712
+ cy.mount(processTabNavigation);
1713
+
1714
+ // Fourth tab has no itemCountText — count span must exist and read "0"
1715
+ cy.get("[udex-tab-navigation]")
1716
+ .shadow()
1717
+ .find("button[role='tab']")
1718
+ .eq(3)
1719
+ .find(".udex-tab-navigation__button-item-count")
1720
+ .should("exist")
1721
+ .and("have.text", "0");
1722
+
1723
+ // .udex-tab-navigation__button-text-block must still be present
1724
+ cy.get("[udex-tab-navigation]")
1725
+ .shadow()
1726
+ .find("button[role='tab']")
1727
+ .eq(3)
1728
+ .find(".udex-tab-navigation__button-text-block")
1729
+ .should("exist");
1730
+ });
1731
+
1732
+ it("does NOT render .udex-tab-navigation__button-item-count when processTab is false even if itemCountText is set", () => {
1733
+ cy.mount(
1734
+ <UDExTabNavigation>
1735
+ <UDExTab text="Tab 1" itemCountText="70 of 123" selected>
1736
+ <div>Content 1</div>
1737
+ </UDExTab>
1738
+ <UDExTab text="Tab 2" itemCountText="50 of 123">
1739
+ <div>Content 2</div>
1740
+ </UDExTab>
1741
+ </UDExTabNavigation>
1742
+ );
1743
+
1744
+ cy.get("[udex-tab-navigation]")
1745
+ .shadow()
1746
+ .find(".udex-tab-navigation__button-item-count")
1747
+ .should("not.exist");
1748
+ });
1749
+
1750
+ it("item count text is inside the text block, which is inside the tab button", () => {
1751
+ cy.mount(processTabNavigation);
1752
+
1753
+ cy.get("[udex-tab-navigation]")
1754
+ .shadow()
1755
+ .find("button[role='tab']")
1756
+ .eq(0)
1757
+ .within(() => {
1758
+ cy.get(".udex-tab-navigation__button-text-block").within(() => {
1759
+ cy.get(".udex-tab-navigation__button-item-count").should("have.text", "1 of 4");
1760
+ cy.get(".udex-tab-navigation__button-text").should("contain.text", "Step 1");
1761
+ });
1762
+ });
1763
+ });
1764
+ });
1765
+
1766
+ describe("Tab label rendering inside text block", () => {
1767
+ it("renders the tab label inside .udex-tab-navigation__button-text-block in process tab mode", () => {
1768
+ cy.mount(processTabNavigation);
1769
+
1770
+ cy.get("[udex-tab-navigation]")
1771
+ .shadow()
1772
+ .find("button[role='tab']")
1773
+ .each(($btn, i) => {
1774
+ cy.wrap($btn)
1775
+ .find(".udex-tab-navigation__button-text-block .udex-tab-navigation__button-text")
1776
+ .should("contain.text", `Step ${i + 1}`);
1777
+ });
1778
+ });
1779
+ });
1780
+
1781
+ describe("Tab selection in process tab variant", () => {
1782
+ beforeEach(() => {
1783
+ cy.mount(processTabNavigation);
1784
+ });
1785
+
1786
+ it("first tab is selected by default", () => {
1787
+ cy.get("[udex-tab-navigation]")
1788
+ .shadow()
1789
+ .find("button[role='tab'][aria-selected='true']")
1790
+ .should("contain.text", "Step 1");
1791
+ });
1792
+
1793
+ it("clicking a process tab selects it and updates aria-selected", () => {
1794
+ cy.get("[udex-tab-navigation]")
1795
+ .shadow()
1796
+ .find("button[role='tab']")
1797
+ .eq(1)
1798
+ .click();
1799
+
1800
+ cy.get("[udex-tab-navigation]")
1801
+ .shadow()
1802
+ .find("button[role='tab']")
1803
+ .eq(1)
1804
+ .should("have.attr", "aria-selected", "true")
1805
+ .and("have.class", "udex-tab-navigation__button-tab--active");
1806
+
1807
+ cy.get("[udex-tab-navigation]")
1808
+ .shadow()
1809
+ .find("button[role='tab']")
1810
+ .eq(0)
1811
+ .should("have.attr", "aria-selected", "false");
1812
+ });
1813
+
1814
+ it("selected process tab retains .udex-tab-navigation__button-tab--process class", () => {
1815
+ cy.get("[udex-tab-navigation]")
1816
+ .shadow()
1817
+ .find("button[role='tab']")
1818
+ .eq(2)
1819
+ .click();
1820
+
1821
+ cy.get("[udex-tab-navigation]")
1822
+ .shadow()
1823
+ .find("button[role='tab'][aria-selected='true']")
1824
+ .should("have.class", "udex-tab-navigation__button-tab--process");
1825
+ });
1826
+
1827
+ it("fires tab-select event when a process tab is clicked", () => {
1828
+ const tabSelectHandler = cy.stub().as("tabSelect");
1829
+
1830
+ cy.mount(
1831
+ <UDExTabNavigation processTab onTabSelect={tabSelectHandler}>
1832
+ <UDExTab text="Step 1" icon="home" itemCountText="1 of 2" selected>
1833
+ <div>Content 1</div>
1834
+ </UDExTab>
1835
+ <UDExTab text="Step 2" icon="action" itemCountText="2 of 2">
1836
+ <div>Content 2</div>
1837
+ </UDExTab>
1838
+ </UDExTabNavigation>
1839
+ );
1840
+
1841
+ cy.get("[udex-tab-navigation]")
1842
+ .shadow()
1843
+ .find("button[role='tab']")
1844
+ .eq(1)
1845
+ .click();
1846
+
1847
+ cy.get("@tabSelect").should("have.been.called");
1848
+ });
1849
+ });
1850
+
1851
+ describe("Keyboard navigation in process tab variant", () => {
1852
+ beforeEach(() => {
1853
+ cy.mount(processTabNavigation);
1854
+ });
1855
+
1856
+ it("navigates to next process tab with ArrowRight key", () => {
1857
+ cy.get("[udex-tab-navigation]")
1858
+ .shadow()
1859
+ .find("button[role='tab']")
1860
+ .eq(0)
1861
+ .focus()
1862
+ .realPress("ArrowRight");
1863
+
1864
+ cy.get("[udex-tab-navigation]")
1865
+ .shadow()
1866
+ .find("button[role='tab']")
1867
+ .eq(1)
1868
+ .should("be.focused");
1869
+ });
1870
+
1871
+ it("navigates to previous process tab with ArrowLeft key", () => {
1872
+ cy.get("[udex-tab-navigation]")
1873
+ .shadow()
1874
+ .find("button[role='tab']")
1875
+ .eq(2)
1876
+ .focus()
1877
+ .realPress("ArrowLeft");
1878
+
1879
+ cy.get("[udex-tab-navigation]")
1880
+ .shadow()
1881
+ .find("button[role='tab']")
1882
+ .eq(1)
1883
+ .should("be.focused");
1884
+ });
1885
+
1886
+ it("activates a process tab with Enter key", () => {
1887
+ cy.get("[udex-tab-navigation]")
1888
+ .shadow()
1889
+ .find("button[role='tab']")
1890
+ .eq(1)
1891
+ .focus()
1892
+ .realPress("Enter");
1893
+
1894
+ cy.get("[udex-tab-navigation]")
1895
+ .shadow()
1896
+ .find("button[role='tab']")
1897
+ .eq(1)
1898
+ .should("have.attr", "aria-selected", "true");
1899
+ });
1900
+
1901
+ it("activates a process tab with Space key", () => {
1902
+ cy.get("[udex-tab-navigation]")
1903
+ .shadow()
1904
+ .find("button[role='tab']")
1905
+ .eq(2)
1906
+ .focus()
1907
+ .realPress("Space");
1908
+
1909
+ cy.get("[udex-tab-navigation]")
1910
+ .shadow()
1911
+ .find("button[role='tab']")
1912
+ .eq(2)
1913
+ .should("have.attr", "aria-selected", "true");
1914
+ });
1915
+
1916
+ it("moves focus to first tab with Home key", () => {
1917
+ cy.get("[udex-tab-navigation]")
1918
+ .shadow()
1919
+ .find("button[role='tab']")
1920
+ .eq(3)
1921
+ .focus()
1922
+ .realPress("Home");
1923
+
1924
+ cy.get("[udex-tab-navigation]")
1925
+ .shadow()
1926
+ .find("button[role='tab']")
1927
+ .eq(0)
1928
+ .should("be.focused");
1929
+ });
1930
+
1931
+ it("moves focus to last tab with End key", () => {
1932
+ cy.get("[udex-tab-navigation]")
1933
+ .shadow()
1934
+ .find("button[role='tab']")
1935
+ .eq(0)
1936
+ .focus()
1937
+ .realPress("End");
1938
+
1939
+ cy.get("[udex-tab-navigation]")
1940
+ .shadow()
1941
+ .find("button[role='tab']")
1942
+ .eq(3)
1943
+ .should("be.focused");
1944
+ });
1945
+ });
1946
+
1947
+ describe("Accessibility - process tab variant", () => {
1948
+ beforeEach(() => {
1949
+ cy.mount(processTabNavigation);
1950
+ });
1951
+
1952
+ it("every process tab button has role=tab", () => {
1953
+ cy.get("[udex-tab-navigation]")
1954
+ .shadow()
1955
+ .find("button[role='tab']")
1956
+ .should("have.length", 4);
1957
+ });
1958
+
1959
+ it("tablist has correct ARIA orientation for horizontal process tabs", () => {
1960
+ cy.get("[udex-tab-navigation]")
1961
+ .shadow()
1962
+ .find("[role='tablist']")
1963
+ .should("have.attr", "aria-orientation", "horizontal");
1964
+ });
1965
+
1966
+ it("selected process tab has tabindex 0, others have tabindex -1", () => {
1967
+ cy.get("[udex-tab-navigation]")
1968
+ .shadow()
1969
+ .find("button[role='tab'][aria-selected='true']")
1970
+ .should("have.attr", "tabindex", "0");
1971
+
1972
+ cy.get("[udex-tab-navigation]")
1973
+ .shadow()
1974
+ .find("button[role='tab'][aria-selected='false']")
1975
+ .each($btn => {
1976
+ cy.wrap($btn).should("have.attr", "tabindex", "-1");
1977
+ });
1978
+ });
1979
+
1980
+ it("process tab button has aria-controls pointing to the tab panel", () => {
1981
+ cy.get("[udex-tab-navigation]")
1982
+ .shadow()
1983
+ .find("button[role='tab']")
1984
+ .each($btn => {
1985
+ cy.wrap($btn).should("have.attr", "aria-controls");
1986
+ });
1987
+ });
1988
+
1989
+ it("item count text is inside the button so screen readers read it as part of the tab label", () => {
1990
+ // .udex-tab-navigation__button-item-count must be a descendant of button[role='tab'],
1991
+ // ensuring it is included in the accessible name computation.
1992
+ cy.get("[udex-tab-navigation]")
1993
+ .shadow()
1994
+ .find("button[role='tab']")
1995
+ .eq(0)
1996
+ .find(".udex-tab-navigation__button-item-count")
1997
+ .should("exist");
1998
+ });
1999
+
2000
+ it("process tab buttons are focusable", () => {
2001
+ cy.get("[udex-tab-navigation]")
2002
+ .shadow()
2003
+ .find("button[role='tab'][aria-selected='true']")
2004
+ .focus()
2005
+ .should("be.focused");
2006
+ });
2007
+ });
2008
+ });
1588
2009
  });
@@ -34,8 +34,13 @@ import UDExLinkListItem from "../../instrumented/LinkListItem.js";
34
34
  import UDExList from "../../instrumented/List.js";
35
35
  import UDExListGroupHeader from "../../instrumented/ListGroupHeader.js";
36
36
  import UDExListItem from "../../instrumented/ListItem.js";
37
+ import UDExMastheadItem from "../../instrumented/MastheadItem.js";
38
+ import UDExMastheadMenu from "../../instrumented/MastheadMenu.js";
39
+ import UDExMastheadMobileMenu from "../../instrumented/MastheadMobileMenu.js";
37
40
  import UDExMastheadProfileMenu from "../../instrumented/MastheadProfileMenu.js";
41
+ import UDExMastheadShell from "../../instrumented/MastheadShell.js";
38
42
  import UDExMessageStrip from "../../instrumented/MessageStrip.js";
43
+ import UDExSearch from "../../instrumented/Search.js";
39
44
  import UDExMediaPlayer from "../../instrumented/MediaPlayer.js";
40
45
  import UDExPasswordField from "../../instrumented/PasswordField.js";
41
46
  import UDExPhoneNumberField from "../../instrumented/PhoneNumberField.js";
@@ -56,6 +61,8 @@ import UDExStatusBadge from "../../instrumented/StatusBadge.js";
56
61
  import UDExStatusMessage from "../../instrumented/StatusMessage.js";
57
62
  import UDExStepInput from "../../instrumented/StepInput.js";
58
63
  import UDExSwitch from "../../instrumented/Switch.js";
64
+ import UDExTab from "../../instrumented/Tab.js";
65
+ import UDExTabNavigation from "../../instrumented/TabNavigation.js";
59
66
  import UDExTable from "../../instrumented/Table.js";
60
67
  import UDExTableCell from "../../instrumented/TableCell.js";
61
68
  import UDExTableGroupRow from "../../instrumented/TableGroupRow.js";
@@ -111,9 +118,14 @@ export {
111
118
  UDExList,
112
119
  UDExListItem,
113
120
  UDExListGroupHeader,
121
+ UDExMastheadItem,
122
+ UDExMastheadMenu,
123
+ UDExMastheadMobileMenu,
114
124
  UDExMastheadProfileMenu,
125
+ UDExMastheadShell,
115
126
  UDExMessageStrip,
116
127
  UDExMediaPlayer,
128
+ UDExSearch,
117
129
  UDExPasswordField,
118
130
  UDExPhoneNumberField,
119
131
  UDExPromoTile,
@@ -133,6 +145,8 @@ export {
133
145
  UDExStatusMessage,
134
146
  UDExStepInput,
135
147
  UDExSwitch,
148
+ UDExTab,
149
+ UDExTabNavigation,
136
150
  UDExTable,
137
151
  UDExTableCell,
138
152
  UDExTableGroupRow,
@@ -34,8 +34,13 @@ import UDExLinkListItem from "../../src/LinkListItem.js";
34
34
  import UDExList from "../../src/List.js";
35
35
  import UDExListGroupHeader from "../../src/ListGroupHeader.js";
36
36
  import UDExListItem from "../../src/ListItem.js";
37
+ import UDExMastheadItem from "../../src/MastheadItem.js";
38
+ import UDExMastheadMenu from "../../src/MastheadMenu.js";
39
+ import UDExMastheadMobileMenu from "../../src/MastheadMobileMenu.js";
37
40
  import UDExMastheadProfileMenu from "../../src/MastheadProfileMenu.js";
41
+ import UDExMastheadShell from "../../src/MastheadShell.js";
38
42
  import UDExMessageStrip from "../../src/MessageStrip.js";
43
+ import UDExSearch from "../../src/Search.js";
39
44
  import UDExMediaPlayer from "../../src/MediaPlayer.js";
40
45
  import UDExPasswordField from "../../src/PasswordField.js";
41
46
  import UDExPhoneNumberField from "../../src/PhoneNumberField.js";
@@ -113,9 +118,14 @@ export {
113
118
  UDExList,
114
119
  UDExListItem,
115
120
  UDExListGroupHeader,
121
+ UDExMastheadItem,
122
+ UDExMastheadMenu,
123
+ UDExMastheadMobileMenu,
116
124
  UDExMastheadProfileMenu,
125
+ UDExMastheadShell,
117
126
  UDExMessageStrip,
118
127
  UDExMediaPlayer,
128
+ UDExSearch,
119
129
  UDExPasswordField,
120
130
  UDExPhoneNumberField,
121
131
  UDExPromoTile,
@@ -6,6 +6,7 @@ import "@ui5/webcomponents-icons/dist/home.js";
6
6
  import UDExBreadcrumbsItem from "./BreadcrumbsItem.js";
7
7
  import UDExDropdown from "./Dropdown.js";
8
8
  import UDExLink from "./Link.js";
9
+ import type { AccessibilityAttributes } from "@ui5/webcomponents-base/dist/types.js";
9
10
  type UDExBreadcrumbsItemClickEventDetail = {
10
11
  item: UDExBreadcrumbsItem;
11
12
  altKey?: boolean;
@@ -48,6 +49,15 @@ declare class UDExBreadcrumbs extends UI5Element {
48
49
  * @public
49
50
  */
50
51
  showItems: number;
52
+ /**
53
+ * Defines whether the current page item is displayed in the main navigation path.
54
+ * When set to `true`, the current page is shown as a non-interactive label at the end of the breadcrumb trail.
55
+ * By default, the current page is hidden from the main path and only visible in the dropdown.
56
+ *
57
+ * @default false
58
+ * @public
59
+ */
60
+ showCurrentPage: boolean;
51
61
  /**
52
62
  * Indicates if dropdown is opened
53
63
  *
@@ -97,10 +107,12 @@ declare class UDExBreadcrumbs extends UI5Element {
97
107
  get _linksData(): Array<UDExBreadcrumbsItem>;
98
108
  get _visibleItems(): Array<UDExBreadcrumbsItem>;
99
109
  get _dropdownItems(): Array<UDExBreadcrumbsItem>;
110
+ get _triggerAccessibilityAttributes(): Pick<AccessibilityAttributes, "hasPopup" | "expanded">;
100
111
  get _triggerClass(): string;
101
112
  get _breadcrumbsAccessibleNameText(): string;
102
113
  get _dropdownArrowAccessibleNameText(): string;
103
114
  get _dropdownAccessibleNameText(): string;
115
+ get _ofText(): string;
104
116
  }
105
117
  export default UDExBreadcrumbs;
106
118
  export type { UDExBreadcrumbsItemClickEventDetail };
@@ -11,7 +11,7 @@ import jsxRenderer from "@ui5/webcomponents-base/renderer/JsxRenderer.js";
11
11
  import property from "@ui5/webcomponents-base/dist/decorators/property.js";
12
12
  import slot from "@ui5/webcomponents-base/dist/decorators/slot.js";
13
13
  import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js";
14
- import { isTabNext, isTabPrevious, isEscape } from "@ui5/webcomponents-base/dist/Keys.js";
14
+ import { isTabNext, isTabPrevious } from "@ui5/webcomponents-base/dist/Keys.js";
15
15
  import UI5Icon from "@ui5/webcomponents/dist/Icon.js";
16
16
  import i18n from "@ui5/webcomponents-base/dist/decorators/i18n.js";
17
17
  import UI5BreadcrumbsCss from "@ui5/webcomponents/dist/generated/themes/Breadcrumbs.css.js";
@@ -21,7 +21,7 @@ import BreadcrumbsTemplate from "./BreadcrumbsTemplate.js";
21
21
  import UDExBreadcrumbsItem from "./BreadcrumbsItem.js";
22
22
  import UDExDropdown from "./Dropdown.js";
23
23
  import UDExLink from "./Link.js";
24
- import { AVAILABLE_VALUES, BREADCRUMBS_ARIA_LABEL, BREADCRUMBS_OVERFLOW_ARIA_LABEL, } from "./generated/i18n/i18n-defaults.js";
24
+ import { AVAILABLE_VALUES, BREADCRUMBS_ARIA_LABEL, BREADCRUMBS_OVERFLOW_ARIA_LABEL, OF, } from "./generated/i18n/i18n-defaults.js";
25
25
  import translate from "./utils/translate.js";
26
26
  // Styles
27
27
  import BreadcrumbsCss from "./generated/themes/Breadcrumbs.css.js";
@@ -58,6 +58,22 @@ let UDExBreadcrumbs = UDExBreadcrumbs_1 = class UDExBreadcrumbs extends UI5Eleme
58
58
  * @public
59
59
  */
60
60
  this.showItems = 3;
61
+ /**
62
+ * Defines whether the current page item is displayed in the main navigation path.
63
+ * When set to `true`, the current page is shown as a non-interactive label at the end of the breadcrumb trail.
64
+ * By default, the current page is hidden from the main path and only visible in the dropdown.
65
+ *
66
+ * @default false
67
+ * @public
68
+ */
69
+ this.showCurrentPage = false;
70
+ /**
71
+ * Indicates if dropdown is opened
72
+ *
73
+ * @default false
74
+ * @private
75
+ */
76
+ this._dropdownOpened = false;
61
77
  this._rootClass = "udex-breadcrumbs";
62
78
  }
63
79
  onBeforeRendering() {
@@ -143,10 +159,6 @@ let UDExBreadcrumbs = UDExBreadcrumbs_1 = class UDExBreadcrumbs extends UI5Eleme
143
159
  e.preventDefault();
144
160
  this._dropdownArrowLink.focus();
145
161
  this._toggleDropdown();
146
- return;
147
- }
148
- if (isEscape(e)) {
149
- this._toggleDropdown();
150
162
  }
151
163
  }
152
164
  _handleOutsideClick() {
@@ -196,6 +208,12 @@ let UDExBreadcrumbs = UDExBreadcrumbs_1 = class UDExBreadcrumbs extends UI5Eleme
196
208
  get _dropdownItems() {
197
209
  return this._getItems().filter(i => this._isItemVisible(i));
198
210
  }
211
+ get _triggerAccessibilityAttributes() {
212
+ return {
213
+ hasPopup: "listbox",
214
+ expanded: this._dropdownOpened ? "true" : "false",
215
+ };
216
+ }
199
217
  get _triggerClass() {
200
218
  const rootClass = "udex-breadcrumbs";
201
219
  return this._dropdownOpened ? `${rootClass} ${rootClass}__trigger--opened` : rootClass;
@@ -209,10 +227,16 @@ let UDExBreadcrumbs = UDExBreadcrumbs_1 = class UDExBreadcrumbs extends UI5Eleme
209
227
  get _dropdownAccessibleNameText() {
210
228
  return translate(UDExBreadcrumbs_1, AVAILABLE_VALUES);
211
229
  }
230
+ get _ofText() {
231
+ return translate(UDExBreadcrumbs_1, OF);
232
+ }
212
233
  };
213
234
  __decorate([
214
235
  property({ type: Number })
215
236
  ], UDExBreadcrumbs.prototype, "showItems", void 0);
237
+ __decorate([
238
+ property({ type: Boolean })
239
+ ], UDExBreadcrumbs.prototype, "showCurrentPage", void 0);
216
240
  __decorate([
217
241
  property({ noAttribute: true, type: Boolean })
218
242
  ], UDExBreadcrumbs.prototype, "_dropdownOpened", void 0);