@xyflow/react 12.0.0-next.5 → 12.0.0-next.7
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/LICENSE +1 -1
- package/dist/esm/additional-components/Background/types.d.ts +13 -0
- package/dist/esm/additional-components/Background/types.d.ts.map +1 -1
- package/dist/esm/additional-components/Controls/Controls.d.ts +1 -1
- package/dist/esm/additional-components/Controls/Controls.d.ts.map +1 -1
- package/dist/esm/additional-components/Controls/types.d.ts +19 -2
- package/dist/esm/additional-components/Controls/types.d.ts.map +1 -1
- package/dist/esm/additional-components/MiniMap/types.d.ts +21 -0
- package/dist/esm/additional-components/MiniMap/types.d.ts.map +1 -1
- package/dist/esm/additional-components/NodeResizer/types.d.ts +25 -0
- package/dist/esm/additional-components/NodeResizer/types.d.ts.map +1 -1
- package/dist/esm/additional-components/NodeToolbar/types.d.ts +10 -0
- package/dist/esm/additional-components/NodeToolbar/types.d.ts.map +1 -1
- package/dist/esm/components/EdgeWrapper/EdgeUpdateAnchors.d.ts.map +1 -1
- package/dist/esm/components/Handle/index.d.ts.map +1 -1
- package/dist/esm/components/Panel/index.d.ts +3 -0
- package/dist/esm/components/Panel/index.d.ts.map +1 -1
- package/dist/esm/container/ReactFlow/index.d.ts +3 -3
- package/dist/esm/hooks/useNodesEdgesState.d.ts +2 -2
- package/dist/esm/hooks/useNodesEdgesState.d.ts.map +1 -1
- package/dist/esm/hooks/useReactFlow.d.ts.map +1 -1
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +168 -163
- package/dist/esm/index.mjs +168 -163
- package/dist/esm/types/changes.d.ts +8 -6
- package/dist/esm/types/changes.d.ts.map +1 -1
- package/dist/esm/types/component-props.d.ts +339 -1
- package/dist/esm/types/component-props.d.ts.map +1 -1
- package/dist/esm/types/edges.d.ts +11 -0
- package/dist/esm/types/edges.d.ts.map +1 -1
- package/dist/esm/types/general.d.ts +5 -3
- package/dist/esm/types/general.d.ts.map +1 -1
- package/dist/esm/types/instance.d.ts +1 -11
- package/dist/esm/types/instance.d.ts.map +1 -1
- package/dist/esm/utils/changes.d.ts +20 -2
- package/dist/esm/utils/changes.d.ts.map +1 -1
- package/dist/esm/utils/general.d.ts +2 -49
- package/dist/esm/utils/general.d.ts.map +1 -1
- package/dist/umd/additional-components/Background/types.d.ts +13 -0
- package/dist/umd/additional-components/Background/types.d.ts.map +1 -1
- package/dist/umd/additional-components/Controls/Controls.d.ts +1 -1
- package/dist/umd/additional-components/Controls/Controls.d.ts.map +1 -1
- package/dist/umd/additional-components/Controls/types.d.ts +19 -2
- package/dist/umd/additional-components/Controls/types.d.ts.map +1 -1
- package/dist/umd/additional-components/MiniMap/types.d.ts +21 -0
- package/dist/umd/additional-components/MiniMap/types.d.ts.map +1 -1
- package/dist/umd/additional-components/NodeResizer/types.d.ts +25 -0
- package/dist/umd/additional-components/NodeResizer/types.d.ts.map +1 -1
- package/dist/umd/additional-components/NodeToolbar/types.d.ts +10 -0
- package/dist/umd/additional-components/NodeToolbar/types.d.ts.map +1 -1
- package/dist/umd/components/EdgeWrapper/EdgeUpdateAnchors.d.ts.map +1 -1
- package/dist/umd/components/Handle/index.d.ts.map +1 -1
- package/dist/umd/components/Panel/index.d.ts +3 -0
- package/dist/umd/components/Panel/index.d.ts.map +1 -1
- package/dist/umd/container/ReactFlow/index.d.ts +3 -3
- package/dist/umd/hooks/useNodesEdgesState.d.ts +2 -2
- package/dist/umd/hooks/useNodesEdgesState.d.ts.map +1 -1
- package/dist/umd/hooks/useReactFlow.d.ts.map +1 -1
- package/dist/umd/index.d.ts +2 -2
- package/dist/umd/index.d.ts.map +1 -1
- package/dist/umd/index.js +2 -2
- package/dist/umd/types/changes.d.ts +8 -6
- package/dist/umd/types/changes.d.ts.map +1 -1
- package/dist/umd/types/component-props.d.ts +339 -1
- package/dist/umd/types/component-props.d.ts.map +1 -1
- package/dist/umd/types/edges.d.ts +11 -0
- package/dist/umd/types/edges.d.ts.map +1 -1
- package/dist/umd/types/general.d.ts +5 -3
- package/dist/umd/types/general.d.ts.map +1 -1
- package/dist/umd/types/instance.d.ts +1 -11
- package/dist/umd/types/instance.d.ts.map +1 -1
- package/dist/umd/utils/changes.d.ts +20 -2
- package/dist/umd/utils/changes.d.ts.map +1 -1
- package/dist/umd/utils/general.d.ts +2 -49
- package/dist/umd/utils/general.d.ts.map +1 -1
- package/package.json +4 -4
package/dist/esm/index.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
3
3
|
import { createContext, useContext, useMemo, useEffect, useRef, useState, useCallback, forwardRef, memo } from 'react';
|
|
4
4
|
import cc from 'classcat';
|
|
5
|
-
import { errorMessages, infiniteExtent, isInputDOMNode, fitView, getViewportForBounds, pointToRendererPoint, rendererPointToPoint, isNodeBase, isEdgeBase,
|
|
6
|
-
export { ConnectionLineType, ConnectionMode, MarkerType, PanOnScrollMode, Position, SelectionMode, getBezierEdgeCenter, getBezierPath, getEdgeCenter, getNodesBounds, getSmoothStepPath, getStraightPath, getViewportForBounds, internalsSymbol } from '@xyflow/system';
|
|
5
|
+
import { errorMessages, infiniteExtent, isInputDOMNode, fitView, getViewportForBounds, pointToRendererPoint, rendererPointToPoint, isNodeBase, isEdgeBase, getElementsToRemove, isRectObject, nodeToRect, getOverlappingArea, getDimensions, XYPanZoom, PanOnScrollMode, SelectionMode, getEventPosition, getNodesInside, XYDrag, snapPosition, calcNextPosition, 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, updateNodeDimensions, updateAbsolutePositions, panBy, isMacOs, areConnectionMapsEqual, handleConnectionChange, getNodePositionWithOrigin, XYMinimap, getBoundsOfRects, ResizeControlVariant, XYResizer, XY_RESIZER_LINE_POSITIONS, XY_RESIZER_HANDLE_POSITIONS, getNodeToolbarTransform } from '@xyflow/system';
|
|
6
|
+
export { ConnectionLineType, ConnectionMode, MarkerType, PanOnScrollMode, Position, SelectionMode, addEdge, getBezierEdgeCenter, getBezierPath, getConnectedEdges, getEdgeCenter, getIncomers, getNodesBounds, getOutgoers, getSmoothStepPath, getStraightPath, getViewportForBounds, internalsSymbol, updateEdge } from '@xyflow/system';
|
|
7
7
|
import { useStoreWithEqualityFn, createWithEqualityFn } from 'zustand/traditional';
|
|
8
8
|
import { shallow } from 'zustand/shallow';
|
|
9
9
|
import { createPortal } from 'react-dom';
|
|
@@ -424,8 +424,8 @@ const useViewportHelper = () => {
|
|
|
424
424
|
const viewport = getViewportForBounds(bounds, width, height, minZoom, maxZoom, options?.padding ?? 0.1);
|
|
425
425
|
panZoom?.setViewport(viewport, { duration: options?.duration });
|
|
426
426
|
},
|
|
427
|
-
screenToFlowPosition: (position) => {
|
|
428
|
-
const { transform,
|
|
427
|
+
screenToFlowPosition: (position, options = { snapToGrid: true }) => {
|
|
428
|
+
const { transform, snapGrid, domNode } = store.getState();
|
|
429
429
|
if (!domNode) {
|
|
430
430
|
return position;
|
|
431
431
|
}
|
|
@@ -434,7 +434,7 @@ const useViewportHelper = () => {
|
|
|
434
434
|
x: position.x - domX,
|
|
435
435
|
y: position.y - domY,
|
|
436
436
|
};
|
|
437
|
-
return pointToRendererPoint(correctedPosition, transform, snapToGrid, snapGrid
|
|
437
|
+
return pointToRendererPoint(correctedPosition, transform, options.snapToGrid, snapGrid);
|
|
438
438
|
},
|
|
439
439
|
flowToScreenPosition: (position) => {
|
|
440
440
|
const { transform, domNode } = store.getState();
|
|
@@ -496,97 +496,102 @@ function handleParentExpand(updatedElements, updateItem) {
|
|
|
496
496
|
// When you drag a node for example, React Flow will send a position change update.
|
|
497
497
|
// This function then applies the changes and returns the updated elements.
|
|
498
498
|
function applyChanges(changes, elements) {
|
|
499
|
-
// we need this hack to handle the setNodes and setEdges function of the useReactFlow hook for controlled flows
|
|
500
|
-
if (changes.some((c) => c.type === 'reset')) {
|
|
501
|
-
return changes.filter((c) => c.type === 'reset').map((c) => c.item);
|
|
502
|
-
}
|
|
503
|
-
let remainingChanges = [];
|
|
504
499
|
const updatedElements = [];
|
|
500
|
+
// By storing a map of changes for each element, we can a quick lookup as we
|
|
501
|
+
// iterate over the elements array!
|
|
502
|
+
const changesMap = new Map();
|
|
505
503
|
for (const change of changes) {
|
|
506
504
|
if (change.type === 'add') {
|
|
507
505
|
updatedElements.push(change.item);
|
|
506
|
+
continue;
|
|
508
507
|
}
|
|
509
|
-
else {
|
|
510
|
-
|
|
508
|
+
else if (change.type === 'remove' || change.type === 'replace') {
|
|
509
|
+
// For a 'remove' change we can safely ignore any other changes queued for
|
|
510
|
+
// the same element, it's going to be removed anyway!
|
|
511
|
+
changesMap.set(change.id, [change]);
|
|
511
512
|
}
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
nextChanges.push(change);
|
|
513
|
+
else {
|
|
514
|
+
const elementChanges = changesMap.get(change.id);
|
|
515
|
+
if (elementChanges) {
|
|
516
|
+
// If we have some changes queued already, we can do a mutable update of
|
|
517
|
+
// that array and save ourselves some copying.
|
|
518
|
+
elementChanges.push(change);
|
|
519
519
|
}
|
|
520
520
|
else {
|
|
521
|
-
|
|
521
|
+
changesMap.set(change.id, [change]);
|
|
522
522
|
}
|
|
523
523
|
}
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
524
|
+
}
|
|
525
|
+
for (const element of elements) {
|
|
526
|
+
const changes = changesMap.get(element.id);
|
|
527
|
+
// When there are no changes for an element we can just push it unmodified,
|
|
528
|
+
// no need to copy it.
|
|
529
|
+
if (!changes) {
|
|
530
|
+
updatedElements.push(element);
|
|
527
531
|
continue;
|
|
528
532
|
}
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
break;
|
|
537
|
-
}
|
|
538
|
-
case 'position': {
|
|
539
|
-
if (typeof currentChange.position !== 'undefined') {
|
|
540
|
-
updateItem.position = currentChange.position;
|
|
541
|
-
}
|
|
542
|
-
if (typeof currentChange.positionAbsolute !== 'undefined') {
|
|
543
|
-
if (!updateItem.computed) {
|
|
544
|
-
updateItem.computed = {};
|
|
545
|
-
}
|
|
546
|
-
updateItem.computed.positionAbsolute = currentChange.positionAbsolute;
|
|
547
|
-
}
|
|
548
|
-
if (typeof currentChange.dragging !== 'undefined') {
|
|
549
|
-
updateItem.dragging = currentChange.dragging;
|
|
550
|
-
}
|
|
551
|
-
if (updateItem.expandParent) {
|
|
552
|
-
handleParentExpand(updatedElements, updateItem);
|
|
553
|
-
}
|
|
554
|
-
break;
|
|
555
|
-
}
|
|
556
|
-
case 'dimensions': {
|
|
557
|
-
if (typeof currentChange.dimensions !== 'undefined') {
|
|
558
|
-
if (!updateItem.computed) {
|
|
559
|
-
updateItem.computed = {};
|
|
560
|
-
}
|
|
561
|
-
updateItem.computed.width = currentChange.dimensions.width;
|
|
562
|
-
updateItem.computed.height = currentChange.dimensions.height;
|
|
563
|
-
// this is needed for the node resizer to work
|
|
564
|
-
if (currentChange.resizing) {
|
|
565
|
-
updateItem.width = currentChange.dimensions.width;
|
|
566
|
-
updateItem.height = currentChange.dimensions.height;
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
if (typeof currentChange.resizing === 'boolean') {
|
|
570
|
-
updateItem.resizing = currentChange.resizing;
|
|
571
|
-
}
|
|
572
|
-
if (updateItem.expandParent) {
|
|
573
|
-
handleParentExpand(updatedElements, updateItem);
|
|
574
|
-
}
|
|
575
|
-
break;
|
|
576
|
-
}
|
|
577
|
-
case 'remove': {
|
|
578
|
-
isDeletion = true;
|
|
579
|
-
continue;
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
}
|
|
533
|
+
// If we have a 'remove' change queued, it'll be the only change in the array
|
|
534
|
+
if (changes[0].type === 'remove') {
|
|
535
|
+
continue;
|
|
536
|
+
}
|
|
537
|
+
if (changes[0].type === 'replace') {
|
|
538
|
+
updatedElements.push({ ...changes[0].item });
|
|
539
|
+
continue;
|
|
583
540
|
}
|
|
584
|
-
|
|
585
|
-
|
|
541
|
+
// For other types of changes, we want to start with a shallow copy of the
|
|
542
|
+
// object so React knows this element has changed. Sequential changes will
|
|
543
|
+
/// each _mutate_ this object, so there's only ever one copy.
|
|
544
|
+
const updatedElement = { ...element };
|
|
545
|
+
for (const change of changes) {
|
|
546
|
+
applyChange(change, updatedElement, elements);
|
|
586
547
|
}
|
|
548
|
+
updatedElements.push(updatedElement);
|
|
587
549
|
}
|
|
588
550
|
return updatedElements;
|
|
589
551
|
}
|
|
552
|
+
// Applies a single change to an element. This is a *mutable* update.
|
|
553
|
+
function applyChange(change, element, elements = []) {
|
|
554
|
+
switch (change.type) {
|
|
555
|
+
case 'select': {
|
|
556
|
+
element.selected = change.selected;
|
|
557
|
+
break;
|
|
558
|
+
}
|
|
559
|
+
case 'position': {
|
|
560
|
+
if (typeof change.position !== 'undefined') {
|
|
561
|
+
element.position = change.position;
|
|
562
|
+
}
|
|
563
|
+
if (typeof change.positionAbsolute !== 'undefined') {
|
|
564
|
+
element.computed ??= {};
|
|
565
|
+
element.computed.positionAbsolute = change.positionAbsolute;
|
|
566
|
+
}
|
|
567
|
+
if (typeof change.dragging !== 'undefined') {
|
|
568
|
+
element.dragging = change.dragging;
|
|
569
|
+
}
|
|
570
|
+
if (element.expandParent) {
|
|
571
|
+
handleParentExpand(elements, element);
|
|
572
|
+
}
|
|
573
|
+
break;
|
|
574
|
+
}
|
|
575
|
+
case 'dimensions': {
|
|
576
|
+
if (typeof change.dimensions !== 'undefined') {
|
|
577
|
+
element.computed ??= {};
|
|
578
|
+
element.computed.width = change.dimensions.width;
|
|
579
|
+
element.computed.height = change.dimensions.height;
|
|
580
|
+
if (change.resizing) {
|
|
581
|
+
element.width = change.dimensions.width;
|
|
582
|
+
element.height = change.dimensions.height;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
if (typeof change.resizing === 'boolean') {
|
|
586
|
+
element.resizing = change.resizing;
|
|
587
|
+
}
|
|
588
|
+
if (element.expandParent) {
|
|
589
|
+
handleParentExpand(elements, element);
|
|
590
|
+
}
|
|
591
|
+
break;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
}
|
|
590
595
|
/**
|
|
591
596
|
* Drop in function that applies node changes to an array of nodes.
|
|
592
597
|
* @public
|
|
@@ -655,6 +660,26 @@ function getSelectionChanges(items, selectedIds = new Set(), mutateItem = false)
|
|
|
655
660
|
}
|
|
656
661
|
return changes;
|
|
657
662
|
}
|
|
663
|
+
function getElementsDiffChanges({ items = [], lookup, }) {
|
|
664
|
+
const changes = [];
|
|
665
|
+
const itemsLookup = new Map(items.map((item) => [item.id, item]));
|
|
666
|
+
for (const item of items) {
|
|
667
|
+
const storeItem = lookup.get(item.id);
|
|
668
|
+
if (storeItem !== undefined && storeItem !== item) {
|
|
669
|
+
changes.push({ id: item.id, item: item, type: 'replace' });
|
|
670
|
+
}
|
|
671
|
+
if (storeItem === undefined) {
|
|
672
|
+
changes.push({ item: item, type: 'add' });
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
for (const [id] of lookup) {
|
|
676
|
+
const nextNode = itemsLookup.get(id);
|
|
677
|
+
if (nextNode === undefined) {
|
|
678
|
+
changes.push({ id, type: 'remove' });
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
return changes;
|
|
682
|
+
}
|
|
658
683
|
|
|
659
684
|
/**
|
|
660
685
|
* Test whether an object is useable as a Node
|
|
@@ -663,7 +688,7 @@ function getSelectionChanges(items, selectedIds = new Set(), mutateItem = false)
|
|
|
663
688
|
* @param element - The element to test
|
|
664
689
|
* @returns A boolean indicating whether the element is an Node
|
|
665
690
|
*/
|
|
666
|
-
const isNode = (isNodeBase);
|
|
691
|
+
const isNode = (element) => isNodeBase(element);
|
|
667
692
|
/**
|
|
668
693
|
* Test whether an object is useable as an Edge
|
|
669
694
|
* @public
|
|
@@ -671,50 +696,7 @@ const isNode = (isNodeBase);
|
|
|
671
696
|
* @param element - The element to test
|
|
672
697
|
* @returns A boolean indicating whether the element is an Edge
|
|
673
698
|
*/
|
|
674
|
-
const isEdge = (isEdgeBase);
|
|
675
|
-
/**
|
|
676
|
-
* Pass in a node, and get connected nodes where edge.source === node.id
|
|
677
|
-
* @public
|
|
678
|
-
* @param node - The node to get the connected nodes from
|
|
679
|
-
* @param nodes - The array of all nodes
|
|
680
|
-
* @param edges - The array of all edges
|
|
681
|
-
* @returns An array of nodes that are connected over eges where the source is the given node
|
|
682
|
-
*/
|
|
683
|
-
const getOutgoers = (getOutgoersBase);
|
|
684
|
-
/**
|
|
685
|
-
* Pass in a node, and get connected nodes where edge.target === node.id
|
|
686
|
-
* @public
|
|
687
|
-
* @param node - The node to get the connected nodes from
|
|
688
|
-
* @param nodes - The array of all nodes
|
|
689
|
-
* @param edges - The array of all edges
|
|
690
|
-
* @returns An array of nodes that are connected over eges where the target is the given node
|
|
691
|
-
*/
|
|
692
|
-
const getIncomers = (getIncomersBase);
|
|
693
|
-
/**
|
|
694
|
-
* This util is a convenience function to add a new Edge to an array of edges
|
|
695
|
-
* @remarks It also performs some validation to make sure you don't add an invalid edge or duplicate an existing one.
|
|
696
|
-
* @public
|
|
697
|
-
* @param edgeParams - Either an Edge or a Connection you want to add
|
|
698
|
-
* @param edges - The array of all current edges
|
|
699
|
-
* @returns A new array of edges with the new edge added
|
|
700
|
-
*/
|
|
701
|
-
const addEdge = (addEdgeBase);
|
|
702
|
-
/**
|
|
703
|
-
* A handy utility to update an existing Edge with new properties
|
|
704
|
-
* @param oldEdge - The edge you want to update
|
|
705
|
-
* @param newConnection - The new connection you want to update the edge with
|
|
706
|
-
* @param edges - The array of all current edges
|
|
707
|
-
* @param options.shouldReplaceId - should the id of the old edge be replaced with the new connection id
|
|
708
|
-
* @returns the updated edges array
|
|
709
|
-
*/
|
|
710
|
-
const updateEdge = (updateEdgeBase);
|
|
711
|
-
/**
|
|
712
|
-
* Get all connecting edges for a given set of nodes
|
|
713
|
-
* @param nodes - Nodes you want to get the connected edges for
|
|
714
|
-
* @param edges - All edges
|
|
715
|
-
* @returns Array of edges that connect any of the given nodes with each other
|
|
716
|
-
*/
|
|
717
|
-
const getConnectedEdges = (getConnectedEdgesBase);
|
|
699
|
+
const isEdge = (element) => isEdgeBase(element);
|
|
718
700
|
|
|
719
701
|
/**
|
|
720
702
|
* Hook for accessing the ReactFlow instance.
|
|
@@ -739,31 +721,50 @@ function useReactFlow() {
|
|
|
739
721
|
const { edges = [] } = store.getState();
|
|
740
722
|
return edges.find((e) => e.id === id);
|
|
741
723
|
}, []);
|
|
724
|
+
// this is used to handle multiple syncronous setNodes calls
|
|
725
|
+
const setNodesData = useRef();
|
|
726
|
+
const setNodesTimeout = useRef();
|
|
742
727
|
const setNodes = useCallback((payload) => {
|
|
743
|
-
const { nodes, setNodes, hasDefaultNodes, onNodesChange } = store.getState();
|
|
744
|
-
const nextNodes = typeof payload === 'function' ? payload(nodes) : payload;
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
728
|
+
const { nodes = [], setNodes, hasDefaultNodes, onNodesChange, nodeLookup } = store.getState();
|
|
729
|
+
const nextNodes = typeof payload === 'function' ? payload(setNodesData.current || nodes) : payload;
|
|
730
|
+
setNodesData.current = nextNodes;
|
|
731
|
+
if (setNodesTimeout.current) {
|
|
732
|
+
clearTimeout(setNodesTimeout.current);
|
|
733
|
+
}
|
|
734
|
+
// if there are multiple synchronous setNodes calls, we only want to call onNodesChange once
|
|
735
|
+
// for this, we use a timeout to wait for the last call and store updated nodes in setNodesData
|
|
736
|
+
// this is not perfect, but should work in most cases
|
|
737
|
+
setNodesTimeout.current = setTimeout(() => {
|
|
738
|
+
if (hasDefaultNodes) {
|
|
739
|
+
setNodes(nextNodes);
|
|
740
|
+
}
|
|
741
|
+
else if (onNodesChange) {
|
|
742
|
+
const changes = getElementsDiffChanges({ items: setNodesData.current, lookup: nodeLookup });
|
|
743
|
+
onNodesChange(changes);
|
|
744
|
+
}
|
|
745
|
+
setNodesData.current = undefined;
|
|
746
|
+
}, 0);
|
|
754
747
|
}, []);
|
|
748
|
+
// this is used to handle multiple syncronous setEdges calls
|
|
749
|
+
const setEdgesData = useRef();
|
|
750
|
+
const setEdgesTimeout = useRef();
|
|
755
751
|
const setEdges = useCallback((payload) => {
|
|
756
|
-
const { edges = [], setEdges, hasDefaultEdges, onEdgesChange } = store.getState();
|
|
757
|
-
const nextEdges = typeof payload === 'function' ? payload(edges) : payload;
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
else if (onEdgesChange) {
|
|
762
|
-
const changes = nextEdges.length === 0
|
|
763
|
-
? edges.map((edge) => ({ type: 'remove', id: edge.id }))
|
|
764
|
-
: nextEdges.map((edge) => ({ item: edge, type: 'reset' }));
|
|
765
|
-
onEdgesChange(changes);
|
|
752
|
+
const { edges = [], setEdges, hasDefaultEdges, onEdgesChange, edgeLookup } = store.getState();
|
|
753
|
+
const nextEdges = typeof payload === 'function' ? payload(setEdgesData.current || edges) : payload;
|
|
754
|
+
setEdgesData.current = nextEdges;
|
|
755
|
+
if (setEdgesTimeout.current) {
|
|
756
|
+
clearTimeout(setEdgesTimeout.current);
|
|
766
757
|
}
|
|
758
|
+
setEdgesTimeout.current = setTimeout(() => {
|
|
759
|
+
if (hasDefaultEdges) {
|
|
760
|
+
setEdges(nextEdges);
|
|
761
|
+
}
|
|
762
|
+
else if (onEdgesChange) {
|
|
763
|
+
const changes = getElementsDiffChanges({ items: nextEdges, lookup: edgeLookup });
|
|
764
|
+
onEdgesChange(changes);
|
|
765
|
+
}
|
|
766
|
+
setEdgesData.current = undefined;
|
|
767
|
+
}, 0);
|
|
767
768
|
}, []);
|
|
768
769
|
const addNodes = useCallback((payload) => {
|
|
769
770
|
const nodes = Array.isArray(payload) ? payload : [payload];
|
|
@@ -801,8 +802,8 @@ function useReactFlow() {
|
|
|
801
802
|
},
|
|
802
803
|
};
|
|
803
804
|
}, []);
|
|
804
|
-
const deleteElements = useCallback(async ({ nodes: nodesToRemove = [], edges: edgesToRemove = []
|
|
805
|
-
const { nodes, edges, hasDefaultNodes, hasDefaultEdges, onNodesDelete, onEdgesDelete, onNodesChange, onEdgesChange, onDelete, } = store.getState();
|
|
805
|
+
const deleteElements = useCallback(async ({ nodes: nodesToRemove = [], edges: edgesToRemove = [] }) => {
|
|
806
|
+
const { nodes, edges, hasDefaultNodes, hasDefaultEdges, onNodesDelete, onEdgesDelete, onNodesChange, onEdgesChange, onDelete, onBeforeDelete, } = store.getState();
|
|
806
807
|
const { nodes: matchingNodes, edges: matchingEdges } = await getElementsToRemove({
|
|
807
808
|
nodesToRemove,
|
|
808
809
|
edgesToRemove,
|
|
@@ -814,9 +815,8 @@ function useReactFlow() {
|
|
|
814
815
|
const hasMatchingNodes = matchingNodes.length > 0;
|
|
815
816
|
if (hasMatchingEdges) {
|
|
816
817
|
if (hasDefaultEdges) {
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
});
|
|
818
|
+
const nextEdges = edges.filter((e) => !matchingEdges.some((mE) => mE.id === e.id));
|
|
819
|
+
store.getState().setEdges(nextEdges);
|
|
820
820
|
}
|
|
821
821
|
onEdgesDelete?.(matchingEdges);
|
|
822
822
|
onEdgesChange?.(matchingEdges.map((edge) => ({
|
|
@@ -826,9 +826,8 @@ function useReactFlow() {
|
|
|
826
826
|
}
|
|
827
827
|
if (hasMatchingNodes) {
|
|
828
828
|
if (hasDefaultNodes) {
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
});
|
|
829
|
+
const nextNodes = nodes.filter((n) => !matchingNodes.some((mN) => mN.id === n.id));
|
|
830
|
+
store.getState().setNodes(nextNodes);
|
|
832
831
|
}
|
|
833
832
|
onNodesDelete?.(matchingNodes);
|
|
834
833
|
onNodesChange?.(matchingNodes.map((node) => ({ id: node.id, type: 'remove' })));
|
|
@@ -841,6 +840,9 @@ function useReactFlow() {
|
|
|
841
840
|
const getNodeRect = useCallback((nodeOrRect) => {
|
|
842
841
|
const isRect = isRectObject(nodeOrRect);
|
|
843
842
|
const node = isRect ? null : store.getState().nodeLookup.get(nodeOrRect.id);
|
|
843
|
+
if (!isRect && !node) {
|
|
844
|
+
return [null, null, isRect];
|
|
845
|
+
}
|
|
844
846
|
const nodeRect = isRect ? nodeOrRect : nodeToRect(node);
|
|
845
847
|
return [nodeRect, node, isRect];
|
|
846
848
|
}, []);
|
|
@@ -934,8 +936,8 @@ function useGlobalKeyHandler({ deleteKeyCode, multiSelectionKeyCode, }) {
|
|
|
934
936
|
const multiSelectionKeyPressed = useKeyPress(multiSelectionKeyCode);
|
|
935
937
|
useEffect(() => {
|
|
936
938
|
if (deleteKeyPressed) {
|
|
937
|
-
const { edges, nodes
|
|
938
|
-
deleteElements({ nodes: nodes.filter(selected), edges: edges.filter(selected)
|
|
939
|
+
const { edges, nodes } = store.getState();
|
|
940
|
+
deleteElements({ nodes: nodes.filter(selected), edges: edges.filter(selected) });
|
|
939
941
|
store.setState({ nodesSelectionActive: false });
|
|
940
942
|
}
|
|
941
943
|
}, [deleteKeyPressed]);
|
|
@@ -1345,9 +1347,9 @@ const useNodeId = () => {
|
|
|
1345
1347
|
};
|
|
1346
1348
|
|
|
1347
1349
|
const selector$i = (s) => ({
|
|
1348
|
-
connectionStartHandle: s.connectionStartHandle,
|
|
1349
1350
|
connectOnClick: s.connectOnClick,
|
|
1350
1351
|
noPanClassName: s.noPanClassName,
|
|
1352
|
+
rfId: s.rfId,
|
|
1351
1353
|
});
|
|
1352
1354
|
const connectingSelector = (nodeId, handleId, type) => (state) => {
|
|
1353
1355
|
const { connectionStartHandle: startHandle, connectionEndHandle: endHandle, connectionClickStartHandle: clickHandle, } = state;
|
|
@@ -1362,7 +1364,7 @@ const HandleComponent = forwardRef(({ type = 'source', position = Position.Top,
|
|
|
1362
1364
|
const isTarget = type === 'target';
|
|
1363
1365
|
const store = useStoreApi();
|
|
1364
1366
|
const nodeId = useNodeId();
|
|
1365
|
-
const { connectOnClick, noPanClassName } = useStore(selector$i, shallow);
|
|
1367
|
+
const { connectOnClick, noPanClassName, rfId } = useStore(selector$i, shallow);
|
|
1366
1368
|
const { connecting, clickConnecting } = useStore(connectingSelector(nodeId, handleId, type), shallow);
|
|
1367
1369
|
if (!nodeId) {
|
|
1368
1370
|
store.getState().onError?.('010', errorMessages['error010']());
|
|
@@ -1398,6 +1400,7 @@ const HandleComponent = forwardRef(({ type = 'source', position = Position.Top,
|
|
|
1398
1400
|
isTarget,
|
|
1399
1401
|
handleId,
|
|
1400
1402
|
nodeId,
|
|
1403
|
+
flowId: currentStore.rfId,
|
|
1401
1404
|
panBy: currentStore.panBy,
|
|
1402
1405
|
cancelConnection: currentStore.cancelConnection,
|
|
1403
1406
|
onConnectStart: currentStore.onConnectStart,
|
|
@@ -1416,7 +1419,7 @@ const HandleComponent = forwardRef(({ type = 'source', position = Position.Top,
|
|
|
1416
1419
|
}
|
|
1417
1420
|
};
|
|
1418
1421
|
const onClick = (event) => {
|
|
1419
|
-
const { onClickConnectStart, onClickConnectEnd, connectionClickStartHandle, connectionMode, isValidConnection: isValidConnectionStore, lib, } = store.getState();
|
|
1422
|
+
const { onClickConnectStart, onClickConnectEnd, connectionClickStartHandle, connectionMode, isValidConnection: isValidConnectionStore, lib, rfId: flowId, } = store.getState();
|
|
1420
1423
|
if (!nodeId || (!connectionClickStartHandle && !isConnectableStart)) {
|
|
1421
1424
|
return;
|
|
1422
1425
|
}
|
|
@@ -1438,6 +1441,7 @@ const HandleComponent = forwardRef(({ type = 'source', position = Position.Top,
|
|
|
1438
1441
|
fromHandleId: connectionClickStartHandle.handleId || null,
|
|
1439
1442
|
fromType: connectionClickStartHandle.type,
|
|
1440
1443
|
isValidConnection: isValidConnectionHandler,
|
|
1444
|
+
flowId,
|
|
1441
1445
|
doc,
|
|
1442
1446
|
lib,
|
|
1443
1447
|
});
|
|
@@ -1447,7 +1451,7 @@ const HandleComponent = forwardRef(({ type = 'source', position = Position.Top,
|
|
|
1447
1451
|
onClickConnectEnd?.(event);
|
|
1448
1452
|
store.setState({ connectionClickStartHandle: null });
|
|
1449
1453
|
};
|
|
1450
|
-
return (jsx("div", { "data-handleid": handleId, "data-nodeid": nodeId, "data-handlepos": position, "data-id": `${nodeId}-${handleId}-${type}`, className: cc([
|
|
1454
|
+
return (jsx("div", { "data-handleid": handleId, "data-nodeid": nodeId, "data-handlepos": position, "data-id": `${rfId}-${nodeId}-${handleId}-${type}`, className: cc([
|
|
1451
1455
|
'react-flow__handle',
|
|
1452
1456
|
`react-flow__handle-${position}`,
|
|
1453
1457
|
'nodrag',
|
|
@@ -2095,7 +2099,7 @@ function EdgeUpdateAnchors({ isUpdatable, edgeUpdaterRadius, edge, targetHandleI
|
|
|
2095
2099
|
if (event.button !== 0) {
|
|
2096
2100
|
return;
|
|
2097
2101
|
}
|
|
2098
|
-
const { autoPanOnConnect, domNode, isValidConnection, connectionMode, connectionRadius, lib, onConnectStart, onConnectEnd, cancelConnection, nodes, panBy, updateConnection, } = store.getState();
|
|
2102
|
+
const { autoPanOnConnect, domNode, isValidConnection, connectionMode, connectionRadius, lib, onConnectStart, onConnectEnd, cancelConnection, nodes, rfId: flowId, panBy, updateConnection, } = store.getState();
|
|
2099
2103
|
const nodeId = isSourceHandle ? edge.target : edge.source;
|
|
2100
2104
|
const handleId = (isSourceHandle ? targetHandleId : sourceHandleId) || null;
|
|
2101
2105
|
const handleType = isSourceHandle ? 'target' : 'source';
|
|
@@ -2118,6 +2122,7 @@ function EdgeUpdateAnchors({ isUpdatable, edgeUpdaterRadius, edge, targetHandleI
|
|
|
2118
2122
|
isTarget,
|
|
2119
2123
|
edgeUpdaterType: handleType,
|
|
2120
2124
|
lib,
|
|
2125
|
+
flowId,
|
|
2121
2126
|
cancelConnection,
|
|
2122
2127
|
panBy,
|
|
2123
2128
|
isValidConnection,
|
|
@@ -3120,7 +3125,7 @@ const selector$3 = (s) => ({
|
|
|
3120
3125
|
minZoomReached: s.transform[2] <= s.minZoom,
|
|
3121
3126
|
maxZoomReached: s.transform[2] >= s.maxZoom,
|
|
3122
3127
|
});
|
|
3123
|
-
function ControlsComponent({ style, showZoom = true, showFitView = true, showInteractive = true, fitViewOptions, onZoomIn, onZoomOut, onFitView, onInteractiveChange, className, children, position = 'bottom-left', }) {
|
|
3128
|
+
function ControlsComponent({ style, showZoom = true, showFitView = true, showInteractive = true, fitViewOptions, onZoomIn, onZoomOut, onFitView, onInteractiveChange, className, children, position = 'bottom-left', 'aria-label': ariaLabel = 'React Flow controls', }) {
|
|
3124
3129
|
const store = useStoreApi();
|
|
3125
3130
|
const { isInteractive, minZoomReached, maxZoomReached } = useStore(selector$3, shallow);
|
|
3126
3131
|
const { zoomIn, zoomOut, fitView } = useReactFlow();
|
|
@@ -3144,7 +3149,7 @@ function ControlsComponent({ style, showZoom = true, showFitView = true, showInt
|
|
|
3144
3149
|
});
|
|
3145
3150
|
onInteractiveChange?.(!isInteractive);
|
|
3146
3151
|
};
|
|
3147
|
-
return (jsxs(Panel, { className: cc(['react-flow__controls', className]), position: position, style: style, "data-testid": "rf__controls", children: [showZoom && (jsxs(Fragment, { children: [jsx(ControlButton, { onClick: onZoomInHandler, className: "react-flow__controls-zoomin", title: "zoom in", "aria-label": "zoom in", disabled: maxZoomReached, children: jsx(PlusIcon, {}) }), jsx(ControlButton, { onClick: onZoomOutHandler, className: "react-flow__controls-zoomout", title: "zoom out", "aria-label": "zoom out", disabled: minZoomReached, children: jsx(MinusIcon, {}) })] })), showFitView && (jsx(ControlButton, { className: "react-flow__controls-fitview", onClick: onFitViewHandler, title: "fit view", "aria-label": "fit view", children: jsx(FitViewIcon, {}) })), showInteractive && (jsx(ControlButton, { className: "react-flow__controls-interactive", onClick: onToggleInteractivity, title: "toggle interactivity", "aria-label": "toggle interactivity", children: isInteractive ? jsx(UnlockIcon, {}) : jsx(LockIcon, {}) })), children] }));
|
|
3152
|
+
return (jsxs(Panel, { className: cc(['react-flow__controls', className]), position: position, style: style, "data-testid": "rf__controls", "aria-label": ariaLabel, children: [showZoom && (jsxs(Fragment, { children: [jsx(ControlButton, { onClick: onZoomInHandler, className: "react-flow__controls-zoomin", title: "zoom in", "aria-label": "zoom in", disabled: maxZoomReached, children: jsx(PlusIcon, {}) }), jsx(ControlButton, { onClick: onZoomOutHandler, className: "react-flow__controls-zoomout", title: "zoom out", "aria-label": "zoom out", disabled: minZoomReached, children: jsx(MinusIcon, {}) })] })), showFitView && (jsx(ControlButton, { className: "react-flow__controls-fitview", onClick: onFitViewHandler, title: "fit view", "aria-label": "fit view", children: jsx(FitViewIcon, {}) })), showInteractive && (jsx(ControlButton, { className: "react-flow__controls-interactive", onClick: onToggleInteractivity, title: "toggle interactivity", "aria-label": "toggle interactivity", children: isInteractive ? jsx(UnlockIcon, {}) : jsx(LockIcon, {}) })), children] }));
|
|
3148
3153
|
}
|
|
3149
3154
|
ControlsComponent.displayName = 'Controls';
|
|
3150
3155
|
const Controls = memo(ControlsComponent);
|
|
@@ -3456,4 +3461,4 @@ function NodeToolbar({ nodeId, children, className, style, isVisible, position =
|
|
|
3456
3461
|
return (jsx(NodeToolbarPortal, { children: jsx("div", { style: wrapperStyle, className: cc(['react-flow__node-toolbar', className]), ...rest, "data-id": nodes.reduce((acc, node) => `${acc}${node.id} `, '').trim(), children: children }) }));
|
|
3457
3462
|
}
|
|
3458
3463
|
|
|
3459
|
-
export { Background, BackgroundVariant, BaseEdge, BezierEdge, ControlButton, Controls, EdgeLabelRenderer, EdgeText, Handle, MiniMap, NodeResizeControl, NodeResizer, NodeToolbar, Panel, ReactFlow, ReactFlowProvider, SimpleBezierEdge, SmoothStepEdge, StepEdge, StraightEdge, ViewportPortal,
|
|
3464
|
+
export { Background, BackgroundVariant, BaseEdge, BezierEdge, ControlButton, Controls, EdgeLabelRenderer, EdgeText, Handle, MiniMap, NodeResizeControl, NodeResizer, NodeToolbar, Panel, ReactFlow, ReactFlowProvider, SimpleBezierEdge, SmoothStepEdge, StepEdge, StraightEdge, ViewportPortal, applyEdgeChanges, applyNodeChanges, getSimpleBezierPath, handleParentExpand, isEdge, isNode, useConnection, useEdges, useEdgesState, useHandleConnections, useKeyPress, useNodeId, useNodes, useNodesData, useNodesInitialized, useNodesState, useOnSelectionChange, useOnViewportChange, useReactFlow, useStore, useStoreApi, useUpdateNodeInternals, useViewport };
|