@sapudex/web-components 2.30.0 → 2.32.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 (215) hide show
  1. package/cypress/specs/Breadcrumbs.cy.tsx +26 -0
  2. package/cypress/specs/ListItem.cy.tsx +22 -26
  3. package/cypress/specs/MediaPlayer.cy.tsx +209 -0
  4. package/cypress/specs/PromoTile.cy.tsx +10 -0
  5. package/cypress/specs/SecondaryNavigationDesktop.cy.tsx +74 -21
  6. package/cypress/specs/SecondaryNavigationMobile.cy.tsx +58 -1
  7. package/cypress/specs/SelectBox.cy.tsx +76 -0
  8. package/cypress/specs/TabNavigation.cy.tsx +603 -39
  9. package/cypress/support/component-imports.instrumented.ts +2 -0
  10. package/cypress/support/component-imports.src.ts +2 -0
  11. package/dist/Breadcrumbs.d.ts +5 -4
  12. package/dist/Breadcrumbs.js +15 -17
  13. package/dist/Breadcrumbs.js.map +1 -1
  14. package/dist/BreadcrumbsTemplate.js +1 -1
  15. package/dist/BreadcrumbsTemplate.js.map +1 -1
  16. package/dist/List.js +3 -3
  17. package/dist/List.js.map +1 -1
  18. package/dist/ListItemBase.d.ts +0 -2
  19. package/dist/ListItemBase.js +0 -6
  20. package/dist/ListItemBase.js.map +1 -1
  21. package/dist/MastheadCountrySelector.d.ts +3 -15
  22. package/dist/MastheadCountrySelector.js +28 -72
  23. package/dist/MastheadCountrySelector.js.map +1 -1
  24. package/dist/MastheadItem.d.ts +1 -0
  25. package/dist/MastheadItem.js +12 -4
  26. package/dist/MastheadItem.js.map +1 -1
  27. package/dist/MastheadMenuItem.d.ts +7 -0
  28. package/dist/MastheadMenuItem.js +3 -0
  29. package/dist/MastheadMenuItem.js.map +1 -1
  30. package/dist/MastheadMobileMenu.d.ts +2 -12
  31. package/dist/MastheadMobileMenu.js +31 -116
  32. package/dist/MastheadMobileMenu.js.map +1 -1
  33. package/dist/MastheadProfileMenu.js +1 -1
  34. package/dist/MastheadProfileMenu.js.map +1 -1
  35. package/dist/MastheadShell.d.ts +1 -6
  36. package/dist/MastheadShell.js +7 -44
  37. package/dist/MastheadShell.js.map +1 -1
  38. package/dist/MediaPlayer.d.ts +15 -0
  39. package/dist/MediaPlayer.js +28 -0
  40. package/dist/MediaPlayer.js.map +1 -1
  41. package/dist/Pagination.d.ts +14 -1
  42. package/dist/Pagination.js +39 -6
  43. package/dist/Pagination.js.map +1 -1
  44. package/dist/PromoTile.d.ts +8 -0
  45. package/dist/PromoTile.js +4 -0
  46. package/dist/PromoTile.js.map +1 -1
  47. package/dist/PromoTileTemplate.js +3 -1
  48. package/dist/PromoTileTemplate.js.map +1 -1
  49. package/dist/SecondaryNavigation.d.ts +12 -2
  50. package/dist/SecondaryNavigation.js +59 -8
  51. package/dist/SecondaryNavigation.js.map +1 -1
  52. package/dist/SecondaryNavigationItem.d.ts +0 -1
  53. package/dist/SecondaryNavigationItem.js +7 -5
  54. package/dist/SecondaryNavigationItem.js.map +1 -1
  55. package/dist/SecondaryNavigationSubItem.js +1 -1
  56. package/dist/SecondaryNavigationSubItem.js.map +1 -1
  57. package/dist/SelectBase.js +28 -7
  58. package/dist/SelectBase.js.map +1 -1
  59. package/dist/Tab.d.ts +1 -1
  60. package/dist/Tab.js +3 -3
  61. package/dist/Tab.js.map +1 -1
  62. package/dist/TabNavigation.d.ts +64 -0
  63. package/dist/TabNavigation.js +124 -1
  64. package/dist/TabNavigation.js.map +1 -1
  65. package/dist/assets/{InputSuggestions-CaAXs3ok.js → InputSuggestions-CHLLTki3.js} +1 -1
  66. package/dist/assets/{ListItemStandardExpandableTextTemplate-CPqUBd--.js → ListItemStandardExpandableTextTemplate-vM1eIFe4.js} +1 -1
  67. package/dist/assets/{bundle.esm-L-7H6J4f.js → bundle.esm-fUZ1I3qm.js} +218 -218
  68. package/dist/assets/messagebundle_en-iNqRB1VZ.js +1 -0
  69. package/dist/css/themes/BreadcrumbsPopover.css +1 -1
  70. package/dist/css/themes/Dropdown.css +1 -1
  71. package/dist/css/themes/Link.css +1 -1
  72. package/dist/css/themes/ListGroupHeader.css +1 -1
  73. package/dist/css/themes/MastheadCountrySelector.css +1 -1
  74. package/dist/css/themes/MastheadItem.css +1 -1
  75. package/dist/css/themes/MastheadShell.css +1 -1
  76. package/dist/css/themes/RatingIndicator.css +1 -1
  77. package/dist/css/themes/SecondaryNavigation.css +1 -1
  78. package/dist/css/themes/SecondaryNavigationItem.css +1 -1
  79. package/dist/css/themes/SecondaryNavigationSubItem.css +1 -1
  80. package/dist/css/themes/Slider.css +1 -1
  81. package/dist/css/themes/TabNavigation.css +1 -1
  82. package/dist/custom-elements-internal.json +407 -167
  83. package/dist/custom-elements.json +320 -152
  84. package/dist/generated/assets/i18n/messagebundle_en.json +1 -1
  85. package/dist/generated/i18n/i18n-defaults.d.ts +2 -1
  86. package/dist/generated/i18n/i18n-defaults.js +3 -2
  87. package/dist/generated/i18n/i18n-defaults.js.map +1 -1
  88. package/dist/generated/templates/ListGroupHeaderTemplate.lit.js +12 -16
  89. package/dist/generated/templates/ListGroupHeaderTemplate.lit.js.map +1 -1
  90. package/dist/generated/templates/ListItemTemplate.lit.js +32 -36
  91. package/dist/generated/templates/ListItemTemplate.lit.js.map +1 -1
  92. package/dist/generated/templates/MastheadCountrySelectorTemplate.lit.js +3 -3
  93. package/dist/generated/templates/MastheadCountrySelectorTemplate.lit.js.map +1 -1
  94. package/dist/generated/templates/MastheadMenuItemTemplate.lit.js +1 -1
  95. package/dist/generated/templates/MastheadMenuItemTemplate.lit.js.map +1 -1
  96. package/dist/generated/templates/MastheadMobileMenuTemplate.lit.js +1 -1
  97. package/dist/generated/templates/MastheadMobileMenuTemplate.lit.js.map +1 -1
  98. package/dist/generated/templates/MastheadShellTemplate.lit.js +9 -10
  99. package/dist/generated/templates/MastheadShellTemplate.lit.js.map +1 -1
  100. package/dist/generated/templates/SecondaryNavigationTemplate.lit.js +1 -1
  101. package/dist/generated/templates/SecondaryNavigationTemplate.lit.js.map +1 -1
  102. package/dist/generated/templates/TabNavigationTemplate.lit.js +10 -8
  103. package/dist/generated/templates/TabNavigationTemplate.lit.js.map +1 -1
  104. package/dist/generated/themes/BreadcrumbsPopover.css.d.ts +1 -1
  105. package/dist/generated/themes/BreadcrumbsPopover.css.js +1 -1
  106. package/dist/generated/themes/BreadcrumbsPopover.css.js.map +1 -1
  107. package/dist/generated/themes/Dropdown.css.d.ts +1 -1
  108. package/dist/generated/themes/Dropdown.css.js +1 -1
  109. package/dist/generated/themes/Dropdown.css.js.map +1 -1
  110. package/dist/generated/themes/Link.css.d.ts +1 -1
  111. package/dist/generated/themes/Link.css.js +1 -1
  112. package/dist/generated/themes/Link.css.js.map +1 -1
  113. package/dist/generated/themes/ListGroupHeader.css.d.ts +1 -1
  114. package/dist/generated/themes/ListGroupHeader.css.js +1 -1
  115. package/dist/generated/themes/ListGroupHeader.css.js.map +1 -1
  116. package/dist/generated/themes/MastheadCountrySelector.css.d.ts +1 -1
  117. package/dist/generated/themes/MastheadCountrySelector.css.js +1 -1
  118. package/dist/generated/themes/MastheadCountrySelector.css.js.map +1 -1
  119. package/dist/generated/themes/MastheadItem.css.d.ts +1 -1
  120. package/dist/generated/themes/MastheadItem.css.js +1 -1
  121. package/dist/generated/themes/MastheadItem.css.js.map +1 -1
  122. package/dist/generated/themes/MastheadShell.css.d.ts +1 -1
  123. package/dist/generated/themes/MastheadShell.css.js +1 -1
  124. package/dist/generated/themes/MastheadShell.css.js.map +1 -1
  125. package/dist/generated/themes/RatingIndicator.css.d.ts +1 -1
  126. package/dist/generated/themes/RatingIndicator.css.js +1 -1
  127. package/dist/generated/themes/RatingIndicator.css.js.map +1 -1
  128. package/dist/generated/themes/SecondaryNavigation.css.d.ts +1 -1
  129. package/dist/generated/themes/SecondaryNavigation.css.js +1 -1
  130. package/dist/generated/themes/SecondaryNavigation.css.js.map +1 -1
  131. package/dist/generated/themes/SecondaryNavigationItem.css.d.ts +1 -1
  132. package/dist/generated/themes/SecondaryNavigationItem.css.js +1 -1
  133. package/dist/generated/themes/SecondaryNavigationItem.css.js.map +1 -1
  134. package/dist/generated/themes/SecondaryNavigationSubItem.css.d.ts +1 -1
  135. package/dist/generated/themes/SecondaryNavigationSubItem.css.js +1 -1
  136. package/dist/generated/themes/SecondaryNavigationSubItem.css.js.map +1 -1
  137. package/dist/generated/themes/Slider.css.d.ts +1 -1
  138. package/dist/generated/themes/Slider.css.js +1 -1
  139. package/dist/generated/themes/Slider.css.js.map +1 -1
  140. package/dist/generated/themes/TabNavigation.css.d.ts +1 -1
  141. package/dist/generated/themes/TabNavigation.css.js +1 -1
  142. package/dist/generated/themes/TabNavigation.css.js.map +1 -1
  143. package/dist/messagebundle.properties +4 -1
  144. package/dist/messagebundle_en.properties +2 -1
  145. package/dist/types/List.d.ts +0 -2
  146. package/dist/types/List.js +0 -2
  147. package/dist/types/List.js.map +1 -1
  148. package/dist/vscode.html-custom-data.json +45 -76
  149. package/dist/web-types.json +96 -76
  150. package/package.json +2 -1
  151. package/src/Breadcrumbs.ts +17 -21
  152. package/src/BreadcrumbsTemplate.tsx +1 -1
  153. package/src/List.ts +3 -3
  154. package/src/ListGroupHeader.hbs +7 -11
  155. package/src/ListItem.hbs +0 -2
  156. package/src/ListItemBase.ts +0 -8
  157. package/src/MastheadCountrySelector.hbs +5 -2
  158. package/src/MastheadCountrySelector.ts +31 -85
  159. package/src/MastheadItem.ts +13 -4
  160. package/src/MastheadMenuItem.hbs +1 -0
  161. package/src/MastheadMenuItem.ts +9 -0
  162. package/src/MastheadMobileMenu.hbs +0 -1
  163. package/src/MastheadMobileMenu.ts +34 -130
  164. package/src/MastheadProfileMenu.ts +1 -1
  165. package/src/MastheadShell.hbs +9 -11
  166. package/src/MastheadShell.ts +8 -50
  167. package/src/MediaPlayer.ts +35 -0
  168. package/src/Pagination.ts +51 -7
  169. package/src/PromoTile.ts +10 -0
  170. package/src/PromoTileTemplate.tsx +4 -1
  171. package/src/SecondaryNavigation.hbs +1 -0
  172. package/src/SecondaryNavigation.ts +77 -9
  173. package/src/SecondaryNavigationItem.ts +1 -8
  174. package/src/SecondaryNavigationSubItem.ts +1 -1
  175. package/src/SelectBase.ts +33 -7
  176. package/src/Tab.ts +4 -4
  177. package/src/TabNavigation.hbs +15 -0
  178. package/src/TabNavigation.ts +134 -1
  179. package/src/generated/i18n/i18n-defaults.ts +2 -2
  180. package/src/generated/templates/ListGroupHeaderTemplate.lit.ts +12 -16
  181. package/src/generated/templates/ListItemTemplate.lit.ts +32 -36
  182. package/src/generated/templates/MastheadCountrySelectorTemplate.lit.ts +3 -3
  183. package/src/generated/templates/MastheadMenuItemTemplate.lit.ts +1 -1
  184. package/src/generated/templates/MastheadMobileMenuTemplate.lit.ts +1 -1
  185. package/src/generated/templates/MastheadShellTemplate.lit.ts +9 -10
  186. package/src/generated/templates/SecondaryNavigationTemplate.lit.ts +1 -1
  187. package/src/generated/templates/TabNavigationTemplate.lit.ts +10 -8
  188. package/src/generated/themes/BreadcrumbsPopover.css.ts +1 -1
  189. package/src/generated/themes/Dropdown.css.ts +1 -1
  190. package/src/generated/themes/Link.css.ts +1 -1
  191. package/src/generated/themes/ListGroupHeader.css.ts +1 -1
  192. package/src/generated/themes/MastheadCountrySelector.css.ts +1 -1
  193. package/src/generated/themes/MastheadItem.css.ts +1 -1
  194. package/src/generated/themes/MastheadShell.css.ts +1 -1
  195. package/src/generated/themes/RatingIndicator.css.ts +1 -1
  196. package/src/generated/themes/SecondaryNavigation.css.ts +1 -1
  197. package/src/generated/themes/SecondaryNavigationItem.css.ts +1 -1
  198. package/src/generated/themes/SecondaryNavigationSubItem.css.ts +1 -1
  199. package/src/generated/themes/Slider.css.ts +1 -1
  200. package/src/generated/themes/TabNavigation.css.ts +1 -1
  201. package/src/i18n/messagebundle.properties +4 -1
  202. package/src/i18n/messagebundle_en.properties +2 -1
  203. package/src/themes/BreadcrumbsPopover.css +4 -2
  204. package/src/themes/Dropdown.css +5 -1
  205. package/src/themes/Link.css +2 -3
  206. package/src/themes/ListGroupHeader.css +3 -11
  207. package/src/themes/MastheadCountrySelector.css +2 -2
  208. package/src/themes/MastheadItem.css +57 -0
  209. package/src/themes/MastheadShell.css +0 -2
  210. package/src/themes/SecondaryNavigation.css +6 -3
  211. package/src/themes/SecondaryNavigationItem.css +11 -10
  212. package/src/themes/SecondaryNavigationSubItem.css +3 -2
  213. package/src/themes/TabNavigation.css +27 -16
  214. package/src/types/List.ts +0 -2
  215. package/dist/assets/messagebundle_en-J-MHTtdL.js +0 -1
@@ -1,4 +1,4 @@
1
- import UDExTabNavigation from "../../src/TabNavigation.js";
1
+ import UDExTabNavigation, { UDExTabNavigationOrientation, UDExTabNavigationPlacement, UDExTabNavigationVerticalAlignment } from "../../src/TabNavigation.js";
2
2
  import UDExTab from "../../src/Tab.js";
3
3
 
4
4
  // Test fixtures
@@ -725,9 +725,7 @@ describe("Tab Navigation component", () => {
725
725
  .should("not.exist");
726
726
  });
727
727
 
728
- it("does NOT show link slot in header for horizontal tabs", () => {
729
- // Note: The Tab component uses a `link` slot for adding links
730
- // In horizontal mode, even with bodyText, the wrapper and links should not be shown
728
+ it("does NOT show tab wrapper in header for horizontal tabs", () => {
731
729
  cy.mount(
732
730
  <UDExTabNavigation orientation="Horizontal">
733
731
  <UDExTab text="Settings" bodyText="Configure your preferences" selected>
@@ -739,12 +737,6 @@ describe("Tab Navigation component", () => {
739
737
  </UDExTabNavigation>
740
738
  );
741
739
 
742
- // Link container should NOT be visible in the header for horizontal tabs
743
- cy.get("[udex-tab-navigation]")
744
- .shadow()
745
- .find(".udex-tab-navigation__button-links")
746
- .should("not.exist");
747
-
748
740
  // Wrapper should NOT be used for horizontal tabs
749
741
  cy.get("[udex-tab-navigation]")
750
742
  .shadow()
@@ -804,35 +796,6 @@ describe("Tab Navigation component", () => {
804
796
  .should("have.length", 2);
805
797
  });
806
798
 
807
- it("shows link slot in header for vertical tabs with link elements", () => {
808
- // The Tab component uses a `link` slot for adding links in vertical mode
809
- // When link slot elements are provided, they should be rendered in the tab header
810
- cy.mount(
811
- <UDExTabNavigation orientation="Vertical">
812
- <UDExTab text="Settings" selected>
813
- <a slot="link" href="https://example.com">Learn more</a>
814
- <div>Settings content</div>
815
- </UDExTab>
816
- <UDExTab text="Account">
817
- <a slot="link" href="https://example.com">View details</a>
818
- <div>Account content</div>
819
- </UDExTab>
820
- </UDExTabNavigation>
821
- );
822
-
823
- // Wrapper should be used for vertical tabs with link slot
824
- cy.get("[udex-tab-navigation]")
825
- .shadow()
826
- .find(".udex-tab-navigation__tab-wrapper")
827
- .should("have.length", 2);
828
-
829
- // Link container should exist for tabs with link slot
830
- cy.get("[udex-tab-navigation]")
831
- .shadow()
832
- .find(".udex-tab-navigation__button-links")
833
- .should("have.length", 2);
834
- });
835
-
836
799
  it("displays body text content correctly for each vertical tab", () => {
837
800
  cy.mount(
838
801
  <UDExTabNavigation orientation="Vertical">
@@ -898,6 +861,605 @@ describe("Tab Navigation component", () => {
898
861
  });
899
862
  });
900
863
 
864
+ describe("TabNavigation - Vertical Placement", () => {
865
+ const verticalTabItems = (
866
+ <>
867
+ <UDExTab text="Settings" selected><div>Settings content</div></UDExTab>
868
+ <UDExTab text="Account"><div>Account content</div></UDExTab>
869
+ </>
870
+ );
871
+
872
+ it("renders header before content by default (Start placement)", () => {
873
+ cy.mount(
874
+ <UDExTabNavigation orientation={UDExTabNavigationOrientation.Vertical}>
875
+ {verticalTabItems}
876
+ </UDExTabNavigation>
877
+ );
878
+
879
+ cy.get("[udex-tab-navigation]").shadow().then($shadow => {
880
+ const header = $shadow[0].querySelector(".udex-tab-navigation__header") as HTMLElement;
881
+ const content = $shadow[0].querySelector(".udex-tab-navigation__content") as HTMLElement;
882
+ expect(header.getBoundingClientRect().left).to.be.lessThan(content.getBoundingClientRect().left);
883
+ });
884
+ });
885
+
886
+ it("renders header after content for End placement", () => {
887
+ cy.mount(
888
+ <UDExTabNavigation
889
+ orientation={UDExTabNavigationOrientation.Vertical}
890
+ placement={UDExTabNavigationPlacement.End}
891
+ >
892
+ {verticalTabItems}
893
+ </UDExTabNavigation>
894
+ );
895
+
896
+ cy.get("[udex-tab-navigation]").shadow().then($shadow => {
897
+ const header = $shadow[0].querySelector(".udex-tab-navigation__header") as HTMLElement;
898
+ const content = $shadow[0].querySelector(".udex-tab-navigation__content") as HTMLElement;
899
+ expect(header.getBoundingClientRect().left).to.be.greaterThan(content.getBoundingClientRect().left);
900
+ });
901
+ });
902
+
903
+ it("sets placement attribute on the host element", () => {
904
+ cy.mount(
905
+ <UDExTabNavigation
906
+ orientation={UDExTabNavigationOrientation.Vertical}
907
+ placement={UDExTabNavigationPlacement.End}
908
+ >
909
+ {verticalTabItems}
910
+ </UDExTabNavigation>
911
+ );
912
+
913
+ cy.get("[udex-tab-navigation]").should("have.attr", "placement", "End");
914
+ });
915
+
916
+ it("does not apply End placement in Horizontal orientation", () => {
917
+ cy.mount(
918
+ <UDExTabNavigation
919
+ orientation={UDExTabNavigationOrientation.Horizontal}
920
+ placement={UDExTabNavigationPlacement.End}
921
+ >
922
+ {verticalTabItems}
923
+ </UDExTabNavigation>
924
+ );
925
+
926
+ cy.get("[udex-tab-navigation]").shadow().then($shadow => {
927
+ const header = $shadow[0].querySelector(".udex-tab-navigation__header") as HTMLElement;
928
+ expect(getComputedStyle(header).order).to.equal("0");
929
+ });
930
+ });
931
+
932
+ it("tab switching works correctly with End placement", () => {
933
+ cy.mount(
934
+ <UDExTabNavigation
935
+ orientation={UDExTabNavigationOrientation.Vertical}
936
+ placement={UDExTabNavigationPlacement.End}
937
+ >
938
+ {verticalTabItems}
939
+ </UDExTabNavigation>
940
+ );
941
+
942
+ cy.get("[udex-tab-navigation]")
943
+ .shadow()
944
+ .find("button[role='tab']")
945
+ .contains("Account")
946
+ .click();
947
+
948
+ cy.get("[udex-tab-navigation]")
949
+ .shadow()
950
+ .find("button[role='tab'][aria-selected='true']")
951
+ .should("contain.text", "Account");
952
+ });
953
+ });
954
+
955
+ describe("TabNavigation - Footer slot", () => {
956
+ it("renders footer slot content below the tablist in Vertical orientation", () => {
957
+ cy.mount(
958
+ <UDExTabNavigation orientation={UDExTabNavigationOrientation.Vertical}>
959
+ <UDExTab text="Settings" selected><div>Settings content</div></UDExTab>
960
+ <UDExTab text="Account"><div>Account content</div></UDExTab>
961
+ <button slot="footer">Overview</button>
962
+ </UDExTabNavigation>
963
+ );
964
+
965
+ cy.get("[udex-tab-navigation]")
966
+ .shadow()
967
+ .find(".udex-tab-navigation__footer")
968
+ .should("exist");
969
+ });
970
+
971
+ it("does not render footer container when no footer slot content is provided", () => {
972
+ cy.mount(
973
+ <UDExTabNavigation orientation={UDExTabNavigationOrientation.Vertical}>
974
+ <UDExTab text="Settings" selected><div>Settings content</div></UDExTab>
975
+ <UDExTab text="Account"><div>Account content</div></UDExTab>
976
+ </UDExTabNavigation>
977
+ );
978
+
979
+ cy.get("[udex-tab-navigation]")
980
+ .shadow()
981
+ .find(".udex-tab-navigation__footer")
982
+ .should("not.exist");
983
+ });
984
+
985
+ it("footer is below the tablist in the DOM order", () => {
986
+ cy.mount(
987
+ <UDExTabNavigation orientation={UDExTabNavigationOrientation.Vertical}>
988
+ <UDExTab text="Settings" selected><div>Settings content</div></UDExTab>
989
+ <UDExTab text="Account"><div>Account content</div></UDExTab>
990
+ <button slot="footer">Overview</button>
991
+ </UDExTabNavigation>
992
+ );
993
+
994
+ cy.get("[udex-tab-navigation]").shadow().then($shadow => {
995
+ const tablist = $shadow[0].querySelector(".udex-tab-navigation__header-tabs") as HTMLElement;
996
+ const footer = $shadow[0].querySelector(".udex-tab-navigation__footer") as HTMLElement;
997
+ expect(tablist.getBoundingClientRect().bottom).to.be.lessThan(footer.getBoundingClientRect().top);
998
+ });
999
+ });
1000
+
1001
+ it("does not render footer slot for Horizontal orientation", () => {
1002
+ cy.mount(
1003
+ <UDExTabNavigation orientation={UDExTabNavigationOrientation.Horizontal}>
1004
+ <UDExTab text="Settings" selected><div>Settings content</div></UDExTab>
1005
+ <UDExTab text="Account"><div>Account content</div></UDExTab>
1006
+ <button slot="footer">Overview</button>
1007
+ </UDExTabNavigation>
1008
+ );
1009
+
1010
+ cy.get("[udex-tab-navigation]")
1011
+ .shadow()
1012
+ .find(".udex-tab-navigation__footer")
1013
+ .should("not.exist");
1014
+ });
1015
+ });
1016
+
1017
+ describe("TabNavigation - Link slot", () => {
1018
+ it("renders the links container inside the tab wrapper when link slot elements are provided in Vertical orientation", () => {
1019
+ cy.mount(
1020
+ <UDExTabNavigation orientation={UDExTabNavigationOrientation.Vertical}>
1021
+ <UDExTab text="Account" body-text="Privacy settings" selected>
1022
+ <udex-link slot="link" href="https://sap.com/" design="Default">Privacy Policy</udex-link>
1023
+ <div>Account content</div>
1024
+ </UDExTab>
1025
+ <UDExTab text="Settings">
1026
+ <div>Settings content</div>
1027
+ </UDExTab>
1028
+ </UDExTabNavigation>
1029
+ );
1030
+
1031
+ cy.get("[udex-tab-navigation]")
1032
+ .shadow()
1033
+ .find(".udex-tab-navigation__button-links")
1034
+ .should("exist");
1035
+ });
1036
+
1037
+ it("renders all slotted link elements inside the links container", () => {
1038
+ cy.mount(
1039
+ <UDExTabNavigation orientation={UDExTabNavigationOrientation.Vertical}>
1040
+ <UDExTab text="Account" selected>
1041
+ <udex-link slot="link" href="https://sap.com/privacy" design="Default">Privacy Policy</udex-link>
1042
+ <udex-link slot="link" href="https://sap.com/terms" design="Default">Terms of Service</udex-link>
1043
+ <div>Account content</div>
1044
+ </UDExTab>
1045
+ <UDExTab text="Settings">
1046
+ <div>Settings content</div>
1047
+ </UDExTab>
1048
+ </UDExTabNavigation>
1049
+ );
1050
+
1051
+ cy.get("[udex-tab-navigation]")
1052
+ .shadow()
1053
+ .find(".udex-tab-navigation__button-links udex-link")
1054
+ .should("have.length", 2);
1055
+ });
1056
+
1057
+ it("links container is hidden on a non-selected tab and visible on the selected tab", () => {
1058
+ cy.mount(
1059
+ <UDExTabNavigation orientation={UDExTabNavigationOrientation.Vertical}>
1060
+ <UDExTab text="Account" selected>
1061
+ <udex-link slot="link" href="https://sap.com/" design="Default">Privacy Policy</udex-link>
1062
+ <div>Account content</div>
1063
+ </UDExTab>
1064
+ <UDExTab text="Settings">
1065
+ <udex-link slot="link" href="https://sap.com/" design="Default">Terms of Service</udex-link>
1066
+ <div>Settings content</div>
1067
+ </UDExTab>
1068
+ </UDExTabNavigation>
1069
+ );
1070
+
1071
+ // Selected tab's links container must be visible (display: flex via CSS sibling rule)
1072
+ cy.get("[udex-tab-navigation]")
1073
+ .shadow()
1074
+ .find(".udex-tab-navigation__button-tab--active ~ .udex-tab-navigation__button-links")
1075
+ .should("have.css", "display", "flex");
1076
+
1077
+ // Non-selected tab's links container must be hidden (display: none)
1078
+ cy.get("[udex-tab-navigation]")
1079
+ .shadow()
1080
+ .find(".udex-tab-navigation__tab-wrapper")
1081
+ .not(":has(.udex-tab-navigation__button-tab--active)")
1082
+ .find(".udex-tab-navigation__button-links")
1083
+ .should("have.css", "display", "none");
1084
+ });
1085
+
1086
+ it("links container becomes visible after switching to a tab that has link slot elements", () => {
1087
+ cy.mount(
1088
+ <UDExTabNavigation orientation={UDExTabNavigationOrientation.Vertical}>
1089
+ <UDExTab text="Account" selected>
1090
+ <div>Account content</div>
1091
+ </UDExTab>
1092
+ <UDExTab text="Settings">
1093
+ <udex-link slot="link" href="https://sap.com/" design="Default">Privacy Policy</udex-link>
1094
+ <div>Settings content</div>
1095
+ </UDExTab>
1096
+ </UDExTabNavigation>
1097
+ );
1098
+
1099
+ cy.get("[udex-tab-navigation]")
1100
+ .shadow()
1101
+ .find("button[role='tab']")
1102
+ .contains("Settings")
1103
+ .click();
1104
+
1105
+ cy.get("[udex-tab-navigation]")
1106
+ .shadow()
1107
+ .find(".udex-tab-navigation__button-tab--active ~ .udex-tab-navigation__button-links")
1108
+ .should("have.css", "display", "flex");
1109
+ });
1110
+
1111
+ it("does not render the links container in Horizontal orientation", () => {
1112
+ cy.mount(
1113
+ <UDExTabNavigation orientation={UDExTabNavigationOrientation.Horizontal}>
1114
+ <UDExTab text="Account" selected>
1115
+ <udex-link slot="link" href="https://sap.com/" design="Default">Privacy Policy</udex-link>
1116
+ <div>Account content</div>
1117
+ </UDExTab>
1118
+ <UDExTab text="Settings">
1119
+ <div>Settings content</div>
1120
+ </UDExTab>
1121
+ </UDExTabNavigation>
1122
+ );
1123
+
1124
+ // hasBodyTextOrLink requires _isVertical=true, so the wrapper branch is never entered
1125
+ cy.get("[udex-tab-navigation]")
1126
+ .shadow()
1127
+ .find(".udex-tab-navigation__button-links")
1128
+ .should("not.exist");
1129
+ });
1130
+
1131
+ it("does not render links container when the link slot is empty", () => {
1132
+ cy.mount(
1133
+ <UDExTabNavigation orientation={UDExTabNavigationOrientation.Vertical}>
1134
+ <UDExTab text="Account" selected>
1135
+ <div>Account content</div>
1136
+ </UDExTab>
1137
+ <UDExTab text="Settings">
1138
+ <div>Settings content</div>
1139
+ </UDExTab>
1140
+ </UDExTabNavigation>
1141
+ );
1142
+
1143
+ cy.get("[udex-tab-navigation]")
1144
+ .shadow()
1145
+ .find(".udex-tab-navigation__button-links")
1146
+ .should("not.exist");
1147
+ });
1148
+ });
1149
+
1150
+ describe("TabNavigation - Auto-play", () => {
1151
+ const autoPlayTabs = (
1152
+ <>
1153
+ <UDExTab text="Tab 1" selected><div>Content 1</div></UDExTab>
1154
+ <UDExTab text="Tab 2"><div>Content 2</div></UDExTab>
1155
+ <UDExTab text="Tab 3"><div>Content 3</div></UDExTab>
1156
+ </>
1157
+ );
1158
+
1159
+ it("renders play button when autoPlay is enabled on Vertical orientation", () => {
1160
+ cy.mount(
1161
+ <UDExTabNavigation
1162
+ orientation={UDExTabNavigationOrientation.Vertical}
1163
+ autoPlay
1164
+ autoPlayInterval={5000}
1165
+ >
1166
+ {autoPlayTabs}
1167
+ </UDExTabNavigation>
1168
+ );
1169
+
1170
+ cy.get("[udex-tab-navigation]")
1171
+ .shadow()
1172
+ .find(".udex-tab-navigation__play-button")
1173
+ .should("exist");
1174
+ });
1175
+
1176
+ it("does not render play button for Horizontal orientation", () => {
1177
+ cy.mount(
1178
+ <UDExTabNavigation
1179
+ orientation={UDExTabNavigationOrientation.Horizontal}
1180
+ autoPlay
1181
+ >
1182
+ {autoPlayTabs}
1183
+ </UDExTabNavigation>
1184
+ );
1185
+
1186
+ cy.get("[udex-tab-navigation]")
1187
+ .shadow()
1188
+ .find(".udex-tab-navigation__play-button")
1189
+ .should("not.exist");
1190
+ });
1191
+
1192
+ it("does not render play button when autoPlay is false", () => {
1193
+ cy.mount(
1194
+ <UDExTabNavigation orientation={UDExTabNavigationOrientation.Vertical}>
1195
+ {autoPlayTabs}
1196
+ </UDExTabNavigation>
1197
+ );
1198
+
1199
+ cy.get("[udex-tab-navigation]")
1200
+ .shadow()
1201
+ .find(".udex-tab-navigation__play-button")
1202
+ .should("not.exist");
1203
+ });
1204
+
1205
+ it("advances to next tab after interval", () => {
1206
+ cy.clock(0, ["setInterval", "clearInterval"]);
1207
+ cy.mount(
1208
+ <UDExTabNavigation
1209
+ orientation={UDExTabNavigationOrientation.Vertical}
1210
+ autoPlay
1211
+ autoPlayInterval={1000}
1212
+ >
1213
+ {autoPlayTabs}
1214
+ </UDExTabNavigation>
1215
+ );
1216
+
1217
+ cy.get("[udex-tab-navigation]")
1218
+ .shadow()
1219
+ .find("button[role='tab'][aria-selected='true']")
1220
+ .should("contain.text", "Tab 1");
1221
+
1222
+ cy.tick(1000);
1223
+
1224
+ cy.get("[udex-tab-navigation]")
1225
+ .shadow()
1226
+ .find("button[role='tab'][aria-selected='true']")
1227
+ .should("contain.text", "Tab 2");
1228
+ });
1229
+
1230
+ it("loops back to first tab after the last tab", () => {
1231
+ cy.clock(0, ["setInterval", "clearInterval"]);
1232
+ cy.mount(
1233
+ <UDExTabNavigation
1234
+ orientation={UDExTabNavigationOrientation.Vertical}
1235
+ autoPlay
1236
+ autoPlayInterval={1000}
1237
+ >
1238
+ {autoPlayTabs}
1239
+ </UDExTabNavigation>
1240
+ );
1241
+
1242
+ cy.tick(3000);
1243
+
1244
+ cy.get("[udex-tab-navigation]")
1245
+ .shadow()
1246
+ .find("button[role='tab'][aria-selected='true']")
1247
+ .should("contain.text", "Tab 1");
1248
+ });
1249
+
1250
+ it("pauses auto-play when play button is clicked", () => {
1251
+ cy.clock(0, ["setInterval", "clearInterval"]);
1252
+ cy.mount(
1253
+ <UDExTabNavigation
1254
+ orientation={UDExTabNavigationOrientation.Vertical}
1255
+ autoPlay
1256
+ autoPlayInterval={1000}
1257
+ >
1258
+ {autoPlayTabs}
1259
+ </UDExTabNavigation>
1260
+ );
1261
+
1262
+ cy.get("[udex-tab-navigation]")
1263
+ .shadow()
1264
+ .find(".udex-tab-navigation__play-button")
1265
+ .click();
1266
+
1267
+ cy.tick(2000);
1268
+
1269
+ cy.get("[udex-tab-navigation]")
1270
+ .shadow()
1271
+ .find("button[role='tab'][aria-selected='true']")
1272
+ .should("contain.text", "Tab 1");
1273
+ });
1274
+
1275
+ it("resumes auto-play when play button is clicked again after pause", () => {
1276
+ cy.clock(0, ["setInterval", "clearInterval"]);
1277
+ cy.mount(
1278
+ <UDExTabNavigation
1279
+ orientation={UDExTabNavigationOrientation.Vertical}
1280
+ autoPlay
1281
+ autoPlayInterval={1000}
1282
+ >
1283
+ {autoPlayTabs}
1284
+ </UDExTabNavigation>
1285
+ );
1286
+
1287
+ cy.get("[udex-tab-navigation]")
1288
+ .shadow()
1289
+ .find(".udex-tab-navigation__play-button")
1290
+ .click();
1291
+
1292
+ cy.get("[udex-tab-navigation]")
1293
+ .shadow()
1294
+ .find(".udex-tab-navigation__play-button")
1295
+ .click();
1296
+
1297
+ cy.tick(1000);
1298
+
1299
+ cy.get("[udex-tab-navigation]")
1300
+ .shadow()
1301
+ .find("button[role='tab'][aria-selected='true']")
1302
+ .should("contain.text", "Tab 2");
1303
+ });
1304
+
1305
+ it("respects custom autoPlayInterval", () => {
1306
+ cy.clock(0, ["setInterval", "clearInterval"]);
1307
+ cy.mount(
1308
+ <UDExTabNavigation
1309
+ orientation={UDExTabNavigationOrientation.Vertical}
1310
+ autoPlay
1311
+ autoPlayInterval={3000}
1312
+ >
1313
+ {autoPlayTabs}
1314
+ </UDExTabNavigation>
1315
+ );
1316
+
1317
+ cy.tick(2000);
1318
+
1319
+ cy.get("[udex-tab-navigation]")
1320
+ .shadow()
1321
+ .find("button[role='tab'][aria-selected='true']")
1322
+ .should("contain.text", "Tab 1");
1323
+
1324
+ cy.tick(1000);
1325
+
1326
+ cy.get("[udex-tab-navigation]")
1327
+ .shadow()
1328
+ .find("button[role='tab'][aria-selected='true']")
1329
+ .should("contain.text", "Tab 2");
1330
+ });
1331
+
1332
+ it("resets interval timer when tab is manually selected", () => {
1333
+ cy.clock(0, ["setInterval", "clearInterval"]);
1334
+ cy.mount(
1335
+ <UDExTabNavigation
1336
+ orientation={UDExTabNavigationOrientation.Vertical}
1337
+ autoPlay
1338
+ autoPlayInterval={1000}
1339
+ >
1340
+ {autoPlayTabs}
1341
+ </UDExTabNavigation>
1342
+ );
1343
+
1344
+ cy.tick(800);
1345
+
1346
+ cy.get("[udex-tab-navigation]")
1347
+ .shadow()
1348
+ .find("button[role='tab']")
1349
+ .contains("Tab 3")
1350
+ .click();
1351
+
1352
+ cy.tick(800);
1353
+
1354
+ cy.get("[udex-tab-navigation]")
1355
+ .shadow()
1356
+ .find("button[role='tab'][aria-selected='true']")
1357
+ .should("contain.text", "Tab 3");
1358
+
1359
+ cy.tick(200);
1360
+
1361
+ cy.get("[udex-tab-navigation]")
1362
+ .shadow()
1363
+ .find("button[role='tab'][aria-selected='true']")
1364
+ .should("contain.text", "Tab 1");
1365
+ });
1366
+
1367
+ it("shows pause icon when playing and play icon when paused", () => {
1368
+ cy.mount(
1369
+ <UDExTabNavigation
1370
+ orientation={UDExTabNavigationOrientation.Vertical}
1371
+ autoPlay
1372
+ autoPlayInterval={5000}
1373
+ >
1374
+ {autoPlayTabs}
1375
+ </UDExTabNavigation>
1376
+ );
1377
+
1378
+ cy.get("[udex-tab-navigation]")
1379
+ .shadow()
1380
+ .find(".udex-tab-navigation__play-button")
1381
+ .should("have.attr", "icon", "pause");
1382
+
1383
+ cy.get("[udex-tab-navigation]")
1384
+ .shadow()
1385
+ .find(".udex-tab-navigation__play-button")
1386
+ .click();
1387
+
1388
+ cy.get("[udex-tab-navigation]")
1389
+ .shadow()
1390
+ .find(".udex-tab-navigation__play-button")
1391
+ .should("have.attr", "icon", "play");
1392
+ });
1393
+ });
1394
+
1395
+ describe("TabNavigation - Vertical Alignment", () => {
1396
+ const alignmentTabs = (
1397
+ <>
1398
+ <UDExTab text="Tab 1" selected><div style={{ height: "200px" }}>Tall content 1</div></UDExTab>
1399
+ <UDExTab text="Tab 2"><div style={{ height: "200px" }}>Tall content 2</div></UDExTab>
1400
+ </>
1401
+ );
1402
+
1403
+ it("defaults to Top alignment when verticalAlignment is not set", () => {
1404
+ cy.mount(
1405
+ <UDExTabNavigation orientation={UDExTabNavigationOrientation.Vertical}>
1406
+ {alignmentTabs}
1407
+ </UDExTabNavigation>
1408
+ );
1409
+
1410
+ cy.get("[udex-tab-navigation]").should("not.have.attr", "vertical-alignment", "Center");
1411
+ cy.get("[udex-tab-navigation]")
1412
+ .shadow()
1413
+ .find(".udex-tab-navigation__header")
1414
+ .should("have.css", "align-self", "flex-start");
1415
+ });
1416
+
1417
+ it("applies center alignment when verticalAlignment is Center", () => {
1418
+ cy.mount(
1419
+ <UDExTabNavigation
1420
+ orientation={UDExTabNavigationOrientation.Vertical}
1421
+ verticalAlignment={UDExTabNavigationVerticalAlignment.Center}
1422
+ >
1423
+ {alignmentTabs}
1424
+ </UDExTabNavigation>
1425
+ );
1426
+
1427
+ cy.get("[udex-tab-navigation]")
1428
+ .shadow()
1429
+ .find(".udex-tab-navigation__header")
1430
+ .should("have.css", "align-self", "center");
1431
+ });
1432
+
1433
+ it("reflects vertical-alignment attribute on the host element", () => {
1434
+ cy.mount(
1435
+ <UDExTabNavigation
1436
+ orientation={UDExTabNavigationOrientation.Vertical}
1437
+ verticalAlignment={UDExTabNavigationVerticalAlignment.Center}
1438
+ >
1439
+ {alignmentTabs}
1440
+ </UDExTabNavigation>
1441
+ );
1442
+
1443
+ cy.get("[udex-tab-navigation]").should("have.attr", "vertical-alignment", "Center");
1444
+ });
1445
+
1446
+ it("does not apply vertical-alignment styles in Horizontal orientation", () => {
1447
+ cy.mount(
1448
+ <UDExTabNavigation
1449
+ orientation={UDExTabNavigationOrientation.Horizontal}
1450
+ verticalAlignment={UDExTabNavigationVerticalAlignment.Center}
1451
+ >
1452
+ {alignmentTabs}
1453
+ </UDExTabNavigation>
1454
+ );
1455
+
1456
+ cy.get("[udex-tab-navigation]")
1457
+ .shadow()
1458
+ .find(".udex-tab-navigation__header")
1459
+ .should("not.have.css", "align-self", "center");
1460
+ });
1461
+ });
1462
+
901
1463
  describe("TabNavigation - Additional Features", () => {
902
1464
  it("applies tabWidth property to vertical tabs", () => {
903
1465
  cy.mount(
@@ -990,6 +1552,8 @@ describe("Tab Navigation component", () => {
990
1552
  });
991
1553
 
992
1554
  it("handles tab selection in vertical mode with many tabs", () => {
1555
+ cy.viewport(1280, 1200);
1556
+
993
1557
  const manyTabs = Array.from({ length: 10 }, (_, i) => (
994
1558
  <UDExTab text={`Tab ${i + 1}`} selected={i === 0}>
995
1559
  <div>Content {i + 1}</div>
@@ -36,6 +36,7 @@ import UDExListGroupHeader from "../../instrumented/ListGroupHeader.js";
36
36
  import UDExListItem from "../../instrumented/ListItem.js";
37
37
  import UDExMastheadProfileMenu from "../../instrumented/MastheadProfileMenu.js";
38
38
  import UDExMessageStrip from "../../instrumented/MessageStrip.js";
39
+ import UDExMediaPlayer from "../../instrumented/MediaPlayer.js";
39
40
  import UDExPasswordField from "../../instrumented/PasswordField.js";
40
41
  import UDExPhoneNumberField from "../../instrumented/PhoneNumberField.js";
41
42
  import UDExPromoTile from "../../instrumented/PromoTile.js";
@@ -111,6 +112,7 @@ export {
111
112
  UDExListGroupHeader,
112
113
  UDExMastheadProfileMenu,
113
114
  UDExMessageStrip,
115
+ UDExMediaPlayer,
114
116
  UDExPasswordField,
115
117
  UDExPhoneNumberField,
116
118
  UDExPromoTile,