refactor(react): init store with user nodeOrigin

This commit is contained in:
moklick
2024-06-27 17:01:01 +02:00
parent 15241b4fd0
commit aa0e131162
8 changed files with 27 additions and 11 deletions
@@ -4,6 +4,7 @@ import { Provider } from '../../contexts/StoreContext';
import { createStore } from '../../store'; import { createStore } from '../../store';
import { BatchProvider } from '../BatchProvider'; import { BatchProvider } from '../BatchProvider';
import type { Node, Edge } from '../../types'; import type { Node, Edge } from '../../types';
import { NodeOrigin } from '@xyflow/system';
export type ReactFlowProviderProps = { export type ReactFlowProviderProps = {
initialNodes?: Node[]; initialNodes?: Node[];
@@ -13,6 +14,7 @@ export type ReactFlowProviderProps = {
initialWidth?: number; initialWidth?: number;
initialHeight?: number; initialHeight?: number;
fitView?: boolean; fitView?: boolean;
nodeOrigin?: NodeOrigin;
children: ReactNode; children: ReactNode;
}; };
@@ -24,6 +26,7 @@ export function ReactFlowProvider({
initialWidth: width, initialWidth: width,
initialHeight: height, initialHeight: height,
fitView, fitView,
nodeOrigin,
children, children,
}: ReactFlowProviderProps) { }: ReactFlowProviderProps) {
const [store] = useState(() => const [store] = useState(() =>
@@ -35,6 +38,7 @@ export function ReactFlowProvider({
width, width,
height, height,
fitView, fitView,
nodeOrigin,
}) })
); );
@@ -3,6 +3,7 @@ import { useContext, type ReactNode } from 'react';
import StoreContext from '../../contexts/StoreContext'; import StoreContext from '../../contexts/StoreContext';
import { ReactFlowProvider } from '../../components/ReactFlowProvider'; import { ReactFlowProvider } from '../../components/ReactFlowProvider';
import type { Node, Edge } from '../../types'; import type { Node, Edge } from '../../types';
import { NodeOrigin } from '@xyflow/system';
export function Wrapper({ export function Wrapper({
children, children,
@@ -13,6 +14,7 @@ export function Wrapper({
width, width,
height, height,
fitView, fitView,
nodeOrigin,
}: { }: {
children: ReactNode; children: ReactNode;
nodes?: Node[]; nodes?: Node[];
@@ -22,6 +24,7 @@ export function Wrapper({
width?: number; width?: number;
height?: number; height?: number;
fitView?: boolean; fitView?: boolean;
nodeOrigin?: NodeOrigin;
}) { }) {
const isWrapped = useContext(StoreContext); const isWrapped = useContext(StoreContext);
@@ -40,6 +43,7 @@ export function Wrapper({
initialWidth={width} initialWidth={width}
initialHeight={height} initialHeight={height}
fitView={fitView} fitView={fitView}
nodeOrigin={nodeOrigin}
> >
{children} {children}
</ReactFlowProvider> </ReactFlowProvider>
@@ -157,7 +157,7 @@ function ReactFlow<NodeType extends Node = Node, EdgeType extends Edge = Edge>(
data-testid="rf__wrapper" data-testid="rf__wrapper"
id={id} 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> <GraphView<NodeType, EdgeType>
onInit={onInit} onInit={onInit}
onNodeClick={onNodeClick} onNodeClick={onNodeClick}
+4 -1
View File
@@ -12,6 +12,7 @@ import {
EdgeSelectionChange, EdgeSelectionChange,
NodeSelectionChange, NodeSelectionChange,
ParentExpandChild, ParentExpandChild,
NodeOrigin,
} from '@xyflow/system'; } from '@xyflow/system';
import { applyEdgeChanges, applyNodeChanges, createSelectionChange, getSelectionChanges } from '../utils/changes'; import { applyEdgeChanges, applyNodeChanges, createSelectionChange, getSelectionChanges } from '../utils/changes';
@@ -26,6 +27,7 @@ const createStore = ({
width, width,
height, height,
fitView, fitView,
nodeOrigin,
}: { }: {
nodes?: Node[]; nodes?: Node[];
edges?: Edge[]; edges?: Edge[];
@@ -34,10 +36,11 @@ const createStore = ({
width?: number; width?: number;
height?: number; height?: number;
fitView?: boolean; fitView?: boolean;
nodeOrigin?: NodeOrigin;
}) => }) =>
createWithEqualityFn<ReactFlowState>( createWithEqualityFn<ReactFlowState>(
(set, get) => ({ (set, get) => ({
...getInitialState({ nodes, edges, width, height, fitView, defaultNodes, defaultEdges }), ...getInitialState({ nodes, edges, width, height, fitView, nodeOrigin, defaultNodes, defaultEdges }),
setNodes: (nodes: Node[]) => { setNodes: (nodes: Node[]) => {
const { nodeLookup, parentLookup, nodeOrigin, elevateNodesOnSelect } = get(); const { nodeLookup, parentLookup, nodeOrigin, elevateNodesOnSelect } = get();
// setNodes() is called exclusively in response to user actions: // setNodes() is called exclusively in response to user actions:
+7 -3
View File
@@ -7,6 +7,7 @@ import {
updateConnectionLookup, updateConnectionLookup,
devWarn, devWarn,
getInternalNodesBounds, getInternalNodesBounds,
NodeOrigin,
} from '@xyflow/system'; } from '@xyflow/system';
import type { Edge, InternalNode, Node, ReactFlowStore } from '../types'; import type { Edge, InternalNode, Node, ReactFlowStore } from '../types';
@@ -19,6 +20,7 @@ const getInitialState = ({
width, width,
height, height,
fitView, fitView,
nodeOrigin,
}: { }: {
nodes?: Node[]; nodes?: Node[];
edges?: Edge[]; edges?: Edge[];
@@ -27,6 +29,7 @@ const getInitialState = ({
width?: number; width?: number;
height?: number; height?: number;
fitView?: boolean; fitView?: boolean;
nodeOrigin?: NodeOrigin;
} = {}): ReactFlowStore => { } = {}): ReactFlowStore => {
const nodeLookup = new Map<string, InternalNode>(); const nodeLookup = new Map<string, InternalNode>();
const parentLookup = new Map(); const parentLookup = new Map();
@@ -34,20 +37,21 @@ const getInitialState = ({
const edgeLookup = new Map(); const edgeLookup = new Map();
const storeEdges = defaultEdges ?? edges ?? []; const storeEdges = defaultEdges ?? edges ?? [];
const storeNodes = defaultNodes ?? nodes ?? []; const storeNodes = defaultNodes ?? nodes ?? [];
const storeNodeOrigin = nodeOrigin ?? [0, 0];
updateConnectionLookup(connectionLookup, edgeLookup, storeEdges); updateConnectionLookup(connectionLookup, edgeLookup, storeEdges);
adoptUserNodes(storeNodes, nodeLookup, parentLookup, { adoptUserNodes(storeNodes, nodeLookup, parentLookup, {
nodeOrigin: [0, 0], nodeOrigin: storeNodeOrigin,
elevateNodesOnSelect: false, elevateNodesOnSelect: false,
}); });
let transform: Transform = [0, 0, 1]; let transform: Transform = [0, 0, 1];
if (fitView && width && height) { if (fitView && width && height) {
// @todo users nodeOrigin should be used here
const bounds = getInternalNodesBounds(nodeLookup, { const bounds = getInternalNodesBounds(nodeLookup, {
filter: (node) => !!((node.width || node.initialWidth) && (node.height || node.initialHeight)), filter: (node) => !!((node.width || node.initialWidth) && (node.height || node.initialHeight)),
}); });
const { x, y, zoom } = getViewportForBounds(bounds, width, height, 0.5, 2, 0.1); const { x, y, zoom } = getViewportForBounds(bounds, width, height, 0.5, 2, 0.1);
transform = [x, y, zoom]; transform = [x, y, zoom];
} }
@@ -81,7 +85,7 @@ const getInitialState = ({
domNode: null, domNode: null,
paneDragging: false, paneDragging: false,
noPanClassName: 'nopan', noPanClassName: 'nopan',
nodeOrigin: [0, 0], nodeOrigin: storeNodeOrigin,
nodeDragThreshold: 1, nodeDragThreshold: 1,
snapGrid: [15, 15], snapGrid: [15, 15],
+2 -1
View File
@@ -27,6 +27,7 @@ import {
type NodeLookup, type NodeLookup,
NodeChange, NodeChange,
EdgeChange, EdgeChange,
ParentLookup,
} from '@xyflow/system'; } from '@xyflow/system';
import type { import type {
@@ -54,7 +55,7 @@ export type ReactFlowStore<NodeType extends Node = Node, EdgeType extends Edge =
transform: Transform; transform: Transform;
nodes: NodeType[]; nodes: NodeType[];
nodeLookup: NodeLookup<InternalNode<NodeType>>; nodeLookup: NodeLookup<InternalNode<NodeType>>;
parentLookup: Map<string, Map<string, InternalNode<NodeType>>>; parentLookup: ParentLookup<InternalNode<NodeType>>;
edges: Edge[]; edges: Edge[];
edgeLookup: EdgeLookup<EdgeType>; edgeLookup: EdgeLookup<EdgeType>;
connectionLookup: ConnectionLookup; connectionLookup: ConnectionLookup;
+4 -4
View File
@@ -75,8 +75,8 @@ export const nodeToRect = (node: InternalNodeBase | NodeBase, nodeOrigin: NodeOr
return { return {
x, x,
y, y,
width: node.measured?.width ?? node.width ?? 0, width: node.measured?.width ?? node.width ?? node.initialWidth ?? 0,
height: node.measured?.height ?? node.height ?? 0, height: node.measured?.height ?? node.height ?? node.initialHeight ?? 0,
}; };
}; };
@@ -88,8 +88,8 @@ export const nodeToBox = (node: InternalNodeBase | NodeBase, nodeOrigin: NodeOri
return { return {
x, x,
y, y,
x2: x + (node.measured?.width ?? node.width ?? 0), x2: x + (node.measured?.width ?? node.width ?? node.initialWidth ?? 0),
y2: y + (node.measured?.height ?? node.height ?? 0), y2: y + (node.measured?.height ?? node.height ?? node.initialHeight ?? 0),
}; };
}; };
+1 -1
View File
@@ -166,7 +166,7 @@ export const getInternalNodesBounds = <NodeType extends InternalNodeBase | NodeD
let box = { x: Infinity, y: Infinity, x2: -Infinity, y2: -Infinity }; let box = { x: Infinity, y: Infinity, x2: -Infinity, y2: -Infinity };
nodeLookup.forEach((node) => { nodeLookup.forEach((node) => {
if (params.filter == undefined || params.filter(node)) { if (params.filter === undefined || params.filter(node)) {
const nodeBox = nodeToBox(node as InternalNodeBase); const nodeBox = nodeToBox(node as InternalNodeBase);
box = getBoundsOfBoxes(box, nodeBox); box = getBoundsOfBoxes(box, nodeBox);
} }