@xyflow/react 12.4.3 → 12.5.0
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 +8 -4
- package/dist/esm/additional-components/Background/types.d.ts +20 -4
- package/dist/esm/additional-components/Background/types.d.ts.map +1 -1
- package/dist/esm/additional-components/Controls/types.d.ts +33 -9
- package/dist/esm/additional-components/Controls/types.d.ts.map +1 -1
- package/dist/esm/additional-components/MiniMap/MiniMap.d.ts.map +1 -1
- package/dist/esm/additional-components/NodeToolbar/types.d.ts +8 -2
- package/dist/esm/additional-components/NodeToolbar/types.d.ts.map +1 -1
- package/dist/esm/components/EdgeLabelRenderer/index.d.ts +31 -29
- package/dist/esm/components/EdgeLabelRenderer/index.d.ts.map +1 -1
- package/dist/esm/components/EdgeWrapper/index.d.ts +1 -1
- package/dist/esm/components/EdgeWrapper/index.d.ts.map +1 -1
- package/dist/esm/components/Edges/BezierEdge.d.ts +26 -0
- package/dist/esm/components/Edges/BezierEdge.d.ts.map +1 -1
- package/dist/esm/components/Edges/EdgeAnchor.d.ts +3 -0
- package/dist/esm/components/Edges/EdgeAnchor.d.ts.map +1 -1
- package/dist/esm/components/Edges/EdgeText.d.ts +18 -18
- package/dist/esm/components/Edges/EdgeText.d.ts.map +1 -1
- package/dist/esm/components/Edges/SmoothStepEdge.d.ts +26 -0
- package/dist/esm/components/Edges/SmoothStepEdge.d.ts.map +1 -1
- package/dist/esm/components/Edges/StepEdge.d.ts +26 -0
- package/dist/esm/components/Edges/StepEdge.d.ts.map +1 -1
- package/dist/esm/components/Edges/StraightEdge.d.ts +24 -0
- package/dist/esm/components/Edges/StraightEdge.d.ts.map +1 -1
- package/dist/esm/components/Handle/index.d.ts +1 -1
- package/dist/esm/components/Handle/index.d.ts.map +1 -1
- package/dist/esm/components/SelectionListener/index.d.ts +4 -4
- package/dist/esm/components/SelectionListener/index.d.ts.map +1 -1
- package/dist/esm/container/Pane/index.d.ts.map +1 -1
- package/dist/esm/container/ReactFlow/index.d.ts +1 -1
- package/dist/esm/hooks/useKeyPress.d.ts +1 -0
- package/dist/esm/hooks/useKeyPress.d.ts.map +1 -1
- package/dist/esm/hooks/useNodeConnections.d.ts +1 -1
- package/dist/esm/hooks/useOnSelectionChange.d.ts +4 -4
- package/dist/esm/hooks/useOnSelectionChange.d.ts.map +1 -1
- package/dist/esm/hooks/useReactFlow.d.ts.map +1 -1
- package/dist/esm/hooks/useViewportHelper.d.ts.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +427 -341
- package/dist/esm/index.mjs +427 -341
- package/dist/esm/store/index.d.ts +9 -9
- package/dist/esm/store/index.d.ts.map +1 -1
- package/dist/esm/store/initialState.d.ts +9 -9
- package/dist/esm/store/initialState.d.ts.map +1 -1
- package/dist/esm/types/component-props.d.ts +1 -1
- package/dist/esm/types/component-props.d.ts.map +1 -1
- package/dist/esm/types/edges.d.ts +23 -3
- package/dist/esm/types/edges.d.ts.map +1 -1
- package/dist/esm/types/general.d.ts +8 -19
- package/dist/esm/types/general.d.ts.map +1 -1
- package/dist/esm/types/instance.d.ts +2 -2
- package/dist/esm/types/instance.d.ts.map +1 -1
- package/dist/esm/types/store.d.ts +5 -7
- package/dist/esm/types/store.d.ts.map +1 -1
- package/dist/esm/utils/general.d.ts +1 -1
- package/dist/esm/utils/general.d.ts.map +1 -1
- package/dist/style.css +8 -4
- package/dist/umd/additional-components/Background/types.d.ts +20 -4
- package/dist/umd/additional-components/Background/types.d.ts.map +1 -1
- package/dist/umd/additional-components/Controls/types.d.ts +33 -9
- package/dist/umd/additional-components/Controls/types.d.ts.map +1 -1
- package/dist/umd/additional-components/MiniMap/MiniMap.d.ts.map +1 -1
- package/dist/umd/additional-components/NodeToolbar/types.d.ts +8 -2
- package/dist/umd/additional-components/NodeToolbar/types.d.ts.map +1 -1
- package/dist/umd/components/EdgeLabelRenderer/index.d.ts +31 -29
- package/dist/umd/components/EdgeLabelRenderer/index.d.ts.map +1 -1
- package/dist/umd/components/EdgeWrapper/index.d.ts +1 -1
- package/dist/umd/components/EdgeWrapper/index.d.ts.map +1 -1
- package/dist/umd/components/Edges/BezierEdge.d.ts +26 -0
- package/dist/umd/components/Edges/BezierEdge.d.ts.map +1 -1
- package/dist/umd/components/Edges/EdgeAnchor.d.ts +3 -0
- package/dist/umd/components/Edges/EdgeAnchor.d.ts.map +1 -1
- package/dist/umd/components/Edges/EdgeText.d.ts +18 -18
- package/dist/umd/components/Edges/EdgeText.d.ts.map +1 -1
- package/dist/umd/components/Edges/SmoothStepEdge.d.ts +26 -0
- package/dist/umd/components/Edges/SmoothStepEdge.d.ts.map +1 -1
- package/dist/umd/components/Edges/StepEdge.d.ts +26 -0
- package/dist/umd/components/Edges/StepEdge.d.ts.map +1 -1
- package/dist/umd/components/Edges/StraightEdge.d.ts +24 -0
- package/dist/umd/components/Edges/StraightEdge.d.ts.map +1 -1
- package/dist/umd/components/Handle/index.d.ts +1 -1
- package/dist/umd/components/Handle/index.d.ts.map +1 -1
- package/dist/umd/components/SelectionListener/index.d.ts +4 -4
- package/dist/umd/components/SelectionListener/index.d.ts.map +1 -1
- package/dist/umd/container/Pane/index.d.ts.map +1 -1
- package/dist/umd/container/ReactFlow/index.d.ts +1 -1
- package/dist/umd/hooks/useKeyPress.d.ts +1 -0
- package/dist/umd/hooks/useKeyPress.d.ts.map +1 -1
- package/dist/umd/hooks/useNodeConnections.d.ts +1 -1
- package/dist/umd/hooks/useOnSelectionChange.d.ts +4 -4
- package/dist/umd/hooks/useOnSelectionChange.d.ts.map +1 -1
- package/dist/umd/hooks/useReactFlow.d.ts.map +1 -1
- package/dist/umd/hooks/useViewportHelper.d.ts.map +1 -1
- package/dist/umd/index.d.ts +1 -1
- package/dist/umd/index.d.ts.map +1 -1
- package/dist/umd/index.js +2 -2
- package/dist/umd/store/index.d.ts +9 -9
- package/dist/umd/store/index.d.ts.map +1 -1
- package/dist/umd/store/initialState.d.ts +9 -9
- package/dist/umd/store/initialState.d.ts.map +1 -1
- package/dist/umd/types/component-props.d.ts +1 -1
- package/dist/umd/types/component-props.d.ts.map +1 -1
- package/dist/umd/types/edges.d.ts +23 -3
- package/dist/umd/types/edges.d.ts.map +1 -1
- package/dist/umd/types/general.d.ts +8 -19
- package/dist/umd/types/general.d.ts.map +1 -1
- package/dist/umd/types/instance.d.ts +2 -2
- package/dist/umd/types/instance.d.ts.map +1 -1
- package/dist/umd/types/store.d.ts +5 -7
- package/dist/umd/types/store.d.ts.map +1 -1
- package/dist/umd/utils/general.d.ts +1 -1
- package/dist/umd/utils/general.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/esm/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
3
3
|
import { createContext, useContext, useMemo, forwardRef, useEffect, useRef, useState, useLayoutEffect, useCallback, memo } from 'react';
|
|
4
4
|
import cc from 'classcat';
|
|
5
|
-
import { errorMessages, infiniteExtent, isInputDOMNode,
|
|
5
|
+
import { errorMessages, infiniteExtent, isInputDOMNode, getViewportForBounds, pointToRendererPoint, rendererPointToPoint, isNodeBase, isEdgeBase, getElementsToRemove, isRectObject, nodeToRect, getOverlappingArea, getNodesBounds, evaluateAbsolutePosition, getDimensions, XYPanZoom, PanOnScrollMode, SelectionMode, getEventPosition, getNodesInside, areSetsEqual, XYDrag, snapPosition, calculateNodePosition, Position, ConnectionMode, isMouseEvent, XYHandle, getHostForElement, addEdge, getInternalNodesBounds, isNumeric, nodeHasDimensions, getNodeDimensions, elementSelectionKeys, isEdgeVisible, MarkerType, createMarkerIds, getBezierEdgeCenter, getSmoothStepPath, getStraightPath, getBezierPath, getEdgePosition, getElevatedEdgeZIndex, getMarkerId, getConnectionStatus, ConnectionLineType, updateConnectionLookup, adoptUserNodes, initialConnection, devWarn, updateNodeInternals, updateAbsolutePositions, handleExpandParent, panBy, fitViewport, isMacOs, areConnectionMapsEqual, handleConnectionChange, shallowNodeData, XYMinimap, getBoundsOfRects, ResizeControlVariant, XYResizer, XY_RESIZER_LINE_POSITIONS, XY_RESIZER_HANDLE_POSITIONS, getNodeToolbarTransform } from '@xyflow/system';
|
|
6
6
|
export { ConnectionLineType, ConnectionMode, MarkerType, PanOnScrollMode, Position, ResizeControlVariant, SelectionMode, addEdge, getBezierEdgeCenter, getBezierPath, getConnectedEdges, getEdgeCenter, getIncomers, getNodesBounds, getOutgoers, getSmoothStepPath, getStraightPath, getViewportForBounds, reconnectEdge } from '@xyflow/system';
|
|
7
7
|
import { useStoreWithEqualityFn, createWithEqualityFn } from 'zustand/traditional';
|
|
8
8
|
import { shallow } from 'zustand/shallow';
|
|
@@ -148,7 +148,7 @@ function areEqual(a, b) {
|
|
|
148
148
|
return (shallow(a.selectedNodes.map(selectId), b.selectedNodes.map(selectId)) &&
|
|
149
149
|
shallow(a.selectedEdges.map(selectId), b.selectedEdges.map(selectId)));
|
|
150
150
|
}
|
|
151
|
-
function SelectionListenerInner({ onSelectionChange }) {
|
|
151
|
+
function SelectionListenerInner({ onSelectionChange, }) {
|
|
152
152
|
const store = useStoreApi();
|
|
153
153
|
const { selectedNodes, selectedEdges } = useStore(selector$m, areEqual);
|
|
154
154
|
useEffect(() => {
|
|
@@ -159,7 +159,7 @@ function SelectionListenerInner({ onSelectionChange }) {
|
|
|
159
159
|
return null;
|
|
160
160
|
}
|
|
161
161
|
const changeSelector = (s) => !!s.onSelectionChangeHandlers;
|
|
162
|
-
function SelectionListener({ onSelectionChange }) {
|
|
162
|
+
function SelectionListener({ onSelectionChange, }) {
|
|
163
163
|
const storeHasSelectionChangeHandlers = useStore(changeSelector);
|
|
164
164
|
if (onSelectionChange || storeHasSelectionChangeHandlers) {
|
|
165
165
|
return jsx(SelectionListenerInner, { onSelectionChange: onSelectionChange });
|
|
@@ -298,9 +298,9 @@ function StoreUpdater(props) {
|
|
|
298
298
|
setPaneClickDistance(fieldValue);
|
|
299
299
|
// Renamed fields
|
|
300
300
|
else if (fieldName === 'fitView')
|
|
301
|
-
store.setState({
|
|
301
|
+
store.setState({ fitViewQueued: fieldValue });
|
|
302
302
|
else if (fieldName === 'fitViewOptions')
|
|
303
|
-
store.setState({
|
|
303
|
+
store.setState({ fitViewOptions: fieldValue });
|
|
304
304
|
// General case
|
|
305
305
|
else
|
|
306
306
|
store.setState({ [fieldName]: fieldValue });
|
|
@@ -410,7 +410,7 @@ keyCode = null, options = { target: defaultDoc, actInsideInputWithModifier: true
|
|
|
410
410
|
const target = options?.target || defaultDoc;
|
|
411
411
|
if (keyCode !== null) {
|
|
412
412
|
const downHandler = (event) => {
|
|
413
|
-
modifierPressed.current = event.ctrlKey || event.metaKey || event.shiftKey;
|
|
413
|
+
modifierPressed.current = event.ctrlKey || event.metaKey || event.shiftKey || event.altKey;
|
|
414
414
|
const preventAction = (!modifierPressed.current || (modifierPressed.current && !options.actInsideInputWithModifier)) &&
|
|
415
415
|
isInputDOMNode(event);
|
|
416
416
|
if (preventAction) {
|
|
@@ -419,16 +419,15 @@ keyCode = null, options = { target: defaultDoc, actInsideInputWithModifier: true
|
|
|
419
419
|
const keyOrCode = useKeyOrCode(event.code, keysToWatch);
|
|
420
420
|
pressedKeys.current.add(event[keyOrCode]);
|
|
421
421
|
if (isMatchingKey(keyCodes, pressedKeys.current, false)) {
|
|
422
|
-
event.
|
|
422
|
+
const target = (event.composedPath?.()?.[0] || event.target);
|
|
423
|
+
const isInteractiveElement = target?.nodeName === 'BUTTON' || target?.nodeName === 'A';
|
|
424
|
+
if (options.preventDefault !== false && (modifierPressed.current || !isInteractiveElement)) {
|
|
425
|
+
event.preventDefault();
|
|
426
|
+
}
|
|
423
427
|
setKeyPressed(true);
|
|
424
428
|
}
|
|
425
429
|
};
|
|
426
430
|
const upHandler = (event) => {
|
|
427
|
-
const preventAction = (!modifierPressed.current || (modifierPressed.current && !options.actInsideInputWithModifier)) &&
|
|
428
|
-
isInputDOMNode(event);
|
|
429
|
-
if (preventAction) {
|
|
430
|
-
return false;
|
|
431
|
-
}
|
|
432
431
|
const keyOrCode = useKeyOrCode(event.code, keysToWatch);
|
|
433
432
|
if (isMatchingKey(keyCodes, pressedKeys.current, true)) {
|
|
434
433
|
setKeyPressed(false);
|
|
@@ -519,22 +518,6 @@ const useViewportHelper = () => {
|
|
|
519
518
|
const [x, y, zoom] = store.getState().transform;
|
|
520
519
|
return { x, y, zoom };
|
|
521
520
|
},
|
|
522
|
-
fitView: (options) => {
|
|
523
|
-
const { nodeLookup, minZoom, maxZoom, panZoom, domNode } = store.getState();
|
|
524
|
-
if (!panZoom || !domNode) {
|
|
525
|
-
return Promise.resolve(false);
|
|
526
|
-
}
|
|
527
|
-
const fitViewNodes = getFitViewNodes(nodeLookup, options);
|
|
528
|
-
const { width, height } = getDimensions(domNode);
|
|
529
|
-
return fitView({
|
|
530
|
-
nodes: fitViewNodes,
|
|
531
|
-
width,
|
|
532
|
-
height,
|
|
533
|
-
minZoom,
|
|
534
|
-
maxZoom,
|
|
535
|
-
panZoom,
|
|
536
|
-
}, options);
|
|
537
|
-
},
|
|
538
521
|
setCenter: async (x, y, options) => {
|
|
539
522
|
const { width, height, maxZoom, panZoom } = store.getState();
|
|
540
523
|
const nextZoom = typeof options?.zoom !== 'undefined' ? options.zoom : maxZoom;
|
|
@@ -1174,6 +1157,15 @@ function useReactFlow() {
|
|
|
1174
1157
|
.getState()
|
|
1175
1158
|
.connectionLookup.get(`${nodeId}${type ? (handleId ? `-${type}-${handleId}` : `-${type}`) : ''}`)
|
|
1176
1159
|
?.values() ?? []),
|
|
1160
|
+
fitView: async (options) => {
|
|
1161
|
+
// We either create a new Promise or reuse the existing one
|
|
1162
|
+
// Even if fitView is called multiple times in a row, we only end up with a single Promise
|
|
1163
|
+
const fitViewResolver = store.getState().fitViewResolver ?? Promise.withResolvers();
|
|
1164
|
+
// We schedule a fitView by setting fitViewQueued and triggering a setNodes
|
|
1165
|
+
store.setState({ fitViewQueued: true, fitViewOptions: options, fitViewResolver });
|
|
1166
|
+
batchContext.nodeQueue.push((nodes) => [...nodes]);
|
|
1167
|
+
return fitViewResolver.promise;
|
|
1168
|
+
},
|
|
1177
1169
|
};
|
|
1178
1170
|
}, []);
|
|
1179
1171
|
return useMemo(() => {
|
|
@@ -1371,11 +1363,12 @@ const wrapHandler = (handler, containerRef) => {
|
|
|
1371
1363
|
const selector$h = (s) => ({
|
|
1372
1364
|
userSelectionActive: s.userSelectionActive,
|
|
1373
1365
|
elementsSelectable: s.elementsSelectable,
|
|
1366
|
+
connectionInProgress: s.connection.inProgress,
|
|
1374
1367
|
dragging: s.paneDragging,
|
|
1375
1368
|
});
|
|
1376
1369
|
function Pane({ isSelecting, selectionKeyPressed, selectionMode = SelectionMode.Full, panOnDrag, selectionOnDrag, onSelectionStart, onSelectionEnd, onPaneClick, onPaneContextMenu, onPaneScroll, onPaneMouseEnter, onPaneMouseMove, onPaneMouseLeave, children, }) {
|
|
1377
1370
|
const store = useStoreApi();
|
|
1378
|
-
const { userSelectionActive, elementsSelectable, dragging } = useStore(selector$h, shallow);
|
|
1371
|
+
const { userSelectionActive, elementsSelectable, dragging, connectionInProgress } = useStore(selector$h, shallow);
|
|
1379
1372
|
const hasActiveSelection = elementsSelectable && (isSelecting || userSelectionActive);
|
|
1380
1373
|
const container = useRef(null);
|
|
1381
1374
|
const containerBounds = useRef();
|
|
@@ -1386,7 +1379,8 @@ function Pane({ isSelecting, selectionKeyPressed, selectionMode = SelectionMode.
|
|
|
1386
1379
|
const selectionStarted = useRef(false);
|
|
1387
1380
|
const onClick = (event) => {
|
|
1388
1381
|
// We prevent click events when the user let go of the selectionKey during a selection
|
|
1389
|
-
|
|
1382
|
+
// We also prevent click events when a connection is in progress
|
|
1383
|
+
if (selectionInProgress.current || connectionInProgress) {
|
|
1390
1384
|
selectionInProgress.current = false;
|
|
1391
1385
|
return;
|
|
1392
1386
|
}
|
|
@@ -1681,6 +1675,7 @@ const connectingSelector = (nodeId, handleId, type) => (state) => {
|
|
|
1681
1675
|
? fromHandle?.type !== type
|
|
1682
1676
|
: nodeId !== fromHandle?.nodeId || handleId !== fromHandle?.id,
|
|
1683
1677
|
connectionInProcess: !!fromHandle,
|
|
1678
|
+
clickConnectionInProcess: !!clickHandle,
|
|
1684
1679
|
valid: connectingTo && isValid,
|
|
1685
1680
|
};
|
|
1686
1681
|
};
|
|
@@ -1690,7 +1685,7 @@ function HandleComponent({ type = 'source', position = Position.Top, isValidConn
|
|
|
1690
1685
|
const store = useStoreApi();
|
|
1691
1686
|
const nodeId = useNodeId();
|
|
1692
1687
|
const { connectOnClick, noPanClassName, rfId } = useStore(selector$g, shallow);
|
|
1693
|
-
const { connectingFrom, connectingTo, clickConnecting, isPossibleEndHandle, connectionInProcess, valid } = useStore(connectingSelector(nodeId, handleId, type), shallow);
|
|
1688
|
+
const { connectingFrom, connectingTo, clickConnecting, isPossibleEndHandle, connectionInProcess, clickConnectionInProcess, valid, } = useStore(connectingSelector(nodeId, handleId, type), shallow);
|
|
1694
1689
|
if (!nodeId) {
|
|
1695
1690
|
store.getState().onError?.('010', errorMessages['error010']());
|
|
1696
1691
|
}
|
|
@@ -1804,7 +1799,7 @@ function HandleComponent({ type = 'source', position = Position.Top, isValidConn
|
|
|
1804
1799
|
*/
|
|
1805
1800
|
connectionindicator: isConnectable &&
|
|
1806
1801
|
(!connectionInProcess || isPossibleEndHandle) &&
|
|
1807
|
-
(connectionInProcess ? isConnectableEnd : isConnectableStart),
|
|
1802
|
+
(connectionInProcess || clickConnectionInProcess ? isConnectableEnd : isConnectableStart),
|
|
1808
1803
|
},
|
|
1809
1804
|
]), onMouseDown: onPointerDown, onTouchStart: onPointerDown, onClick: connectOnClick ? onClick : undefined, ref: ref, ...rest, children: children }));
|
|
1810
1805
|
}
|
|
@@ -2309,7 +2304,7 @@ const MarkerDefinitions = ({ defaultColor, rfId }) => {
|
|
|
2309
2304
|
MarkerDefinitions.displayName = 'MarkerDefinitions';
|
|
2310
2305
|
var MarkerDefinitions$1 = memo(MarkerDefinitions);
|
|
2311
2306
|
|
|
2312
|
-
function EdgeTextComponent({ x, y, label, labelStyle
|
|
2307
|
+
function EdgeTextComponent({ x, y, label, labelStyle, labelShowBg = true, labelBgStyle, labelBgPadding = [2, 4], labelBgBorderRadius = 2, children, className, ...rest }) {
|
|
2313
2308
|
const [edgeTextBbox, setEdgeTextBbox] = useState({ x: 1, y: 0, width: 0, height: 0 });
|
|
2314
2309
|
const edgeTextClasses = cc(['react-flow__edge-textwrapper', className]);
|
|
2315
2310
|
const edgeTextRef = useRef(null);
|
|
@@ -2324,7 +2319,7 @@ function EdgeTextComponent({ x, y, label, labelStyle = {}, labelShowBg = true, l
|
|
|
2324
2319
|
});
|
|
2325
2320
|
}
|
|
2326
2321
|
}, [label]);
|
|
2327
|
-
if (
|
|
2322
|
+
if (!label) {
|
|
2328
2323
|
return null;
|
|
2329
2324
|
}
|
|
2330
2325
|
return (jsxs("g", { transform: `translate(${x - edgeTextBbox.width / 2} ${y - edgeTextBbox.height / 2})`, className: edgeTextClasses, visibility: edgeTextBbox.width ? 'visible' : 'hidden', ...rest, children: [labelShowBg && (jsx("rect", { width: edgeTextBbox.width + 2 * labelBgPadding[0], x: -labelBgPadding[0], y: -labelBgPadding[1], height: edgeTextBbox.height + 2 * labelBgPadding[1], className: "react-flow__edge-textbg", style: labelBgStyle, rx: labelBgBorderRadius, ry: labelBgBorderRadius })), jsx("text", { className: "react-flow__edge-text", y: edgeTextBbox.height / 2, dy: "0.3em", ref: edgeTextRef, style: labelStyle, children: label }), children] }));
|
|
@@ -2334,26 +2329,26 @@ EdgeTextComponent.displayName = 'EdgeText';
|
|
|
2334
2329
|
* You can use the `<EdgeText />` component as a helper component to display text
|
|
2335
2330
|
* within your custom edges.
|
|
2336
2331
|
*
|
|
2337
|
-
|
|
2332
|
+
* @public
|
|
2338
2333
|
*
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
*import { EdgeText } from '@xyflow/react';
|
|
2334
|
+
* @example
|
|
2335
|
+
* ```jsx
|
|
2336
|
+
* import { EdgeText } from '@xyflow/react';
|
|
2342
2337
|
*
|
|
2343
|
-
*export function CustomEdgeLabel({ label }) {
|
|
2344
|
-
*
|
|
2345
|
-
*
|
|
2346
|
-
*
|
|
2347
|
-
*
|
|
2348
|
-
*
|
|
2349
|
-
*
|
|
2350
|
-
*
|
|
2351
|
-
*
|
|
2352
|
-
*
|
|
2353
|
-
*
|
|
2354
|
-
*
|
|
2355
|
-
*
|
|
2356
|
-
*}
|
|
2338
|
+
* export function CustomEdgeLabel({ label }) {
|
|
2339
|
+
* return (
|
|
2340
|
+
* <EdgeText
|
|
2341
|
+
* x={100}
|
|
2342
|
+
* y={100}
|
|
2343
|
+
* label={label}
|
|
2344
|
+
* labelStyle={{ fill: 'white' }}
|
|
2345
|
+
* labelShowBg
|
|
2346
|
+
* labelBgStyle={{ fill: 'red' }}
|
|
2347
|
+
* labelBgPadding={[2, 4]}
|
|
2348
|
+
* labelBgBorderRadius={2}
|
|
2349
|
+
* />
|
|
2350
|
+
* );
|
|
2351
|
+
* }
|
|
2357
2352
|
*```
|
|
2358
2353
|
*/
|
|
2359
2354
|
const EdgeText = memo(EdgeTextComponent);
|
|
@@ -2470,7 +2465,33 @@ function createSmoothStepEdge(params) {
|
|
|
2470
2465
|
return (jsx(BaseEdge, { id: _id, path: path, labelX: labelX, labelY: labelY, label: label, labelStyle: labelStyle, labelShowBg: labelShowBg, labelBgStyle: labelBgStyle, labelBgPadding: labelBgPadding, labelBgBorderRadius: labelBgBorderRadius, style: style, markerEnd: markerEnd, markerStart: markerStart, interactionWidth: interactionWidth }));
|
|
2471
2466
|
});
|
|
2472
2467
|
}
|
|
2468
|
+
/**
|
|
2469
|
+
* Component that can be used inside a custom edge to render a smooth step edge.
|
|
2470
|
+
*
|
|
2471
|
+
* @public
|
|
2472
|
+
* @example
|
|
2473
|
+
*
|
|
2474
|
+
* ```tsx
|
|
2475
|
+
* import { SmoothStepEdge } from '@xyflow/react';
|
|
2476
|
+
*
|
|
2477
|
+
* function CustomEdge({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition }) {
|
|
2478
|
+
* return (
|
|
2479
|
+
* <SmoothStepEdge
|
|
2480
|
+
* sourceX={sourceX}
|
|
2481
|
+
* sourceY={sourceY}
|
|
2482
|
+
* targetX={targetX}
|
|
2483
|
+
* targetY={targetY}
|
|
2484
|
+
* sourcePosition={sourcePosition}
|
|
2485
|
+
* targetPosition={targetPosition}
|
|
2486
|
+
* />
|
|
2487
|
+
* );
|
|
2488
|
+
* }
|
|
2489
|
+
* ```
|
|
2490
|
+
*/
|
|
2473
2491
|
const SmoothStepEdge = createSmoothStepEdge({ isInternal: false });
|
|
2492
|
+
/**
|
|
2493
|
+
* @internal
|
|
2494
|
+
*/
|
|
2474
2495
|
const SmoothStepEdgeInternal = createSmoothStepEdge({ isInternal: true });
|
|
2475
2496
|
SmoothStepEdge.displayName = 'SmoothStepEdge';
|
|
2476
2497
|
SmoothStepEdgeInternal.displayName = 'SmoothStepEdgeInternal';
|
|
@@ -2482,7 +2503,33 @@ function createStepEdge(params) {
|
|
|
2482
2503
|
return (jsx(SmoothStepEdge, { ...props, id: _id, pathOptions: useMemo(() => ({ borderRadius: 0, offset: props.pathOptions?.offset }), [props.pathOptions?.offset]) }));
|
|
2483
2504
|
});
|
|
2484
2505
|
}
|
|
2506
|
+
/**
|
|
2507
|
+
* Component that can be used inside a custom edge to render a step edge.
|
|
2508
|
+
*
|
|
2509
|
+
* @public
|
|
2510
|
+
* @example
|
|
2511
|
+
*
|
|
2512
|
+
* ```tsx
|
|
2513
|
+
* import { StepEdge } from '@xyflow/react';
|
|
2514
|
+
*
|
|
2515
|
+
* function CustomEdge({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition }) {
|
|
2516
|
+
* return (
|
|
2517
|
+
* <StepEdge
|
|
2518
|
+
* sourceX={sourceX}
|
|
2519
|
+
* sourceY={sourceY}
|
|
2520
|
+
* targetX={targetX}
|
|
2521
|
+
* targetY={targetY}
|
|
2522
|
+
* sourcePosition={sourcePosition}
|
|
2523
|
+
* targetPosition={targetPosition}
|
|
2524
|
+
* />
|
|
2525
|
+
* );
|
|
2526
|
+
* }
|
|
2527
|
+
* ```
|
|
2528
|
+
*/
|
|
2485
2529
|
const StepEdge = createStepEdge({ isInternal: false });
|
|
2530
|
+
/**
|
|
2531
|
+
* @internal
|
|
2532
|
+
*/
|
|
2486
2533
|
const StepEdgeInternal = createStepEdge({ isInternal: true });
|
|
2487
2534
|
StepEdge.displayName = 'StepEdge';
|
|
2488
2535
|
StepEdgeInternal.displayName = 'StepEdgeInternal';
|
|
@@ -2495,7 +2542,31 @@ function createStraightEdge(params) {
|
|
|
2495
2542
|
return (jsx(BaseEdge, { id: _id, path: path, labelX: labelX, labelY: labelY, label: label, labelStyle: labelStyle, labelShowBg: labelShowBg, labelBgStyle: labelBgStyle, labelBgPadding: labelBgPadding, labelBgBorderRadius: labelBgBorderRadius, style: style, markerEnd: markerEnd, markerStart: markerStart, interactionWidth: interactionWidth }));
|
|
2496
2543
|
});
|
|
2497
2544
|
}
|
|
2545
|
+
/**
|
|
2546
|
+
* Component that can be used inside a custom edge to render a straight line.
|
|
2547
|
+
*
|
|
2548
|
+
* @public
|
|
2549
|
+
* @example
|
|
2550
|
+
*
|
|
2551
|
+
* ```tsx
|
|
2552
|
+
* import { StraightEdge } from '@xyflow/react';
|
|
2553
|
+
*
|
|
2554
|
+
* function CustomEdge({ sourceX, sourceY, targetX, targetY }) {
|
|
2555
|
+
* return (
|
|
2556
|
+
* <StraightEdge
|
|
2557
|
+
* sourceX={sourceX}
|
|
2558
|
+
* sourceY={sourceY}
|
|
2559
|
+
* targetX={targetX}
|
|
2560
|
+
* targetY={targetY}
|
|
2561
|
+
* />
|
|
2562
|
+
* );
|
|
2563
|
+
* }
|
|
2564
|
+
* ```
|
|
2565
|
+
*/
|
|
2498
2566
|
const StraightEdge = createStraightEdge({ isInternal: false });
|
|
2567
|
+
/**
|
|
2568
|
+
* @internal
|
|
2569
|
+
*/
|
|
2499
2570
|
const StraightEdgeInternal = createStraightEdge({ isInternal: true });
|
|
2500
2571
|
StraightEdge.displayName = 'StraightEdge';
|
|
2501
2572
|
StraightEdgeInternal.displayName = 'StraightEdgeInternal';
|
|
@@ -2516,7 +2587,33 @@ function createBezierEdge(params) {
|
|
|
2516
2587
|
return (jsx(BaseEdge, { id: _id, path: path, labelX: labelX, labelY: labelY, label: label, labelStyle: labelStyle, labelShowBg: labelShowBg, labelBgStyle: labelBgStyle, labelBgPadding: labelBgPadding, labelBgBorderRadius: labelBgBorderRadius, style: style, markerEnd: markerEnd, markerStart: markerStart, interactionWidth: interactionWidth }));
|
|
2517
2588
|
});
|
|
2518
2589
|
}
|
|
2590
|
+
/**
|
|
2591
|
+
* Component that can be used inside a custom edge to render a bezier curve.
|
|
2592
|
+
*
|
|
2593
|
+
* @public
|
|
2594
|
+
* @example
|
|
2595
|
+
*
|
|
2596
|
+
* ```tsx
|
|
2597
|
+
* import { BezierEdge } from '@xyflow/react';
|
|
2598
|
+
*
|
|
2599
|
+
* function CustomEdge({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition }) {
|
|
2600
|
+
* return (
|
|
2601
|
+
* <BezierEdge
|
|
2602
|
+
* sourceX={sourceX}
|
|
2603
|
+
* sourceY={sourceY}
|
|
2604
|
+
* targetX={targetX}
|
|
2605
|
+
* targetY={targetY}
|
|
2606
|
+
* sourcePosition={sourcePosition}
|
|
2607
|
+
* targetPosition={targetPosition}
|
|
2608
|
+
* />
|
|
2609
|
+
* );
|
|
2610
|
+
* }
|
|
2611
|
+
* ```
|
|
2612
|
+
*/
|
|
2519
2613
|
const BezierEdge = createBezierEdge({ isInternal: false });
|
|
2614
|
+
/**
|
|
2615
|
+
* @internal
|
|
2616
|
+
*/
|
|
2520
2617
|
const BezierEdgeInternal = createBezierEdge({ isInternal: true });
|
|
2521
2618
|
BezierEdge.displayName = 'BezierEdge';
|
|
2522
2619
|
BezierEdgeInternal.displayName = 'BezierEdgeInternal';
|
|
@@ -2552,6 +2649,9 @@ const shiftY = (y, shift, position) => {
|
|
|
2552
2649
|
return y;
|
|
2553
2650
|
};
|
|
2554
2651
|
const EdgeUpdaterClassName = 'react-flow__edgeupdater';
|
|
2652
|
+
/**
|
|
2653
|
+
* @internal
|
|
2654
|
+
*/
|
|
2555
2655
|
function EdgeAnchor({ position, centerX, centerY, radius = 10, onMouseDown, onMouseEnter, onMouseOut, type, }) {
|
|
2556
2656
|
return (jsx("circle", { onMouseDown: onMouseDown, onMouseEnter: onMouseEnter, onMouseOut: onMouseOut, className: cc([EdgeUpdaterClassName, `${EdgeUpdaterClassName}-${type}`]), cx: shiftX(centerX, radius, position), cy: shiftY(centerY, radius, position), r: radius, stroke: "transparent", fill: "transparent" }));
|
|
2557
2657
|
}
|
|
@@ -2992,11 +3092,11 @@ const getInitialState = ({ nodes, edges, defaultNodes, defaultEdges, width, heig
|
|
|
2992
3092
|
elementsSelectable: true,
|
|
2993
3093
|
elevateNodesOnSelect: true,
|
|
2994
3094
|
elevateEdgesOnSelect: false,
|
|
2995
|
-
fitViewOnInit: false,
|
|
2996
|
-
fitViewDone: false,
|
|
2997
|
-
fitViewOnInitOptions: undefined,
|
|
2998
3095
|
selectNodesOnDrag: true,
|
|
2999
3096
|
multiSelectionActive: false,
|
|
3097
|
+
fitViewQueued: fitView ?? false,
|
|
3098
|
+
fitViewOptions: undefined,
|
|
3099
|
+
fitViewResolver: null,
|
|
3000
3100
|
connection: { ...initialConnection },
|
|
3001
3101
|
connectionClickStartHandle: null,
|
|
3002
3102
|
connectOnClick: true,
|
|
@@ -3013,274 +3113,256 @@ const getInitialState = ({ nodes, edges, defaultNodes, defaultEdges, width, heig
|
|
|
3013
3113
|
};
|
|
3014
3114
|
};
|
|
3015
3115
|
|
|
3016
|
-
const createStore = ({ nodes, edges, defaultNodes, defaultEdges, width, height, fitView
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
/*
|
|
3021
|
-
* setNodes() is called exclusively in response to user actions:
|
|
3022
|
-
* - either when the `<ReactFlow nodes>` prop is updated in the controlled ReactFlow setup,
|
|
3023
|
-
* - or when the user calls something like `reactFlowInstance.setNodes()` in an uncontrolled ReactFlow setup.
|
|
3024
|
-
*
|
|
3025
|
-
* When this happens, we take the note objects passed by the user and extend them with fields
|
|
3026
|
-
* relevant for internal React Flow operations.
|
|
3027
|
-
*/
|
|
3028
|
-
adoptUserNodes(nodes, nodeLookup, parentLookup, {
|
|
3029
|
-
nodeOrigin,
|
|
3030
|
-
nodeExtent,
|
|
3031
|
-
elevateNodesOnSelect,
|
|
3032
|
-
checkEquality: true,
|
|
3033
|
-
});
|
|
3034
|
-
set({ nodes });
|
|
3035
|
-
},
|
|
3036
|
-
setEdges: (edges) => {
|
|
3037
|
-
const { connectionLookup, edgeLookup } = get();
|
|
3038
|
-
updateConnectionLookup(connectionLookup, edgeLookup, edges);
|
|
3039
|
-
set({ edges });
|
|
3040
|
-
},
|
|
3041
|
-
setDefaultNodesAndEdges: (nodes, edges) => {
|
|
3042
|
-
if (nodes) {
|
|
3043
|
-
const { setNodes } = get();
|
|
3044
|
-
setNodes(nodes);
|
|
3045
|
-
set({ hasDefaultNodes: true });
|
|
3046
|
-
}
|
|
3047
|
-
if (edges) {
|
|
3048
|
-
const { setEdges } = get();
|
|
3049
|
-
setEdges(edges);
|
|
3050
|
-
set({ hasDefaultEdges: true });
|
|
3051
|
-
}
|
|
3052
|
-
},
|
|
3053
|
-
/*
|
|
3054
|
-
* Every node gets registerd at a ResizeObserver. Whenever a node
|
|
3055
|
-
* changes its dimensions, this function is called to measure the
|
|
3056
|
-
* new dimensions and update the nodes.
|
|
3057
|
-
*/
|
|
3058
|
-
updateNodeInternals: (updates, params = { triggerFitView: true }) => {
|
|
3059
|
-
const { triggerNodeChanges, nodeLookup, parentLookup, fitViewOnInit, fitViewDone, fitViewOnInitOptions, domNode, nodeOrigin, nodeExtent, debug, fitViewSync, } = get();
|
|
3060
|
-
const { changes, updatedInternals } = updateNodeInternals(updates, nodeLookup, parentLookup, domNode, nodeOrigin, nodeExtent);
|
|
3061
|
-
if (!updatedInternals) {
|
|
3116
|
+
const createStore = ({ nodes, edges, defaultNodes, defaultEdges, width, height, fitView, nodeOrigin, nodeExtent, }) => createWithEqualityFn((set, get) => {
|
|
3117
|
+
async function resolveFitView() {
|
|
3118
|
+
const { nodeLookup, panZoom, fitViewOptions, fitViewResolver, width, height, minZoom, maxZoom } = get();
|
|
3119
|
+
if (!panZoom || !fitViewResolver) {
|
|
3062
3120
|
return;
|
|
3063
3121
|
}
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3122
|
+
await fitViewport({
|
|
3123
|
+
nodes: nodeLookup,
|
|
3124
|
+
width,
|
|
3125
|
+
height,
|
|
3126
|
+
panZoom,
|
|
3127
|
+
minZoom,
|
|
3128
|
+
maxZoom,
|
|
3129
|
+
}, fitViewOptions);
|
|
3130
|
+
fitViewResolver.resolve(true);
|
|
3131
|
+
/**
|
|
3132
|
+
* wait for the fitViewport to resolve before deleting the resolver,
|
|
3133
|
+
* we want to reuse the old resolver if the user calls fitView again in the mean time
|
|
3134
|
+
*/
|
|
3135
|
+
set({ fitViewResolver: null });
|
|
3136
|
+
}
|
|
3137
|
+
return {
|
|
3138
|
+
...getInitialState({ nodes, edges, width, height, fitView, nodeOrigin, nodeExtent, defaultNodes, defaultEdges }),
|
|
3139
|
+
setNodes: (nodes) => {
|
|
3140
|
+
const { nodeLookup, parentLookup, nodeOrigin, elevateNodesOnSelect, fitViewQueued } = get();
|
|
3074
3141
|
/*
|
|
3075
|
-
*
|
|
3076
|
-
*
|
|
3077
|
-
*
|
|
3078
|
-
*
|
|
3079
|
-
*
|
|
3142
|
+
* setNodes() is called exclusively in response to user actions:
|
|
3143
|
+
* - either when the `<ReactFlow nodes>` prop is updated in the controlled ReactFlow setup,
|
|
3144
|
+
* - or when the user calls something like `reactFlowInstance.setNodes()` in an uncontrolled ReactFlow setup.
|
|
3145
|
+
*
|
|
3146
|
+
* When this happens, we take the note objects passed by the user and extend them with fields
|
|
3147
|
+
* relevant for internal React Flow operations.
|
|
3080
3148
|
*/
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3149
|
+
const nodesInitialized = adoptUserNodes(nodes, nodeLookup, parentLookup, {
|
|
3150
|
+
nodeOrigin,
|
|
3151
|
+
nodeExtent,
|
|
3152
|
+
elevateNodesOnSelect,
|
|
3153
|
+
checkEquality: true,
|
|
3154
|
+
});
|
|
3155
|
+
if (fitViewQueued && nodesInitialized) {
|
|
3156
|
+
resolveFitView();
|
|
3157
|
+
set({ nodes, fitViewQueued: false, fitViewOptions: undefined });
|
|
3090
3158
|
}
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3159
|
+
else {
|
|
3160
|
+
set({ nodes });
|
|
3161
|
+
}
|
|
3162
|
+
},
|
|
3163
|
+
setEdges: (edges) => {
|
|
3164
|
+
const { connectionLookup, edgeLookup } = get();
|
|
3165
|
+
updateConnectionLookup(connectionLookup, edgeLookup, edges);
|
|
3166
|
+
set({ edges });
|
|
3167
|
+
},
|
|
3168
|
+
setDefaultNodesAndEdges: (nodes, edges) => {
|
|
3169
|
+
if (nodes) {
|
|
3170
|
+
const { setNodes } = get();
|
|
3171
|
+
setNodes(nodes);
|
|
3172
|
+
set({ hasDefaultNodes: true });
|
|
3173
|
+
}
|
|
3174
|
+
if (edges) {
|
|
3175
|
+
const { setEdges } = get();
|
|
3176
|
+
setEdges(edges);
|
|
3177
|
+
set({ hasDefaultEdges: true });
|
|
3178
|
+
}
|
|
3179
|
+
},
|
|
3180
|
+
/*
|
|
3181
|
+
* Every node gets registerd at a ResizeObserver. Whenever a node
|
|
3182
|
+
* changes its dimensions, this function is called to measure the
|
|
3183
|
+
* new dimensions and update the nodes.
|
|
3184
|
+
*/
|
|
3185
|
+
updateNodeInternals: (updates) => {
|
|
3186
|
+
const { triggerNodeChanges, nodeLookup, parentLookup, domNode, nodeOrigin, nodeExtent, debug, fitViewQueued } = get();
|
|
3187
|
+
const { changes, updatedInternals } = updateNodeInternals(updates, nodeLookup, parentLookup, domNode, nodeOrigin, nodeExtent);
|
|
3188
|
+
if (!updatedInternals) {
|
|
3189
|
+
return;
|
|
3190
|
+
}
|
|
3191
|
+
updateAbsolutePositions(nodeLookup, parentLookup, { nodeOrigin, nodeExtent });
|
|
3192
|
+
if (fitViewQueued) {
|
|
3193
|
+
resolveFitView();
|
|
3194
|
+
set({ fitViewQueued: false, fitViewOptions: undefined });
|
|
3195
|
+
}
|
|
3196
|
+
else {
|
|
3197
|
+
// we always want to trigger useStore calls whenever updateNodeInternals is called
|
|
3198
|
+
set({});
|
|
3199
|
+
}
|
|
3200
|
+
if (changes?.length > 0) {
|
|
3201
|
+
if (debug) {
|
|
3202
|
+
console.log('React Flow: trigger node changes', changes);
|
|
3203
|
+
}
|
|
3204
|
+
triggerNodeChanges?.(changes);
|
|
3205
|
+
}
|
|
3206
|
+
},
|
|
3207
|
+
updateNodePositions: (nodeDragItems, dragging = false) => {
|
|
3208
|
+
const parentExpandChildren = [];
|
|
3209
|
+
const changes = [];
|
|
3210
|
+
const { nodeLookup, triggerNodeChanges } = get();
|
|
3211
|
+
for (const [id, dragItem] of nodeDragItems) {
|
|
3212
|
+
// we are using the nodelookup to be sure to use the current expandParent and parentId value
|
|
3213
|
+
const node = nodeLookup.get(id);
|
|
3214
|
+
const expandParent = !!(node?.expandParent && node?.parentId && dragItem?.position);
|
|
3215
|
+
const change = {
|
|
3112
3216
|
id,
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3217
|
+
type: 'position',
|
|
3218
|
+
position: expandParent
|
|
3219
|
+
? {
|
|
3220
|
+
x: Math.max(0, dragItem.position.x),
|
|
3221
|
+
y: Math.max(0, dragItem.position.y),
|
|
3222
|
+
}
|
|
3223
|
+
: dragItem.position,
|
|
3224
|
+
dragging,
|
|
3225
|
+
};
|
|
3226
|
+
if (expandParent && node.parentId) {
|
|
3227
|
+
parentExpandChildren.push({
|
|
3228
|
+
id,
|
|
3229
|
+
parentId: node.parentId,
|
|
3230
|
+
rect: {
|
|
3231
|
+
...dragItem.internals.positionAbsolute,
|
|
3232
|
+
width: dragItem.measured.width ?? 0,
|
|
3233
|
+
height: dragItem.measured.height ?? 0,
|
|
3234
|
+
},
|
|
3235
|
+
});
|
|
3236
|
+
}
|
|
3237
|
+
changes.push(change);
|
|
3120
3238
|
}
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
changes
|
|
3127
|
-
}
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3239
|
+
if (parentExpandChildren.length > 0) {
|
|
3240
|
+
const { parentLookup, nodeOrigin } = get();
|
|
3241
|
+
const parentExpandChanges = handleExpandParent(parentExpandChildren, nodeLookup, parentLookup, nodeOrigin);
|
|
3242
|
+
changes.push(...parentExpandChanges);
|
|
3243
|
+
}
|
|
3244
|
+
triggerNodeChanges(changes);
|
|
3245
|
+
},
|
|
3246
|
+
triggerNodeChanges: (changes) => {
|
|
3247
|
+
const { onNodesChange, setNodes, nodes, hasDefaultNodes, debug } = get();
|
|
3248
|
+
if (changes?.length) {
|
|
3249
|
+
if (hasDefaultNodes) {
|
|
3250
|
+
const updatedNodes = applyNodeChanges(changes, nodes);
|
|
3251
|
+
setNodes(updatedNodes);
|
|
3252
|
+
}
|
|
3253
|
+
if (debug) {
|
|
3254
|
+
console.log('React Flow: trigger node changes', changes);
|
|
3255
|
+
}
|
|
3256
|
+
onNodesChange?.(changes);
|
|
3136
3257
|
}
|
|
3137
|
-
|
|
3138
|
-
|
|
3258
|
+
},
|
|
3259
|
+
triggerEdgeChanges: (changes) => {
|
|
3260
|
+
const { onEdgesChange, setEdges, edges, hasDefaultEdges, debug } = get();
|
|
3261
|
+
if (changes?.length) {
|
|
3262
|
+
if (hasDefaultEdges) {
|
|
3263
|
+
const updatedEdges = applyEdgeChanges(changes, edges);
|
|
3264
|
+
setEdges(updatedEdges);
|
|
3265
|
+
}
|
|
3266
|
+
if (debug) {
|
|
3267
|
+
console.log('React Flow: trigger edge changes', changes);
|
|
3268
|
+
}
|
|
3269
|
+
onEdgesChange?.(changes);
|
|
3139
3270
|
}
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
const updatedEdges = applyEdgeChanges(changes, edges);
|
|
3148
|
-
setEdges(updatedEdges);
|
|
3271
|
+
},
|
|
3272
|
+
addSelectedNodes: (selectedNodeIds) => {
|
|
3273
|
+
const { multiSelectionActive, edgeLookup, nodeLookup, triggerNodeChanges, triggerEdgeChanges } = get();
|
|
3274
|
+
if (multiSelectionActive) {
|
|
3275
|
+
const nodeChanges = selectedNodeIds.map((nodeId) => createSelectionChange(nodeId, true));
|
|
3276
|
+
triggerNodeChanges(nodeChanges);
|
|
3277
|
+
return;
|
|
3149
3278
|
}
|
|
3150
|
-
|
|
3151
|
-
|
|
3279
|
+
triggerNodeChanges(getSelectionChanges(nodeLookup, new Set([...selectedNodeIds]), true));
|
|
3280
|
+
triggerEdgeChanges(getSelectionChanges(edgeLookup));
|
|
3281
|
+
},
|
|
3282
|
+
addSelectedEdges: (selectedEdgeIds) => {
|
|
3283
|
+
const { multiSelectionActive, edgeLookup, nodeLookup, triggerNodeChanges, triggerEdgeChanges } = get();
|
|
3284
|
+
if (multiSelectionActive) {
|
|
3285
|
+
const changedEdges = selectedEdgeIds.map((edgeId) => createSelectionChange(edgeId, true));
|
|
3286
|
+
triggerEdgeChanges(changedEdges);
|
|
3287
|
+
return;
|
|
3152
3288
|
}
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
const
|
|
3289
|
+
triggerEdgeChanges(getSelectionChanges(edgeLookup, new Set([...selectedEdgeIds])));
|
|
3290
|
+
triggerNodeChanges(getSelectionChanges(nodeLookup, new Set(), true));
|
|
3291
|
+
},
|
|
3292
|
+
unselectNodesAndEdges: ({ nodes, edges } = {}) => {
|
|
3293
|
+
const { edges: storeEdges, nodes: storeNodes, nodeLookup, triggerNodeChanges, triggerEdgeChanges } = get();
|
|
3294
|
+
const nodesToUnselect = nodes ? nodes : storeNodes;
|
|
3295
|
+
const edgesToUnselect = edges ? edges : storeEdges;
|
|
3296
|
+
const nodeChanges = nodesToUnselect.map((n) => {
|
|
3297
|
+
const internalNode = nodeLookup.get(n.id);
|
|
3298
|
+
if (internalNode) {
|
|
3299
|
+
/*
|
|
3300
|
+
* we need to unselect the internal node that was selected previously before we
|
|
3301
|
+
* send the change to the user to prevent it to be selected while dragging the new node
|
|
3302
|
+
*/
|
|
3303
|
+
internalNode.selected = false;
|
|
3304
|
+
}
|
|
3305
|
+
return createSelectionChange(n.id, false);
|
|
3306
|
+
});
|
|
3307
|
+
const edgeChanges = edgesToUnselect.map((edge) => createSelectionChange(edge.id, false));
|
|
3160
3308
|
triggerNodeChanges(nodeChanges);
|
|
3161
|
-
|
|
3162
|
-
}
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
const
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
}
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
const
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3309
|
+
triggerEdgeChanges(edgeChanges);
|
|
3310
|
+
},
|
|
3311
|
+
setMinZoom: (minZoom) => {
|
|
3312
|
+
const { panZoom, maxZoom } = get();
|
|
3313
|
+
panZoom?.setScaleExtent([minZoom, maxZoom]);
|
|
3314
|
+
set({ minZoom });
|
|
3315
|
+
},
|
|
3316
|
+
setMaxZoom: (maxZoom) => {
|
|
3317
|
+
const { panZoom, minZoom } = get();
|
|
3318
|
+
panZoom?.setScaleExtent([minZoom, maxZoom]);
|
|
3319
|
+
set({ maxZoom });
|
|
3320
|
+
},
|
|
3321
|
+
setTranslateExtent: (translateExtent) => {
|
|
3322
|
+
get().panZoom?.setTranslateExtent(translateExtent);
|
|
3323
|
+
set({ translateExtent });
|
|
3324
|
+
},
|
|
3325
|
+
setPaneClickDistance: (clickDistance) => {
|
|
3326
|
+
get().panZoom?.setClickDistance(clickDistance);
|
|
3327
|
+
},
|
|
3328
|
+
resetSelectedElements: () => {
|
|
3329
|
+
const { edges, nodes, triggerNodeChanges, triggerEdgeChanges } = get();
|
|
3330
|
+
const nodeChanges = nodes.reduce((res, node) => (node.selected ? [...res, createSelectionChange(node.id, false)] : res), []);
|
|
3331
|
+
const edgeChanges = edges.reduce((res, edge) => (edge.selected ? [...res, createSelectionChange(edge.id, false)] : res), []);
|
|
3332
|
+
triggerNodeChanges(nodeChanges);
|
|
3333
|
+
triggerEdgeChanges(edgeChanges);
|
|
3334
|
+
},
|
|
3335
|
+
setNodeExtent: (nextNodeExtent) => {
|
|
3336
|
+
const { nodes, nodeLookup, parentLookup, nodeOrigin, elevateNodesOnSelect, nodeExtent } = get();
|
|
3337
|
+
if (nextNodeExtent[0][0] === nodeExtent[0][0] &&
|
|
3338
|
+
nextNodeExtent[0][1] === nodeExtent[0][1] &&
|
|
3339
|
+
nextNodeExtent[1][0] === nodeExtent[1][0] &&
|
|
3340
|
+
nextNodeExtent[1][1] === nodeExtent[1][1]) {
|
|
3341
|
+
return;
|
|
3188
3342
|
}
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
resetSelectedElements: () => {
|
|
3213
|
-
const { edges, nodes, triggerNodeChanges, triggerEdgeChanges } = get();
|
|
3214
|
-
const nodeChanges = nodes.reduce((res, node) => (node.selected ? [...res, createSelectionChange(node.id, false)] : res), []);
|
|
3215
|
-
const edgeChanges = edges.reduce((res, edge) => (edge.selected ? [...res, createSelectionChange(edge.id, false)] : res), []);
|
|
3216
|
-
triggerNodeChanges(nodeChanges);
|
|
3217
|
-
triggerEdgeChanges(edgeChanges);
|
|
3218
|
-
},
|
|
3219
|
-
setNodeExtent: (nextNodeExtent) => {
|
|
3220
|
-
const { nodes, nodeLookup, parentLookup, nodeOrigin, elevateNodesOnSelect, nodeExtent } = get();
|
|
3221
|
-
if (nextNodeExtent[0][0] === nodeExtent[0][0] &&
|
|
3222
|
-
nextNodeExtent[0][1] === nodeExtent[0][1] &&
|
|
3223
|
-
nextNodeExtent[1][0] === nodeExtent[1][0] &&
|
|
3224
|
-
nextNodeExtent[1][1] === nodeExtent[1][1]) {
|
|
3225
|
-
return;
|
|
3226
|
-
}
|
|
3227
|
-
adoptUserNodes(nodes, nodeLookup, parentLookup, {
|
|
3228
|
-
nodeOrigin,
|
|
3229
|
-
nodeExtent: nextNodeExtent,
|
|
3230
|
-
elevateNodesOnSelect,
|
|
3231
|
-
checkEquality: false,
|
|
3232
|
-
});
|
|
3233
|
-
set({ nodeExtent: nextNodeExtent });
|
|
3234
|
-
},
|
|
3235
|
-
panBy: (delta) => {
|
|
3236
|
-
const { transform, width, height, panZoom, translateExtent } = get();
|
|
3237
|
-
return panBy({ delta, panZoom, transform, translateExtent, width, height });
|
|
3238
|
-
},
|
|
3239
|
-
fitView: (options) => {
|
|
3240
|
-
const { panZoom, width, height, minZoom, maxZoom, nodeLookup } = get();
|
|
3241
|
-
if (!panZoom) {
|
|
3242
|
-
return Promise.resolve(false);
|
|
3243
|
-
}
|
|
3244
|
-
const fitViewNodes = getFitViewNodes(nodeLookup, options);
|
|
3245
|
-
return fitView({
|
|
3246
|
-
nodes: fitViewNodes,
|
|
3247
|
-
width,
|
|
3248
|
-
height,
|
|
3249
|
-
panZoom,
|
|
3250
|
-
minZoom,
|
|
3251
|
-
maxZoom,
|
|
3252
|
-
}, options);
|
|
3253
|
-
},
|
|
3254
|
-
/*
|
|
3255
|
-
* we can't call an asnychronous function in updateNodeInternals
|
|
3256
|
-
* for that we created this sync version of fitView
|
|
3257
|
-
*/
|
|
3258
|
-
fitViewSync: (options) => {
|
|
3259
|
-
const { panZoom, width, height, minZoom, maxZoom, nodeLookup } = get();
|
|
3260
|
-
if (!panZoom) {
|
|
3261
|
-
return false;
|
|
3262
|
-
}
|
|
3263
|
-
const fitViewNodes = getFitViewNodes(nodeLookup, options);
|
|
3264
|
-
fitView({
|
|
3265
|
-
nodes: fitViewNodes,
|
|
3266
|
-
width,
|
|
3267
|
-
height,
|
|
3268
|
-
panZoom,
|
|
3269
|
-
minZoom,
|
|
3270
|
-
maxZoom,
|
|
3271
|
-
}, options);
|
|
3272
|
-
return fitViewNodes.size > 0;
|
|
3273
|
-
},
|
|
3274
|
-
cancelConnection: () => {
|
|
3275
|
-
set({
|
|
3276
|
-
connection: { ...initialConnection },
|
|
3277
|
-
});
|
|
3278
|
-
},
|
|
3279
|
-
updateConnection: (connection) => {
|
|
3280
|
-
set({ connection });
|
|
3281
|
-
},
|
|
3282
|
-
reset: () => set({ ...getInitialState() }),
|
|
3283
|
-
}), Object.is);
|
|
3343
|
+
adoptUserNodes(nodes, nodeLookup, parentLookup, {
|
|
3344
|
+
nodeOrigin,
|
|
3345
|
+
nodeExtent: nextNodeExtent,
|
|
3346
|
+
elevateNodesOnSelect,
|
|
3347
|
+
checkEquality: false,
|
|
3348
|
+
});
|
|
3349
|
+
set({ nodeExtent: nextNodeExtent });
|
|
3350
|
+
},
|
|
3351
|
+
panBy: (delta) => {
|
|
3352
|
+
const { transform, width, height, panZoom, translateExtent } = get();
|
|
3353
|
+
return panBy({ delta, panZoom, transform, translateExtent, width, height });
|
|
3354
|
+
},
|
|
3355
|
+
cancelConnection: () => {
|
|
3356
|
+
set({
|
|
3357
|
+
connection: { ...initialConnection },
|
|
3358
|
+
});
|
|
3359
|
+
},
|
|
3360
|
+
updateConnection: (connection) => {
|
|
3361
|
+
set({ connection });
|
|
3362
|
+
},
|
|
3363
|
+
reset: () => set({ ...getInitialState() }),
|
|
3364
|
+
};
|
|
3365
|
+
}, Object.is);
|
|
3284
3366
|
|
|
3285
3367
|
/**
|
|
3286
3368
|
* The `<ReactFlowProvider />` component is a [context provider](https://react.dev/learn/passing-data-deeply-with-context#)
|
|
@@ -3387,37 +3469,38 @@ const selector$6 = (s) => s.domNode?.querySelector('.react-flow__edgelabel-rende
|
|
|
3387
3469
|
* Edges are SVG-based. If you want to render more complex labels you can use the
|
|
3388
3470
|
* `<EdgeLabelRenderer />` component to access a div based renderer. This component
|
|
3389
3471
|
* is a portal that renders the label in a `<div />` that is positioned on top of
|
|
3390
|
-
* the edges. You can see an example usage of the component in the
|
|
3472
|
+
* the edges. You can see an example usage of the component in the
|
|
3473
|
+
* [edge label renderer example](/examples/edges/edge-label-renderer).
|
|
3391
3474
|
* @public
|
|
3392
3475
|
*
|
|
3393
3476
|
* @example
|
|
3394
|
-
|
|
3395
|
-
*import React from 'react';
|
|
3396
|
-
*import { getBezierPath, EdgeLabelRenderer, BaseEdge } from '@xyflow/react';
|
|
3477
|
+
* ```jsx
|
|
3478
|
+
* import React from 'react';
|
|
3479
|
+
* import { getBezierPath, EdgeLabelRenderer, BaseEdge } from '@xyflow/react';
|
|
3397
3480
|
*
|
|
3398
|
-
*export function CustomEdge({ id, data, ...props }) {
|
|
3399
|
-
*
|
|
3481
|
+
* export function CustomEdge({ id, data, ...props }) {
|
|
3482
|
+
* const [edgePath, labelX, labelY] = getBezierPath(props);
|
|
3400
3483
|
*
|
|
3401
|
-
*
|
|
3402
|
-
*
|
|
3403
|
-
*
|
|
3404
|
-
*
|
|
3405
|
-
*
|
|
3406
|
-
*
|
|
3407
|
-
*
|
|
3408
|
-
*
|
|
3409
|
-
*
|
|
3410
|
-
*
|
|
3411
|
-
*
|
|
3412
|
-
*
|
|
3413
|
-
*
|
|
3414
|
-
*
|
|
3415
|
-
*
|
|
3416
|
-
*
|
|
3417
|
-
*
|
|
3418
|
-
*
|
|
3419
|
-
*};
|
|
3420
|
-
|
|
3484
|
+
* return (
|
|
3485
|
+
* <>
|
|
3486
|
+
* <BaseEdge id={id} path={edgePath} />
|
|
3487
|
+
* <EdgeLabelRenderer>
|
|
3488
|
+
* <div
|
|
3489
|
+
* style={{
|
|
3490
|
+
* position: 'absolute',
|
|
3491
|
+
* transform: `translate(-50%, -50%) translate(${labelX}px,${labelY}px)`,
|
|
3492
|
+
* background: '#ffcc00',
|
|
3493
|
+
* padding: 10,
|
|
3494
|
+
* }}
|
|
3495
|
+
* className="nodrag nopan"
|
|
3496
|
+
* >
|
|
3497
|
+
* {data.label}
|
|
3498
|
+
* </div>
|
|
3499
|
+
* </EdgeLabelRenderer>
|
|
3500
|
+
* </>
|
|
3501
|
+
* );
|
|
3502
|
+
* };
|
|
3503
|
+
* ```
|
|
3421
3504
|
*
|
|
3422
3505
|
* @remarks The `<EdgeLabelRenderer />` has no pointer events by default. If you want to
|
|
3423
3506
|
* add mouse interactions you need to set the style `pointerEvents: all` and add
|
|
@@ -3775,7 +3858,7 @@ function useOnViewportChange({ onStart, onChange, onEnd }) {
|
|
|
3775
3858
|
*
|
|
3776
3859
|
* @remarks You need to memoize the passed `onChange` handler, otherwise the hook will not work correctly.
|
|
3777
3860
|
*/
|
|
3778
|
-
function useOnSelectionChange({ onChange }) {
|
|
3861
|
+
function useOnSelectionChange({ onChange, }) {
|
|
3779
3862
|
const store = useStoreApi();
|
|
3780
3863
|
useEffect(() => {
|
|
3781
3864
|
const nextOnSelectionChangeHandlers = [...store.getState().onSelectionChangeHandlers, onChange];
|
|
@@ -3888,7 +3971,7 @@ const error014 = errorMessages['error014']();
|
|
|
3888
3971
|
*
|
|
3889
3972
|
*export default function () {
|
|
3890
3973
|
* const connections = useNodeConnections({
|
|
3891
|
-
*
|
|
3974
|
+
* handleType: 'target',
|
|
3892
3975
|
* handleId: 'my-handle',
|
|
3893
3976
|
* });
|
|
3894
3977
|
*
|
|
@@ -4240,6 +4323,7 @@ var MiniMapNodes$1 = memo(MiniMapNodes);
|
|
|
4240
4323
|
|
|
4241
4324
|
const defaultWidth = 200;
|
|
4242
4325
|
const defaultHeight = 150;
|
|
4326
|
+
const filterHidden = (node) => !node.hidden;
|
|
4243
4327
|
const selector$1 = (s) => {
|
|
4244
4328
|
const viewBB = {
|
|
4245
4329
|
x: -s.transform[0] / s.transform[2],
|
|
@@ -4249,7 +4333,9 @@ const selector$1 = (s) => {
|
|
|
4249
4333
|
};
|
|
4250
4334
|
return {
|
|
4251
4335
|
viewBB,
|
|
4252
|
-
boundingRect: s.nodeLookup.size > 0
|
|
4336
|
+
boundingRect: s.nodeLookup.size > 0
|
|
4337
|
+
? getBoundsOfRects(getInternalNodesBounds(s.nodeLookup, { filter: filterHidden }), viewBB)
|
|
4338
|
+
: viewBB,
|
|
4253
4339
|
rfId: s.rfId,
|
|
4254
4340
|
panZoom: s.panZoom,
|
|
4255
4341
|
translateExtent: s.translateExtent,
|
|
@@ -4388,8 +4474,8 @@ function ResizeControl({ nodeId, position, variant = ResizeControlVariant.Handle
|
|
|
4388
4474
|
const node = nodeLookup.get(id);
|
|
4389
4475
|
if (node && node.expandParent && node.parentId) {
|
|
4390
4476
|
const origin = node.origin ?? nodeOrigin;
|
|
4391
|
-
const width = change.width ?? node.measured.width;
|
|
4392
|
-
const height = change.height ?? node.measured.height;
|
|
4477
|
+
const width = change.width ?? node.measured.width ?? 0;
|
|
4478
|
+
const height = change.height ?? node.measured.height ?? 0;
|
|
4393
4479
|
const child = {
|
|
4394
4480
|
id: node.id,
|
|
4395
4481
|
parentId: node.parentId,
|