@octaviaflow/core 3.0.14 → 3.0.18-beta.0

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.
Files changed (258) hide show
  1. package/dist/chunk-2AWVQFSC.js +2456 -0
  2. package/dist/chunk-2AWVQFSC.js.map +1 -0
  3. package/dist/chunk-2K7IQR2F.js +2432 -0
  4. package/dist/chunk-2K7IQR2F.js.map +1 -0
  5. package/dist/chunk-2RD5OERK.js +2553 -0
  6. package/dist/chunk-2RD5OERK.js.map +1 -0
  7. package/dist/chunk-2YUWZPIT.js +2483 -0
  8. package/dist/chunk-2YUWZPIT.js.map +1 -0
  9. package/dist/chunk-4VCRGPYQ.js +2452 -0
  10. package/dist/chunk-4VCRGPYQ.js.map +1 -0
  11. package/dist/chunk-4WU5YAL2.js +2470 -0
  12. package/dist/chunk-4WU5YAL2.js.map +1 -0
  13. package/dist/chunk-5L4TGL74.js +2448 -0
  14. package/dist/chunk-5L4TGL74.js.map +1 -0
  15. package/dist/chunk-7M5HFY2J.js +2483 -0
  16. package/dist/chunk-7M5HFY2J.js.map +1 -0
  17. package/dist/chunk-AJ4556EH.js +2490 -0
  18. package/dist/chunk-AJ4556EH.js.map +1 -0
  19. package/dist/chunk-AOL365B3.js +2448 -0
  20. package/dist/chunk-AOL365B3.js.map +1 -0
  21. package/dist/chunk-CGWNV2HS.js +2549 -0
  22. package/dist/chunk-CGWNV2HS.js.map +1 -0
  23. package/dist/chunk-CS7JWNQD.js +2552 -0
  24. package/dist/chunk-CS7JWNQD.js.map +1 -0
  25. package/dist/chunk-D4X7RMGF.js +2481 -0
  26. package/dist/chunk-D4X7RMGF.js.map +1 -0
  27. package/dist/chunk-D6CFZILB.js +2550 -0
  28. package/dist/chunk-D6CFZILB.js.map +1 -0
  29. package/dist/chunk-DCGXCPD4.js +2389 -0
  30. package/dist/chunk-DCGXCPD4.js.map +1 -0
  31. package/dist/chunk-DG35MIV3.js +2480 -0
  32. package/dist/chunk-DG35MIV3.js.map +1 -0
  33. package/dist/chunk-DRZ73Q5X.js +2503 -0
  34. package/dist/chunk-DRZ73Q5X.js.map +1 -0
  35. package/dist/chunk-DRZMET2G.js +2458 -0
  36. package/dist/chunk-DRZMET2G.js.map +1 -0
  37. package/dist/chunk-DYCW4TYB.js +2546 -0
  38. package/dist/chunk-DYCW4TYB.js.map +1 -0
  39. package/dist/chunk-E7WR7DMP.js +2451 -0
  40. package/dist/chunk-E7WR7DMP.js.map +1 -0
  41. package/dist/chunk-ECOTUJWJ.js +2548 -0
  42. package/dist/chunk-ECOTUJWJ.js.map +1 -0
  43. package/dist/chunk-ELNQQAHD.js +2454 -0
  44. package/dist/chunk-ELNQQAHD.js.map +1 -0
  45. package/dist/chunk-F3ZHEDDP.js +2548 -0
  46. package/dist/chunk-F3ZHEDDP.js.map +1 -0
  47. package/dist/chunk-FN3MFN6C.js +2389 -0
  48. package/dist/chunk-FN3MFN6C.js.map +1 -0
  49. package/dist/chunk-IBTEGHFT.js +10 -0
  50. package/dist/chunk-IBTEGHFT.js.map +1 -0
  51. package/dist/chunk-JCPM7YF2.js +2474 -0
  52. package/dist/chunk-JCPM7YF2.js.map +1 -0
  53. package/dist/chunk-JLPCCZKG.js +2459 -0
  54. package/dist/chunk-JLPCCZKG.js.map +1 -0
  55. package/dist/chunk-KY4JHPIE.js +2546 -0
  56. package/dist/chunk-KY4JHPIE.js.map +1 -0
  57. package/dist/chunk-LCQMQAWJ.js +2461 -0
  58. package/dist/chunk-LCQMQAWJ.js.map +1 -0
  59. package/dist/chunk-LSDAQCUJ.js +2546 -0
  60. package/dist/chunk-LSDAQCUJ.js.map +1 -0
  61. package/dist/chunk-LW4ZHQKL.js +2432 -0
  62. package/dist/chunk-LW4ZHQKL.js.map +1 -0
  63. package/dist/chunk-MMZW3Q26.js +2442 -0
  64. package/dist/chunk-MMZW3Q26.js.map +1 -0
  65. package/dist/chunk-MXJR2WHG.js +2470 -0
  66. package/dist/chunk-MXJR2WHG.js.map +1 -0
  67. package/dist/chunk-OK2CUIKQ.js +2447 -0
  68. package/dist/chunk-OK2CUIKQ.js.map +1 -0
  69. package/dist/chunk-OSOP2WPT.js +2456 -0
  70. package/dist/chunk-OSOP2WPT.js.map +1 -0
  71. package/dist/chunk-PNBZLLWT.js +2529 -0
  72. package/dist/chunk-PNBZLLWT.js.map +1 -0
  73. package/dist/chunk-PULX2GK5.js +2447 -0
  74. package/dist/chunk-PULX2GK5.js.map +1 -0
  75. package/dist/chunk-QDT45KF4.js +2480 -0
  76. package/dist/chunk-QDT45KF4.js.map +1 -0
  77. package/dist/chunk-QI3ITHAZ.js +2450 -0
  78. package/dist/chunk-QI3ITHAZ.js.map +1 -0
  79. package/dist/chunk-QSGJ3DNA.js +2475 -0
  80. package/dist/chunk-QSGJ3DNA.js.map +1 -0
  81. package/dist/chunk-QWICIDGH.js +2547 -0
  82. package/dist/chunk-QWICIDGH.js.map +1 -0
  83. package/dist/chunk-RDGJWRHM.js +2490 -0
  84. package/dist/chunk-RDGJWRHM.js.map +1 -0
  85. package/dist/chunk-SDE3ARKY.js +2451 -0
  86. package/dist/chunk-SDE3ARKY.js.map +1 -0
  87. package/dist/chunk-SX7WRJGD.js +2441 -0
  88. package/dist/chunk-SX7WRJGD.js.map +1 -0
  89. package/dist/chunk-TTKIDRN7.js +2551 -0
  90. package/dist/chunk-TTKIDRN7.js.map +1 -0
  91. package/dist/chunk-TZ56MSYM.js +2452 -0
  92. package/dist/chunk-TZ56MSYM.js.map +1 -0
  93. package/dist/chunk-UEQLKS2B.js +2445 -0
  94. package/dist/chunk-UEQLKS2B.js.map +1 -0
  95. package/dist/chunk-UFGAO5OY.js +2546 -0
  96. package/dist/chunk-UFGAO5OY.js.map +1 -0
  97. package/dist/chunk-UNU6YNTL.js +2452 -0
  98. package/dist/chunk-UNU6YNTL.js.map +1 -0
  99. package/dist/chunk-UUG6XYUC.js +2482 -0
  100. package/dist/chunk-UUG6XYUC.js.map +1 -0
  101. package/dist/chunk-VEY3BP5E.js +2447 -0
  102. package/dist/chunk-VEY3BP5E.js.map +1 -0
  103. package/dist/chunk-WBTXV3Q2.js +2482 -0
  104. package/dist/chunk-WBTXV3Q2.js.map +1 -0
  105. package/dist/chunk-WILVB7XA.js +2512 -0
  106. package/dist/chunk-WILVB7XA.js.map +1 -0
  107. package/dist/chunk-WQCHABP3.js +2441 -0
  108. package/dist/chunk-WQCHABP3.js.map +1 -0
  109. package/dist/chunk-WUFAW3TB.js +2512 -0
  110. package/dist/chunk-WUFAW3TB.js.map +1 -0
  111. package/dist/chunk-WYBJKALZ.js +2458 -0
  112. package/dist/chunk-WYBJKALZ.js.map +1 -0
  113. package/dist/chunk-XZ7FELMT.js +2448 -0
  114. package/dist/chunk-XZ7FELMT.js.map +1 -0
  115. package/dist/chunk-YATCRJVF.js +2458 -0
  116. package/dist/chunk-YATCRJVF.js.map +1 -0
  117. package/dist/chunk-YSSD2T4M.js +2451 -0
  118. package/dist/chunk-YSSD2T4M.js.map +1 -0
  119. package/dist/chunk-YW6ZOYCG.js +2451 -0
  120. package/dist/chunk-YW6ZOYCG.js.map +1 -0
  121. package/dist/components/ActionsDrawer/ActionsDrawer.d.ts +95 -0
  122. package/dist/components/ActionsDrawer/ActionsDrawer.d.ts.map +1 -0
  123. package/dist/components/ActionsDrawer/index.d.ts +2 -0
  124. package/dist/components/ActionsDrawer/index.d.ts.map +1 -0
  125. package/dist/components/AgentCard/AgentCard.d.ts +1 -1
  126. package/dist/components/AgentCard/AgentCard.d.ts.map +1 -1
  127. package/dist/components/AuthCard/AuthCard.d.ts.map +1 -1
  128. package/dist/components/Button/Button.d.ts.map +1 -1
  129. package/dist/components/CodeEditor/CodeEditor.d.ts.map +1 -1
  130. package/dist/components/CodeEditor/index.d.ts +1 -1
  131. package/dist/components/CodeEditor/index.d.ts.map +1 -1
  132. package/dist/components/ConfigPanel/ConfigPanel.d.ts +20 -1
  133. package/dist/components/ConfigPanel/ConfigPanel.d.ts.map +1 -1
  134. package/dist/components/DataMapper/DataMapper.d.ts.map +1 -1
  135. package/dist/components/DataTable/DataTable.d.ts.map +1 -1
  136. package/dist/components/DataTable/index.d.ts +1 -1
  137. package/dist/components/DataTable/index.d.ts.map +1 -1
  138. package/dist/components/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  139. package/dist/components/ExecutionConsole/ExecutionConsole.d.ts +45 -3
  140. package/dist/components/ExecutionConsole/ExecutionConsole.d.ts.map +1 -1
  141. package/dist/components/FileDropzone/FileDropzone.d.ts.map +1 -1
  142. package/dist/components/FlowEdge/FlowEdge.d.ts +15 -14
  143. package/dist/components/FlowEdge/FlowEdge.d.ts.map +1 -1
  144. package/dist/components/FlowMinimap/FlowMinimap.d.ts +27 -2
  145. package/dist/components/FlowMinimap/FlowMinimap.d.ts.map +1 -1
  146. package/dist/components/FlowToolbar/FlowToolbar.d.ts +91 -1
  147. package/dist/components/FlowToolbar/FlowToolbar.d.ts.map +1 -1
  148. package/dist/components/FlowToolbar/index.d.ts +1 -1
  149. package/dist/components/FlowToolbar/index.d.ts.map +1 -1
  150. package/dist/components/Input/Input.d.ts.map +1 -1
  151. package/dist/components/MonacoEditor/MonacoDiffEditor.d.ts.map +1 -1
  152. package/dist/components/MonacoEditor/MonacoEditor.d.ts.map +1 -1
  153. package/dist/components/MonacoEditor/index.d.ts +1 -1
  154. package/dist/components/MonacoEditor/index.d.ts.map +1 -1
  155. package/dist/components/PromptInput/PromptInput.d.ts.map +1 -1
  156. package/dist/components/Radio/Radio.d.ts.map +1 -1
  157. package/dist/components/Resizable/Resizable.d.ts.map +1 -1
  158. package/dist/components/Resizable/index.d.ts +1 -1
  159. package/dist/components/Resizable/index.d.ts.map +1 -1
  160. package/dist/components/Select/Select.d.ts +16 -1
  161. package/dist/components/Select/Select.d.ts.map +1 -1
  162. package/dist/components/Sortable/Sortable.d.ts.map +1 -1
  163. package/dist/components/Sortable/index.d.ts +1 -1
  164. package/dist/components/Sortable/index.d.ts.map +1 -1
  165. package/dist/components/Tabs/Tabs.d.ts.map +1 -1
  166. package/dist/components/Toast/Toast.d.ts.map +1 -1
  167. package/dist/components/ToolCard/ToolCard.d.ts +1 -1
  168. package/dist/components/ToolCard/ToolCard.d.ts.map +1 -1
  169. package/dist/components/TopBar/TopBar.d.ts +22 -1
  170. package/dist/components/TopBar/TopBar.d.ts.map +1 -1
  171. package/dist/components/TraceStep/TraceStep.d.ts.map +1 -1
  172. package/dist/components/TraceStep/index.d.ts +1 -1
  173. package/dist/components/TraceStep/index.d.ts.map +1 -1
  174. package/dist/components/WorkflowEditor/WorkflowEditor.d.ts +10 -2
  175. package/dist/components/WorkflowEditor/WorkflowEditor.d.ts.map +1 -1
  176. package/dist/components/XmlViewer/XmlViewer.d.ts.map +1 -1
  177. package/dist/components/YamlViewer/YamlViewer.d.ts.map +1 -1
  178. package/dist/index.cjs +10526 -6533
  179. package/dist/index.cjs.map +1 -1
  180. package/dist/index.d.ts +5 -5
  181. package/dist/index.d.ts.map +1 -1
  182. package/dist/index.js +4060 -2513
  183. package/dist/index.js.map +1 -1
  184. package/dist/monaco.cjs +344 -201
  185. package/dist/monaco.cjs.map +1 -1
  186. package/dist/monaco.js +348 -205
  187. package/dist/monaco.js.map +1 -1
  188. package/dist/stories/state-matrix.d.ts.map +1 -1
  189. package/dist/styles.css +1 -1
  190. package/dist/utils/a11y.d.ts.map +1 -1
  191. package/dist/utils/sanitizeUrl.d.ts.map +1 -1
  192. package/dist/workflow/components/ConfigPanel/ConfigPanel.d.ts +64 -0
  193. package/dist/workflow/components/ConfigPanel/ConfigPanel.d.ts.map +1 -0
  194. package/dist/workflow/components/FlowCanvas/FlowCanvas.d.ts +111 -0
  195. package/dist/workflow/components/FlowCanvas/FlowCanvas.d.ts.map +1 -0
  196. package/dist/workflow/components/FlowCanvas/FlowCanvasContext.d.ts +47 -0
  197. package/dist/workflow/components/FlowCanvas/FlowCanvasContext.d.ts.map +1 -0
  198. package/dist/workflow/components/FlowEdge/FlowEdge.d.ts +26 -0
  199. package/dist/workflow/components/FlowEdge/FlowEdge.d.ts.map +1 -0
  200. package/dist/workflow/components/FlowNode/FlowNode.d.ts +13 -0
  201. package/dist/workflow/components/FlowNode/FlowNode.d.ts.map +1 -0
  202. package/dist/workflow/components/FlowNode/FlowNodeContext.d.ts +9 -0
  203. package/dist/workflow/components/FlowNode/FlowNodeContext.d.ts.map +1 -0
  204. package/dist/workflow/components/FlowNode/nodeKinds.d.ts +25 -0
  205. package/dist/workflow/components/FlowNode/nodeKinds.d.ts.map +1 -0
  206. package/dist/workflow/components/Handle/Handle.d.ts +26 -0
  207. package/dist/workflow/components/Handle/Handle.d.ts.map +1 -0
  208. package/dist/workflow/components/Handle/handleRegistry.d.ts +32 -0
  209. package/dist/workflow/components/Handle/handleRegistry.d.ts.map +1 -0
  210. package/dist/workflow/components/NodeResizer/NodeResizer.d.ts +27 -0
  211. package/dist/workflow/components/NodeResizer/NodeResizer.d.ts.map +1 -0
  212. package/dist/workflow/components/NodeToolbar/NodeToolbar.d.ts +19 -0
  213. package/dist/workflow/components/NodeToolbar/NodeToolbar.d.ts.map +1 -0
  214. package/dist/workflow/components/kinds/BaseNode.d.ts +46 -0
  215. package/dist/workflow/components/kinds/BaseNode.d.ts.map +1 -0
  216. package/dist/workflow/components/kinds/index.d.ts +61 -0
  217. package/dist/workflow/components/kinds/index.d.ts.map +1 -0
  218. package/dist/workflow/editor.d.ts +181 -0
  219. package/dist/workflow/editor.d.ts.map +1 -0
  220. package/dist/workflow/hooks/useAutoLayout.d.ts +35 -0
  221. package/dist/workflow/hooks/useAutoLayout.d.ts.map +1 -0
  222. package/dist/workflow/hooks/useFlow.d.ts +61 -0
  223. package/dist/workflow/hooks/useFlow.d.ts.map +1 -0
  224. package/dist/workflow/hooks/useFlowState.d.ts +33 -0
  225. package/dist/workflow/hooks/useFlowState.d.ts.map +1 -0
  226. package/dist/workflow/index.d.ts +25 -0
  227. package/dist/workflow/index.d.ts.map +1 -0
  228. package/dist/workflow/layout/dagre.d.ts +24 -0
  229. package/dist/workflow/layout/dagre.d.ts.map +1 -0
  230. package/dist/workflow/layout/elk.d.ts +22 -0
  231. package/dist/workflow/layout/elk.d.ts.map +1 -0
  232. package/dist/workflow/layout/types.d.ts +55 -0
  233. package/dist/workflow/layout/types.d.ts.map +1 -0
  234. package/dist/workflow/store/changes.d.ts +34 -0
  235. package/dist/workflow/store/changes.d.ts.map +1 -0
  236. package/dist/workflow/store/context.d.ts +4 -0
  237. package/dist/workflow/store/context.d.ts.map +1 -0
  238. package/dist/workflow/store/createFlowStore.d.ts +27 -0
  239. package/dist/workflow/store/createFlowStore.d.ts.map +1 -0
  240. package/dist/workflow/store/selectors.d.ts +33 -0
  241. package/dist/workflow/store/selectors.d.ts.map +1 -0
  242. package/dist/workflow/types/index.d.ts +181 -0
  243. package/dist/workflow/types/index.d.ts.map +1 -0
  244. package/dist/workflow/utils/collapse.d.ts +26 -0
  245. package/dist/workflow/utils/collapse.d.ts.map +1 -0
  246. package/dist/workflow/utils/collision.d.ts +37 -0
  247. package/dist/workflow/utils/collision.d.ts.map +1 -0
  248. package/dist/workflow/utils/geometry.d.ts +46 -0
  249. package/dist/workflow/utils/geometry.d.ts.map +1 -0
  250. package/dist/workflow/utils/parenting.d.ts +28 -0
  251. package/dist/workflow/utils/parenting.d.ts.map +1 -0
  252. package/dist/workflow/utils/paths.d.ts +19 -0
  253. package/dist/workflow/utils/paths.d.ts.map +1 -0
  254. package/dist/workflow.cjs +3569 -0
  255. package/dist/workflow.cjs.map +1 -0
  256. package/dist/workflow.js +1029 -0
  257. package/dist/workflow.js.map +1 -0
  258. package/package.json +6 -1
@@ -0,0 +1,1029 @@
1
+ import {
2
+ ActionNode,
3
+ ConditionNode,
4
+ DEFAULT_NODE_HEIGHT,
5
+ DEFAULT_NODE_KINDS,
6
+ DEFAULT_NODE_WIDTH,
7
+ ErrorNode,
8
+ FlowCanvas,
9
+ FlowEdge,
10
+ FlowNode,
11
+ ForEachNode,
12
+ GroupNode,
13
+ Handle,
14
+ HttpRequestNode,
15
+ OutputNode,
16
+ ParallelNode,
17
+ StickyNode,
18
+ TriggerNode,
19
+ WaitNode,
20
+ WebhookNode,
21
+ applyEdgeChanges,
22
+ applyNodeChanges,
23
+ bezierPath,
24
+ bezierPath2,
25
+ buildEdgePath,
26
+ buildNodeKindRegistry,
27
+ change,
28
+ clampToParentExtent,
29
+ descendantsOf,
30
+ findAncestor,
31
+ findContainingGroup,
32
+ flowToScreen,
33
+ handleCentre,
34
+ screenToFlow,
35
+ smoothStepPath,
36
+ stepPath,
37
+ straightPath,
38
+ useFlow,
39
+ useFlowNodeContext,
40
+ useFlowStore
41
+ } from "./chunk-2RD5OERK.js";
42
+ import {
43
+ cn
44
+ } from "./chunk-ZAUUGK2Y.js";
45
+
46
+ // src/workflow/hooks/useAutoLayout.ts
47
+ import { useCallback, useEffect, useRef, useState } from "react";
48
+ function signature(nodes, edges) {
49
+ const nodeKeys = nodes.map((n) => `${n.id}:${n.parentId ?? ""}`).sort().join("|");
50
+ const edgeKeys = edges.map((e) => `${e.id}:${e.source}>${e.target}`).sort().join("|");
51
+ return `${nodeKeys}::${edgeKeys}`;
52
+ }
53
+ function useAutoLayout({
54
+ engine,
55
+ nodes,
56
+ edges,
57
+ onNodesChange,
58
+ options,
59
+ auto = false,
60
+ debounceMs = 250,
61
+ onLayout,
62
+ onError
63
+ }) {
64
+ const [isLaying, setIsLaying] = useState(false);
65
+ const runningRef = useRef(false);
66
+ const optionsRef = useRef(options);
67
+ const onLayoutRef = useRef(onLayout);
68
+ const onErrorRef = useRef(onError);
69
+ const onNodesChangeRef = useRef(onNodesChange);
70
+ useEffect(() => {
71
+ optionsRef.current = options;
72
+ }, [options]);
73
+ useEffect(() => {
74
+ onLayoutRef.current = onLayout;
75
+ }, [onLayout]);
76
+ useEffect(() => {
77
+ onErrorRef.current = onError;
78
+ }, [onError]);
79
+ useEffect(() => {
80
+ onNodesChangeRef.current = onNodesChange;
81
+ }, [onNodesChange]);
82
+ const nodesRef = useRef(nodes);
83
+ const edgesRef = useRef(edges);
84
+ useEffect(() => {
85
+ nodesRef.current = nodes;
86
+ }, [nodes]);
87
+ useEffect(() => {
88
+ edgesRef.current = edges;
89
+ }, [edges]);
90
+ const runLayout = useCallback(async () => {
91
+ if (!engine) return;
92
+ if (runningRef.current) return;
93
+ runningRef.current = true;
94
+ setIsLaying(true);
95
+ try {
96
+ const positions = await engine.layout(nodesRef.current, edgesRef.current, optionsRef.current);
97
+ const positionedIds = new Set(positions.map((p) => p.id));
98
+ const deltas = /* @__PURE__ */ new Map();
99
+ const cs = [];
100
+ for (const p of positions) {
101
+ const cur = nodesRef.current.find((n) => n.id === p.id);
102
+ if (!cur) continue;
103
+ if (cur.position.x === p.position.x && cur.position.y === p.position.y) continue;
104
+ cs.push(change.node.position(p.id, p.position, false));
105
+ deltas.set(p.id, {
106
+ dx: p.position.x - cur.position.x,
107
+ dy: p.position.y - cur.position.y
108
+ });
109
+ }
110
+ const findParent = (id) => nodesRef.current.find((x) => x.id === id);
111
+ for (const n of nodesRef.current) {
112
+ if (positionedIds.has(n.id)) continue;
113
+ if (!n.parentId) continue;
114
+ let cursor = n.parentId;
115
+ const seen = /* @__PURE__ */ new Set();
116
+ let delta;
117
+ while (cursor) {
118
+ if (seen.has(cursor)) break;
119
+ seen.add(cursor);
120
+ const found = deltas.get(cursor);
121
+ if (found) {
122
+ delta = found;
123
+ break;
124
+ }
125
+ cursor = findParent(cursor)?.parentId;
126
+ }
127
+ if (!delta) continue;
128
+ cs.push(
129
+ change.node.position(
130
+ n.id,
131
+ { x: n.position.x + delta.dx, y: n.position.y + delta.dy },
132
+ false
133
+ )
134
+ );
135
+ }
136
+ if (cs.length) onNodesChangeRef.current?.(cs);
137
+ onLayoutRef.current?.(positions);
138
+ } catch (err) {
139
+ onErrorRef.current?.(err);
140
+ } finally {
141
+ runningRef.current = false;
142
+ setIsLaying(false);
143
+ }
144
+ }, [engine]);
145
+ const sig = signature(nodes, edges);
146
+ const sigRef = useRef(sig);
147
+ useEffect(() => {
148
+ if (!auto) return;
149
+ if (sigRef.current === sig) return;
150
+ sigRef.current = sig;
151
+ const timer = setTimeout(() => void runLayout(), debounceMs);
152
+ return () => clearTimeout(timer);
153
+ }, [sig, auto, debounceMs, runLayout]);
154
+ return { runLayout, isLaying };
155
+ }
156
+
157
+ // src/workflow/hooks/useFlowState.ts
158
+ import { useCallback as useCallback2, useMemo, useRef as useRef2, useState as useState2 } from "react";
159
+ function useFlowState(options = {}) {
160
+ const [nodes, setNodes] = useState2(options.initialNodes ?? []);
161
+ const [edges, setEdges] = useState2(options.initialEdges ?? []);
162
+ const nodesRef = useRef2(nodes);
163
+ nodesRef.current = nodes;
164
+ const onNodesChange = useCallback2((changes) => {
165
+ setNodes((prev) => applyNodeChanges(prev, changes));
166
+ }, []);
167
+ const onEdgesChange = useCallback2((changes) => {
168
+ setEdges((prev) => applyEdgeChanges(prev, changes));
169
+ }, []);
170
+ const updateNodeData = useCallback2((id, patch) => {
171
+ setNodes((prev) => {
172
+ let touched = false;
173
+ const next = prev.map((n) => {
174
+ if (n.id !== id) return n;
175
+ const nextData = typeof patch === "function" ? patch(n.data) : { ...n.data ?? {}, ...patch };
176
+ if (Object.is(nextData, n.data)) return n;
177
+ touched = true;
178
+ return { ...n, data: nextData };
179
+ });
180
+ return touched ? next : prev;
181
+ });
182
+ }, []);
183
+ const getNode = useCallback2((id) => nodesRef.current.find((n) => n.id === id), []);
184
+ return useMemo(
185
+ () => ({
186
+ nodes,
187
+ edges,
188
+ onNodesChange,
189
+ onEdgesChange,
190
+ setNodes,
191
+ setEdges,
192
+ updateNodeData,
193
+ getNode
194
+ }),
195
+ [nodes, edges, onNodesChange, onEdgesChange, updateNodeData, getNode]
196
+ );
197
+ }
198
+
199
+ // src/workflow/layout/dagre.ts
200
+ function createDagreEngine(dagre, defaults = {}) {
201
+ const lib = resolveDagre(dagre);
202
+ const defaultDir = defaults.direction ?? "TB";
203
+ const defaultNodeSpacing = defaults.nodeSpacing ?? 60;
204
+ const defaultRankSpacing = defaults.rankSpacing ?? 80;
205
+ return {
206
+ name: "dagre",
207
+ async layout(nodes, edges, options) {
208
+ const direction = options?.direction ?? defaultDir;
209
+ const nodesep = options?.nodeSpacing ?? defaultNodeSpacing;
210
+ const ranksep = options?.rankSpacing ?? defaultRankSpacing;
211
+ const g = new lib.graphlib.Graph({ multigraph: true, compound: true });
212
+ g.setGraph({
213
+ rankdir: direction,
214
+ nodesep,
215
+ ranksep,
216
+ ...options?.engine ?? {}
217
+ });
218
+ g.setDefaultEdgeLabel(() => ({}));
219
+ for (const n of nodes) {
220
+ if (n.hidden) continue;
221
+ g.setNode(n.id, {
222
+ width: n.width ?? DEFAULT_NODE_WIDTH,
223
+ height: n.height ?? DEFAULT_NODE_HEIGHT,
224
+ ...n.parentId ? { parent: n.parentId } : {}
225
+ });
226
+ if (n.parentId) {
227
+ g.setParent(
228
+ n.id,
229
+ n.parentId
230
+ );
231
+ }
232
+ }
233
+ for (const e of edges) {
234
+ if (e.hidden) continue;
235
+ g.setEdge(e.source, e.target, { id: e.id });
236
+ }
237
+ lib.layout(g);
238
+ const result = [];
239
+ for (const id of g.nodes()) {
240
+ const out = g.node(id);
241
+ if (!out) continue;
242
+ result.push({
243
+ id,
244
+ position: { x: out.x - out.width / 2, y: out.y - out.height / 2 }
245
+ });
246
+ }
247
+ return result;
248
+ }
249
+ };
250
+ }
251
+ function resolveDagre(input) {
252
+ const asAny = input;
253
+ if (asAny && typeof asAny.layout === "function" && asAny.graphlib?.Graph) {
254
+ return asAny;
255
+ }
256
+ if (asAny?.default && typeof asAny.default.layout === "function") {
257
+ return asAny.default;
258
+ }
259
+ throw new Error(
260
+ "[@octaviaflow/core/workflow] createDagreEngine: input does not look like the dagre module. Pass `dagre` (the default export) or `import * as dagre from 'dagre'`."
261
+ );
262
+ }
263
+
264
+ // src/workflow/layout/elk.ts
265
+ var ELK_DIRECTION = {
266
+ TB: "DOWN",
267
+ BT: "UP",
268
+ LR: "RIGHT",
269
+ RL: "LEFT"
270
+ };
271
+ function createElkEngine(elk, defaults = {}) {
272
+ const algorithm = defaults.algorithm ?? "layered";
273
+ const defaultDir = defaults.direction ?? "TB";
274
+ const defaultNodeSpacing = defaults.nodeSpacing ?? 60;
275
+ const defaultRankSpacing = defaults.rankSpacing ?? 80;
276
+ return {
277
+ name: "elk",
278
+ async layout(nodes, edges, options) {
279
+ const direction = options?.direction ?? defaultDir;
280
+ const nodeSpacing = options?.nodeSpacing ?? defaultNodeSpacing;
281
+ const rankSpacing = options?.rankSpacing ?? defaultRankSpacing;
282
+ const childrenByParent = /* @__PURE__ */ new Map();
283
+ for (const n of nodes) {
284
+ if (n.hidden) continue;
285
+ const key = n.parentId ?? void 0;
286
+ const list = childrenByParent.get(key);
287
+ if (list) list.push(n);
288
+ else childrenByParent.set(key, [n]);
289
+ }
290
+ const buildChildren = (parentId) => {
291
+ const list = childrenByParent.get(parentId) ?? [];
292
+ return list.map((n) => ({
293
+ id: n.id,
294
+ width: n.width ?? DEFAULT_NODE_WIDTH,
295
+ height: n.height ?? DEFAULT_NODE_HEIGHT,
296
+ children: childrenByParent.has(n.id) ? buildChildren(n.id) : void 0,
297
+ layoutOptions: childrenByParent.has(n.id) ? {
298
+ "elk.algorithm": algorithm,
299
+ "elk.direction": ELK_DIRECTION[direction],
300
+ "elk.spacing.nodeNode": String(nodeSpacing),
301
+ "elk.layered.spacing.nodeNodeBetweenLayers": String(rankSpacing)
302
+ } : void 0
303
+ }));
304
+ };
305
+ const elkEdges = edges.filter((e) => !e.hidden).map((e) => ({
306
+ id: e.id,
307
+ sources: [e.source],
308
+ targets: [e.target]
309
+ }));
310
+ const graph = {
311
+ id: "root",
312
+ layoutOptions: {
313
+ "elk.algorithm": algorithm,
314
+ "elk.direction": ELK_DIRECTION[direction],
315
+ "elk.spacing.nodeNode": String(nodeSpacing),
316
+ "elk.layered.spacing.nodeNodeBetweenLayers": String(rankSpacing),
317
+ ...Object.fromEntries(
318
+ Object.entries(options?.engine ?? {}).map(([k, v]) => [k, String(v)])
319
+ )
320
+ },
321
+ children: buildChildren(void 0),
322
+ edges: elkEdges
323
+ };
324
+ const laidOut = await elk.layout(graph);
325
+ const result = [];
326
+ const walk = (g, ox, oy) => {
327
+ const ax = ox + (g.x ?? 0);
328
+ const ay = oy + (g.y ?? 0);
329
+ if (g.id !== "root") {
330
+ result.push({ id: g.id, position: { x: ax, y: ay } });
331
+ }
332
+ if (g.children) {
333
+ for (const c of g.children) walk(c, ax, ay);
334
+ }
335
+ };
336
+ walk(laidOut, 0, 0);
337
+ return result;
338
+ }
339
+ };
340
+ }
341
+
342
+ // src/workflow/store/selectors.ts
343
+ import { useMemo as useMemo2, useSyncExternalStore } from "react";
344
+ function useFlowSelector(selector, isEqual = Object.is) {
345
+ void isEqual;
346
+ const store = useFlowStore();
347
+ return useSyncExternalStore(
348
+ store.subscribe,
349
+ () => selector(store.getSnapshot()),
350
+ () => selector(store.getSnapshot())
351
+ );
352
+ }
353
+ function useNodes() {
354
+ return useFlowSelector((s) => s.nodes);
355
+ }
356
+ function useEdges() {
357
+ return useFlowSelector((s) => s.edges);
358
+ }
359
+ function useViewport() {
360
+ return useFlowSelector((s) => s.viewport);
361
+ }
362
+ function useNodeById(id) {
363
+ return useFlowSelector((s) => s.nodes.find((n) => n.id === id));
364
+ }
365
+ function useNodeData(id) {
366
+ return useFlowSelector(
367
+ (s) => s.nodes.find((n) => n.id === id)?.data ?? void 0
368
+ );
369
+ }
370
+ function useEdgeById(id) {
371
+ return useFlowSelector((s) => s.edges.find((e) => e.id === id));
372
+ }
373
+ function useIsNodeSelected(id) {
374
+ return useFlowSelector((s) => s.selectedNodeIds.has(id));
375
+ }
376
+ function useIsEdgeSelected(id) {
377
+ return useFlowSelector((s) => s.selectedEdgeIds.has(id));
378
+ }
379
+ function useConnection() {
380
+ return useFlowSelector((s) => s.connection);
381
+ }
382
+ function useSelection() {
383
+ const nodes = useNodes();
384
+ const edges = useEdges();
385
+ const selectedNodeIds = useFlowSelector((s) => s.selectedNodeIds);
386
+ const selectedEdgeIds = useFlowSelector((s) => s.selectedEdgeIds);
387
+ return useMemo2(
388
+ () => ({
389
+ nodes: nodes.filter((n) => selectedNodeIds.has(n.id)),
390
+ edges: edges.filter((e) => selectedEdgeIds.has(e.id))
391
+ }),
392
+ [nodes, edges, selectedNodeIds, selectedEdgeIds]
393
+ );
394
+ }
395
+
396
+ // src/workflow/components/ConfigPanel/ConfigPanel.tsx
397
+ import {
398
+ useCallback as useCallback3,
399
+ useEffect as useEffect2,
400
+ useRef as useRef3,
401
+ useState as useState3
402
+ } from "react";
403
+ import { jsx, jsxs } from "react/jsx-runtime";
404
+ var SAVE_STATE_LABEL = {
405
+ clean: "Saved",
406
+ dirty: "Unsaved changes",
407
+ saving: "Saving\u2026",
408
+ saved: "Saved",
409
+ error: "Save failed"
410
+ };
411
+ var SAVE_STATE_DOT = {
412
+ clean: "var(--ods-text-tertiary)",
413
+ dirty: "var(--ods-status-warning, #d97706)",
414
+ saving: "var(--ods-status-running, #2563eb)",
415
+ saved: "var(--ods-status-success, #16a34a)",
416
+ error: "var(--ods-status-failed, #dc2626)"
417
+ };
418
+ function ConfigPanel({
419
+ open = true,
420
+ title,
421
+ kindLabel,
422
+ icon,
423
+ banner,
424
+ tabs,
425
+ activeTab: controlledActive,
426
+ defaultActiveTab,
427
+ onTabChange,
428
+ saveState = "clean",
429
+ onTitleChange,
430
+ onClose,
431
+ onSave,
432
+ onCancel,
433
+ resizable = true,
434
+ defaultWidth = 360,
435
+ minWidth = 280,
436
+ maxWidth = 720,
437
+ maxWidthContainerInset = 80,
438
+ variant = "pinned",
439
+ children,
440
+ footer,
441
+ className,
442
+ style
443
+ }) {
444
+ const [width, setWidth] = useState3(defaultWidth);
445
+ const [effectiveMax, setEffectiveMax] = useState3(maxWidth);
446
+ const panelRef = useRef3(null);
447
+ useEffect2(() => {
448
+ const el = panelRef.current;
449
+ if (!el) return;
450
+ const parent = el.parentElement;
451
+ if (!parent || typeof ResizeObserver === "undefined") return;
452
+ const update = () => {
453
+ const room = parent.clientWidth - maxWidthContainerInset;
454
+ const next = Math.max(minWidth, Math.min(maxWidth, room));
455
+ setEffectiveMax(next);
456
+ setWidth((w) => w > next ? next : w);
457
+ };
458
+ update();
459
+ const ro = new ResizeObserver(update);
460
+ ro.observe(parent);
461
+ return () => ro.disconnect();
462
+ }, [maxWidth, minWidth, maxWidthContainerInset]);
463
+ const [internalActive, setInternalActive] = useState3(
464
+ defaultActiveTab ?? tabs?.[0]?.id
465
+ );
466
+ const activeTabId = controlledActive ?? internalActive;
467
+ const selectTab = (id) => {
468
+ if (controlledActive === void 0) setInternalActive(id);
469
+ onTabChange?.(id);
470
+ };
471
+ const [editingTitle, setEditingTitle] = useState3(false);
472
+ const [draftTitle, setDraftTitle] = useState3(title ?? "");
473
+ useEffect2(() => {
474
+ if (!editingTitle) setDraftTitle(title ?? "");
475
+ }, [title, editingTitle]);
476
+ const commitTitle = (next) => {
477
+ setEditingTitle(false);
478
+ if (next !== title) onTitleChange?.(next);
479
+ };
480
+ const titleKeyDown = (e) => {
481
+ if (e.key === "Enter") {
482
+ e.preventDefault();
483
+ commitTitle(draftTitle);
484
+ } else if (e.key === "Escape") {
485
+ e.preventDefault();
486
+ setEditingTitle(false);
487
+ setDraftTitle(title ?? "");
488
+ }
489
+ };
490
+ const resizeRef = useRef3(null);
491
+ const onResizeDown = useCallback3(
492
+ (e) => {
493
+ if (!resizable) return;
494
+ e.preventDefault();
495
+ e.stopPropagation();
496
+ resizeRef.current = { pointerId: e.pointerId, startX: e.clientX, startWidth: width };
497
+ e.target.setPointerCapture(e.pointerId);
498
+ },
499
+ [resizable, width]
500
+ );
501
+ const onResizeMove = (e) => {
502
+ const r = resizeRef.current;
503
+ if (!r || r.pointerId !== e.pointerId) return;
504
+ const delta = r.startX - e.clientX;
505
+ const next = Math.max(minWidth, Math.min(effectiveMax, r.startWidth + delta));
506
+ setWidth(next);
507
+ };
508
+ const onResizeUp = (e) => {
509
+ if (resizeRef.current?.pointerId === e.pointerId) resizeRef.current = null;
510
+ };
511
+ if (!open) return null;
512
+ const activeTab = tabs?.find((t) => t.id === activeTabId);
513
+ return /* @__PURE__ */ jsxs(
514
+ "aside",
515
+ {
516
+ ref: panelRef,
517
+ className: cn(
518
+ "ods-flow-config-panel",
519
+ `ods-flow-config-panel--${variant}`,
520
+ editingTitle && "ods-flow-config-panel--editing-title",
521
+ className
522
+ ),
523
+ style: { width, ...style },
524
+ "aria-label": title ?? "Configuration",
525
+ children: [
526
+ resizable && /* @__PURE__ */ jsx(
527
+ "div",
528
+ {
529
+ className: "ods-flow-config-panel__resize",
530
+ onPointerDown: onResizeDown,
531
+ onPointerMove: onResizeMove,
532
+ onPointerUp: onResizeUp,
533
+ onPointerCancel: onResizeUp,
534
+ "aria-hidden": "true"
535
+ }
536
+ ),
537
+ /* @__PURE__ */ jsxs("header", { className: "ods-flow-config-panel__header", children: [
538
+ kindLabel && /* @__PURE__ */ jsx("span", { className: "ods-flow-config-panel__breadcrumb", children: kindLabel }),
539
+ /* @__PURE__ */ jsxs("div", { className: "ods-flow-config-panel__title-row", children: [
540
+ icon && /* @__PURE__ */ jsx("span", { className: "ods-flow-config-panel__icon", children: icon }),
541
+ editingTitle ? /* @__PURE__ */ jsx(
542
+ "input",
543
+ {
544
+ className: "ods-flow-config-panel__title-input",
545
+ value: draftTitle,
546
+ autoFocus: true,
547
+ onChange: (e) => setDraftTitle(e.target.value),
548
+ onBlur: () => commitTitle(draftTitle),
549
+ onKeyDown: titleKeyDown,
550
+ "aria-label": "Edit title"
551
+ }
552
+ ) : /* @__PURE__ */ jsx(
553
+ "button",
554
+ {
555
+ type: "button",
556
+ className: "ods-flow-config-panel__title",
557
+ onDoubleClick: () => {
558
+ if (!onTitleChange) return;
559
+ setDraftTitle(title ?? "");
560
+ setEditingTitle(true);
561
+ },
562
+ title: onTitleChange ? "Double-click to rename" : void 0,
563
+ children: title ?? "Untitled"
564
+ }
565
+ ),
566
+ onClose && /* @__PURE__ */ jsx(
567
+ "button",
568
+ {
569
+ type: "button",
570
+ className: "ods-flow-config-panel__close",
571
+ onClick: onClose,
572
+ "aria-label": "Close panel",
573
+ children: /* @__PURE__ */ jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", "aria-hidden": "true", children: /* @__PURE__ */ jsx(
574
+ "path",
575
+ {
576
+ d: "M3 3l8 8M11 3l-8 8",
577
+ stroke: "currentColor",
578
+ strokeWidth: "1.5",
579
+ strokeLinecap: "round"
580
+ }
581
+ ) })
582
+ }
583
+ )
584
+ ] })
585
+ ] }),
586
+ tabs && tabs.length > 1 && /* @__PURE__ */ jsx("nav", { className: "ods-flow-config-panel__tabs", role: "tablist", children: tabs.map((t) => /* @__PURE__ */ jsxs(
587
+ "button",
588
+ {
589
+ type: "button",
590
+ role: "tab",
591
+ "aria-selected": activeTabId === t.id,
592
+ disabled: t.disabled,
593
+ className: cn(
594
+ "ods-flow-config-panel__tab",
595
+ activeTabId === t.id && "ods-flow-config-panel__tab--active"
596
+ ),
597
+ onClick: () => selectTab(t.id),
598
+ children: [
599
+ /* @__PURE__ */ jsx("span", { children: t.label }),
600
+ t.badge !== void 0 && t.badge !== null && /* @__PURE__ */ jsx("span", { className: "ods-flow-config-panel__tab-badge", children: t.badge })
601
+ ]
602
+ },
603
+ t.id
604
+ )) }),
605
+ banner && /* @__PURE__ */ jsx("div", { className: "ods-flow-config-panel__banner", children: banner }),
606
+ /* @__PURE__ */ jsx("div", { className: "ods-flow-config-panel__body", role: "tabpanel", children: tabs ? activeTab?.content : children }),
607
+ /* @__PURE__ */ jsxs("footer", { className: "ods-flow-config-panel__footer", children: [
608
+ /* @__PURE__ */ jsxs(
609
+ "span",
610
+ {
611
+ className: cn(
612
+ "ods-flow-config-panel__save-state",
613
+ `ods-flow-config-panel__save-state--${saveState}`
614
+ ),
615
+ children: [
616
+ /* @__PURE__ */ jsx(
617
+ "span",
618
+ {
619
+ className: "ods-flow-config-panel__save-dot",
620
+ style: { background: SAVE_STATE_DOT[saveState] },
621
+ "aria-hidden": "true"
622
+ }
623
+ ),
624
+ SAVE_STATE_LABEL[saveState]
625
+ ]
626
+ }
627
+ ),
628
+ footer ?? /* @__PURE__ */ jsxs("div", { className: "ods-flow-config-panel__footer-actions", children: [
629
+ onCancel && /* @__PURE__ */ jsx(
630
+ "button",
631
+ {
632
+ type: "button",
633
+ className: "ods-flow-config-panel__btn ods-flow-config-panel__btn--ghost",
634
+ onClick: onCancel,
635
+ children: "Cancel"
636
+ }
637
+ ),
638
+ onSave && /* @__PURE__ */ jsx(
639
+ "button",
640
+ {
641
+ type: "button",
642
+ className: "ods-flow-config-panel__btn ods-flow-config-panel__btn--primary",
643
+ onClick: onSave,
644
+ disabled: saveState === "saving" || saveState === "clean",
645
+ children: saveState === "saving" ? "Saving\u2026" : "Save"
646
+ }
647
+ )
648
+ ] })
649
+ ] })
650
+ ]
651
+ }
652
+ );
653
+ }
654
+
655
+ // src/workflow/components/NodeResizer/NodeResizer.tsx
656
+ import { useRef as useRef4 } from "react";
657
+ import { jsx as jsx2 } from "react/jsx-runtime";
658
+ function NodeResizer({
659
+ isVisible,
660
+ minWidth = 80,
661
+ minHeight = 60,
662
+ maxWidth,
663
+ maxHeight,
664
+ keepAspectRatio = false,
665
+ onResize,
666
+ onResizeEnd,
667
+ color
668
+ }) {
669
+ const { node, selected } = useFlowNodeContext();
670
+ const viewport = useViewport();
671
+ const flow = useFlow();
672
+ const dragRef = useRef4(null);
673
+ const show = isVisible ?? selected;
674
+ if (!show) return null;
675
+ const beginResize = (e, corner) => {
676
+ e.preventDefault();
677
+ e.stopPropagation();
678
+ e.target.setPointerCapture(e.pointerId);
679
+ const w = node.width ?? DEFAULT_NODE_WIDTH;
680
+ const h = node.height ?? DEFAULT_NODE_HEIGHT;
681
+ dragRef.current = {
682
+ pointerId: e.pointerId,
683
+ corner,
684
+ startClientX: e.clientX,
685
+ startClientY: e.clientY,
686
+ startWidth: w,
687
+ startHeight: h,
688
+ startX: node.position.x,
689
+ startY: node.position.y,
690
+ aspect: w / Math.max(1, h)
691
+ };
692
+ };
693
+ const onMove = (e) => {
694
+ const drag = dragRef.current;
695
+ if (!drag || drag.pointerId !== e.pointerId) return;
696
+ const dx = (e.clientX - drag.startClientX) / viewport.zoom;
697
+ const dy = (e.clientY - drag.startClientY) / viewport.zoom;
698
+ let nextW = drag.startWidth;
699
+ let nextH = drag.startHeight;
700
+ let nextX = drag.startX;
701
+ let nextY = drag.startY;
702
+ switch (drag.corner) {
703
+ case "se":
704
+ nextW = drag.startWidth + dx;
705
+ nextH = drag.startHeight + dy;
706
+ break;
707
+ case "sw":
708
+ nextW = drag.startWidth - dx;
709
+ nextH = drag.startHeight + dy;
710
+ nextX = drag.startX + dx;
711
+ break;
712
+ case "ne":
713
+ nextW = drag.startWidth + dx;
714
+ nextH = drag.startHeight - dy;
715
+ nextY = drag.startY + dy;
716
+ break;
717
+ case "nw":
718
+ nextW = drag.startWidth - dx;
719
+ nextH = drag.startHeight - dy;
720
+ nextX = drag.startX + dx;
721
+ nextY = drag.startY + dy;
722
+ break;
723
+ }
724
+ if (keepAspectRatio) {
725
+ nextH = nextW / drag.aspect;
726
+ if (drag.corner === "nw" || drag.corner === "ne") {
727
+ nextY = drag.startY + (drag.startHeight - nextH);
728
+ }
729
+ }
730
+ nextW = Math.max(minWidth, maxWidth ? Math.min(maxWidth, nextW) : nextW);
731
+ nextH = Math.max(minHeight, maxHeight ? Math.min(maxHeight, nextH) : nextH);
732
+ flow.updateNode(node.id, {
733
+ width: nextW,
734
+ height: nextH,
735
+ position: { x: nextX, y: nextY }
736
+ });
737
+ onResize?.({ width: nextW, height: nextH });
738
+ };
739
+ const onUp = (e) => {
740
+ if (dragRef.current?.pointerId === e.pointerId) {
741
+ const cur = flow.getNode(node.id);
742
+ if (cur) {
743
+ onResizeEnd?.({
744
+ width: cur.width ?? DEFAULT_NODE_WIDTH,
745
+ height: cur.height ?? DEFAULT_NODE_HEIGHT
746
+ });
747
+ }
748
+ dragRef.current = null;
749
+ }
750
+ };
751
+ const handleColor = color ?? "var(--ods-accent)";
752
+ const handleStyle = (corner) => {
753
+ const base = {
754
+ position: "absolute",
755
+ width: 12,
756
+ height: 12,
757
+ background: "var(--ods-surface-canvas)",
758
+ border: `2px solid ${handleColor}`,
759
+ borderRadius: 2,
760
+ cursor: cursorFor(corner),
761
+ touchAction: "none",
762
+ // Place each handle so its CENTRE sits on the corresponding corner.
763
+ transform: "translate(-50%, -50%)"
764
+ };
765
+ switch (corner) {
766
+ case "nw":
767
+ return { ...base, top: 0, left: 0 };
768
+ case "ne":
769
+ return { ...base, top: 0, left: "100%" };
770
+ case "sw":
771
+ return { ...base, top: "100%", left: 0 };
772
+ case "se":
773
+ return { ...base, top: "100%", left: "100%" };
774
+ }
775
+ };
776
+ return /* @__PURE__ */ jsx2("div", { className: cn("ods-node-resizer"), "data-flow-no-drag": "true", children: ["nw", "ne", "sw", "se"].map((corner) => /* @__PURE__ */ jsx2(
777
+ "div",
778
+ {
779
+ style: handleStyle(corner),
780
+ onPointerDown: (e) => beginResize(e, corner),
781
+ onPointerMove: onMove,
782
+ onPointerUp: onUp,
783
+ onPointerCancel: onUp,
784
+ "aria-label": `Resize ${corner}`
785
+ },
786
+ corner
787
+ )) });
788
+ }
789
+ function cursorFor(corner) {
790
+ switch (corner) {
791
+ case "nw":
792
+ case "se":
793
+ return "nwse-resize";
794
+ case "ne":
795
+ case "sw":
796
+ return "nesw-resize";
797
+ }
798
+ }
799
+
800
+ // src/workflow/components/NodeToolbar/NodeToolbar.tsx
801
+ import { jsx as jsx3 } from "react/jsx-runtime";
802
+ function NodeToolbar({
803
+ isVisible,
804
+ position = "top",
805
+ offset = 10,
806
+ align = "center",
807
+ children,
808
+ className,
809
+ style
810
+ }) {
811
+ const node = useFlowNodeContext();
812
+ const viewport = useViewport();
813
+ const show = isVisible ?? node.selected;
814
+ if (!show) return null;
815
+ const inverseScale = 1 / viewport.zoom;
816
+ return /* @__PURE__ */ jsx3(
817
+ "div",
818
+ {
819
+ className: cn("ods-node-toolbar", `ods-node-toolbar--${position}`, className),
820
+ "data-flow-no-drag": "true",
821
+ style: {
822
+ ...positionStyle(position, offset, align),
823
+ ...style
824
+ },
825
+ onPointerDown: (e) => e.stopPropagation(),
826
+ onMouseDown: (e) => e.stopPropagation(),
827
+ onClick: (e) => e.stopPropagation(),
828
+ children: /* @__PURE__ */ jsx3(
829
+ "div",
830
+ {
831
+ className: "ods-node-toolbar__inner",
832
+ style: {
833
+ transform: `scale(${inverseScale})`,
834
+ transformOrigin: transformOriginFor(position, align)
835
+ },
836
+ children
837
+ }
838
+ )
839
+ }
840
+ );
841
+ }
842
+ function positionStyle(side, offset, align) {
843
+ const center = align === "center";
844
+ const start = align === "start";
845
+ switch (side) {
846
+ case "top":
847
+ return {
848
+ position: "absolute",
849
+ bottom: "100%",
850
+ marginBottom: offset,
851
+ left: start ? 0 : center ? "50%" : void 0,
852
+ right: align === "end" ? 0 : void 0,
853
+ transform: center ? "translateX(-50%)" : void 0
854
+ };
855
+ case "bottom":
856
+ return {
857
+ position: "absolute",
858
+ top: "100%",
859
+ marginTop: offset,
860
+ left: start ? 0 : center ? "50%" : void 0,
861
+ right: align === "end" ? 0 : void 0,
862
+ transform: center ? "translateX(-50%)" : void 0
863
+ };
864
+ case "left":
865
+ return {
866
+ position: "absolute",
867
+ right: "100%",
868
+ marginRight: offset,
869
+ top: start ? 0 : center ? "50%" : void 0,
870
+ bottom: align === "end" ? 0 : void 0,
871
+ transform: center ? "translateY(-50%)" : void 0
872
+ };
873
+ case "right":
874
+ return {
875
+ position: "absolute",
876
+ left: "100%",
877
+ marginLeft: offset,
878
+ top: start ? 0 : center ? "50%" : void 0,
879
+ bottom: align === "end" ? 0 : void 0,
880
+ transform: center ? "translateY(-50%)" : void 0
881
+ };
882
+ }
883
+ }
884
+ function transformOriginFor(side, align) {
885
+ if (side === "top")
886
+ return align === "start" ? "left bottom" : align === "end" ? "right bottom" : "center bottom";
887
+ if (side === "bottom")
888
+ return align === "start" ? "left top" : align === "end" ? "right top" : "center top";
889
+ if (side === "left")
890
+ return align === "start" ? "right top" : align === "end" ? "right bottom" : "right center";
891
+ return align === "start" ? "left top" : align === "end" ? "left bottom" : "left center";
892
+ }
893
+
894
+ // src/workflow/utils/collapse.ts
895
+ function collapseFor(nodes, edges) {
896
+ const collapsedAncestorOf = /* @__PURE__ */ new Map();
897
+ const parents = /* @__PURE__ */ new Map();
898
+ for (const n of nodes) if (n.parentId) parents.set(n.id, n.parentId);
899
+ const isCollapsed = (node) => {
900
+ const d = node?.data;
901
+ return !!d?.collapsed;
902
+ };
903
+ for (const n of nodes) {
904
+ let cursor = n.id;
905
+ let outermostCollapsed;
906
+ const seen = /* @__PURE__ */ new Set([cursor]);
907
+ while (cursor) {
908
+ const p = parents.get(cursor);
909
+ if (!p || seen.has(p)) break;
910
+ seen.add(p);
911
+ const parentNode = nodes.find((x) => x.id === p);
912
+ if (isCollapsed(parentNode)) outermostCollapsed = p;
913
+ cursor = p;
914
+ }
915
+ if (outermostCollapsed && outermostCollapsed !== n.id) {
916
+ collapsedAncestorOf.set(n.id, outermostCollapsed);
917
+ }
918
+ }
919
+ const outNodes = nodes.map((n) => {
920
+ const anc = collapsedAncestorOf.get(n.id);
921
+ if (anc) return { ...n, hidden: true };
922
+ return n;
923
+ });
924
+ const BOUNDARY_DASH = "2 4";
925
+ const outEdges = [];
926
+ const hiddenCount = /* @__PURE__ */ new Map();
927
+ for (const e of edges) {
928
+ const srcAnc = collapsedAncestorOf.get(e.source);
929
+ const tgtAnc = collapsedAncestorOf.get(e.target);
930
+ if (srcAnc && tgtAnc && srcAnc === tgtAnc) continue;
931
+ let src = e.source;
932
+ let srcHandle = e.sourceHandle;
933
+ let tgt = e.target;
934
+ let tgtHandle = e.targetHandle;
935
+ const rewritten = !!(srcAnc || tgtAnc);
936
+ if (srcAnc) {
937
+ src = srcAnc;
938
+ srcHandle = "__group_out";
939
+ }
940
+ if (tgtAnc) {
941
+ tgt = tgtAnc;
942
+ tgtHandle = "__group_in";
943
+ }
944
+ if (src === tgt) continue;
945
+ const nextEdge = {
946
+ ...e,
947
+ source: src,
948
+ sourceHandle: srcHandle,
949
+ target: tgt,
950
+ targetHandle: tgtHandle
951
+ };
952
+ if (rewritten) {
953
+ nextEdge.style = { ...e.style ?? {}, strokeDasharray: BOUNDARY_DASH };
954
+ }
955
+ outEdges.push(nextEdge);
956
+ }
957
+ for (const [_id, anc] of collapsedAncestorOf) {
958
+ hiddenCount.set(anc, (hiddenCount.get(anc) ?? 0) + 1);
959
+ }
960
+ return { nodes: outNodes, edges: outEdges, hiddenCountByGroupId: hiddenCount };
961
+ }
962
+ function toggleGroupCollapse(groupId, nodes) {
963
+ return nodes.map((n) => {
964
+ if (n.id !== groupId) return n;
965
+ const data = n.data ?? {};
966
+ return { ...n, data: { ...data, collapsed: !data.collapsed } };
967
+ });
968
+ }
969
+ export {
970
+ ActionNode,
971
+ ConditionNode,
972
+ ConfigPanel,
973
+ DEFAULT_NODE_HEIGHT,
974
+ DEFAULT_NODE_KINDS,
975
+ DEFAULT_NODE_WIDTH,
976
+ ErrorNode,
977
+ FlowCanvas,
978
+ FlowEdge,
979
+ FlowNode,
980
+ ForEachNode,
981
+ GroupNode,
982
+ Handle,
983
+ HttpRequestNode,
984
+ NodeResizer,
985
+ NodeToolbar,
986
+ OutputNode,
987
+ ParallelNode,
988
+ StickyNode,
989
+ TriggerNode,
990
+ WaitNode,
991
+ WebhookNode,
992
+ applyEdgeChanges,
993
+ applyNodeChanges,
994
+ bezierPath2 as bezierPath,
995
+ bezierPath as bezierPathFn,
996
+ buildEdgePath,
997
+ buildNodeKindRegistry,
998
+ change,
999
+ clampToParentExtent,
1000
+ collapseFor,
1001
+ createDagreEngine,
1002
+ createElkEngine,
1003
+ descendantsOf,
1004
+ findAncestor,
1005
+ findContainingGroup,
1006
+ flowToScreen,
1007
+ handleCentre,
1008
+ screenToFlow,
1009
+ smoothStepPath,
1010
+ stepPath,
1011
+ straightPath,
1012
+ toggleGroupCollapse,
1013
+ useAutoLayout,
1014
+ useConnection,
1015
+ useEdgeById,
1016
+ useEdges,
1017
+ useFlow,
1018
+ useFlowNodeContext,
1019
+ useFlowSelector,
1020
+ useFlowState,
1021
+ useIsEdgeSelected,
1022
+ useIsNodeSelected,
1023
+ useNodeById,
1024
+ useNodeData,
1025
+ useNodes,
1026
+ useSelection,
1027
+ useViewport
1028
+ };
1029
+ //# sourceMappingURL=workflow.js.map