Skip to content

Commit 60555bc

Browse files
severinoAmmiratiSeverinoAmmirati
andauthored
Sidebar overflow and scroll to active item (#51)
Sidebar overflow and scroll to active item --------- Co-authored-by: SeverinoAmmirati <severino.ammirati@oncode.it>
1 parent d75362c commit 60555bc

4 files changed

Lines changed: 52 additions & 33 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- Sidebar overflow and automatic scroll to active item with `scrollIntoView`
13+
1014
## [3.1.1] - 2024-01-09
1115

1216
### Fixed

cypress/cypress/component/PanelSidebar/PanelSidebar.cy.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,6 @@ describe("PanelSidebar.cy.tsx", () => {
145145
cy.mount(PanelSidebar(sidebarItems));
146146

147147
// Check active entries
148-
cy.get("#home").parent("li").should("have.class", "active");
148+
cy.get("#home").parent("div").parent("li").should("have.class", "active");
149149
});
150150
});

src/lib/Layout/PanelSideBarLayout/PanelSideBar/PanelSideBarItem.tsx

Lines changed: 40 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
22
import classNames from "classnames";
3-
import { ComponentType, useState } from "react";
3+
import { ComponentType, useState, useRef, useEffect } from "react";
44
import { Collapse, NavItem } from "reactstrap";
55
import { LinkRendererProps } from "src/lib/SideBar/SideBarMenuContext";
66
import { PanelItem } from "./../PanelSideBar/Definitions/PanelItem";
@@ -19,52 +19,62 @@ const PanelSideBarItem = (props: PanelSideBarItemProps) => {
1919
const { depth = 0, children: item, LinkRenderer, onClick, toggledItemIds = [], toggledSidebar } = props;
2020

2121
const hasitem = !!item.children?.length;
22+
const isActive = item.children?.find((s) => s.active) || item.active;
2223
const [isOpen, setIsOpen] = useState(toggledItemIds?.includes(item.id) || item.expanded);
2324
if (item.display === false) {
2425
return null;
2526
}
27+
const scrollToActiveItemRef = useRef<HTMLDivElement>(null);
28+
29+
useEffect(() => {
30+
if (scrollToActiveItemRef.current && isActive) {
31+
scrollToActiveItemRef.current.scrollIntoView();
32+
}
33+
}, []);
2634

2735
return (
2836
<>
2937
<NavItem
3038
onClick={() => onClick && onClick(item)}
31-
className={classNames({ "menu-open": isOpen, active: item.children?.find((s) => s.active) || item.active })}
39+
className={classNames({ "menu-open": isOpen, active: isActive })}
3240
style={{ paddingLeft: depth ? `${depth + 1}rem` : undefined }}
3341
>
34-
{hasitem ? (
35-
<div className={classNames("d-flex flex-row", { "justify-content-between": item.collapseIconOnly })}>
36-
{item.collapseIconOnly && (
42+
<div ref={scrollToActiveItemRef}>
43+
{hasitem ? (
44+
<div className={classNames("d-flex flex-row", { "justify-content-between": item.collapseIconOnly })}>
45+
{item.collapseIconOnly && (
46+
<LinkRenderer item={item}>
47+
<span className="nav-link">
48+
{item.icon && <FontAwesomeIcon icon={item.icon} className="me-2" />}
49+
{item.title}
50+
</span>
51+
</LinkRenderer>
52+
)}
53+
54+
<a
55+
role="button"
56+
className={classNames("nav-link", { "w-100": !item.collapseIconOnly }, { "dropdown-toggle": hasitem })}
57+
onClick={() => setIsOpen(!isOpen)}
58+
>
59+
{!item.collapseIconOnly && (
60+
<span>
61+
{item.icon && <FontAwesomeIcon className="me-2" icon={item.icon} />}
62+
{item.title}
63+
</span>
64+
)}
65+
</a>
66+
</div>
67+
) : (
68+
<>
3769
<LinkRenderer item={item}>
3870
<span className="nav-link">
3971
{item.icon && <FontAwesomeIcon icon={item.icon} className="me-2" />}
4072
{item.title}
4173
</span>
4274
</LinkRenderer>
43-
)}
44-
45-
<a
46-
role="button"
47-
className={classNames("nav-link", { "w-100": !item.collapseIconOnly }, { "dropdown-toggle": hasitem })}
48-
onClick={() => setIsOpen(!isOpen)}
49-
>
50-
{!item.collapseIconOnly && (
51-
<span>
52-
{item.icon && <FontAwesomeIcon className="me-2" icon={item.icon} />}
53-
{item.title}
54-
</span>
55-
)}
56-
</a>
57-
</div>
58-
) : (
59-
<>
60-
<LinkRenderer item={item}>
61-
<span className="nav-link">
62-
{item.icon && <FontAwesomeIcon icon={item.icon} className="me-2" />}
63-
{item.title}
64-
</span>
65-
</LinkRenderer>
66-
</>
67-
)}
75+
</>
76+
)}
77+
</div>
6878
</NavItem>
6979

7080
{hasitem && (

styles/Layout/PanelSideBarLayout.scss

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,14 +131,13 @@ section.content:first-of-type {
131131
position: fixed;
132132
display: flex;
133133
align-items: flex-start;
134-
overflow-y: auto;
135-
overflow-x: hidden;
136134
bottom: 0;
137135
background-color: $primary;
138136
width: $sidenav-base-width;
139137
top: $topnav-base-height;
140138
z-index: $zindex-fixed;
141139
transition: $sidebar-transition;
140+
overflow: hidden;
142141

143142
@include slim-scrollbar();
144143

@@ -166,6 +165,8 @@ section.content:first-of-type {
166165
height: 100%;
167166
width: 100%;
168167
transition: #{width $sidebar-transition};
168+
overflow-x: hidden;
169+
overflow-y: auto;
169170

170171
a {
171172
color: inherit;
@@ -203,6 +204,10 @@ section.content:first-of-type {
203204
margin-right: 0.5rem;
204205
}
205206

207+
&.dropdown-toggle {
208+
position: relative;
209+
}
210+
206211
&.dropdown-toggle::after {
207212
@include chevron-right();
208213
}

0 commit comments

Comments
 (0)