From 895e0bc5247e0425d0cf53f80f822fb453c11f07 Mon Sep 17 00:00:00 2001 From: moklick Date: Sat, 11 Dec 2021 05:22:41 +0100 Subject: [PATCH] refactor(store): use store.setState directly instead of actions --- src/additional-components/Controls/index.tsx | 14 ++-- src/components/Edges/wrapEdge.tsx | 26 +------ src/components/Handle/handler.ts | 37 +++++---- src/components/Handle/index.tsx | 25 ++---- src/components/Nodes/wrapNode.tsx | 15 ++-- src/components/StoreUpdater/index.tsx | 80 ++++++++------------ src/components/UserSelection/index.tsx | 19 ++--- src/container/FlowRenderer/index.tsx | 9 ++- src/container/ZoomPane/index.tsx | 11 +-- src/hooks/useGlobalKeyHandler.ts | 10 +-- src/hooks/useResizeHandler.ts | 9 +-- src/hooks/useUpdateNodeInternals.ts | 4 +- src/store/index.ts | 48 ------------ src/types/general.ts | 48 ++---------- 14 files changed, 110 insertions(+), 245 deletions(-) diff --git a/src/additional-components/Controls/index.tsx b/src/additional-components/Controls/index.tsx index 0c9444aa..e12a88fb 100644 --- a/src/additional-components/Controls/index.tsx +++ b/src/additional-components/Controls/index.tsx @@ -1,7 +1,7 @@ import React, { memo, useCallback, HTMLAttributes, FC, useEffect, useState } from 'react'; import cc from 'classcat'; -import { useStore } from '../../store'; +import { useStore, useStoreApi } from '../../store'; import PlusIcon from '../../../assets/icons/plus.svg'; import MinusIcon from '../../../assets/icons/minus.svg'; @@ -31,7 +31,6 @@ export const ControlButton: FC = ({ children, className, ... ); -const setInteractiveSelector = (s: ReactFlowState) => s.setInteractive; const isInteractiveSelector = (s: ReactFlowState) => s.nodesDraggable && s.nodesConnectable && s.elementsSelectable; const Controls: FC = ({ @@ -47,8 +46,8 @@ const Controls: FC = ({ className, children, }) => { + const store = useStoreApi(); const [isVisible, setIsVisible] = useState(false); - const setInteractive = useStore(setInteractiveSelector); const isInteractive = useStore(isInteractiveSelector); const { zoomIn, zoomOut, fitView } = useZoomPanHelper(); @@ -70,9 +69,14 @@ const Controls: FC = ({ }, [fitView, fitViewParams, onFitView]); const onInteractiveChangeHandler = useCallback(() => { - setInteractive?.(!isInteractive); + store.setState({ + nodesDraggable: !isInteractive, + nodesConnectable: !isInteractive, + elementsSelectable: !isInteractive, + }); + onInteractiveChange?.(!isInteractive); - }, [isInteractive, setInteractive, onInteractiveChange]); + }, [isInteractive, onInteractiveChange]); useEffect(() => { setIsVisible(true); diff --git a/src/components/Edges/wrapEdge.tsx b/src/components/Edges/wrapEdge.tsx index 1697ef64..e8b0f3a0 100644 --- a/src/components/Edges/wrapEdge.tsx +++ b/src/components/Edges/wrapEdge.tsx @@ -10,9 +10,6 @@ import { getMarkerId } from '../../utils/graph'; const selector = (s: ReactFlowState) => ({ addSelectedEdges: s.addSelectedEdges, - setConnectionNodeId: s.setConnectionNodeId, - setNodesSelectionActive: s.setNodesSelectionActive, - setPosition: s.setConnectionPosition, connectionMode: s.connectionMode, }); @@ -57,10 +54,7 @@ export default (EdgeComponent: ComponentType) => { markerStart, }: WrapEdgeProps): JSX.Element | null => { const store = useStoreApi(); - const { addSelectedEdges, setConnectionNodeId, setNodesSelectionActive, setPosition, connectionMode } = useStore( - selector, - shallow - ); + const { addSelectedEdges, connectionMode } = useStore(selector, shallow); const [updating, setUpdating] = useState(false); @@ -99,7 +93,7 @@ export default (EdgeComponent: ComponentType) => { const onEdgeClick = useCallback( (event: React.MouseEvent): void => { if (elementsSelectable) { - setNodesSelectionActive(false); + store.setState({ nodesSelectionActive: false }); addSelectedEdges([edgeElement.id]); } @@ -169,8 +163,7 @@ export default (EdgeComponent: ComponentType) => { event, handleId, nodeId, - setConnectionNodeId, - setPosition, + store.setState, onConnectEdge, isTarget, isValidConnection, @@ -180,18 +173,7 @@ export default (EdgeComponent: ComponentType) => { store.getState ); }, - [ - id, - source, - target, - type, - sourceHandleId, - targetHandleId, - setConnectionNodeId, - setPosition, - edgeElement, - onEdgeUpdate, - ] + [id, source, target, type, sourceHandleId, targetHandleId, edgeElement, onEdgeUpdate] ); const onEdgeUpdaterSourceMouseDown = useCallback( diff --git a/src/components/Handle/handler.ts b/src/components/Handle/handler.ts index b1097453..8e7e31ae 100644 --- a/src/components/Handle/handler.ts +++ b/src/components/Handle/handler.ts @@ -1,23 +1,19 @@ import { MouseEvent as ReactMouseEvent } from 'react'; +import { SetState } from 'zustand'; import { getHostForElement } from '../../utils'; - import { OnConnect, OnConnectStart, OnConnectStop, OnConnectEnd, ConnectionMode, - SetConnectionId, Connection, HandleType, - XYPosition, + ReactFlowState, } from '../../types'; type ValidConnectionFunc = (connection: Connection) => boolean; -export type SetSourceIdFunc = (params: SetConnectionId) => void; - -export type SetPosition = (pos: XYPosition) => void; type Result = { elementBelow: Element | null; @@ -90,8 +86,7 @@ export function onMouseDown( event: ReactMouseEvent, handleId: string | null, nodeId: string, - setConnectionNodeId: SetSourceIdFunc, - setPosition: SetPosition, + setState: SetState, onConnect: OnConnect, isTarget: boolean, isValidConnection: ValidConnectionFunc, @@ -122,18 +117,24 @@ export function onMouseDown( const containerBounds = reactFlowNode.getBoundingClientRect(); let recentHoveredHandle: Element; - setPosition({ - x: event.clientX - containerBounds.left, - y: event.clientY - containerBounds.top, + setState({ + connectionPosition: { + x: event.clientX - containerBounds.left, + y: event.clientY - containerBounds.top, + }, + connectionNodeId: nodeId, + connectionHandleId: handleId, + connectionHandleType: handleType, }); - setConnectionNodeId({ connectionNodeId: nodeId, connectionHandleId: handleId, connectionHandleType: handleType }); onConnectStart?.(event, { nodeId, handleId, handleType }); function onMouseMove(event: MouseEvent) { - setPosition({ - x: event.clientX - containerBounds.left, - y: event.clientY - containerBounds.top, + setState({ + connectionPosition: { + x: event.clientX - containerBounds.left, + y: event.clientY - containerBounds.top, + }, }); const { connection, elementBelow, isValid, isHoveringHandle } = checkElementBelowIsValid( @@ -183,7 +184,11 @@ export function onMouseDown( } resetRecentHandle(recentHoveredHandle); - setConnectionNodeId({ connectionNodeId: null, connectionHandleId: null, connectionHandleType: null }); + setState({ + connectionNodeId: null, + connectionHandleId: null, + connectionHandleType: null, + }); doc.removeEventListener('mousemove', onMouseMove as EventListenerOrEventListenerObject); doc.removeEventListener('mouseup', onMouseUp as EventListenerOrEventListenerObject); diff --git a/src/components/Handle/index.tsx b/src/components/Handle/index.tsx index bdf32606..4d1e14f3 100644 --- a/src/components/Handle/index.tsx +++ b/src/components/Handle/index.tsx @@ -2,18 +2,16 @@ import React, { memo, useContext, useCallback, HTMLAttributes, forwardRef } from import cc from 'classcat'; import shallow from 'zustand/shallow'; -import { useStore } from '../../store'; +import { useStore, useStoreApi } from '../../store'; import NodeIdContext from '../../contexts/NodeIdContext'; import { HandleProps, Connection, ReactFlowState, Position } from '../../types'; -import { onMouseDown, SetSourceIdFunc, SetPosition } from './handler'; +import { onMouseDown } from './handler'; const alwaysValid = () => true; export type HandleComponentProps = HandleProps & Omit, 'id'>; const selector = (s: ReactFlowState) => ({ - setPosition: s.setConnectionPosition, - setConnectionNodeId: s.setConnectionNodeId, onConnectAction: s.onConnect, onConnectStart: s.onConnectStart, onConnectStop: s.onConnectStop, @@ -36,16 +34,12 @@ const Handle = forwardRef( }, ref ) => { + const store = useStoreApi(); const nodeId = useContext(NodeIdContext) as string; - const { - setPosition, - setConnectionNodeId, - onConnectAction, - onConnectStart, - onConnectStop, - onConnectEnd, - connectionMode, - } = useStore(selector, shallow); + const { onConnectAction, onConnectStart, onConnectStop, onConnectEnd, connectionMode } = useStore( + selector, + shallow + ); const handleId = id || null; const isTarget = type === 'target'; @@ -64,8 +58,7 @@ const Handle = forwardRef( event, handleId, nodeId, - setConnectionNodeId as unknown as SetSourceIdFunc, - setPosition as unknown as SetPosition, + store.setState, onConnectExtended, isTarget, isValidConnection, @@ -80,8 +73,6 @@ const Handle = forwardRef( [ handleId, nodeId, - setConnectionNodeId, - setPosition, onConnectExtended, isTarget, isValidConnection, diff --git a/src/components/Nodes/wrapNode.tsx b/src/components/Nodes/wrapNode.tsx index be29a0c7..8a15f0c4 100644 --- a/src/components/Nodes/wrapNode.tsx +++ b/src/components/Nodes/wrapNode.tsx @@ -3,13 +3,12 @@ import { DraggableCore, DraggableData, DraggableEvent } from 'react-draggable'; import cc from 'classcat'; import shallow from 'zustand/shallow'; -import { useStore } from '../../store'; +import { useStore, useStoreApi } from '../../store'; import { Provider } from '../../contexts/NodeIdContext'; import { NodeProps, WrapNodeProps, ReactFlowState } from '../../types'; const selector = (s: ReactFlowState) => ({ addSelectedNodes: s.addSelectedNodes, - setNodesSelectionActive: s.setNodesSelectionActive, updateNodePosition: s.updateNodePosition, unselectNodesAndEdges: s.unselectNodesAndEdges, }); @@ -52,10 +51,8 @@ export default (NodeComponent: ComponentType) => { noPanClassName, noDragClassName, }: WrapNodeProps) => { - const { addSelectedNodes, unselectNodesAndEdges, setNodesSelectionActive, updateNodePosition } = useStore( - selector, - shallow - ); + const store = useStoreApi(); + const { addSelectedNodes, unselectNodesAndEdges, updateNodePosition } = useStore(selector, shallow); const nodeElement = useRef(null); const hasPointerEvents = isSelectable || isDraggable || onClick || onMouseEnter || onMouseMove || onMouseLeave; const nodeStyle: CSSProperties = useMemo( @@ -109,7 +106,7 @@ export default (NodeComponent: ComponentType) => { (event: MouseEvent) => { if (!isDraggable) { if (isSelectable) { - setNodesSelectionActive(false); + store.setState({ nodesSelectionActive: false }); if (!selected) { addSelectedNodes([node.id]); @@ -127,14 +124,14 @@ export default (NodeComponent: ComponentType) => { onNodeDragStart?.(event as MouseEvent, node); if (selectNodesOnDrag && isSelectable) { - setNodesSelectionActive(false); + store.setState({ nodesSelectionActive: false }); if (!selected) { addSelectedNodes([node.id]); } } else if (!selectNodesOnDrag && !selected && isSelectable) { unselectNodesAndEdges(); - setNodesSelectionActive(false); + store.setState({ nodesSelectionActive: false }); } }, [node, selected, selectNodesOnDrag, isSelectable, onNodeDragStart] diff --git a/src/components/StoreUpdater/index.tsx b/src/components/StoreUpdater/index.tsx index 4047b114..d2b5a37b 100644 --- a/src/components/StoreUpdater/index.tsx +++ b/src/components/StoreUpdater/index.tsx @@ -1,7 +1,8 @@ import { useEffect } from 'react'; +import { SetState } from 'zustand'; import shallow from 'zustand/shallow'; -import { useStore } from '../../store'; +import { useStore, useStoreApi } from '../../store'; import { Node, Edge, @@ -42,24 +43,11 @@ interface StoreUpdaterProps { const selector = (s: ReactFlowState) => ({ setNodes: s.setNodes, setEdges: s.setEdges, - setOnConnect: s.setOnConnect, - setOnConnectStart: s.setOnConnectStart, - setOnConnectStop: s.setOnConnectStop, - setOnConnectEnd: s.setOnConnectEnd, - setSnapGrid: s.setSnapGrid, - setSnapToGrid: s.setSnapToGrid, - setNodesDraggable: s.setNodesDraggable, - setNodesConnectable: s.setNodesConnectable, - setElementsSelectable: s.setElementsSelectable, setMinZoom: s.setMinZoom, setMaxZoom: s.setMaxZoom, setTranslateExtent: s.setTranslateExtent, setNodeExtent: s.setNodeExtent, - setConnectionMode: s.setConnectionMode, - setOnNodesChange: s.setOnNodesChange, - setOnEdgesChange: s.setOnEdgesChange, reset: s.reset, - setFitViewOnInit: s.setFitViewOnInit, }); function useStoreUpdater(value: T | undefined, setStoreState: (param: T) => void) { @@ -70,6 +58,15 @@ function useStoreUpdater(value: T | undefined, setStoreState: (param: T) => v }, [value]); } +function useDirectStoreUpdater(key: keyof ReactFlowState, value: any, setState: SetState) { + useEffect(() => { + if (typeof value !== 'undefined') { + // @ts-ignore + setState({ [key]: value }); + } + }, [value]); +} + const StoreUpdater = ({ nodes, edges, @@ -91,28 +88,11 @@ const StoreUpdater = ({ translateExtent, fitViewOnInit, }: StoreUpdaterProps) => { - const { - setNodes, - setEdges, - setOnConnect, - setOnConnectStart, - setOnConnectStop, - setOnConnectEnd, - setNodesDraggable, - setSnapGrid, - setSnapToGrid, - setNodesConnectable, - setElementsSelectable, - setMinZoom, - setMaxZoom, - setTranslateExtent, - setNodeExtent, - setOnNodesChange, - setOnEdgesChange, - setConnectionMode, - reset, - setFitViewOnInit, - } = useStore(selector, shallow); + const { setNodes, setEdges, setMinZoom, setMaxZoom, setTranslateExtent, setNodeExtent, reset } = useStore( + selector, + shallow + ); + const store = useStoreApi(); useEffect(() => { return () => { @@ -122,24 +102,24 @@ const StoreUpdater = ({ useStoreUpdater(nodes, setNodes); useStoreUpdater(edges, setEdges); - useStoreUpdater(onConnect, setOnConnect); - useStoreUpdater(onConnect, setOnConnect); - useStoreUpdater(onConnectStart, setOnConnectStart); - useStoreUpdater(onConnectStop, setOnConnectStop); - useStoreUpdater(onConnectEnd, setOnConnectEnd); - useStoreUpdater(snapToGrid, setSnapToGrid); - useStoreUpdater(snapGrid, setSnapGrid); - useStoreUpdater(nodesDraggable, setNodesDraggable); - useStoreUpdater(nodesConnectable, setNodesConnectable); - useStoreUpdater(elementsSelectable, setElementsSelectable); useStoreUpdater(minZoom, setMinZoom); useStoreUpdater(maxZoom, setMaxZoom); useStoreUpdater(translateExtent, setTranslateExtent); useStoreUpdater(nodeExtent, setNodeExtent); - useStoreUpdater(connectionMode, setConnectionMode); - useStoreUpdater(onNodesChange, setOnNodesChange); - useStoreUpdater(onEdgesChange, setOnEdgesChange); - useStoreUpdater(fitViewOnInit, setFitViewOnInit); + + useDirectStoreUpdater('connectionMode', connectionMode, store.setState); + useDirectStoreUpdater('onConnect', onConnect, store.setState); + useDirectStoreUpdater('onConnectStart', onConnectStart, store.setState); + useDirectStoreUpdater('onConnectStop', onConnectStop, store.setState); + useDirectStoreUpdater('onConnectEnd', onConnectEnd, store.setState); + useDirectStoreUpdater('nodesDraggable', nodesDraggable, store.setState); + useDirectStoreUpdater('nodesConnectable', nodesConnectable, store.setState); + useDirectStoreUpdater('elementsSelectable', elementsSelectable, store.setState); + useDirectStoreUpdater('fitViewOnInit', fitViewOnInit, store.setState); + useDirectStoreUpdater('snapToGrid', snapToGrid, store.setState); + useDirectStoreUpdater('snapGrid', snapGrid, store.setState); + useDirectStoreUpdater('onNodesChange', onNodesChange, store.setState); + useDirectStoreUpdater('onEdgesChange', onEdgesChange, store.setState); return null; }; diff --git a/src/components/UserSelection/index.tsx b/src/components/UserSelection/index.tsx index b8692387..ea9c6b27 100644 --- a/src/components/UserSelection/index.tsx +++ b/src/components/UserSelection/index.tsx @@ -30,8 +30,6 @@ function getMousePosition(event: React.MouseEvent, containerBounds: DOMRect): XY const selector = (s: ReactFlowState) => ({ userSelectionActive: s.userSelectionActive, elementsSelectable: s.elementsSelectable, - setUserSelectionActive: s.setUserSelectionActive, - setNodesSelectionActive: s.setNodesSelectionActive, }); const initialRect: SelectionRect = { @@ -50,16 +48,14 @@ export default memo(({ selectionKeyPressed }: UserSelectionProps) => { const prevSelectedEdgesCount = useRef(0); const containerBounds = useRef(); const [userSelectionRect, setUserSelectionRect] = useState(initialRect); - const { userSelectionActive, elementsSelectable, setUserSelectionActive, setNodesSelectionActive } = useStore( - selector, - shallow - ); + const { userSelectionActive, elementsSelectable } = useStore(selector, shallow); const renderUserSelectionPane = userSelectionActive || selectionKeyPressed; const resetUserSelection = useCallback(() => { setUserSelectionRect(initialRect); - setUserSelectionActive(false); + + store.setState({ userSelectionActive: false }); prevSelectedNodesCount.current = 0; prevSelectedEdgesCount.current = 0; @@ -81,8 +77,7 @@ export default memo(({ selectionKeyPressed }: UserSelectionProps) => { draw: true, }); - setUserSelectionActive(true); - setNodesSelectionActive(false); + store.setState({ userSelectionActive: true, nodesSelectionActive: false }); }, []); const onMouseMove = (event: React.MouseEvent): void => { @@ -128,12 +123,14 @@ export default memo(({ selectionKeyPressed }: UserSelectionProps) => { }; const onMouseUp = useCallback(() => { - setNodesSelectionActive(prevSelectedNodesCount.current > 0); + store.setState({ nodesSelectionActive: prevSelectedNodesCount.current > 0 }); + resetUserSelection(); }, []); const onMouseLeave = useCallback(() => { - setNodesSelectionActive(false); + store.setState({ nodesSelectionActive: false }); + resetUserSelection(); }, []); diff --git a/src/container/FlowRenderer/index.tsx b/src/container/FlowRenderer/index.tsx index 4231d71a..35b4674f 100644 --- a/src/container/FlowRenderer/index.tsx +++ b/src/container/FlowRenderer/index.tsx @@ -1,7 +1,7 @@ import React, { useCallback, memo, ReactNode, WheelEvent, MouseEvent } from 'react'; import shallow from 'zustand/shallow'; -import { useStore } from '../../store'; +import { useStore, useStoreApi } from '../../store'; import useGlobalKeyHandler from '../../hooks/useGlobalKeyHandler'; import useKeyPress from '../../hooks/useKeyPress'; import { GraphViewProps } from '../GraphView'; @@ -27,7 +27,6 @@ interface FlowRendererProps } const selector = (s: ReactFlowState) => ({ - setNodesSelectionActive: s.setNodesSelectionActive, resetSelectedElements: s.resetSelectedElements, nodesSelectionActive: s.nodesSelectionActive, }); @@ -62,7 +61,8 @@ const FlowRenderer = ({ noWheelClassName, noPanClassName, }: FlowRendererProps) => { - const { setNodesSelectionActive, resetSelectedElements, nodesSelectionActive } = useStore(selector, shallow); + const store = useStoreApi(); + const { resetSelectedElements, nodesSelectionActive } = useStore(selector, shallow); const selectionKeyPressed = useKeyPress(selectionKeyCode); useGlobalKeyHandler({ deleteKeyCode, multiSelectionKeyCode }); @@ -70,8 +70,9 @@ const FlowRenderer = ({ const onClick = useCallback( (event: MouseEvent) => { onPaneClick?.(event); - setNodesSelectionActive(false); resetSelectedElements(); + + store.setState({ nodesSelectionActive: false }); }, [onPaneClick] ); diff --git a/src/container/ZoomPane/index.tsx b/src/container/ZoomPane/index.tsx index 3a149f5d..d3598c44 100644 --- a/src/container/ZoomPane/index.tsx +++ b/src/container/ZoomPane/index.tsx @@ -48,9 +48,6 @@ const selector = (s: ReactFlowState) => ({ d3Zoom: s.d3Zoom, d3Selection: s.d3Selection, d3ZoomHandler: s.d3ZoomHandler, - - initD3Zoom: s.initD3Zoom, - updateTransform: s.updateTransform, }); const ZoomPane = ({ @@ -77,7 +74,7 @@ const ZoomPane = ({ const store = useStoreApi(); const zoomPane = useRef(null); const prevTransform = useRef({ x: 0, y: 0, zoom: 0 }); - const { d3Zoom, d3Selection, d3ZoomHandler, initD3Zoom, updateTransform } = useStore(selector, shallow); + const { d3Zoom, d3Selection, d3ZoomHandler } = useStore(selector, shallow); const zoomActivationKeyPressed = useKeyPress(zoomActivationKeyCode); useResizeHandler(zoomPane); @@ -95,7 +92,7 @@ const ZoomPane = ({ d3ZoomInstance.transform(selection, updatedTransform); - initD3Zoom({ + store.setState({ d3Zoom: d3ZoomInstance, d3Selection: selection, d3ZoomHandler: selection.on('wheel.zoom'), @@ -171,7 +168,7 @@ const ZoomPane = ({ d3Zoom.on('zoom', null); } else { d3Zoom.on('zoom', (event: any) => { - updateTransform([event.transform.x, event.transform.y, event.transform.k]); + store.setState({ transform: [event.transform.x, event.transform.y, event.transform.k] }); if (onMove) { const flowTransform = eventToFlowTransform(event.transform); @@ -180,7 +177,7 @@ const ZoomPane = ({ }); } } - }, [selectionKeyPressed, d3Zoom, updateTransform, onMove]); + }, [selectionKeyPressed, d3Zoom, onMove]); useEffect(() => { if (d3Zoom) { diff --git a/src/hooks/useGlobalKeyHandler.ts b/src/hooks/useGlobalKeyHandler.ts index 27f283e7..22e17d40 100644 --- a/src/hooks/useGlobalKeyHandler.ts +++ b/src/hooks/useGlobalKeyHandler.ts @@ -12,8 +12,6 @@ interface HookParams { } const selector = (s: ReactFlowState) => ({ - setNodesSelectionActive: s.setNodesSelectionActive, - setMultiSelectionActive: s.setMultiSelectionActive, resetSelectedElements: s.resetSelectedElements, onNodesChange: s.onNodesChange, onEdgesChange: s.onEdgesChange, @@ -21,8 +19,7 @@ const selector = (s: ReactFlowState) => ({ export default ({ deleteKeyCode, multiSelectionKeyCode }: HookParams): void => { const store = useStoreApi(); - const { setNodesSelectionActive, setMultiSelectionActive, resetSelectedElements, onNodesChange, onEdgesChange } = - useStore(selector, shallow); + const { resetSelectedElements, onNodesChange, onEdgesChange } = useStore(selector, shallow); const deleteKeyPressed = useKeyPress(deleteKeyCode); const multiSelectionKeyPressed = useKeyPress(multiSelectionKeyCode); @@ -46,12 +43,13 @@ export default ({ deleteKeyCode, multiSelectionKeyCode }: HookParams): void => { onNodesChange?.(nodeChanges); onEdgesChange?.(edgeChanges); - setNodesSelectionActive(false); + store.setState({ nodesSelectionActive: false }); + resetSelectedElements(); } }, [deleteKeyPressed, onNodesChange, onEdgesChange]); useEffect(() => { - setMultiSelectionActive(multiSelectionKeyPressed); + store.setState({ multiSelectionActive: multiSelectionKeyPressed }); }, [multiSelectionKeyPressed]); }; diff --git a/src/hooks/useResizeHandler.ts b/src/hooks/useResizeHandler.ts index 12450359..0c0573b4 100644 --- a/src/hooks/useResizeHandler.ts +++ b/src/hooks/useResizeHandler.ts @@ -1,13 +1,10 @@ import { useEffect, MutableRefObject } from 'react'; -import { useStore } from '../store'; +import { useStoreApi } from '../store'; import { getDimensions } from '../utils'; -import { ReactFlowState } from '../types'; - -const updateSizeSelector = (state: ReactFlowState) => state.updateSize; function useResizeHandler(rendererNode: MutableRefObject): void { - const updateSize = useStore(updateSizeSelector); + const store = useStoreApi(); useEffect(() => { let resizeObserver: ResizeObserver; @@ -23,7 +20,7 @@ function useResizeHandler(rendererNode: MutableRefObject) console.warn('The React Flow parent container needs a width and a height to render the graph.'); } - updateSize(size); + store.setState({ width: size.width || 500, height: size.height || 500 }); }; updateDimensions(); diff --git a/src/hooks/useUpdateNodeInternals.ts b/src/hooks/useUpdateNodeInternals.ts index 27da895f..7429f986 100644 --- a/src/hooks/useUpdateNodeInternals.ts +++ b/src/hooks/useUpdateNodeInternals.ts @@ -3,10 +3,10 @@ import { useCallback } from 'react'; import { useStore } from '../store'; import { UpdateNodeInternals, ReactFlowState } from '../types'; -const updateNodeDimsSelector = (state: ReactFlowState) => state.updateNodeDimensions; +const selector = (state: ReactFlowState) => state.updateNodeDimensions; function useUpdateNodeInternals(): UpdateNodeInternals { - const updateNodeDimensions = useStore(updateNodeDimsSelector); + const updateNodeDimensions = useStore(selector); return useCallback((id: string) => { const nodeElement = document.querySelector(`.react-flow__node[data-id="${id}"]`) as HTMLDivElement; diff --git a/src/store/index.ts b/src/store/index.ts index 7f39354e..6e75e370 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -4,27 +4,14 @@ import createContext from 'zustand/context'; import { clampPosition, getDimensions } from '../utils'; import { ReactFlowState, - ConnectionMode, Node, Edge, NodeDimensionUpdate, NodeDiffUpdate, - InitD3ZoomPayload, CoordinateExtent, - OnConnect, - OnConnectStart, - OnConnectStop, - OnConnectEnd, - SetConnectionId, - SnapGrid, NodeChange, - OnNodesChange, - OnEdgesChange, EdgeChange, NodeDimensionChange, - Transform, - Dimensions, - XYPosition, } from '../types'; import { getHandleBounds } from '../components/Nodes/utils'; import { createSelectionChange, getSelectionChanges } from '../utils/changes'; @@ -36,7 +23,6 @@ const { Provider, useStore, useStoreApi } = createContext(); const createStore = () => create((set, get) => ({ ...initialState, - setNodes: (nodes: Node[]) => { const nodeInternals = createNodeInternals(nodes, get().nodeInternals); @@ -158,13 +144,6 @@ const createStore = () => onEdgesChange?.(edgesToUnselect); } }, - initD3Zoom: ({ d3Zoom, d3Selection, d3ZoomHandler, transform }: InitD3ZoomPayload) => - set({ - d3Zoom, - d3Selection, - d3ZoomHandler, - transform, - }), setMinZoom: (minZoom: number) => { const { d3Zoom, maxZoom } = get(); d3Zoom?.scaleExtent([minZoom, maxZoom]); @@ -183,7 +162,6 @@ const createStore = () => set({ translateExtent }); }, - resetSelectedElements: () => { const { nodeInternals, edges, onNodesChange, onEdgesChange } = get(); // @TODO: work with nodeInternals instead of converting it to an array @@ -210,33 +188,7 @@ const createStore = () => nodeInternals: new Map(nodeInternals), }); }, - setUserSelectionActive: (userSelectionActive: boolean) => set({ userSelectionActive }), - setNodesSelectionActive: (nodesSelectionActive: boolean) => set({ nodesSelectionActive }), - updateTransform: (transform: Transform) => set({ transform }), - updateSize: (size: Dimensions) => set({ width: size.width || 500, height: size.height || 500 }), - setOnConnect: (onConnect: OnConnect) => set({ onConnect }), - setOnConnectStart: (onConnectStart: OnConnectStart) => set({ onConnectStart }), - setOnConnectStop: (onConnectStop: OnConnectStop) => set({ onConnectStop }), - setOnConnectEnd: (onConnectEnd: OnConnectEnd) => set({ onConnectEnd }), - setConnectionPosition: (connectionPosition: XYPosition) => set({ connectionPosition }), - setConnectionNodeId: (params: SetConnectionId) => set({ ...params }), - setSnapToGrid: (snapToGrid: boolean) => set({ snapToGrid }), - setSnapGrid: (snapGrid: SnapGrid) => set({ snapGrid }), - setInteractive: (isInteractive: boolean) => - set({ - nodesDraggable: isInteractive, - nodesConnectable: isInteractive, - elementsSelectable: isInteractive, - }), - setNodesDraggable: (nodesDraggable: boolean) => set({ nodesDraggable }), - setNodesConnectable: (nodesConnectable: boolean) => set({ nodesConnectable }), - setElementsSelectable: (elementsSelectable: boolean) => set({ elementsSelectable }), - setMultiSelectionActive: (multiSelectionActive: boolean) => set({ multiSelectionActive }), - setConnectionMode: (connectionMode: ConnectionMode) => set({ connectionMode }), - setOnNodesChange: (onNodesChange: OnNodesChange) => set({ onNodesChange }), - setOnEdgesChange: (onEdgesChange: OnEdgesChange) => set({ onEdgesChange }), reset: () => set({ ...initialState }), - setFitViewOnInit: (fitViewOnInit: boolean) => set({ fitViewOnInit }), })); export { Provider, useStore, createStore, useStoreApi }; diff --git a/src/types/general.ts b/src/types/general.ts index ab1b101b..1f67dbc9 100644 --- a/src/types/general.ts +++ b/src/types/general.ts @@ -1,7 +1,7 @@ import { MouseEvent as ReactMouseEvent, ReactNode } from 'react'; import { Selection as D3Selection, ZoomBehavior } from 'd3'; -import { XYPosition, Rect, Transform, CoordinateExtent, Dimensions } from './utils'; +import { XYPosition, Rect, Transform, CoordinateExtent } from './utils'; import { NodeChange, EdgeChange } from './changes'; import { Node, NodeInternals, NodeDimensionUpdate, NodeDiffUpdate } from './nodes'; import { Edge } from './edges'; @@ -90,12 +90,6 @@ export type OnConnectStop = (event: MouseEvent) => void; export type OnConnectEnd = (event: MouseEvent) => void; -export type SetConnectionId = { - connectionNodeId: string | null; - connectionHandleId: string | null; - connectionHandleType: HandleType | null; -}; - export enum BackgroundVariant { Lines = 'lines', Dots = 'dots', @@ -143,13 +137,6 @@ export interface ZoomPanHelperFunctions { initialized: boolean; } -export type InitD3ZoomPayload = { - d3Zoom: ZoomBehavior; - d3Selection: D3Selection; - d3ZoomHandler: ((this: Element, event: any, d: unknown) => void) | undefined; - transform: Transform; -}; - export type ReactFlowStore = { width: number; height: number; @@ -190,6 +177,11 @@ export type ReactFlowStore = { fitViewOnInit: boolean; fitViewOnInitDone: boolean; + + onConnect?: OnConnect; + onConnectStart?: OnConnectStart; + onConnectStop?: OnConnectStop; + onConnectEnd?: OnConnectEnd; }; export type ReactFlowActions = { @@ -197,43 +189,15 @@ export type ReactFlowActions = { setEdges: (edges: Edge[]) => void; updateNodeDimensions: (updates: NodeDimensionUpdate[]) => void; updateNodePosition: (update: NodeDiffUpdate) => void; - setNodesSelectionActive: (isActive: boolean) => void; - setUserSelectionActive: (isActive: boolean) => void; resetSelectedElements: () => void; unselectNodesAndEdges: () => void; addSelectedNodes: (nodeIds: string[]) => void; addSelectedEdges: (edgeIds: string[]) => void; - updateTransform: (transform: Transform) => void; - updateSize: (size: Dimensions) => void; - initD3Zoom: (payload: InitD3ZoomPayload) => void; setMinZoom: (minZoom: number) => void; setMaxZoom: (maxZoom: number) => void; setTranslateExtent: (translateExtent: CoordinateExtent) => void; setNodeExtent: (nodeExtent: CoordinateExtent) => void; - setOnConnect: (onConnectFunction: OnConnect) => void; - setOnConnectStart: (onConnectFunction: OnConnectStart) => void; - setOnConnectStop: (onConnectFunction: OnConnectStop) => void; - setOnConnectEnd: (onConnectFunction: OnConnectEnd) => void; - setConnectionPosition: (connectionPosition: XYPosition) => void; - setConnectionNodeId: (payload: SetConnectionId) => void; - setSnapToGrid: (snapToGrid: boolean) => void; - setSnapGrid: (snapGrid: SnapGrid) => void; - setInteractive: (isInteractive: boolean) => void; - setNodesDraggable: (nodesDraggable: boolean) => void; - setNodesConnectable: (nodesConnectable: boolean) => void; - setElementsSelectable: (elementsSelectable: boolean) => void; - setMultiSelectionActive: (multiSelectionActive: boolean) => void; - setConnectionMode: (connectionMode: ConnectionMode) => void; - setOnNodesChange: (onNodesChange: OnNodesChange) => void; - setOnEdgesChange: (onEdgesChange: OnEdgesChange) => void; - - onConnect?: OnConnect; - onConnectStart?: OnConnectStart; - onConnectStop?: OnConnectStop; - onConnectEnd?: OnConnectEnd; - reset: () => void; - setFitViewOnInit: (fitViewOnInit: boolean) => void; }; export type ReactFlowState = ReactFlowStore & ReactFlowActions;