章节
组件
import {
ResizableHandle,
ResizablePanel,Resizable 会把一块区域拆分成多个面板,用户拖动分隔条即可重新分配比例——横向或纵向都行,可以嵌套,手柄也支持键盘操作。两种变体封装的都是 bvaughn 的 react-resizable-panels,并按新粗野主义的配方设计:粗边框、硬阴影、加粗字体。
适合以下场景:
- 代码编辑器与 IDE 式布局——文件树、编辑器和预览窗格,尺寸由用户自己定。
- 主从视图——收件箱与会话、表格与记录详情,分隔线就放在用户想要的位置。
- 仪表盘与控制台——让日志窗格或终端从主视图里挤出高度,无需弹出模态框。
关于#
Resizable 组件基于 bvaughn 开发的 react-resizable-panels 构建。
安装#
pnpm dlx shadcn@latest add https://neobrutalism.com/r/base/resizable.jsonnpx shadcn@latest add https://neobrutalism.com/r/base/resizable.jsonyarn dlx shadcn@latest add https://neobrutalism.com/r/base/resizable.jsonbunx --bun shadcn@latest add https://neobrutalism.com/r/base/resizable.json
安装以下依赖:
pnpm add react-resizable-panelsnpm install react-resizable-panelsyarn add react-resizable-panelsbun add react-resizable-panels
将以下代码复制并粘贴到您的项目中。
"use client"
import * as ResizablePrimitive from "react-resizable-panels"
import { cn } from "@/lib/utils"
function ResizablePanelGroup({
className,
...props
}: ResizablePrimitive.GroupProps) {
return (
<ResizablePrimitive.Group
data-slot="resizable-panel-group"
className={cn(
"flex h-full w-full aria-[orientation=vertical]:flex-col",
className
)}
{...props}
/>
)
}
function ResizablePanel({ ...props }: ResizablePrimitive.PanelProps) {
return <ResizablePrimitive.Panel data-slot="resizable-panel" {...props} />
}
function ResizableHandle({
withHandle,
className,
...props
}: ResizablePrimitive.SeparatorProps & {
withHandle?: boolean
}) {
return (
<ResizablePrimitive.Separator
data-slot="resizable-handle"
className={cn(
"relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary aria-[orientation=horizontal]:h-px aria-[orientation=horizontal]:w-full aria-[orientation=horizontal]:after:left-0 aria-[orientation=horizontal]:after:h-1 aria-[orientation=horizontal]:after:w-full aria-[orientation=horizontal]:after:translate-x-0 aria-[orientation=horizontal]:after:-translate-y-1/2 [&[aria-orientation=horizontal]>div]:rotate-90",
className
)}
{...props}
>
{withHandle && (
<div className="z-10 flex h-6 w-1 shrink-0 rounded-lg bg-border" />
)}
</ResizablePrimitive.Separator>
)
}
export { ResizableHandle, ResizablePanel, ResizablePanelGroup }
更新导入路径以匹配您的项目结构。
用法#
import {
ResizableHandle,
ResizablePanel,
ResizablePanelGroup,
} from "@/components/ui/resizable"<ResizablePanelGroup orientation="horizontal">
<ResizablePanel>One</ResizablePanel>
<ResizableHandle />
<ResizablePanel>Two</ResizablePanel>
</ResizablePanelGroup>组合#
使用以下组合来构建 ResizablePanelGroup:
ResizablePanelGroup
├── ResizablePanel
├── ResizableHandle
└── ResizablePanel示例#
垂直#
对于垂直方向的调整,使用 orientation="vertical"。
import {
ResizableHandle,
ResizablePanel,手柄#
使用 ResizableHandle 上的 withHandle 属性显示可见的手柄。
import {
ResizableHandle,
ResizablePanel,RTL#
若要在 Neobrutalism 中启用 RTL 支持,请参阅 RTL 配置指南。
"use client"
import * as React from "react"无障碍#
手柄遵循 WAI-ARIA Window Splitter 模式:react-resizable-panels 会把每个手柄渲染成可聚焦的 role="separator",带上 aria-valuenow / aria-valuemin / aria-valuemax,并让 aria-controls 指向它所调整的那个面板,因此分隔位置一变化,屏幕阅读器就会播报出来。
键盘交互:
| 按键 | 操作 |
|---|---|
Tab / Shift + Tab | 把焦点移到某个调整手柄上或移开 |
ArrowLeft / ArrowRight | 按一个步长调整横向面板组 |
ArrowUp / ArrowDown | 按一个步长调整纵向面板组 |
Home | 把手柄前面的面板收缩到最小尺寸 |
End | 把手柄前面的面板扩展到最大尺寸 |
Enter | 在折叠与展开之间切换可折叠面板 |
API 参考#
更多信息请参阅 react-resizable-panels 文档。
更新日志#
2025-02-02 react-resizable-panels v4#
已更新至 react-resizable-panels v4。完整详情请参阅 v4.0.0 发布说明。
如果您直接使用 react-resizable-panels 的基础原语,请注意以下变更:
| v3 | v4 |
|---|---|
PanelGroup | Group |
PanelResizeHandle | Separator |
direction prop | orientation prop |
defaultSize={50} | defaultSize="50%" |
onLayout | onLayoutChange |
ImperativePanelHandle | PanelImperativeHandle |
ref prop on Panel | panelRef prop |
data-panel-group-direction | aria-orientation |
Neobrutalism 的封装组件(ResizablePanelGroup、ResizablePanel、
ResizableHandle)保持不变。