@barefootjs/xyflow

中文文档
0.40.2发布于 2026/11/02MITTypeScriptES Module构建来源已验证近 30 天下载 3232

Signal-based xyflow wrapper for BarefootJS

原始使用文档
文档目录6 节
  1. Usage
  2. Custom node bodies
  3. What this package exports
  4. Source layout
  5. Browser bundle (importmap)
  6. Related

@barefootjs/xyflow

Signal-based wrapper around @xyflow/system for BarefootJS. Ships the utility layer (store, signal hooks, types, geometry helpers, imperative pointer-paced subsystems). The JSX-native renderer components (Flow, Background, Controls, MiniMap, Handle, NodeWrapper, SimpleEdge) live in the shadcn-style registry at ui/components/ui/xyflow/ and ship to consumers via:

bf add xyflow            # via the BarefootJS CLI
npx shadcn@latest add https://ui.barefootjs.dev/r/xyflow.json

This split mirrors the chart pattern (@barefootjs/chart for utility, ui/components/ui/chart/ for JSX components).

Usage

"use client"

import { Flow, Background, Controls, MiniMap } from "@/components/ui/xyflow"
import { useNodesState, useEdgesState } from "@barefootjs/xyflow"

const initialNodes = [
  { id: "1", position: { x: 100, y: 100 }, data: { label: "Input" } },
  { id: "2", position: { x: 350, y: 50 },  data: { label: "Transform" } },
  { id: "3", position: { x: 600, y: 125 }, data: { label: "Output" } },
]
const initialEdges = [
  { id: "e1-2", source: "1", target: "2" },
  { id: "e2-3", source: "2", target: "3" },
]

export function MyCanvas() {
  const [nodes, setNodes] = useNodesState(initialNodes)
  const [edges, setEdges] = useEdgesState(initialEdges)

  return (
    <div className="w-full h-[420px]">
      <Flow nodes={nodes()} edges={edges()}>
        <Background variant="dots" gap={20} />
        <Controls />
        <MiniMap pannable zoomable />
      </Flow>
    </div>
  )
}

Custom node bodies

The default <Flow> loop renders data.label ?? id inside each <NodeWrapper>. To compose custom node bodies, mount your own <NodeWrapper> instances as Flow children:

<Flow nodes={nodes()} edges={edges()}>
  <Background />
  {nodes().map((n) => (
    <NodeWrapper key={n.id} nodeId={n.id}>
      <div className="rounded-md border bg-card px-3 py-2">
        {n.data.label}
        <Handle type="target" position={Position.Left}  nodeId={n.id} />
        <Handle type="source" position={Position.Right} nodeId={n.id} />
      </div>
    </NodeWrapper>
  ))}
</Flow>

What this package exports

SurfaceItemPurpose
Store / statecreateFlowStore, FlowContextReactive node / edge / viewport state
HooksuseFlow, useViewport, useNodes, useEdges, useNodesInitialized, useStore, screenToFlowPositionRead store from descendants
React Flow shimuseNodesState, useEdgesState, useReactFlow, addEdge, reconnectEdgeDrop-in helpers for migrators
GeometrycomputeEdgePosition, getEdgePathPath math shared with <SimpleEdge>
Subsystem attachattachFlowSubsystems<Flow>'s ref calls this — pan / zoom / keyboard / selection rectangle / pane click
Subsystem attachattachConnectionHandler, attachReconnectionHandler<Handle> and reconnect overlay refs
Subsystem attachmeasureNode<NodeWrapper>'s ResizeObserver — node size + handle bounds for edge endpoints
Imperative-onlysetupKeyboardHandlers, setupNodeSelection, setupSelectionRectangle, initNodeResizerPointer-paced primitives that JSX gives no leverage to
Re-exportsgetBezierPath, getSmoothStepPath, getStraightPath, getConnectedEdges, getOutgoers, getIncomers, getNodesBounds, getNodesInside, getEdgeToolbarTransform, Position, MarkerType, ConnectionModeFrom @xyflow/system
TypesFlowProps, FlowStore, InternalFlowStore, NodeBase, EdgeBase, Viewport, NodeLookup, EdgeLookup, Connection, OnConnect, OnReconnect, IsValidConnection, HandleType, …(see src/types.ts)

Source layout

src/
├── index.ts            re-exports the utility surface above
├── store.ts            createFlowStore + signal wiring
├── hooks.ts            useFlow / useViewport / useNodes / ...
├── context.ts          FlowContext
├── types.ts            FlowProps / FlowStore / InternalFlowStore / ...
├── constants.ts        SVG_NS / INFINITE_EXTENT / ...
├── utils.ts            misc helpers
├── edge-path.ts        computeEdgePosition / getEdgePath
├── flow-subsystems.ts  attachFlowSubsystems (panZoom + ResizeObserver + ...)
├── connection.ts       attachConnectionHandler / attachReconnectionHandler
├── selection.ts        setupKeyboardHandlers / setupSelectionRectangle / setupNodeSelection
├── node-measure.ts     measureNode (node size + handle bounds)
├── node-resizer.ts     initNodeResizer (pointer-paced resize handles)
├── compat.ts           React Flow API shims
└── __tests__/          store / compat / jsx-smoke unit tests

JSX-native components are deliberately not in this package — they live in ui/components/ui/xyflow/index.tsx so consumers add the source directly into their app, can edit it, and own their own copy (shadcn pattern). This avoids the JSX-runtime resolution headaches that come from publishing .tsx directly from a workspace package.

Browser bundle (importmap)

bun run build also emits dist/xyflow.browser.min.js: a minified ESM build with @barefootjs/client, @barefootjs/client/runtime and @barefootjs/client/reactive left as externals (build:browser in package.json). Serve it as an independently cached static asset instead of re-bundling xyflow into every client entry. Re-bundling by hand needs all three externals — missing one silently inlines a second copy of the reactive primitives, and signals stop propagating across the boundary (fitView becomes a no-op, FlowContext reads from the wrong owner).

The file is also the umd export condition and the unpkg / jsdelivr top-level fields, so https://unpkg.com/@barefootjs/xyflow serves it.

Copy it next to your client build and map it in an importmap:

cp node_modules/@barefootjs/xyflow/dist/xyflow.browser.min.js public/static/components/xyflow.js
cp node_modules/@barefootjs/xyflow/dist/xyflow.browser.min.js.map public/static/components/xyflow.js.map  # optional
<script type="importmap">
{
  "imports": {
    "@barefootjs/client":          "/static/components/barefoot.js",
    "@barefootjs/client/runtime":  "/static/components/barefoot.js",
    "@barefootjs/client/reactive": "/static/components/barefoot.js",
    "@barefootjs/xyflow":          "/static/components/xyflow.js"
  }
}
</script>

All three @barefootjs/client* entries point at one file so the browser keeps a single module instance and the reactive primitives share one Listener / Owner.

  • Escape < inside the importmap JSON. A mapped URL containing </script> would close the <script type="importmap"> element early. When serializing the map dynamically, replace every < with \u003c before writing it into the tag — JSON decodes it back to <.

  • Add crossorigin to a cross-origin modulepreload, e.g. when pointing at the unpkg URL instead of a copied file:

    <link rel="modulepreload" href="https://unpkg.com/@barefootjs/xyflow" crossorigin>
    

    A module import is always a CORS fetch; without crossorigin the preload does not match it and the browser fetches the module twice. It is harmless on a same-origin preload.

  • @xyflow/system — upstream pan/zoom + edge-path math library this package wraps.

版本与发布记录

@barefootjs/xyflow 共发布 112 个版本,首次发布于 2026/05/25;过去 12 个月发布了 112 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.40.2latest2026/11/025 天前
0.40.12026/10/299 天前
0.40.02026/10/2612 天前
0.39.92026/10/2513 天前
0.39.82026/10/2117 天前
0.39.72026/10/1820 天前

关于 @barefootjs/xyflow 的常见问题

@barefootjs/xyflow 是什么?

Signal-based xyflow wrapper for BarefootJS

如何安装 @barefootjs/xyflow?

在项目目录运行 npm install @barefootjs/xyflow,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:@barefootjs/jsx(>=0.2.0)、@barefootjs/client(>=0.2.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@barefootjs/xyflow 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@barefootjs/xyflow 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@barefootjs/xyflow 可以商用吗?

@barefootjs/xyflow 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@barefootjs/xyflow 的下载量有多少?

根据 npm 官方下载统计,@barefootjs/xyflow 在 2026/10/08 – 2026/11/06 这 30 天内被下载 3,232 次,日均约 108 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@barefootjs/xyflow 还在维护吗?

最新版本 0.40.2 发布于 2026/11/02(5 天前);至今共发布 112 个版本,其中过去 12 个月发布了 112 个;首次发布于 2026/05/25。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。