Connection
Connection line shown while dragging a new edge.
Drag from the right handle of Start.
Drag from the right handle of Start.
Drag from the right handle of Start.
import { Canvas } from "@/components/ai/canvas";import { Connection } from "@/components/ai/connection";import { Node, NodeHeader, NodeTitle } from "@/components/ai/node";
const nodes = [ { id: "a", type: "step", position: { x: 0, y: 40 }, data: { l: "Start", t: false }, }, { id: "b", type: "step", position: { x: 320, y: 40 }, data: { l: "Check drift", t: true }, },];
const nodeTypes = { step: ({ data }: { data: { l: string; t: boolean } }) => ( <Node handles={{ target: data.t, source: !data.t }} className="w-40"> <NodeHeader className="border-b-0"> <NodeTitle>{data.l}</NodeTitle> </NodeHeader> </Node> ),};
export default function Demo() { return ( <div className="h-56 w-full overflow-hidden rounded-[calc(var(--radius)*1.4)] border border-border"> <p className="absolute z-10 m-3 text-xs text-muted-foreground"> Drag from the right handle of Start. </p> <Canvas connectionLineComponent={Connection} edges={[]} nodes={nodes} nodeTypes={nodeTypes} /> </div> );}<script setup lang="ts">import { Canvas } from "@/components/ai/canvas";import { Connection } from "@/components/ai/connection";import { Node, NodeHeader, NodeTitle } from "@/components/ai/node";
const nodes = [ { id: "a", type: "step", position: { x: 0, y: 40 }, data: { l: "Start", t: false } }, { id: "b", type: "step", position: { x: 320, y: 40 }, data: { l: "Check drift", t: true } },];</script>
<template> <div class="relative h-56 w-full overflow-hidden rounded-[calc(var(--radius)*1.4)] border border-border"> <p class="absolute z-10 m-3 text-xs text-muted-foreground">Drag from the right handle of Start.</p> <Canvas :nodes="nodes" :edges="[]"> <template #node-step="{ data }"> <Node :handles="{ target: data.t, source: !data.t }" class="w-40"> <NodeHeader class="border-b-0"> <NodeTitle>{{ data.l }}</NodeTitle> </NodeHeader> </Node> </template> <template #connection-line="props"> <Connection v-bind="props" /> </template> </Canvas> </div></template><script lang="ts"> import { Canvas } from "$lib/components/ai/canvas"; import { Connection } from "$lib/components/ai/connection"; import Step from "./_shared/ai-workflow-step.svelte";
const nodeTypes = { step: Step };
const step = (title: string, target: boolean) => ({ title, compact: true, handles: { target, source: !target } });
let nodes = $state.raw([ { id: "a", type: "step", position: { x: 0, y: 40 }, data: step("Start", false) }, { id: "b", type: "step", position: { x: 320, y: 40 }, data: step("Check drift", true) }, ]); let edges = $state.raw([]);</script>
<div style="height: 224px" class="relative w-full overflow-hidden rounded-[calc(var(--radius)*1.4)] border border-border"> <p class="absolute z-10 m-3 text-xs text-muted-foreground">Drag from the right handle of Start.</p> <Canvas bind:nodes bind:edges {nodeTypes} connectionLineComponent={Connection} /></div>Installation
Section titled “Installation”npx shadcn@latest add @edmi-ui/ai-connectionpnpm dlx shadcn@latest add @edmi-ui/ai-connectionyarn dlx shadcn@latest add @edmi-ui/ai-connectionbunx shadcn@latest add @edmi-ui/ai-connectionPick your package manager above; the choice is remembered. Add the @edmi-ui registry first, see Getting started.
Install the dependencies:
Terminal window npm install @xyflow/reactTerminal window pnpm add @xyflow/reactTerminal window yarn add @xyflow/reactTerminal window bun add @xyflow/reactCopy the code from Component source into your project and update the import paths to match your aliases.
npx shadcn-vue@latest add @edmi-ui/ai-connectionpnpm dlx shadcn-vue@latest add @edmi-ui/ai-connectionyarn dlx shadcn-vue@latest add @edmi-ui/ai-connectionbunx shadcn-vue@latest add @edmi-ui/ai-connectionPick your package manager above; the choice is remembered. Add the @edmi-ui registry first, see Getting started.
Install the dependencies:
Terminal window npm install @vue-flow/coreTerminal window pnpm add @vue-flow/coreTerminal window yarn add @vue-flow/coreTerminal window bun add @vue-flow/coreCopy the code from Component source into your project and update the import paths to match your aliases.
npx shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/ai-connection.jsonpnpm dlx shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/ai-connection.jsonyarn dlx shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/ai-connection.jsonbunx --bun shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/ai-connection.jsonPick your package manager above; the choice is remembered. Add the @edmi-ui registry first, see Getting started.
Copy the code from Component source into your project and update the import paths to match your aliases.
import { Canvas } from "@/components/ai/canvas";
<div className="h-56 w-full overflow-hidden rounded-[calc(var(--radius)*1.4)] border border-border"> <p className="absolute z-10 m-3 text-xs text-muted-foreground"> Drag from the right handle of Start. </p> <Canvas connectionLineComponent={Connection} edges={[]} /></div><script setup lang="ts">import { Canvas } from "@/components/ai/canvas";import { Connection } from "@/components/ai/connection";import { Node, NodeHeader, NodeTitle } from "@/components/ai/node";</script>
<template> <div class="relative h-56 w-full overflow-hidden rounded-[calc(var(--radius)*1.4)] border border-border"> <p class="absolute z-10 m-3 text-xs text-muted-foreground">Drag from the right handle of Start.</p> <Canvas :edges="[]"> <template #node-step="{ data }"> <Node :handles="{ target: data.t, source: !data.t }" class="w-40"> <NodeHeader class="border-b-0"> <NodeTitle>{{ data.l }}</NodeTitle> </NodeHeader> </Node> </template> <template #connection-line="props"> <Connection v-bind="props" /> </template> </Canvas> </div></template><script lang="ts"> import { Canvas } from "$lib/components/ai/canvas";</script>
<div style="height: 224px" class="relative w-full overflow-hidden rounded-[calc(var(--radius)*1.4)] border border-border"> <p class="absolute z-10 m-3 text-xs text-muted-foreground">Drag from the right handle of Start.</p> <Canvas bind:nodes bind:edges connectionLineComponent={Connection} /></div>Component source
Section titled “Component source”import type { ConnectionLineComponent } from "@xyflow/react";
const HALF = 0.5;
/** Line drawn while dragging from a handle: ring-colored bezier with an end dot. */export const Connection: ConnectionLineComponent = ({ fromX, fromY, toX, toY,}) => ( <g> <path className="animated" d={`M${fromX},${fromY} C ${fromX + (toX - fromX) * HALF},${fromY} ${fromX + (toX - fromX) * HALF},${toY} ${toX},${toY}`} fill="none" stroke="var(--ring)" strokeLinecap="round" strokeWidth={1.6} /> <circle cx={fromX} cy={fromY} fill="var(--card)" r={4.5} stroke="var(--ring)" strokeWidth={1.6} /> <circle cx={toX} cy={toY} fill="var(--ring)" r={3} /> </g>);<script setup lang="ts">import type { ConnectionLineProps } from "@vue-flow/core"import { computed } from "vue"
/** Line drawn while dragging from a handle: ring-colored bezier with an end dot. */const props = defineProps<ConnectionLineProps>()
const HALF = 0.5
const pathD = computed(() => { const { sourceX, sourceY, targetX, targetY } = props const controlX = sourceX + (targetX - sourceX) * HALF return `M${sourceX},${sourceY} C ${controlX},${sourceY} ${controlX},${targetY} ${targetX},${targetY}`})</script>
<template> <g data-slot="ai-connection"> <path class="animated" fill="none" stroke="var(--ring)" stroke-linecap="round" :stroke-width="1.6" :d="pathD" /> <circle :cx="sourceX" :cy="sourceY" fill="var(--card)" :r="4.5" stroke="var(--ring)" :stroke-width="1.6" /> <circle :cx="targetX" :cy="targetY" fill="var(--ring)" :r="3" /> </g></template>export { default as Connection } from "./Connection.vue";<script lang="ts"> import { useConnection } from "@xyflow/svelte";
/** Line drawn while dragging from a handle: ring-colored bezier with an end dot. */ const connection = useConnection();
const HALF = 0.5;
const line = $derived.by(() => { const { from, to, inProgress } = connection.current; if (!inProgress || !from || !to) return null; const controlX = from.x + (to.x - from.x) * HALF; return { from, to, d: `M${from.x},${from.y} C ${controlX},${from.y} ${controlX},${to.y} ${to.x},${to.y}`, }; });</script>
{#if line} <g data-slot="ai-connection"> <path class="animated" d={line.d} fill="none" stroke="var(--ring)" stroke-linecap="round" stroke-width="1.6" /> <circle cx={line.from.x} cy={line.from.y} r="4.5" fill="var(--card)" stroke="var(--ring)" stroke-width="1.6" /> <circle cx={line.to.x} cy={line.to.y} r="3" fill="var(--ring)" /> </g>{/if}import Connection from "./connection.svelte";
export { Connection };| Part | Prop | Type | Default |
|---|---|---|---|
| Connection | connectionLineComponent |
ring-colored bezier with a hollow start and a filled end dot |