@xyflow/react 12.0.0-next.8 → 12.0.0-next.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/base.css +19 -1
- package/dist/esm/additional-components/MiniMap/MiniMap.d.ts +1 -1
- package/dist/esm/additional-components/MiniMap/MiniMap.d.ts.map +1 -1
- package/dist/esm/additional-components/MiniMap/types.d.ts +2 -0
- package/dist/esm/additional-components/MiniMap/types.d.ts.map +1 -1
- package/dist/esm/additional-components/NodeResizer/NodeResizeControl.d.ts.map +1 -1
- package/dist/esm/components/NodeWrapper/index.d.ts.map +1 -1
- package/dist/esm/components/NodesSelection/index.d.ts.map +1 -1
- package/dist/esm/components/ReactFlowProvider/index.d.ts +3 -1
- package/dist/esm/components/ReactFlowProvider/index.d.ts.map +1 -1
- package/dist/esm/components/StoreUpdater/index.d.ts.map +1 -1
- package/dist/esm/container/GraphView/index.d.ts +1 -1
- package/dist/esm/container/GraphView/index.d.ts.map +1 -1
- package/dist/esm/container/ReactFlow/Wrapper.d.ts +3 -1
- package/dist/esm/container/ReactFlow/Wrapper.d.ts.map +1 -1
- package/dist/esm/container/ReactFlow/index.d.ts +0 -2
- package/dist/esm/container/ReactFlow/index.d.ts.map +1 -1
- package/dist/esm/container/ReactFlow/init-values.d.ts +4 -0
- package/dist/esm/container/ReactFlow/init-values.d.ts.map +1 -0
- package/dist/esm/hooks/useHandleConnections.d.ts +3 -3
- package/dist/esm/hooks/useHandleConnections.d.ts.map +1 -1
- package/dist/esm/hooks/useKeyPress.d.ts.map +1 -1
- package/dist/esm/hooks/useMoveSelectedNodes.d.ts +12 -0
- package/dist/esm/hooks/useMoveSelectedNodes.d.ts.map +1 -0
- package/dist/esm/hooks/useReactFlow.d.ts.map +1 -1
- package/dist/esm/hooks/useUpdateNodePositions.d.ts.map +1 -1
- package/dist/esm/index.js +217 -241
- package/dist/esm/index.mjs +217 -241
- package/dist/esm/store/index.d.ts +3 -1
- package/dist/esm/store/index.d.ts.map +1 -1
- package/dist/esm/store/initialState.d.ts +3 -1
- package/dist/esm/store/initialState.d.ts.map +1 -1
- package/dist/esm/types/component-props.d.ts +2 -2
- package/dist/esm/types/store.d.ts +4 -3
- package/dist/esm/types/store.d.ts.map +1 -1
- package/dist/esm/utils/changes.d.ts +1 -1
- package/dist/esm/utils/changes.d.ts.map +1 -1
- package/dist/style.css +19 -1
- package/dist/umd/additional-components/MiniMap/MiniMap.d.ts +1 -1
- package/dist/umd/additional-components/MiniMap/MiniMap.d.ts.map +1 -1
- package/dist/umd/additional-components/MiniMap/types.d.ts +2 -0
- package/dist/umd/additional-components/MiniMap/types.d.ts.map +1 -1
- package/dist/umd/additional-components/NodeResizer/NodeResizeControl.d.ts.map +1 -1
- package/dist/umd/components/NodeWrapper/index.d.ts.map +1 -1
- package/dist/umd/components/NodesSelection/index.d.ts.map +1 -1
- package/dist/umd/components/ReactFlowProvider/index.d.ts +3 -1
- package/dist/umd/components/ReactFlowProvider/index.d.ts.map +1 -1
- package/dist/umd/components/StoreUpdater/index.d.ts.map +1 -1
- package/dist/umd/container/GraphView/index.d.ts +1 -1
- package/dist/umd/container/GraphView/index.d.ts.map +1 -1
- package/dist/umd/container/ReactFlow/Wrapper.d.ts +3 -1
- package/dist/umd/container/ReactFlow/Wrapper.d.ts.map +1 -1
- package/dist/umd/container/ReactFlow/index.d.ts +0 -2
- package/dist/umd/container/ReactFlow/index.d.ts.map +1 -1
- package/dist/umd/container/ReactFlow/init-values.d.ts +4 -0
- package/dist/umd/container/ReactFlow/init-values.d.ts.map +1 -0
- package/dist/umd/hooks/useHandleConnections.d.ts +3 -3
- package/dist/umd/hooks/useHandleConnections.d.ts.map +1 -1
- package/dist/umd/hooks/useKeyPress.d.ts.map +1 -1
- package/dist/umd/hooks/useMoveSelectedNodes.d.ts +12 -0
- package/dist/umd/hooks/useMoveSelectedNodes.d.ts.map +1 -0
- package/dist/umd/hooks/useReactFlow.d.ts.map +1 -1
- package/dist/umd/index.js +2 -2
- package/dist/umd/store/index.d.ts +3 -1
- package/dist/umd/store/index.d.ts.map +1 -1
- package/dist/umd/store/initialState.d.ts +3 -1
- package/dist/umd/store/initialState.d.ts.map +1 -1
- package/dist/umd/types/component-props.d.ts +2 -2
- package/dist/umd/types/store.d.ts +4 -3
- package/dist/umd/types/store.d.ts.map +1 -1
- package/dist/umd/utils/changes.d.ts +1 -1
- package/dist/umd/utils/changes.d.ts.map +1 -1
- package/package.json +4 -4
package/dist/esm/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
3
|
-
import { createContext, useContext, useMemo, useEffect, useRef, useState, useCallback, forwardRef, memo } from 'react';
|
|
3
|
+
import { createContext, useContext, useMemo, useEffect, useRef, useState, useCallback, useLayoutEffect, forwardRef, memo } from 'react';
|
|
4
4
|
import cc from 'classcat';
|
|
5
5
|
import { errorMessages, infiniteExtent, isInputDOMNode, fitView, getViewportForBounds, pointToRendererPoint, rendererPointToPoint, isNodeBase, isEdgeBase, getElementsToRemove, isRectObject, nodeToRect, getOverlappingArea, getDimensions, XYPanZoom, PanOnScrollMode, SelectionMode, getEventPosition, getNodesInside, XYDrag, snapPosition, calculateNodePosition, Position, isMouseEvent, XYHandle, getHostForElement, addEdge, getNodesBounds, clampPosition, internalsSymbol, getPositionWithOrigin, elementSelectionKeys, isEdgeVisible, MarkerType, createMarkerIds, isNumeric, getBezierEdgeCenter, getSmoothStepPath, getStraightPath, getBezierPath, getEdgePosition, getElevatedEdgeZIndex, getMarkerId, ConnectionMode, ConnectionLineType, updateConnectionLookup, adoptUserProvidedNodes, devWarn, updateNodeDimensions, updateAbsolutePositions, panBy, isMacOs, areConnectionMapsEqual, handleConnectionChange, getNodePositionWithOrigin, XYMinimap, getBoundsOfRects, ResizeControlVariant, XYResizer, XY_RESIZER_LINE_POSITIONS, XY_RESIZER_HANDLE_POSITIONS, getNodeToolbarTransform } from '@xyflow/system';
|
|
6
6
|
export { ConnectionLineType, ConnectionMode, MarkerType, PanOnScrollMode, Position, SelectionMode, addEdge, getBezierEdgeCenter, getBezierPath, getConnectedEdges, getEdgeCenter, getIncomers, getNodesBounds, getOutgoers, getSmoothStepPath, getStraightPath, getViewportForBounds, internalsSymbol, updateEdge } from '@xyflow/system';
|
|
@@ -106,6 +106,9 @@ function SelectionListener({ onSelectionChange }) {
|
|
|
106
106
|
return null;
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
+
const defaultNodeOrigin = [0, 0];
|
|
110
|
+
const defaultViewport = { x: 0, y: 0, zoom: 1 };
|
|
111
|
+
|
|
109
112
|
/*
|
|
110
113
|
* This component helps us to update the store with the vlues coming from the user.
|
|
111
114
|
* We distinguish between values we can update directly with `useDirectStoreUpdater` (like `snapGrid`)
|
|
@@ -171,35 +174,37 @@ const fieldsToTrack = [...reactFlowFieldsToTrack, 'rfId'];
|
|
|
171
174
|
const selector$n = (s) => ({
|
|
172
175
|
setNodes: s.setNodes,
|
|
173
176
|
setEdges: s.setEdges,
|
|
174
|
-
setDefaultNodesAndEdges: s.setDefaultNodesAndEdges,
|
|
175
177
|
setMinZoom: s.setMinZoom,
|
|
176
178
|
setMaxZoom: s.setMaxZoom,
|
|
177
179
|
setTranslateExtent: s.setTranslateExtent,
|
|
178
180
|
setNodeExtent: s.setNodeExtent,
|
|
179
181
|
reset: s.reset,
|
|
182
|
+
setDefaultNodesAndEdges: s.setDefaultNodesAndEdges,
|
|
180
183
|
});
|
|
184
|
+
const initPrevValues = {
|
|
185
|
+
// these are values that are also passed directly to other components
|
|
186
|
+
// than the StoreUpdater. We can reduce the number of setStore calls
|
|
187
|
+
// by setting the same values here as prev fields.
|
|
188
|
+
translateExtent: infiniteExtent,
|
|
189
|
+
nodeOrigin: defaultNodeOrigin,
|
|
190
|
+
minZoom: 0.5,
|
|
191
|
+
maxZoom: 2,
|
|
192
|
+
elementsSelectable: true,
|
|
193
|
+
noPanClassName: 'nopan',
|
|
194
|
+
rfId: '1',
|
|
195
|
+
};
|
|
181
196
|
function StoreUpdater(props) {
|
|
182
|
-
const { setNodes, setEdges,
|
|
197
|
+
const { setNodes, setEdges, setMinZoom, setMaxZoom, setTranslateExtent, setNodeExtent, reset, setDefaultNodesAndEdges, } = useStore(selector$n, shallow);
|
|
183
198
|
const store = useStoreApi();
|
|
184
199
|
useEffect(() => {
|
|
185
|
-
|
|
186
|
-
setDefaultNodesAndEdges(props.defaultNodes, edgesWithDefaults);
|
|
200
|
+
setDefaultNodesAndEdges(props.defaultNodes, props.defaultEdges);
|
|
187
201
|
return () => {
|
|
202
|
+
// when we reset the store we also need to reset the previous fields
|
|
203
|
+
previousFields.current = initPrevValues;
|
|
188
204
|
reset();
|
|
189
205
|
};
|
|
190
206
|
}, []);
|
|
191
|
-
const previousFields = useRef(
|
|
192
|
-
// these are values that are also passed directly to other components
|
|
193
|
-
// than the StoreUpdater. We can reduce the number of setStore calls
|
|
194
|
-
// by setting the same values here as prev fields.
|
|
195
|
-
translateExtent: infiniteExtent,
|
|
196
|
-
nodeOrigin: initNodeOrigin,
|
|
197
|
-
minZoom: 0.5,
|
|
198
|
-
maxZoom: 2,
|
|
199
|
-
elementsSelectable: true,
|
|
200
|
-
noPanClassName: 'nopan',
|
|
201
|
-
rfId: '1',
|
|
202
|
-
});
|
|
207
|
+
const previousFields = useRef(initPrevValues);
|
|
203
208
|
useEffect(() => {
|
|
204
209
|
for (const fieldName of fieldsToTrack) {
|
|
205
210
|
const fieldValue = props[fieldName];
|
|
@@ -333,6 +338,10 @@ keyCode = null, options = { target: defaultDoc, actInsideInputWithModifier: true
|
|
|
333
338
|
else {
|
|
334
339
|
pressedKeys.current.delete(event[keyOrCode]);
|
|
335
340
|
}
|
|
341
|
+
// fix for Mac: when cmd key is pressed, keyup is not triggered for any other key, see: https://stackoverflow.com/questions/27380018/when-cmd-key-is-kept-pressed-keyup-is-not-triggered-for-any-other-key
|
|
342
|
+
if (event.key === 'Meta') {
|
|
343
|
+
pressedKeys.current.clear();
|
|
344
|
+
}
|
|
336
345
|
modifierPressed.current = false;
|
|
337
346
|
};
|
|
338
347
|
const resetHandler = () => {
|
|
@@ -636,11 +645,13 @@ function applyNodeChanges(changes, nodes) {
|
|
|
636
645
|
function applyEdgeChanges(changes, edges) {
|
|
637
646
|
return applyChanges(changes, edges);
|
|
638
647
|
}
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
648
|
+
function createSelectionChange(id, selected) {
|
|
649
|
+
return {
|
|
650
|
+
id,
|
|
651
|
+
type: 'select',
|
|
652
|
+
selected,
|
|
653
|
+
};
|
|
654
|
+
}
|
|
644
655
|
function getSelectionChanges(items, selectedIds = new Set(), mutateItem = false) {
|
|
645
656
|
const changes = [];
|
|
646
657
|
for (const item of items) {
|
|
@@ -719,73 +730,86 @@ function useReactFlow() {
|
|
|
719
730
|
const { edges = [] } = store.getState();
|
|
720
731
|
return edges.find((e) => e.id === id);
|
|
721
732
|
}, []);
|
|
722
|
-
//
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
const
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
//
|
|
735
|
-
|
|
733
|
+
// A reference of all the batched updates to process before the next render. We
|
|
734
|
+
// want a mutable reference here so multiple synchronous calls to `setNodes` etc
|
|
735
|
+
// can be batched together.
|
|
736
|
+
const setElementsQueue = useRef({ nodes: [], edges: [] });
|
|
737
|
+
// Because we're using a ref above, we need some way to let React know when to
|
|
738
|
+
// actually process the queue. We flip this bit of state to `true` any time we
|
|
739
|
+
// mutate the queue and then flip it back to `false` after flushing the queue.
|
|
740
|
+
const [shouldFlushQueue, setShouldFlushQueue] = useState(false);
|
|
741
|
+
// Layout effects are guaranteed to run before the next render which means we
|
|
742
|
+
// shouldn't run into any issues with stale state or weird issues that come from
|
|
743
|
+
// rendering things one frame later than expected (we used to use `setTimeout`).
|
|
744
|
+
useLayoutEffect(() => {
|
|
745
|
+
// Because we need to flip the state back to false after flushing, this should
|
|
746
|
+
// trigger the hook again (!). If the hook is being run again we know that any
|
|
747
|
+
// updates should have been processed by now and we can safely clear the queue
|
|
748
|
+
// and bail early.
|
|
749
|
+
if (!shouldFlushQueue) {
|
|
750
|
+
setElementsQueue.current = { nodes: [], edges: [] };
|
|
751
|
+
return;
|
|
752
|
+
}
|
|
753
|
+
if (setElementsQueue.current.nodes.length) {
|
|
754
|
+
const { nodes = [], setNodes, hasDefaultNodes, onNodesChange, nodeLookup } = store.getState();
|
|
755
|
+
// This is essentially an `Array.reduce` in imperative clothing. Processing
|
|
756
|
+
// this queue is a relatively hot path so we'd like to avoid the overhead of
|
|
757
|
+
// array methods where we can.
|
|
758
|
+
let next = nodes;
|
|
759
|
+
for (const payload of setElementsQueue.current.nodes) {
|
|
760
|
+
next = typeof payload === 'function' ? payload(next) : payload;
|
|
761
|
+
}
|
|
736
762
|
if (hasDefaultNodes) {
|
|
737
|
-
setNodes(
|
|
763
|
+
setNodes(next);
|
|
738
764
|
}
|
|
739
765
|
else if (onNodesChange) {
|
|
740
|
-
|
|
741
|
-
|
|
766
|
+
onNodesChange(getElementsDiffChanges({
|
|
767
|
+
items: next,
|
|
768
|
+
lookup: nodeLookup,
|
|
769
|
+
}));
|
|
742
770
|
}
|
|
743
|
-
|
|
744
|
-
}, 0);
|
|
745
|
-
}, []);
|
|
746
|
-
// this is used to handle multiple syncronous setEdges calls
|
|
747
|
-
const setEdgesData = useRef();
|
|
748
|
-
const setEdgesTimeout = useRef();
|
|
749
|
-
const setEdges = useCallback((payload) => {
|
|
750
|
-
const { edges = [], setEdges, hasDefaultEdges, onEdgesChange, edgeLookup } = store.getState();
|
|
751
|
-
const nextEdges = typeof payload === 'function' ? payload(setEdgesData.current || edges) : payload;
|
|
752
|
-
setEdgesData.current = nextEdges;
|
|
753
|
-
if (setEdgesTimeout.current) {
|
|
754
|
-
clearTimeout(setEdgesTimeout.current);
|
|
771
|
+
setElementsQueue.current.nodes = [];
|
|
755
772
|
}
|
|
756
|
-
|
|
773
|
+
if (setElementsQueue.current.edges.length) {
|
|
774
|
+
const { edges = [], setEdges, hasDefaultEdges, onEdgesChange, edgeLookup } = store.getState();
|
|
775
|
+
let next = edges;
|
|
776
|
+
for (const payload of setElementsQueue.current.edges) {
|
|
777
|
+
next = typeof payload === 'function' ? payload(next) : payload;
|
|
778
|
+
}
|
|
757
779
|
if (hasDefaultEdges) {
|
|
758
|
-
setEdges(
|
|
780
|
+
setEdges(next);
|
|
759
781
|
}
|
|
760
782
|
else if (onEdgesChange) {
|
|
761
|
-
|
|
762
|
-
|
|
783
|
+
onEdgesChange(getElementsDiffChanges({
|
|
784
|
+
items: next,
|
|
785
|
+
lookup: edgeLookup,
|
|
786
|
+
}));
|
|
763
787
|
}
|
|
764
|
-
|
|
765
|
-
}
|
|
788
|
+
setElementsQueue.current.edges = [];
|
|
789
|
+
}
|
|
790
|
+
// Beacuse we're using reactive state to trigger this effect, we need to flip
|
|
791
|
+
// it back to false.
|
|
792
|
+
setShouldFlushQueue(false);
|
|
793
|
+
}, [shouldFlushQueue]);
|
|
794
|
+
const setNodes = useCallback((payload) => {
|
|
795
|
+
setElementsQueue.current.nodes.push(payload);
|
|
796
|
+
setShouldFlushQueue(true);
|
|
797
|
+
}, []);
|
|
798
|
+
const setEdges = useCallback((payload) => {
|
|
799
|
+
setElementsQueue.current.edges.push(payload);
|
|
800
|
+
setShouldFlushQueue(true);
|
|
766
801
|
}, []);
|
|
767
802
|
const addNodes = useCallback((payload) => {
|
|
768
|
-
const
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
}
|
|
774
|
-
else if (onNodesChange) {
|
|
775
|
-
const changes = nodes.map((node) => ({ item: node, type: 'add' }));
|
|
776
|
-
onNodesChange(changes);
|
|
777
|
-
}
|
|
803
|
+
const newNodes = Array.isArray(payload) ? payload : [payload];
|
|
804
|
+
// Queueing a functional update means that we won't worry about other calls
|
|
805
|
+
// to `setNodes` that might happen elsewhere.
|
|
806
|
+
setElementsQueue.current.nodes.push((nodes) => [...nodes, ...newNodes]);
|
|
807
|
+
setShouldFlushQueue(true);
|
|
778
808
|
}, []);
|
|
779
809
|
const addEdges = useCallback((payload) => {
|
|
780
|
-
const
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
setEdges([...edges, ...nextEdges]);
|
|
784
|
-
}
|
|
785
|
-
else if (onEdgesChange) {
|
|
786
|
-
const changes = nextEdges.map((edge) => ({ item: edge, type: 'add' }));
|
|
787
|
-
onEdgesChange(changes);
|
|
788
|
-
}
|
|
810
|
+
const newEdges = Array.isArray(payload) ? payload : [payload];
|
|
811
|
+
setElementsQueue.current.edges.push((edges) => [...edges, ...newEdges]);
|
|
812
|
+
setShouldFlushQueue(true);
|
|
789
813
|
}, []);
|
|
790
814
|
const toObject = useCallback(() => {
|
|
791
815
|
const { nodes = [], edges = [], transform } = store.getState();
|
|
@@ -1296,23 +1320,22 @@ function useDrag({ nodeRef, disabled = false, noDragClassName, handleSelector, n
|
|
|
1296
1320
|
|
|
1297
1321
|
const selectedAndDraggable = (nodesDraggable) => (n) => n.selected && (n.draggable || (nodesDraggable && typeof n.draggable === 'undefined'));
|
|
1298
1322
|
/**
|
|
1299
|
-
* Hook for updating node positions
|
|
1323
|
+
* Hook for updating node positions by passing a direction and factor
|
|
1300
1324
|
*
|
|
1301
1325
|
* @internal
|
|
1302
1326
|
* @returns function for updating node positions
|
|
1303
1327
|
*/
|
|
1304
|
-
function
|
|
1328
|
+
function useMoveSelectedNodes() {
|
|
1305
1329
|
const store = useStoreApi();
|
|
1306
|
-
const
|
|
1330
|
+
const moveSelectedNodes = useCallback((params) => {
|
|
1307
1331
|
const { nodeExtent, nodes, snapToGrid, snapGrid, nodesDraggable, onError, updateNodePositions, nodeLookup, nodeOrigin, } = store.getState();
|
|
1308
1332
|
const selectedNodes = nodes.filter(selectedAndDraggable(nodesDraggable));
|
|
1309
|
-
// by default a node moves 5px on each key press
|
|
1310
|
-
// if snap grid is enabled, we use that for the velocity
|
|
1333
|
+
// by default a node moves 5px on each key press
|
|
1334
|
+
// if snap grid is enabled, we use that for the velocity
|
|
1311
1335
|
const xVelo = snapToGrid ? snapGrid[0] : 5;
|
|
1312
1336
|
const yVelo = snapToGrid ? snapGrid[1] : 5;
|
|
1313
|
-
const
|
|
1314
|
-
const
|
|
1315
|
-
const yDiff = params.y * yVelo * factor;
|
|
1337
|
+
const xDiff = params.direction.x * xVelo * params.factor;
|
|
1338
|
+
const yDiff = params.direction.y * yVelo * params.factor;
|
|
1316
1339
|
const nodeUpdates = selectedNodes.map((node) => {
|
|
1317
1340
|
if (node.computed?.positionAbsolute) {
|
|
1318
1341
|
let nextPosition = {
|
|
@@ -1335,9 +1358,9 @@ function useUpdateNodePositions() {
|
|
|
1335
1358
|
}
|
|
1336
1359
|
return node;
|
|
1337
1360
|
});
|
|
1338
|
-
updateNodePositions(nodeUpdates
|
|
1361
|
+
updateNodePositions(nodeUpdates);
|
|
1339
1362
|
}, []);
|
|
1340
|
-
return
|
|
1363
|
+
return moveSelectedNodes;
|
|
1341
1364
|
}
|
|
1342
1365
|
|
|
1343
1366
|
const NodeIdContext = createContext(null);
|
|
@@ -1519,7 +1542,7 @@ const selector$h = (s) => {
|
|
|
1519
1542
|
function NodesSelection({ onSelectionContextMenu, noPanClassName, disableKeyboardA11y }) {
|
|
1520
1543
|
const store = useStoreApi();
|
|
1521
1544
|
const { width, height, transformString, userSelectionActive } = useStore(selector$h, shallow);
|
|
1522
|
-
const
|
|
1545
|
+
const moveSelectedNodes = useMoveSelectedNodes();
|
|
1523
1546
|
const nodeRef = useRef(null);
|
|
1524
1547
|
useEffect(() => {
|
|
1525
1548
|
if (!disableKeyboardA11y) {
|
|
@@ -1542,10 +1565,9 @@ function NodesSelection({ onSelectionContextMenu, noPanClassName, disableKeyboar
|
|
|
1542
1565
|
: undefined;
|
|
1543
1566
|
const onKeyDown = (event) => {
|
|
1544
1567
|
if (Object.prototype.hasOwnProperty.call(arrowKeyDiffs, event.key)) {
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
isShiftPressed: event.shiftKey,
|
|
1568
|
+
moveSelectedNodes({
|
|
1569
|
+
direction: arrowKeyDiffs[event.key],
|
|
1570
|
+
factor: event.shiftKey ? 4 : 1,
|
|
1549
1571
|
});
|
|
1550
1572
|
}
|
|
1551
1573
|
};
|
|
@@ -1653,14 +1675,29 @@ function NodeWrapper({ id, onClick, onMouseEnter, onMouseMove, onMouseLeave, onC
|
|
|
1653
1675
|
const prevSourcePosition = useRef(node.sourcePosition);
|
|
1654
1676
|
const prevTargetPosition = useRef(node.targetPosition);
|
|
1655
1677
|
const prevType = useRef(nodeType);
|
|
1656
|
-
const
|
|
1678
|
+
const width = node.width ?? undefined;
|
|
1679
|
+
const height = node.height ?? undefined;
|
|
1680
|
+
const computedWidth = node.computed?.width;
|
|
1681
|
+
const computedHeight = node.computed?.height;
|
|
1682
|
+
const initialized = (!!computedWidth && !!computedHeight) || (!!width && !!height);
|
|
1683
|
+
const hasHandleBounds = !!node[internalsSymbol]?.handleBounds;
|
|
1684
|
+
const moveSelectedNodes = useMoveSelectedNodes();
|
|
1685
|
+
useEffect(() => {
|
|
1686
|
+
return () => {
|
|
1687
|
+
if (nodeRef.current) {
|
|
1688
|
+
resizeObserver?.unobserve(nodeRef.current);
|
|
1689
|
+
}
|
|
1690
|
+
};
|
|
1691
|
+
}, []);
|
|
1657
1692
|
useEffect(() => {
|
|
1658
1693
|
if (nodeRef.current && !node.hidden) {
|
|
1659
1694
|
const currNode = nodeRef.current;
|
|
1660
|
-
|
|
1661
|
-
|
|
1695
|
+
if (!initialized || !hasHandleBounds) {
|
|
1696
|
+
resizeObserver?.unobserve(currNode);
|
|
1697
|
+
resizeObserver?.observe(currNode);
|
|
1698
|
+
}
|
|
1662
1699
|
}
|
|
1663
|
-
}, [node.hidden]);
|
|
1700
|
+
}, [node.hidden, initialized, hasHandleBounds]);
|
|
1664
1701
|
useEffect(() => {
|
|
1665
1702
|
// when the user programmatically changes the source or handle position, we re-initialize the node
|
|
1666
1703
|
const typeChanged = prevType.current !== nodeType;
|
|
@@ -1690,10 +1727,6 @@ function NodeWrapper({ id, onClick, onMouseEnter, onMouseMove, onMouseLeave, onC
|
|
|
1690
1727
|
if (node.hidden) {
|
|
1691
1728
|
return null;
|
|
1692
1729
|
}
|
|
1693
|
-
const width = node.width ?? undefined;
|
|
1694
|
-
const height = node.height ?? undefined;
|
|
1695
|
-
const computedWidth = node.computed?.width;
|
|
1696
|
-
const computedHeight = node.computed?.height;
|
|
1697
1730
|
const positionAbsoluteOrigin = getPositionWithOrigin({
|
|
1698
1731
|
x: positionAbsoluteX,
|
|
1699
1732
|
y: positionAbsoluteY,
|
|
@@ -1701,7 +1734,6 @@ function NodeWrapper({ id, onClick, onMouseEnter, onMouseMove, onMouseLeave, onC
|
|
|
1701
1734
|
height: computedHeight ?? height ?? 0,
|
|
1702
1735
|
origin: node.origin || nodeOrigin,
|
|
1703
1736
|
});
|
|
1704
|
-
const initialized = (!!computedWidth && !!computedHeight) || (!!width && !!height);
|
|
1705
1737
|
const hasPointerEvents = isSelectable || isDraggable || onClick || onMouseEnter || onMouseMove || onMouseLeave;
|
|
1706
1738
|
const onMouseEnterHandler = onMouseEnter ? (event) => onMouseEnter(event, { ...node }) : undefined;
|
|
1707
1739
|
const onMouseMoveHandler = onMouseMove ? (event) => onMouseMove(event, { ...node }) : undefined;
|
|
@@ -1745,10 +1777,9 @@ function NodeWrapper({ id, onClick, onMouseEnter, onMouseMove, onMouseLeave, onC
|
|
|
1745
1777
|
.replace('Arrow', '')
|
|
1746
1778
|
.toLowerCase()}. New position, x: ${~~positionAbsoluteX}, y: ${~~positionAbsoluteY}`,
|
|
1747
1779
|
});
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
isShiftPressed: event.shiftKey,
|
|
1780
|
+
moveSelectedNodes({
|
|
1781
|
+
direction: arrowKeyDiffs[event.key],
|
|
1782
|
+
factor: event.shiftKey ? 4 : 1,
|
|
1752
1783
|
});
|
|
1753
1784
|
}
|
|
1754
1785
|
};
|
|
@@ -2200,8 +2231,8 @@ function EdgeWrapper({ id, edgesFocusable, edgesUpdatable, elementsSelectable, o
|
|
|
2200
2231
|
...(edgePosition || nullPosition),
|
|
2201
2232
|
};
|
|
2202
2233
|
}, [edge.source, edge.target, edge.sourceHandle, edge.targetHandle, edge.selected, edge.zIndex]), shallow);
|
|
2203
|
-
const markerStartUrl = useMemo(() => (edge.markerStart ? `url(#${getMarkerId(edge.markerStart, rfId)})` : undefined), [edge.markerStart, rfId]);
|
|
2204
|
-
const markerEndUrl = useMemo(() => (edge.markerEnd ? `url(#${getMarkerId(edge.markerEnd, rfId)})` : undefined), [edge.markerEnd, rfId]);
|
|
2234
|
+
const markerStartUrl = useMemo(() => (edge.markerStart ? `url('#${getMarkerId(edge.markerStart, rfId)}')` : undefined), [edge.markerStart, rfId]);
|
|
2235
|
+
const markerEndUrl = useMemo(() => (edge.markerEnd ? `url('#${getMarkerId(edge.markerEnd, rfId)}')` : undefined), [edge.markerEnd, rfId]);
|
|
2205
2236
|
if (edge.hidden || !sourceX || !sourceY || !targetX || !targetY) {
|
|
2206
2237
|
return null;
|
|
2207
2238
|
}
|
|
@@ -2442,37 +2473,14 @@ function GraphViewComponent({ nodeTypes, edgeTypes, onInit, onNodeClick, onEdgeC
|
|
|
2442
2473
|
GraphViewComponent.displayName = 'GraphView';
|
|
2443
2474
|
const GraphView = memo(GraphViewComponent);
|
|
2444
2475
|
|
|
2445
|
-
|
|
2446
|
-
return items.map((item) => {
|
|
2447
|
-
const change = changes.find((change) => change.id === item.id);
|
|
2448
|
-
if (change) {
|
|
2449
|
-
item.selected = change.selected;
|
|
2450
|
-
}
|
|
2451
|
-
return item;
|
|
2452
|
-
});
|
|
2453
|
-
}
|
|
2454
|
-
function updateNodesAndEdgesSelections({ changedNodes, changedEdges, get, set }) {
|
|
2455
|
-
const { nodes, edges, onNodesChange, onEdgesChange, hasDefaultNodes, hasDefaultEdges } = get();
|
|
2456
|
-
if (changedNodes?.length) {
|
|
2457
|
-
if (hasDefaultNodes) {
|
|
2458
|
-
set({ nodes: handleControlledSelectionChange(changedNodes, nodes) });
|
|
2459
|
-
}
|
|
2460
|
-
onNodesChange?.(changedNodes);
|
|
2461
|
-
}
|
|
2462
|
-
if (changedEdges?.length) {
|
|
2463
|
-
if (hasDefaultEdges) {
|
|
2464
|
-
set({ edges: handleControlledSelectionChange(changedEdges, edges) });
|
|
2465
|
-
}
|
|
2466
|
-
onEdgesChange?.(changedEdges);
|
|
2467
|
-
}
|
|
2468
|
-
}
|
|
2469
|
-
|
|
2470
|
-
const getInitialState = ({ nodes = [], edges = [], width, height, fitView, } = {}) => {
|
|
2476
|
+
const getInitialState = ({ nodes, edges, defaultNodes, defaultEdges, width, height, fitView, } = {}) => {
|
|
2471
2477
|
const nodeLookup = new Map();
|
|
2472
2478
|
const connectionLookup = new Map();
|
|
2473
2479
|
const edgeLookup = new Map();
|
|
2474
|
-
|
|
2475
|
-
const
|
|
2480
|
+
const storeEdges = defaultEdges ?? edges ?? [];
|
|
2481
|
+
const storeNodes = defaultNodes ?? nodes ?? [];
|
|
2482
|
+
updateConnectionLookup(connectionLookup, edgeLookup, storeEdges);
|
|
2483
|
+
const nextNodes = adoptUserProvidedNodes(storeNodes, nodeLookup, {
|
|
2476
2484
|
nodeOrigin: [0, 0],
|
|
2477
2485
|
elevateNodesOnSelect: false,
|
|
2478
2486
|
});
|
|
@@ -2491,13 +2499,13 @@ const getInitialState = ({ nodes = [], edges = [], width, height, fitView, } = {
|
|
|
2491
2499
|
transform,
|
|
2492
2500
|
nodes: nextNodes,
|
|
2493
2501
|
nodeLookup,
|
|
2494
|
-
edges,
|
|
2502
|
+
edges: storeEdges,
|
|
2495
2503
|
edgeLookup,
|
|
2496
2504
|
connectionLookup,
|
|
2497
2505
|
onNodesChange: null,
|
|
2498
2506
|
onEdgesChange: null,
|
|
2499
|
-
hasDefaultNodes:
|
|
2500
|
-
hasDefaultEdges:
|
|
2507
|
+
hasDefaultNodes: defaultNodes !== undefined,
|
|
2508
|
+
hasDefaultEdges: defaultEdges !== undefined,
|
|
2501
2509
|
panZoom: null,
|
|
2502
2510
|
minZoom: 0.5,
|
|
2503
2511
|
maxZoom: 2,
|
|
@@ -2544,8 +2552,8 @@ const getInitialState = ({ nodes = [], edges = [], width, height, fitView, } = {
|
|
|
2544
2552
|
};
|
|
2545
2553
|
};
|
|
2546
2554
|
|
|
2547
|
-
const createRFStore = ({ nodes, edges, width, height, fitView: fitView$1, }) => createWithEqualityFn((set, get) => ({
|
|
2548
|
-
...getInitialState({ nodes, edges, width, height, fitView: fitView$1 }),
|
|
2555
|
+
const createRFStore = ({ nodes, edges, defaultNodes, defaultEdges, width, height, fitView: fitView$1, }) => createWithEqualityFn((set, get) => ({
|
|
2556
|
+
...getInitialState({ nodes, edges, width, height, fitView: fitView$1, defaultNodes, defaultEdges }),
|
|
2549
2557
|
setNodes: (nodes) => {
|
|
2550
2558
|
const { nodeLookup, nodeOrigin, elevateNodesOnSelect } = get();
|
|
2551
2559
|
// setNodes() is called exclusively in response to user actions:
|
|
@@ -2554,7 +2562,6 @@ const createRFStore = ({ nodes, edges, width, height, fitView: fitView$1, }) =>
|
|
|
2554
2562
|
//
|
|
2555
2563
|
// When this happens, we take the note objects passed by the user and extend them with fields
|
|
2556
2564
|
// relevant for internal React Flow operations.
|
|
2557
|
-
// TODO: consider updating the types to reflect the distinction between user-provided nodes and internal nodes.
|
|
2558
2565
|
const nodesWithInternalData = adoptUserProvidedNodes(nodes, nodeLookup, { nodeOrigin, elevateNodesOnSelect });
|
|
2559
2566
|
set({ nodes: nodesWithInternalData });
|
|
2560
2567
|
},
|
|
@@ -2563,28 +2570,17 @@ const createRFStore = ({ nodes, edges, width, height, fitView: fitView$1, }) =>
|
|
|
2563
2570
|
updateConnectionLookup(connectionLookup, edgeLookup, edges);
|
|
2564
2571
|
set({ edges });
|
|
2565
2572
|
},
|
|
2566
|
-
// when the user works with an uncontrolled flow,
|
|
2567
|
-
// we set a flag `hasDefaultNodes` / `hasDefaultEdges`
|
|
2568
2573
|
setDefaultNodesAndEdges: (nodes, edges) => {
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
hasDefaultNodes
|
|
2573
|
-
hasDefaultEdges,
|
|
2574
|
-
};
|
|
2575
|
-
if (hasDefaultNodes) {
|
|
2576
|
-
const { nodeLookup, nodeOrigin, elevateNodesOnSelect } = get();
|
|
2577
|
-
nextState.nodes = adoptUserProvidedNodes(nodes, nodeLookup, {
|
|
2578
|
-
nodeOrigin,
|
|
2579
|
-
elevateNodesOnSelect,
|
|
2580
|
-
});
|
|
2574
|
+
if (nodes) {
|
|
2575
|
+
const { setNodes } = get();
|
|
2576
|
+
setNodes(nodes);
|
|
2577
|
+
set({ hasDefaultNodes: true });
|
|
2581
2578
|
}
|
|
2582
|
-
if (
|
|
2583
|
-
const {
|
|
2584
|
-
|
|
2585
|
-
|
|
2579
|
+
if (edges) {
|
|
2580
|
+
const { setEdges } = get();
|
|
2581
|
+
setEdges(edges);
|
|
2582
|
+
set({ hasDefaultEdges: true });
|
|
2586
2583
|
}
|
|
2587
|
-
set(nextState);
|
|
2588
2584
|
},
|
|
2589
2585
|
// Every node gets registerd at a ResizeObserver. Whenever a node
|
|
2590
2586
|
// changes its dimensions, this function is called to measure the
|
|
@@ -2621,86 +2617,70 @@ const createRFStore = ({ nodes, edges, width, height, fitView: fitView$1, }) =>
|
|
|
2621
2617
|
onNodesChange?.(changes);
|
|
2622
2618
|
}
|
|
2623
2619
|
},
|
|
2624
|
-
updateNodePositions: (nodeDragItems,
|
|
2620
|
+
updateNodePositions: (nodeDragItems, dragging = false) => {
|
|
2625
2621
|
const changes = nodeDragItems.map((node) => {
|
|
2626
2622
|
const change = {
|
|
2627
2623
|
id: node.id,
|
|
2628
2624
|
type: 'position',
|
|
2625
|
+
position: node.position,
|
|
2626
|
+
positionAbsolute: node.computed?.positionAbsolute,
|
|
2629
2627
|
dragging,
|
|
2630
2628
|
};
|
|
2631
|
-
if (positionChanged) {
|
|
2632
|
-
change.positionAbsolute = node.computed?.positionAbsolute;
|
|
2633
|
-
change.position = node.position;
|
|
2634
|
-
}
|
|
2635
2629
|
return change;
|
|
2636
2630
|
});
|
|
2637
2631
|
get().triggerNodeChanges(changes);
|
|
2638
2632
|
},
|
|
2639
2633
|
triggerNodeChanges: (changes) => {
|
|
2640
|
-
const { onNodesChange,
|
|
2634
|
+
const { onNodesChange, setNodes, nodes, hasDefaultNodes } = get();
|
|
2641
2635
|
if (changes?.length) {
|
|
2642
2636
|
if (hasDefaultNodes) {
|
|
2643
2637
|
const updatedNodes = applyNodeChanges(changes, nodes);
|
|
2644
|
-
|
|
2645
|
-
nodeOrigin,
|
|
2646
|
-
elevateNodesOnSelect,
|
|
2647
|
-
});
|
|
2648
|
-
set({ nodes: nextNodes });
|
|
2638
|
+
setNodes(updatedNodes);
|
|
2649
2639
|
}
|
|
2650
2640
|
onNodesChange?.(changes);
|
|
2651
2641
|
}
|
|
2652
2642
|
},
|
|
2643
|
+
triggerEdgeChanges: (changes) => {
|
|
2644
|
+
const { onEdgesChange, setEdges, edges, hasDefaultEdges } = get();
|
|
2645
|
+
if (changes?.length) {
|
|
2646
|
+
if (hasDefaultEdges) {
|
|
2647
|
+
const updatedEdges = applyEdgeChanges(changes, edges);
|
|
2648
|
+
setEdges(updatedEdges);
|
|
2649
|
+
}
|
|
2650
|
+
onEdgesChange?.(changes);
|
|
2651
|
+
}
|
|
2652
|
+
},
|
|
2653
2653
|
addSelectedNodes: (selectedNodeIds) => {
|
|
2654
|
-
const { multiSelectionActive, edges, nodes } = get();
|
|
2655
|
-
let changedNodes;
|
|
2656
|
-
let changedEdges = null;
|
|
2654
|
+
const { multiSelectionActive, edges, nodes, triggerNodeChanges, triggerEdgeChanges } = get();
|
|
2657
2655
|
if (multiSelectionActive) {
|
|
2658
|
-
|
|
2656
|
+
const nodeChanges = selectedNodeIds.map((nodeId) => createSelectionChange(nodeId, true));
|
|
2657
|
+
triggerNodeChanges(nodeChanges);
|
|
2658
|
+
return;
|
|
2659
2659
|
}
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
changedEdges = getSelectionChanges(edges);
|
|
2663
|
-
}
|
|
2664
|
-
updateNodesAndEdgesSelections({
|
|
2665
|
-
changedNodes,
|
|
2666
|
-
changedEdges,
|
|
2667
|
-
get,
|
|
2668
|
-
set,
|
|
2669
|
-
});
|
|
2660
|
+
triggerNodeChanges(getSelectionChanges(nodes, new Set([...selectedNodeIds]), true));
|
|
2661
|
+
triggerEdgeChanges(getSelectionChanges(edges));
|
|
2670
2662
|
},
|
|
2671
2663
|
addSelectedEdges: (selectedEdgeIds) => {
|
|
2672
|
-
const { multiSelectionActive, edges, nodes } = get();
|
|
2673
|
-
let changedEdges;
|
|
2674
|
-
let changedNodes = null;
|
|
2664
|
+
const { multiSelectionActive, edges, nodes, triggerNodeChanges, triggerEdgeChanges } = get();
|
|
2675
2665
|
if (multiSelectionActive) {
|
|
2676
|
-
changedEdges = selectedEdgeIds.map((edgeId) => createSelectionChange(edgeId, true));
|
|
2666
|
+
const changedEdges = selectedEdgeIds.map((edgeId) => createSelectionChange(edgeId, true));
|
|
2667
|
+
triggerEdgeChanges(changedEdges);
|
|
2668
|
+
return;
|
|
2677
2669
|
}
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
changedNodes = getSelectionChanges(nodes, new Set(), true);
|
|
2681
|
-
}
|
|
2682
|
-
updateNodesAndEdgesSelections({
|
|
2683
|
-
changedNodes,
|
|
2684
|
-
changedEdges,
|
|
2685
|
-
get,
|
|
2686
|
-
set,
|
|
2687
|
-
});
|
|
2670
|
+
triggerEdgeChanges(getSelectionChanges(edges, new Set([...selectedEdgeIds])));
|
|
2671
|
+
triggerNodeChanges(getSelectionChanges(nodes, new Set(), true));
|
|
2688
2672
|
},
|
|
2689
2673
|
unselectNodesAndEdges: ({ nodes, edges } = {}) => {
|
|
2690
|
-
const { edges: storeEdges, nodes: storeNodes } = get();
|
|
2674
|
+
const { edges: storeEdges, nodes: storeNodes, triggerNodeChanges, triggerEdgeChanges } = get();
|
|
2691
2675
|
const nodesToUnselect = nodes ? nodes : storeNodes;
|
|
2692
2676
|
const edgesToUnselect = edges ? edges : storeEdges;
|
|
2693
|
-
const
|
|
2677
|
+
const nodeChanges = nodesToUnselect.map((n) => {
|
|
2694
2678
|
n.selected = false;
|
|
2695
2679
|
return createSelectionChange(n.id, false);
|
|
2696
2680
|
});
|
|
2697
|
-
const
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
changedEdges,
|
|
2701
|
-
get,
|
|
2702
|
-
set,
|
|
2703
|
-
});
|
|
2681
|
+
const edgeChanges = edgesToUnselect.map((edge) => createSelectionChange(edge.id, false));
|
|
2682
|
+
triggerNodeChanges(nodeChanges);
|
|
2683
|
+
triggerEdgeChanges(edgeChanges);
|
|
2704
2684
|
},
|
|
2705
2685
|
setMinZoom: (minZoom) => {
|
|
2706
2686
|
const { panZoom, maxZoom } = get();
|
|
@@ -2717,19 +2697,11 @@ const createRFStore = ({ nodes, edges, width, height, fitView: fitView$1, }) =>
|
|
|
2717
2697
|
set({ translateExtent });
|
|
2718
2698
|
},
|
|
2719
2699
|
resetSelectedElements: () => {
|
|
2720
|
-
const { edges, nodes } = get();
|
|
2721
|
-
const
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
.filter((e) => e.selected)
|
|
2726
|
-
.map((e) => createSelectionChange(e.id, false));
|
|
2727
|
-
updateNodesAndEdgesSelections({
|
|
2728
|
-
changedNodes: nodesToUnselect,
|
|
2729
|
-
changedEdges: edgesToUnselect,
|
|
2730
|
-
get,
|
|
2731
|
-
set,
|
|
2732
|
-
});
|
|
2700
|
+
const { edges, nodes, triggerNodeChanges, triggerEdgeChanges } = get();
|
|
2701
|
+
const nodeChanges = nodes.reduce((res, node) => (node.selected ? [...res, createSelectionChange(node.id, false)] : res), []);
|
|
2702
|
+
const edgeChanges = edges.reduce((res, edge) => (edge.selected ? [...res, createSelectionChange(edge.id, false)] : res), []);
|
|
2703
|
+
triggerNodeChanges(nodeChanges);
|
|
2704
|
+
triggerEdgeChanges(edgeChanges);
|
|
2733
2705
|
},
|
|
2734
2706
|
setNodeExtent: (nodeExtent) => {
|
|
2735
2707
|
const { nodes } = get();
|
|
@@ -2781,21 +2753,17 @@ const createRFStore = ({ nodes, edges, width, height, fitView: fitView$1, }) =>
|
|
|
2781
2753
|
};
|
|
2782
2754
|
set(currentConnection);
|
|
2783
2755
|
},
|
|
2784
|
-
reset: () => {
|
|
2785
|
-
// @todo: what should we do about this? Do we still need it?
|
|
2786
|
-
// if you are on a SPA with multiple flows, we want to make sure that the store gets resetted
|
|
2787
|
-
// when you switch pages. Does this reset solves this? Currently it always gets called. This
|
|
2788
|
-
// leads to an emtpy nodes array at the beginning.
|
|
2789
|
-
// set({ ...getInitialState() });
|
|
2790
|
-
},
|
|
2756
|
+
reset: () => set({ ...getInitialState() }),
|
|
2791
2757
|
}), Object.is);
|
|
2792
2758
|
|
|
2793
|
-
function ReactFlowProvider({ children, initialNodes, initialEdges, initialWidth, initialHeight, fitView, }) {
|
|
2759
|
+
function ReactFlowProvider({ children, initialNodes, initialEdges, defaultNodes, defaultEdges, initialWidth, initialHeight, fitView, }) {
|
|
2794
2760
|
const storeRef = useRef(null);
|
|
2795
2761
|
if (!storeRef.current) {
|
|
2796
2762
|
storeRef.current = createRFStore({
|
|
2797
2763
|
nodes: initialNodes,
|
|
2798
2764
|
edges: initialEdges,
|
|
2765
|
+
defaultNodes,
|
|
2766
|
+
defaultEdges,
|
|
2799
2767
|
width: initialWidth,
|
|
2800
2768
|
height: initialHeight,
|
|
2801
2769
|
fitView,
|
|
@@ -2804,18 +2772,16 @@ function ReactFlowProvider({ children, initialNodes, initialEdges, initialWidth,
|
|
|
2804
2772
|
return jsx(Provider$1, { value: storeRef.current, children: children });
|
|
2805
2773
|
}
|
|
2806
2774
|
|
|
2807
|
-
function Wrapper({ children, nodes, edges, width, height, fitView, }) {
|
|
2775
|
+
function Wrapper({ children, nodes, edges, defaultNodes, defaultEdges, width, height, fitView, }) {
|
|
2808
2776
|
const isWrapped = useContext(StoreContext);
|
|
2809
2777
|
if (isWrapped) {
|
|
2810
2778
|
// we need to wrap it with a fragment because it's not allowed for children to be a ReactNode
|
|
2811
2779
|
// https://github.com/DefinitelyTyped/DefinitelyTyped/issues/18051
|
|
2812
2780
|
return jsx(Fragment, { children: children });
|
|
2813
2781
|
}
|
|
2814
|
-
return (jsx(ReactFlowProvider, { initialNodes: nodes, initialEdges: edges, initialWidth: width, initialHeight: height, fitView: fitView, children: children }));
|
|
2782
|
+
return (jsx(ReactFlowProvider, { initialNodes: nodes, initialEdges: edges, defaultNodes: defaultNodes, defaultEdges: defaultEdges, initialWidth: width, initialHeight: height, fitView: fitView, children: children }));
|
|
2815
2783
|
}
|
|
2816
2784
|
|
|
2817
|
-
const initNodeOrigin = [0, 0];
|
|
2818
|
-
const initDefaultViewport = { x: 0, y: 0, zoom: 1 };
|
|
2819
2785
|
const wrapperStyle = {
|
|
2820
2786
|
width: '100%',
|
|
2821
2787
|
height: '100%',
|
|
@@ -2823,10 +2789,10 @@ const wrapperStyle = {
|
|
|
2823
2789
|
position: 'relative',
|
|
2824
2790
|
zIndex: 0,
|
|
2825
2791
|
};
|
|
2826
|
-
const ReactFlow = forwardRef(({ nodes, edges, defaultNodes, defaultEdges, className, nodeTypes, edgeTypes, onNodeClick, onEdgeClick, onInit, onMove, onMoveStart, onMoveEnd, onConnect, onConnectStart, onConnectEnd, onClickConnectStart, onClickConnectEnd, onNodeMouseEnter, onNodeMouseMove, onNodeMouseLeave, onNodeContextMenu, onNodeDoubleClick, onNodeDragStart, onNodeDrag, onNodeDragStop, onNodesDelete, onEdgesDelete, onDelete, onSelectionChange, onSelectionDragStart, onSelectionDrag, onSelectionDragStop, onSelectionContextMenu, onSelectionStart, onSelectionEnd, onBeforeDelete, connectionMode, connectionLineType = ConnectionLineType.Bezier, connectionLineStyle, connectionLineComponent, connectionLineContainerStyle, deleteKeyCode = 'Backspace', selectionKeyCode = 'Shift', selectionOnDrag = false, selectionMode = SelectionMode.Full, panActivationKeyCode = 'Space', multiSelectionKeyCode = isMacOs() ? 'Meta' : 'Control', zoomActivationKeyCode = isMacOs() ? 'Meta' : 'Control', snapToGrid, snapGrid, onlyRenderVisibleElements = false, selectNodesOnDrag, nodesDraggable, nodesConnectable, nodesFocusable, nodeOrigin =
|
|
2792
|
+
const ReactFlow = forwardRef(({ nodes, edges, defaultNodes, defaultEdges, className, nodeTypes, edgeTypes, onNodeClick, onEdgeClick, onInit, onMove, onMoveStart, onMoveEnd, onConnect, onConnectStart, onConnectEnd, onClickConnectStart, onClickConnectEnd, onNodeMouseEnter, onNodeMouseMove, onNodeMouseLeave, onNodeContextMenu, onNodeDoubleClick, onNodeDragStart, onNodeDrag, onNodeDragStop, onNodesDelete, onEdgesDelete, onDelete, onSelectionChange, onSelectionDragStart, onSelectionDrag, onSelectionDragStop, onSelectionContextMenu, onSelectionStart, onSelectionEnd, onBeforeDelete, connectionMode, connectionLineType = ConnectionLineType.Bezier, connectionLineStyle, connectionLineComponent, connectionLineContainerStyle, deleteKeyCode = 'Backspace', selectionKeyCode = 'Shift', selectionOnDrag = false, selectionMode = SelectionMode.Full, panActivationKeyCode = 'Space', multiSelectionKeyCode = isMacOs() ? 'Meta' : 'Control', zoomActivationKeyCode = isMacOs() ? 'Meta' : 'Control', snapToGrid, snapGrid, onlyRenderVisibleElements = false, selectNodesOnDrag, nodesDraggable, nodesConnectable, nodesFocusable, nodeOrigin = defaultNodeOrigin, edgesFocusable, edgesUpdatable, elementsSelectable = true, defaultViewport: defaultViewport$1 = defaultViewport, minZoom = 0.5, maxZoom = 2, translateExtent = infiniteExtent, preventScrolling = true, nodeExtent, defaultMarkerColor = '#b1b1b7', zoomOnScroll = true, zoomOnPinch = true, panOnScroll = false, panOnScrollSpeed = 0.5, panOnScrollMode = PanOnScrollMode.Free, zoomOnDoubleClick = true, panOnDrag = true, onPaneClick, onPaneMouseEnter, onPaneMouseMove, onPaneMouseLeave, onPaneScroll, onPaneContextMenu, children, onEdgeUpdate, onEdgeContextMenu, onEdgeDoubleClick, onEdgeMouseEnter, onEdgeMouseMove, onEdgeMouseLeave, onEdgeUpdateStart, onEdgeUpdateEnd, edgeUpdaterRadius = 10, onNodesChange, onEdgesChange, noDragClassName = 'nodrag', noWheelClassName = 'nowheel', noPanClassName = 'nopan', fitView, fitViewOptions, connectOnClick, attributionPosition, proOptions, defaultEdgeOptions, elevateNodesOnSelect, elevateEdgesOnSelect, disableKeyboardA11y = false, autoPanOnConnect, autoPanOnNodeDrag, connectionRadius, isValidConnection, onError, style, id, nodeDragThreshold, viewport, onViewportChange, width, height, colorMode = 'light', ...rest }, ref) => {
|
|
2827
2793
|
const rfId = id || '1';
|
|
2828
2794
|
const colorModeClassName = useColorModeClass(colorMode);
|
|
2829
|
-
return (jsx("div", { ...rest, style: { ...style, ...wrapperStyle }, ref: ref, className: cc(['react-flow', className, colorModeClassName]), "data-testid": "rf__wrapper", id: id, children: jsxs(Wrapper, { nodes: nodes, edges: edges, width: width, height: height, fitView: fitView, children: [jsx(GraphView, { onInit: onInit, onNodeClick: onNodeClick, onEdgeClick: onEdgeClick, onNodeMouseEnter: onNodeMouseEnter, onNodeMouseMove: onNodeMouseMove, onNodeMouseLeave: onNodeMouseLeave, onNodeContextMenu: onNodeContextMenu, onNodeDoubleClick: onNodeDoubleClick, nodeTypes: nodeTypes, edgeTypes: edgeTypes, connectionLineType: connectionLineType, connectionLineStyle: connectionLineStyle, connectionLineComponent: connectionLineComponent, connectionLineContainerStyle: connectionLineContainerStyle, selectionKeyCode: selectionKeyCode, selectionOnDrag: selectionOnDrag, selectionMode: selectionMode, deleteKeyCode: deleteKeyCode, multiSelectionKeyCode: multiSelectionKeyCode, panActivationKeyCode: panActivationKeyCode, zoomActivationKeyCode: zoomActivationKeyCode, onlyRenderVisibleElements: onlyRenderVisibleElements, defaultViewport: defaultViewport, translateExtent: translateExtent, minZoom: minZoom, maxZoom: maxZoom, preventScrolling: preventScrolling, zoomOnScroll: zoomOnScroll, zoomOnPinch: zoomOnPinch, zoomOnDoubleClick: zoomOnDoubleClick, panOnScroll: panOnScroll, panOnScrollSpeed: panOnScrollSpeed, panOnScrollMode: panOnScrollMode, panOnDrag: panOnDrag, onPaneClick: onPaneClick, onPaneMouseEnter: onPaneMouseEnter, onPaneMouseMove: onPaneMouseMove, onPaneMouseLeave: onPaneMouseLeave, onPaneScroll: onPaneScroll, onPaneContextMenu: onPaneContextMenu, onSelectionContextMenu: onSelectionContextMenu, onSelectionStart: onSelectionStart, onSelectionEnd: onSelectionEnd, onEdgeUpdate: onEdgeUpdate, onEdgeContextMenu: onEdgeContextMenu, onEdgeDoubleClick: onEdgeDoubleClick, onEdgeMouseEnter: onEdgeMouseEnter, onEdgeMouseMove: onEdgeMouseMove, onEdgeMouseLeave: onEdgeMouseLeave, onEdgeUpdateStart: onEdgeUpdateStart, onEdgeUpdateEnd: onEdgeUpdateEnd, edgeUpdaterRadius: edgeUpdaterRadius, defaultMarkerColor: defaultMarkerColor, noDragClassName: noDragClassName, noWheelClassName: noWheelClassName, noPanClassName: noPanClassName, rfId: rfId, disableKeyboardA11y: disableKeyboardA11y, nodeOrigin: nodeOrigin, nodeExtent: nodeExtent, viewport: viewport, onViewportChange: onViewportChange }), jsx(StoreUpdater, { nodes: nodes, edges: edges, defaultNodes: defaultNodes, defaultEdges: defaultEdges, onConnect: onConnect, onConnectStart: onConnectStart, onConnectEnd: onConnectEnd, onClickConnectStart: onClickConnectStart, onClickConnectEnd: onClickConnectEnd, nodesDraggable: nodesDraggable, nodesConnectable: nodesConnectable, nodesFocusable: nodesFocusable, edgesFocusable: edgesFocusable, edgesUpdatable: edgesUpdatable, elementsSelectable: elementsSelectable, elevateNodesOnSelect: elevateNodesOnSelect, elevateEdgesOnSelect: elevateEdgesOnSelect, minZoom: minZoom, maxZoom: maxZoom, nodeExtent: nodeExtent, onNodesChange: onNodesChange, onEdgesChange: onEdgesChange, snapToGrid: snapToGrid, snapGrid: snapGrid, connectionMode: connectionMode, translateExtent: translateExtent, connectOnClick: connectOnClick, defaultEdgeOptions: defaultEdgeOptions, fitView: fitView, fitViewOptions: fitViewOptions, onNodesDelete: onNodesDelete, onEdgesDelete: onEdgesDelete, onDelete: onDelete, onNodeDragStart: onNodeDragStart, onNodeDrag: onNodeDrag, onNodeDragStop: onNodeDragStop, onSelectionDrag: onSelectionDrag, onSelectionDragStart: onSelectionDragStart, onSelectionDragStop: onSelectionDragStop, onMove: onMove, onMoveStart: onMoveStart, onMoveEnd: onMoveEnd, noPanClassName: noPanClassName, nodeOrigin: nodeOrigin, rfId: rfId, autoPanOnConnect: autoPanOnConnect, autoPanOnNodeDrag: autoPanOnNodeDrag, onError: onError, connectionRadius: connectionRadius, isValidConnection: isValidConnection, selectNodesOnDrag: selectNodesOnDrag, nodeDragThreshold: nodeDragThreshold, onBeforeDelete: onBeforeDelete }), jsx(SelectionListener, { onSelectionChange: onSelectionChange }), children, jsx(Attribution, { proOptions: proOptions, position: attributionPosition }), jsx(A11yDescriptions, { rfId: rfId, disableKeyboardA11y: disableKeyboardA11y })] }) }));
|
|
2795
|
+
return (jsx("div", { ...rest, style: { ...style, ...wrapperStyle }, ref: ref, className: cc(['react-flow', className, colorModeClassName]), "data-testid": "rf__wrapper", id: id, children: jsxs(Wrapper, { nodes: nodes, edges: edges, defaultNodes: defaultNodes, defaultEdges: defaultEdges, width: width, height: height, fitView: fitView, children: [jsx(GraphView, { onInit: onInit, onNodeClick: onNodeClick, onEdgeClick: onEdgeClick, onNodeMouseEnter: onNodeMouseEnter, onNodeMouseMove: onNodeMouseMove, onNodeMouseLeave: onNodeMouseLeave, onNodeContextMenu: onNodeContextMenu, onNodeDoubleClick: onNodeDoubleClick, nodeTypes: nodeTypes, edgeTypes: edgeTypes, connectionLineType: connectionLineType, connectionLineStyle: connectionLineStyle, connectionLineComponent: connectionLineComponent, connectionLineContainerStyle: connectionLineContainerStyle, selectionKeyCode: selectionKeyCode, selectionOnDrag: selectionOnDrag, selectionMode: selectionMode, deleteKeyCode: deleteKeyCode, multiSelectionKeyCode: multiSelectionKeyCode, panActivationKeyCode: panActivationKeyCode, zoomActivationKeyCode: zoomActivationKeyCode, onlyRenderVisibleElements: onlyRenderVisibleElements, defaultViewport: defaultViewport$1, translateExtent: translateExtent, minZoom: minZoom, maxZoom: maxZoom, preventScrolling: preventScrolling, zoomOnScroll: zoomOnScroll, zoomOnPinch: zoomOnPinch, zoomOnDoubleClick: zoomOnDoubleClick, panOnScroll: panOnScroll, panOnScrollSpeed: panOnScrollSpeed, panOnScrollMode: panOnScrollMode, panOnDrag: panOnDrag, onPaneClick: onPaneClick, onPaneMouseEnter: onPaneMouseEnter, onPaneMouseMove: onPaneMouseMove, onPaneMouseLeave: onPaneMouseLeave, onPaneScroll: onPaneScroll, onPaneContextMenu: onPaneContextMenu, onSelectionContextMenu: onSelectionContextMenu, onSelectionStart: onSelectionStart, onSelectionEnd: onSelectionEnd, onEdgeUpdate: onEdgeUpdate, onEdgeContextMenu: onEdgeContextMenu, onEdgeDoubleClick: onEdgeDoubleClick, onEdgeMouseEnter: onEdgeMouseEnter, onEdgeMouseMove: onEdgeMouseMove, onEdgeMouseLeave: onEdgeMouseLeave, onEdgeUpdateStart: onEdgeUpdateStart, onEdgeUpdateEnd: onEdgeUpdateEnd, edgeUpdaterRadius: edgeUpdaterRadius, defaultMarkerColor: defaultMarkerColor, noDragClassName: noDragClassName, noWheelClassName: noWheelClassName, noPanClassName: noPanClassName, rfId: rfId, disableKeyboardA11y: disableKeyboardA11y, nodeOrigin: nodeOrigin, nodeExtent: nodeExtent, viewport: viewport, onViewportChange: onViewportChange }), jsx(StoreUpdater, { nodes: nodes, edges: edges, defaultNodes: defaultNodes, defaultEdges: defaultEdges, onConnect: onConnect, onConnectStart: onConnectStart, onConnectEnd: onConnectEnd, onClickConnectStart: onClickConnectStart, onClickConnectEnd: onClickConnectEnd, nodesDraggable: nodesDraggable, nodesConnectable: nodesConnectable, nodesFocusable: nodesFocusable, edgesFocusable: edgesFocusable, edgesUpdatable: edgesUpdatable, elementsSelectable: elementsSelectable, elevateNodesOnSelect: elevateNodesOnSelect, elevateEdgesOnSelect: elevateEdgesOnSelect, minZoom: minZoom, maxZoom: maxZoom, nodeExtent: nodeExtent, onNodesChange: onNodesChange, onEdgesChange: onEdgesChange, snapToGrid: snapToGrid, snapGrid: snapGrid, connectionMode: connectionMode, translateExtent: translateExtent, connectOnClick: connectOnClick, defaultEdgeOptions: defaultEdgeOptions, fitView: fitView, fitViewOptions: fitViewOptions, onNodesDelete: onNodesDelete, onEdgesDelete: onEdgesDelete, onDelete: onDelete, onNodeDragStart: onNodeDragStart, onNodeDrag: onNodeDrag, onNodeDragStop: onNodeDragStop, onSelectionDrag: onSelectionDrag, onSelectionDragStart: onSelectionDragStart, onSelectionDragStop: onSelectionDragStop, onMove: onMove, onMoveStart: onMoveStart, onMoveEnd: onMoveEnd, noPanClassName: noPanClassName, nodeOrigin: nodeOrigin, rfId: rfId, autoPanOnConnect: autoPanOnConnect, autoPanOnNodeDrag: autoPanOnNodeDrag, onError: onError, connectionRadius: connectionRadius, isValidConnection: isValidConnection, selectNodesOnDrag: selectNodesOnDrag, nodeDragThreshold: nodeDragThreshold, onBeforeDelete: onBeforeDelete }), jsx(SelectionListener, { onSelectionChange: onSelectionChange }), children, jsx(Attribution, { proOptions: proOptions, position: attributionPosition }), jsx(A11yDescriptions, { rfId: rfId, disableKeyboardA11y: disableKeyboardA11y })] }) }));
|
|
2830
2796
|
});
|
|
2831
2797
|
ReactFlow.displayName = 'ReactFlow';
|
|
2832
2798
|
|
|
@@ -3011,12 +2977,12 @@ function useNodesInitialized(options = defaultOptions) {
|
|
|
3011
2977
|
* @param param.id - the handle id (this is only needed if the node has multiple handles of the same type)
|
|
3012
2978
|
* @param param.onConnect - gets called when a connection is established
|
|
3013
2979
|
* @param param.onDisconnect - gets called when a connection is removed
|
|
3014
|
-
* @returns an array with connections
|
|
2980
|
+
* @returns an array with handle connections
|
|
3015
2981
|
*/
|
|
3016
2982
|
function useHandleConnections({ type, id = null, nodeId, onConnect, onDisconnect, }) {
|
|
3017
2983
|
const _nodeId = useNodeId();
|
|
2984
|
+
const currentNodeId = nodeId ?? _nodeId;
|
|
3018
2985
|
const prevConnections = useRef(null);
|
|
3019
|
-
const currentNodeId = nodeId || _nodeId;
|
|
3020
2986
|
const connections = useStore((state) => state.connectionLookup.get(`${currentNodeId}-${type}-${id}`), areConnectionMapsEqual);
|
|
3021
2987
|
useEffect(() => {
|
|
3022
2988
|
// @todo dicuss if onConnect/onDisconnect should be called when the component mounts/unmounts
|
|
@@ -3244,7 +3210,7 @@ const ARIA_LABEL_KEY = 'react-flow__minimap-desc';
|
|
|
3244
3210
|
function MiniMapComponent({ style, className, nodeStrokeColor, nodeColor, nodeClassName = '', nodeBorderRadius = 5, nodeStrokeWidth,
|
|
3245
3211
|
// We need to rename the prop to be `CapitalCase` so that JSX will render it as
|
|
3246
3212
|
// a component properly.
|
|
3247
|
-
nodeComponent, maskColor, maskStrokeColor
|
|
3213
|
+
nodeComponent, bgColor, maskColor, maskStrokeColor, maskStrokeWidth, position = 'bottom-right', onClick, onNodeClick, pannable = false, zoomable = false, ariaLabel = 'React Flow mini map', inversePan, zoomStep = 10, offsetScale = 5, }) {
|
|
3248
3214
|
const store = useStoreApi();
|
|
3249
3215
|
const svg = useRef(null);
|
|
3250
3216
|
const { boundingRect, viewBB, rfId, panZoom, translateExtent, flowWidth, flowHeight } = useStore(selector$1, shallow);
|
|
@@ -3302,12 +3268,15 @@ nodeComponent, maskColor, maskStrokeColor = 'none', maskStrokeWidth = 1, positio
|
|
|
3302
3268
|
: undefined;
|
|
3303
3269
|
return (jsx(Panel, { position: position, style: {
|
|
3304
3270
|
...style,
|
|
3305
|
-
'--xy-minimap-
|
|
3271
|
+
'--xy-minimap-background-color-props': typeof bgColor === 'string' ? bgColor : undefined,
|
|
3272
|
+
'--xy-minimap-mask-background-color-props': typeof maskColor === 'string' ? maskColor : undefined,
|
|
3273
|
+
'--xy-minimap-mask-stroke-color-props': typeof maskStrokeColor === 'string' ? maskStrokeColor : undefined,
|
|
3274
|
+
'--xy-minimap-mask-stroke-width-props': typeof maskStrokeWidth === 'number' ? maskStrokeWidth * viewScale : undefined,
|
|
3306
3275
|
'--xy-minimap-node-background-color-props': typeof nodeColor === 'string' ? nodeColor : undefined,
|
|
3307
3276
|
'--xy-minimap-node-stroke-color-props': typeof nodeStrokeColor === 'string' ? nodeStrokeColor : undefined,
|
|
3308
3277
|
'--xy-minimap-node-stroke-width-props': typeof nodeStrokeWidth === 'string' ? nodeStrokeWidth : undefined,
|
|
3309
|
-
}, className: cc(['react-flow__minimap', className]), "data-testid": "rf__minimap", children: jsxs("svg", { width: elementWidth, height: elementHeight, viewBox: `${x} ${y} ${width} ${height}`, role: "img", "aria-labelledby": labelledBy, ref: svg, onClick: onSvgClick, children: [ariaLabel && jsx("title", { id: labelledBy, children: ariaLabel }), jsx(MiniMapNodes$1, { onClick: onSvgNodeClick, nodeColor: nodeColor, nodeStrokeColor: nodeStrokeColor, nodeBorderRadius: nodeBorderRadius, nodeClassName: nodeClassName, nodeStrokeWidth: nodeStrokeWidth, nodeComponent: nodeComponent }), jsx("path", { className: "react-flow__minimap-mask", d: `M${x - offset},${y - offset}h${width + offset * 2}v${height + offset * 2}h${-width - offset * 2}z
|
|
3310
|
-
M${viewBB.x},${viewBB.y}h${viewBB.width}v${viewBB.height}h${-viewBB.width}z`, fillRule: "evenodd",
|
|
3278
|
+
}, className: cc(['react-flow__minimap', className]), "data-testid": "rf__minimap", children: jsxs("svg", { width: elementWidth, height: elementHeight, viewBox: `${x} ${y} ${width} ${height}`, className: "react-flow__minimap-svg", role: "img", "aria-labelledby": labelledBy, ref: svg, onClick: onSvgClick, children: [ariaLabel && jsx("title", { id: labelledBy, children: ariaLabel }), jsx(MiniMapNodes$1, { onClick: onSvgNodeClick, nodeColor: nodeColor, nodeStrokeColor: nodeStrokeColor, nodeBorderRadius: nodeBorderRadius, nodeClassName: nodeClassName, nodeStrokeWidth: nodeStrokeWidth, nodeComponent: nodeComponent }), jsx("path", { className: "react-flow__minimap-mask", d: `M${x - offset},${y - offset}h${width + offset * 2}v${height + offset * 2}h${-width - offset * 2}z
|
|
3279
|
+
M${viewBB.x},${viewBB.y}h${viewBB.width}v${viewBB.height}h${-viewBB.width}z`, fillRule: "evenodd", pointerEvents: "none" })] }) }));
|
|
3311
3280
|
}
|
|
3312
3281
|
MiniMapComponent.displayName = 'MiniMap';
|
|
3313
3282
|
const MiniMap = memo(MiniMapComponent);
|
|
@@ -3337,7 +3306,7 @@ function ResizeControl({ nodeId, position, variant = ResizeControlVariant.Handle
|
|
|
3337
3306
|
snapToGrid,
|
|
3338
3307
|
};
|
|
3339
3308
|
},
|
|
3340
|
-
onChange: (change) => {
|
|
3309
|
+
onChange: (change, childChanges) => {
|
|
3341
3310
|
const { triggerNodeChanges } = store.getState();
|
|
3342
3311
|
const changes = [];
|
|
3343
3312
|
if (change.isXPosChange || change.isYPosChange) {
|
|
@@ -3363,6 +3332,13 @@ function ResizeControl({ nodeId, position, variant = ResizeControlVariant.Handle
|
|
|
3363
3332
|
};
|
|
3364
3333
|
changes.push(dimensionChange);
|
|
3365
3334
|
}
|
|
3335
|
+
for (const childChange of childChanges) {
|
|
3336
|
+
const positionChange = {
|
|
3337
|
+
...childChange,
|
|
3338
|
+
type: 'position',
|
|
3339
|
+
};
|
|
3340
|
+
changes.push(positionChange);
|
|
3341
|
+
}
|
|
3366
3342
|
triggerNodeChanges(changes);
|
|
3367
3343
|
},
|
|
3368
3344
|
onEnd: () => {
|