{
  "name": "SidePanel",
  "source": "src/components/SidePanel.tsx",
  "propsType": "SidePanelProps",
  "description": "SidePanel — detail that opens beside the content, and leaves it usable.\n\nWHY NOT A DRAWER\n\nA Drawer is a modal dialog: it traps focus, marks the page inert and tells\na screen reader the page behind is gone. A detail pane beside a list is the\nopposite — the list stays live, the next row can be picked with the pane\nopen, and saying \"dialog\" about it would be a lie about where the user can\ngo. Same reasoning as ApprovalGate not being a Modal: the page is the\ncontext.\n\nHOW IT BEHAVES\n\n  - A `<section>` region named by its title, rendered in place — not\n    portalled — so it is part of the page's layout and reading order. Put\n    it in a SidePanelLayout beside the content.\n  - Opening focuses the title — unless `autoFocus={false}`, for a panel\n    that follows a List's selection. Closing with focus inside returns it\n    to the last thing focused outside the panel. Changing its content\n    does neither.\n  - Escape closes it from inside; Escape elsewhere is the page's own.\n  - No focus trap, no scrim, nothing hidden. Closed, it renders nothing.\n  - Below `overlayBelow` (768px) there is no \"beside\": the panel would\n    cover the list, so it opens as a Drawer — modal, honestly so.",
  "import": "import { SidePanel } from 'ionbase-ui';",
  "status": "stable",
  "summary": "Detail that opens beside the content and leaves it usable — pick a row, read it in the panel, pick the next. A labelled region in the page, not a dialog.",
  "useWhen": [
    "the detail of a list item should sit beside the list, and the next item should be pickable without closing anything — runs, tickets, records",
    "the user compares or works down a list, reading each item's detail in turn",
    "the detail is read or lightly acted on, not a task that must be finished or cancelled"
  ],
  "useInstead": [
    {
      "when": "the page behind must not be touched until the task is done — an edit form, a filter set that applies on confirm",
      "use": "Drawer",
      "why": "that is modal behaviour, and a Drawer says so: it traps focus and hides the page. A SidePanel leaves the page live"
    },
    {
      "when": "the detail is the whole of what the user came for — a record they will spend minutes in",
      "use": "a page of its own",
      "why": "a panel is a side view; a record with sections, tabs and history needs a URL and the full width"
    },
    {
      "when": "a sentence or two about one field",
      "use": "Toggletip"
    }
  ],
  "variants": {
    "size": {
      "sm": {
        "use": "a summary: a few facts and an action — 22rem"
      },
      "md": {
        "use": "the default — 30rem"
      },
      "lg": {
        "use": "detail with its own sections, on wide screens — 40rem"
      }
    }
  },
  "slots": {
    "title": {
      "accepts": "text",
      "note": "required — it names the region and is where focus lands on open"
    },
    "description": {
      "accepts": "text"
    },
    "children": {
      "accepts": "any content",
      "note": "the only scrolling region"
    },
    "footer": {
      "accepts": "Button",
      "note": "pinned to the bottom edge"
    }
  },
  "a11y": {
    "requires": [
      "`title` — the region's accessible name, through `aria-labelledby`",
      "a `SidePanelLayout` with the content first and the panel second — DOM order is reading order, and the panel is the detail of what comes before it"
    ],
    "guarantees": [
      "a `<section>` region named by its title, rendered in place — not portalled, not a dialog, and nothing on the page is hidden or made inert",
      "opening focuses the title, so the panel is announced and reading starts at its top — unless `autoFocus={false}`, when focus stays where it is",
      "changing what an open panel shows does not move focus — the list can be arrowed through with the panel open",
      "Escape from inside closes it; Escape elsewhere on the page does not. A Toggletip, Menu or Select inside closes first",
      "closing with focus inside returns focus to the last thing focused outside it — the row picked most recently",
      "no focus trap: Tab walks out of the panel into the rest of the page",
      "closed, it renders nothing, so it leaves no tab stops",
      "below 768px (`overlayBelow`) it opens as a Drawer, because there is no room beside the content and a panel covering the list must be modal to say so",
      "it sticks to `--ion-side-panel-top` while the page scrolls, and its body scrolls when the detail is taller than the screen",
      "the content column has `min-width: 0`, so a wide Table beside the panel scrolls in its own container rather than pushing the panel off screen"
    ],
    "notes": [
      "set `--ion-side-panel-top` on the app shell (any ancestor) to the height of a sticky app header, or the panel's top slides under it",
      "the title's heading level is `headingLevel`, default 2 — set it to follow the page's own outline",
      "`isOpen` and `onOpenChange` usually derive from the selected item: open while one is selected, and `onOpenChange(false)` clears the selection",
      "`autoFocus={false}` beside a List with `selectionMode=\"single\"`: its selection follows focus, so tabbing into the list selects the first row and opens the panel. Taking focus then would pull the user out of the list before they had pressed a key. Tab reaches the panel next, because it comes next in the DOM. The ListDetail pattern is this case. As a Drawer, below `overlayBelow`, it is modal and always takes focus"
    ]
  },
  "antiPatterns": [
    {
      "dont": "<Drawer> for a record's detail beside the list it came from",
      "do": "<SidePanelLayout><Table …/><SidePanel …/></SidePanelLayout>",
      "why": "a Drawer blocks the list: picking the next row means closing, clicking, reopening, and a screen reader is told the list is gone"
    },
    {
      "dont": "a SidePanel holding a form that must be saved or cancelled before anything else",
      "do": "<Drawer> or <Modal>",
      "why": "a live page beside an unsaved form lets the user wander off and lose it; that task wants to be modal"
    },
    {
      "dont": "the panel before the content in the DOM, moved to the right with CSS",
      "do": "content first, SidePanel second, inside SidePanelLayout",
      "why": "reading and Tab order would reach the detail before the list it is the detail of"
    },
    {
      "dont": "a SidePanel that takes focus on open, beside a List whose selection follows focus",
      "do": "`autoFocus={false}`, and rows that open on a press below `overlayBelow`",
      "why": "tabbing into the list selects its first row, the panel opens and takes focus, and the list can never be walked"
    },
    {
      "dont": "moving focus into the panel every time the selected row changes",
      "do": "let the panel follow the selection; it focuses its title only when it opens",
      "why": "focus jumping to the panel on each pick makes the list impossible to walk with the keyboard"
    }
  ],
  "stylesheet": "src/styles/side-panel.css",
  "tokens": [
    "--border-focus",
    "--border-subtle",
    "--border-width-default",
    "--border-width-thick",
    "--font-family-sans",
    "--font-weight-semibold",
    "--icon-secondary",
    "--icon-size-md",
    "--ion-duration-base",
    "--ion-ease-out",
    "--ion-side-panel-size",
    "--ion-side-panel-top",
    "--radius-lg",
    "--radius-sm",
    "--spacing-12",
    "--spacing-24",
    "--spacing-32",
    "--spacing-4",
    "--spacing-8",
    "--surface-default",
    "--surface-hover",
    "--text-default",
    "--text-secondary",
    "--type-body",
    "--type-body-line-height",
    "--type-body-sm",
    "--type-body-sm-line-height",
    "--type-h5",
    "--type-h5-line-height"
  ],
  "props": {
    "isOpen": {
      "type": "boolean | undefined",
      "required": false,
      "origin": "own"
    },
    "defaultOpen": {
      "type": "boolean | undefined",
      "required": false,
      "origin": "own"
    },
    "onOpenChange": {
      "type": "((isOpen: boolean) => void) | undefined",
      "required": false,
      "origin": "own",
      "description": "`false` when the panel asks to close — its close button, or Escape."
    },
    "title": {
      "type": "React.ReactNode",
      "required": true,
      "origin": "own",
      "description": "Required: names the region, and is where focus lands on open."
    },
    "description": {
      "type": "React.ReactNode",
      "required": false,
      "origin": "own"
    },
    "footer": {
      "type": "React.ReactNode",
      "required": false,
      "origin": "own",
      "description": "Actions pinned to the bottom edge."
    },
    "children": {
      "type": "React.ReactNode",
      "required": false,
      "origin": "own"
    },
    "size": {
      "type": "SidePanelSize | undefined",
      "required": false,
      "origin": "own",
      "description": "22rem, 30rem or 40rem — Drawer's sizes.",
      "values": [
        "sm",
        "md",
        "lg"
      ]
    },
    "headingLevel": {
      "type": "2 | 3 | 4 | undefined",
      "required": false,
      "origin": "own",
      "description": "The title's heading level. Default 2."
    },
    "showClose": {
      "type": "boolean | undefined",
      "required": false,
      "origin": "own"
    },
    "closeLabel": {
      "type": "string | undefined",
      "required": false,
      "origin": "own"
    },
    "autoFocus": {
      "type": "boolean | undefined",
      "required": false,
      "origin": "own",
      "description": "Focus the title on open. Default `true`. `false` when the panel opens\nbecause of where focus already is — a List whose selection follows focus,\nwhere tabbing in selects the first row — so focus stays in the list and\nthe next ↓ still reaches the next row. Tab from the list reaches the\npanel, which comes next in the DOM. Below `overlayBelow` it opens as a\nDrawer, which is modal and always takes focus."
    },
    "overlayBelow": {
      "type": "number | false | undefined",
      "required": false,
      "origin": "own",
      "description": "Below this viewport width, in px, there is no room beside the content and\nthe panel opens as a Drawer instead — modal, because it covers what it\nwould have sat beside. Default 768. `false` never switches.",
      "default": 768
    },
    "id": {
      "type": "string | undefined",
      "required": false,
      "origin": "own"
    },
    "className": {
      "type": "string | undefined",
      "required": false,
      "origin": "own"
    }
  },
  "propCounts": {
    "own": 15,
    "aria": 0,
    "dom": 0,
    "other": 0
  }
}
