# SplitView

> El master-detail de iCloud Mail: sidebar, lista y detalle separados por la línea entre paneles, que en el teléfono pasa a un panel por vez con «‹ Atrás».

```tsx
import { SplitView, SplitViewBack, SplitViewDetail, SplitViewList, … } from "sebs7n-ui/split-view"
```

## Ejemplos

### Sidebar, lista y detalle

El master-detail de Mail: se acomoda al ancho que le toca. Ancho, los tres paneles; mediano, lista y detalle; angosto (el teléfono), un panel por vez y «‹ Atrás» vuelve al anterior. Achicá la ventana para verlo.

```tsx
function Basico() {
  return <Correo />
}
```

### Redimensionable

Con `resizable`, el sidebar y la lista llevan el separador de `Resizable` en su borde: se arrastra o se enfoca con Tab y se mueve con las flechas (10 px, Shift 40). Por defecto no, como Mail.

```tsx
function Redimensionable() {
  return <Correo resizable />
}
```

## Props

### SplitView

Hereda las props de `<div>`.

| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
| `defaultPane` | `"list" \| "sidebar" \| "detail"` | `"list"` | El panel activo al arrancar. Por defecto `list`. |
| `defaultWidths` | `Partial<SplitViewWidths>` | — | Los anchos al arrancar, en px (`{ sidebar, list }`). Por defecto 230 y 380. |
| `onPaneChange` | `(pane: SplitViewPane) => void` | — | Se llama con el panel nuevo. |
| `onWidthsChange` | `(widths: SplitViewWidths) => void` | — | Se llama con los anchos al soltar un separador o con cada tecla. |
| `pane` | `"list" \| "sidebar" \| "detail"` | — | El panel activo (`sidebar`, `list`, `detail`): el que se ve en angosto. Pasarlo lo vuelve controlado. |
| `resizable` | `boolean` | `false` | El sidebar y la lista se redimensionan con un separador en su borde. Por defecto no, como Mail. |
| `className` | `string` | — | Se fusiona con las clases del componente vía `cn()` (tailwind-merge): lo que pongas gana. |

### SplitViewBack

Hereda las props de `<button>`.

| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
| `onClick` | `MouseEventHandler<T>` | — | Se llama antes de volver. Con `event.preventDefault()` no vuelve (para confirmar un cambio sin guardar). |
| `to` | `"list" \| "sidebar" \| "detail"` | — | Adónde vuelve. Por defecto, el anterior: del detalle a la lista, de la lista al sidebar. El texto del botón (los hijos) es el nombre de ese panel («Facturas»). |
| `className` | `string` | — | Se fusiona con las clases del componente vía `cn()` (tailwind-merge): lo que pongas gana. |

### SplitViewDetail

Sin props propias: pasa todo al primitivo.

### SplitViewList

Sin props propias: pasa todo al primitivo.

### SplitViewSidebar

Sin props propias: pasa todo al primitivo.

## Teclado

| Tecla | Qué hace |
|---|---|
| Tab | Recorre los paneles en orden: sidebar, lista, detalle. En angosto, solo el que se ve. |
| Enter | En `SplitViewBack`, vuelve al panel anterior. |
| ← → (en un separador, con `resizable`) | Cambian el ancho del panel de a 10 px; con Shift, 40. Home y End, al mínimo y al máximo. |

## Accesibilidad

- Cada panel es un `<section>`: con `aria-label` es una región con nombre, y el lector salta entre paneles con los atajos de regiones.
- En angosto los paneles que no se ven llevan `display: none`: no quedan en el orden de Tab ni los lee el lector.
- **Al pasar de panel en angosto, el foco va solo**: si estaba en el panel que se oculta, pasa al que llega —a la fila elegida (`aria-current` o `data-state="selected"`) al volver a la lista, o al primer título del panel—. En ancho, donde el de antes sigue a la vista, no se mueve.
- `SplitViewBack` es un `<button>` con el nombre del panel al que vuelve («‹ Facturas»), como iOS: nunca solo el chevron.
- Con `resizable`, cada separador es un `role="separator"` tabulable con el ancho en px (`aria-valuenow/min/max`), `aria-controls` al panel y el nombre del panel («Cambiar el tamaño: Facturas»). En angosto no se ve.

## Reglas de uso

- **Para recorrer una colección y ver un ítem al lado**: comprobantes, clientes, mensajes. Si el detalle es otra pantalla, es una `List` con `chevron`.
- Anchos de iCloud: sidebar 230, lista 380 (320 en mediano), detalle el resto. Se acomoda al **ancho del contenedor** (container query), no al de la ventana: adentro de un panel angosto también pasa a un panel.
- **La fila de la lista llama `setPane("detail")`** (`useSplitView()`) al elegirse: en ancho no cambia nada, en angosto muestra el detalle.
- Dos paneles: omití el que sobra. Sin lista, `SplitViewBack` del detalle vuelve al sidebar con `to="sidebar"`.
- No se redimensiona, como iCloud. Con `resizable`, el sidebar (180–360) y la lista (260–560) llevan el separador de `Resizable` en su borde; guardá los anchos de `onWidthsChange` y devolvelos en `defaultWidths`. Para repartir en % otra cosa, `Resizable`.
- El alto lo pone quien lo contiene (`h-full` adentro de `AppShell`, o un alto fijo); cada panel scrollea por su cuenta.
- Solo por subpath (`sebs7n-ui/split-view`): no está en el barrel, por peso.

## Relacionados

[list-row](/docs/components/list-row.md) · [app-shell](/docs/components/app-shell.md) · [sidebar](/docs/components/sidebar.md) · [resizable](/docs/components/resizable.md)
