Skip to content
Merged
181 changes: 181 additions & 0 deletions apps/test/app/examples/workflow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
"use client";

import { Canvas } from "@repo/elements/canvas";
import { Edge } from "@repo/elements/edge";
import {
Node,
NodeContent,
NodeDescription,
NodeFooter,
NodeHeader,
NodeTitle,
} from "@repo/elements/node";

const nodeIds = {
start: "start",
process1: "process1",
process2: "process2",
decision: "decision",
output1: "output1",
output2: "output2",
};

const nodes = [
{
id: nodeIds.start,
type: "workflow",
position: { x: 0, y: 0 },
data: {
label: "Start",
description: "Initialize workflow",
handles: { target: false, source: true },
content: "Triggered by user action at 09:30 AM",
footer: "Status: Ready",
},
},
{
id: nodeIds.process1,
type: "workflow",
position: { x: 500, y: 0 },
data: {
label: "Process Data",
description: "Transform input",
handles: { target: true, source: true },
content: "Validating 1,234 records and applying business rules",
footer: "Duration: ~2.5s",
},
},
{
id: nodeIds.decision,
type: "workflow",
position: { x: 1000, y: 0 },
data: {
label: "Decision Point",
description: "Route based on conditions",
handles: { target: true, source: true },
content: "Evaluating: data.status === 'valid' && data.score > 0.8",
footer: "Confidence: 94%",
},
},
{
id: nodeIds.output1,
type: "workflow",
position: { x: 1500, y: -300 },
data: {
label: "Success Path",
description: "Handle success case",
handles: { target: true, source: true },
content: "1,156 records passed validation (93.7%)",
footer: "Next: Send to production",
},
},
{
id: nodeIds.output2,
type: "workflow",
position: { x: 1500, y: 300 },
data: {
label: "Error Path",
description: "Handle error case",
handles: { target: true, source: true },
content: "78 records failed validation (6.3%)",
footer: "Next: Queue for review",
},
},
{
id: nodeIds.process2,
type: "workflow",
position: { x: 2000, y: 0 },
data: {
label: "Complete",
description: "Finalize workflow",
handles: { target: true, source: false },
content: "All records processed and routed successfully",
footer: "Total time: 4.2s",
},
},
];

const edges = [
{
id: "edge1",
source: nodeIds.start,
target: nodeIds.process1,
type: "animated",
},
{
id: "edge2",
source: nodeIds.process1,
target: nodeIds.decision,
type: "animated",
},
{
id: "edge3",
source: nodeIds.decision,
target: nodeIds.output1,
type: "animated",
},
{
id: "edge4",
source: nodeIds.decision,
target: nodeIds.output2,
type: "temporary",
},
{
id: "edge5",
source: nodeIds.output1,
target: nodeIds.process2,
type: "animated",
},
{
id: "edge6",
source: nodeIds.output2,
target: nodeIds.process2,
type: "temporary",
},
];

const nodeTypes = {
workflow: ({
data,
}: {
data: {
label: string;
description: string;
handles: { target: boolean; source: boolean };
content: string;
footer: string;
};
}) => (
<Node handles={data.handles}>
<NodeHeader>
<NodeTitle>{data.label}</NodeTitle>
<NodeDescription>{data.description}</NodeDescription>
</NodeHeader>
<NodeContent>
<p className="text-sm">{data.content}</p>
</NodeContent>
<NodeFooter>
<p className="text-muted-foreground text-xs">{data.footer}</p>
</NodeFooter>
</Node>
),
};

const edgeTypes = {
animated: Edge.Animated,
temporary: Edge.Temporary,
};

const Example = () => (
<div style={{ height: "400px", width: "100%" }}>
<Canvas
edges={edges}
edgeTypes={edgeTypes}
fitView
nodes={nodes}
nodeTypes={nodeTypes}
/>
</div>
);

export default Example;
2 changes: 2 additions & 0 deletions apps/test/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@ import Suggestion from "@/app/examples/suggestion";
import Task from "@/app/examples/task";
import Tool from "@/app/examples/tool";
import WebPreview from "@/app/examples/web-preview";
import Workflow from "@/app/examples/workflow";

const components = [
{ name: "Actions", Component: Actions },
{ name: "Artifact", Component: Artifact },
{ name: "Branch", Component: Branch },
{ name: "Workflow", Component: Workflow },
{ name: "ChainOfThought", Component: ChainOfThought },
{ name: "CodeBlock", Component: CodeBlock },
{ name: "Context", Component: Context },
Expand Down
1 change: 1 addition & 0 deletions apps/test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"@icons-pack/react-simple-icons": "^13.7.0",
"@repo/elements": "workspace:*",
"@repo/shadcn-ui": "workspace:*",
"@xyflow/react": "^12.8.6",
"ai": "5.0.37",
"lucide-react": "^0.542.0",
"nanoid": "^5.1.5",
Expand Down
1 change: 1 addition & 0 deletions packages/elements/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"dependencies": {
"@radix-ui/react-use-controllable-state": "^1.2.2",
"@repo/shadcn-ui": "workspace:*",
"@xyflow/react": "^12.8.6",
"ai": "5.0.37",
"class-variance-authority": "^0.7.1",
"lucide-react": "^0.542.0",
Expand Down
22 changes: 22 additions & 0 deletions packages/elements/src/canvas.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Background, ReactFlow, type ReactFlowProps } from "@xyflow/react";
import type { ReactNode } from "react";
import "@xyflow/react/dist/style.css";

type CanvasProps = ReactFlowProps & {
children?: ReactNode;
};

export const Canvas = ({ children, ...props }: CanvasProps) => (
<ReactFlow
deleteKeyCode={["Backspace", "Delete"]}
fitView
panOnDrag={false}
panOnScroll
selectionOnDrag={true}
zoomOnDoubleClick={false}
{...props}
>
<Background bgColor="var(--sidebar)" />
{children}
</ReactFlow>
);
28 changes: 28 additions & 0 deletions packages/elements/src/connection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import type { ConnectionLineComponent } from "@xyflow/react";

const HALF = 0.5;

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(--color-ring)"
strokeWidth={1}
/>
<circle
cx={toX}
cy={toY}
fill="#fff"
r={3}
stroke="var(--color-ring)"
strokeWidth={1}
/>
</g>
);
18 changes: 18 additions & 0 deletions packages/elements/src/controls.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"use client";

import { cn } from "@repo/shadcn-ui/lib/utils";
import { Controls as ControlsPrimitive } from "@xyflow/react";
import type { ComponentProps } from "react";

export type ControlsProps = ComponentProps<typeof ControlsPrimitive>;

export const Controls = ({ className, ...props }: ControlsProps) => (
<ControlsPrimitive
className={cn(
"gap-px overflow-hidden rounded-md border bg-card p-1 shadow-none!",
"[&>button]:rounded-md [&>button]:border-none",
className
)}
{...props}
/>
);
Loading