Resizable
Paneles que se reparten el espacio y se redimensionan arrastrando la línea entre paneles de Mail, que se vuelve acento al agarrarla; con teclado, mínimos, máximos y el reparto para guardar.
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "sebs7n-ui/resizable"Ejemplos
Carpetas, lista y vista previa
Tres paneles lado a lado: la línea entre paneles de Mail se agarra (se vuelve acento) y se arrastra, o se enfoca con Tab y se mueve con las flechas. `onLayout` avisa el reparto para guardarlo.
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "sebs7n-ui/resizable"
import { useState } from "react"
function Basico() {
const [reparto, setReparto] = useState<number[]>([22, 33, 45])
return (
<div className="flex w-full flex-col gap-2">
<div className="h-72 w-full overflow-hidden rounded-surface border border-separator-strong">
<ResizablePanelGroup defaultLayout={reparto} onLayout={setReparto}>
<ResizablePanel className="bg-surface-secondary p-4" maxSize={40} minSize={15}>
<p className="text-callout font-semibold">Carpetas</p>
<p className="text-callout text-label-secondary">Emitidas · Recibidas · Archivo</p>
</ResizablePanel>
<ResizableHandle aria-label="Ancho de las carpetas" />
<ResizablePanel className="p-4" minSize={25}>
<p className="text-callout font-semibold">Facturas</p>
<p className="text-callout text-label-secondary">A-0012 · Acme S.A.</p>
</ResizablePanel>
<ResizableHandle aria-label="Ancho de la lista" withHandle />
<ResizablePanel className="p-4" minSize={25}>
<p className="text-callout font-semibold">Vista previa</p>
<p className="text-callout text-label-secondary">Servicios de septiembre · $ 128.400</p>
</ResizablePanel>
</ResizablePanelGroup>
</div>
<p className="text-footnote text-label-secondary tabular-nums">Reparto: {reparto.map((size) => `${Math.round(size)} %`).join(" · ")}</p>
</div>
)
}Apilados
`orientation="vertical"`: el detalle arriba y las notas abajo; la línea se mueve con ↑ ↓.
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "sebs7n-ui/resizable"
function Vertical() {
return (
<div className="h-72 w-full max-w-md overflow-hidden rounded-surface border border-separator-strong">
<ResizablePanelGroup orientation="vertical">
<ResizablePanel className="p-4" defaultSize={60} minSize={30}>
<p className="text-callout font-semibold">Factura A-0012</p>
<p className="text-callout text-label-secondary">Acme S.A. · Vence el 30/09</p>
</ResizablePanel>
<ResizableHandle aria-label="Alto de las notas" withHandle />
<ResizablePanel className="bg-surface-secondary p-4" minSize={20}>
<p className="text-callout font-semibold">Notas internas</p>
<p className="text-callout text-label-secondary">Pedir la orden de compra antes de enviar.</p>
</ResizablePanel>
</ResizablePanelGroup>
</div>
)
}Props
Generadas del TypeScript del paquete. Las propias del componente, más las heredadas del primitivo que tienen algo que explicar —marcadas «heredada de Base UI»—. El resto está en la línea «hereda de».
ResizableHandle
Hereda las props de <div>.
| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
aria-label | string | — | Nombre accesible del elemento. |
onKeyDown | KeyboardEventHandler<T> | — | Se llama antes de mover. Con event.preventDefault(), la tecla no mueve. |
onPointerDown | PointerEventHandler<T> | — | Se llama antes de empezar a arrastrar. Con event.preventDefault(), no arrastra. |
withHandle | boolean | false | Una manija visible en el medio de la línea. |
className | string | — | Se fusiona con las clases del componente vía cn() (tailwind-merge): lo que pongas gana. |
ResizablePanel
Hereda las props de <div>.
| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
defaultSize | number | — | El tamaño al arrancar, en %. Sin él, reparte el resto. |
id | string | — | El id del panel (el aria-controls del separador). Por defecto, uno generado. |
maxSize | number | 100 | El máximo, en %. Por defecto, 100. |
minSize | number | 0 | El mínimo, en %. Por defecto, 0. |
style | CSSProperties | — | Se suma al flex que pone el reparto; no pises flex-grow. |
className | string | — | Se fusiona con las clases del componente vía cn() (tailwind-merge): lo que pongas gana. |
ResizablePanelGroup
Hereda las props de <div>.
| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
defaultLayout | number[] | — | Los tamaños al arrancar (lo guardado con onLayout). Le gana al defaultSize de cada panel. |
keyboardStep | number | 5 | Cuánto mueve una flecha, en %. Shift, el doble. Por defecto, 5. |
onLayout | (sizes: number[]) => void | — | Se llama con los tamaños (en %, en el orden de los paneles) al soltar o con cada tecla. |
orientation | "horizontal" | "vertical" | "horizontal" | horizontal (default, lado a lado) o vertical (apilados). |
className | string | — | Se fusiona con las clases del componente vía cn() (tailwind-merge): lo que pongas gana. |
Teclado
- Tab
- Enfoca el separador (la línea pasa a la banda de foco de 3 px).
- ← → (lado a lado) · ↑ ↓ (apilados)
- Mueven la línea de a
keyboardStep(5 %); con Shift, el doble. En RTL, ← agranda el panel de antes. - Home / End
- Llevan el panel de antes a su mínimo o a su máximo.
Accesibilidad
- Cada
ResizableHandlees el «window splitter» de WAI-ARIA:role="separator"tabulable conaria-orientation,aria-valuenow(el tamaño del panel de antes, en %),aria-valuemin/aria-valuemax(los reales, sin romper al vecino) yaria-controlsal panel que mueve. - Nombralo por lo que cambia: «Ancho de la lista» (
aria-label). Sin él dice «Cambiar el tamaño», que con dos separadores no alcanza. - La manija (
withHandle) es decorativa. El área para agarrar la línea mide 12 px (24 con el dedo) aunque la línea mida 1.
Reglas de uso
- Para que la persona decida cuánto lugar le da a cada parte: una lista y su vista previa, un editor y su resultado. Si los anchos fijos alcanzan,
SplitViewsin redimensionar, como Mail. - Los tamaños son porcentajes del grupo:
defaultSize,minSize,maxSizepor panel. Los que no traendefaultSizese reparten el resto. - Para recordar el reparto: guardá lo que llega en
onLayout(al soltar o con cada tecla) y devolvelo endefaultLayout. - El grupo toma el alto de su contenedor (
h-full): ponele un alto al de afuera. Cada panel scrollea por su cuenta. SplitView resizableusa la misma línea en px para el sidebar y la lista.- Solo por subpath (
sebs7n-ui/resizable): no está en el barrel, por peso.