Merge pull request #2345 from wbkd/chore/zustand-4.0

Chore: upgrade zustand v4.0
This commit is contained in:
Moritz Klack
2022-08-08 11:25:46 +02:00
committed by GitHub
42 changed files with 178 additions and 99 deletions
+1 -1
View File
@@ -2,4 +2,4 @@ nodeLinker: node-modules
plugins: plugins:
- path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs - path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs
spec: "@yarnpkg/plugin-workspace-tools" spec: '@yarnpkg/plugin-workspace-tools'
+2 -3
View File
@@ -17,10 +17,9 @@ import ColorSelectorNode from './ColorSelectorNode';
const onInit = (reactFlowInstance: ReactFlowInstance) => { const onInit = (reactFlowInstance: ReactFlowInstance) => {
console.log('flow loaded:', reactFlowInstance); console.log('flow loaded:', reactFlowInstance);
reactFlowInstance.fitView();
}; };
const onNodeDragStop = (_: MouseEvent, node: Node) =>
console.log('drag stop', node); const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node);
const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node); const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node);
const initBgColor = '#1A192B'; const initBgColor = '#1A192B';
+3 -26
View File
@@ -1,19 +1,4 @@
.react-flow__edge { .react-flow__edge {
&.selected,
&:focus,
&:focus-visible {
outline: none;
.react-flow__edge-path {
stroke: #555;
}
}
&.animated path {
stroke-dasharray: 5;
animation: dashdraw 0.5s linear infinite;
}
&.updating { &.updating {
.react-flow__edge-path { .react-flow__edge-path {
stroke: #777; stroke: #777;
@@ -21,20 +6,10 @@
} }
} }
.react-flow__edge-path {
stroke: #b1b1b7;
stroke-width: 1;
}
.react-flow__edge-text { .react-flow__edge-text {
font-size: 10px; font-size: 10px;
} }
.react-flow__connection-path {
stroke: #b1b1b7;
stroke-width: 1;
}
.react-flow__node-default, .react-flow__node-default,
.react-flow__node-input, .react-flow__node-input,
.react-flow__node-output, .react-flow__node-output,
@@ -52,6 +27,7 @@
&.selected, &.selected,
&:focus, &:focus,
&:focus-visible { &:focus-visible {
border: none;
box-shadow: 0 0 0 0.5px #1a192b; box-shadow: 0 0 0 0.5px #1a192b;
outline: none; outline: none;
} }
@@ -72,8 +48,9 @@
&.selected, &.selected,
&:focus, &:focus,
&:focus-visible { &:focus-visible {
outline: none; border: none;
box-shadow: 0 0 0 0.5px #1a192b; box-shadow: 0 0 0 0.5px #1a192b;
outline: none;
} }
} }
+1 -1
View File
@@ -22,7 +22,7 @@
"d3-drag": "^3.0.0", "d3-drag": "^3.0.0",
"d3-selection": "^3.0.0", "d3-selection": "^3.0.0",
"d3-zoom": "^3.0.0", "d3-zoom": "^3.0.0",
"zustand": "^3.7.2" "zustand": "^4.0.0"
}, },
"peerDependencies": { "peerDependencies": {
"react": ">=18", "react": ">=18",
@@ -1,10 +1,10 @@
import React, { CSSProperties, useCallback } from 'react'; import React, { CSSProperties, useCallback } from 'react';
import shallow from 'zustand/shallow'; import shallow from 'zustand/shallow';
import { useStore } from '../../store'; import { useStore } from '../../hooks/useStore';
import { getBezierPath } from '../Edges/BezierEdge'; import { getBezierPath } from '../Edges/BezierEdge';
import { getSmoothStepPath } from '../Edges/SmoothStepEdge'; import { getSmoothStepPath } from '../Edges/SmoothStepEdge';
import { ConnectionLineType, ConnectionLineComponent, HandleType, Position } from '../../types'; import { ConnectionLineType, ConnectionLineComponent, HandleType, Position, ReactFlowStore } from '../../types';
import { getSimpleBezierPath } from '../Edges/SimpleBezierEdge'; import { getSimpleBezierPath } from '../Edges/SimpleBezierEdge';
import { internalsSymbol } from '../../utils'; import { internalsSymbol } from '../../utils';
@@ -34,7 +34,7 @@ export default ({
}: ConnectionLineProps) => { }: ConnectionLineProps) => {
const { fromNode, handleId, toX, toY } = useStore( const { fromNode, handleId, toX, toY } = useStore(
useCallback( useCallback(
(s) => ({ (s: ReactFlowStore) => ({
fromNode: s.nodeInternals.get(connectionNodeId), fromNode: s.nodeInternals.get(connectionNodeId),
handleId: s.connectionHandleId, handleId: s.connectionHandleId,
toX: (s.connectionPosition.x - s.transform[0]) / s.transform[2], toX: (s.connectionPosition.x - s.transform[0]) / s.transform[2],
@@ -1,7 +1,7 @@
import React, { memo, ComponentType, useState, useMemo, KeyboardEvent, useRef } from 'react'; import React, { memo, ComponentType, useState, useMemo, KeyboardEvent, useRef } from 'react';
import cc from 'classcat'; import cc from 'classcat';
import { useStoreApi } from '../../store'; import { useStoreApi } from '../../hooks/useStore';
import { ARIA_EDGE_DESC_KEY } from '../A11yDescriptions'; import { ARIA_EDGE_DESC_KEY } from '../A11yDescriptions';
import { handleMouseDown } from '../Handle/handler'; import { handleMouseDown } from '../Handle/handler';
import { EdgeAnchor } from './EdgeAnchor'; import { EdgeAnchor } from './EdgeAnchor';
@@ -153,6 +153,7 @@ export function handleMouseDown({
} }
if (connection.source !== connection.target && elementBelow) { if (connection.source !== connection.target && elementBelow) {
resetRecentHandle(recentHoveredHandle);
recentHoveredHandle = elementBelow; recentHoveredHandle = elementBelow;
elementBelow.classList.add('react-flow__handle-connecting'); elementBelow.classList.add('react-flow__handle-connecting');
elementBelow.classList.toggle('react-flow__handle-valid', isValid); elementBelow.classList.toggle('react-flow__handle-valid', isValid);
@@ -2,7 +2,7 @@ import React, { memo, useContext, HTMLAttributes, forwardRef } from 'react';
import cc from 'classcat'; import cc from 'classcat';
import shallow from 'zustand/shallow'; import shallow from 'zustand/shallow';
import { useStore, useStoreApi } from '../../store'; import { useStore, useStoreApi } from '../../hooks/useStore';
import NodeIdContext from '../../contexts/NodeIdContext'; import NodeIdContext from '../../contexts/NodeIdContext';
import { HandleProps, Connection, ReactFlowState, Position } from '../../types'; import { HandleProps, Connection, ReactFlowState, Position } from '../../types';
import { checkElementBelowIsValid, handleMouseDown } from './handler'; import { checkElementBelowIsValid, handleMouseDown } from './handler';
@@ -1,7 +1,7 @@
import React, { useEffect, useRef, memo, ComponentType, MouseEvent, KeyboardEvent } from 'react'; import React, { useEffect, useRef, memo, ComponentType, MouseEvent, KeyboardEvent } from 'react';
import cc from 'classcat'; import cc from 'classcat';
import { useStoreApi } from '../../store'; import { useStoreApi } from '../../hooks/useStore';
import { Provider } from '../../contexts/NodeIdContext'; import { Provider } from '../../contexts/NodeIdContext';
import { ARIA_NODE_DESC_KEY } from '../A11yDescriptions'; import { ARIA_NODE_DESC_KEY } from '../A11yDescriptions';
import useDrag from '../../hooks/useDrag'; import useDrag from '../../hooks/useDrag';
@@ -7,7 +7,7 @@ import React, { memo, useRef, MouseEvent, KeyboardEvent, useEffect } from 'react
import cc from 'classcat'; import cc from 'classcat';
import shallow from 'zustand/shallow'; import shallow from 'zustand/shallow';
import { useStore, useStoreApi } from '../../store'; import { useStore, useStoreApi } from '../../hooks/useStore';
import { Node, ReactFlowState } from '../../types'; import { Node, ReactFlowState } from '../../types';
import { getRectOfNodes } from '../../utils/graph'; import { getRectOfNodes } from '../../utils/graph';
import useDrag from '../../hooks/useDrag'; import useDrag from '../../hooks/useDrag';
@@ -1,10 +1,19 @@
import React, { FC, PropsWithChildren } from 'react'; import React, { FC, PropsWithChildren, useRef } from 'react';
import { StoreApi } from 'zustand';
import { Provider, createStore } from '../../store'; import { Provider } from '../../contexts/RFStoreContext';
import { createRFStore } from '../../store';
import { ReactFlowState } from '../../types';
const ReactFlowProvider: FC<PropsWithChildren<{}>> = ({ children }) => ( const ReactFlowProvider: FC<PropsWithChildren<{}>> = ({ children }) => {
<Provider createStore={createStore}>{children}</Provider> const storeRef = useRef<StoreApi<ReactFlowState> | null>(null);
);
if (!storeRef.current) {
storeRef.current = createRFStore();
}
return <Provider value={storeRef.current}>{children}</Provider>;
};
ReactFlowProvider.displayName = 'ReactFlowProvider'; ReactFlowProvider.displayName = 'ReactFlowProvider';
@@ -2,7 +2,7 @@ import { memo, useEffect } from 'react';
import shallow from 'zustand/shallow'; import shallow from 'zustand/shallow';
import { ReactFlowState, OnSelectionChangeFunc, Node, Edge } from '../../types'; import { ReactFlowState, OnSelectionChangeFunc, Node, Edge } from '../../types';
import { useStore } from '../../store'; import { useStore } from '../../hooks/useStore';
interface SelectionListenerProps { interface SelectionListenerProps {
onSelectionChange: OnSelectionChangeFunc; onSelectionChange: OnSelectionChangeFunc;
@@ -1,9 +1,9 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
import { SetState } from 'zustand'; import { StoreApi } from 'zustand';
import shallow from 'zustand/shallow'; import shallow from 'zustand/shallow';
import { useStore, useStoreApi } from '../../store'; import { useStore, useStoreApi } from '../../hooks/useStore';
import { Node, Edge, ReactFlowState, CoordinateExtent, ReactFlowProps } from '../../types'; import { Node, Edge, ReactFlowState, CoordinateExtent, ReactFlowProps, ReactFlowStore } from '../../types';
type StoreUpdaterProps = Pick< type StoreUpdaterProps = Pick<
ReactFlowProps, ReactFlowProps,
@@ -61,10 +61,14 @@ function useStoreUpdater<T>(value: T | undefined, setStoreState: (param: T) => v
}, [value]); }, [value]);
} }
function useDirectStoreUpdater(key: keyof ReactFlowState, value: any, setState: SetState<ReactFlowState>) { // updates with values in store that don't have a dedicated setter function
function useDirectStoreUpdater(
key: keyof ReactFlowStore,
value: unknown,
setState: StoreApi<ReactFlowState>['setState']
) {
useEffect(() => { useEffect(() => {
if (typeof value !== 'undefined') { if (typeof value !== 'undefined') {
// @ts-ignore
setState({ [key]: value }); setState({ [key]: value });
} }
}, [value]); }, [value]);
@@ -153,8 +157,6 @@ const StoreUpdater = ({
useStoreUpdater<Node[]>(nodes, setNodes); useStoreUpdater<Node[]>(nodes, setNodes);
useStoreUpdater<Edge[]>(edges, setEdges); useStoreUpdater<Edge[]>(edges, setEdges);
useStoreUpdater<Node[]>(defaultNodes, setNodes);
useStoreUpdater<Edge[]>(defaultEdges, setEdges);
useStoreUpdater<number>(minZoom, setMinZoom); useStoreUpdater<number>(minZoom, setMinZoom);
useStoreUpdater<number>(maxZoom, setMaxZoom); useStoreUpdater<number>(maxZoom, setMaxZoom);
useStoreUpdater<CoordinateExtent>(translateExtent, setTranslateExtent); useStoreUpdater<CoordinateExtent>(translateExtent, setTranslateExtent);
@@ -5,7 +5,7 @@
import React, { memo, useState, useRef } from 'react'; import React, { memo, useState, useRef } from 'react';
import shallow from 'zustand/shallow'; import shallow from 'zustand/shallow';
import { useStore, useStoreApi } from '../../store'; import { useStore, useStoreApi } from '../../hooks/useStore';
import { getSelectionChanges } from '../../utils/changes'; import { getSelectionChanges } from '../../utils/changes';
import { XYPosition, ReactFlowState, NodeChange, EdgeChange, Rect } from '../../types'; import { XYPosition, ReactFlowState, NodeChange, EdgeChange, Rect } from '../../types';
import { getConnectedEdges, getNodesInside } from '../../utils/graph'; import { getConnectedEdges, getNodesInside } from '../../utils/graph';
@@ -1,6 +1,6 @@
import React, { memo, useCallback } from 'react'; import React, { memo, useCallback } from 'react';
import { useStore } from '../../store'; import { useStore } from '../../hooks/useStore';
import { EdgeMarker, ReactFlowState } from '../../types'; import { EdgeMarker, ReactFlowState } from '../../types';
import { getMarkerId } from '../../utils/graph'; import { getMarkerId } from '../../utils/graph';
import { useMarkerSymbol } from './MarkerSymbols'; import { useMarkerSymbol } from './MarkerSymbols';
@@ -2,7 +2,7 @@ import React, { memo, CSSProperties } from 'react';
import shallow from 'zustand/shallow'; import shallow from 'zustand/shallow';
import cc from 'classcat'; import cc from 'classcat';
import { useStore } from '../../store'; import { useStore } from '../../hooks/useStore';
import ConnectionLine from '../../components/ConnectionLine/index'; import ConnectionLine from '../../components/ConnectionLine/index';
import MarkerDefinitions from './MarkerDefinitions'; import MarkerDefinitions from './MarkerDefinitions';
import { getEdgePositions, getHandle, getNodeData } from './utils'; import { getEdgePositions, getHandle, getNodeData } from './utils';
@@ -1,6 +1,6 @@
import React, { memo, ReactNode, WheelEvent, MouseEvent } from 'react'; import React, { memo, ReactNode, WheelEvent, MouseEvent } from 'react';
import { useStore, useStoreApi } from '../../store'; import { useStore, useStoreApi } from '../../hooks/useStore';
import useGlobalKeyHandler from '../../hooks/useGlobalKeyHandler'; import useGlobalKeyHandler from '../../hooks/useGlobalKeyHandler';
import useKeyPress from '../../hooks/useKeyPress'; import useKeyPress from '../../hooks/useKeyPress';
import { GraphViewProps } from '../GraphView'; import { GraphViewProps } from '../GraphView';
@@ -54,6 +54,9 @@ const FlowRenderer = ({
zoomOnDoubleClick, zoomOnDoubleClick,
panOnDrag, panOnDrag,
defaultViewport, defaultViewport,
translateExtent,
minZoom,
maxZoom,
preventScrolling, preventScrolling,
onSelectionContextMenu, onSelectionContextMenu,
noWheelClassName, noWheelClassName,
@@ -90,6 +93,9 @@ const FlowRenderer = ({
zoomOnDoubleClick={zoomOnDoubleClick} zoomOnDoubleClick={zoomOnDoubleClick}
panOnDrag={panOnDrag} panOnDrag={panOnDrag}
defaultViewport={defaultViewport} defaultViewport={defaultViewport}
translateExtent={translateExtent}
minZoom={minZoom}
maxZoom={maxZoom}
zoomActivationKeyCode={zoomActivationKeyCode} zoomActivationKeyCode={zoomActivationKeyCode}
preventScrolling={preventScrolling} preventScrolling={preventScrolling}
noWheelClassName={noWheelClassName} noWheelClassName={noWheelClassName}
@@ -5,7 +5,15 @@ import NodeRenderer from '../NodeRenderer';
import EdgeRenderer from '../EdgeRenderer'; import EdgeRenderer from '../EdgeRenderer';
import ViewportWrapper from '../Viewport'; import ViewportWrapper from '../Viewport';
import useOnInitHandler from '../../hooks/useOnInitHandler'; import useOnInitHandler from '../../hooks/useOnInitHandler';
import { NodeTypesWrapped, EdgeTypesWrapped, ConnectionLineType, KeyCode, ReactFlowProps, Viewport } from '../../types'; import {
NodeTypesWrapped,
EdgeTypesWrapped,
ConnectionLineType,
KeyCode,
ReactFlowProps,
Viewport,
CoordinateExtent,
} from '../../types';
export interface GraphViewProps export interface GraphViewProps
extends Omit<ReactFlowProps, 'onSelectionChange' | 'nodes' | 'edges' | 'nodeTypes' | 'edgeTypes'> { extends Omit<ReactFlowProps, 'onSelectionChange' | 'nodes' | 'edges' | 'nodeTypes' | 'edgeTypes'> {
@@ -16,6 +24,9 @@ export interface GraphViewProps
multiSelectionKeyCode: KeyCode | null; multiSelectionKeyCode: KeyCode | null;
connectionLineType: ConnectionLineType; connectionLineType: ConnectionLineType;
onlyRenderVisibleElements: boolean; onlyRenderVisibleElements: boolean;
translateExtent: CoordinateExtent;
minZoom: number;
maxZoom: number;
defaultMarkerColor: string; defaultMarkerColor: string;
selectNodesOnDrag: boolean; selectNodesOnDrag: boolean;
noDragClassName: string; noDragClassName: string;
@@ -54,6 +65,9 @@ const GraphView = ({
elementsSelectable, elementsSelectable,
selectNodesOnDrag, selectNodesOnDrag,
defaultViewport, defaultViewport,
translateExtent,
minZoom,
maxZoom,
preventScrolling, preventScrolling,
defaultMarkerColor, defaultMarkerColor,
zoomOnScroll, zoomOnScroll,
@@ -110,6 +124,9 @@ const GraphView = ({
panOnScrollMode={panOnScrollMode} panOnScrollMode={panOnScrollMode}
panOnDrag={panOnDrag} panOnDrag={panOnDrag}
defaultViewport={defaultViewport} defaultViewport={defaultViewport}
translateExtent={translateExtent}
minZoom={minZoom}
maxZoom={maxZoom}
onSelectionContextMenu={onSelectionContextMenu} onSelectionContextMenu={onSelectionContextMenu}
preventScrolling={preventScrolling} preventScrolling={preventScrolling}
noDragClassName={noDragClassName} noDragClassName={noDragClassName}
@@ -2,10 +2,10 @@ import React, { memo, useMemo, ComponentType, useEffect, useRef } from 'react';
import shallow from 'zustand/shallow'; import shallow from 'zustand/shallow';
import useVisibleNodes from '../../hooks/useVisibleNodes'; import useVisibleNodes from '../../hooks/useVisibleNodes';
import { useStore } from '../../store'; import { useStore } from '../../hooks/useStore';
import { internalsSymbol } from '../../utils';
import { containerStyle } from '../../styles'; import { containerStyle } from '../../styles';
import { NodeMouseHandler, NodeTypesWrapped, Position, ReactFlowState, WrapNodeProps } from '../../types'; import { NodeMouseHandler, NodeTypesWrapped, Position, ReactFlowState, WrapNodeProps } from '../../types';
import { internalsSymbol } from '../../utils';
interface NodeRendererProps { interface NodeRendererProps {
nodeTypes: NodeTypesWrapped; nodeTypes: NodeTypesWrapped;
@@ -46,7 +46,6 @@ const NodeRenderer = (props: NodeRendererProps) => {
nodeElement: entry.target as HTMLDivElement, nodeElement: entry.target as HTMLDivElement,
forceUpdate: true, forceUpdate: true,
})); }));
updateNodeDimensions(updates); updateNodeDimensions(updates);
}); });
@@ -1,6 +1,7 @@
import React, { FC, PropsWithChildren } from 'react'; import React, { FC, PropsWithChildren } from 'react';
import { Provider, createStore, useStoreApi } from '../../store'; import { useStoreApi } from '../../hooks/useStore';
import ReactFlowProvider from '../../components/ReactFlowProvider';
const Wrapper: FC<PropsWithChildren<{}>> = ({ children }) => { const Wrapper: FC<PropsWithChildren<{}>> = ({ children }) => {
let isWrapped = true; let isWrapped = true;
@@ -17,7 +18,7 @@ const Wrapper: FC<PropsWithChildren<{}>> = ({ children }) => {
return <>{children}</>; return <>{children}</>;
} }
return <Provider createStore={createStore}>{children}</Provider>; return <ReactFlowProvider>{children}</ReactFlowProvider>;
}; };
Wrapper.displayName = 'ReactFlowWrapper'; Wrapper.displayName = 'ReactFlowWrapper';
@@ -31,6 +31,7 @@ import { createNodeTypes } from '../NodeRenderer/utils';
import { useNodeOrEdgeTypes } from './utils'; import { useNodeOrEdgeTypes } from './utils';
import Wrapper from './Wrapper'; import Wrapper from './Wrapper';
import A11yDescriptions from '../../components/A11yDescriptions'; import A11yDescriptions from '../../components/A11yDescriptions';
import { infiniteExtent } from '../../store/initialState';
const defaultNodeTypes: NodeTypes = { const defaultNodeTypes: NodeTypes = {
input: InputNode, input: InputNode,
@@ -108,10 +109,10 @@ const ReactFlow = forwardRef<ReactFlowRefType, ReactFlowProps>(
nodesDraggable, nodesDraggable,
nodesConnectable, nodesConnectable,
elementsSelectable, elementsSelectable,
minZoom,
maxZoom,
defaultViewport = initDefaultViewport, defaultViewport = initDefaultViewport,
translateExtent, minZoom = 0.5,
maxZoom = 2,
translateExtent = infiniteExtent,
preventScrolling = true, preventScrolling = true,
nodeExtent, nodeExtent,
defaultMarkerColor = '#b1b1b7', defaultMarkerColor = '#b1b1b7',
@@ -188,6 +189,9 @@ const ReactFlow = forwardRef<ReactFlowRefType, ReactFlowProps>(
onlyRenderVisibleElements={onlyRenderVisibleElements} onlyRenderVisibleElements={onlyRenderVisibleElements}
selectNodesOnDrag={selectNodesOnDrag} selectNodesOnDrag={selectNodesOnDrag}
defaultViewport={defaultViewport} defaultViewport={defaultViewport}
translateExtent={translateExtent}
minZoom={minZoom}
maxZoom={maxZoom}
preventScrolling={preventScrolling} preventScrolling={preventScrolling}
zoomOnScroll={zoomOnScroll} zoomOnScroll={zoomOnScroll}
zoomOnPinch={zoomOnPinch} zoomOnPinch={zoomOnPinch}
@@ -1,6 +1,6 @@
import React, { ReactNode } from 'react'; import React, { ReactNode } from 'react';
import { useStore } from '../../store'; import { useStore } from '../../hooks/useStore';
import { ReactFlowState } from '../../types'; import { ReactFlowState } from '../../types';
const selector = (s: ReactFlowState) => `translate(${s.transform[0]}px,${s.transform[1]}px) scale(${s.transform[2]})`; const selector = (s: ReactFlowState) => `translate(${s.transform[0]}px,${s.transform[1]}px) scale(${s.transform[2]})`;
@@ -6,10 +6,10 @@ import shallow from 'zustand/shallow';
import { clamp } from '../../utils'; 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 '../../hooks/useStore';
import { Viewport, PanOnScrollMode, ReactFlowState } from '../../types';
import { FlowRendererProps } from '../FlowRenderer'; import { FlowRendererProps } from '../FlowRenderer';
import { containerStyle } from '../../styles'; import { containerStyle } from '../../styles';
import { Viewport, PanOnScrollMode, ReactFlowState } from '../../types';
type ZoomPaneProps = Omit< type ZoomPaneProps = Omit<
FlowRendererProps, FlowRendererProps,
@@ -47,6 +47,9 @@ const ZoomPane = ({
elementsSelectable, elementsSelectable,
panOnDrag = true, panOnDrag = true,
defaultViewport, defaultViewport,
translateExtent,
minZoom,
maxZoom,
zoomActivationKeyCode, zoomActivationKeyCode,
preventScrolling = true, preventScrolling = true,
children, children,
@@ -64,7 +67,6 @@ const ZoomPane = ({
useEffect(() => { useEffect(() => {
if (zoomPane.current) { if (zoomPane.current) {
const { minZoom, maxZoom, translateExtent } = store.getState();
const d3ZoomInstance = zoom().scaleExtent([minZoom, maxZoom]).translateExtent(translateExtent); const d3ZoomInstance = zoom().scaleExtent([minZoom, maxZoom]).translateExtent(translateExtent);
const selection = select(zoomPane.current as Element).call(d3ZoomInstance); const selection = select(zoomPane.current as Element).call(d3ZoomInstance);
@@ -81,7 +83,7 @@ const ZoomPane = ({
d3ZoomHandler: selection.on('wheel.zoom'), d3ZoomHandler: selection.on('wheel.zoom'),
// we need to pass transform because zoom handler is not registered when we set the initial transform // we need to pass transform because zoom handler is not registered when we set the initial transform
transform: [clampedX, clampedY, clampedZoom], transform: [clampedX, clampedY, clampedZoom],
domNode: selection.node()?.closest('.react-flow') as HTMLElement, domNode: zoomPane.current.closest('.react-flow') as HTMLDivElement,
}); });
} }
}, []); }, []);
@@ -0,0 +1,8 @@
import { createContext } from 'react';
import { createRFStore } from '../store';
const StoreContext = createContext<ReturnType<typeof createRFStore> | null>(null);
export const Provider = StoreContext.Provider;
export default StoreContext;
+1 -1
View File
@@ -2,7 +2,7 @@ import { RefObject, useEffect, useRef, MouseEvent, useState, useCallback } from
import { D3DragEvent, drag, SubjectPosition } from 'd3-drag'; import { D3DragEvent, drag, SubjectPosition } from 'd3-drag';
import { select } from 'd3-selection'; import { select } from 'd3-selection';
import { useStoreApi } from '../../store'; import { useStoreApi } from '../../hooks/useStore';
import { pointToRendererPoint } from '../../utils/graph'; import { pointToRendererPoint } from '../../utils/graph';
import { NodeDragItem, Node, SelectionDragHandler } from '../../types'; import { NodeDragItem, Node, SelectionDragHandler } from '../../types';
import { getDragItems, getEventHandlerParams, hasSelector, calcNextPosition } from './utils'; import { getDragItems, getEventHandlerParams, hasSelector, calcNextPosition } from './utils';
+1 -1
View File
@@ -1,4 +1,4 @@
import { useStore } from '../store'; import { useStore } from '../hooks/useStore';
import { Edge, ReactFlowState } from '../types'; import { Edge, ReactFlowState } from '../types';
const edgesSelector = (state: ReactFlowState) => state.edges; const edgesSelector = (state: ReactFlowState) => state.edges;
@@ -1,6 +1,6 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
import { useStoreApi } from '../store'; import { useStoreApi } from '../hooks/useStore';
import useKeyPress from './useKeyPress'; import useKeyPress from './useKeyPress';
import { getConnectedEdges } from '../utils/graph'; import { getConnectedEdges } from '../utils/graph';
import { KeyCode, NodeChange, Node } from '../types'; import { KeyCode, NodeChange, Node } from '../types';
+1 -1
View File
@@ -1,4 +1,4 @@
import { useStore } from '../store'; import { useStore } from '../hooks/useStore';
import { Node, ReactFlowState } from '../types'; import { Node, ReactFlowState } from '../types';
const nodesSelector = (state: ReactFlowState) => Array.from(state.nodeInternals.values()); const nodesSelector = (state: ReactFlowState) => Array.from(state.nodeInternals.values());
+1 -1
View File
@@ -1,7 +1,7 @@
import { useCallback } from 'react'; import { useCallback } from 'react';
import useViewportHelper from './useViewportHelper'; import useViewportHelper from './useViewportHelper';
import { useStoreApi } from '../store'; import { useStoreApi } from '../hooks/useStore';
import { import {
ReactFlowInstance, ReactFlowInstance,
Instance, Instance,
+3 -3
View File
@@ -1,6 +1,6 @@
import { useEffect, MutableRefObject } from 'react'; import { useEffect, MutableRefObject } from 'react';
import { useStoreApi } from '../store'; import { useStoreApi } from '../hooks/useStore';
import { getDimensions } from '../utils'; import { getDimensions } from '../utils';
function useResizeHandler(rendererNode: MutableRefObject<HTMLDivElement | null>): void { function useResizeHandler(rendererNode: MutableRefObject<HTMLDivElement | null>): void {
@@ -29,7 +29,7 @@ function useResizeHandler(rendererNode: MutableRefObject<HTMLDivElement | null>)
}; };
updateDimensions(); updateDimensions();
window.onresize = updateDimensions; window.addEventListener('resize', updateDimensions);
if (rendererNode.current) { if (rendererNode.current) {
resizeObserver = new ResizeObserver(() => updateDimensions()); resizeObserver = new ResizeObserver(() => updateDimensions());
@@ -37,7 +37,7 @@ function useResizeHandler(rendererNode: MutableRefObject<HTMLDivElement | null>)
} }
return () => { return () => {
window.onresize = null; window.removeEventListener('resize', updateDimensions);
if (resizeObserver && rendererNode.current) { if (resizeObserver && rendererNode.current) {
resizeObserver.unobserve(rendererNode.current!); resizeObserver.unobserve(rendererNode.current!);
+43
View File
@@ -0,0 +1,43 @@
import { useContext, useMemo } from 'react';
import { StoreApi, useStore as useZustandStore } from 'zustand';
import StoreContext from '../contexts/RFStoreContext';
import { ReactFlowState } from '../types';
const errorMessage =
'[React Flow]: Seems like you have not used zustand provider as an ancestor. Help: https://reactflow.dev/error#100';
type ExtractState = StoreApi<ReactFlowState> extends { getState: () => infer T } ? T : never;
function useStore<StateSlice = ExtractState>(
selector: (state: ReactFlowState) => StateSlice,
equalityFn?: (a: StateSlice, b: StateSlice) => boolean
) {
const store = useContext(StoreContext);
if (store === null) {
throw new Error(errorMessage);
}
return useZustandStore(store, selector, equalityFn);
}
const useStoreApi = () => {
const store = useContext(StoreContext);
if (store === null) {
throw new Error(errorMessage);
}
return useMemo(
() => ({
getState: store.getState,
setState: store.setState,
subscribe: store.subscribe,
destroy: store.destroy,
}),
[store]
);
};
export { useStore, useStoreApi };
@@ -1,6 +1,6 @@
import { useCallback } from 'react'; import { useCallback } from 'react';
import { useStore, useStoreApi } from '../store'; import { useStore, useStoreApi } from '../hooks/useStore';
import { UpdateNodeInternals, ReactFlowState } from '../types'; import { UpdateNodeInternals, ReactFlowState } from '../types';
const selector = (state: ReactFlowState) => state.updateNodeDimensions; const selector = (state: ReactFlowState) => state.updateNodeDimensions;
@@ -1,6 +1,6 @@
import { useCallback } from 'react'; import { useCallback } from 'react';
import { useStoreApi } from '../store'; import { useStoreApi } from '../hooks/useStore';
import { calcNextPosition } from './useDrag/utils'; import { calcNextPosition } from './useDrag/utils';
import { XYPosition } from '../types'; import { XYPosition } from '../types';
+1 -1
View File
@@ -1,6 +1,6 @@
import shallow from 'zustand/shallow'; import shallow from 'zustand/shallow';
import { useStore } from '../store'; import { useStore } from '../hooks/useStore';
import { Viewport, ReactFlowState } from '../types'; import { Viewport, ReactFlowState } from '../types';
const viewportSelector = (state: ReactFlowState) => ({ const viewportSelector = (state: ReactFlowState) => ({
+1 -1
View File
@@ -2,7 +2,7 @@ import { useMemo } from 'react';
import { zoomIdentity } from 'd3-zoom'; import { zoomIdentity } from 'd3-zoom';
import shallow from 'zustand/shallow'; import shallow from 'zustand/shallow';
import { useStoreApi, useStore } from '../store'; import { useStoreApi, useStore } from '../hooks/useStore';
import { pointToRendererPoint, getTransformForBounds, getD3Transition } from '../utils/graph'; import { pointToRendererPoint, getTransformForBounds, getD3Transition } from '../utils/graph';
import { FitViewOptions, Viewport, ViewportHelperFunctions, ReactFlowState, Rect, XYPosition } from '../types'; import { FitViewOptions, Viewport, ViewportHelperFunctions, ReactFlowState, Rect, XYPosition } from '../types';
import { fitView as fitViewStore } from '../store/utils'; import { fitView as fitViewStore } from '../store/utils';
+1 -1
View File
@@ -1,6 +1,6 @@
import { useCallback } from 'react'; import { useCallback } from 'react';
import { useStore } from '../store'; import { useStore } from '../hooks/useStore';
import { isEdgeVisible } from '../container/EdgeRenderer/utils'; import { isEdgeVisible } from '../container/EdgeRenderer/utils';
import { ReactFlowState, NodeInternals, Edge } from '../types'; import { ReactFlowState, NodeInternals, Edge } from '../types';
import { internalsSymbol, isNumeric } from '../utils'; import { internalsSymbol, isNumeric } from '../utils';
+1 -1
View File
@@ -1,6 +1,6 @@
import { useCallback } from 'react'; import { useCallback } from 'react';
import { useStore } from '../store'; import { useStore } from '../hooks/useStore';
import { getNodesInside } from '../utils/graph'; import { getNodesInside } from '../utils/graph';
import { ReactFlowState } from '../types'; import { ReactFlowState } from '../types';
+1 -1
View File
@@ -39,6 +39,6 @@ export { default as useEdges } from './hooks/useEdges';
export { default as useViewport } from './hooks/useViewport'; export { default as useViewport } from './hooks/useViewport';
export { default as useKeyPress } from './hooks/useKeyPress'; export { default as useKeyPress } from './hooks/useKeyPress';
export * from './hooks/useNodesEdgesState'; export * from './hooks/useNodesEdgesState';
export { useStore, useStoreApi } from './store'; export { useStore, useStoreApi } from './hooks/useStore';
export * from './types'; export * from './types';
+4 -7
View File
@@ -1,5 +1,4 @@
import create from 'zustand'; import { createStore } from 'zustand';
import createContext from 'zustand/context';
import { clampPosition, getDimensions, internalsSymbol } from '../utils'; import { clampPosition, getDimensions, internalsSymbol } from '../utils';
import { applyNodeChanges } from '../utils/changes'; import { applyNodeChanges } from '../utils/changes';
@@ -21,10 +20,8 @@ import { createSelectionChange, getSelectionChanges } from '../utils/changes';
import { createNodeInternals, fitView, updateNodesAndEdgesSelections } from './utils'; import { createNodeInternals, fitView, updateNodesAndEdgesSelections } from './utils';
import initialState from './initialState'; import initialState from './initialState';
const { Provider, useStore, useStoreApi } = createContext<ReactFlowState>(); const createRFStore = () =>
createStore<ReactFlowState>((set, get) => ({
const createStore = () =>
create<ReactFlowState>((set, get) => ({
...initialState, ...initialState,
setNodes: (nodes: Node[]) => { setNodes: (nodes: Node[]) => {
set({ nodeInternals: createNodeInternals(nodes, get().nodeInternals) }); set({ nodeInternals: createNodeInternals(nodes, get().nodeInternals) });
@@ -236,4 +233,4 @@ const createStore = () =>
reset: () => set({ ...initialState }), reset: () => set({ ...initialState }),
})); }));
export { Provider, useStore, createStore, useStoreApi }; export { createRFStore };
+1 -1
View File
@@ -135,7 +135,7 @@ export type ReactFlowStore = {
onEdgesChange: OnEdgesChange | null; onEdgesChange: OnEdgesChange | null;
hasDefaultNodes: boolean; hasDefaultNodes: boolean;
hasDefaultEdges: boolean; hasDefaultEdges: boolean;
domNode: HTMLElement | null; domNode: HTMLDivElement | null;
d3Zoom: ZoomBehavior<Element, unknown> | null; d3Zoom: ZoomBehavior<Element, unknown> | null;
d3Selection: D3Selection<Element, unknown, null, undefined> | null; d3Selection: D3Selection<Element, unknown, null, undefined> | null;
+1 -1
View File
@@ -9,7 +9,7 @@
"@react-flow/core": "^11.0.0", "@react-flow/core": "^11.0.0",
"@react-flow/css-utils": "^11.0.0", "@react-flow/css-utils": "^11.0.0",
"classcat": "^5.0.3", "classcat": "^5.0.3",
"zustand": "^3.7.2" "zustand": "^4.0.0"
}, },
"peerDependencies": { "peerDependencies": {
"react": "^18.1.0", "react": "^18.1.0",
+20 -6
View File
@@ -1938,7 +1938,7 @@ __metadata:
postcss-cli: ^10.0.0 postcss-cli: ^10.0.0
postcss-import: ^14.1.0 postcss-import: ^14.1.0
postcss-nested: ^5.0.6 postcss-nested: ^5.0.6
zustand: ^3.7.2 zustand: ^4.0.0
peerDependencies: peerDependencies:
react: ">=18" react: ">=18"
react-dom: ">=18" react-dom: ">=18"
@@ -1958,7 +1958,7 @@ __metadata:
"@react-flow/core": ^11.0.0 "@react-flow/core": ^11.0.0
"@react-flow/css-utils": ^11.0.0 "@react-flow/css-utils": ^11.0.0
classcat: ^5.0.3 classcat: ^5.0.3
zustand: ^3.7.2 zustand: ^4.0.0
peerDependencies: peerDependencies:
react: ^18.1.0 react: ^18.1.0
react-dom: ">=18" react-dom: ">=18"
@@ -8216,6 +8216,15 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"use-sync-external-store@npm:1.2.0":
version: 1.2.0
resolution: "use-sync-external-store@npm:1.2.0"
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0
checksum: 5c639e0f8da3521d605f59ce5be9e094ca772bd44a4ce7322b055a6f58eeed8dda3c94cabd90c7a41fb6fa852210092008afe48f7038792fd47501f33299116a
languageName: node
linkType: hard
"util-deprecate@npm:^1.0.1, util-deprecate@npm:^1.0.2": "util-deprecate@npm:^1.0.1, util-deprecate@npm:^1.0.2":
version: 1.0.2 version: 1.0.2
resolution: "util-deprecate@npm:1.0.2" resolution: "util-deprecate@npm:1.0.2"
@@ -8414,14 +8423,19 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"zustand@npm:^3.7.2": "zustand@npm:^4.0.0":
version: 3.7.2 version: 4.0.0
resolution: "zustand@npm:3.7.2" resolution: "zustand@npm:4.0.0"
dependencies:
use-sync-external-store: 1.2.0
peerDependencies: peerDependencies:
immer: ">=9.0"
react: ">=16.8" react: ">=16.8"
peerDependenciesMeta: peerDependenciesMeta:
immer:
optional: true
react: react:
optional: true optional: true
checksum: 18f025b1b666a311121d3855303ff58e6a21fd107920ca474307e86984c13338d6c4cfa5cdf13382a9e0f76821f2554a12d4d200a98a66b58637e729f149797b checksum: b8ae5971dff79a1007d46f9a6bfa39ed5cc5b101a877eeec069ebdb6c8285ec8e3463e40cfa7c0f1507a41f43fe26ffb44b556063cb70ac03bccf1ea6e0f69d6
languageName: node languageName: node
linkType: hard linkType: hard