diff --git a/CHANGELOG.md b/CHANGELOG.md
index c1771ba7e..9f947eb42 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,10 +8,39 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
This is a major release, and it might be not compatible with your current usage of our library. Please read about the necessary changes in the section about how to migrate.
+### Added
+
+- ``
+ - it's basically `` without any special configs
+- ``
+ - only supported for v12, in v9 as straight edge is used
+ - use `curvature` property in the edge `data` object to define the bezier layout (0..1, default: 0.25)
+- ``
+ - the `data` object provides `markerAppearance` to set and remove the edge arrows
+- ``
+ - component for React Flow v12, displaying new connection lines
+
+### Removed
+
+- support for React Flow v10 was completely removed
+
### Fixed
- ``:
- - Add 'nopan', 'nowheel' and 'nodrag' classes to Modal's overlay classes in order to always prevent react-flow to react to drag and pan actions in modals.
+ - Add 'nopan', 'nowheel' and 'nodrag' classes to Modal's overlay classes in order to always prevent react-flow to react to drag and pan actions in modals.
+
+### Changed
+
+- `` and ``
+ - support now v9 and v12 of react flow
+- ``
+ - use `` by default for new connection lines, you can overwrite it by setting `connectionLineComponent` to `undefined`
+
+### Deprecated
+
+- support for React Flow v9 will be removed in v26
+- ``
+ - use `` or build it on single ``
## [24.4.0] - 2025-08-07
@@ -130,7 +159,7 @@ If you use Jest then you can use the same aliases for the `moduleNameMapper` con
### Migration from v24 to v25
-- remove deprecated components, properties and imports from your project, if the info cannot be found here then it was already mentioned in **Deprecated** sections of the v24.* changelogs.
+- remove deprecated components, properties and imports from your project, if the info cannot be found here then it was already mentioned in **Deprecated** sections of the v24.\* changelogs.
- we changed the integration of the supported react flow versions, formerly names `legacy` and `next` resources were renamed to more precise `v9` and `v10`, please see all info in the section about changes
## [24.1.0] - 2025-04-16
diff --git a/package.json b/package.json
index b8f2ad331..9ec76cb67 100644
--- a/package.json
+++ b/package.json
@@ -94,7 +94,6 @@
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-flow-renderer": "9.7.4",
- "react-flow-renderer-lts": "npm:react-flow-renderer@^10.3.17",
"react-inlinesvg": "^3.0.3",
"react-markdown": "^10.1.0",
"react-markdown-deprecated": "npm:react-markdown@^8.0.7",
diff --git a/src/cmem/react-flow/ReactFlow/ReactFlow.stories.tsx b/src/cmem/react-flow/ReactFlow/ReactFlow.stories.tsx
index d0177a550..9db7a8822 100644
--- a/src/cmem/react-flow/ReactFlow/ReactFlow.stories.tsx
+++ b/src/cmem/react-flow/ReactFlow/ReactFlow.stories.tsx
@@ -6,16 +6,6 @@ import {
FlowElement,
Position,
} from "react-flow-renderer";
-import {
- Background as BackgroundV10,
- BackgroundVariant as BackgroundVariantV10,
- Edge as Edge10,
- Node as Node10,
- OnInit as OnInitV10,
- ReactFlowInstance as ReactFlowInstanceV10,
- useEdgesState as useEdgesState10,
- useNodesState as useNodesState10,
-} from "react-flow-renderer-lts";
import { Meta, StoryFn } from "@storybook/react";
import { fn } from "@storybook/test";
import {
@@ -31,7 +21,6 @@ import {
ApplicationContainer,
EdgeTools,
MiniMap,
- MiniMapV10,
MiniMapV12,
NodeTools,
ReactFlowExtended,
@@ -425,7 +414,7 @@ export default {
},
flowVersion: {
control: "select",
- options: [undefined, "v9", "v10", "v12"],
+ options: [undefined, "v9", "v12"],
},
},
} as Meta;
@@ -490,33 +479,6 @@ const ReactFlowExampleV9: FC = (args) => {
);
};
-const ReactFlowExampleV10: FC = (args) => {
- const [reactFlowInstance, setReactFlowInstance] = React.useState(undefined);
- const [nodes, ,] = useNodesState10(nodeExamples[args.configuration ?? "unspecified"].nodes as Node10[]);
- const [edges, ,] = useEdgesState10(nodeExamples[args.configuration ?? "unspecified"].edges as Edge10[]);
-
- const onInit: OnInitV10 = React.useCallback((_reactFlowInstance: ReactFlowInstanceV10) => {
- setReactFlowInstance(_reactFlowInstance);
- }, []);
-
- const reactFlowExtendedProps = {
- ...args,
- defaultZoom: 1,
- nodes,
- edges,
- onInit,
- } as ReactFlowExtendedProps;
-
- return (
-
-
-
-
-
-
- );
-};
-
const ReactFlowExampleV12: FC = (args) => {
const [nodes, ,] = useNodesState12(nodeExamples[args.configuration ?? "unspecified"].nodes as Node12[]);
const [edges, ,] = useEdgesState12(nodeExamples[args.configuration ?? "unspecified"].edges as Edge12[]);
@@ -549,8 +511,6 @@ const ReactFlowExample: FC = (args) => {
case undefined:
case "v9":
return ;
- case "v10":
- return ;
case "v12":
return ;
default:
diff --git a/src/cmem/react-flow/ReactFlow/ReactFlow.tsx b/src/cmem/react-flow/ReactFlow/ReactFlow.tsx
index 9357e97ef..0caa31bac 100644
--- a/src/cmem/react-flow/ReactFlow/ReactFlow.tsx
+++ b/src/cmem/react-flow/ReactFlow/ReactFlow.tsx
@@ -1,6 +1,5 @@
import React, {ReactElement, Ref} from "react";
import { KeyCode as KeyCodeV9 } from "react-flow-renderer";
-import { KeyCode as KeyCodeV10 } from "react-flow-renderer-lts";
import { KeyCode as KeyCodeV12} from "@xyflow/react";
import { CLASSPREFIX as eccgui } from "../../../configuration/constants";
@@ -8,14 +7,12 @@ import { ReactFlowMarkers } from "../../../extensions/react-flow/markers/ReactFl
import { ReactFlowVersions } from "../../../extensions/react-flow/versionsupport";
import { ReactFlowHotkeyContext } from "../extensions/ReactFlowHotkeyContext";
import { useReactFlowScrollOnDragV9 } from "../extensions/scrollOnDragHook";
-import { useReactFlowScrollOnDragV10 } from "../extensions/scrollOnDragHookV10";
import * as graphConfig from "./../configuration/graph";
import * as linkingConfig from "./../configuration/linking";
import * as unspecifiedConfig from "./../configuration/unspecified";
import * as workflowConfig from "./../configuration/workflow";
import { ReactFlowV9Container, ReactFlowV9ContainerProps } from "./ReactFlowV9";
-import { ReactFlowV10Container, ReactFlowV10ContainerProps } from "./ReactFlowV10";
import { ReactFlowV12Container, ReactFlowV12ContainerProps } from "./ReactFlowV12";
export interface ReactFlowExtendedExtraProps {
@@ -55,13 +52,6 @@ interface ReactFlowExtendedVersion9SupportProps {
flowVersion?: ReactFlowVersions.V9;
}
-interface ReactFlowExtendedVersion10SupportProps {
- /**
- * Set version of `ReactFlow` that is used internally.
- */
- flowVersion: ReactFlowVersions.V10;
-}
-
interface ReactFlowExtendedVersion12SupportProps {
/**
* Set version of `ReactFlow` that is used internally.
@@ -74,16 +64,15 @@ interface ReactFlowExtendedVersion12SupportProps {
}
export type ReactFlowExtendedPropsV9 = ReactFlowExtendedVersion9SupportProps & ReactFlowV9ContainerProps & ReactFlowExtendedExtraProps & ReactFlowExtendedScrollProps
-export type ReactFlowExtendedPropsV10 = ReactFlowExtendedVersion10SupportProps & ReactFlowV10ContainerProps & ReactFlowExtendedExtraProps & ReactFlowExtendedScrollProps
export type ReactFlowExtendedPropsV12 = ReactFlowExtendedVersion12SupportProps & ReactFlowV12ContainerProps & ReactFlowExtendedExtraProps
-export type ReactFlowExtendedProps = ReactFlowExtendedPropsV9 | ReactFlowExtendedPropsV10 | ReactFlowExtendedPropsV12
+export type ReactFlowExtendedProps = ReactFlowExtendedPropsV9 | ReactFlowExtendedPropsV12
/**
* `ReactFlow` container extension that includes pre-configured nodes and edges for
* Corporate Memory tools.
*
- * @param T The concrete type of the corresponding version, i.e. either one of ReactFlowExtendedPropsV9, ReactFlowExtendedPropsV10 or ReactFlowExtendedPropsV12
+ * @param T The concrete type of the corresponding version, i.e. either one of ReactFlowExtendedPropsV9 or ReactFlowExtendedPropsV12
*/
const ReactFlowExtendedPlain = ({
configuration = "unspecified",
@@ -157,14 +146,6 @@ const ReactFlowExtendedPlain = ({
zoomActivationKeyCode: hotKeysDisabled ? undefined : (zoomActivationKeyCode as KeyCodeV9),
};
break;
- case "v10":
- keyCodeConfig = {
- selectionKeyCode: hotKeysDisabled ? undefined : (selectionKeyCode as KeyCodeV10),
- deleteKeyCode: hotKeysDisabled ? undefined : (deleteKeyCode as KeyCodeV10),
- multiSelectionKeyCode: hotKeysDisabled ? undefined : (multiSelectionKeyCode as KeyCodeV10),
- zoomActivationKeyCode: hotKeysDisabled ? undefined : (zoomActivationKeyCode as KeyCodeV10),
- };
- break;
case "v12":
keyCodeConfig = {
selectionKeyCode: hotKeysDisabled ? null : (selectionKeyCode as KeyCodeV12),
@@ -183,12 +164,6 @@ const ReactFlowExtendedPlain = ({
scrollOnDrag,
});
break;
- case "v10":
- scrollOnDragFunctions = useReactFlowScrollOnDragV10({
- reactFlowProps: originalProps as ReactFlowV10ContainerProps,
- scrollOnDrag,
- });
- break;
// should not be necessary for v12
}
@@ -207,13 +182,6 @@ const ReactFlowExtendedPlain = ({
);
- case "v10":
- return (
-
- {children}
-
-
- );
case "v12":
return (
diff --git a/src/cmem/react-flow/ReactFlow/ReactFlowV10.tsx b/src/cmem/react-flow/ReactFlow/ReactFlowV10.tsx
deleted file mode 100644
index 5b72a62b8..000000000
--- a/src/cmem/react-flow/ReactFlow/ReactFlowV10.tsx
+++ /dev/null
@@ -1,54 +0,0 @@
-import React from "react";
-import {
- default as ReactFlowV10,
- Edge,
- Node,
- ReactFlowProps as ReactFlowV10Props,
- useEdgesState,
- useNodesState,
-} from "react-flow-renderer-lts";
-
-import { CLASSPREFIX as eccgui } from "../../../configuration/constants";
-
-export type ReactFlowV10ContainerProps = ReactFlowV10Props;
-
-/**
- * Our own `ReactFlow` v10 container.
- */
-export const ReactFlowV10Container = React.forwardRef(
- ({ children, className, ...originalProps }, outerRef) => {
- const innerRef = React.useRef(null);
- React.useImperativeHandle(outerRef, () => innerRef.current!, []);
-
- const [nodesFallback, , onNodesChangeFallback] = useNodesState(originalProps.nodes || ([] as Node[]));
- const [edgesFallback, , onEdgesChangeFallback] = useEdgesState(originalProps.edges || ([] as Edge[]));
-
- const missingNodesChangeCallback =
- !!originalProps.nodes && !originalProps.onNodesChange
- ? {
- nodes: nodesFallback,
- onNodesChange: onNodesChangeFallback,
- }
- : {};
-
- const missingEdgesChangeCallback =
- !!originalProps.edges && !originalProps.onEdgesChange
- ? {
- edges: edgesFallback,
- onEdgesChange: onEdgesChangeFallback,
- }
- : {};
-
- return (
-
- {children}
-
- );
- }
-);
diff --git a/src/cmem/react-flow/ReactFlow/ReactFlowV12.tsx b/src/cmem/react-flow/ReactFlow/ReactFlowV12.tsx
index 83a06d316..23b22e2fb 100644
--- a/src/cmem/react-flow/ReactFlow/ReactFlowV12.tsx
+++ b/src/cmem/react-flow/ReactFlow/ReactFlowV12.tsx
@@ -9,6 +9,7 @@ import {
} from "@xyflow/react";
import { CLASSPREFIX as eccgui } from "../../../configuration/constants";
+import { EdgeNew } from "./../../../extensions/react-flow/edges/EdgeNew";
export type ReactFlowV12ContainerProps = ReactFlowV12Props;
@@ -43,6 +44,7 @@ export const ReactFlowV12Container = React.forwardRef> = {
+const nodeTypes: Record*/> = {
default: NodeDefault,
graph: NodeDefault,
class: NodeDefault,
diff --git a/src/cmem/react-flow/configuration/linking.ts b/src/cmem/react-flow/configuration/linking.ts
index 036e475be..4a8326a78 100644
--- a/src/cmem/react-flow/configuration/linking.ts
+++ b/src/cmem/react-flow/configuration/linking.ts
@@ -2,8 +2,8 @@ import { EdgeStep } from "./../../../extensions/react-flow/edges/EdgeStep";
import { NodeDefault } from "./../../../extensions/react-flow/nodes/NodeDefault";
import { StickyNoteNode } from "./../nodes/StickyNoteNode";
import { LINKING_NODE_TYPES } from "./typing";
-import {ComponentType} from "react";
-import {NodeProps} from "react-flow-renderer-lts";
+//import {ComponentType} from "react";
+//import {NodeProps} from "react-flow-renderer-lts";
const edgeTypes = {
default: EdgeStep,
@@ -14,7 +14,7 @@ const edgeTypes = {
danger: EdgeStep,
};
-const nodeTypes: Record> = {
+const nodeTypes: Record*/> = {
default: NodeDefault,
sourcepath: NodeDefault,
targetpath: NodeDefault,
diff --git a/src/cmem/react-flow/configuration/unspecified.ts b/src/cmem/react-flow/configuration/unspecified.ts
index 28ae0c019..0d7774937 100644
--- a/src/cmem/react-flow/configuration/unspecified.ts
+++ b/src/cmem/react-flow/configuration/unspecified.ts
@@ -1,10 +1,11 @@
import { EdgeDefault } from "./../../../extensions/react-flow/edges/EdgeDefault";
import { EdgeStep } from "./../../../extensions/react-flow/edges/EdgeStep";
+import { EdgeStraight } from "./../../../extensions/react-flow/edges/EdgeStraight";
import { NodeDefault } from "./../../../extensions/react-flow/nodes/NodeDefault";
export const edgeTypes = {
default: EdgeDefault,
- straight: EdgeDefault,
+ straight: EdgeStraight,
step: EdgeStep,
};
diff --git a/src/cmem/react-flow/configuration/workflow.ts b/src/cmem/react-flow/configuration/workflow.ts
index 14ff19a51..5a8621a89 100644
--- a/src/cmem/react-flow/configuration/workflow.ts
+++ b/src/cmem/react-flow/configuration/workflow.ts
@@ -2,8 +2,8 @@ import { EdgeStep } from "./../../../extensions/react-flow/edges/EdgeStep";
import { NodeDefault } from "./../../../extensions/react-flow/nodes/NodeDefault";
import { StickyNoteNode } from "./../nodes/StickyNoteNode";
import { WORKFLOW_NODE_TYPES } from "./typing";
-import {ComponentType} from "react";
-import {NodeProps} from "react-flow-renderer-lts";
+//import {ComponentType} from "react";
+//import {NodeProps} from "react-flow-renderer-lts";
const edgeTypes = {
default: EdgeStep,
@@ -12,7 +12,7 @@ const edgeTypes = {
danger: EdgeStep,
};
-const nodeTypes: Record> = {
+const nodeTypes: Record*/> = {
default: NodeDefault,
dataset: NodeDefault,
linking: NodeDefault,
diff --git a/src/cmem/react-flow/extensions/scrollOnDragHookV10.ts b/src/cmem/react-flow/extensions/scrollOnDragHookV10.ts
deleted file mode 100644
index 1685113f8..000000000
--- a/src/cmem/react-flow/extensions/scrollOnDragHookV10.ts
+++ /dev/null
@@ -1,267 +0,0 @@
-import React, { MouseEvent as ReactMouseEvent, useCallback } from "react";
-import {
- Edge,
- Node,
- OnConnectStart,
- OnConnectStartParams,
- OnConnectStop,
- OnInit,
- ReactFlowInstance,
- Transform,
- useStore,
-} from "react-flow-renderer-lts";
-import { HandleType } from "react-flow-renderer-lts/dist/esm/types/handles";
-
-import { ReactFlowExtendedScrollProps } from "../ReactFlow/ReactFlow";
-import { ReactFlowV10ContainerProps } from "../ReactFlow/ReactFlowV10";
-
-import { ScrollStateShared } from "./scrollOnDragHook";
-
-interface IProps extends ReactFlowExtendedScrollProps {
- /** The original react-flow props. */
- reactFlowProps: ReactFlowV10ContainerProps;
-}
-
-interface ScrollState extends ScrollStateShared {
- // The react-flow instance
- reactFlowInstance?: ReactFlowInstance;
-}
-
-type ReturnType = Pick<
- ReactFlowV10ContainerProps,
- | "onInit"
- | "onNodeDragStart"
- | "onNodeDragStop"
- | "onConnectStart"
- | "onConnectStop"
- | "onSelectionDragStart"
- | "onSelectionDragStop"
- | "onEdgeUpdateStart"
- | "onEdgeUpdateEnd"
->;
-
-/** Handles the scrolling of the react-flow canvas on all drag operations when the mouse pointer gets near or over the borders.
- * The return value contains the wrapped react-flow callback functions that need to be handed over to the react-flow component. */
-export const useReactFlowScrollOnDragV10 = ({ reactFlowProps, scrollOnDrag }: IProps): ReturnType => {
- /** Tracks the zoom on drag to border functionality. */
- const scrollState = React.useRef({
- reactFlowInstance: undefined,
- currentX: 0,
- currentY: 0,
- currentZoom: 1,
- loggedWarning: false,
- scrollX: false,
- scrollY: false,
- draggingOperationActive: false,
- });
-
- const useStoreStateInternal = (): Transform => {
- try {
- return useStore((state) => state.transform);
- } catch (ex) {
- if (reactFlowProps.id && scrollOnDrag) {
- // eslint-disable-next-line no-console
- console.warn("Scroll on drag is not correctly working. Reason: " + ex);
- }
- return [0, 0, 1];
- }
- };
-
- /** The current position and zoom factor of the view port. */
- const [currentX, currentY, currentZoom] = useStoreStateInternal();
- scrollState.current.currentX = currentX;
- scrollState.current.currentY = currentY;
- scrollState.current.currentZoom = currentZoom;
-
- const originalOnInit = reactFlowProps.onInit;
- const originalOnNodeDragStart = reactFlowProps.onNodeDragStart;
- const originalOnNodeDragStop = reactFlowProps.onNodeDragStop;
- const originalOnConnectStart = reactFlowProps.onConnectStart;
- const originalOnConnectStop = reactFlowProps.onConnectStop;
- const originalOnSelectionDragStart = reactFlowProps.onSelectionDragStart;
- const originalOnSelectionDragStop = reactFlowProps.onSelectionDragStop;
- const originalOnEdgeUpdateStart = reactFlowProps.onEdgeUpdateStart;
- const originalOnEdgeUpdateEnd = reactFlowProps.onEdgeUpdateEnd;
-
- const scrollInterval = scrollOnDrag?.scrollInterval;
- const scrollStepSize = scrollOnDrag?.scrollStepSize;
-
- const reactFlowInstanceId = reactFlowProps.id;
-
- const clearIntervalIfExists = React.useCallback(() => {
- if (scrollState.current.scrollTaskId) {
- clearInterval(scrollState.current.scrollTaskId);
- }
- }, []);
-
- const setScrolling = React.useCallback(
- (active: boolean) => {
- scrollState.current.draggingOperationActive = active;
- if (!active) {
- clearIntervalIfExists();
- }
- },
- [clearIntervalIfExists]
- );
-
- // Handle scrolling if any operation is active e.g. connecting or dragging a node
- React.useEffect(() => {
- if (scrollInterval && scrollStepSize && reactFlowInstanceId) {
- const handleScrolling = (event: MouseEvent) => {
- const state = scrollState.current;
- if (!state.draggingOperationActive) {
- clearIntervalIfExists();
- return;
- }
- // Check if mouse pointer is outside of the canvas
- const canvasElement = document.getElementById(reactFlowInstanceId);
- if (!canvasElement) {
- if (!state.loggedWarning) {
- // eslint-disable-next-line no-console
- console.warn("No element found with ID " + reactFlowInstanceId);
- state.loggedWarning = true;
- }
- return;
- }
- const boundingRect = canvasElement.getBoundingClientRect();
- const xStepSize = boundingRect.width * scrollStepSize;
- const yStepSize = boundingRect.height * scrollStepSize;
- if (
- boundingRect.top > event.clientY ||
- boundingRect.bottom < event.clientY ||
- boundingRect.left > event.clientX ||
- boundingRect.right < event.clientX
- ) {
- const scrollX: number =
- boundingRect.left > event.clientX
- ? xStepSize
- : boundingRect.right < event.clientX
- ? -xStepSize
- : 0;
- const scrollY: number =
- boundingRect.top > event.clientY
- ? yStepSize
- : boundingRect.bottom < event.clientY
- ? -yStepSize
- : 0;
- if (state.scrollY === (scrollY !== 0) && state.scrollX === (scrollX !== 0)) {
- // Nothing has changed, do not change interval function
- return;
- }
- clearIntervalIfExists();
- state.scrollTaskId = setInterval(() => {
- state.reactFlowInstance?.setViewport({
- x: state.currentX + scrollX,
- y: state.currentY + scrollY,
- zoom: state.currentZoom,
- });
- }, scrollInterval);
- } else {
- clearIntervalIfExists();
- }
- };
- const disableScrollingOnMouseUp = () => {
- scrollState.current.draggingOperationActive = false;
- clearIntervalIfExists();
- };
- document.addEventListener("mousemove", handleScrolling);
- document.addEventListener("mouseup", disableScrollingOnMouseUp);
- return () => {
- document.removeEventListener("mousemove", handleScrolling);
- document.removeEventListener("mouseup", disableScrollingOnMouseUp);
- };
- } else {
- return undefined;
- }
- }, [scrollInterval, scrollStepSize, reactFlowInstanceId, clearIntervalIfExists]);
-
- const onInit: OnInit = useCallback(
- (rfi: ReactFlowInstance) => {
- scrollState.current.reactFlowInstance = rfi;
- originalOnInit?.(rfi);
- },
- [originalOnInit]
- );
-
- /** Wrap original callbacks to turn scrolling on and off. */
- const onConnectStart: OnConnectStart = React.useCallback(
- (event: ReactMouseEvent, params: OnConnectStartParams) => {
- setScrolling(true);
- originalOnConnectStart?.(event, params);
- },
- [originalOnConnectStart, setScrolling]
- );
-
- const onConnectStop: OnConnectStop = React.useCallback(
- (event: MouseEvent) => {
- setScrolling(false);
- originalOnConnectStop?.(event);
- },
- [originalOnConnectStop, setScrolling]
- );
-
- const onNodeDragStart = React.useCallback(
- (event: ReactMouseEvent, node: Node, nodes: Node[]) => {
- setScrolling(true);
- originalOnNodeDragStart?.(event, node, nodes);
- },
- [originalOnNodeDragStart, setScrolling]
- );
-
- const onNodeDragStop = React.useCallback(
- (event: ReactMouseEvent, node: Node, nodes: Node[]) => {
- setScrolling(false);
- originalOnNodeDragStop?.(event, node, nodes);
- },
- [originalOnNodeDragStop, setScrolling]
- );
-
- const onSelectionDragStart = React.useCallback(
- (event: ReactMouseEvent, nodes: Node[]) => {
- setScrolling(true);
- originalOnSelectionDragStart?.(event, nodes);
- },
- [originalOnSelectionDragStart, setScrolling]
- );
-
- const onSelectionDragStop = React.useCallback(
- (event: ReactMouseEvent, nodes: Node[]) => {
- setScrolling(false);
- originalOnSelectionDragStop?.(event, nodes);
- },
- [originalOnSelectionDragStop, setScrolling]
- );
-
- const onEdgeUpdateStart = React.useCallback(
- (event: ReactMouseEvent, edge: Edge, handleType: HandleType) => {
- setScrolling(true);
- originalOnEdgeUpdateStart?.(event, edge, handleType);
- },
- [originalOnEdgeUpdateStart, setScrolling]
- );
-
- const onEdgeUpdateEnd = React.useCallback(
- (event: MouseEvent, edge: Edge, handleType: HandleType) => {
- setScrolling(false);
- originalOnEdgeUpdateEnd?.(event, edge, handleType);
- },
- [originalOnEdgeUpdateEnd, setScrolling]
- );
-
- if (!reactFlowProps.id || !scrollOnDrag) {
- // No instance ID or config available, return empty object that will not overwrite any react-flow config parameters
- return {};
- } else {
- return {
- onInit,
- onNodeDragStart,
- onNodeDragStop,
- onConnectStart,
- onConnectStop,
- onSelectionDragStart,
- onSelectionDragStop,
- onEdgeUpdateStart,
- onEdgeUpdateEnd,
- };
- }
-};
diff --git a/src/extensions/react-flow/_config.scss b/src/extensions/react-flow/_config.scss
index d5855aaf4..f07e25a0e 100644
--- a/src/extensions/react-flow/_config.scss
+++ b/src/extensions/react-flow/_config.scss
@@ -1,3 +1,4 @@
+$reactflow-background-color: $card-background-color !default;
$reactflow-node-basesize: $button-height !default;
$reactflow-node-largesize: mini-units(6) !default;
$reactflow-node-border-color: $eccgui-color-workspace-text !default;
diff --git a/src/extensions/react-flow/_react-flow.scss b/src/extensions/react-flow/_react-flow.scss
index 3a331543a..21f6f4f4e 100644
--- a/src/extensions/react-flow/_react-flow.scss
+++ b/src/extensions/react-flow/_react-flow.scss
@@ -1,10 +1,7 @@
@import "config";
@import "nodes/nodes";
@import "edges/edges";
+@import "markers/markers";
@import "handles/handles";
@import "minimap/minimap";
@import "react-flow_v12";
-
-.react-flow__background {
- border: solid 1px $eccgui-color-separation-divider;
-}
diff --git a/src/extensions/react-flow/_react-flow_v12.scss b/src/extensions/react-flow/_react-flow_v12.scss
index e96d8f9fb..3a39599ee 100644
--- a/src/extensions/react-flow/_react-flow_v12.scss
+++ b/src/extensions/react-flow/_react-flow_v12.scss
@@ -1,17 +1,187 @@
-.react-flow__edges svg:not(.#{$eccgui}-icon) {
+/**
+ * We need some styles from "@xyflow/react/dist/style.css" to ensure proper functionality.
+ * Some of them are directly included to the component styles.
+ * Other stuff is here.
+ * Colors are removed or altered.
+ */
+
+.react-flow {
+ direction: ltr;
+}
+
+.react-flow__pane {
+ z-index: 1;
+}
+
+.react-flow__pane.draggable {
+ cursor: grab;
+}
+
+.react-flow__pane.dragging {
+ cursor: grabbing;
+}
+
+.react-flow__pane.selection {
+ cursor: pointer;
+}
+
+.react-flow__viewport {
+ z-index: 2;
+ pointer-events: none;
+ transform-origin: 0 0;
+}
+
+.react-flow__renderer {
+ z-index: 4;
+}
+
+.react-flow__selection {
+ z-index: 6;
+}
+
+.react-flow__controls {
+ display: flex;
+ flex-direction: column;
+}
+
+.react-flow__controls.horizontal {
+ flex-direction: row;
+}
+
+.react-flow__controls-button {
+ display: flex;
+ justify-content: center;
+ cursor: pointer;
+ user-select: none;
+}
+
+.react-flow__controls-button svg {
+ width: 100%;
+ max-width: 12px;
+ max-height: 12px;
+ fill: currentcolor;
+}
+
+.react-flow .react-flow__edges {
+ position: absolute;
+}
+
+.react-flow .react-flow__edges svg {
position: absolute;
overflow: visible;
pointer-events: none;
}
+.react-flow__edge {
+ pointer-events: visiblestroke;
+}
+
+.react-flow__edge.inactive {
+ pointer-events: none;
+}
+
+.react-flow__edge-textwrapper {
+ pointer-events: all;
+}
+
+.react-flow__edge .react-flow__edge-text {
+ pointer-events: none;
+ user-select: none;
+}
+
+.react-flow__connection {
+ pointer-events: none;
+}
+
svg.react-flow__connectionline {
position: absolute;
z-index: 1001;
overflow: visible;
}
+.react-flow__nodes {
+ pointer-events: none;
+ transform-origin: 0 0;
+}
+
+.react-flow__node {
+ position: absolute;
+ box-sizing: border-box;
+ pointer-events: all;
+ cursor: default;
+ user-select: none;
+ transform-origin: 0 0;
+}
+
+.react-flow__node.selectable {
+ cursor: pointer;
+}
+
+.react-flow__node.draggable {
+ pointer-events: all;
+ cursor: grab;
+}
+
+.react-flow__node.draggable.dragging {
+ cursor: grabbing;
+}
+
+.react-flow__nodesselection {
+ z-index: 3;
+ pointer-events: none;
+ transform-origin: left top;
+}
+
+.react-flow__nodesselection-rect {
+ position: absolute;
+ pointer-events: all;
+ cursor: grab;
+}
+
+.react-flow__handle.connectingfrom {
+ pointer-events: all;
+}
+
+.react-flow__handle.connectionindicator {
+ pointer-events: all;
+}
+
+.react-flow__edgeupdater {
+ pointer-events: all;
+ cursor: move;
+}
+
+.react-flow__minimap-svg {
+ display: block;
+}
+
+.react-flow__node.selectable:focus,
+.react-flow__node.selectable:focus-visible {
+ outline: none;
+}
+
+.react-flow__nodesselection-rect:focus,
+.react-flow__nodesselection-rect:focus-visible,
+.react-flow__selection:focus,
+.react-flow__selection:focus-visible {
+ outline: none;
+}
+
+.react-flow__controls-button:disabled {
+ pointer-events: none;
+}
+
+// -- adjustments
+
+.react-flow__background {
+ z-index: -1;
+ pointer-events: none;
+ background-color: $reactflow-background-color;
+ border: solid 1px $eccgui-color-separation-divider;
+}
+
.react-flow__background-pattern {
- opacity: 0.39;
+ opacity: $eccgui-opacity-ghostly;
}
.react-flow__background-pattern.dots {
@@ -25,3 +195,20 @@ svg.react-flow__connectionline {
.react-flow__background-pattern.cross {
stroke: $eccgui-color-separation-divider;
}
+
+.react-flow__attribution {
+ position: absolute;
+ right: 0;
+ bottom: 0;
+ z-index: 10;
+ padding: $eccgui-size-inline-whitespace * 0.5 $eccgui-size-inline-whitespace;
+ margin: 0;
+ font-size: $eccgui-size-typo-caption * 0.61;
+ background: transparent;
+ opacity: $eccgui-opacity-muted;
+}
+
+.react-flow__attribution a {
+ color: $eccgui-color-workspace-text;
+ text-decoration: none;
+}
diff --git a/src/extensions/react-flow/edges/EdgeBezier.tsx b/src/extensions/react-flow/edges/EdgeBezier.tsx
new file mode 100644
index 000000000..f86419336
--- /dev/null
+++ b/src/extensions/react-flow/edges/EdgeBezier.tsx
@@ -0,0 +1,47 @@
+import React, { memo } from "react";
+import { Edge, EdgeProps, getBezierPath } from "@xyflow/react";
+
+import { ReactFlowVersions, useReactFlowVersion } from "../versionsupport";
+
+import { EdgeDefault, EdgeDefaultV9Props } from "./EdgeDefault";
+import { EdgeDefaultV12DataProps, EdgeDefaultV12Props } from "./EdgeDefaultV12";
+
+interface EdgeBezierDataV12Props extends EdgeDefaultV12DataProps {
+ curvature?: number;
+}
+
+/**
+ * @deprecated (v26) v9 support is removed after v25
+ */
+export interface EdgeBezierV12Props
+ extends Omit,
+ EdgeProps> {}
+
+export type EdgeBezierProps = EdgeDefaultV9Props | EdgeBezierV12Props;
+
+/**
+ * This element cannot be used directly, it must be connected via a `edgeTypes` definition.
+ * Our v9 edges do not support bezier paths.
+ * @see https://reactflow.dev/docs/api/nodes/
+ */
+export const EdgeBezier = memo((props: EdgeBezierProps) => {
+ const flowVersionCheck = useReactFlowVersion();
+ switch (flowVersionCheck) {
+ case ReactFlowVersions.V9:
+ return ;
+ case ReactFlowVersions.V12:
+ return (
+ {
+ return getBezierPath({
+ ...params,
+ curvature: (props.data as EdgeBezierDataV12Props)?.curvature,
+ });
+ }}
+ />
+ );
+ default:
+ return <>>;
+ }
+});
diff --git a/src/extensions/react-flow/edges/EdgeDefault.tsx b/src/extensions/react-flow/edges/EdgeDefault.tsx
index 65b7b2675..86660a558 100644
--- a/src/extensions/react-flow/edges/EdgeDefault.tsx
+++ b/src/extensions/react-flow/edges/EdgeDefault.tsx
@@ -4,9 +4,11 @@ import { EdgeProps as ReactFlowEdgeProps } from "react-flow-renderer/dist/types"
import { intentClassName, IntentTypes } from "../../../common/Intent";
import { CLASSPREFIX as eccgui } from "../../../configuration/constants";
+import { ReactFlowVersions, useReactFlowVersion } from "../versionsupport";
import { nodeContentUtils } from "./../nodes/NodeContent";
import { NodeHighlightColor } from "./../nodes/sharedTypes";
+import { EdgeDefaultV12, EdgeDefaultV12Props } from "./EdgeDefaultV12";
import { drawEdgeStep, drawEdgeStraight } from "./utils";
export interface EdgeDefaultDataProps {
@@ -30,11 +32,7 @@ export interface EdgeDefaultDataProps {
* Direction of the SVG path is inversed.
* This is important for the placement of the markers and the animation movement.
*/
- inversePath?: boolean;
- /**
- * Reference link to the SVG marker used for the start of the edge
- */
- markerStart?: string;
+ inversePath?: boolean; // FIXME: diection of animation is not inverted
/**
* Callback handler that returns a React element used as edge title.
*/
@@ -46,19 +44,35 @@ export interface EdgeDefaultDataProps {
edgeSvgProps?: React.SVGProps;
}
-export interface EdgeDefaultProps extends ReactFlowEdgeProps {
+/**
+ * @deprecated (v26) v9 support is removed after v25
+ */
+export interface EdgeDefaultV9DataProps extends EdgeDefaultDataProps {
+ /**
+ * Reference link to the SVG marker used for the start of the edge
+ * @deprecated (v26) only necessary for react flow v9
+ */
+ markerStart?: string;
+}
+
+/**
+ * @deprecated (v26) v9 support is removed after v25
+ */
+export interface EdgeDefaultV9Props extends ReactFlowEdgeProps {
/**
* Defining content and markers for the edge.
*/
- data?: EdgeDefaultDataProps;
+ data?: EdgeDefaultV9DataProps;
/**
* Callback handler that returns a SVG path as string to define how the edge is rendered.
*/
drawSvgPath?: (edge: ReactFlowEdgeProps) => string;
}
-export const EdgeDefault = memo(
- ({ data = {}, drawSvgPath = drawEdgeStraight, ...edgeOriginalProperties }: EdgeDefaultProps) => {
+export type EdgeDefaultProps = EdgeDefaultV9Props | EdgeDefaultV12Props;
+
+const EdgeDefaultV9 = memo(
+ ({ data = {}, drawSvgPath = drawEdgeStraight, ...edgeOriginalProperties }: EdgeDefaultV9Props) => {
const { pathGlowWidth = 10, markerStart, strokeType, intent, highlightColor, edgeSvgProps } = data;
const pathDisplay = drawSvgPath({ ...edgeOriginalProperties, data });
@@ -94,7 +108,11 @@ export const EdgeDefault = memo(
return (
{
+ const flowVersionCheck = useReactFlowVersion();
+ switch (flowVersionCheck) {
+ case ReactFlowVersions.V9:
+ return ;
+ case ReactFlowVersions.V12:
+ return ;
+ default:
+ return <>>;
+ }
+});
+
const createEdgeDefaultClassName = (
{ strokeType, intent, highlightColor }: EdgeDefaultDataProps,
- baseClass = "react-flow__edge-path"
+ baseClass = "react-flow__edge-path",
+ flowVersion?: ReactFlowVersions
) => {
const { highlightClassNameSuffix } = nodeContentUtils.evaluateHighlightColors("--edge-highlight", highlightColor);
return (
baseClass +
+ (flowVersion ? ` react-flow__edge--${flowVersion}` : "") +
(strokeType ? ` ${baseClass}--stroke-${strokeType}` : "") +
(intent ? ` ${intentClassName(intent)}` : "") +
(highlightClassNameSuffix.length > 0
diff --git a/src/extensions/react-flow/edges/EdgeDefaultV12.tsx b/src/extensions/react-flow/edges/EdgeDefaultV12.tsx
index 5ffed2cdc..e3cea9ed9 100644
--- a/src/extensions/react-flow/edges/EdgeDefaultV12.tsx
+++ b/src/extensions/react-flow/edges/EdgeDefaultV12.tsx
@@ -1,44 +1,32 @@
-import { memo } from "react";
-import React from "react";
-import { BaseEdge, Edge, EdgeProps, EdgeText, getBezierPath, getEdgeCenter } from "@xyflow/react";
+import React, { memo } from "react";
+import { BaseEdge, Edge, EdgeProps, EdgeText, GetBezierPathParams } from "@xyflow/react";
-import { IntentTypes } from "../../../common/Intent";
import { nodeContentUtils } from "../nodes/NodeContent";
-import { NodeHighlightColor } from "../nodes/sharedTypes";
+import { ReactFlowVersions } from "../versionsupport";
-import { edgeDefaultUtils } from "./EdgeDefault";
+import { EdgeDefaultDataProps, edgeDefaultUtils } from "./EdgeDefault";
+import { getStraightPath } from "./utils";
-export type EdgeDefaultV12DataProps = Record & {
- /**
- * Overwrites the default style how the edge stroke is displayed.
- */
- strokeType?: "solid" | "dashed" | "dotted" | "double" | "doubledashed";
- /**
- * Feedback state of the node.
- */
- intent?: IntentTypes;
- /**
- * Set the color of used highlights to mark the edge.
- */
- highlightColor?: NodeHighlightColor | [NodeHighlightColor, NodeHighlightColor];
- /**
- * Size of the "glow" effect when the edge is hovered.
- */
- pathGlowWidth?: number;
- /*
- * Direction of the SVG path is inversed.
- * This is important for the placement of the markers and the animation movement.
- */
- inversePath?: boolean;
+/**
+ * @deprecated (v26) use EdgeDefaultDataProps
+ */
+export interface EdgeDefaultV12DataProps extends Record, EdgeDefaultDataProps {
/**
- * Callback handler that returns a React element used as edge title.
+ * Set the marker used on the start or end of the edge.
*/
- renderLabel?: (edgeCenter: [number, number, number, number]) => React.ReactNode;
+ markerAppearance?: "arrow-closed" | "none";
+}
+
+/**
+ * @deprecated (v26) use EdgeDefaultProps
+ */
+export type EdgeDefaultV12Props = EdgeProps> & {
/**
- * Properties are forwarded to the internally used SVG `g` element.
- * Data attributes for test ids coud be included here.
+ * Callback handler that returns SVG path and label position of the edge.
*/
- edgeSvgProps?: React.SVGProps;
+ getPath?: (
+ edgeParams: Omit & Record
+ ) => [path: string, labelX: number, labelY: number, offsetX: number, offsetY: number];
};
/**
@@ -62,11 +50,12 @@ export const EdgeDefaultV12 = memo(
labelBgPadding = [5, 5],
labelBgBorderRadius = 3,
data = {},
+ getPath = getStraightPath,
...edgeOriginalProperties
- }: EdgeProps>) => {
+ }: EdgeDefaultV12Props) => {
const { pathGlowWidth = 10, highlightColor, renderLabel, edgeSvgProps, intent, inversePath, strokeType } = data;
- const [edgePath, labelX, labelY] = getBezierPath({
+ const [edgePath, labelX, labelY] = getPath({
sourceX,
sourceY,
sourcePosition,
@@ -81,19 +70,12 @@ export const EdgeDefaultV12 = memo(
highlightColor
);
- const edgeCenter = getEdgeCenter({
- sourceX,
- sourceY,
- targetX,
- targetY,
- });
-
const renderedLabel =
renderLabel?.([labelX, labelY, sourceX, targetX]) ??
(label ? (
) : null);
+ const appearance = data.markerAppearance ?? "arrow-closed";
+
+ const marker =
+ appearance !== "none"
+ ? {
+ markerStart: inversePath
+ ? `url(#react-flow__marker--${appearance}${intent ? `-${intent}` : "-none"}-reverse)`
+ : undefined,
+ markerEnd: !inversePath
+ ? `url(#react-flow__marker--${appearance}${intent ? `-${intent}` : "-none"}`
+ : undefined,
+ }
+ : {};
+
return (
-
- {highlightColor && (
-
- )}
-
-
-
+ )}
+
{renderedLabel}
);
diff --git a/src/extensions/react-flow/edges/EdgeDefs.tsx b/src/extensions/react-flow/edges/EdgeDefs.tsx
index aa3d2a440..bc77e038b 100644
--- a/src/extensions/react-flow/edges/EdgeDefs.tsx
+++ b/src/extensions/react-flow/edges/EdgeDefs.tsx
@@ -1,5 +1,8 @@
import React from "react";
+/**
+ * @deprecated (v26) use ``
+ */
export const EdgeDefs = React.memo(() => (