feat: add maxHeight prop with sectionContent wrapper to SidebarSection

Adds position and maxHeight to SidebarSectionProps and wraps children in a .sectionContent div when the section is open, enabling scrollable constrained height via inline style.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-15 20:57:43 +02:00
parent 7e2fce8b14
commit 57d60bf2ed
2 changed files with 81 additions and 1 deletions

View File

@@ -324,4 +324,73 @@ describe('Sidebar compound component', () => {
const item = screen.getByText('Admin').closest('[role="button"]')!
expect(item.className).toMatch(/bottomItemActive/)
})
// 17. renders sectionContent wrapper with maxHeight when open
it('renders section content wrapper with maxHeight style when open', () => {
const { container } = render(
<Wrapper>
<Sidebar>
<Sidebar.Section
icon={<span>ic</span>}
label="Apps"
open
onToggle={vi.fn()}
maxHeight="200px"
>
<div>child</div>
</Sidebar.Section>
</Sidebar>
</Wrapper>,
)
const contentWrapper = container.querySelector('.sectionContent')
expect(contentWrapper).toBeInTheDocument()
expect(contentWrapper).toHaveStyle({ maxHeight: '200px' })
expect(screen.getByText('child')).toBeInTheDocument()
})
// 18. renders sectionContent wrapper without maxHeight when not provided
it('renders section content wrapper without inline maxHeight when maxHeight is not provided', () => {
const { container } = render(
<Wrapper>
<Sidebar>
<Sidebar.Section
icon={<span>ic</span>}
label="Apps"
open
onToggle={vi.fn()}
>
<div>child</div>
</Sidebar.Section>
</Sidebar>
</Wrapper>,
)
const contentWrapper = container.querySelector('.sectionContent')
expect(contentWrapper).toBeInTheDocument()
expect(contentWrapper).not.toHaveStyle({ maxHeight: '200px' })
expect(screen.getByText('child')).toBeInTheDocument()
})
// 19. does not render sectionContent wrapper when section is closed
it('does not render section content wrapper when section is closed', () => {
const { container } = render(
<Wrapper>
<Sidebar>
<Sidebar.Section
icon={<span>ic</span>}
label="Apps"
open={false}
onToggle={vi.fn()}
maxHeight="200px"
>
<div>child</div>
</Sidebar.Section>
</Sidebar>
</Wrapper>,
)
const contentWrapper = container.querySelector('.sectionContent')
expect(contentWrapper).not.toBeInTheDocument()
})
})

View File

@@ -26,6 +26,8 @@ interface SidebarSectionProps {
active?: boolean
children: ReactNode
className?: string
position?: 'top' | 'bottom'
maxHeight?: string
}
interface SidebarFooterProps {
@@ -83,6 +85,8 @@ function SidebarSection({
active,
children,
className,
position: _position,
maxHeight,
}: SidebarSectionProps) {
const { collapsed, onCollapseToggle } = useSidebarContext()
@@ -125,7 +129,14 @@ function SidebarSection({
{icon && <span className={styles.sectionIcon}>{icon}</span>}
<span className={styles.treeSectionLabel}>{label}</span>
</div>
{open && children}
{open && (
<div
className={styles.sectionContent}
style={maxHeight ? { maxHeight } : undefined}
>
{children}
</div>
)}
</div>
)
}