@og-mcp/reactflow-mcp 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +74 -74
- package/dist/data/api-types.js +69 -69
- package/dist/data/components.js +217 -217
- package/dist/data/hooks.js +106 -106
- package/dist/data/migration.js +44 -44
- package/dist/data/patterns.js +582 -582
- package/dist/data/templates.js +126 -126
- package/dist/data/utilities.js +29 -29
- package/dist/index.js +0 -0
- package/dist/tools/cheatsheet.js +84 -84
- package/dist/tools/generate-flow.js +89 -89
- package/package.json +54 -54
package/dist/data/hooks.js
CHANGED
|
@@ -7,37 +7,37 @@ const useReactFlowHook = {
|
|
|
7
7
|
description: "Returns a ReactFlowInstance to update nodes/edges, manipulate the viewport, or query flow state. Does NOT cause re-renders on state changes.",
|
|
8
8
|
importPath: "import { useReactFlow } from '@xyflow/react'",
|
|
9
9
|
returns: "ReactFlowInstance",
|
|
10
|
-
usage: `const { getNodes, setNodes, addNodes, getEdges, setEdges, addEdges,
|
|
11
|
-
fitView, zoomIn, zoomOut, getViewport, setViewport,
|
|
12
|
-
screenToFlowPosition, deleteElements, updateNode, updateNodeData,
|
|
10
|
+
usage: `const { getNodes, setNodes, addNodes, getEdges, setEdges, addEdges,
|
|
11
|
+
fitView, zoomIn, zoomOut, getViewport, setViewport,
|
|
12
|
+
screenToFlowPosition, deleteElements, updateNode, updateNodeData,
|
|
13
13
|
getIntersectingNodes, toObject } = useReactFlow();`,
|
|
14
14
|
examples: [
|
|
15
15
|
{
|
|
16
16
|
title: "Add node on button click",
|
|
17
17
|
category: "interaction",
|
|
18
|
-
code: `function AddNodeButton() {
|
|
19
|
-
const { addNodes, screenToFlowPosition } = useReactFlow();
|
|
20
|
-
const onClick = () => {
|
|
21
|
-
addNodes({
|
|
22
|
-
id: crypto.randomUUID(),
|
|
23
|
-
position: screenToFlowPosition({ x: 200, y: 200 }),
|
|
24
|
-
data: { label: 'New Node' },
|
|
25
|
-
});
|
|
26
|
-
};
|
|
27
|
-
return <button onClick={onClick}>Add Node</button>;
|
|
18
|
+
code: `function AddNodeButton() {
|
|
19
|
+
const { addNodes, screenToFlowPosition } = useReactFlow();
|
|
20
|
+
const onClick = () => {
|
|
21
|
+
addNodes({
|
|
22
|
+
id: crypto.randomUUID(),
|
|
23
|
+
position: screenToFlowPosition({ x: 200, y: 200 }),
|
|
24
|
+
data: { label: 'New Node' },
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
return <button onClick={onClick}>Add Node</button>;
|
|
28
28
|
}`,
|
|
29
29
|
},
|
|
30
30
|
{
|
|
31
31
|
title: "Delete selected elements",
|
|
32
32
|
category: "interaction",
|
|
33
|
-
code: `function DeleteButton() {
|
|
34
|
-
const { deleteElements, getNodes, getEdges } = useReactFlow();
|
|
35
|
-
const onClick = async () => {
|
|
36
|
-
const selectedNodes = getNodes().filter((n) => n.selected);
|
|
37
|
-
const selectedEdges = getEdges().filter((e) => e.selected);
|
|
38
|
-
await deleteElements({ nodes: selectedNodes, edges: selectedEdges });
|
|
39
|
-
};
|
|
40
|
-
return <button onClick={onClick}>Delete Selected</button>;
|
|
33
|
+
code: `function DeleteButton() {
|
|
34
|
+
const { deleteElements, getNodes, getEdges } = useReactFlow();
|
|
35
|
+
const onClick = async () => {
|
|
36
|
+
const selectedNodes = getNodes().filter((n) => n.selected);
|
|
37
|
+
const selectedEdges = getEdges().filter((e) => e.selected);
|
|
38
|
+
await deleteElements({ nodes: selectedNodes, edges: selectedEdges });
|
|
39
|
+
};
|
|
40
|
+
return <button onClick={onClick}>Delete Selected</button>;
|
|
41
41
|
}`,
|
|
42
42
|
},
|
|
43
43
|
],
|
|
@@ -54,33 +54,33 @@ const useNodesStateHook = {
|
|
|
54
54
|
description: "Like React's useState but with a built-in change handler for nodes. Quick prototyping of controlled flows without Zustand.",
|
|
55
55
|
importPath: "import { useNodesState } from '@xyflow/react'",
|
|
56
56
|
returns: "[Node[], setNodes, onNodesChange]",
|
|
57
|
-
usage: `const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
|
|
58
|
-
|
|
57
|
+
usage: `const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
|
|
58
|
+
|
|
59
59
|
<ReactFlow nodes={nodes} onNodesChange={onNodesChange} />`,
|
|
60
60
|
examples: [
|
|
61
61
|
{
|
|
62
62
|
title: "Minimal controlled flow",
|
|
63
63
|
category: "quickstart",
|
|
64
|
-
code: `import { ReactFlow, useNodesState, useEdgesState, addEdge } from '@xyflow/react';
|
|
65
|
-
|
|
66
|
-
const initialNodes = [
|
|
67
|
-
{ id: '1', position: { x: 0, y: 0 }, data: { label: 'A' } },
|
|
68
|
-
{ id: '2', position: { x: 200, y: 100 }, data: { label: 'B' } },
|
|
69
|
-
];
|
|
70
|
-
const initialEdges = [{ id: 'e1-2', source: '1', target: '2' }];
|
|
71
|
-
|
|
72
|
-
export default function Flow() {
|
|
73
|
-
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
|
|
74
|
-
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
|
75
|
-
const onConnect = useCallback((connection) => setEdges((eds) => addEdge(connection, eds)), [setEdges]);
|
|
76
|
-
|
|
77
|
-
return (
|
|
78
|
-
<ReactFlow
|
|
79
|
-
nodes={nodes} edges={edges}
|
|
80
|
-
onNodesChange={onNodesChange} onEdgesChange={onEdgesChange}
|
|
81
|
-
onConnect={onConnect} fitView
|
|
82
|
-
/>
|
|
83
|
-
);
|
|
64
|
+
code: `import { ReactFlow, useNodesState, useEdgesState, addEdge } from '@xyflow/react';
|
|
65
|
+
|
|
66
|
+
const initialNodes = [
|
|
67
|
+
{ id: '1', position: { x: 0, y: 0 }, data: { label: 'A' } },
|
|
68
|
+
{ id: '2', position: { x: 200, y: 100 }, data: { label: 'B' } },
|
|
69
|
+
];
|
|
70
|
+
const initialEdges = [{ id: 'e1-2', source: '1', target: '2' }];
|
|
71
|
+
|
|
72
|
+
export default function Flow() {
|
|
73
|
+
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
|
|
74
|
+
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
|
75
|
+
const onConnect = useCallback((connection) => setEdges((eds) => addEdge(connection, eds)), [setEdges]);
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<ReactFlow
|
|
79
|
+
nodes={nodes} edges={edges}
|
|
80
|
+
onNodesChange={onNodesChange} onEdgesChange={onEdgesChange}
|
|
81
|
+
onConnect={onConnect} fitView
|
|
82
|
+
/>
|
|
83
|
+
);
|
|
84
84
|
}`,
|
|
85
85
|
},
|
|
86
86
|
],
|
|
@@ -125,24 +125,24 @@ const useNodesDataHook = {
|
|
|
125
125
|
description: "Subscribe to data changes of specific nodes by ID. More efficient than useNodes when you only need certain nodes' data.",
|
|
126
126
|
importPath: "import { useNodesData } from '@xyflow/react'",
|
|
127
127
|
returns: "Pick<Node, 'id' | 'data' | 'type'>[]",
|
|
128
|
-
usage: `const nodesData = useNodesData(['node-1', 'node-2']);
|
|
129
|
-
// or single node:
|
|
128
|
+
usage: `const nodesData = useNodesData(['node-1', 'node-2']);
|
|
129
|
+
// or single node:
|
|
130
130
|
const nodeData = useNodesData('node-1');`,
|
|
131
131
|
examples: [
|
|
132
132
|
{
|
|
133
133
|
title: "Display connected node data",
|
|
134
134
|
category: "custom-nodes",
|
|
135
|
-
code: `function DisplayNode({ id }) {
|
|
136
|
-
const connections = useHandleConnections({ type: 'target' });
|
|
137
|
-
const sourceIds = connections.map((c) => c.source);
|
|
138
|
-
const sourcesData = useNodesData(sourceIds);
|
|
139
|
-
|
|
140
|
-
return (
|
|
141
|
-
<div>
|
|
142
|
-
<Handle type="target" position={Position.Left} />
|
|
143
|
-
<div>Connected sources: {sourcesData.map((d) => d.data.label).join(', ')}</div>
|
|
144
|
-
</div>
|
|
145
|
-
);
|
|
135
|
+
code: `function DisplayNode({ id }) {
|
|
136
|
+
const connections = useHandleConnections({ type: 'target' });
|
|
137
|
+
const sourceIds = connections.map((c) => c.source);
|
|
138
|
+
const sourcesData = useNodesData(sourceIds);
|
|
139
|
+
|
|
140
|
+
return (
|
|
141
|
+
<div>
|
|
142
|
+
<Handle type="target" position={Position.Left} />
|
|
143
|
+
<div>Connected sources: {sourcesData.map((d) => d.data.label).join(', ')}</div>
|
|
144
|
+
</div>
|
|
145
|
+
);
|
|
146
146
|
}`,
|
|
147
147
|
},
|
|
148
148
|
],
|
|
@@ -154,9 +154,9 @@ const useNodeIdHook = {
|
|
|
154
154
|
description: "Returns the ID of the node it is used inside. Useful deep in the render tree without prop drilling.",
|
|
155
155
|
importPath: "import { useNodeId } from '@xyflow/react'",
|
|
156
156
|
returns: "string | null",
|
|
157
|
-
usage: `function DeepChildComponent() {
|
|
158
|
-
const nodeId = useNodeId();
|
|
159
|
-
return <span>Node: {nodeId}</span>;
|
|
157
|
+
usage: `function DeepChildComponent() {
|
|
158
|
+
const nodeId = useNodeId();
|
|
159
|
+
return <span>Node: {nodeId}</span>;
|
|
160
160
|
}`,
|
|
161
161
|
examples: [],
|
|
162
162
|
relatedApis: ["useInternalNode", "useNodesData"],
|
|
@@ -167,24 +167,24 @@ const useConnectionHook = {
|
|
|
167
167
|
description: "Returns the current connection state during an active connection interaction. Returns null properties when no connection is active. Useful for colorizing handles based on validity.",
|
|
168
168
|
importPath: "import { useConnection } from '@xyflow/react'",
|
|
169
169
|
returns: "ConnectionState",
|
|
170
|
-
usage: `const connection = useConnection();
|
|
170
|
+
usage: `const connection = useConnection();
|
|
171
171
|
// connection.inProgress, connection.fromNode, connection.fromHandle, etc.`,
|
|
172
172
|
examples: [
|
|
173
173
|
{
|
|
174
174
|
title: "Colorize handle during connection",
|
|
175
175
|
category: "connections",
|
|
176
|
-
code: `function CustomHandle({ type, position, id }) {
|
|
177
|
-
const connection = useConnection();
|
|
178
|
-
const isTarget = connection.inProgress && connection.fromNode?.id !== useNodeId();
|
|
179
|
-
|
|
180
|
-
return (
|
|
181
|
-
<Handle
|
|
182
|
-
type={type}
|
|
183
|
-
position={position}
|
|
184
|
-
id={id}
|
|
185
|
-
style={{ background: isTarget ? '#22c55e' : '#6b7280' }}
|
|
186
|
-
/>
|
|
187
|
-
);
|
|
176
|
+
code: `function CustomHandle({ type, position, id }) {
|
|
177
|
+
const connection = useConnection();
|
|
178
|
+
const isTarget = connection.inProgress && connection.fromNode?.id !== useNodeId();
|
|
179
|
+
|
|
180
|
+
return (
|
|
181
|
+
<Handle
|
|
182
|
+
type={type}
|
|
183
|
+
position={position}
|
|
184
|
+
id={id}
|
|
185
|
+
style={{ background: isTarget ? '#22c55e' : '#6b7280' }}
|
|
186
|
+
/>
|
|
187
|
+
);
|
|
188
188
|
}`,
|
|
189
189
|
},
|
|
190
190
|
],
|
|
@@ -215,11 +215,11 @@ const useOnSelectionChangeHook = {
|
|
|
215
215
|
kind: "hook",
|
|
216
216
|
description: "Listen for changes to both node and edge selection.",
|
|
217
217
|
importPath: "import { useOnSelectionChange } from '@xyflow/react'",
|
|
218
|
-
usage: `useOnSelectionChange({
|
|
219
|
-
onChange: ({ nodes, edges }) => {
|
|
220
|
-
console.log('Selected nodes:', nodes);
|
|
221
|
-
console.log('Selected edges:', edges);
|
|
222
|
-
},
|
|
218
|
+
usage: `useOnSelectionChange({
|
|
219
|
+
onChange: ({ nodes, edges }) => {
|
|
220
|
+
console.log('Selected nodes:', nodes);
|
|
221
|
+
console.log('Selected edges:', edges);
|
|
222
|
+
},
|
|
223
223
|
});`,
|
|
224
224
|
examples: [],
|
|
225
225
|
relatedApis: ["useReactFlow", "ReactFlow"],
|
|
@@ -229,10 +229,10 @@ const useOnViewportChangeHook = {
|
|
|
229
229
|
kind: "hook",
|
|
230
230
|
description: "Listen for viewport changes (pan, zoom). Provides callbacks for start, change, and end phases.",
|
|
231
231
|
importPath: "import { useOnViewportChange } from '@xyflow/react'",
|
|
232
|
-
usage: `useOnViewportChange({
|
|
233
|
-
onStart: (viewport) => console.log('move start', viewport),
|
|
234
|
-
onChange: (viewport) => console.log('moving', viewport),
|
|
235
|
-
onEnd: (viewport) => console.log('move end', viewport),
|
|
232
|
+
usage: `useOnViewportChange({
|
|
233
|
+
onStart: (viewport) => console.log('move start', viewport),
|
|
234
|
+
onChange: (viewport) => console.log('moving', viewport),
|
|
235
|
+
onEnd: (viewport) => console.log('move end', viewport),
|
|
236
236
|
});`,
|
|
237
237
|
examples: [],
|
|
238
238
|
relatedApis: ["useViewport", "useReactFlow"],
|
|
@@ -253,7 +253,7 @@ const useStoreHook = {
|
|
|
253
253
|
kind: "hook",
|
|
254
254
|
description: "Subscribe to internal React Flow Zustand store. Re-exported from Zustand. Use selectors to minimize re-renders.",
|
|
255
255
|
importPath: "import { useStore } from '@xyflow/react'",
|
|
256
|
-
usage: `const nodes = useStore((state) => state.nodes);
|
|
256
|
+
usage: `const nodes = useStore((state) => state.nodes);
|
|
257
257
|
const zoom = useStore((state) => state.transform[2]);`,
|
|
258
258
|
examples: [],
|
|
259
259
|
tips: ["Always use a selector function to avoid re-rendering on every state change.", "For most use cases, prefer useReactFlow, useNodes, or useEdges instead."],
|
|
@@ -265,8 +265,8 @@ const useStoreApiHook = {
|
|
|
265
265
|
description: "Returns the Zustand store object directly for on-demand state access without causing re-renders.",
|
|
266
266
|
importPath: "import { useStoreApi } from '@xyflow/react'",
|
|
267
267
|
returns: "StoreApi",
|
|
268
|
-
usage: `const store = useStoreApi();
|
|
269
|
-
// Access state on demand:
|
|
268
|
+
usage: `const store = useStoreApi();
|
|
269
|
+
// Access state on demand:
|
|
270
270
|
const nodes = store.getState().nodes;`,
|
|
271
271
|
examples: [],
|
|
272
272
|
relatedApis: ["useStore", "useReactFlow"],
|
|
@@ -277,29 +277,29 @@ const useNodesInitializedHook = {
|
|
|
277
277
|
description: "Returns whether all nodes have been measured and given width/height. Returns false when new nodes are added, then true once measured.",
|
|
278
278
|
importPath: "import { useNodesInitialized } from '@xyflow/react'",
|
|
279
279
|
returns: "boolean",
|
|
280
|
-
usage: `const initialized = useNodesInitialized();
|
|
281
|
-
|
|
282
|
-
useEffect(() => {
|
|
283
|
-
if (initialized) {
|
|
284
|
-
// Safe to run layout algorithms or fitView
|
|
285
|
-
}
|
|
280
|
+
usage: `const initialized = useNodesInitialized();
|
|
281
|
+
|
|
282
|
+
useEffect(() => {
|
|
283
|
+
if (initialized) {
|
|
284
|
+
// Safe to run layout algorithms or fitView
|
|
285
|
+
}
|
|
286
286
|
}, [initialized]);`,
|
|
287
287
|
examples: [
|
|
288
288
|
{
|
|
289
289
|
title: "Auto-layout on mount",
|
|
290
290
|
category: "layout",
|
|
291
|
-
code: `function LayoutFlow() {
|
|
292
|
-
const { fitView } = useReactFlow();
|
|
293
|
-
const initialized = useNodesInitialized();
|
|
294
|
-
|
|
295
|
-
useEffect(() => {
|
|
296
|
-
if (initialized) {
|
|
297
|
-
// Run Dagre/ELK layout here, then fitView
|
|
298
|
-
fitView({ duration: 300 });
|
|
299
|
-
}
|
|
300
|
-
}, [initialized, fitView]);
|
|
301
|
-
|
|
302
|
-
return <ReactFlow nodes={nodes} edges={edges} />;
|
|
291
|
+
code: `function LayoutFlow() {
|
|
292
|
+
const { fitView } = useReactFlow();
|
|
293
|
+
const initialized = useNodesInitialized();
|
|
294
|
+
|
|
295
|
+
useEffect(() => {
|
|
296
|
+
if (initialized) {
|
|
297
|
+
// Run Dagre/ELK layout here, then fitView
|
|
298
|
+
fitView({ duration: 300 });
|
|
299
|
+
}
|
|
300
|
+
}, [initialized, fitView]);
|
|
301
|
+
|
|
302
|
+
return <ReactFlow nodes={nodes} edges={edges} />;
|
|
303
303
|
}`,
|
|
304
304
|
},
|
|
305
305
|
],
|
|
@@ -311,8 +311,8 @@ const useUpdateNodeInternalsHook = {
|
|
|
311
311
|
description: "Notify React Flow when you programmatically add/remove handles or change handle positions on a node.",
|
|
312
312
|
importPath: "import { useUpdateNodeInternals } from '@xyflow/react'",
|
|
313
313
|
returns: "(nodeId: string | string[]) => void",
|
|
314
|
-
usage: `const updateNodeInternals = useUpdateNodeInternals();
|
|
315
|
-
// After modifying handles:
|
|
314
|
+
usage: `const updateNodeInternals = useUpdateNodeInternals();
|
|
315
|
+
// After modifying handles:
|
|
316
316
|
updateNodeInternals('node-1');`,
|
|
317
317
|
examples: [],
|
|
318
318
|
tips: ["Call this after dynamically adding/removing Handle components inside a custom node."],
|
|
@@ -324,7 +324,7 @@ const useKeyPressHook = {
|
|
|
324
324
|
description: "Listen for specific key codes and returns whether they are currently pressed.",
|
|
325
325
|
importPath: "import { useKeyPress } from '@xyflow/react'",
|
|
326
326
|
returns: "boolean",
|
|
327
|
-
usage: `const shiftPressed = useKeyPress('Shift');
|
|
327
|
+
usage: `const shiftPressed = useKeyPress('Shift');
|
|
328
328
|
const ctrlZ = useKeyPress(['Control+z', 'Meta+z']);`,
|
|
329
329
|
examples: [],
|
|
330
330
|
relatedApis: ["ReactFlow"],
|
|
@@ -335,7 +335,7 @@ const useInternalNodeHook = {
|
|
|
335
335
|
description: "Returns an InternalNode object with additional computed properties like positionAbsolute and measured dimensions.",
|
|
336
336
|
importPath: "import { useInternalNode } from '@xyflow/react'",
|
|
337
337
|
returns: "InternalNode | undefined",
|
|
338
|
-
usage: `const internalNode = useInternalNode('node-1');
|
|
338
|
+
usage: `const internalNode = useInternalNode('node-1');
|
|
339
339
|
// internalNode.internals.positionAbsolute, internalNode.measured.width, etc.`,
|
|
340
340
|
examples: [],
|
|
341
341
|
relatedApis: ["useReactFlow", "useNodeId"],
|
package/dist/data/migration.js
CHANGED
|
@@ -1,48 +1,48 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.V12_MIGRATION = void 0;
|
|
4
|
-
exports.V12_MIGRATION = `# React Flow v12 Migration Guide (from v11)
|
|
5
|
-
|
|
6
|
-
## Package Change
|
|
7
|
-
\`\`\`bash
|
|
8
|
-
# Remove old package
|
|
9
|
-
npm uninstall reactflow
|
|
10
|
-
|
|
11
|
-
# Install v12
|
|
12
|
-
npm install @xyflow/react
|
|
13
|
-
\`\`\`
|
|
14
|
-
|
|
15
|
-
## Import Changes
|
|
16
|
-
\`\`\`tsx
|
|
17
|
-
// v11 (OLD)
|
|
18
|
-
import ReactFlow, { Background, Controls } from 'reactflow';
|
|
19
|
-
import 'reactflow/dist/style.css';
|
|
20
|
-
|
|
21
|
-
// v12 (NEW)
|
|
22
|
-
import { ReactFlow, Background, Controls } from '@xyflow/react';
|
|
23
|
-
import '@xyflow/react/dist/style.css';
|
|
24
|
-
\`\`\`
|
|
25
|
-
|
|
26
|
-
## Key Breaking Changes
|
|
27
|
-
|
|
28
|
-
| v11 | v12 |
|
|
29
|
-
|-----|-----|
|
|
30
|
-
| \`node.width\` / \`node.height\` | \`node.measured.width\` / \`node.measured.height\` |
|
|
31
|
-
| \`nodeInternals\` | \`nodeLookup\` |
|
|
32
|
-
| \`project()\` | \`screenToFlowPosition()\` |
|
|
33
|
-
| \`getNode(id)\` returns \`null\` | \`getNode(id)\` returns \`undefined\` |
|
|
34
|
-
| \`getEdge(id)\` returns \`null\` | \`getEdge(id)\` returns \`undefined\` |
|
|
35
|
-
| Default export | Named export: \`{ ReactFlow }\` |
|
|
36
|
-
| \`onEdgeUpdate\` | \`onReconnect\` |
|
|
37
|
-
| \`edgesUpdatable\` | \`edgesReconnectable\` |
|
|
38
|
-
| \`updateEdge()\` util | \`reconnectEdge()\` util |
|
|
39
|
-
|
|
40
|
-
## Type Changes
|
|
41
|
-
\`\`\`tsx
|
|
42
|
-
// v11: generic data in Node type
|
|
43
|
-
type MyNode = Node<{ label: string }>;
|
|
44
|
-
|
|
45
|
-
// v12: data AND type in generic
|
|
46
|
-
type MyNode = Node<{ label: string }, 'customType'>;
|
|
47
|
-
\`\`\`
|
|
4
|
+
exports.V12_MIGRATION = `# React Flow v12 Migration Guide (from v11)
|
|
5
|
+
|
|
6
|
+
## Package Change
|
|
7
|
+
\`\`\`bash
|
|
8
|
+
# Remove old package
|
|
9
|
+
npm uninstall reactflow
|
|
10
|
+
|
|
11
|
+
# Install v12
|
|
12
|
+
npm install @xyflow/react
|
|
13
|
+
\`\`\`
|
|
14
|
+
|
|
15
|
+
## Import Changes
|
|
16
|
+
\`\`\`tsx
|
|
17
|
+
// v11 (OLD)
|
|
18
|
+
import ReactFlow, { Background, Controls } from 'reactflow';
|
|
19
|
+
import 'reactflow/dist/style.css';
|
|
20
|
+
|
|
21
|
+
// v12 (NEW)
|
|
22
|
+
import { ReactFlow, Background, Controls } from '@xyflow/react';
|
|
23
|
+
import '@xyflow/react/dist/style.css';
|
|
24
|
+
\`\`\`
|
|
25
|
+
|
|
26
|
+
## Key Breaking Changes
|
|
27
|
+
|
|
28
|
+
| v11 | v12 |
|
|
29
|
+
|-----|-----|
|
|
30
|
+
| \`node.width\` / \`node.height\` | \`node.measured.width\` / \`node.measured.height\` |
|
|
31
|
+
| \`nodeInternals\` | \`nodeLookup\` |
|
|
32
|
+
| \`project()\` | \`screenToFlowPosition()\` |
|
|
33
|
+
| \`getNode(id)\` returns \`null\` | \`getNode(id)\` returns \`undefined\` |
|
|
34
|
+
| \`getEdge(id)\` returns \`null\` | \`getEdge(id)\` returns \`undefined\` |
|
|
35
|
+
| Default export | Named export: \`{ ReactFlow }\` |
|
|
36
|
+
| \`onEdgeUpdate\` | \`onReconnect\` |
|
|
37
|
+
| \`edgesUpdatable\` | \`edgesReconnectable\` |
|
|
38
|
+
| \`updateEdge()\` util | \`reconnectEdge()\` util |
|
|
39
|
+
|
|
40
|
+
## Type Changes
|
|
41
|
+
\`\`\`tsx
|
|
42
|
+
// v11: generic data in Node type
|
|
43
|
+
type MyNode = Node<{ label: string }>;
|
|
44
|
+
|
|
45
|
+
// v12: data AND type in generic
|
|
46
|
+
type MyNode = Node<{ label: string }, 'customType'>;
|
|
47
|
+
\`\`\`
|
|
48
48
|
`;
|