diff --git a/src/additional-components/MiniMap/index.tsx b/src/additional-components/MiniMap/index.tsx index bf3fe8d6..0585aff5 100644 --- a/src/additional-components/MiniMap/index.tsx +++ b/src/additional-components/MiniMap/index.tsx @@ -7,7 +7,7 @@ import { useStore } from '../../store'; import { getRectOfNodes } from '../../utils/graph'; import { getBoundsofRects } from '../../utils'; -import { MiniMapProps, GetMiniMapNodeAttribute, ReactFlowState, Rect } from '../../types'; +import { MiniMapProps, GetMiniMapNodeAttribute, ReactFlowState } from '../../types'; declare const window: any; @@ -15,9 +15,12 @@ const defaultWidth = 200; const defaultHeight = 150; const selector = (s: ReactFlowState) => ({ - width: s.width, - height: s.height, - transform: s.transform, + viewBBox: { + x: -s.transform[0] / s.transform[2], + y: -s.transform[1] / s.transform[2], + width: s.width / s.transform[2], + height: s.height / s.transform[2], + }, nodes: Array.from(s.nodeInternals.values()), }); @@ -33,19 +36,13 @@ const MiniMap = ({ nodeStrokeWidth = 2, maskColor = 'rgb(240, 242, 243, 0.7)', }: MiniMapProps) => { - const { width: containerWidth, height: containerHeight, transform, nodes } = useStore(selector, shallow); + const { viewBBox, nodes } = useStore(selector, shallow); const elementWidth = (style?.width as number) ?? defaultWidth; const elementHeight = (style?.height as number) ?? defaultHeight; const nodeColorFunc = getAttrFunction(nodeColor); const nodeStrokeColorFunc = getAttrFunction(nodeStrokeColor); const nodeClassNameFunc = getAttrFunction(nodeClassName); - const viewBB: Rect = { - x: -transform[0] / transform[2], - y: -transform[1] / transform[2], - width: containerWidth / transform[2], - height: containerHeight / transform[2], - }; - const boundingRect = nodes.length > 0 ? getBoundsofRects(getRectOfNodes(nodes), viewBB) : viewBB; + const boundingRect = nodes.length > 0 ? getBoundsofRects(getRectOfNodes(nodes), viewBBox) : viewBBox; const scaledWidth = boundingRect.width / elementWidth; const scaledHeight = boundingRect.height / elementHeight; const viewScale = Math.max(scaledWidth, scaledHeight); @@ -89,7 +86,7 @@ const MiniMap = ({ diff --git a/src/components/ConnectionLine/index.tsx b/src/components/ConnectionLine/index.tsx index 2fa29ba0..3634e08f 100644 --- a/src/components/ConnectionLine/index.tsx +++ b/src/components/ConnectionLine/index.tsx @@ -1,58 +1,54 @@ -import React, { useRef, CSSProperties } from 'react'; +import React, { CSSProperties, useCallback } from 'react'; import shallow from 'zustand/shallow'; import { useStore } from '../../store'; import { getBezierPath } from '../Edges/BezierEdge'; import { getSmoothStepPath } from '../Edges/SmoothStepEdge'; -import { ConnectionLineType, ConnectionLineComponent, HandleType, Node, ReactFlowState, Position } from '../../types'; +import { ConnectionLineType, ConnectionLineComponent, HandleType, Position } from '../../types'; import { getSimpleBezierPath } from '../Edges/SimpleBezierEdge'; import { internalsSymbol } from '../../utils'; interface ConnectionLineProps { connectionNodeId: string; - connectionHandleId: string | null; connectionHandleType: HandleType; - connectionPositionX: number; - connectionPositionY: number; connectionLineType: ConnectionLineType; isConnectable: boolean; connectionLineStyle?: CSSProperties; CustomConnectionLineComponent?: ConnectionLineComponent; } -const selector = (s: ReactFlowState) => ({ nodeInternals: s.nodeInternals, transform: s.transform }); - export default ({ connectionNodeId, - connectionHandleId, connectionHandleType, connectionLineStyle, - connectionPositionX, - connectionPositionY, connectionLineType = ConnectionLineType.Bezier, isConnectable, CustomConnectionLineComponent, }: ConnectionLineProps) => { - const nodeId = connectionNodeId; - const handleId = connectionHandleId; + const { fromNode, handleId, toX, toY } = useStore( + useCallback( + (s) => ({ + fromNode: s.nodeInternals.get(connectionNodeId), + handleId: s.connectionHandleId, + toX: (s.connectionPosition.x - s.transform[0]) / s.transform[2], + toY: (s.connectionPosition.y - s.transform[1]) / s.transform[2], + }), + [connectionNodeId] + ), + shallow + ); + const fromHandleBounds = fromNode?.[internalsSymbol]?.handleBounds; - const { nodeInternals, transform } = useStore(selector, shallow); - const fromNode = useRef(nodeInternals.get(nodeId)); - const fromHandleBounds = fromNode.current?.[internalsSymbol]?.handleBounds; - - if (!fromNode.current || !isConnectable || !fromHandleBounds?.[connectionHandleType]) { + if (!fromNode || !isConnectable || !fromHandleBounds?.[connectionHandleType]) { return null; } const handleBound = fromHandleBounds[connectionHandleType]; const fromHandle = handleId ? handleBound?.find((d) => d.id === handleId) : handleBound?.[0]; - const fromHandleX = fromHandle ? fromHandle.x + fromHandle.width / 2 : (fromNode.current?.width ?? 0) / 2; - const fromHandleY = fromHandle ? fromHandle.y + fromHandle.height / 2 : fromNode.current?.height ?? 0; - const fromX = (fromNode.current.positionAbsolute?.x || 0) + fromHandleX; - const fromY = (fromNode.current.positionAbsolute?.y || 0) + fromHandleY; - - const toX = (connectionPositionX - transform[0]) / transform[2]; - const toY = (connectionPositionY - transform[1]) / transform[2]; + const fromHandleX = fromHandle ? fromHandle.x + fromHandle.width / 2 : (fromNode?.width ?? 0) / 2; + const fromHandleY = fromHandle ? fromHandle.y + fromHandle.height / 2 : fromNode?.height ?? 0; + const fromX = (fromNode?.positionAbsolute?.x || 0) + fromHandleX; + const fromY = (fromNode?.positionAbsolute?.y || 0) + fromHandleY; const fromPosition = fromHandle?.position; @@ -114,10 +110,10 @@ export default ({ targetPosition={targetPosition} connectionLineType={connectionLineType} connectionLineStyle={connectionLineStyle} - fromNode={fromNode.current} + fromNode={fromNode} fromHandle={fromHandle} // backward compatibility, mark as deprecated? - sourceNode={fromNode.current} + sourceNode={fromNode} sourceHandle={fromHandle} /> diff --git a/src/components/Edges/wrapEdge.tsx b/src/components/Edges/wrapEdge.tsx index 4062565d..0f2938bd 100644 --- a/src/components/Edges/wrapEdge.tsx +++ b/src/components/Edges/wrapEdge.tsx @@ -84,14 +84,7 @@ export default (EdgeComponent: ComponentType) => { ? (evt: MouseEvent): void => onEdgeUpdateEnd(evt, edge, handleType) : undefined; - const onConnectEdge = (connection: Connection) => { - const { edges } = store.getState(); - const edge = edges.find((e) => e.id === id); - - if (edge && onEdgeUpdate) { - onEdgeUpdate(edge, connection); - } - }; + const onConnectEdge = (connection: Connection) => onEdgeUpdate?.(edge, connection); handleMouseDown({ event, diff --git a/src/components/Handle/index.tsx b/src/components/Handle/index.tsx index 88bf294f..289d934f 100644 --- a/src/components/Handle/index.tsx +++ b/src/components/Handle/index.tsx @@ -16,7 +16,6 @@ export type HandleComponentProps = HandleProps & Omit ({ connectionStartHandle: s.connectionStartHandle, connectOnClick: s.connectOnClick, - hasDefaultEdges: s.hasDefaultEdges, }); const Handle = forwardRef( @@ -37,13 +36,13 @@ const Handle = forwardRef( ) => { const store = useStoreApi(); const nodeId = useContext(NodeIdContext) as string; - const { connectionStartHandle, connectOnClick, hasDefaultEdges } = useStore(selector, shallow); + const { connectionStartHandle, connectOnClick } = useStore(selector, shallow); const handleId = id || null; const isTarget = type === 'target'; const onConnectExtended = (params: Connection) => { - const { defaultEdgeOptions, onConnect: onConnectAction } = store.getState(); + const { defaultEdgeOptions, onConnect: onConnectAction, hasDefaultEdges } = store.getState(); const edgeParams = { ...defaultEdgeOptions, @@ -104,28 +103,26 @@ const Handle = forwardRef( store.setState({ connectionStartHandle: null }); }; - const handleClasses = cc([ - 'react-flow__handle', - `react-flow__handle-${position}`, - 'nodrag', - className, - { - source: !isTarget, - target: isTarget, - connectable: isConnectable, - connecting: - connectionStartHandle?.nodeId === nodeId && - connectionStartHandle?.handleId === handleId && - connectionStartHandle?.type === type, - }, - ]); - return (
s.updateNodeDimensions; - export default (NodeComponent: ComponentType) => { const NodeWrapper = ({ id, @@ -23,9 +21,6 @@ export default (NodeComponent: ComponentType) => { onMouseLeave, onContextMenu, onDoubleClick, - onDragStart, - onDrag, - onDragStop, style, className, isDraggable, @@ -44,7 +39,6 @@ export default (NodeComponent: ComponentType) => { initialized, }: WrapNodeProps) => { const store = useStoreApi(); - const updateNodeDimensions = useStore(selector); const nodeRef = useRef(null); const prevSourcePosition = useRef(sourcePosition); const prevTargetPosition = useRef(targetPosition); @@ -96,14 +90,11 @@ export default (NodeComponent: ComponentType) => { if (targetPosChanged) { prevTargetPosition.current = targetPosition; } - updateNodeDimensions([{ id, nodeElement: nodeRef.current, forceUpdate: true }]); + store.getState().updateNodeDimensions([{ id, nodeElement: nodeRef.current, forceUpdate: true }]); } }, [id, type, sourcePosition, targetPosition]); const dragging = useDrag({ - onStart: onDragStart, - onDrag: onDrag, - onStop: onDragStop, nodeRef, disabled: hidden || !isDraggable, noDragClassName, diff --git a/src/components/NodesSelection/index.tsx b/src/components/NodesSelection/index.tsx index b3da5045..468fea87 100644 --- a/src/components/NodesSelection/index.tsx +++ b/src/components/NodesSelection/index.tsx @@ -3,7 +3,7 @@ * made a selection with on or several nodes */ -import React, { memo, useCallback, useRef, MouseEvent } from 'react'; +import React, { memo, useRef, MouseEvent } from 'react'; import cc from 'classcat'; import shallow from 'zustand/shallow'; @@ -13,48 +13,22 @@ import { getRectOfNodes } from '../../utils/graph'; import useDrag from '../../hooks/useDrag'; export interface NodesSelectionProps { - onSelectionDragStart?: (event: MouseEvent, nodes: Node[]) => void; - onSelectionDrag?: (event: MouseEvent, nodes: Node[]) => void; - onSelectionDragStop?: (event: MouseEvent, nodes: Node[]) => void; onSelectionContextMenu?: (event: MouseEvent, nodes: Node[]) => void; noPanClassName?: string; } const selector = (s: ReactFlowState) => ({ - transform: s.transform, + transformString: `translate(${s.transform[0]}px,${s.transform[1]}px) scale(${s.transform[2]})`, userSelectionActive: s.userSelectionActive, + ...getRectOfNodes(Array.from(s.nodeInternals.values()).filter((n) => n.selected)), }); -const bboxSelector = (s: ReactFlowState) => { - const selectedNodes = Array.from(s.nodeInternals.values()).filter((n) => n.selected); - return getRectOfNodes(selectedNodes); -}; - -function useGetMemoizedHandler(handler?: (event: MouseEvent, nodes: Node[]) => void) { - return useCallback((event: MouseEvent, _: Node, nodes: Node[]) => handler?.(event, nodes), [handler]); -} - -function NodesSelection({ - onSelectionDragStart, - onSelectionDrag, - onSelectionDragStop, - onSelectionContextMenu, - noPanClassName, -}: NodesSelectionProps) { +function NodesSelection({ onSelectionContextMenu, noPanClassName }: NodesSelectionProps) { const store = useStoreApi(); - const { transform, userSelectionActive } = useStore(selector, shallow); - const { width, height, x: left, y: top } = useStore(bboxSelector, shallow); + const { transformString, userSelectionActive, width, height, x: top, y: left } = useStore(selector, shallow); const nodeRef = useRef(null); - // it's important that these handlers are memoized to avoid multiple creation of d3 drag handler - const onStart = useGetMemoizedHandler(onSelectionDragStart); - const onDrag = useGetMemoizedHandler(onSelectionDrag); - const onStop = useGetMemoizedHandler(onSelectionDragStop); - useDrag({ - onStart, - onDrag, - onStop, nodeRef, }); @@ -73,7 +47,7 @@ function NodesSelection({
; const selector = (s: ReactFlowState) => ({ setNodes: s.setNodes, @@ -112,6 +102,12 @@ const StoreUpdater = ({ fitViewOptions, onNodesDelete, onEdgesDelete, + onNodeDrag, + onNodeDragStart, + onNodeDragStop, + onSelectionDrag, + onSelectionDragStart, + onSelectionDragStop, }: StoreUpdaterProps) => { const { setNodes, @@ -154,6 +150,12 @@ const StoreUpdater = ({ useDirectStoreUpdater('fitViewOnInitOptions', fitViewOptions, store.setState); useDirectStoreUpdater('onNodesDelete', onNodesDelete, store.setState); useDirectStoreUpdater('onEdgesDelete', onEdgesDelete, store.setState); + useDirectStoreUpdater('onNodeDrag', onNodeDrag, store.setState); + useDirectStoreUpdater('onNodeDragStart', onNodeDragStart, store.setState); + useDirectStoreUpdater('onNodeDragStop', onNodeDragStop, store.setState); + useDirectStoreUpdater('onSelectionDrag', onSelectionDrag, store.setState); + useDirectStoreUpdater('onSelectionDragStart', onSelectionDragStart, store.setState); + useDirectStoreUpdater('onSelectionDragStop', onSelectionDragStop, store.setState); useStoreUpdater(nodes, setNodes); useStoreUpdater(edges, setEdges); diff --git a/src/container/EdgeRenderer/index.tsx b/src/container/EdgeRenderer/index.tsx index 98f90b1d..b5f47151 100644 --- a/src/container/EdgeRenderer/index.tsx +++ b/src/container/EdgeRenderer/index.tsx @@ -45,9 +45,7 @@ interface EdgeRendererProps { const selector = (s: ReactFlowState) => ({ connectionNodeId: s.connectionNodeId, - connectionHandleId: s.connectionHandleId, connectionHandleType: s.connectionHandleType, - connectionPosition: s.connectionPosition, nodesConnectable: s.nodesConnectable, elementsSelectable: s.elementsSelectable, width: s.width, @@ -59,9 +57,7 @@ const selector = (s: ReactFlowState) => ({ const EdgeRenderer = (props: EdgeRendererProps) => { const { connectionNodeId, - connectionHandleId, connectionHandleType, - connectionPosition, nodesConnectable, elementsSelectable, width, @@ -201,10 +197,7 @@ const EdgeRenderer = (props: EdgeRendererProps) => { > ({ - resetSelectedElements: s.resetSelectedElements, - nodesSelectionActive: s.nodesSelectionActive, -}); +const selector = (s: ReactFlowState) => s.nodesSelectionActive; const FlowRenderer = ({ children, @@ -55,27 +51,24 @@ const FlowRenderer = ({ defaultPosition, defaultZoom, preventScrolling, - onSelectionDragStart, - onSelectionDrag, - onSelectionDragStop, onSelectionContextMenu, noWheelClassName, noPanClassName, }: FlowRendererProps) => { const store = useStoreApi(); - const { resetSelectedElements, nodesSelectionActive } = useStore(selector, shallow); + const nodesSelectionActive = useStore(selector); const selectionKeyPressed = useKeyPress(selectionKeyCode); useGlobalKeyHandler({ deleteKeyCode, multiSelectionKeyCode }); const onClick = (event: MouseEvent) => { onPaneClick?.(event); - resetSelectedElements(); - + store.getState().resetSelectedElements(); store.setState({ nodesSelectionActive: false }); }; - const onContextMenu = (event: MouseEvent) => onPaneContextMenu?.(event); - const onWheel = (event: WheelEvent) => onPaneScroll?.(event); + + const onContextMenu = onPaneContextMenu ? (event: MouseEvent) => onPaneContextMenu(event) : undefined; + const onWheel = onPaneScroll ? (event: WheelEvent) => onPaneScroll(event) : undefined; return ( {nodesSelectionActive && ( - + )}
{ onMouseLeave={props.onNodeMouseLeave} onContextMenu={props.onNodeContextMenu} onDoubleClick={props.onNodeDoubleClick} - onDragStart={props.onNodeDragStart} - onDrag={props.onNodeDrag} - onDragStop={props.onNodeDragStop} selected={!!node.selected} isDraggable={isDraggable} isSelectable={isSelectable} diff --git a/src/container/ReactFlow/index.tsx b/src/container/ReactFlow/index.tsx index 3e815045..e5fc446b 100644 --- a/src/container/ReactFlow/index.tsx +++ b/src/container/ReactFlow/index.tsx @@ -165,9 +165,6 @@ const ReactFlow = forwardRef( onNodeMouseLeave={onNodeMouseLeave} onNodeContextMenu={onNodeContextMenu} onNodeDoubleClick={onNodeDoubleClick} - onNodeDragStart={onNodeDragStart} - onNodeDrag={onNodeDrag} - onNodeDragStop={onNodeDragStop} nodeTypes={nodeTypesWrapped} edgeTypes={edgeTypesWrapped} connectionLineType={connectionLineType} @@ -193,9 +190,6 @@ const ReactFlow = forwardRef( onPaneClick={onPaneClick} onPaneScroll={onPaneScroll} onPaneContextMenu={onPaneContextMenu} - onSelectionDragStart={onSelectionDragStart} - onSelectionDrag={onSelectionDrag} - onSelectionDragStop={onSelectionDragStop} onSelectionContextMenu={onSelectionContextMenu} onEdgeUpdate={onEdgeUpdate} onEdgeContextMenu={onEdgeContextMenu} @@ -243,6 +237,12 @@ const ReactFlow = forwardRef( fitViewOptions={fitViewOptions} onNodesDelete={onNodesDelete} onEdgesDelete={onEdgesDelete} + onNodeDragStart={onNodeDragStart} + onNodeDrag={onNodeDrag} + onNodeDragStop={onNodeDragStop} + onSelectionDrag={onSelectionDrag} + onSelectionDragStart={onSelectionDragStart} + onSelectionDragStop={onSelectionDragStop} /> {onSelectionChange && } {children} diff --git a/src/container/Viewport/index.tsx b/src/container/Viewport/index.tsx index 590b7516..ec6877bd 100644 --- a/src/container/Viewport/index.tsx +++ b/src/container/Viewport/index.tsx @@ -3,7 +3,7 @@ import React, { ReactNode } from 'react'; import { useStore } from '../../store'; import { ReactFlowState } from '../../types'; -const selector = (s: ReactFlowState) => s.transform; +const selector = (s: ReactFlowState) => `translate(${s.transform[0]}px,${s.transform[1]}px) scale(${s.transform[2]})`; type ViewportProps = { children: ReactNode; @@ -13,10 +13,7 @@ function Viewport({ children }: ViewportProps) { const transform = useStore(selector); return ( -
+
{children}
); diff --git a/src/hooks/useDrag/index.ts b/src/hooks/useDrag/index.ts index b14ad14d..da626085 100644 --- a/src/hooks/useDrag/index.ts +++ b/src/hooks/useDrag/index.ts @@ -4,7 +4,7 @@ import { select } from 'd3-selection'; import { useStoreApi } from '../../store'; import { pointToRendererPoint } from '../../utils/graph'; -import { NodeDragItem, NodeDragHandler } from '../../types'; +import { NodeDragItem, Node, SelectionDragHandler } from '../../types'; import { getDragItems, getEventHandlerParams, hasSelector, updatePosition } from './utils'; import { handleNodeClick } from '../../components/Nodes/utils'; @@ -13,9 +13,6 @@ export type UseDragData = { dx: number; dy: number }; type UseDragParams = { nodeRef: RefObject; - onStart?: NodeDragHandler; - onDrag?: NodeDragHandler; - onStop?: NodeDragHandler; disabled?: boolean; noDragClassName?: string; handleSelector?: string; @@ -24,10 +21,11 @@ type UseDragParams = { selectNodesOnDrag?: boolean; }; +function wrapSelectionDragFunc(selectionFunc?: SelectionDragHandler) { + return (event: MouseEvent, _: Node, nodes: Node[]) => selectionFunc?.(event, nodes); +} + function useDrag({ - onStart, - onDrag, - onStop, nodeRef, disabled = false, noDragClassName, @@ -60,7 +58,15 @@ function useDrag({ } else { const dragHandler = drag() .on('start', (event: UseDragEvent) => { - const { nodeInternals, multiSelectionActive, unselectNodesAndEdges } = store.getState(); + const { + nodeInternals, + multiSelectionActive, + unselectNodesAndEdges, + onNodeDragStart, + onSelectionDragStart, + } = store.getState(); + + const onStart = nodeId ? onNodeDragStart : wrapSelectionDragFunc(onSelectionDragStart); if (!selectNodesOnDrag && !multiSelectionActive && nodeId) { if (!nodeInternals.get(nodeId)?.selected) { @@ -90,7 +96,7 @@ function useDrag({ } }) .on('drag', (event: UseDragEvent) => { - const { updateNodePositions, nodeInternals, nodeExtent } = store.getState(); + const { updateNodePositions, nodeInternals, nodeExtent, onNodeDrag, onSelectionDrag } = store.getState(); const pointerPos = getPointerPosition(event); // skip events without movement @@ -100,6 +106,8 @@ function useDrag({ updatePosition(n, pointerPos, nodeInternals, nodeExtent) ); + const onDrag = nodeId ? onNodeDrag : wrapSelectionDragFunc(onSelectionDrag); + updateNodePositions(dragItems.current, true, true); setDragging(true); @@ -116,6 +124,9 @@ function useDrag({ event.on('end', (event) => { setDragging(false); if (dragItems.current) { + const { updateNodePositions, nodeInternals, onNodeDragStop, onSelectionDragStop } = store.getState(); + const onStop = nodeId ? onNodeDragStop : wrapSelectionDragFunc(onSelectionDragStop); + updateNodePositions(dragItems.current, false, false); if (onStop) { @@ -147,9 +158,6 @@ function useDrag({ } } }, [ - onStart, - onDrag, - onStop, nodeRef, disabled, noDragClassName, diff --git a/src/hooks/useVisibleNodes.ts b/src/hooks/useVisibleNodes.ts index ebda8953..8c8b7190 100644 --- a/src/hooks/useVisibleNodes.ts +++ b/src/hooks/useVisibleNodes.ts @@ -8,11 +8,10 @@ import { ReactFlowState } from '../types'; function useVisibleNodes(onlyRenderVisible: boolean) { const nodes = useStore( useCallback( - (s: ReactFlowState) => { - return onlyRenderVisible + (s: ReactFlowState) => + onlyRenderVisible ? getNodesInside(s.nodeInternals, { x: 0, y: 0, width: s.width, height: s.height }, s.transform, true) - : Array.from(s.nodeInternals.values()); - }, + : Array.from(s.nodeInternals.values()), [onlyRenderVisible] ) ); diff --git a/src/types/component-props.ts b/src/types/component-props.ts index 200495eb..75261021 100644 --- a/src/types/component-props.ts +++ b/src/types/component-props.ts @@ -38,6 +38,7 @@ import { OnMoveEnd, NodeDragHandler, NodeMouseHandler, + SelectionDragHandler, } from '.'; import { HandleType } from './handles'; @@ -73,9 +74,9 @@ export interface ReactFlowProps extends HTMLAttributes { onMoveStart?: OnMoveStart; onMoveEnd?: OnMoveEnd; onSelectionChange?: OnSelectionChangeFunc; - onSelectionDragStart?: (event: ReactMouseEvent, nodes: Node[]) => void; - onSelectionDrag?: (event: ReactMouseEvent, nodes: Node[]) => void; - onSelectionDragStop?: (event: ReactMouseEvent, nodes: Node[]) => void; + onSelectionDragStart?: SelectionDragHandler; + onSelectionDrag?: SelectionDragHandler; + onSelectionDragStop?: SelectionDragHandler; onSelectionContextMenu?: (event: ReactMouseEvent, nodes: Node[]) => void; onPaneScroll?: (event?: WheelEvent) => void; onPaneClick?: (event: ReactMouseEvent) => void; diff --git a/src/types/general.ts b/src/types/general.ts index 2e870eed..a1708cb9 100644 --- a/src/types/general.ts +++ b/src/types/general.ts @@ -3,7 +3,16 @@ import { Selection as D3Selection, ZoomBehavior } from 'd3'; import { XYPosition, Rect, Transform, CoordinateExtent } from './utils'; import { NodeChange, EdgeChange } from './changes'; -import { Node, NodeInternals, NodeDimensionUpdate, NodeProps, WrapNodeProps, NodeDragItem } from './nodes'; +import { + Node, + NodeInternals, + NodeDimensionUpdate, + NodeProps, + WrapNodeProps, + NodeDragItem, + NodeDragHandler, + SelectionDragHandler, +} from './nodes'; import { Edge, EdgeProps, WrapEdgeProps } from './edges'; import { HandleType, StartHandle } from './handles'; import { DefaultEdgeOptions } from '.'; @@ -165,6 +174,14 @@ export type ReactFlowStore = { connectionStartHandle: StartHandle | null; + onNodeDragStart?: NodeDragHandler; + onNodeDrag?: NodeDragHandler; + onNodeDragStop?: NodeDragHandler; + + onSelectionDragStart?: SelectionDragHandler; + onSelectionDrag?: SelectionDragHandler; + onSelectionDragStop?: SelectionDragHandler; + onConnect?: OnConnect; onConnectStart?: OnConnectStart; onConnectStop?: OnConnectStop; diff --git a/src/types/nodes.ts b/src/types/nodes.ts index 31712102..36c612e2 100644 --- a/src/types/nodes.ts +++ b/src/types/nodes.ts @@ -55,6 +55,7 @@ export interface NodeProps { export type NodeMouseHandler = (event: ReactMouseEvent, node: Node) => void; export type NodeDragHandler = (event: ReactMouseEvent, node: Node, nodes: Node[]) => void; +export type SelectionDragHandler = (event: ReactMouseEvent, nodes: Node[]) => void; export interface WrapNodeProps { id: string; @@ -74,9 +75,6 @@ export interface WrapNodeProps { onMouseMove?: NodeMouseHandler; onMouseLeave?: NodeMouseHandler; onContextMenu?: NodeMouseHandler; - onDragStart?: NodeDragHandler; - onDrag?: NodeDragHandler; - onDragStop?: NodeDragHandler; style?: CSSProperties; className?: string; sourcePosition: Position;