@kiberon-labs/behave-graph-flow 1.0.0 → 3.0.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 (378) hide show
  1. package/.fallowrc.json +16 -0
  2. package/.storybook/main.ts +32 -0
  3. package/.storybook/manager.ts +6 -0
  4. package/.storybook/preview.ts +64 -0
  5. package/.storybook/styles.css +16 -0
  6. package/.turbo/turbo-build.log +7 -0
  7. package/CHANGELOG.md +368 -0
  8. package/LICENSE +6 -0
  9. package/README.md +2 -2
  10. package/data/Polynomial.json +510 -0
  11. package/data/sequence.json +337 -0
  12. package/data/trigger-event.json +241 -0
  13. package/data/variable-change.json +210 -0
  14. package/dist/AnyControlImpl-Ds-CShIB.js +20 -0
  15. package/dist/AnyControlImpl-Ds-CShIB.js.map +1 -0
  16. package/dist/DocumentationBrowserPanelImpl-deZNzFX8.js +166 -0
  17. package/dist/DocumentationBrowserPanelImpl-deZNzFX8.js.map +1 -0
  18. package/dist/entry.css +4 -0
  19. package/dist/index.css +42 -0
  20. package/dist/index.css.map +1 -0
  21. package/dist/index.d.ts +3597 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +18009 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/noteImpl-KkrrWgJd.js +242 -0
  26. package/dist/noteImpl-KkrrWgJd.js.map +1 -0
  27. package/dist/styles.module-CvmpDkZj.css +3 -0
  28. package/dist/styles.module-CvmpDkZj.css.map +1 -0
  29. package/dist/styles.module-DZxg8aW9.js +271 -0
  30. package/dist/styles.module-DZxg8aW9.js.map +1 -0
  31. package/dist/useChangeNodeData-ChQGK7AI.js +23 -0
  32. package/dist/useChangeNodeData-ChQGK7AI.js.map +1 -0
  33. package/docs/notifications.md +246 -0
  34. package/docs/protocol.md +702 -0
  35. package/docs/specifics.md +191 -0
  36. package/package.json +82 -22
  37. package/postcss.config.ts +3 -4
  38. package/src/annotations/index.ts +32 -0
  39. package/src/components/FloatingToolbar/index.module.css +37 -0
  40. package/src/components/FloatingToolbar/index.tsx +256 -0
  41. package/src/components/Flow.tsx +287 -75
  42. package/src/components/contextMenus/DynamicContextMenu.tsx +85 -0
  43. package/src/components/contextMenus/NodePicker.module.css +274 -0
  44. package/src/components/contextMenus/NodePicker.tsx +481 -0
  45. package/src/components/contextMenus/edge.tsx +22 -0
  46. package/src/components/contextMenus/node.tsx +15 -0
  47. package/src/components/contextMenus/selection.tsx +11 -0
  48. package/src/components/controls/any/AnyControlImpl.tsx +14 -0
  49. package/src/components/controls/any/index.tsx +19 -0
  50. package/src/components/controls/boolean/index.tsx +13 -0
  51. package/src/components/controls/colorPicker/InputPopover.module.css +100 -0
  52. package/src/components/controls/colorPicker/InputPopover.tsx +31 -0
  53. package/src/components/controls/colorPicker/index.module.css +18 -0
  54. package/src/components/controls/colorPicker/index.tsx +61 -0
  55. package/src/components/controls/number/index.tsx +35 -0
  56. package/src/components/controls/string/index.tsx +16 -0
  57. package/src/components/edges/index.tsx +475 -0
  58. package/src/components/edges/offsetBezier.ts +134 -0
  59. package/src/components/hotKeys.tsx +20 -0
  60. package/src/components/layoutController/index.module.css +13 -0
  61. package/src/components/layoutController/index.tsx +140 -0
  62. package/src/components/layoutController/utils.ts +248 -0
  63. package/src/components/menubar/defaults.tsx +516 -0
  64. package/src/components/menubar/index.tsx +49 -0
  65. package/src/components/menubar/menuItem.module.css +31 -0
  66. package/src/components/menubar/menuItem.tsx +65 -0
  67. package/src/components/nodes/behave/Node.module.css +23 -0
  68. package/src/components/nodes/behave/Node.tsx +176 -0
  69. package/src/components/nodes/behave/NodeContainer.module.css +88 -0
  70. package/src/components/nodes/behave/NodeContainer.tsx +46 -0
  71. package/src/components/nodes/behave/index.tsx +14 -0
  72. package/src/components/nodes/group/index.tsx +109 -0
  73. package/src/components/nodes/wrapper/index.tsx +73 -0
  74. package/src/components/nodes/wrapper/styles.module.css +87 -0
  75. package/src/components/notifications/NotificationProvider.tsx +81 -0
  76. package/src/components/notifications/index.ts +2 -0
  77. package/src/components/notifications/utils.ts +71 -0
  78. package/src/components/panels/alignment/index.module.css +10 -0
  79. package/src/components/panels/alignment/index.tsx +244 -0
  80. package/src/components/panels/base/index.tsx +5 -0
  81. package/src/components/panels/base/styles.module.css +12 -0
  82. package/src/components/panels/common/PanelHeader.module.css +24 -0
  83. package/src/components/panels/common/PanelHeader.tsx +22 -0
  84. package/src/components/panels/common/SectionTitle.module.css +13 -0
  85. package/src/components/panels/common/SectionTitle.tsx +10 -0
  86. package/src/components/panels/events/EditEventPanel.tsx +324 -0
  87. package/src/components/panels/events/ManageEventsPanel.tsx +101 -0
  88. package/src/components/panels/events/index.tsx +23 -0
  89. package/src/components/panels/events/styles.module.css +178 -0
  90. package/src/components/panels/graphProperties/index.tsx +125 -0
  91. package/src/components/panels/history/index.tsx +92 -0
  92. package/src/components/panels/history/styles.module.css +97 -0
  93. package/src/components/panels/keymaps/index.module.css +68 -0
  94. package/src/components/panels/keymaps/index.tsx +166 -0
  95. package/src/components/panels/layers/index.tsx +245 -0
  96. package/src/components/panels/layers/styles.module.css +107 -0
  97. package/src/components/panels/legend/index.module.css +6 -0
  98. package/src/components/panels/legend/index.tsx +76 -0
  99. package/src/components/panels/logs/index.module.css +218 -0
  100. package/src/components/panels/logs/index.tsx +288 -0
  101. package/src/components/panels/nodeInputs/InputControl.tsx +63 -0
  102. package/src/components/panels/nodeInputs/InputsGroup.tsx +65 -0
  103. package/src/components/panels/nodeInputs/MultipleNodesView.tsx +37 -0
  104. package/src/components/panels/nodeInputs/NodeSettings.tsx +92 -0
  105. package/src/components/panels/nodeInputs/NodeTitleEditor.tsx +125 -0
  106. package/src/components/panels/nodeInputs/OutputsGroup.tsx +55 -0
  107. package/src/components/panels/nodeInputs/SocketGenerators.tsx +32 -0
  108. package/src/components/panels/nodeInputs/index.module.css +308 -0
  109. package/src/components/panels/nodeInputs/index.tsx +349 -0
  110. package/src/components/panels/nodeInputs/useNodeHandlers.ts +76 -0
  111. package/src/components/panels/nodeInputs/useNodeInputsData.ts +153 -0
  112. package/src/components/panels/nodePicker/index.tsx +115 -0
  113. package/src/components/panels/panel/index.module.css +66 -0
  114. package/src/components/panels/panel/index.tsx +88 -0
  115. package/src/components/panels/search/index.module.css +16 -0
  116. package/src/components/panels/search/index.tsx +215 -0
  117. package/src/components/panels/systemSettings/ConversionsSettings.tsx +203 -0
  118. package/src/components/panels/systemSettings/index.tsx +251 -0
  119. package/src/components/panels/systemSettings/styles.module.css +138 -0
  120. package/src/components/panels/traces/GridLines.tsx +38 -0
  121. package/src/components/panels/traces/TimeGrid.tsx +48 -0
  122. package/src/components/panels/traces/TraceLane.tsx +62 -0
  123. package/src/components/panels/traces/TraceTooltip.tsx +22 -0
  124. package/src/components/panels/traces/TracesHeader.tsx +56 -0
  125. package/src/components/panels/traces/index.module.css +159 -0
  126. package/src/components/panels/traces/index.tsx +298 -0
  127. package/src/components/panels/traces/types.ts +48 -0
  128. package/src/components/panels/traces/useDerivedSpans.ts +307 -0
  129. package/src/components/panels/traces/utils.ts +33 -0
  130. package/src/components/panels/variables/CreateVariableScreen.tsx +162 -0
  131. package/src/components/panels/variables/ManageVariablesScreen.tsx +147 -0
  132. package/src/components/panels/variables/index.tsx +125 -0
  133. package/src/components/panels/variables/styles.module.css +149 -0
  134. package/src/components/primitives/icon.module.css +45 -0
  135. package/src/components/primitives/icon.tsx +38 -0
  136. package/src/components/sockets/input/index.tsx +83 -0
  137. package/src/components/sockets/input/styles.module.css +26 -0
  138. package/src/components/sockets/output/index.tsx +68 -0
  139. package/src/components/sockets/output/styles.module.css +22 -0
  140. package/src/css/notes.css +135 -0
  141. package/src/css/prosemirror.css +57 -0
  142. package/src/css/rc-dock.css +212 -0
  143. package/src/css/rc-menu.css +101 -0
  144. package/src/css/themes/kiberon.css +127 -0
  145. package/src/css/vars.css +198 -0
  146. package/src/css/vscode-elements.css +124 -0
  147. package/src/entry.css +4 -0
  148. package/src/generators/CallSubgraphGenerator.tsx +136 -0
  149. package/src/generators/CustomEventOnTriggeredGenerator.tsx +85 -0
  150. package/src/generators/GraphBoundaryGenerator.module.css +32 -0
  151. package/src/generators/GraphBoundaryGenerator.tsx +193 -0
  152. package/src/generators/SequenceGenerator.tsx +104 -0
  153. package/src/generators/SwitchOnIntegerGenerator.tsx +256 -0
  154. package/src/generators/SwitchOnStringGenerator.tsx +263 -0
  155. package/src/generators/callSubgraphSync.ts +126 -0
  156. package/src/generators/registerDefaultGenerators.ts +55 -0
  157. package/src/generators/registerDefaults.ts +26 -0
  158. package/src/hooks/useBehaveGraphFlow.ts +17 -16
  159. package/src/hooks/useFlowHandlers.ts +154 -30
  160. package/src/hooks/useWasdPan.ts +210 -0
  161. package/src/index.css +134 -0
  162. package/src/index.ts +53 -18
  163. package/src/manifest/contributionRegistry.ts +93 -0
  164. package/src/manifest/index.ts +4 -0
  165. package/src/manifest/loadManifest.ts +82 -0
  166. package/src/manifest/manifestPlugin.ts +29 -0
  167. package/src/manifest/passthroughValueType.ts +40 -0
  168. package/src/plugin/alignment/index.ts +91 -0
  169. package/src/plugin/autosave/controller.ts +366 -0
  170. package/src/plugin/autosave/index.tsx +114 -0
  171. package/src/plugin/autosave/panel/BackupPanel.tsx +141 -0
  172. package/src/plugin/autosave/panel/index.tsx +1 -0
  173. package/src/plugin/autosave/panel/styles.module.css +56 -0
  174. package/src/plugin/autosave/settings.ts +65 -0
  175. package/src/plugin/autosave/storage.ts +147 -0
  176. package/src/plugin/docs/index.tsx +297 -0
  177. package/src/plugin/docs/panel/DocumentationBrowserPanelImpl.tsx +200 -0
  178. package/src/plugin/docs/panel/index.tsx +21 -0
  179. package/src/plugin/docs/panel/styles.module.css +174 -0
  180. package/src/plugin/graphrunner/actions.ts +326 -0
  181. package/src/plugin/graphrunner/buttons.tsx +95 -0
  182. package/src/plugin/graphrunner/client.ts +707 -0
  183. package/src/plugin/graphrunner/index.tsx +184 -0
  184. package/src/plugin/graphrunner/panel.tsx +386 -0
  185. package/src/plugin/graphrunner/runController.ts +283 -0
  186. package/src/plugin/graphrunner/runner.ts +187 -0
  187. package/src/plugin/graphrunner/session.ts +243 -0
  188. package/src/plugin/graphrunner/store.ts +196 -0
  189. package/src/plugin/graphrunner/styles.module.css +171 -0
  190. package/src/plugin/graphrunner/transport.ts +250 -0
  191. package/src/plugin/graphrunner/types.ts +693 -0
  192. package/src/plugin/graphrunner-local/execution-utils.ts +637 -0
  193. package/src/plugin/graphrunner-local/index.tsx +172 -0
  194. package/src/plugin/graphrunner-local/panel.tsx +187 -0
  195. package/src/plugin/graphrunner-local/store.ts +41 -0
  196. package/src/plugin/graphrunner-local/styles.module.css +82 -0
  197. package/src/plugin/graphrunner-local/transport.ts +1339 -0
  198. package/src/plugin/graphrunner-local/types.ts +10 -0
  199. package/src/plugin/graphrunner-webworker/graph-executor.worker.ts +635 -0
  200. package/src/plugin/graphrunner-webworker/index.tsx +140 -0
  201. package/src/plugin/graphrunner-webworker/panel.tsx +173 -0
  202. package/src/plugin/graphrunner-webworker/store.ts +98 -0
  203. package/src/plugin/graphrunner-webworker/worker-transport.ts +123 -0
  204. package/src/plugin/kitchen-sink/index.ts +38 -0
  205. package/src/plugin/layout/dagre.ts +131 -0
  206. package/src/plugin/layout/elk.ts +216 -0
  207. package/src/plugin/layout/index.ts +80 -0
  208. package/src/plugin/notes/FormatToolbar.tsx +200 -0
  209. package/src/plugin/notes/index.tsx +191 -0
  210. package/src/plugin/notes/nodeActions.ts +100 -0
  211. package/src/plugin/notes/note.tsx +20 -0
  212. package/src/plugin/notes/noteImpl.tsx +89 -0
  213. package/src/plugin/realtime/realtimeRunner.ts +624 -0
  214. package/src/specifics/CustomEventOnTriggeredSpecific.tsx +92 -0
  215. package/src/specifics/CustomEventTriggerSpecific.tsx +141 -0
  216. package/src/specifics/VariableGetSpecific.tsx +110 -0
  217. package/src/specifics/VariableSetSpecific.tsx +110 -0
  218. package/src/store/actions.tsx +698 -0
  219. package/src/store/commands.ts +278 -0
  220. package/src/store/contextMenu.ts +192 -0
  221. package/src/store/controls.tsx +62 -0
  222. package/src/store/conversions.ts +47 -0
  223. package/src/store/documentation.tsx +69 -0
  224. package/src/store/events.tsx +116 -0
  225. package/src/store/flow.tsx +230 -0
  226. package/src/store/graphMeta.ts +39 -0
  227. package/src/store/hotKeys.tsx +364 -0
  228. package/src/store/layers.ts +259 -0
  229. package/src/store/legend.tsx +76 -0
  230. package/src/store/logs.ts +28 -0
  231. package/src/store/menubar.ts +41 -0
  232. package/src/store/refs.ts +84 -0
  233. package/src/store/registry.ts +51 -0
  234. package/src/store/selection.ts +22 -0
  235. package/src/store/settings.ts +99 -0
  236. package/src/store/settingsSchema.ts +210 -0
  237. package/src/store/socketGenerator.tsx +54 -0
  238. package/src/store/specific.tsx +75 -0
  239. package/src/store/specs.tsx +35 -0
  240. package/src/store/tabs.ts +282 -0
  241. package/src/store/toolbar.tsx +45 -0
  242. package/src/store/traces.ts +240 -0
  243. package/src/store/variables.ts +37 -0
  244. package/src/system/graph.ts +131 -0
  245. package/src/system/graphSession.ts +172 -0
  246. package/src/system/index.ts +6 -0
  247. package/src/system/notifications.ts +111 -0
  248. package/src/system/persistence.ts +82 -0
  249. package/src/system/plugin.ts +55 -0
  250. package/src/system/provider.tsx +86 -0
  251. package/src/system/pubsub.ts +323 -0
  252. package/src/system/system.ts +653 -0
  253. package/src/system/tabLoader.tsx +303 -0
  254. package/src/system/undoRedo.ts +103 -0
  255. package/src/transformers/Uigraph.ts +61 -0
  256. package/src/transformers/behaveToFlow.ts +16 -4
  257. package/src/transformers/contract.ts +87 -0
  258. package/src/transformers/flowToBehave.ts +40 -12
  259. package/src/types/NodeMetadata.ts +27 -0
  260. package/src/types/graph.ts +49 -0
  261. package/src/types/nodes.ts +50 -0
  262. package/src/types.ts +18 -0
  263. package/src/util/autoConvert.ts +200 -0
  264. package/src/util/colors.ts +1 -29
  265. package/src/util/downloadJson.ts +18 -0
  266. package/src/util/extractNodeMetadata.ts +16 -0
  267. package/src/util/getPickerFilters.ts +1 -1
  268. package/src/util/isBehaveNode.ts +6 -0
  269. package/src/util/isValidConnection.ts +51 -17
  270. package/src/util/mergeSockets.ts +29 -0
  271. package/src/util/serializeVariables.ts +66 -0
  272. package/src/util/sockets.ts +43 -0
  273. package/stories/apex/layoutController/example-graph.worker.ts +39 -0
  274. package/stories/apex/layoutController/index.stories.tsx +48 -0
  275. package/stories/apex/layoutController/webworker.stories.tsx +103 -0
  276. package/stories/apex/menubar/menubar.stories.tsx +19 -0
  277. package/stories/components/colorpicker/index.stories.tsx +20 -0
  278. package/stories/components/contextMenus/edge.stories.tsx +32 -0
  279. package/stories/components/contextMenus/node.stories.tsx +26 -0
  280. package/stories/components/contextMenus/nodePicker.stories.tsx +115 -0
  281. package/stories/components/controls/any/index.stories.tsx +19 -0
  282. package/stories/components/controls/boolean/index.stories.tsx +19 -0
  283. package/stories/components/controls/colorPicker/index.stories.tsx +49 -0
  284. package/stories/components/controls/number/index.stories.tsx +19 -0
  285. package/stories/components/controls/string/index.stories.tsx +19 -0
  286. package/stories/components/nodes/behaveNode.stories.tsx +108 -0
  287. package/stories/components/panels/alignment.stories.tsx +24 -0
  288. package/stories/components/panels/events.stories.tsx +38 -0
  289. package/stories/components/panels/graphRunner.stories.tsx +317 -0
  290. package/stories/components/panels/history.stories.tsx +37 -0
  291. package/stories/components/panels/keymaps.stories.tsx +21 -0
  292. package/stories/components/panels/legend.stories.tsx +37 -0
  293. package/stories/components/panels/logs.stories.tsx +24 -0
  294. package/stories/components/panels/nodeInputs.stories.tsx +21 -0
  295. package/stories/components/panels/nodePicker.stories.tsx +37 -0
  296. package/stories/components/panels/panel.stories.tsx +39 -0
  297. package/stories/components/panels/search.stories.tsx +24 -0
  298. package/stories/components/panels/systemSettings.stories.tsx +26 -0
  299. package/stories/components/panels/traces.stories.tsx +225 -0
  300. package/stories/components/panels/variables.stories.tsx +24 -0
  301. package/stories/defaults/defaultStoryProvider.tsx +170 -0
  302. package/stories/defaults/systemGenerator.ts +43 -0
  303. package/stories/plugins/notes.stories.tsx +100 -0
  304. package/tests/autoConvert.test.ts +329 -0
  305. package/tests/autosavePlugin.test.ts +204 -0
  306. package/tests/callSubgraphSync.test.ts +148 -0
  307. package/tests/commandRegistry.test.ts +137 -0
  308. package/tests/components/edges/offsetBezier.test.ts +51 -0
  309. package/tests/components/layoutController/utils.test.ts +68 -0
  310. package/tests/components/panels/traces/utils.test.ts +52 -0
  311. package/tests/contract.test.ts +51 -0
  312. package/tests/contractSerialize.test.ts +62 -0
  313. package/tests/deriveSpans.test.ts +71 -0
  314. package/tests/flowToBehave.test.ts +27 -4
  315. package/tests/hotkeys.test.ts +79 -0
  316. package/tests/keepAliveLifecycle.test.ts +167 -0
  317. package/tests/loadManifest.test.ts +113 -0
  318. package/tests/noteMarkdown.test.ts +65 -0
  319. package/tests/notesPlugin.test.ts +162 -0
  320. package/tests/notifications.test.ts +87 -0
  321. package/tests/persistence.test.ts +51 -0
  322. package/tests/saveLoad.test.ts +373 -0
  323. package/tests/settings.test.ts +178 -0
  324. package/tests/traceStore.test.ts +46 -0
  325. package/tests/util/calculateNewEdge.test.ts +98 -0
  326. package/tests/util/getSocketsByNodeTypeAndHandleType.test.ts +31 -0
  327. package/tests/util/hasPositionMetaData.test.ts +33 -0
  328. package/tests/util/isBehaveNode.test.ts +22 -0
  329. package/tests/util/isHandleConnected.test.ts +37 -0
  330. package/tests/util/mergeSockets.test.ts +43 -0
  331. package/tests/visual/README.md +64 -0
  332. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-alignment-chromium-win32.png +0 -0
  333. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-conversation-chromium-win32.png +0 -0
  334. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-events-chromium-win32.png +0 -0
  335. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-history-chromium-win32.png +0 -0
  336. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-keymaps-chromium-win32.png +0 -0
  337. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-layers-chromium-win32.png +0 -0
  338. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-legend-chromium-win32.png +0 -0
  339. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-localGraphRunner-chromium-win32.png +0 -0
  340. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-logs-chromium-win32.png +0 -0
  341. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-nodeInputs-chromium-win32.png +0 -0
  342. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-nodePicker-chromium-win32.png +0 -0
  343. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-panel-chromium-win32.png +0 -0
  344. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-search-chromium-win32.png +0 -0
  345. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-systemSettings-chromium-win32.png +0 -0
  346. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-traces-chromium-win32.png +0 -0
  347. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-variables-chromium-win32.png +0 -0
  348. package/tests/visual/panels.visual.test.tsx +76 -0
  349. package/tests/wasdPan.test.ts +71 -0
  350. package/tsconfig.base.json +39 -0
  351. package/tsconfig.json +18 -59
  352. package/tsconfig.prod.json +23 -0
  353. package/tsdown.config.ts +15 -3
  354. package/typedoc.json +7 -7
  355. package/vite.config.js +7 -0
  356. package/vitest.config.ts +5 -2
  357. package/vitest.visual.config.ts +55 -0
  358. package/src/components/AutoSizeInput.tsx +0 -65
  359. package/src/components/Controls.tsx +0 -87
  360. package/src/components/InputSocket.tsx +0 -142
  361. package/src/components/Node.tsx +0 -68
  362. package/src/components/NodeContainer.tsx +0 -46
  363. package/src/components/NodePicker.tsx +0 -77
  364. package/src/components/OutputSocket.tsx +0 -58
  365. package/src/components/modals/ClearModal.tsx +0 -40
  366. package/src/components/modals/HelpModal.tsx +0 -36
  367. package/src/components/modals/LoadModal.tsx +0 -96
  368. package/src/components/modals/Modal.tsx +0 -64
  369. package/src/components/modals/SaveModal.tsx +0 -60
  370. package/src/hooks/useCustomNodeTypes.tsx +0 -31
  371. package/src/hooks/useGraphRunner.ts +0 -104
  372. package/src/hooks/useMergeMap.ts +0 -14
  373. package/src/hooks/useNodeSpecJson.ts +0 -20
  374. package/src/hooks/useQueriableDefinitions.ts +0 -22
  375. package/src/styles.css +0 -8
  376. package/tailwind.config.ts +0 -19
  377. package/tests/tsconfig.json +0 -10
  378. /package/src/{types.d.ts → types-declarations.d.ts} +0 -0
@@ -0,0 +1,191 @@
1
+ # Creating Custom Specifics for Nodes
2
+
3
+ Specifics are UI extensions that add custom controls and functionality to specific node types. They allow you to create dynamic interfaces for nodes with configurable sockets, special controls, or custom rendering.
4
+
5
+ ## What are Specifics?
6
+
7
+ A "specific" is a React component that gets rendered inside a node when certain conditions are met. It's perfect for:
8
+ - Adding/removing dynamic sockets (like the Switch nodes)
9
+ - Custom dropdown controls (like Custom Event selection)
10
+ - Preview panels (like image previews)
11
+ - Any node-specific UI controls
12
+
13
+ ## Creating a Specific
14
+
15
+ A specific consists of three parts:
16
+
17
+ 1. **Check function** - Determines if this specific applies to a node
18
+ 2. **Render component** - The React component to render
19
+ 3. **Unique name** - An identifier for the specific
20
+
21
+ ### Example: Dynamic Socket Management
22
+
23
+ Here's how the SwitchOnString specific works:
24
+
25
+ ```typescript
26
+ import React, { useCallback } from 'react';
27
+ import { VscodeButton } from '@vscode-elements/react-elements';
28
+ import { Plus, Minus } from 'iconoir-react';
29
+ import { useSystem } from '@/system/provider';
30
+ import type { SpecificRenderProps } from '@/store/specific';
31
+
32
+ const NAME = 'flow/switch/string.dynamicSockets';
33
+
34
+ export function getSwitchOnStringSpecific() {
35
+ return {
36
+ name: NAME,
37
+ check: (spec: any) => spec?.type === 'flow/switch/string',
38
+ render: SwitchOnStringSpecific
39
+ };
40
+ }
41
+
42
+ const SwitchOnStringSpecific: React.FC<SpecificRenderProps> = ({ node }) => {
43
+ const system = useSystem();
44
+ const numCases = node.data?.configuration?.numCases ?? 0;
45
+
46
+ const updateNumCases = useCallback(
47
+ (newNumCases: number) => {
48
+ if (newNumCases < 0) return;
49
+
50
+ // Update the node configuration
51
+ system.nodeStore.getState().setNodes((prev) =>
52
+ prev.map((n: any) => {
53
+ if (n.id !== node.id) return n;
54
+ return {
55
+ ...n,
56
+ data: {
57
+ ...n.data,
58
+ configuration: {
59
+ ...n.data?.configuration,
60
+ numCases: newNumCases
61
+ }
62
+ }
63
+ };
64
+ })
65
+ );
66
+
67
+ // Invalidate cache to trigger socket recalculation
68
+ system.flowStore.getState().invalidateCache();
69
+ },
70
+ [node.id, system]
71
+ );
72
+
73
+ const addCase = useCallback(() => {
74
+ updateNumCases(numCases + 1);
75
+ }, [numCases, updateNumCases]);
76
+
77
+ const removeCase = useCallback(() => {
78
+ updateNumCases(Math.max(0, numCases - 1));
79
+ }, [numCases, updateNumCases]);
80
+
81
+ return (
82
+ <div style={{ padding: 8, display: 'flex', flexDirection: 'column', gap: 8 }}>
83
+ <div style={{ fontSize: 12, opacity: 0.9 }}>Cases: {numCases}</div>
84
+ <div style={{ display: 'flex', gap: 4 }}>
85
+ <VscodeButton onClick={addCase}>
86
+ <Plus width={16} height={16} /> Add Case
87
+ </VscodeButton>
88
+ <VscodeButton onClick={removeCase} disabled={numCases === 0}>
89
+ <Minus width={16} height={16} /> Remove
90
+ </VscodeButton>
91
+ </div>
92
+ </div>
93
+ );
94
+ };
95
+ ```
96
+
97
+ ## Registering Specifics
98
+
99
+ ### Built-in Registration
100
+
101
+ Default specifics are automatically registered in `registerDefaultSpecifics`. To add yours:
102
+
103
+ ```typescript
104
+ // In registerDefaultSpecifics.ts
105
+ import { getYourCustomSpecific } from './YourCustomSpecific';
106
+
107
+ export function registerDefaultSpecifics(system: System): () => void {
108
+ const store = system.specificStore.getState();
109
+
110
+ const yourCustom = getYourCustomSpecific();
111
+ store.registerSpecific(yourCustom);
112
+
113
+ return () => {
114
+ system.specificStore.getState().unregisterSpecific(yourCustom.name);
115
+ };
116
+ }
117
+ ```
118
+
119
+ ### External Registration
120
+
121
+ You can also register specifics from external packages:
122
+
123
+ ```typescript
124
+ import { System } from '@kiberon-labs/behave-graph-flow';
125
+ import { getSwitchOnStringSpecific } from '@kiberon-labs/behave-graph-flow';
126
+
127
+ export function registerMyPlugin(system: System) {
128
+ const switchSpecific = getSwitchOnStringSpecific();
129
+ system.specificStore.getState().registerSpecific(switchSpecific);
130
+
131
+ // Or create your own
132
+ const mySpecific = {
133
+ name: 'my-custom-specific',
134
+ check: (spec) => spec.type === 'my/custom/node',
135
+ render: MyCustomComponent
136
+ };
137
+
138
+ system.specificStore.getState().registerSpecific(mySpecific);
139
+ }
140
+ ```
141
+
142
+ ## Key Patterns
143
+
144
+ ### Updating Node Configuration
145
+
146
+ When your specific needs to update node configuration (like changing socket counts):
147
+
148
+ ```typescript
149
+ system.nodeStore.getState().setNodes((prev) =>
150
+ prev.map((n: any) => {
151
+ if (n.id !== node.id) return n;
152
+ return {
153
+ ...n,
154
+ data: {
155
+ ...n.data,
156
+ configuration: {
157
+ ...n.data?.configuration,
158
+ yourConfigKey: newValue
159
+ }
160
+ }
161
+ };
162
+ })
163
+ );
164
+
165
+ // Important: Invalidate cache to recalculate sockets
166
+ system.flowStore.getState().invalidateCache();
167
+ ```
168
+
169
+ ### Accessing Node Data
170
+
171
+ The `node` prop contains:
172
+ - `id` - Node ID
173
+ - `data` - Node data (configuration, ports, annotations)
174
+ - `spec` - Node specification
175
+ - `selected` - Whether node is selected
176
+
177
+ ## Available Specifics
178
+
179
+ Currently registered specifics:
180
+
181
+ 1. **CustomEventOnTriggered** - Dropdown for selecting custom events
182
+ 2. **SwitchOnString** - Add/remove string case sockets
183
+ 3. **SwitchOnInteger** - Add/remove integer case sockets
184
+
185
+ ## Tips
186
+
187
+ - Keep specifics focused on a single node type
188
+ - Use unique names to avoid conflicts
189
+ - Always invalidate the flow cache when changing node configuration that affects sockets
190
+ - Use inline styles or CSS modules (not Tailwind per AI instructions)
191
+ - Leverage the `useSystem` hook to access all system stores
package/package.json CHANGED
@@ -1,42 +1,102 @@
1
1
  {
2
2
  "name": "@kiberon-labs/behave-graph-flow",
3
- "version": "1.0.0",
3
+ "version": "3.0.0",
4
4
  "type": "module",
5
- "types": "./dist/index.d.ts",
5
+ "exports": {
6
+ ".": {
7
+ "import": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "default": "./dist/index.js"
10
+ },
11
+ "./entry.css": "./dist/entry.css",
12
+ "./package.json": "./package.json"
13
+ },
6
14
  "main": "./dist/index.js",
7
- "source": "./src/index.ts",
8
- "scripts": {
9
- "dev": "tsdown --watch src",
10
- "build": "tsdown",
11
- "test": "vitest",
12
- "check": "oxfmt --check",
13
- "format": "oxfmt",
14
- "lint": "oxlint",
15
- "typecheck": "tsc"
15
+ "types": "./dist/index.d.ts",
16
+ "publishConfig": {
17
+ "provenance": true,
18
+ "access": "public"
16
19
  },
17
20
  "devDependencies": {
18
- "@testing-library/react": "^13.3.0",
19
- "@testing-library/user-event": "^13.5.0",
21
+ "@storybook/addon-a11y": "^10.0.8",
22
+ "@storybook/addon-docs": "^10.0.8",
23
+ "@storybook/addon-vitest": "^10.0.8",
24
+ "@storybook/react-vite": "^10.0.8",
25
+ "@types/dagre": "^0.7.53",
26
+ "@types/graphlib": "^2.1.12",
20
27
  "@types/react": "^19.2.6",
21
28
  "@types/uuid": "^8.3.4",
29
+ "@vitest/browser": "^4.0.10",
30
+ "@vitest/browser-playwright": "4.0.10",
22
31
  "autoprefixer": "^10.4.22",
32
+ "fallow": "^2.89.0",
33
+ "happy-dom": "^20.4.0",
34
+ "jsdom": "^27.3.0",
35
+ "oxfmt": "^0.14.0",
23
36
  "oxlint": "^1.29.0",
24
- "react": "^19.2.0",
25
- "tailwindcss": "^4.1.17",
37
+ "playwright": "^1.60.0",
38
+ "react": "19.2.3",
39
+ "react-dom": "19.2.3",
40
+ "reactflow": "^11.11.4",
41
+ "storybook": "^10.0.8",
26
42
  "tsdown": "^0.16.5",
43
+ "unplugin-lightningcss": "^0.4.3",
44
+ "vite": "^7.2.4",
45
+ "vite-tsconfig-paths": "^5.1.4",
27
46
  "vitest": "^4.0.10",
28
- "oxfmt": "^0.14.0"
47
+ "vitest-browser-react": "^2.2.0",
48
+ "@kiberon-labs/behave-graph": "1.2.0"
29
49
  },
50
+ "repository": {
51
+ "type": "git",
52
+ "url": "https://github.com/Kiberon-Labs/behave-graph",
53
+ "directory": "packages/flow"
54
+ },
55
+ "author": "kiberonlabsdev",
56
+ "bugs": "https://github.com/Kiberon-Labs/behave-graph/issues",
30
57
  "dependencies": {
31
- "@fortawesome/fontawesome-svg-core": "^6.1.2",
32
- "@fortawesome/free-solid-svg-icons": "^6.1.2",
33
- "@fortawesome/react-fontawesome": "^0.2.0",
58
+ "@radix-ui/react-popover": "^1.1.15",
59
+ "@reactflow/node-resizer": "^2.2.14",
60
+ "@tiptap/extension-youtube": "^3.27.1",
61
+ "@tiptap/react": "^3.19.0",
62
+ "@tiptap/starter-kit": "^3.19.0",
63
+ "@vscode-elements/react-elements": "^2.4.0",
34
64
  "classnames": "^2.3.1",
35
- "downshift": "^6.1.7",
36
- "uuid": "^8.3.2"
65
+ "clsx": "^2.1.1",
66
+ "copy-to-clipboard": "^3.3.3",
67
+ "dagre": "^0.8.5",
68
+ "elkjs": "^0.11.0",
69
+ "fuse.js": "^7.1.0",
70
+ "graphlib": "^2.1.8",
71
+ "iconoir-react": "^7.11.0",
72
+ "json-edit-react": "^1.29.0",
73
+ "rc-dock": "4.0.0-alpha.2",
74
+ "rc-menu": "^9.16.1",
75
+ "react-colorful": "^5.6.1",
76
+ "react-error-boundary": "^6.0.0",
77
+ "react-hot-toast": "^2.6.0",
78
+ "react-hotkeys": "^2.0.0",
79
+ "tiptap-markdown": "^0.9.0",
80
+ "uuid": "^8.3.2",
81
+ "zustand": "^5.0.8"
37
82
  },
38
83
  "peerDependencies": {
39
84
  "reactflow": "^11.1.1",
40
- "@kiberon-labs/behave-graph": "*"
85
+ "@kiberon-labs/behave-graph": "1.2.0"
86
+ },
87
+ "scripts": {
88
+ "audit": "fallow",
89
+ "dev": "tsdown --watch src",
90
+ "build": "tsdown",
91
+ "release": "npm publish --dry-run",
92
+ "test": "vitest",
93
+ "test:visual": "vitest run --config vitest.visual.config.ts",
94
+ "test:visual:update": "vitest run --config vitest.visual.config.ts --update",
95
+ "check": "oxfmt --check",
96
+ "format": "oxfmt",
97
+ "lint": "oxlint",
98
+ "storybook": "storybook dev -p 6006",
99
+ "build-storybook": "storybook build",
100
+ "typecheck": "tsc --noEmit -p tsconfig.prod.json"
41
101
  }
42
102
  }
package/postcss.config.ts CHANGED
@@ -1,6 +1,5 @@
1
- import autoprefixer from 'autoprefixer';
2
- import tailwindcss from 'tailwindcss';
3
-
4
1
  export default {
5
- plugins: [tailwindcss, autoprefixer]
2
+ plugins: {
3
+ autoprefixer: {}
4
+ }
6
5
  };
@@ -0,0 +1,32 @@
1
+ //Used on ports to indicate meta from a ui
2
+
3
+ /**
4
+ * Indicates that the port can be completely deleted
5
+ */
6
+ export const nonDeletable = 'ui.nonDeletable';
7
+ /**
8
+ * Indicates that the port can be reset to its default value / type
9
+ */
10
+ export const resetable = 'ui.resetable';
11
+ /**
12
+ * Indicates that the port cannot be edited
13
+ */
14
+ export const readonly = 'ui.readonly';
15
+ /**
16
+ * Indicates that the port is hidden from the user
17
+ */
18
+ export const hidden = 'ui.hidden';
19
+
20
+ //Used on nodes and graph
21
+ export const annotatedTitle = 'ui.title';
22
+ export const description = 'ui.description';
23
+ export const executing = 'ui.executing';
24
+ export const pinned = 'ui.pinned';
25
+ export const layerId = 'ui.layerId';
26
+
27
+ //Used exclusively on graph
28
+ export const uiVersion = 'ui.version';
29
+
30
+ export const realtime = 'ui.realtime';
31
+ //UI annotation to detect realtime output nodes, which are used to display outputs in the UI without affecting the actual graph outputs
32
+ export const AnnotatedOutput = 'ui.annotatedOutput';
@@ -0,0 +1,37 @@
1
+ .panel {
2
+ margin: 0.5rem;
3
+ pointer-events: auto;
4
+ }
5
+
6
+ .toolbar {
7
+ display: flex;
8
+ gap: 0.5rem;
9
+ padding: 0.25rem;
10
+ background: var(--ds-widget-bg, #292929);
11
+ border: 1px solid var(--ds-border-subtle, #454545);
12
+ border-radius: 0.375rem;
13
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.36);
14
+ }
15
+
16
+ .buttonGroup {
17
+ display: flex;
18
+ gap: 0.125rem;
19
+ padding: 0.125rem;
20
+ }
21
+
22
+ .buttonGroup vscode-button {
23
+ min-width: 28px;
24
+ height: 28px;
25
+ }
26
+
27
+ .zoomLevel {
28
+ display: flex;
29
+ align-items: center;
30
+ padding: 0 0.5rem;
31
+ font-size: var(--fs-label, 0.8rem);
32
+ font-weight: 500;
33
+ color: var(--ds-fg);
34
+ user-select: none;
35
+ min-width: 3rem;
36
+ justify-content: center;
37
+ }
@@ -0,0 +1,256 @@
1
+ import React, { useCallback, useState, useRef } from 'react';
2
+ import { Panel, useViewport } from 'reactflow';
3
+ import {
4
+ VscodeButton,
5
+ VscodeContextMenu
6
+ } from '@vscode-elements/react-elements';
7
+ import { ZoomIn, ZoomOut, AlignLeft, LayoutRight } from 'iconoir-react';
8
+ import { useGraph } from '@/system/provider';
9
+ import { useStore } from 'zustand';
10
+ import styles from './index.module.css';
11
+ import { useRefFromStore } from '@/system';
12
+ import type { ToolbarButton } from '@/store/toolbar';
13
+ import type { AlignmentAxis, AlignmentType } from '@/plugin/alignment';
14
+
15
+ export const FloatingToolbar: React.FC = () => {
16
+ const session = useGraph();
17
+ const visible = useStore(session.editor.toolbarStore, (x) => x.visible);
18
+ const customGroups = useStore(session.editor.toolbarStore, (x) => x.groups);
19
+ const reactFlowInstance = useRefFromStore(session.refStore, 'reactflow');
20
+ const { zoom } = useViewport();
21
+ const currentZoom = Math.round(zoom * 100);
22
+ const [alignMenuOpen, setAlignMenuOpen] = useState(false);
23
+ const [distributeMenuOpen, setDistributeMenuOpen] = useState(false);
24
+ const [menuPosition, setMenuPosition] = useState({ top: 0, left: 0 });
25
+ const alignBtnRef = useRef<any>(null);
26
+ const distributeBtnRef = useRef<any>(null);
27
+
28
+ const publishAlignment = useCallback(
29
+ (type: AlignmentType, axis: AlignmentAxis) => {
30
+ session.pubsub.publishSync('alignment:align', { type, axis });
31
+ },
32
+ [session]
33
+ );
34
+
35
+ const publishDistribution = useCallback(
36
+ (type: AlignmentType, axis: AlignmentAxis) => {
37
+ session.pubsub.publishSync('alignment:distribute', { type, axis });
38
+ },
39
+ [session]
40
+ );
41
+
42
+ const handleZoomIn = useCallback(() => {
43
+ reactFlowInstance?.zoomIn();
44
+ }, [reactFlowInstance]);
45
+
46
+ const handleZoomOut = useCallback(() => {
47
+ reactFlowInstance?.zoomOut();
48
+ }, [reactFlowInstance]);
49
+
50
+ const handleAlignSelect = useCallback(
51
+ (e: any) => {
52
+ setAlignMenuOpen(false);
53
+ const value = e.detail?.value;
54
+ switch (value) {
55
+ case 'left':
56
+ publishAlignment('start', 'x');
57
+ break;
58
+ case 'center-h':
59
+ publishAlignment('center', 'x');
60
+ break;
61
+ case 'right':
62
+ publishAlignment('end', 'x');
63
+ break;
64
+ case 'top':
65
+ publishAlignment('start', 'y');
66
+ break;
67
+ case 'center-v':
68
+ publishAlignment('center', 'y');
69
+ break;
70
+ case 'bottom':
71
+ publishAlignment('end', 'y');
72
+ break;
73
+ }
74
+ },
75
+ [publishAlignment]
76
+ );
77
+
78
+ const handleDistributeSelect = useCallback(
79
+ (e: any) => {
80
+ setDistributeMenuOpen(false);
81
+ const value = e.detail?.value;
82
+ switch (value) {
83
+ case 'left':
84
+ publishDistribution('start', 'x');
85
+ break;
86
+ case 'center-h':
87
+ publishDistribution('center', 'x');
88
+ break;
89
+ case 'right':
90
+ publishDistribution('end', 'x');
91
+ break;
92
+ case 'top':
93
+ publishDistribution('start', 'y');
94
+ break;
95
+ case 'center-v':
96
+ publishDistribution('center', 'y');
97
+ break;
98
+ case 'bottom':
99
+ publishDistribution('end', 'y');
100
+ break;
101
+ }
102
+ },
103
+ [publishDistribution]
104
+ );
105
+
106
+ if (!visible) return null;
107
+
108
+ return (
109
+ <>
110
+ <Panel position="top-center" className={styles.panel}>
111
+ <div className={styles.toolbar}>
112
+ {/* Zoom Controls */}
113
+ <div className={styles.buttonGroup}>
114
+ <VscodeButton
115
+ secondary
116
+ iconOnly
117
+ title="Zoom In"
118
+ onClick={handleZoomIn}
119
+ >
120
+ <ZoomIn />
121
+ </VscodeButton>
122
+ <span className={styles.zoomLevel}>{currentZoom}%</span>
123
+ <VscodeButton
124
+ secondary
125
+ iconOnly
126
+ title="Zoom Out"
127
+ onClick={handleZoomOut}
128
+ >
129
+ <ZoomOut />
130
+ </VscodeButton>
131
+ </div>
132
+
133
+ {/* Align Button */}
134
+ <div className={styles.buttonGroup}>
135
+ <VscodeButton
136
+ ref={alignBtnRef}
137
+ secondary
138
+ iconOnly
139
+ title="Align"
140
+ onClick={() => {
141
+ const rect = alignBtnRef.current?.getBoundingClientRect();
142
+ if (rect) {
143
+ setMenuPosition({ top: rect.bottom, left: rect.left });
144
+ setAlignMenuOpen(!alignMenuOpen);
145
+ }
146
+ }}
147
+ >
148
+ <AlignLeft />
149
+ </VscodeButton>
150
+ </div>
151
+
152
+ {/* Distribute Button */}
153
+ <div className={styles.buttonGroup}>
154
+ <VscodeButton
155
+ ref={distributeBtnRef}
156
+ secondary
157
+ iconOnly
158
+ title="Distribute"
159
+ onClick={() => {
160
+ const rect = distributeBtnRef.current?.getBoundingClientRect();
161
+ if (rect) {
162
+ setMenuPosition({ top: rect.bottom, left: rect.left });
163
+ setDistributeMenuOpen(!distributeMenuOpen);
164
+ }
165
+ }}
166
+ >
167
+ <LayoutRight />
168
+ </VscodeButton>
169
+ </div>
170
+
171
+ {/* Custom Groups */}
172
+ {customGroups.map((group) => (
173
+ <div key={group.id} className={styles.buttonGroup}>
174
+ {(Array.isArray(group.buttons) ? group.buttons : []).map(
175
+ (button: ToolbarButton | React.ReactNode, index: number) => {
176
+ // Support custom ReactNode buttons
177
+ if (React.isValidElement(button)) {
178
+ return (
179
+ <React.Fragment key={index}>{button}</React.Fragment>
180
+ );
181
+ }
182
+
183
+ // Standard button definition
184
+ const typedButton = button as ToolbarButton;
185
+ const isDisabled =
186
+ typeof typedButton.disabled === 'function'
187
+ ? typedButton.disabled()
188
+ : typedButton.disabled;
189
+
190
+ return (
191
+ <VscodeButton
192
+ key={typedButton.id}
193
+ secondary
194
+ iconOnly
195
+ title={typedButton.label}
196
+ onClick={typedButton.onClick}
197
+ disabled={isDisabled}
198
+ >
199
+ {typedButton.icon}
200
+ </VscodeButton>
201
+ );
202
+ }
203
+ )}
204
+ </div>
205
+ ))}
206
+ </div>
207
+ </Panel>
208
+
209
+ {/* Align Context Menu */}
210
+ {alignMenuOpen && (
211
+ <VscodeContextMenu
212
+ show
213
+ onVscContextMenuSelect={handleAlignSelect}
214
+ style={{
215
+ position: 'fixed',
216
+ top: `${menuPosition.top}px`,
217
+ left: `${menuPosition.left}px`,
218
+ zIndex: 2000
219
+ }}
220
+ data={[
221
+ { label: 'Align Left', value: 'left' },
222
+ { label: 'Align Center Horizontal', value: 'center-h' },
223
+ { label: 'Align Right', value: 'right' },
224
+ { separator: true },
225
+ { label: 'Align Top', value: 'top' },
226
+ { label: 'Align Center Vertical', value: 'center-v' },
227
+ { label: 'Align Bottom', value: 'bottom' }
228
+ ]}
229
+ />
230
+ )}
231
+
232
+ {/* Distribute Context Menu */}
233
+ {distributeMenuOpen && (
234
+ <VscodeContextMenu
235
+ show
236
+ onVscContextMenuSelect={handleDistributeSelect}
237
+ style={{
238
+ position: 'fixed',
239
+ top: `${menuPosition.top}px`,
240
+ left: `${menuPosition.left}px`,
241
+ zIndex: 2000
242
+ }}
243
+ data={[
244
+ { label: 'Distribute Horizontal Left', value: 'left' },
245
+ { label: 'Distribute Horizontal Center', value: 'center-h' },
246
+ { label: 'Distribute Horizontal Right', value: 'right' },
247
+ { separator: true },
248
+ { label: 'Distribute Vertical Top', value: 'top' },
249
+ { label: 'Distribute Vertical Center', value: 'center-v' },
250
+ { label: 'Distribute Vertical Bottom', value: 'bottom' }
251
+ ]}
252
+ />
253
+ )}
254
+ </>
255
+ );
256
+ };