diff --git a/packages/editor-ui/src/components/canvas/Canvas.vue b/packages/editor-ui/src/components/canvas/Canvas.vue
index f4c734cd98..c5995c5cd6 100644
--- a/packages/editor-ui/src/components/canvas/Canvas.vue
+++ b/packages/editor-ui/src/components/canvas/Canvas.vue
@@ -401,6 +401,10 @@ watch(() => props.readOnly, setReadonly, {
/>
+
+
+
+
diff --git a/packages/editor-ui/src/components/canvas/elements/edges/CanvasConnectionLine.spec.ts b/packages/editor-ui/src/components/canvas/elements/edges/CanvasConnectionLine.spec.ts
new file mode 100644
index 0000000000..876cde7ca6
--- /dev/null
+++ b/packages/editor-ui/src/components/canvas/elements/edges/CanvasConnectionLine.spec.ts
@@ -0,0 +1,56 @@
+import CanvasConnectionLine from './CanvasConnectionLine.vue';
+import { createComponentRenderer } from '@/__tests__/render';
+import { createTestingPinia } from '@pinia/testing';
+import { setActivePinia } from 'pinia';
+import type { ConnectionLineProps } from '@vue-flow/core';
+import { Position } from '@vue-flow/core';
+
+const DEFAULT_PROPS = {
+ sourceX: 0,
+ sourceY: 0,
+ sourcePosition: Position.Top,
+ targetX: 100,
+ targetY: 100,
+ targetPosition: Position.Bottom,
+} satisfies Partial;
+const renderComponent = createComponentRenderer(CanvasConnectionLine, {
+ props: DEFAULT_PROPS,
+});
+
+beforeEach(() => {
+ const pinia = createTestingPinia();
+ setActivePinia(pinia);
+});
+
+describe('CanvasConnectionLine', () => {
+ it('should render a correct bezier path', () => {
+ const { container } = renderComponent({
+ props: DEFAULT_PROPS,
+ });
+
+ const edge = container.querySelector('.vue-flow__edge-path');
+
+ expect(edge).toHaveAttribute('d', 'M0,0 C0,-62.5 100,162.5 100,100');
+ });
+
+ it('should render a correct smooth step path when the connection is backwards', () => {
+ const { container } = renderComponent({
+ props: {
+ ...DEFAULT_PROPS,
+ sourceX: 0,
+ sourceY: 0,
+ sourcePosition: Position.Right,
+ targetX: -100,
+ targetY: -100,
+ targetPosition: Position.Left,
+ },
+ });
+
+ const edge = container.querySelector('.vue-flow__edge-path');
+
+ expect(edge).toHaveAttribute(
+ 'd',
+ 'M0 0L 32,0Q 40,0 40,8L 40,132Q 40,140 32,140L1 140L0 140M0 140L-40 140L -132,140Q -140,140 -140,132L -140,-92Q -140,-100 -132,-100L-100 -100',
+ );
+ });
+});
diff --git a/packages/editor-ui/src/components/canvas/elements/edges/CanvasConnectionLine.vue b/packages/editor-ui/src/components/canvas/elements/edges/CanvasConnectionLine.vue
new file mode 100644
index 0000000000..86b1a5971d
--- /dev/null
+++ b/packages/editor-ui/src/components/canvas/elements/edges/CanvasConnectionLine.vue
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
diff --git a/packages/editor-ui/src/components/canvas/elements/edges/utils/edgePath.ts b/packages/editor-ui/src/components/canvas/elements/edges/utils/edgePath.ts
index 0a98519bbb..348a0283b8 100644
--- a/packages/editor-ui/src/components/canvas/elements/edges/utils/edgePath.ts
+++ b/packages/editor-ui/src/components/canvas/elements/edges/utils/edgePath.ts
@@ -1,18 +1,25 @@
-import { getBezierPath, getSmoothStepPath, Position, type EdgeProps } from '@vue-flow/core';
+import type { EdgeProps } from '@vue-flow/core';
+import { getBezierPath, getSmoothStepPath, Position } from '@vue-flow/core';
const EDGE_PADDING_Y = 140;
const EDGE_PADDING_Y_TOP = 80;
const EDGE_BORDER_RADIUS = 8;
const EDGE_OFFSET = 40;
+const HANDLE_SIZE = 16;
-export function getCustomPath(props: EdgeProps) {
+export function getCustomPath(
+ props: Pick<
+ EdgeProps,
+ 'sourceX' | 'sourceY' | 'sourcePosition' | 'targetX' | 'targetY' | 'targetPosition'
+ >,
+) {
const { targetX, targetY, sourceX, sourceY, sourcePosition, targetPosition } = props;
const xDiff = targetX - sourceX;
const yDiff = targetY - sourceY;
// Connection is backwards and the source is on the right side
// -> We need to avoid overlapping the source node
- if (xDiff < 0 && sourcePosition === Position.Right) {
+ if (xDiff < -HANDLE_SIZE && sourcePosition === Position.Right) {
const direction = yDiff < -EDGE_PADDING_Y || yDiff > 0 ? 'up' : 'down';
const firstSegmentTargetX = sourceX;
const firstSegmentTargetY =
@@ -41,5 +48,6 @@ export function getCustomPath(props: EdgeProps) {
path[0] = firstSegmentPath + path[0];
return path;
}
+
return getBezierPath(props);
}