ai-design-system 0.1.38 → 0.1.40
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/components/blocks/WorkflowCanvas/WorkflowCanvas.tsx +3 -13
- package/components/blocks/WorkflowCanvas/index.ts +1 -0
- package/components/blocks/WorkflowCanvas/layout-engine.ts +59 -0
- package/components/blocks/index.ts +1 -1
- package/components/composites/StateNode/StateNode.tsx +6 -7
- package/components/composites/TriggerNode/TriggerNode.tsx +7 -5
- package/components/index.ts +1 -0
- package/dist/index.cjs +62 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +0 -6
- package/dist/index.d.ts +1 -0
- package/dist/index.js +62 -13
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
|
@@ -2,25 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
ConnectionMode,
|
|
5
|
-
MiniMap,
|
|
6
5
|
ReactFlowProvider,
|
|
7
|
-
type Node,
|
|
8
|
-
type NodeChange,
|
|
9
|
-
type EdgeChange,
|
|
10
6
|
type Connection,
|
|
11
|
-
type OnConnectStartParams,
|
|
12
7
|
useReactFlow,
|
|
13
8
|
} from "@xyflow/react";
|
|
14
9
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
15
|
-
import type { ReactNode } from "react";
|
|
16
10
|
import { Canvas } from "@/components/ai-elements/canvas";
|
|
17
11
|
import { Connection as ConnectionLine } from "@/components/ai-elements/connection";
|
|
18
12
|
import { Controls } from "@/components/ai-elements/controls";
|
|
19
13
|
import { Edge } from "@/components/ai-elements/edge";
|
|
20
14
|
import { Panel } from "@/components/ai-elements/panel";
|
|
21
|
-
import { StateNode
|
|
22
|
-
import { TransitionNode
|
|
23
|
-
import { TriggerNode
|
|
15
|
+
import { StateNode } from "@/components/composites/StateNode";
|
|
16
|
+
import { TransitionNode } from "@/components/composites/TransitionNode";
|
|
17
|
+
import { TriggerNode } from "@/components/composites/TriggerNode";
|
|
24
18
|
import type { WorkflowCanvasProps, WorkflowEdge } from "./interfaces";
|
|
25
19
|
import "@xyflow/react/dist/style.css";
|
|
26
20
|
|
|
@@ -47,7 +41,6 @@ function WorkflowCanvasInner({
|
|
|
47
41
|
onPaneClick,
|
|
48
42
|
onNodeClick,
|
|
49
43
|
onEdgeClick,
|
|
50
|
-
showMinimap = false,
|
|
51
44
|
interactive = false,
|
|
52
45
|
topLeft,
|
|
53
46
|
topRight,
|
|
@@ -141,9 +134,6 @@ function WorkflowCanvasInner({
|
|
|
141
134
|
>
|
|
142
135
|
<Controls />
|
|
143
136
|
</Panel>
|
|
144
|
-
{showMinimap && (
|
|
145
|
-
<MiniMap bgColor="var(--sidebar)" nodeStrokeColor="var(--border)" />
|
|
146
|
-
)}
|
|
147
137
|
</Canvas>
|
|
148
138
|
</div>
|
|
149
139
|
);
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import ELK from 'elkjs';
|
|
2
|
+
import type { WorkflowNode, WorkflowEdge } from './interfaces';
|
|
3
|
+
|
|
4
|
+
const NODE_WIDTH = 180;
|
|
5
|
+
const NODE_HEIGHT = 52;
|
|
6
|
+
|
|
7
|
+
const elk = new ELK();
|
|
8
|
+
|
|
9
|
+
export async function getLayoutedElements(
|
|
10
|
+
nodes: WorkflowNode[],
|
|
11
|
+
edges: WorkflowEdge[],
|
|
12
|
+
): Promise<{ nodes: WorkflowNode[]; edges: WorkflowEdge[] }> {
|
|
13
|
+
const graph = {
|
|
14
|
+
id: 'root',
|
|
15
|
+
layoutOptions: {
|
|
16
|
+
'elk.algorithm': 'layered',
|
|
17
|
+
'elk.direction': 'DOWN',
|
|
18
|
+
'elk.layered.spacing.nodeNodeBetweenLayers': '60',
|
|
19
|
+
'elk.spacing.nodeNode': '40',
|
|
20
|
+
'elk.layered.nodePlacement.strategy': 'BRANDES_KOEPF',
|
|
21
|
+
'elk.layered.nodePlacement.bk.fixedAlignment': 'BALANCED',
|
|
22
|
+
'elk.layered.considerModelOrder': 'true',
|
|
23
|
+
'elk.hierarchyHandling': 'INCLUDE_CHILDREN',
|
|
24
|
+
},
|
|
25
|
+
children: nodes.map((n) => ({
|
|
26
|
+
id: n.id,
|
|
27
|
+
width: NODE_WIDTH,
|
|
28
|
+
height: NODE_HEIGHT,
|
|
29
|
+
})),
|
|
30
|
+
edges: edges.map((e) => {
|
|
31
|
+
return {
|
|
32
|
+
id: e.id,
|
|
33
|
+
sources: [e.source],
|
|
34
|
+
targets: [e.target],
|
|
35
|
+
};
|
|
36
|
+
}),
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
40
|
+
const layout = await elk.layout(graph as any);
|
|
41
|
+
|
|
42
|
+
const layoutedNodes: WorkflowNode[] = nodes.map((n) => {
|
|
43
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
44
|
+
const elkNode = (layout.children ?? []).find((c: any) => c.id === n.id);
|
|
45
|
+
if (!elkNode || elkNode.x == null || elkNode.y == null) return n;
|
|
46
|
+
return {
|
|
47
|
+
...n,
|
|
48
|
+
position: { x: elkNode.x, y: elkNode.y },
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const layoutedEdges: WorkflowEdge[] = edges.map((e) => ({
|
|
53
|
+
...e,
|
|
54
|
+
sourceHandle: 'source-bottom',
|
|
55
|
+
targetHandle: 'target-top',
|
|
56
|
+
}));
|
|
57
|
+
|
|
58
|
+
return { nodes: layoutedNodes, edges: layoutedEdges };
|
|
59
|
+
}
|
|
@@ -15,7 +15,7 @@ export * from './LayoutProvider'
|
|
|
15
15
|
export * from './SectionLayout'
|
|
16
16
|
export type { LayoutProviderProps } from './LayoutProvider'
|
|
17
17
|
|
|
18
|
-
export { WorkflowCanvas } from './WorkflowCanvas'
|
|
18
|
+
export { WorkflowCanvas, getLayoutedElements } from './WorkflowCanvas'
|
|
19
19
|
export type { WorkflowCanvasProps, WorkflowNode, WorkflowEdge, WorkflowNodeData } from './WorkflowCanvas'
|
|
20
20
|
|
|
21
21
|
export { DashboardHeader } from './DashboardHeader'
|
|
@@ -66,13 +66,12 @@ export const StateNode = memo(({ data, selected, id }: StateNodeProps) => {
|
|
|
66
66
|
const isTerminal = data.isTerminal === true;
|
|
67
67
|
|
|
68
68
|
return (
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
)}
|
|
69
|
+
<Node
|
|
70
|
+
className={cn(
|
|
71
|
+
"relative flex flex-col items-center justify-center border border-border bg-card shadow-none transition-all duration-150 ease-out",
|
|
72
|
+
selected ? "border-primary border-2" : "border border-border",
|
|
73
|
+
isDisabled && "opacity-50"
|
|
74
|
+
)}
|
|
76
75
|
data-testid={`state-node-${id}`}
|
|
77
76
|
handles={{ target: true, source: true }}
|
|
78
77
|
status={status}
|
|
@@ -35,19 +35,21 @@ export const TriggerNode = memo(({ data, selected, id }: TriggerNodeProps) => {
|
|
|
35
35
|
return (
|
|
36
36
|
<Node
|
|
37
37
|
className={cn(
|
|
38
|
-
"relative flex
|
|
38
|
+
"relative flex flex-col items-center justify-center bg-purple-50 dark:bg-purple-950/30 border border-purple-200 dark:border-purple-800 shadow-none transition-all duration-150 ease-out",
|
|
39
39
|
selected && "border-primary border-2"
|
|
40
40
|
)}
|
|
41
41
|
data-testid={`trigger-node-${id}`}
|
|
42
42
|
handles={{ target: false, source: true }}
|
|
43
43
|
status={status}
|
|
44
44
|
>
|
|
45
|
-
<div className="flex items-center gap-1.5 px-3 py-2">
|
|
45
|
+
<div className="flex h-full w-full items-center justify-center gap-1.5 px-3 py-2">
|
|
46
46
|
<Play className="size-3 shrink-0 text-purple-600 dark:text-purple-400" strokeWidth={1.5} />
|
|
47
|
-
<div className="
|
|
48
|
-
<NodeTitle className="text-xs font-medium leading-tight"
|
|
47
|
+
<div className="min-w-0 flex-1 text-center">
|
|
48
|
+
<NodeTitle className="line-clamp-2 text-center text-xs font-medium leading-tight" title={displayTitle}>
|
|
49
|
+
{displayTitle}
|
|
50
|
+
</NodeTitle>
|
|
49
51
|
{displayDescription && (
|
|
50
|
-
<NodeDescription className="text-[10px] leading-tight
|
|
52
|
+
<NodeDescription className="mt-0.5 line-clamp-2 text-center text-[10px] leading-tight" title={displayDescription}>
|
|
51
53
|
{displayDescription}
|
|
52
54
|
</NodeDescription>
|
|
53
55
|
)}
|
package/components/index.ts
CHANGED
|
@@ -9,6 +9,7 @@ export type * from './features';
|
|
|
9
9
|
|
|
10
10
|
// Composites (value exports not covered by export type *)
|
|
11
11
|
export { ModeSwitcher } from './composites';
|
|
12
|
+
export { getLayoutedElements } from './blocks';
|
|
12
13
|
|
|
13
14
|
// External library re-exports
|
|
14
15
|
export { ReactFlowProvider, applyNodeChanges, applyEdgeChanges, addEdge } from '@xyflow/react';
|
package/dist/index.cjs
CHANGED
|
@@ -48,6 +48,7 @@ var zod = require('zod');
|
|
|
48
48
|
var uiSchemaContracts = require('ui-schema-contracts');
|
|
49
49
|
var react = require('@xyflow/react');
|
|
50
50
|
require('@xyflow/react/dist/style.css');
|
|
51
|
+
var ELK = require('elkjs');
|
|
51
52
|
var form = require('design-schema/schemas/form');
|
|
52
53
|
|
|
53
54
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -92,6 +93,7 @@ var ProgressPrimitive__namespace = /*#__PURE__*/_interopNamespace(ProgressPrimit
|
|
|
92
93
|
var ToggleGroupPrimitive__namespace = /*#__PURE__*/_interopNamespace(ToggleGroupPrimitive);
|
|
93
94
|
var StarterKit__default = /*#__PURE__*/_interopDefault(StarterKit);
|
|
94
95
|
var Highlight__default = /*#__PURE__*/_interopDefault(Highlight);
|
|
96
|
+
var ELK__default = /*#__PURE__*/_interopDefault(ELK);
|
|
95
97
|
|
|
96
98
|
var __defProp = Object.defineProperty;
|
|
97
99
|
var __defProps = Object.defineProperties;
|
|
@@ -8296,14 +8298,13 @@ var StateNode = React3.memo(({ data, selected, id }) => {
|
|
|
8296
8298
|
const displayDescription = data.description;
|
|
8297
8299
|
const status = data.status;
|
|
8298
8300
|
const isDisabled = data.enabled === false;
|
|
8299
|
-
|
|
8301
|
+
data.isTerminal === true;
|
|
8300
8302
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
8301
8303
|
Node2,
|
|
8302
8304
|
{
|
|
8303
8305
|
className: cn(
|
|
8304
8306
|
"relative flex flex-col items-center justify-center border border-border bg-card shadow-none transition-all duration-150 ease-out",
|
|
8305
|
-
selected
|
|
8306
|
-
isTerminal && "border-2 border-primary",
|
|
8307
|
+
selected ? "border-primary border-2" : "border border-border",
|
|
8307
8308
|
isDisabled && "opacity-50"
|
|
8308
8309
|
),
|
|
8309
8310
|
"data-testid": `state-node-${id}`,
|
|
@@ -8381,17 +8382,17 @@ var TriggerNode = React3.memo(({ data, selected, id }) => {
|
|
|
8381
8382
|
Node2,
|
|
8382
8383
|
{
|
|
8383
8384
|
className: cn(
|
|
8384
|
-
"relative flex
|
|
8385
|
+
"relative flex flex-col items-center justify-center bg-purple-50 dark:bg-purple-950/30 border border-purple-200 dark:border-purple-800 shadow-none transition-all duration-150 ease-out",
|
|
8385
8386
|
selected && "border-primary border-2"
|
|
8386
8387
|
),
|
|
8387
8388
|
"data-testid": `trigger-node-${id}`,
|
|
8388
8389
|
handles: { target: false, source: true },
|
|
8389
8390
|
status,
|
|
8390
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 px-3 py-2", children: [
|
|
8391
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full w-full items-center justify-center gap-1.5 px-3 py-2", children: [
|
|
8391
8392
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Play, { className: "size-3 shrink-0 text-purple-600 dark:text-purple-400", strokeWidth: 1.5 }),
|
|
8392
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "
|
|
8393
|
-
/* @__PURE__ */ jsxRuntime.jsx(NodeTitle, { className: "text-xs font-medium leading-tight", children: displayTitle }),
|
|
8394
|
-
displayDescription && /* @__PURE__ */ jsxRuntime.jsx(NodeDescription, { className: "text-[10px] leading-tight
|
|
8393
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1 text-center", children: [
|
|
8394
|
+
/* @__PURE__ */ jsxRuntime.jsx(NodeTitle, { className: "line-clamp-2 text-center text-xs font-medium leading-tight", title: displayTitle, children: displayTitle }),
|
|
8395
|
+
displayDescription && /* @__PURE__ */ jsxRuntime.jsx(NodeDescription, { className: "mt-0.5 line-clamp-2 text-center text-[10px] leading-tight", title: displayDescription, children: displayDescription })
|
|
8395
8396
|
] })
|
|
8396
8397
|
] })
|
|
8397
8398
|
}
|
|
@@ -9383,7 +9384,6 @@ function WorkflowCanvasInner({
|
|
|
9383
9384
|
onPaneClick,
|
|
9384
9385
|
onNodeClick,
|
|
9385
9386
|
onEdgeClick,
|
|
9386
|
-
showMinimap = false,
|
|
9387
9387
|
interactive = false,
|
|
9388
9388
|
topLeft,
|
|
9389
9389
|
topRight,
|
|
@@ -9476,8 +9476,7 @@ function WorkflowCanvasInner({
|
|
|
9476
9476
|
position: "bottom-left",
|
|
9477
9477
|
children: /* @__PURE__ */ jsxRuntime.jsx(Controls, {})
|
|
9478
9478
|
}
|
|
9479
|
-
)
|
|
9480
|
-
showMinimap && /* @__PURE__ */ jsxRuntime.jsx(react.MiniMap, { bgColor: "var(--sidebar)", nodeStrokeColor: "var(--border)" })
|
|
9479
|
+
)
|
|
9481
9480
|
]
|
|
9482
9481
|
}
|
|
9483
9482
|
)
|
|
@@ -9487,6 +9486,50 @@ function WorkflowCanvasInner({
|
|
|
9487
9486
|
function WorkflowCanvas(props) {
|
|
9488
9487
|
return /* @__PURE__ */ jsxRuntime.jsx(react.ReactFlowProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(WorkflowCanvasInner, __spreadValues({}, props)) });
|
|
9489
9488
|
}
|
|
9489
|
+
var NODE_WIDTH = 180;
|
|
9490
|
+
var NODE_HEIGHT = 52;
|
|
9491
|
+
var elk = new ELK__default.default();
|
|
9492
|
+
async function getLayoutedElements(nodes, edges) {
|
|
9493
|
+
const graph = {
|
|
9494
|
+
id: "root",
|
|
9495
|
+
layoutOptions: {
|
|
9496
|
+
"elk.algorithm": "layered",
|
|
9497
|
+
"elk.direction": "DOWN",
|
|
9498
|
+
"elk.layered.spacing.nodeNodeBetweenLayers": "60",
|
|
9499
|
+
"elk.spacing.nodeNode": "40",
|
|
9500
|
+
"elk.layered.nodePlacement.strategy": "BRANDES_KOEPF",
|
|
9501
|
+
"elk.layered.nodePlacement.bk.fixedAlignment": "BALANCED",
|
|
9502
|
+
"elk.layered.considerModelOrder": "true",
|
|
9503
|
+
"elk.hierarchyHandling": "INCLUDE_CHILDREN"
|
|
9504
|
+
},
|
|
9505
|
+
children: nodes.map((n) => ({
|
|
9506
|
+
id: n.id,
|
|
9507
|
+
width: NODE_WIDTH,
|
|
9508
|
+
height: NODE_HEIGHT
|
|
9509
|
+
})),
|
|
9510
|
+
edges: edges.map((e) => {
|
|
9511
|
+
return {
|
|
9512
|
+
id: e.id,
|
|
9513
|
+
sources: [e.source],
|
|
9514
|
+
targets: [e.target]
|
|
9515
|
+
};
|
|
9516
|
+
})
|
|
9517
|
+
};
|
|
9518
|
+
const layout = await elk.layout(graph);
|
|
9519
|
+
const layoutedNodes = nodes.map((n) => {
|
|
9520
|
+
var _a;
|
|
9521
|
+
const elkNode = ((_a = layout.children) != null ? _a : []).find((c) => c.id === n.id);
|
|
9522
|
+
if (!elkNode || elkNode.x == null || elkNode.y == null) return n;
|
|
9523
|
+
return __spreadProps(__spreadValues({}, n), {
|
|
9524
|
+
position: { x: elkNode.x, y: elkNode.y }
|
|
9525
|
+
});
|
|
9526
|
+
});
|
|
9527
|
+
const layoutedEdges = edges.map((e) => __spreadProps(__spreadValues({}, e), {
|
|
9528
|
+
sourceHandle: "source-bottom",
|
|
9529
|
+
targetHandle: "target-top"
|
|
9530
|
+
}));
|
|
9531
|
+
return { nodes: layoutedNodes, edges: layoutedEdges };
|
|
9532
|
+
}
|
|
9490
9533
|
function WorkflowBuilder({
|
|
9491
9534
|
workflowName,
|
|
9492
9535
|
versions,
|
|
@@ -10501,6 +10544,13 @@ var selectedWorkflowRunMock = {
|
|
|
10501
10544
|
suspensionReason: "-"
|
|
10502
10545
|
})
|
|
10503
10546
|
});
|
|
10547
|
+
var DashboardHeader = React3__namespace.memo(({ ctaLabel = "Quick Create" }) => {
|
|
10548
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
10549
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button2, { variant: "outline", size: "sm", className: "hidden sm:flex", children: ctaLabel }),
|
|
10550
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-muted-foreground", children: "GitHub" })
|
|
10551
|
+
] });
|
|
10552
|
+
});
|
|
10553
|
+
DashboardHeader.displayName = "DashboardHeader";
|
|
10504
10554
|
|
|
10505
10555
|
Object.defineProperty(exports, "ReactFlowProvider", {
|
|
10506
10556
|
enumerable: true,
|
|
@@ -10528,5 +10578,6 @@ exports.SpecNavigator = SpecNavigator;
|
|
|
10528
10578
|
exports.WorkflowBuilder = WorkflowBuilder;
|
|
10529
10579
|
exports.WorkflowObservabilityFeature = WorkflowObservabilityFeature;
|
|
10530
10580
|
exports.cn = cn;
|
|
10581
|
+
exports.getLayoutedElements = getLayoutedElements;
|
|
10531
10582
|
//# sourceMappingURL=index.cjs.map
|
|
10532
10583
|
//# sourceMappingURL=index.cjs.map
|