## collapsible (`poetry_collapsible`)

An interactive element that expands and collapses a section of content.

Class: Poetry::Ui::Collapsible::Component - BEM block `poetry-ui-collapsible`.
Content block REQUIRED (the disclosed panel body) - a blockless call raises.
Slot REQUIRED: with_trigger (the disclosure control) - a call without it raises.
- `open:` (boolean) - default false - The server-rendered initial state; the trigger toggles it client-side.
Slots: trigger (The disclosure control - a real button, wired for you (aria-expanded, aria-controls); options merge onto it.; with_trigger yields NOTHING to the block - no |param|, write content directly).
- PART `collapsible` - The disclosure root - the state controller flips the pair here | states: data-open (expanded (server-rendered from open:; the controller flips the pair at runtime)); data-closed (collapsed (the server-rendered default))
- PART `collapsible-trigger` - The disclosure button - mirrors aria-expanded | states: data-panel-open (its content is open (controller-written; absent while closed))
- PART `collapsible-content` - The disclosure panel - stays in the DOM when closed (hidden) and rides the presence helper on exit | states: data-open (content is open or entering); data-closed (content is closed or animating out (hidden lands after the exit finishes))
- WIRING root: `poetry--core--state` registers
- WIRING trigger: `poetry--core--state` actions toggle on click; targets trigger
- WIRING content: `poetry--core--state` targets content
- RULE: with_trigger(compose: true) { |wiring| ... } composes YOUR control as the trigger: the block is yielded the trigger wiring (the Stimulus behavior the overlay needs; poppers add id/aria and their trigger slot, modals hand only the open action) - splat it onto a wiring-free control (poetry_sidebar_menu_button, a plain tag); without compose: the classic composed Button renders.
- RULE: The trigger is with_trigger { "label" } - a real button, wired for you (aria-expanded/controls).
- RULE: Server-render the initial state via open: - never toggle data-open/data-closed by hand.
- RULE: Content stays in the DOM when closed (hidden) - do not conditionally render it.
- RULE: For URL-controlled disclosure without JS, render open: from params - the same markup serves both.
