@r2digisolutions/components 0.1.7 → 0.3.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 (350) hide show
  1. package/dist/components/atoms/IconButton/IconButton.svelte +1 -1
  2. package/dist/components/atoms/MediaKindIcon/MediaKindIcon.stories.js +8 -0
  3. package/dist/components/atoms/MediaKindIcon/MediaKindIcon.svelte +122 -0
  4. package/dist/components/atoms/MediaKindIcon/MediaKindIcon.svelte.d.ts +11 -0
  5. package/dist/components/atoms/MediaKindIcon/MediaKindIconStory.svelte +12 -0
  6. package/dist/components/atoms/MediaKindIcon/MediaKindIconStory.svelte.d.ts +18 -0
  7. package/dist/components/atoms/PanKnob/PanKnob.stories.d.ts +9 -0
  8. package/dist/components/atoms/PanKnob/PanKnob.stories.js +8 -0
  9. package/dist/components/atoms/PanKnob/PanKnob.svelte +218 -0
  10. package/dist/components/atoms/PanKnob/PanKnob.svelte.d.ts +19 -0
  11. package/dist/components/atoms/PanKnob/PanKnobStory.svelte +15 -0
  12. package/dist/components/atoms/PanKnob/PanKnobStory.svelte.d.ts +3 -0
  13. package/dist/components/atoms/Playhead/Playhead.stories.js +8 -0
  14. package/dist/components/atoms/Playhead/Playhead.svelte +98 -0
  15. package/dist/components/atoms/Playhead/Playhead.svelte.d.ts +21 -0
  16. package/dist/components/atoms/Playhead/PlayheadStory.svelte +9 -0
  17. package/dist/components/atoms/Playhead/PlayheadStory.svelte.d.ts +18 -0
  18. package/dist/components/atoms/TimeRuler/TimeRuler.stories.js +8 -0
  19. package/dist/components/atoms/TimeRuler/TimeRuler.svelte +117 -0
  20. package/dist/components/atoms/TimeRuler/TimeRuler.svelte.d.ts +17 -0
  21. package/dist/components/atoms/TimeRuler/TimeRulerStory.svelte +7 -0
  22. package/dist/components/atoms/TimeRuler/TimeRulerStory.svelte.d.ts +18 -0
  23. package/dist/components/atoms/TimelineGrid/TimelineGrid.stories.js +8 -0
  24. package/dist/components/atoms/TimelineGrid/TimelineGrid.svelte +39 -0
  25. package/dist/components/atoms/TimelineGrid/TimelineGrid.svelte.d.ts +11 -0
  26. package/dist/components/atoms/TimelineGrid/TimelineGridStory.svelte +7 -0
  27. package/dist/components/atoms/TimelineGrid/TimelineGridStory.svelte.d.ts +18 -0
  28. package/dist/components/atoms/Tooltip/Tooltip.svelte +1 -1
  29. package/dist/components/atoms/TrimHandle/TrimHandle.stories.js +8 -0
  30. package/dist/components/atoms/TrimHandle/TrimHandle.svelte +63 -0
  31. package/dist/components/atoms/TrimHandle/TrimHandle.svelte.d.ts +12 -0
  32. package/dist/components/atoms/TrimHandle/TrimHandleStory.svelte +11 -0
  33. package/dist/components/atoms/TrimHandle/TrimHandleStory.svelte.d.ts +18 -0
  34. package/dist/components/molecules/AiAssistPanel/AiAssistPanel.stories.d.ts +9 -0
  35. package/dist/components/molecules/AiAssistPanel/AiAssistPanel.stories.js +8 -0
  36. package/dist/components/molecules/AiAssistPanel/AiAssistPanel.svelte +102 -0
  37. package/dist/components/molecules/AiAssistPanel/AiAssistPanel.svelte.d.ts +20 -0
  38. package/dist/components/molecules/AiAssistPanel/AiAssistPanelStory.svelte +34 -0
  39. package/dist/components/molecules/AiAssistPanel/AiAssistPanelStory.svelte.d.ts +3 -0
  40. package/dist/components/molecules/BulkActionBar/BulkActionBar.svelte +97 -61
  41. package/dist/components/molecules/BulkActionBar/BulkActionBar.svelte.d.ts +2 -0
  42. package/dist/components/molecules/BulkEditPanel/BulkEditPanel.stories.js +8 -0
  43. package/dist/components/molecules/BulkEditPanel/BulkEditPanel.svelte +117 -0
  44. package/dist/components/molecules/BulkEditPanel/BulkEditPanel.svelte.d.ts +23 -0
  45. package/dist/components/molecules/BulkEditPanel/BulkEditPanelStory.svelte +18 -0
  46. package/dist/components/molecules/BulkEditPanel/BulkEditPanelStory.svelte.d.ts +18 -0
  47. package/dist/components/molecules/CanvasElementsPanel/CanvasElementsPanel.stories.js +8 -0
  48. package/dist/components/molecules/CanvasElementsPanel/CanvasElementsPanel.svelte +858 -0
  49. package/dist/components/molecules/CanvasElementsPanel/CanvasElementsPanel.svelte.d.ts +43 -0
  50. package/dist/components/molecules/CanvasElementsPanel/CanvasElementsPanelStory.svelte +7 -0
  51. package/dist/components/molecules/CanvasElementsPanel/CanvasElementsPanelStory.svelte.d.ts +18 -0
  52. package/dist/components/molecules/CanvasInspector/CanvasInspector.stories.d.ts +9 -0
  53. package/dist/components/molecules/CanvasInspector/CanvasInspector.stories.js +8 -0
  54. package/dist/components/molecules/CanvasInspector/CanvasInspector.svelte +1140 -0
  55. package/dist/components/molecules/CanvasInspector/CanvasInspector.svelte.d.ts +28 -0
  56. package/dist/components/molecules/CanvasInspector/CanvasInspectorStory.svelte +20 -0
  57. package/dist/components/molecules/CanvasInspector/CanvasInspectorStory.svelte.d.ts +3 -0
  58. package/dist/components/molecules/ColorPicker/ColorPicker.svelte +46 -5
  59. package/dist/components/molecules/ColorPicker/ColorPicker.svelte.d.ts +2 -0
  60. package/dist/components/molecules/ColumnVisibilityMenu/ColumnVisibilityMenu.stories.d.ts +9 -0
  61. package/dist/components/molecules/ColumnVisibilityMenu/ColumnVisibilityMenu.stories.js +8 -0
  62. package/dist/components/molecules/ColumnVisibilityMenu/ColumnVisibilityMenu.svelte +108 -0
  63. package/dist/components/molecules/ColumnVisibilityMenu/ColumnVisibilityMenu.svelte.d.ts +18 -0
  64. package/dist/components/molecules/ColumnVisibilityMenu/ColumnVisibilityMenuStory.svelte +15 -0
  65. package/dist/components/molecules/ColumnVisibilityMenu/ColumnVisibilityMenuStory.svelte.d.ts +3 -0
  66. package/dist/components/molecules/ConflictResolver/ConflictResolver.stories.js +8 -0
  67. package/dist/components/molecules/ConflictResolver/ConflictResolver.svelte +73 -0
  68. package/dist/components/molecules/ConflictResolver/ConflictResolver.svelte.d.ts +16 -0
  69. package/dist/components/molecules/ConflictResolver/ConflictResolverStory.svelte +11 -0
  70. package/dist/components/molecules/ConflictResolver/ConflictResolverStory.svelte.d.ts +18 -0
  71. package/dist/components/molecules/ContextMenu/ContextMenu.svelte +237 -66
  72. package/dist/components/molecules/ContextMenu/ContextMenu.svelte.d.ts +9 -0
  73. package/dist/components/molecules/ExpressionEditor/ExpressionEditor.stories.d.ts +9 -0
  74. package/dist/components/molecules/ExpressionEditor/ExpressionEditor.stories.js +8 -0
  75. package/dist/components/molecules/ExpressionEditor/ExpressionEditor.svelte +56 -0
  76. package/dist/components/molecules/ExpressionEditor/ExpressionEditor.svelte.d.ts +12 -0
  77. package/dist/components/molecules/ExpressionEditor/ExpressionEditorStory.svelte +12 -0
  78. package/dist/components/molecules/ExpressionEditor/ExpressionEditorStory.svelte.d.ts +3 -0
  79. package/dist/components/molecules/FilterList/FilterList.stories.d.ts +9 -0
  80. package/dist/components/molecules/FilterList/FilterList.stories.js +8 -0
  81. package/dist/components/molecules/FilterList/FilterList.svelte +101 -0
  82. package/dist/components/molecules/FilterList/FilterList.svelte.d.ts +18 -0
  83. package/dist/components/molecules/FilterList/FilterListStory.svelte +31 -0
  84. package/dist/components/molecules/FilterList/FilterListStory.svelte.d.ts +3 -0
  85. package/dist/components/molecules/MediaAssetBrowser/MediaAssetBrowser.stories.d.ts +9 -0
  86. package/dist/components/molecules/MediaAssetBrowser/MediaAssetBrowser.stories.js +8 -0
  87. package/dist/components/molecules/MediaAssetBrowser/MediaAssetBrowser.svelte +109 -0
  88. package/dist/components/molecules/MediaAssetBrowser/MediaAssetBrowser.svelte.d.ts +20 -0
  89. package/dist/components/molecules/MediaAssetBrowser/MediaAssetBrowserStory.svelte +18 -0
  90. package/dist/components/molecules/MediaAssetBrowser/MediaAssetBrowserStory.svelte.d.ts +3 -0
  91. package/dist/components/molecules/MediaAssetCard/MediaAssetCard.stories.js +8 -0
  92. package/dist/components/molecules/MediaAssetCard/MediaAssetCard.svelte +50 -0
  93. package/dist/components/molecules/MediaAssetCard/MediaAssetCard.svelte.d.ts +11 -0
  94. package/dist/components/molecules/MediaAssetCard/MediaAssetCardStory.svelte +13 -0
  95. package/dist/components/molecules/MediaAssetCard/MediaAssetCardStory.svelte.d.ts +18 -0
  96. package/dist/components/molecules/MediaLayerItem/MediaLayerItem.stories.js +8 -0
  97. package/dist/components/molecules/MediaLayerItem/MediaLayerItem.svelte +380 -0
  98. package/dist/components/molecules/MediaLayerItem/MediaLayerItem.svelte.d.ts +33 -0
  99. package/dist/components/molecules/MediaLayerItem/MediaLayerItemStory.svelte +14 -0
  100. package/dist/components/molecules/MediaLayerItem/MediaLayerItemStory.svelte.d.ts +18 -0
  101. package/dist/components/molecules/MediaLayerList/MediaLayerList.stories.d.ts +9 -0
  102. package/dist/components/molecules/MediaLayerList/MediaLayerList.stories.js +8 -0
  103. package/dist/components/molecules/MediaLayerList/MediaLayerList.svelte +399 -0
  104. package/dist/components/molecules/MediaLayerList/MediaLayerList.svelte.d.ts +37 -0
  105. package/dist/components/molecules/MediaLayerList/MediaLayerListStory.svelte +24 -0
  106. package/dist/components/molecules/MediaLayerList/MediaLayerListStory.svelte.d.ts +3 -0
  107. package/dist/components/molecules/MediaStage/MediaStage.stories.d.ts +9 -0
  108. package/dist/components/molecules/MediaStage/MediaStage.stories.js +8 -0
  109. package/dist/components/molecules/MediaStage/MediaStage.svelte +1498 -0
  110. package/dist/components/molecules/MediaStage/MediaStage.svelte.d.ts +45 -0
  111. package/dist/components/molecules/MediaStage/MediaStageStory.svelte +35 -0
  112. package/dist/components/molecules/MediaStage/MediaStageStory.svelte.d.ts +3 -0
  113. package/dist/components/molecules/MediaTimeline/MediaTimeline.stories.d.ts +9 -0
  114. package/dist/components/molecules/MediaTimeline/MediaTimeline.stories.js +8 -0
  115. package/dist/components/molecules/MediaTimeline/MediaTimeline.svelte +441 -0
  116. package/dist/components/molecules/MediaTimeline/MediaTimeline.svelte.d.ts +39 -0
  117. package/dist/components/molecules/MediaTimeline/MediaTimelineStory.svelte +20 -0
  118. package/dist/components/molecules/MediaTimeline/MediaTimelineStory.svelte.d.ts +3 -0
  119. package/dist/components/molecules/MixerChannel/MixerChannel.stories.d.ts +9 -0
  120. package/dist/components/molecules/MixerChannel/MixerChannel.stories.js +8 -0
  121. package/dist/components/molecules/MixerChannel/MixerChannel.svelte +92 -0
  122. package/dist/components/molecules/MixerChannel/MixerChannel.svelte.d.ts +11 -0
  123. package/dist/components/molecules/MixerChannel/MixerChannelStory.svelte +13 -0
  124. package/dist/components/molecules/MixerChannel/MixerChannelStory.svelte.d.ts +3 -0
  125. package/dist/components/molecules/NodeGraph/GraphBlueprintNode.svelte +454 -0
  126. package/dist/components/molecules/NodeGraph/GraphBlueprintNode.svelte.d.ts +8 -0
  127. package/dist/components/molecules/NodeGraph/GraphFlowBridge.svelte +26 -0
  128. package/dist/components/molecules/NodeGraph/GraphFlowBridge.svelte.d.ts +22 -0
  129. package/dist/components/molecules/NodeGraph/NodeGraph.stories.d.ts +12 -0
  130. package/dist/components/molecules/NodeGraph/NodeGraph.stories.js +9 -0
  131. package/dist/components/molecules/NodeGraph/NodeGraph.svelte +1409 -0
  132. package/dist/components/molecules/NodeGraph/NodeGraph.svelte.d.ts +33 -0
  133. package/dist/components/molecules/NodeGraph/NodeGraphStory.svelte +90 -0
  134. package/dist/components/molecules/NodeGraph/NodeGraphStory.svelte.d.ts +3 -0
  135. package/dist/components/molecules/NodePalette/NodePalette.stories.js +8 -0
  136. package/dist/components/molecules/NodePalette/NodePalette.svelte +86 -0
  137. package/dist/components/molecules/NodePalette/NodePalette.svelte.d.ts +11 -0
  138. package/dist/components/molecules/NodePalette/NodePaletteStory.svelte +11 -0
  139. package/dist/components/molecules/NodePalette/NodePaletteStory.svelte.d.ts +18 -0
  140. package/dist/components/molecules/PdfViewer/PdfViewer.svelte.d.ts +1 -1
  141. package/dist/components/molecules/Poll/Poll.stories.d.ts +1 -1
  142. package/dist/components/molecules/ProgramMonitor/ProgramMonitor.stories.js +8 -0
  143. package/dist/components/molecules/ProgramMonitor/ProgramMonitor.svelte +794 -0
  144. package/dist/components/molecules/ProgramMonitor/ProgramMonitor.svelte.d.ts +25 -0
  145. package/dist/components/molecules/ProgramMonitor/ProgramMonitorStory.svelte +16 -0
  146. package/dist/components/molecules/ProgramMonitor/ProgramMonitorStory.svelte.d.ts +18 -0
  147. package/dist/components/molecules/PropertyField/PropertyField.svelte +57 -3
  148. package/dist/components/molecules/PropertyField/PropertyField.svelte.d.ts +10 -0
  149. package/dist/components/molecules/PropertyField/PropertyFieldStory.svelte +21 -0
  150. package/dist/components/molecules/PropertyGroup/PropertyGroup.svelte +1 -1
  151. package/dist/components/molecules/QueryBuilder/QueryBuilder.stories.d.ts +9 -0
  152. package/dist/components/molecules/QueryBuilder/QueryBuilder.stories.js +8 -0
  153. package/dist/components/molecules/QueryBuilder/QueryBuilder.svelte +52 -0
  154. package/dist/components/molecules/QueryBuilder/QueryBuilder.svelte.d.ts +18 -0
  155. package/dist/components/molecules/QueryBuilder/QueryBuilderStory.svelte +62 -0
  156. package/dist/components/molecules/QueryBuilder/QueryBuilderStory.svelte.d.ts +3 -0
  157. package/dist/components/molecules/RelationPicker/RelationPicker.stories.d.ts +9 -0
  158. package/dist/components/molecules/RelationPicker/RelationPicker.stories.js +8 -0
  159. package/dist/components/molecules/RelationPicker/RelationPicker.svelte +180 -0
  160. package/dist/components/molecules/RelationPicker/RelationPicker.svelte.d.ts +24 -0
  161. package/dist/components/molecules/RelationPicker/RelationPickerStory.svelte +16 -0
  162. package/dist/components/molecules/RelationPicker/RelationPickerStory.svelte.d.ts +3 -0
  163. package/dist/components/molecules/SchemaFieldBuilder/SchemaFieldBuilder.stories.d.ts +9 -0
  164. package/dist/components/molecules/SchemaFieldBuilder/SchemaFieldBuilder.stories.js +8 -0
  165. package/dist/components/molecules/SchemaFieldBuilder/SchemaFieldBuilder.svelte +154 -0
  166. package/dist/components/molecules/SchemaFieldBuilder/SchemaFieldBuilder.svelte.d.ts +12 -0
  167. package/dist/components/molecules/SchemaFieldBuilder/SchemaFieldBuilderStory.svelte +16 -0
  168. package/dist/components/molecules/SchemaFieldBuilder/SchemaFieldBuilderStory.svelte.d.ts +3 -0
  169. package/dist/components/molecules/SecretField/SecretField.stories.d.ts +9 -0
  170. package/dist/components/molecules/SecretField/SecretField.stories.js +8 -0
  171. package/dist/components/molecules/SecretField/SecretField.svelte +58 -0
  172. package/dist/components/molecules/SecretField/SecretField.svelte.d.ts +15 -0
  173. package/dist/components/molecules/SecretField/SecretFieldStory.svelte +8 -0
  174. package/dist/components/molecules/SecretField/SecretFieldStory.svelte.d.ts +3 -0
  175. package/dist/components/molecules/SplitPane/SplitPane.svelte +99 -40
  176. package/dist/components/molecules/SplitPane/SplitPane.svelte.d.ts +10 -2
  177. package/dist/components/molecules/TableToolbar/TableToolbar.svelte.d.ts +1 -1
  178. package/dist/components/molecules/Terminal/Terminal.stories.js +20 -0
  179. package/dist/components/molecules/Terminal/Terminal.svelte +238 -0
  180. package/dist/components/molecules/Terminal/Terminal.svelte.d.ts +19 -0
  181. package/dist/components/molecules/Terminal/TerminalStory.svelte +47 -0
  182. package/dist/components/molecules/Terminal/TerminalStory.svelte.d.ts +6 -0
  183. package/dist/components/molecules/TimelineClip/TimelineClip.stories.js +8 -0
  184. package/dist/components/molecules/TimelineClip/TimelineClip.svelte +193 -0
  185. package/dist/components/molecules/TimelineClip/TimelineClip.svelte.d.ts +18 -0
  186. package/dist/components/molecules/TimelineClip/TimelineClipStory.svelte +18 -0
  187. package/dist/components/molecules/TimelineClip/TimelineClipStory.svelte.d.ts +18 -0
  188. package/dist/components/molecules/TimelineTrack/TimelineTrack.stories.js +8 -0
  189. package/dist/components/molecules/TimelineTrack/TimelineTrack.svelte +126 -0
  190. package/dist/components/molecules/TimelineTrack/TimelineTrack.svelte.d.ts +27 -0
  191. package/dist/components/molecules/TimelineTrack/TimelineTrackStory.svelte +35 -0
  192. package/dist/components/molecules/TimelineTrack/TimelineTrackStory.svelte.d.ts +18 -0
  193. package/dist/components/molecules/TraceWaterfall/TraceWaterfall.stories.js +8 -0
  194. package/dist/components/molecules/TraceWaterfall/TraceWaterfall.svelte +158 -0
  195. package/dist/components/molecules/TraceWaterfall/TraceWaterfall.svelte.d.ts +18 -0
  196. package/dist/components/molecules/TraceWaterfall/TraceWaterfallStory.svelte +55 -0
  197. package/dist/components/molecules/TraceWaterfall/TraceWaterfallStory.svelte.d.ts +18 -0
  198. package/dist/components/molecules/TrackHeader/TrackHeader.stories.d.ts +9 -0
  199. package/dist/components/molecules/TrackHeader/TrackHeader.stories.js +8 -0
  200. package/dist/components/molecules/TrackHeader/TrackHeader.svelte +54 -0
  201. package/dist/components/molecules/TrackHeader/TrackHeader.svelte.d.ts +9 -0
  202. package/dist/components/molecules/TrackHeader/TrackHeaderStory.svelte +10 -0
  203. package/dist/components/molecules/TrackHeader/TrackHeaderStory.svelte.d.ts +3 -0
  204. package/dist/components/molecules/TransportControls/TransportControls.stories.d.ts +9 -0
  205. package/dist/components/molecules/TransportControls/TransportControls.stories.js +8 -0
  206. package/dist/components/molecules/TransportControls/TransportControls.svelte +135 -0
  207. package/dist/components/molecules/TransportControls/TransportControls.svelte.d.ts +24 -0
  208. package/dist/components/molecules/TransportControls/TransportControlsStory.svelte +40 -0
  209. package/dist/components/molecules/TransportControls/TransportControlsStory.svelte.d.ts +3 -0
  210. package/dist/components/molecules/VersionHistoryPanel/VersionHistoryPanel.stories.js +8 -0
  211. package/dist/components/molecules/VersionHistoryPanel/VersionHistoryPanel.svelte +117 -0
  212. package/dist/components/molecules/VersionHistoryPanel/VersionHistoryPanel.svelte.d.ts +20 -0
  213. package/dist/components/molecules/VersionHistoryPanel/VersionHistoryPanelStory.svelte +36 -0
  214. package/dist/components/molecules/VersionHistoryPanel/VersionHistoryPanelStory.svelte.d.ts +18 -0
  215. package/dist/components/molecules/VideoAnimationsPanel/VideoAnimationsPanel.stories.js +8 -0
  216. package/dist/components/molecules/VideoAnimationsPanel/VideoAnimationsPanel.svelte +213 -0
  217. package/dist/components/molecules/VideoAnimationsPanel/VideoAnimationsPanel.svelte.d.ts +22 -0
  218. package/dist/components/molecules/VideoAnimationsPanel/VideoAnimationsPanelStory.svelte +7 -0
  219. package/dist/components/molecules/VideoAnimationsPanel/VideoAnimationsPanelStory.svelte.d.ts +18 -0
  220. package/dist/components/molecules/VideoComponentsPanel/VideoComponentsPanel.stories.js +8 -0
  221. package/dist/components/molecules/VideoComponentsPanel/VideoComponentsPanel.svelte +524 -0
  222. package/dist/components/molecules/VideoComponentsPanel/VideoComponentsPanel.svelte.d.ts +32 -0
  223. package/dist/components/molecules/VideoComponentsPanel/VideoComponentsPanelStory.svelte +7 -0
  224. package/dist/components/molecules/VideoComponentsPanel/VideoComponentsPanelStory.svelte.d.ts +18 -0
  225. package/dist/components/molecules/VideoPlayer/VideoPlayer.stories.d.ts +1 -1
  226. package/dist/components/molecules/VideoTrackHeader/VideoTrackHeader.stories.d.ts +9 -0
  227. package/dist/components/molecules/VideoTrackHeader/VideoTrackHeader.stories.js +8 -0
  228. package/dist/components/molecules/VideoTrackHeader/VideoTrackHeader.svelte +112 -0
  229. package/dist/components/molecules/VideoTrackHeader/VideoTrackHeader.svelte.d.ts +15 -0
  230. package/dist/components/molecules/VideoTrackHeader/VideoTrackHeaderStory.svelte +10 -0
  231. package/dist/components/molecules/VideoTrackHeader/VideoTrackHeaderStory.svelte.d.ts +3 -0
  232. package/dist/components/molecules/VideoTransitionsPanel/VideoTransitionsPanel.stories.js +8 -0
  233. package/dist/components/molecules/VideoTransitionsPanel/VideoTransitionsPanel.svelte +113 -0
  234. package/dist/components/molecules/VideoTransitionsPanel/VideoTransitionsPanel.svelte.d.ts +18 -0
  235. package/dist/components/molecules/VideoTransitionsPanel/VideoTransitionsPanelStory.svelte +7 -0
  236. package/dist/components/molecules/VideoTransitionsPanel/VideoTransitionsPanelStory.svelte.d.ts +18 -0
  237. package/dist/components/molecules/WaveformRegion/WaveformRegion.stories.js +8 -0
  238. package/dist/components/molecules/WaveformRegion/WaveformRegion.svelte +82 -0
  239. package/dist/components/molecules/WaveformRegion/WaveformRegion.svelte.d.ts +13 -0
  240. package/dist/components/molecules/WaveformRegion/WaveformRegionStory.svelte +17 -0
  241. package/dist/components/molecules/WaveformRegion/WaveformRegionStory.svelte.d.ts +18 -0
  242. package/dist/components/molecules/WidgetCanvas/WidgetCanvas.svelte +13 -4
  243. package/dist/components/molecules/WidgetCanvas/WidgetCanvas.svelte.d.ts +3 -1
  244. package/dist/components/molecules/WidgetCanvas/widgetCanvasContext.d.ts +2 -0
  245. package/dist/components/molecules/WidgetFrame/WidgetFrame.svelte +206 -37
  246. package/dist/components/molecules/WidgetFrame/WidgetFrame.svelte.d.ts +31 -0
  247. package/dist/components/organisms/AudioEditor/AudioEditor.stories.d.ts +12 -0
  248. package/dist/components/organisms/AudioEditor/AudioEditor.stories.js +9 -0
  249. package/dist/components/organisms/AudioEditor/AudioEditor.svelte +324 -0
  250. package/dist/components/organisms/AudioEditor/AudioEditor.svelte.d.ts +13 -0
  251. package/dist/components/organisms/AudioEditor/AudioEditorStory.svelte +10 -0
  252. package/dist/components/organisms/AudioEditor/AudioEditorStory.svelte.d.ts +3 -0
  253. package/dist/components/organisms/BlogEditor/BlogEditor.stories.d.ts +12 -0
  254. package/dist/components/organisms/BlogEditor/BlogEditor.stories.js +9 -0
  255. package/dist/components/organisms/BlogEditor/BlogEditor.svelte +1208 -0
  256. package/dist/components/organisms/BlogEditor/BlogEditor.svelte.d.ts +16 -0
  257. package/dist/components/organisms/BlogEditor/BlogEditorStory.svelte +144 -0
  258. package/dist/components/organisms/BlogEditor/BlogEditorStory.svelte.d.ts +3 -0
  259. package/dist/components/organisms/BlogEditor/DemoBlogCard.svelte +28 -0
  260. package/dist/components/organisms/BlogEditor/DemoBlogCard.svelte.d.ts +10 -0
  261. package/dist/components/organisms/BlogEditor/DemoBlogStats.svelte +34 -0
  262. package/dist/components/organisms/BlogEditor/DemoBlogStats.svelte.d.ts +11 -0
  263. package/dist/components/organisms/BlogEditor/DemoBlogWidget.svelte +13 -0
  264. package/dist/components/organisms/BlogEditor/DemoBlogWidget.svelte.d.ts +8 -0
  265. package/dist/components/organisms/BlogRenderer/BlogRenderer.stories.js +8 -0
  266. package/dist/components/organisms/BlogRenderer/BlogRenderer.svelte +469 -0
  267. package/dist/components/organisms/BlogRenderer/BlogRenderer.svelte.d.ts +14 -0
  268. package/dist/components/organisms/BlogRenderer/BlogRendererStory.svelte +20 -0
  269. package/dist/components/organisms/BlogRenderer/BlogRendererStory.svelte.d.ts +18 -0
  270. package/dist/components/organisms/BlueprintEditor/BlueprintEditor.stories.d.ts +12 -0
  271. package/dist/components/organisms/BlueprintEditor/BlueprintEditor.stories.js +9 -0
  272. package/dist/components/organisms/BlueprintEditor/BlueprintEditor.svelte +1012 -0
  273. package/dist/components/organisms/BlueprintEditor/BlueprintEditor.svelte.d.ts +16 -0
  274. package/dist/components/organisms/BlueprintEditor/BlueprintEditorStory.svelte +76 -0
  275. package/dist/components/organisms/BlueprintEditor/BlueprintEditorStory.svelte.d.ts +3 -0
  276. package/dist/components/organisms/CanvasEditor/CanvasEditor.stories.d.ts +12 -0
  277. package/dist/components/organisms/CanvasEditor/CanvasEditor.stories.js +9 -0
  278. package/dist/components/organisms/CanvasEditor/CanvasEditor.svelte +1680 -0
  279. package/dist/components/organisms/CanvasEditor/CanvasEditor.svelte.d.ts +18 -0
  280. package/dist/components/organisms/CanvasEditor/CanvasEditorStory.svelte +329 -0
  281. package/dist/components/organisms/CanvasEditor/CanvasEditorStory.svelte.d.ts +3 -0
  282. package/dist/components/organisms/DashboardBuilderPage/DashboardBuilderPage.svelte.d.ts +1 -1
  283. package/dist/components/organisms/DesktopShell/DesktopShell.svelte.d.ts +1 -1
  284. package/dist/components/organisms/EditorShell/EditorShell.svelte +162 -57
  285. package/dist/components/organisms/EditorShell/EditorShell.svelte.d.ts +21 -1
  286. package/dist/components/organisms/FileUploader/FileUploader.stories.d.ts +10 -0
  287. package/dist/components/organisms/FileUploader/FileUploader.stories.js +21 -0
  288. package/dist/components/organisms/FileUploader/FileUploader.svelte +127 -25
  289. package/dist/components/organisms/FileUploader/FileUploader.svelte.d.ts +20 -0
  290. package/dist/components/organisms/FileUploader/FileUploaderStory.svelte +7 -1
  291. package/dist/components/organisms/FileUploader/FileUploaderStory.svelte.d.ts +3 -0
  292. package/dist/components/organisms/ImportWizard/ImportWizard.stories.js +8 -0
  293. package/dist/components/organisms/ImportWizard/ImportWizard.svelte +209 -0
  294. package/dist/components/organisms/ImportWizard/ImportWizard.svelte.d.ts +22 -0
  295. package/dist/components/organisms/ImportWizard/ImportWizardStory.svelte +16 -0
  296. package/dist/components/organisms/ImportWizard/ImportWizardStory.svelte.d.ts +18 -0
  297. package/dist/components/organisms/VideoEditor/VideoEditor.stories.d.ts +12 -0
  298. package/dist/components/organisms/VideoEditor/VideoEditor.stories.js +9 -0
  299. package/dist/components/organisms/VideoEditor/VideoEditor.svelte +1687 -0
  300. package/dist/components/organisms/VideoEditor/VideoEditor.svelte.d.ts +14 -0
  301. package/dist/components/organisms/VideoEditor/VideoEditorStory.svelte +11 -0
  302. package/dist/components/organisms/VideoEditor/VideoEditorStory.svelte.d.ts +3 -0
  303. package/dist/components/templates/AudioEditorTemplate/AudioEditorTemplate.stories.d.ts +12 -0
  304. package/dist/components/templates/AudioEditorTemplate/AudioEditorTemplate.stories.js +9 -0
  305. package/dist/components/templates/AudioEditorTemplate/AudioEditorTemplate.svelte +22 -0
  306. package/dist/components/templates/AudioEditorTemplate/AudioEditorTemplate.svelte.d.ts +13 -0
  307. package/dist/components/templates/AudioEditorTemplate/AudioEditorTemplateStory.svelte +8 -0
  308. package/dist/components/templates/AudioEditorTemplate/AudioEditorTemplateStory.svelte.d.ts +3 -0
  309. package/dist/components/templates/CanvasEditorTemplate/CanvasEditorTemplate.stories.d.ts +12 -0
  310. package/dist/components/templates/CanvasEditorTemplate/CanvasEditorTemplate.stories.js +9 -0
  311. package/dist/components/templates/CanvasEditorTemplate/CanvasEditorTemplate.svelte +32 -0
  312. package/dist/components/templates/CanvasEditorTemplate/CanvasEditorTemplate.svelte.d.ts +17 -0
  313. package/dist/components/templates/CanvasEditorTemplate/CanvasEditorTemplateStory.svelte +21 -0
  314. package/dist/components/templates/CanvasEditorTemplate/CanvasEditorTemplateStory.svelte.d.ts +3 -0
  315. package/dist/components/templates/VideoEditorTemplate/VideoEditorTemplate.stories.d.ts +12 -0
  316. package/dist/components/templates/VideoEditorTemplate/VideoEditorTemplate.stories.js +9 -0
  317. package/dist/components/templates/VideoEditorTemplate/VideoEditorTemplate.svelte +22 -0
  318. package/dist/components/templates/VideoEditorTemplate/VideoEditorTemplate.svelte.d.ts +13 -0
  319. package/dist/components/templates/VideoEditorTemplate/VideoEditorTemplateStory.svelte +8 -0
  320. package/dist/components/templates/VideoEditorTemplate/VideoEditorTemplateStory.svelte.d.ts +3 -0
  321. package/dist/index.d.ts +91 -1
  322. package/dist/index.js +64 -0
  323. package/dist/types/xyflow-svelte.d.ts +62 -0
  324. package/dist/utils/audioProject.d.ts +19 -0
  325. package/dist/utils/audioProject.js +70 -0
  326. package/dist/utils/blogDocument.d.ts +175 -0
  327. package/dist/utils/blogDocument.js +220 -0
  328. package/dist/utils/blueprintRuntime.d.ts +34 -0
  329. package/dist/utils/blueprintRuntime.js +289 -0
  330. package/dist/utils/canvasDocument.d.ts +239 -0
  331. package/dist/utils/canvasDocument.js +443 -0
  332. package/dist/utils/canvasExport.d.ts +10 -0
  333. package/dist/utils/canvasExport.js +469 -0
  334. package/dist/utils/canvasHierarchy.d.ts +189 -0
  335. package/dist/utils/canvasHierarchy.js +674 -0
  336. package/dist/utils/canvasHistory.d.ts +19 -0
  337. package/dist/utils/canvasHistory.js +48 -0
  338. package/dist/utils/canvasWidget.d.ts +81 -0
  339. package/dist/utils/canvasWidget.js +597 -0
  340. package/dist/utils/mediaTime.d.ts +26 -0
  341. package/dist/utils/mediaTime.js +76 -0
  342. package/dist/utils/mediaTracks.d.ts +215 -0
  343. package/dist/utils/mediaTracks.js +798 -0
  344. package/dist/utils/nodeGraph.d.ts +354 -0
  345. package/dist/utils/nodeGraph.js +1453 -0
  346. package/dist/utils/queryBridge.d.ts +18 -0
  347. package/dist/utils/queryBridge.js +118 -0
  348. package/dist/utils/videoSequence.d.ts +13 -0
  349. package/dist/utils/videoSequence.js +94 -0
  350. package/package.json +5 -2
@@ -0,0 +1,1453 @@
1
+ /**
2
+ * Node graph helpers — Blueprint-style typed pins, edges, validation.
3
+ */
4
+ export const DEFAULT_NODE_WIDTH = 220;
5
+ export const DEFAULT_NODE_HEIGHT = 80;
6
+ export const PORT_SIZE = 12;
7
+ /** Half of the pin glyph — wire starts/ends at the rim of the circle/play icon. */
8
+ export const EDGE_PORT_PAD = PORT_SIZE / 2;
9
+ /** SVG marker tip length (viewBox units ≈ user units with markerWidth 8). */
10
+ export const EDGE_ARROW_LENGTH = 8;
11
+ export const PIN_TYPE_COLORS = {
12
+ exec: '#e2e8f0',
13
+ bool: '#ef4444',
14
+ int: '#22c55e',
15
+ float: '#86efac',
16
+ string: '#a855f7',
17
+ object: '#38bdf8',
18
+ any: '#94a3b8'
19
+ };
20
+ export function pinColor(port) {
21
+ const dt = port.dataType ?? (port.kind === 'exec' ? 'exec' : 'any');
22
+ return PIN_TYPE_COLORS[dt] ?? PIN_TYPE_COLORS.any;
23
+ }
24
+ function execPort(id, label, side, offset) {
25
+ return { id, label, side, offset, kind: 'exec', dataType: 'exec' };
26
+ }
27
+ function dataPort(id, label, dataType, side, offset) {
28
+ return { id, label, side, offset, kind: 'data', dataType };
29
+ }
30
+ export const DEFAULT_NODE_TYPES = [
31
+ {
32
+ type: 'trigger',
33
+ label: 'Trigger',
34
+ category: 'Events',
35
+ description: 'Starts the flow',
36
+ color: '#10b981',
37
+ inputs: [],
38
+ outputs: [execPort('exec', 'Then', 'right')]
39
+ },
40
+ {
41
+ type: 'action',
42
+ label: 'Action',
43
+ category: 'Actions',
44
+ description: 'Do something',
45
+ color: '#3b82f6',
46
+ inputs: [execPort('exec_in', 'Exec', 'left')],
47
+ outputs: [execPort('exec', 'Then', 'right')]
48
+ },
49
+ {
50
+ type: 'condition',
51
+ label: 'Branch',
52
+ category: 'Flow',
53
+ description: 'Branch on a boolean',
54
+ color: '#f59e0b',
55
+ height: 96,
56
+ inputs: [
57
+ execPort('exec_in', 'Exec', 'left', 0.28),
58
+ dataPort('condition', 'Condition', 'bool', 'left', 0.72)
59
+ ],
60
+ outputs: [
61
+ execPort('true', 'True', 'right', 0.32),
62
+ execPort('false', 'False', 'right', 0.68)
63
+ ]
64
+ },
65
+ {
66
+ type: 'transform',
67
+ label: 'Transform',
68
+ category: 'Actions',
69
+ description: 'Map data then continue',
70
+ color: '#8b5cf6',
71
+ height: 96,
72
+ inputs: [
73
+ execPort('exec_in', 'Exec', 'left', 0.28),
74
+ dataPort('in', 'In', 'any', 'left', 0.72)
75
+ ],
76
+ outputs: [
77
+ execPort('exec', 'Then', 'right', 0.28),
78
+ dataPort('out', 'Out', 'any', 'right', 0.72)
79
+ ]
80
+ },
81
+ {
82
+ type: 'delay',
83
+ label: 'Delay',
84
+ category: 'Flow',
85
+ description: 'Wait before continuing',
86
+ color: '#64748b',
87
+ inputs: [
88
+ execPort('exec_in', 'Exec', 'left', 0.3),
89
+ dataPort('seconds', 'Seconds', 'float', 'left', 0.7)
90
+ ],
91
+ outputs: [execPort('exec', 'Then', 'right')]
92
+ },
93
+ {
94
+ type: 'end',
95
+ label: 'End',
96
+ category: 'Flow',
97
+ description: 'Terminal step',
98
+ color: '#ef4444',
99
+ inputs: [execPort('exec_in', 'Exec', 'left')],
100
+ outputs: []
101
+ },
102
+ {
103
+ type: 'get_string',
104
+ label: 'Get String',
105
+ category: 'Functions',
106
+ description: 'Pure data — no exec pins',
107
+ color: '#a855f7',
108
+ width: 168,
109
+ height: 56,
110
+ inputs: [],
111
+ outputs: [dataPort('value', 'Return', 'string', 'right')],
112
+ defaultData: { label: '"Hello"' }
113
+ },
114
+ {
115
+ type: 'format_string',
116
+ label: 'Format String',
117
+ category: 'Functions',
118
+ description: 'Pure function — data in/out only',
119
+ color: '#a855f7',
120
+ height: 88,
121
+ inputs: [
122
+ dataPort('template', 'Template', 'string', 'left', 0.35),
123
+ dataPort('value', 'Value', 'any', 'left', 0.7)
124
+ ],
125
+ outputs: [dataPort('out', 'Result', 'string', 'right')]
126
+ },
127
+ {
128
+ type: 'to_bool',
129
+ label: 'To Bool',
130
+ category: 'Functions',
131
+ description: 'Cast / coerce to boolean',
132
+ color: '#ef4444',
133
+ width: 160,
134
+ height: 56,
135
+ inputs: [dataPort('in', 'In', 'any', 'left')],
136
+ outputs: [dataPort('out', 'Out', 'bool', 'right')]
137
+ },
138
+ {
139
+ type: 'comment',
140
+ label: 'Comment',
141
+ category: 'Utility',
142
+ description: 'Annotation box',
143
+ color: '#fbbf24',
144
+ width: 220,
145
+ height: 100,
146
+ inputs: [],
147
+ outputs: [],
148
+ defaultData: { label: 'Comment', commentColor: 'rgba(251, 191, 36, 0.25)' }
149
+ },
150
+ {
151
+ type: 'reroute',
152
+ label: 'Reroute',
153
+ category: 'Utility',
154
+ description: 'Wire knot / pass-through',
155
+ color: '#94a3b8',
156
+ width: 16,
157
+ height: 16,
158
+ hidden: true,
159
+ inputs: [dataPort('in', '', 'any', 'left')],
160
+ outputs: [dataPort('out', '', 'any', 'right')]
161
+ },
162
+ {
163
+ type: 'collapsed_graph',
164
+ label: 'Collapsed Graph',
165
+ category: 'Utility',
166
+ description: 'Collapsed selection (expand with E)',
167
+ color: '#7c3aed',
168
+ width: 220,
169
+ height: 72,
170
+ hidden: true,
171
+ inputs: [execPort('exec_in', 'Exec', 'left')],
172
+ outputs: [execPort('exec', 'Then', 'right')],
173
+ defaultData: { label: 'Collapsed Graph' }
174
+ }
175
+ ];
176
+ /** Unreal-inspired blueprint catalog */
177
+ export const DEFAULT_BLUEPRINT_NODE_TYPES = [
178
+ {
179
+ type: 'event_begin',
180
+ label: 'Event BeginPlay',
181
+ category: 'Events',
182
+ color: '#dc2626',
183
+ contexts: ['event_graph'],
184
+ inputs: [],
185
+ outputs: [execPort('exec', 'Then', 'right')],
186
+ defaultData: { label: 'Event BeginPlay' }
187
+ },
188
+ {
189
+ type: 'event_tick',
190
+ label: 'Event Tick',
191
+ category: 'Events',
192
+ color: '#dc2626',
193
+ contexts: ['event_graph'],
194
+ height: 88,
195
+ inputs: [],
196
+ outputs: [
197
+ execPort('exec', 'Then', 'right'),
198
+ dataPort('delta', 'Delta Seconds', 'float', 'right')
199
+ ],
200
+ defaultData: { label: 'Event Tick' }
201
+ },
202
+ {
203
+ type: 'branch',
204
+ label: 'Branch',
205
+ category: 'Flow Control',
206
+ color: '#64748b',
207
+ contexts: ['event_graph', 'function_graph', 'macro_graph'],
208
+ width: 240,
209
+ height: 88,
210
+ inputs: [
211
+ execPort('exec_in', 'Exec', 'left'),
212
+ dataPort('condition', 'Condition', 'bool', 'left')
213
+ ],
214
+ outputs: [execPort('true', 'True', 'right'), execPort('false', 'False', 'right')]
215
+ },
216
+ {
217
+ type: 'delay_bp',
218
+ label: 'Delay',
219
+ category: 'Flow Control',
220
+ color: '#64748b',
221
+ contexts: ['event_graph', 'function_graph'],
222
+ width: 240,
223
+ height: 88,
224
+ inputs: [
225
+ execPort('exec_in', 'Exec', 'left'),
226
+ dataPort('duration', 'Duration', 'float', 'left')
227
+ ],
228
+ outputs: [
229
+ execPort('completed', 'Completed', 'right'),
230
+ execPort('aborted', 'Aborted', 'right')
231
+ ]
232
+ },
233
+ {
234
+ type: 'print_string',
235
+ label: 'Print String',
236
+ category: 'Utilities',
237
+ color: '#0ea5e9',
238
+ contexts: ['event_graph', 'function_graph', 'macro_graph'],
239
+ width: 250,
240
+ height: 110,
241
+ inputs: [
242
+ execPort('exec_in', 'Exec', 'left'),
243
+ dataPort('in_string', 'In String', 'string', 'left'),
244
+ dataPort('duration', 'Duration', 'float', 'left')
245
+ ],
246
+ outputs: [execPort('exec', 'Then', 'right')]
247
+ },
248
+ {
249
+ type: 'make_string',
250
+ label: 'Make Literal String',
251
+ category: 'Utilities',
252
+ color: '#a855f7',
253
+ contexts: ['event_graph', 'function_graph', 'macro_graph', 'construction_script'],
254
+ width: 180,
255
+ height: 56,
256
+ inputs: [],
257
+ outputs: [dataPort('value', 'Return', 'string', 'right')],
258
+ defaultData: { label: '"Hello"' }
259
+ },
260
+ {
261
+ type: 'return_node',
262
+ label: 'Return Node',
263
+ category: 'Flow Control',
264
+ color: '#dc2626',
265
+ contexts: ['function_graph'],
266
+ description: 'Only available inside function graphs',
267
+ inputs: [execPort('exec_in', 'Exec', 'left')],
268
+ outputs: []
269
+ },
270
+ {
271
+ type: 'construction_add',
272
+ label: 'Add Component',
273
+ category: 'Components',
274
+ color: '#f97316',
275
+ contexts: ['construction_script'],
276
+ description: 'Only available in Construction Script',
277
+ inputs: [execPort('exec_in', 'Exec', 'left')],
278
+ outputs: [execPort('exec', 'Then', 'right'), dataPort('component', 'Component', 'object', 'right')]
279
+ },
280
+ {
281
+ type: 'comment',
282
+ label: 'Comment',
283
+ category: 'Utility',
284
+ color: '#fbbf24',
285
+ width: 240,
286
+ height: 110,
287
+ inputs: [],
288
+ outputs: [],
289
+ defaultData: { label: 'Comment', commentColor: 'rgba(251, 191, 36, 0.28)' }
290
+ },
291
+ {
292
+ type: 'reroute',
293
+ label: 'Reroute',
294
+ category: 'Utility',
295
+ description: 'Wire knot / pass-through',
296
+ color: '#94a3b8',
297
+ width: 16,
298
+ height: 16,
299
+ hidden: true,
300
+ inputs: [dataPort('in', '', 'any', 'left')],
301
+ outputs: [dataPort('out', '', 'any', 'right')]
302
+ },
303
+ {
304
+ type: 'collapsed_graph',
305
+ label: 'Collapsed Graph',
306
+ category: 'Utility',
307
+ description: 'Collapsed selection (expand with E)',
308
+ color: '#7c3aed',
309
+ width: 220,
310
+ height: 72,
311
+ hidden: true,
312
+ inputs: [execPort('exec_in', 'Exec', 'left')],
313
+ outputs: [execPort('exec', 'Then', 'right')],
314
+ defaultData: { label: 'Collapsed Graph' }
315
+ },
316
+ /** Templates for dynamic variable nodes (hidden from palette). */
317
+ {
318
+ type: 'var_get',
319
+ label: 'Get',
320
+ category: 'Variables',
321
+ hidden: true,
322
+ width: 160,
323
+ height: 52,
324
+ inputs: [],
325
+ outputs: [dataPort('value', '', 'any', 'right')]
326
+ },
327
+ {
328
+ type: 'var_set',
329
+ label: 'Set',
330
+ category: 'Variables',
331
+ hidden: true,
332
+ height: 72,
333
+ inputs: [execPort('exec_in', 'Exec', 'left'), dataPort('value', '', 'any', 'left')],
334
+ outputs: [execPort('exec', 'Then', 'right'), dataPort('out', '', 'any', 'right')]
335
+ }
336
+ ];
337
+ export function emptyGraphDocument() {
338
+ return { version: 1, nodes: [], edges: [] };
339
+ }
340
+ function uid(prefix) {
341
+ return `${prefix}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 7)}`;
342
+ }
343
+ export function resolveNodeType(type, catalog = DEFAULT_NODE_TYPES) {
344
+ return catalog.find((t) => t.type === type);
345
+ }
346
+ export function defaultPortsForType(type, catalog = DEFAULT_NODE_TYPES) {
347
+ const def = resolveNodeType(type, catalog);
348
+ if (def) {
349
+ return {
350
+ inputs: (def.inputs ?? []).map((p) => ({ ...p })),
351
+ outputs: (def.outputs ?? []).map((p) => ({ ...p }))
352
+ };
353
+ }
354
+ return {
355
+ inputs: [execPort('exec_in', 'Exec', 'left')],
356
+ outputs: [execPort('exec', 'Then', 'right')]
357
+ };
358
+ }
359
+ export function createGraphNode(partial, catalog = DEFAULT_NODE_TYPES) {
360
+ const def = resolveNodeType(partial.type, catalog);
361
+ const ports = defaultPortsForType(partial.type, catalog);
362
+ return {
363
+ id: partial.id ?? uid('n'),
364
+ type: partial.type,
365
+ x: partial.x,
366
+ y: partial.y,
367
+ width: partial.width ?? def?.width ?? DEFAULT_NODE_WIDTH,
368
+ height: partial.height ?? def?.height ?? DEFAULT_NODE_HEIGHT,
369
+ data: {
370
+ label: def?.label ?? partial.type,
371
+ color: def?.color,
372
+ ...(def?.defaultData ?? {}),
373
+ ...(partial.data ?? {})
374
+ },
375
+ inputs: partial.inputs ?? ports.inputs,
376
+ outputs: partial.outputs ?? ports.outputs
377
+ };
378
+ }
379
+ /** Duplicate nodes (+ internal edges), like UE Blueprint Ctrl+W / duplicate. */
380
+ export function duplicateGraphSelection(doc, nodeIds, opts) {
381
+ const idSet = new Set(nodeIds);
382
+ const sources = doc.nodes.filter((n) => idSet.has(n.id));
383
+ if (!sources.length)
384
+ return { doc, newNodeIds: [] };
385
+ const dx = opts?.offsetX ?? 32;
386
+ const dy = opts?.offsetY ?? 32;
387
+ const idMap = new Map();
388
+ const clones = sources.map((n) => {
389
+ const id = uid('n');
390
+ idMap.set(n.id, id);
391
+ return {
392
+ ...n,
393
+ id,
394
+ x: n.x + dx,
395
+ y: n.y + dy,
396
+ inputs: n.inputs?.map((p) => ({ ...p })),
397
+ outputs: n.outputs?.map((p) => ({ ...p })),
398
+ data: n.data ? { ...n.data } : undefined
399
+ };
400
+ });
401
+ const edgeClones = doc.edges
402
+ .filter((e) => idSet.has(e.source) && idSet.has(e.target))
403
+ .map((e) => ({
404
+ ...e,
405
+ id: uid('e'),
406
+ source: idMap.get(e.source),
407
+ target: idMap.get(e.target)
408
+ }));
409
+ return {
410
+ doc: {
411
+ ...doc,
412
+ nodes: [...doc.nodes, ...clones],
413
+ edges: [...doc.edges, ...edgeClones]
414
+ },
415
+ newNodeIds: clones.map((n) => n.id)
416
+ };
417
+ }
418
+ export function cloneGraphDocument(doc) {
419
+ return JSON.parse(JSON.stringify(doc));
420
+ }
421
+ export const GRAPH_CLIPBOARD_MIME = 'application/x-r2-graph-fragment';
422
+ export function extractGraphSelection(doc, nodeIds) {
423
+ const idSet = new Set(nodeIds);
424
+ const nodes = doc.nodes
425
+ .filter((n) => idSet.has(n.id))
426
+ .map((n) => ({
427
+ ...n,
428
+ inputs: n.inputs?.map((p) => ({ ...p })),
429
+ outputs: n.outputs?.map((p) => ({ ...p })),
430
+ data: n.data ? { ...n.data } : undefined
431
+ }));
432
+ const edges = doc.edges
433
+ .filter((e) => idSet.has(e.source) && idSet.has(e.target))
434
+ .map((e) => ({ ...e }));
435
+ return { version: 1, nodes, edges };
436
+ }
437
+ export function encodeGraphClipboard(fragment) {
438
+ const payload = {
439
+ mime: GRAPH_CLIPBOARD_MIME,
440
+ version: 1,
441
+ fragment: cloneGraphDocument(fragment)
442
+ };
443
+ return JSON.stringify(payload);
444
+ }
445
+ export function decodeGraphClipboard(raw) {
446
+ try {
447
+ const parsed = JSON.parse(raw);
448
+ if (parsed &&
449
+ typeof parsed === 'object' &&
450
+ 'mime' in parsed &&
451
+ parsed.mime === GRAPH_CLIPBOARD_MIME &&
452
+ parsed.fragment) {
453
+ return cloneGraphDocument(parsed.fragment);
454
+ }
455
+ if (parsed && typeof parsed === 'object' && 'nodes' in parsed && Array.isArray(parsed.nodes)) {
456
+ return cloneGraphDocument(parsed);
457
+ }
458
+ }
459
+ catch {
460
+ /* ignore */
461
+ }
462
+ return null;
463
+ }
464
+ export function pasteGraphSelection(doc, fragment, opts) {
465
+ if (!fragment.nodes.length)
466
+ return { doc, newNodeIds: [] };
467
+ const dx = opts?.offsetX ?? 40;
468
+ const dy = opts?.offsetY ?? 40;
469
+ let ox = 0;
470
+ let oy = 0;
471
+ if (opts?.origin) {
472
+ const minX = Math.min(...fragment.nodes.map((n) => n.x));
473
+ const minY = Math.min(...fragment.nodes.map((n) => n.y));
474
+ ox = opts.origin.x - minX;
475
+ oy = opts.origin.y - minY;
476
+ }
477
+ else {
478
+ ox = dx;
479
+ oy = dy;
480
+ }
481
+ const idMap = new Map();
482
+ const clones = fragment.nodes.map((n) => {
483
+ const id = uid('n');
484
+ idMap.set(n.id, id);
485
+ return {
486
+ ...n,
487
+ id,
488
+ x: n.x + ox,
489
+ y: n.y + oy,
490
+ inputs: n.inputs?.map((p) => ({ ...p })),
491
+ outputs: n.outputs?.map((p) => ({ ...p })),
492
+ data: n.data ? { ...n.data } : undefined
493
+ };
494
+ });
495
+ const edgeClones = fragment.edges
496
+ .filter((e) => idMap.has(e.source) && idMap.has(e.target))
497
+ .map((e) => ({
498
+ ...e,
499
+ id: uid('e'),
500
+ source: idMap.get(e.source),
501
+ target: idMap.get(e.target)
502
+ }));
503
+ return {
504
+ doc: {
505
+ ...doc,
506
+ nodes: [...doc.nodes, ...clones],
507
+ edges: [...doc.edges, ...edgeClones]
508
+ },
509
+ newNodeIds: clones.map((n) => n.id)
510
+ };
511
+ }
512
+ export function alignGraphNodes(doc, nodeIds, align) {
513
+ const idSet = new Set(nodeIds);
514
+ const targets = doc.nodes.filter((n) => idSet.has(n.id) && n.type !== 'comment');
515
+ if (targets.length < 2)
516
+ return doc;
517
+ const boxes = targets.map((n) => {
518
+ const { w, h } = nodeSize(n);
519
+ return { n, w, h, cx: n.x + w / 2, cy: n.y + h / 2, r: n.x + w, b: n.y + h };
520
+ });
521
+ let anchor = 0;
522
+ switch (align) {
523
+ case 'left':
524
+ anchor = Math.min(...boxes.map((b) => b.n.x));
525
+ break;
526
+ case 'right':
527
+ anchor = Math.max(...boxes.map((b) => b.r));
528
+ break;
529
+ case 'top':
530
+ anchor = Math.min(...boxes.map((b) => b.n.y));
531
+ break;
532
+ case 'bottom':
533
+ anchor = Math.max(...boxes.map((b) => b.b));
534
+ break;
535
+ case 'centerX':
536
+ anchor = boxes.reduce((s, b) => s + b.cx, 0) / boxes.length;
537
+ break;
538
+ case 'centerY':
539
+ anchor = boxes.reduce((s, b) => s + b.cy, 0) / boxes.length;
540
+ break;
541
+ }
542
+ const nextPos = new Map();
543
+ for (const b of boxes) {
544
+ let x = b.n.x;
545
+ let y = b.n.y;
546
+ if (align === 'left')
547
+ x = anchor;
548
+ else if (align === 'right')
549
+ x = anchor - b.w;
550
+ else if (align === 'centerX')
551
+ x = anchor - b.w / 2;
552
+ else if (align === 'top')
553
+ y = anchor;
554
+ else if (align === 'bottom')
555
+ y = anchor - b.h;
556
+ else if (align === 'centerY')
557
+ y = anchor - b.h / 2;
558
+ nextPos.set(b.n.id, { x, y });
559
+ }
560
+ return {
561
+ ...doc,
562
+ nodes: doc.nodes.map((n) => {
563
+ const p = nextPos.get(n.id);
564
+ return p ? { ...n, x: p.x, y: p.y } : n;
565
+ })
566
+ };
567
+ }
568
+ export function distributeGraphNodes(doc, nodeIds, axis) {
569
+ const idSet = new Set(nodeIds);
570
+ const targets = doc.nodes.filter((n) => idSet.has(n.id) && n.type !== 'comment');
571
+ if (targets.length < 3)
572
+ return doc;
573
+ const sorted = [...targets].sort((a, b) => (axis === 'horizontal' ? a.x - b.x : a.y - b.y));
574
+ const first = sorted[0];
575
+ const last = sorted[sorted.length - 1];
576
+ const { w: lw, h: lh } = nodeSize(last);
577
+ const start = axis === 'horizontal' ? first.x : first.y;
578
+ const end = axis === 'horizontal' ? last.x + lw : last.y + lh;
579
+ const totalSize = sorted.reduce((s, n) => {
580
+ const { w, h } = nodeSize(n);
581
+ return s + (axis === 'horizontal' ? w : h);
582
+ }, 0);
583
+ const gap = (end - start - totalSize) / (sorted.length - 1);
584
+ const nextPos = new Map();
585
+ let cursor = start;
586
+ for (const n of sorted) {
587
+ const { w, h } = nodeSize(n);
588
+ if (axis === 'horizontal')
589
+ nextPos.set(n.id, { x: cursor, y: n.y });
590
+ else
591
+ nextPos.set(n.id, { x: n.x, y: cursor });
592
+ cursor += (axis === 'horizontal' ? w : h) + gap;
593
+ }
594
+ return {
595
+ ...doc,
596
+ nodes: doc.nodes.map((n) => {
597
+ const p = nextPos.get(n.id);
598
+ return p ? { ...n, x: p.x, y: p.y } : n;
599
+ })
600
+ };
601
+ }
602
+ export function selectionBounds(doc, nodeIds, padding = 24) {
603
+ const idSet = new Set(nodeIds);
604
+ const nodes = doc.nodes.filter((n) => idSet.has(n.id));
605
+ if (!nodes.length)
606
+ return null;
607
+ let minX = Infinity;
608
+ let minY = Infinity;
609
+ let maxX = -Infinity;
610
+ let maxY = -Infinity;
611
+ for (const n of nodes) {
612
+ const { w, h } = nodeSize(n);
613
+ minX = Math.min(minX, n.x);
614
+ minY = Math.min(minY, n.y);
615
+ maxX = Math.max(maxX, n.x + w);
616
+ maxY = Math.max(maxY, n.y + h);
617
+ }
618
+ return {
619
+ x: minX - padding,
620
+ y: minY - padding,
621
+ width: maxX - minX + padding * 2,
622
+ height: maxY - minY + padding * 2
623
+ };
624
+ }
625
+ export function createCommentFromSelection(doc, nodeIds, opts) {
626
+ const bounds = selectionBounds(doc, nodeIds, 28);
627
+ if (!bounds)
628
+ return null;
629
+ const comment = {
630
+ id: uid('n'),
631
+ type: 'comment',
632
+ x: bounds.x,
633
+ y: bounds.y,
634
+ width: Math.max(180, bounds.width),
635
+ height: Math.max(80, bounds.height),
636
+ data: {
637
+ label: opts?.label ?? 'Comment',
638
+ commentColor: 'rgba(251, 191, 36, 0.18)',
639
+ memberIds: [...nodeIds]
640
+ },
641
+ inputs: [],
642
+ outputs: []
643
+ };
644
+ return {
645
+ doc: { ...doc, nodes: [comment, ...doc.nodes] },
646
+ commentId: comment.id
647
+ };
648
+ }
649
+ export function createRerouteNode(pos, port) {
650
+ const kind = port.kind ?? (port.dataType === 'exec' ? 'exec' : 'data');
651
+ const dataType = (port.dataType ?? (kind === 'exec' ? 'exec' : 'any'));
652
+ return {
653
+ id: uid('n'),
654
+ type: 'reroute',
655
+ x: pos.x - 8,
656
+ y: pos.y - 8,
657
+ width: 16,
658
+ height: 16,
659
+ data: {
660
+ label: 'Reroute',
661
+ pinKind: kind,
662
+ pinDataType: dataType,
663
+ color: kind === 'exec' ? '#94a3b8' : pinColor({ id: 'p', kind, dataType })
664
+ },
665
+ inputs: [{ id: 'in', label: '', side: 'left', kind, dataType }],
666
+ outputs: [{ id: 'out', label: '', side: 'right', kind, dataType }]
667
+ };
668
+ }
669
+ export function insertRerouteOnEdge(doc, edgeId, pos) {
670
+ const edge = doc.edges.find((e) => e.id === edgeId);
671
+ if (!edge)
672
+ return null;
673
+ const source = doc.nodes.find((n) => n.id === edge.source);
674
+ const out = source?.outputs?.find((p) => p.id === (edge.sourceHandle ?? p.id)) ??
675
+ source?.outputs?.[0];
676
+ const port = out ?? { kind: 'data', dataType: 'any' };
677
+ const reroute = createRerouteNode(pos, port);
678
+ const left = {
679
+ id: uid('e'),
680
+ source: edge.source,
681
+ target: reroute.id,
682
+ sourceHandle: edge.sourceHandle,
683
+ targetHandle: 'in',
684
+ label: edge.label
685
+ };
686
+ const right = {
687
+ id: uid('e'),
688
+ source: reroute.id,
689
+ target: edge.target,
690
+ sourceHandle: 'out',
691
+ targetHandle: edge.targetHandle
692
+ };
693
+ return {
694
+ doc: {
695
+ ...doc,
696
+ nodes: [...doc.nodes, reroute],
697
+ edges: [...doc.edges.filter((e) => e.id !== edgeId), left, right]
698
+ },
699
+ rerouteId: reroute.id
700
+ };
701
+ }
702
+ export function breakLinksAtHandle(doc, nodeId, handleId, handleType) {
703
+ if (!handleId) {
704
+ return {
705
+ ...doc,
706
+ edges: doc.edges.filter((e) => handleType === 'source'
707
+ ? e.source !== nodeId
708
+ : handleType === 'target'
709
+ ? e.target !== nodeId
710
+ : e.source !== nodeId && e.target !== nodeId)
711
+ };
712
+ }
713
+ return {
714
+ ...doc,
715
+ edges: doc.edges.filter((e) => {
716
+ if (handleType === 'source' || handleType == null) {
717
+ if (e.source === nodeId && (e.sourceHandle ?? '') === handleId)
718
+ return false;
719
+ }
720
+ if (handleType === 'target' || handleType == null) {
721
+ if (e.target === nodeId && (e.targetHandle ?? '') === handleId)
722
+ return false;
723
+ }
724
+ return true;
725
+ })
726
+ };
727
+ }
728
+ export function collapseSelectionToFunction(doc, nodeIds, opts) {
729
+ const idSet = new Set(nodeIds.filter((id) => doc.nodes.some((n) => n.id === id)));
730
+ const members = doc.nodes.filter((n) => idSet.has(n.id) && n.type !== 'comment' && n.type !== 'collapsed_graph');
731
+ if (members.length < 1)
732
+ return null;
733
+ const memberIds = new Set(members.map((n) => n.id));
734
+ const internalEdges = doc.edges.filter((e) => memberIds.has(e.source) && memberIds.has(e.target));
735
+ const incoming = doc.edges.filter((e) => memberIds.has(e.target) && !memberIds.has(e.source));
736
+ const outgoing = doc.edges.filter((e) => memberIds.has(e.source) && !memberIds.has(e.target));
737
+ const inputs = [];
738
+ const outputs = [];
739
+ const inMap = [];
740
+ const outMap = [];
741
+ incoming.forEach((edge, i) => {
742
+ const target = members.find((n) => n.id === edge.target);
743
+ const port = target?.inputs?.find((p) => p.id === (edge.targetHandle ?? p.id)) ??
744
+ target?.inputs?.[0];
745
+ const pinId = `in_${i}`;
746
+ inputs.push({
747
+ id: pinId,
748
+ label: port?.label ?? `In ${i + 1}`,
749
+ side: 'left',
750
+ kind: port?.kind ?? 'data',
751
+ dataType: port?.dataType ?? 'any'
752
+ });
753
+ inMap.push({ edge, pinId });
754
+ });
755
+ outgoing.forEach((edge, i) => {
756
+ const source = members.find((n) => n.id === edge.source);
757
+ const port = source?.outputs?.find((p) => p.id === (edge.sourceHandle ?? p.id)) ??
758
+ source?.outputs?.[0];
759
+ const pinId = `out_${i}`;
760
+ outputs.push({
761
+ id: pinId,
762
+ label: port?.label ?? `Out ${i + 1}`,
763
+ side: 'right',
764
+ kind: port?.kind ?? 'data',
765
+ dataType: port?.dataType ?? 'any'
766
+ });
767
+ outMap.push({ edge, pinId });
768
+ });
769
+ if (!inputs.length)
770
+ inputs.push(execPort('exec_in', 'Exec', 'left'));
771
+ if (!outputs.length)
772
+ outputs.push(execPort('exec', 'Then', 'right'));
773
+ const bounds = selectionBounds(doc, [...memberIds], 0);
774
+ const collapsed = {
775
+ id: uid('n'),
776
+ type: 'collapsed_graph',
777
+ x: bounds ? bounds.x + bounds.width / 2 - 110 : members[0].x,
778
+ y: bounds ? bounds.y + bounds.height / 2 - 36 : members[0].y,
779
+ width: 220,
780
+ height: Math.max(72, 40 + Math.max(inputs.length, outputs.length) * 22),
781
+ data: {
782
+ label: opts?.label ?? `Collapsed (${members.length})`,
783
+ color: '#7c3aed',
784
+ collapsedGraph: {
785
+ version: 1,
786
+ nodes: members.map((n) => ({
787
+ ...n,
788
+ inputs: n.inputs?.map((p) => ({ ...p })),
789
+ outputs: n.outputs?.map((p) => ({ ...p })),
790
+ data: n.data ? { ...n.data } : undefined
791
+ })),
792
+ edges: internalEdges.map((e) => ({ ...e }))
793
+ },
794
+ boundaryIn: inMap.map(({ edge, pinId }) => ({
795
+ pinId,
796
+ innerNodeId: edge.target,
797
+ innerHandle: edge.targetHandle
798
+ })),
799
+ boundaryOut: outMap.map(({ edge, pinId }) => ({
800
+ pinId,
801
+ innerNodeId: edge.source,
802
+ innerHandle: edge.sourceHandle
803
+ }))
804
+ },
805
+ inputs,
806
+ outputs
807
+ };
808
+ const rewired = [
809
+ ...inMap.map(({ edge, pinId }) => ({
810
+ id: uid('e'),
811
+ source: edge.source,
812
+ target: collapsed.id,
813
+ sourceHandle: edge.sourceHandle,
814
+ targetHandle: pinId
815
+ })),
816
+ ...outMap.map(({ edge, pinId }) => ({
817
+ id: uid('e'),
818
+ source: collapsed.id,
819
+ target: edge.target,
820
+ sourceHandle: pinId,
821
+ targetHandle: edge.targetHandle
822
+ }))
823
+ ];
824
+ const keepEdges = doc.edges.filter((e) => !memberIds.has(e.source) && !memberIds.has(e.target));
825
+ return {
826
+ doc: {
827
+ ...doc,
828
+ nodes: [...doc.nodes.filter((n) => !memberIds.has(n.id)), collapsed],
829
+ edges: [...keepEdges, ...rewired]
830
+ },
831
+ collapsedId: collapsed.id
832
+ };
833
+ }
834
+ export function expandCollapsedGraph(doc, nodeId) {
835
+ const node = doc.nodes.find((n) => n.id === nodeId && n.type === 'collapsed_graph');
836
+ if (!node)
837
+ return null;
838
+ const subgraph = node.data?.collapsedGraph;
839
+ if (!subgraph?.nodes?.length)
840
+ return null;
841
+ const idMap = new Map();
842
+ const clones = subgraph.nodes.map((n) => {
843
+ const id = uid('n');
844
+ idMap.set(n.id, id);
845
+ return {
846
+ ...n,
847
+ id,
848
+ x: n.x,
849
+ y: n.y,
850
+ inputs: n.inputs?.map((p) => ({ ...p })),
851
+ outputs: n.outputs?.map((p) => ({ ...p })),
852
+ data: n.data ? { ...n.data } : undefined
853
+ };
854
+ });
855
+ const internal = (subgraph.edges ?? []).map((e) => ({
856
+ ...e,
857
+ id: uid('e'),
858
+ source: idMap.get(e.source),
859
+ target: idMap.get(e.target)
860
+ }));
861
+ const boundaryIn = node.data?.boundaryIn ?? [];
862
+ const boundaryOut = node.data?.boundaryOut ?? [];
863
+ const external = doc.edges.filter((e) => e.source !== nodeId && e.target !== nodeId);
864
+ const restoredIn = doc.edges
865
+ .filter((e) => e.target === nodeId)
866
+ .map((e) => {
867
+ const b = boundaryIn.find((x) => x.pinId === (e.targetHandle ?? x.pinId));
868
+ const inner = b ? idMap.get(b.innerNodeId) : clones[0]?.id;
869
+ if (!inner)
870
+ return null;
871
+ return {
872
+ id: uid('e'),
873
+ source: e.source,
874
+ target: inner,
875
+ sourceHandle: e.sourceHandle,
876
+ targetHandle: b?.innerHandle
877
+ };
878
+ })
879
+ .filter(Boolean);
880
+ const restoredOut = doc.edges
881
+ .filter((e) => e.source === nodeId)
882
+ .map((e) => {
883
+ const b = boundaryOut.find((x) => x.pinId === (e.sourceHandle ?? x.pinId));
884
+ const inner = b ? idMap.get(b.innerNodeId) : clones[clones.length - 1]?.id;
885
+ if (!inner)
886
+ return null;
887
+ return {
888
+ id: uid('e'),
889
+ source: inner,
890
+ target: e.target,
891
+ sourceHandle: b?.innerHandle,
892
+ targetHandle: e.targetHandle
893
+ };
894
+ })
895
+ .filter(Boolean);
896
+ return {
897
+ doc: {
898
+ ...doc,
899
+ nodes: [...doc.nodes.filter((n) => n.id !== nodeId), ...clones],
900
+ edges: [...external, ...internal, ...restoredIn, ...restoredOut]
901
+ },
902
+ newNodeIds: clones.map((n) => n.id)
903
+ };
904
+ }
905
+ export function createGraphEdge(source, target, opts) {
906
+ return {
907
+ id: opts?.id ?? uid('e'),
908
+ source,
909
+ target,
910
+ label: opts?.label,
911
+ sourceHandle: opts?.sourceHandle ?? 'exec',
912
+ targetHandle: opts?.targetHandle ?? 'exec_in'
913
+ };
914
+ }
915
+ export function serializeGraphDocument(doc) {
916
+ return JSON.stringify(doc, null, 2);
917
+ }
918
+ export function parseGraphDocument(raw) {
919
+ if (typeof raw !== 'string')
920
+ return normalizeGraph(raw);
921
+ try {
922
+ return normalizeGraph(JSON.parse(raw));
923
+ }
924
+ catch {
925
+ return emptyGraphDocument();
926
+ }
927
+ }
928
+ function normalizeGraph(input) {
929
+ if (!input || typeof input !== 'object')
930
+ return emptyGraphDocument();
931
+ const obj = input;
932
+ const nodes = Array.isArray(obj.nodes)
933
+ ? obj.nodes.filter((n) => !!n &&
934
+ typeof n === 'object' &&
935
+ typeof n.id === 'string' &&
936
+ typeof n.type === 'string')
937
+ : [];
938
+ const edges = Array.isArray(obj.edges)
939
+ ? obj.edges.filter((e) => !!e &&
940
+ typeof e === 'object' &&
941
+ typeof e.id === 'string' &&
942
+ typeof e.source === 'string' &&
943
+ typeof e.target === 'string')
944
+ : [];
945
+ return { version: 1, nodes, edges };
946
+ }
947
+ export function removeNode(doc, nodeId) {
948
+ return {
949
+ ...doc,
950
+ nodes: doc.nodes.filter((n) => n.id !== nodeId),
951
+ edges: doc.edges.filter((e) => e.source !== nodeId && e.target !== nodeId)
952
+ };
953
+ }
954
+ export function removeEdge(doc, edgeId) {
955
+ return { ...doc, edges: doc.edges.filter((e) => e.id !== edgeId) };
956
+ }
957
+ export function updateNodePosition(doc, nodeId, x, y) {
958
+ return {
959
+ ...doc,
960
+ nodes: doc.nodes.map((n) => (n.id === nodeId ? { ...n, x, y } : n))
961
+ };
962
+ }
963
+ export function nodeSize(node, fallbackW = DEFAULT_NODE_WIDTH, fallbackH = DEFAULT_NODE_HEIGHT) {
964
+ return { w: node.width ?? fallbackW, h: node.height ?? fallbackH };
965
+ }
966
+ export function nodeCenter(node, width, height) {
967
+ const { w, h } = nodeSize(node, width, height);
968
+ return { x: node.x + w / 2, y: node.y + h / 2 };
969
+ }
970
+ function portOffset(port, index, total) {
971
+ if (typeof port.offset === 'number')
972
+ return Math.min(1, Math.max(0, port.offset));
973
+ if (total <= 1)
974
+ return 0.5;
975
+ return (index + 1) / (total + 1);
976
+ }
977
+ export function portPosition(node, port, kind, index = 0, total = 1, fallbackW = DEFAULT_NODE_WIDTH, fallbackH = DEFAULT_NODE_HEIGHT) {
978
+ const { w, h } = nodeSize(node, fallbackW, fallbackH);
979
+ const side = port.side ?? (kind === 'input' ? 'left' : 'right');
980
+ const t = portOffset(port, index, total);
981
+ switch (side) {
982
+ case 'left':
983
+ return { x: node.x, y: node.y + h * t };
984
+ case 'right':
985
+ return { x: node.x + w, y: node.y + h * t };
986
+ case 'top':
987
+ return { x: node.x + w * t, y: node.y };
988
+ case 'bottom':
989
+ return { x: node.x + w * t, y: node.y + h };
990
+ default:
991
+ return { x: node.x + w, y: node.y + h / 2 };
992
+ }
993
+ }
994
+ export function findPort(node, handleId, kind) {
995
+ const list = kind === 'input' ? (node.inputs ?? []) : (node.outputs ?? []);
996
+ if (!list.length)
997
+ return null;
998
+ const index = handleId ? list.findIndex((p) => p.id === handleId) : 0;
999
+ const i = index >= 0 ? index : 0;
1000
+ return { port: list[i], index: i, total: list.length };
1001
+ }
1002
+ export function edgeEndpoints(doc, edge, fallbackW = DEFAULT_NODE_WIDTH, fallbackH = DEFAULT_NODE_HEIGHT) {
1003
+ const source = doc.nodes.find((n) => n.id === edge.source);
1004
+ const target = doc.nodes.find((n) => n.id === edge.target);
1005
+ if (!source || !target)
1006
+ return null;
1007
+ const out = findPort(source, edge.sourceHandle, 'output');
1008
+ const inn = findPort(target, edge.targetHandle, 'input');
1009
+ const from = out
1010
+ ? portPosition(source, out.port, 'output', out.index, out.total, fallbackW, fallbackH)
1011
+ : {
1012
+ x: source.x + nodeSize(source, fallbackW, fallbackH).w,
1013
+ y: source.y + nodeSize(source, fallbackW, fallbackH).h / 2
1014
+ };
1015
+ const to = inn
1016
+ ? portPosition(target, inn.port, 'input', inn.index, inn.total, fallbackW, fallbackH)
1017
+ : { x: target.x, y: target.y + nodeSize(target, fallbackW, fallbackH).h / 2 };
1018
+ return { from, to };
1019
+ }
1020
+ /** Offset a port-center point along its side normal (away from the node). */
1021
+ export function offsetPortPoint(point, side, distance) {
1022
+ switch (side) {
1023
+ case 'left':
1024
+ return { x: point.x - distance, y: point.y };
1025
+ case 'right':
1026
+ return { x: point.x + distance, y: point.y };
1027
+ case 'top':
1028
+ return { x: point.x, y: point.y - distance };
1029
+ case 'bottom':
1030
+ return { x: point.x, y: point.y + distance };
1031
+ default:
1032
+ return { x: point.x + distance, y: point.y };
1033
+ }
1034
+ }
1035
+ export function isExecPort(port) {
1036
+ return (port.kind ?? port.dataType) === 'exec' || port.dataType === 'exec';
1037
+ }
1038
+ export function isDataPort(port) {
1039
+ return !isExecPort(port);
1040
+ }
1041
+ export function formatPortLiteral(port) {
1042
+ if (port.value == null)
1043
+ return '';
1044
+ if (typeof port.value === 'boolean')
1045
+ return port.value ? 'true' : 'false';
1046
+ return String(port.value);
1047
+ }
1048
+ export function parsePortLiteral(port, raw) {
1049
+ const dt = port.dataType ?? 'any';
1050
+ if (dt === 'bool') {
1051
+ const v = raw.trim().toLowerCase();
1052
+ if (v === 'true' || v === '1' || v === 'yes')
1053
+ return true;
1054
+ if (v === 'false' || v === '0' || v === 'no' || v === '')
1055
+ return false;
1056
+ return Boolean(raw);
1057
+ }
1058
+ if (dt === 'int') {
1059
+ const n = parseInt(raw, 10);
1060
+ return Number.isFinite(n) ? n : 0;
1061
+ }
1062
+ if (dt === 'float') {
1063
+ const n = parseFloat(raw);
1064
+ return Number.isFinite(n) ? n : 0;
1065
+ }
1066
+ if (dt === 'object') {
1067
+ const t = raw.trim();
1068
+ if (!t || t === 'null')
1069
+ return null;
1070
+ try {
1071
+ return JSON.parse(t);
1072
+ }
1073
+ catch {
1074
+ return t;
1075
+ }
1076
+ }
1077
+ return raw;
1078
+ }
1079
+ export function defaultPortLiteral(port) {
1080
+ if (port.value !== undefined)
1081
+ return port.value;
1082
+ const dt = port.dataType ?? 'any';
1083
+ switch (dt) {
1084
+ case 'bool':
1085
+ return false;
1086
+ case 'int':
1087
+ return 0;
1088
+ case 'float':
1089
+ return 0;
1090
+ case 'string':
1091
+ return '';
1092
+ case 'object':
1093
+ return null;
1094
+ default:
1095
+ return '';
1096
+ }
1097
+ }
1098
+ /** Map nodeId → input handle ids that have an incoming edge. */
1099
+ export function wiredInputIdsByNode(edges) {
1100
+ const map = new Map();
1101
+ for (const e of edges) {
1102
+ const handle = e.targetHandle ?? 'exec_in';
1103
+ if (!map.has(e.target))
1104
+ map.set(e.target, new Set());
1105
+ map.get(e.target).add(handle);
1106
+ }
1107
+ return map;
1108
+ }
1109
+ /** Bezier with endpoints on the pin rim along the side normal (not the chord). */
1110
+ export function edgePathForPorts(from, to, opts) {
1111
+ const fromSide = opts?.fromSide ?? 'right';
1112
+ const toSide = opts?.toSide ?? 'left';
1113
+ const padStart = opts?.padStart ?? EDGE_PORT_PAD;
1114
+ /** Tip of the marker sits on the path end — stop at pin rim. */
1115
+ const padEnd = opts?.padEnd ?? EDGE_PORT_PAD;
1116
+ const curvature = opts?.curvature ?? 0.45;
1117
+ const a = offsetPortPoint(from, fromSide, padStart);
1118
+ const b = offsetPortPoint(to, toSide, padEnd);
1119
+ return edgePathFromPoints(a, b, curvature);
1120
+ }
1121
+ /** True if the type exposes at least one input pin compatible with `source`. */
1122
+ export function nodeTypeAcceptsPort(typeDef, source) {
1123
+ return (typeDef.inputs ?? []).some((p) => pinsCompatible(source, p));
1124
+ }
1125
+ export function firstCompatibleInput(node, source) {
1126
+ return (node.inputs ?? []).find((p) => pinsCompatible(source, p)) ?? null;
1127
+ }
1128
+ export function edgePathFromPoints(from, to, curvature = 0.45) {
1129
+ const dx = Math.abs(to.x - from.x);
1130
+ const dy = Math.abs(to.y - from.y);
1131
+ const offset = Math.max(40, Math.min(dx * curvature, 180));
1132
+ if (dx >= dy * 0.4) {
1133
+ const c1x = from.x + offset;
1134
+ const c2x = to.x - offset;
1135
+ return `M ${from.x} ${from.y} C ${c1x} ${from.y}, ${c2x} ${to.y}, ${to.x} ${to.y}`;
1136
+ }
1137
+ const c1y = from.y + offset;
1138
+ const c2y = to.y - offset;
1139
+ return `M ${from.x} ${from.y} C ${from.x} ${c1y}, ${to.x} ${c2y}, ${to.x} ${to.y}`;
1140
+ }
1141
+ export function pinsCompatible(source, target) {
1142
+ const sk = source.kind ?? (source.dataType === 'exec' ? 'exec' : 'data');
1143
+ const tk = target.kind ?? (target.dataType === 'exec' ? 'exec' : 'data');
1144
+ if (sk !== tk)
1145
+ return false;
1146
+ if (sk === 'exec')
1147
+ return true;
1148
+ const st = source.dataType ?? 'any';
1149
+ const tt = target.dataType ?? 'any';
1150
+ if (st === 'any' || tt === 'any')
1151
+ return true;
1152
+ return st === tt;
1153
+ }
1154
+ export function validateGraph(doc) {
1155
+ const issues = [];
1156
+ for (const edge of doc.edges) {
1157
+ const source = doc.nodes.find((n) => n.id === edge.source);
1158
+ const target = doc.nodes.find((n) => n.id === edge.target);
1159
+ if (!source || !target) {
1160
+ issues.push({
1161
+ id: `missing-${edge.id}`,
1162
+ level: 'error',
1163
+ message: `Edge ${edge.id} references missing node`,
1164
+ edgeId: edge.id
1165
+ });
1166
+ continue;
1167
+ }
1168
+ const out = findPort(source, edge.sourceHandle, 'output');
1169
+ const inn = findPort(target, edge.targetHandle, 'input');
1170
+ if (!out || !inn) {
1171
+ issues.push({
1172
+ id: `port-${edge.id}`,
1173
+ level: 'error',
1174
+ message: `Edge ${edge.id} has invalid handles`,
1175
+ edgeId: edge.id
1176
+ });
1177
+ continue;
1178
+ }
1179
+ if (!pinsCompatible(out.port, inn.port)) {
1180
+ issues.push({
1181
+ id: `type-${edge.id}`,
1182
+ level: 'error',
1183
+ message: `Incompatible pins: ${out.port.dataType ?? out.port.kind} → ${inn.port.dataType ?? inn.port.kind}`,
1184
+ edgeId: edge.id
1185
+ });
1186
+ }
1187
+ }
1188
+ for (const node of doc.nodes) {
1189
+ if (node.type === 'comment' || node.type === 'reroute' || node.type === 'collapsed_graph')
1190
+ continue;
1191
+ const hasExecOut = (node.outputs ?? []).some((p) => (p.kind ?? p.dataType) === 'exec' || p.dataType === 'exec');
1192
+ const hasExecIn = (node.inputs ?? []).some((p) => (p.kind ?? p.dataType) === 'exec' || p.dataType === 'exec');
1193
+ // Entry/event nodes with no continuation — not sinks like Print/Delay (Then unused is fine).
1194
+ if (hasExecOut && !hasExecIn && !doc.edges.some((e) => e.source === node.id)) {
1195
+ issues.push({
1196
+ id: `orphan-out-${node.id}`,
1197
+ level: 'warning',
1198
+ message: `Node "${node.data?.label ?? node.type}" has no outgoing exec wire`,
1199
+ nodeId: node.id
1200
+ });
1201
+ }
1202
+ if (hasExecIn && !doc.edges.some((e) => e.target === node.id)) {
1203
+ issues.push({
1204
+ id: `orphan-in-${node.id}`,
1205
+ level: 'warning',
1206
+ message: `Node "${node.data?.label ?? node.type}" has no incoming wire`,
1207
+ nodeId: node.id
1208
+ });
1209
+ }
1210
+ }
1211
+ return issues;
1212
+ }
1213
+ export function snap(value, grid) {
1214
+ if (grid <= 1)
1215
+ return value;
1216
+ return Math.round(value / grid) * grid;
1217
+ }
1218
+ export function fitView(nodes, viewport, padding = 48, fallbackW = DEFAULT_NODE_WIDTH, fallbackH = DEFAULT_NODE_HEIGHT) {
1219
+ if (!nodes.length)
1220
+ return { pan: { x: 0, y: 0 }, scale: 1 };
1221
+ let minX = Infinity;
1222
+ let minY = Infinity;
1223
+ let maxX = -Infinity;
1224
+ let maxY = -Infinity;
1225
+ for (const n of nodes) {
1226
+ const { w, h } = nodeSize(n, fallbackW, fallbackH);
1227
+ minX = Math.min(minX, n.x);
1228
+ minY = Math.min(minY, n.y);
1229
+ maxX = Math.max(maxX, n.x + w);
1230
+ maxY = Math.max(maxY, n.y + h);
1231
+ }
1232
+ const bw = maxX - minX || 1;
1233
+ const bh = maxY - minY || 1;
1234
+ const scale = Math.min(2, Math.max(0.35, Math.min((viewport.width - padding * 2) / bw, (viewport.height - padding * 2) / bh)));
1235
+ return {
1236
+ pan: {
1237
+ x: (viewport.width - bw * scale) / 2 - minX * scale,
1238
+ y: (viewport.height - bh * scale) / 2 - minY * scale
1239
+ },
1240
+ scale
1241
+ };
1242
+ }
1243
+ export function groupNodeTypesByCategory(types) {
1244
+ const map = new Map();
1245
+ for (const t of types) {
1246
+ const cat = t.category ?? 'Other';
1247
+ if (!map.has(cat))
1248
+ map.set(cat, []);
1249
+ map.get(cat).push(t);
1250
+ }
1251
+ return [...map.entries()].map(([category, list]) => ({ category, types: list }));
1252
+ }
1253
+ export function nodeTypeAllowedInContext(type, context) {
1254
+ if (!context)
1255
+ return true;
1256
+ if (!type.contexts?.length)
1257
+ return true;
1258
+ return type.contexts.includes(context);
1259
+ }
1260
+ /** Palette / place-menu catalog: context + hide templates. */
1261
+ export function filterNodeTypesForGraph(types, opts) {
1262
+ return types.filter((t) => {
1263
+ if (!opts?.includeHidden && t.hidden)
1264
+ return false;
1265
+ return nodeTypeAllowedInContext(t, opts?.context);
1266
+ });
1267
+ }
1268
+ export function variablePinColor(dataType) {
1269
+ return PIN_TYPE_COLORS[dataType] ?? PIN_TYPE_COLORS.any;
1270
+ }
1271
+ export function defaultValueForPinType(dataType) {
1272
+ switch (dataType) {
1273
+ case 'bool':
1274
+ return false;
1275
+ case 'int':
1276
+ return 0;
1277
+ case 'float':
1278
+ return 0;
1279
+ case 'string':
1280
+ return '';
1281
+ case 'object':
1282
+ return null;
1283
+ default:
1284
+ return undefined;
1285
+ }
1286
+ }
1287
+ export function createVarGetNode(variable, pos) {
1288
+ const color = variablePinColor(variable.dataType);
1289
+ const w = Math.max(148, variable.name.length * 8 + 56);
1290
+ return {
1291
+ id: uid('n'),
1292
+ type: 'var_get',
1293
+ x: pos.x,
1294
+ y: pos.y,
1295
+ width: w,
1296
+ height: 52,
1297
+ data: {
1298
+ label: variable.name,
1299
+ color,
1300
+ variableId: variable.id,
1301
+ variableName: variable.name,
1302
+ access: 'get'
1303
+ },
1304
+ inputs: [],
1305
+ outputs: [dataPort('value', '', variable.dataType, 'right')]
1306
+ };
1307
+ }
1308
+ export function createVarSetNode(variable, pos) {
1309
+ const color = variablePinColor(variable.dataType);
1310
+ const w = Math.max(168, variable.name.length * 8 + 72);
1311
+ return {
1312
+ id: uid('n'),
1313
+ type: 'var_set',
1314
+ x: pos.x,
1315
+ y: pos.y,
1316
+ width: w,
1317
+ height: 72,
1318
+ data: {
1319
+ label: `Set ${variable.name}`,
1320
+ color,
1321
+ variableId: variable.id,
1322
+ variableName: variable.name,
1323
+ access: 'set'
1324
+ },
1325
+ inputs: [
1326
+ execPort('exec_in', 'Exec', 'left'),
1327
+ dataPort('value', variable.name, variable.dataType, 'left')
1328
+ ],
1329
+ outputs: [
1330
+ execPort('exec', 'Then', 'right'),
1331
+ dataPort('out', '', variable.dataType, 'right')
1332
+ ]
1333
+ };
1334
+ }
1335
+ /** Place-menu entries for Get/Set of each blueprint variable. */
1336
+ export function variablePlaceItems(variables) {
1337
+ const items = [];
1338
+ for (const v of variables) {
1339
+ const color = variablePinColor(v.dataType);
1340
+ items.push({
1341
+ id: `get:${v.id}`,
1342
+ kind: 'get',
1343
+ variable: v,
1344
+ label: `Get ${v.name}`,
1345
+ color
1346
+ });
1347
+ items.push({
1348
+ id: `set:${v.id}`,
1349
+ kind: 'set',
1350
+ variable: v,
1351
+ label: `Set ${v.name}`,
1352
+ color
1353
+ });
1354
+ }
1355
+ return items;
1356
+ }
1357
+ export function emptyBlueprintDocument(name = 'New Blueprint') {
1358
+ return { version: 1, name, graph: emptyGraphDocument(), variables: [] };
1359
+ }
1360
+ export function toFlowNodes(doc, catalog = DEFAULT_NODE_TYPES, selectedIds = []) {
1361
+ const selected = new Set(selectedIds);
1362
+ // Comments first so they paint under other nodes when z-index ties.
1363
+ const ordered = [
1364
+ ...doc.nodes.filter((n) => n.type === 'comment'),
1365
+ ...doc.nodes.filter((n) => n.type !== 'comment')
1366
+ ];
1367
+ return ordered.map((n) => {
1368
+ const def = resolveNodeType(n.type, catalog);
1369
+ const { w, h } = nodeSize(n);
1370
+ const isComment = n.type === 'comment';
1371
+ return {
1372
+ id: n.id,
1373
+ type: 'blueprint',
1374
+ position: { x: n.x, y: n.y },
1375
+ selected: selected.has(n.id),
1376
+ width: w,
1377
+ height: h,
1378
+ zIndex: isComment ? -1 : 1,
1379
+ class: isComment ? 'bp-flow-comment' : undefined,
1380
+ data: {
1381
+ ...(n.data ?? {}),
1382
+ graphType: n.type,
1383
+ label: n.data?.label ?? def?.label ?? n.type,
1384
+ description: n.data?.description,
1385
+ color: n.data?.color ?? def?.color,
1386
+ commentColor: n.data?.commentColor,
1387
+ memberIds: Array.isArray(n.data?.memberIds)
1388
+ ? [...n.data.memberIds]
1389
+ : undefined,
1390
+ inputs: (n.inputs ?? []).map((p) => ({ ...p })),
1391
+ outputs: (n.outputs ?? []).map((p) => ({ ...p })),
1392
+ width: n.width ?? def?.width,
1393
+ height: n.height ?? def?.height
1394
+ }
1395
+ };
1396
+ });
1397
+ }
1398
+ export function toFlowEdges(doc, selectedIds = []) {
1399
+ const selected = new Set(selectedIds);
1400
+ return doc.edges.map((e) => ({
1401
+ id: e.id,
1402
+ source: e.source,
1403
+ target: e.target,
1404
+ sourceHandle: e.sourceHandle ?? null,
1405
+ targetHandle: e.targetHandle ?? null,
1406
+ label: e.label,
1407
+ selected: selected.has(e.id)
1408
+ }));
1409
+ }
1410
+ export function fromFlowNodes(nodes) {
1411
+ return nodes.map((n) => {
1412
+ const { graphType, inputs, outputs, width, height, _alert: _a, _wiredInputs: _w, _onLiteral: _o, ...rest } = n.data;
1413
+ return {
1414
+ id: n.id,
1415
+ type: graphType,
1416
+ x: n.position.x,
1417
+ y: n.position.y,
1418
+ width: width ?? n.width,
1419
+ height: height ?? n.height,
1420
+ data: { ...rest },
1421
+ inputs: (inputs ?? []).map((p) => ({ ...p })),
1422
+ outputs: (outputs ?? []).map((p) => ({ ...p }))
1423
+ };
1424
+ });
1425
+ }
1426
+ export function fromFlowEdges(edges) {
1427
+ return edges.map((e) => ({
1428
+ id: e.id,
1429
+ source: e.source,
1430
+ target: e.target,
1431
+ sourceHandle: e.sourceHandle ?? undefined,
1432
+ targetHandle: e.targetHandle ?? undefined,
1433
+ label: typeof e.label === 'string' ? e.label : undefined
1434
+ }));
1435
+ }
1436
+ export function flowDocumentFromFlow(nodes, edges) {
1437
+ return {
1438
+ version: 1,
1439
+ nodes: fromFlowNodes(nodes),
1440
+ edges: fromFlowEdges(edges)
1441
+ };
1442
+ }
1443
+ /** Resolve a port on a flow node by handle id + direction. */
1444
+ export function flowPortOnNode(node, handleId, kind) {
1445
+ if (!node)
1446
+ return null;
1447
+ const list = kind === 'input' ? node.data.inputs : node.data.outputs;
1448
+ if (!list?.length)
1449
+ return null;
1450
+ if (!handleId)
1451
+ return list[0] ?? null;
1452
+ return list.find((p) => p.id === handleId) ?? null;
1453
+ }