## sidebar (`poetry_sidebar`)

A collapsible app-shell navigation column.

Class: Poetry::Ui::Sidebar::Component - BEM block `poetry-ui-sidebar`.
Slot REQUIRED: with_nav (the sidebar column) - a call without it raises.
- `collapsible:` (symbol) - one of offcanvas|icon|none, default "offcanvas" - What collapsing does: slide fully away, shrink to an icon rail, or :none for a static column.
- `open:` (boolean) - default true - The expanded/collapsed state at first paint - feed it from the persisted cookie so there is no collapse flash.
- `side:` (symbol) - one of left|right, default "left" - Which edge the column hangs on.
- `variant:` (symbol) - one of sidebar|floating|inset, default "sidebar" - The column treatment: flush column, floating card, or inset panel.
Slots: nav (The sidebar column's content (required) - groups, menus, header/footer.), inset (The page area beside the column - rendered as the <main> inset.).
- PART `sidebar-wrapper` - The provider shell around the column, the mobile dialog, and the inset | vars: --sidebar-width (the expanded column width (16rem) - the gap/container geometry reads it); --sidebar-width-icon (the collapsed icon-rail width (3rem))
- PART `sidebar` - The desktop state peer - the collapse state lives here and the pure-CSS group-data chrome keys on it | states: data-state (expanded or collapsed - the controller flips it and persists the cookie); data-collapsible=offcanvas|icon|none (the collapse mode WHILE collapsed (empty while expanded - source parity)); data-variant=sidebar|floating|inset (the column treatment); data-side=left|right (which edge the column hangs on)
- PART `sidebar-gap` - The in-flow width ghost that pushes the inset over - its width animates on collapse
- PART `sidebar-container` - The fixed-position column itself | states: data-side=left|right (which edge it pins to)
- PART `sidebar-inner` - The flex column receiving the nav slot - the mobile mode adopts its children from here
- PART `sidebar-mobile` - The mobile sheet <dialog> (below md) - server-rendered empty; the controller adopts the nav children on open | states: data-open (sheet is open (presence flips the pair at runtime)); data-closed (sheet is closed (the server-rendered state)); data-mobile (always "true" - the mobile-mode marker); data-side=left|right (which edge the sheet slides from); data-sidebar (always "sidebar" - the suite-wide sub-part marker) | vars: --sidebar-width (overridden inline to the mobile sheet width (18rem))
- PART `sidebar-mobile-inner` - The adoption container the nav children move into while the sheet is open
- PART `sidebar-inset` - The <main> page area beside the column
- PART `sidebar-header` - Top block of the column (with_nav content)
- PART `sidebar-footer` - Bottom block of the column
- PART `sidebar-content` - The scrollable middle of the column
- PART `sidebar-group` - One titled section inside the content
- PART `sidebar-group-label` - The section heading - fades and collapses away in icon mode
- PART `sidebar-menu` - The <ul> of menu items inside a group
- PART `sidebar-menu-item` - One <li> menu row (the group/menu-item hover scope)
- PART `sidebar-menu-button` - The row's link (href:) or button - the navigation entry itself | states: data-active (the current route (active: - links also get aria-current=page)); data-open (when the button is a collapsible's trigger - the disclosure state the collapsible controller flips); data-size (the row size variant (default, sm, or lg) - the action/badge tops key on it); data-variant=default|outline (always - the treatment)
- PART `sidebar-menu-action` - The item-corner action button, absolutely positioned in the row | states: data-sidebar (always "menu-action" - the suite-wide sub-part marker)
- PART `sidebar-menu-badge` - The trailing count/status chrome in the row corner - pointer-transparent | states: data-sidebar (always "menu-badge" - the suite-wide sub-part marker)
In blocks: `app-shell` - for a screen, start from the block (MCP compose/describe_block, or `bin/rails g poetry:block`), not from scratch.
- WIRING root: `poetry--core--sidebar` registers; values open, collapsible
- WIRING peer: `poetry--core--sidebar` targets sidebar
- WIRING inner: `poetry--core--sidebar` targets inner
- WIRING mobile: `poetry--core--sidebar` actions closeMobile on cancel, mobileBackdropClose on click; targets mobileDialog
- WIRING mobile_inner: `poetry--core--sidebar` targets mobileInner
- WIRING trigger: `poetry--core--sidebar` actions toggle on click
- RULE: Wrap the WHOLE shell: with_nav is the sidebar column, with_inset is the page area (the trigger lives in the inset).
- RULE: Read the persisted state server-side - open: cookies[:sidebar_state] != "false" - so the first paint has no collapse flash.
- RULE: collapsible: :icon keeps icon rails visible when collapsed; :offcanvas slides it fully away; :none is a static column.
- RULE: Menu entries are poetry_sidebar_menu_button(href:) links (active: marks the current route) - navigation navigates.
