# app-shell

- 分组：组合组件（Composite）
- 页面：/components/app-shell
- 源码：packages/react/src/components/app-shell.tsx

## 导出

```ts
import { AppShell, SiderCollapseButton, SiderToggle, useSiderToggle } from "@modra/react";
```

## Props（AppShellProps）

| 名称 | 必填 | 类型 | 说明 |
| --- | --- | --- | --- |
| `breakpoint` | 否 | `Breakpoint` | Below this breakpoint the shell renders the mobile layout (top bar + content + tabbar). |
| `sidebar` | 否 | `React.ReactNode` | Desktop navigation, rendered inside a collapsible Sider. Below the breakpoint it moves into a drawer. |
| `header` | 否 | `React.ReactNode` | Shown above the content on both desktop and mobile. On mobile it sits in the top bar after the hamburger. |
| `brand` | 否 | `React.ReactNode` | Logo / product name shown in the mobile top bar next to the hamburger button. |
| `tabbar` | 否 | `React.ReactNode` | Mobile bottom navigation, typically a <Tabbar>. Ignored on desktop. |
| `siderWidth` | 否 | `number \| string` | Expanded sidebar width. Defaults to the `--component-layout-sider-width` token. |
| `siderCollapsed` | 否 | `boolean` |  |
| `defaultSiderCollapsed` | 否 | `boolean` |  |
| `onSiderCollapse` | 否 | `(collapsed: boolean) => void` |  |
| `siderCollapsedStorageKey` | 否 | `string` | Persist the uncontrolled sidebar collapsed state in `localStorage` under this key. The stored value is read after mount (SSR-safe) and wins over `defaultSiderCollapsed`; storage errors are ignored. Has no effect when `siderCollapsed` is controlled. |
| `siderTrigger` | 否 | `React.ReactNode` | Replaces the built-in collapse strip at the bottom of the sidebar. `null` hides it; pair that with a `SiderCollapseButton` (or `useSiderToggle`) inside `sidebar`. Defaults to the built-in strip. |
| `expandSiderOnGroupClick` | 否 | `boolean` | When the desktop sidebar is collapsed, activating a submenu trigger of a Menu inside it expands the sidebar (through `onSiderCollapse(false)`) and opens that submenu inline instead of a flyout. Defaults to true. |
| `siderTheme` | 否 | `"light" \| "dark"` | Surface of the sidebar and of the mobile drawer. `dark` uses the `sidebar*` tokens. |
| `mobileNav` | 否 | `AppShellMobileNav` | How the sidebar is reached below the breakpoint. `drawer` (default) renders a hamburger button in the top bar that opens the sidebar in a sheet; `none` keeps the previous behavior of hiding it. |
| `drawerOpen` | 否 | `boolean` |  |
| `defaultDrawerOpen` | 否 | `boolean` |  |
| `onDrawerOpenChange` | 否 | `(open: boolean) => void` |  |
| `drawerWidth` | 否 | `number \| string` | Drawer width; defaults to 18rem capped at 85vw. |
| `closeDrawerOnNavigate` | 否 | `boolean` | Close the drawer when a link or a leaf menu item inside it is activated. Defaults to true. |
| `contentClassName` | 否 | `string` |  |
| `fullscreen` | 否 | `boolean` | Fill the dynamic viewport (`h-dvh`) instead of the parent's height (`h-full`). Enable it when the shell is the page root so no wrapper needs an explicit height. |
