diff --git a/packages/react/src/components/ReactFlowProvider/index.tsx b/packages/react/src/components/ReactFlowProvider/index.tsx index f04ebebd..4843afeb 100644 --- a/packages/react/src/components/ReactFlowProvider/index.tsx +++ b/packages/react/src/components/ReactFlowProvider/index.tsx @@ -4,6 +4,7 @@ import { Provider } from '../../contexts/StoreContext'; import { createStore } from '../../store'; import { BatchProvider } from '../BatchProvider'; import type { Node, Edge } from '../../types'; +import { NodeOrigin } from '@xyflow/system'; export type ReactFlowProviderProps = { initialNodes?: Node[]; @@ -13,6 +14,7 @@ export type ReactFlowProviderProps = { initialWidth?: number; initialHeight?: number; fitView?: boolean; + nodeOrigin?: NodeOrigin; children: ReactNode; }; @@ -24,6 +26,7 @@ export function ReactFlowProvider({ initialWidth: width, initialHeight: height, fitView, + nodeOrigin, children, }: ReactFlowProviderProps) { const [store] = useState(() => @@ -35,6 +38,7 @@ export function ReactFlowProvider({ width, height, fitView, + nodeOrigin, }) ); diff --git a/packages/react/src/container/ReactFlow/Wrapper.tsx b/packages/react/src/container/ReactFlow/Wrapper.tsx index af9ad4a4..ce1b5a74 100644 --- a/packages/react/src/container/ReactFlow/Wrapper.tsx +++ b/packages/react/src/container/ReactFlow/Wrapper.tsx @@ -3,6 +3,7 @@ import { useContext, type ReactNode } from 'react'; import StoreContext from '../../contexts/StoreContext'; import { ReactFlowProvider } from '../../components/ReactFlowProvider'; import type { Node, Edge } from '../../types'; +import { NodeOrigin } from '@xyflow/system'; export function Wrapper({ children, @@ -13,6 +14,7 @@ export function Wrapper({ width, height, fitView, + nodeOrigin, }: { children: ReactNode; nodes?: Node[]; @@ -22,6 +24,7 @@ export function Wrapper({ width?: number; height?: number; fitView?: boolean; + nodeOrigin?: NodeOrigin; }) { const isWrapped = useContext(StoreContext); @@ -40,6 +43,7 @@ export function Wrapper({ initialWidth={width} initialHeight={height} fitView={fitView} + nodeOrigin={nodeOrigin} > {children} diff --git a/packages/react/src/container/ReactFlow/index.tsx b/packages/react/src/container/ReactFlow/index.tsx index 31f7c315..c301d9d4 100644 --- a/packages/react/src/container/ReactFlow/index.tsx +++ b/packages/react/src/container/ReactFlow/index.tsx @@ -157,7 +157,7 @@ function ReactFlow( data-testid="rf__wrapper" id={id} > - + onInit={onInit} onNodeClick={onNodeClick} diff --git a/packages/react/src/store/index.ts b/packages/react/src/store/index.ts index 31e2ed21..ccc522d4 100644 --- a/packages/react/src/store/index.ts +++ b/packages/react/src/store/index.ts @@ -12,6 +12,7 @@ import { EdgeSelectionChange, NodeSelectionChange, ParentExpandChild, + NodeOrigin, } from '@xyflow/system'; import { applyEdgeChanges, applyNodeChanges, createSelectionChange, getSelectionChanges } from '../utils/changes'; @@ -26,6 +27,7 @@ const createStore = ({ width, height, fitView, + nodeOrigin, }: { nodes?: Node[]; edges?: Edge[]; @@ -34,10 +36,11 @@ const createStore = ({ width?: number; height?: number; fitView?: boolean; + nodeOrigin?: NodeOrigin; }) => createWithEqualityFn( (set, get) => ({ - ...getInitialState({ nodes, edges, width, height, fitView, defaultNodes, defaultEdges }), + ...getInitialState({ nodes, edges, width, height, fitView, nodeOrigin, defaultNodes, defaultEdges }), setNodes: (nodes: Node[]) => { const { nodeLookup, parentLookup, nodeOrigin, elevateNodesOnSelect } = get(); // setNodes() is called exclusively in response to user actions: diff --git a/packages/react/src/store/initialState.ts b/packages/react/src/store/initialState.ts index d80706a4..1b98ee68 100644 --- a/packages/react/src/store/initialState.ts +++ b/packages/react/src/store/initialState.ts @@ -7,6 +7,7 @@ import { updateConnectionLookup, devWarn, getInternalNodesBounds, + NodeOrigin, } from '@xyflow/system'; import type { Edge, InternalNode, Node, ReactFlowStore } from '../types'; @@ -19,6 +20,7 @@ const getInitialState = ({ width, height, fitView, + nodeOrigin, }: { nodes?: Node[]; edges?: Edge[]; @@ -27,6 +29,7 @@ const getInitialState = ({ width?: number; height?: number; fitView?: boolean; + nodeOrigin?: NodeOrigin; } = {}): ReactFlowStore => { const nodeLookup = new Map(); const parentLookup = new Map(); @@ -34,20 +37,21 @@ const getInitialState = ({ const edgeLookup = new Map(); const storeEdges = defaultEdges ?? edges ?? []; const storeNodes = defaultNodes ?? nodes ?? []; + const storeNodeOrigin = nodeOrigin ?? [0, 0]; updateConnectionLookup(connectionLookup, edgeLookup, storeEdges); adoptUserNodes(storeNodes, nodeLookup, parentLookup, { - nodeOrigin: [0, 0], + nodeOrigin: storeNodeOrigin, elevateNodesOnSelect: false, }); let transform: Transform = [0, 0, 1]; if (fitView && width && height) { - // @todo users nodeOrigin should be used here const bounds = getInternalNodesBounds(nodeLookup, { filter: (node) => !!((node.width || node.initialWidth) && (node.height || node.initialHeight)), }); + const { x, y, zoom } = getViewportForBounds(bounds, width, height, 0.5, 2, 0.1); transform = [x, y, zoom]; } @@ -81,7 +85,7 @@ const getInitialState = ({ domNode: null, paneDragging: false, noPanClassName: 'nopan', - nodeOrigin: [0, 0], + nodeOrigin: storeNodeOrigin, nodeDragThreshold: 1, snapGrid: [15, 15], diff --git a/packages/react/src/types/store.ts b/packages/react/src/types/store.ts index 52ffae5d..89e33748 100644 --- a/packages/react/src/types/store.ts +++ b/packages/react/src/types/store.ts @@ -27,6 +27,7 @@ import { type NodeLookup, NodeChange, EdgeChange, + ParentLookup, } from '@xyflow/system'; import type { @@ -54,7 +55,7 @@ export type ReactFlowStore>; - parentLookup: Map>>; + parentLookup: ParentLookup>; edges: Edge[]; edgeLookup: EdgeLookup; connectionLookup: ConnectionLookup; diff --git a/packages/system/src/utils/general.ts b/packages/system/src/utils/general.ts index f2087ab9..0513f562 100644 --- a/packages/system/src/utils/general.ts +++ b/packages/system/src/utils/general.ts @@ -75,8 +75,8 @@ export const nodeToRect = (node: InternalNodeBase | NodeBase, nodeOrigin: NodeOr return { x, y, - width: node.measured?.width ?? node.width ?? 0, - height: node.measured?.height ?? node.height ?? 0, + width: node.measured?.width ?? node.width ?? node.initialWidth ?? 0, + height: node.measured?.height ?? node.height ?? node.initialHeight ?? 0, }; }; @@ -88,8 +88,8 @@ export const nodeToBox = (node: InternalNodeBase | NodeBase, nodeOrigin: NodeOri return { x, y, - x2: x + (node.measured?.width ?? node.width ?? 0), - y2: y + (node.measured?.height ?? node.height ?? 0), + x2: x + (node.measured?.width ?? node.width ?? node.initialWidth ?? 0), + y2: y + (node.measured?.height ?? node.height ?? node.initialHeight ?? 0), }; }; diff --git a/packages/system/src/utils/graph.ts b/packages/system/src/utils/graph.ts index 3bf34784..d09fe1ef 100644 --- a/packages/system/src/utils/graph.ts +++ b/packages/system/src/utils/graph.ts @@ -166,7 +166,7 @@ export const getInternalNodesBounds = { - if (params.filter == undefined || params.filter(node)) { + if (params.filter === undefined || params.filter(node)) { const nodeBox = nodeToBox(node as InternalNodeBase); box = getBoundsOfBoxes(box, nodeBox); }