@flowdrop/flowdrop 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (388) hide show
  1. package/README.md +50 -50
  2. package/dist/adapters/WorkflowAdapter.d.ts +1 -1
  3. package/dist/adapters/WorkflowAdapter.js +25 -25
  4. package/dist/adapters/agentspec/AgentSpecAdapter.d.ts +2 -2
  5. package/dist/adapters/agentspec/AgentSpecAdapter.js +133 -122
  6. package/dist/adapters/agentspec/agentAdapter.d.ts +2 -2
  7. package/dist/adapters/agentspec/agentAdapter.js +10 -10
  8. package/dist/adapters/agentspec/autoLayout.d.ts +1 -1
  9. package/dist/adapters/agentspec/autoLayout.js +2 -2
  10. package/dist/adapters/agentspec/componentTypeDefaults.d.ts +1 -1
  11. package/dist/adapters/agentspec/componentTypeDefaults.js +120 -120
  12. package/dist/adapters/agentspec/defaultNodeTypes.d.ts +2 -2
  13. package/dist/adapters/agentspec/defaultNodeTypes.js +307 -307
  14. package/dist/adapters/agentspec/index.d.ts +10 -10
  15. package/dist/adapters/agentspec/index.js +6 -6
  16. package/dist/adapters/agentspec/validator.d.ts +2 -2
  17. package/dist/adapters/agentspec/validator.js +22 -20
  18. package/dist/api/enhanced-client.d.ts +3 -3
  19. package/dist/api/enhanced-client.js +73 -72
  20. package/dist/components/App.svelte +1081 -961
  21. package/dist/components/App.svelte.d.ts +9 -6
  22. package/dist/components/CanvasBanner.stories.svelte +23 -20
  23. package/dist/components/CanvasBanner.stories.svelte.d.ts +1 -1
  24. package/dist/components/CanvasBanner.svelte +46 -46
  25. package/dist/components/ConfigForm.svelte +1164 -1065
  26. package/dist/components/ConfigForm.svelte.d.ts +2 -2
  27. package/dist/components/ConfigModal.svelte +180 -180
  28. package/dist/components/ConfigModal.svelte.d.ts +1 -1
  29. package/dist/components/ConfigPanel.stories.svelte +35 -35
  30. package/dist/components/ConfigPanel.stories.svelte.d.ts +1 -1
  31. package/dist/components/ConfigPanel.svelte +178 -167
  32. package/dist/components/ConfigPanel.svelte.d.ts +1 -1
  33. package/dist/components/ConnectionLine.svelte +25 -25
  34. package/dist/components/EdgeRefresher.svelte +26 -26
  35. package/dist/components/FlowDropEdge.stories.svelte +197 -0
  36. package/dist/components/FlowDropEdge.stories.svelte.d.ts +26 -0
  37. package/dist/components/FlowDropEdge.svelte +168 -0
  38. package/dist/components/FlowDropEdge.svelte.d.ts +4 -0
  39. package/dist/components/FlowDropZone.svelte +63 -60
  40. package/dist/components/FlowDropZone.svelte.d.ts +1 -1
  41. package/dist/components/LoadingSpinner.stories.svelte +19 -19
  42. package/dist/components/LoadingSpinner.stories.svelte.d.ts +1 -1
  43. package/dist/components/LoadingSpinner.svelte +21 -21
  44. package/dist/components/LoadingSpinner.svelte.d.ts +1 -1
  45. package/dist/components/Logo.stories.svelte +13 -13
  46. package/dist/components/Logo.stories.svelte.d.ts +1 -1
  47. package/dist/components/Logo.svelte +101 -95
  48. package/dist/components/LogsSidebar.svelte +553 -546
  49. package/dist/components/LogsSidebar.svelte.d.ts +1 -1
  50. package/dist/components/MarkdownDisplay.stories.svelte +29 -23
  51. package/dist/components/MarkdownDisplay.stories.svelte.d.ts +1 -1
  52. package/dist/components/MarkdownDisplay.svelte +16 -14
  53. package/dist/components/Navbar.stories.svelte +43 -38
  54. package/dist/components/Navbar.stories.svelte.d.ts +1 -1
  55. package/dist/components/Navbar.svelte +760 -706
  56. package/dist/components/Navbar.svelte.d.ts +1 -1
  57. package/dist/components/NodeSidebar.svelte +900 -746
  58. package/dist/components/NodeSidebar.svelte.d.ts +3 -1
  59. package/dist/components/NodeStatusOverlay.stories.svelte +82 -70
  60. package/dist/components/NodeStatusOverlay.stories.svelte.d.ts +1 -1
  61. package/dist/components/NodeStatusOverlay.svelte +295 -280
  62. package/dist/components/NodeStatusOverlay.svelte.d.ts +3 -3
  63. package/dist/components/PipelineStatus.svelte +326 -300
  64. package/dist/components/PipelineStatus.svelte.d.ts +4 -4
  65. package/dist/components/PortCoordinateTracker.svelte +49 -47
  66. package/dist/components/PortCoordinateTracker.svelte.d.ts +1 -1
  67. package/dist/components/ReadOnlyDetails.svelte +156 -156
  68. package/dist/components/SchemaForm.stories.svelte +106 -98
  69. package/dist/components/SchemaForm.stories.svelte.d.ts +1 -1
  70. package/dist/components/SchemaForm.svelte +490 -463
  71. package/dist/components/SchemaForm.svelte.d.ts +2 -2
  72. package/dist/components/SettingsModal.svelte +226 -223
  73. package/dist/components/SettingsModal.svelte.d.ts +1 -1
  74. package/dist/components/SettingsPanel.svelte +637 -601
  75. package/dist/components/SettingsPanel.svelte.d.ts +1 -1
  76. package/dist/components/StatusIcon.stories.svelte +62 -49
  77. package/dist/components/StatusIcon.stories.svelte.d.ts +1 -1
  78. package/dist/components/StatusIcon.svelte +87 -87
  79. package/dist/components/StatusIcon.svelte.d.ts +2 -2
  80. package/dist/components/StatusLabel.stories.svelte +12 -12
  81. package/dist/components/StatusLabel.stories.svelte.d.ts +1 -1
  82. package/dist/components/StatusLabel.svelte +19 -19
  83. package/dist/components/ThemeToggle.stories.svelte +16 -16
  84. package/dist/components/ThemeToggle.stories.svelte.d.ts +1 -1
  85. package/dist/components/ThemeToggle.svelte +180 -169
  86. package/dist/components/ThemeToggle.svelte.d.ts +1 -1
  87. package/dist/components/UniversalNode.svelte +150 -138
  88. package/dist/components/UniversalNode.svelte.d.ts +3 -3
  89. package/dist/components/WorkflowEditor.svelte +1069 -1007
  90. package/dist/components/WorkflowEditor.svelte.d.ts +4 -4
  91. package/dist/components/form/FormArray.svelte +1034 -973
  92. package/dist/components/form/FormArray.svelte.d.ts +1 -1
  93. package/dist/components/form/FormAutocomplete.svelte +1021 -978
  94. package/dist/components/form/FormAutocomplete.svelte.d.ts +1 -1
  95. package/dist/components/form/FormCheckboxGroup.stories.svelte +23 -20
  96. package/dist/components/form/FormCheckboxGroup.stories.svelte.d.ts +1 -1
  97. package/dist/components/form/FormCheckboxGroup.svelte +136 -136
  98. package/dist/components/form/FormCodeEditor.svelte +452 -434
  99. package/dist/components/form/FormField.svelte +366 -355
  100. package/dist/components/form/FormField.svelte.d.ts +2 -2
  101. package/dist/components/form/FormFieldLight.svelte +400 -384
  102. package/dist/components/form/FormFieldLight.svelte.d.ts +1 -1
  103. package/dist/components/form/FormFieldWrapper.stories.svelte +42 -42
  104. package/dist/components/form/FormFieldWrapper.stories.svelte.d.ts +1 -1
  105. package/dist/components/form/FormFieldWrapper.svelte +100 -93
  106. package/dist/components/form/FormFieldWrapper.svelte.d.ts +1 -1
  107. package/dist/components/form/FormFieldset.svelte +108 -108
  108. package/dist/components/form/FormFieldset.svelte.d.ts +2 -2
  109. package/dist/components/form/FormMarkdownEditor.svelte +758 -725
  110. package/dist/components/form/FormNumberField.stories.svelte +25 -25
  111. package/dist/components/form/FormNumberField.stories.svelte.d.ts +1 -1
  112. package/dist/components/form/FormNumberField.svelte +88 -88
  113. package/dist/components/form/FormRangeField.stories.svelte +20 -20
  114. package/dist/components/form/FormRangeField.stories.svelte.d.ts +1 -1
  115. package/dist/components/form/FormRangeField.svelte +234 -226
  116. package/dist/components/form/FormSelect.stories.svelte +38 -38
  117. package/dist/components/form/FormSelect.stories.svelte.d.ts +1 -1
  118. package/dist/components/form/FormSelect.svelte +101 -101
  119. package/dist/components/form/FormSelect.svelte.d.ts +1 -1
  120. package/dist/components/form/FormTemplateEditor.svelte +847 -798
  121. package/dist/components/form/FormTemplateEditor.svelte.d.ts +1 -1
  122. package/dist/components/form/FormTextField.stories.svelte +29 -23
  123. package/dist/components/form/FormTextField.stories.svelte.d.ts +1 -1
  124. package/dist/components/form/FormTextField.svelte +68 -68
  125. package/dist/components/form/FormTextarea.stories.svelte +28 -25
  126. package/dist/components/form/FormTextarea.stories.svelte.d.ts +1 -1
  127. package/dist/components/form/FormTextarea.svelte +74 -74
  128. package/dist/components/form/FormToggle.stories.svelte +23 -20
  129. package/dist/components/form/FormToggle.stories.svelte.d.ts +1 -1
  130. package/dist/components/form/FormToggle.svelte +98 -98
  131. package/dist/components/form/FormUISchemaRenderer.svelte +120 -113
  132. package/dist/components/form/FormUISchemaRenderer.svelte.d.ts +3 -3
  133. package/dist/components/form/index.d.ts +19 -19
  134. package/dist/components/form/index.js +18 -18
  135. package/dist/components/form/templateAutocomplete.d.ts +2 -2
  136. package/dist/components/form/templateAutocomplete.js +64 -55
  137. package/dist/components/form/types.d.ts +6 -6
  138. package/dist/components/form/types.js +9 -4
  139. package/dist/components/icons/AlertCircleIcon.svelte +11 -0
  140. package/dist/components/icons/AlertCircleIcon.svelte.d.ts +26 -0
  141. package/dist/components/icons/CogIcon.svelte +11 -0
  142. package/dist/components/icons/CogIcon.svelte.d.ts +26 -0
  143. package/dist/components/interrupt/ChoicePrompt.stories.svelte +54 -38
  144. package/dist/components/interrupt/ChoicePrompt.stories.svelte.d.ts +1 -1
  145. package/dist/components/interrupt/ChoicePrompt.svelte +407 -383
  146. package/dist/components/interrupt/ChoicePrompt.svelte.d.ts +1 -1
  147. package/dist/components/interrupt/ConfirmationPrompt.stories.svelte +48 -48
  148. package/dist/components/interrupt/ConfirmationPrompt.stories.svelte.d.ts +1 -1
  149. package/dist/components/interrupt/ConfirmationPrompt.svelte +280 -274
  150. package/dist/components/interrupt/ConfirmationPrompt.svelte.d.ts +1 -1
  151. package/dist/components/interrupt/FormPrompt.svelte +223 -218
  152. package/dist/components/interrupt/FormPrompt.svelte.d.ts +1 -1
  153. package/dist/components/interrupt/InterruptBubble.svelte +617 -583
  154. package/dist/components/interrupt/InterruptBubble.svelte.d.ts +2 -2
  155. package/dist/components/interrupt/ReviewPrompt.stories.svelte +66 -56
  156. package/dist/components/interrupt/ReviewPrompt.stories.svelte.d.ts +1 -1
  157. package/dist/components/interrupt/ReviewPrompt.svelte +861 -841
  158. package/dist/components/interrupt/ReviewPrompt.svelte.d.ts +1 -1
  159. package/dist/components/interrupt/TextInputPrompt.stories.svelte +38 -33
  160. package/dist/components/interrupt/TextInputPrompt.stories.svelte.d.ts +1 -1
  161. package/dist/components/interrupt/TextInputPrompt.svelte +333 -328
  162. package/dist/components/interrupt/TextInputPrompt.svelte.d.ts +1 -1
  163. package/dist/components/interrupt/index.d.ts +5 -5
  164. package/dist/components/interrupt/index.js +5 -5
  165. package/dist/components/layouts/MainLayout.svelte +724 -691
  166. package/dist/components/layouts/MainLayout.svelte.d.ts +6 -6
  167. package/dist/components/nodes/GatewayNode.stories.svelte +100 -99
  168. package/dist/components/nodes/GatewayNode.svelte +605 -571
  169. package/dist/components/nodes/GatewayNode.svelte.d.ts +3 -3
  170. package/dist/components/nodes/IdeaNode.stories.svelte +44 -43
  171. package/dist/components/nodes/IdeaNode.svelte +451 -437
  172. package/dist/components/nodes/IdeaNode.svelte.d.ts +1 -1
  173. package/dist/components/nodes/NotesNode.stories.svelte +65 -64
  174. package/dist/components/nodes/NotesNode.svelte +380 -369
  175. package/dist/components/nodes/NotesNode.svelte.d.ts +1 -1
  176. package/dist/components/nodes/SimpleNode.stories.svelte +145 -144
  177. package/dist/components/nodes/SimpleNode.svelte +486 -424
  178. package/dist/components/nodes/SimpleNode.svelte.d.ts +1 -1
  179. package/dist/components/nodes/SquareNode.stories.svelte +73 -73
  180. package/dist/components/nodes/SquareNode.svelte +439 -380
  181. package/dist/components/nodes/SquareNode.svelte.d.ts +1 -1
  182. package/dist/components/nodes/TerminalNode.stories.svelte +13 -13
  183. package/dist/components/nodes/TerminalNode.svelte +709 -670
  184. package/dist/components/nodes/TerminalNode.svelte.d.ts +1 -1
  185. package/dist/components/nodes/ToolNode.stories.svelte +181 -180
  186. package/dist/components/nodes/ToolNode.svelte +505 -447
  187. package/dist/components/nodes/ToolNode.svelte.d.ts +1 -1
  188. package/dist/components/nodes/WorkflowNode.stories.svelte +70 -46
  189. package/dist/components/nodes/WorkflowNode.svelte +621 -551
  190. package/dist/components/nodes/WorkflowNode.svelte.d.ts +3 -3
  191. package/dist/components/playground/ChatPanel.svelte +945 -889
  192. package/dist/components/playground/ExecutionLogs.svelte +495 -472
  193. package/dist/components/playground/InputCollector.svelte +449 -428
  194. package/dist/components/playground/MessageBubble.stories.svelte +47 -47
  195. package/dist/components/playground/MessageBubble.stories.svelte.d.ts +1 -1
  196. package/dist/components/playground/MessageBubble.svelte +626 -610
  197. package/dist/components/playground/MessageBubble.svelte.d.ts +1 -1
  198. package/dist/components/playground/Playground.svelte +1088 -1057
  199. package/dist/components/playground/Playground.svelte.d.ts +3 -3
  200. package/dist/components/playground/PlaygroundModal.svelte +208 -204
  201. package/dist/components/playground/PlaygroundModal.svelte.d.ts +3 -3
  202. package/dist/components/playground/SessionManager.svelte +527 -521
  203. package/dist/components/playground/SessionManager.svelte.d.ts +1 -1
  204. package/dist/config/agentSpecEndpoints.d.ts +1 -1
  205. package/dist/config/agentSpecEndpoints.js +20 -20
  206. package/dist/config/constants.d.ts +8 -0
  207. package/dist/config/constants.js +10 -2
  208. package/dist/config/defaultCategories.d.ts +1 -1
  209. package/dist/config/defaultCategories.js +86 -86
  210. package/dist/config/defaultPortConfig.d.ts +1 -1
  211. package/dist/config/defaultPortConfig.js +144 -144
  212. package/dist/config/endpoints.d.ts +4 -4
  213. package/dist/config/endpoints.js +65 -65
  214. package/dist/config/runtimeConfig.d.ts +2 -2
  215. package/dist/config/runtimeConfig.js +8 -8
  216. package/dist/core/index.d.ts +63 -59
  217. package/dist/core/index.js +35 -33
  218. package/dist/display/index.d.ts +2 -2
  219. package/dist/display/index.js +2 -2
  220. package/dist/editor/index.d.ts +62 -62
  221. package/dist/editor/index.js +53 -53
  222. package/dist/form/code.d.ts +5 -5
  223. package/dist/form/code.js +14 -14
  224. package/dist/form/fieldRegistry.d.ts +3 -3
  225. package/dist/form/fieldRegistry.js +11 -9
  226. package/dist/form/full.d.ts +8 -8
  227. package/dist/form/full.js +9 -9
  228. package/dist/form/index.d.ts +18 -18
  229. package/dist/form/index.js +16 -16
  230. package/dist/form/markdown.d.ts +4 -4
  231. package/dist/form/markdown.js +8 -8
  232. package/dist/helpers/proximityConnect.d.ts +3 -3
  233. package/dist/helpers/proximityConnect.js +34 -32
  234. package/dist/helpers/workflowEditorHelper.d.ts +5 -5
  235. package/dist/helpers/workflowEditorHelper.js +108 -96
  236. package/dist/index.d.ts +6 -6
  237. package/dist/index.js +6 -6
  238. package/dist/mocks/app-environment.js +2 -2
  239. package/dist/mocks/app-forms.js +9 -9
  240. package/dist/mocks/app-navigation.js +11 -11
  241. package/dist/mocks/app-stores.js +8 -8
  242. package/dist/playground/index.d.ts +19 -19
  243. package/dist/playground/index.js +16 -16
  244. package/dist/playground/mount.d.ts +3 -3
  245. package/dist/playground/mount.js +24 -24
  246. package/dist/registry/builtinFormats.js +13 -13
  247. package/dist/registry/builtinNodes.d.ts +2 -2
  248. package/dist/registry/builtinNodes.js +77 -77
  249. package/dist/registry/index.d.ts +4 -4
  250. package/dist/registry/index.js +4 -4
  251. package/dist/registry/nodeComponentRegistry.d.ts +8 -8
  252. package/dist/registry/nodeComponentRegistry.js +11 -9
  253. package/dist/registry/plugin.d.ts +2 -2
  254. package/dist/registry/plugin.js +11 -11
  255. package/dist/registry/workflowFormatRegistry.d.ts +3 -3
  256. package/dist/registry/workflowFormatRegistry.js +2 -2
  257. package/dist/schema/index.d.ts +1 -1
  258. package/dist/schema/index.js +2 -2
  259. package/dist/schemas/v1/workflow.schema.json +22 -107
  260. package/dist/services/agentSpecExecutionService.d.ts +3 -3
  261. package/dist/services/agentSpecExecutionService.js +59 -55
  262. package/dist/services/api.d.ts +18 -4
  263. package/dist/services/api.js +46 -43
  264. package/dist/services/apiVariableService.d.ts +1 -1
  265. package/dist/services/apiVariableService.js +41 -34
  266. package/dist/services/autoSaveService.js +8 -8
  267. package/dist/services/categoriesApi.d.ts +2 -2
  268. package/dist/services/categoriesApi.js +8 -8
  269. package/dist/services/draftStorage.d.ts +1 -1
  270. package/dist/services/draftStorage.js +11 -11
  271. package/dist/services/dynamicSchemaService.d.ts +1 -1
  272. package/dist/services/dynamicSchemaService.js +41 -39
  273. package/dist/services/globalSave.d.ts +2 -2
  274. package/dist/services/globalSave.js +53 -42
  275. package/dist/services/historyService.d.ts +1 -1
  276. package/dist/services/historyService.js +8 -8
  277. package/dist/services/interruptService.d.ts +1 -1
  278. package/dist/services/interruptService.js +35 -29
  279. package/dist/services/nodeExecutionService.d.ts +1 -1
  280. package/dist/services/nodeExecutionService.js +45 -44
  281. package/dist/services/playgroundService.d.ts +1 -1
  282. package/dist/services/playgroundService.js +29 -29
  283. package/dist/services/portConfigApi.d.ts +2 -2
  284. package/dist/services/portConfigApi.js +8 -8
  285. package/dist/services/settingsService.d.ts +2 -2
  286. package/dist/services/settingsService.js +25 -19
  287. package/dist/services/toastService.d.ts +4 -4
  288. package/dist/services/toastService.js +33 -33
  289. package/dist/services/variableService.d.ts +1 -1
  290. package/dist/services/variableService.js +36 -36
  291. package/dist/services/workflowStorage.d.ts +2 -2
  292. package/dist/services/workflowStorage.js +13 -13
  293. package/dist/settings/index.d.ts +7 -7
  294. package/dist/settings/index.js +6 -6
  295. package/dist/skins/default.d.ts +2 -0
  296. package/dist/skins/default.js +1 -0
  297. package/dist/skins/index.d.ts +13 -0
  298. package/dist/skins/index.js +30 -0
  299. package/dist/skins/slate.d.ts +2 -0
  300. package/dist/skins/slate.js +78 -0
  301. package/dist/stores/categoriesStore.svelte.d.ts +1 -1
  302. package/dist/stores/categoriesStore.svelte.js +5 -5
  303. package/dist/stores/editorStateMachine.svelte.d.ts +2 -2
  304. package/dist/stores/editorStateMachine.svelte.js +65 -33
  305. package/dist/stores/historyStore.svelte.d.ts +4 -4
  306. package/dist/stores/historyStore.svelte.js +4 -4
  307. package/dist/stores/interruptStore.svelte.d.ts +3 -3
  308. package/dist/stores/interruptStore.svelte.js +21 -21
  309. package/dist/stores/playgroundStore.svelte.d.ts +2 -2
  310. package/dist/stores/playgroundStore.svelte.js +25 -18
  311. package/dist/stores/portCoordinateStore.svelte.d.ts +2 -2
  312. package/dist/stores/portCoordinateStore.svelte.js +15 -8
  313. package/dist/stores/settingsStore.svelte.d.ts +2 -2
  314. package/dist/stores/settingsStore.svelte.js +62 -57
  315. package/dist/stores/workflowStore.svelte.d.ts +3 -3
  316. package/dist/stores/workflowStore.svelte.js +50 -47
  317. package/dist/stories/CanvasDecorator.svelte +35 -32
  318. package/dist/stories/CanvasDecorator.svelte.d.ts +2 -2
  319. package/dist/stories/EdgeDecorator.svelte +125 -0
  320. package/dist/stories/EdgeDecorator.svelte.d.ts +17 -0
  321. package/dist/stories/NodeDecorator.svelte +59 -53
  322. package/dist/stories/NodeDecorator.svelte.d.ts +1 -1
  323. package/dist/stories/utils.d.ts +2 -2
  324. package/dist/stories/utils.js +105 -67
  325. package/dist/styles/base.css +599 -595
  326. package/dist/styles/toast.css +14 -14
  327. package/dist/styles/tokens.css +409 -378
  328. package/dist/svelte-app.d.ts +9 -9
  329. package/dist/svelte-app.js +39 -39
  330. package/dist/themes/default.d.ts +2 -0
  331. package/dist/themes/default.js +9 -0
  332. package/dist/themes/index.d.ts +13 -0
  333. package/dist/themes/index.js +44 -0
  334. package/dist/themes/minimal.d.ts +2 -0
  335. package/dist/themes/minimal.js +11 -0
  336. package/dist/types/agentspec.d.ts +18 -18
  337. package/dist/types/agentspec.js +2 -2
  338. package/dist/types/auth.d.ts +1 -1
  339. package/dist/types/auth.js +6 -6
  340. package/dist/types/config.d.ts +6 -6
  341. package/dist/types/events.d.ts +2 -2
  342. package/dist/types/events.js +2 -2
  343. package/dist/types/index.d.ts +32 -32
  344. package/dist/types/index.js +6 -6
  345. package/dist/types/interrupt.d.ts +6 -6
  346. package/dist/types/interrupt.js +21 -21
  347. package/dist/types/interruptState.d.ts +12 -12
  348. package/dist/types/interruptState.js +66 -66
  349. package/dist/types/playground.d.ts +7 -7
  350. package/dist/types/playground.js +14 -14
  351. package/dist/types/settings.d.ts +5 -3
  352. package/dist/types/settings.js +25 -18
  353. package/dist/types/skin.d.ts +31 -0
  354. package/dist/types/skin.js +1 -0
  355. package/dist/types/theme.d.ts +35 -0
  356. package/dist/types/theme.js +1 -0
  357. package/dist/types/uischema.d.ts +4 -4
  358. package/dist/types/uischema.js +3 -3
  359. package/dist/utils/colors.d.ts +1 -1
  360. package/dist/utils/colors.js +97 -95
  361. package/dist/utils/config.d.ts +2 -2
  362. package/dist/utils/config.js +48 -48
  363. package/dist/utils/connections.d.ts +2 -2
  364. package/dist/utils/connections.js +15 -15
  365. package/dist/utils/errors.js +3 -3
  366. package/dist/utils/fetchWithAuth.d.ts +1 -1
  367. package/dist/utils/fetchWithAuth.js +2 -2
  368. package/dist/utils/handleIds.d.ts +2 -2
  369. package/dist/utils/handleIds.js +8 -8
  370. package/dist/utils/handlePositioning.d.ts +1 -1
  371. package/dist/utils/handlePositioning.js +2 -2
  372. package/dist/utils/icons.d.ts +1 -1
  373. package/dist/utils/icons.js +74 -74
  374. package/dist/utils/logger.d.ts +1 -1
  375. package/dist/utils/logger.js +7 -7
  376. package/dist/utils/nodeStatus.d.ts +1 -1
  377. package/dist/utils/nodeStatus.js +48 -48
  378. package/dist/utils/nodeTypes.d.ts +1 -1
  379. package/dist/utils/nodeTypes.js +21 -20
  380. package/dist/utils/nodeWrapper.d.ts +7 -7
  381. package/dist/utils/nodeWrapper.js +21 -19
  382. package/dist/utils/performanceUtils.d.ts +1 -1
  383. package/dist/utils/performanceUtils.js +2 -1
  384. package/dist/utils/sanitize.js +1 -1
  385. package/dist/utils/uischema.d.ts +2 -2
  386. package/dist/utils/uischema.js +8 -8
  387. package/dist/utils/validation.js +20 -8
  388. package/package.json +296 -291
@@ -9,563 +9,633 @@
9
9
  -->
10
10
 
11
11
  <script lang="ts">
12
- import { Position, Handle } from '@xyflow/svelte';
13
- import type { WorkflowNode, NodePort, DynamicPort } from '../../types/index.js';
14
- import { dynamicPortToNodePort } from '../../types/index.js';
15
- import Icon from '@iconify/svelte';
16
- import { getNodeIcon } from '../../utils/icons.js';
17
- import {
18
- getDataTypeColorToken,
19
- getCategoryColorToken,
20
- getPortBackgroundColor
21
- } from '../../utils/colors.js';
22
- import { getConnectedHandles } from '../../stores/workflowStore.svelte.js';
23
-
24
- interface Props {
25
- data: WorkflowNode['data'] & {
26
- nodeId?: string;
27
- onConfigOpen?: (node: { id: string; type: string; data: WorkflowNode['data'] }) => void;
28
- };
29
- selected?: boolean;
30
- }
31
-
32
- let props: Props = $props();
33
- let isHandleInteraction = $state(false);
34
-
35
- /**
36
- * Instance-specific title override from config.
37
- * Falls back to the original label if not set.
38
- * This allows users to customize the node title per-instance via config.
39
- */
40
- const displayTitle = $derived((props.data.config?.instanceTitle as string) || props.data.label);
41
-
42
- /**
43
- * Instance-specific description override from config.
44
- * Falls back to the metadata description if not set.
45
- * This allows users to customize the node description per-instance via config.
46
- */
47
- const displayDescription = $derived(
48
- (props.data.config?.instanceDescription as string) || props.data.metadata.description
49
- );
50
-
51
- /**
52
- * Get the hideUnconnectedHandles setting from extensions
53
- * Merges node type defaults with instance overrides
54
- */
55
- const hideUnconnectedHandles = $derived(() => {
56
- const typeDefault = props.data.metadata?.extensions?.ui?.hideUnconnectedHandles ?? false;
57
- const instanceOverride = props.data.extensions?.ui?.hideUnconnectedHandles;
58
- return instanceOverride ?? typeDefault;
59
- });
60
-
61
- /**
62
- * Dynamic inputs from config - user-defined input ports
63
- * Similar to how branches work in GatewayNode
64
- */
65
- const dynamicInputs = $derived(
66
- ((props.data.config?.dynamicInputs as DynamicPort[]) || []).map((port) =>
67
- dynamicPortToNodePort(port, 'input')
68
- )
69
- );
70
-
71
- /**
72
- * Dynamic outputs from config - user-defined output ports
73
- * Similar to how branches work in GatewayNode
74
- */
75
- const dynamicOutputs = $derived(
76
- ((props.data.config?.dynamicOutputs as DynamicPort[]) || []).map((port) =>
77
- dynamicPortToNodePort(port, 'output')
78
- )
79
- );
80
-
81
- /**
82
- * Combined input ports: static metadata inputs + dynamic config inputs
83
- */
84
- const allInputPorts = $derived([...props.data.metadata.inputs, ...dynamicInputs]);
85
-
86
- /**
87
- * Combined output ports: static metadata outputs + dynamic config outputs
88
- */
89
- const allOutputPorts = $derived([...props.data.metadata.outputs, ...dynamicOutputs]);
90
-
91
- /**
92
- * Check if a port should be visible based on connection state and settings
93
- * @param port - The port to check
94
- * @param type - Whether this is an 'input' or 'output' port
95
- * @returns true if the port should be visible
96
- */
97
- function isPortVisible(port: NodePort, type: 'input' | 'output'): boolean {
98
- // Always show if hideUnconnectedHandles is disabled
99
- if (!hideUnconnectedHandles()) {
100
- return true;
101
- }
102
-
103
- // Always show required ports
104
- if (port.required) {
105
- return true;
106
- }
107
-
108
- // Check if port is connected
109
- const handleId = `${props.data.nodeId}-${type}-${port.id}`;
110
- return getConnectedHandles().has(handleId);
111
- }
112
-
113
- /**
114
- * Derived list of visible input ports based on hideUnconnectedHandles setting
115
- * Now includes both static and dynamic inputs
116
- */
117
- const visibleInputPorts = $derived(allInputPorts.filter((port) => isPortVisible(port, 'input')));
118
-
119
- /**
120
- * Derived list of visible output ports based on hideUnconnectedHandles setting
121
- * Now includes both static and dynamic outputs
122
- */
123
- const visibleOutputPorts = $derived(
124
- allOutputPorts.filter((port) => isPortVisible(port, 'output'))
125
- );
126
-
127
- /**
128
- * Handle node click - only handle selection, no config opening
129
- */
130
- function handleNodeClick(): void {
131
- // Node selection is handled by Svelte Flow
132
- }
133
-
134
- /**
135
- * Handle double-click to open config
136
- */
137
- function handleDoubleClick(): void {
138
- openConfigSidebar();
139
- }
140
-
141
- /**
142
- * Handle configuration sidebar - now using global ConfigSidebar
143
- */
144
- function openConfigSidebar(): void {
145
- if (props.data.onConfigOpen) {
146
- // Create a WorkflowNodeType-like object for the global ConfigSidebar
147
- const nodeForConfig = {
148
- id: props.data.nodeId || 'unknown',
149
- type: 'workflowNode',
150
- data: props.data
151
- };
152
- props.data.onConfigOpen(nodeForConfig);
153
- }
154
- }
12
+ import { Position, Handle } from "@xyflow/svelte";
13
+ import type {
14
+ WorkflowNode,
15
+ NodePort,
16
+ DynamicPort,
17
+ } from "../../types/index.js";
18
+ import { dynamicPortToNodePort } from "../../types/index.js";
19
+ import Icon from "@iconify/svelte";
20
+ import { getNodeIcon } from "../../utils/icons.js";
21
+ import CogIcon from "../icons/CogIcon.svelte";
22
+ import {
23
+ getDataTypeColorToken,
24
+ getCategoryColorToken,
25
+ getPortBackgroundColor,
26
+ } from "../../utils/colors.js";
27
+ import { getConnectedHandles } from "../../stores/workflowStore.svelte.js";
28
+
29
+ interface Props {
30
+ data: WorkflowNode["data"] & {
31
+ nodeId?: string;
32
+ onConfigOpen?: (node: {
33
+ id: string;
34
+ type: string;
35
+ data: WorkflowNode["data"];
36
+ }) => void;
37
+ };
38
+ selected?: boolean;
39
+ }
40
+
41
+ let props: Props = $props();
42
+ let isHandleInteraction = $state(false);
43
+
44
+ /**
45
+ * Instance-specific title override from config.
46
+ * Falls back to the original label if not set.
47
+ * This allows users to customize the node title per-instance via config.
48
+ */
49
+ const displayTitle = $derived(
50
+ (props.data.config?.instanceTitle as string) || props.data.label,
51
+ );
52
+
53
+ /**
54
+ * Instance-specific description override from config.
55
+ * Falls back to the metadata description if not set.
56
+ * This allows users to customize the node description per-instance via config.
57
+ */
58
+ const displayDescription = $derived(
59
+ (props.data.config?.instanceDescription as string) ||
60
+ props.data.metadata.description,
61
+ );
62
+
63
+ /**
64
+ * Get the hideUnconnectedHandles setting from extensions
65
+ * Merges node type defaults with instance overrides
66
+ */
67
+ const hideUnconnectedHandles = $derived(() => {
68
+ const typeDefault =
69
+ props.data.metadata?.extensions?.ui?.hideUnconnectedHandles ?? false;
70
+ const instanceOverride = props.data.extensions?.ui?.hideUnconnectedHandles;
71
+ return instanceOverride ?? typeDefault;
72
+ });
73
+
74
+ /**
75
+ * Dynamic inputs from config - user-defined input ports
76
+ * Similar to how branches work in GatewayNode
77
+ */
78
+ const dynamicInputs = $derived(
79
+ ((props.data.config?.dynamicInputs as DynamicPort[]) || []).map((port) =>
80
+ dynamicPortToNodePort(port, "input"),
81
+ ),
82
+ );
83
+
84
+ /**
85
+ * Dynamic outputs from config - user-defined output ports
86
+ * Similar to how branches work in GatewayNode
87
+ */
88
+ const dynamicOutputs = $derived(
89
+ ((props.data.config?.dynamicOutputs as DynamicPort[]) || []).map((port) =>
90
+ dynamicPortToNodePort(port, "output"),
91
+ ),
92
+ );
93
+
94
+ /**
95
+ * Combined input ports: static metadata inputs + dynamic config inputs
96
+ */
97
+ const allInputPorts = $derived([
98
+ ...props.data.metadata.inputs,
99
+ ...dynamicInputs,
100
+ ]);
101
+
102
+ /**
103
+ * Combined output ports: static metadata outputs + dynamic config outputs
104
+ */
105
+ const allOutputPorts = $derived([
106
+ ...props.data.metadata.outputs,
107
+ ...dynamicOutputs,
108
+ ]);
109
+
110
+ /**
111
+ * Check if a port should be visible based on connection state and settings
112
+ * @param port - The port to check
113
+ * @param type - Whether this is an 'input' or 'output' port
114
+ * @returns true if the port should be visible
115
+ */
116
+ function isPortVisible(port: NodePort, type: "input" | "output"): boolean {
117
+ // Always show if hideUnconnectedHandles is disabled
118
+ if (!hideUnconnectedHandles()) {
119
+ return true;
120
+ }
121
+
122
+ // Always show required ports
123
+ if (port.required) {
124
+ return true;
125
+ }
126
+
127
+ // Check if port is connected
128
+ const handleId = `${props.data.nodeId}-${type}-${port.id}`;
129
+ return getConnectedHandles().has(handleId);
130
+ }
131
+
132
+ /**
133
+ * Derived list of visible input ports based on hideUnconnectedHandles setting
134
+ * Now includes both static and dynamic inputs
135
+ */
136
+ const visibleInputPorts = $derived(
137
+ allInputPorts.filter((port) => isPortVisible(port, "input")),
138
+ );
139
+
140
+ /**
141
+ * Derived list of visible output ports based on hideUnconnectedHandles setting
142
+ * Now includes both static and dynamic outputs
143
+ */
144
+ const visibleOutputPorts = $derived(
145
+ allOutputPorts.filter((port) => isPortVisible(port, "output")),
146
+ );
147
+
148
+ /**
149
+ * Handle node click - only handle selection, no config opening
150
+ */
151
+ function handleNodeClick(): void {
152
+ // Node selection is handled by Svelte Flow
153
+ }
154
+
155
+ /**
156
+ * Handle double-click to open config
157
+ */
158
+ function handleDoubleClick(): void {
159
+ openConfigSidebar();
160
+ }
161
+
162
+ /**
163
+ * Handle configuration sidebar - now using global ConfigSidebar
164
+ */
165
+ function openConfigSidebar(): void {
166
+ if (props.data.onConfigOpen) {
167
+ // Create a WorkflowNodeType-like object for the global ConfigSidebar
168
+ const nodeForConfig = {
169
+ id: props.data.nodeId || "unknown",
170
+ type: "workflowNode",
171
+ data: props.data,
172
+ };
173
+ props.data.onConfigOpen(nodeForConfig);
174
+ }
175
+ }
155
176
  </script>
156
177
 
157
178
  <!-- Node Container -->
158
179
  <div
159
- class="flowdrop-workflow-node"
160
- class:flowdrop-workflow-node--selected={props.selected}
161
- onclick={handleNodeClick}
162
- ondblclick={handleDoubleClick}
163
- onmouseup={() => {
164
- isHandleInteraction = false;
165
- }}
166
- data-handle-interaction={isHandleInteraction}
167
- role="button"
168
- tabindex="0"
169
- onkeydown={(e) => {
170
- if (e.key === 'Enter' || e.key === ' ') {
171
- e.preventDefault();
172
- handleDoubleClick();
173
- }
174
- }}
175
- aria-label="Workflow node: {props.data.metadata.name}"
176
- aria-describedby="node-description-{props.data.nodeId || 'unknown'}"
180
+ class="flowdrop-workflow-node"
181
+ class:flowdrop-workflow-node--selected={props.selected}
182
+ onclick={handleNodeClick}
183
+ ondblclick={handleDoubleClick}
184
+ onmouseup={() => {
185
+ isHandleInteraction = false;
186
+ }}
187
+ data-handle-interaction={isHandleInteraction}
188
+ role="button"
189
+ tabindex="0"
190
+ onkeydown={(e) => {
191
+ if (e.key === "Enter" || e.key === " ") {
192
+ e.preventDefault();
193
+ handleDoubleClick();
194
+ }
195
+ }}
196
+ aria-label="Workflow node: {props.data.metadata.name}"
197
+ aria-describedby="node-description-{props.data.nodeId || 'unknown'}"
177
198
  >
178
- <!-- Default Node Header: expands in multiples of 10 (title row 40px + gap 10px + description 20px per line) -->
179
- <div class="flowdrop-workflow-node__header">
180
- <div class="flowdrop-workflow-node__header-title">
181
- <!-- Node Icon with Squircle Background -->
182
- <div
183
- class="flowdrop-workflow-node__icon-wrapper"
184
- style="--_icon-color: {getCategoryColorToken(props.data.metadata.category)}"
185
- >
186
- <Icon
187
- icon={getNodeIcon(props.data.metadata.icon, props.data.metadata.category)}
188
- class="flowdrop-workflow-node__icon"
189
- />
190
- </div>
191
-
192
- <!-- Node Title - Icon and Title on same line -->
193
- <h3 class="flowdrop-text--sm flowdrop-font--medium flowdrop-truncate flowdrop-flex--1">
194
- {displayTitle}
195
- </h3>
196
-
197
- <!-- Status Indicators -->
198
- <div class="flowdrop-flex flowdrop-gap--2 flowdrop-items--center"></div>
199
- </div>
200
- <!-- Node Description - line-height 20px so header grows in steps of 10 -->
201
- <p
202
- class="flowdrop-workflow-node__header-desc"
203
- id="node-description-{props.data.nodeId || 'unknown'}"
204
- >
205
- {displayDescription}
206
- </p>
207
- </div>
208
-
209
- <!-- Input Ports Container -->
210
- {#if visibleInputPorts.length > 0}
211
- <div class="flowdrop-workflow-node__ports">
212
- <div class="flowdrop-workflow-node__ports-list">
213
- {#each visibleInputPorts as port, inputIndex (port.id)}
214
- <div class="flowdrop-workflow-node__port">
215
- <!-- Input Handle: centered in row, at node edge (ports have no padding) -->
216
- <Handle
217
- type="target"
218
- position={Position.Left}
219
- id={`${props.data.nodeId}-input-${port.id}`}
220
- class="flowdrop-workflow-node__handle"
221
- style="top: 50%; transform: translateY(-50%); --fd-handle-fill: {getDataTypeColorToken(
222
- port.dataType
223
- )}; --fd-handle-border-color: var(--fd-handle-border);"
224
- role="button"
225
- tabindex={0}
226
- aria-label="Connect to {port.name} input port"
227
- />
228
-
229
- <!-- Port Info: padding lives here so handle position is simple -->
230
- <div class="flowdrop-workflow-node__port-content flowdrop-flex--1 flowdrop-min-w--0">
231
- <div class="flowdrop-flex flowdrop-gap--2">
232
- <span class="flowdrop-text--xs flowdrop-font--medium">{port.name}</span>
233
- <span
234
- class="flowdrop-badge flowdrop-badge--sm"
235
- style="background-color: {getPortBackgroundColor(
236
- port.dataType,
237
- 15
238
- )}; color: {getDataTypeColorToken(
239
- port.dataType
240
- )}; border: 1px solid {getPortBackgroundColor(port.dataType, 30)};"
241
- >
242
- {port.dataType}
243
- </span>
244
- {#if port.required}
245
- <span class="flowdrop-badge flowdrop-badge--error flowdrop-badge--sm"
246
- >Required</span
247
- >
248
- {/if}
249
- </div>
250
- {#if port.description}
251
- <p class="flowdrop-text--xs flowdrop-text--gray flowdrop-truncate">
252
- {port.description}
253
- </p>
254
- {/if}
255
- </div>
256
- </div>
257
- {/each}
258
- </div>
259
- </div>
260
- {/if}
261
-
262
- <!-- Output Ports Container -->
263
- {#if visibleOutputPorts.length > 0}
264
- <div class="flowdrop-workflow-node__ports">
265
- <div class="flowdrop-workflow-node__ports-list">
266
- {#each visibleOutputPorts as port, outputIndex (port.id)}
267
- <div class="flowdrop-workflow-node__port">
268
- <!-- Port Info: padding lives here so handle position is simple -->
269
- <div
270
- class="flowdrop-workflow-node__port-content flowdrop-flex--1 flowdrop-min-w--0 flowdrop-text--right"
271
- >
272
- <div class="flowdrop-flex flowdrop-gap--2 flowdrop-justify--end">
273
- <span class="flowdrop-text--xs flowdrop-font--medium">{port.name}</span>
274
- <span
275
- class="flowdrop-badge flowdrop-badge--sm"
276
- style="background-color: {getPortBackgroundColor(
277
- port.dataType,
278
- 15
279
- )}; color: {getDataTypeColorToken(
280
- port.dataType
281
- )}; border: 1px solid {getPortBackgroundColor(port.dataType, 30)};"
282
- >
283
- {port.dataType}
284
- </span>
285
- </div>
286
- {#if port.description}
287
- <p class="flowdrop-text--xs flowdrop-text--gray flowdrop-truncate">
288
- {port.description}
289
- </p>
290
- {/if}
291
- </div>
292
-
293
- <!-- Output Handle: centered in row, at node edge (ports have no padding) -->
294
- <Handle
295
- type="source"
296
- position={Position.Right}
297
- id={`${props.data.nodeId}-output-${port.id}`}
298
- class="flowdrop-workflow-node__handle"
299
- style="top: 50%; transform: translateY(-50%); --fd-handle-fill: {getDataTypeColorToken(
300
- port.dataType
301
- )}; --fd-handle-border-color: var(--fd-handle-border);"
302
- role="button"
303
- tabindex={0}
304
- aria-label="Connect from {port.name} output port"
305
- />
306
- </div>
307
- {/each}
308
- </div>
309
- </div>
310
- {/if}
311
-
312
- <!-- Config button -->
313
- <button
314
- class="flowdrop-workflow-node__config-btn"
315
- onclick={openConfigSidebar}
316
- title="Configure node"
317
- >
318
- <Icon icon="mdi:cog" />
319
- </button>
199
+ <!-- Default Node Header: expands in multiples of 10 (title row 40px + gap 10px + description 20px per line) -->
200
+ <div class="flowdrop-workflow-node__header">
201
+ <div class="flowdrop-workflow-node__header-title">
202
+ <!-- Squircle icon visibility controlled by --fd-node-icon-display -->
203
+ <div
204
+ class="flowdrop-workflow-node__icon-wrapper"
205
+ style="--_icon-color: {getCategoryColorToken(
206
+ props.data.metadata.category,
207
+ )}"
208
+ >
209
+ <Icon
210
+ icon={getNodeIcon(
211
+ props.data.metadata.icon,
212
+ props.data.metadata.category,
213
+ )}
214
+ class="flowdrop-workflow-node__icon"
215
+ />
216
+ </div>
217
+ <!-- Circle dot — visibility controlled by --fd-node-circle-display -->
218
+ <span
219
+ class="flowdrop-workflow-node__color-dot"
220
+ style="background: {getCategoryColorToken(
221
+ props.data.metadata.category,
222
+ )}"
223
+ ></span>
224
+
225
+ <!-- Node Title - Icon and Title on same line -->
226
+ <h3
227
+ class="flowdrop-text--sm flowdrop-font--medium flowdrop-truncate flowdrop-flex--1"
228
+ >
229
+ {displayTitle}
230
+ </h3>
231
+
232
+ <!-- Status Indicators -->
233
+ <div class="flowdrop-flex flowdrop-gap--2 flowdrop-items--center"></div>
234
+ </div>
235
+ <!-- Node Description - line-height 20px so header grows in steps of 10 -->
236
+ <p
237
+ class="flowdrop-workflow-node__header-desc"
238
+ id="node-description-{props.data.nodeId || 'unknown'}"
239
+ >
240
+ {displayDescription}
241
+ </p>
242
+ </div>
243
+
244
+ <!-- Input Ports Container -->
245
+ {#if visibleInputPorts.length > 0}
246
+ <div class="flowdrop-workflow-node__ports">
247
+ <div class="flowdrop-workflow-node__ports-list">
248
+ {#each visibleInputPorts as port, inputIndex (port.id)}
249
+ <div class="flowdrop-workflow-node__port">
250
+ <!-- Input Handle: centered in row, at node edge (ports have no padding) -->
251
+ <Handle
252
+ type="target"
253
+ position={Position.Left}
254
+ id={`${props.data.nodeId}-input-${port.id}`}
255
+ class="flowdrop-workflow-node__handle"
256
+ style="top: 50%; transform: translateY(-50%); --fd-handle-fill: var(--fd-port-skin-color, {getDataTypeColorToken(
257
+ port.dataType,
258
+ )}); --fd-handle-border-color: var(--fd-handle-border);"
259
+ role="button"
260
+ tabindex={0}
261
+ aria-label="Connect to {port.name} input port"
262
+ />
263
+
264
+ <!-- Port Info: padding lives here so handle position is simple -->
265
+ <div
266
+ class="flowdrop-workflow-node__port-content flowdrop-flex--1 flowdrop-min-w--0"
267
+ >
268
+ <div class="flowdrop-flex flowdrop-gap--2">
269
+ <span class="flowdrop-text--xs flowdrop-font--medium"
270
+ >{port.name}</span
271
+ >
272
+ <span
273
+ class="flowdrop-badge flowdrop-badge--sm"
274
+ style="background-color: {getPortBackgroundColor(
275
+ port.dataType,
276
+ 15,
277
+ )}; color: {getDataTypeColorToken(
278
+ port.dataType,
279
+ )}; border: 1px solid {getPortBackgroundColor(
280
+ port.dataType,
281
+ 30,
282
+ )};"
283
+ >
284
+ {port.dataType}
285
+ </span>
286
+ {#if port.required}
287
+ <span
288
+ class="flowdrop-badge flowdrop-badge--error flowdrop-badge--sm"
289
+ >Required</span
290
+ >
291
+ {/if}
292
+ </div>
293
+ {#if port.description}
294
+ <p
295
+ class="flowdrop-text--xs flowdrop-text--gray flowdrop-truncate"
296
+ >
297
+ {port.description}
298
+ </p>
299
+ {/if}
300
+ </div>
301
+ </div>
302
+ {/each}
303
+ </div>
304
+ </div>
305
+ {/if}
306
+
307
+ <!-- Output Ports Container -->
308
+ {#if visibleOutputPorts.length > 0}
309
+ <div class="flowdrop-workflow-node__ports">
310
+ <div class="flowdrop-workflow-node__ports-list">
311
+ {#each visibleOutputPorts as port, outputIndex (port.id)}
312
+ <div class="flowdrop-workflow-node__port">
313
+ <!-- Port Info: padding lives here so handle position is simple -->
314
+ <div
315
+ class="flowdrop-workflow-node__port-content flowdrop-flex--1 flowdrop-min-w--0 flowdrop-text--right"
316
+ >
317
+ <div class="flowdrop-flex flowdrop-gap--2 flowdrop-justify--end">
318
+ <span class="flowdrop-text--xs flowdrop-font--medium"
319
+ >{port.name}</span
320
+ >
321
+ <span
322
+ class="flowdrop-badge flowdrop-badge--sm"
323
+ style="background-color: {getPortBackgroundColor(
324
+ port.dataType,
325
+ 15,
326
+ )}; color: {getDataTypeColorToken(
327
+ port.dataType,
328
+ )}; border: 1px solid {getPortBackgroundColor(
329
+ port.dataType,
330
+ 30,
331
+ )};"
332
+ >
333
+ {port.dataType}
334
+ </span>
335
+ </div>
336
+ {#if port.description}
337
+ <p
338
+ class="flowdrop-text--xs flowdrop-text--gray flowdrop-truncate"
339
+ >
340
+ {port.description}
341
+ </p>
342
+ {/if}
343
+ </div>
344
+
345
+ <!-- Output Handle: centered in row, at node edge (ports have no padding) -->
346
+ <Handle
347
+ type="source"
348
+ position={Position.Right}
349
+ id={`${props.data.nodeId}-output-${port.id}`}
350
+ class="flowdrop-workflow-node__handle"
351
+ style="top: 50%; transform: translateY(-50%); --fd-handle-fill: var(--fd-port-skin-color, {getDataTypeColorToken(
352
+ port.dataType,
353
+ )}); --fd-handle-border-color: var(--fd-handle-border);"
354
+ role="button"
355
+ tabindex={0}
356
+ aria-label="Connect from {port.name} output port"
357
+ />
358
+ </div>
359
+ {/each}
360
+ </div>
361
+ </div>
362
+ {/if}
363
+
364
+ <!-- Config button -->
365
+ <button
366
+ class="flowdrop-workflow-node__config-btn"
367
+ onclick={openConfigSidebar}
368
+ title="Configure node"
369
+ >
370
+ <CogIcon />
371
+ </button>
320
372
  </div>
321
373
 
322
374
  <style>
323
- .flowdrop-workflow-node {
324
- position: relative;
325
- background-color: var(--fd-card);
326
- border: 1.5px solid var(--fd-node-border);
327
- border-radius: var(--fd-radius-xl);
328
- box-shadow: var(--fd-shadow-md);
329
- width: var(--fd-node-default-width);
330
- z-index: 10;
331
- color: var(--fd-foreground);
332
- transition: all var(--fd-transition-fast);
333
- }
334
-
335
- .flowdrop-workflow-node:hover {
336
- box-shadow: var(--fd-shadow-lg);
337
- border-color: var(--fd-node-border-hover);
338
- }
339
-
340
- .flowdrop-workflow-node--selected {
341
- box-shadow:
342
- 0 0 0 2px var(--fd-primary-muted),
343
- var(--fd-shadow-lg);
344
- border-color: var(--fd-primary);
345
- }
346
-
347
- .flowdrop-workflow-node--selected:hover {
348
- box-shadow:
349
- 0 0 0 2px var(--fd-primary-muted),
350
- var(--fd-shadow-lg);
351
- border-color: var(--fd-primary);
352
- }
353
-
354
- .flowdrop-workflow-node:focus-visible {
355
- outline: 2px solid var(--fd-ring);
356
- outline-offset: 2px;
357
- }
358
-
359
- .flowdrop-workflow-node__header {
360
- box-sizing: border-box;
361
- padding: var(--fd-node-header-gap) var(--fd-space-xl);
362
- border-bottom: 1px solid var(--fd-border-muted);
363
- background: var(--fd-header);
364
- border-top-left-radius: var(--fd-radius-xl);
365
- border-top-right-radius: var(--fd-radius-xl);
366
- display: flex;
367
- flex-direction: column;
368
- gap: var(--fd-node-header-gap);
369
- min-height: calc(
370
- var(--fd-node-header-gap) * 2 + var(--fd-node-header-title-height) +
371
- var(--fd-node-header-desc-line)
372
- );
373
- }
374
-
375
- .flowdrop-workflow-node__header-title {
376
- display: flex;
377
- align-items: center;
378
- gap: var(--fd-space-md);
379
- min-height: var(--fd-node-header-title-height);
380
- flex-shrink: 0;
381
- }
382
-
383
- .flowdrop-workflow-node__header-desc {
384
- margin: 0;
385
- font-size: var(--fd-text-xs);
386
- color: var(--fd-muted-foreground);
387
- line-height: var(--fd-node-header-desc-line);
388
- min-height: var(--fd-node-header-desc-line);
389
- overflow: hidden;
390
- text-overflow: ellipsis;
391
- display: -webkit-box;
392
- -webkit-line-clamp: 3;
393
- line-clamp: 3;
394
- -webkit-box-orient: vertical;
395
- }
396
-
397
- /* Squircle icon wrapper - Apple-style rounded square background */
398
- .flowdrop-workflow-node__icon-wrapper {
399
- display: flex;
400
- align-items: center;
401
- justify-content: center;
402
- width: 2.25rem;
403
- height: 2.25rem;
404
- border-radius: 0.5rem;
405
- background: color-mix(in srgb, var(--_icon-color) var(--fd-node-icon-bg-opacity), transparent);
406
- flex-shrink: 0;
407
- transition: all var(--fd-transition-normal);
408
- }
409
-
410
- .flowdrop-workflow-node:hover .flowdrop-workflow-node__icon-wrapper {
411
- background: color-mix(
412
- in srgb,
413
- var(--_icon-color) var(--fd-node-icon-bg-opacity-hover),
414
- transparent
415
- );
416
- transform: scale(1.05);
417
- }
418
-
419
- .flowdrop-workflow-node__icon-wrapper :global(.flowdrop-workflow-node__icon) {
420
- width: 1.25rem;
421
- height: 1.25rem;
422
- color: var(--fd-node-icon);
423
- }
424
-
425
- .flowdrop-workflow-node__header-title h3 {
426
- margin: 0;
427
- line-height: 1;
428
- }
429
-
430
- @keyframes pulse {
431
- 0%,
432
- 100% {
433
- opacity: 1;
434
- }
435
- 50% {
436
- opacity: 0.5;
437
- }
438
- }
439
-
440
- .flowdrop-workflow-node__ports {
441
- padding: 0;
442
- }
443
-
444
- .flowdrop-workflow-node__ports-list {
445
- display: flex;
446
- flex-direction: column;
447
- gap: var(--fd-node-header-gap);
448
- padding: var(--fd-node-header-gap) 0;
449
- }
450
-
451
- .flowdrop-workflow-node__port {
452
- display: flex;
453
- align-items: center;
454
- gap: 0;
455
- min-height: var(--fd-node-port-row-height);
456
- padding: var(--fd-space-3xs) 0;
457
- position: relative;
458
- }
459
-
460
- .flowdrop-workflow-node__port-content {
461
- padding: 0 var(--fd-space-xl);
462
- }
463
-
464
- .flowdrop-badge {
465
- padding: 0.125rem var(--fd-space-3xs);
466
- border-radius: var(--fd-radius-sm);
467
- font-size: 0.625rem;
468
- font-weight: 500;
469
- text-transform: uppercase;
470
- letter-spacing: 0.05em;
471
- }
472
-
473
- .flowdrop-badge--error {
474
- background-color: var(--fd-error);
475
- color: var(--fd-error-foreground);
476
- }
477
-
478
- .flowdrop-badge--sm {
479
- font-size: 0.625rem;
480
- padding: 0.125rem var(--fd-space-3xs);
481
- }
482
-
483
- /* Handle overrides: hover scale (base 20px/12px from base.css) */
484
- :global(.flowdrop-workflow-node__handle:hover) {
485
- transform: translateY(-50%) scale(1.2);
486
- }
487
-
488
- /* Utility classes */
489
- .flowdrop-flex {
490
- display: flex;
491
- }
492
-
493
- .flowdrop-flex--1 {
494
- flex: 1;
495
- }
496
-
497
- .flowdrop-gap--2 {
498
- gap: var(--fd-space-xs);
499
- }
500
-
501
- .flowdrop-items--center {
502
- align-items: center;
503
- }
504
-
505
- .flowdrop-justify--end {
506
- justify-content: flex-end;
507
- }
508
-
509
- .flowdrop-min-w--0 {
510
- min-width: 0;
511
- }
512
-
513
- .flowdrop-text--xs {
514
- font-size: var(--fd-text-xs);
515
- line-height: 1rem;
516
- }
517
-
518
- .flowdrop-text--sm {
519
- font-size: var(--fd-text-sm);
520
- line-height: 1.25rem;
521
- }
522
-
523
- .flowdrop-text--gray {
524
- color: var(--fd-muted-foreground);
525
- }
526
-
527
- .flowdrop-font--medium {
528
- font-weight: 500;
529
- }
530
-
531
- .flowdrop-truncate {
532
- overflow: hidden;
533
- text-overflow: ellipsis;
534
- white-space: nowrap;
535
- }
536
-
537
- .flowdrop-text--right {
538
- text-align: right;
539
- }
540
-
541
- .flowdrop-workflow-node__config-btn {
542
- position: absolute;
543
- top: var(--fd-space-xs);
544
- right: var(--fd-space-xs);
545
- width: 1.5rem;
546
- height: 1.5rem;
547
- background-color: var(--fd-backdrop);
548
- border: 1px solid var(--fd-border);
549
- border-radius: var(--fd-radius-sm);
550
- color: var(--fd-muted-foreground);
551
- cursor: pointer;
552
- display: flex;
553
- align-items: center;
554
- justify-content: center;
555
- opacity: 0;
556
- transition: all var(--fd-transition-normal);
557
- backdrop-filter: var(--fd-backdrop-blur);
558
- z-index: 15;
559
- font-size: var(--fd-text-sm);
560
- }
561
-
562
- .flowdrop-workflow-node:hover .flowdrop-workflow-node__config-btn {
563
- opacity: 1;
564
- }
565
-
566
- .flowdrop-workflow-node__config-btn:hover {
567
- background-color: var(--fd-muted);
568
- border-color: var(--fd-border-strong);
569
- color: var(--fd-foreground);
570
- }
375
+ .flowdrop-workflow-node {
376
+ position: relative;
377
+ background-color: var(--fd-card);
378
+ border: 1.5px solid var(--fd-node-border);
379
+ border-radius: var(--fd-radius-xl);
380
+ box-shadow: var(--fd-shadow-md);
381
+ width: var(--fd-node-default-width);
382
+ z-index: 10;
383
+ color: var(--fd-foreground);
384
+ transition: all var(--fd-transition-fast);
385
+ }
386
+
387
+ .flowdrop-workflow-node:hover {
388
+ box-shadow: var(--fd-shadow-lg);
389
+ border-color: var(--fd-node-border-hover);
390
+ }
391
+
392
+ .flowdrop-workflow-node--selected {
393
+ box-shadow:
394
+ 0 0 0 2px var(--fd-primary-muted),
395
+ var(--fd-shadow-lg);
396
+ border-color: var(--fd-primary);
397
+ }
398
+
399
+ .flowdrop-workflow-node--selected:hover {
400
+ box-shadow:
401
+ 0 0 0 2px var(--fd-primary-muted),
402
+ var(--fd-shadow-lg);
403
+ border-color: var(--fd-primary);
404
+ }
405
+
406
+ .flowdrop-workflow-node:focus-visible {
407
+ outline: 2px solid var(--fd-ring);
408
+ outline-offset: 2px;
409
+ }
410
+
411
+ .flowdrop-workflow-node__header {
412
+ box-sizing: border-box;
413
+ padding: var(--fd-node-header-gap) var(--fd-space-xl);
414
+ border-bottom: 1px solid var(--fd-border-muted);
415
+ background: var(--fd-header);
416
+ border-top-left-radius: var(--fd-radius-xl);
417
+ border-top-right-radius: var(--fd-radius-xl);
418
+ display: flex;
419
+ flex-direction: column;
420
+ gap: var(--fd-node-header-gap);
421
+ min-height: calc(
422
+ var(--fd-node-header-gap) * 2 + var(--fd-node-header-title-height) +
423
+ var(--fd-node-header-desc-line)
424
+ );
425
+ }
426
+
427
+ .flowdrop-workflow-node__header-title {
428
+ display: flex;
429
+ align-items: center;
430
+ gap: var(--fd-space-md);
431
+ min-height: var(--fd-node-header-title-height);
432
+ flex-shrink: 0;
433
+ }
434
+
435
+ .flowdrop-workflow-node__header-desc {
436
+ margin: 0;
437
+ font-size: var(--fd-text-xs);
438
+ color: var(--fd-muted-foreground);
439
+ line-height: var(--fd-node-header-desc-line);
440
+ min-height: var(--fd-node-header-desc-line);
441
+ overflow: hidden;
442
+ text-overflow: ellipsis;
443
+ display: -webkit-box;
444
+ -webkit-line-clamp: 3;
445
+ line-clamp: 3;
446
+ -webkit-box-orient: vertical;
447
+ }
448
+
449
+ /* Squircle icon wrapper - Apple-style rounded square background */
450
+ .flowdrop-workflow-node__icon-wrapper {
451
+ display: var(--fd-node-icon-display, flex);
452
+ align-items: center;
453
+ justify-content: center;
454
+ width: 2.25rem;
455
+ height: 2.25rem;
456
+ border-radius: 0.5rem;
457
+ background: color-mix(
458
+ in srgb,
459
+ var(--_icon-color) var(--fd-node-icon-bg-opacity),
460
+ transparent
461
+ );
462
+ flex-shrink: 0;
463
+ transition: all var(--fd-transition-normal);
464
+ }
465
+
466
+ .flowdrop-workflow-node:hover .flowdrop-workflow-node__icon-wrapper {
467
+ background: color-mix(
468
+ in srgb,
469
+ var(--_icon-color) var(--fd-node-icon-bg-opacity-hover),
470
+ transparent
471
+ );
472
+ transform: scale(1.05);
473
+ }
474
+
475
+ .flowdrop-workflow-node__icon-wrapper :global(.flowdrop-workflow-node__icon) {
476
+ width: 1.25rem;
477
+ height: 1.25rem;
478
+ color: var(--fd-node-icon);
479
+ }
480
+
481
+ /* Circle dot icon — shown in minimal skin via --fd-node-circle-display */
482
+ .flowdrop-workflow-node__color-dot {
483
+ width: 10px;
484
+ height: 10px;
485
+ border-radius: 50%;
486
+ flex-shrink: 0;
487
+ display: var(--fd-node-circle-display, none);
488
+ }
489
+
490
+ .flowdrop-workflow-node__header-title h3 {
491
+ margin: 0;
492
+ line-height: 1;
493
+ }
494
+
495
+ @keyframes pulse {
496
+ 0%,
497
+ 100% {
498
+ opacity: 1;
499
+ }
500
+ 50% {
501
+ opacity: 0.5;
502
+ }
503
+ }
504
+
505
+ .flowdrop-workflow-node__ports {
506
+ padding: 0;
507
+ }
508
+
509
+ .flowdrop-workflow-node__ports-list {
510
+ display: flex;
511
+ flex-direction: column;
512
+ gap: var(--fd-node-header-gap);
513
+ padding: var(--fd-node-header-gap) 0;
514
+ }
515
+
516
+ .flowdrop-workflow-node__port {
517
+ display: flex;
518
+ align-items: center;
519
+ gap: 0;
520
+ min-height: var(--fd-node-port-row-height);
521
+ padding: var(--fd-space-3xs) 0;
522
+ position: relative;
523
+ }
524
+
525
+ .flowdrop-workflow-node__port-content {
526
+ padding: 0 var(--fd-space-xl);
527
+ }
528
+
529
+ .flowdrop-badge {
530
+ padding: 0.125rem var(--fd-space-3xs);
531
+ border-radius: var(--fd-radius-sm);
532
+ font-size: 0.625rem;
533
+ font-weight: 500;
534
+ text-transform: uppercase;
535
+ letter-spacing: 0.05em;
536
+ }
537
+
538
+ .flowdrop-badge--error {
539
+ background-color: var(--fd-error);
540
+ color: var(--fd-error-foreground);
541
+ }
542
+
543
+ .flowdrop-badge--sm {
544
+ font-size: 0.625rem;
545
+ padding: 0.125rem var(--fd-space-3xs);
546
+ }
547
+
548
+ /* Handle overrides: hover scale (base 20px/12px from base.css) */
549
+ :global(.flowdrop-workflow-node__handle:hover) {
550
+ transform: translateY(-50%) scale(1.2);
551
+ }
552
+
553
+ /* Utility classes */
554
+ .flowdrop-flex {
555
+ display: flex;
556
+ }
557
+
558
+ .flowdrop-flex--1 {
559
+ flex: 1;
560
+ }
561
+
562
+ .flowdrop-gap--2 {
563
+ gap: var(--fd-space-xs);
564
+ }
565
+
566
+ .flowdrop-items--center {
567
+ align-items: center;
568
+ }
569
+
570
+ .flowdrop-justify--end {
571
+ justify-content: flex-end;
572
+ }
573
+
574
+ .flowdrop-min-w--0 {
575
+ min-width: 0;
576
+ }
577
+
578
+ .flowdrop-text--xs {
579
+ font-size: var(--fd-text-xs);
580
+ line-height: 1rem;
581
+ }
582
+
583
+ .flowdrop-text--sm {
584
+ font-size: var(--fd-text-sm);
585
+ line-height: 1.25rem;
586
+ }
587
+
588
+ .flowdrop-text--gray {
589
+ color: var(--fd-muted-foreground);
590
+ }
591
+
592
+ .flowdrop-font--medium {
593
+ font-weight: 500;
594
+ }
595
+
596
+ .flowdrop-truncate {
597
+ overflow: hidden;
598
+ text-overflow: ellipsis;
599
+ white-space: nowrap;
600
+ }
601
+
602
+ .flowdrop-text--right {
603
+ text-align: right;
604
+ }
605
+
606
+ .flowdrop-workflow-node__config-btn :global(svg) {
607
+ width: 14px;
608
+ height: 14px;
609
+ }
610
+
611
+ .flowdrop-workflow-node__config-btn {
612
+ position: absolute;
613
+ top: var(--fd-space-xs);
614
+ right: var(--fd-space-xs);
615
+ width: 1.5rem;
616
+ height: 1.5rem;
617
+ background-color: var(--fd-backdrop);
618
+ border: 1px solid var(--fd-border);
619
+ border-radius: var(--fd-radius-sm);
620
+ color: var(--fd-muted-foreground);
621
+ cursor: pointer;
622
+ display: flex;
623
+ align-items: center;
624
+ justify-content: center;
625
+ opacity: 0;
626
+ transition: all var(--fd-transition-normal);
627
+ backdrop-filter: var(--fd-backdrop-blur);
628
+ z-index: 15;
629
+ font-size: var(--fd-text-sm);
630
+ }
631
+
632
+ .flowdrop-workflow-node:hover .flowdrop-workflow-node__config-btn {
633
+ opacity: 1;
634
+ }
635
+
636
+ .flowdrop-workflow-node__config-btn:hover {
637
+ background-color: var(--fd-muted);
638
+ border-color: var(--fd-border-strong);
639
+ color: var(--fd-foreground);
640
+ }
571
641
  </style>