ai-design-system 0.1.38 → 0.1.39

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.
@@ -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, type StateNodeData } from "@/components/composites/StateNode";
22
- import { TransitionNode, type TransitionNodeData } from "@/components/composites/TransitionNode";
23
- import { TriggerNode, type TriggerNodeData } from "@/components/composites/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
  );
@@ -1,2 +1,3 @@
1
1
  export { WorkflowCanvas } from "./WorkflowCanvas";
2
2
  export type { WorkflowCanvasProps, WorkflowNode, WorkflowEdge, WorkflowNodeData } from "./interfaces";
3
+ export { getLayoutedElements } from "./layout-engine";
@@ -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'
@@ -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 h-auto w-auto min-w-[120px] max-w-[180px] 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",
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="flex flex-col">
48
- <NodeTitle className="text-xs font-medium leading-tight">{displayTitle}</NodeTitle>
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 mt-0.5">
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
  )}
@@ -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;
@@ -8381,17 +8383,17 @@ var TriggerNode = React3.memo(({ data, selected, id }) => {
8381
8383
  Node2,
8382
8384
  {
8383
8385
  className: cn(
8384
- "relative flex h-auto w-auto min-w-[120px] max-w-[180px] 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",
8386
+ "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
8387
  selected && "border-primary border-2"
8386
8388
  ),
8387
8389
  "data-testid": `trigger-node-${id}`,
8388
8390
  handles: { target: false, source: true },
8389
8391
  status,
8390
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 px-3 py-2", children: [
8392
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full w-full items-center justify-center gap-1.5 px-3 py-2", children: [
8391
8393
  /* @__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: "flex flex-col", children: [
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 mt-0.5", children: displayDescription })
8394
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1 text-center", children: [
8395
+ /* @__PURE__ */ jsxRuntime.jsx(NodeTitle, { className: "line-clamp-2 text-center text-xs font-medium leading-tight", title: displayTitle, children: displayTitle }),
8396
+ displayDescription && /* @__PURE__ */ jsxRuntime.jsx(NodeDescription, { className: "mt-0.5 line-clamp-2 text-center text-[10px] leading-tight", title: displayDescription, children: displayDescription })
8395
8397
  ] })
8396
8398
  ] })
8397
8399
  }
@@ -9383,7 +9385,6 @@ function WorkflowCanvasInner({
9383
9385
  onPaneClick,
9384
9386
  onNodeClick,
9385
9387
  onEdgeClick,
9386
- showMinimap = false,
9387
9388
  interactive = false,
9388
9389
  topLeft,
9389
9390
  topRight,
@@ -9476,8 +9477,7 @@ function WorkflowCanvasInner({
9476
9477
  position: "bottom-left",
9477
9478
  children: /* @__PURE__ */ jsxRuntime.jsx(Controls, {})
9478
9479
  }
9479
- ),
9480
- showMinimap && /* @__PURE__ */ jsxRuntime.jsx(react.MiniMap, { bgColor: "var(--sidebar)", nodeStrokeColor: "var(--border)" })
9480
+ )
9481
9481
  ]
9482
9482
  }
9483
9483
  )
@@ -9487,6 +9487,50 @@ function WorkflowCanvasInner({
9487
9487
  function WorkflowCanvas(props) {
9488
9488
  return /* @__PURE__ */ jsxRuntime.jsx(react.ReactFlowProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(WorkflowCanvasInner, __spreadValues({}, props)) });
9489
9489
  }
9490
+ var NODE_WIDTH = 180;
9491
+ var NODE_HEIGHT = 52;
9492
+ var elk = new ELK__default.default();
9493
+ async function getLayoutedElements(nodes, edges) {
9494
+ const graph = {
9495
+ id: "root",
9496
+ layoutOptions: {
9497
+ "elk.algorithm": "layered",
9498
+ "elk.direction": "DOWN",
9499
+ "elk.layered.spacing.nodeNodeBetweenLayers": "60",
9500
+ "elk.spacing.nodeNode": "40",
9501
+ "elk.layered.nodePlacement.strategy": "BRANDES_KOEPF",
9502
+ "elk.layered.nodePlacement.bk.fixedAlignment": "BALANCED",
9503
+ "elk.layered.considerModelOrder": "true",
9504
+ "elk.hierarchyHandling": "INCLUDE_CHILDREN"
9505
+ },
9506
+ children: nodes.map((n) => ({
9507
+ id: n.id,
9508
+ width: NODE_WIDTH,
9509
+ height: NODE_HEIGHT
9510
+ })),
9511
+ edges: edges.map((e) => {
9512
+ return {
9513
+ id: e.id,
9514
+ sources: [e.source],
9515
+ targets: [e.target]
9516
+ };
9517
+ })
9518
+ };
9519
+ const layout = await elk.layout(graph);
9520
+ const layoutedNodes = nodes.map((n) => {
9521
+ var _a;
9522
+ const elkNode = ((_a = layout.children) != null ? _a : []).find((c) => c.id === n.id);
9523
+ if (!elkNode || elkNode.x == null || elkNode.y == null) return n;
9524
+ return __spreadProps(__spreadValues({}, n), {
9525
+ position: { x: elkNode.x, y: elkNode.y }
9526
+ });
9527
+ });
9528
+ const layoutedEdges = edges.map((e) => __spreadProps(__spreadValues({}, e), {
9529
+ sourceHandle: "source-bottom",
9530
+ targetHandle: "target-top"
9531
+ }));
9532
+ return { nodes: layoutedNodes, edges: layoutedEdges };
9533
+ }
9490
9534
  function WorkflowBuilder({
9491
9535
  workflowName,
9492
9536
  versions,
@@ -10501,6 +10545,13 @@ var selectedWorkflowRunMock = {
10501
10545
  suspensionReason: "-"
10502
10546
  })
10503
10547
  });
10548
+ var DashboardHeader = React3__namespace.memo(({ ctaLabel = "Quick Create" }) => {
10549
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
10550
+ /* @__PURE__ */ jsxRuntime.jsx(Button2, { variant: "outline", size: "sm", className: "hidden sm:flex", children: ctaLabel }),
10551
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-muted-foreground", children: "GitHub" })
10552
+ ] });
10553
+ });
10554
+ DashboardHeader.displayName = "DashboardHeader";
10504
10555
 
10505
10556
  Object.defineProperty(exports, "ReactFlowProvider", {
10506
10557
  enumerable: true,
@@ -10528,5 +10579,6 @@ exports.SpecNavigator = SpecNavigator;
10528
10579
  exports.WorkflowBuilder = WorkflowBuilder;
10529
10580
  exports.WorkflowObservabilityFeature = WorkflowObservabilityFeature;
10530
10581
  exports.cn = cn;
10582
+ exports.getLayoutedElements = getLayoutedElements;
10531
10583
  //# sourceMappingURL=index.cjs.map
10532
10584
  //# sourceMappingURL=index.cjs.map