entangle-ui 0.10.0 → 0.12.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 (589) hide show
  1. package/CHANGELOG.md +145 -0
  2. package/README.md +7 -5
  3. package/dist/esm/assets/src/components/controls/Select/{Select.css.ts.vanilla-oZnFUorL.css → Select.css.ts.vanilla-Cpu2BvWL.css} +3 -0
  4. package/dist/esm/assets/src/components/controls/Slider/{Slider.css.ts.vanilla-Cqm3fQ0S.css → Slider.css.ts.vanilla-CLf_RC0A.css} +50 -47
  5. package/dist/esm/assets/src/components/editor/PropertyInspector/{PropertyPanel.css.ts.vanilla-RYv_XgOu.css → PropertyPanel.css.ts.vanilla-Dpr_k5I3.css} +4 -1
  6. package/dist/esm/assets/src/components/editor/PropertyInspector/{PropertyRow.css.ts.vanilla-C3YZnnHb.css → PropertyRow.css.ts.vanilla-pq1Uhd2a.css} +15 -8
  7. package/dist/esm/assets/src/components/editor/PropertyInspector/{PropertySection.css.ts.vanilla-DK12opZc.css → PropertySection.css.ts.vanilla-6MWWAqyd.css} +50 -32
  8. package/dist/esm/assets/src/components/navigation/Menu/{Menu.css.ts.vanilla-B5iVe5S2.css → Menu.css.ts.vanilla-Bhh1L5yl.css} +14 -11
  9. package/dist/esm/assets/src/components/primitives/Tooltip/{Tooltip.css.ts.vanilla-CrEFoLBX.css → Tooltip.css.ts.vanilla-BqaiGrFQ.css} +12 -9
  10. package/dist/esm/assets/src/components/shell/AppShell/{AppShell.css.ts.vanilla-BYmtU0O_.css → AppShell.css.ts.vanilla-BLK2-DRL.css} +1 -0
  11. package/dist/esm/assets/src/components/shell/MenuBar/{MenuBar.css.ts.vanilla-TgPcl4yA.css → MenuBar.css.ts.vanilla-Dt3w4f-q.css} +18 -6
  12. package/dist/esm/components/Icons/AddIcon.js.map +1 -1
  13. package/dist/esm/components/Icons/AiChatIcon.js.map +1 -1
  14. package/dist/esm/components/Icons/AiSparklesIcon.js.map +1 -1
  15. package/dist/esm/components/Icons/ArchiveIcon.js.map +1 -1
  16. package/dist/esm/components/Icons/ArrowDownIcon.js.map +1 -1
  17. package/dist/esm/components/Icons/ArrowLeftIcon.js.map +1 -1
  18. package/dist/esm/components/Icons/ArrowRightIcon.js.map +1 -1
  19. package/dist/esm/components/Icons/ArrowUpIcon.js.map +1 -1
  20. package/dist/esm/components/Icons/BookmarkIcon.js.map +1 -1
  21. package/dist/esm/components/Icons/BugIcon.js.map +1 -1
  22. package/dist/esm/components/Icons/BuildingIcon.js.map +1 -1
  23. package/dist/esm/components/Icons/CalendarIcon.js.map +1 -1
  24. package/dist/esm/components/Icons/CameraIcon.js +31 -0
  25. package/dist/esm/components/Icons/CameraIcon.js.map +1 -0
  26. package/dist/esm/components/Icons/CheckIcon.js.map +1 -1
  27. package/dist/esm/components/Icons/ChevronDownIcon.js.map +1 -1
  28. package/dist/esm/components/Icons/ChevronLeftIcon.js.map +1 -1
  29. package/dist/esm/components/Icons/ChevronRightIcon.js.map +1 -1
  30. package/dist/esm/components/Icons/ChevronUpIcon.js.map +1 -1
  31. package/dist/esm/components/Icons/CircleIcon.js.map +1 -1
  32. package/dist/esm/components/Icons/ClockIcon.js.map +1 -1
  33. package/dist/esm/components/Icons/CloseIcon.js.map +1 -1
  34. package/dist/esm/components/Icons/CloudUploadIcon.js.map +1 -1
  35. package/dist/esm/components/Icons/CodeIcon.js.map +1 -1
  36. package/dist/esm/components/Icons/CopyIcon.js.map +1 -1
  37. package/dist/esm/components/Icons/CubeIcon.js +31 -0
  38. package/dist/esm/components/Icons/CubeIcon.js.map +1 -0
  39. package/dist/esm/components/Icons/CutIcon.js.map +1 -1
  40. package/dist/esm/components/Icons/DotsHorizontalIcon.js.map +1 -1
  41. package/dist/esm/components/Icons/DotsVerticalIcon.js.map +1 -1
  42. package/dist/esm/components/Icons/DownloadIcon.js.map +1 -1
  43. package/dist/esm/components/Icons/EditIcon.js.map +1 -1
  44. package/dist/esm/components/Icons/ErrorIcon.js.map +1 -1
  45. package/dist/esm/components/Icons/ExternalLinkIcon.js.map +1 -1
  46. package/dist/esm/components/Icons/EyeDropperIcon.js.map +1 -1
  47. package/dist/esm/components/Icons/EyeIcon.js.map +1 -1
  48. package/dist/esm/components/Icons/FileTextIcon.js.map +1 -1
  49. package/dist/esm/components/Icons/FilterIcon.js.map +1 -1
  50. package/dist/esm/components/Icons/FirstIcon.js.map +1 -1
  51. package/dist/esm/components/Icons/FolderCogIcon.js.map +1 -1
  52. package/dist/esm/components/Icons/FolderIcon.js.map +1 -1
  53. package/dist/esm/components/Icons/FolderOpenIcon.js.map +1 -1
  54. package/dist/esm/components/Icons/FullscreenIcon.js.map +1 -1
  55. package/dist/esm/components/Icons/GitBranchIcon.js.map +1 -1
  56. package/dist/esm/components/Icons/GridIcon.js.map +1 -1
  57. package/dist/esm/components/Icons/HeartIcon.js.map +1 -1
  58. package/dist/esm/components/Icons/HelpIcon.js.map +1 -1
  59. package/dist/esm/components/Icons/HomeIcon.js.map +1 -1
  60. package/dist/esm/components/Icons/ImageIcon.js.map +1 -1
  61. package/dist/esm/components/Icons/InfoIcon.js.map +1 -1
  62. package/dist/esm/components/Icons/LastIcon.js.map +1 -1
  63. package/dist/esm/components/Icons/LinkIcon.js.map +1 -1
  64. package/dist/esm/components/Icons/ListIcon.js.map +1 -1
  65. package/dist/esm/components/Icons/LockIcon.js.map +1 -1
  66. package/dist/esm/components/Icons/MaximizeIcon.js.map +1 -1
  67. package/dist/esm/components/Icons/MenuIcon.js.map +1 -1
  68. package/dist/esm/components/Icons/MinimizeIcon.js.map +1 -1
  69. package/dist/esm/components/Icons/MinusIcon.js.map +1 -1
  70. package/dist/esm/components/Icons/OrbitIcon.js +31 -0
  71. package/dist/esm/components/Icons/OrbitIcon.js.map +1 -0
  72. package/dist/esm/components/Icons/PasteIcon.js.map +1 -1
  73. package/dist/esm/components/Icons/PauseIcon.js.map +1 -1
  74. package/dist/esm/components/Icons/PinIcon.js.map +1 -1
  75. package/dist/esm/components/Icons/PlayIcon.js.map +1 -1
  76. package/dist/esm/components/Icons/RedoIcon.js.map +1 -1
  77. package/dist/esm/components/Icons/RefreshIcon.js.map +1 -1
  78. package/dist/esm/components/Icons/RobotIcon.js.map +1 -1
  79. package/dist/esm/components/Icons/RotateIcon.js +32 -0
  80. package/dist/esm/components/Icons/RotateIcon.js.map +1 -0
  81. package/dist/esm/components/Icons/SaveIcon.js.map +1 -1
  82. package/dist/esm/components/Icons/SearchIcon.js.map +1 -1
  83. package/dist/esm/components/Icons/SendIcon.js.map +1 -1
  84. package/dist/esm/components/Icons/SettingsIcon.js.map +1 -1
  85. package/dist/esm/components/Icons/SortIcon.js.map +1 -1
  86. package/dist/esm/components/Icons/SpinIcon.js +32 -0
  87. package/dist/esm/components/Icons/SpinIcon.js.map +1 -0
  88. package/dist/esm/components/Icons/StarIcon.js.map +1 -1
  89. package/dist/esm/components/Icons/StopIcon.js.map +1 -1
  90. package/dist/esm/components/Icons/SuccessIcon.js.map +1 -1
  91. package/dist/esm/components/Icons/TagIcon.js.map +1 -1
  92. package/dist/esm/components/Icons/TangentAlignedIcon.js.map +1 -1
  93. package/dist/esm/components/Icons/TangentAutoIcon.js.map +1 -1
  94. package/dist/esm/components/Icons/TangentFreeIcon.js.map +1 -1
  95. package/dist/esm/components/Icons/TangentLinearIcon.js.map +1 -1
  96. package/dist/esm/components/Icons/TangentMirroredIcon.js.map +1 -1
  97. package/dist/esm/components/Icons/TangentStepIcon.js.map +1 -1
  98. package/dist/esm/components/Icons/TerminalIcon.js.map +1 -1
  99. package/dist/esm/components/Icons/TrashIcon.js.map +1 -1
  100. package/dist/esm/components/Icons/UndoIcon.js.map +1 -1
  101. package/dist/esm/components/Icons/UnlinkIcon.js.map +1 -1
  102. package/dist/esm/components/Icons/UnlockIcon.js.map +1 -1
  103. package/dist/esm/components/Icons/UploadIcon.js.map +1 -1
  104. package/dist/esm/components/Icons/UserIcon.js.map +1 -1
  105. package/dist/esm/components/Icons/UsersIcon.js.map +1 -1
  106. package/dist/esm/components/Icons/WarningIcon.js.map +1 -1
  107. package/dist/esm/components/Icons/ZoomFitIcon.js +32 -0
  108. package/dist/esm/components/Icons/ZoomFitIcon.js.map +1 -0
  109. package/dist/esm/components/Icons/ZoomInIcon.js.map +1 -1
  110. package/dist/esm/components/Icons/ZoomOutIcon.js.map +1 -1
  111. package/dist/esm/components/controls/CartesianPicker/CartesianPicker.js.map +1 -1
  112. package/dist/esm/components/controls/CartesianPicker/useCartesianInteraction.js.map +1 -1
  113. package/dist/esm/components/controls/CartesianPicker/useCartesianRenderer.js.map +1 -1
  114. package/dist/esm/components/controls/ColorPicker/AlphaSlider.js.map +1 -1
  115. package/dist/esm/components/controls/ColorPicker/ColorArea.js.map +1 -1
  116. package/dist/esm/components/controls/ColorPicker/ColorInputs.js.map +1 -1
  117. package/dist/esm/components/controls/ColorPicker/ColorPalette.js.map +1 -1
  118. package/dist/esm/components/controls/ColorPicker/ColorPicker.js.map +1 -1
  119. package/dist/esm/components/controls/ColorPicker/ColorPresets.js.map +1 -1
  120. package/dist/esm/components/controls/ColorPicker/ColorSwatch.js.map +1 -1
  121. package/dist/esm/components/controls/ColorPicker/EyeDropper.js.map +1 -1
  122. package/dist/esm/components/controls/ColorPicker/HueSlider.js.map +1 -1
  123. package/dist/esm/components/controls/ColorPicker/colorUtils.js.map +1 -1
  124. package/dist/esm/components/controls/ColorPicker/palettes/material.js.map +1 -1
  125. package/dist/esm/components/controls/ColorPicker/palettes/professional.js.map +1 -1
  126. package/dist/esm/components/controls/ColorPicker/palettes/tailwind.js.map +1 -1
  127. package/dist/esm/components/controls/ColorPicker/useColor.js.map +1 -1
  128. package/dist/esm/components/controls/Combobox/Combobox.js.map +1 -1
  129. package/dist/esm/components/controls/CurveEditor/CurveCanvas.js.map +1 -1
  130. package/dist/esm/components/controls/CurveEditor/CurveEditor.js.map +1 -1
  131. package/dist/esm/components/controls/CurveEditor/CurveToolbar.js.map +1 -1
  132. package/dist/esm/components/controls/CurveEditor/curvePresets.js.map +1 -1
  133. package/dist/esm/components/controls/CurveEditor/curveUtils.js.map +1 -1
  134. package/dist/esm/components/controls/CurveEditor/useCurveInteraction.js.map +1 -1
  135. package/dist/esm/components/controls/CurveEditor/useCurveRenderer.js.map +1 -1
  136. package/dist/esm/components/controls/FileTree/FileTree.js +7 -1
  137. package/dist/esm/components/controls/FileTree/FileTree.js.map +1 -1
  138. package/dist/esm/components/controls/FileTree/fileTreeIcons.js.map +1 -1
  139. package/dist/esm/components/controls/FileTree/fileTreeLabels.js.map +1 -1
  140. package/dist/esm/components/controls/FileTree/useFileTreeDrop.js +1 -1
  141. package/dist/esm/components/controls/FileTree/useFileTreeDrop.js.map +1 -1
  142. package/dist/esm/components/controls/FileUploader/FileUploader.js.map +1 -1
  143. package/dist/esm/components/controls/MultiSelect/MultiSelect.js.map +1 -1
  144. package/dist/esm/components/controls/NumberInput/NumberInput.js.map +1 -1
  145. package/dist/esm/components/controls/NumberInput/useNumberInput.js.map +1 -1
  146. package/dist/esm/components/controls/Select/Select.css.js +1 -1
  147. package/dist/esm/components/controls/Select/Select.js +15 -7
  148. package/dist/esm/components/controls/Select/Select.js.map +1 -1
  149. package/dist/esm/components/controls/Slider/Slider.css.js +10 -11
  150. package/dist/esm/components/controls/Slider/Slider.css.js.map +1 -1
  151. package/dist/esm/components/controls/Slider/Slider.js +40 -7
  152. package/dist/esm/components/controls/Slider/Slider.js.map +1 -1
  153. package/dist/esm/components/controls/TagInput/TagInput.js.map +1 -1
  154. package/dist/esm/components/controls/TreeView/TreeNode.js +6 -0
  155. package/dist/esm/components/controls/TreeView/TreeNode.js.map +1 -1
  156. package/dist/esm/components/controls/TreeView/TreeView.js.map +1 -1
  157. package/dist/esm/components/controls/TreeView/useTreeState.js.map +1 -1
  158. package/dist/esm/components/controls/VectorInput/VectorInput.js +6 -0
  159. package/dist/esm/components/controls/VectorInput/VectorInput.js.map +1 -1
  160. package/dist/esm/components/data/DataTable/DataTable.js.map +1 -1
  161. package/dist/esm/components/editor/AssetBrowser/AssetBrowser.js.map +1 -1
  162. package/dist/esm/components/editor/AssetBrowser/AssetBrowserAnnouncementLive.js.map +1 -1
  163. package/dist/esm/components/editor/AssetBrowser/AssetBrowserBreadcrumbs.js.map +1 -1
  164. package/dist/esm/components/editor/AssetBrowser/AssetBrowserContent.js +6 -0
  165. package/dist/esm/components/editor/AssetBrowser/AssetBrowserContent.js.map +1 -1
  166. package/dist/esm/components/editor/AssetBrowser/AssetBrowserContext.js.map +1 -1
  167. package/dist/esm/components/editor/AssetBrowser/AssetBrowserContextMenu.js.map +1 -1
  168. package/dist/esm/components/editor/AssetBrowser/AssetBrowserDefaultMenus.js +6 -0
  169. package/dist/esm/components/editor/AssetBrowser/AssetBrowserDefaultMenus.js.map +1 -1
  170. package/dist/esm/components/editor/AssetBrowser/AssetBrowserGrid.js +1 -1
  171. package/dist/esm/components/editor/AssetBrowser/AssetBrowserGrid.js.map +1 -1
  172. package/dist/esm/components/editor/AssetBrowser/AssetBrowserGridItem.js +6 -0
  173. package/dist/esm/components/editor/AssetBrowser/AssetBrowserGridItem.js.map +1 -1
  174. package/dist/esm/components/editor/AssetBrowser/AssetBrowserList.js +6 -0
  175. package/dist/esm/components/editor/AssetBrowser/AssetBrowserList.js.map +1 -1
  176. package/dist/esm/components/editor/AssetBrowser/AssetBrowserRenameField.js.map +1 -1
  177. package/dist/esm/components/editor/AssetBrowser/AssetBrowserSidebar.js.map +1 -1
  178. package/dist/esm/components/editor/AssetBrowser/AssetBrowserStatusBar.js.map +1 -1
  179. package/dist/esm/components/editor/AssetBrowser/AssetBrowserStore.js.map +1 -1
  180. package/dist/esm/components/editor/AssetBrowser/AssetBrowserSurface.js +6 -0
  181. package/dist/esm/components/editor/AssetBrowser/AssetBrowserSurface.js.map +1 -1
  182. package/dist/esm/components/editor/AssetBrowser/AssetBrowserToolbar.js +6 -0
  183. package/dist/esm/components/editor/AssetBrowser/AssetBrowserToolbar.js.map +1 -1
  184. package/dist/esm/components/editor/AssetBrowser/assetBrowserFilter.js.map +1 -1
  185. package/dist/esm/components/editor/AssetBrowser/assetBrowserFormat.js.map +1 -1
  186. package/dist/esm/components/editor/AssetBrowser/assetBrowserGeometry.js.map +1 -1
  187. package/dist/esm/components/editor/AssetBrowser/assetBrowserKeyboard.js.map +1 -1
  188. package/dist/esm/components/editor/AssetBrowser/assetBrowserLabels.js.map +1 -1
  189. package/dist/esm/components/editor/AssetBrowser/slots.js.map +1 -1
  190. package/dist/esm/components/editor/AssetBrowser/useAssetBrowserAnnouncement.js.map +1 -1
  191. package/dist/esm/components/editor/AssetBrowser/useAssetBrowserHandle.js +1 -1
  192. package/dist/esm/components/editor/AssetBrowser/useAssetBrowserHandle.js.map +1 -1
  193. package/dist/esm/components/editor/AssetBrowser/useAssetBrowserViewState.js +1 -1
  194. package/dist/esm/components/editor/AssetBrowser/useAssetBrowserViewState.js.map +1 -1
  195. package/dist/esm/components/editor/AssetBrowser/useAssetDnd.js +1 -1
  196. package/dist/esm/components/editor/AssetBrowser/useAssetDnd.js.map +1 -1
  197. package/dist/esm/components/editor/AssetBrowser/useAssetGridKeyboardNav.js.map +1 -1
  198. package/dist/esm/components/editor/AssetBrowser/useAssetGridVirtualizer.js +1 -1
  199. package/dist/esm/components/editor/AssetBrowser/useAssetGridVirtualizer.js.map +1 -1
  200. package/dist/esm/components/editor/AssetBrowser/useAssetMarqueeGesture.js +1 -1
  201. package/dist/esm/components/editor/AssetBrowser/useAssetMarqueeGesture.js.map +1 -1
  202. package/dist/esm/components/editor/AssetBrowser/useAssetMutationKeyboard.js +1 -1
  203. package/dist/esm/components/editor/AssetBrowser/useAssetMutationKeyboard.js.map +1 -1
  204. package/dist/esm/components/editor/AssetBrowser/useAssetMutations.js +1 -1
  205. package/dist/esm/components/editor/AssetBrowser/useAssetMutations.js.map +1 -1
  206. package/dist/esm/components/editor/AssetBrowser/useAssetNavigation.js +1 -1
  207. package/dist/esm/components/editor/AssetBrowser/useAssetNavigation.js.map +1 -1
  208. package/dist/esm/components/editor/AssetBrowser/useAssetSelectionController.js +1 -1
  209. package/dist/esm/components/editor/AssetBrowser/useAssetSelectionController.js.map +1 -1
  210. package/dist/esm/components/editor/ChatPanel/ChatActionBar.js.map +1 -1
  211. package/dist/esm/components/editor/ChatPanel/ChatAttachment.js.map +1 -1
  212. package/dist/esm/components/editor/ChatPanel/ChatBubble.js.map +1 -1
  213. package/dist/esm/components/editor/ChatPanel/ChatCodeBlock.js +6 -0
  214. package/dist/esm/components/editor/ChatPanel/ChatCodeBlock.js.map +1 -1
  215. package/dist/esm/components/editor/ChatPanel/ChatContextChip.js.map +1 -1
  216. package/dist/esm/components/editor/ChatPanel/ChatEmptyState.js.map +1 -1
  217. package/dist/esm/components/editor/ChatPanel/ChatIcons.js.map +1 -1
  218. package/dist/esm/components/editor/ChatPanel/ChatInput.js +6 -0
  219. package/dist/esm/components/editor/ChatPanel/ChatInput.js.map +1 -1
  220. package/dist/esm/components/editor/ChatPanel/ChatInputToolbar.js.map +1 -1
  221. package/dist/esm/components/editor/ChatPanel/ChatMarkdownRenderer.js.map +1 -1
  222. package/dist/esm/components/editor/ChatPanel/ChatMessage.js +6 -0
  223. package/dist/esm/components/editor/ChatPanel/ChatMessage.js.map +1 -1
  224. package/dist/esm/components/editor/ChatPanel/ChatMessageList.js.map +1 -1
  225. package/dist/esm/components/editor/ChatPanel/ChatPanel.js.map +1 -1
  226. package/dist/esm/components/editor/ChatPanel/ChatToolCall.js.map +1 -1
  227. package/dist/esm/components/editor/ChatPanel/ChatTypingIndicator.js.map +1 -1
  228. package/dist/esm/components/editor/ChatPanel/useChatInput.js.map +1 -1
  229. package/dist/esm/components/editor/ChatPanel/useChatMessages.js.map +1 -1
  230. package/dist/esm/components/editor/ChatPanel/useChatScroll.js.map +1 -1
  231. package/dist/esm/components/editor/Minimap/Minimap.js +1 -1
  232. package/dist/esm/components/editor/Minimap/Minimap.js.map +1 -1
  233. package/dist/esm/components/editor/Minimap/Minimap.types.js.map +1 -1
  234. package/dist/esm/components/editor/Minimap/MinimapContext.js.map +1 -1
  235. package/dist/esm/components/editor/Minimap/MinimapCorner.js.map +1 -1
  236. package/dist/esm/components/editor/Minimap/MinimapFooter.js.map +1 -1
  237. package/dist/esm/components/editor/Minimap/MinimapStore.js.map +1 -1
  238. package/dist/esm/components/editor/Minimap/MinimapTitle.js.map +1 -1
  239. package/dist/esm/components/editor/Minimap/ViewportMinimap.js +1 -1
  240. package/dist/esm/components/editor/Minimap/ViewportMinimap.js.map +1 -1
  241. package/dist/esm/components/editor/Minimap/computeBoundsFromItems.js.map +1 -1
  242. package/dist/esm/components/editor/Minimap/index.js.map +1 -1
  243. package/dist/esm/components/editor/Minimap/minimapCoords.js.map +1 -1
  244. package/dist/esm/components/editor/Minimap/minimapDrawing.js.map +1 -1
  245. package/dist/esm/components/editor/Minimap/minimapHitTest.js.map +1 -1
  246. package/dist/esm/components/editor/Minimap/useMinimapGestures.js +1 -1
  247. package/dist/esm/components/editor/Minimap/useMinimapGestures.js.map +1 -1
  248. package/dist/esm/components/editor/NodeGraph/NodeGraph.js +1 -1
  249. package/dist/esm/components/editor/NodeGraph/NodeGraph.js.map +1 -1
  250. package/dist/esm/components/editor/NodeGraph/NodeGraph.types.js.map +1 -1
  251. package/dist/esm/components/editor/NodeGraph/NodeGraphContext.js.map +1 -1
  252. package/dist/esm/components/editor/NodeGraph/NodeGraphEdgeLabels.js.map +1 -1
  253. package/dist/esm/components/editor/NodeGraph/NodeGraphGroup.js.map +1 -1
  254. package/dist/esm/components/editor/NodeGraph/NodeGraphMinimap.js.map +1 -1
  255. package/dist/esm/components/editor/NodeGraph/NodeGraphNode.js +1 -1
  256. package/dist/esm/components/editor/NodeGraph/NodeGraphNode.js.map +1 -1
  257. package/dist/esm/components/editor/NodeGraph/NodeGraphNodeContext.js.map +1 -1
  258. package/dist/esm/components/editor/NodeGraph/NodeGraphNodeParts.js.map +1 -1
  259. package/dist/esm/components/editor/NodeGraph/NodeGraphNodeSection.js +1 -1
  260. package/dist/esm/components/editor/NodeGraph/NodeGraphNodeSection.js.map +1 -1
  261. package/dist/esm/components/editor/NodeGraph/NodeGraphNodeSectionContext.js.map +1 -1
  262. package/dist/esm/components/editor/NodeGraph/NodeGraphPin.js.map +1 -1
  263. package/dist/esm/components/editor/NodeGraph/NodeGraphPort.js +1 -1
  264. package/dist/esm/components/editor/NodeGraph/NodeGraphPort.js.map +1 -1
  265. package/dist/esm/components/editor/NodeGraph/NodeGraphPortVisual.js.map +1 -1
  266. package/dist/esm/components/editor/NodeGraph/NodeGraphSlots.js.map +1 -1
  267. package/dist/esm/components/editor/NodeGraph/NodeGraphSpawnPalette.js.map +1 -1
  268. package/dist/esm/components/editor/NodeGraph/NodeGraphStore.js.map +1 -1
  269. package/dist/esm/components/editor/NodeGraph/NodeGraphToolbar.js.map +1 -1
  270. package/dist/esm/components/editor/NodeGraph/createTypeMatchValidator.js.map +1 -1
  271. package/dist/esm/components/editor/NodeGraph/nodeGraphActions.js.map +1 -1
  272. package/dist/esm/components/editor/NodeGraph/nodeGraphDrawing.js.map +1 -1
  273. package/dist/esm/components/editor/NodeGraph/nodeGraphIds.js.map +1 -1
  274. package/dist/esm/components/editor/NodeGraph/nodeGraphMath.js.map +1 -1
  275. package/dist/esm/components/editor/NodeGraph/sortSlots.js.map +1 -1
  276. package/dist/esm/components/editor/NodeGraph/useDragGesture.js.map +1 -1
  277. package/dist/esm/components/editor/NodeGraph/useNodeGraph.js +1 -1
  278. package/dist/esm/components/editor/NodeGraph/useNodeGraph.js.map +1 -1
  279. package/dist/esm/components/editor/NodeGraph/useNodeGraphConnection.js +1 -1
  280. package/dist/esm/components/editor/NodeGraph/useNodeGraphConnection.js.map +1 -1
  281. package/dist/esm/components/editor/NodeGraph/useNodeGraphEdgeInteraction.js +1 -1
  282. package/dist/esm/components/editor/NodeGraph/useNodeGraphEdgeInteraction.js.map +1 -1
  283. package/dist/esm/components/editor/NodeGraph/useNodeGraphGroupDrag.js +1 -1
  284. package/dist/esm/components/editor/NodeGraph/useNodeGraphGroupDrag.js.map +1 -1
  285. package/dist/esm/components/editor/NodeGraph/useNodeGraphKeyboard.js +1 -1
  286. package/dist/esm/components/editor/NodeGraph/useNodeGraphKeyboard.js.map +1 -1
  287. package/dist/esm/components/editor/NodeGraph/useNodeGraphNodeDrag.js +1 -1
  288. package/dist/esm/components/editor/NodeGraph/useNodeGraphNodeDrag.js.map +1 -1
  289. package/dist/esm/components/editor/NodeGraph/useStoreSlice.js.map +1 -1
  290. package/dist/esm/components/editor/PropertyInspector/PropertyGroup.js.map +1 -1
  291. package/dist/esm/components/editor/PropertyInspector/PropertyPanel.css.js +4 -3
  292. package/dist/esm/components/editor/PropertyInspector/PropertyPanel.css.js.map +1 -1
  293. package/dist/esm/components/editor/PropertyInspector/PropertyPanel.js +5 -4
  294. package/dist/esm/components/editor/PropertyInspector/PropertyPanel.js.map +1 -1
  295. package/dist/esm/components/editor/PropertyInspector/PropertyRow.css.js +7 -6
  296. package/dist/esm/components/editor/PropertyInspector/PropertyRow.css.js.map +1 -1
  297. package/dist/esm/components/editor/PropertyInspector/PropertyRow.js +18 -3
  298. package/dist/esm/components/editor/PropertyInspector/PropertyRow.js.map +1 -1
  299. package/dist/esm/components/editor/PropertyInspector/PropertySection.css.js +11 -10
  300. package/dist/esm/components/editor/PropertyInspector/PropertySection.css.js.map +1 -1
  301. package/dist/esm/components/editor/PropertyInspector/PropertySection.js +29 -21
  302. package/dist/esm/components/editor/PropertyInspector/PropertySection.js.map +1 -1
  303. package/dist/esm/components/editor/PropertyInspector/usePropertyUndo.js.map +1 -1
  304. package/dist/esm/components/editor/Timeline/Timeline.js +1 -1
  305. package/dist/esm/components/editor/Timeline/Timeline.js.map +1 -1
  306. package/dist/esm/components/editor/Timeline/Timeline.types.js.map +1 -1
  307. package/dist/esm/components/editor/Timeline/TimelineContext.js.map +1 -1
  308. package/dist/esm/components/editor/Timeline/TimelineFooter.js.map +1 -1
  309. package/dist/esm/components/editor/Timeline/TimelineMinimap.js +1 -1
  310. package/dist/esm/components/editor/Timeline/TimelineMinimap.js.map +1 -1
  311. package/dist/esm/components/editor/Timeline/TimelineStore.js.map +1 -1
  312. package/dist/esm/components/editor/Timeline/TimelineToolbar.js.map +1 -1
  313. package/dist/esm/components/editor/Timeline/TimelineTrackHeaders.js +1 -1
  314. package/dist/esm/components/editor/Timeline/TimelineTrackHeaders.js.map +1 -1
  315. package/dist/esm/components/editor/Timeline/TimelineTrackScale.js.map +1 -1
  316. package/dist/esm/components/editor/Timeline/index.js.map +1 -1
  317. package/dist/esm/components/editor/Timeline/timelineCoords.js.map +1 -1
  318. package/dist/esm/components/editor/Timeline/timelineDrawing.js.map +1 -1
  319. package/dist/esm/components/editor/Timeline/timelineEdits.js.map +1 -1
  320. package/dist/esm/components/editor/Timeline/timelineHitTest.js.map +1 -1
  321. package/dist/esm/components/editor/Timeline/timelineLayout.js.map +1 -1
  322. package/dist/esm/components/editor/Timeline/timelineSelection.js.map +1 -1
  323. package/dist/esm/components/editor/Timeline/useTimelineDraw.js +1 -1
  324. package/dist/esm/components/editor/Timeline/useTimelineDraw.js.map +1 -1
  325. package/dist/esm/components/editor/Timeline/useTimelineGestures.js +1 -1
  326. package/dist/esm/components/editor/Timeline/useTimelineGestures.js.map +1 -1
  327. package/dist/esm/components/editor/Timeline/useTimelinePlayback.js.map +1 -1
  328. package/dist/esm/components/editor/TransformControl/TransformControl.js.map +1 -1
  329. package/dist/esm/components/editor/ViewportGizmo/ViewportGizmo.js.map +1 -1
  330. package/dist/esm/components/editor/ViewportGizmo/gizmoMath.js.map +1 -1
  331. package/dist/esm/components/editor/ViewportGizmo/useGizmoInteraction.js.map +1 -1
  332. package/dist/esm/components/editor/ViewportGizmo/useGizmoRenderer.js.map +1 -1
  333. package/dist/esm/components/feedback/Alert/Alert.js.map +1 -1
  334. package/dist/esm/components/feedback/Alert/AlertActions.js.map +1 -1
  335. package/dist/esm/components/feedback/Alert/AlertDescription.js.map +1 -1
  336. package/dist/esm/components/feedback/Alert/AlertTitle.js.map +1 -1
  337. package/dist/esm/components/feedback/CommandPalette/CommandPalette.js.map +1 -1
  338. package/dist/esm/components/feedback/CommandPalette/fuzzySearch.js.map +1 -1
  339. package/dist/esm/components/feedback/CommandPalette/useRecentItems.js.map +1 -1
  340. package/dist/esm/components/feedback/Dialog/Dialog.js.map +1 -1
  341. package/dist/esm/components/feedback/Dialog/DialogBody.js.map +1 -1
  342. package/dist/esm/components/feedback/Dialog/DialogClose.js.map +1 -1
  343. package/dist/esm/components/feedback/Dialog/DialogFooter.js.map +1 -1
  344. package/dist/esm/components/feedback/Dialog/DialogHeader.js.map +1 -1
  345. package/dist/esm/components/feedback/Dialog/useDialogAnimation.js.map +1 -1
  346. package/dist/esm/components/feedback/Drawer/Drawer.js.map +1 -1
  347. package/dist/esm/components/feedback/Drawer/useDrawerAnimation.js.map +1 -1
  348. package/dist/esm/components/feedback/EmptyState/EmptyState.js.map +1 -1
  349. package/dist/esm/components/feedback/LogView/LogView.js.map +1 -1
  350. package/dist/esm/components/feedback/LogView/LogViewBody.js.map +1 -1
  351. package/dist/esm/components/feedback/LogView/LogViewContext.js.map +1 -1
  352. package/dist/esm/components/feedback/LogView/LogViewParts.js.map +1 -1
  353. package/dist/esm/components/feedback/LogView/LogViewStore.js.map +1 -1
  354. package/dist/esm/components/feedback/LogView/logViewLabels.js.map +1 -1
  355. package/dist/esm/components/feedback/LogView/logViewLevels.js.map +1 -1
  356. package/dist/esm/components/feedback/LogView/logViewUtils.js.map +1 -1
  357. package/dist/esm/components/feedback/LogView/useFollowTail.js.map +1 -1
  358. package/dist/esm/components/feedback/LogView/useLogSelection.js.map +1 -1
  359. package/dist/esm/components/feedback/ProgressBar/CircularProgress.js.map +1 -1
  360. package/dist/esm/components/feedback/ProgressBar/ProgressBar.js.map +1 -1
  361. package/dist/esm/components/feedback/Skeleton/Skeleton.js.map +1 -1
  362. package/dist/esm/components/feedback/Skeleton/SkeletonGroup.js.map +1 -1
  363. package/dist/esm/components/feedback/Skeleton/SkeletonLayout.js.map +1 -1
  364. package/dist/esm/components/feedback/Spinner/Spinner.js +12 -3
  365. package/dist/esm/components/feedback/Spinner/Spinner.js.map +1 -1
  366. package/dist/esm/components/feedback/Stat/Stat.js.map +1 -1
  367. package/dist/esm/components/feedback/Toast/ToastContainer.js.map +1 -1
  368. package/dist/esm/components/feedback/Toast/ToastItem.js.map +1 -1
  369. package/dist/esm/components/feedback/Toast/ToastProvider.js.map +1 -1
  370. package/dist/esm/components/feedback/Toast/useToast.js.map +1 -1
  371. package/dist/esm/components/form/FormHelperText.js.map +1 -1
  372. package/dist/esm/components/form/FormLabel.js.map +1 -1
  373. package/dist/esm/components/form/InputWrapper.js.map +1 -1
  374. package/dist/esm/components/layout/Accordion/Accordion.js.map +1 -1
  375. package/dist/esm/components/layout/Accordion/AccordionContent.js.map +1 -1
  376. package/dist/esm/components/layout/Accordion/AccordionItem.js.map +1 -1
  377. package/dist/esm/components/layout/Accordion/AccordionTrigger.js.map +1 -1
  378. package/dist/esm/components/layout/Card/Card.js.map +1 -1
  379. package/dist/esm/components/layout/Divider/Divider.js.map +1 -1
  380. package/dist/esm/components/layout/Flex/Flex.js.map +1 -1
  381. package/dist/esm/components/layout/Grid/Grid.js.map +1 -1
  382. package/dist/esm/components/layout/ListItem/ListItem.js.map +1 -1
  383. package/dist/esm/components/layout/PageHeader/PageHeader.js.map +1 -1
  384. package/dist/esm/components/layout/PanelSurface/PanelSurface.js.map +1 -1
  385. package/dist/esm/components/layout/ScrollArea/ScrollArea.js.map +1 -1
  386. package/dist/esm/components/layout/Spacer/Spacer.js.map +1 -1
  387. package/dist/esm/components/layout/SplitPane/SplitPane.js.map +1 -1
  388. package/dist/esm/components/layout/SplitPane/SplitPanePanel.js.map +1 -1
  389. package/dist/esm/components/layout/Stack/Stack.js.map +1 -1
  390. package/dist/esm/components/navigation/Breadcrumbs/BreadcrumbEllipsis.js.map +1 -1
  391. package/dist/esm/components/navigation/Breadcrumbs/BreadcrumbItem.js.map +1 -1
  392. package/dist/esm/components/navigation/Breadcrumbs/BreadcrumbSeparator.js.map +1 -1
  393. package/dist/esm/components/navigation/Breadcrumbs/Breadcrumbs.js +6 -0
  394. package/dist/esm/components/navigation/Breadcrumbs/Breadcrumbs.js.map +1 -1
  395. package/dist/esm/components/navigation/ContextMenu/ContextMenu.js +2 -2
  396. package/dist/esm/components/navigation/ContextMenu/ContextMenu.js.map +1 -1
  397. package/dist/esm/components/navigation/Menu/Menu.css.js +11 -10
  398. package/dist/esm/components/navigation/Menu/Menu.css.js.map +1 -1
  399. package/dist/esm/components/navigation/Menu/Menu.js +2 -2
  400. package/dist/esm/components/navigation/Menu/Menu.js.map +1 -1
  401. package/dist/esm/components/navigation/Menu/MenuGapContext.js.map +1 -1
  402. package/dist/esm/components/navigation/Pagination/Pagination.js.map +1 -1
  403. package/dist/esm/components/navigation/Pagination/usePagination.js.map +1 -1
  404. package/dist/esm/components/navigation/PathBar/PathBar.js +7 -1
  405. package/dist/esm/components/navigation/PathBar/PathBar.js.map +1 -1
  406. package/dist/esm/components/navigation/PathBar/PathBarSiblingMenu.js +6 -0
  407. package/dist/esm/components/navigation/PathBar/PathBarSiblingMenu.js.map +1 -1
  408. package/dist/esm/components/navigation/PathBar/pathUtils.js.map +1 -1
  409. package/dist/esm/components/navigation/SegmentedControl/SegmentedControl.js.map +1 -1
  410. package/dist/esm/components/navigation/SegmentedControl/SegmentedControlItem.js.map +1 -1
  411. package/dist/esm/components/navigation/Tabs/Tab.js.map +1 -1
  412. package/dist/esm/components/navigation/Tabs/TabList.js.map +1 -1
  413. package/dist/esm/components/navigation/Tabs/TabPanel.js.map +1 -1
  414. package/dist/esm/components/navigation/Tabs/Tabs.js.map +1 -1
  415. package/dist/esm/components/primitives/Avatar/Avatar.js +6 -0
  416. package/dist/esm/components/primitives/Avatar/Avatar.js.map +1 -1
  417. package/dist/esm/components/primitives/Avatar/AvatarGroup.js.map +1 -1
  418. package/dist/esm/components/primitives/Badge/Badge.js +6 -0
  419. package/dist/esm/components/primitives/Badge/Badge.js.map +1 -1
  420. package/dist/esm/components/primitives/Button/Button.js.map +1 -1
  421. package/dist/esm/components/primitives/Checkbox/Checkbox.js.map +1 -1
  422. package/dist/esm/components/primitives/Checkbox/CheckboxGroup.js.map +1 -1
  423. package/dist/esm/components/primitives/Code/Code.js.map +1 -1
  424. package/dist/esm/components/primitives/Collapsible/Collapsible.js.map +1 -1
  425. package/dist/esm/components/primitives/HoverCard/HoverCard.js.map +1 -1
  426. package/dist/esm/components/primitives/Icon/Icon.js.map +1 -1
  427. package/dist/esm/components/primitives/IconButton/IconButton.js +4 -2
  428. package/dist/esm/components/primitives/IconButton/IconButton.js.map +1 -1
  429. package/dist/esm/components/primitives/Input/Input.js.map +1 -1
  430. package/dist/esm/components/primitives/Kbd/Kbd.js.map +1 -1
  431. package/dist/esm/components/primitives/Link/Link.js.map +1 -1
  432. package/dist/esm/components/primitives/Paper/Paper.js.map +1 -1
  433. package/dist/esm/components/primitives/Popover/Popover.js.map +1 -1
  434. package/dist/esm/components/primitives/Popover/PopoverClose.js.map +1 -1
  435. package/dist/esm/components/primitives/Popover/PopoverContent.js.map +1 -1
  436. package/dist/esm/components/primitives/Popover/PopoverTrigger.js.map +1 -1
  437. package/dist/esm/components/primitives/Radio/Radio.js.map +1 -1
  438. package/dist/esm/components/primitives/Radio/RadioGroup.js.map +1 -1
  439. package/dist/esm/components/primitives/Switch/Switch.js.map +1 -1
  440. package/dist/esm/components/primitives/Text/Text.js.map +1 -1
  441. package/dist/esm/components/primitives/TextArea/TextArea.js.map +1 -1
  442. package/dist/esm/components/primitives/Tooltip/Arrow.js.map +1 -1
  443. package/dist/esm/components/primitives/Tooltip/Tooltip.css.js +6 -5
  444. package/dist/esm/components/primitives/Tooltip/Tooltip.css.js.map +1 -1
  445. package/dist/esm/components/primitives/Tooltip/Tooltip.js +12 -2
  446. package/dist/esm/components/primitives/Tooltip/Tooltip.js.map +1 -1
  447. package/dist/esm/components/primitives/Tooltip/utils.js.map +1 -1
  448. package/dist/esm/components/primitives/VisuallyHidden/VisuallyHidden.js.map +1 -1
  449. package/dist/esm/components/primitives/canvas/CanvasContainer.js.map +1 -1
  450. package/dist/esm/components/primitives/canvas/canvasCoords.js.map +1 -1
  451. package/dist/esm/components/primitives/canvas/canvasDrawing.js.map +1 -1
  452. package/dist/esm/components/primitives/canvas/canvasTheme.js.map +1 -1
  453. package/dist/esm/components/primitives/canvas/useCanvasRenderer.js.map +1 -1
  454. package/dist/esm/components/primitives/viewport/Viewport.js +6 -3
  455. package/dist/esm/components/primitives/viewport/Viewport.js.map +1 -1
  456. package/dist/esm/components/primitives/viewport/ViewportContext.js.map +1 -1
  457. package/dist/esm/components/primitives/viewport/ViewportLayer.js +1 -1
  458. package/dist/esm/components/primitives/viewport/ViewportLayer.js.map +1 -1
  459. package/dist/esm/components/primitives/viewport/ViewportOverlay.js.map +1 -1
  460. package/dist/esm/components/primitives/viewport/ViewportStore.js.map +1 -1
  461. package/dist/esm/components/primitives/viewport/ViewportWorld.js.map +1 -1
  462. package/dist/esm/components/primitives/viewport/useViewportGestures.js +1 -1
  463. package/dist/esm/components/primitives/viewport/useViewportGestures.js.map +1 -1
  464. package/dist/esm/components/primitives/viewport/viewportCoords.js.map +1 -1
  465. package/dist/esm/components/primitives/viewport/viewportMath.js.map +1 -1
  466. package/dist/esm/components/shell/AppShell/AppShell.css.js +1 -1
  467. package/dist/esm/components/shell/AppShell/AppShell.js.map +1 -1
  468. package/dist/esm/components/shell/FloatingPanel/FloatingPanel.js.map +1 -1
  469. package/dist/esm/components/shell/MenuBar/MenuBar.css.js +7 -6
  470. package/dist/esm/components/shell/MenuBar/MenuBar.css.js.map +1 -1
  471. package/dist/esm/components/shell/MenuBar/MenuBar.js +52 -3
  472. package/dist/esm/components/shell/MenuBar/MenuBar.js.map +1 -1
  473. package/dist/esm/components/shell/StatusBar/StatusBar.js.map +1 -1
  474. package/dist/esm/components/shell/Toolbar/Toolbar.js.map +1 -1
  475. package/dist/esm/context/KeyboardContext.js.map +1 -1
  476. package/dist/esm/hooks/useBreakpoint/useBreakpoint.js.map +1 -1
  477. package/dist/esm/hooks/useClickOutside/useClickOutside.js.map +1 -1
  478. package/dist/esm/hooks/useClipboard/useClipboard.js.map +1 -1
  479. package/dist/esm/hooks/useControlledState/useControlledState.js.map +1 -1
  480. package/dist/esm/hooks/useDebounced/useDebouncedCallback.js.map +1 -1
  481. package/dist/esm/hooks/useDebounced/useDebouncedValue.js.map +1 -1
  482. package/dist/esm/hooks/useDisclosure/useDisclosure.js.map +1 -1
  483. package/dist/esm/hooks/useEventCallback/useEventCallback.js.map +1 -1
  484. package/dist/esm/hooks/useFocusTrap/useFocusTrap.js.map +1 -1
  485. package/dist/esm/hooks/useHotkey/useHotkey.js.map +1 -1
  486. package/dist/esm/hooks/useIntersectionObserver/useIntersectionObserver.js.map +1 -1
  487. package/dist/esm/hooks/useIsMounted/useIsMounted.js.map +1 -1
  488. package/dist/esm/hooks/useKeyboard/useKeyboard.js.map +1 -1
  489. package/dist/esm/hooks/useKeyboard/utils.js.map +1 -1
  490. package/dist/esm/hooks/useLatest/useLatest.js.map +1 -1
  491. package/dist/esm/hooks/useListboxNav/useListboxNav.js.map +1 -1
  492. package/dist/esm/hooks/useMediaQuery/useMediaQuery.js.map +1 -1
  493. package/dist/esm/hooks/useMergedRef/useMergedRef.js.map +1 -1
  494. package/dist/esm/hooks/useNavigationHistory/useNavigationHistory.js.map +1 -1
  495. package/dist/esm/hooks/useResizeObserver/useResizeObserver.js.map +1 -1
  496. package/dist/esm/hooks/useTheme/useTheme.js +1 -1
  497. package/dist/esm/hooks/useTheme/useTheme.js.map +1 -1
  498. package/dist/esm/hooks/useThrottledCallback/useThrottledCallback.js.map +1 -1
  499. package/dist/esm/index.js +6 -0
  500. package/dist/esm/index.js.map +1 -1
  501. package/dist/esm/node_modules/tslib/tslib.es6.js.map +1 -1
  502. package/dist/esm/styles.css.js +3 -0
  503. package/dist/esm/styles.css.js.map +1 -0
  504. package/dist/esm/theme/ThemeProvider.js +5 -3
  505. package/dist/esm/theme/ThemeProvider.js.map +1 -1
  506. package/dist/esm/theme/VanillaThemeProvider.js.map +1 -1
  507. package/dist/esm/theme/breakpoints.js.map +1 -1
  508. package/dist/esm/theme/createCustomTheme.js +1 -1
  509. package/dist/esm/theme/createCustomTheme.js.map +1 -1
  510. package/dist/esm/theme/createLightTheme.js.map +1 -1
  511. package/dist/esm/theme/darkThemeValues.js.map +1 -1
  512. package/dist/esm/theme/lightThemeValues.js.map +1 -1
  513. package/dist/esm/theme/themeContractData.js.map +1 -1
  514. package/dist/esm/utils/cx.js.map +1 -1
  515. package/dist/esm/utils/devWarn.js.map +1 -1
  516. package/dist/esm/utils/mathExpression.js.map +1 -1
  517. package/dist/esm/utils/mathUtils.js.map +1 -1
  518. package/dist/esm/utils/objects.js.map +1 -1
  519. package/dist/esm/utils/platform.js.map +1 -1
  520. package/dist/tokens/tokens.dark.css +1 -1
  521. package/dist/tokens/tokens.json +1 -1
  522. package/dist/tokens/tokens.light.css +1 -1
  523. package/dist/types/components/Icons/CameraIcon.d.ts +34 -0
  524. package/dist/types/components/Icons/CubeIcon.d.ts +34 -0
  525. package/dist/types/components/Icons/OrbitIcon.d.ts +34 -0
  526. package/dist/types/components/Icons/RotateIcon.d.ts +35 -0
  527. package/dist/types/components/Icons/SpinIcon.d.ts +35 -0
  528. package/dist/types/components/Icons/ZoomFitIcon.d.ts +35 -0
  529. package/dist/types/components/controls/Select/Select.d.ts +1 -1
  530. package/dist/types/components/controls/Select/Select.types.d.ts +43 -9
  531. package/dist/types/components/controls/Slider/Slider.d.ts +7 -0
  532. package/dist/types/components/editor/PropertyInspector/PropertyInspector.types.d.ts +49 -3
  533. package/dist/types/components/feedback/Spinner/Spinner.d.ts +6 -1
  534. package/dist/types/components/feedback/Spinner/Spinner.types.d.ts +8 -0
  535. package/dist/types/components/primitives/Button/Button.d.ts +1 -1
  536. package/dist/types/components/primitives/IconButton/IconButton.d.ts +3 -2
  537. package/dist/types/components/primitives/viewport/Viewport.d.ts +5 -2
  538. package/dist/types/components/shell/MenuBar/MenuBar.d.ts +862 -0
  539. package/dist/types/index.d.ts +6 -0
  540. package/dist/types/theme/ThemeProvider.d.ts +5 -3
  541. package/package.json +6 -2
  542. package/dist/esm/_virtual/_commonjsHelpers.js +0 -6
  543. package/dist/esm/_virtual/_commonjsHelpers.js.map +0 -1
  544. package/dist/esm/_virtual/cjs.js +0 -4
  545. package/dist/esm/_virtual/cjs.js.map +0 -1
  546. package/dist/esm/_virtual/cssesc.js +0 -8
  547. package/dist/esm/_virtual/cssesc.js.map +0 -1
  548. package/dist/esm/_virtual/picocolors.js +0 -8
  549. package/dist/esm/_virtual/picocolors.js.map +0 -1
  550. package/dist/esm/_virtual/picocolors2.js +0 -4
  551. package/dist/esm/_virtual/picocolors2.js.map +0 -1
  552. package/dist/esm/node_modules/@emotion/hash/dist/emotion-hash.esm.js +0 -56
  553. package/dist/esm/node_modules/@emotion/hash/dist/emotion-hash.esm.js.map +0 -1
  554. package/dist/esm/node_modules/@vanilla-extract/css/adapter/dist/vanilla-extract-css-adapter.esm.js +0 -46
  555. package/dist/esm/node_modules/@vanilla-extract/css/adapter/dist/vanilla-extract-css-adapter.esm.js.map +0 -1
  556. package/dist/esm/node_modules/@vanilla-extract/css/dist/taggedTemplateLiteral-10998315.esm.js +0 -13
  557. package/dist/esm/node_modules/@vanilla-extract/css/dist/taggedTemplateLiteral-10998315.esm.js.map +0 -1
  558. package/dist/esm/node_modules/@vanilla-extract/css/dist/transformCss-fd0786e1.esm.js +0 -962
  559. package/dist/esm/node_modules/@vanilla-extract/css/dist/transformCss-fd0786e1.esm.js.map +0 -1
  560. package/dist/esm/node_modules/@vanilla-extract/css/dist/vanilla-extract-css.esm.js +0 -309
  561. package/dist/esm/node_modules/@vanilla-extract/css/dist/vanilla-extract-css.esm.js.map +0 -1
  562. package/dist/esm/node_modules/@vanilla-extract/css/fileScope/dist/vanilla-extract-css-fileScope.esm.js +0 -18
  563. package/dist/esm/node_modules/@vanilla-extract/css/fileScope/dist/vanilla-extract-css-fileScope.esm.js.map +0 -1
  564. package/dist/esm/node_modules/@vanilla-extract/css/injectStyles/dist/vanilla-extract-css-injectStyles.esm.js +0 -23
  565. package/dist/esm/node_modules/@vanilla-extract/css/injectStyles/dist/vanilla-extract-css-injectStyles.esm.js.map +0 -1
  566. package/dist/esm/node_modules/@vanilla-extract/css/node_modules/lru-cache/dist/esm/index.js +0 -1543
  567. package/dist/esm/node_modules/@vanilla-extract/css/node_modules/lru-cache/dist/esm/index.js.map +0 -1
  568. package/dist/esm/node_modules/@vanilla-extract/private/dist/vanilla-extract-private.esm.js +0 -38
  569. package/dist/esm/node_modules/@vanilla-extract/private/dist/vanilla-extract-private.esm.js.map +0 -1
  570. package/dist/esm/node_modules/css-what/lib/es/parse.js +0 -424
  571. package/dist/esm/node_modules/css-what/lib/es/parse.js.map +0 -1
  572. package/dist/esm/node_modules/css-what/lib/es/types.js +0 -29
  573. package/dist/esm/node_modules/css-what/lib/es/types.js.map +0 -1
  574. package/dist/esm/node_modules/cssesc/cssesc.js +0 -120
  575. package/dist/esm/node_modules/cssesc/cssesc.js.map +0 -1
  576. package/dist/esm/node_modules/dedent/dist/dedent.js +0 -100
  577. package/dist/esm/node_modules/dedent/dist/dedent.js.map +0 -1
  578. package/dist/esm/node_modules/deep-object-diff/mjs/diff.js +0 -40
  579. package/dist/esm/node_modules/deep-object-diff/mjs/diff.js.map +0 -1
  580. package/dist/esm/node_modules/deep-object-diff/mjs/utils.js +0 -9
  581. package/dist/esm/node_modules/deep-object-diff/mjs/utils.js.map +0 -1
  582. package/dist/esm/node_modules/deepmerge/dist/cjs.js +0 -143
  583. package/dist/esm/node_modules/deepmerge/dist/cjs.js.map +0 -1
  584. package/dist/esm/node_modules/media-query-parser/dist/media-query-parser.esm.js +0 -1386
  585. package/dist/esm/node_modules/media-query-parser/dist/media-query-parser.esm.js.map +0 -1
  586. package/dist/esm/node_modules/modern-ahocorasick/dist/index.js +0 -102
  587. package/dist/esm/node_modules/modern-ahocorasick/dist/index.js.map +0 -1
  588. package/dist/esm/node_modules/picocolors/picocolors.js +0 -87
  589. package/dist/esm/node_modules/picocolors/picocolors.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"NodeGraphEdgeLabels.js","sources":["../../../../../../src/components/editor/NodeGraph/NodeGraphEdgeLabels.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;AAsBA;AACA;AACA;AAEA;;AACe;AACb;AAA8B;AAC9B;AACF;AAEA;;AAKA;AAEA;;;;;AAKG;AACH;;;AAOE;AACE;AACA;;AACK;AACL;AACA;;AAEF;AAAoB;AACpB;AACA;AACA;AAAkC;AAClC;AACF;AAEA;;;;;;;;;;;AAWG;;AAgBD;;;;AAIA;;;;;;;;;;AAgBM;AAA+C;AAC/C;;AAUR;AAEA;AAOE;AACA;AACA;;;;;;AAMA;;;AAGmC;;AAE/B;AACE;AACA;AACF;;;;;AAOJ;;;;AAgBA;AAKA;AAKA;AAAkB;AAElB;AACA;AACA;AACA;;;;;;;;AAQA;;AAEA;AAA0C;;AAKpC;AACA;AACA;;;;AAIA;AACA;AACA;;AAMR;;"}
1
+ {"version":3,"file":"NodeGraphEdgeLabels.js","sources":["src/components/editor/NodeGraph/NodeGraphEdgeLabels.tsx"],"sourcesContent":["'use client';\n\nimport React, { useCallback, useSyncExternalStore } from 'react';\n\nimport { useNodeGraphStore } from './NodeGraphContext';\nimport { resolvePortRef } from './nodeGraphMath';\nimport { useStoreSlice } from './useStoreSlice';\n\nimport type { NodeGraphEdge } from './NodeGraph.types';\nimport type { NodeGraphInteractionState } from './NodeGraphStore';\nimport type { Point2D } from '@/components/primitives/canvas/canvas.types';\n\ninterface RenderEdgeLabelRef {\n current: ((edge: NodeGraphEdge) => React.ReactNode) | undefined;\n}\n\n/** Live drag deltas for an edge's two endpoints during the current gesture. */\ninterface EdgeEndpointDeltas {\n src: Point2D | null;\n tgt: Point2D | null;\n}\n\n// Shared sentinel for \"this edge isn't affected by the current gesture\" —\n// one reference so the equality check below short-circuits cleanly.\nconst NO_EDGE_DELTAS: EdgeEndpointDeltas = { src: null, tgt: null };\n\nfunction pointEqualNullable(a: Point2D | null, b: Point2D | null): boolean {\n if (a === b) return true;\n if (a === null || b === null) return false;\n return a.x === b.x && a.y === b.y;\n}\n\nfunction edgeDeltasEqual(\n a: EdgeEndpointDeltas,\n b: EdgeEndpointDeltas\n): boolean {\n return pointEqualNullable(a.src, b.src) && pointEqualNullable(a.tgt, b.tgt);\n}\n\n/**\n * Live drag delta for an edge's endpoints, or {@link NO_EDGE_DELTAS} when\n * neither endpoint's node is part of the current drag. Mirrors the per-node\n * selector in `NodeGraphNode` so a label only updates when an endpoint it\n * actually owns is moving.\n */\nfunction selectEdgeDeltas(\n interaction: NodeGraphInteractionState,\n sourceNode: string,\n targetNode: string\n): EdgeEndpointDeltas {\n let ids: ReadonlySet<string> | null = null;\n let delta: Point2D | null = null;\n if (interaction.kind === 'drag-nodes') {\n ids = interaction.nodeIds;\n delta = interaction.delta;\n } else if (interaction.kind === 'drag-groups') {\n ids = interaction.containedNodeIds;\n delta = interaction.delta;\n }\n if (!ids || !delta) return NO_EDGE_DELTAS;\n const src = ids.has(sourceNode) ? delta : null;\n const tgt = ids.has(targetNode) ? delta : null;\n if (src === null && tgt === null) return NO_EDGE_DELTAS;\n return { src, tgt };\n}\n\n/**\n * Mounts one `<EdgeLabel>` per edge as a world-space sibling inside\n * `<ViewportWorld>`. Each label subscribes to the interaction slice on\n * its own so a drag of an unrelated node doesn't re-render every label\n * in the graph — only the labels whose endpoints actually move.\n *\n * One subscriber per edge: each `EdgeLabel` subscribes to the `interaction`\n * slice through `useStoreSlice` with an endpoint-delta selector + equality,\n * so it re-renders only when an endpoint it actually owns moves. Labels on\n * edges untouched by the current gesture short-circuit on the equality check\n * and skip the per-frame re-render entirely.\n */\nexport function EdgeLabelsLayer({\n renderEdgeLabelRef,\n hasRenderEdgeLabel,\n}: {\n renderEdgeLabelRef: RenderEdgeLabelRef;\n /**\n * Whether the consumer supplied a `renderEdgeLabel` callback. When `false`,\n * edges without an explicit `edge.label` prop are skipped — no `EdgeLabel`\n * subscriber is mounted for them. This avoids the cost of one interaction-\n * slice subscriber per edge in graphs that don't use labels at all (the\n * benchmark, simple recipes, etc.), which is otherwise pure waste — the\n * subscriber fires on every drag tick and the body returns `null`.\n */\n hasRenderEdgeLabel: boolean;\n}): React.ReactElement | null {\n const store = useNodeGraphStore();\n // Subscribe to data + port positions at this level so we know which\n // edges exist. Each `EdgeLabel` below subscribes to interaction on its\n // own for live drag tracking.\n const data = useSyncExternalStore(store.subscribeData, store.getData);\n useSyncExternalStore(\n store.subscribePortPositions,\n store.getPortPositionsVersion\n );\n\n return (\n <>\n {data.edges.map(edge => {\n // Skip mounting an `EdgeLabel` subscriber when there's nothing it\n // could ever render. When `renderEdgeLabel` is provided the\n // consumer controls visibility per edge from inside their callback\n // (and may return `null`), so we still have to mount — but if no\n // callback exists, the only thing the label could show is\n // `edge.label`, and a `null` value there means there's nothing to\n // draw and no reason to pay for a per-edge store subscription.\n if (!hasRenderEdgeLabel && edge.label == null) return null;\n return (\n <EdgeLabel\n key={edge.id}\n edge={edge}\n renderEdgeLabelRef={renderEdgeLabelRef}\n />\n );\n })}\n </>\n );\n}\n\nfunction EdgeLabel({\n edge,\n renderEdgeLabelRef,\n}: {\n edge: NodeGraphEdge;\n renderEdgeLabelRef: RenderEdgeLabelRef;\n}): React.ReactElement | null {\n const store = useNodeGraphStore();\n const sourceNode = edge.source.node;\n const targetNode = edge.target.node;\n // Subscribe to interaction changes affecting either endpoint via the\n // per-node channel — a drag of an unrelated node never wakes this\n // subscriber, even before the selector runs. When source and target\n // sit on the same node, a single subscription is enough (deduplicates\n // the notification).\n const subscribeEndpoints = useCallback(\n (cb: () => void): (() => void) => {\n const unsubSource = store.subscribeNodeInteraction(sourceNode, cb);\n if (sourceNode === targetNode) return unsubSource;\n const unsubTarget = store.subscribeNodeInteraction(targetNode, cb);\n return () => {\n unsubSource();\n unsubTarget();\n };\n },\n [store, sourceNode, targetNode]\n );\n // Selector still reads the global snapshot to compute per-endpoint\n // deltas — the subscription change above only narrows *when* this\n // subscriber gets woken, not *what* it sees.\n const { src: srcDelta, tgt: tgtDelta } = useStoreSlice<\n NodeGraphInteractionState,\n EdgeEndpointDeltas\n >(\n subscribeEndpoints,\n store.getInteraction,\n interaction => selectEdgeDeltas(interaction, sourceNode, targetNode),\n edgeDeltasEqual\n );\n // Re-render when port positions update too (initial measure + body\n // re-layout shift the anchor).\n useSyncExternalStore(\n store.subscribePortPositions,\n store.getPortPositionsVersion\n );\n\n const src = resolvePortRef(\n edge.source,\n store.getNodeById,\n store.getPortPosition\n );\n const tgt = resolvePortRef(\n edge.target,\n store.getNodeById,\n store.getPortPosition\n );\n if (!src || !tgt) return null;\n\n const sx = src.position.x + (srcDelta?.x ?? 0);\n const sy = src.position.y + (srcDelta?.y ?? 0);\n const tx = tgt.position.x + (tgtDelta?.x ?? 0);\n const ty = tgt.position.y + (tgtDelta?.y ?? 0);\n const midX = (sx + tx) / 2;\n const midY = (sy + ty) / 2;\n // The render callback lives in a `useLatest` ref so swapping it doesn't\n // re-render every edge label; reading the current value here is deliberate.\n // Labels refresh on the next data / interaction tick, which is the only\n // moment their content is consumed anyway.\n // eslint-disable-next-line react-hooks/refs -- intentional latest-callback read\n const render = renderEdgeLabelRef.current;\n const content = render ? render(edge) : (edge.label ?? null);\n if (content == null || content === false) return null;\n\n return (\n <div\n style={{\n position: 'absolute',\n left: 0,\n top: 0,\n // World-space position via `transform` so each frame's update is\n // a GPU-friendly transform mutation (no CSS layout). The\n // -50%/-50% piece centres the label on its midpoint.\n transform: `translate3d(${midX}px, ${midY}px, 0) translate(-50%, -50%)`,\n pointerEvents: 'auto',\n willChange: 'transform',\n }}\n >\n {content}\n </div>\n );\n}\n"],"names":[],"mappings":";;;;;;;AAsBA;AACA;AACA;AAEA;;AACe;AACb;AAA8B;AAC9B;AACF;AAEA;;AAKA;AAEA;;;;;AAKG;AACH;;;AAOE;AACE;AACA;;AACK;AACL;AACA;;AAEF;AAAoB;AACpB;AACA;AACA;AAAkC;AAClC;AACF;AAEA;;;;;;;;;;;AAWG;;AAgBD;;;;AAIA;;;;;;;;;;AAgBM;AAA+C;AAC/C;;AAUR;AAEA;AAOE;AACA;AACA;;;;;;AAMA;;;AAGmC;;AAE/B;AACE;AACA;AACF;;;;;AAOJ;;;;AAgBA;AAKA;AAKA;AAAkB;AAElB;AACA;AACA;AACA;;;;;;;;AAQA;;AAEA;AAA0C;;AAKpC;AACA;AACA;;;;AAIA;AACA;AACA;;AAMR;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"NodeGraphGroup.js","sources":["../../../../../../src/components/editor/NodeGraph/NodeGraphGroup.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;;;;;;AAyDA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAGF;;;;;;;;;;AAcA;;;;;;;;;;AAWA;AAuBA;;AAIe;AACb;AAA8B;AAC9B;AAAuB;AACvB;AAA6B;AAC7B;;;AAGA;AACE;;;;;;;;AAUF;AACF;AAEA;AAIE;;AAEI;;;;;AAKJ;;AAEI;;;;;;;AAOJ;AACF;AAEA;;;AAKE;;;;AAII;AACA;;;AAGJ;AACF;AAEA;;;;;;;;;;;;;;AAcG;AACH;AASE;AACA;;;AAeA;AACA;;;;;;;;AASA;AACA;;;;AAKI;AACA;;AAEJ;AAEA;AACE;;;;AAGA;;AAGF;;AAEE;AACF;AAEA;;;;;AAMI;;AAEF;AAIF;AAEI;;AAEE;;AACK;;AAEL;;;;AAIJ;;;;;;;AAUF;AAEI;AACF;;;AAMF;AAEA;;;;;AAQK;AAIC;AACF;AAEE;;;;;;;AAWA;AAUM;;AAgDN;;AAMQ;;AAKA;AACF;AAGN;AAGR;AAEO;AACP;;"}
1
+ {"version":3,"file":"NodeGraphGroup.js","sources":["src/components/editor/NodeGraph/NodeGraphGroup.tsx"],"sourcesContent":["'use client';\n\nimport React, { useCallback, useEffect, useRef, useState } from 'react';\n\nimport { ColorPicker } from '@/components/controls/ColorPicker/ColorPicker';\nimport { Popover } from '@/components/primitives/Popover/Popover';\nimport { PopoverContent } from '@/components/primitives/Popover/PopoverContent';\nimport { PopoverTrigger } from '@/components/primitives/Popover/PopoverTrigger';\nimport { cx } from '@/utils/cx';\n\nimport {\n groupColorSwatchStyle,\n groupLabelBarStyle,\n groupLabelInputStyle,\n groupLabelStyle,\n groupOverlayRecipe,\n groupResizeHandleStyle,\n} from './NodeGraph.css';\nimport { useNodeGraphStore } from './NodeGraphContext';\nimport { applyGroupResize } from './nodeGraphMath';\nimport { useStoreSlice } from './useStoreSlice';\n\nimport type { NodeGraphGroup } from './NodeGraph.types';\nimport type {\n NodeGraphGroupResizeHandle,\n NodeGraphInteractionState,\n} from './NodeGraphStore';\nimport type { WorldRect } from '@/components/primitives/viewport';\n\ninterface NodeGraphGroupViewProps {\n group: NodeGraphGroup;\n /** Pointer-down on the group body — used for drag / click selection. */\n onBodyPointerDown: (\n event: React.PointerEvent<HTMLDivElement>,\n group: NodeGraphGroup\n ) => void;\n /** Pointer-up on the group body — completes click-to-select if no drag. */\n onBodyPointerUp: (\n event: React.PointerEvent<HTMLDivElement>,\n group: NodeGraphGroup\n ) => void;\n /** Pointer-down on a resize handle. */\n onHandlePointerDown: (\n event: React.PointerEvent<HTMLDivElement>,\n group: NodeGraphGroup,\n handle: NodeGraphGroupResizeHandle\n ) => void;\n onBodyContextMenu: (event: React.MouseEvent<HTMLDivElement>) => void;\n /**\n * Commit a label or colour edit. The library calls this when the user\n * finishes editing the label (Enter / blur) or picks a new colour from\n * the swatch. Parent forwards to `setGroups` / `onGroupsChange`.\n */\n onLabelChange: (group: NodeGraphGroup, nextLabel: string) => void;\n onColorChange: (group: NodeGraphGroup, nextColor: string) => void;\n}\n\nconst RESIZE_CURSORS: Record<NodeGraphGroupResizeHandle, string> = {\n nw: 'nwse-resize',\n n: 'ns-resize',\n ne: 'nesw-resize',\n e: 'ew-resize',\n se: 'nwse-resize',\n s: 'ns-resize',\n sw: 'nesw-resize',\n w: 'ew-resize',\n};\n\nconst HANDLE_POSITIONS: Record<\n NodeGraphGroupResizeHandle,\n { left?: string; right?: string; top?: string; bottom?: string }\n> = {\n nw: { left: '-5px', top: '-5px' },\n n: { left: 'calc(50% - 5px)', top: '-5px' },\n ne: { right: '-5px', top: '-5px' },\n e: { right: '-5px', top: 'calc(50% - 5px)' },\n se: { right: '-5px', bottom: '-5px' },\n s: { left: 'calc(50% - 5px)', bottom: '-5px' },\n sw: { left: '-5px', bottom: '-5px' },\n w: { left: '-5px', top: 'calc(50% - 5px)' },\n};\n\nconst ALL_HANDLES: NodeGraphGroupResizeHandle[] = [\n 'nw',\n 'n',\n 'ne',\n 'e',\n 'se',\n 's',\n 'sw',\n 'w',\n];\n\nconst DEFAULT_PICKER_COLOR = '#5d8dff';\n\n/**\n * Per-group slice of the interaction state — `null` for groups that\n * aren't currently being dragged or resized. Two distinct `null`\n * references would defeat the equality short-circuit, so we share the\n * module-level constant below.\n */\ntype GroupGestureState =\n | {\n kind: 'drag';\n delta: { x: number; y: number };\n blocked: boolean;\n }\n | {\n kind: 'resize';\n handle: NodeGraphGroupResizeHandle;\n startBounds: WorldRect;\n delta: { x: number; y: number };\n blocked: boolean;\n }\n | null;\n\nfunction gestureStateEqual(\n a: GroupGestureState,\n b: GroupGestureState\n): boolean {\n if (a === b) return true;\n if (a === null || b === null) return false;\n if (a.kind !== b.kind) return false;\n if (a.blocked !== b.blocked) return false;\n if (a.kind === 'drag' && b.kind === 'drag') {\n return a.delta.x === b.delta.x && a.delta.y === b.delta.y;\n }\n if (a.kind === 'resize' && b.kind === 'resize') {\n return (\n a.handle === b.handle &&\n a.delta.x === b.delta.x &&\n a.delta.y === b.delta.y &&\n a.startBounds.x === b.startBounds.x &&\n a.startBounds.y === b.startBounds.y &&\n a.startBounds.width === b.startBounds.width &&\n a.startBounds.height === b.startBounds.height\n );\n }\n return false;\n}\n\nfunction selectGroupGesture(\n interaction: NodeGraphInteractionState,\n groupId: string\n): GroupGestureState {\n if (interaction.kind === 'drag-groups' && interaction.groupIds.has(groupId)) {\n return {\n kind: 'drag',\n delta: interaction.delta,\n blocked: interaction.blocked,\n };\n }\n if (interaction.kind === 'resize-group' && interaction.groupId === groupId) {\n return {\n kind: 'resize',\n handle: interaction.handle,\n startBounds: interaction.startBounds,\n delta: interaction.delta,\n blocked: interaction.blocked,\n };\n }\n return null;\n}\n\nfunction computeLiveBounds(\n group: NodeGraphGroup,\n gesture: GroupGestureState\n): WorldRect {\n if (gesture === null) return group.bounds;\n if (gesture.kind === 'drag') {\n return {\n x: group.bounds.x + gesture.delta.x,\n y: group.bounds.y + gesture.delta.y,\n width: group.bounds.width,\n height: group.bounds.height,\n };\n }\n return applyGroupResize(gesture.startBounds, gesture.handle, gesture.delta);\n}\n\n/**\n * Render a single interactive group overlay positioned in world space.\n * The canvas layer draws the visual fill underneath — this HTML element\n * handles selection, drag-to-move, corner/edge resize, label editing,\n * and the colour swatch.\n *\n * Uses per-id selectors so a group only re-renders when *its* selection\n * or gesture state changes — drag deltas of other groups never reach the\n * subscriber.\n *\n * Wrapped in `React.memo` for the same reason as\n * {@link NodeGraphNodeView}: a parent render caused by an unrelated\n * controlled-state update would otherwise iterate every group. Handlers\n * passed from `NodeGraphImpl` are all `useCallback`-stable.\n */\nfunction NodeGraphGroupViewImpl({\n group,\n onBodyPointerDown,\n onBodyPointerUp,\n onHandlePointerDown,\n onBodyContextMenu,\n onLabelChange,\n onColorChange,\n}: NodeGraphGroupViewProps): React.ReactElement {\n const store = useNodeGraphStore();\n const groupId = group.id;\n\n const selected = useStoreSlice(\n store.subscribeSelection,\n store.getSelection,\n sel => sel.groups.includes(groupId)\n );\n\n const gesture = useStoreSlice<NodeGraphInteractionState, GroupGestureState>(\n store.subscribeInteraction,\n store.getInteraction,\n interaction => selectGroupGesture(interaction, groupId),\n gestureStateEqual\n );\n\n const dragging = gesture?.kind === 'drag';\n const blocked = gesture?.blocked ?? false;\n const bounds = computeLiveBounds(group, gesture);\n\n // ── Inline label edit ──\n // `draft` is initialised from `group.label` on mount and re-synced by\n // `cancelLabel` / `commitLabel` / `handleLabelDoubleClick` on every\n // transition out of / into edit mode. Mirroring `group.label` into\n // state via a side effect would be the classic anti-pattern.\n const [editing, setEditing] = useState(false);\n const [draft, setDraft] = useState(group.label ?? '');\n const inputRef = useRef<HTMLInputElement>(null);\n\n useEffect(() => {\n if (editing) {\n // Defer focus until the input has been mounted.\n inputRef.current?.focus();\n inputRef.current?.select();\n }\n }, [editing]);\n\n const commitLabel = useCallback((): void => {\n const trimmed = draft.trim();\n setEditing(false);\n if (trimmed === (group.label ?? '')) return;\n onLabelChange(group, trimmed);\n }, [draft, group, onLabelChange]);\n\n const cancelLabel = useCallback((): void => {\n setEditing(false);\n setDraft(group.label ?? '');\n }, [group.label]);\n\n const handleLabelDoubleClick = useCallback(\n (event: React.MouseEvent<HTMLSpanElement>): void => {\n event.stopPropagation();\n // Re-sync from the prop on open — covers the case where `group.label`\n // changed externally while we weren't editing, so the input opens\n // with the current value rather than a stale draft.\n setDraft(group.label ?? '');\n setEditing(true);\n },\n [group.label]\n );\n\n const handleInputKeyDown = useCallback(\n (event: React.KeyboardEvent<HTMLInputElement>): void => {\n if (event.key === 'Enter') {\n event.preventDefault();\n commitLabel();\n } else if (event.key === 'Escape') {\n event.preventDefault();\n cancelLabel();\n }\n // Stop arrow keys from triggering the graph's nudge handler.\n event.stopPropagation();\n },\n [commitLabel, cancelLabel]\n );\n\n // ── Colour picker ──\n //\n // The swatch is a `<button>` that triggers the entangle-ui `<ColorPicker>`\n // popover. The picker has `showAlpha` enabled so it returns proper\n // `rgba(...)` strings when the user lowers opacity — the canvas\n // `drawGroups` fill plumbs that straight through with no transform.\n const handleColorChange = useCallback(\n (next: string): void => {\n onColorChange(group, next);\n },\n [group, onColorChange]\n );\n\n // Picker value falls back to a sensible default when the group hasn't\n // been coloured yet (the library doesn't impose a default).\n const pickerValue = group.color ?? DEFAULT_PICKER_COLOR;\n\n return (\n <div\n className={cx(groupOverlayRecipe({ selected, dragging, blocked }))}\n style={{\n left: bounds.x,\n top: bounds.y,\n width: bounds.width,\n height: bounds.height,\n }}\n data-group-id={group.id}\n data-blocked={blocked || undefined}\n onPointerDown={e => {\n onBodyPointerDown(e, group);\n }}\n onPointerUp={e => {\n onBodyPointerUp(e, group);\n }}\n onContextMenu={onBodyContextMenu}\n >\n <div\n className={groupLabelBarStyle}\n // Don't let pointerdown on the label bar (label text, color swatch,\n // input) fall through to the body drag handler — the label bar is\n // an interactive control row, not a draggable handle.\n onPointerDown={e => {\n e.stopPropagation();\n }}\n >\n {editing ? (\n <input\n ref={inputRef}\n className={groupLabelInputStyle}\n value={draft}\n placeholder=\"Group name\"\n spellCheck={false}\n onChange={e => {\n setDraft(e.target.value);\n }}\n onBlur={commitLabel}\n onKeyDown={handleInputKeyDown}\n />\n ) : (\n <span\n className={groupLabelStyle}\n onDoubleClick={handleLabelDoubleClick}\n title=\"Double-click to rename\"\n >\n {group.label?.trim() ? group.label : 'Group'}\n </span>\n )}\n <Popover placement=\"bottom-end\">\n <PopoverTrigger>\n <button\n type=\"button\"\n aria-label=\"Change group colour\"\n title=\"Change group colour\"\n className={groupColorSwatchStyle}\n style={{ background: group.color ?? DEFAULT_PICKER_COLOR }}\n />\n </PopoverTrigger>\n <PopoverContent padding=\"md\">\n {/* Uncontrolled picker — `useColor` only mutates its internal\n state when `value` is undefined, so passing `defaultValue`\n lets the user actually drag the sliders / click the\n palette. PopoverContent unmounts on close, so each open\n gets a fresh mount that picks up the current\n `group.color` via `defaultValue`. `showAlpha` lets the\n picker emit translucent fills directly — we ask for\n `format=\"rgba\"` so the alpha channel is actually included\n in the output string (`\"rgb\"` strips it). Survives\n round-trip through the canvas group fill with no\n consumer-side transform. */}\n <ColorPicker\n inline\n showAlpha\n defaultValue={pickerValue}\n format=\"rgba\"\n palette=\"material\"\n onChangeComplete={handleColorChange}\n />\n </PopoverContent>\n </Popover>\n </div>\n {selected\n ? ALL_HANDLES.map(handle => (\n <div\n key={handle}\n className={groupResizeHandleStyle}\n style={{\n ...HANDLE_POSITIONS[handle],\n cursor: RESIZE_CURSORS[handle],\n }}\n data-group-id={group.id}\n data-group-handle={handle}\n onPointerDown={e => {\n onHandlePointerDown(e, group, handle);\n }}\n />\n ))\n : null}\n </div>\n );\n}\n\nexport const NodeGraphGroupView = React.memo(NodeGraphGroupViewImpl);\nNodeGraphGroupView.displayName = 'NodeGraphGroupView';\n"],"names":[],"mappings":";;;;;;;;;;;;;AAyDA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAGF;;;;;;;;;;AAcA;;;;;;;;;;AAWA;AAuBA;;AAIe;AACb;AAA8B;AAC9B;AAAuB;AACvB;AAA6B;AAC7B;;;AAGA;AACE;;;;;;;;AAUF;AACF;AAEA;AAIE;;AAEI;;;;;AAKJ;;AAEI;;;;;;;AAOJ;AACF;AAEA;;;AAKE;;;;AAII;AACA;;;AAGJ;AACF;AAEA;;;;;;;;;;;;;;AAcG;AACH;AASE;AACA;;;AAeA;AACA;;;;;;;;AASA;AACA;;;;AAKI;AACA;;AAEJ;AAEA;AACE;;;;AAGA;;AAGF;;AAEE;AACF;AAEA;;;;;AAMI;;AAEF;AAIF;AAEI;;AAEE;;AACK;;AAEL;;;;AAIJ;;;;;;;AAUF;AAEI;AACF;;;AAMF;AAEA;;;;;AAQK;AAIC;AACF;AAEE;;;;;;;AAWA;AAUM;;AAgDN;;AAMQ;;AAKA;AACF;AAGN;AAGR;AAEO;AACP;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"NodeGraphMinimap.js","sources":["../../../../../../src/components/editor/NodeGraph/NodeGraphMinimap.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;;;;AAyBA;;;;AAIG;AACH;;;AAGG;AACH;;AAQE;AACE;AACA;AACD;AACD;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEF;AAEM;AASJ;AACA;AACA;;;;;AAKA;AAKA;;AAEI;AAKA;AACA;;;AAGA;AAEA;;AAGE;;;;;;AAMA;;AAEE;AACA;AACA;;;;AAIF;;AAGF;;AAEE;;;;;;AAMF;AAAe;AACf;AACF;;;;;;AAMF;AACE;AACA;AACA;;;;;AAKD;AAED;AACE;AAKA;;;AAGE;;;AAGF;AACA;;AAEE;AACA;AACA;AACA;;;;;AAKJ;;AAcF;;"}
1
+ {"version":3,"file":"NodeGraphMinimap.js","sources":["src/components/editor/NodeGraph/NodeGraphMinimap.tsx"],"sourcesContent":["'use client';\n\nimport React, { useMemo, useSyncExternalStore } from 'react';\n\nimport { Minimap } from '@/components/editor/Minimap';\nimport { ViewportMinimap } from '@/components/editor/Minimap/ViewportMinimap';\nimport { cx } from '@/utils/cx';\n\nimport { minimapSlotStyle } from './NodeGraph.css';\nimport {\n useNodeGraphData,\n useNodeGraphSelection,\n useNodeGraphStore,\n} from './NodeGraphContext';\nimport { computeNodesBounds, getNodeBox } from './nodeGraphMath';\n\nimport type { NodeGraphMinimapSlotProps } from './NodeGraph.types';\nimport type {\n MinimapCustomItem,\n MinimapDrawInfo,\n MinimapItem,\n MinimapRectItem,\n} from '@/components/editor/Minimap';\nimport type { WorldRect } from '@/components/primitives/viewport';\n\n/**\n * Live renderer for `<NodeGraph.Minimap>`. Mounted inside the `<Viewport>`\n * subtree by the main `NodeGraph` component when the user supplies a\n * minimap slot child.\n */\n/**\n * Draw a two-tone \"header strip + body\" mini-node into the minimap canvas,\n * converting the node's world rect to minimap pixels via the draw helpers.\n */\nfunction drawMiniNode(\n ctx: CanvasRenderingContext2D,\n info: MinimapDrawInfo,\n rect: WorldRect,\n bodyColor: string | undefined,\n headerColor: string\n): void {\n const tl = info.worldToMinimap({ x: rect.x, y: rect.y });\n const br = info.worldToMinimap({\n x: rect.x + rect.width,\n y: rect.y + rect.height,\n });\n const x = Math.min(tl.x, br.x);\n const y = Math.min(tl.y, br.y);\n const w = Math.abs(br.x - tl.x);\n const h = Math.abs(br.y - tl.y);\n ctx.fillStyle = bodyColor ?? 'rgba(180, 190, 210, 0.5)';\n ctx.fillRect(x, y, w, h);\n const headerH = Math.min(h, Math.max(2, h * 0.32));\n ctx.fillStyle = headerColor;\n ctx.fillRect(x, y, w, headerH);\n}\n\nexport function NodeGraphMinimapInner({\n placement = 'bottom-right',\n margin = 12,\n width = 200,\n title,\n className,\n selectedColor,\n nodeStyle,\n}: NodeGraphMinimapSlotProps): React.ReactElement {\n const data = useNodeGraphData();\n const selection = useNodeGraphSelection();\n const store = useNodeGraphStore();\n // Subscribe to measured-size updates so the minimap rect for each node\n // grows/shrinks as its DOM body changes height (auto-sized nodes). The\n // version snapshot doubles as a `useMemo` dep below, so the item /\n // bounds caches invalidate on every real size change.\n const measuredSizesVersion = useSyncExternalStore(\n store.subscribeMeasuredSizes,\n store.getMeasuredSizesVersion\n );\n\n const items = useMemo<MinimapItem[]>(() => {\n return data.nodes.map<MinimapItem>(node => {\n const box = getNodeBox(\n node,\n store.getMeasuredSize(node.id),\n data.defaultNodeSize\n );\n const isSelected = selection.nodes.includes(node.id);\n const style = nodeStyle?.(node);\n // Selection tint wins over the per-node body colour so the highlight\n // stays visible.\n const bodyColor =\n isSelected && selectedColor ? selectedColor : style?.color;\n const headerColor = style?.headerColor;\n\n if (headerColor) {\n const rect: WorldRect = {\n x: box.x,\n y: box.y,\n width: box.width,\n height: box.height,\n };\n const item: MinimapCustomItem = {\n id: node.id,\n type: 'custom',\n bounds: rect,\n draw: (ctx, info) => {\n drawMiniNode(ctx, info, rect, bodyColor, headerColor);\n },\n };\n return item;\n }\n\n const item: MinimapRectItem = {\n id: node.id,\n type: 'rect',\n x: box.x,\n y: box.y,\n width: box.width,\n height: box.height,\n };\n if (bodyColor) item.color = bodyColor;\n return item;\n });\n // `measuredSizesVersion` is an intentional invalidation key: the body reads\n // `store.getMeasuredSize(...)` — mutable state React can't track — so the\n // memo must recompute whenever a node's measured size changes. The linter\n // flags it as unused because it isn't referenced directly.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n data.nodes,\n data.defaultNodeSize,\n selection.nodes,\n selectedColor,\n nodeStyle,\n store,\n measuredSizesVersion,\n ]);\n\n const worldBounds = useMemo(() => {\n const bounds = computeNodesBounds(\n data.nodes,\n store.getMeasuredSize,\n data.defaultNodeSize\n );\n if (bounds.width === 0 && bounds.height === 0) {\n // Provide a sensible default world rect so the minimap renders even\n // when the graph is empty.\n return { x: -200, y: -150, width: 400, height: 300 };\n }\n // Add 10% padding around content for nicer framing.\n const padX = bounds.width * 0.1;\n const padY = bounds.height * 0.1;\n return {\n x: bounds.x - padX,\n y: bounds.y - padY,\n width: bounds.width + padX * 2,\n height: bounds.height + padY * 2,\n };\n // See note above: `measuredSizesVersion` keys the cache off mutable measured\n // sizes that `computeNodesBounds` reads via `store.getMeasuredSize`.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [data.nodes, data.defaultNodeSize, store, measuredSizesVersion]);\n\n return (\n <ViewportMinimap\n placement={placement}\n margin={margin}\n width={width}\n items={items}\n worldBounds={worldBounds}\n className={cx(minimapSlotStyle, className)}\n >\n {title ? <Minimap.Title>{title}</Minimap.Title> : null}\n </ViewportMinimap>\n );\n}\n\nexport { NodeGraphMinimap, NodeGraphBackground } from './NodeGraphSlots';\n"],"names":[],"mappings":";;;;;;;;;;;AAyBA;;;;AAIG;AACH;;;AAGG;AACH;;AAQE;AACE;AACA;AACD;AACD;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEF;AAEM;AASJ;AACA;AACA;;;;;AAKA;AAKA;;AAEI;AAKA;AACA;;;AAGA;AAEA;;AAGE;;;;;;AAMA;;AAEE;AACA;AACA;;;;AAIF;;AAGF;;AAEE;;;;;;AAMF;AAAe;AACf;AACF;;;;;;AAMF;AACE;AACA;AACA;;;;;AAKD;AAED;AACE;AAKA;;;AAGE;;;AAGF;AACA;;AAEE;AACA;AACA;AACA;;;;;AAKJ;;AAcF;;"}
@@ -7,7 +7,7 @@ import '../../../utils/devWarn.js';
7
7
  import { useResizeObserver } from '../../../hooks/useResizeObserver/useResizeObserver.js';
8
8
  import '../../../hooks/useBreakpoint/useBreakpoint.js';
9
9
  import './../../../assets/src/theme/lightTheme.css.ts.vanilla-Ct6f9Iym.css';
10
- import '../../../node_modules/@vanilla-extract/css/dist/vanilla-extract-css.esm.js';
10
+ import '@vanilla-extract/css';
11
11
  import './../../../assets/src/theme/darkTheme.css.ts.vanilla-BHZ3ecRn.css';
12
12
  import './../../../assets/src/theme/globalScrollbars.css.ts.vanilla-BAJwnUEJ.css';
13
13
  import '../../../hooks/useNavigationHistory/useNavigationHistory.js';
@@ -1 +1 @@
1
- {"version":3,"file":"NodeGraphNode.js","sources":["../../../../../../src/components/editor/NodeGraph/NodeGraphNode.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;AAoDA;AAOE;AACA;AAEE;AACA;AAEA;;;;AAGF;AAKF;AAEA;;AACe;AACb;AAA8B;AAC9B;AACF;AAEA;;;;;;;;;;;;;;;;AAgBG;AACH;AAGE;AAQA;AACA;AACA;;;;;;;;AAcA;AAIA;AAOI;;;;;AAOA;;;;AAMA;;AAIJ;;;;;AAeA;;;;;;AAOA;AACE;AACE;AACA;AACD;AACH;AAEA;AACA;;AAEA;AACA;AAEA;AACE;AACA;;;;AAIA;AACE;;AAEF;AACE;;;AAGA;;;AAGJ;;;AAGE;AACA;;;AAGD;AAED;;;;;;AAOA;;AAOA;AACE;AACA;;AACA;;AAGF;AACE;AACA;;AACA;;;AAIF;;AAGI;;;;;;;;;;AAwBE;AACF;AAEE;AACF;AAIE;AACF;AAON;AAEO;AACP;;"}
1
+ {"version":3,"file":"NodeGraphNode.js","sources":["src/components/editor/NodeGraph/NodeGraphNode.tsx"],"sourcesContent":["'use client';\n\nimport { assignInlineVars } from '@vanilla-extract/dynamic';\nimport React, { useCallback, useDeferredValue, useMemo, useRef } from 'react';\n\nimport { useViewportStore } from '@/components/primitives/viewport/ViewportContext';\nimport { useResizeObserver } from '@/hooks';\nimport { cx } from '@/utils/cx';\n\nimport {\n defaultNodeBodyRecipe,\n nodeHeightVar,\n nodeWidthVar,\n nodeWrapperRecipe,\n} from './NodeGraph.css';\nimport { useNodeGraphStore } from './NodeGraphContext';\nimport { NodeGraphNodeContext } from './NodeGraphNodeContext';\nimport { useStoreSlice } from './useStoreSlice';\n\nimport type { NodeGraphNode, NodeGraphRenderCtx } from './NodeGraph.types';\nimport type { NodeGraphNodeContextValue } from './NodeGraphNodeContext';\nimport type { Point2D } from '@/components/primitives/canvas/canvas.types';\n\ninterface NodeGraphNodeViewProps {\n node: NodeGraphNode;\n renderNode?: (\n node: NodeGraphNode,\n ctx: NodeGraphRenderCtx\n ) => React.ReactNode;\n /** Pointer-down on the node body (drag / select). */\n onBodyPointerDown: (\n event: React.PointerEvent<HTMLDivElement>,\n node: NodeGraphNode\n ) => void;\n /** Pointer-up on the node body (used to detect plain clicks for selection). */\n onBodyPointerUp: (\n event: React.PointerEvent<HTMLDivElement>,\n node: NodeGraphNode\n ) => void;\n /** Pointer-down on a port (starts a connection drag). */\n onPortPointerDown: (\n event: React.PointerEvent<HTMLElement>,\n nodeId: string,\n portId: string\n ) => void;\n /** Native context menu (right-click) — dispatched up to the main component. */\n onBodyContextMenu: (\n event: React.MouseEvent<HTMLDivElement>,\n node: NodeGraphNode\n ) => void;\n}\n\nfunction DefaultNodeBody({\n node,\n selected,\n}: {\n node: NodeGraphNode;\n selected: boolean;\n}): React.ReactElement {\n let label = node.id;\n if (\n node.data !== null &&\n typeof node.data === 'object' &&\n 'label' in node.data\n ) {\n const candidate = (node.data as { label?: unknown }).label;\n if (typeof candidate === 'string') label = candidate;\n }\n return (\n <div className={defaultNodeBodyRecipe({ selected })}>\n <span>{label}</span>\n </div>\n );\n}\n\nfunction pointEqualNullable(a: Point2D | null, b: Point2D | null): boolean {\n if (a === b) return true;\n if (a === null || b === null) return false;\n return a.x === b.x && a.y === b.y;\n}\n\n/**\n * Internal — render a single node as an HTML element positioned in world\n * space. Connection endpoints live inside the consumer's `renderNode`\n * tree as `<NodeGraph.Port>` slots; this view just provides the wrapper,\n * the `NodeGraphNodeContext`, and the ResizeObserver that feeds the\n * node's measured size back to the store.\n *\n * Subscribes to per-id slices via `useStoreSlice` so each node re-renders\n * only when its own selection / drag delta / hover state changes — not on\n * every pointermove tick of an unrelated drag.\n *\n * Wrapped in `React.memo` so a parent re-render (e.g. caused by an\n * unrelated controlled-state update) doesn't cascade through every\n * mounted node. Stable identity for the parent-provided handlers\n * (`onBodyPointerDown`, etc.) is ensured by `useCallback` in\n * `NodeGraphImpl`; `node` identity is preserved by consumer immutability.\n */\nfunction NodeGraphNodeViewImpl(\n props: NodeGraphNodeViewProps\n): React.ReactElement {\n const {\n node,\n renderNode,\n onBodyPointerDown,\n onBodyPointerUp,\n onPortPointerDown,\n onBodyContextMenu,\n } = props;\n const store = useNodeGraphStore();\n const viewportStore = useViewportStore();\n const wrapperRef = useRef<HTMLDivElement>(null);\n\n const selected = useStoreSlice(\n store.subscribeSelection,\n store.getSelection,\n sel => sel.nodes.includes(node.id)\n );\n\n // Subscribe to the per-node interaction channel rather than the global\n // one. The store fans notifications out only to ids in the prev ∪ next\n // drag set, so an unrelated drag of another node never wakes this\n // subscriber. The selector itself is unchanged — `useStoreSlice` still\n // reads from the global getInteraction snapshot to decide whether *this*\n // id has a delta to apply.\n const subscribeNodeInteraction = useCallback(\n (cb: () => void) => store.subscribeNodeInteraction(node.id, cb),\n [store, node.id]\n );\n const dragDelta = useStoreSlice<\n ReturnType<typeof store.getInteraction>,\n Point2D | null\n >(\n subscribeNodeInteraction,\n store.getInteraction,\n interaction => {\n if (\n interaction.kind === 'drag-nodes' &&\n interaction.nodeIds.has(node.id)\n ) {\n return interaction.delta;\n }\n // Nodes fully contained inside a dragged group move with the group.\n if (\n interaction.kind === 'drag-groups' &&\n interaction.containedNodeIds.has(node.id)\n ) {\n return interaction.delta;\n }\n return null;\n },\n pointEqualNullable\n );\n const dragging = dragDelta !== null;\n\n const hovered = useStoreSlice(\n store.subscribeHover,\n store.getHover,\n hover => hover.hoveredNodeId === node.id\n );\n\n const liveZoom = useStoreSlice(\n viewportStore.subscribeTransform,\n viewportStore.getTransform,\n transform => transform.zoom\n );\n // Defer the zoom value passed into consumer renderNode so heavy node\n // bodies don't block the pointer gesture loop during a zoom-while-drag.\n const zoom = useDeferredValue(liveZoom);\n\n // ── Auto-size: feed measured wrapper size back to the store ──\n //\n // When the consumer omits `node.width`/`height`, the library reads the\n // measured DOM size for hit-testing, marquee, and fitToContent. Explicit\n // overrides on the node still win — this just records the rendered size.\n useResizeObserver(wrapperRef, entry => {\n store.setMeasuredSize(node.id, {\n width: entry.contentRect.width,\n height: entry.contentRect.height,\n });\n });\n\n const explicitWidth = node.width;\n const explicitHeight = node.height;\n const autoSize = explicitWidth === undefined && explicitHeight === undefined;\n const draggable = node.draggable !== false;\n const selectable = node.selectable !== false;\n\n const wrapperStyle = useMemo<React.CSSProperties>(() => {\n const x = node.position.x + (dragDelta?.x ?? 0);\n const y = node.position.y + (dragDelta?.y ?? 0);\n // assignInlineVars only emits the keys it's given — when explicit\n // dimensions are absent the auto-sized recipe variant kicks in.\n const dimensionVars: Record<string, string> = {};\n if (explicitWidth !== undefined) {\n dimensionVars[nodeWidthVar] = `${explicitWidth}px`;\n }\n if (explicitHeight !== undefined) {\n dimensionVars[nodeHeightVar] = `${explicitHeight}px`;\n }\n return {\n transform: `translate(${x}px, ${y}px)`,\n ...assignInlineVars(dimensionVars),\n };\n }, [\n node.position.x,\n node.position.y,\n dragDelta?.x,\n dragDelta?.y,\n explicitWidth,\n explicitHeight,\n ]);\n\n const renderCtx: NodeGraphRenderCtx = {\n selected,\n dragging,\n hovered,\n zoom,\n };\n\n const body = renderNode ? (\n renderNode(node, renderCtx)\n ) : (\n <DefaultNodeBody node={node} selected={selected} />\n );\n\n // ── Hover wiring ──\n const onPointerEnter = useCallback((): void => {\n const current = store.getHover();\n if (current.hoveredNodeId === node.id) return;\n store.setHover({ ...current, hoveredNodeId: node.id });\n }, [store, node.id]);\n\n const onPointerLeave = useCallback((): void => {\n const current = store.getHover();\n if (current.hoveredNodeId !== node.id) return;\n store.setHover({ ...current, hoveredNodeId: null });\n }, [store, node.id]);\n\n // ── Per-node context for `<NodeGraph.Port>` slots ──\n const nodeContext = useMemo<NodeGraphNodeContextValue>(\n () => ({\n nodeId: node.id,\n onPortPointerDown: (event, portId) => {\n onPortPointerDown(event, node.id, portId);\n },\n }),\n [node.id, onPortPointerDown]\n );\n\n return (\n <div\n ref={wrapperRef}\n className={cx(\n nodeWrapperRecipe({\n draggable,\n selectable,\n dragging,\n autoSize,\n })\n )}\n style={wrapperStyle}\n data-node-id={node.id}\n data-hovered={hovered ? 'true' : undefined}\n data-selected={selected ? 'true' : undefined}\n data-dragging={dragging ? 'true' : undefined}\n onPointerDown={e => {\n onBodyPointerDown(e, node);\n }}\n onPointerUp={e => {\n onBodyPointerUp(e, node);\n }}\n onPointerEnter={onPointerEnter}\n onPointerLeave={onPointerLeave}\n onContextMenu={e => {\n onBodyContextMenu(e, node);\n }}\n >\n <NodeGraphNodeContext.Provider value={nodeContext}>\n {body}\n </NodeGraphNodeContext.Provider>\n </div>\n );\n}\n\nexport const NodeGraphNodeView = React.memo(NodeGraphNodeViewImpl);\nNodeGraphNodeView.displayName = 'NodeGraphNodeView';\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;AAoDA;AAOE;AACA;AAEE;AACA;AAEA;;;;AAGF;AAKF;AAEA;;AACe;AACb;AAA8B;AAC9B;AACF;AAEA;;;;;;;;;;;;;;;;AAgBG;AACH;AAGE;AAQA;AACA;AACA;;;;;;;;AAcA;AAIA;AAOI;;;;;AAOA;;;;AAMA;;AAIJ;;;;;AAeA;;;;;;AAOA;AACE;AACE;AACA;AACD;AACH;AAEA;AACA;;AAEA;AACA;AAEA;AACE;AACA;;;;AAIA;AACE;;AAEF;AACE;;;AAGA;;;AAGJ;;;AAGE;AACA;;;AAGD;AAED;;;;;;AAOA;;AAOA;AACE;AACA;;AACA;;AAGF;AACE;AACA;;AACA;;;AAIF;;AAGI;;;;;;;;;;AAwBE;AACF;AAEE;AACF;AAIE;AACF;AAON;AAEO;AACP;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"NodeGraphNodeContext.js","sources":["../../../../../../src/components/editor/NodeGraph/NodeGraphNodeContext.ts"],"sourcesContent":[null],"names":[],"mappings":";;;;AAyBE;AAEF;;;;;AAKG;;AAED;;AAEE;;AAIF;AACF;;"}
1
+ {"version":3,"file":"NodeGraphNodeContext.js","sources":["src/components/editor/NodeGraph/NodeGraphNodeContext.ts"],"sourcesContent":["'use client';\n\nimport { createContext, useContext } from 'react';\n\nimport type React from 'react';\n\n/**\n * Per-node context wired by `NodeGraphNodeView` so `<NodeGraph.Port>` slots\n * rendered inside `renderNode` can identify their owning node and start a\n * connection drag without the consumer threading any IDs through manually.\n */\nexport interface NodeGraphNodeContextValue {\n /** Owning node id. */\n nodeId: string;\n /**\n * Start a connection drag from the given port. Wired by the parent to\n * the shared `useNodeGraphConnection` controller.\n */\n onPortPointerDown: (\n event: React.PointerEvent<HTMLElement>,\n portId: string\n ) => void;\n}\n\nexport const NodeGraphNodeContext =\n /*#__PURE__*/ createContext<NodeGraphNodeContextValue | null>(null);\n\n/**\n * Read the active per-node context. Throws when used outside a node body\n * (i.e. outside `renderNode`) — the throw is intentional, since the\n * library guarantees the context is provided when the consumer's\n * `renderNode` is invoked.\n */\nexport function useNodeGraphNodeContext(): NodeGraphNodeContextValue {\n const ctx = useContext(NodeGraphNodeContext);\n if (!ctx) {\n throw new Error(\n '<NodeGraph.Port> must be rendered inside the renderNode body of a <NodeGraph>'\n );\n }\n return ctx;\n}\n"],"names":[],"mappings":";;;;AAyBE;AAEF;;;;;AAKG;;AAED;;AAEE;;AAIF;AACF;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"NodeGraphNodeParts.js","sources":["../../../../../../src/components/editor/NodeGraph/NodeGraphNodeParts.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;;AAqDM;AASJ;AACA;;;AAaA;AACA;;;;;AAME;;AAGF;AAQF;;AA2BE;AACE;AACA;;AAEF;AAmBF;AAiBM;;;;;;AAYA;;;;;AAKmB;;AACM;;AACtB;AACP;AAEA;AAYF;AAqBM;AAOJ;AASF;;"}
1
+ {"version":3,"file":"NodeGraphNodeParts.js","sources":["src/components/editor/NodeGraph/NodeGraphNodeParts.tsx"],"sourcesContent":["'use client';\n\nimport React from 'react';\n\nimport { cx } from '@/utils/cx';\n\nimport {\n nodeBodyRecipe,\n nodeHeaderStyle,\n nodeHeaderIconStyle,\n nodeHeaderTextStyle,\n nodeHeaderTitleStyle,\n nodeHeaderSubtitleStyle,\n pinListStyle,\n pinListColumnStyle,\n pinRowRecipe,\n} from './NodeGraph.css';\nimport { useNodeGraphStore } from './NodeGraphContext';\nimport { useNodeGraphNodeContext } from './NodeGraphNodeContext';\nimport { useStoreSlice } from './useStoreSlice';\n\nimport type { NodeGraphPortSide } from './NodeGraph.types';\n\n/**\n * Default node body wrapper — a themed panel with the standard\n * selected/hovered visual states the library provides out of the box.\n * Drop it inside your `renderNode` and you get a node that looks at\n * home next to the rest of the library; override `className` / `style`\n * to take over.\n *\n * Selection / hover / drag state is read from the store via the\n * per-node context so the body re-themes itself without the consumer\n * threading state in from `renderNode`'s `ctx`. Pass `selected` /\n * `hovered` explicitly to drive the visual from outside (e.g. running\n * a node-state machine in your own React tree).\n */\nexport interface NodeGraphNodeBodyProps {\n /** Override the accent colour (default border / shadow when selected). */\n accent?: string;\n /** Override the auto-derived `selected` state. */\n selected?: boolean;\n /** Override the auto-derived `hovered` state. */\n hovered?: boolean;\n /** Visual variant — affects default chrome density. */\n variant?: 'panel' | 'flat' | 'minimal';\n /** Extra classes applied to the body wrapper. */\n className?: string;\n /** Inline style override (lower priority than CSS classes). */\n style?: React.CSSProperties;\n /** Body content — typically `<NodeGraph.NodeHeader>` + `<NodeGraph.PinList>`. */\n children?: React.ReactNode;\n}\n\nexport function NodeGraphNodeBody({\n accent,\n selected: selectedProp,\n hovered: hoveredProp,\n variant = 'panel',\n className,\n style,\n children,\n}: NodeGraphNodeBodyProps): React.ReactElement {\n const { nodeId } = useNodeGraphNodeContext();\n const store = useNodeGraphStore();\n\n const autoSelected = useStoreSlice(\n store.subscribeSelection,\n store.getSelection,\n sel => sel.nodes.includes(nodeId)\n );\n const autoHovered = useStoreSlice(\n store.subscribeHover,\n store.getHover,\n hover => hover.hoveredNodeId === nodeId\n );\n\n const selected = selectedProp ?? autoSelected;\n const hovered = hoveredProp ?? autoHovered;\n\n // Accent drives both the selected border and a soft glow. CSS vars\n // let recipe variants pick up the consumer's value without us\n // pre-baking a token contract for every possible colour.\n const accentStyle = accent\n ? ({ ['--etui-ng-accent' as string]: accent } as React.CSSProperties)\n : undefined;\n\n return (\n <div\n className={cx(nodeBodyRecipe({ selected, hovered, variant }), className)}\n style={{ ...accentStyle, ...style }}\n >\n {children}\n </div>\n );\n}\n\n/**\n * Header bar for a node — gradient strip + optional icon, title and\n * subtitle. Pass `children` to take full control of the header layout.\n */\nexport interface NodeGraphNodeHeaderProps {\n title?: React.ReactNode;\n subtitle?: React.ReactNode;\n /** Small leading icon (typically 14-18 px). */\n icon?: React.ReactNode;\n /** Override the header background — defaults to theme accent gradient. */\n background?: string;\n className?: string;\n style?: React.CSSProperties;\n children?: React.ReactNode;\n}\n\nexport function NodeGraphNodeHeader({\n title,\n subtitle,\n icon,\n background,\n className,\n style,\n children,\n}: NodeGraphNodeHeaderProps): React.ReactElement {\n const styleOverride: React.CSSProperties = {\n ...(background ? { background } : null),\n ...style,\n };\n return (\n <div className={cx(nodeHeaderStyle, className)} style={styleOverride}>\n {children ?? (\n <>\n {icon != null ? (\n <span className={nodeHeaderIconStyle}>{icon}</span>\n ) : null}\n <div className={nodeHeaderTextStyle}>\n {title != null ? (\n <div className={nodeHeaderTitleStyle}>{title}</div>\n ) : null}\n {subtitle != null ? (\n <div className={nodeHeaderSubtitleStyle}>{subtitle}</div>\n ) : null}\n </div>\n </>\n )}\n </div>\n );\n}\n\n/**\n * Two-column pin container — children are routed into the left or right\n * column based on each `<NodeGraph.PinRow side>`. Anything that isn't a\n * `<NodeGraph.PinRow>` falls through into a center \"loose\" slot below\n * the columns (so you can drop inline editors / body content next to\n * your pin rows without breaking layout).\n */\nexport interface NodeGraphPinListProps {\n className?: string;\n style?: React.CSSProperties;\n /** Gap between left and right columns, in CSS px. Default 16. */\n columnGap?: number;\n children?: React.ReactNode;\n}\n\nexport function NodeGraphPinList({\n className,\n style,\n columnGap = 16,\n children,\n}: NodeGraphPinListProps): React.ReactElement {\n const left: React.ReactNode[] = [];\n const right: React.ReactNode[] = [];\n const loose: React.ReactNode[] = [];\n\n React.Children.forEach(children, child => {\n if (!React.isValidElement(child)) {\n loose.push(child);\n return;\n }\n const side =\n (child.props as { side?: NodeGraphPortSide } | undefined)?.side ?? null;\n if (side === 'left') left.push(child);\n else if (side === 'right') right.push(child);\n else loose.push(child);\n });\n\n return (\n <div\n className={cx(pinListStyle, className)}\n style={{ columnGap, ...style }}\n >\n <div className={pinListColumnStyle}>{left}</div>\n <div className={pinListColumnStyle}>{right}</div>\n {loose.length > 0 ? (\n <div style={{ gridColumn: '1 / -1' }}>{loose}</div>\n ) : null}\n </div>\n );\n}\n\n/**\n * Single pin row — typically holds a `<NodeGraph.Port>` plus a label.\n * Side determines which end of the row the port sits at: `left` puts\n * the port first (left edge), `right` puts it last (right edge).\n *\n * The row is layout-only — pin position math comes from the slot's DOM\n * measurement, not from where in the row it lives. You can rearrange\n * the order inside the row without breaking edges.\n */\nexport interface NodeGraphPinRowProps {\n /** Which side this pin anchors to. Drives the layout / justification. */\n side: NodeGraphPortSide;\n /** Optional row height (CSS px). Default 22. */\n height?: number;\n className?: string;\n style?: React.CSSProperties;\n children?: React.ReactNode;\n}\n\nexport function NodeGraphPinRow({\n side,\n height = 22,\n className,\n style,\n children,\n}: NodeGraphPinRowProps): React.ReactElement {\n return (\n <div\n className={cx(pinRowRecipe({ side }), className)}\n style={{ height, ...style }}\n data-pin-side={side}\n >\n {children}\n </div>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;AAqDM;AASJ;AACA;;;AAaA;AACA;;;;;AAME;;AAGF;AAQF;;AA2BE;AACE;AACA;;AAEF;AAmBF;AAiBM;;;;;;AAYA;;;;;AAKmB;;AACM;;AACtB;AACP;AAEA;AAYF;AAqBM;AAOJ;AASF;;"}
@@ -5,7 +5,7 @@ import '../../../utils/devWarn.js';
5
5
  import { useControlledState } from '../../../hooks/useControlledState/useControlledState.js';
6
6
  import '../../../hooks/useBreakpoint/useBreakpoint.js';
7
7
  import './../../../assets/src/theme/lightTheme.css.ts.vanilla-Ct6f9Iym.css';
8
- import '../../../node_modules/@vanilla-extract/css/dist/vanilla-extract-css.esm.js';
8
+ import '@vanilla-extract/css';
9
9
  import './../../../assets/src/theme/darkTheme.css.ts.vanilla-BHZ3ecRn.css';
10
10
  import './../../../assets/src/theme/globalScrollbars.css.ts.vanilla-BAJwnUEJ.css';
11
11
  import '../../../hooks/useNavigationHistory/useNavigationHistory.js';
@@ -1 +1 @@
1
- {"version":3,"file":"NodeGraphNodeSection.js","sources":["../../../../../../src/components/editor/NodeGraph/NodeGraphNodeSection.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;;;;;;;;AAsCA;;;;;;;;;;;;;;;;;;AAkBG;AACG;AAUJ;AACE;AACA;AACA;AACA;AACD;;;AAID;AACE;;;AAEF;;AAGA;;;AAOA;AAKA;AA8BF;AAEA;;"}
1
+ {"version":3,"file":"NodeGraphNodeSection.js","sources":["src/components/editor/NodeGraph/NodeGraphNodeSection.tsx"],"sourcesContent":["'use client';\n\nimport React, { useCallback, useMemo } from 'react';\n\nimport { useControlledState } from '@/hooks';\nimport { cx } from '@/utils/cx';\n\nimport {\n nodeSectionStyle,\n nodeSectionHeaderStyle,\n nodeSectionChevronRecipe,\n nodeSectionTitleStyle,\n nodeSectionContentStyle,\n} from './NodeGraph.css';\nimport { NodeGraphNodeSectionContext } from './NodeGraphNodeSectionContext';\n\nimport type { NodeGraphNodeSectionContextValue } from './NodeGraphNodeSectionContext';\n\nexport interface NodeGraphNodeSectionProps {\n /** Header label shown next to the collapse toggle. */\n title?: React.ReactNode;\n /**\n * Whether the header toggles the section. When false the section is a\n * static labelled group (no chevron, always shown). @default true\n */\n collapsible?: boolean;\n /** Controlled collapsed state. Pair with `onCollapsedChange`. */\n collapsed?: boolean;\n /** Initial collapsed state when uncontrolled. @default false */\n defaultCollapsed?: boolean;\n /** Fires when the user toggles the section. */\n onCollapsedChange?: (collapsed: boolean) => void;\n className?: string;\n style?: React.CSSProperties;\n /** Section body — typically a `<NodeGraph.PinList>` of the extra pins. */\n children?: React.ReactNode;\n}\n\n/**\n * A collapsible section inside a node body — the place to tuck \"advanced\" /\n * overflow pins so the node stays compact. The collapse is **purely visual**:\n * the children never unmount, so their state is preserved and there's no\n * remount cost. `<NodeGraph.Port>` slots inside a collapsed section\n * unregister their position while hidden, so the pins' edges hide with them\n * and reappear on expand — no dangling wires, no manual re-anchoring.\n *\n * @example\n * ```tsx\n * <NodeGraph.NodeBody>\n * <NodeGraph.NodeHeader title=\"Make Transform\" />\n * <NodeGraph.PinList>{mainPins}</NodeGraph.PinList>\n * <NodeGraph.NodeSection title=\"Advanced\" defaultCollapsed>\n * <NodeGraph.PinList>{advancedPins}</NodeGraph.PinList>\n * </NodeGraph.NodeSection>\n * </NodeGraph.NodeBody>\n * ```\n */\nexport function NodeGraphNodeSection({\n title,\n collapsible = true,\n collapsed: collapsedProp,\n defaultCollapsed,\n onCollapsedChange,\n className,\n style,\n children,\n}: NodeGraphNodeSectionProps): React.ReactElement {\n const [collapsedState, setCollapsed] = useControlledState<boolean>({\n value: collapsedProp,\n defaultValue: defaultCollapsed,\n onChange: onCollapsedChange,\n fallback: false,\n });\n // A non-collapsible section is always expanded regardless of state.\n const collapsed = collapsible ? collapsedState : false;\n\n const toggle = useCallback(() => {\n if (!collapsible) return;\n setCollapsed(prev => !prev);\n }, [collapsible, setCollapsed]);\n\n // Toggling the section must not start a node drag / selection.\n const stopPointer = useCallback(\n (event: React.PointerEvent<HTMLButtonElement>) => {\n event.stopPropagation();\n },\n []\n );\n\n const ctxValue = useMemo<NodeGraphNodeSectionContextValue>(\n () => ({ collapsed }),\n [collapsed]\n );\n\n return (\n <div className={cx(nodeSectionStyle, className)} style={style}>\n <button\n type=\"button\"\n className={nodeSectionHeaderStyle}\n onClick={toggle}\n onPointerDown={stopPointer}\n disabled={!collapsible}\n aria-expanded={collapsible ? !collapsed : undefined}\n >\n {collapsible ? (\n <span\n className={nodeSectionChevronRecipe({ collapsed })}\n aria-hidden=\"true\"\n />\n ) : null}\n {title != null ? (\n <span className={nodeSectionTitleStyle}>{title}</span>\n ) : null}\n </button>\n <div\n className={nodeSectionContentStyle}\n style={collapsed ? { display: 'none' } : undefined}\n >\n <NodeGraphNodeSectionContext.Provider value={ctxValue}>\n {children}\n </NodeGraphNodeSectionContext.Provider>\n </div>\n </div>\n );\n}\n\nNodeGraphNodeSection.displayName = 'NodeGraphNodeSection';\n"],"names":[],"mappings":";;;;;;;;;;;;;;;AAsCA;;;;;;;;;;;;;;;;;;AAkBG;AACG;AAUJ;AACE;AACA;AACA;AACA;AACD;;;AAID;AACE;;;AAEF;;AAGA;;;AAOA;AAKA;AA8BF;AAEA;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"NodeGraphNodeSectionContext.js","sources":["../../../../../../src/components/editor/NodeGraph/NodeGraphNodeSectionContext.ts"],"sourcesContent":[null],"names":[],"mappings":";;;AAgBA;;AAGE;AAEF;;;;AAIG;;AAED;AACF;;"}
1
+ {"version":3,"file":"NodeGraphNodeSectionContext.js","sources":["src/components/editor/NodeGraph/NodeGraphNodeSectionContext.ts"],"sourcesContent":["'use client';\n\nimport { createContext, useContext } from 'react';\n\n/**\n * Context published by `<NodeGraph.NodeSection>` so the `<NodeGraph.Port>`\n * slots rendered inside it know whether they're currently collapsed. The\n * section never unmounts its children (a collapse is purely visual), so a\n * collapsed port stays in the React tree but unregisters its measured\n * position — which hides its edges until the section is expanded again,\n * without any remount cost or re-anchor bookkeeping.\n */\nexport interface NodeGraphNodeSectionContextValue {\n collapsed: boolean;\n}\n\nconst DEFAULT: NodeGraphNodeSectionContextValue = { collapsed: false };\n\nexport const NodeGraphNodeSectionContext =\n /*#__PURE__*/ createContext<NodeGraphNodeSectionContextValue>(DEFAULT);\n\n/**\n * Read the enclosing section's collapsed state. Returns `{ collapsed: false }`\n * when the port isn't inside a `<NodeGraph.NodeSection>`, so ports outside a\n * section behave exactly as before.\n */\nexport function useNodeGraphNodeSection(): NodeGraphNodeSectionContextValue {\n return useContext(NodeGraphNodeSectionContext);\n}\n"],"names":[],"mappings":";;;AAgBA;;AAGE;AAEF;;;;AAIG;;AAED;AACF;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"NodeGraphPin.js","sources":["../../../../../../src/components/editor/NodeGraph/NodeGraphPin.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;AA4CA;;;;;;;;;;;;;;;AAeG;AACG;;AA0BJ;;;;AASA;AAoBF;AAEA;;"}
1
+ {"version":3,"file":"NodeGraphPin.js","sources":["src/components/editor/NodeGraph/NodeGraphPin.tsx"],"sourcesContent":["'use client';\n\nimport React from 'react';\n\nimport { cx } from '@/utils/cx';\n\nimport { pinLabelStyle } from './NodeGraph.css';\nimport { NodeGraphPinRow } from './NodeGraphNodeParts';\nimport { NodeGraphPort } from './NodeGraphPort';\n\nimport type { NodeGraphPortShape, NodeGraphPortSide } from './NodeGraph.types';\n\nexport interface NodeGraphPinProps {\n /** Port id — referenced by `NodeGraphEdge.source` / `.target`. */\n id: string;\n /** Which side the pin anchors to. Drives row layout and edge tangent. */\n side: NodeGraphPortSide;\n /** Opaque type token forwarded to `isValidConnection` and edge styling. */\n dataType?: string;\n /** Row label shown next to the handle. */\n label?: React.ReactNode;\n /** Handle colour (any CSS colour). Defaults to the theme focus colour. */\n color?: string;\n /** Built-in handle shape. @default 'circle' */\n shape?: NodeGraphPortShape;\n /**\n * Force the handle filled / hollow. When omitted, the handle fills\n * automatically while the pin is connected to an edge.\n */\n filled?: boolean;\n /** Row height in CSS px. @default 22 */\n height?: number;\n /** Accessible label for the port handle. Falls back to the port default. */\n portLabel?: string;\n /** Class applied to the row wrapper. */\n className?: string;\n /** Inline style applied to the row wrapper. */\n style?: React.CSSProperties;\n /** Class applied to the label span. */\n labelClassName?: string;\n /** Inline style applied to the label span. */\n labelStyle?: React.CSSProperties;\n}\n\n/**\n * `<NodeGraph.Pin>` — the one-liner for the common \"handle + label\" row.\n * Renders a `<NodeGraph.PinRow>` containing a `<NodeGraph.Port>` and a\n * label, ordered so the handle always sits flush against the node edge\n * (port → label on the left/top, label → port on the right). Reach for\n * `<NodeGraph.PinRow>` + `<NodeGraph.Port>` directly only when you need a\n * layout this doesn't cover (multiple controls in a row, inline editors).\n *\n * @example\n * ```tsx\n * <NodeGraph.PinList>\n * <NodeGraph.Pin id=\"exec\" side=\"left\" shape=\"triangle\" color=\"#fff\" />\n * <NodeGraph.Pin id=\"value\" side=\"right\" dataType=\"float\" color=\"#9ee65a\" label=\"Value\" />\n * </NodeGraph.PinList>\n * ```\n */\nexport function NodeGraphPin({\n id,\n side,\n dataType,\n label,\n color,\n shape,\n filled,\n height,\n portLabel,\n className,\n style,\n labelClassName,\n labelStyle,\n}: NodeGraphPinProps): React.ReactElement {\n const port = (\n <NodeGraphPort\n id={id}\n side={side}\n {...(dataType !== undefined ? { dataType } : {})}\n {...(color !== undefined ? { color } : {})}\n {...(shape !== undefined ? { shape } : {})}\n {...(filled !== undefined ? { filled } : {})}\n {...(portLabel !== undefined ? { label: portLabel } : {})}\n />\n );\n const labelEl =\n label != null && label !== '' ? (\n <span className={cx(pinLabelStyle, labelClassName)} style={labelStyle}>\n {label}\n </span>\n ) : null;\n // Port leads the row on the left / top so the handle hugs the node edge;\n // on the right the label leads and the handle trails.\n const portFirst = side === 'left' || side === 'top';\n return (\n <NodeGraphPinRow\n side={side}\n {...(height !== undefined ? { height } : {})}\n {...(className !== undefined ? { className } : {})}\n {...(style !== undefined ? { style } : {})}\n >\n {portFirst ? (\n <>\n {port}\n {labelEl}\n </>\n ) : (\n <>\n {labelEl}\n {port}\n </>\n )}\n </NodeGraphPinRow>\n );\n}\n\nNodeGraphPin.displayName = 'NodeGraphPin';\n"],"names":[],"mappings":";;;;;;;AA4CA;;;;;;;;;;;;;;;AAeG;AACG;;AA0BJ;;;;AASA;AAoBF;AAEA;;"}
@@ -6,7 +6,7 @@ import '../../../utils/devWarn.js';
6
6
  import { useResizeObserver } from '../../../hooks/useResizeObserver/useResizeObserver.js';
7
7
  import '../../../hooks/useBreakpoint/useBreakpoint.js';
8
8
  import './../../../assets/src/theme/lightTheme.css.ts.vanilla-Ct6f9Iym.css';
9
- import '../../../node_modules/@vanilla-extract/css/dist/vanilla-extract-css.esm.js';
9
+ import '@vanilla-extract/css';
10
10
  import './../../../assets/src/theme/darkTheme.css.ts.vanilla-BHZ3ecRn.css';
11
11
  import './../../../assets/src/theme/globalScrollbars.css.ts.vanilla-BAJwnUEJ.css';
12
12
  import '../../../hooks/useNavigationHistory/useNavigationHistory.js';
@@ -1 +1 @@
1
- {"version":3,"file":"NodeGraphPort.js","sources":["../../../../../../src/components/editor/NodeGraph/NodeGraphPort.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AA8BA;AACE;AACA;AACA;AACA;;AAGF;AACE;AAEE;AACA;AACA;AAEJ;AAEA;;;;;;;;;;;;;;;;;;;;;;AAsBG;AACH;;AAaE;AACA;AACA;AACA;;;;;;AAYA;AAII;AAAoC;AACpC;AAEA;AAEE;AACA;AACF;AAA+B;;;;AAI7B;AACA;;;AAMN;AAII;AACA;AAEE;AACA;;AAKN;AACA;AACA;AACA;;;;;;;;;;;;;AAcA;;;;;AAKI;;;AAGF;AACA;;;AAEA;;AACA;AACA;;;;;;AAMA;AACA;AACA;AACF;;;;;;;;;;AAkBE;AACF;AAEA;AACE;AACF;;;AAIE;AACE;AACF;;;;;;;AAQF;AACE;AACA;;;;AAKF;AACE;AACA;;AAEA;;AAGF;AAEI;AACF;;AAKF;;;;;AAMA;;;;;AAuBQ;AACA;AACA;AACA;;AAgBV;AAEO;AACP;;"}
1
+ {"version":3,"file":"NodeGraphPort.js","sources":["src/components/editor/NodeGraph/NodeGraphPort.tsx"],"sourcesContent":["'use client';\n\nimport React, {\n useCallback,\n useLayoutEffect,\n useMemo,\n useRef,\n useSyncExternalStore,\n} from 'react';\n\nimport { useViewportStore } from '@/components/primitives/viewport/ViewportContext';\nimport { useResizeObserver } from '@/hooks';\nimport { cx } from '@/utils/cx';\n\nimport { portSlotRecipe } from './NodeGraph.css';\nimport { useNodeGraphStore } from './NodeGraphContext';\nimport { useNodeGraphNodeContext } from './NodeGraphNodeContext';\nimport { useNodeGraphNodeSection } from './NodeGraphNodeSectionContext';\nimport { NodeGraphPortVisual } from './NodeGraphPortVisual';\nimport { useStoreSlice } from './useStoreSlice';\n\nimport type { NodeGraphPortSlotProps } from './NodeGraph.types';\n\ninterface PortVisualState {\n isSource: boolean;\n isCandidate: boolean;\n isInvalid: boolean;\n isHovered: boolean;\n}\n\nconst EMPTY_VISUAL: PortVisualState = {\n isSource: false,\n isCandidate: false,\n isInvalid: false,\n isHovered: false,\n};\n\nfunction visualEqual(a: PortVisualState, b: PortVisualState): boolean {\n return (\n a.isSource === b.isSource &&\n a.isCandidate === b.isCandidate &&\n a.isInvalid === b.isInvalid &&\n a.isHovered === b.isHovered\n );\n}\n\n/**\n * `<NodeGraph.Port>` — compound slot that declares a connection endpoint\n * for the current node. Render it anywhere inside `renderNode`; the\n * library measures its DOM position, registers it as the anchor for any\n * edge that references this port id, and wires pointer events so the\n * user can drag from it to start a connection.\n *\n * The slot renders a single `<span>` with `display: inline-flex` — drop\n * it inline next to a label and it will sit beside the text. The wrapper\n * carries the default UE-style circle / exec-triangle visual; pass\n * `children` to replace the chrome entirely (state for theming is\n * exposed via `data-port-*` attributes).\n *\n * @example\n * ```tsx\n * <NodeGraph.Port id=\"in\" side=\"left\" dataType=\"exec\" />\n * ```\n *\n * Wrapped in `React.memo` — ports re-mount on every consumer `renderNode`\n * call by default, so memoization only helps consumers who memoize their\n * own node body. When they do, ports skip re-renders on unrelated store\n * updates entirely.\n */\nfunction NodeGraphPortImpl({\n id,\n side,\n dataType,\n shape = 'circle',\n color,\n filled,\n children,\n label,\n className,\n style,\n}: NodeGraphPortSlotProps): React.ReactElement {\n const { nodeId, onPortPointerDown } = useNodeGraphNodeContext();\n const { collapsed } = useNodeGraphNodeSection();\n const store = useNodeGraphStore();\n const viewportStore = useViewportStore();\n const elementRef = useRef<HTMLSpanElement>(null);\n\n // ── Connected state (slice subscription — only flips re-render) ──\n // The store recomputes the connected-ports index when edges change, so\n // each port re-renders only when its own connected-ness actually flips.\n const connected = useStoreSlice(\n store.subscribeConnectedPorts,\n store.getConnectedPorts,\n () => store.isPortConnected(nodeId, id)\n );\n\n // ── Per-port visual state (slice subscription — no re-render storm) ──\n const visual = useStoreSlice(\n store.subscribeInteraction,\n store.getInteraction,\n interaction => {\n if (interaction.kind !== 'connect') return EMPTY_VISUAL;\n const isSource =\n interaction.source.node === nodeId && interaction.source.port === id;\n const isCandidate =\n interaction.candidate !== null &&\n interaction.candidate.node === nodeId &&\n interaction.candidate.port === id;\n if (!isSource && !isCandidate) return EMPTY_VISUAL;\n return {\n isSource,\n isCandidate,\n isInvalid: isCandidate && interaction.invalid,\n isHovered: false,\n };\n },\n visualEqual\n );\n\n const hoverState = useStoreSlice(\n store.subscribeHover,\n store.getHover,\n hover => ({\n ...EMPTY_VISUAL,\n isHovered:\n hover.hoveredPort !== null &&\n hover.hoveredPort.node === nodeId &&\n hover.hoveredPort.port === id,\n }),\n visualEqual\n );\n\n const isHovered = hoverState.isHovered;\n const isSource = visual.isSource;\n const isCandidate = visual.isCandidate;\n const isInvalid = visual.isInvalid;\n\n // ── DOM measurement → store ──\n //\n // Run synchronously before paint so first frame's edges anchor at the\n // correct point. `useResizeObserver` picks up later size changes on the\n // port itself, and the per-node layout-version subscription below picks\n // up layout shifts inside the node body that move the port without\n // resizing it (e.g. a sibling row expands).\n //\n // `closest('[data-node-id]:not([data-port-id])')` skips the slot itself\n // — the slot wrapper carries `data-node-id` too (so connection-drop\n // hit-tests can walk up from any descendant), so a plain `[data-node-id]`\n // would match the port and report position (~6, ~6) for every port.\n const measure = useCallback((): void => {\n // Inside a collapsed section the port is hidden; drop its registered\n // position so its edges hide too (re-registers on expand). The component\n // stays mounted, so no remount churn.\n if (collapsed) {\n store.removePortPosition(nodeId, id);\n return;\n }\n const el = elementRef.current;\n if (!el) return;\n const wrapper = el.closest('[data-node-id]:not([data-port-id])');\n if (!wrapper) return;\n const portRect = el.getBoundingClientRect();\n const nodeRect = wrapper.getBoundingClientRect();\n // Convert from screen pixels to node-local world units. `ViewportWorld`\n // applies `transform: scale(zoom)` to all node wrappers, so the rects\n // we just read are scaled by `zoom`. Dividing brings us back to the\n // un-scaled layout pixels, which are 1:1 with world units inside a node.\n const zoom = viewportStore.getTransform().zoom || 1;\n const x = (portRect.left + portRect.width / 2 - nodeRect.left) / zoom;\n const y = (portRect.top + portRect.height / 2 - nodeRect.top) / zoom;\n store.setPortPosition(nodeId, id, { x, y, side, dataType });\n }, [store, viewportStore, nodeId, id, side, dataType, collapsed]);\n\n // Re-measure triggers (the per-port `ResizeObserver` only fires when\n // the port's own size changes, which misses layout shifts inside the\n // node body that move the port without resizing it — e.g. a sibling\n // row expanding). Subscribing to the per-node measured size makes this\n // component re-render on every wrapper resize, and the layout effect\n // below re-runs the measurement.\n const getMeasuredForNode = useMemo(\n () => () => store.getMeasuredSize(nodeId),\n [store, nodeId]\n );\n const measuredSize = useSyncExternalStore(\n store.subscribeMeasuredSizes,\n getMeasuredForNode\n );\n\n useLayoutEffect(() => {\n measure();\n }, [measure, measuredSize]);\n\n useResizeObserver(elementRef, () => {\n measure();\n });\n\n // Unregister on unmount / id change.\n useLayoutEffect(() => {\n return () => {\n store.removePortPosition(nodeId, id);\n };\n }, [store, nodeId, id]);\n\n // ── Hover wiring ──\n //\n // Update the store's `hoveredPort` slice on enter/leave so node bodies,\n // edges, and other ports can react. Library guards against duplicate\n // notifications when the value doesn't actually change.\n const onPointerEnter = useCallback((): void => {\n const current = store.getHover();\n if (current.hoveredPort?.node === nodeId && current.hoveredPort.port === id)\n return;\n store.setHover({ ...current, hoveredPort: { node: nodeId, port: id } });\n }, [store, nodeId, id]);\n\n const onPointerLeave = useCallback((): void => {\n const current = store.getHover();\n if (current.hoveredPort?.node !== nodeId || current.hoveredPort.port !== id)\n return;\n store.setHover({ ...current, hoveredPort: null });\n }, [store, nodeId, id]);\n\n const handlePointerDown = useCallback(\n (event: React.PointerEvent<HTMLSpanElement>): void => {\n onPortPointerDown(event, id);\n },\n [onPortPointerDown, id]\n );\n\n const hasCustomVisual = children !== undefined && children !== null;\n const isFilled = filled ?? connected;\n\n // Route the consumer's `color` into the slot via a CSS custom property so\n // the built-in visual (which paints with `currentColor`) picks it up,\n // while the source / candidate / invalid recipe variants can still\n // override `color` to keep connection-drag feedback visible.\n const portStyle: React.CSSProperties | undefined =\n color !== undefined\n ? { ['--etui-ng-port-color' as string]: color, ...style }\n : style;\n\n return (\n <span\n ref={elementRef}\n role=\"button\"\n tabIndex={-1}\n aria-label={label ?? `${side} port ${id}`}\n data-node-id={nodeId}\n data-port-id={id}\n data-port-side={side}\n data-port-data-type={dataType}\n data-port-source={isSource || undefined}\n data-port-candidate={isCandidate || undefined}\n data-port-invalid={isInvalid || undefined}\n data-port-hovered={isHovered || undefined}\n data-port-connected={connected || undefined}\n className={cx(\n portSlotRecipe({\n side,\n custom: hasCustomVisual,\n source: isSource,\n candidate: isCandidate,\n invalid: isInvalid,\n }),\n className\n )}\n style={portStyle}\n onPointerDown={handlePointerDown}\n onPointerEnter={onPointerEnter}\n onPointerLeave={onPointerLeave}\n >\n {hasCustomVisual ? (\n children\n ) : (\n <NodeGraphPortVisual shape={shape} filled={isFilled} />\n )}\n </span>\n );\n}\n\nexport const NodeGraphPort = React.memo(NodeGraphPortImpl);\nNodeGraphPort.displayName = 'NodeGraphPort';\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AA8BA;AACE;AACA;AACA;AACA;;AAGF;AACE;AAEE;AACA;AACA;AAEJ;AAEA;;;;;;;;;;;;;;;;;;;;;;AAsBG;AACH;;AAaE;AACA;AACA;AACA;;;;;;AAYA;AAII;AAAoC;AACpC;AAEA;AAEE;AACA;AACF;AAA+B;;;;AAI7B;AACA;;;AAMN;AAII;AACA;AAEE;AACA;;AAKN;AACA;AACA;AACA;;;;;;;;;;;;;AAcA;;;;;AAKI;;;AAGF;AACA;;;AAEA;;AACA;AACA;;;;;;AAMA;AACA;AACA;AACF;;;;;;;;;;AAkBE;AACF;AAEA;AACE;AACF;;;AAIE;AACE;AACF;;;;;;;AAQF;AACE;AACA;;;;AAKF;AACE;AACA;;AAEA;;AAGF;AAEI;AACF;;AAKF;;;;;AAMA;;;;;AAuBQ;AACA;AACA;AACA;;AAgBV;AAEO;AACP;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"NodeGraphPortVisual.js","sources":["../../../../../../src/components/editor/NodeGraph/NodeGraphPortVisual.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;AAiCA;AACA;AACA;AACA;AAEA;AAKE;;;AAGE;AACA;;;AAGA;;AAEA;AACE;AACF;;AAEE;AACF;AACA;AACE;;AAEN;AAEA;;;;;;;;;AASG;AACG;AAQJ;AACA;;AAcF;AAEA;;"}
1
+ {"version":3,"file":"NodeGraphPortVisual.js","sources":["src/components/editor/NodeGraph/NodeGraphPortVisual.tsx"],"sourcesContent":["'use client';\n\nimport React from 'react';\n\nimport type { NodeGraphPortShape } from './NodeGraph.types';\n\nexport interface NodeGraphPortVisualProps {\n /**\n * Handle shape. @default 'circle'\n */\n shape?: NodeGraphPortShape;\n /**\n * Stroke / fill colour. Defaults to `currentColor` so the parent\n * `<NodeGraph.Port>` can route its colour prop and interaction-state\n * colours (source / candidate / invalid) into the shape via the CSS\n * `color` cascade. Pass an explicit colour when using the visual\n * standalone (outside a port slot).\n */\n color?: string;\n /**\n * Filled (`true`) paints the interior; hollow (`false`) draws an outline\n * only — the standard \"wired vs unwired pin\" convention.\n * @default false\n */\n filled?: boolean;\n /**\n * Box size in CSS pixels. @default 14\n */\n size?: number;\n className?: string;\n style?: React.CSSProperties;\n}\n\n// All shapes are authored in a 16×16 user space and scaled to `size`, so a\n// single stroke width reads consistently across shapes.\nconst VIEW = 16;\nconst STROKE = 2;\n\nfunction shapeElement(\n shape: NodeGraphPortShape,\n stroke: string,\n fill: string\n): React.ReactElement {\n const common = {\n stroke,\n fill,\n strokeWidth: STROKE,\n strokeLinejoin: 'round' as const,\n };\n switch (shape) {\n case 'square':\n return <rect x={3} y={3} width={10} height={10} rx={1.5} {...common} />;\n case 'diamond':\n return <polygon points=\"8,2 14,8 8,14 2,8\" {...common} />;\n case 'triangle':\n // Right-pointing exec/flow arrow (UE Blueprint convention).\n return <polygon points=\"3,2.5 13.5,8 3,13.5\" {...common} />;\n case 'circle':\n default:\n return <circle cx={8} cy={8} r={5} {...common} />;\n }\n}\n\n/**\n * Presentational handle shape for a node-graph port. Rendered by\n * `<NodeGraph.Port>` when no `children` are supplied, and exported so\n * consumers can reuse the exact handle look inside fully custom port\n * visuals (e.g. a coloured ring beside a typed label).\n *\n * The shape paints with `currentColor` unless `color` is set, which lets\n * the port slot drive the colour from its `color` prop and override it on\n * the connection-drag states without this component knowing about them.\n */\nexport function NodeGraphPortVisual({\n shape = 'circle',\n color,\n filled = false,\n size = 14,\n className,\n style,\n}: NodeGraphPortVisualProps): React.ReactElement {\n const stroke = color ?? 'currentColor';\n const fill = filled ? (color ?? 'currentColor') : 'none';\n return (\n <svg\n width={size}\n height={size}\n viewBox={`0 0 ${VIEW} ${VIEW}`}\n className={className}\n style={{ display: 'block', overflow: 'visible', ...style }}\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n {shapeElement(shape, stroke, fill)}\n </svg>\n );\n}\n\nNodeGraphPortVisual.displayName = 'NodeGraphPortVisual';\n"],"names":[],"mappings":";;;AAiCA;AACA;AACA;AACA;AAEA;AAKE;;;AAGE;AACA;;;AAGA;;AAEA;AACE;AACF;;AAEE;AACF;AACA;AACE;;AAEN;AAEA;;;;;;;;;AASG;AACG;AAQJ;AACA;;AAcF;AAEA;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"NodeGraphSlots.js","sources":["../../../../../../src/components/editor/NodeGraph/NodeGraphSlots.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAUA;;;;;;;AAOG;AACH,MAAM,oBAAoB,GAA+C,MACvE,IAAI;MAEO,gBAAgB,GAAG,MAAM,CAAC,MAAM,CAAC,oBAAoB,EAAE;AAClE,IAAA,WAAW,EAAE,mBAAmB;IAChC,CAAC,eAAe,GAAG,SAAkB;AACtC,CAAA;AAGD;;;;AAIG;AACH,MAAM,uBAAuB,GAEjB,MAAM,IAAI;MAET,mBAAmB,GAAG,MAAM,CAAC,MAAM,CAAC,uBAAuB,EAAE;AACxE,IAAA,WAAW,EAAE,sBAAsB;IACnC,CAAC,eAAe,GAAG,YAAqB;AACzC,CAAA;AAGD;;;;;AAKG;AACH,MAAM,oBAAoB,GAA+C,MACvE,IAAI;MAEO,gBAAgB,GAAG,MAAM,CAAC,MAAM,CAAC,oBAAoB,EAAE;AAClE,IAAA,WAAW,EAAE,mBAAmB;IAChC,CAAC,eAAe,GAAG,SAAkB;AACtC,CAAA;AAGD;;;;;AAKG;AACH,MAAM,yBAAyB,GAEnB,MAAM,IAAI;MAET,qBAAqB,GAAG,MAAM,CAAC,MAAM,CAAC,yBAAyB,EAAE;AAC5E,IAAA,WAAW,EAAE,wBAAwB;IACrC,CAAC,eAAe,GAAG,eAAwB;AAC5C,CAAA;;;;"}
1
+ {"version":3,"file":"NodeGraphSlots.js","sources":["src/components/editor/NodeGraph/NodeGraphSlots.ts"],"sourcesContent":["import { NODE_GRAPH_SLOT } from './NodeGraph.types';\n\nimport type {\n NodeGraphBackgroundSlotProps,\n NodeGraphMinimapSlotProps,\n NodeGraphSlotMarker,\n NodeGraphSpawnPaletteSlotProps,\n NodeGraphToolbarSlotProps,\n} from './NodeGraph.types';\n\n/**\n * Marker behind `<NodeGraph.Minimap>` — returns `null` and carries a Symbol\n * the parent uses to identify it inside `children`. The actual minimap is\n * mounted by `NodeGraph` itself as `<NodeGraphMinimapInner>`.\n *\n * Pure marker, no hooks — kept out of any `'use client'` boundary so RSC\n * frameworks can keep the type-level slot identity on the server.\n */\nconst NodeGraphMinimapImpl: (props: NodeGraphMinimapSlotProps) => null = () =>\n null;\n\nexport const NodeGraphMinimap = Object.assign(NodeGraphMinimapImpl, {\n displayName: 'NodeGraph.Minimap',\n [NODE_GRAPH_SLOT]: 'minimap' as const,\n}) as unknown as ((props: NodeGraphMinimapSlotProps) => null) &\n NodeGraphSlotMarker & { displayName: string };\n\n/**\n * Marker behind `<NodeGraph.Background>` — see {@link NodeGraphMinimap} for\n * the rationale. The parent picks this up and mounts the background canvas\n * layer in the correct position in the layer stack.\n */\nconst NodeGraphBackgroundImpl: (\n props: NodeGraphBackgroundSlotProps\n) => null = () => null;\n\nexport const NodeGraphBackground = Object.assign(NodeGraphBackgroundImpl, {\n displayName: 'NodeGraph.Background',\n [NODE_GRAPH_SLOT]: 'background' as const,\n}) as unknown as ((props: NodeGraphBackgroundSlotProps) => null) &\n NodeGraphSlotMarker & { displayName: string };\n\n/**\n * Marker behind `<NodeGraph.Toolbar>` — picked up from `<NodeGraph>` children\n * and mounted into the viewport overlay layer at the requested\n * placement. Children render via `<NodeGraphToolbarInner>` which keeps\n * the toolbar positioned over the graph.\n */\nconst NodeGraphToolbarImpl: (props: NodeGraphToolbarSlotProps) => null = () =>\n null;\n\nexport const NodeGraphToolbar = Object.assign(NodeGraphToolbarImpl, {\n displayName: 'NodeGraph.Toolbar',\n [NODE_GRAPH_SLOT]: 'toolbar' as const,\n}) as unknown as ((props: NodeGraphToolbarSlotProps) => null) &\n NodeGraphSlotMarker & { displayName: string };\n\n/**\n * Marker behind `<NodeGraph.SpawnPalette>` — picked up by the parent\n * and mounted as a portal-rendered fuzzy-search palette. Auto-opens on\n * right-click of empty / group targets via the store's spawn-request\n * channel.\n */\nconst NodeGraphSpawnPaletteImpl: (\n props: NodeGraphSpawnPaletteSlotProps\n) => null = () => null;\n\nexport const NodeGraphSpawnPalette = Object.assign(NodeGraphSpawnPaletteImpl, {\n displayName: 'NodeGraph.SpawnPalette',\n [NODE_GRAPH_SLOT]: 'spawn-palette' as const,\n}) as unknown as ((props: NodeGraphSpawnPaletteSlotProps) => null) &\n NodeGraphSlotMarker & { displayName: string };\n"],"names":[],"mappings":";;AAUA;;;;;;;AAOG;AACH,MAAM,oBAAoB,GAA+C,MACvE,IAAI;MAEO,gBAAgB,GAAG,MAAM,CAAC,MAAM,CAAC,oBAAoB,EAAE;AAClE,IAAA,WAAW,EAAE,mBAAmB;IAChC,CAAC,eAAe,GAAG,SAAkB;AACtC,CAAA;AAGD;;;;AAIG;AACH,MAAM,uBAAuB,GAEjB,MAAM,IAAI;MAET,mBAAmB,GAAG,MAAM,CAAC,MAAM,CAAC,uBAAuB,EAAE;AACxE,IAAA,WAAW,EAAE,sBAAsB;IACnC,CAAC,eAAe,GAAG,YAAqB;AACzC,CAAA;AAGD;;;;;AAKG;AACH,MAAM,oBAAoB,GAA+C,MACvE,IAAI;MAEO,gBAAgB,GAAG,MAAM,CAAC,MAAM,CAAC,oBAAoB,EAAE;AAClE,IAAA,WAAW,EAAE,mBAAmB;IAChC,CAAC,eAAe,GAAG,SAAkB;AACtC,CAAA;AAGD;;;;;AAKG;AACH,MAAM,yBAAyB,GAEnB,MAAM,IAAI;MAET,qBAAqB,GAAG,MAAM,CAAC,MAAM,CAAC,yBAAyB,EAAE;AAC5E,IAAA,WAAW,EAAE,wBAAwB;IACrC,CAAC,eAAe,GAAG,eAAwB;AAC5C,CAAA;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"NodeGraphSpawnPalette.js","sources":["../../../../../../src/components/editor/NodeGraph/NodeGraphSpawnPalette.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;AAiBA;;;;;;;;;;;;;AAaG;AACG;AAQJ;;;;;;;AAWE;;;AAGA;AACF;AAEA;;;;;;;;AAQG;AACH;AAEA;;;;AAKA;AAEI;AACA;;AACA;;AAEA;AACE;AACA;;AAEF;;;;AAIA;AACA;;;AAiBN;;"}
1
+ {"version":3,"file":"NodeGraphSpawnPalette.js","sources":["src/components/editor/NodeGraph/NodeGraphSpawnPalette.tsx"],"sourcesContent":["'use client';\n\nimport React, { useCallback, useEffect, useMemo, useState } from 'react';\n\nimport { CommandPalette } from '@/components/feedback/CommandPalette/CommandPalette';\n\nimport { useNodeGraphStore } from './NodeGraphContext';\nimport { generateNodeId } from './nodeGraphIds';\n\nimport type {\n NodeGraphNode,\n NodeGraphSpawnContext,\n NodeGraphSpawnPaletteSlotProps,\n} from './NodeGraph.types';\nimport type { CommandItem } from '@/components/feedback/CommandPalette/CommandPalette.types';\nimport type { Point2D } from '@/components/primitives/canvas/canvas.types';\n\n/**\n * Live renderer for `<NodeGraph.SpawnPalette>`. Mounted by the parent\n * when the slot is present in `<NodeGraph>` children. Subscribes to the\n * store's spawn-request channel — the main `NodeGraph` component fires\n * the request when the user right-clicks empty space or a group, so\n * the consumer doesn't need to wire context-menu state through React.\n *\n * Selection on a template:\n * 1. Calls `template.build(worldPoint)` to get the node body\n * 2. Assigns a unique id\n * 3. Hands the full node to `onSpawn(node, ctx)` — typically appends\n * to the consumer's `nodes` state\n * 4. Closes the palette\n */\nexport function NodeGraphSpawnPaletteInner({\n templates,\n onSpawn,\n placeholder = 'Search nodes…',\n recentKey,\n width = 400,\n maxHeight = 360,\n}: NodeGraphSpawnPaletteSlotProps): React.ReactElement {\n const store = useNodeGraphStore();\n const [open, setOpen] = useState(false);\n const [spawnAt, setSpawnAt] = useState<{\n worldPoint: Point2D;\n screenPoint: Point2D;\n } | null>(null);\n\n // Listen for \"user wants to spawn a node here\" pings from the main\n // NodeGraph component (fired from its handleContextMenu for empty /\n // group targets). Multiple subscribers is fine — the store fans out.\n useEffect(() => {\n return store.subscribeSpawnRequest(info => {\n setSpawnAt(info);\n setOpen(true);\n });\n }, [store]);\n\n const items = useMemo<CommandItem[]>(() => {\n return templates.map(t => ({\n id: t.id,\n label: t.title,\n ...(t.subtitle !== undefined ? { description: t.subtitle } : {}),\n ...(t.group !== undefined ? { group: t.group } : {}),\n ...(t.keywords !== undefined ? { keywords: [...t.keywords] } : {}),\n ...(t.icon !== undefined ? { icon: t.icon } : {}),\n }));\n }, [templates]);\n\n const handleClose = useCallback(() => {\n setOpen(false);\n setSpawnAt(null);\n }, []);\n\n const handleSelect = useCallback(\n (item: CommandItem): void => {\n const template = templates.find(t => t.id === item.id);\n if (!template || !spawnAt) return;\n const worldPoint = spawnAt.worldPoint;\n const draft = template.build(worldPoint);\n const node: NodeGraphNode = {\n ...draft,\n id: generateNodeId(template.id),\n };\n const ctx: NodeGraphSpawnContext = {\n worldPoint,\n screenPoint: spawnAt.screenPoint,\n };\n onSpawn(node, ctx);\n handleClose();\n },\n [templates, spawnAt, onSpawn, handleClose]\n );\n\n return (\n <CommandPalette\n open={open}\n onClose={handleClose}\n items={items}\n onSelect={handleSelect}\n placeholder={placeholder}\n {...(recentKey !== undefined ? { recentKey } : {})}\n width={width}\n maxHeight={maxHeight}\n />\n );\n}\n"],"names":[],"mappings":";;;;;;;AAiBA;;;;;;;;;;;;;AAaG;AACG;AAQJ;;;;;;;AAWE;;;AAGA;AACF;AAEA;;;;;;;;AAQG;AACH;AAEA;;;;AAKA;AAEI;AACA;;AACA;;AAEA;AACE;AACA;;AAEF;;;;AAIA;AACA;;;AAiBN;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"NodeGraphStore.js","sources":["../../../../../../src/components/editor/NodeGraph/NodeGraphStore.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"NodeGraphStore.js","sources":["src/components/editor/NodeGraph/NodeGraphStore.ts"],"sourcesContent":["import type {\n NodeGraphEdge,\n NodeGraphNode,\n NodeGraphGroup,\n NodeGraphPortRef,\n NodeGraphPortSide,\n NodeGraphSelection,\n} from './NodeGraph.types';\nimport type { Point2D } from '@/components/primitives/canvas/canvas.types';\nimport type { WorldRect } from '@/components/primitives/viewport';\n\n/** Snapshot of the data slice — the canonical graph contents. */\nexport interface NodeGraphDataState {\n nodes: ReadonlyArray<NodeGraphNode>;\n edges: ReadonlyArray<NodeGraphEdge>;\n groups: ReadonlyArray<NodeGraphGroup>;\n defaultNodeSize: { width: number; height: number };\n}\n\n/**\n * A port's measured position registered by a `<NodeGraph.Port>` slot.\n * Coordinates are in **node-local pixels** (relative to the node wrapper's\n * top-left). Because the wrapper is positioned in world space but rendered\n * in CSS pixels at zoom = 1 (zoom is applied by the parent `<ViewportWorld>`\n * transform), these pixels are equivalent to node-local world units.\n */\nexport interface NodeGraphPortPosition {\n x: number;\n y: number;\n side: NodeGraphPortSide;\n dataType?: string;\n}\n\n/** Measured DOM size of a node wrapper, in node-local world units. */\nexport interface NodeGraphMeasuredSize {\n width: number;\n height: number;\n}\n\n/**\n * Snapshot of the interaction slice — the active gesture (if any) and its\n * scratch data. Designed so the edge/preview drawing layer can read everything\n * it needs in one slice subscription.\n */\n/** Eight points along a rectangle that can be grabbed to resize a group. */\nexport type NodeGraphGroupResizeHandle =\n | 'nw'\n | 'n'\n | 'ne'\n | 'e'\n | 'se'\n | 's'\n | 'sw'\n | 'w';\n\nexport type NodeGraphInteractionState =\n | { kind: 'idle' }\n | {\n kind: 'drag-nodes';\n /**\n * Ids of nodes being dragged together. Set (not Array) so per-node\n * subscribers can do O(1) membership checks in the hot per-frame\n * selector path — a Cartesian `Array.includes` was a measurable cost\n * at high node counts when the user dragged the whole selection.\n */\n nodeIds: ReadonlySet<string>;\n /** Pointer-down world position (start of the drag). */\n startWorld: Point2D;\n /** Cumulative drag delta in world units (snapped if grid active). */\n delta: Point2D;\n }\n | {\n kind: 'drag-groups';\n /** Ids of groups being dragged together. See {@link nodeIds} for why Set. */\n groupIds: ReadonlySet<string>;\n /**\n * Ids of nodes that were fully contained inside one of the dragged\n * groups at gesture start. They ride along with the group(s) and\n * receive the same drag delta — see `rectContains` in `nodeGraphMath`.\n */\n containedNodeIds: ReadonlySet<string>;\n /** Pointer-down world position. */\n startWorld: Point2D;\n /** Cumulative drag delta (snapped if grid active). */\n delta: Point2D;\n /**\n * True when the projected positions of the dragged groups would\n * overlap any other (non-dragged) group. The HTML overlay paints a\n * rejection state and the pointerup handler refuses to commit when\n * this is set.\n */\n blocked: boolean;\n }\n | {\n kind: 'resize-group';\n groupId: string;\n handle: NodeGraphGroupResizeHandle;\n /** Original bounds at the start of the resize. */\n startBounds: { x: number; y: number; width: number; height: number };\n /** Cumulative pointer delta in world units (snapped). */\n delta: Point2D;\n /** Set when the resized bounds would overlap another group. */\n blocked: boolean;\n }\n | {\n kind: 'connect';\n /**\n * Fixed endpoint the preview draws from. For a new connection this is\n * the port the drag started on; for a reconnect it's the *other* end\n * of the edge being edited (the one staying put).\n */\n source: NodeGraphPortRef;\n /** Current pointer position in world coordinates. */\n currentWorld: Point2D;\n /** Hovered candidate target port, or null when none. */\n candidate: NodeGraphPortRef | null;\n /** Whether the candidate is currently rejected by `isValidConnection`. */\n invalid: boolean;\n /**\n * Set while re-dragging an existing edge's endpoint. The edge is hidden\n * from the edge layer for the duration so only the preview shows, and\n * the drop either moves the endpoint, deletes the edge (detach), or —\n * on a click with no drag — selects it.\n */\n reconnectEdgeId?: string;\n /** Which end of `reconnectEdgeId` is being dragged. */\n reconnectEnd?: 'source' | 'target';\n }\n | {\n kind: 'marquee';\n /** Marquee start in world coordinates. */\n startWorld: Point2D;\n /** Current pointer position in world coordinates. */\n currentWorld: Point2D;\n /** Whether the additive modifier was held at gesture start. */\n additive: boolean;\n };\n\n/** Snapshot of the hover slice. */\nexport interface NodeGraphHoverState {\n hoveredNodeId: string | null;\n hoveredEdgeId: string | null;\n hoveredPort: NodeGraphPortRef | null;\n}\n\nconst EMPTY_DATA: NodeGraphDataState = {\n nodes: [],\n edges: [],\n groups: [],\n defaultNodeSize: { width: 180, height: 80 },\n};\n\nconst EMPTY_SELECTION: NodeGraphSelection = {\n nodes: [],\n edges: [],\n groups: [],\n};\n\nconst EMPTY_HOVER: NodeGraphHoverState = {\n hoveredNodeId: null,\n hoveredEdgeId: null,\n hoveredPort: null,\n};\n\nconst IDLE: NodeGraphInteractionState = { kind: 'idle' };\n\n/**\n * Hot-path runtime state for `<NodeGraph>` — graph data, selection,\n * interaction, hover. Each slice carries its own subscribe/get pair so\n * subscribers re-render only on relevant changes (e.g. the edge canvas\n * subscribes to data + interaction, individual node bodies subscribe only\n * to selection + drag delta for their own id).\n *\n * Mirrors `ViewportStore` / `MinimapStore` in structure.\n */\nexport class NodeGraphStore {\n private data: NodeGraphDataState = EMPTY_DATA;\n private selection: NodeGraphSelection = EMPTY_SELECTION;\n private interaction: NodeGraphInteractionState = IDLE;\n private hover: NodeGraphHoverState = EMPTY_HOVER;\n // `Map<id, NodeGraphNode>` mirror of `data.nodes` — rebuilt in `setData`.\n // Enables O(1) `getNodeById` lookups for hot paths (edge drawing,\n // pointer-driven drag handlers) that previously did O(n) `nodes.find`\n // per call.\n private nodeIndex = new Map<string, NodeGraphNode>();\n // Set of `\"${node}\\0${port}\"` keys for every port referenced by an edge\n // endpoint — recomputed in `setData` only when the edges reference\n // changes. Lets `<NodeGraph.Port>` slots auto-derive their \"connected\"\n // visual state without the consumer threading a parallel index down\n // through `renderNode`.\n private connectedPorts: ReadonlySet<string> = new Set<string>();\n\n // Map<nodeId, Map<portId, NodeGraphPortPosition>>.\n // Mutated in place by `<NodeGraph.Port>` slots on mount/resize. Listeners\n // are notified whenever any port's position, side, or dataType changes.\n private portPositions = new Map<string, Map<string, NodeGraphPortPosition>>();\n // Map<nodeId, NodeGraphMeasuredSize>. Populated by NodeGraphNodeView's\n // ResizeObserver — used by getNodeBox when node.width/height are absent.\n private measuredSizes = new Map<string, NodeGraphMeasuredSize>();\n\n private dataListeners = new Set<() => void>();\n private connectedPortsListeners = new Set<() => void>();\n private selectionListeners = new Set<() => void>();\n private interactionListeners = new Set<() => void>();\n // Per-node interaction subscriptions. Each `<NodeGraphNodeView>` registers\n // for its own id and is woken only when the interaction state changes in\n // a way that could affect that node's drag delta — i.e. the node was, or\n // now is, part of the active drag set. This cuts the notify fan-out from\n // O(all-nodes) to O(dragged-nodes) per pointermove flush, which is the\n // dominant cost when dragging a single node out of a large graph.\n private nodeInteractionListeners = new Map<string, Set<() => void>>();\n private hoverListeners = new Set<() => void>();\n private portPositionListeners = new Set<() => void>();\n private measuredSizeListeners = new Set<() => void>();\n\n // Monotonic counters used as `useSyncExternalStore` snapshots for the\n // notify-only port-positions / measured-sizes channels. A stable null\n // snapshot would let React skip the update via `Object.is(prev, next)`,\n // even when the subscription fired.\n private portPositionsVersion = 0;\n private measuredSizesVersion = 0;\n private spawnRequestListeners = new Set<\n (info: { worldPoint: Point2D; screenPoint: Point2D }) => void\n >();\n\n // ── Public read API ──\n\n getData = (): NodeGraphDataState => this.data;\n getSelection = (): NodeGraphSelection => this.selection;\n getInteraction = (): NodeGraphInteractionState => this.interaction;\n getHover = (): NodeGraphHoverState => this.hover;\n\n /**\n * The set of `\"${node}\\0${port}\"` keys that are referenced by at least\n * one edge endpoint. Reference is stable until the membership actually\n * changes, so it can back a `useSyncExternalStore` snapshot directly.\n */\n getConnectedPorts = (): ReadonlySet<string> => this.connectedPorts;\n\n /** True when the given port is referenced by at least one edge endpoint. */\n isPortConnected = (nodeId: string, portId: string): boolean => {\n return this.connectedPorts.has(portKey(nodeId, portId));\n };\n\n /**\n * O(1) node lookup by id, backed by an internal Map rebuilt on each\n * `setData`. Use this from hot paths instead of `data.nodes.find(...)`.\n */\n getNodeById = (id: string): NodeGraphNode | undefined => {\n return this.nodeIndex.get(id);\n };\n\n /**\n * Read the registered position of a single port. Returns `null` when the\n * port hasn't yet been measured (e.g. on first paint before\n * `useLayoutEffect` has run, or after the slot unmounted).\n */\n getPortPosition = (\n nodeId: string,\n portId: string\n ): NodeGraphPortPosition | null => {\n return this.portPositions.get(nodeId)?.get(portId) ?? null;\n };\n\n /** Read the measured DOM size of a node wrapper. */\n getMeasuredSize = (nodeId: string): NodeGraphMeasuredSize | null => {\n return this.measuredSizes.get(nodeId) ?? null;\n };\n\n /**\n * Monotonic snapshot of the port-positions channel — pass to\n * `useSyncExternalStore` alongside `subscribePortPositions` so React\n * actually re-renders consumers on every real change. Incremented\n * whenever a port position is added, updated, removed, or GC'd by\n * `setData`. Skipped on no-op writes.\n */\n getPortPositionsVersion = (): number => this.portPositionsVersion;\n\n /**\n * Monotonic snapshot of the measured-sizes channel — same role as\n * `getPortPositionsVersion`, for `subscribeMeasuredSizes`.\n */\n getMeasuredSizesVersion = (): number => this.measuredSizesVersion;\n\n // ── Subscriptions ──\n\n subscribeData = (cb: () => void): (() => void) => {\n this.dataListeners.add(cb);\n return () => {\n this.dataListeners.delete(cb);\n };\n };\n\n /**\n * Subscribe to the connected-ports channel — fires only when the set of\n * edge-referenced ports actually changes membership (not on every node\n * move). Backs the auto-`connected` state on `<NodeGraph.Port>`.\n */\n subscribeConnectedPorts = (cb: () => void): (() => void) => {\n this.connectedPortsListeners.add(cb);\n return () => {\n this.connectedPortsListeners.delete(cb);\n };\n };\n\n subscribeSelection = (cb: () => void): (() => void) => {\n this.selectionListeners.add(cb);\n return () => {\n this.selectionListeners.delete(cb);\n };\n };\n\n subscribeInteraction = (cb: () => void): (() => void) => {\n this.interactionListeners.add(cb);\n return () => {\n this.interactionListeners.delete(cb);\n };\n };\n\n /**\n * Subscribe to interaction changes that affect a specific node id. The\n * callback fires only when the node enters or leaves the active drag set\n * (drag-nodes `nodeIds`, drag-groups `containedNodeIds`) — every other\n * tick where the drag set is unchanged for this id is filtered out at the\n * store layer instead of waking the subscriber for a no-op compare.\n *\n * Use this from per-node React subscribers; the global\n * {@link subscribeInteraction} channel stays in place for canvas layers\n * and other consumers that care about every interaction change.\n */\n subscribeNodeInteraction = (nodeId: string, cb: () => void): (() => void) => {\n let set = this.nodeInteractionListeners.get(nodeId);\n if (!set) {\n set = new Set();\n this.nodeInteractionListeners.set(nodeId, set);\n }\n set.add(cb);\n return () => {\n const current = this.nodeInteractionListeners.get(nodeId);\n if (!current) return;\n current.delete(cb);\n if (current.size === 0) {\n this.nodeInteractionListeners.delete(nodeId);\n }\n };\n };\n\n subscribeHover = (cb: () => void): (() => void) => {\n this.hoverListeners.add(cb);\n return () => {\n this.hoverListeners.delete(cb);\n };\n };\n\n subscribePortPositions = (cb: () => void): (() => void) => {\n this.portPositionListeners.add(cb);\n return () => {\n this.portPositionListeners.delete(cb);\n };\n };\n\n subscribeMeasuredSizes = (cb: () => void): (() => void) => {\n this.measuredSizeListeners.add(cb);\n return () => {\n this.measuredSizeListeners.delete(cb);\n };\n };\n\n // ── Spawn-palette request channel ──\n //\n // Notification-only channel used by `<NodeGraph.SpawnPalette>` to\n // listen for \"user wants to spawn a node here\" events without forcing\n // the consumer to wire context-menu state through their own React\n // tree. The main `NodeGraph` component pumps this channel from its\n // `handleContextMenu` when the right-click target is `empty` or\n // `group` (i.e. a place where it makes sense to drop a new node).\n subscribeSpawnRequest = (\n cb: (info: { worldPoint: Point2D; screenPoint: Point2D }) => void\n ): (() => void) => {\n this.spawnRequestListeners.add(cb);\n return () => {\n this.spawnRequestListeners.delete(cb);\n };\n };\n\n requestSpawn(info: { worldPoint: Point2D; screenPoint: Point2D }): void {\n this.spawnRequestListeners.forEach(cb => {\n cb(info);\n });\n }\n\n // ── Mutators ──\n\n setData(next: NodeGraphDataState): void {\n if (\n next.nodes === this.data.nodes &&\n next.edges === this.data.edges &&\n next.groups === this.data.groups &&\n next.defaultNodeSize.width === this.data.defaultNodeSize.width &&\n next.defaultNodeSize.height === this.data.defaultNodeSize.height\n ) {\n return;\n }\n const edgesChanged = next.edges !== this.data.edges;\n const prevNodeIds = new Set(this.data.nodes.map(n => n.id));\n // Rebuild the id → node lookup in the same pass that collects the\n // next-frame id set, so GC and the index stay in sync without a\n // second iteration.\n this.nodeIndex.clear();\n const nextNodeIds = new Set<string>();\n for (const n of next.nodes) {\n nextNodeIds.add(n.id);\n this.nodeIndex.set(n.id, n);\n }\n // Garbage-collect port positions + measured sizes for nodes that have\n // been removed from the data. Slot unmount effects normally clear their\n // own entries, but if the node disappears in a single render tick (drop\n // from controlled state) the unmount and the data swap can race.\n let didMutatePortPositions = false;\n let didMutateMeasuredSizes = false;\n for (const id of prevNodeIds) {\n if (nextNodeIds.has(id)) continue;\n if (this.portPositions.delete(id)) didMutatePortPositions = true;\n if (this.measuredSizes.delete(id)) didMutateMeasuredSizes = true;\n }\n this.data = next;\n this.dataListeners.forEach(cb => {\n cb();\n });\n // Recompute the connected-ports index when edges changed, and notify\n // its dedicated channel only if the membership actually differs — an\n // edges array that was replaced but carries the same endpoints (e.g.\n // a label edit) leaves port \"connected\" state untouched.\n if (edgesChanged) {\n const nextConnected = computeConnectedPorts(next.edges);\n if (!connectedSetsEqual(nextConnected, this.connectedPorts)) {\n this.connectedPorts = nextConnected;\n this.connectedPortsListeners.forEach(cb => {\n cb();\n });\n }\n }\n if (didMutatePortPositions) {\n this.portPositionsVersion++;\n this.portPositionListeners.forEach(cb => {\n cb();\n });\n }\n if (didMutateMeasuredSizes) {\n this.measuredSizesVersion++;\n this.measuredSizeListeners.forEach(cb => {\n cb();\n });\n }\n }\n\n setSelection(next: NodeGraphSelection): void {\n if (selectionEqual(next, this.selection)) return;\n this.selection = next;\n this.selectionListeners.forEach(cb => {\n cb();\n });\n }\n\n setInteraction(next: NodeGraphInteractionState): void {\n if (interactionEqual(next, this.interaction)) return;\n const prev = this.interaction;\n this.interaction = next;\n\n // Global listeners: canvas layers, the main NodeGraph component (for\n // layer invalidation), and any consumer hook that wants every change.\n this.interactionListeners.forEach(cb => {\n cb();\n });\n\n // Per-node listeners: notify ids that are in the next or the prev drag\n // set. A node that *leaves* the drag set needs to clear its local\n // delta, so previously-affected ids must fire too even when they're no\n // longer in `next`.\n const prevIds = getDragAffectedNodeIds(prev);\n const nextIds = getDragAffectedNodeIds(next);\n if (prevIds.size === 0 && nextIds.size === 0) return;\n\n for (const id of nextIds) {\n this.nodeInteractionListeners.get(id)?.forEach(cb => {\n cb();\n });\n }\n for (const id of prevIds) {\n // Dedupe — already notified above when the node is in both sets.\n if (nextIds.has(id)) continue;\n this.nodeInteractionListeners.get(id)?.forEach(cb => {\n cb();\n });\n }\n }\n\n setHover(next: NodeGraphHoverState): void {\n if (hoverEqual(next, this.hover)) return;\n this.hover = next;\n this.hoverListeners.forEach(cb => {\n cb();\n });\n }\n\n /**\n * Register a port's measured position. Called by `<NodeGraph.Port>` from\n * a `useLayoutEffect` + `ResizeObserver`. No-ops when the incoming\n * position is identical to the cached one — protects edge layer from\n * redraw storms when nodes resize without porting any pin movement.\n */\n setPortPosition(\n nodeId: string,\n portId: string,\n next: NodeGraphPortPosition\n ): void {\n let perNode = this.portPositions.get(nodeId);\n if (!perNode) {\n perNode = new Map();\n this.portPositions.set(nodeId, perNode);\n }\n const prev = perNode.get(portId);\n if (\n prev?.x === next.x &&\n prev.y === next.y &&\n prev.side === next.side &&\n prev.dataType === next.dataType\n ) {\n return;\n }\n perNode.set(portId, next);\n this.portPositionsVersion++;\n this.portPositionListeners.forEach(cb => {\n cb();\n });\n }\n\n /** Remove a port registration. Called by `<NodeGraph.Port>` cleanup. */\n removePortPosition(nodeId: string, portId: string): void {\n const perNode = this.portPositions.get(nodeId);\n if (!perNode) return;\n if (!perNode.delete(portId)) return;\n if (perNode.size === 0) this.portPositions.delete(nodeId);\n this.portPositionsVersion++;\n this.portPositionListeners.forEach(cb => {\n cb();\n });\n }\n\n /**\n * Register / refresh the measured DOM size of a node wrapper. No-ops on\n * identical width+height.\n */\n setMeasuredSize(nodeId: string, next: NodeGraphMeasuredSize): void {\n const prev = this.measuredSizes.get(nodeId);\n if (prev?.width === next.width && prev.height === next.height) {\n return;\n }\n this.measuredSizes.set(nodeId, next);\n this.measuredSizesVersion++;\n this.measuredSizeListeners.forEach(cb => {\n cb();\n });\n }\n\n /** Clear the measured size of a node (called on unmount). */\n clearMeasuredSize(nodeId: string): void {\n if (!this.measuredSizes.delete(nodeId)) return;\n this.measuredSizesVersion++;\n this.measuredSizeListeners.forEach(cb => {\n cb();\n });\n }\n\n // ── Convenience selection helpers ──\n\n /** True when a node id is currently selected. */\n isNodeSelected(id: string): boolean {\n return this.selection.nodes.includes(id);\n }\n\n /** True when an edge id is currently selected. */\n isEdgeSelected(id: string): boolean {\n return this.selection.edges.includes(id);\n }\n\n /** True when a group id is currently selected. */\n isGroupSelected(id: string): boolean {\n return this.selection.groups.includes(id);\n }\n}\n\n// ─── Connected-ports index ───\n\n/**\n * Key for the connected-ports set. Uses a NUL separator so node / port ids\n * containing dots or dashes can't collide (`\"a.b\" + \"c\"` vs `\"a\" + \"b.c\"`).\n */\nfunction portKey(node: string, port: string): string {\n return `${node}\\u0000${port}`;\n}\n\n/** Build the set of `\"${node}\\0${port}\"` keys referenced by any edge. */\nfunction computeConnectedPorts(\n edges: ReadonlyArray<NodeGraphEdge>\n): Set<string> {\n const set = new Set<string>();\n for (const edge of edges) {\n set.add(portKey(edge.source.node, edge.source.port));\n set.add(portKey(edge.target.node, edge.target.port));\n }\n return set;\n}\n\nfunction connectedSetsEqual(\n a: ReadonlySet<string>,\n b: ReadonlySet<string>\n): boolean {\n if (a === b) return true;\n if (a.size !== b.size) return false;\n for (const key of a) {\n if (!b.has(key)) return false;\n }\n return true;\n}\n\n// ─── Equality helpers (shallow, identity-aware) ───\n\nfunction arrEqual<T>(a: ReadonlyArray<T>, b: ReadonlyArray<T>): boolean {\n if (a === b) return true;\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) return false;\n }\n return true;\n}\n\nfunction setEqual<T>(a: ReadonlySet<T>, b: ReadonlySet<T>): boolean {\n if (a === b) return true;\n if (a.size !== b.size) return false;\n for (const item of a) {\n if (!b.has(item)) return false;\n }\n return true;\n}\n\nconst EMPTY_NODE_ID_SET: ReadonlySet<string> = new Set<string>();\n\n/**\n * Node ids whose drag delta could be affected by the given interaction\n * state — used by `setInteraction` to fan out per-node notifications.\n * Idle / connect / marquee / resize-group don't move nodes, so they\n * return the empty set (no per-node subscriber needs waking).\n */\nfunction getDragAffectedNodeIds(\n state: NodeGraphInteractionState\n): ReadonlySet<string> {\n if (state.kind === 'drag-nodes') return state.nodeIds;\n if (state.kind === 'drag-groups') return state.containedNodeIds;\n return EMPTY_NODE_ID_SET;\n}\n\nfunction selectionEqual(a: NodeGraphSelection, b: NodeGraphSelection): boolean {\n return (\n arrEqual(a.nodes, b.nodes) &&\n arrEqual(a.edges, b.edges) &&\n arrEqual(a.groups, b.groups)\n );\n}\n\nfunction pointEqual(a: Point2D, b: Point2D): boolean {\n return a.x === b.x && a.y === b.y;\n}\n\nfunction portRefEqual(\n a: NodeGraphPortRef | null,\n b: NodeGraphPortRef | null\n): boolean {\n if (a === b) return true;\n if (!a || !b) return false;\n return a.node === b.node && a.port === b.port;\n}\n\nfunction interactionEqual(\n a: NodeGraphInteractionState,\n b: NodeGraphInteractionState\n): boolean {\n if (a === b) return true;\n if (a.kind !== b.kind) return false;\n switch (a.kind) {\n case 'idle':\n return true;\n case 'drag-nodes': {\n const bx = b as Extract<\n NodeGraphInteractionState,\n { kind: 'drag-nodes' }\n >;\n return (\n setEqual(a.nodeIds, bx.nodeIds) &&\n pointEqual(a.startWorld, bx.startWorld) &&\n pointEqual(a.delta, bx.delta)\n );\n }\n case 'drag-groups': {\n const bx = b as Extract<\n NodeGraphInteractionState,\n { kind: 'drag-groups' }\n >;\n return (\n setEqual(a.groupIds, bx.groupIds) &&\n setEqual(a.containedNodeIds, bx.containedNodeIds) &&\n pointEqual(a.startWorld, bx.startWorld) &&\n pointEqual(a.delta, bx.delta) &&\n a.blocked === bx.blocked\n );\n }\n case 'resize-group': {\n const bx = b as Extract<\n NodeGraphInteractionState,\n { kind: 'resize-group' }\n >;\n return (\n a.groupId === bx.groupId &&\n a.handle === bx.handle &&\n a.startBounds.x === bx.startBounds.x &&\n a.startBounds.y === bx.startBounds.y &&\n a.startBounds.width === bx.startBounds.width &&\n a.startBounds.height === bx.startBounds.height &&\n pointEqual(a.delta, bx.delta) &&\n a.blocked === bx.blocked\n );\n }\n case 'connect': {\n const bx = b as Extract<NodeGraphInteractionState, { kind: 'connect' }>;\n return (\n portRefEqual(a.source, bx.source) &&\n pointEqual(a.currentWorld, bx.currentWorld) &&\n portRefEqual(a.candidate, bx.candidate) &&\n a.invalid === bx.invalid &&\n a.reconnectEdgeId === bx.reconnectEdgeId &&\n a.reconnectEnd === bx.reconnectEnd\n );\n }\n case 'marquee': {\n const bx = b as Extract<NodeGraphInteractionState, { kind: 'marquee' }>;\n return (\n pointEqual(a.startWorld, bx.startWorld) &&\n pointEqual(a.currentWorld, bx.currentWorld) &&\n a.additive === bx.additive\n );\n }\n default:\n return false;\n }\n}\n\nfunction hoverEqual(a: NodeGraphHoverState, b: NodeGraphHoverState): boolean {\n return (\n a.hoveredNodeId === b.hoveredNodeId &&\n a.hoveredEdgeId === b.hoveredEdgeId &&\n portRefEqual(a.hoveredPort, b.hoveredPort)\n );\n}\n\n/**\n * Compute the rectangle of a marquee interaction in world coordinates,\n * normalized so width/height are non-negative.\n */\nexport function marqueeWorldRect(\n state: Extract<NodeGraphInteractionState, { kind: 'marquee' }>\n): WorldRect {\n const x = Math.min(state.startWorld.x, state.currentWorld.x);\n const y = Math.min(state.startWorld.y, state.currentWorld.y);\n return {\n x,\n y,\n width: Math.abs(state.currentWorld.x - state.startWorld.x),\n height: Math.abs(state.currentWorld.y - state.startWorld.y),\n };\n}\n"],"names":[],"mappings":"AAiJA,MAAM,UAAU,GAAuB;AACrC,IAAA,KAAK,EAAE,EAAE;AACT,IAAA,KAAK,EAAE,EAAE;AACT,IAAA,MAAM,EAAE,EAAE;IACV,eAAe,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE;CAC5C;AAED,MAAM,eAAe,GAAuB;AAC1C,IAAA,KAAK,EAAE,EAAE;AACT,IAAA,KAAK,EAAE,EAAE;AACT,IAAA,MAAM,EAAE,EAAE;CACX;AAED,MAAM,WAAW,GAAwB;AACvC,IAAA,aAAa,EAAE,IAAI;AACnB,IAAA,aAAa,EAAE,IAAI;AACnB,IAAA,WAAW,EAAE,IAAI;CAClB;AAED,MAAM,IAAI,GAA8B,EAAE,IAAI,EAAE,MAAM,EAAE;AAExD;;;;;;;;AAQG;MACU,cAAc,CAAA;AAA3B,IAAA,WAAA,GAAA;QACU,IAAA,CAAA,IAAI,GAAuB,UAAU;QACrC,IAAA,CAAA,SAAS,GAAuB,eAAe;QAC/C,IAAA,CAAA,WAAW,GAA8B,IAAI;QAC7C,IAAA,CAAA,KAAK,GAAwB,WAAW;;;;;AAKxC,QAAA,IAAA,CAAA,SAAS,GAAG,IAAI,GAAG,EAAyB;;;;;;AAM5C,QAAA,IAAA,CAAA,cAAc,GAAwB,IAAI,GAAG,EAAU;;;;AAKvD,QAAA,IAAA,CAAA,aAAa,GAAG,IAAI,GAAG,EAA8C;;;AAGrE,QAAA,IAAA,CAAA,aAAa,GAAG,IAAI,GAAG,EAAiC;AAExD,QAAA,IAAA,CAAA,aAAa,GAAG,IAAI,GAAG,EAAc;AACrC,QAAA,IAAA,CAAA,uBAAuB,GAAG,IAAI,GAAG,EAAc;AAC/C,QAAA,IAAA,CAAA,kBAAkB,GAAG,IAAI,GAAG,EAAc;AAC1C,QAAA,IAAA,CAAA,oBAAoB,GAAG,IAAI,GAAG,EAAc;;;;;;;AAO5C,QAAA,IAAA,CAAA,wBAAwB,GAAG,IAAI,GAAG,EAA2B;AAC7D,QAAA,IAAA,CAAA,cAAc,GAAG,IAAI,GAAG,EAAc;AACtC,QAAA,IAAA,CAAA,qBAAqB,GAAG,IAAI,GAAG,EAAc;AAC7C,QAAA,IAAA,CAAA,qBAAqB,GAAG,IAAI,GAAG,EAAc;;;;;QAM7C,IAAA,CAAA,oBAAoB,GAAG,CAAC;QACxB,IAAA,CAAA,oBAAoB,GAAG,CAAC;AACxB,QAAA,IAAA,CAAA,qBAAqB,GAAG,IAAI,GAAG,EAEpC;;AAIH,QAAA,IAAA,CAAA,OAAO,GAAG,MAA0B,IAAI,CAAC,IAAI;AAC7C,QAAA,IAAA,CAAA,YAAY,GAAG,MAA0B,IAAI,CAAC,SAAS;AACvD,QAAA,IAAA,CAAA,cAAc,GAAG,MAAiC,IAAI,CAAC,WAAW;AAClE,QAAA,IAAA,CAAA,QAAQ,GAAG,MAA2B,IAAI,CAAC,KAAK;AAEhD;;;;AAIG;AACH,QAAA,IAAA,CAAA,iBAAiB,GAAG,MAA2B,IAAI,CAAC,cAAc;;AAGlE,QAAA,IAAA,CAAA,eAAe,GAAG,CAAC,MAAc,EAAE,MAAc,KAAa;AAC5D,YAAA,OAAO,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACzD,QAAA,CAAC;AAED;;;AAGG;AACH,QAAA,IAAA,CAAA,WAAW,GAAG,CAAC,EAAU,KAA+B;YACtD,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;AAC/B,QAAA,CAAC;AAED;;;;AAIG;AACH,QAAA,IAAA,CAAA,eAAe,GAAG,CAChB,MAAc,EACd,MAAc,KACkB;AAChC,YAAA,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI;AAC5D,QAAA,CAAC;;AAGD,QAAA,IAAA,CAAA,eAAe,GAAG,CAAC,MAAc,KAAkC;YACjE,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI;AAC/C,QAAA,CAAC;AAED;;;;;;AAMG;AACH,QAAA,IAAA,CAAA,uBAAuB,GAAG,MAAc,IAAI,CAAC,oBAAoB;AAEjE;;;AAGG;AACH,QAAA,IAAA,CAAA,uBAAuB,GAAG,MAAc,IAAI,CAAC,oBAAoB;;AAIjE,QAAA,IAAA,CAAA,aAAa,GAAG,CAAC,EAAc,KAAkB;AAC/C,YAAA,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;AAC1B,YAAA,OAAO,MAAK;AACV,gBAAA,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC;AAC/B,YAAA,CAAC;AACH,QAAA,CAAC;AAED;;;;AAIG;AACH,QAAA,IAAA,CAAA,uBAAuB,GAAG,CAAC,EAAc,KAAkB;AACzD,YAAA,IAAI,CAAC,uBAAuB,CAAC,GAAG,CAAC,EAAE,CAAC;AACpC,YAAA,OAAO,MAAK;AACV,gBAAA,IAAI,CAAC,uBAAuB,CAAC,MAAM,CAAC,EAAE,CAAC;AACzC,YAAA,CAAC;AACH,QAAA,CAAC;AAED,QAAA,IAAA,CAAA,kBAAkB,GAAG,CAAC,EAAc,KAAkB;AACpD,YAAA,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC;AAC/B,YAAA,OAAO,MAAK;AACV,gBAAA,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,EAAE,CAAC;AACpC,YAAA,CAAC;AACH,QAAA,CAAC;AAED,QAAA,IAAA,CAAA,oBAAoB,GAAG,CAAC,EAAc,KAAkB;AACtD,YAAA,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,EAAE,CAAC;AACjC,YAAA,OAAO,MAAK;AACV,gBAAA,IAAI,CAAC,oBAAoB,CAAC,MAAM,CAAC,EAAE,CAAC;AACtC,YAAA,CAAC;AACH,QAAA,CAAC;AAED;;;;;;;;;;AAUG;AACH,QAAA,IAAA,CAAA,wBAAwB,GAAG,CAAC,MAAc,EAAE,EAAc,KAAkB;YAC1E,IAAI,GAAG,GAAG,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,MAAM,CAAC;YACnD,IAAI,CAAC,GAAG,EAAE;AACR,gBAAA,GAAG,GAAG,IAAI,GAAG,EAAE;gBACf,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC;YAChD;AACA,YAAA,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;AACX,YAAA,OAAO,MAAK;gBACV,MAAM,OAAO,GAAG,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,MAAM,CAAC;AACzD,gBAAA,IAAI,CAAC,OAAO;oBAAE;AACd,gBAAA,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;AAClB,gBAAA,IAAI,OAAO,CAAC,IAAI,KAAK,CAAC,EAAE;AACtB,oBAAA,IAAI,CAAC,wBAAwB,CAAC,MAAM,CAAC,MAAM,CAAC;gBAC9C;AACF,YAAA,CAAC;AACH,QAAA,CAAC;AAED,QAAA,IAAA,CAAA,cAAc,GAAG,CAAC,EAAc,KAAkB;AAChD,YAAA,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC;AAC3B,YAAA,OAAO,MAAK;AACV,gBAAA,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC;AAChC,YAAA,CAAC;AACH,QAAA,CAAC;AAED,QAAA,IAAA,CAAA,sBAAsB,GAAG,CAAC,EAAc,KAAkB;AACxD,YAAA,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,CAAC;AAClC,YAAA,OAAO,MAAK;AACV,gBAAA,IAAI,CAAC,qBAAqB,CAAC,MAAM,CAAC,EAAE,CAAC;AACvC,YAAA,CAAC;AACH,QAAA,CAAC;AAED,QAAA,IAAA,CAAA,sBAAsB,GAAG,CAAC,EAAc,KAAkB;AACxD,YAAA,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,CAAC;AAClC,YAAA,OAAO,MAAK;AACV,gBAAA,IAAI,CAAC,qBAAqB,CAAC,MAAM,CAAC,EAAE,CAAC;AACvC,YAAA,CAAC;AACH,QAAA,CAAC;;;;;;;;;AAUD,QAAA,IAAA,CAAA,qBAAqB,GAAG,CACtB,EAAiE,KACjD;AAChB,YAAA,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,EAAE,CAAC;AAClC,YAAA,OAAO,MAAK;AACV,gBAAA,IAAI,CAAC,qBAAqB,CAAC,MAAM,CAAC,EAAE,CAAC;AACvC,YAAA,CAAC;AACH,QAAA,CAAC;IA+MH;AA7ME,IAAA,YAAY,CAAC,IAAmD,EAAA;AAC9D,QAAA,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,EAAE,IAAG;YACtC,EAAE,CAAC,IAAI,CAAC;AACV,QAAA,CAAC,CAAC;IACJ;;AAIA,IAAA,OAAO,CAAC,IAAwB,EAAA;QAC9B,IACE,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,IAAI,CAAC,KAAK;AAC9B,YAAA,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,IAAI,CAAC,KAAK;AAC9B,YAAA,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,IAAI,CAAC,MAAM;YAChC,IAAI,CAAC,eAAe,CAAC,KAAK,KAAK,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,KAAK;AAC9D,YAAA,IAAI,CAAC,eAAe,CAAC,MAAM,KAAK,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,MAAM,EAChE;YACA;QACF;QACA,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,IAAI,CAAC,KAAK;QACnD,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC;;;;AAI3D,QAAA,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE;AACtB,QAAA,MAAM,WAAW,GAAG,IAAI,GAAG,EAAU;AACrC,QAAA,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE;AAC1B,YAAA,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YACrB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC7B;;;;;QAKA,IAAI,sBAAsB,GAAG,KAAK;QAClC,IAAI,sBAAsB,GAAG,KAAK;AAClC,QAAA,KAAK,MAAM,EAAE,IAAI,WAAW,EAAE;AAC5B,YAAA,IAAI,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;gBAAE;AACzB,YAAA,IAAI,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC;gBAAE,sBAAsB,GAAG,IAAI;AAChE,YAAA,IAAI,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC;gBAAE,sBAAsB,GAAG,IAAI;QAClE;AACA,QAAA,IAAI,CAAC,IAAI,GAAG,IAAI;AAChB,QAAA,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,IAAG;AAC9B,YAAA,EAAE,EAAE;AACN,QAAA,CAAC,CAAC;;;;;QAKF,IAAI,YAAY,EAAE;YAChB,MAAM,aAAa,GAAG,qBAAqB,CAAC,IAAI,CAAC,KAAK,CAAC;YACvD,IAAI,CAAC,kBAAkB,CAAC,aAAa,EAAE,IAAI,CAAC,cAAc,CAAC,EAAE;AAC3D,gBAAA,IAAI,CAAC,cAAc,GAAG,aAAa;AACnC,gBAAA,IAAI,CAAC,uBAAuB,CAAC,OAAO,CAAC,EAAE,IAAG;AACxC,oBAAA,EAAE,EAAE;AACN,gBAAA,CAAC,CAAC;YACJ;QACF;QACA,IAAI,sBAAsB,EAAE;YAC1B,IAAI,CAAC,oBAAoB,EAAE;AAC3B,YAAA,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,EAAE,IAAG;AACtC,gBAAA,EAAE,EAAE;AACN,YAAA,CAAC,CAAC;QACJ;QACA,IAAI,sBAAsB,EAAE;YAC1B,IAAI,CAAC,oBAAoB,EAAE;AAC3B,YAAA,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,EAAE,IAAG;AACtC,gBAAA,EAAE,EAAE;AACN,YAAA,CAAC,CAAC;QACJ;IACF;AAEA,IAAA,YAAY,CAAC,IAAwB,EAAA;AACnC,QAAA,IAAI,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;YAAE;AAC1C,QAAA,IAAI,CAAC,SAAS,GAAG,IAAI;AACrB,QAAA,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,EAAE,IAAG;AACnC,YAAA,EAAE,EAAE;AACN,QAAA,CAAC,CAAC;IACJ;AAEA,IAAA,cAAc,CAAC,IAA+B,EAAA;AAC5C,QAAA,IAAI,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC;YAAE;AAC9C,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW;AAC7B,QAAA,IAAI,CAAC,WAAW,GAAG,IAAI;;;AAIvB,QAAA,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC,EAAE,IAAG;AACrC,YAAA,EAAE,EAAE;AACN,QAAA,CAAC,CAAC;;;;;AAMF,QAAA,MAAM,OAAO,GAAG,sBAAsB,CAAC,IAAI,CAAC;AAC5C,QAAA,MAAM,OAAO,GAAG,sBAAsB,CAAC,IAAI,CAAC;QAC5C,IAAI,OAAO,CAAC,IAAI,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,KAAK,CAAC;YAAE;AAE9C,QAAA,KAAK,MAAM,EAAE,IAAI,OAAO,EAAE;AACxB,YAAA,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,IAAG;AAClD,gBAAA,EAAE,EAAE;AACN,YAAA,CAAC,CAAC;QACJ;AACA,QAAA,KAAK,MAAM,EAAE,IAAI,OAAO,EAAE;;AAExB,YAAA,IAAI,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;gBAAE;AACrB,YAAA,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,IAAG;AAClD,gBAAA,EAAE,EAAE;AACN,YAAA,CAAC,CAAC;QACJ;IACF;AAEA,IAAA,QAAQ,CAAC,IAAyB,EAAA;AAChC,QAAA,IAAI,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC;YAAE;AAClC,QAAA,IAAI,CAAC,KAAK,GAAG,IAAI;AACjB,QAAA,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,IAAG;AAC/B,YAAA,EAAE,EAAE;AACN,QAAA,CAAC,CAAC;IACJ;AAEA;;;;;AAKG;AACH,IAAA,eAAe,CACb,MAAc,EACd,MAAc,EACd,IAA2B,EAAA;QAE3B,IAAI,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC;QAC5C,IAAI,CAAC,OAAO,EAAE;AACZ,YAAA,OAAO,GAAG,IAAI,GAAG,EAAE;YACnB,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC;QACzC;QACA,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;AAChC,QAAA,IACE,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC,CAAC;AAClB,YAAA,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;AACjB,YAAA,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI;AACvB,YAAA,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,QAAQ,EAC/B;YACA;QACF;AACA,QAAA,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC;QACzB,IAAI,CAAC,oBAAoB,EAAE;AAC3B,QAAA,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,EAAE,IAAG;AACtC,YAAA,EAAE,EAAE;AACN,QAAA,CAAC,CAAC;IACJ;;IAGA,kBAAkB,CAAC,MAAc,EAAE,MAAc,EAAA;QAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC;AAC9C,QAAA,IAAI,CAAC,OAAO;YAAE;AACd,QAAA,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC;YAAE;AAC7B,QAAA,IAAI,OAAO,CAAC,IAAI,KAAK,CAAC;AAAE,YAAA,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC;QACzD,IAAI,CAAC,oBAAoB,EAAE;AAC3B,QAAA,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,EAAE,IAAG;AACtC,YAAA,EAAE,EAAE;AACN,QAAA,CAAC,CAAC;IACJ;AAEA;;;AAGG;IACH,eAAe,CAAC,MAAc,EAAE,IAA2B,EAAA;QACzD,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC;AAC3C,QAAA,IAAI,IAAI,EAAE,KAAK,KAAK,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM,EAAE;YAC7D;QACF;QACA,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC;QACpC,IAAI,CAAC,oBAAoB,EAAE;AAC3B,QAAA,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,EAAE,IAAG;AACtC,YAAA,EAAE,EAAE;AACN,QAAA,CAAC,CAAC;IACJ;;AAGA,IAAA,iBAAiB,CAAC,MAAc,EAAA;QAC9B,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC;YAAE;QACxC,IAAI,CAAC,oBAAoB,EAAE;AAC3B,QAAA,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,EAAE,IAAG;AACtC,YAAA,EAAE,EAAE;AACN,QAAA,CAAC,CAAC;IACJ;;;AAKA,IAAA,cAAc,CAAC,EAAU,EAAA;QACvB,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;IAC1C;;AAGA,IAAA,cAAc,CAAC,EAAU,EAAA;QACvB,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;IAC1C;;AAGA,IAAA,eAAe,CAAC,EAAU,EAAA;QACxB,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;IAC3C;AACD;AAED;AAEA;;;AAGG;AACH,SAAS,OAAO,CAAC,IAAY,EAAE,IAAY,EAAA;AACzC,IAAA,OAAO,CAAA,EAAG,IAAI,CAAA,MAAA,EAAS,IAAI,EAAE;AAC/B;AAEA;AACA,SAAS,qBAAqB,CAC5B,KAAmC,EAAA;AAEnC,IAAA,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU;AAC7B,IAAA,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;AACxB,QAAA,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AACpD,QAAA,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACtD;AACA,IAAA,OAAO,GAAG;AACZ;AAEA,SAAS,kBAAkB,CACzB,CAAsB,EACtB,CAAsB,EAAA;IAEtB,IAAI,CAAC,KAAK,CAAC;AAAE,QAAA,OAAO,IAAI;AACxB,IAAA,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI;AAAE,QAAA,OAAO,KAAK;AACnC,IAAA,KAAK,MAAM,GAAG,IAAI,CAAC,EAAE;AACnB,QAAA,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;AAAE,YAAA,OAAO,KAAK;IAC/B;AACA,IAAA,OAAO,IAAI;AACb;AAEA;AAEA,SAAS,QAAQ,CAAI,CAAmB,EAAE,CAAmB,EAAA;IAC3D,IAAI,CAAC,KAAK,CAAC;AAAE,QAAA,OAAO,IAAI;AACxB,IAAA,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;AAAE,QAAA,OAAO,KAAK;AACvC,IAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;QACjC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAAE,YAAA,OAAO,KAAK;IACjC;AACA,IAAA,OAAO,IAAI;AACb;AAEA,SAAS,QAAQ,CAAI,CAAiB,EAAE,CAAiB,EAAA;IACvD,IAAI,CAAC,KAAK,CAAC;AAAE,QAAA,OAAO,IAAI;AACxB,IAAA,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI;AAAE,QAAA,OAAO,KAAK;AACnC,IAAA,KAAK,MAAM,IAAI,IAAI,CAAC,EAAE;AACpB,QAAA,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;AAAE,YAAA,OAAO,KAAK;IAChC;AACA,IAAA,OAAO,IAAI;AACb;AAEA,MAAM,iBAAiB,GAAwB,IAAI,GAAG,EAAU;AAEhE;;;;;AAKG;AACH,SAAS,sBAAsB,CAC7B,KAAgC,EAAA;AAEhC,IAAA,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY;QAAE,OAAO,KAAK,CAAC,OAAO;AACrD,IAAA,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa;QAAE,OAAO,KAAK,CAAC,gBAAgB;AAC/D,IAAA,OAAO,iBAAiB;AAC1B;AAEA,SAAS,cAAc,CAAC,CAAqB,EAAE,CAAqB,EAAA;IAClE,QACE,QAAQ,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC;QAC1B,QAAQ,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC;QAC1B,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;AAEhC;AAEA,SAAS,UAAU,CAAC,CAAU,EAAE,CAAU,EAAA;AACxC,IAAA,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AACnC;AAEA,SAAS,YAAY,CACnB,CAA0B,EAC1B,CAA0B,EAAA;IAE1B,IAAI,CAAC,KAAK,CAAC;AAAE,QAAA,OAAO,IAAI;AACxB,IAAA,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AAAE,QAAA,OAAO,KAAK;AAC1B,IAAA,OAAO,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI;AAC/C;AAEA,SAAS,gBAAgB,CACvB,CAA4B,EAC5B,CAA4B,EAAA;IAE5B,IAAI,CAAC,KAAK,CAAC;AAAE,QAAA,OAAO,IAAI;AACxB,IAAA,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI;AAAE,QAAA,OAAO,KAAK;AACnC,IAAA,QAAQ,CAAC,CAAC,IAAI;AACZ,QAAA,KAAK,MAAM;AACT,YAAA,OAAO,IAAI;QACb,KAAK,YAAY,EAAE;YACjB,MAAM,EAAE,GAAG,CAGV;YACD,QACE,QAAQ,CAAC,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC;gBAC/B,UAAU,CAAC,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC;gBACvC,UAAU,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC;QAEjC;QACA,KAAK,aAAa,EAAE;YAClB,MAAM,EAAE,GAAG,CAGV;YACD,QACE,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC;gBACjC,QAAQ,CAAC,CAAC,CAAC,gBAAgB,EAAE,EAAE,CAAC,gBAAgB,CAAC;gBACjD,UAAU,CAAC,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC;gBACvC,UAAU,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC;AAC7B,gBAAA,CAAC,CAAC,OAAO,KAAK,EAAE,CAAC,OAAO;QAE5B;QACA,KAAK,cAAc,EAAE;YACnB,MAAM,EAAE,GAAG,CAGV;AACD,YAAA,QACE,CAAC,CAAC,OAAO,KAAK,EAAE,CAAC,OAAO;AACxB,gBAAA,CAAC,CAAC,MAAM,KAAK,EAAE,CAAC,MAAM;gBACtB,CAAC,CAAC,WAAW,CAAC,CAAC,KAAK,EAAE,CAAC,WAAW,CAAC,CAAC;gBACpC,CAAC,CAAC,WAAW,CAAC,CAAC,KAAK,EAAE,CAAC,WAAW,CAAC,CAAC;gBACpC,CAAC,CAAC,WAAW,CAAC,KAAK,KAAK,EAAE,CAAC,WAAW,CAAC,KAAK;gBAC5C,CAAC,CAAC,WAAW,CAAC,MAAM,KAAK,EAAE,CAAC,WAAW,CAAC,MAAM;gBAC9C,UAAU,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC;AAC7B,gBAAA,CAAC,CAAC,OAAO,KAAK,EAAE,CAAC,OAAO;QAE5B;QACA,KAAK,SAAS,EAAE;YACd,MAAM,EAAE,GAAG,CAA4D;YACvE,QACE,YAAY,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC;gBACjC,UAAU,CAAC,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,YAAY,CAAC;gBAC3C,YAAY,CAAC,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC;AACvC,gBAAA,CAAC,CAAC,OAAO,KAAK,EAAE,CAAC,OAAO;AACxB,gBAAA,CAAC,CAAC,eAAe,KAAK,EAAE,CAAC,eAAe;AACxC,gBAAA,CAAC,CAAC,YAAY,KAAK,EAAE,CAAC,YAAY;QAEtC;QACA,KAAK,SAAS,EAAE;YACd,MAAM,EAAE,GAAG,CAA4D;YACvE,QACE,UAAU,CAAC,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC;gBACvC,UAAU,CAAC,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,YAAY,CAAC;AAC3C,gBAAA,CAAC,CAAC,QAAQ,KAAK,EAAE,CAAC,QAAQ;QAE9B;AACA,QAAA;AACE,YAAA,OAAO,KAAK;;AAElB;AAEA,SAAS,UAAU,CAAC,CAAsB,EAAE,CAAsB,EAAA;AAChE,IAAA,QACE,CAAC,CAAC,aAAa,KAAK,CAAC,CAAC,aAAa;AACnC,QAAA,CAAC,CAAC,aAAa,KAAK,CAAC,CAAC,aAAa;QACnC,YAAY,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,WAAW,CAAC;AAE9C;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"NodeGraphToolbar.js","sources":["../../../../../../src/components/editor/NodeGraph/NodeGraphToolbar.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;;;;AAkBA;;;;;;;;AAQG;AACG;AAQJ;;;AAMM;AACD;;AAGD;AAKN;AAWM;;;AAYI;AAIV;AA2BM;AAUJ;AACA;AACA;AACE;AACA;;;;;;AAsBJ;AAWM;AAUJ;AACA;;;AAOA;AACE;AACA;AACA;;;;AAGA;;;;;;AAuBJ;AAQA;AAIE;AACA;;AAEA;AACA;AACE;AACA;;AAEF;;;AAGF;AAEM;AAUJ;AACA;AAKM;AACF;AAUN;AAEM;AAUJ;AACA;AAKM;AACF;AAUN;AAEA;AACM;AASJ;AACA;AAKM;AACF;AAUN;;"}
1
+ {"version":3,"file":"NodeGraphToolbar.js","sources":["src/components/editor/NodeGraph/NodeGraphToolbar.tsx"],"sourcesContent":["'use client';\n\nimport React, { useCallback } from 'react';\n\nimport { Button } from '@/components/primitives/Button';\nimport { useViewportStore } from '@/components/primitives/viewport/ViewportContext';\nimport { cx } from '@/utils/cx';\n\nimport {\n nodeGraphToolbarRecipe,\n nodeGraphToolbarSeparatorStyle,\n} from './NodeGraph.css';\nimport { useNodeGraphStore } from './NodeGraphContext';\nimport { computeNodesBounds } from './nodeGraphMath';\nimport { useStoreSlice } from './useStoreSlice';\n\nimport type { NodeGraphToolbarSlotProps } from './NodeGraph.types';\n\n/**\n * Live renderer for `<NodeGraph.Toolbar>`. Mounted inside the\n * `<ViewportOverlay>` so the toolbar sits above the graph but ignores\n * pan/zoom (toolbar buttons stay anchored to a viewport corner).\n *\n * Pointer events are auto-handled — the wrapper enables them so clicks\n * on toolbar buttons don't fall through to the underlying graph (which\n * would start a marquee selection).\n */\nexport function NodeGraphToolbarInner({\n placement = 'top-left',\n margin = 12,\n gap = 4,\n className,\n style,\n children,\n}: NodeGraphToolbarSlotProps): React.ReactElement {\n return (\n <div\n className={cx(nodeGraphToolbarRecipe({ placement }), className)}\n style={{\n margin,\n gap,\n ...style,\n }}\n onPointerDown={e => {\n e.stopPropagation();\n }}\n >\n {children}\n </div>\n );\n}\n\n/**\n * Visual separator for grouping toolbar buttons. Just a 1 px line; pass\n * `orientation=\"vertical\"` (default) inside a horizontal toolbar.\n */\nexport interface NodeGraphToolbarSeparatorProps {\n orientation?: 'horizontal' | 'vertical';\n className?: string;\n}\n\nexport function NodeGraphToolbarSeparator({\n orientation = 'vertical',\n className,\n}: NodeGraphToolbarSeparatorProps): React.ReactElement {\n return (\n <div\n role=\"separator\"\n aria-orientation={orientation}\n className={cx(nodeGraphToolbarSeparatorStyle, className)}\n style={\n orientation === 'horizontal'\n ? { width: '100%', height: 1 }\n : { width: 1, height: 18 }\n }\n />\n );\n}\n\n// ─── Action buttons ────────────────────────────────────────────────\n\ninterface CommonButtonProps {\n /** Override the label text. */\n label?: React.ReactNode;\n /** Override the icon (replaces the default). */\n icon?: React.ReactNode;\n /** Pass-through to the underlying `<Button>`. */\n size?: 'sm' | 'md' | 'lg';\n /** Pass-through variant. */\n variant?: 'default' | 'ghost' | 'filled';\n /** Extra class on the button. */\n className?: string;\n /** Inline style override. */\n style?: React.CSSProperties;\n /** Override the title / tooltip. */\n title?: string;\n}\n\n/** Fit all nodes inside the viewport. Calls the same code path as `ref.fitToContent`. */\nexport interface NodeGraphFitContentButtonProps extends CommonButtonProps {\n /** World-unit padding around the fitted bounds. @default 32 */\n padding?: number;\n}\n\nexport function NodeGraphFitContentButton({\n padding = 32,\n label = 'Fit',\n icon = '⊕',\n size = 'sm',\n variant = 'ghost',\n className,\n style,\n title = 'Fit all content in viewport',\n}: NodeGraphFitContentButtonProps): React.ReactElement {\n const ngStore = useNodeGraphStore();\n const vpStore = useViewportStore();\n const onClick = useCallback((): void => {\n const data = ngStore.getData();\n const bounds = computeNodesBounds(\n data.nodes,\n ngStore.getMeasuredSize,\n data.defaultNodeSize\n );\n if (bounds.width === 0 && bounds.height === 0) return;\n vpStore.handle.fitToContent(bounds, padding);\n }, [ngStore, vpStore, padding]);\n return (\n <Button\n size={size}\n variant={variant}\n onClick={onClick}\n className={className}\n style={style}\n title={title}\n aria-label={title}\n >\n {icon != null ? <span aria-hidden=\"true\">{icon}</span> : null}\n {label}\n </Button>\n );\n}\n\n/**\n * Fit the currently-selected nodes inside the viewport. Disabled when\n * the selection contains no nodes — reads the live selection slice so\n * the button's disabled state updates without consumer plumbing.\n */\nexport interface NodeGraphFitSelectionButtonProps extends CommonButtonProps {\n padding?: number;\n}\n\nexport function NodeGraphFitSelectionButton({\n padding = 64,\n label = 'Fit selection',\n icon = '◎',\n size = 'sm',\n variant = 'ghost',\n className,\n style,\n title = 'Fit selected nodes in viewport',\n}: NodeGraphFitSelectionButtonProps): React.ReactElement {\n const ngStore = useNodeGraphStore();\n const vpStore = useViewportStore();\n // Live disabled state — re-renders when the selection slice changes.\n const hasNodeSelection = useStoreSlice(\n ngStore.subscribeSelection,\n ngStore.getSelection,\n sel => sel.nodes.length > 0\n );\n const onClick = useCallback((): void => {\n const data = ngStore.getData();\n const sel = ngStore.getSelection();\n if (sel.nodes.length === 0) return;\n const selectedIds = new Set(sel.nodes);\n const selectedNodes = data.nodes.filter(n => selectedIds.has(n.id));\n const bounds = computeNodesBounds(\n selectedNodes,\n ngStore.getMeasuredSize,\n data.defaultNodeSize\n );\n if (bounds.width === 0 && bounds.height === 0) return;\n vpStore.handle.fitToContent(bounds, padding);\n }, [ngStore, vpStore, padding]);\n return (\n <Button\n size={size}\n variant={variant}\n onClick={onClick}\n disabled={!hasNodeSelection}\n className={className}\n style={style}\n title={title}\n aria-label={title}\n >\n {icon != null ? <span aria-hidden=\"true\">{icon}</span> : null}\n {label}\n </Button>\n );\n}\n\n/** Zoom in by a fixed factor (default 1.25×). */\nexport interface NodeGraphZoomButtonProps extends CommonButtonProps {\n /** Multiplier applied to the current zoom. @default 1.25 */\n factor?: number;\n}\n\nfunction applyZoomStep(\n vpStore: ReturnType<typeof useViewportStore>,\n factor: number\n): void {\n const t = vpStore.getTransform();\n const size = vpStore.getSize();\n // Anchor zoom at the viewport centre so the visible content stays put.\n const centerScreen = { x: size.width / 2, y: size.height / 2 };\n const centerWorld = {\n x: (centerScreen.x - t.x) / t.zoom,\n y: (centerScreen.y - t.y) / t.zoom,\n };\n const nextZoom = t.zoom * factor;\n // Reposition pan so `centerWorld` stays under `centerScreen` at the new zoom.\n vpStore.handle.centerOn(centerWorld, nextZoom);\n}\n\nexport function NodeGraphZoomInButton({\n factor = 1.25,\n label = '',\n icon = '+',\n size = 'sm',\n variant = 'ghost',\n className,\n style,\n title = 'Zoom in',\n}: NodeGraphZoomButtonProps): React.ReactElement {\n const vpStore = useViewportStore();\n return (\n <Button\n size={size}\n variant={variant}\n onClick={() => {\n applyZoomStep(vpStore, factor);\n }}\n className={className}\n style={style}\n title={title}\n aria-label={title}\n >\n {icon != null ? <span aria-hidden=\"true\">{icon}</span> : null}\n {label}\n </Button>\n );\n}\n\nexport function NodeGraphZoomOutButton({\n factor = 1.25,\n label = '',\n icon = '−',\n size = 'sm',\n variant = 'ghost',\n className,\n style,\n title = 'Zoom out',\n}: NodeGraphZoomButtonProps): React.ReactElement {\n const vpStore = useViewportStore();\n return (\n <Button\n size={size}\n variant={variant}\n onClick={() => {\n applyZoomStep(vpStore, 1 / factor);\n }}\n className={className}\n style={style}\n title={title}\n aria-label={title}\n >\n {icon != null ? <span aria-hidden=\"true\">{icon}</span> : null}\n {label}\n </Button>\n );\n}\n\n/** Reset zoom to 1× centred on the world origin. */\nexport function NodeGraphResetZoomButton({\n label = '1:1',\n icon,\n size = 'sm',\n variant = 'ghost',\n className,\n style,\n title = 'Reset zoom to 100%',\n}: CommonButtonProps): React.ReactElement {\n const vpStore = useViewportStore();\n return (\n <Button\n size={size}\n variant={variant}\n onClick={() => {\n vpStore.handle.centerOn({ x: 0, y: 0 }, 1);\n }}\n className={className}\n style={style}\n title={title}\n aria-label={title}\n >\n {icon != null ? <span aria-hidden=\"true\">{icon}</span> : null}\n {label}\n </Button>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;AAkBA;;;;;;;;AAQG;AACG;AAQJ;;;AAMM;AACD;;AAGD;AAKN;AAWM;;;AAYI;AAIV;AA2BM;AAUJ;AACA;AACA;AACE;AACA;;;;;;AAsBJ;AAWM;AAUJ;AACA;;;AAOA;AACE;AACA;AACA;;;;AAGA;;;;;;AAuBJ;AAQA;AAIE;AACA;;AAEA;AACA;AACE;AACA;;AAEF;;;AAGF;AAEM;AAUJ;AACA;AAKM;AACF;AAUN;AAEM;AAUJ;AACA;AAKM;AACF;AAUN;AAEA;AACM;AASJ;AACA;AAKM;AACF;AAUN;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"createTypeMatchValidator.js","sources":["../../../../../../src/components/editor/NodeGraph/createTypeMatchValidator.ts"],"sourcesContent":[null],"names":[],"mappings":"AAgCA;;;;;;;;;;;;;AAaG;AACG,SAAU,wBAAwB,CACtC,OAAmC,EAAA;AAMnC,IAAA,MAAM,UAAU,GAAG,IAAI,GAAG,CACxB,OAAO,EAAE,UAAU,IAAI,CAAC,aAAa,EAAE,aAAa,CAAC,CACtD;AACD,IAAA,MAAM,OAAO,GAAG,OAAO,EAAE,OAAO,IAAI,KAAK;AACzC,IAAA,MAAM,aAAa,GAAG,OAAO,EAAE,aAAa,IAAI,KAAK;AACrD,IAAA,MAAM,KAAK,GACT,OAAO,EAAE,KAAK;AACd,SAAC,CAAC,MAAM,EAAE,MAAM,KAAa;AAC3B,YAAA,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,SAAS;AAAE,gBAAA,OAAO,IAAI;YAC7D,IAAI,MAAM,KAAK,MAAM;AAAE,gBAAA,OAAO,IAAI;AAClC,YAAA,OAAO,MAAM,KAAK,OAAO,IAAI,MAAM,KAAK,OAAO;AACjD,QAAA,CAAC,CAAC;AAEJ,IAAA,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,KAAa;AACzC,QAAA,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,QAAQ;AAAE,YAAA,OAAO,KAAK;QACjD,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC;AAAE,YAAA,OAAO,KAAK;QACjD,OAAO,KAAK,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,cAAc,CAAC;AACxD,IAAA,CAAC;AACH;;;;"}
1
+ {"version":3,"file":"createTypeMatchValidator.js","sources":["src/components/editor/NodeGraph/createTypeMatchValidator.ts"],"sourcesContent":["import type {\n NodeGraphConnectionValidationInfo,\n NodeGraphPortRef,\n} from './NodeGraph.types';\n\nexport interface TypeMatchValidatorOptions {\n /**\n * Allowed `info.sideCombo` values (e.g. `'right->left'`). Defaults to both\n * horizontal directions so the user can start the drag from either end of\n * a wire. Pass `['right->left']` to force output→input only.\n * @default ['right->left', 'left->right']\n */\n directions?: ReadonlyArray<string>;\n /**\n * `dataType` token that connects to anything. @default 'any'\n */\n anyType?: string;\n /**\n * Allow connecting two ports on the same node. @default false\n */\n allowSameNode?: boolean;\n /**\n * Custom type comparison, replacing the default (equality + `anyType` +\n * \"untyped ports accept anything\"). Receives the resolved `dataType`s,\n * either of which may be `undefined` when the port declared none.\n */\n match?: (\n sourceDataType: string | undefined,\n targetDataType: string | undefined\n ) => boolean;\n}\n\n/**\n * Build an `isValidConnection` validator for the common \"connect ports of\n * matching `dataType`, in an allowed direction\" rule — the logic most node\n * editors hand-write. Drop the result straight onto `<NodeGraph>`:\n *\n * ```tsx\n * const isValidConnection = useMemo(() => createTypeMatchValidator(), []);\n * <NodeGraph isValidConnection={isValidConnection} />\n * ```\n *\n * The default `match` accepts a connection when either port is untyped, the\n * two `dataType`s are equal, or one side is the `anyType` token. Override\n * `match` for richer rules (subtype graphs, numeric coercion, etc.).\n */\nexport function createTypeMatchValidator(\n options?: TypeMatchValidatorOptions\n): (\n source: NodeGraphPortRef,\n target: NodeGraphPortRef,\n info: NodeGraphConnectionValidationInfo\n) => boolean {\n const directions = new Set(\n options?.directions ?? ['right->left', 'left->right']\n );\n const anyType = options?.anyType ?? 'any';\n const allowSameNode = options?.allowSameNode ?? false;\n const match =\n options?.match ??\n ((source, target): boolean => {\n if (source === undefined || target === undefined) return true;\n if (source === target) return true;\n return source === anyType || target === anyType;\n });\n\n return (_source, _target, info): boolean => {\n if (!allowSameNode && info.sameNode) return false;\n if (!directions.has(info.sideCombo)) return false;\n return match(info.sourceDataType, info.targetDataType);\n };\n}\n"],"names":[],"mappings":"AAgCA;;;;;;;;;;;;;AAaG;AACG,SAAU,wBAAwB,CACtC,OAAmC,EAAA;AAMnC,IAAA,MAAM,UAAU,GAAG,IAAI,GAAG,CACxB,OAAO,EAAE,UAAU,IAAI,CAAC,aAAa,EAAE,aAAa,CAAC,CACtD;AACD,IAAA,MAAM,OAAO,GAAG,OAAO,EAAE,OAAO,IAAI,KAAK;AACzC,IAAA,MAAM,aAAa,GAAG,OAAO,EAAE,aAAa,IAAI,KAAK;AACrD,IAAA,MAAM,KAAK,GACT,OAAO,EAAE,KAAK;AACd,SAAC,CAAC,MAAM,EAAE,MAAM,KAAa;AAC3B,YAAA,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,SAAS;AAAE,gBAAA,OAAO,IAAI;YAC7D,IAAI,MAAM,KAAK,MAAM;AAAE,gBAAA,OAAO,IAAI;AAClC,YAAA,OAAO,MAAM,KAAK,OAAO,IAAI,MAAM,KAAK,OAAO;AACjD,QAAA,CAAC,CAAC;AAEJ,IAAA,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,KAAa;AACzC,QAAA,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,QAAQ;AAAE,YAAA,OAAO,KAAK;QACjD,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC;AAAE,YAAA,OAAO,KAAK;QACjD,OAAO,KAAK,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,cAAc,CAAC;AACxD,IAAA,CAAC;AACH;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"nodeGraphActions.js","sources":["../../../../../../src/components/editor/NodeGraph/nodeGraphActions.ts"],"sourcesContent":[null],"names":[],"mappings":";;AASA;;;;AAIG;AACG,SAAU,oBAAoB,CAClC,KAAmC,EACnC,GAAqB,EAAA;IAErB,MAAM,GAAG,GAAa,EAAE;AACxB,IAAA,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;QACxB,IACE,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI;aAC9D,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,CAAC,EAChE;AACA,YAAA,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACnB;IACF;AACA,IAAA,OAAO,GAAG;AACZ;AAeA;;;;;;;;;;;;;AAaG;SACa,cAAc,CAC5B,KAAmC,EACnC,GAA0B,EAC1B,OAA+B,EAAA;AAE/B,IAAA,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE;AAClD,IAAA,MAAM,MAAM,GAAG,OAAO,EAAE,SAAS,KAAK,GAAG,IAAI,cAAc,CAAC,CAAA,EAAG,GAAG,CAAA,KAAA,CAAO,CAAC,CAAC;AAC3E,IAAA,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC;IAC3B,MAAM,MAAM,GAAoB,EAAE;AAClC,IAAA,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;QACxB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAAE;QAC1B,MAAM,CAAC,IAAI,CAAC;AACV,YAAA,GAAG,IAAI;AACP,YAAA,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;AACnB,YAAA,QAAQ,EAAE;gBACR,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC;gBAC7B,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC;AAC9B,aAAA;AACF,SAAA,CAAC;IACJ;AACA,IAAA,OAAO,MAAM;AACf;;;;"}
1
+ {"version":3,"file":"nodeGraphActions.js","sources":["src/components/editor/NodeGraph/nodeGraphActions.ts"],"sourcesContent":["import { generateNodeId } from './nodeGraphIds';\n\nimport type {\n NodeGraphEdge,\n NodeGraphNode,\n NodeGraphPortRef,\n} from './NodeGraph.types';\nimport type { Point2D } from '@/components/primitives/canvas/canvas.types';\n\n/**\n * Ids of every edge with an endpoint on the given port — i.e. all wires\n * connected to one socket. Use it to \"detach all\" or select a socket's wires\n * without maintaining a parallel index.\n */\nexport function edgesConnectedToPort(\n edges: ReadonlyArray<NodeGraphEdge>,\n ref: NodeGraphPortRef\n): string[] {\n const ids: string[] = [];\n for (const edge of edges) {\n if (\n (edge.source.node === ref.node && edge.source.port === ref.port) ||\n (edge.target.node === ref.node && edge.target.port === ref.port)\n ) {\n ids.push(edge.id);\n }\n }\n return ids;\n}\n\nexport interface DuplicateNodesOptions {\n /**\n * World-unit offset applied to each clone so it doesn't sit exactly on\n * top of its source. @default { x: 32, y: 32 }\n */\n offset?: Point2D;\n /**\n * Build the id for a clone from its source id. Defaults to a unique id\n * derived from `${sourceId}-copy`. Override to keep your own id scheme.\n */\n idFactory?: (sourceId: string) => string;\n}\n\n/**\n * Clone the nodes whose ids are listed in `ids`, offsetting each copy.\n * Pure — returns only the new node objects (not merged into the source\n * list), so callers stay in control of ordering and selection:\n *\n * ```ts\n * const copies = duplicateNodes(nodes, selection.nodes);\n * setNodes(prev => [...prev, ...copies]);\n * setSelection({ nodes: copies.map(n => n.id), edges: [], groups: [] });\n * ```\n *\n * Edges between duplicated nodes are intentionally not copied — wire that\n * in at the call site if your editor needs it.\n */\nexport function duplicateNodes(\n nodes: ReadonlyArray<NodeGraphNode>,\n ids: ReadonlyArray<string>,\n options?: DuplicateNodesOptions\n): NodeGraphNode[] {\n const offset = options?.offset ?? { x: 32, y: 32 };\n const makeId = options?.idFactory ?? (sid => generateNodeId(`${sid}-copy`));\n const wanted = new Set(ids);\n const copies: NodeGraphNode[] = [];\n for (const node of nodes) {\n if (!wanted.has(node.id)) continue;\n copies.push({\n ...node,\n id: makeId(node.id),\n position: {\n x: node.position.x + offset.x,\n y: node.position.y + offset.y,\n },\n });\n }\n return copies;\n}\n"],"names":[],"mappings":";;AASA;;;;AAIG;AACG,SAAU,oBAAoB,CAClC,KAAmC,EACnC,GAAqB,EAAA;IAErB,MAAM,GAAG,GAAa,EAAE;AACxB,IAAA,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;QACxB,IACE,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI;aAC9D,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,CAAC,EAChE;AACA,YAAA,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACnB;IACF;AACA,IAAA,OAAO,GAAG;AACZ;AAeA;;;;;;;;;;;;;AAaG;SACa,cAAc,CAC5B,KAAmC,EACnC,GAA0B,EAC1B,OAA+B,EAAA;AAE/B,IAAA,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE;AAClD,IAAA,MAAM,MAAM,GAAG,OAAO,EAAE,SAAS,KAAK,GAAG,IAAI,cAAc,CAAC,CAAA,EAAG,GAAG,CAAA,KAAA,CAAO,CAAC,CAAC;AAC3E,IAAA,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC;IAC3B,MAAM,MAAM,GAAoB,EAAE;AAClC,IAAA,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;QACxB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAAE;QAC1B,MAAM,CAAC,IAAI,CAAC;AACV,YAAA,GAAG,IAAI;AACP,YAAA,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;AACnB,YAAA,QAAQ,EAAE;gBACR,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC;gBAC7B,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC;AAC9B,aAAA;AACF,SAAA,CAAC;IACJ;AACA,IAAA,OAAO,MAAM;AACf;;;;"}