import { Meta, Canvas, Controls } from '@storybook/addon-docs/blocks'
import * as CollapsibleSectionStories from './CollapsibleSection.stories'
import * as SidebarStories from './Sidebar.stories'

<Meta of={CollapsibleSectionStories} />

# CollapsibleSection

A section that opens and closes: a SectionHeader whose title is the
toggle, and the rows under it, sliding shut and open.

<Canvas of={CollapsibleSectionStories.Default} />

## When

- A group of rows in a sidebar or a panel that the reader may want out of
  the way — starred items, recent places.
- `defaultOpen={false}` for a group that starts folded.
- `storageKey` when the section should stay how the reader left it across
  reloads: this browser remembers, under that key. The app prefixes the
  key (`app.sidebar.starred`).
- `open` + `onOpenChange` when the app owns the state.
- `pending` when the rows are read as it opens and usually arrive quickly:
  the title turns open at once (and says `aria-busy`), the panel stays shut
  until `pending` is false, then opens once with every row. A skeleton that
  the rows replace would move everything below it twice. Only for rows not
  yet drawn: on a section already showing its rows, `pending` shuts them
  until it is false. The tests pin the state (open, busy, rows hidden); the
  single slide is Chrome's to show, measured in Peek (OPT-11).
- `actions` for add, sort, filter beside the title — SectionHeader's,
  revealed while the row is hovered or keyboard-focused.
- `look="row"` when the section is a row among rows — a folder in a
  sidebar, under a quiet label: the title at a row's weight, and its rows
  indented under it, past the chevron.

<Canvas of={CollapsibleSectionStories.AsARow} />

- `indent` with the standard heading: its rows start under its title, past
  the chevron — a group in a sidebar whose rows read as inside it. **NavTree**
  draws its groups this way.

<Canvas of={CollapsibleSectionStories.Indented} />

In a sidebar — the Sidebar's own Composed canvas, which is where that
composition lives:

<Canvas of={SidebarStories.Composed} />

## When not

- A heading over rows that never fold → **SectionHeader** without
  `chevron`. Never a row drawn by hand.
- Several panels where opening one closes the others → not here; that is
  an accordion, and no app has asked for one.
- Content that appears on demand from a control elsewhere → **Popover**.

## How

```tsx
import { CollapsibleSection, NavItem } from '@estiva-app/ui'

<CollapsibleSection title="Starred" storageKey="app.sidebar.starred" className="mt-2 shrink-0" contentClassName="gap-px">
  <NavItem href="/p/1" label="Item one" />
  <NavItem href="/p/2" label="Item two" />
</CollapsibleSection>
```

- On Base UI's `Collapsible`: the state, the title button's
  `aria-expanded` and `aria-controls`, the keys, the panel's height for
  the slide (150ms; none under `prefers-reduced-motion`), and
  `hiddenUntilFound` — the browser's find-in-page can find a row inside a
  closed section and open it. The rows stay in the DOM while closed.
- `className` is the section's box: `mt-2` between groups, `shrink-0` in
  a scrolling column — the missing-`shrink-0` family. `contentClassName`
  is the box the rows sit in: the gap between them.
- A closed section stays closed whatever is selected inside it — the
  reader closed it. An app that wants it to spring open owns the state
  with `open`.
- A browser that blocks storage still gets a working section; it forgets.

## What it owns

It does these by itself. Write none of them around it.

| It does | So you never write | Refused when written by hand |
|---|---|---|
| Opens and closes from its title, on a click, Enter or Space | open state, or a key handler |  |
| Tells assistive technology whether it is open | `aria-expanded` |  |

## Keys

| Key | Does |
|---|---|
| Enter, Space | on the title: opens or closes |
| Tab | the title, then each action, then the rows when open |

## Props

<Controls of={CollapsibleSectionStories.Default} />
