feat(hooks): add useReactFlow hook, refactor types and properties
This commit is contained in:
+24
-28
@@ -1,15 +1,12 @@
|
|||||||
import { useState, MouseEvent } from 'react';
|
import { MouseEvent } from 'react';
|
||||||
|
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
addEdge,
|
ReactFlowProvider,
|
||||||
Background,
|
Background,
|
||||||
BackgroundVariant,
|
BackgroundVariant,
|
||||||
Node,
|
Node,
|
||||||
Edge,
|
Edge,
|
||||||
Connection,
|
useReactFlow,
|
||||||
useNodesState,
|
|
||||||
useEdgesState,
|
|
||||||
ReactFlowInstance,
|
|
||||||
} from 'react-flow-renderer';
|
} from 'react-flow-renderer';
|
||||||
|
|
||||||
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node);
|
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node);
|
||||||
@@ -28,52 +25,45 @@ const initialEdges: Edge[] = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const BasicFlow = () => {
|
const BasicFlow = () => {
|
||||||
const [rfInstance, setRfInstance] = useState<ReactFlowInstance | null>(null);
|
const instance = useReactFlow();
|
||||||
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
|
|
||||||
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
|
||||||
const onConnect = (params: Edge | Connection) => setEdges((els) => addEdge(params, els));
|
|
||||||
const onPaneReady = (reactFlowInstance: ReactFlowInstance) => setRfInstance(reactFlowInstance);
|
|
||||||
|
|
||||||
const updatePos = () => {
|
const updatePos = () => {
|
||||||
setNodes((nds) => {
|
instance.setNodes((nodes) =>
|
||||||
return nds.map((node) => {
|
nodes.map((node) => {
|
||||||
node.position = {
|
node.position = {
|
||||||
x: Math.random() * 400,
|
x: Math.random() * 400,
|
||||||
y: Math.random() * 400,
|
y: Math.random() * 400,
|
||||||
};
|
};
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
});
|
})
|
||||||
});
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const logToObject = () => console.log(rfInstance?.toObject());
|
const logToObject = () => console.log(instance.toObject());
|
||||||
const resetTransform = () => rfInstance?.setTransform({ x: 0, y: 0, zoom: 1 });
|
const resetTransform = () => instance.setViewport({ x: 0, y: 0, zoom: 1 });
|
||||||
|
|
||||||
const toggleClassnames = () => {
|
const toggleClassnames = () => {
|
||||||
setNodes((nds) => {
|
instance.setNodes((nodes) =>
|
||||||
return nds.map((node) => {
|
nodes.map((node) => {
|
||||||
node.className = node.className === 'light' ? 'dark' : 'light';
|
node.className = node.className === 'light' ? 'dark' : 'light';
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
});
|
})
|
||||||
});
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
nodes={nodes}
|
defaultNodes={initialNodes}
|
||||||
edges={edges}
|
defaultEdges={initialEdges}
|
||||||
onNodesChange={onNodesChange}
|
|
||||||
onEdgesChange={onEdgesChange}
|
|
||||||
onPaneReady={onPaneReady}
|
|
||||||
onNodeClick={onNodeClick}
|
onNodeClick={onNodeClick}
|
||||||
onConnect={onConnect}
|
|
||||||
onNodeDragStop={onNodeDragStop}
|
onNodeDragStop={onNodeDragStop}
|
||||||
className="react-flow-basic-example"
|
className="react-flow-basic-example"
|
||||||
defaultZoom={1.5}
|
defaultZoom={1.5}
|
||||||
minZoom={0.2}
|
minZoom={0.2}
|
||||||
maxZoom={4}
|
maxZoom={4}
|
||||||
|
fitViewOnInit
|
||||||
>
|
>
|
||||||
<Background variant={BackgroundVariant.Lines} />
|
<Background variant={BackgroundVariant.Lines} />
|
||||||
|
|
||||||
@@ -93,4 +83,10 @@ const BasicFlow = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default BasicFlow;
|
export default function App() {
|
||||||
|
return (
|
||||||
|
<ReactFlowProvider>
|
||||||
|
<BasicFlow />
|
||||||
|
</ReactFlowProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
import { useState } from 'react';
|
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
|
useReactFlow,
|
||||||
Background,
|
Background,
|
||||||
BackgroundVariant,
|
BackgroundVariant,
|
||||||
Node,
|
Node,
|
||||||
Edge,
|
Edge,
|
||||||
ReactFlowInstance,
|
|
||||||
ReactFlowProvider,
|
ReactFlowProvider,
|
||||||
useUpdateNodes,
|
|
||||||
useUpdateEdges,
|
|
||||||
} from 'react-flow-renderer';
|
} from 'react-flow-renderer';
|
||||||
|
|
||||||
const defaultNodes: Node[] = [
|
const defaultNodes: Node[] = [
|
||||||
@@ -27,40 +24,34 @@ const defaultEdgeOptions = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const DefaultNodes = () => {
|
const DefaultNodes = () => {
|
||||||
const [rfInstance, setRfInstance] = useState<ReactFlowInstance | null>(null);
|
const instance = useReactFlow();
|
||||||
const updateNodes = useUpdateNodes();
|
|
||||||
const updateEdges = useUpdateEdges();
|
|
||||||
|
|
||||||
const logToObject = () => console.log(rfInstance?.toObject());
|
const logToObject = () => console.log(instance.toObject());
|
||||||
const resetTransform = () => rfInstance?.setTransform({ x: 0, y: 0, zoom: 1 });
|
const resetTransform = () => instance.setViewport({ x: 0, y: 0, zoom: 1 });
|
||||||
|
|
||||||
const updateNodePositions = () => {
|
const updateNodePositions = () => {
|
||||||
updateNodes((nodes, setNodes) => {
|
instance.setNodes((nodes) =>
|
||||||
setNodes(
|
nodes.map((node) => {
|
||||||
nodes.map((node) => {
|
node.position = {
|
||||||
node.position = {
|
x: Math.random() * 400,
|
||||||
x: Math.random() * 400,
|
y: Math.random() * 400,
|
||||||
y: Math.random() * 400,
|
};
|
||||||
};
|
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateEdgeColors = () => {
|
const updateEdgeColors = () => {
|
||||||
updateEdges((edges, setEdges) => {
|
instance.setEdges((edges) =>
|
||||||
setEdges(
|
edges.map((edge) => {
|
||||||
edges.map((edge) => {
|
edge.style = {
|
||||||
edge.style = {
|
stroke: '#ff5050',
|
||||||
stroke: '#ff5050',
|
};
|
||||||
};
|
|
||||||
|
|
||||||
return edge;
|
return edge;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -68,7 +59,6 @@ const DefaultNodes = () => {
|
|||||||
defaultNodes={defaultNodes}
|
defaultNodes={defaultNodes}
|
||||||
defaultEdges={defaultEdges}
|
defaultEdges={defaultEdges}
|
||||||
defaultEdgeOptions={defaultEdgeOptions}
|
defaultEdgeOptions={defaultEdgeOptions}
|
||||||
onPaneReady={setRfInstance}
|
|
||||||
fitViewOnInit
|
fitViewOnInit
|
||||||
>
|
>
|
||||||
<Background variant={BackgroundVariant.Lines} />
|
<Background variant={BackgroundVariant.Lines} />
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import ReactFlow, {
|
|||||||
Connection,
|
Connection,
|
||||||
Edge,
|
Edge,
|
||||||
PanOnScrollMode,
|
PanOnScrollMode,
|
||||||
FlowTransform,
|
Viewport,
|
||||||
useNodesState,
|
useNodesState,
|
||||||
useEdgesState,
|
useEdgesState,
|
||||||
} from 'react-flow-renderer';
|
} from 'react-flow-renderer';
|
||||||
@@ -31,7 +31,7 @@ const onEdgeClick = (_: MouseEvent, edge: Edge) => console.log('click', edge);
|
|||||||
const onPaneClick = (event: MouseEvent) => console.log('onPaneClick', event);
|
const onPaneClick = (event: MouseEvent) => console.log('onPaneClick', event);
|
||||||
const onPaneScroll = (event?: WheelEvent) => console.log('onPaneScroll', event);
|
const onPaneScroll = (event?: WheelEvent) => console.log('onPaneScroll', event);
|
||||||
const onPaneContextMenu = (event: MouseEvent) => console.log('onPaneContextMenu', event);
|
const onPaneContextMenu = (event: MouseEvent) => console.log('onPaneContextMenu', event);
|
||||||
const onMoveEnd = (flowTranasform?: FlowTransform) => console.log('onMoveEnd', flowTranasform);
|
const onMoveEnd = (viewport?: Viewport) => console.log('onMoveEnd', viewport);
|
||||||
|
|
||||||
const InteractionFlow = () => {
|
const InteractionFlow = () => {
|
||||||
const [nodes, , onNodesChange] = useNodesState(initialNodes);
|
const [nodes, , onNodesChange] = useNodesState(initialNodes);
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ const NestedFlow = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const logToObject = () => console.log(rfInstance?.toObject());
|
const logToObject = () => console.log(rfInstance?.toObject());
|
||||||
const resetTransform = () => rfInstance?.setTransform({ x: 0, y: 0, zoom: 1 });
|
const resetTransform = () => rfInstance?.setViewport({ x: 0, y: 0, zoom: 1 });
|
||||||
|
|
||||||
const toggleClassnames = () => {
|
const toggleClassnames = () => {
|
||||||
setNodes((nds) => {
|
setNodes((nds) => {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import ReactFlow, {
|
|||||||
Controls,
|
Controls,
|
||||||
Background,
|
Background,
|
||||||
Node,
|
Node,
|
||||||
FlowTransform,
|
Viewport,
|
||||||
SnapGrid,
|
SnapGrid,
|
||||||
Connection,
|
Connection,
|
||||||
Edge,
|
Edge,
|
||||||
@@ -36,8 +36,8 @@ const onPaneReady = (reactFlowInstance: ReactFlowInstance) => {
|
|||||||
console.log('pane ready:', reactFlowInstance);
|
console.log('pane ready:', reactFlowInstance);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onMoveStart = (transform?: FlowTransform) => console.log('zoom/move start', transform);
|
const onMoveStart = (transform?: Viewport) => console.log('zoom/move start', transform);
|
||||||
const onMoveEnd = (transform?: FlowTransform) => console.log('zoom/move end', transform);
|
const onMoveEnd = (transform?: Viewport) => console.log('zoom/move end', transform);
|
||||||
const onEdgeContextMenu = (_: MouseEvent, edge: Edge) => console.log('edge context menu', edge);
|
const onEdgeContextMenu = (_: MouseEvent, edge: Edge) => console.log('edge context menu', edge);
|
||||||
const onEdgeMouseEnter = (_: MouseEvent, edge: Edge) => console.log('edge mouse enter', edge);
|
const onEdgeMouseEnter = (_: MouseEvent, edge: Edge) => console.log('edge mouse enter', edge);
|
||||||
const onEdgeMouseMove = (_: MouseEvent, edge: Edge) => console.log('edge mouse move', edge);
|
const onEdgeMouseMove = (_: MouseEvent, edge: Edge) => console.log('edge mouse move', edge);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { memo, useCallback, Dispatch, FC } from 'react';
|
import React, { memo, useCallback, Dispatch, FC } from 'react';
|
||||||
import { useZoomPanHelper, ReactFlowInstance, Edge, Node, FlowExportObject } from 'react-flow-renderer';
|
import { useReactFlow, ReactFlowInstance, Edge, Node, ReactFlowJsonObject } from 'react-flow-renderer';
|
||||||
import localforage from 'localforage';
|
import localforage from 'localforage';
|
||||||
|
|
||||||
localforage.config({
|
localforage.config({
|
||||||
@@ -18,7 +18,7 @@ type ControlsProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const Controls: FC<ControlsProps> = ({ rfInstance, setNodes, setEdges }) => {
|
const Controls: FC<ControlsProps> = ({ rfInstance, setNodes, setEdges }) => {
|
||||||
const { setTransform } = useZoomPanHelper();
|
const { setViewport } = useReactFlow();
|
||||||
|
|
||||||
const onSave = useCallback(() => {
|
const onSave = useCallback(() => {
|
||||||
if (rfInstance) {
|
if (rfInstance) {
|
||||||
@@ -29,18 +29,18 @@ const Controls: FC<ControlsProps> = ({ rfInstance, setNodes, setEdges }) => {
|
|||||||
|
|
||||||
const onRestore = useCallback(() => {
|
const onRestore = useCallback(() => {
|
||||||
const restoreFlow = async () => {
|
const restoreFlow = async () => {
|
||||||
const flow: FlowExportObject | null = await localforage.getItem(flowKey);
|
const flow: ReactFlowJsonObject | null = await localforage.getItem(flowKey);
|
||||||
|
|
||||||
if (flow) {
|
if (flow) {
|
||||||
const [x = 0, y = 0] = flow.position;
|
const { x, y, zoom } = flow.viewport;
|
||||||
setNodes(flow.nodes || []);
|
setNodes(flow.nodes || []);
|
||||||
setEdges(flow.edges || []);
|
setEdges(flow.edges || []);
|
||||||
setTransform({ x, y, zoom: flow.zoom || 0 });
|
setViewport({ x, y, zoom: zoom || 0 });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
restoreFlow();
|
restoreFlow();
|
||||||
}, [setNodes, setEdges, setTransform]);
|
}, [setNodes, setEdges, setViewport]);
|
||||||
|
|
||||||
const onAdd = useCallback(() => {
|
const onAdd = useCallback(() => {
|
||||||
const newNode = {
|
const newNode = {
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ const BasicFlow = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const logToObject = () => console.log(rfInstance?.toObject());
|
const logToObject = () => console.log(rfInstance?.toObject());
|
||||||
const resetTransform = () => rfInstance?.setTransform({ x: 0, y: 0, zoom: 1 });
|
const resetTransform = () => rfInstance?.setViewport({ x: 0, y: 0, zoom: 1 });
|
||||||
|
|
||||||
const toggleClassnames = () => {
|
const toggleClassnames = () => {
|
||||||
setNodes((nds) => {
|
setNodes((nds) => {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
|
useReactFlow,
|
||||||
NodeTypesType,
|
NodeTypesType,
|
||||||
addEdge,
|
addEdge,
|
||||||
useZoomPanHelper,
|
|
||||||
ReactFlowProvider,
|
ReactFlowProvider,
|
||||||
Node,
|
Node,
|
||||||
Connection,
|
Connection,
|
||||||
@@ -184,7 +184,7 @@ const UpdateNodeInternalsFlow = () => {
|
|||||||
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
||||||
|
|
||||||
const onConnect = (params: Edge | Connection) => setEdges((els) => addEdge(params, els));
|
const onConnect = (params: Edge | Connection) => setEdges((els) => addEdge(params, els));
|
||||||
const { project } = useZoomPanHelper();
|
const { project } = useReactFlow();
|
||||||
const onEdgeUpdate = (oldEdge: Edge, newConnection: Connection) =>
|
const onEdgeUpdate = (oldEdge: Edge, newConnection: Connection) =>
|
||||||
setEdges((els) => updateEdge(oldEdge, newConnection, els));
|
setEdges((els) => updateEdge(oldEdge, newConnection, els));
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { useCallback, CSSProperties } from 'react';
|
|||||||
import ReactFlow, {
|
import ReactFlow, {
|
||||||
NodeTypesType,
|
NodeTypesType,
|
||||||
addEdge,
|
addEdge,
|
||||||
useZoomPanHelper,
|
useReactFlow,
|
||||||
ReactFlowProvider,
|
ReactFlowProvider,
|
||||||
Node,
|
Node,
|
||||||
Connection,
|
Connection,
|
||||||
@@ -41,7 +41,7 @@ const UpdateNodeInternalsFlow = () => {
|
|||||||
const onConnect = (params: Edge | Connection) => setEdges((els) => addEdge(params, els));
|
const onConnect = (params: Edge | Connection) => setEdges((els) => addEdge(params, els));
|
||||||
|
|
||||||
const updateNodeInternals = useUpdateNodeInternals();
|
const updateNodeInternals = useUpdateNodeInternals();
|
||||||
const { project } = useZoomPanHelper();
|
const { project } = useReactFlow();
|
||||||
|
|
||||||
const onPaneClick = useCallback(
|
const onPaneClick = useCallback(
|
||||||
(evt) =>
|
(evt) =>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import ReactFlow, {
|
|||||||
addEdge,
|
addEdge,
|
||||||
Background,
|
Background,
|
||||||
MiniMap,
|
MiniMap,
|
||||||
useZoomPanHelper,
|
useReactFlow,
|
||||||
ReactFlowProvider,
|
ReactFlowProvider,
|
||||||
Connection,
|
Connection,
|
||||||
Edge,
|
Edge,
|
||||||
@@ -33,7 +33,7 @@ const UseZoomPanHelperFlow = () => {
|
|||||||
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: Connection | Edge) => setEdges((eds) => addEdge(params, eds));
|
const onConnect = (params: Connection | Edge) => setEdges((eds) => addEdge(params, eds));
|
||||||
const { project, setCenter, zoomIn, zoomOut } = useZoomPanHelper();
|
const { project, setCenter, zoomIn, zoomOut } = useReactFlow();
|
||||||
|
|
||||||
const onPaneClick = useCallback(
|
const onPaneClick = useCallback(
|
||||||
(evt) => {
|
(evt) => {
|
||||||
|
|||||||
@@ -1,16 +1,9 @@
|
|||||||
import React, { memo, useMemo, FC, HTMLAttributes } from 'react';
|
import React, { memo, useMemo, FC } from 'react';
|
||||||
import cc from 'classcat';
|
import cc from 'classcat';
|
||||||
|
|
||||||
import { useStore } from '../../store';
|
import { useStore } from '../../store';
|
||||||
import { BackgroundVariant, ReactFlowState } from '../../types';
|
|
||||||
import { createGridLinesPath, createGridDotsPath } from './utils';
|
import { createGridLinesPath, createGridDotsPath } from './utils';
|
||||||
|
import { BackgroundVariant, ReactFlowState, BackgroundProps } from '../../types';
|
||||||
export interface BackgroundProps extends HTMLAttributes<SVGElement> {
|
|
||||||
variant?: BackgroundVariant;
|
|
||||||
gap?: number;
|
|
||||||
color?: string;
|
|
||||||
size?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
const defaultColors = {
|
const defaultColors = {
|
||||||
[BackgroundVariant.Dots]: '#81818a',
|
[BackgroundVariant.Dots]: '#81818a',
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import React, { memo, useCallback, HTMLAttributes, FC, useEffect, useState } from 'react';
|
import React, { memo, useCallback, FC, useEffect, useState } from 'react';
|
||||||
import cc from 'classcat';
|
import cc from 'classcat';
|
||||||
|
|
||||||
import { useStore, useStoreApi } from '../../store';
|
import { useStore, useStoreApi } from '../../store';
|
||||||
|
import useViewportHelper from '../../hooks/useViewportHelper';
|
||||||
|
|
||||||
import PlusIcon from '../../../assets/icons/plus.svg';
|
import PlusIcon from '../../../assets/icons/plus.svg';
|
||||||
import MinusIcon from '../../../assets/icons/minus.svg';
|
import MinusIcon from '../../../assets/icons/minus.svg';
|
||||||
@@ -9,21 +10,7 @@ import FitviewIcon from '../../../assets/icons/fitview.svg';
|
|||||||
import LockIcon from '../../../assets/icons/lock.svg';
|
import LockIcon from '../../../assets/icons/lock.svg';
|
||||||
import UnlockIcon from '../../../assets/icons/unlock.svg';
|
import UnlockIcon from '../../../assets/icons/unlock.svg';
|
||||||
|
|
||||||
import useZoomPanHelper from '../../hooks/useZoomPanHelper';
|
import { ControlProps, ControlButtonProps, ReactFlowState } from '../../types';
|
||||||
import { FitViewParams, ReactFlowState } from '../../types';
|
|
||||||
|
|
||||||
export interface ControlProps extends HTMLAttributes<HTMLDivElement> {
|
|
||||||
showZoom?: boolean;
|
|
||||||
showFitView?: boolean;
|
|
||||||
showInteractive?: boolean;
|
|
||||||
fitViewParams?: FitViewParams;
|
|
||||||
onZoomIn?: () => void;
|
|
||||||
onZoomOut?: () => void;
|
|
||||||
onFitView?: () => void;
|
|
||||||
onInteractiveChange?: (interactiveStatus: boolean) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ControlButtonProps extends HTMLAttributes<HTMLButtonElement> {}
|
|
||||||
|
|
||||||
export const ControlButton: FC<ControlButtonProps> = ({ children, className, ...rest }) => (
|
export const ControlButton: FC<ControlButtonProps> = ({ children, className, ...rest }) => (
|
||||||
<button type="button" className={cc(['react-flow__controls-button', className])} {...rest}>
|
<button type="button" className={cc(['react-flow__controls-button', className])} {...rest}>
|
||||||
@@ -49,7 +36,7 @@ const Controls: FC<ControlProps> = ({
|
|||||||
const store = useStoreApi();
|
const store = useStoreApi();
|
||||||
const [isVisible, setIsVisible] = useState<boolean>(false);
|
const [isVisible, setIsVisible] = useState<boolean>(false);
|
||||||
const isInteractive = useStore(isInteractiveSelector);
|
const isInteractive = useStore(isInteractiveSelector);
|
||||||
const { zoomIn, zoomOut, fitView } = useZoomPanHelper();
|
const { zoomIn, zoomOut, fitView } = useViewportHelper();
|
||||||
|
|
||||||
const mapClasses = cc(['react-flow__controls', className]);
|
const mapClasses = cc(['react-flow__controls', className]);
|
||||||
|
|
||||||
|
|||||||
@@ -1,23 +1,14 @@
|
|||||||
import React, { memo, HTMLAttributes } from 'react';
|
import React, { memo } from 'react';
|
||||||
import cc from 'classcat';
|
import cc from 'classcat';
|
||||||
import shallow from 'zustand/shallow';
|
import shallow from 'zustand/shallow';
|
||||||
|
|
||||||
|
import MiniMapNode from './MiniMapNode';
|
||||||
|
|
||||||
import { useStore } from '../../store';
|
import { useStore } from '../../store';
|
||||||
import { getRectOfNodeInternals } from '../../utils/graph';
|
import { getRectOfNodeInternals } from '../../utils/graph';
|
||||||
import { getBoundsofRects } from '../../utils';
|
import { getBoundsofRects } from '../../utils';
|
||||||
import { Node, ReactFlowState, Rect } from '../../types';
|
|
||||||
import MiniMapNode from './MiniMapNode';
|
|
||||||
|
|
||||||
type StringFunc = (node: Node) => string;
|
import { MiniMapProps, GetMiniMapNodeAttribute, ReactFlowState, Rect } from '../../types';
|
||||||
|
|
||||||
export interface MiniMapProps extends HTMLAttributes<SVGSVGElement> {
|
|
||||||
nodeColor?: string | StringFunc;
|
|
||||||
nodeStrokeColor?: string | StringFunc;
|
|
||||||
nodeClassName?: string | StringFunc;
|
|
||||||
nodeBorderRadius?: number;
|
|
||||||
nodeStrokeWidth?: number;
|
|
||||||
maskColor?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare const window: any;
|
declare const window: any;
|
||||||
|
|
||||||
@@ -47,11 +38,13 @@ const MiniMap = ({
|
|||||||
const mapClasses = cc(['react-flow__minimap', className]);
|
const mapClasses = cc(['react-flow__minimap', className]);
|
||||||
const elementWidth = (style?.width || defaultWidth)! as number;
|
const elementWidth = (style?.width || defaultWidth)! as number;
|
||||||
const elementHeight = (style?.height || defaultHeight)! as number;
|
const elementHeight = (style?.height || defaultHeight)! as number;
|
||||||
const nodeColorFunc = (nodeColor instanceof Function ? nodeColor : () => nodeColor) as StringFunc;
|
const nodeColorFunc = (nodeColor instanceof Function ? nodeColor : () => nodeColor) as GetMiniMapNodeAttribute;
|
||||||
const nodeStrokeColorFunc = (
|
const nodeStrokeColorFunc = (
|
||||||
nodeStrokeColor instanceof Function ? nodeStrokeColor : () => nodeStrokeColor
|
nodeStrokeColor instanceof Function ? nodeStrokeColor : () => nodeStrokeColor
|
||||||
) as StringFunc;
|
) as GetMiniMapNodeAttribute;
|
||||||
const nodeClassNameFunc = (nodeClassName instanceof Function ? nodeClassName : () => nodeClassName) as StringFunc;
|
const nodeClassNameFunc = (
|
||||||
|
nodeClassName instanceof Function ? nodeClassName : () => nodeClassName
|
||||||
|
) as GetMiniMapNodeAttribute;
|
||||||
const hasNodes = nodeInternals && nodeInternals.size > 0;
|
const hasNodes = nodeInternals && nodeInternals.size > 0;
|
||||||
// @TODO: work with nodeInternals instead of converting it to an array
|
// @TODO: work with nodeInternals instead of converting it to an array
|
||||||
const nodes = Array.from(nodeInternals).map(([_, node]) => node);
|
const nodes = Array.from(nodeInternals).map(([_, node]) => node);
|
||||||
|
|||||||
@@ -4,9 +4,8 @@ import FlowRenderer from '../FlowRenderer';
|
|||||||
import NodeRenderer from '../NodeRenderer';
|
import NodeRenderer from '../NodeRenderer';
|
||||||
import EdgeRenderer from '../EdgeRenderer';
|
import EdgeRenderer from '../EdgeRenderer';
|
||||||
import Viewport from '../Viewport';
|
import Viewport from '../Viewport';
|
||||||
import { ReactFlowProps } from '../ReactFlow';
|
|
||||||
import useOnPaneReadyHandler from '../../hooks/useOnPaneReadyHandler';
|
import useOnPaneReadyHandler from '../../hooks/useOnPaneReadyHandler';
|
||||||
import { NodeTypesType, EdgeTypesType, ConnectionLineType, KeyCode } from '../../types';
|
import { NodeTypesType, EdgeTypesType, ConnectionLineType, KeyCode, ReactFlowProps } from '../../types';
|
||||||
|
|
||||||
export interface GraphViewProps extends Omit<ReactFlowProps, 'onSelectionChange' | 'nodes' | 'edges'> {
|
export interface GraphViewProps extends Omit<ReactFlowProps, 'onSelectionChange' | 'nodes' | 'edges'> {
|
||||||
nodeTypes: NodeTypesType;
|
nodeTypes: NodeTypesType;
|
||||||
|
|||||||
@@ -1,12 +1,4 @@
|
|||||||
import React, {
|
import React, { useMemo, forwardRef, FunctionComponent } from 'react';
|
||||||
useMemo,
|
|
||||||
CSSProperties,
|
|
||||||
HTMLAttributes,
|
|
||||||
MouseEvent as ReactMouseEvent,
|
|
||||||
WheelEvent,
|
|
||||||
forwardRef,
|
|
||||||
FunctionComponent,
|
|
||||||
} from 'react';
|
|
||||||
import cc from 'classcat';
|
import cc from 'classcat';
|
||||||
|
|
||||||
import GraphView from '../GraphView';
|
import GraphView from '../GraphView';
|
||||||
@@ -20,31 +12,8 @@ import { BezierEdge, StepEdge, SmoothStepEdge, StraightEdge } from '../../compon
|
|||||||
import Attribution from '../../components/Attribution';
|
import Attribution from '../../components/Attribution';
|
||||||
import { createEdgeTypes } from '../EdgeRenderer/utils';
|
import { createEdgeTypes } from '../EdgeRenderer/utils';
|
||||||
import Wrapper from './Wrapper';
|
import Wrapper from './Wrapper';
|
||||||
import {
|
|
||||||
OnSelectionChangeFunc,
|
import { ConnectionMode, ConnectionLineType, PanOnScrollMode, ReactFlowProps, ReactFlowRefType } from '../../types';
|
||||||
NodeTypesType,
|
|
||||||
EdgeTypesType,
|
|
||||||
Node,
|
|
||||||
Edge,
|
|
||||||
ConnectionMode,
|
|
||||||
ConnectionLineType,
|
|
||||||
ConnectionLineComponent,
|
|
||||||
FlowTransform,
|
|
||||||
OnConnectStart,
|
|
||||||
OnConnectStop,
|
|
||||||
OnConnectEnd,
|
|
||||||
OnConnect,
|
|
||||||
CoordinateExtent,
|
|
||||||
KeyCode,
|
|
||||||
PanOnScrollMode,
|
|
||||||
OnEdgeUpdateFunc,
|
|
||||||
NodeChange,
|
|
||||||
EdgeChange,
|
|
||||||
OnPaneReady,
|
|
||||||
ProOptions,
|
|
||||||
AttributionPosition,
|
|
||||||
DefaultEdgeOptions,
|
|
||||||
} from '../../types';
|
|
||||||
|
|
||||||
import '../../style.css';
|
import '../../style.css';
|
||||||
import '../../theme-default.css';
|
import '../../theme-default.css';
|
||||||
@@ -62,92 +31,6 @@ const defaultEdgeTypes = {
|
|||||||
smoothstep: SmoothStepEdge,
|
smoothstep: SmoothStepEdge,
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface ReactFlowProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onPaneReady'> {
|
|
||||||
nodes?: Node[];
|
|
||||||
edges?: Edge[];
|
|
||||||
defaultNodes?: Node[];
|
|
||||||
defaultEdges?: Edge[];
|
|
||||||
defaultEdgeOptions?: DefaultEdgeOptions;
|
|
||||||
onNodesChange?: (nodeChanges: NodeChange[]) => void;
|
|
||||||
onEdgesChange?: (edgeChanges: EdgeChange[]) => void;
|
|
||||||
onNodeClick?: (event: React.MouseEvent, node: Node) => void;
|
|
||||||
onEdgeClick?: (event: React.MouseEvent, node: Edge) => void;
|
|
||||||
onNodeDoubleClick?: (event: ReactMouseEvent, node: Node) => void;
|
|
||||||
onNodeMouseEnter?: (event: ReactMouseEvent, node: Node) => void;
|
|
||||||
onNodeMouseMove?: (event: ReactMouseEvent, node: Node) => void;
|
|
||||||
onNodeMouseLeave?: (event: ReactMouseEvent, node: Node) => void;
|
|
||||||
onNodeContextMenu?: (event: ReactMouseEvent, node: Node) => void;
|
|
||||||
onNodeDragStart?: (event: ReactMouseEvent, node: Node) => void;
|
|
||||||
onNodeDrag?: (event: ReactMouseEvent, node: Node) => void;
|
|
||||||
onNodeDragStop?: (event: ReactMouseEvent, node: Node) => void;
|
|
||||||
onConnect?: OnConnect;
|
|
||||||
onConnectStart?: OnConnectStart;
|
|
||||||
onConnectStop?: OnConnectStop;
|
|
||||||
onConnectEnd?: OnConnectEnd;
|
|
||||||
onPaneReady?: OnPaneReady;
|
|
||||||
onMove?: (flowTransform?: FlowTransform) => void;
|
|
||||||
onMoveStart?: (flowTransform?: FlowTransform) => void;
|
|
||||||
onMoveEnd?: (flowTransform?: FlowTransform) => void;
|
|
||||||
onSelectionChange?: OnSelectionChangeFunc;
|
|
||||||
onSelectionDragStart?: (event: ReactMouseEvent, nodes: Node[]) => void;
|
|
||||||
onSelectionDrag?: (event: ReactMouseEvent, nodes: Node[]) => void;
|
|
||||||
onSelectionDragStop?: (event: ReactMouseEvent, nodes: Node[]) => void;
|
|
||||||
onSelectionContextMenu?: (event: ReactMouseEvent, nodes: Node[]) => void;
|
|
||||||
onPaneScroll?: (event?: WheelEvent) => void;
|
|
||||||
onPaneClick?: (event: ReactMouseEvent) => void;
|
|
||||||
onPaneContextMenu?: (event: ReactMouseEvent) => void;
|
|
||||||
nodeTypes?: NodeTypesType;
|
|
||||||
edgeTypes?: EdgeTypesType;
|
|
||||||
connectionMode?: ConnectionMode;
|
|
||||||
connectionLineType?: ConnectionLineType;
|
|
||||||
connectionLineStyle?: CSSProperties;
|
|
||||||
connectionLineComponent?: ConnectionLineComponent;
|
|
||||||
deleteKeyCode?: KeyCode;
|
|
||||||
selectionKeyCode?: KeyCode;
|
|
||||||
multiSelectionKeyCode?: KeyCode;
|
|
||||||
zoomActivationKeyCode?: KeyCode;
|
|
||||||
snapToGrid?: boolean;
|
|
||||||
snapGrid?: [number, number];
|
|
||||||
onlyRenderVisibleElements?: boolean;
|
|
||||||
nodesDraggable?: boolean;
|
|
||||||
nodesConnectable?: boolean;
|
|
||||||
elementsSelectable?: boolean;
|
|
||||||
selectNodesOnDrag?: boolean;
|
|
||||||
paneMoveable?: boolean;
|
|
||||||
minZoom?: number;
|
|
||||||
maxZoom?: number;
|
|
||||||
defaultZoom?: number;
|
|
||||||
defaultPosition?: [number, number];
|
|
||||||
translateExtent?: CoordinateExtent;
|
|
||||||
preventScrolling?: boolean;
|
|
||||||
nodeExtent?: CoordinateExtent;
|
|
||||||
defaultMarkerColor?: string;
|
|
||||||
zoomOnScroll?: boolean;
|
|
||||||
zoomOnPinch?: boolean;
|
|
||||||
panOnScroll?: boolean;
|
|
||||||
panOnScrollSpeed?: number;
|
|
||||||
panOnScrollMode?: PanOnScrollMode;
|
|
||||||
zoomOnDoubleClick?: boolean;
|
|
||||||
onEdgeUpdate?: OnEdgeUpdateFunc;
|
|
||||||
onEdgeContextMenu?: (event: ReactMouseEvent, edge: Edge) => void;
|
|
||||||
onEdgeMouseEnter?: (event: ReactMouseEvent, edge: Edge) => void;
|
|
||||||
onEdgeMouseMove?: (event: ReactMouseEvent, edge: Edge) => void;
|
|
||||||
onEdgeMouseLeave?: (event: ReactMouseEvent, edge: Edge) => void;
|
|
||||||
onEdgeDoubleClick?: (event: ReactMouseEvent, edge: Edge) => void;
|
|
||||||
onEdgeUpdateStart?: (event: ReactMouseEvent, edge: Edge) => void;
|
|
||||||
onEdgeUpdateEnd?: (event: MouseEvent, edge: Edge) => void;
|
|
||||||
edgeUpdaterRadius?: number;
|
|
||||||
noDragClassName?: string;
|
|
||||||
noWheelClassName?: string;
|
|
||||||
noPanClassName?: string;
|
|
||||||
fitViewOnInit?: boolean;
|
|
||||||
connectOnClick?: boolean;
|
|
||||||
attributionPosition?: AttributionPosition;
|
|
||||||
pro?: ProOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ReactFlowRefType = HTMLDivElement;
|
|
||||||
|
|
||||||
const initSnapGrid: [number, number] = [15, 15];
|
const initSnapGrid: [number, number] = [15, 15];
|
||||||
const initDefaultPosition: [number, number] = [0, 0];
|
const initDefaultPosition: [number, number] = [0, 0];
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { clamp } from '../../utils';
|
|||||||
import useKeyPress from '../../hooks/useKeyPress';
|
import useKeyPress from '../../hooks/useKeyPress';
|
||||||
import useResizeHandler from '../../hooks/useResizeHandler';
|
import useResizeHandler from '../../hooks/useResizeHandler';
|
||||||
import { useStore, useStoreApi } from '../../store';
|
import { useStore, useStoreApi } from '../../store';
|
||||||
import { FlowTransform, PanOnScrollMode, KeyCode, ReactFlowState } from '../../types';
|
import { Viewport, PanOnScrollMode, KeyCode, ReactFlowState } from '../../types';
|
||||||
|
|
||||||
interface ZoomPaneProps {
|
interface ZoomPaneProps {
|
||||||
selectionKeyPressed: boolean;
|
selectionKeyPressed: boolean;
|
||||||
@@ -21,9 +21,9 @@ interface ZoomPaneProps {
|
|||||||
paneMoveable?: boolean;
|
paneMoveable?: boolean;
|
||||||
defaultPosition?: [number, number];
|
defaultPosition?: [number, number];
|
||||||
defaultZoom?: number;
|
defaultZoom?: number;
|
||||||
onMove?: (flowTransform?: FlowTransform) => void;
|
onMove?: (viewport?: Viewport) => void;
|
||||||
onMoveStart?: (flowTransform?: FlowTransform) => void;
|
onMoveStart?: (viewport?: Viewport) => void;
|
||||||
onMoveEnd?: (flowTransform?: FlowTransform) => void;
|
onMoveEnd?: (viewport?: Viewport) => void;
|
||||||
zoomActivationKeyCode?: KeyCode;
|
zoomActivationKeyCode?: KeyCode;
|
||||||
preventScrolling?: boolean;
|
preventScrolling?: boolean;
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
@@ -31,15 +31,13 @@ interface ZoomPaneProps {
|
|||||||
noPanClassName: string;
|
noPanClassName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const viewChanged = (prevTransform: FlowTransform, eventTransform: any): boolean =>
|
const viewChanged = (prevViewport: Viewport, eventViewport: any): boolean =>
|
||||||
prevTransform.x !== eventTransform.x ||
|
prevViewport.x !== eventViewport.x || prevViewport.y !== eventViewport.y || prevViewport.zoom !== eventViewport.k;
|
||||||
prevTransform.y !== eventTransform.y ||
|
|
||||||
prevTransform.zoom !== eventTransform.k;
|
|
||||||
|
|
||||||
const eventToFlowTransform = (eventTransform: any): FlowTransform => ({
|
const eventToFlowTransform = (eventViewport: any): Viewport => ({
|
||||||
x: eventTransform.x,
|
x: eventViewport.x,
|
||||||
y: eventTransform.y,
|
y: eventViewport.y,
|
||||||
zoom: eventTransform.k,
|
zoom: eventViewport.k,
|
||||||
});
|
});
|
||||||
|
|
||||||
const isWrappedWithClass = (event: any, className: string | undefined) => event.target.closest(`.${className}`);
|
const isWrappedWithClass = (event: any, className: string | undefined) => event.target.closest(`.${className}`);
|
||||||
@@ -73,7 +71,7 @@ const ZoomPane = ({
|
|||||||
}: ZoomPaneProps) => {
|
}: ZoomPaneProps) => {
|
||||||
const store = useStoreApi();
|
const store = useStoreApi();
|
||||||
const zoomPane = useRef<HTMLDivElement>(null);
|
const zoomPane = useRef<HTMLDivElement>(null);
|
||||||
const prevTransform = useRef<FlowTransform>({ x: 0, y: 0, zoom: 0 });
|
const prevTransform = useRef<Viewport>({ x: 0, y: 0, zoom: 0 });
|
||||||
const { d3Zoom, d3Selection, d3ZoomHandler } = useStore(selector, shallow);
|
const { d3Zoom, d3Selection, d3ZoomHandler } = useStore(selector, shallow);
|
||||||
const zoomActivationKeyPressed = useKeyPress(zoomActivationKeyCode);
|
const zoomActivationKeyPressed = useKeyPress(zoomActivationKeyCode);
|
||||||
|
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
import { useCallback } from 'react';
|
|
||||||
import shallow from 'zustand/shallow';
|
|
||||||
|
|
||||||
import { NodeBounds } from '../types';
|
|
||||||
import { useStore } from '../store';
|
|
||||||
|
|
||||||
function useNodeBounds(id: string): NodeBounds | null {
|
|
||||||
const nodeBounds = useStore(
|
|
||||||
useCallback(
|
|
||||||
(s) => {
|
|
||||||
const nodeItem = s.nodeInternals.get(id);
|
|
||||||
|
|
||||||
if (!nodeItem) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...nodeItem.positionAbsolute,
|
|
||||||
width: nodeItem.width ?? null,
|
|
||||||
height: nodeItem.height ?? null,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
[id]
|
|
||||||
),
|
|
||||||
shallow
|
|
||||||
);
|
|
||||||
|
|
||||||
return nodeBounds;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default useNodeBounds;
|
|
||||||
@@ -1,67 +1,19 @@
|
|||||||
import { useEffect, useRef } from 'react';
|
import { useEffect, useRef } from 'react';
|
||||||
|
|
||||||
import { pointToRendererPoint } from '../utils/graph';
|
import useReactFlow from './useReactFlow';
|
||||||
import { useStoreApi } from '../store';
|
import { OnPaneReady } from '../types';
|
||||||
import useZoomPanHelper from '../hooks/useZoomPanHelper';
|
|
||||||
import { OnPaneReady, XYPosition, Node, Edge, FlowExportObject } from '../types';
|
|
||||||
|
|
||||||
function useOnPaneReadyHandler(onPaneReady: OnPaneReady<any> | undefined) {
|
function useOnPaneReadyHandler(onPaneReady: OnPaneReady<any> | undefined) {
|
||||||
|
const ReactFlowInstance = useReactFlow();
|
||||||
const isInitialized = useRef<boolean>(false);
|
const isInitialized = useRef<boolean>(false);
|
||||||
const store = useStoreApi();
|
|
||||||
const { zoomIn, zoomOut, zoomTo, getZoom, setTransform, getTransform, setCenter, fitView, initialized } =
|
|
||||||
useZoomPanHelper();
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isInitialized.current && initialized) {
|
if (!isInitialized.current && ReactFlowInstance.viewportInitialized && onPaneReady) {
|
||||||
if (onPaneReady) {
|
onPaneReady(ReactFlowInstance);
|
||||||
const project = (position: XYPosition): XYPosition => {
|
|
||||||
const { transform, snapToGrid, snapGrid } = store.getState();
|
|
||||||
return pointToRendererPoint(position, transform, snapToGrid, snapGrid);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getNodes = (): Node[] => {
|
|
||||||
const { nodeInternals } = store.getState();
|
|
||||||
// @TODO: work with nodeInternals instead of converting it to an array
|
|
||||||
const nodes = Array.from(nodeInternals).map(([_, node]) => node);
|
|
||||||
return nodes.map((n) => ({ ...n }));
|
|
||||||
};
|
|
||||||
|
|
||||||
const getEdges = (): Edge[] => {
|
|
||||||
const { edges = [] } = store.getState();
|
|
||||||
return edges.map((e) => ({ ...e }));
|
|
||||||
};
|
|
||||||
|
|
||||||
const toObject = (): FlowExportObject => {
|
|
||||||
const { nodeInternals, edges = [], transform } = store.getState();
|
|
||||||
// @TODO: work with nodeInternals instead of converting it to an array
|
|
||||||
const nodes = Array.from(nodeInternals).map(([_, node]) => node);
|
|
||||||
return {
|
|
||||||
nodes: nodes.map((n) => ({ ...n })),
|
|
||||||
edges: edges.map((e) => ({ ...e })),
|
|
||||||
position: [transform[0], transform[1]],
|
|
||||||
zoom: transform[2],
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
onPaneReady({
|
|
||||||
fitView: (params = { padding: 0.1 }) => fitView(params),
|
|
||||||
zoomIn,
|
|
||||||
zoomOut,
|
|
||||||
zoomTo,
|
|
||||||
getZoom,
|
|
||||||
setTransform,
|
|
||||||
getTransform,
|
|
||||||
setCenter,
|
|
||||||
project,
|
|
||||||
getNodes,
|
|
||||||
getEdges,
|
|
||||||
toObject,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
isInitialized.current = true;
|
isInitialized.current = true;
|
||||||
}
|
}
|
||||||
}, [onPaneReady, zoomIn, zoomOut, zoomTo, setTransform, fitView, initialized]);
|
}, [onPaneReady, ReactFlowInstance]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default useOnPaneReadyHandler;
|
export default useOnPaneReadyHandler;
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
import { useCallback } from 'react';
|
||||||
|
import useViewportHelper from './useViewportHelper';
|
||||||
|
import { useStoreApi } from '../store';
|
||||||
|
import { ReactFlowInstance, Instance } from '../types';
|
||||||
|
|
||||||
|
export default function useReactFlow<NodeData, EdgeData>(): ReactFlowInstance<NodeData, EdgeData> {
|
||||||
|
const { initialized: viewportInitialized, ...viewportHelperFunctions } = useViewportHelper();
|
||||||
|
const store = useStoreApi();
|
||||||
|
|
||||||
|
const getNodes = useCallback<Instance.GetNodes<NodeData>>(() => {
|
||||||
|
const { nodeInternals } = store.getState();
|
||||||
|
const nodes = Array.from(nodeInternals.values());
|
||||||
|
return nodes.map((n) => ({ ...n }));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const getNode = useCallback<Instance.GetNode<NodeData>>((id) => {
|
||||||
|
const { nodeInternals } = store.getState();
|
||||||
|
return nodeInternals.get(id);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const getEdges = useCallback<Instance.GetEdges<EdgeData>>(() => {
|
||||||
|
const { edges = [] } = store.getState();
|
||||||
|
return edges.map((e) => ({ ...e }));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const getEdge = useCallback<Instance.GetEdge<EdgeData>>((id) => {
|
||||||
|
const { edges = [] } = store.getState();
|
||||||
|
return edges.find((e) => e.id === id);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const setNodes = useCallback<Instance.SetNodes<NodeData>>((payload) => {
|
||||||
|
const { nodeInternals, setNodes } = store.getState();
|
||||||
|
const nodes = Array.from(nodeInternals.values());
|
||||||
|
const nextNodes = typeof payload === 'function' ? payload(nodes) : payload;
|
||||||
|
setNodes(nextNodes);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const setEdges = useCallback<Instance.SetEdges<EdgeData>>((payload) => {
|
||||||
|
const { edges = [], setEdges } = store.getState();
|
||||||
|
const nextEdges = typeof payload === 'function' ? payload(edges) : payload;
|
||||||
|
setEdges(nextEdges);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const addNodes = useCallback<Instance.AddNodes<NodeData>>((payload) => {
|
||||||
|
const nodes = Array.isArray(payload) ? payload : [payload];
|
||||||
|
const { nodeInternals, setNodes } = store.getState();
|
||||||
|
const currentNodes = Array.from(nodeInternals.values());
|
||||||
|
const nextNodes = [...currentNodes, ...nodes];
|
||||||
|
setNodes(nextNodes);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const addEdges = useCallback<Instance.AddEdges<EdgeData>>((payload) => {
|
||||||
|
const nextEdges = Array.isArray(payload) ? payload : [payload];
|
||||||
|
const { edges = [], setEdges } = store.getState();
|
||||||
|
setEdges([...edges, ...nextEdges]);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const toObject = useCallback<Instance.ToObject<NodeData, EdgeData>>(() => {
|
||||||
|
const { nodeInternals, edges = [], transform } = store.getState();
|
||||||
|
const nodes = Array.from(nodeInternals.values());
|
||||||
|
const [x, y, zoom] = transform;
|
||||||
|
return {
|
||||||
|
nodes: nodes.map((n) => ({ ...n })),
|
||||||
|
edges: edges.map((e) => ({ ...e })),
|
||||||
|
viewport: {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
zoom,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...viewportHelperFunctions,
|
||||||
|
viewportInitialized,
|
||||||
|
getNodes,
|
||||||
|
getNode,
|
||||||
|
getEdges,
|
||||||
|
getEdge,
|
||||||
|
setNodes,
|
||||||
|
setEdges,
|
||||||
|
addNodes,
|
||||||
|
addEdges,
|
||||||
|
toObject,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
import { useMemo } from 'react';
|
|
||||||
import { useStoreApi } from '../store';
|
|
||||||
import { Edge } from '../types';
|
|
||||||
|
|
||||||
type FunctionParams<T> = (nodes: Edge<T>[], setEdges: (nodes: Edge<T>[]) => void) => void;
|
|
||||||
|
|
||||||
function useUpdateEdges<T>() {
|
|
||||||
const store = useStoreApi();
|
|
||||||
|
|
||||||
const update = useMemo(() => {
|
|
||||||
return (action: FunctionParams<T>): void => {
|
|
||||||
const { edges, setEdges } = store.getState();
|
|
||||||
|
|
||||||
if (typeof action === 'function') {
|
|
||||||
action(edges, setEdges);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return update;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default useUpdateEdges;
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
import { useMemo } from 'react';
|
|
||||||
import { useStoreApi } from '../store';
|
|
||||||
import { Node } from '../types';
|
|
||||||
|
|
||||||
type FunctionParams<T> = (nodes: Node<T>[], setNodes: (nodes: Node<T>[]) => void) => void;
|
|
||||||
|
|
||||||
function useUpdateNodes<T>() {
|
|
||||||
const store = useStoreApi();
|
|
||||||
|
|
||||||
const update = useMemo(() => {
|
|
||||||
return (action: FunctionParams<T>): void => {
|
|
||||||
const { nodeInternals, setNodes } = store.getState();
|
|
||||||
const nodes = Array.from(nodeInternals.values()) as Node<T>[];
|
|
||||||
|
|
||||||
if (typeof action === 'function') {
|
|
||||||
action(nodes, setNodes);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return update;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default useUpdateNodes;
|
|
||||||
@@ -5,17 +5,17 @@ import { Selection as D3Selection } from 'd3';
|
|||||||
|
|
||||||
import { useStoreApi, useStore } from '../store';
|
import { useStoreApi, useStore } from '../store';
|
||||||
import { getRectOfNodeInternals, pointToRendererPoint, getTransformForBounds } from '../utils/graph';
|
import { getRectOfNodeInternals, pointToRendererPoint, getTransformForBounds } from '../utils/graph';
|
||||||
import { FitViewParams, FlowTransform, ZoomPanHelperFunctions, ReactFlowState, Rect, XYPosition } from '../types';
|
import { FitViewParams, Viewport, ViewportHelperFunctions, ReactFlowState, Rect, XYPosition } from '../types';
|
||||||
|
|
||||||
const DEFAULT_PADDING = 0.1;
|
const DEFAULT_PADDING = 0.1;
|
||||||
|
|
||||||
const initialZoomPanHelper: ZoomPanHelperFunctions = {
|
const initialViewportHelper: ViewportHelperFunctions = {
|
||||||
zoomIn: () => {},
|
zoomIn: () => {},
|
||||||
zoomOut: () => {},
|
zoomOut: () => {},
|
||||||
zoomTo: (_: number) => {},
|
zoomTo: (_: number) => {},
|
||||||
getZoom: () => 1,
|
getZoom: () => 1,
|
||||||
setTransform: (_: FlowTransform) => {},
|
setViewport: (_: Viewport) => {},
|
||||||
getTransform: () => ({ x: 0, y: 0, zoom: 1 }),
|
getViewport: () => ({ x: 0, y: 0, zoom: 1 }),
|
||||||
fitView: (_: FitViewParams = { padding: DEFAULT_PADDING, includeHiddenNodes: false }) => {},
|
fitView: (_: FitViewParams = { padding: DEFAULT_PADDING, includeHiddenNodes: false }) => {},
|
||||||
setCenter: (_: number, __: number) => {},
|
setCenter: (_: number, __: number) => {},
|
||||||
fitBounds: (_: Rect) => {},
|
fitBounds: (_: Rect) => {},
|
||||||
@@ -32,11 +32,11 @@ const getTransition = (selection: D3Selection<Element, unknown, null, undefined>
|
|||||||
return selection.transition().duration(duration);
|
return selection.transition().duration(duration);
|
||||||
};
|
};
|
||||||
|
|
||||||
const useZoomPanHelper = (): ZoomPanHelperFunctions => {
|
const useViewportHelper = (): ViewportHelperFunctions => {
|
||||||
const store = useStoreApi();
|
const store = useStoreApi();
|
||||||
const { d3Zoom, d3Selection } = useStore(selector, shallow);
|
const { d3Zoom, d3Selection } = useStore(selector, shallow);
|
||||||
|
|
||||||
const zoomPanHelperFunctions = useMemo<ZoomPanHelperFunctions>(() => {
|
const viewportHelperFunctions = useMemo<ViewportHelperFunctions>(() => {
|
||||||
if (d3Selection && d3Zoom) {
|
if (d3Selection && d3Zoom) {
|
||||||
return {
|
return {
|
||||||
zoomIn: (options) => d3Zoom.scaleBy(getTransition(d3Selection, options?.duration), 1.2),
|
zoomIn: (options) => d3Zoom.scaleBy(getTransition(d3Selection, options?.duration), 1.2),
|
||||||
@@ -46,11 +46,11 @@ const useZoomPanHelper = (): ZoomPanHelperFunctions => {
|
|||||||
const [, , zoom] = store.getState().transform;
|
const [, , zoom] = store.getState().transform;
|
||||||
return zoom;
|
return zoom;
|
||||||
},
|
},
|
||||||
setTransform: (transform, options) => {
|
setViewport: (transform, options) => {
|
||||||
const nextTransform = zoomIdentity.translate(transform.x, transform.y).scale(transform.zoom);
|
const nextTransform = zoomIdentity.translate(transform.x, transform.y).scale(transform.zoom);
|
||||||
d3Zoom.transform(getTransition(d3Selection, options?.duration), nextTransform);
|
d3Zoom.transform(getTransition(d3Selection, options?.duration), nextTransform);
|
||||||
},
|
},
|
||||||
getTransform: () => {
|
getViewport: () => {
|
||||||
const [x, y, zoom] = store.getState().transform;
|
const [x, y, zoom] = store.getState().transform;
|
||||||
return { x, y, zoom };
|
return { x, y, zoom };
|
||||||
},
|
},
|
||||||
@@ -109,10 +109,10 @@ const useZoomPanHelper = (): ZoomPanHelperFunctions => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return initialZoomPanHelper;
|
return initialViewportHelper;
|
||||||
}, [d3Zoom, d3Selection]);
|
}, [d3Zoom, d3Selection]);
|
||||||
|
|
||||||
return zoomPanHelperFunctions;
|
return viewportHelperFunctions;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useZoomPanHelper;
|
export default useViewportHelper;
|
||||||
+4
-12
@@ -8,7 +8,7 @@ export { default as StraightEdge } from './components/Edges/StraightEdge';
|
|||||||
export { default as StepEdge } from './components/Edges/StepEdge';
|
export { default as StepEdge } from './components/Edges/StepEdge';
|
||||||
export { default as BezierEdge, getBezierPath } from './components/Edges/BezierEdge';
|
export { default as BezierEdge, getBezierPath } from './components/Edges/BezierEdge';
|
||||||
export { default as SmoothStepEdge, getSmoothStepPath } from './components/Edges/SmoothStepEdge';
|
export { default as SmoothStepEdge, getSmoothStepPath } from './components/Edges/SmoothStepEdge';
|
||||||
export { getMarkerEnd, getCenter as getEdgeCenter } from './components/Edges/utils';
|
export * from './additional-components';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
isNode,
|
isNode,
|
||||||
@@ -22,19 +22,11 @@ export {
|
|||||||
getRectOfNodes,
|
getRectOfNodes,
|
||||||
} from './utils/graph';
|
} from './utils/graph';
|
||||||
export { applyNodeChanges, applyEdgeChanges } from './utils/changes';
|
export { applyNodeChanges, applyEdgeChanges } from './utils/changes';
|
||||||
|
export { getMarkerEnd, getCenter as getEdgeCenter } from './components/Edges/utils';
|
||||||
|
|
||||||
export { default as useZoomPanHelper } from './hooks/useZoomPanHelper';
|
export { default as useReactFlow } from './hooks/useReactFlow';
|
||||||
export { default as useUpdateNodeInternals } from './hooks/useUpdateNodeInternals';
|
export { default as useUpdateNodeInternals } from './hooks/useUpdateNodeInternals';
|
||||||
export { default as useNodeBounds } from './hooks/useNodeBounds';
|
|
||||||
export { default as useUpdateNodes } from './hooks/useUpdateNodes';
|
|
||||||
export { default as useUpdateEdges } from './hooks/useUpdateEdges';
|
|
||||||
export * from './hooks/useNodesEdgesState';
|
export * from './hooks/useNodesEdgesState';
|
||||||
|
|
||||||
export * from './additional-components';
|
|
||||||
export { useStore, useStoreApi } from './store';
|
export { useStore, useStoreApi } from './store';
|
||||||
export * from './types';
|
|
||||||
|
|
||||||
export { ReactFlowProps } from './container/ReactFlow';
|
export * from './types';
|
||||||
export { MiniMapProps } from './additional-components/MiniMap';
|
|
||||||
export { ControlProps } from './additional-components/Controls';
|
|
||||||
export { BackgroundProps } from './additional-components/Background';
|
|
||||||
|
|||||||
@@ -0,0 +1,146 @@
|
|||||||
|
import React, { CSSProperties, HTMLAttributes, MouseEvent as ReactMouseEvent, WheelEvent } from 'react';
|
||||||
|
|
||||||
|
import {
|
||||||
|
OnSelectionChangeFunc,
|
||||||
|
NodeTypesType,
|
||||||
|
EdgeTypesType,
|
||||||
|
Node,
|
||||||
|
Edge,
|
||||||
|
ConnectionMode,
|
||||||
|
ConnectionLineType,
|
||||||
|
ConnectionLineComponent,
|
||||||
|
Viewport,
|
||||||
|
OnConnectStart,
|
||||||
|
OnConnectStop,
|
||||||
|
OnConnectEnd,
|
||||||
|
OnConnect,
|
||||||
|
CoordinateExtent,
|
||||||
|
KeyCode,
|
||||||
|
PanOnScrollMode,
|
||||||
|
OnEdgeUpdateFunc,
|
||||||
|
NodeChange,
|
||||||
|
EdgeChange,
|
||||||
|
OnPaneReady,
|
||||||
|
ProOptions,
|
||||||
|
AttributionPosition,
|
||||||
|
DefaultEdgeOptions,
|
||||||
|
FitViewParams,
|
||||||
|
BackgroundVariant,
|
||||||
|
} from '.';
|
||||||
|
|
||||||
|
export interface ReactFlowProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onPaneReady'> {
|
||||||
|
nodes?: Node[];
|
||||||
|
edges?: Edge[];
|
||||||
|
defaultNodes?: Node[];
|
||||||
|
defaultEdges?: Edge[];
|
||||||
|
defaultEdgeOptions?: DefaultEdgeOptions;
|
||||||
|
onNodesChange?: (nodeChanges: NodeChange[]) => void;
|
||||||
|
onEdgesChange?: (edgeChanges: EdgeChange[]) => void;
|
||||||
|
onNodeClick?: (event: React.MouseEvent, node: Node) => void;
|
||||||
|
onEdgeClick?: (event: React.MouseEvent, node: Edge) => void;
|
||||||
|
onNodeDoubleClick?: (event: ReactMouseEvent, node: Node) => void;
|
||||||
|
onNodeMouseEnter?: (event: ReactMouseEvent, node: Node) => void;
|
||||||
|
onNodeMouseMove?: (event: ReactMouseEvent, node: Node) => void;
|
||||||
|
onNodeMouseLeave?: (event: ReactMouseEvent, node: Node) => void;
|
||||||
|
onNodeContextMenu?: (event: ReactMouseEvent, node: Node) => void;
|
||||||
|
onNodeDragStart?: (event: ReactMouseEvent, node: Node) => void;
|
||||||
|
onNodeDrag?: (event: ReactMouseEvent, node: Node) => void;
|
||||||
|
onNodeDragStop?: (event: ReactMouseEvent, node: Node) => void;
|
||||||
|
onConnect?: OnConnect;
|
||||||
|
onConnectStart?: OnConnectStart;
|
||||||
|
onConnectStop?: OnConnectStop;
|
||||||
|
onConnectEnd?: OnConnectEnd;
|
||||||
|
onPaneReady?: OnPaneReady;
|
||||||
|
onMove?: (viewport?: Viewport) => void;
|
||||||
|
onMoveStart?: (viewport?: Viewport) => void;
|
||||||
|
onMoveEnd?: (viewport?: Viewport) => void;
|
||||||
|
onSelectionChange?: OnSelectionChangeFunc;
|
||||||
|
onSelectionDragStart?: (event: ReactMouseEvent, nodes: Node[]) => void;
|
||||||
|
onSelectionDrag?: (event: ReactMouseEvent, nodes: Node[]) => void;
|
||||||
|
onSelectionDragStop?: (event: ReactMouseEvent, nodes: Node[]) => void;
|
||||||
|
onSelectionContextMenu?: (event: ReactMouseEvent, nodes: Node[]) => void;
|
||||||
|
onPaneScroll?: (event?: WheelEvent) => void;
|
||||||
|
onPaneClick?: (event: ReactMouseEvent) => void;
|
||||||
|
onPaneContextMenu?: (event: ReactMouseEvent) => void;
|
||||||
|
nodeTypes?: NodeTypesType;
|
||||||
|
edgeTypes?: EdgeTypesType;
|
||||||
|
connectionMode?: ConnectionMode;
|
||||||
|
connectionLineType?: ConnectionLineType;
|
||||||
|
connectionLineStyle?: CSSProperties;
|
||||||
|
connectionLineComponent?: ConnectionLineComponent;
|
||||||
|
deleteKeyCode?: KeyCode;
|
||||||
|
selectionKeyCode?: KeyCode;
|
||||||
|
multiSelectionKeyCode?: KeyCode;
|
||||||
|
zoomActivationKeyCode?: KeyCode;
|
||||||
|
snapToGrid?: boolean;
|
||||||
|
snapGrid?: [number, number];
|
||||||
|
onlyRenderVisibleElements?: boolean;
|
||||||
|
nodesDraggable?: boolean;
|
||||||
|
nodesConnectable?: boolean;
|
||||||
|
elementsSelectable?: boolean;
|
||||||
|
selectNodesOnDrag?: boolean;
|
||||||
|
paneMoveable?: boolean;
|
||||||
|
minZoom?: number;
|
||||||
|
maxZoom?: number;
|
||||||
|
defaultZoom?: number;
|
||||||
|
defaultPosition?: [number, number];
|
||||||
|
translateExtent?: CoordinateExtent;
|
||||||
|
preventScrolling?: boolean;
|
||||||
|
nodeExtent?: CoordinateExtent;
|
||||||
|
defaultMarkerColor?: string;
|
||||||
|
zoomOnScroll?: boolean;
|
||||||
|
zoomOnPinch?: boolean;
|
||||||
|
panOnScroll?: boolean;
|
||||||
|
panOnScrollSpeed?: number;
|
||||||
|
panOnScrollMode?: PanOnScrollMode;
|
||||||
|
zoomOnDoubleClick?: boolean;
|
||||||
|
onEdgeUpdate?: OnEdgeUpdateFunc;
|
||||||
|
onEdgeContextMenu?: (event: ReactMouseEvent, edge: Edge) => void;
|
||||||
|
onEdgeMouseEnter?: (event: ReactMouseEvent, edge: Edge) => void;
|
||||||
|
onEdgeMouseMove?: (event: ReactMouseEvent, edge: Edge) => void;
|
||||||
|
onEdgeMouseLeave?: (event: ReactMouseEvent, edge: Edge) => void;
|
||||||
|
onEdgeDoubleClick?: (event: ReactMouseEvent, edge: Edge) => void;
|
||||||
|
onEdgeUpdateStart?: (event: ReactMouseEvent, edge: Edge) => void;
|
||||||
|
onEdgeUpdateEnd?: (event: MouseEvent, edge: Edge) => void;
|
||||||
|
edgeUpdaterRadius?: number;
|
||||||
|
noDragClassName?: string;
|
||||||
|
noWheelClassName?: string;
|
||||||
|
noPanClassName?: string;
|
||||||
|
fitViewOnInit?: boolean;
|
||||||
|
connectOnClick?: boolean;
|
||||||
|
attributionPosition?: AttributionPosition;
|
||||||
|
pro?: ProOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ReactFlowRefType = HTMLDivElement;
|
||||||
|
|
||||||
|
export type GetMiniMapNodeAttribute<NodeData = any> = (node: Node<NodeData>) => string;
|
||||||
|
|
||||||
|
export interface MiniMapProps<NodeData = any> extends HTMLAttributes<SVGSVGElement> {
|
||||||
|
nodeColor?: string | GetMiniMapNodeAttribute<NodeData>;
|
||||||
|
nodeStrokeColor?: string | GetMiniMapNodeAttribute<NodeData>;
|
||||||
|
nodeClassName?: string | GetMiniMapNodeAttribute<NodeData>;
|
||||||
|
nodeBorderRadius?: number;
|
||||||
|
nodeStrokeWidth?: number;
|
||||||
|
maskColor?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ControlProps extends HTMLAttributes<HTMLDivElement> {
|
||||||
|
showZoom?: boolean;
|
||||||
|
showFitView?: boolean;
|
||||||
|
showInteractive?: boolean;
|
||||||
|
fitViewParams?: FitViewParams;
|
||||||
|
onZoomIn?: () => void;
|
||||||
|
onZoomOut?: () => void;
|
||||||
|
onFitView?: () => void;
|
||||||
|
onInteractiveChange?: (interactiveStatus: boolean) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ControlButtonProps extends HTMLAttributes<HTMLButtonElement> {}
|
||||||
|
|
||||||
|
export interface BackgroundProps extends HTMLAttributes<SVGElement> {
|
||||||
|
variant?: BackgroundVariant;
|
||||||
|
gap?: number;
|
||||||
|
color?: string;
|
||||||
|
size?: number;
|
||||||
|
}
|
||||||
+15
-36
@@ -7,6 +7,7 @@ import { Node, NodeInternals, NodeDimensionUpdate, NodeDiffUpdate } from './node
|
|||||||
import { Edge } from './edges';
|
import { Edge } from './edges';
|
||||||
import { HandleType, StartHandle } from './handles';
|
import { HandleType, StartHandle } from './handles';
|
||||||
import { DefaultEdgeOptions } from '.';
|
import { DefaultEdgeOptions } from '.';
|
||||||
|
import { ReactFlowInstance } from './instance';
|
||||||
|
|
||||||
export type NodeTypesType = { [key: string]: ReactNode };
|
export type NodeTypesType = { [key: string]: ReactNode };
|
||||||
export type EdgeTypesType = NodeTypesType;
|
export type EdgeTypesType = NodeTypesType;
|
||||||
@@ -15,36 +16,21 @@ export type FitView = (fitViewOptions?: FitViewParams) => void;
|
|||||||
|
|
||||||
export type Project = (position: XYPosition) => XYPosition;
|
export type Project = (position: XYPosition) => XYPosition;
|
||||||
|
|
||||||
export type ToObject<T = any> = () => FlowExportObject<T>;
|
|
||||||
|
|
||||||
export type OnNodesChange = (nodes: NodeChange[]) => void;
|
export type OnNodesChange = (nodes: NodeChange[]) => void;
|
||||||
|
|
||||||
export type OnEdgesChange = (nodes: EdgeChange[]) => void;
|
export type OnEdgesChange = (nodes: EdgeChange[]) => void;
|
||||||
|
|
||||||
export type ZoomInOut = (options?: ZoomPanHelperFunctionOptions) => void;
|
export type ZoomInOut = (options?: ViewportHelperFunctionOptions) => void;
|
||||||
export type ZoomTo = (zoomLevel: number, options?: ZoomPanHelperFunctionOptions) => void;
|
export type ZoomTo = (zoomLevel: number, options?: ViewportHelperFunctionOptions) => void;
|
||||||
export type GetZoom = () => number;
|
export type GetZoom = () => number;
|
||||||
export type GetTransform = () => FlowTransform;
|
export type GetViewport = () => Viewport;
|
||||||
export type SetTransform = (transform: FlowTransform, options?: ZoomPanHelperFunctionOptions) => void;
|
export type SetViewport = (viewport: Viewport, options?: ViewportHelperFunctionOptions) => void;
|
||||||
export type SetCenter = (x: number, y: number, options?: SetCenterOptions) => void;
|
export type SetCenter = (x: number, y: number, options?: SetCenterOptions) => void;
|
||||||
export type FitBounds = (bounds: Rect, options?: FitBoundsOptions) => void;
|
export type FitBounds = (bounds: Rect, options?: FitBoundsOptions) => void;
|
||||||
|
|
||||||
export type ReactFlowInstance<T = any> = {
|
export type OnPaneReady<NodeData = any, EdgeData = any> = (
|
||||||
zoomIn: ZoomInOut;
|
reactFlowInstance: ReactFlowInstance<NodeData, EdgeData>
|
||||||
zoomOut: ZoomInOut;
|
) => void;
|
||||||
zoomTo: ZoomTo;
|
|
||||||
getZoom: () => number;
|
|
||||||
setCenter: SetCenter;
|
|
||||||
fitView: FitView;
|
|
||||||
project: Project;
|
|
||||||
getNodes: () => Node<T>[];
|
|
||||||
getEdges: () => Edge<T>[];
|
|
||||||
setTransform: SetTransform;
|
|
||||||
getTransform: () => FlowTransform;
|
|
||||||
toObject: ToObject<T>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type OnPaneReady<T = any> = (reactFlowInstance: ReactFlowInstance<T>) => void;
|
|
||||||
|
|
||||||
export interface Connection {
|
export interface Connection {
|
||||||
source: string | null;
|
source: string | null;
|
||||||
@@ -58,13 +44,6 @@ export enum ConnectionMode {
|
|||||||
Loose = 'loose',
|
Loose = 'loose',
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FlowExportObject<T = any> = {
|
|
||||||
nodes: Node<T>[];
|
|
||||||
edges: Edge<T>[];
|
|
||||||
position: [number, number];
|
|
||||||
zoom: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type OnConnect = (connection: Connection) => void;
|
export type OnConnect = (connection: Connection) => void;
|
||||||
|
|
||||||
export type FitViewParams = {
|
export type FitViewParams = {
|
||||||
@@ -92,7 +71,7 @@ export enum BackgroundVariant {
|
|||||||
Dots = 'dots',
|
Dots = 'dots',
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FlowTransform = {
|
export type Viewport = {
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
zoom: number;
|
zoom: number;
|
||||||
@@ -108,25 +87,25 @@ export enum PanOnScrollMode {
|
|||||||
Horizontal = 'horizontal',
|
Horizontal = 'horizontal',
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ZoomPanHelperFunctionOptions = {
|
export type ViewportHelperFunctionOptions = {
|
||||||
duration?: number;
|
duration?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SetCenterOptions = ZoomPanHelperFunctionOptions & {
|
export type SetCenterOptions = ViewportHelperFunctionOptions & {
|
||||||
zoom?: number;
|
zoom?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type FitBoundsOptions = ZoomPanHelperFunctionOptions & {
|
export type FitBoundsOptions = ViewportHelperFunctionOptions & {
|
||||||
padding?: number;
|
padding?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface ZoomPanHelperFunctions {
|
export interface ViewportHelperFunctions {
|
||||||
zoomIn: ZoomInOut;
|
zoomIn: ZoomInOut;
|
||||||
zoomOut: ZoomInOut;
|
zoomOut: ZoomInOut;
|
||||||
zoomTo: ZoomTo;
|
zoomTo: ZoomTo;
|
||||||
getZoom: GetZoom;
|
getZoom: GetZoom;
|
||||||
setTransform: SetTransform;
|
setViewport: SetViewport;
|
||||||
getTransform: GetTransform;
|
getViewport: GetViewport;
|
||||||
fitView: FitView;
|
fitView: FitView;
|
||||||
setCenter: SetCenter;
|
setCenter: SetCenter;
|
||||||
fitBounds: FitBounds;
|
fitBounds: FitBounds;
|
||||||
|
|||||||
@@ -4,3 +4,5 @@ export * from './edges';
|
|||||||
export * from './handles';
|
export * from './handles';
|
||||||
export * from './changes';
|
export * from './changes';
|
||||||
export * from './utils';
|
export * from './utils';
|
||||||
|
export * from './instance';
|
||||||
|
export * from './component-props';
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import { ViewportHelperFunctions, Viewport } from './general';
|
||||||
|
import { Node } from './nodes';
|
||||||
|
import { Edge } from './edges';
|
||||||
|
|
||||||
|
export type ReactFlowJsonObject<NodeData = any, EdgeData = any> = {
|
||||||
|
nodes: Node<NodeData>[];
|
||||||
|
edges: Edge<EdgeData>[];
|
||||||
|
viewport: Viewport;
|
||||||
|
};
|
||||||
|
|
||||||
|
export namespace Instance {
|
||||||
|
export type GetNodes<NodeData> = () => Node<NodeData>[];
|
||||||
|
export type SetNodes<NodeData> = (
|
||||||
|
payload: Node<NodeData>[] | ((nodes: Node<NodeData>[]) => Node<NodeData>[])
|
||||||
|
) => void;
|
||||||
|
export type AddNodes<NodeData> = (payload: Node<NodeData>[] | Node<NodeData>) => void;
|
||||||
|
export type GetNode<NodeData> = (id: string) => Node<NodeData> | undefined;
|
||||||
|
export type GetEdges<EdgeData> = () => Edge<EdgeData>[];
|
||||||
|
export type SetEdges<EdgeData> = (
|
||||||
|
payload: Edge<EdgeData>[] | ((edges: Edge<EdgeData>[]) => Edge<EdgeData>[])
|
||||||
|
) => void;
|
||||||
|
export type GetEdge<EdgeData> = (id: string) => Edge<EdgeData> | undefined;
|
||||||
|
export type AddEdges<EdgeData> = (payload: Edge<EdgeData>[] | Edge<EdgeData>) => void;
|
||||||
|
export type ToObject<NodeData = any, EdgeData = any> = () => ReactFlowJsonObject<NodeData, EdgeData>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ReactFlowInstance<NodeData = any, EdgeData = any> = {
|
||||||
|
getNodes: Instance.GetNodes<NodeData>;
|
||||||
|
setNodes: Instance.SetNodes<NodeData>;
|
||||||
|
addNodes: Instance.AddNodes<NodeData>;
|
||||||
|
getNode: Instance.GetNode<NodeData>;
|
||||||
|
getEdges: Instance.GetEdges<EdgeData>;
|
||||||
|
setEdges: Instance.SetEdges<EdgeData>;
|
||||||
|
addEdges: Instance.AddEdges<EdgeData>;
|
||||||
|
getEdge: Instance.GetEdge<EdgeData>;
|
||||||
|
toObject: Instance.ToObject<NodeData, EdgeData>;
|
||||||
|
viewportInitialized: boolean;
|
||||||
|
} & Omit<ViewportHelperFunctions, 'initialized'>;
|
||||||
Reference in New Issue
Block a user