# AppShell

> El layout de un panel: sidebar sticky desde `lg` y, debajo, una barra de 56px con hamburguesa.

```tsx
import { AppShell } from "sebs7n-ui/app-shell"
```

## Ejemplos

### El layout completo

Achicá la ventana por debajo de 1024px: el sidebar pasa a un Sheet detrás de la hamburguesa. El alto sale de `--app-shell-height`; acá está fijado en 560px para que entre en la página.

```tsx
import { AppShell } from "sebs7n-ui/app-shell"
import { AppShellContent } from "sebs7n-ui/app-shell-content"
import { Button } from "sebs7n-ui/button"
import { Card, CardContent } from "sebs7n-ui/card"
import { DropdownMenuItem } from "sebs7n-ui/dropdown-menu"
import { FileTextIcon, LogOutIcon, UsersIcon } from "lucide-react"
import { PageHeader, PageHeaderActions, PageHeaderDescription, PageHeaderTitle } from "sebs7n-ui/page-header"
import { Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupLabel, SidebarHeader, SidebarItem } from "sebs7n-ui/sidebar"
import { Stat } from "sebs7n-ui/stat"
import { UserMenu } from "sebs7n-ui/user-menu"

function Completo() {
  const usuario = { name: "Ana Pérez", email: "ana@acme.com" }
  return (
    <div className="overflow-hidden rounded-xl border border-gray-400">
      <AppShell
        className="[--app-shell-height:560px]"
        mobileBar={
          <>
            <div className="size-6 rounded-md bg-gray-1000" />
            <span className="ml-auto" />
            <UserMenu collapsed user={usuario} />
          </>
        }
        sidebar={
          <Sidebar>
            <SidebarHeader>
              <div className="flex h-8 items-center gap-2 px-1">
                <div className="size-6 shrink-0 rounded-md bg-gray-1000" />
                <span className="text-label-14 font-medium">Acme</span>
              </div>
            </SidebarHeader>
            <SidebarContent>
              <SidebarGroup>
                <SidebarGroupLabel>Operación</SidebarGroupLabel>
                <SidebarItem active icon={<FileTextIcon />}>
                  Facturas
                </SidebarItem>
                <SidebarItem icon={<UsersIcon />}>Clientes</SidebarItem>
              </SidebarGroup>
            </SidebarContent>
            <SidebarFooter>
              <UserMenu
                signOut={
                  <DropdownMenuItem>
                    <LogOutIcon />
                    Cerrar sesión
                  </DropdownMenuItem>
                }
                user={usuario}
              />
            </SidebarFooter>
          </Sidebar>
        }
      >
        <AppShellContent>
          <PageHeader>
            <PageHeaderTitle>Facturas</PageHeaderTitle>
            <PageHeaderDescription>Todo lo emitido en septiembre.</PageHeaderDescription>
            <PageHeaderActions>
              <Button variant="accent">Nueva factura</Button>
            </PageHeaderActions>
          </PageHeader>
          <div className="grid gap-4 sm:grid-cols-2">
            <Card size="sm">
              <CardContent>
                <Stat delta="+12,4 %" hint="vs. agosto" label="Facturado" trend="up" value="$ 1.284.000" />
              </CardContent>
            </Card>
            <Card size="sm">
              <CardContent>
                <Stat delta="6 facturas" label="Vencido" trend="down" value="$ 142.900" />
              </CardContent>
            </Card>
          </div>
        </AppShellContent>
      </AppShell>
    </div>
  )
}
```

## Props

### AppShell

Hereda las props de `<div>`.

| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
| `sidebar` * | `React.ReactNode` | — | Un <Sidebar>. Se renderiza fijo en desktop y dentro de un Sheet en mobile. |
| `labels` | `Partial<AppShellLabels>` | — | — |
| `mainId` | `string` | `"contenido"` | `id` del `<main>`; es a donde apunta el skip link. |
| `mobileBar` | `React.ReactNode` | — | Contenido de la barra de 56px a la derecha de la hamburguesa. |
| `pathname` | `string` | — | La ruta actual. Cuando cambia, el Sheet mobile se cierra. |
| `className` | `string` | — | — |

`*` obligatoria.

## Teclado

| Tecla | Qué hace |
|---|---|
| Tab (primera parada) | «Ir al contenido», el skip link que salta al `<main>`. |
| Escape | Cierra el Sheet mobile. |

## Accesibilidad

- Trae el skip link «Ir al contenido» apuntando al `<main>`: es la primera parada de tabulación de toda la app.
- El `<main>` tiene `id` (`mainId`, por defecto `contenido`) y es enfocable por programa.
- Al elegir un ítem en el Sheet mobile, se cierra y el foco va al `<main>`.
- Los textos son configurables por `labels`, para traducir la app entera.

## Reglas de uso

- **Pasale `pathname={usePathname()}`**: cualquier navegación —un link del contenido, un `router.push`— cierra el Sheet mobile.
- **Usá `AppShellContent` como hijo directo**: es el contenedor de página, así todas las pantallas tienen el mismo ancho.
- El alto sale de `--app-shell-height` (100dvh). Para embeberlo en una caja: `className="[--app-shell-height:720px]"`.
- Para cerrar el Sheet desde un caso propio: `useAppShell().closeMobile({ focusMain: true })`.

## Relacionados

[sidebar](/docs/components/sidebar.md) · [app-shell-content](/docs/components/app-shell-content.md) · [user-menu](/docs/components/user-menu.md) · [sheet](/docs/components/sheet.md)
