diff --git a/packages/fiori/cypress/specs/SideNavigation.cy.tsx b/packages/fiori/cypress/specs/SideNavigation.cy.tsx
index 9b85c2a090660..6ced9d1f2bc6d 100644
--- a/packages/fiori/cypress/specs/SideNavigation.cy.tsx
+++ b/packages/fiori/cypress/specs/SideNavigation.cy.tsx
@@ -76,6 +76,64 @@ describe("Side Navigation Rendering", () => {
.should("have.attr", "design", "Action");
});
+ it.only("Tests overflow item visibility and items in overflow", () => {
+ cy.mount(
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+
+ cy.get("#sideNav")
+ .should("be.visible");
+
+ // the overflow item should be visible
+ cy.get("#sideNav")
+ .shadow()
+ .find(".ui5-sn-item-overflow:not(.ui5-sn-item-hidden)")
+ .should("be.visible")
+ .realClick();
+
+ // exactly 2 items should be in the overflow menu
+ cy.get("#sideNav")
+ .shadow()
+ .find(".ui5-side-navigation-overflow-menu [ui5-navigation-menu-item]")
+ .should("have.length", 2);
+
+
+ // check the last separator calculations
+ // when the height is 440px, also 2 items should go to the overflow
+ cy.get("#sideNav")
+ .invoke("attr", "style", "height:440px");
+
+ // the overflow item should be visible
+ cy.get("#sideNav")
+ .shadow()
+ .find(".ui5-sn-item-overflow:not(.ui5-sn-item-hidden)")
+ .should("be.visible")
+ .realClick();
+
+ // exactly 2 items should be in the overflow menu
+ cy.get("#sideNav")
+ .shadow()
+ .find(".ui5-side-navigation-overflow-menu [ui5-navigation-menu-item]")
+ .should("have.length", 2);
+ });
+
it("Tests accessibility", () => {
cy.mount(
@@ -1369,7 +1427,7 @@ describe("Side Navigation Accessibility", () => {
.shadow()
.find(".ui5-sn-item-overflow")
.realClick();
-
+
// Assert
cy.get("#sideNav")
.shadow()
diff --git a/packages/fiori/src/SideNavigation.ts b/packages/fiori/src/SideNavigation.ts
index cc636aa9bc187..2bb0db35dc261 100644
--- a/packages/fiori/src/SideNavigation.ts
+++ b/packages/fiori/src/SideNavigation.ts
@@ -313,8 +313,6 @@ class SideNavigation extends UI5Element {
(popover?.opener as HTMLElement)?.classList.remove("ui5-sn-item-active");
}
- _bn?: SideNavigationSelectableItemBase;
-
_onMenuClose() {
const menu = this.getOverflowPopover();
if (!menu._popover.preventFocusRestore) {
@@ -543,8 +541,7 @@ class SideNavigation extends UI5Element {
return null;
}
- const overflowItem = this._overflowItem!;
- const flexibleContentDomRef: HTMLElement = domRef.querySelector(".ui5-sn-flexible")!;
+ const overflowItem = this._overflowItem;
if (!overflowItem) {
return null;
}
@@ -553,18 +550,13 @@ class SideNavigation extends UI5Element {
const overflowItems = this.overflowItems;
- let itemsHeight = overflowItems.reduce((sum, itemRef) => {
- if (!itemRef) {
- return sum;
- }
- itemRef.classList.remove("ui5-sn-item-hidden");
- return sum + itemRef.offsetHeight;
- }, 0);
+ let itemsHeight = this._calculateItemsHeight(overflowItems);
+ const flexibleContentDomRef: HTMLElement = domRef.querySelector(".ui5-sn-flexible")!;
const { paddingTop, paddingBottom } = window.getComputedStyle(flexibleContentDomRef);
const listHeight = flexibleContentDomRef?.offsetHeight - parseInt(paddingTop) - parseInt(paddingBottom);
- if (itemsHeight <= listHeight) {
+ if (itemsHeight < listHeight) {
return;
}
@@ -572,41 +564,115 @@ class SideNavigation extends UI5Element {
itemsHeight = overflowItem.offsetHeight;
- const selectedItem = overflowItems.filter(isInstanceOfSideNavigationSelectableItemBase).find(item => item._selected);
+ const navItems = overflowItems.filter(isInstanceOfSideNavigationSelectableItemBase);
+ const selectedItem = navItems.find(item => item._selected);
+
+ itemsHeight += this._getSelectedItemHeight(overflowItems, selectedItem) + 1; // +1 for sub-pixel rounding
+ itemsHeight += this._getLastSeparatorHeight(navItems, overflowItems);
+
+ this._updateItemsVisibility(overflowItems, selectedItem, itemsHeight, listHeight);
+
+ this._flexibleItemNavigation._init();
+ }
+
+ _calculateItemsHeight(overflowItems: Array) {
+ return overflowItems.reduce((sum, itemRef) => {
+ if (!itemRef) {
+ return sum;
+ }
+ itemRef.classList.remove("ui5-sn-item-hidden");
+
+ let itemDomRef = itemRef;
+
+ if (isInstanceOfSideNavigationItemBase(itemRef) && itemRef.getDomRef()) {
+ itemDomRef = itemRef.getDomRef()!;
+ }
+
+ const { marginTop, marginBottom } = window.getComputedStyle(itemDomRef);
+
+ return sum + itemDomRef.offsetHeight + parseFloat(marginTop) + parseFloat(marginBottom);
+ }, 0);
+ }
+
+ _getSelectedItemHeight(overflowItems: Array, selectedItem: SideNavigationSelectableItemBase | undefined) {
+ if (!selectedItem) {
+ return 0;
+ }
+
+ let height = 0;
if (selectedItem) {
const selectedItemDomRef = selectedItem.getDomRef();
if (selectedItemDomRef) {
const { marginTop, marginBottom } = window.getComputedStyle(selectedItemDomRef);
- itemsHeight += selectedItemDomRef.offsetHeight + parseFloat(marginTop) + parseFloat(marginBottom);
+ height += selectedItemDomRef.offsetHeight + parseFloat(marginTop) + parseFloat(marginBottom);
+ }
+
+ const indexOf = overflowItems.indexOf(selectedItem);
+ const itemAfterSelected = overflowItems[indexOf + 1];
+ if (itemAfterSelected && !isInstanceOfSideNavigationItemBase(itemAfterSelected)) {
+ height += itemAfterSelected.offsetHeight;
}
}
- overflowItems.forEach(item => {
+ return height;
+ }
+
+ _getLastSeparatorHeight(navItems: Array, overflowItems: Array) {
+ const lastNonSelectedItem = navItems.findLast(item => !item._selected);
+ if (!lastNonSelectedItem) {
+ return 0;
+ }
+
+ const indexOf = overflowItems.indexOf(lastNonSelectedItem);
+ const nextSeparator = overflowItems[indexOf + 1];
+
+ if (nextSeparator && !isInstanceOfSideNavigationItemBase(nextSeparator)) {
+ return nextSeparator.offsetHeight;
+ }
+
+ return 0;
+ }
+
+ _updateItemsVisibility(overflowItems: Array, selectedItem: SideNavigationSelectableItemBase | undefined, itemsHeight: number, listHeight: number) {
+ for (let i = 0; i < overflowItems.length; i++) {
+ const item = overflowItems[i];
+
if (!item || item === selectedItem) {
- return;
+ // eslint-disable-next-line no-continue
+ continue;
}
let itemDomRef;
- if (isInstanceOfSideNavigationItemBase(item) && item.getDomRef()) {
+ if (isInstanceOfSideNavigationItemBase(item)) {
itemDomRef = item.getDomRef();
- } else {
- itemDomRef = item;
}
- if (itemDomRef) {
- const { marginTop, marginBottom } = window.getComputedStyle(itemDomRef);
- itemsHeight += itemDomRef.offsetHeight + parseFloat(marginTop) + parseFloat(marginBottom);
+ if (!itemDomRef) {
+ // eslint-disable-next-line no-continue
+ continue;
+ }
- if (itemsHeight > listHeight) {
- item.classList.add("ui5-sn-item-hidden");
- }
+ const { marginTop, marginBottom } = window.getComputedStyle(itemDomRef);
+ itemsHeight += itemDomRef.offsetHeight + parseFloat(marginTop) + parseFloat(marginBottom);
+
+ // if the next item is a separator, the item and the separator
+ // should be hidden together, so we need to add the separator height to the itemsHeight
+ const nextItem = overflowItems[i + 1];
+ let nextItemDomRef;
+ if (nextItem && !isInstanceOfSideNavigationItemBase(nextItem)) {
+ nextItemDomRef = nextItem;
+ itemsHeight += nextItemDomRef.offsetHeight;
+ i++;
}
- });
- this._flexibleItemNavigation._init();
+ if (itemsHeight > listHeight) {
+ item.classList.add("ui5-sn-item-hidden");
+ nextItemDomRef?.classList.add("ui5-sn-item-hidden");
+ }
+ }
}
_findFocusedItem(items: Array): SideNavigationItemBase | undefined {
diff --git a/packages/fiori/src/themes/SideNavigation.css b/packages/fiori/src/themes/SideNavigation.css
index c2379289e2a10..3f5c159c31288 100644
--- a/packages/fiori/src/themes/SideNavigation.css
+++ b/packages/fiori/src/themes/SideNavigation.css
@@ -85,4 +85,12 @@
.ui5-sn-item-overflow {
margin-top: auto;
+}
+
+.ui5-sn-spacer {
+ margin: var(--_ui5_side_navigation_navigation_separator_margin);
+ height: var(--_ui5_side_navigation_navigation_separator_height);
+ min-height: var(--_ui5_side_navigation_navigation_separator_height);
+ background-color: var(--_ui5_side_navigation_navigation_separator_background_color);
+ border-radius: var(--_ui5_side_navigation_navigation_separator_radius);
}
\ No newline at end of file
diff --git a/packages/fiori/src/themes/SideNavigationGroup.css b/packages/fiori/src/themes/SideNavigationGroup.css
index 00833c2f23d2b..c28a6eb844165 100644
--- a/packages/fiori/src/themes/SideNavigationGroup.css
+++ b/packages/fiori/src/themes/SideNavigationGroup.css
@@ -22,12 +22,4 @@
.ui5-sn-item-group-below-group.ui5-sn-item-separator,
.ui5-sn-item-group-below-group .ui5-sn-item-separator:first-child {
display: none;
-}
-
-.ui5-sn-spacer {
- margin: var(--_ui5_side_navigation_navigation_separator_margin);
- height: var(--_ui5_side_navigation_navigation_separator_height);
- min-height: var(--_ui5_side_navigation_navigation_separator_height);
- background-color: var(--_ui5_side_navigation_navigation_separator_background_color);
- border-radius: var(--_ui5_side_navigation_navigation_separator_radius);
-}
+}
\ No newline at end of file
diff --git a/packages/fiori/test/pages/SideNavigationOverflowOverlap.html b/packages/fiori/test/pages/SideNavigationOverflowOverlap.html
new file mode 100644
index 0000000000000..69e962bd55d21
--- /dev/null
+++ b/packages/fiori/test/pages/SideNavigationOverflowOverlap.html
@@ -0,0 +1,58 @@
+
+
+
+
+ Side Navigation Only
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+