@@ -25,6 +25,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@cypress/skip-test": "^2.6.1",
|
"@cypress/skip-test": "^2.6.1",
|
||||||
|
"@types/dagre": "^0.7.48",
|
||||||
"@types/react": "^18.0.17",
|
"@types/react": "^18.0.17",
|
||||||
"@types/react-dom": "^18.0.6",
|
"@types/react-dom": "^18.0.6",
|
||||||
"@vitejs/plugin-react": "^3.0.1",
|
"@vitejs/plugin-react": "^3.0.1",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { FC } from 'react';
|
import { FC } from 'react';
|
||||||
|
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
Node,
|
Node,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { MouseEvent } from 'react';
|
import { MouseEvent } from 'react';
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
MiniMap,
|
MiniMap,
|
||||||
Background,
|
Background,
|
||||||
@@ -8,7 +8,7 @@ import ReactFlow, {
|
|||||||
Node,
|
Node,
|
||||||
Edge,
|
Edge,
|
||||||
useReactFlow,
|
useReactFlow,
|
||||||
NodeOrigin,
|
Panel,
|
||||||
} from 'reactflow';
|
} from 'reactflow';
|
||||||
|
|
||||||
const onNodeDrag = (_: MouseEvent, node: Node) => console.log('drag', node);
|
const onNodeDrag = (_: MouseEvent, node: Node) => console.log('drag', node);
|
||||||
@@ -22,7 +22,6 @@ const initialNodes: Node[] = [
|
|||||||
data: { label: 'Node 1' },
|
data: { label: 'Node 1' },
|
||||||
position: { x: 250, y: 5 },
|
position: { x: 250, y: 5 },
|
||||||
className: 'light',
|
className: 'light',
|
||||||
draggable: false,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '2',
|
id: '2',
|
||||||
@@ -100,20 +99,12 @@ const BasicFlow = () => {
|
|||||||
<MiniMap />
|
<MiniMap />
|
||||||
<Controls />
|
<Controls />
|
||||||
|
|
||||||
<div style={{ position: 'absolute', right: 10, top: 10, zIndex: 4 }}>
|
<Panel position="top-right">
|
||||||
<button onClick={resetTransform} style={{ marginRight: 5 }}>
|
<button onClick={resetTransform}>reset transform</button>
|
||||||
reset transform
|
<button onClick={updatePos}>change pos</button>
|
||||||
</button>
|
<button onClick={toggleClassnames}>toggle classnames</button>
|
||||||
<button onClick={updatePos} style={{ marginRight: 5 }}>
|
<button onClick={logToObject}>toObject</button>
|
||||||
change pos
|
</Panel>
|
||||||
</button>
|
|
||||||
<button onClick={toggleClassnames} style={{ marginRight: 5 }}>
|
|
||||||
toggle classnames
|
|
||||||
</button>
|
|
||||||
<button onClick={logToObject} style={{ marginRight: 5 }}>
|
|
||||||
toObject
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</ReactFlow>
|
</ReactFlow>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
Node,
|
Node,
|
||||||
addEdge,
|
addEdge,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useEffect, MouseEvent, ChangeEvent, useCallback } from 'react';
|
import { useState, useEffect, MouseEvent, ChangeEvent, useCallback } from 'react';
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
MiniMap,
|
MiniMap,
|
||||||
Controls,
|
Controls,
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
import ReactFlow, { useReactFlow, Node, Edge, ReactFlowProvider, Background, BackgroundVariant } from 'reactflow';
|
import ReactFlow, {
|
||||||
|
useReactFlow,
|
||||||
|
Node,
|
||||||
|
Edge,
|
||||||
|
ReactFlowProvider,
|
||||||
|
Background,
|
||||||
|
BackgroundVariant,
|
||||||
|
Panel,
|
||||||
|
} from 'reactflow';
|
||||||
|
|
||||||
const defaultNodes: Node[] = [
|
const defaultNodes: Node[] = [
|
||||||
{
|
{
|
||||||
@@ -72,18 +80,12 @@ const DefaultNodes = () => {
|
|||||||
<ReactFlow defaultNodes={defaultNodes} defaultEdges={defaultEdges} defaultEdgeOptions={defaultEdgeOptions} fitView>
|
<ReactFlow defaultNodes={defaultNodes} defaultEdges={defaultEdges} defaultEdgeOptions={defaultEdgeOptions} fitView>
|
||||||
<Background variant={BackgroundVariant.Lines} />
|
<Background variant={BackgroundVariant.Lines} />
|
||||||
|
|
||||||
<div style={{ position: 'absolute', right: 10, top: 10, zIndex: 4 }}>
|
<Panel position="top-right">
|
||||||
<button onClick={resetTransform} style={{ marginRight: 5 }}>
|
<button onClick={resetTransform}>reset transform</button>
|
||||||
reset transform
|
<button onClick={updateNodePositions}>change pos</button>
|
||||||
</button>
|
<button onClick={updateEdgeColors}>red edges</button>
|
||||||
<button onClick={updateNodePositions} style={{ marginRight: 5 }}>
|
|
||||||
change pos
|
|
||||||
</button>
|
|
||||||
<button onClick={updateEdgeColors} style={{ marginRight: 5 }}>
|
|
||||||
red edges
|
|
||||||
</button>
|
|
||||||
<button onClick={logToObject}>toObject</button>
|
<button onClick={logToObject}>toObject</button>
|
||||||
</div>
|
</Panel>
|
||||||
</ReactFlow>
|
</ReactFlow>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { MouseEvent } from 'react';
|
import { MouseEvent } from 'react';
|
||||||
import ReactFlow, { Node, Edge, useNodesState, useEdgesState } from 'reactflow';
|
import ReactFlow, { Node, Edge, useNodesState, useEdgesState } from 'reactflow';
|
||||||
|
|
||||||
import DragHandleNode from './DragHandleNode';
|
import DragHandleNode from './DragHandleNode';
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React, { DragEvent } from 'react';
|
import { DragEvent } from 'react';
|
||||||
|
|
||||||
import styles from './dnd.module.css';
|
import styles from './dnd.module.css';
|
||||||
|
|
||||||
const onDragStart = (event: DragEvent, nodeType: string) => {
|
const onDragStart = (event: DragEvent, nodeType: string) => {
|
||||||
@@ -9,25 +10,19 @@ const onDragStart = (event: DragEvent, nodeType: string) => {
|
|||||||
const Sidebar = () => {
|
const Sidebar = () => {
|
||||||
return (
|
return (
|
||||||
<aside className={styles.aside}>
|
<aside className={styles.aside}>
|
||||||
<div className={styles.description}>
|
<div className={styles.description}>You can drag these nodes to the pane on the left.</div>
|
||||||
You can drag these nodes to the pane on the left.
|
<div className="react-flow__node-input" onDragStart={(event: DragEvent) => onDragStart(event, 'input')} draggable>
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className='react-flow__node-input'
|
|
||||||
onDragStart={(event: DragEvent) => onDragStart(event, 'input')}
|
|
||||||
draggable
|
|
||||||
>
|
|
||||||
Input Node
|
Input Node
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className='react-flow__node-default'
|
className="react-flow__node-default"
|
||||||
onDragStart={(event: DragEvent) => onDragStart(event, 'default')}
|
onDragStart={(event: DragEvent) => onDragStart(event, 'default')}
|
||||||
draggable
|
draggable
|
||||||
>
|
>
|
||||||
Default Node
|
Default Node
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className='react-flow__node-output'
|
className="react-flow__node-output"
|
||||||
onDragStart={(event: DragEvent) => onDragStart(event, 'output')}
|
onDragStart={(event: DragEvent) => onDragStart(event, 'output')}
|
||||||
draggable
|
draggable
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, DragEvent } from 'react';
|
import { useState, DragEvent } from 'react';
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
ReactFlowProvider,
|
ReactFlowProvider,
|
||||||
addEdge,
|
addEdge,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Handle, NodeProps, Position, ReactFlowState, useStore } from 'reactflow
|
|||||||
|
|
||||||
const connectionNodeIdSelector = (state: ReactFlowState) => state.connectionNodeId;
|
const connectionNodeIdSelector = (state: ReactFlowState) => state.connectionNodeId;
|
||||||
|
|
||||||
export default function CustomNode({ id }: NodeProps) {
|
export default function CustomNode({ id, isConnectable }: NodeProps) {
|
||||||
const connectionNodeId = useStore(connectionNodeIdSelector);
|
const connectionNodeId = useStore(connectionNodeIdSelector);
|
||||||
const isTarget = connectionNodeId && connectionNodeId !== id;
|
const isTarget = connectionNodeId && connectionNodeId !== id;
|
||||||
|
|
||||||
@@ -18,8 +18,20 @@ export default function CustomNode({ id }: NodeProps) {
|
|||||||
backgroundColor: isTarget ? '#ffcce3' : '#ccd9f6',
|
backgroundColor: isTarget ? '#ffcce3' : '#ccd9f6',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Handle className="targetHandle" style={{ zIndex: 2 }} position={Position.Right} type="source" />
|
<Handle
|
||||||
<Handle className="targetHandle" style={targetHandleStyle} position={Position.Left} type="target" />
|
className="targetHandle"
|
||||||
|
style={{ zIndex: 2 }}
|
||||||
|
position={Position.Right}
|
||||||
|
type="source"
|
||||||
|
isConnectable={isConnectable}
|
||||||
|
/>
|
||||||
|
<Handle
|
||||||
|
className="targetHandle"
|
||||||
|
style={targetHandleStyle}
|
||||||
|
position={Position.Left}
|
||||||
|
type="target"
|
||||||
|
isConnectable={isConnectable}
|
||||||
|
/>
|
||||||
{label}
|
{label}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { MouseEvent, useCallback } from 'react';
|
import { MouseEvent, useCallback } from 'react';
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
Controls,
|
Controls,
|
||||||
Background,
|
Background,
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
/**
|
import { useCallback } from 'react';
|
||||||
* Example for checking the different edge types and source and target positions
|
|
||||||
*/
|
|
||||||
import React, { useCallback } from 'react';
|
|
||||||
|
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
Background,
|
Background,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { MouseEvent, useCallback } from 'react';
|
import { MouseEvent, useCallback } from 'react';
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
Controls,
|
Controls,
|
||||||
Background,
|
Background,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { MouseEvent, CSSProperties, useCallback } from 'react';
|
import { MouseEvent, CSSProperties, useCallback } from 'react';
|
||||||
|
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
Background,
|
Background,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
Background,
|
Background,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useEffect, useCallback } from 'react';
|
import { useState, useEffect, useCallback } from 'react';
|
||||||
|
|
||||||
import ReactFlow, { addEdge, Connection, Edge, Node, useNodesState, useEdgesState, MiniMap, Controls } from 'reactflow';
|
import ReactFlow, { addEdge, Connection, Edge, Node, useNodesState, useEdgesState, MiniMap, Controls } from 'reactflow';
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, MouseEvent as ReactMouseEvent, WheelEvent } from 'react';
|
import { useState, MouseEvent as ReactMouseEvent, WheelEvent } from 'react';
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
addEdge,
|
addEdge,
|
||||||
Node,
|
Node,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React, { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
import dagre from 'dagre';
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
Controls,
|
Controls,
|
||||||
ReactFlowProvider,
|
ReactFlowProvider,
|
||||||
@@ -10,10 +11,10 @@ import ReactFlow, {
|
|||||||
useEdgesState,
|
useEdgesState,
|
||||||
MarkerType,
|
MarkerType,
|
||||||
EdgeMarker,
|
EdgeMarker,
|
||||||
|
Panel,
|
||||||
|
useReactFlow,
|
||||||
} from 'reactflow';
|
} from 'reactflow';
|
||||||
|
|
||||||
import dagre from 'dagre';
|
|
||||||
|
|
||||||
import initialItems from './initial-elements';
|
import initialItems from './initial-elements';
|
||||||
|
|
||||||
import styles from './layouting.module.css';
|
import styles from './layouting.module.css';
|
||||||
@@ -29,6 +30,7 @@ const nodeExtent: CoordinateExtent = [
|
|||||||
const LayoutFlow = () => {
|
const LayoutFlow = () => {
|
||||||
const [nodes, setNodes, onNodesChange] = useNodesState(initialItems.nodes);
|
const [nodes, setNodes, onNodesChange] = useNodesState(initialItems.nodes);
|
||||||
const [edges, setEdges, onEdgesChange] = useEdgesState(initialItems.edges);
|
const [edges, setEdges, onEdgesChange] = useEdgesState(initialItems.edges);
|
||||||
|
const { fitView } = useReactFlow();
|
||||||
|
|
||||||
const onConnect = useCallback(
|
const onConnect = useCallback(
|
||||||
(connection: Connection) => {
|
(connection: Connection) => {
|
||||||
@@ -85,31 +87,31 @@ const LayoutFlow = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.layoutflow}>
|
<div className={styles.layoutflow}>
|
||||||
<ReactFlowProvider>
|
<ReactFlow
|
||||||
<ReactFlow
|
nodes={nodes}
|
||||||
nodes={nodes}
|
edges={edges}
|
||||||
edges={edges}
|
onConnect={onConnect}
|
||||||
onConnect={onConnect}
|
nodeExtent={nodeExtent}
|
||||||
nodeExtent={nodeExtent}
|
onInit={() => onLayout('TB')}
|
||||||
onInit={() => onLayout('TB')}
|
onNodesChange={onNodesChange}
|
||||||
onNodesChange={onNodesChange}
|
onEdgesChange={onEdgesChange}
|
||||||
onEdgesChange={onEdgesChange}
|
>
|
||||||
>
|
<Controls />
|
||||||
<Controls />
|
</ReactFlow>
|
||||||
</ReactFlow>
|
<Panel position="top-right">
|
||||||
<div className={styles.controls}>
|
<button onClick={() => onLayout('TB')}>vertical layout</button>
|
||||||
<button onClick={() => onLayout('TB')} style={{ marginRight: 10 }}>
|
<button onClick={() => onLayout('LR')}>horizontal layout</button>
|
||||||
vertical layout
|
<button onClick={() => unselect()}>unselect nodes</button>
|
||||||
</button>
|
<button onClick={() => changeMarker()}>change marker</button>
|
||||||
<button onClick={() => onLayout('LR')} style={{ marginRight: 10 }}>
|
<button onClick={() => fitView()}>fitView</button>
|
||||||
horizontal layout
|
<button onClick={() => fitView({ nodes: nodes.slice(0, 2) })}>fitView partially</button>
|
||||||
</button>
|
</Panel>
|
||||||
<button onClick={() => unselect()}>unselect nodes</button>
|
|
||||||
<button onClick={() => changeMarker()}>change marker</button>
|
|
||||||
</div>
|
|
||||||
</ReactFlowProvider>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default LayoutFlow;
|
export default () => (
|
||||||
|
<ReactFlowProvider>
|
||||||
|
<LayoutFlow />
|
||||||
|
</ReactFlowProvider>
|
||||||
|
);
|
||||||
|
|||||||
@@ -2,10 +2,3 @@
|
|||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.controls {
|
|
||||||
position: absolute;
|
|
||||||
right: 10px;
|
|
||||||
top: 10px;
|
|
||||||
z-index: 10;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { FC } from 'react';
|
import { FC } from 'react';
|
||||||
|
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
Background,
|
Background,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, MouseEvent, useCallback } from 'react';
|
import { useState, MouseEvent, useCallback } from 'react';
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
Controls,
|
Controls,
|
||||||
MiniMap,
|
MiniMap,
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import React, { CSSProperties, useCallback } from 'react';
|
import { CSSProperties, useCallback } from 'react';
|
||||||
|
|
||||||
import ReactFlow, { addEdge, Node, Position, Connection, Edge, useNodesState, useEdgesState } from 'reactflow';
|
import ReactFlow, { addEdge, Node, Position, Connection, Edge, useNodesState, useEdgesState } from 'reactflow';
|
||||||
|
|
||||||
const initialNodes: Node[] = [
|
const initialNodes: Node[] = [
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, CSSProperties, FC, useCallback } from 'react';
|
import { useState, CSSProperties, FC, useCallback } from 'react';
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
addEdge,
|
addEdge,
|
||||||
Node,
|
Node,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { MouseEvent as ReactMouseEvent, CSSProperties, useCallback } from 'react';
|
import { MouseEvent as ReactMouseEvent, CSSProperties, useCallback } from 'react';
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
addEdge,
|
addEdge,
|
||||||
Node,
|
Node,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { MouseEvent, useCallback } from 'react';
|
import { MouseEvent, useCallback } from 'react';
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
Controls,
|
Controls,
|
||||||
ReactFlowProvider,
|
ReactFlowProvider,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import React, { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import ReactFlow, { ReactFlowProvider, Node, addEdge, Connection, Edge, useNodesState, useEdgesState } from 'reactflow';
|
import ReactFlow, { ReactFlowProvider, Node, addEdge, Connection, Edge, useNodesState, useEdgesState } from 'reactflow';
|
||||||
|
|
||||||
import Controls from './Controls';
|
import Controls from './Controls';
|
||||||
|
|
||||||
const initialNodes: Node[] = [
|
const initialNodes: Node[] = [
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, CSSProperties, useCallback } from 'react';
|
import { useState, CSSProperties, useCallback } from 'react';
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
ReactFlowInstance,
|
ReactFlowInstance,
|
||||||
Edge,
|
Edge,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, MouseEvent, useCallback } from 'react';
|
import { useState, MouseEvent, useCallback } from 'react';
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
addEdge,
|
addEdge,
|
||||||
Node,
|
Node,
|
||||||
@@ -12,7 +12,6 @@ import ReactFlow, {
|
|||||||
MiniMap,
|
MiniMap,
|
||||||
Background,
|
Background,
|
||||||
Panel,
|
Panel,
|
||||||
NodeOrigin,
|
|
||||||
} from 'reactflow';
|
} from 'reactflow';
|
||||||
|
|
||||||
import DebugNode from './DebugNode';
|
import DebugNode from './DebugNode';
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import ReactFlow, { Node, Edge, useNodesState, useEdgesState, Position, Connection, addEdge } from 'reactflow';
|
import ReactFlow, { Node, Edge, useNodesState, useEdgesState, Position, Connection, addEdge } from 'reactflow';
|
||||||
|
|
||||||
import styles from './touch-device.module.css';
|
import styles from './touch-device.module.css';
|
||||||
|
|||||||
@@ -182,12 +182,13 @@ const getId = () => `${id++}`;
|
|||||||
const UpdateNodeInternalsFlow = () => {
|
const UpdateNodeInternalsFlow = () => {
|
||||||
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
|
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
|
||||||
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
||||||
|
|
||||||
const onConnect = (params: Edge | Connection) => setEdges((els) => addEdge(params, els));
|
|
||||||
|
|
||||||
const { project } = useReactFlow();
|
const { project } = useReactFlow();
|
||||||
const onEdgeUpdate = (oldEdge: Edge, newConnection: Connection) =>
|
|
||||||
setEdges((els) => updateEdge(oldEdge, newConnection, els));
|
const onConnect = useCallback((params: Edge | Connection) => setEdges((els) => addEdge(params, els)), [setEdges]);
|
||||||
|
const onEdgeUpdate = useCallback(
|
||||||
|
(oldEdge: Edge, newConnection: Connection) => setEdges((els) => updateEdge(oldEdge, newConnection, els)),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
const onPaneClick = useCallback(
|
const onPaneClick = useCallback(
|
||||||
(evt: MouseEvent) =>
|
(evt: MouseEvent) =>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useCallback } from 'react';
|
import { useState, useCallback, MouseEvent as ReactMouseEvent } from 'react';
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
Controls,
|
Controls,
|
||||||
updateEdge,
|
updateEdge,
|
||||||
@@ -60,9 +60,9 @@ const initialNodes: Node[] = [
|
|||||||
const initialEdges = [{ id: 'e1-2', source: '1', target: '2', label: 'This is a draggable edge' }];
|
const initialEdges = [{ id: 'e1-2', source: '1', target: '2', label: 'This is a draggable edge' }];
|
||||||
|
|
||||||
const onInit = (reactFlowInstance: ReactFlowInstance) => reactFlowInstance.fitView();
|
const onInit = (reactFlowInstance: ReactFlowInstance) => reactFlowInstance.fitView();
|
||||||
const onEdgeUpdateStart = (_: React.MouseEvent, edge: Edge, handleType: HandleType) =>
|
const onEdgeUpdateStart = (_: ReactMouseEvent, edge: Edge, handleType: HandleType) =>
|
||||||
console.log(`start update ${handleType} handle`, edge);
|
console.log(`start update ${handleType} handle`, edge);
|
||||||
const onEdgeUpdateEnd = (_: MouseEvent, edge: Edge, handleType: HandleType) =>
|
const onEdgeUpdateEnd = (_: MouseEvent | TouchEvent, edge: Edge, handleType: HandleType) =>
|
||||||
console.log(`end update ${handleType} handle`, edge);
|
console.log(`end update ${handleType} handle`, edge);
|
||||||
|
|
||||||
const UpdatableEdge = () => {
|
const UpdatableEdge = () => {
|
||||||
@@ -91,8 +91,8 @@ const UpdatableEdge = () => {
|
|||||||
snapToGrid={true}
|
snapToGrid={true}
|
||||||
onEdgeUpdate={onEdgeUpdate}
|
onEdgeUpdate={onEdgeUpdate}
|
||||||
onConnect={onConnect}
|
onConnect={onConnect}
|
||||||
// onEdgeUpdateStart={onEdgeUpdateStart}
|
onEdgeUpdateStart={onEdgeUpdateStart}
|
||||||
// onEdgeUpdateEnd={onEdgeUpdateEnd}
|
onEdgeUpdateEnd={onEdgeUpdateEnd}
|
||||||
>
|
>
|
||||||
<Controls />
|
<Controls />
|
||||||
</ReactFlow>
|
</ReactFlow>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import ReactFlow, { Node, Edge, useNodesState, useEdgesState } from 'reactflow';
|
import ReactFlow, { Node, Edge, useNodesState, useEdgesState } from 'reactflow';
|
||||||
|
|
||||||
import styles from './updatenode.module.css';
|
import styles from './updatenode.module.css';
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useCallback, MouseEvent, useEffect } from 'react';
|
import { useCallback, MouseEvent, useEffect } from 'react';
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
Background,
|
Background,
|
||||||
MiniMap,
|
MiniMap,
|
||||||
@@ -10,6 +10,7 @@ import ReactFlow, {
|
|||||||
Edge,
|
Edge,
|
||||||
useNodesState,
|
useNodesState,
|
||||||
useEdgesState,
|
useEdgesState,
|
||||||
|
Panel,
|
||||||
} from 'reactflow';
|
} from 'reactflow';
|
||||||
|
|
||||||
const initialNodes: Node[] = [
|
const initialNodes: Node[] = [
|
||||||
@@ -65,7 +66,7 @@ const UseZoomPanHelperFlow = () => {
|
|||||||
addEdges,
|
addEdges,
|
||||||
getNodes,
|
getNodes,
|
||||||
getEdges,
|
getEdges,
|
||||||
deleteElements
|
deleteElements,
|
||||||
} = useReactFlow();
|
} = useReactFlow();
|
||||||
|
|
||||||
const onPaneClick = useCallback(
|
const onPaneClick = useCallback(
|
||||||
@@ -114,14 +115,14 @@ const UseZoomPanHelperFlow = () => {
|
|||||||
}, [getNodes, getEdges]);
|
}, [getNodes, getEdges]);
|
||||||
|
|
||||||
const deleteSelectedElements = useCallback(() => {
|
const deleteSelectedElements = useCallback(() => {
|
||||||
const selectedNodes = nodes.filter(node => node.selected);
|
const selectedNodes = nodes.filter((node) => node.selected);
|
||||||
const selectedEdges = edges.filter(edge => edge.selected);
|
const selectedEdges = edges.filter((edge) => edge.selected);
|
||||||
deleteElements({ nodes: selectedNodes, edges: selectedEdges });
|
deleteElements({ nodes: selectedNodes, edges: selectedEdges });
|
||||||
}, [deleteElements, nodes, edges])
|
}, [deleteElements, nodes, edges]);
|
||||||
|
|
||||||
const deleteSomeElements = useCallback(() => {
|
const deleteSomeElements = useCallback(() => {
|
||||||
deleteElements({ nodes: [{ id: '2' }], edges: [{ id: 'e1-3' }] })
|
deleteElements({ nodes: [{ id: '2' }], edges: [{ id: 'e1-3' }] });
|
||||||
}, [])
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
addEdges({ id: 'e3-4', source: '3', target: '4' });
|
addEdges({ id: 'e3-4', source: '3', target: '4' });
|
||||||
@@ -142,7 +143,7 @@ const UseZoomPanHelperFlow = () => {
|
|||||||
fitViewOptions={{ duration: 1200, padding: 0.2 }}
|
fitViewOptions={{ duration: 1200, padding: 0.2 }}
|
||||||
maxZoom={Infinity}
|
maxZoom={Infinity}
|
||||||
>
|
>
|
||||||
<div style={{ position: 'absolute', left: 0, top: 0, zIndex: 100 }}>
|
<Panel position="top-right">
|
||||||
<button onClick={() => zoomIn({ duration: 1200 })}>zoomIn</button>
|
<button onClick={() => zoomIn({ duration: 1200 })}>zoomIn</button>
|
||||||
<button onClick={() => zoomOut({ duration: 0 })}>zoomOut</button>
|
<button onClick={() => zoomOut({ duration: 0 })}>zoomOut</button>
|
||||||
<button onClick={() => fitView({ duration: 1200, padding: 0.3 })}>fitView</button>
|
<button onClick={() => fitView({ duration: 1200, padding: 0.3 })}>fitView</button>
|
||||||
@@ -151,7 +152,7 @@ const UseZoomPanHelperFlow = () => {
|
|||||||
<button onClick={logNodes}>useNodes</button>
|
<button onClick={logNodes}>useNodes</button>
|
||||||
<button onClick={deleteSelectedElements}>deleteSelectedElements</button>
|
<button onClick={deleteSelectedElements}>deleteSelectedElements</button>
|
||||||
<button onClick={deleteSomeElements}>deleteSomeElements</button>
|
<button onClick={deleteSomeElements}>deleteSomeElements</button>
|
||||||
</div>
|
</Panel>
|
||||||
<Background />
|
<Background />
|
||||||
<MiniMap />
|
<MiniMap />
|
||||||
</ReactFlow>
|
</ReactFlow>
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
# @reactflow/background
|
# @reactflow/background
|
||||||
|
|
||||||
|
## 11.1.8
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [[`72216ff6`](https://github.com/wbkd/react-flow/commit/72216ff62014acd2d73999053c72bd7aeed351f6), [`959b1114`](https://github.com/wbkd/react-flow/commit/959b111448bba4686040473e46988be9e7befbe6), [`0d259b02`](https://github.com/wbkd/react-flow/commit/0d259b028558aab650546f3371a85f3bce45252f), [`f3de9335`](https://github.com/wbkd/react-flow/commit/f3de9335af6cd96cd77dc77f24a944eef85384e5), [`23424ea6`](https://github.com/wbkd/react-flow/commit/23424ea6750f092210f83df17a00c89adb910d96), [`021f5a92`](https://github.com/wbkd/react-flow/commit/021f5a9210f47a968e50446cd2f9dae1f97880a4)]:
|
||||||
|
- @reactflow/core@11.5.5
|
||||||
|
|
||||||
## 11.1.7
|
## 11.1.7
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@reactflow/background",
|
"name": "@reactflow/background",
|
||||||
"version": "11.1.7",
|
"version": "11.1.8",
|
||||||
"description": "Background component with different variants for React Flow",
|
"description": "Background component with different variants for React Flow",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react",
|
"react",
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
# @reactflow/controls
|
# @reactflow/controls
|
||||||
|
|
||||||
|
## 11.1.8
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [[`72216ff6`](https://github.com/wbkd/react-flow/commit/72216ff62014acd2d73999053c72bd7aeed351f6), [`959b1114`](https://github.com/wbkd/react-flow/commit/959b111448bba4686040473e46988be9e7befbe6), [`0d259b02`](https://github.com/wbkd/react-flow/commit/0d259b028558aab650546f3371a85f3bce45252f), [`f3de9335`](https://github.com/wbkd/react-flow/commit/f3de9335af6cd96cd77dc77f24a944eef85384e5), [`23424ea6`](https://github.com/wbkd/react-flow/commit/23424ea6750f092210f83df17a00c89adb910d96), [`021f5a92`](https://github.com/wbkd/react-flow/commit/021f5a9210f47a968e50446cd2f9dae1f97880a4)]:
|
||||||
|
- @reactflow/core@11.5.5
|
||||||
|
|
||||||
## 11.1.7
|
## 11.1.7
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@reactflow/controls",
|
"name": "@reactflow/controls",
|
||||||
"version": "11.1.7",
|
"version": "11.1.8",
|
||||||
"description": "Component to control the viewport of a React Flow instance",
|
"description": "Component to control the viewport of a React Flow instance",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react",
|
"react",
|
||||||
|
|||||||
@@ -1,5 +1,16 @@
|
|||||||
# @reactflow/core
|
# @reactflow/core
|
||||||
|
|
||||||
|
## 11.5.5
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- [#2834](https://github.com/wbkd/react-flow/pull/2834) [`23424ea6`](https://github.com/wbkd/react-flow/commit/23424ea6750f092210f83df17a00c89adb910d96) Thanks [@bcakmakoglu](https://github.com/bcakmakoglu)! - Add `nodes` to fit view options to allow fitting view only around specified set of nodes
|
||||||
|
- [#2836](https://github.com/wbkd/react-flow/pull/2836) [`959b1114`](https://github.com/wbkd/react-flow/commit/959b111448bba4686040473e46988be9e7befbe6) - Fix: connections for handles with bigger handles than connection radius
|
||||||
|
- [#2819](https://github.com/wbkd/react-flow/pull/2819) [`0d259b02`](https://github.com/wbkd/react-flow/commit/0d259b028558aab650546f3371a85f3bce45252f) Thanks [@bcakmakoglu](https://github.com/bcakmakoglu)! - Avoid triggering edge update if not using left mouse button
|
||||||
|
- [#2832](https://github.com/wbkd/react-flow/pull/2832) [`f3de9335`](https://github.com/wbkd/react-flow/commit/f3de9335af6cd96cd77dc77f24a944eef85384e5) - fitView: return type boolean
|
||||||
|
- [#2838](https://github.com/wbkd/react-flow/pull/2838) [`021f5a92`](https://github.com/wbkd/react-flow/commit/021f5a9210f47a968e50446cd2f9dae1f97880a4) - refactor: use key press handle modifier keys + input
|
||||||
|
- [#2839](https://github.com/wbkd/react-flow/pull/2839) [`72216ff6`](https://github.com/wbkd/react-flow/commit/72216ff62014acd2d73999053c72bd7aeed351f6) - fix PropsWithChildren: pass default generic for v17 types
|
||||||
|
|
||||||
## 11.5.4
|
## 11.5.4
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@reactflow/core",
|
"name": "@reactflow/core",
|
||||||
"version": "11.5.4",
|
"version": "11.5.5",
|
||||||
"description": "Core components and util functions of React Flow.",
|
"description": "Core components and util functions of React Flow.",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react",
|
"react",
|
||||||
|
|||||||
@@ -89,6 +89,11 @@ export default (EdgeComponent: ComponentType<EdgeProps>) => {
|
|||||||
const onEdgeMouseLeave = getMouseHandler(id, store.getState, onMouseLeave);
|
const onEdgeMouseLeave = getMouseHandler(id, store.getState, onMouseLeave);
|
||||||
|
|
||||||
const handleEdgeUpdater = (event: React.MouseEvent<SVGGElement, MouseEvent>, isSourceHandle: boolean) => {
|
const handleEdgeUpdater = (event: React.MouseEvent<SVGGElement, MouseEvent>, isSourceHandle: boolean) => {
|
||||||
|
// avoid triggering edge updater if mouse btn is not left
|
||||||
|
if (event.button !== 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const nodeId = isSourceHandle ? target : source;
|
const nodeId = isSourceHandle ? target : source;
|
||||||
const handleId = (isSourceHandle ? targetHandleId : sourceHandleId) || null;
|
const handleId = (isSourceHandle ? targetHandleId : sourceHandleId) || null;
|
||||||
const handleType = isSourceHandle ? 'target' : 'source';
|
const handleType = isSourceHandle ? 'target' : 'source';
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ export function handlePointerDown({
|
|||||||
let autoPanStarted = false;
|
let autoPanStarted = false;
|
||||||
let connection: Connection | null = null;
|
let connection: Connection | null = null;
|
||||||
let isValid = false;
|
let isValid = false;
|
||||||
|
let handleDomNode: Element | null = null;
|
||||||
|
|
||||||
const handleLookup = getHandleLookup({
|
const handleLookup = getHandleLookup({
|
||||||
nodes: getNodes(),
|
nodes: getNodes(),
|
||||||
@@ -111,7 +112,7 @@ export function handlePointerDown({
|
|||||||
autoPanStarted = true;
|
autoPanStarted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { handleDomNode, ...result } = isValidHandle(
|
const result = isValidHandle(
|
||||||
event,
|
event,
|
||||||
prevClosestHandle,
|
prevClosestHandle,
|
||||||
connectionMode,
|
connectionMode,
|
||||||
@@ -122,9 +123,13 @@ export function handlePointerDown({
|
|||||||
doc
|
doc
|
||||||
);
|
);
|
||||||
|
|
||||||
|
handleDomNode = result.handleDomNode;
|
||||||
|
connection = result.connection;
|
||||||
|
isValid = result.isValid;
|
||||||
|
|
||||||
setState({
|
setState({
|
||||||
connectionPosition:
|
connectionPosition:
|
||||||
prevClosestHandle && result.isValid
|
prevClosestHandle && isValid
|
||||||
? rendererPointToPoint(
|
? rendererPointToPoint(
|
||||||
{
|
{
|
||||||
x: prevClosestHandle.x,
|
x: prevClosestHandle.x,
|
||||||
@@ -133,16 +138,13 @@ export function handlePointerDown({
|
|||||||
transform
|
transform
|
||||||
)
|
)
|
||||||
: connectionPosition,
|
: connectionPosition,
|
||||||
connectionStatus: getConnectionStatus(!!prevClosestHandle, result.isValid),
|
connectionStatus: getConnectionStatus(!!prevClosestHandle, isValid),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!prevClosestHandle && !result.isValid) {
|
if (!prevClosestHandle && !isValid && !handleDomNode) {
|
||||||
return resetRecentHandle(prevActiveHandle);
|
return resetRecentHandle(prevActiveHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
connection = result.connection;
|
|
||||||
isValid = result.isValid;
|
|
||||||
|
|
||||||
if (connection.source !== connection.target && handleDomNode) {
|
if (connection.source !== connection.target && handleDomNode) {
|
||||||
resetRecentHandle(prevActiveHandle);
|
resetRecentHandle(prevActiveHandle);
|
||||||
prevActiveHandle = handleDomNode;
|
prevActiveHandle = handleDomNode;
|
||||||
@@ -154,7 +156,7 @@ export function handlePointerDown({
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onPointerUp(event: MouseEvent | TouchEvent) {
|
function onPointerUp(event: MouseEvent | TouchEvent) {
|
||||||
if (prevClosestHandle && connection && isValid) {
|
if ((prevClosestHandle || handleDomNode) && connection && isValid) {
|
||||||
onConnect?.(connection);
|
onConnect?.(connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,6 +174,7 @@ export function handlePointerDown({
|
|||||||
autoPanStarted = false;
|
autoPanStarted = false;
|
||||||
isValid = false;
|
isValid = false;
|
||||||
connection = null;
|
connection = null;
|
||||||
|
handleDomNode = null;
|
||||||
|
|
||||||
doc.removeEventListener('mousemove', onPointerMove as EventListener);
|
doc.removeEventListener('mousemove', onPointerMove as EventListener);
|
||||||
doc.removeEventListener('mouseup', onPointerUp as EventListener);
|
doc.removeEventListener('mouseup', onPointerUp as EventListener);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { Provider } from '../../contexts/RFStoreContext';
|
|||||||
import { createRFStore } from '../../store';
|
import { createRFStore } from '../../store';
|
||||||
import type { ReactFlowState } from '../../types';
|
import type { ReactFlowState } from '../../types';
|
||||||
|
|
||||||
const ReactFlowProvider: FC<PropsWithChildren> = ({ children }) => {
|
const ReactFlowProvider: FC<PropsWithChildren<unknown>> = ({ children }) => {
|
||||||
const storeRef = useRef<StoreApi<ReactFlowState> | null>(null);
|
const storeRef = useRef<StoreApi<ReactFlowState> | null>(null);
|
||||||
|
|
||||||
if (!storeRef.current) {
|
if (!storeRef.current) {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import type { FC, PropsWithChildren } from 'react';
|
|||||||
import StoreContext from '../../contexts/RFStoreContext';
|
import StoreContext from '../../contexts/RFStoreContext';
|
||||||
import ReactFlowProvider from '../../components/ReactFlowProvider';
|
import ReactFlowProvider from '../../components/ReactFlowProvider';
|
||||||
|
|
||||||
const Wrapper: FC<PropsWithChildren> = ({ children }) => {
|
const Wrapper: FC<PropsWithChildren<unknown>> = ({ children }) => {
|
||||||
const isWrapped = useContext(StoreContext);
|
const isWrapped = useContext(StoreContext);
|
||||||
|
|
||||||
if (isWrapped) {
|
if (isWrapped) {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { shallow } from 'zustand/shallow';
|
|||||||
|
|
||||||
import { useStoreApi, useStore } from '../hooks/useStore';
|
import { useStoreApi, useStore } from '../hooks/useStore';
|
||||||
import { pointToRendererPoint, getTransformForBounds, getD3Transition } from '../utils/graph';
|
import { pointToRendererPoint, getTransformForBounds, getD3Transition } from '../utils/graph';
|
||||||
import { fitView as fitViewStore } from '../store/utils';
|
import { fitView } from '../store/utils';
|
||||||
import type { ViewportHelperFunctions, ReactFlowState, XYPosition } from '../types';
|
import type { ViewportHelperFunctions, ReactFlowState, XYPosition } from '../types';
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||||
@@ -17,7 +17,7 @@ const initialViewportHelper: ViewportHelperFunctions = {
|
|||||||
getZoom: () => 1,
|
getZoom: () => 1,
|
||||||
setViewport: noop,
|
setViewport: noop,
|
||||||
getViewport: () => ({ x: 0, y: 0, zoom: 1 }),
|
getViewport: () => ({ x: 0, y: 0, zoom: 1 }),
|
||||||
fitView: noop,
|
fitView: () => false,
|
||||||
setCenter: noop,
|
setCenter: noop,
|
||||||
fitBounds: noop,
|
fitBounds: noop,
|
||||||
project: (position: XYPosition) => position,
|
project: (position: XYPosition) => position,
|
||||||
@@ -51,7 +51,7 @@ const useViewportHelper = (): ViewportHelperFunctions => {
|
|||||||
const [x, y, zoom] = store.getState().transform;
|
const [x, y, zoom] = store.getState().transform;
|
||||||
return { x, y, zoom };
|
return { x, y, zoom };
|
||||||
},
|
},
|
||||||
fitView: (options) => fitViewStore(store.getState, options),
|
fitView: (options) => fitView(store.getState, options),
|
||||||
setCenter: (x, y, options) => {
|
setCenter: (x, y, options) => {
|
||||||
const { width, height, maxZoom } = store.getState();
|
const { width, height, maxZoom } = store.getState();
|
||||||
const nextZoom = typeof options?.zoom !== 'undefined' ? options.zoom : maxZoom;
|
const nextZoom = typeof options?.zoom !== 'undefined' ? options.zoom : maxZoom;
|
||||||
|
|||||||
@@ -138,35 +138,43 @@ export function fitView(get: StoreApi<ReactFlowState>['getState'], options: Inte
|
|||||||
fitViewOnInit,
|
fitViewOnInit,
|
||||||
nodeOrigin,
|
nodeOrigin,
|
||||||
} = get();
|
} = get();
|
||||||
|
const isInitialFitView = options.initial && !fitViewOnInitDone && fitViewOnInit;
|
||||||
|
const d3initialized = d3Zoom && d3Selection;
|
||||||
|
|
||||||
if ((options.initial && !fitViewOnInitDone && fitViewOnInit) || !options.initial) {
|
if (d3initialized && (isInitialFitView || !options.initial)) {
|
||||||
if (d3Zoom && d3Selection) {
|
const nodes = getNodes().filter((n) => {
|
||||||
const nodes = getNodes().filter((n) => (options.includeHiddenNodes ? n.width && n.height : !n.hidden));
|
const isVisible = options.includeHiddenNodes ? n.width && n.height : !n.hidden;
|
||||||
|
|
||||||
const nodesInitialized = nodes.every((n) => n.width && n.height);
|
if (options.nodes?.length) {
|
||||||
|
return isVisible && options.nodes.some((optionNode) => optionNode.id === n.id);
|
||||||
if (nodes.length > 0 && nodesInitialized) {
|
|
||||||
const bounds = getRectOfNodes(nodes, nodeOrigin);
|
|
||||||
|
|
||||||
const [x, y, zoom] = getTransformForBounds(
|
|
||||||
bounds,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
options.minZoom ?? minZoom,
|
|
||||||
options.maxZoom ?? maxZoom,
|
|
||||||
options.padding ?? 0.1
|
|
||||||
);
|
|
||||||
|
|
||||||
const nextTransform = zoomIdentity.translate(x, y).scale(zoom);
|
|
||||||
|
|
||||||
if (typeof options.duration === 'number' && options.duration > 0) {
|
|
||||||
d3Zoom.transform(getD3Transition(d3Selection, options.duration), nextTransform);
|
|
||||||
} else {
|
|
||||||
d3Zoom.transform(d3Selection, nextTransform);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return isVisible;
|
||||||
|
});
|
||||||
|
|
||||||
|
const nodesInitialized = nodes.every((n) => n.width && n.height);
|
||||||
|
|
||||||
|
if (nodes.length > 0 && nodesInitialized) {
|
||||||
|
const bounds = getRectOfNodes(nodes, nodeOrigin);
|
||||||
|
|
||||||
|
const [x, y, zoom] = getTransformForBounds(
|
||||||
|
bounds,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
options.minZoom ?? minZoom,
|
||||||
|
options.maxZoom ?? maxZoom,
|
||||||
|
options.padding ?? 0.1
|
||||||
|
);
|
||||||
|
|
||||||
|
const nextTransform = zoomIdentity.translate(x, y).scale(zoom);
|
||||||
|
|
||||||
|
if (typeof options.duration === 'number' && options.duration > 0) {
|
||||||
|
d3Zoom.transform(getD3Transition(d3Selection, options.duration), nextTransform);
|
||||||
|
} else {
|
||||||
|
d3Zoom.transform(d3Selection, nextTransform);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -230,4 +230,5 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export type NodeTypesWrapped = { [key: string]: MemoExoticComponent<ComponentTyp
|
|||||||
export type EdgeTypes = { [key: string]: ComponentType<EdgeProps> };
|
export type EdgeTypes = { [key: string]: ComponentType<EdgeProps> };
|
||||||
export type EdgeTypesWrapped = { [key: string]: MemoExoticComponent<ComponentType<WrapEdgeProps>> };
|
export type EdgeTypesWrapped = { [key: string]: MemoExoticComponent<ComponentType<WrapEdgeProps>> };
|
||||||
|
|
||||||
export type FitView = (fitViewOptions?: FitViewOptions) => void;
|
export type FitView = (fitViewOptions?: FitViewOptions) => boolean;
|
||||||
|
|
||||||
export type Project = (position: XYPosition) => XYPosition;
|
export type Project = (position: XYPosition) => XYPosition;
|
||||||
|
|
||||||
@@ -76,6 +76,7 @@ export type FitViewOptions = {
|
|||||||
minZoom?: number;
|
minZoom?: number;
|
||||||
maxZoom?: number;
|
maxZoom?: number;
|
||||||
duration?: number;
|
duration?: number;
|
||||||
|
nodes?: (Partial<Node> & { id: Node['id'] })[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type OnConnectStartParams = {
|
export type OnConnectStartParams = {
|
||||||
|
|||||||
@@ -103,17 +103,12 @@ export function isInputDOMNode(event: KeyboardEvent | ReactKeyboardEvent): boole
|
|||||||
// using composed path for handling shadow dom
|
// using composed path for handling shadow dom
|
||||||
const target = (kbEvent.composedPath?.()?.[0] || event.target) as HTMLElement;
|
const target = (kbEvent.composedPath?.()?.[0] || event.target) as HTMLElement;
|
||||||
|
|
||||||
|
const isInput = ['INPUT', 'SELECT', 'TEXTAREA'].includes(target?.nodeName) || target?.hasAttribute('contenteditable');
|
||||||
// we want to be able to do a multi selection event if we are in an input field
|
// we want to be able to do a multi selection event if we are in an input field
|
||||||
if (event.ctrlKey || event.metaKey || event.shiftKey) {
|
const isModifierKey = event.ctrlKey || event.metaKey || event.shiftKey;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// when an input field is focused we don't want to trigger deletion or movement of nodes
|
// when an input field is focused we don't want to trigger deletion or movement of nodes
|
||||||
return (
|
return (isInput && !isModifierKey) || !!target?.closest('.nokey');
|
||||||
['INPUT', 'SELECT', 'TEXTAREA'].includes(target?.nodeName) ||
|
|
||||||
target?.hasAttribute('contenteditable') ||
|
|
||||||
!!target?.closest('.nokey')
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const isMouseEvent = (
|
export const isMouseEvent = (
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
# @reactflow/minimap
|
# @reactflow/minimap
|
||||||
|
|
||||||
|
## 11.3.8
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [[`72216ff6`](https://github.com/wbkd/react-flow/commit/72216ff62014acd2d73999053c72bd7aeed351f6), [`959b1114`](https://github.com/wbkd/react-flow/commit/959b111448bba4686040473e46988be9e7befbe6), [`0d259b02`](https://github.com/wbkd/react-flow/commit/0d259b028558aab650546f3371a85f3bce45252f), [`f3de9335`](https://github.com/wbkd/react-flow/commit/f3de9335af6cd96cd77dc77f24a944eef85384e5), [`23424ea6`](https://github.com/wbkd/react-flow/commit/23424ea6750f092210f83df17a00c89adb910d96), [`021f5a92`](https://github.com/wbkd/react-flow/commit/021f5a9210f47a968e50446cd2f9dae1f97880a4)]:
|
||||||
|
- @reactflow/core@11.5.5
|
||||||
|
|
||||||
## 11.3.7
|
## 11.3.7
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@reactflow/minimap",
|
"name": "@reactflow/minimap",
|
||||||
"version": "11.3.7",
|
"version": "11.3.8",
|
||||||
"description": "Minimap component for React Flow.",
|
"description": "Minimap component for React Flow.",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react",
|
"react",
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
# @reactflow/node-toolbar
|
# @reactflow/node-toolbar
|
||||||
|
|
||||||
|
## 1.1.8
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [[`72216ff6`](https://github.com/wbkd/react-flow/commit/72216ff62014acd2d73999053c72bd7aeed351f6), [`959b1114`](https://github.com/wbkd/react-flow/commit/959b111448bba4686040473e46988be9e7befbe6), [`0d259b02`](https://github.com/wbkd/react-flow/commit/0d259b028558aab650546f3371a85f3bce45252f), [`f3de9335`](https://github.com/wbkd/react-flow/commit/f3de9335af6cd96cd77dc77f24a944eef85384e5), [`23424ea6`](https://github.com/wbkd/react-flow/commit/23424ea6750f092210f83df17a00c89adb910d96), [`021f5a92`](https://github.com/wbkd/react-flow/commit/021f5a9210f47a968e50446cd2f9dae1f97880a4)]:
|
||||||
|
- @reactflow/core@11.5.5
|
||||||
|
|
||||||
## 1.1.7
|
## 1.1.7
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@reactflow/node-toolbar",
|
"name": "@reactflow/node-toolbar",
|
||||||
"version": "1.1.7",
|
"version": "1.1.8",
|
||||||
"description": "A toolbar component for React Flow that can be attached to a node.",
|
"description": "A toolbar component for React Flow that can be attached to a node.",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react",
|
"react",
|
||||||
|
|||||||
@@ -1,5 +1,23 @@
|
|||||||
# reactflow
|
# reactflow
|
||||||
|
|
||||||
|
## 11.5.6
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- [#2834](https://github.com/wbkd/react-flow/pull/2834) [`23424ea6`](https://github.com/wbkd/react-flow/commit/23424ea6750f092210f83df17a00c89adb910d96) Thanks [@bcakmakoglu](https://github.com/bcakmakoglu)! - Add `nodes` to fit view options to allow fitting view only around specified set of nodes
|
||||||
|
- [#2836](https://github.com/wbkd/react-flow/pull/2836) [`959b1114`](https://github.com/wbkd/react-flow/commit/959b111448bba4686040473e46988be9e7befbe6) - Fix: connections for handles with bigger handles than connection radius
|
||||||
|
- [#2819](https://github.com/wbkd/react-flow/pull/2819) [`0d259b02`](https://github.com/wbkd/react-flow/commit/0d259b028558aab650546f3371a85f3bce45252f) Thanks [@bcakmakoglu](https://github.com/bcakmakoglu)! - Avoid triggering edge update if not using left mouse button
|
||||||
|
- [#2832](https://github.com/wbkd/react-flow/pull/2832) [`f3de9335`](https://github.com/wbkd/react-flow/commit/f3de9335af6cd96cd77dc77f24a944eef85384e5) - fitView: return type boolean
|
||||||
|
- [#2838](https://github.com/wbkd/react-flow/pull/2838) [`021f5a92`](https://github.com/wbkd/react-flow/commit/021f5a9210f47a968e50446cd2f9dae1f97880a4) - refactor: use key press handle modifier keys + input
|
||||||
|
- [#2839](https://github.com/wbkd/react-flow/pull/2839) [`72216ff6`](https://github.com/wbkd/react-flow/commit/72216ff62014acd2d73999053c72bd7aeed351f6) - fix PropsWithChildren: pass default generic for v17 types
|
||||||
|
|
||||||
|
- Updated dependencies [[`72216ff6`](https://github.com/wbkd/react-flow/commit/72216ff62014acd2d73999053c72bd7aeed351f6), [`959b1114`](https://github.com/wbkd/react-flow/commit/959b111448bba4686040473e46988be9e7befbe6), [`0d259b02`](https://github.com/wbkd/react-flow/commit/0d259b028558aab650546f3371a85f3bce45252f), [`f3de9335`](https://github.com/wbkd/react-flow/commit/f3de9335af6cd96cd77dc77f24a944eef85384e5), [`23424ea6`](https://github.com/wbkd/react-flow/commit/23424ea6750f092210f83df17a00c89adb910d96), [`021f5a92`](https://github.com/wbkd/react-flow/commit/021f5a9210f47a968e50446cd2f9dae1f97880a4)]:
|
||||||
|
- @reactflow/core@11.5.5
|
||||||
|
- @reactflow/background@11.1.8
|
||||||
|
- @reactflow/controls@11.1.8
|
||||||
|
- @reactflow/minimap@11.3.8
|
||||||
|
- @reactflow/node-toolbar@1.1.8
|
||||||
|
|
||||||
## 11.5.5
|
## 11.5.5
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "reactflow",
|
"name": "reactflow",
|
||||||
"version": "11.5.5",
|
"version": "11.5.6",
|
||||||
"description": "A highly customizable React library for building node-based editors and interactive flow charts",
|
"description": "A highly customizable React library for building node-based editors and interactive flow charts",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"react",
|
"react",
|
||||||
|
|||||||
Generated
+8
@@ -58,6 +58,7 @@ importers:
|
|||||||
specifiers:
|
specifiers:
|
||||||
'@cypress/skip-test': ^2.6.1
|
'@cypress/skip-test': ^2.6.1
|
||||||
'@reactflow/node-resizer': workspace:*
|
'@reactflow/node-resizer': workspace:*
|
||||||
|
'@types/dagre': ^0.7.48
|
||||||
'@types/react': ^18.0.17
|
'@types/react': ^18.0.17
|
||||||
'@types/react-dom': ^18.0.6
|
'@types/react-dom': ^18.0.6
|
||||||
'@vitejs/plugin-react': ^3.0.1
|
'@vitejs/plugin-react': ^3.0.1
|
||||||
@@ -84,6 +85,7 @@ importers:
|
|||||||
reactflow: link:../../packages/reactflow
|
reactflow: link:../../packages/reactflow
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@cypress/skip-test': registry.npmjs.org/@cypress/skip-test/2.6.1
|
'@cypress/skip-test': registry.npmjs.org/@cypress/skip-test/2.6.1
|
||||||
|
'@types/dagre': registry.npmjs.org/@types/dagre/0.7.48
|
||||||
'@types/react': registry.npmjs.org/@types/react/18.0.19
|
'@types/react': registry.npmjs.org/@types/react/18.0.19
|
||||||
'@types/react-dom': registry.npmjs.org/@types/react-dom/18.0.6
|
'@types/react-dom': registry.npmjs.org/@types/react-dom/18.0.6
|
||||||
'@vitejs/plugin-react': registry.npmjs.org/@vitejs/plugin-react/3.0.1_vite@4.0.4
|
'@vitejs/plugin-react': registry.npmjs.org/@vitejs/plugin-react/3.0.1_vite@4.0.4
|
||||||
@@ -2046,6 +2048,12 @@ packages:
|
|||||||
'@types/d3-zoom': registry.npmjs.org/@types/d3-zoom/3.0.1
|
'@types/d3-zoom': registry.npmjs.org/@types/d3-zoom/3.0.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
registry.npmjs.org/@types/dagre/0.7.48:
|
||||||
|
resolution: {integrity: sha512-rF3yXSwHIrDxEkN6edCE4TXknb5YSEpiXfLaspw1I08grC49ZFuAVGOQCmZGIuLUGoFgcqGlUFBL/XrpgYpQgw==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@types/dagre/-/dagre-0.7.48.tgz}
|
||||||
|
name: '@types/dagre'
|
||||||
|
version: 0.7.48
|
||||||
|
dev: true
|
||||||
|
|
||||||
registry.npmjs.org/@types/estree/0.0.39:
|
registry.npmjs.org/@types/estree/0.0.39:
|
||||||
resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz}
|
resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz}
|
||||||
name: '@types/estree'
|
name: '@types/estree'
|
||||||
|
|||||||
Reference in New Issue
Block a user