@octaviaflow/core 3.0.18-beta.0 → 3.0.18-beta.10

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