React 19 · gzip 后 8 kB · 零依赖

工具之下的
骨架

边缘是图标导轨,中间是你自己的区域,四周是可调节大小的面板;刷新页面后布局依然还在。底层无渲染,上层可随意重绘。

查看示例
这是实时的。拖动面板之间的缝隙,点击导轨图标或把它拖到另一半,或调整窗口大小。

四种上手方式

每个示例都在你的浏览器中运行,完整源码就在下方。从最接近你需求的那个开始。

最小示例

能跑起来的最小骨架:两列、一条底栏、一个中心区域,以及一个由你掌控的顶栏。

import { Panels, Panel } from '@pasquelin/panels'
import '@pasquelin/panels/styles.css'

<Panels<PanelId>>
  <Panel<PanelId> id="files" zone="left" title="Files">
    <FileTree />
  </Panel>

  <Panel<PanelId> id="notes" zone="right" opens={380}>
    <Notes />
  </Panel>

  <Panels.Center>
    <YourApp />
  </Panels.Center>
</Panels>

提示。 共用同一区域和同一半的面板会轮流显示,由导轨切换。想让它们同时显示,就把第二个放进 secondary 半区,它会叠在第一个下方。 在这里,导轨图标还可以从一半拖到另一半。

打开最小示例

React Router

中心区域是一个出口。导航只改变中间内容——列宽保持不变,打开的面板依然打开。

function Layout() {
  return (
    <Panels<PanelId>>
      <Panel<PanelId> id="sites" zone="left" title="Sites">
        <SiteList />
      </Panel>

      <Panels.Center>
        <Outlet />
      </Panels.Center>
    </Panels>
  )
}

提示。 把面板声明在布局路由里、出口之上。若逐页声明,每次导航都会卸载它们,其中的状态也随之丢失。

打开React Router

文档标签页

中心区域用 Dockview 承载文档——可拖拽、可分屏的标签页——而面板始终留在边缘。

import { DockviewCenter } from '@pasquelin/panels/dockview'

<Panels.Center>
  <DockviewCenter
    documents={{ editor: Editor }}
    empty={NothingOpen}
    onReady={setApi}
  />
</Panels.Center>

提示。 从 dockview 入口导入,它的体积就只落在需要标签页的项目上。工具面板永远不进入中心:文档有名字,面板有图标。

打开文档标签页

重新配色

同一个骨架,四套配色。颜色、圆角、导轨宽度、标题栏高度——全都是自定义属性。

.pnl-root {
  --pnl-chassis: #2e2b26;
  --pnl-panel: #1b1916;
  --pnl-accent: #d99a2b;
  --pnl-radius: 12px;
  --pnl-rail: 60px;
}

提示。 在任意祖先元素上设置强调色变量,骨架就会继承你的品牌色,而不是强加自己的。还不够?每个部件都已导出,可以单独替换。

打开重新配色

全部 API

并不多,这正是重点。只需了解六件事。

声明

面板是一个描述符:挂在哪里、叫什么名字、渲染什么内容。

<Panel id="files" zone="left" title="Files" icon={<Icon />}>
  <FileTree />
</Panel>
控制

一个 hook,供任何需要操作面板的顶栏、快捷键或菜单使用。

const { reveal, close, toggle, isShown } = usePanels<PanelId>()
重新排列

一个属性,读者就能把导轨图标拖到另一半。放置的位置会与其余布局一起被记住。

<Panels<PanelId> draggablePanels>
在 React 之外控制

自己创建 store,之后 socket 消息、原生菜单或 worker 都能打开面板。

const store = createPanelsStore<PanelId>()
socket.on('alert', () => store.getState().show('alerts'))
重新配色

每个值都是自定义属性。设置强调色,导轨就会跟随你的品牌。

.pnl-root {
  --pnl-panel: #101418;
  --pnl-accent: #47965c;
  --pnl-radius: 10px;
}
或只取逻辑

组件建立在不渲染任何内容的 hook 之上。用它们画你自己的框架。

const zone = useZone('left')
useContainerFit(ref)