feat: clicking section group header toggles collapse/expand (#164)

- Clicking a collapsed section header now expands it (onToggle + onSelect)
- Clicking the active section header collapses it (onToggle only)
- Clicking an inactive, expanded section header selects it (onSelect only)
- Adds 33 tests covering toggle behavior in Sidebar

Co-authored-by: Test <test@test.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This commit is contained in:
Luca Rossi
2026-03-02 01:50:46 +01:00
committed by GitHub
parent 1a18de2340
commit 2bcb36c7b4
2 changed files with 38 additions and 1 deletions

View File

@@ -296,6 +296,39 @@ describe('Sidebar', () => {
})
})
it('expands a collapsed section when clicking its header', () => {
render(<Sidebar entries={mockEntries} selection={defaultSelection} onSelect={() => {}} />)
// Sections start collapsed — items hidden
expect(screen.queryByText('Build Laputa App')).not.toBeInTheDocument()
// Click the section header text (not the chevron)
fireEvent.click(screen.getByText('Projects'))
// Section should now be expanded
expect(screen.getByText('Build Laputa App')).toBeInTheDocument()
})
it('collapses an expanded+selected section when clicking its header again', () => {
const projectSelection: SidebarSelection = { kind: 'sectionGroup', type: 'Project' }
render(<Sidebar entries={mockEntries} selection={projectSelection} onSelect={() => {}} />)
// First click expands (starts collapsed) and selects
fireEvent.click(screen.getByText('Projects'))
expect(screen.getByText('Build Laputa App')).toBeInTheDocument()
// Second click: section is expanded + selected → should collapse
fireEvent.click(screen.getByText('Projects'))
expect(screen.queryByText('Build Laputa App')).not.toBeInTheDocument()
})
it('selects but keeps expanded an unselected expanded section when clicking its header', () => {
const onSelect = vi.fn()
render(<Sidebar entries={mockEntries} selection={defaultSelection} onSelect={onSelect} />)
// Expand via chevron first
fireEvent.click(screen.getByLabelText('Expand Projects'))
expect(screen.getByText('Build Laputa App')).toBeInTheDocument()
// Click the header — section is expanded but not selected → should select and stay expanded
fireEvent.click(screen.getByText('Projects'))
expect(onSelect).toHaveBeenCalledWith({ kind: 'sectionGroup', type: 'Project' })
expect(screen.getByText('Build Laputa App')).toBeInTheDocument()
})
it('calls onSelect with sectionGroup for People', () => {
const onSelect = vi.fn()
render(<Sidebar entries={mockEntries} selection={defaultSelection} onSelect={onSelect} />)

View File

@@ -156,7 +156,11 @@ function SectionHeader({ label, type, Icon, sectionColor, isCollapsed, isActive,
<div
className={cn("group/section flex cursor-pointer select-none items-center justify-between rounded transition-colors", isActive ? "bg-secondary" : "hover:bg-accent")}
style={{ padding: '6px 8px 6px 6px', borderRadius: 4, gap: 4 }}
onClick={onSelect} onContextMenu={onContextMenu}
onClick={() => {
if (isCollapsed) { onToggle(); onSelect() }
else if (isActive) { onToggle() }
else { onSelect() }
}} onContextMenu={onContextMenu}
>
<div className="flex items-center" style={{ gap: 4 }}>
<div className="flex shrink-0 items-center justify-center text-muted-foreground opacity-0 group-hover/section:opacity-50 hover:!opacity-100 cursor-grab" style={{ width: 16, height: 16 }} {...dragHandleProps} aria-label={`Drag to reorder ${label}`}>