@octaviaflow/core 3.0.17-beta.0 → 3.0.18-beta.1

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 (464) hide show
  1. package/dist/chunk-2RD5OERK.js +2553 -0
  2. package/dist/chunk-2RD5OERK.js.map +1 -0
  3. package/dist/chunk-CGWNV2HS.js +2549 -0
  4. package/dist/chunk-CGWNV2HS.js.map +1 -0
  5. package/dist/chunk-CS7JWNQD.js +2552 -0
  6. package/dist/chunk-CS7JWNQD.js.map +1 -0
  7. package/dist/chunk-D6CFZILB.js +2550 -0
  8. package/dist/chunk-D6CFZILB.js.map +1 -0
  9. package/dist/chunk-ECOTUJWJ.js +2548 -0
  10. package/dist/chunk-ECOTUJWJ.js.map +1 -0
  11. package/dist/chunk-F3ZHEDDP.js +2548 -0
  12. package/dist/chunk-F3ZHEDDP.js.map +1 -0
  13. package/dist/chunk-QWICIDGH.js +2547 -0
  14. package/dist/chunk-QWICIDGH.js.map +1 -0
  15. package/dist/chunk-TTKIDRN7.js +2551 -0
  16. package/dist/chunk-TTKIDRN7.js.map +1 -0
  17. package/dist/chunk-UFGAO5OY.js +2546 -0
  18. package/dist/chunk-UFGAO5OY.js.map +1 -0
  19. package/dist/components/Accordion/Accordion.d.ts +45 -0
  20. package/dist/components/Accordion/Accordion.d.ts.map +1 -0
  21. package/dist/components/Accordion/index.d.ts +2 -0
  22. package/dist/components/Accordion/index.d.ts.map +1 -0
  23. package/dist/components/ActionsDrawer/ActionsDrawer.d.ts +6 -0
  24. package/dist/components/ActionsDrawer/ActionsDrawer.d.ts.map +1 -1
  25. package/dist/components/AgentCard/AgentCard.d.ts +53 -7
  26. package/dist/components/AgentCard/AgentCard.d.ts.map +1 -1
  27. package/dist/components/AlertCard/AlertCard.d.ts +76 -0
  28. package/dist/components/AlertCard/AlertCard.d.ts.map +1 -0
  29. package/dist/components/AlertCard/index.d.ts +2 -0
  30. package/dist/components/AlertCard/index.d.ts.map +1 -0
  31. package/dist/components/AuthCard/AuthCard.d.ts +29 -42
  32. package/dist/components/AuthCard/AuthCard.d.ts.map +1 -1
  33. package/dist/components/Avatar/Avatar.d.ts +48 -11
  34. package/dist/components/Avatar/Avatar.d.ts.map +1 -1
  35. package/dist/components/Avatar/index.d.ts +1 -1
  36. package/dist/components/Avatar/index.d.ts.map +1 -1
  37. package/dist/components/Badge/Badge.d.ts +46 -8
  38. package/dist/components/Badge/Badge.d.ts.map +1 -1
  39. package/dist/components/Badge/index.d.ts +1 -1
  40. package/dist/components/Badge/index.d.ts.map +1 -1
  41. package/dist/components/Banner/Banner.d.ts +53 -6
  42. package/dist/components/Banner/Banner.d.ts.map +1 -1
  43. package/dist/components/Banner/index.d.ts +1 -1
  44. package/dist/components/Banner/index.d.ts.map +1 -1
  45. package/dist/components/BarChart/BarChart.d.ts +62 -5
  46. package/dist/components/BarChart/BarChart.d.ts.map +1 -1
  47. package/dist/components/BarChart/index.d.ts +1 -1
  48. package/dist/components/BarChart/index.d.ts.map +1 -1
  49. package/dist/components/BlogCard/BlogCard.d.ts +39 -4
  50. package/dist/components/BlogCard/BlogCard.d.ts.map +1 -1
  51. package/dist/components/Button/Button.d.ts +23 -5
  52. package/dist/components/Button/Button.d.ts.map +1 -1
  53. package/dist/components/Calendar/Calendar.d.ts +53 -4
  54. package/dist/components/Calendar/Calendar.d.ts.map +1 -1
  55. package/dist/components/CalendarHeatmap/CalendarHeatmap.d.ts +47 -0
  56. package/dist/components/CalendarHeatmap/CalendarHeatmap.d.ts.map +1 -0
  57. package/dist/components/CalendarHeatmap/index.d.ts +2 -0
  58. package/dist/components/CalendarHeatmap/index.d.ts.map +1 -0
  59. package/dist/components/Callout/Callout.d.ts +33 -7
  60. package/dist/components/Callout/Callout.d.ts.map +1 -1
  61. package/dist/components/Callout/index.d.ts +1 -1
  62. package/dist/components/Callout/index.d.ts.map +1 -1
  63. package/dist/components/Card/Card.d.ts +49 -8
  64. package/dist/components/Card/Card.d.ts.map +1 -1
  65. package/dist/components/Card/index.d.ts +1 -1
  66. package/dist/components/Card/index.d.ts.map +1 -1
  67. package/dist/components/ChatBubble/ChatBubble.d.ts +32 -7
  68. package/dist/components/ChatBubble/ChatBubble.d.ts.map +1 -1
  69. package/dist/components/ChatBubble/index.d.ts +1 -1
  70. package/dist/components/ChatBubble/index.d.ts.map +1 -1
  71. package/dist/components/Checkbox/Checkbox.d.ts +16 -3
  72. package/dist/components/Checkbox/Checkbox.d.ts.map +1 -1
  73. package/dist/components/Checkbox/index.d.ts +1 -1
  74. package/dist/components/Checkbox/index.d.ts.map +1 -1
  75. package/dist/components/Chip/Chip.d.ts +28 -9
  76. package/dist/components/Chip/Chip.d.ts.map +1 -1
  77. package/dist/components/Chip/index.d.ts +1 -1
  78. package/dist/components/Chip/index.d.ts.map +1 -1
  79. package/dist/components/ChoiceCard/ChoiceCard.d.ts +44 -6
  80. package/dist/components/ChoiceCard/ChoiceCard.d.ts.map +1 -1
  81. package/dist/components/ChoiceCard/index.d.ts +1 -1
  82. package/dist/components/ChoiceCard/index.d.ts.map +1 -1
  83. package/dist/components/Coachmark/Coachmark.d.ts +52 -0
  84. package/dist/components/Coachmark/Coachmark.d.ts.map +1 -0
  85. package/dist/components/Coachmark/index.d.ts +2 -0
  86. package/dist/components/Coachmark/index.d.ts.map +1 -0
  87. package/dist/components/CodeEditor/CodeEditor.d.ts +10 -1
  88. package/dist/components/CodeEditor/CodeEditor.d.ts.map +1 -1
  89. package/dist/components/ColorPicker/ColorPicker.d.ts +25 -6
  90. package/dist/components/ColorPicker/ColorPicker.d.ts.map +1 -1
  91. package/dist/components/ColorPicker/index.d.ts +1 -1
  92. package/dist/components/ColorPicker/index.d.ts.map +1 -1
  93. package/dist/components/CommandPalette/CommandPalette.d.ts +64 -0
  94. package/dist/components/CommandPalette/CommandPalette.d.ts.map +1 -0
  95. package/dist/components/CommandPalette/index.d.ts +2 -0
  96. package/dist/components/CommandPalette/index.d.ts.map +1 -0
  97. package/dist/components/ConditionBuilder/ConditionBuilder.d.ts +24 -4
  98. package/dist/components/ConditionBuilder/ConditionBuilder.d.ts.map +1 -1
  99. package/dist/components/ConfigPanel/ConfigPanel.d.ts +29 -4
  100. package/dist/components/ConfigPanel/ConfigPanel.d.ts.map +1 -1
  101. package/dist/components/ConfigPanel/index.d.ts +1 -1
  102. package/dist/components/ConfigPanel/index.d.ts.map +1 -1
  103. package/dist/components/ConfirmDialog/ConfirmDialog.d.ts +47 -0
  104. package/dist/components/ConfirmDialog/ConfirmDialog.d.ts.map +1 -0
  105. package/dist/components/ConfirmDialog/index.d.ts +2 -0
  106. package/dist/components/ConfirmDialog/index.d.ts.map +1 -0
  107. package/dist/components/ConnectorCard/ConnectorCard.d.ts +49 -0
  108. package/dist/components/ConnectorCard/ConnectorCard.d.ts.map +1 -0
  109. package/dist/components/ConnectorCard/index.d.ts +2 -0
  110. package/dist/components/ConnectorCard/index.d.ts.map +1 -0
  111. package/dist/components/ContextMenu/ContextMenu.d.ts +46 -0
  112. package/dist/components/ContextMenu/ContextMenu.d.ts.map +1 -0
  113. package/dist/components/ContextMenu/index.d.ts +2 -0
  114. package/dist/components/ContextMenu/index.d.ts.map +1 -0
  115. package/dist/components/CountUp/CountUp.d.ts +35 -0
  116. package/dist/components/CountUp/CountUp.d.ts.map +1 -0
  117. package/dist/components/CountUp/index.d.ts +2 -0
  118. package/dist/components/CountUp/index.d.ts.map +1 -0
  119. package/dist/components/DataMapper/DataMapper.d.ts +3 -3
  120. package/dist/components/DataMapper/DataMapper.d.ts.map +1 -1
  121. package/dist/components/DataTable/DataTable.d.ts +35 -3
  122. package/dist/components/DataTable/DataTable.d.ts.map +1 -1
  123. package/dist/components/DatasetCard/DatasetCard.d.ts +55 -0
  124. package/dist/components/DatasetCard/DatasetCard.d.ts.map +1 -0
  125. package/dist/components/DatasetCard/index.d.ts +2 -0
  126. package/dist/components/DatasetCard/index.d.ts.map +1 -0
  127. package/dist/components/DatePicker/DatePicker.d.ts +18 -5
  128. package/dist/components/DatePicker/DatePicker.d.ts.map +1 -1
  129. package/dist/components/DatePicker/index.d.ts +1 -1
  130. package/dist/components/DatePicker/index.d.ts.map +1 -1
  131. package/dist/components/DescriptionList/DescriptionList.d.ts +10 -6
  132. package/dist/components/DescriptionList/DescriptionList.d.ts.map +1 -1
  133. package/dist/components/DescriptionList/index.d.ts +1 -1
  134. package/dist/components/DescriptionList/index.d.ts.map +1 -1
  135. package/dist/components/Dialog/Dialog.d.ts +13 -5
  136. package/dist/components/Dialog/Dialog.d.ts.map +1 -1
  137. package/dist/components/Dialog/index.d.ts +1 -1
  138. package/dist/components/Dialog/index.d.ts.map +1 -1
  139. package/dist/components/Divider/Divider.d.ts +24 -0
  140. package/dist/components/Divider/Divider.d.ts.map +1 -0
  141. package/dist/components/Divider/index.d.ts +2 -0
  142. package/dist/components/Divider/index.d.ts.map +1 -0
  143. package/dist/components/DonutChart/DonutChart.d.ts +32 -4
  144. package/dist/components/DonutChart/DonutChart.d.ts.map +1 -1
  145. package/dist/components/Drawer/Drawer.d.ts +12 -5
  146. package/dist/components/Drawer/Drawer.d.ts.map +1 -1
  147. package/dist/components/Drawer/index.d.ts +1 -1
  148. package/dist/components/Drawer/index.d.ts.map +1 -1
  149. package/dist/components/EmptyState/EmptyState.d.ts +16 -6
  150. package/dist/components/EmptyState/EmptyState.d.ts.map +1 -1
  151. package/dist/components/EmptyState/index.d.ts +1 -1
  152. package/dist/components/EmptyState/index.d.ts.map +1 -1
  153. package/dist/components/ExecutionConsole/ExecutionConsole.d.ts +18 -2
  154. package/dist/components/ExecutionConsole/ExecutionConsole.d.ts.map +1 -1
  155. package/dist/components/FeatureCard/FeatureCard.d.ts +29 -10
  156. package/dist/components/FeatureCard/FeatureCard.d.ts.map +1 -1
  157. package/dist/components/FileDropzone/FileDropzone.d.ts +3 -3
  158. package/dist/components/FileDropzone/FileDropzone.d.ts.map +1 -1
  159. package/dist/components/FlowMinimap/FlowMinimap.d.ts +27 -2
  160. package/dist/components/FlowMinimap/FlowMinimap.d.ts.map +1 -1
  161. package/dist/components/FlowToolbar/FlowToolbar.d.ts +91 -1
  162. package/dist/components/FlowToolbar/FlowToolbar.d.ts.map +1 -1
  163. package/dist/components/FlowToolbar/index.d.ts +1 -1
  164. package/dist/components/FlowToolbar/index.d.ts.map +1 -1
  165. package/dist/components/Gauge/Gauge.d.ts +46 -0
  166. package/dist/components/Gauge/Gauge.d.ts.map +1 -0
  167. package/dist/components/Gauge/index.d.ts +2 -0
  168. package/dist/components/Gauge/index.d.ts.map +1 -0
  169. package/dist/components/Grid/Grid.d.ts +46 -0
  170. package/dist/components/Grid/Grid.d.ts.map +1 -0
  171. package/dist/components/Grid/index.d.ts +2 -0
  172. package/dist/components/Grid/index.d.ts.map +1 -0
  173. package/dist/components/Heatmap/Heatmap.d.ts +54 -0
  174. package/dist/components/Heatmap/Heatmap.d.ts.map +1 -0
  175. package/dist/components/Heatmap/index.d.ts +2 -0
  176. package/dist/components/Heatmap/index.d.ts.map +1 -0
  177. package/dist/components/IconCard/IconCard.d.ts +24 -6
  178. package/dist/components/IconCard/IconCard.d.ts.map +1 -1
  179. package/dist/components/IconCard/index.d.ts +1 -1
  180. package/dist/components/IconCard/index.d.ts.map +1 -1
  181. package/dist/components/InlineMessage/InlineMessage.d.ts +24 -0
  182. package/dist/components/InlineMessage/InlineMessage.d.ts.map +1 -0
  183. package/dist/components/InlineMessage/index.d.ts +2 -0
  184. package/dist/components/InlineMessage/index.d.ts.map +1 -0
  185. package/dist/components/Input/Input.d.ts.map +1 -1
  186. package/dist/components/IntegrationCard/IntegrationCard.d.ts +69 -0
  187. package/dist/components/IntegrationCard/IntegrationCard.d.ts.map +1 -0
  188. package/dist/components/IntegrationCard/index.d.ts +2 -0
  189. package/dist/components/IntegrationCard/index.d.ts.map +1 -0
  190. package/dist/components/JsonViewer/JsonViewer.d.ts +10 -4
  191. package/dist/components/JsonViewer/JsonViewer.d.ts.map +1 -1
  192. package/dist/components/KanbanCard/KanbanCard.d.ts +40 -7
  193. package/dist/components/KanbanCard/KanbanCard.d.ts.map +1 -1
  194. package/dist/components/Kbd/Kbd.d.ts +8 -9
  195. package/dist/components/Kbd/Kbd.d.ts.map +1 -1
  196. package/dist/components/Kbd/index.d.ts +1 -1
  197. package/dist/components/Kbd/index.d.ts.map +1 -1
  198. package/dist/components/LineChart/LineChart.d.ts +42 -4
  199. package/dist/components/LineChart/LineChart.d.ts.map +1 -1
  200. package/dist/components/LineChart/index.d.ts +1 -1
  201. package/dist/components/LineChart/index.d.ts.map +1 -1
  202. package/dist/components/LinkButton/LinkButton.d.ts +16 -4
  203. package/dist/components/LinkButton/LinkButton.d.ts.map +1 -1
  204. package/dist/components/LinkButton/index.d.ts +1 -1
  205. package/dist/components/LinkButton/index.d.ts.map +1 -1
  206. package/dist/components/MetricCard/MetricCard.d.ts +71 -0
  207. package/dist/components/MetricCard/MetricCard.d.ts.map +1 -0
  208. package/dist/components/MetricCard/index.d.ts +2 -0
  209. package/dist/components/MetricCard/index.d.ts.map +1 -0
  210. package/dist/components/MonacoEditor/MonacoDiffEditor.d.ts +22 -5
  211. package/dist/components/MonacoEditor/MonacoDiffEditor.d.ts.map +1 -1
  212. package/dist/components/MonacoEditor/MonacoEditor.d.ts +28 -7
  213. package/dist/components/MonacoEditor/MonacoEditor.d.ts.map +1 -1
  214. package/dist/components/MonacoEditor/index.d.ts +2 -2
  215. package/dist/components/MonacoEditor/index.d.ts.map +1 -1
  216. package/dist/components/MultiSelect/MultiSelect.d.ts +23 -7
  217. package/dist/components/MultiSelect/MultiSelect.d.ts.map +1 -1
  218. package/dist/components/MultiSelect/index.d.ts +1 -1
  219. package/dist/components/MultiSelect/index.d.ts.map +1 -1
  220. package/dist/components/NumberInput/NumberInput.d.ts +13 -7
  221. package/dist/components/NumberInput/NumberInput.d.ts.map +1 -1
  222. package/dist/components/NumberInput/index.d.ts +1 -1
  223. package/dist/components/NumberInput/index.d.ts.map +1 -1
  224. package/dist/components/OTPInput/OTPInput.d.ts +27 -4
  225. package/dist/components/OTPInput/OTPInput.d.ts.map +1 -1
  226. package/dist/components/OTPInput/index.d.ts +1 -1
  227. package/dist/components/OTPInput/index.d.ts.map +1 -1
  228. package/dist/components/Pagination/Pagination.d.ts +50 -0
  229. package/dist/components/Pagination/Pagination.d.ts.map +1 -0
  230. package/dist/components/Pagination/index.d.ts +2 -0
  231. package/dist/components/Pagination/index.d.ts.map +1 -0
  232. package/dist/components/PasswordInput/PasswordInput.d.ts +22 -7
  233. package/dist/components/PasswordInput/PasswordInput.d.ts.map +1 -1
  234. package/dist/components/PasswordInput/index.d.ts +1 -1
  235. package/dist/components/PasswordInput/index.d.ts.map +1 -1
  236. package/dist/components/PhoneInput/PhoneInput.d.ts +19 -6
  237. package/dist/components/PhoneInput/PhoneInput.d.ts.map +1 -1
  238. package/dist/components/PhoneInput/countries.d.ts +15 -0
  239. package/dist/components/PhoneInput/countries.d.ts.map +1 -0
  240. package/dist/components/PhoneInput/index.d.ts +2 -1
  241. package/dist/components/PhoneInput/index.d.ts.map +1 -1
  242. package/dist/components/PipelineCard/PipelineCard.d.ts +100 -0
  243. package/dist/components/PipelineCard/PipelineCard.d.ts.map +1 -0
  244. package/dist/components/PipelineCard/index.d.ts +2 -0
  245. package/dist/components/PipelineCard/index.d.ts.map +1 -0
  246. package/dist/components/Popover/Popover.d.ts +5 -1
  247. package/dist/components/Popover/Popover.d.ts.map +1 -1
  248. package/dist/components/PricingCard/PricingCard.d.ts +28 -5
  249. package/dist/components/PricingCard/PricingCard.d.ts.map +1 -1
  250. package/dist/components/ProductCard/ProductCard.d.ts +35 -4
  251. package/dist/components/ProductCard/ProductCard.d.ts.map +1 -1
  252. package/dist/components/ProgressBar/ProgressBar.d.ts +28 -0
  253. package/dist/components/ProgressBar/ProgressBar.d.ts.map +1 -0
  254. package/dist/components/ProgressBar/index.d.ts +2 -0
  255. package/dist/components/ProgressBar/index.d.ts.map +1 -0
  256. package/dist/components/ProgressRing/ProgressRing.d.ts +22 -5
  257. package/dist/components/ProgressRing/ProgressRing.d.ts.map +1 -1
  258. package/dist/components/ProgressRing/index.d.ts +1 -1
  259. package/dist/components/ProgressRing/index.d.ts.map +1 -1
  260. package/dist/components/PromptInput/PromptInput.d.ts +59 -16
  261. package/dist/components/PromptInput/PromptInput.d.ts.map +1 -1
  262. package/dist/components/PromptInput/index.d.ts +1 -1
  263. package/dist/components/PromptInput/index.d.ts.map +1 -1
  264. package/dist/components/Quote/Quote.d.ts +20 -6
  265. package/dist/components/Quote/Quote.d.ts.map +1 -1
  266. package/dist/components/Quote/index.d.ts +1 -1
  267. package/dist/components/Quote/index.d.ts.map +1 -1
  268. package/dist/components/Radio/Radio.d.ts +12 -5
  269. package/dist/components/Radio/Radio.d.ts.map +1 -1
  270. package/dist/components/Radio/RadioGroup.d.ts +16 -15
  271. package/dist/components/Radio/RadioGroup.d.ts.map +1 -1
  272. package/dist/components/Radio/index.d.ts +2 -2
  273. package/dist/components/Radio/index.d.ts.map +1 -1
  274. package/dist/components/RangeSlider/RangeSlider.d.ts +18 -5
  275. package/dist/components/RangeSlider/RangeSlider.d.ts.map +1 -1
  276. package/dist/components/RangeSlider/index.d.ts +1 -1
  277. package/dist/components/RangeSlider/index.d.ts.map +1 -1
  278. package/dist/components/Rating/BinaryRating.d.ts +40 -0
  279. package/dist/components/Rating/BinaryRating.d.ts.map +1 -0
  280. package/dist/components/Rating/Rating.d.ts +21 -6
  281. package/dist/components/Rating/Rating.d.ts.map +1 -1
  282. package/dist/components/Rating/index.d.ts +2 -1
  283. package/dist/components/Rating/index.d.ts.map +1 -1
  284. package/dist/components/Resizable/Resizable.d.ts +32 -36
  285. package/dist/components/Resizable/Resizable.d.ts.map +1 -1
  286. package/dist/components/Resizable/index.d.ts +1 -1
  287. package/dist/components/Resizable/index.d.ts.map +1 -1
  288. package/dist/components/Ribbon/Ribbon.d.ts +12 -6
  289. package/dist/components/Ribbon/Ribbon.d.ts.map +1 -1
  290. package/dist/components/Ribbon/index.d.ts +1 -1
  291. package/dist/components/Ribbon/index.d.ts.map +1 -1
  292. package/dist/components/Sankey/Sankey.d.ts +53 -0
  293. package/dist/components/Sankey/Sankey.d.ts.map +1 -0
  294. package/dist/components/Sankey/index.d.ts +2 -0
  295. package/dist/components/Sankey/index.d.ts.map +1 -0
  296. package/dist/components/ScrollArea/ScrollArea.d.ts +33 -0
  297. package/dist/components/ScrollArea/ScrollArea.d.ts.map +1 -0
  298. package/dist/components/ScrollArea/index.d.ts +2 -0
  299. package/dist/components/ScrollArea/index.d.ts.map +1 -0
  300. package/dist/components/SegmentedControl/SegmentedControl.d.ts +38 -0
  301. package/dist/components/SegmentedControl/SegmentedControl.d.ts.map +1 -0
  302. package/dist/components/SegmentedControl/index.d.ts +2 -0
  303. package/dist/components/SegmentedControl/index.d.ts.map +1 -0
  304. package/dist/components/Select/Select.d.ts +19 -1
  305. package/dist/components/Select/Select.d.ts.map +1 -1
  306. package/dist/components/Sheet/Sheet.d.ts.map +1 -1
  307. package/dist/components/Show/Show.d.ts +35 -0
  308. package/dist/components/Show/Show.d.ts.map +1 -0
  309. package/dist/components/Show/index.d.ts +2 -0
  310. package/dist/components/Show/index.d.ts.map +1 -0
  311. package/dist/components/Sidebar/Sidebar.d.ts +7 -8
  312. package/dist/components/Sidebar/Sidebar.d.ts.map +1 -1
  313. package/dist/components/Skeleton/Skeleton.d.ts +43 -5
  314. package/dist/components/Skeleton/Skeleton.d.ts.map +1 -1
  315. package/dist/components/Skeleton/index.d.ts +1 -1
  316. package/dist/components/Skeleton/index.d.ts.map +1 -1
  317. package/dist/components/Slider/Slider.d.ts +26 -7
  318. package/dist/components/Slider/Slider.d.ts.map +1 -1
  319. package/dist/components/Slider/index.d.ts +1 -1
  320. package/dist/components/Slider/index.d.ts.map +1 -1
  321. package/dist/components/SocialButton/SocialButton.d.ts +23 -5
  322. package/dist/components/SocialButton/SocialButton.d.ts.map +1 -1
  323. package/dist/components/SocialButton/index.d.ts +1 -1
  324. package/dist/components/SocialButton/index.d.ts.map +1 -1
  325. package/dist/components/Sortable/Sortable.d.ts +14 -6
  326. package/dist/components/Sortable/Sortable.d.ts.map +1 -1
  327. package/dist/components/Sparkline/Sparkline.d.ts +38 -3
  328. package/dist/components/Sparkline/Sparkline.d.ts.map +1 -1
  329. package/dist/components/Sparkline/index.d.ts +1 -1
  330. package/dist/components/Sparkline/index.d.ts.map +1 -1
  331. package/dist/components/Spinner/Spinner.d.ts +14 -5
  332. package/dist/components/Spinner/Spinner.d.ts.map +1 -1
  333. package/dist/components/Spinner/index.d.ts +1 -1
  334. package/dist/components/Spinner/index.d.ts.map +1 -1
  335. package/dist/components/Spotlight/Spotlight.d.ts +37 -0
  336. package/dist/components/Spotlight/Spotlight.d.ts.map +1 -0
  337. package/dist/components/Spotlight/index.d.ts +2 -0
  338. package/dist/components/Spotlight/index.d.ts.map +1 -0
  339. package/dist/components/Stack/Stack.d.ts +41 -0
  340. package/dist/components/Stack/Stack.d.ts.map +1 -0
  341. package/dist/components/Stack/index.d.ts +2 -0
  342. package/dist/components/Stack/index.d.ts.map +1 -0
  343. package/dist/components/Stat/Stat.d.ts +15 -6
  344. package/dist/components/Stat/Stat.d.ts.map +1 -1
  345. package/dist/components/Stat/index.d.ts +1 -1
  346. package/dist/components/Stat/index.d.ts.map +1 -1
  347. package/dist/components/StatusTiles/StatusTiles.d.ts +39 -0
  348. package/dist/components/StatusTiles/StatusTiles.d.ts.map +1 -0
  349. package/dist/components/StatusTiles/index.d.ts +2 -0
  350. package/dist/components/StatusTiles/index.d.ts.map +1 -0
  351. package/dist/components/Stepper/Stepper.d.ts +53 -0
  352. package/dist/components/Stepper/Stepper.d.ts.map +1 -0
  353. package/dist/components/Stepper/index.d.ts +2 -0
  354. package/dist/components/Stepper/index.d.ts.map +1 -0
  355. package/dist/components/Switch/Switch.d.ts +11 -6
  356. package/dist/components/Switch/Switch.d.ts.map +1 -1
  357. package/dist/components/Switch/index.d.ts +1 -1
  358. package/dist/components/Switch/index.d.ts.map +1 -1
  359. package/dist/components/Table/Table.d.ts +11 -5
  360. package/dist/components/Table/Table.d.ts.map +1 -1
  361. package/dist/components/Tabs/Tabs.d.ts.map +1 -1
  362. package/dist/components/TagsInput/TagsInput.d.ts +10 -5
  363. package/dist/components/TagsInput/TagsInput.d.ts.map +1 -1
  364. package/dist/components/TagsInput/index.d.ts +1 -1
  365. package/dist/components/TagsInput/index.d.ts.map +1 -1
  366. package/dist/components/TemplateCard/TemplateCard.d.ts +120 -0
  367. package/dist/components/TemplateCard/TemplateCard.d.ts.map +1 -0
  368. package/dist/components/TemplateCard/index.d.ts +2 -0
  369. package/dist/components/TemplateCard/index.d.ts.map +1 -0
  370. package/dist/components/TestimonialCard/TestimonialCard.d.ts +30 -5
  371. package/dist/components/TestimonialCard/TestimonialCard.d.ts.map +1 -1
  372. package/dist/components/Textarea/Textarea.d.ts +81 -7
  373. package/dist/components/Textarea/Textarea.d.ts.map +1 -1
  374. package/dist/components/Textarea/index.d.ts +1 -1
  375. package/dist/components/Textarea/index.d.ts.map +1 -1
  376. package/dist/components/TimePicker/TimePicker.d.ts +7 -5
  377. package/dist/components/TimePicker/TimePicker.d.ts.map +1 -1
  378. package/dist/components/TimePicker/index.d.ts +1 -1
  379. package/dist/components/TimePicker/index.d.ts.map +1 -1
  380. package/dist/components/Timeline/Timeline.d.ts +14 -5
  381. package/dist/components/Timeline/Timeline.d.ts.map +1 -1
  382. package/dist/components/Timeline/index.d.ts +1 -1
  383. package/dist/components/Timeline/index.d.ts.map +1 -1
  384. package/dist/components/TimezonePicker/TimezonePicker.d.ts +8 -5
  385. package/dist/components/TimezonePicker/TimezonePicker.d.ts.map +1 -1
  386. package/dist/components/TimezonePicker/index.d.ts +1 -1
  387. package/dist/components/TimezonePicker/index.d.ts.map +1 -1
  388. package/dist/components/Toast/Toast.d.ts +15 -0
  389. package/dist/components/Toast/Toast.d.ts.map +1 -1
  390. package/dist/components/Toggle/Toggle.d.ts +16 -6
  391. package/dist/components/Toggle/Toggle.d.ts.map +1 -1
  392. package/dist/components/Toggle/index.d.ts +1 -1
  393. package/dist/components/Toggle/index.d.ts.map +1 -1
  394. package/dist/components/ToolCard/ToolCard.d.ts +12 -10
  395. package/dist/components/ToolCard/ToolCard.d.ts.map +1 -1
  396. package/dist/components/Tooltip/Tooltip.d.ts +13 -2
  397. package/dist/components/Tooltip/Tooltip.d.ts.map +1 -1
  398. package/dist/components/Tooltip/index.d.ts +1 -1
  399. package/dist/components/Tooltip/index.d.ts.map +1 -1
  400. package/dist/components/TraceStep/TraceStep.d.ts +37 -8
  401. package/dist/components/TraceStep/TraceStep.d.ts.map +1 -1
  402. package/dist/components/TreeView/TreeView.d.ts +54 -0
  403. package/dist/components/TreeView/TreeView.d.ts.map +1 -0
  404. package/dist/components/TreeView/index.d.ts +2 -0
  405. package/dist/components/TreeView/index.d.ts.map +1 -0
  406. package/dist/components/UserCard/UserCard.d.ts +38 -5
  407. package/dist/components/UserCard/UserCard.d.ts.map +1 -1
  408. package/dist/components/XmlViewer/XmlViewer.d.ts +11 -6
  409. package/dist/components/XmlViewer/XmlViewer.d.ts.map +1 -1
  410. package/dist/components/YamlViewer/YamlViewer.d.ts +13 -6
  411. package/dist/components/YamlViewer/YamlViewer.d.ts.map +1 -1
  412. package/dist/hooks/useBanner.d.ts +27 -0
  413. package/dist/hooks/useBanner.d.ts.map +1 -0
  414. package/dist/hooks/useBreakpoint.d.ts +29 -0
  415. package/dist/hooks/useBreakpoint.d.ts.map +1 -0
  416. package/dist/hooks/useCallout.d.ts +32 -0
  417. package/dist/hooks/useCallout.d.ts.map +1 -0
  418. package/dist/hooks/useMediaQuery.d.ts +15 -0
  419. package/dist/hooks/useMediaQuery.d.ts.map +1 -0
  420. package/dist/hooks/usePasswordStrength.d.ts +37 -0
  421. package/dist/hooks/usePasswordStrength.d.ts.map +1 -0
  422. package/dist/hooks/useRating.d.ts +51 -0
  423. package/dist/hooks/useRating.d.ts.map +1 -0
  424. package/dist/hooks/useTextareaCommands.d.ts +55 -0
  425. package/dist/hooks/useTextareaCommands.d.ts.map +1 -0
  426. package/dist/hooks/useTextareaSelection.d.ts +34 -0
  427. package/dist/hooks/useTextareaSelection.d.ts.map +1 -0
  428. package/dist/hooks/useTextareaTools.d.ts +88 -0
  429. package/dist/hooks/useTextareaTools.d.ts.map +1 -0
  430. package/dist/hooks/useTimeline.d.ts +31 -0
  431. package/dist/hooks/useTimeline.d.ts.map +1 -0
  432. package/dist/hooks/useTraceTimeline.d.ts +54 -0
  433. package/dist/hooks/useTraceTimeline.d.ts.map +1 -0
  434. package/dist/index.cjs +25553 -12329
  435. package/dist/index.cjs.map +1 -1
  436. package/dist/index.d.ts +92 -49
  437. package/dist/index.d.ts.map +1 -1
  438. package/dist/index.js +25703 -12011
  439. package/dist/index.js.map +1 -1
  440. package/dist/monaco.cjs +359 -488
  441. package/dist/monaco.cjs.map +1 -1
  442. package/dist/monaco.d.ts +1 -1
  443. package/dist/monaco.d.ts.map +1 -1
  444. package/dist/monaco.js +381 -489
  445. package/dist/monaco.js.map +1 -1
  446. package/dist/stories/_shared/TestPage.d.ts +12 -0
  447. package/dist/stories/_shared/TestPage.d.ts.map +1 -0
  448. package/dist/styles.css +1 -1
  449. package/dist/utils/Slot.d.ts +7 -0
  450. package/dist/utils/Slot.d.ts.map +1 -0
  451. package/dist/utils/composeRefs.d.ts +7 -0
  452. package/dist/utils/composeRefs.d.ts.map +1 -0
  453. package/dist/utils/gradients.d.ts +77 -0
  454. package/dist/utils/gradients.d.ts.map +1 -0
  455. package/dist/utils/zIndex.d.ts +53 -0
  456. package/dist/utils/zIndex.d.ts.map +1 -0
  457. package/dist/workflow/components/kinds/BaseNode.d.ts +7 -1
  458. package/dist/workflow/components/kinds/BaseNode.d.ts.map +1 -1
  459. package/dist/workflow/components/kinds/index.d.ts +6 -0
  460. package/dist/workflow/components/kinds/index.d.ts.map +1 -1
  461. package/dist/workflow.cjs +9 -2
  462. package/dist/workflow.cjs.map +1 -1
  463. package/dist/workflow.js +1 -1
  464. package/package.json +5 -5
@@ -0,0 +1,2551 @@
1
+ import {
2
+ cn
3
+ } from "./chunk-ZAUUGK2Y.js";
4
+
5
+ // src/workflow/utils/paths.ts
6
+ function buildEdgePath(routing, start, startSide, end, endSide, options = {}) {
7
+ switch (routing) {
8
+ case "step":
9
+ return stepPath(start, startSide, end, endSide);
10
+ case "smoothstep":
11
+ return smoothStepPath(start, startSide, end, endSide, options.borderRadius ?? 8);
12
+ case "straight":
13
+ return straightPath(start, end);
14
+ default:
15
+ return bezierPath(start, startSide, end, endSide, options.curvature ?? 0.25);
16
+ }
17
+ }
18
+ function bezierPath(start, startSide, end, endSide, curvature = 0.25) {
19
+ const sourceOffset = calcControlOffset(start, startSide, end, curvature);
20
+ const targetOffset = calcControlOffset(end, endSide, start, curvature);
21
+ const c1 = offsetAlongSide(start, startSide, sourceOffset);
22
+ const c2 = offsetAlongSide(end, endSide, targetOffset);
23
+ const d = `M ${start.x},${start.y} C ${c1.x},${c1.y} ${c2.x},${c2.y} ${end.x},${end.y}`;
24
+ const midX = 0.125 * start.x + 0.375 * c1.x + 0.375 * c2.x + 0.125 * end.x;
25
+ const midY = 0.125 * start.y + 0.375 * c1.y + 0.375 * c2.y + 0.125 * end.y;
26
+ const tx = 3 * ((1 - 0.5) ** 2 * (c1.x - start.x) + 2 * (1 - 0.5) * 0.5 * (c2.x - c1.x) + 0.5 ** 2 * (end.x - c2.x));
27
+ const ty = 3 * ((1 - 0.5) ** 2 * (c1.y - start.y) + 2 * (1 - 0.5) * 0.5 * (c2.y - c1.y) + 0.5 ** 2 * (end.y - c2.y));
28
+ const midAngle = Math.atan2(ty, tx);
29
+ return { d, midX, midY, midAngle };
30
+ }
31
+ function axisDistance(from, side, to) {
32
+ switch (side) {
33
+ case "top":
34
+ return from.y - to.y;
35
+ case "bottom":
36
+ return to.y - from.y;
37
+ case "left":
38
+ return from.x - to.x;
39
+ case "right":
40
+ return to.x - from.x;
41
+ }
42
+ }
43
+ function calcControlOffset(from, side, to, curvature) {
44
+ const distance2 = axisDistance(from, side, to);
45
+ if (distance2 >= 0) {
46
+ return distance2 * 0.5 * (1 + curvature);
47
+ }
48
+ return curvature * 25 * Math.sqrt(-distance2);
49
+ }
50
+ function offsetAlongSide(p, side, magnitude) {
51
+ switch (side) {
52
+ case "top":
53
+ return { x: p.x, y: p.y - magnitude };
54
+ case "bottom":
55
+ return { x: p.x, y: p.y + magnitude };
56
+ case "left":
57
+ return { x: p.x - magnitude, y: p.y };
58
+ case "right":
59
+ return { x: p.x + magnitude, y: p.y };
60
+ }
61
+ }
62
+ function stepPath(start, startSide, end, endSide) {
63
+ const corners = computeStepCorners(start, startSide, end, endSide);
64
+ const pts = [start, ...corners, end];
65
+ const d = pts.map((p, i) => `${i === 0 ? "M" : "L"} ${p.x},${p.y}`).join(" ");
66
+ const { midX, midY, midAngle } = midpointOnPolyline(pts);
67
+ return { d, midX, midY, midAngle };
68
+ }
69
+ function smoothStepPath(start, startSide, end, endSide, borderRadius = 8) {
70
+ const corners = computeStepCorners(start, startSide, end, endSide);
71
+ const pts = [start, ...corners, end];
72
+ if (corners.length === 0) {
73
+ return straightPath(start, end);
74
+ }
75
+ const segments = [`M ${pts[0].x},${pts[0].y}`];
76
+ for (let i = 1; i < pts.length - 1; i++) {
77
+ const prev = pts[i - 1];
78
+ const here = pts[i];
79
+ const next = pts[i + 1];
80
+ const r = Math.min(borderRadius, distance(prev, here) / 2, distance(here, next) / 2);
81
+ const enter = pointTowards(here, prev, r);
82
+ const exit = pointTowards(here, next, r);
83
+ segments.push(`L ${enter.x},${enter.y}`);
84
+ segments.push(`Q ${here.x},${here.y} ${exit.x},${exit.y}`);
85
+ }
86
+ const last = pts[pts.length - 1];
87
+ segments.push(`L ${last.x},${last.y}`);
88
+ const d = segments.join(" ");
89
+ const { midX, midY, midAngle } = midpointOnPolyline(pts);
90
+ return { d, midX, midY, midAngle };
91
+ }
92
+ function straightPath(start, end) {
93
+ const d = `M ${start.x},${start.y} L ${end.x},${end.y}`;
94
+ return {
95
+ d,
96
+ midX: (start.x + end.x) / 2,
97
+ midY: (start.y + end.y) / 2,
98
+ midAngle: Math.atan2(end.y - start.y, end.x - start.x)
99
+ };
100
+ }
101
+ function computeStepCorners(start, startSide, end, endSide) {
102
+ const sourceVertical = startSide === "top" || startSide === "bottom";
103
+ const targetVertical = endSide === "top" || endSide === "bottom";
104
+ if (sourceVertical && targetVertical) {
105
+ const midY = (start.y + end.y) / 2;
106
+ return [
107
+ { x: start.x, y: midY },
108
+ { x: end.x, y: midY }
109
+ ];
110
+ }
111
+ if (!sourceVertical && !targetVertical) {
112
+ const midX = (start.x + end.x) / 2;
113
+ return [
114
+ { x: midX, y: start.y },
115
+ { x: midX, y: end.y }
116
+ ];
117
+ }
118
+ if (sourceVertical) {
119
+ return [{ x: end.x, y: start.y }];
120
+ }
121
+ return [{ x: start.x, y: end.y }];
122
+ }
123
+ function midpointOnPolyline(pts) {
124
+ if (pts.length === 2) {
125
+ return {
126
+ midX: (pts[0].x + pts[1].x) / 2,
127
+ midY: (pts[0].y + pts[1].y) / 2,
128
+ midAngle: Math.atan2(pts[1].y - pts[0].y, pts[1].x - pts[0].x)
129
+ };
130
+ }
131
+ let totalLen = 0;
132
+ const lens = [];
133
+ for (let i = 0; i < pts.length - 1; i++) {
134
+ const l = distance(pts[i], pts[i + 1]);
135
+ lens.push(l);
136
+ totalLen += l;
137
+ }
138
+ const half = totalLen / 2;
139
+ let acc = 0;
140
+ for (let i = 0; i < lens.length; i++) {
141
+ if (acc + lens[i] >= half) {
142
+ const seg = lens[i];
143
+ const remaining = half - acc;
144
+ const t = seg === 0 ? 0 : remaining / seg;
145
+ const a = pts[i];
146
+ const b = pts[i + 1];
147
+ return {
148
+ midX: a.x + (b.x - a.x) * t,
149
+ midY: a.y + (b.y - a.y) * t,
150
+ midAngle: Math.atan2(b.y - a.y, b.x - a.x)
151
+ };
152
+ }
153
+ acc += lens[i];
154
+ }
155
+ return { midX: pts[0].x, midY: pts[0].y, midAngle: 0 };
156
+ }
157
+ function distance(a, b) {
158
+ return Math.hypot(b.x - a.x, b.y - a.y);
159
+ }
160
+ function pointTowards(from, to, dist) {
161
+ const d = distance(from, to);
162
+ if (d === 0) return from;
163
+ const t = dist / d;
164
+ return { x: from.x + (to.x - from.x) * t, y: from.y + (to.y - from.y) * t };
165
+ }
166
+
167
+ // src/workflow/hooks/useFlow.ts
168
+ import { createContext, useContext } from "react";
169
+ var FlowInstanceContext = createContext(null);
170
+ function useFlow() {
171
+ const instance = useContext(FlowInstanceContext);
172
+ if (!instance) {
173
+ throw new Error("[@octaviaflow/core/workflow] useFlow() must be called inside <FlowCanvas>.");
174
+ }
175
+ return instance;
176
+ }
177
+
178
+ // src/workflow/store/changes.ts
179
+ function applyNodeChanges(nodes, changes) {
180
+ if (changes.length === 0) return nodes;
181
+ const byId = /* @__PURE__ */ new Map();
182
+ const adds = [];
183
+ const removes = /* @__PURE__ */ new Set();
184
+ let touched = false;
185
+ for (const change2 of changes) {
186
+ switch (change2.type) {
187
+ case "add":
188
+ adds.push(change2.item);
189
+ touched = true;
190
+ break;
191
+ case "remove":
192
+ removes.add(change2.id);
193
+ touched = true;
194
+ break;
195
+ default: {
196
+ const id = change2.id;
197
+ const arr = byId.get(id);
198
+ if (arr) arr.push(change2);
199
+ else byId.set(id, [change2]);
200
+ touched = true;
201
+ break;
202
+ }
203
+ }
204
+ }
205
+ if (!touched) return nodes;
206
+ const next = [];
207
+ for (const node of nodes) {
208
+ if (removes.has(node.id)) continue;
209
+ const patches = byId.get(node.id);
210
+ if (!patches) {
211
+ next.push(node);
212
+ continue;
213
+ }
214
+ let n = node;
215
+ for (const patch of patches) {
216
+ switch (patch.type) {
217
+ case "position":
218
+ n = {
219
+ ...n,
220
+ position: patch.position,
221
+ dragging: patch.dragging
222
+ };
223
+ break;
224
+ case "dimensions":
225
+ n = {
226
+ ...n,
227
+ width: patch.dimensions.width,
228
+ height: patch.dimensions.height
229
+ };
230
+ break;
231
+ case "select":
232
+ if (n.selected === patch.selected) break;
233
+ n = { ...n, selected: patch.selected };
234
+ break;
235
+ case "replace":
236
+ n = patch.item;
237
+ break;
238
+ }
239
+ }
240
+ next.push(n);
241
+ }
242
+ for (const add of adds) next.push(add);
243
+ return next;
244
+ }
245
+ function applyEdgeChanges(edges, changes) {
246
+ if (changes.length === 0) return edges;
247
+ const byId = /* @__PURE__ */ new Map();
248
+ const adds = [];
249
+ const removes = /* @__PURE__ */ new Set();
250
+ let touched = false;
251
+ for (const change2 of changes) {
252
+ switch (change2.type) {
253
+ case "add":
254
+ adds.push(change2.item);
255
+ touched = true;
256
+ break;
257
+ case "remove":
258
+ removes.add(change2.id);
259
+ touched = true;
260
+ break;
261
+ default: {
262
+ const arr = byId.get(change2.id);
263
+ if (arr) arr.push(change2);
264
+ else byId.set(change2.id, [change2]);
265
+ touched = true;
266
+ break;
267
+ }
268
+ }
269
+ }
270
+ if (!touched) return edges;
271
+ const next = [];
272
+ for (const edge of edges) {
273
+ if (removes.has(edge.id)) continue;
274
+ const patches = byId.get(edge.id);
275
+ if (!patches) {
276
+ next.push(edge);
277
+ continue;
278
+ }
279
+ let e = edge;
280
+ for (const patch of patches) {
281
+ switch (patch.type) {
282
+ case "select":
283
+ if (e.selected === patch.selected) break;
284
+ e = { ...e, selected: patch.selected };
285
+ break;
286
+ case "replace":
287
+ e = patch.item;
288
+ break;
289
+ }
290
+ }
291
+ next.push(e);
292
+ }
293
+ for (const add of adds) next.push(add);
294
+ return next;
295
+ }
296
+ var change = {
297
+ node: {
298
+ add(item) {
299
+ return { type: "add", item };
300
+ },
301
+ remove(id) {
302
+ return { type: "remove", id };
303
+ },
304
+ position(id, position, dragging) {
305
+ return { type: "position", id, position, dragging };
306
+ },
307
+ dimensions(id, dimensions) {
308
+ return { type: "dimensions", id, dimensions };
309
+ },
310
+ select(id, selected) {
311
+ return { type: "select", id, selected };
312
+ },
313
+ replace(id, item) {
314
+ return { type: "replace", id, item };
315
+ }
316
+ },
317
+ edge: {
318
+ add(item) {
319
+ return { type: "add", item };
320
+ },
321
+ remove(id) {
322
+ return { type: "remove", id };
323
+ },
324
+ select(id, selected) {
325
+ return { type: "select", id, selected };
326
+ },
327
+ replace(id, item) {
328
+ return { type: "replace", id, item };
329
+ }
330
+ }
331
+ };
332
+
333
+ // src/workflow/utils/geometry.ts
334
+ var DEFAULT_NODE_WIDTH = 368;
335
+ var DEFAULT_NODE_HEIGHT = 96;
336
+ var COLLAPSED_GROUP_HEIGHT = 36;
337
+ var COLLAPSED_FOREACH_HEIGHT = 40;
338
+ function effectiveHeight(node) {
339
+ const data = node.data;
340
+ if (data?.collapsed) {
341
+ if (node.type === "group") return COLLAPSED_GROUP_HEIGHT;
342
+ if (node.type === "forEach") return COLLAPSED_FOREACH_HEIGHT;
343
+ }
344
+ return node.height ?? DEFAULT_NODE_HEIGHT;
345
+ }
346
+ function handleCentre(node, side, index, total) {
347
+ const w = node.width ?? DEFAULT_NODE_WIDTH;
348
+ const h = effectiveHeight(node);
349
+ const x0 = node.position.x;
350
+ const y0 = node.position.y;
351
+ const denom = total + 1;
352
+ const ratio = (index + 1) / denom;
353
+ switch (side) {
354
+ case "top":
355
+ return { x: x0 + w * ratio, y: y0 };
356
+ case "bottom":
357
+ return { x: x0 + w * ratio, y: y0 + h };
358
+ case "left":
359
+ return { x: x0, y: y0 + h * ratio };
360
+ case "right":
361
+ return { x: x0 + w, y: y0 + h * ratio };
362
+ }
363
+ }
364
+ function bezierPath2(start, startSide, end, endSide) {
365
+ const distance2 = Math.hypot(end.x - start.x, end.y - start.y);
366
+ const magnitude = Math.max(40, Math.min(160, distance2 * 0.45));
367
+ const c1 = offsetBySide(start, startSide, magnitude);
368
+ const c2 = offsetBySide(end, endSide, magnitude);
369
+ const d = `M ${start.x},${start.y} C ${c1.x},${c1.y} ${c2.x},${c2.y} ${end.x},${end.y}`;
370
+ const midX = 0.125 * start.x + 0.375 * c1.x + 0.375 * c2.x + 0.125 * end.x;
371
+ const midY = 0.125 * start.y + 0.375 * c1.y + 0.375 * c2.y + 0.125 * end.y;
372
+ return { d, midX, midY };
373
+ }
374
+ function offsetBySide(p, side, m) {
375
+ switch (side) {
376
+ case "top":
377
+ return { x: p.x, y: p.y - m };
378
+ case "bottom":
379
+ return { x: p.x, y: p.y + m };
380
+ case "left":
381
+ return { x: p.x - m, y: p.y };
382
+ case "right":
383
+ return { x: p.x + m, y: p.y };
384
+ }
385
+ }
386
+ function screenToFlow(p, vp) {
387
+ return {
388
+ x: (p.x - vp.x) / vp.zoom,
389
+ y: (p.y - vp.y) / vp.zoom
390
+ };
391
+ }
392
+ function flowToScreen(p, vp) {
393
+ return {
394
+ x: p.x * vp.zoom + vp.x,
395
+ y: p.y * vp.zoom + vp.y
396
+ };
397
+ }
398
+
399
+ // src/workflow/utils/parenting.ts
400
+ function descendantsOf(nodeId, nodes) {
401
+ const childrenByParent = /* @__PURE__ */ new Map();
402
+ for (const n of nodes) {
403
+ if (!n.parentId) continue;
404
+ const arr = childrenByParent.get(n.parentId);
405
+ if (arr) arr.push(n);
406
+ else childrenByParent.set(n.parentId, [n]);
407
+ }
408
+ const out = [];
409
+ const stack = [nodeId];
410
+ const visited = /* @__PURE__ */ new Set([nodeId]);
411
+ while (stack.length) {
412
+ const cur = stack.pop();
413
+ if (cur === void 0) break;
414
+ const list = childrenByParent.get(cur);
415
+ if (!list) continue;
416
+ for (const c of list) {
417
+ if (visited.has(c.id)) continue;
418
+ visited.add(c.id);
419
+ out.push(c);
420
+ stack.push(c.id);
421
+ }
422
+ }
423
+ return out;
424
+ }
425
+ function findAncestor(node, nodes, predicate) {
426
+ let cursor = node;
427
+ const seen = /* @__PURE__ */ new Set();
428
+ while (cursor?.parentId) {
429
+ if (seen.has(cursor.parentId)) return void 0;
430
+ seen.add(cursor.parentId);
431
+ const parent = nodes.find((n) => n.id === cursor.parentId);
432
+ if (!parent) return void 0;
433
+ if (predicate(parent)) return parent;
434
+ cursor = parent;
435
+ }
436
+ return void 0;
437
+ }
438
+ function clampToParentExtent(node, proposed, nodes) {
439
+ if (node.extent !== "parent" || !node.parentId) return proposed;
440
+ const parent = nodes.find((n) => n.id === node.parentId);
441
+ if (!parent) return proposed;
442
+ const pw = parent.width ?? DEFAULT_NODE_WIDTH;
443
+ const ph = effectiveHeight(parent);
444
+ const w = node.width ?? DEFAULT_NODE_WIDTH;
445
+ const h = effectiveHeight(node);
446
+ const minX = parent.position.x;
447
+ const minY = parent.position.y;
448
+ const maxX = parent.position.x + pw - w;
449
+ const maxY = parent.position.y + ph - h;
450
+ return {
451
+ x: Math.max(minX, Math.min(maxX, proposed.x)),
452
+ y: Math.max(minY, Math.min(maxY, proposed.y))
453
+ };
454
+ }
455
+ function findContainingGroup(point, nodes, exclude = []) {
456
+ for (let i = nodes.length - 1; i >= 0; i--) {
457
+ const n = nodes[i];
458
+ if (exclude.includes(n.id)) continue;
459
+ if (n.type !== "group") continue;
460
+ if (n.data && typeof n.data === "object" && n.data.collapsed) {
461
+ continue;
462
+ }
463
+ const w = n.width ?? DEFAULT_NODE_WIDTH;
464
+ const h = effectiveHeight(n);
465
+ if (point.x >= n.position.x && point.y >= n.position.y && point.x <= n.position.x + w && point.y <= n.position.y + h) {
466
+ return n;
467
+ }
468
+ }
469
+ return void 0;
470
+ }
471
+
472
+ // src/workflow/components/FlowEdge/FlowEdge.tsx
473
+ import {
474
+ memo,
475
+ useEffect,
476
+ useId,
477
+ useRef,
478
+ useState
479
+ } from "react";
480
+
481
+ // src/workflow/components/Handle/handleRegistry.ts
482
+ import { createContext as createContext2, useContext as useContext2 } from "react";
483
+ var HandleRegistryContext = createContext2(null);
484
+ function useHandleRegistry() {
485
+ const r = useContext2(HandleRegistryContext);
486
+ if (!r) {
487
+ throw new Error("[@octaviaflow/core/workflow] Handle must be used inside <FlowCanvas>.");
488
+ }
489
+ return r;
490
+ }
491
+ function createHandleRegistry() {
492
+ const map = /* @__PURE__ */ new Map();
493
+ const key = (n, t, h) => `${n}::${t}::${h}`;
494
+ const listeners = /* @__PURE__ */ new Set();
495
+ const notify = () => {
496
+ for (const l of listeners) l();
497
+ };
498
+ return {
499
+ register(d) {
500
+ map.set(key(d.nodeId, d.type, d.handleId), d);
501
+ notify();
502
+ return () => {
503
+ const k = key(d.nodeId, d.type, d.handleId);
504
+ if (map.get(k) === d) {
505
+ map.delete(k);
506
+ notify();
507
+ }
508
+ };
509
+ },
510
+ resolve(nodeId, type, handleId) {
511
+ return map.get(key(nodeId, type, handleId));
512
+ },
513
+ subscribe(listener) {
514
+ listeners.add(listener);
515
+ return () => {
516
+ listeners.delete(listener);
517
+ };
518
+ }
519
+ };
520
+ }
521
+
522
+ // src/workflow/components/FlowEdge/FlowEdge.tsx
523
+ import { jsx, jsxs } from "react/jsx-runtime";
524
+ function FlowEdgeImpl({
525
+ edge,
526
+ nodes,
527
+ onSelect,
528
+ onDelete,
529
+ onLabelChange,
530
+ showDelete = true,
531
+ curvature = 0.25,
532
+ borderRadius = 8
533
+ }) {
534
+ const uid = useId();
535
+ const markerId = `ods-flow-edge-arrow-${uid.replace(/:/g, "")}`;
536
+ const registry = useHandleRegistry();
537
+ const [hovered, setHovered] = useState(false);
538
+ const [editing, setEditing] = useState(false);
539
+ const [draftLabel, setDraftLabel] = useState(edge.label ?? "");
540
+ const inputRef = useRef(null);
541
+ useEffect(() => {
542
+ if (!editing) setDraftLabel(edge.label ?? "");
543
+ }, [edge.label, editing]);
544
+ const sourceNode = nodes.find((n) => n.id === edge.source);
545
+ const targetNode = nodes.find((n) => n.id === edge.target);
546
+ if (!sourceNode || !targetNode) return null;
547
+ const sourceHandleId = edge.sourceHandle ?? "default";
548
+ const targetHandleId = edge.targetHandle ?? "default";
549
+ const sourceDesc = registry.resolve(sourceNode.id, "source", sourceHandleId);
550
+ const targetDesc = registry.resolve(targetNode.id, "target", targetHandleId);
551
+ const sourceSide = sourceDesc?.side ?? sourceNode.sourcePosition ?? "bottom";
552
+ const targetSide = targetDesc?.side ?? targetNode.targetPosition ?? "top";
553
+ const sourceIndex = sourceDesc?.index ?? 0;
554
+ const sourceTotal = sourceDesc?.total ?? 1;
555
+ const targetIndex = targetDesc?.index ?? 0;
556
+ const targetTotal = targetDesc?.total ?? 1;
557
+ const rawStart = handleCentre(sourceNode, sourceSide, sourceIndex, sourceTotal);
558
+ const rawEnd = handleCentre(targetNode, targetSide, targetIndex, targetTotal);
559
+ const HANDLE_GAP = 8;
560
+ const start = offsetAlongSide2(rawStart, sourceSide, HANDLE_GAP);
561
+ const end = offsetAlongSide2(rawEnd, targetSide, HANDLE_GAP);
562
+ const routing = edge.routing ?? "bezier";
563
+ const { d, midX, midY } = buildEdgePath(routing, start, sourceSide, end, targetSide, {
564
+ curvature,
565
+ borderRadius
566
+ });
567
+ const { d: hitD } = buildEdgePath(routing, rawStart, sourceSide, rawEnd, targetSide, {
568
+ curvature,
569
+ borderRadius
570
+ });
571
+ const type = edge.type ?? "default";
572
+ const isHot = hovered || edge.selected;
573
+ const stroke = type === "error" ? "var(--ods-status-failed, #dc2626)" : isHot ? "var(--ods-accent, #4f46e5)" : "var(--ods-border-strong, #6b7280)";
574
+ const typeDash = type === "conditional" ? "6 4" : type === "loop" ? "4 4" : void 0;
575
+ const dash = edge.style?.strokeDasharray ?? typeDash;
576
+ const strokeWidth = edge.style?.strokeWidth ?? (isHot ? 2 : 1.4);
577
+ const animateDash = edge.animated === true;
578
+ const label = edge.label;
579
+ const hasDelete = showDelete && (isHot || edge.selected) && !!onDelete;
580
+ const showChrome = !!label || editing || hasDelete;
581
+ const commitLabel = (next) => {
582
+ setEditing(false);
583
+ if (next !== edge.label) onLabelChange?.(edge.id, next);
584
+ };
585
+ const onLabelKey = (e) => {
586
+ if (e.key === "Enter") {
587
+ e.preventDefault();
588
+ commitLabel(draftLabel);
589
+ } else if (e.key === "Escape") {
590
+ e.preventDefault();
591
+ setEditing(false);
592
+ setDraftLabel(edge.label ?? "");
593
+ }
594
+ };
595
+ return /* @__PURE__ */ jsxs(
596
+ "g",
597
+ {
598
+ className: cn(
599
+ "ods-flow-edge-v2",
600
+ `ods-flow-edge-v2--${type}`,
601
+ `ods-flow-edge-v2--routing-${routing}`,
602
+ edge.selected && "ods-flow-edge-v2--selected",
603
+ hovered && "ods-flow-edge-v2--hovered",
604
+ edge.className
605
+ ),
606
+ "data-edge-id": edge.id,
607
+ "data-edge-routing": routing,
608
+ onMouseEnter: () => setHovered(true),
609
+ onMouseLeave: () => setHovered(false),
610
+ onClick: (e) => {
611
+ e.stopPropagation();
612
+ onSelect?.(edge.id);
613
+ },
614
+ children: [
615
+ /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx(
616
+ "marker",
617
+ {
618
+ id: markerId,
619
+ viewBox: "0 0 10 10",
620
+ refX: "9",
621
+ refY: "5",
622
+ markerWidth: "7",
623
+ markerHeight: "7",
624
+ orient: "auto-start-reverse",
625
+ children: /* @__PURE__ */ jsx("path", { d: "M0 0L10 5L0 10z", fill: stroke })
626
+ }
627
+ ) }),
628
+ /* @__PURE__ */ jsx("path", { d: hitD, stroke: "transparent", strokeWidth: 20, fill: "none" }),
629
+ /* @__PURE__ */ jsx(
630
+ "path",
631
+ {
632
+ d,
633
+ stroke,
634
+ strokeWidth,
635
+ strokeDasharray: dash,
636
+ fill: "none",
637
+ markerEnd: `url(#${markerId})`,
638
+ style: animateDash ? {
639
+ strokeDasharray: dash ?? "6 4",
640
+ animation: "ods-flow-edge-flow 0.6s linear infinite"
641
+ } : void 0
642
+ }
643
+ ),
644
+ showChrome && /* @__PURE__ */ jsx(
645
+ "foreignObject",
646
+ {
647
+ x: midX - 140,
648
+ y: midY - 16,
649
+ width: 280,
650
+ height: 32,
651
+ style: { overflow: "visible", pointerEvents: "none" },
652
+ children: /* @__PURE__ */ jsxs("div", { className: "ods-flow-edge-v2__chrome", children: [
653
+ (label || editing) && (editing ? /* @__PURE__ */ jsx(
654
+ "input",
655
+ {
656
+ ref: inputRef,
657
+ className: "ods-flow-edge-v2__label-input",
658
+ value: draftLabel,
659
+ autoFocus: true,
660
+ onChange: (e) => setDraftLabel(e.target.value),
661
+ onBlur: () => commitLabel(draftLabel),
662
+ onKeyDown: onLabelKey,
663
+ onClick: (e) => e.stopPropagation(),
664
+ onMouseDown: (e) => e.stopPropagation(),
665
+ "aria-label": "Edit edge label"
666
+ }
667
+ ) : /* @__PURE__ */ jsx(
668
+ "button",
669
+ {
670
+ type: "button",
671
+ className: "ods-flow-edge-v2__label-chip",
672
+ onDoubleClick: (e) => {
673
+ if (!onLabelChange) return;
674
+ e.stopPropagation();
675
+ setDraftLabel(edge.label ?? "");
676
+ setEditing(true);
677
+ },
678
+ onClick: (e) => {
679
+ e.stopPropagation();
680
+ onSelect?.(edge.id);
681
+ },
682
+ title: onLabelChange ? "Double-click to edit" : void 0,
683
+ tabIndex: onLabelChange ? 0 : -1,
684
+ children: /* @__PURE__ */ jsx("span", { children: label })
685
+ }
686
+ )),
687
+ hasDelete && /* @__PURE__ */ jsx(
688
+ "button",
689
+ {
690
+ type: "button",
691
+ className: "ods-flow-edge-v2__delete-btn",
692
+ onClick: (e) => {
693
+ e.stopPropagation();
694
+ onDelete?.(edge.id);
695
+ },
696
+ "aria-label": "Delete edge",
697
+ children: /* @__PURE__ */ jsx("svg", { width: "10", height: "10", viewBox: "0 0 10 10", "aria-hidden": "true", children: /* @__PURE__ */ jsx(
698
+ "path",
699
+ {
700
+ d: "M2 2l6 6M8 2l-6 6",
701
+ stroke: "currentColor",
702
+ strokeWidth: 1.5,
703
+ strokeLinecap: "round"
704
+ }
705
+ ) })
706
+ }
707
+ )
708
+ ] })
709
+ }
710
+ )
711
+ ]
712
+ }
713
+ );
714
+ }
715
+ function offsetAlongSide2(p, side, gap) {
716
+ switch (side) {
717
+ case "top":
718
+ return { x: p.x, y: p.y - gap };
719
+ case "bottom":
720
+ return { x: p.x, y: p.y + gap };
721
+ case "left":
722
+ return { x: p.x - gap, y: p.y };
723
+ case "right":
724
+ return { x: p.x + gap, y: p.y };
725
+ }
726
+ }
727
+ var FlowEdge = memo(FlowEdgeImpl, (prev, next) => {
728
+ if (prev.edge !== next.edge) return false;
729
+ if (prev.onSelect !== next.onSelect || prev.onDelete !== next.onDelete) return false;
730
+ if (prev.onLabelChange !== next.onLabelChange) return false;
731
+ if (prev.showDelete !== next.showDelete) return false;
732
+ if (prev.curvature !== next.curvature || prev.borderRadius !== next.borderRadius) return false;
733
+ if (prev.handleVersion !== next.handleVersion) return false;
734
+ const ps = prev.nodes.find((n) => n.id === prev.edge.source);
735
+ const pt = prev.nodes.find((n) => n.id === prev.edge.target);
736
+ const ns = next.nodes.find((n) => n.id === next.edge.source);
737
+ const nt = next.nodes.find((n) => n.id === next.edge.target);
738
+ if (ps !== ns || pt !== nt) return false;
739
+ return true;
740
+ });
741
+
742
+ // src/workflow/components/FlowNode/FlowNodeContext.tsx
743
+ import { createContext as createContext3, useContext as useContext3 } from "react";
744
+ var FlowNodeContext = createContext3(null);
745
+ function useFlowNodeContext() {
746
+ const v = useContext3(FlowNodeContext);
747
+ if (!v) {
748
+ throw new Error(
749
+ "[@octaviaflow/core/workflow] Handle / NodeToolbar must be inside a node renderer."
750
+ );
751
+ }
752
+ return v;
753
+ }
754
+
755
+ // src/workflow/components/FlowNode/FlowNode.tsx
756
+ import { useEffect as useEffect2, useMemo, useRef as useRef2 } from "react";
757
+
758
+ // src/workflow/components/FlowCanvas/FlowCanvasContext.tsx
759
+ import { createContext as createContext4, useContext as useContext4 } from "react";
760
+ var FlowDispatchContext = createContext4(null);
761
+ function useFlowDispatch() {
762
+ const dispatch = useContext4(FlowDispatchContext);
763
+ if (!dispatch) {
764
+ throw new Error(
765
+ "[@octaviaflow/core/workflow] useFlowDispatch must be called inside <FlowCanvas>."
766
+ );
767
+ }
768
+ return dispatch;
769
+ }
770
+ var FlowNodeBridgeContext = createContext4(null);
771
+ function useFlowNodeBridge() {
772
+ const b = useContext4(FlowNodeBridgeContext);
773
+ if (!b) {
774
+ throw new Error("[@octaviaflow/core/workflow] FlowNode must be a child of <FlowCanvas>.");
775
+ }
776
+ return b;
777
+ }
778
+
779
+ // src/workflow/components/FlowNode/FlowNode.tsx
780
+ import { jsx as jsx2 } from "react/jsx-runtime";
781
+ function FlowNode({
782
+ node,
783
+ selected,
784
+ dragging,
785
+ isConnecting,
786
+ Kind,
787
+ // Match the BaseNode body's fixed 368 px width so the wrapper bbox and
788
+ // the rendered card line up on the first paint — before the
789
+ // ResizeObserver has had a chance to write back the measured size.
790
+ // Container kinds (group / forEach) opt out by setting `node.width`.
791
+ defaultWidth = 368
792
+ }) {
793
+ const bridge = useFlowNodeBridge();
794
+ const wrapperRef = useRef2(null);
795
+ useEffect2(() => {
796
+ const el = wrapperRef.current;
797
+ if (!el || typeof ResizeObserver === "undefined") return;
798
+ if (node.type === "group" || node.type === "forEach") return;
799
+ const ro = new ResizeObserver(() => {
800
+ bridge.reportDimensions(node.id, el.offsetWidth, el.offsetHeight);
801
+ });
802
+ ro.observe(el);
803
+ return () => ro.disconnect();
804
+ }, [bridge, node.id, node.type]);
805
+ const ctx = useMemo(
806
+ () => ({ id: node.id, node, selected }),
807
+ [node, selected]
808
+ );
809
+ const downPosRef = useRef2(null);
810
+ const draggedRef = useRef2(false);
811
+ const CLICK_VS_DRAG_PX = 5;
812
+ const handlePointerDown = (e) => {
813
+ if (e.target.closest("[data-handle-id]")) return;
814
+ if (e.target.closest("[data-flow-no-drag='true']")) return;
815
+ e.stopPropagation();
816
+ downPosRef.current = { x: e.clientX, y: e.clientY };
817
+ draggedRef.current = false;
818
+ bridge.beginNodeDrag(node.id, e.pointerId, e.clientX, e.clientY, e.altKey);
819
+ };
820
+ const handlePointerMove = (e) => {
821
+ const start = downPosRef.current;
822
+ if (!start || draggedRef.current) return;
823
+ if (Math.abs(e.clientX - start.x) > CLICK_VS_DRAG_PX || Math.abs(e.clientY - start.y) > CLICK_VS_DRAG_PX) {
824
+ draggedRef.current = true;
825
+ }
826
+ };
827
+ const handleClick = (e) => {
828
+ if (e.target.closest("[data-handle-id]")) return;
829
+ e.stopPropagation();
830
+ if (draggedRef.current) {
831
+ draggedRef.current = false;
832
+ downPosRef.current = null;
833
+ return;
834
+ }
835
+ downPosRef.current = null;
836
+ bridge.selectNode(node.id, e.metaKey || e.ctrlKey || e.shiftKey);
837
+ bridge.notifyNodeClick(node.id);
838
+ };
839
+ return /* @__PURE__ */ jsx2(
840
+ "div",
841
+ {
842
+ ref: wrapperRef,
843
+ "data-node-id": node.id,
844
+ "data-node-type": node.type,
845
+ "data-node-selected": selected ? "true" : "false",
846
+ className: cn(
847
+ "ods-flow-node-v2",
848
+ `ods-flow-node-v2--kind-${node.type}`,
849
+ selected && "ods-flow-node-v2--selected",
850
+ dragging && "ods-flow-node-v2--dragging",
851
+ isConnecting && "ods-flow-node-v2--connecting",
852
+ node.className
853
+ ),
854
+ style: {
855
+ position: "absolute",
856
+ left: node.position.x,
857
+ top: node.position.y,
858
+ width: node.width ?? defaultWidth,
859
+ // Z-stack (per architecture doc): groups (20) sit below normal
860
+ // nodes (30) so children render visually on top of their parent
861
+ // frame. Selection raises by 10. Consumer override wins.
862
+ zIndex: node.zIndex ?? (selected ? node.type === "group" ? 35 : 40 : node.type === "group" ? 20 : 30),
863
+ ...node.style
864
+ },
865
+ onPointerDown: handlePointerDown,
866
+ onPointerMove: handlePointerMove,
867
+ onClick: handleClick,
868
+ children: /* @__PURE__ */ jsx2(FlowNodeContext.Provider, { value: ctx, children: /* @__PURE__ */ jsx2(Kind, { node, selected, dragging, isConnecting }) })
869
+ }
870
+ );
871
+ }
872
+
873
+ // src/workflow/components/FlowNode/nodeKinds.ts
874
+ function buildNodeKindRegistry(defaults, overrides) {
875
+ return Object.freeze({ ...defaults, ...overrides ?? {} });
876
+ }
877
+
878
+ // src/workflow/components/Handle/Handle.tsx
879
+ import { useEffect as useEffect3, useRef as useRef3 } from "react";
880
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
881
+ var DEFAULT_HANDLE_ID = "default";
882
+ function Handle({
883
+ type,
884
+ position,
885
+ id = DEFAULT_HANDLE_ID,
886
+ isConnectable = true,
887
+ isConnectableStart,
888
+ isConnectableEnd,
889
+ index = 0,
890
+ total = 1,
891
+ label,
892
+ className,
893
+ style
894
+ }) {
895
+ const registry = useHandleRegistry();
896
+ const node = useFlowNodeContext();
897
+ const dispatch = useFlowDispatch();
898
+ const ref = useRef3(null);
899
+ const canStart = isConnectableStart ?? isConnectable;
900
+ const canEnd = isConnectableEnd ?? isConnectable;
901
+ useEffect3(() => {
902
+ const dispose = registry.register({
903
+ nodeId: node.id,
904
+ handleId: id,
905
+ type,
906
+ side: position,
907
+ index,
908
+ total
909
+ });
910
+ return dispose;
911
+ }, [registry, node.id, id, type, position, index, total]);
912
+ const handlePointerDown = (e) => {
913
+ if (!canStart) return;
914
+ e.stopPropagation();
915
+ e.preventDefault();
916
+ dispatch({
917
+ type: "connection/start",
918
+ nodeId: node.id,
919
+ handleId: id,
920
+ handleType: type,
921
+ pointerId: e.pointerId,
922
+ clientX: e.clientX,
923
+ clientY: e.clientY
924
+ });
925
+ };
926
+ return /* @__PURE__ */ jsxs2(
927
+ "div",
928
+ {
929
+ ref,
930
+ "data-handle-id": id,
931
+ "data-handle-node-id": node.id,
932
+ "data-handle-type": type,
933
+ "data-handle-side": position,
934
+ "data-handle-connectable-end": canEnd ? "true" : "false",
935
+ className: cn(
936
+ "ods-flow-handle",
937
+ `ods-flow-handle--${type}`,
938
+ `ods-flow-handle--side-${position}`,
939
+ !isConnectable && "ods-flow-handle--disabled",
940
+ className
941
+ ),
942
+ style: {
943
+ ...handleSideStyle(position, index, total),
944
+ ...style
945
+ },
946
+ onPointerDown: handlePointerDown,
947
+ children: [
948
+ /* @__PURE__ */ jsx3("div", { className: "ods-flow-handle__dot" }),
949
+ label && /* @__PURE__ */ jsx3("span", { className: "ods-flow-handle__label", children: label })
950
+ ]
951
+ }
952
+ );
953
+ }
954
+ function handleSideStyle(side, index, total) {
955
+ const ratio = (index + 1) / (total + 1) * 100;
956
+ switch (side) {
957
+ case "top":
958
+ return { position: "absolute", top: -6, left: `${ratio}%`, transform: "translateX(-50%)" };
959
+ case "bottom":
960
+ return { position: "absolute", bottom: -6, left: `${ratio}%`, transform: "translateX(-50%)" };
961
+ case "left":
962
+ return { position: "absolute", left: -6, top: `${ratio}%`, transform: "translateY(-50%)" };
963
+ case "right":
964
+ return { position: "absolute", right: -6, top: `${ratio}%`, transform: "translateY(-50%)" };
965
+ }
966
+ }
967
+
968
+ // src/workflow/components/kinds/BaseNode.tsx
969
+ import { TrashCanIcon } from "@octaviaflow/icons";
970
+ import { useContext as useContext5 } from "react";
971
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
972
+ function BaseNode({
973
+ kind,
974
+ kindIcon,
975
+ icon,
976
+ title,
977
+ chip,
978
+ description,
979
+ valueChip,
980
+ accent = "green",
981
+ status,
982
+ onDelete,
983
+ footer,
984
+ className,
985
+ children
986
+ }) {
987
+ const ctx = useContext5(FlowNodeContext);
988
+ const bridge = useContext5(FlowNodeBridgeContext);
989
+ const deleteHandler = onDelete === false ? void 0 : onDelete ?? (ctx && bridge ? () => bridge.deleteNode(ctx.id) : void 0);
990
+ return /* @__PURE__ */ jsxs3(
991
+ "div",
992
+ {
993
+ className: cn(
994
+ "ods-flow-base-node",
995
+ `ods-flow-base-node--accent-${accent}`,
996
+ status && `ods-flow-base-node--status-${status}`,
997
+ className
998
+ ),
999
+ children: [
1000
+ /* @__PURE__ */ jsxs3("div", { className: "ods-flow-base-node__pill", children: [
1001
+ kindIcon && /* @__PURE__ */ jsx4("span", { className: "ods-flow-base-node__pill-icon", "aria-hidden": "true", children: kindIcon }),
1002
+ /* @__PURE__ */ jsx4("span", { className: "ods-flow-base-node__pill-label", children: kind })
1003
+ ] }),
1004
+ status && status !== "idle" && /* @__PURE__ */ jsx4(
1005
+ "span",
1006
+ {
1007
+ className: cn("ods-flow-base-node__status", `ods-flow-base-node__status--${status}`),
1008
+ "aria-hidden": "true"
1009
+ }
1010
+ ),
1011
+ /* @__PURE__ */ jsxs3("div", { className: "ods-flow-base-node__body", children: [
1012
+ /* @__PURE__ */ jsxs3("div", { className: "ods-flow-base-node__content", children: [
1013
+ /* @__PURE__ */ jsx4("div", { className: "ods-flow-base-node__bubble", "aria-hidden": "true", children: icon }),
1014
+ /* @__PURE__ */ jsxs3("div", { className: "ods-flow-base-node__content-text", children: [
1015
+ /* @__PURE__ */ jsx4("div", { className: "ods-flow-base-node__content-title", children: title }),
1016
+ (chip !== void 0 || description !== void 0 || valueChip !== void 0) && /* @__PURE__ */ jsxs3("div", { className: "ods-flow-base-node__content-info", children: [
1017
+ chip !== void 0 && /* @__PURE__ */ jsx4("span", { className: "ods-flow-base-node__chip", children: chip }),
1018
+ description !== void 0 && /* @__PURE__ */ jsx4("span", { className: "ods-flow-base-node__description", children: description }),
1019
+ valueChip !== void 0 && /* @__PURE__ */ jsx4("span", { className: "ods-flow-base-node__value-chip", children: valueChip })
1020
+ ] })
1021
+ ] })
1022
+ ] }),
1023
+ footer && /* @__PURE__ */ jsx4("div", { className: "ods-flow-base-node__footer", children: footer }),
1024
+ deleteHandler && /* @__PURE__ */ jsx4(
1025
+ "button",
1026
+ {
1027
+ type: "button",
1028
+ className: "ods-flow-base-node__delete",
1029
+ onClick: (e) => {
1030
+ e.stopPropagation();
1031
+ deleteHandler();
1032
+ },
1033
+ "aria-label": "Delete node",
1034
+ "data-flow-no-drag": "true",
1035
+ title: "Delete node",
1036
+ children: /* @__PURE__ */ jsx4(TrashCanIcon, { size: 16, "aria-hidden": true })
1037
+ }
1038
+ )
1039
+ ] }),
1040
+ children
1041
+ ]
1042
+ }
1043
+ );
1044
+ }
1045
+
1046
+ // src/workflow/components/kinds/index.tsx
1047
+ import { Fragment, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
1048
+ var ActionNode = ({
1049
+ node
1050
+ }) => {
1051
+ const d = node.data ?? {};
1052
+ return /* @__PURE__ */ jsxs4(
1053
+ BaseNode,
1054
+ {
1055
+ kind: d.kind ?? "ACTION",
1056
+ icon: d.icon,
1057
+ title: d.title ?? "Action",
1058
+ chip: d.chip ?? d.badge,
1059
+ description: d.description ?? d.subtitle,
1060
+ valueChip: d.valueChip,
1061
+ status: d.status,
1062
+ accent: "green",
1063
+ children: [
1064
+ /* @__PURE__ */ jsx5(Handle, { type: "target", position: "top" }),
1065
+ /* @__PURE__ */ jsx5(Handle, { type: "source", position: "bottom" })
1066
+ ]
1067
+ }
1068
+ );
1069
+ };
1070
+ var TriggerNode = ({
1071
+ node
1072
+ }) => {
1073
+ const d = node.data ?? {};
1074
+ return /* @__PURE__ */ jsx5(
1075
+ BaseNode,
1076
+ {
1077
+ kind: d.kind ?? "TRIGGER",
1078
+ icon: d.icon,
1079
+ title: d.title ?? "Trigger",
1080
+ chip: d.chip,
1081
+ description: d.description ?? "Manually triggered",
1082
+ valueChip: d.valueChip,
1083
+ status: d.status,
1084
+ accent: "green",
1085
+ children: /* @__PURE__ */ jsx5(Handle, { type: "source", position: "bottom" })
1086
+ }
1087
+ );
1088
+ };
1089
+ var ConditionNode = ({
1090
+ node
1091
+ }) => {
1092
+ const d = node.data ?? {};
1093
+ const branches = d.branches ?? [
1094
+ { id: "true", label: "true" },
1095
+ { id: "false", label: "false" }
1096
+ ];
1097
+ return /* @__PURE__ */ jsxs4(
1098
+ BaseNode,
1099
+ {
1100
+ kind: d.kind ?? "CONDITION",
1101
+ icon: d.icon,
1102
+ title: d.title ?? "Condition",
1103
+ chip: d.chip ?? d.badge,
1104
+ description: d.description ?? d.subtitle,
1105
+ status: d.status,
1106
+ accent: "amber",
1107
+ children: [
1108
+ /* @__PURE__ */ jsx5(Handle, { type: "target", position: "top" }),
1109
+ branches.map((b, i) => /* @__PURE__ */ jsx5(
1110
+ Handle,
1111
+ {
1112
+ type: "source",
1113
+ position: "bottom",
1114
+ id: b.id,
1115
+ index: i,
1116
+ total: branches.length,
1117
+ label: b.label
1118
+ },
1119
+ b.id
1120
+ ))
1121
+ ]
1122
+ }
1123
+ );
1124
+ };
1125
+ var GroupNode = ({
1126
+ node
1127
+ }) => {
1128
+ const d = node.data ?? {};
1129
+ const collapsed = !!d.collapsed;
1130
+ const hiddenCount = d.hiddenCount;
1131
+ const bridge = useFlowNodeBridge();
1132
+ const onChevronClick = (e) => {
1133
+ e.stopPropagation();
1134
+ bridge.toggleNodeCollapse(node.id);
1135
+ };
1136
+ return /* @__PURE__ */ jsxs4(
1137
+ "div",
1138
+ {
1139
+ className: "ods-flow-group",
1140
+ "data-collapsed": collapsed ? "true" : "false",
1141
+ style: {
1142
+ width: node.width ?? 360,
1143
+ height: collapsed ? 36 : node.height ?? 200
1144
+ },
1145
+ children: [
1146
+ /* @__PURE__ */ jsxs4("div", { className: "ods-flow-group__header", "data-flow-no-drag": "false", children: [
1147
+ /* @__PURE__ */ jsx5(
1148
+ "button",
1149
+ {
1150
+ type: "button",
1151
+ className: "ods-flow-group__chevron",
1152
+ "data-flow-no-drag": "true",
1153
+ "aria-label": collapsed ? "Expand group" : "Collapse group",
1154
+ "aria-expanded": !collapsed,
1155
+ onClick: onChevronClick,
1156
+ onPointerDown: (e) => e.stopPropagation(),
1157
+ children: collapsed ? "\u25B8" : "\u25BE"
1158
+ }
1159
+ ),
1160
+ /* @__PURE__ */ jsx5("span", { className: "ods-flow-group__title", children: d.title ?? "Group" }),
1161
+ d.subtitle && /* @__PURE__ */ jsx5("span", { className: "ods-flow-group__subtitle", children: d.subtitle }),
1162
+ collapsed && hiddenCount !== void 0 && hiddenCount > 0 && /* @__PURE__ */ jsxs4("span", { className: "ods-flow-group__count", "aria-label": `${hiddenCount} hidden steps`, children: [
1163
+ hiddenCount,
1164
+ " steps"
1165
+ ] })
1166
+ ] }),
1167
+ /* @__PURE__ */ jsx5(Handle, { type: "target", position: "top", id: "__group_in" }),
1168
+ /* @__PURE__ */ jsx5(Handle, { type: "source", position: "bottom", id: "__group_out" })
1169
+ ]
1170
+ }
1171
+ );
1172
+ };
1173
+ var ForEachNode = ({
1174
+ node
1175
+ }) => {
1176
+ const d = node.data ?? {};
1177
+ const iteratorExpr = d.iterator ?? d.description ?? "items[]";
1178
+ const collapsed = !!d.collapsed;
1179
+ const hiddenCount = d.hiddenCount;
1180
+ const bridge = useFlowNodeBridge();
1181
+ const onChevronClick = (e) => {
1182
+ e.stopPropagation();
1183
+ bridge.toggleNodeCollapse(node.id);
1184
+ };
1185
+ return /* @__PURE__ */ jsxs4(
1186
+ "div",
1187
+ {
1188
+ className: "ods-flow-foreach",
1189
+ "data-collapsed": collapsed ? "true" : "false",
1190
+ style: {
1191
+ width: node.width ?? 420,
1192
+ height: collapsed ? 40 : node.height ?? 260
1193
+ },
1194
+ children: [
1195
+ /* @__PURE__ */ jsxs4("div", { className: "ods-flow-foreach__header", children: [
1196
+ /* @__PURE__ */ jsx5(
1197
+ "button",
1198
+ {
1199
+ type: "button",
1200
+ className: "ods-flow-foreach__chevron",
1201
+ "data-flow-no-drag": "true",
1202
+ "aria-label": collapsed ? "Expand iterator" : "Collapse iterator",
1203
+ "aria-expanded": !collapsed,
1204
+ onClick: onChevronClick,
1205
+ onPointerDown: (e) => e.stopPropagation(),
1206
+ children: collapsed ? "\u25B8" : "\u25BE"
1207
+ }
1208
+ ),
1209
+ /* @__PURE__ */ jsx5("span", { className: "ods-flow-foreach__icon", "aria-hidden": "true", children: "\u21BB" }),
1210
+ /* @__PURE__ */ jsx5("span", { className: "ods-flow-foreach__title", children: d.title ?? "For each" }),
1211
+ /* @__PURE__ */ jsx5("code", { className: "ods-flow-foreach__iterator", children: iteratorExpr }),
1212
+ collapsed && hiddenCount !== void 0 && hiddenCount > 0 && /* @__PURE__ */ jsxs4("span", { className: "ods-flow-foreach__count", "aria-label": `${hiddenCount} hidden steps`, children: [
1213
+ hiddenCount,
1214
+ " steps"
1215
+ ] })
1216
+ ] }),
1217
+ /* @__PURE__ */ jsx5(Handle, { type: "target", position: "top", id: "__group_in" }),
1218
+ /* @__PURE__ */ jsx5(Handle, { type: "source", position: "bottom", id: "__group_out" }),
1219
+ !collapsed && // Expanded mode — full 3-handle iterator surface (in / item / done).
1220
+ // `in` shares the top edge with `__group_in`; consumers wiring an
1221
+ // explicit `targetHandle: "in"` get the labelled, visible variant.
1222
+ /* @__PURE__ */ jsxs4(Fragment, { children: [
1223
+ /* @__PURE__ */ jsx5(Handle, { type: "target", position: "top", id: "in", label: "in" }),
1224
+ /* @__PURE__ */ jsx5(Handle, { type: "source", position: "right", id: "item", label: "item" }),
1225
+ /* @__PURE__ */ jsx5(Handle, { type: "source", position: "bottom", id: "done", label: "done" })
1226
+ ] })
1227
+ ]
1228
+ }
1229
+ );
1230
+ };
1231
+ var OutputNode = ({
1232
+ node
1233
+ }) => {
1234
+ const d = node.data ?? {};
1235
+ return /* @__PURE__ */ jsx5(
1236
+ BaseNode,
1237
+ {
1238
+ kind: d.kind ?? "OUTPUT",
1239
+ icon: d.icon,
1240
+ title: d.title ?? "Output",
1241
+ chip: d.chip ?? d.badge,
1242
+ description: d.description ?? d.subtitle,
1243
+ status: d.status,
1244
+ accent: "green",
1245
+ children: /* @__PURE__ */ jsx5(Handle, { type: "target", position: "top" })
1246
+ }
1247
+ );
1248
+ };
1249
+ var ErrorNode = ({
1250
+ node
1251
+ }) => {
1252
+ const d = node.data ?? {};
1253
+ return /* @__PURE__ */ jsxs4(
1254
+ BaseNode,
1255
+ {
1256
+ kind: d.kind ?? "ERROR",
1257
+ icon: d.icon,
1258
+ title: d.title ?? "On error",
1259
+ chip: d.chip ?? d.badge,
1260
+ description: d.description ?? d.subtitle,
1261
+ status: d.status ?? "error",
1262
+ accent: "red",
1263
+ children: [
1264
+ /* @__PURE__ */ jsx5(Handle, { type: "target", position: "top" }),
1265
+ /* @__PURE__ */ jsx5(Handle, { type: "source", position: "bottom" })
1266
+ ]
1267
+ }
1268
+ );
1269
+ };
1270
+ var WaitNode = ({
1271
+ node
1272
+ }) => {
1273
+ const d = node.data ?? {};
1274
+ const waitMs = d.waitMs;
1275
+ const durationChip = waitMs ? `${Math.round(waitMs / 100) / 10}s` : void 0;
1276
+ return /* @__PURE__ */ jsxs4(
1277
+ BaseNode,
1278
+ {
1279
+ kind: d.kind ?? "WAIT",
1280
+ icon: d.icon,
1281
+ title: d.title ?? "Wait",
1282
+ chip: d.chip ?? durationChip,
1283
+ description: d.description ?? (durationChip ? "Pause execution" : void 0),
1284
+ status: d.status,
1285
+ accent: "violet",
1286
+ children: [
1287
+ /* @__PURE__ */ jsx5(Handle, { type: "target", position: "top" }),
1288
+ /* @__PURE__ */ jsx5(Handle, { type: "source", position: "bottom" })
1289
+ ]
1290
+ }
1291
+ );
1292
+ };
1293
+ var ParallelNode = ({
1294
+ node
1295
+ }) => {
1296
+ const d = node.data ?? {};
1297
+ const branches = d.branches ?? [
1298
+ { id: "a", label: "a" },
1299
+ { id: "b", label: "b" }
1300
+ ];
1301
+ return /* @__PURE__ */ jsxs4(
1302
+ BaseNode,
1303
+ {
1304
+ kind: d.kind ?? "PARALLEL",
1305
+ icon: d.icon,
1306
+ title: d.title ?? "Parallel",
1307
+ chip: d.chip ?? `${branches.length}\xD7`,
1308
+ description: d.description ?? "Fan-out branches",
1309
+ status: d.status,
1310
+ accent: "blue",
1311
+ children: [
1312
+ /* @__PURE__ */ jsx5(Handle, { type: "target", position: "top" }),
1313
+ branches.map((b, i) => /* @__PURE__ */ jsx5(
1314
+ Handle,
1315
+ {
1316
+ type: "source",
1317
+ position: "bottom",
1318
+ id: b.id,
1319
+ index: i,
1320
+ total: branches.length,
1321
+ label: b.label
1322
+ },
1323
+ b.id
1324
+ ))
1325
+ ]
1326
+ }
1327
+ );
1328
+ };
1329
+ var StickyNode = ({
1330
+ node
1331
+ }) => {
1332
+ const d = node.data ?? {};
1333
+ return /* @__PURE__ */ jsxs4(
1334
+ "div",
1335
+ {
1336
+ className: "ods-flow-sticky",
1337
+ style: {
1338
+ width: node.width ?? 240,
1339
+ minHeight: node.height ?? 120
1340
+ },
1341
+ children: [
1342
+ d.title && /* @__PURE__ */ jsx5("div", { className: "ods-flow-sticky__title", children: d.title }),
1343
+ d.description && /* @__PURE__ */ jsx5("div", { className: "ods-flow-sticky__body", children: d.description })
1344
+ ]
1345
+ }
1346
+ );
1347
+ };
1348
+ var WebhookNode = ({
1349
+ node
1350
+ }) => {
1351
+ const d = node.data ?? {};
1352
+ return /* @__PURE__ */ jsx5(
1353
+ BaseNode,
1354
+ {
1355
+ kind: d.kind ?? "WEBHOOK",
1356
+ icon: d.icon,
1357
+ title: d.title ?? "Webhook",
1358
+ chip: d.chip ?? d.method ?? "POST",
1359
+ description: d.description ?? d.path ?? "/hooks/incoming",
1360
+ status: d.status,
1361
+ accent: "blue",
1362
+ children: /* @__PURE__ */ jsx5(Handle, { type: "source", position: "bottom" })
1363
+ }
1364
+ );
1365
+ };
1366
+ var HttpRequestNode = ({
1367
+ node
1368
+ }) => {
1369
+ const d = node.data ?? {};
1370
+ return /* @__PURE__ */ jsxs4(
1371
+ BaseNode,
1372
+ {
1373
+ kind: d.kind ?? "HTTP",
1374
+ icon: d.icon,
1375
+ title: d.title ?? "HTTP Request",
1376
+ chip: d.chip ?? d.method ?? "GET",
1377
+ description: d.description ?? d.url ?? "Call an API",
1378
+ valueChip: d.valueChip,
1379
+ status: d.status,
1380
+ accent: "blue",
1381
+ children: [
1382
+ /* @__PURE__ */ jsx5(Handle, { type: "target", position: "top" }),
1383
+ /* @__PURE__ */ jsx5(Handle, { type: "source", position: "bottom" })
1384
+ ]
1385
+ }
1386
+ );
1387
+ };
1388
+ var DEFAULT_NODE_KINDS = {
1389
+ action: ActionNode,
1390
+ trigger: TriggerNode,
1391
+ condition: ConditionNode,
1392
+ group: GroupNode,
1393
+ forEach: ForEachNode,
1394
+ output: OutputNode,
1395
+ error: ErrorNode,
1396
+ wait: WaitNode,
1397
+ parallel: ParallelNode,
1398
+ sticky: StickyNode,
1399
+ webhook: WebhookNode,
1400
+ httpRequest: HttpRequestNode
1401
+ };
1402
+
1403
+ // src/workflow/components/FlowCanvas/FlowCanvas.tsx
1404
+ import {
1405
+ memo as memo2,
1406
+ useCallback,
1407
+ useEffect as useEffect4,
1408
+ useMemo as useMemo2,
1409
+ useRef as useRef4,
1410
+ useState as useState2
1411
+ } from "react";
1412
+
1413
+ // src/workflow/store/context.ts
1414
+ import { createContext as createContext5, useContext as useContext6 } from "react";
1415
+ var FlowStoreContext = createContext5(null);
1416
+ function useFlowStore() {
1417
+ const store = useContext6(FlowStoreContext);
1418
+ if (!store) {
1419
+ throw new Error(
1420
+ "[@octaviaflow/core/workflow] useFlowStore must be called inside a <FlowCanvas>."
1421
+ );
1422
+ }
1423
+ return store;
1424
+ }
1425
+
1426
+ // src/workflow/store/createFlowStore.ts
1427
+ var DEFAULT_VIEWPORT = { x: 0, y: 0, zoom: 1 };
1428
+ function createFlowStore({
1429
+ initialNodes = [],
1430
+ initialEdges = [],
1431
+ initialViewport = DEFAULT_VIEWPORT
1432
+ } = {}) {
1433
+ let snapshot = {
1434
+ nodes: initialNodes,
1435
+ edges: initialEdges,
1436
+ viewport: initialViewport,
1437
+ selectedNodeIds: EMPTY_SET,
1438
+ selectedEdgeIds: EMPTY_SET,
1439
+ connection: null
1440
+ };
1441
+ const listeners = /* @__PURE__ */ new Set();
1442
+ const emit = () => {
1443
+ for (const l of listeners) l();
1444
+ };
1445
+ const subscribe = (listener) => {
1446
+ listeners.add(listener);
1447
+ return () => {
1448
+ listeners.delete(listener);
1449
+ };
1450
+ };
1451
+ const replace = (patch) => {
1452
+ snapshot = { ...snapshot, ...patch };
1453
+ emit();
1454
+ };
1455
+ return {
1456
+ subscribe,
1457
+ getSnapshot: () => snapshot,
1458
+ setNodes(nodes) {
1459
+ if (nodes === snapshot.nodes) return;
1460
+ replace({ nodes });
1461
+ },
1462
+ setEdges(edges) {
1463
+ if (edges === snapshot.edges) return;
1464
+ replace({ edges });
1465
+ },
1466
+ setViewport(viewport) {
1467
+ if (viewport.x === snapshot.viewport.x && viewport.y === snapshot.viewport.y && viewport.zoom === snapshot.viewport.zoom) {
1468
+ return;
1469
+ }
1470
+ replace({ viewport });
1471
+ },
1472
+ setSelection(selectedNodeIds, selectedEdgeIds) {
1473
+ replace({ selectedNodeIds, selectedEdgeIds });
1474
+ },
1475
+ setConnection(connection) {
1476
+ if (connection === snapshot.connection) return;
1477
+ replace({ connection });
1478
+ }
1479
+ };
1480
+ }
1481
+ var EMPTY_SET = /* @__PURE__ */ new Set();
1482
+
1483
+ // src/workflow/utils/collision.ts
1484
+ function resolveNodeCollisions(node, proposed, others, opts) {
1485
+ const { gap, maxIterations = 8, exclude, scopeToSiblings = true } = opts;
1486
+ if (gap < 0 || others.length === 0) return proposed;
1487
+ const w = node.width ?? DEFAULT_NODE_WIDTH;
1488
+ const h = effectiveHeight(node);
1489
+ const parentId = node.parentId;
1490
+ const candidates = others.filter((o) => {
1491
+ if (o.id === node.id) return false;
1492
+ if (o.hidden) return false;
1493
+ if (exclude?.has(o.id)) return false;
1494
+ if (scopeToSiblings && (o.parentId ?? void 0) !== (parentId ?? void 0)) {
1495
+ return false;
1496
+ }
1497
+ return true;
1498
+ });
1499
+ if (candidates.length === 0) return proposed;
1500
+ let cur = proposed;
1501
+ for (let iter = 0; iter < maxIterations; iter++) {
1502
+ let bestOverlap = Number.POSITIVE_INFINITY;
1503
+ let bestPushX = 0;
1504
+ let bestPushY = 0;
1505
+ let hit = false;
1506
+ const aLeft = cur.x - gap;
1507
+ const aRight = cur.x + w + gap;
1508
+ const aTop = cur.y - gap;
1509
+ const aBottom = cur.y + h + gap;
1510
+ for (const o of candidates) {
1511
+ const ow = o.width ?? DEFAULT_NODE_WIDTH;
1512
+ const oh = effectiveHeight(o);
1513
+ const bLeft = o.position.x;
1514
+ const bRight = o.position.x + ow;
1515
+ const bTop = o.position.y;
1516
+ const bBottom = o.position.y + oh;
1517
+ const overlapX = Math.min(aRight, bRight) - Math.max(aLeft, bLeft);
1518
+ const overlapY = Math.min(aBottom, bBottom) - Math.max(aTop, bTop);
1519
+ if (overlapX <= 0 || overlapY <= 0) continue;
1520
+ let pushX = 0;
1521
+ let pushY = 0;
1522
+ let overlap;
1523
+ if (overlapX < overlapY) {
1524
+ const aCx = cur.x + w / 2;
1525
+ const bCx = o.position.x + ow / 2;
1526
+ pushX = aCx < bCx ? -overlapX : overlapX;
1527
+ overlap = overlapX;
1528
+ } else {
1529
+ const aCy = cur.y + h / 2;
1530
+ const bCy = o.position.y + oh / 2;
1531
+ pushY = aCy < bCy ? -overlapY : overlapY;
1532
+ overlap = overlapY;
1533
+ }
1534
+ if (overlap < bestOverlap) {
1535
+ bestOverlap = overlap;
1536
+ bestPushX = pushX;
1537
+ bestPushY = pushY;
1538
+ hit = true;
1539
+ }
1540
+ }
1541
+ if (!hit) break;
1542
+ cur = { x: cur.x + bestPushX, y: cur.y + bestPushY };
1543
+ }
1544
+ return cur;
1545
+ }
1546
+
1547
+ // src/workflow/components/FlowCanvas/FlowCanvas.tsx
1548
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1549
+ var DEFAULT_VIEWPORT2 = { x: 0, y: 0, zoom: 1 };
1550
+ function FlowCanvas({
1551
+ nodes,
1552
+ edges,
1553
+ onNodesChange,
1554
+ onEdgesChange,
1555
+ viewport: controlledViewport,
1556
+ defaultViewport = DEFAULT_VIEWPORT2,
1557
+ onViewportChange,
1558
+ minZoom = 0.25,
1559
+ maxZoom = 2,
1560
+ nodeKinds,
1561
+ onConnect,
1562
+ onConnectStart,
1563
+ onConnectEnd,
1564
+ isValidConnection,
1565
+ onSelectionChange,
1566
+ onPaneClick,
1567
+ onNodeClick,
1568
+ onEdgeClick,
1569
+ onEdgeLabelChange,
1570
+ onInit,
1571
+ onBeforeDelete,
1572
+ onNodeContextMenu,
1573
+ onEdgeContextMenu,
1574
+ onPaneContextMenu,
1575
+ nodesDraggable = true,
1576
+ nodesConnectable = true,
1577
+ panOnDrag: panOnDragProp,
1578
+ zoomOnScroll: zoomOnScrollProp,
1579
+ preset = "mouse",
1580
+ paneClickDistance = 4,
1581
+ paneClickClearsSelection = true,
1582
+ background = "dots",
1583
+ gridSize = 20,
1584
+ snapToGrid = false,
1585
+ nodeCollisionGap = -1,
1586
+ subflowCollisionGap,
1587
+ height = "100%",
1588
+ width = "100%",
1589
+ className,
1590
+ style,
1591
+ children,
1592
+ emptyState
1593
+ }) {
1594
+ const presetDefaults = {
1595
+ mouse: { panOnDrag: true, zoomOnScroll: true },
1596
+ trackpad: { panOnDrag: true, zoomOnScroll: true },
1597
+ touch: { panOnDrag: false, zoomOnScroll: true }
1598
+ };
1599
+ const panOnDrag = panOnDragProp ?? presetDefaults[preset].panOnDrag;
1600
+ const zoomOnScroll = zoomOnScrollProp ?? presetDefaults[preset].zoomOnScroll;
1601
+ const store = useState2(
1602
+ () => createFlowStore({
1603
+ initialNodes: nodes,
1604
+ initialEdges: edges,
1605
+ initialViewport: controlledViewport ?? defaultViewport
1606
+ })
1607
+ )[0];
1608
+ const handleRegistry = useState2(() => createHandleRegistry())[0];
1609
+ const [handleVersion, setHandleVersion] = useState2(0);
1610
+ useEffect4(() => {
1611
+ const unsub = handleRegistry.subscribe(() => {
1612
+ setHandleVersion((v) => v + 1);
1613
+ });
1614
+ return unsub;
1615
+ }, [handleRegistry]);
1616
+ const kinds = useMemo2(() => buildNodeKindRegistry(DEFAULT_NODE_KINDS, nodeKinds), [nodeKinds]);
1617
+ const containerRef = useRef4(null);
1618
+ useEffect4(() => store.setNodes(nodes), [store, nodes]);
1619
+ useEffect4(() => store.setEdges(edges), [store, edges]);
1620
+ const [uncontrolledVp, setUncontrolledVp] = useState2(controlledViewport ?? defaultViewport);
1621
+ const viewport = controlledViewport ?? uncontrolledVp;
1622
+ useEffect4(() => store.setViewport(viewport), [store, viewport]);
1623
+ const setViewport = useCallback(
1624
+ (next) => {
1625
+ if (controlledViewport === void 0) setUncontrolledVp(next);
1626
+ onViewportChange?.(next);
1627
+ },
1628
+ [controlledViewport, onViewportChange]
1629
+ );
1630
+ const selectedNodeIds = useMemo2(() => {
1631
+ const s = /* @__PURE__ */ new Set();
1632
+ for (const n of nodes) if (n.selected) s.add(n.id);
1633
+ return s;
1634
+ }, [nodes]);
1635
+ const selectedEdgeIds = useMemo2(() => {
1636
+ const s = /* @__PURE__ */ new Set();
1637
+ for (const e of edges) if (e.selected) s.add(e.id);
1638
+ return s;
1639
+ }, [edges]);
1640
+ useEffect4(() => {
1641
+ store.setSelection(selectedNodeIds, selectedEdgeIds);
1642
+ if (onSelectionChange) {
1643
+ onSelectionChange({
1644
+ nodes: nodes.filter((n) => selectedNodeIds.has(n.id)),
1645
+ edges: edges.filter((e) => selectedEdgeIds.has(e.id))
1646
+ });
1647
+ }
1648
+ }, [store, selectedNodeIds, selectedEdgeIds, nodes, edges, onSelectionChange]);
1649
+ const selectNode = useCallback(
1650
+ (id, additive) => {
1651
+ const next = [];
1652
+ const nextEdges = [];
1653
+ if (!additive) {
1654
+ for (const n of nodes) {
1655
+ if (n.selected && n.id !== id) next.push(change.node.select(n.id, false));
1656
+ }
1657
+ for (const e of edges) {
1658
+ if (e.selected) nextEdges.push(change.edge.select(e.id, false));
1659
+ }
1660
+ }
1661
+ const isSelected = selectedNodeIds.has(id);
1662
+ if (additive && isSelected) {
1663
+ next.push(change.node.select(id, false));
1664
+ } else if (!isSelected) {
1665
+ next.push(change.node.select(id, true));
1666
+ }
1667
+ if (next.length) onNodesChange?.(next);
1668
+ if (nextEdges.length) onEdgesChange?.(nextEdges);
1669
+ },
1670
+ [nodes, edges, selectedNodeIds, onNodesChange, onEdgesChange]
1671
+ );
1672
+ const notifyNodeClick = useCallback(
1673
+ (id) => {
1674
+ const node = nodes.find((n) => n.id === id);
1675
+ if (node) onNodeClick?.(node);
1676
+ },
1677
+ [nodes, onNodeClick]
1678
+ );
1679
+ const selectEdge = useCallback(
1680
+ (id, additive) => {
1681
+ const next = [];
1682
+ const nextNodes = [];
1683
+ if (!additive) {
1684
+ for (const e of edges) {
1685
+ if (e.selected && e.id !== id) next.push(change.edge.select(e.id, false));
1686
+ }
1687
+ for (const n of nodes) {
1688
+ if (n.selected) nextNodes.push(change.node.select(n.id, false));
1689
+ }
1690
+ }
1691
+ const isSelected = selectedEdgeIds.has(id);
1692
+ if (additive && isSelected) {
1693
+ next.push(change.edge.select(id, false));
1694
+ } else if (!isSelected) {
1695
+ next.push(change.edge.select(id, true));
1696
+ }
1697
+ if (next.length) onEdgesChange?.(next);
1698
+ if (nextNodes.length) onNodesChange?.(nextNodes);
1699
+ const edge = edges.find((e) => e.id === id);
1700
+ if (edge) onEdgeClick?.(edge);
1701
+ },
1702
+ [nodes, edges, selectedEdgeIds, onEdgesChange, onNodesChange, onEdgeClick]
1703
+ );
1704
+ const clearSelection = useCallback(() => {
1705
+ const ns = [];
1706
+ const es = [];
1707
+ for (const n of nodes) if (n.selected) ns.push(change.node.select(n.id, false));
1708
+ for (const e of edges) if (e.selected) es.push(change.edge.select(e.id, false));
1709
+ if (ns.length) onNodesChange?.(ns);
1710
+ if (es.length) onEdgesChange?.(es);
1711
+ }, [nodes, edges, onNodesChange, onEdgesChange]);
1712
+ const dragRef = useRef4(null);
1713
+ const [draggingId, setDraggingId] = useState2(null);
1714
+ const beginNodeDrag = useCallback(
1715
+ (nodeId, pointerId, clientX, clientY, altKey = false) => {
1716
+ if (!nodesDraggable) return;
1717
+ const node = nodes.find((n) => n.id === nodeId);
1718
+ if (!node) return;
1719
+ const kids = descendantsOf(nodeId, nodes).map((d) => ({
1720
+ id: d.id,
1721
+ startPosition: d.position
1722
+ }));
1723
+ dragRef.current = {
1724
+ pointerId,
1725
+ nodeId,
1726
+ startClientX: clientX,
1727
+ startClientY: clientY,
1728
+ startPosition: node.position,
1729
+ descendants: kids,
1730
+ altDetach: altKey && !!node.parentId,
1731
+ rafScheduled: false,
1732
+ nextDelta: null
1733
+ };
1734
+ setDraggingId(nodeId);
1735
+ selectNode(nodeId, false);
1736
+ },
1737
+ [nodes, nodesDraggable, selectNode]
1738
+ );
1739
+ const [conn, setConn] = useState2(null);
1740
+ const connRef = useRef4(null);
1741
+ useEffect4(() => {
1742
+ connRef.current = conn;
1743
+ }, [conn]);
1744
+ const beginConnection = useCallback(
1745
+ (nodeId, handleId, handleType, pointerId, clientX, clientY) => {
1746
+ if (!nodesConnectable) return;
1747
+ const node = nodes.find((n) => n.id === nodeId);
1748
+ if (!node) return;
1749
+ const desc = handleRegistry.resolve(nodeId, handleType, handleId);
1750
+ const side = desc?.side ?? (handleType === "source" ? "bottom" : "top");
1751
+ const index = desc?.index ?? 0;
1752
+ const total = desc?.total ?? 1;
1753
+ const ratio = (index + 1) / (total + 1);
1754
+ const w = node.width ?? 368;
1755
+ const h = effectiveHeight(node);
1756
+ const start = (() => {
1757
+ switch (side) {
1758
+ case "top":
1759
+ return { x: node.position.x + w * ratio, y: node.position.y };
1760
+ case "bottom":
1761
+ return { x: node.position.x + w * ratio, y: node.position.y + h };
1762
+ case "left":
1763
+ return { x: node.position.x, y: node.position.y + h * ratio };
1764
+ case "right":
1765
+ return { x: node.position.x + w, y: node.position.y + h * ratio };
1766
+ }
1767
+ })();
1768
+ const from = { nodeId, handleId, handleType };
1769
+ const rect = containerRef.current?.getBoundingClientRect();
1770
+ const end = rect ? screenToFlow({ x: clientX - rect.left, y: clientY - rect.top }, viewport) : start;
1771
+ setConn({ pointerId, from, start, end });
1772
+ store.setConnection(from);
1773
+ onConnectStart?.({ clientX, clientY, pointerId }, from);
1774
+ },
1775
+ [nodes, nodesConnectable, handleRegistry, viewport, store, onConnectStart]
1776
+ );
1777
+ const viewportRef = useRef4(viewport);
1778
+ const nodesRef = useRef4(nodes);
1779
+ const edgesRef = useRef4(edges);
1780
+ const onNodesChangeRefForInstance = useRef4(onNodesChange);
1781
+ const onEdgesChangeRefForInstance = useRef4(onEdgesChange);
1782
+ const onBeforeDeleteRef = useRef4(onBeforeDelete);
1783
+ const snapToGridRef = useRef4(snapToGrid);
1784
+ const gridSizeRef = useRef4(gridSize);
1785
+ const nodeCollisionGapRef = useRef4(nodeCollisionGap);
1786
+ const subflowCollisionGapRef = useRef4(subflowCollisionGap ?? nodeCollisionGap);
1787
+ useEffect4(() => {
1788
+ edgesRef.current = edges;
1789
+ }, [edges]);
1790
+ useEffect4(() => {
1791
+ onNodesChangeRefForInstance.current = onNodesChange;
1792
+ }, [onNodesChange]);
1793
+ useEffect4(() => {
1794
+ onEdgesChangeRefForInstance.current = onEdgesChange;
1795
+ }, [onEdgesChange]);
1796
+ useEffect4(() => {
1797
+ onBeforeDeleteRef.current = onBeforeDelete;
1798
+ }, [onBeforeDelete]);
1799
+ useEffect4(() => {
1800
+ snapToGridRef.current = snapToGrid;
1801
+ }, [snapToGrid]);
1802
+ useEffect4(() => {
1803
+ gridSizeRef.current = gridSize;
1804
+ }, [gridSize]);
1805
+ useEffect4(() => {
1806
+ nodeCollisionGapRef.current = nodeCollisionGap;
1807
+ }, [nodeCollisionGap]);
1808
+ useEffect4(() => {
1809
+ subflowCollisionGapRef.current = subflowCollisionGap ?? nodeCollisionGap;
1810
+ }, [subflowCollisionGap, nodeCollisionGap]);
1811
+ const onNodesChangeRef = useRef4(onNodesChange);
1812
+ const onConnectRef = useRef4(onConnect);
1813
+ const onConnectEndRef = useRef4(onConnectEnd);
1814
+ const isValidConnectionRef = useRef4(isValidConnection);
1815
+ useEffect4(() => {
1816
+ viewportRef.current = viewport;
1817
+ }, [viewport]);
1818
+ useEffect4(() => {
1819
+ nodesRef.current = nodes;
1820
+ }, [nodes]);
1821
+ useEffect4(() => {
1822
+ onNodesChangeRef.current = onNodesChange;
1823
+ }, [onNodesChange]);
1824
+ useEffect4(() => {
1825
+ onConnectRef.current = onConnect;
1826
+ }, [onConnect]);
1827
+ useEffect4(() => {
1828
+ onConnectEndRef.current = onConnectEnd;
1829
+ }, [onConnectEnd]);
1830
+ useEffect4(() => {
1831
+ isValidConnectionRef.current = isValidConnection;
1832
+ }, [isValidConnection]);
1833
+ useEffect4(() => {
1834
+ const onPointerMove = (e) => {
1835
+ const vp = viewportRef.current;
1836
+ const drag = dragRef.current;
1837
+ if (drag && drag.pointerId === e.pointerId) {
1838
+ const dx = (e.clientX - drag.startClientX) / vp.zoom;
1839
+ const dy = (e.clientY - drag.startClientY) / vp.zoom;
1840
+ drag.nextDelta = { dx, dy };
1841
+ if (!drag.rafScheduled) {
1842
+ drag.rafScheduled = true;
1843
+ requestAnimationFrame(() => {
1844
+ const d = dragRef.current;
1845
+ if (!d) return;
1846
+ d.rafScheduled = false;
1847
+ const delta = d.nextDelta;
1848
+ if (!delta) return;
1849
+ const dragNode = nodesRef.current.find((n) => n.id === d.nodeId);
1850
+ if (!dragNode) return;
1851
+ const proposed = {
1852
+ x: d.startPosition.x + delta.dx,
1853
+ y: d.startPosition.y + delta.dy
1854
+ };
1855
+ const clamped = d.altDetach ? proposed : clampToParentExtent(dragNode, proposed, nodesRef.current);
1856
+ const isContainer = dragNode.type === "group" || dragNode.type === "forEach";
1857
+ const gap = isContainer ? subflowCollisionGapRef.current : nodeCollisionGapRef.current;
1858
+ const excludeIds = /* @__PURE__ */ new Set([d.nodeId, ...d.descendants.map((kid) => kid.id)]);
1859
+ const finalPos = resolveNodeCollisions(dragNode, clamped, nodesRef.current, {
1860
+ gap,
1861
+ exclude: excludeIds
1862
+ });
1863
+ const realDx = finalPos.x - d.startPosition.x;
1864
+ const realDy = finalPos.y - d.startPosition.y;
1865
+ const changes = [change.node.position(d.nodeId, finalPos, true)];
1866
+ for (const kid of d.descendants) {
1867
+ changes.push(
1868
+ change.node.position(
1869
+ kid.id,
1870
+ { x: kid.startPosition.x + realDx, y: kid.startPosition.y + realDy },
1871
+ true
1872
+ )
1873
+ );
1874
+ }
1875
+ onNodesChangeRef.current?.(changes);
1876
+ });
1877
+ }
1878
+ }
1879
+ const c = connRef.current;
1880
+ if (c && c.pointerId === e.pointerId) {
1881
+ const rect = containerRef.current?.getBoundingClientRect();
1882
+ if (rect) {
1883
+ const end = screenToFlow({ x: e.clientX - rect.left, y: e.clientY - rect.top }, vp);
1884
+ setConn({ ...c, end });
1885
+ }
1886
+ }
1887
+ };
1888
+ const onPointerUp = (e) => {
1889
+ const vp = viewportRef.current;
1890
+ const drag = dragRef.current;
1891
+ if (drag && drag.pointerId === e.pointerId) {
1892
+ const dx = (e.clientX - drag.startClientX) / vp.zoom;
1893
+ const dy = (e.clientY - drag.startClientY) / vp.zoom;
1894
+ const dragNode = nodesRef.current.find((n) => n.id === drag.nodeId);
1895
+ if (dragNode) {
1896
+ let proposed = {
1897
+ x: drag.startPosition.x + dx,
1898
+ y: drag.startPosition.y + dy
1899
+ };
1900
+ if (snapToGridRef.current) {
1901
+ const g = gridSizeRef.current;
1902
+ proposed = {
1903
+ x: Math.round(proposed.x / g) * g,
1904
+ y: Math.round(proposed.y / g) * g
1905
+ };
1906
+ }
1907
+ const clamped = drag.altDetach ? proposed : clampToParentExtent(dragNode, proposed, nodesRef.current);
1908
+ const isContainer = dragNode.type === "group" || dragNode.type === "forEach";
1909
+ const gap = isContainer ? subflowCollisionGapRef.current : nodeCollisionGapRef.current;
1910
+ const excludeIds = /* @__PURE__ */ new Set([
1911
+ drag.nodeId,
1912
+ ...drag.descendants.map((kid) => kid.id)
1913
+ ]);
1914
+ const finalPos = resolveNodeCollisions(dragNode, clamped, nodesRef.current, {
1915
+ gap,
1916
+ exclude: excludeIds
1917
+ });
1918
+ const realDx = finalPos.x - drag.startPosition.x;
1919
+ const realDy = finalPos.y - drag.startPosition.y;
1920
+ const changes = [change.node.position(drag.nodeId, finalPos, false)];
1921
+ for (const kid of drag.descendants) {
1922
+ changes.push(
1923
+ change.node.position(
1924
+ kid.id,
1925
+ { x: kid.startPosition.x + realDx, y: kid.startPosition.y + realDy },
1926
+ false
1927
+ )
1928
+ );
1929
+ }
1930
+ if (drag.altDetach && dragNode.parentId) {
1931
+ const targetGroup = findContainingGroup(
1932
+ {
1933
+ x: finalPos.x + (dragNode.width ?? 0) / 2,
1934
+ y: finalPos.y + (dragNode.height ?? 0) / 2
1935
+ },
1936
+ nodesRef.current,
1937
+ [drag.nodeId, ...drag.descendants.map((d) => d.id)]
1938
+ );
1939
+ const nextParentId = targetGroup?.id;
1940
+ const updated = {
1941
+ ...dragNode,
1942
+ position: finalPos,
1943
+ parentId: nextParentId,
1944
+ // Preserve extent only when staying in a group.
1945
+ extent: nextParentId ? dragNode.extent : void 0
1946
+ };
1947
+ changes.push(change.node.replace(drag.nodeId, updated));
1948
+ }
1949
+ onNodesChangeRef.current?.(changes);
1950
+ }
1951
+ dragRef.current = null;
1952
+ setDraggingId(null);
1953
+ }
1954
+ const c = connRef.current;
1955
+ if (c && c.pointerId === e.pointerId) {
1956
+ const target = e.target;
1957
+ const handleEl = target?.closest("[data-handle-id]");
1958
+ let connection = null;
1959
+ let connectedTo;
1960
+ if (handleEl) {
1961
+ const targetNodeId = handleEl.dataset.handleNodeId;
1962
+ const targetHandleId = handleEl.dataset.handleId;
1963
+ const targetType = handleEl.dataset.handleType;
1964
+ const connectableEnd = handleEl.dataset.handleConnectableEnd === "true";
1965
+ if (connectableEnd && (targetNodeId !== c.from.nodeId || targetHandleId !== c.from.handleId) && targetType !== c.from.handleType) {
1966
+ const source = c.from.handleType === "source" ? c.from : { nodeId: targetNodeId, handleId: targetHandleId, handleType: "source" };
1967
+ const target2 = c.from.handleType === "target" ? c.from : { nodeId: targetNodeId, handleId: targetHandleId, handleType: "target" };
1968
+ connection = {
1969
+ source: source.nodeId,
1970
+ sourceHandle: source.handleId,
1971
+ target: target2.nodeId,
1972
+ targetHandle: target2.handleId
1973
+ };
1974
+ connectedTo = {
1975
+ nodeId: targetNodeId,
1976
+ handleId: targetHandleId,
1977
+ handleType: targetType
1978
+ };
1979
+ const validator = isValidConnectionRef.current;
1980
+ if (validator && !validator(connection)) {
1981
+ connection = null;
1982
+ connectedTo = void 0;
1983
+ }
1984
+ }
1985
+ }
1986
+ const rect = containerRef.current?.getBoundingClientRect();
1987
+ const flowPos = rect ? screenToFlow({ x: e.clientX - rect.left, y: e.clientY - rect.top }, vp) : { x: 0, y: 0 };
1988
+ const endState = {
1989
+ cancelled: !connection,
1990
+ position: { x: e.clientX, y: e.clientY },
1991
+ flowPosition: flowPos,
1992
+ from: c.from,
1993
+ to: connectedTo
1994
+ };
1995
+ if (connection) onConnectRef.current?.(connection);
1996
+ onConnectEndRef.current?.(e, endState);
1997
+ setConn(null);
1998
+ store.setConnection(null);
1999
+ }
2000
+ };
2001
+ const onPointerCancel = () => {
2002
+ if (dragRef.current) {
2003
+ dragRef.current = null;
2004
+ setDraggingId(null);
2005
+ }
2006
+ if (connRef.current) {
2007
+ setConn(null);
2008
+ store.setConnection(null);
2009
+ }
2010
+ };
2011
+ window.addEventListener("pointermove", onPointerMove);
2012
+ window.addEventListener("pointerup", onPointerUp);
2013
+ window.addEventListener("pointercancel", onPointerCancel);
2014
+ return () => {
2015
+ window.removeEventListener("pointermove", onPointerMove);
2016
+ window.removeEventListener("pointerup", onPointerUp);
2017
+ window.removeEventListener("pointercancel", onPointerCancel);
2018
+ };
2019
+ }, [store]);
2020
+ const panRef = useRef4(null);
2021
+ const onCanvasPointerDown = (e) => {
2022
+ if (e.button !== 0) return;
2023
+ const t = e.target;
2024
+ if (t.closest("[data-node-id]") || t.closest("[data-edge-id]") || t.closest("[data-handle-id]")) {
2025
+ return;
2026
+ }
2027
+ if (!panOnDrag) {
2028
+ panRef.current = {
2029
+ pointerId: e.pointerId,
2030
+ startClientX: e.clientX,
2031
+ startClientY: e.clientY,
2032
+ startVp: viewport,
2033
+ moved: false
2034
+ };
2035
+ return;
2036
+ }
2037
+ panRef.current = {
2038
+ pointerId: e.pointerId,
2039
+ startClientX: e.clientX,
2040
+ startClientY: e.clientY,
2041
+ startVp: viewport,
2042
+ moved: false
2043
+ };
2044
+ };
2045
+ useEffect4(() => {
2046
+ const onMove = (e) => {
2047
+ const pan = panRef.current;
2048
+ if (!pan || pan.pointerId !== e.pointerId) return;
2049
+ const dx = e.clientX - pan.startClientX;
2050
+ const dy = e.clientY - pan.startClientY;
2051
+ if (Math.abs(dx) > paneClickDistance || Math.abs(dy) > paneClickDistance) {
2052
+ if (!pan.moved) setPanGesture(true);
2053
+ pan.moved = true;
2054
+ }
2055
+ if (pan.moved && panOnDrag) {
2056
+ setViewport({ ...pan.startVp, x: pan.startVp.x + dx, y: pan.startVp.y + dy });
2057
+ }
2058
+ };
2059
+ const onUp = () => {
2060
+ const pan = panRef.current;
2061
+ if (!pan) return;
2062
+ if (!pan.moved) {
2063
+ onPaneClick?.();
2064
+ if (paneClickClearsSelection) clearSelection();
2065
+ }
2066
+ panRef.current = null;
2067
+ setPanGesture(false);
2068
+ };
2069
+ window.addEventListener("pointermove", onMove);
2070
+ window.addEventListener("pointerup", onUp);
2071
+ window.addEventListener("pointercancel", onUp);
2072
+ return () => {
2073
+ window.removeEventListener("pointermove", onMove);
2074
+ window.removeEventListener("pointerup", onUp);
2075
+ window.removeEventListener("pointercancel", onUp);
2076
+ };
2077
+ }, [
2078
+ setViewport,
2079
+ paneClickDistance,
2080
+ panOnDrag,
2081
+ onPaneClick,
2082
+ clearSelection,
2083
+ paneClickClearsSelection
2084
+ ]);
2085
+ const handleWheel = (e) => {
2086
+ if (!zoomOnScroll) return;
2087
+ e.preventDefault();
2088
+ const rect = containerRef.current?.getBoundingClientRect();
2089
+ if (!rect) return;
2090
+ const px = e.clientX - rect.left;
2091
+ const py = e.clientY - rect.top;
2092
+ const factor = Math.exp(-e.deltaY * 1e-3);
2093
+ const nextZoom = Math.max(minZoom, Math.min(maxZoom, viewport.zoom * factor));
2094
+ const k = nextZoom / viewport.zoom;
2095
+ setViewport({
2096
+ zoom: nextZoom,
2097
+ x: px - (px - viewport.x) * k,
2098
+ y: py - (py - viewport.y) * k
2099
+ });
2100
+ };
2101
+ const dispatch = useCallback(
2102
+ (a) => {
2103
+ if (a.type === "connection/start") {
2104
+ beginConnection(a.nodeId, a.handleId, a.handleType, a.pointerId, a.clientX, a.clientY);
2105
+ }
2106
+ },
2107
+ [beginConnection]
2108
+ );
2109
+ const reportDimensions = useCallback(
2110
+ (nodeId, width2, height2) => {
2111
+ const node = nodes.find((n) => n.id === nodeId);
2112
+ if (!node) return;
2113
+ if (node.width === width2 && node.height === height2) return;
2114
+ onNodesChange?.([change.node.dimensions(nodeId, { width: width2, height: height2 })]);
2115
+ },
2116
+ [nodes, onNodesChange]
2117
+ );
2118
+ const toggleNodeCollapseImpl = useCallback(
2119
+ (nodeId) => {
2120
+ const node = nodes.find((n) => n.id === nodeId);
2121
+ if (!node) return;
2122
+ const prevData = node.data ?? {};
2123
+ const nextNode = {
2124
+ ...node,
2125
+ data: { ...prevData, collapsed: !prevData.collapsed }
2126
+ };
2127
+ onNodesChange?.([change.node.replace(nodeId, nextNode)]);
2128
+ },
2129
+ [nodes, onNodesChange]
2130
+ );
2131
+ const deleteNodeImpl = useCallback(
2132
+ (nodeId) => {
2133
+ const incidentEdgeIds = edgesRef.current.filter((e) => e.source === nodeId || e.target === nodeId).map((e) => e.id);
2134
+ if (incidentEdgeIds.length > 0) {
2135
+ onEdgesChange?.(incidentEdgeIds.map((id) => change.edge.remove(id)));
2136
+ }
2137
+ onNodesChange?.([change.node.remove(nodeId)]);
2138
+ },
2139
+ [onNodesChange, onEdgesChange]
2140
+ );
2141
+ const instance = useMemo2(
2142
+ () => ({
2143
+ // viewport
2144
+ getViewport: () => viewportRef.current,
2145
+ setViewport: (vp) => setViewport(vp),
2146
+ setCenter: (x, y, opts) => {
2147
+ const z = opts?.zoom ?? viewportRef.current.zoom;
2148
+ const rect = containerRef.current?.getBoundingClientRect();
2149
+ if (!rect) return;
2150
+ setViewport({
2151
+ zoom: z,
2152
+ x: rect.width / 2 - x * z,
2153
+ y: rect.height / 2 - y * z
2154
+ });
2155
+ },
2156
+ fitView: async (opts) => {
2157
+ const rect = containerRef.current?.getBoundingClientRect();
2158
+ if (!rect) return false;
2159
+ const padding = opts?.padding ?? 80;
2160
+ const targetNodes = opts?.nodes ? nodesRef.current.filter((n) => opts.nodes.some((x) => x.id === n.id)) : nodesRef.current.filter((n) => !n.hidden);
2161
+ if (targetNodes.length === 0) return false;
2162
+ let minX = Number.POSITIVE_INFINITY;
2163
+ let minY = Number.POSITIVE_INFINITY;
2164
+ let maxX = Number.NEGATIVE_INFINITY;
2165
+ let maxY = Number.NEGATIVE_INFINITY;
2166
+ for (const n of targetNodes) {
2167
+ const w = n.width ?? DEFAULT_NODE_WIDTH;
2168
+ const h = effectiveHeight(n);
2169
+ if (n.position.x < minX) minX = n.position.x;
2170
+ if (n.position.y < minY) minY = n.position.y;
2171
+ if (n.position.x + w > maxX) maxX = n.position.x + w;
2172
+ if (n.position.y + h > maxY) maxY = n.position.y + h;
2173
+ }
2174
+ const cw = maxX - minX;
2175
+ const ch = maxY - minY;
2176
+ const zx = (rect.width - padding * 2) / cw;
2177
+ const zy = (rect.height - padding * 2) / ch;
2178
+ const zoom = Math.max(
2179
+ opts?.minZoom ?? 0.25,
2180
+ Math.min(opts?.maxZoom ?? 1.5, Math.min(zx, zy))
2181
+ );
2182
+ setViewport({
2183
+ zoom,
2184
+ x: rect.width / 2 - (minX + maxX) / 2 * zoom,
2185
+ y: rect.height / 2 - (minY + maxY) / 2 * zoom
2186
+ });
2187
+ return true;
2188
+ },
2189
+ zoomIn: (opts) => {
2190
+ const step = opts?.step ?? 0.2;
2191
+ const next = Math.min(maxZoom, viewportRef.current.zoom * (1 + step));
2192
+ setViewport({ ...viewportRef.current, zoom: next });
2193
+ },
2194
+ zoomOut: (opts) => {
2195
+ const step = opts?.step ?? 0.2;
2196
+ const next = Math.max(minZoom, viewportRef.current.zoom / (1 + step));
2197
+ setViewport({ ...viewportRef.current, zoom: next });
2198
+ },
2199
+ zoomTo: (level) => {
2200
+ setViewport({
2201
+ ...viewportRef.current,
2202
+ zoom: Math.max(minZoom, Math.min(maxZoom, level))
2203
+ });
2204
+ },
2205
+ // transforms
2206
+ screenToFlowPosition: (p) => screenToFlow(p, viewportRef.current),
2207
+ flowToScreenPosition: (p) => flowToScreen(p, viewportRef.current),
2208
+ // reads
2209
+ getNodes: () => nodesRef.current.slice(),
2210
+ getEdges: () => edgesRef.current.slice(),
2211
+ getNode: (id) => nodesRef.current.find((n) => n.id === id),
2212
+ getEdge: (id) => edgesRef.current.find((e) => e.id === id),
2213
+ getNodesBounds: (subset) => {
2214
+ const pool = subset ? nodesRef.current.filter((n) => subset.some((x) => x.id === n.id)) : nodesRef.current.filter((n) => !n.hidden);
2215
+ if (pool.length === 0) return { x: 0, y: 0, width: 0, height: 0 };
2216
+ let minX = Number.POSITIVE_INFINITY;
2217
+ let minY = Number.POSITIVE_INFINITY;
2218
+ let maxX = Number.NEGATIVE_INFINITY;
2219
+ let maxY = Number.NEGATIVE_INFINITY;
2220
+ for (const n of pool) {
2221
+ const w = n.width ?? DEFAULT_NODE_WIDTH;
2222
+ const h = effectiveHeight(n);
2223
+ minX = Math.min(minX, n.position.x);
2224
+ minY = Math.min(minY, n.position.y);
2225
+ maxX = Math.max(maxX, n.position.x + w);
2226
+ maxY = Math.max(maxY, n.position.y + h);
2227
+ }
2228
+ return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
2229
+ },
2230
+ getIntersectingNodes: (area, partially = true) => {
2231
+ return nodesRef.current.filter((n) => {
2232
+ if (n.hidden) return false;
2233
+ const w = n.width ?? DEFAULT_NODE_WIDTH;
2234
+ const h = effectiveHeight(n);
2235
+ if (partially) {
2236
+ return n.position.x < area.x + area.width && n.position.x + w > area.x && n.position.y < area.y + area.height && n.position.y + h > area.y;
2237
+ }
2238
+ return n.position.x >= area.x && n.position.y >= area.y && n.position.x + w <= area.x + area.width && n.position.y + h <= area.y + area.height;
2239
+ });
2240
+ },
2241
+ // mutations
2242
+ addNodes: (nodes2) => {
2243
+ const arr = Array.isArray(nodes2) ? nodes2 : [nodes2];
2244
+ onNodesChangeRefForInstance.current?.(arr.map((item) => change.node.add(item)));
2245
+ },
2246
+ addEdges: (edges2) => {
2247
+ const arr = Array.isArray(edges2) ? edges2 : [edges2];
2248
+ onEdgesChangeRefForInstance.current?.(arr.map((item) => change.edge.add(item)));
2249
+ },
2250
+ updateNodeData: (id, partial) => {
2251
+ const cur = nodesRef.current.find((n) => n.id === id);
2252
+ if (!cur) return;
2253
+ const nextData = { ...cur.data ?? {}, ...partial };
2254
+ onNodesChangeRefForInstance.current?.([
2255
+ change.node.replace(id, { ...cur, data: nextData })
2256
+ ]);
2257
+ },
2258
+ updateNode: (id, partial) => {
2259
+ const cur = nodesRef.current.find((n) => n.id === id);
2260
+ if (!cur) return;
2261
+ onNodesChangeRefForInstance.current?.([change.node.replace(id, { ...cur, ...partial })]);
2262
+ },
2263
+ deleteElements: async ({ nodes: ns, edges: es }) => {
2264
+ const nodesToDelete = (ns ?? []).map((x) => nodesRef.current.find((n) => n.id === x.id)).filter((n) => !!n);
2265
+ const edgesToDelete = (es ?? []).map((x) => edgesRef.current.find((e) => e.id === x.id)).filter((e) => !!e);
2266
+ const before = onBeforeDeleteRef.current;
2267
+ if (before) {
2268
+ const ok = await before({ nodes: nodesToDelete, edges: edgesToDelete });
2269
+ if (!ok) return false;
2270
+ }
2271
+ if (nodesToDelete.length > 0) {
2272
+ onNodesChangeRefForInstance.current?.(nodesToDelete.map((n) => change.node.remove(n.id)));
2273
+ }
2274
+ if (edgesToDelete.length > 0) {
2275
+ onEdgesChangeRefForInstance.current?.(edgesToDelete.map((e) => change.edge.remove(e.id)));
2276
+ }
2277
+ return true;
2278
+ }
2279
+ }),
2280
+ [setViewport, minZoom, maxZoom]
2281
+ );
2282
+ const initFiredRef = useRef4(false);
2283
+ useEffect4(() => {
2284
+ if (initFiredRef.current) return;
2285
+ initFiredRef.current = true;
2286
+ onInit?.(instance);
2287
+ }, [instance, onInit]);
2288
+ useEffect4(() => {
2289
+ const onKey = (e) => {
2290
+ if (e.key !== "Backspace" && e.key !== "Delete") return;
2291
+ const target = e.target;
2292
+ if (target && (target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.tagName === "SELECT" || target.isContentEditable)) {
2293
+ return;
2294
+ }
2295
+ if (!containerRef.current?.contains(target) && document.activeElement !== document.body) {
2296
+ return;
2297
+ }
2298
+ const sel = store.getSnapshot();
2299
+ if (sel.selectedNodeIds.size === 0 && sel.selectedEdgeIds.size === 0) return;
2300
+ e.preventDefault();
2301
+ void instance.deleteElements({
2302
+ nodes: Array.from(sel.selectedNodeIds, (id) => ({ id })),
2303
+ edges: Array.from(sel.selectedEdgeIds, (id) => ({ id }))
2304
+ });
2305
+ };
2306
+ window.addEventListener("keydown", onKey);
2307
+ return () => window.removeEventListener("keydown", onKey);
2308
+ }, [instance, store]);
2309
+ const bridge = useMemo2(
2310
+ () => ({
2311
+ beginNodeDrag,
2312
+ selectNode,
2313
+ notifyNodeClick,
2314
+ selectEdge,
2315
+ reportDimensions,
2316
+ deleteNode: deleteNodeImpl,
2317
+ toggleNodeCollapse: toggleNodeCollapseImpl
2318
+ }),
2319
+ [
2320
+ beginNodeDrag,
2321
+ selectNode,
2322
+ notifyNodeClick,
2323
+ selectEdge,
2324
+ reportDimensions,
2325
+ deleteNodeImpl,
2326
+ toggleNodeCollapseImpl
2327
+ ]
2328
+ );
2329
+ const [panGesture, setPanGesture] = useState2(false);
2330
+ const isEmpty = nodes.length === 0 && edges.length === 0;
2331
+ const isConnecting = conn !== null;
2332
+ const visibleNodes = useMemo2(() => nodes.filter((n) => !n.hidden), [nodes]);
2333
+ const visibleEdges = useMemo2(() => {
2334
+ if (visibleNodes.length === nodes.length) return edges;
2335
+ const visibleIds = new Set(visibleNodes.map((n) => n.id));
2336
+ return edges.filter((e) => visibleIds.has(e.source) && visibleIds.has(e.target));
2337
+ }, [edges, nodes, visibleNodes]);
2338
+ const orderedNodes = useMemo2(() => {
2339
+ const isContainer = (n) => n.type === "group" || n.type === "forEach";
2340
+ const depth = (n) => {
2341
+ let d = 0;
2342
+ let cursor = n.parentId;
2343
+ const seen = /* @__PURE__ */ new Set();
2344
+ while (cursor) {
2345
+ if (seen.has(cursor)) return Number.POSITIVE_INFINITY;
2346
+ seen.add(cursor);
2347
+ d++;
2348
+ cursor = visibleNodes.find((x) => x.id === cursor)?.parentId;
2349
+ }
2350
+ return d;
2351
+ };
2352
+ const containers = visibleNodes.filter(isContainer);
2353
+ const others = visibleNodes.filter((n) => !isContainer(n));
2354
+ containers.sort((a, b) => depth(a) - depth(b));
2355
+ return [...containers, ...others];
2356
+ }, [visibleNodes]);
2357
+ return /* @__PURE__ */ jsx6(FlowStoreContext.Provider, { value: store, children: /* @__PURE__ */ jsx6(FlowInstanceContext.Provider, { value: instance, children: /* @__PURE__ */ jsx6(HandleRegistryContext.Provider, { value: handleRegistry, children: /* @__PURE__ */ jsx6(FlowDispatchContext.Provider, { value: dispatch, children: /* @__PURE__ */ jsx6(FlowNodeBridgeContext.Provider, { value: bridge, children: /* @__PURE__ */ jsxs5(
2358
+ "div",
2359
+ {
2360
+ ref: containerRef,
2361
+ className: cn(
2362
+ "ods-flow-canvas-v2",
2363
+ panGesture && "ods-flow-canvas-v2--panning",
2364
+ isConnecting && "ods-flow-canvas-v2--connecting",
2365
+ draggingId && "ods-flow-canvas-v2--dragging",
2366
+ className
2367
+ ),
2368
+ style: {
2369
+ position: "relative",
2370
+ width,
2371
+ height,
2372
+ overflow: "hidden",
2373
+ userSelect: "none",
2374
+ touchAction: "none",
2375
+ // Cursor: state-driven so it flips instantly with the
2376
+ // gesture. CSS `:active` would lag behind pointer-capture.
2377
+ cursor: panGesture ? "grabbing" : isConnecting ? "crosshair" : panOnDrag ? "grab" : "default",
2378
+ ...style
2379
+ },
2380
+ onPointerDown: onCanvasPointerDown,
2381
+ onWheel: handleWheel,
2382
+ onContextMenu: (e) => {
2383
+ const t = e.target;
2384
+ const nodeEl = t.closest("[data-node-id]");
2385
+ if (nodeEl && onNodeContextMenu) {
2386
+ const id = nodeEl.dataset.nodeId;
2387
+ const node = nodes.find((n) => n.id === id);
2388
+ if (node) onNodeContextMenu(e, node);
2389
+ return;
2390
+ }
2391
+ const edgeEl = t.closest("[data-edge-id]");
2392
+ if (edgeEl && onEdgeContextMenu) {
2393
+ const id = edgeEl.dataset.edgeId;
2394
+ const edge = edges.find((x) => x.id === id);
2395
+ if (edge) onEdgeContextMenu(e, edge);
2396
+ return;
2397
+ }
2398
+ onPaneContextMenu?.(e);
2399
+ },
2400
+ "data-empty": isEmpty ? "true" : void 0,
2401
+ children: [
2402
+ background !== "none" && /* @__PURE__ */ jsx6(
2403
+ "div",
2404
+ {
2405
+ className: cn(
2406
+ "ods-flow-canvas-v2__grid",
2407
+ `ods-flow-canvas-v2__grid--${background}`
2408
+ ),
2409
+ style: {
2410
+ // Custom property drives the four variants' SCSS.
2411
+ "--ods-flow-grid-size": `${gridSize * viewport.zoom}px`,
2412
+ backgroundPosition: `${viewport.x}px ${viewport.y}px`
2413
+ }
2414
+ }
2415
+ ),
2416
+ /* @__PURE__ */ jsxs5(
2417
+ "div",
2418
+ {
2419
+ className: "ods-flow-canvas-v2__viewport",
2420
+ style: {
2421
+ position: "absolute",
2422
+ inset: 0,
2423
+ transform: `translate(${viewport.x}px, ${viewport.y}px) scale(${viewport.zoom})`,
2424
+ transformOrigin: "0 0"
2425
+ },
2426
+ children: [
2427
+ /* @__PURE__ */ jsx6(
2428
+ EdgesLayer,
2429
+ {
2430
+ edges: visibleEdges,
2431
+ nodes: visibleNodes,
2432
+ onSelect: (id) => bridge.selectEdge(id, false),
2433
+ onDelete: (id) => onEdgesChangeRef(id, onEdgesChange),
2434
+ onLabelChange: onEdgeLabelChange,
2435
+ ghost: conn ? { start: conn.start, end: conn.end } : null,
2436
+ handleVersion
2437
+ }
2438
+ ),
2439
+ orderedNodes.map((node) => {
2440
+ const Kind = kinds[node.type] ?? kinds.action;
2441
+ if (!Kind) return null;
2442
+ return /* @__PURE__ */ jsx6(
2443
+ FlowNode,
2444
+ {
2445
+ node,
2446
+ selected: selectedNodeIds.has(node.id),
2447
+ dragging: draggingId === node.id,
2448
+ isConnecting,
2449
+ Kind
2450
+ },
2451
+ node.id
2452
+ );
2453
+ })
2454
+ ]
2455
+ }
2456
+ ),
2457
+ isEmpty && emptyState && /* @__PURE__ */ jsx6("div", { className: "ods-flow-canvas-v2__empty", children: emptyState }),
2458
+ children
2459
+ ]
2460
+ }
2461
+ ) }) }) }) }) });
2462
+ }
2463
+ function onEdgesChangeRef(id, cb) {
2464
+ cb?.([change.edge.remove(id)]);
2465
+ }
2466
+ var EdgesLayer = memo2(function EdgesLayer2({
2467
+ edges,
2468
+ nodes,
2469
+ onSelect,
2470
+ onDelete,
2471
+ onLabelChange,
2472
+ ghost,
2473
+ handleVersion: _handleVersion
2474
+ }) {
2475
+ return /* @__PURE__ */ jsxs5(
2476
+ "svg",
2477
+ {
2478
+ className: "ods-flow-canvas-v2__edges",
2479
+ style: { position: "absolute", inset: 0, overflow: "visible", pointerEvents: "none" },
2480
+ width: "100%",
2481
+ height: "100%",
2482
+ children: [
2483
+ /* @__PURE__ */ jsx6("g", { style: { pointerEvents: "auto" }, children: edges.map((edge) => /* @__PURE__ */ jsx6(
2484
+ FlowEdge,
2485
+ {
2486
+ edge,
2487
+ nodes,
2488
+ onSelect,
2489
+ onDelete,
2490
+ onLabelChange,
2491
+ handleVersion: _handleVersion
2492
+ },
2493
+ edge.id
2494
+ )) }),
2495
+ ghost && /* @__PURE__ */ jsx6(
2496
+ "path",
2497
+ {
2498
+ d: `M ${ghost.start.x} ${ghost.start.y} L ${ghost.end.x} ${ghost.end.y}`,
2499
+ stroke: "var(--ods-accent, #4f46e5)",
2500
+ strokeWidth: 1.5,
2501
+ strokeDasharray: "4 4",
2502
+ fill: "none"
2503
+ }
2504
+ )
2505
+ ]
2506
+ }
2507
+ );
2508
+ });
2509
+
2510
+ export {
2511
+ buildEdgePath,
2512
+ bezierPath,
2513
+ stepPath,
2514
+ smoothStepPath,
2515
+ straightPath,
2516
+ useFlow,
2517
+ applyNodeChanges,
2518
+ applyEdgeChanges,
2519
+ change,
2520
+ useFlowStore,
2521
+ DEFAULT_NODE_WIDTH,
2522
+ DEFAULT_NODE_HEIGHT,
2523
+ handleCentre,
2524
+ bezierPath2,
2525
+ screenToFlow,
2526
+ flowToScreen,
2527
+ descendantsOf,
2528
+ findAncestor,
2529
+ clampToParentExtent,
2530
+ findContainingGroup,
2531
+ FlowEdge,
2532
+ useFlowNodeContext,
2533
+ FlowNode,
2534
+ buildNodeKindRegistry,
2535
+ Handle,
2536
+ ActionNode,
2537
+ TriggerNode,
2538
+ ConditionNode,
2539
+ GroupNode,
2540
+ ForEachNode,
2541
+ OutputNode,
2542
+ ErrorNode,
2543
+ WaitNode,
2544
+ ParallelNode,
2545
+ StickyNode,
2546
+ WebhookNode,
2547
+ HttpRequestNode,
2548
+ DEFAULT_NODE_KINDS,
2549
+ FlowCanvas
2550
+ };
2551
+ //# sourceMappingURL=chunk-TTKIDRN7.js.map