refactor(react): init store with user nodeOrigin
This commit is contained in:
@@ -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,
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
@@ -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}
|
||||
</ReactFlowProvider>
|
||||
|
||||
@@ -157,7 +157,7 @@ function ReactFlow<NodeType extends Node = Node, EdgeType extends Edge = Edge>(
|
||||
data-testid="rf__wrapper"
|
||||
id={id}
|
||||
>
|
||||
<Wrapper nodes={nodes} edges={edges} width={width} height={height} fitView={fitView}>
|
||||
<Wrapper nodes={nodes} edges={edges} width={width} height={height} fitView={fitView} nodeOrigin={nodeOrigin}>
|
||||
<GraphView<NodeType, EdgeType>
|
||||
onInit={onInit}
|
||||
onNodeClick={onNodeClick}
|
||||
|
||||
@@ -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<ReactFlowState>(
|
||||
(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:
|
||||
|
||||
@@ -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<string, InternalNode>();
|
||||
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],
|
||||
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
type NodeLookup,
|
||||
NodeChange,
|
||||
EdgeChange,
|
||||
ParentLookup,
|
||||
} from '@xyflow/system';
|
||||
|
||||
import type {
|
||||
@@ -54,7 +55,7 @@ export type ReactFlowStore<NodeType extends Node = Node, EdgeType extends Edge =
|
||||
transform: Transform;
|
||||
nodes: NodeType[];
|
||||
nodeLookup: NodeLookup<InternalNode<NodeType>>;
|
||||
parentLookup: Map<string, Map<string, InternalNode<NodeType>>>;
|
||||
parentLookup: ParentLookup<InternalNode<NodeType>>;
|
||||
edges: Edge[];
|
||||
edgeLookup: EdgeLookup<EdgeType>;
|
||||
connectionLookup: ConnectionLookup;
|
||||
|
||||
@@ -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),
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -166,7 +166,7 @@ export const getInternalNodesBounds = <NodeType extends InternalNodeBase | NodeD
|
||||
let box = { x: Infinity, y: Infinity, x2: -Infinity, y2: -Infinity };
|
||||
|
||||
nodeLookup.forEach((node) => {
|
||||
if (params.filter == undefined || params.filter(node)) {
|
||||
if (params.filter === undefined || params.filter(node)) {
|
||||
const nodeBox = nodeToBox(node as InternalNodeBase);
|
||||
box = getBoundsOfBoxes(box, nodeBox);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user