@flanksource/clicky-ui 0.3.45 → 0.3.47

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 (505) hide show
  1. package/NOTICE.md +11 -0
  2. package/README.md +22 -0
  3. package/dist/ai.cjs +13 -8
  4. package/dist/ai.cjs.map +1 -1
  5. package/dist/ai.js +7 -2
  6. package/dist/ai.js.map +1 -1
  7. package/dist/components/ErrorWrapper.cjs +2 -3
  8. package/dist/components/ErrorWrapper.cjs.map +1 -1
  9. package/dist/components/ErrorWrapper.d.ts.map +1 -1
  10. package/dist/components/ErrorWrapper.js +3 -4
  11. package/dist/components/ErrorWrapper.js.map +1 -1
  12. package/dist/data/AccessMark.cjs +23 -0
  13. package/dist/data/AccessMark.cjs.map +1 -0
  14. package/dist/data/AccessMark.d.ts +11 -0
  15. package/dist/data/AccessMark.d.ts.map +1 -0
  16. package/dist/data/AccessMark.js +23 -0
  17. package/dist/data/AccessMark.js.map +1 -0
  18. package/dist/data/Clicky.cjs +3 -0
  19. package/dist/data/Clicky.cjs.map +1 -1
  20. package/dist/data/Clicky.js +3 -0
  21. package/dist/data/Clicky.js.map +1 -1
  22. package/dist/data/CodeDiff.cjs +116 -23
  23. package/dist/data/CodeDiff.cjs.map +1 -1
  24. package/dist/data/CodeDiff.d.ts +26 -0
  25. package/dist/data/CodeDiff.d.ts.map +1 -1
  26. package/dist/data/CodeDiff.js +116 -23
  27. package/dist/data/CodeDiff.js.map +1 -1
  28. package/dist/data/FilterPill.cjs +15 -2
  29. package/dist/data/FilterPill.cjs.map +1 -1
  30. package/dist/data/FilterPill.d.ts +1 -1
  31. package/dist/data/FilterPill.d.ts.map +1 -1
  32. package/dist/data/FilterPill.js +15 -2
  33. package/dist/data/FilterPill.js.map +1 -1
  34. package/dist/data/GraphDiagram.cjs +65 -13
  35. package/dist/data/GraphDiagram.cjs.map +1 -1
  36. package/dist/data/GraphDiagram.d.ts +9 -2
  37. package/dist/data/GraphDiagram.d.ts.map +1 -1
  38. package/dist/data/GraphDiagram.js +66 -14
  39. package/dist/data/GraphDiagram.js.map +1 -1
  40. package/dist/data/GraphDiagramGroups.cjs +100 -0
  41. package/dist/data/GraphDiagramGroups.cjs.map +1 -0
  42. package/dist/data/GraphDiagramGroups.d.ts +24 -0
  43. package/dist/data/GraphDiagramGroups.d.ts.map +1 -0
  44. package/dist/data/GraphDiagramGroups.js +100 -0
  45. package/dist/data/GraphDiagramGroups.js.map +1 -0
  46. package/dist/data/GraphDiagramNodes.cjs +17 -31
  47. package/dist/data/GraphDiagramNodes.cjs.map +1 -1
  48. package/dist/data/GraphDiagramNodes.d.ts +6 -13
  49. package/dist/data/GraphDiagramNodes.d.ts.map +1 -1
  50. package/dist/data/GraphDiagramNodes.js +17 -31
  51. package/dist/data/GraphDiagramNodes.js.map +1 -1
  52. package/dist/data/LogViewer.cjs +27 -8
  53. package/dist/data/LogViewer.cjs.map +1 -1
  54. package/dist/data/LogViewer.d.ts +11 -3
  55. package/dist/data/LogViewer.d.ts.map +1 -1
  56. package/dist/data/LogViewer.js +27 -8
  57. package/dist/data/LogViewer.js.map +1 -1
  58. package/dist/data/Properties.cjs +2 -15
  59. package/dist/data/Properties.cjs.map +1 -1
  60. package/dist/data/Properties.d.ts +4 -0
  61. package/dist/data/Properties.d.ts.map +1 -1
  62. package/dist/data/Properties.js +2 -15
  63. package/dist/data/Properties.js.map +1 -1
  64. package/dist/data/PropertyValue.cjs +37 -0
  65. package/dist/data/PropertyValue.cjs.map +1 -0
  66. package/dist/data/PropertyValue.d.ts +6 -0
  67. package/dist/data/PropertyValue.d.ts.map +1 -0
  68. package/dist/data/PropertyValue.js +37 -0
  69. package/dist/data/PropertyValue.js.map +1 -0
  70. package/dist/data/Tree.cjs +4 -3
  71. package/dist/data/Tree.cjs.map +1 -1
  72. package/dist/data/Tree.d.ts +3 -1
  73. package/dist/data/Tree.d.ts.map +1 -1
  74. package/dist/data/Tree.js +4 -3
  75. package/dist/data/Tree.js.map +1 -1
  76. package/dist/data/TreeNode.cjs +1 -1
  77. package/dist/data/TreeNode.cjs.map +1 -1
  78. package/dist/data/TreeNode.d.ts.map +1 -1
  79. package/dist/data/TreeNode.js +1 -1
  80. package/dist/data/TreeNode.js.map +1 -1
  81. package/dist/data/ai/ChatFab.cjs +1 -1
  82. package/dist/data/ai/ChatFab.cjs.map +1 -1
  83. package/dist/data/ai/ChatFab.js +1 -1
  84. package/dist/data/ai/ChatFab.js.map +1 -1
  85. package/dist/data/ai/ChatWindow.cjs +106 -171
  86. package/dist/data/ai/ChatWindow.cjs.map +1 -1
  87. package/dist/data/ai/ChatWindow.d.ts +6 -2
  88. package/dist/data/ai/ChatWindow.d.ts.map +1 -1
  89. package/dist/data/ai/ChatWindow.header.cjs +104 -0
  90. package/dist/data/ai/ChatWindow.header.cjs.map +1 -0
  91. package/dist/data/ai/ChatWindow.header.d.ts +29 -0
  92. package/dist/data/ai/ChatWindow.header.d.ts.map +1 -0
  93. package/dist/data/ai/ChatWindow.header.js +104 -0
  94. package/dist/data/ai/ChatWindow.header.js.map +1 -0
  95. package/dist/data/ai/ChatWindow.js +107 -172
  96. package/dist/data/ai/ChatWindow.js.map +1 -1
  97. package/dist/data/ai/ChatWindow.placement.cjs +95 -0
  98. package/dist/data/ai/ChatWindow.placement.cjs.map +1 -0
  99. package/dist/data/ai/ChatWindow.placement.d.ts +32 -0
  100. package/dist/data/ai/ChatWindow.placement.d.ts.map +1 -0
  101. package/dist/data/ai/ChatWindow.placement.js +95 -0
  102. package/dist/data/ai/ChatWindow.placement.js.map +1 -0
  103. package/dist/data/ai/SessionChatComposer.cjs +3 -1
  104. package/dist/data/ai/SessionChatComposer.cjs.map +1 -1
  105. package/dist/data/ai/SessionChatComposer.d.ts +4 -1
  106. package/dist/data/ai/SessionChatComposer.d.ts.map +1 -1
  107. package/dist/data/ai/SessionChatComposer.js +3 -1
  108. package/dist/data/ai/SessionChatComposer.js.map +1 -1
  109. package/dist/data/ai/SessionInspector.cjs +68 -72
  110. package/dist/data/ai/SessionInspector.cjs.map +1 -1
  111. package/dist/data/ai/SessionInspector.composer-slot.cjs +8 -0
  112. package/dist/data/ai/SessionInspector.composer-slot.cjs.map +1 -0
  113. package/dist/data/ai/SessionInspector.composer-slot.d.ts +9 -0
  114. package/dist/data/ai/SessionInspector.composer-slot.d.ts.map +1 -0
  115. package/dist/data/ai/SessionInspector.composer-slot.js +8 -0
  116. package/dist/data/ai/SessionInspector.composer-slot.js.map +1 -0
  117. package/dist/data/ai/SessionInspector.d.ts +6 -1
  118. package/dist/data/ai/SessionInspector.d.ts.map +1 -1
  119. package/dist/data/ai/SessionInspector.js +69 -73
  120. package/dist/data/ai/SessionInspector.js.map +1 -1
  121. package/dist/data/ai/SessionInspector.legacy.cjs +41 -42
  122. package/dist/data/ai/SessionInspector.legacy.cjs.map +1 -1
  123. package/dist/data/ai/SessionInspector.legacy.d.ts.map +1 -1
  124. package/dist/data/ai/SessionInspector.legacy.js +41 -42
  125. package/dist/data/ai/SessionInspector.legacy.js.map +1 -1
  126. package/dist/data/ai/SessionInspector.remote-view.cjs +14 -9
  127. package/dist/data/ai/SessionInspector.remote-view.cjs.map +1 -1
  128. package/dist/data/ai/SessionInspector.remote-view.d.ts +6 -2
  129. package/dist/data/ai/SessionInspector.remote-view.d.ts.map +1 -1
  130. package/dist/data/ai/SessionInspector.remote-view.js +14 -9
  131. package/dist/data/ai/SessionInspector.remote-view.js.map +1 -1
  132. package/dist/data/ai/SessionInspector.remote.cjs +84 -16
  133. package/dist/data/ai/SessionInspector.remote.cjs.map +1 -1
  134. package/dist/data/ai/SessionInspector.remote.d.ts +42 -7
  135. package/dist/data/ai/SessionInspector.remote.d.ts.map +1 -1
  136. package/dist/data/ai/SessionInspector.remote.js +86 -18
  137. package/dist/data/ai/SessionInspector.remote.js.map +1 -1
  138. package/dist/data/ai/SessionInspector.transcript.cjs +5 -0
  139. package/dist/data/ai/SessionInspector.transcript.cjs.map +1 -1
  140. package/dist/data/ai/SessionInspector.transcript.d.ts.map +1 -1
  141. package/dist/data/ai/SessionInspector.transcript.js +5 -0
  142. package/dist/data/ai/SessionInspector.transcript.js.map +1 -1
  143. package/dist/data/ai/SessionTail.cjs +63 -0
  144. package/dist/data/ai/SessionTail.cjs.map +1 -0
  145. package/dist/data/ai/SessionTail.d.ts +14 -0
  146. package/dist/data/ai/SessionTail.d.ts.map +1 -0
  147. package/dist/data/ai/SessionTail.js +63 -0
  148. package/dist/data/ai/SessionTail.js.map +1 -0
  149. package/dist/data/ai/SessionViewer.cjs +10 -3
  150. package/dist/data/ai/SessionViewer.cjs.map +1 -1
  151. package/dist/data/ai/SessionViewer.d.ts +7 -1
  152. package/dist/data/ai/SessionViewer.d.ts.map +1 -1
  153. package/dist/data/ai/SessionViewer.js +10 -3
  154. package/dist/data/ai/SessionViewer.js.map +1 -1
  155. package/dist/data/ai/SessionViewer.unified.d.ts +14 -0
  156. package/dist/data/ai/SessionViewer.unified.d.ts.map +1 -1
  157. package/dist/data/ai/index.d.ts +4 -3
  158. package/dist/data/ai/index.d.ts.map +1 -1
  159. package/dist/data/ai/use-session-scroll.cjs +30 -6
  160. package/dist/data/ai/use-session-scroll.cjs.map +1 -1
  161. package/dist/data/ai/use-session-scroll.d.ts +7 -0
  162. package/dist/data/ai/use-session-scroll.d.ts.map +1 -1
  163. package/dist/data/ai/use-session-scroll.js +30 -6
  164. package/dist/data/ai/use-session-scroll.js.map +1 -1
  165. package/dist/data/call-graph/CallGraph.cjs +50 -31
  166. package/dist/data/call-graph/CallGraph.cjs.map +1 -1
  167. package/dist/data/call-graph/CallGraph.d.ts +10 -1
  168. package/dist/data/call-graph/CallGraph.d.ts.map +1 -1
  169. package/dist/data/call-graph/CallGraph.js +52 -33
  170. package/dist/data/call-graph/CallGraph.js.map +1 -1
  171. package/dist/data/call-graph/CallGraphMembers.cjs +5 -4
  172. package/dist/data/call-graph/CallGraphMembers.cjs.map +1 -1
  173. package/dist/data/call-graph/CallGraphMembers.d.ts +1 -1
  174. package/dist/data/call-graph/CallGraphMembers.d.ts.map +1 -1
  175. package/dist/data/call-graph/CallGraphMembers.js +5 -4
  176. package/dist/data/call-graph/CallGraphMembers.js.map +1 -1
  177. package/dist/data/call-graph/CallGraphToolbar.cjs +17 -5
  178. package/dist/data/call-graph/CallGraphToolbar.cjs.map +1 -1
  179. package/dist/data/call-graph/CallGraphToolbar.d.ts +10 -0
  180. package/dist/data/call-graph/CallGraphToolbar.d.ts.map +1 -1
  181. package/dist/data/call-graph/CallGraphToolbar.js +18 -6
  182. package/dist/data/call-graph/CallGraphToolbar.js.map +1 -1
  183. package/dist/data/call-graph/call-graph-model.cjs +169 -18
  184. package/dist/data/call-graph/call-graph-model.cjs.map +1 -1
  185. package/dist/data/call-graph/call-graph-model.d.ts +40 -4
  186. package/dist/data/call-graph/call-graph-model.d.ts.map +1 -1
  187. package/dist/data/call-graph/call-graph-model.js +170 -19
  188. package/dist/data/call-graph/call-graph-model.js.map +1 -1
  189. package/dist/data/call-graph/call-graph-vocabulary.cjs +19 -1
  190. package/dist/data/call-graph/call-graph-vocabulary.cjs.map +1 -1
  191. package/dist/data/call-graph/call-graph-vocabulary.d.ts +4 -0
  192. package/dist/data/call-graph/call-graph-vocabulary.d.ts.map +1 -1
  193. package/dist/data/call-graph/call-graph-vocabulary.js +19 -1
  194. package/dist/data/call-graph/call-graph-vocabulary.js.map +1 -1
  195. package/dist/data/call-graph/call-graph.fixtures.d.ts.map +1 -1
  196. package/dist/data/call-graph/index.d.ts +2 -2
  197. package/dist/data/call-graph/index.d.ts.map +1 -1
  198. package/dist/data/call-graph/types.cjs.map +1 -1
  199. package/dist/data/call-graph/types.d.ts +7 -2
  200. package/dist/data/call-graph/types.d.ts.map +1 -1
  201. package/dist/data/call-graph/types.js.map +1 -1
  202. package/dist/data/chat/Chat.cjs +1 -1
  203. package/dist/data/chat/Chat.cjs.map +1 -1
  204. package/dist/data/chat/Chat.js +1 -1
  205. package/dist/data/chat/Chat.js.map +1 -1
  206. package/dist/data/chat/ChatRuntimeToolbar.cjs +4 -4
  207. package/dist/data/chat/ChatRuntimeToolbar.cjs.map +1 -1
  208. package/dist/data/chat/ChatRuntimeToolbar.d.ts.map +1 -1
  209. package/dist/data/chat/ChatRuntimeToolbar.js +4 -4
  210. package/dist/data/chat/ChatRuntimeToolbar.js.map +1 -1
  211. package/dist/data/chat/PromptInput.cjs +4 -2
  212. package/dist/data/chat/PromptInput.cjs.map +1 -1
  213. package/dist/data/chat/PromptInput.d.ts +5 -1
  214. package/dist/data/chat/PromptInput.d.ts.map +1 -1
  215. package/dist/data/chat/PromptInput.js +4 -2
  216. package/dist/data/chat/PromptInput.js.map +1 -1
  217. package/dist/data/data-access.cjs +8 -0
  218. package/dist/data/data-access.cjs.map +1 -0
  219. package/dist/data/data-access.d.ts +5 -0
  220. package/dist/data/data-access.d.ts.map +1 -0
  221. package/dist/data/data-access.js +8 -0
  222. package/dist/data/data-access.js.map +1 -0
  223. package/dist/data/diagnostics/ErrorDetails.cjs +13 -2
  224. package/dist/data/diagnostics/ErrorDetails.cjs.map +1 -1
  225. package/dist/data/diagnostics/ErrorDetails.d.ts +3 -1
  226. package/dist/data/diagnostics/ErrorDetails.d.ts.map +1 -1
  227. package/dist/data/diagnostics/ErrorDetails.js +14 -3
  228. package/dist/data/diagnostics/ErrorDetails.js.map +1 -1
  229. package/dist/data/diagnostics/FrameSourceWindow.cjs +3 -2
  230. package/dist/data/diagnostics/FrameSourceWindow.cjs.map +1 -1
  231. package/dist/data/diagnostics/FrameSourceWindow.d.ts.map +1 -1
  232. package/dist/data/diagnostics/FrameSourceWindow.js +3 -2
  233. package/dist/data/diagnostics/FrameSourceWindow.js.map +1 -1
  234. package/dist/data/diagnostics/error-diagnostics.cjs +5 -0
  235. package/dist/data/diagnostics/error-diagnostics.cjs.map +1 -1
  236. package/dist/data/diagnostics/error-diagnostics.d.ts +1 -0
  237. package/dist/data/diagnostics/error-diagnostics.d.ts.map +1 -1
  238. package/dist/data/diagnostics/error-diagnostics.js +6 -1
  239. package/dist/data/diagnostics/error-diagnostics.js.map +1 -1
  240. package/dist/data/git/GitChangeList.cjs +6 -2
  241. package/dist/data/git/GitChangeList.cjs.map +1 -1
  242. package/dist/data/git/GitChangeList.d.ts +6 -1
  243. package/dist/data/git/GitChangeList.d.ts.map +1 -1
  244. package/dist/data/git/GitChangeList.js +6 -2
  245. package/dist/data/git/GitChangeList.js.map +1 -1
  246. package/dist/data/graph-columns-layout.cjs +47 -16
  247. package/dist/data/graph-columns-layout.cjs.map +1 -1
  248. package/dist/data/graph-columns-layout.d.ts +34 -0
  249. package/dist/data/graph-columns-layout.d.ts.map +1 -1
  250. package/dist/data/graph-columns-layout.js +47 -16
  251. package/dist/data/graph-columns-layout.js.map +1 -1
  252. package/dist/data/graph-diagram-model.cjs +5 -0
  253. package/dist/data/graph-diagram-model.cjs.map +1 -1
  254. package/dist/data/graph-diagram-model.d.ts +19 -0
  255. package/dist/data/graph-diagram-model.d.ts.map +1 -1
  256. package/dist/data/graph-diagram-model.js +5 -0
  257. package/dist/data/graph-diagram-model.js.map +1 -1
  258. package/dist/data/graph-group-window.cjs +60 -0
  259. package/dist/data/graph-group-window.cjs.map +1 -0
  260. package/dist/data/graph-group-window.d.ts +33 -0
  261. package/dist/data/graph-group-window.d.ts.map +1 -0
  262. package/dist/data/graph-group-window.js +60 -0
  263. package/dist/data/graph-group-window.js.map +1 -0
  264. package/dist/data/har/HarPanel.cjs +3 -1
  265. package/dist/data/har/HarPanel.cjs.map +1 -1
  266. package/dist/data/har/HarPanel.d.ts +4 -1
  267. package/dist/data/har/HarPanel.d.ts.map +1 -1
  268. package/dist/data/har/HarPanel.js +3 -1
  269. package/dist/data/har/HarPanel.js.map +1 -1
  270. package/dist/data/test-runner/Expectation.cjs +57 -0
  271. package/dist/data/test-runner/Expectation.cjs.map +1 -0
  272. package/dist/data/test-runner/Expectation.d.ts +19 -0
  273. package/dist/data/test-runner/Expectation.d.ts.map +1 -0
  274. package/dist/data/test-runner/Expectation.js +57 -0
  275. package/dist/data/test-runner/Expectation.js.map +1 -0
  276. package/dist/data/test-runner/MarkIcons.cjs +38 -0
  277. package/dist/data/test-runner/MarkIcons.cjs.map +1 -0
  278. package/dist/data/test-runner/MarkIcons.d.ts +15 -0
  279. package/dist/data/test-runner/MarkIcons.d.ts.map +1 -0
  280. package/dist/data/test-runner/MarkIcons.js +38 -0
  281. package/dist/data/test-runner/MarkIcons.js.map +1 -0
  282. package/dist/data/test-runner/TestDetailPanel.cjs +74 -42
  283. package/dist/data/test-runner/TestDetailPanel.cjs.map +1 -1
  284. package/dist/data/test-runner/TestDetailPanel.d.ts.map +1 -1
  285. package/dist/data/test-runner/TestDetailPanel.js +76 -44
  286. package/dist/data/test-runner/TestDetailPanel.js.map +1 -1
  287. package/dist/data/test-runner/TestFailureDetail.cjs +23 -27
  288. package/dist/data/test-runner/TestFailureDetail.cjs.map +1 -1
  289. package/dist/data/test-runner/TestFailureDetail.d.ts +2 -2
  290. package/dist/data/test-runner/TestFailureDetail.d.ts.map +1 -1
  291. package/dist/data/test-runner/TestFailureDetail.js +23 -27
  292. package/dist/data/test-runner/TestFailureDetail.js.map +1 -1
  293. package/dist/data/test-runner/TestFilterBar.cjs +87 -93
  294. package/dist/data/test-runner/TestFilterBar.cjs.map +1 -1
  295. package/dist/data/test-runner/TestFilterBar.d.ts +3 -2
  296. package/dist/data/test-runner/TestFilterBar.d.ts.map +1 -1
  297. package/dist/data/test-runner/TestFilterBar.js +89 -95
  298. package/dist/data/test-runner/TestFilterBar.js.map +1 -1
  299. package/dist/data/test-runner/TestRunSummary.cjs +35 -21
  300. package/dist/data/test-runner/TestRunSummary.cjs.map +1 -1
  301. package/dist/data/test-runner/TestRunSummary.d.ts.map +1 -1
  302. package/dist/data/test-runner/TestRunSummary.js +35 -21
  303. package/dist/data/test-runner/TestRunSummary.js.map +1 -1
  304. package/dist/data/test-runner/TestRunner.cjs +52 -30
  305. package/dist/data/test-runner/TestRunner.cjs.map +1 -1
  306. package/dist/data/test-runner/TestRunner.d.ts +3 -2
  307. package/dist/data/test-runner/TestRunner.d.ts.map +1 -1
  308. package/dist/data/test-runner/TestRunner.js +52 -30
  309. package/dist/data/test-runner/TestRunner.js.map +1 -1
  310. package/dist/data/test-runner/TestTree.cjs +5 -2
  311. package/dist/data/test-runner/TestTree.cjs.map +1 -1
  312. package/dist/data/test-runner/TestTree.d.ts +5 -2
  313. package/dist/data/test-runner/TestTree.d.ts.map +1 -1
  314. package/dist/data/test-runner/TestTree.js +5 -2
  315. package/dist/data/test-runner/TestTree.js.map +1 -1
  316. package/dist/data/test-runner/TestTreeNode.cjs +27 -19
  317. package/dist/data/test-runner/TestTreeNode.cjs.map +1 -1
  318. package/dist/data/test-runner/TestTreeNode.d.ts.map +1 -1
  319. package/dist/data/test-runner/TestTreeNode.js +28 -20
  320. package/dist/data/test-runner/TestTreeNode.js.map +1 -1
  321. package/dist/data/test-runner/adapter.cjs +11 -0
  322. package/dist/data/test-runner/adapter.cjs.map +1 -1
  323. package/dist/data/test-runner/adapter.d.ts +18 -7
  324. package/dist/data/test-runner/adapter.d.ts.map +1 -1
  325. package/dist/data/test-runner/adapter.js +11 -0
  326. package/dist/data/test-runner/adapter.js.map +1 -1
  327. package/dist/data/test-runner/copy.cjs +114 -0
  328. package/dist/data/test-runner/copy.cjs.map +1 -0
  329. package/dist/data/test-runner/copy.d.ts +47 -0
  330. package/dist/data/test-runner/copy.d.ts.map +1 -0
  331. package/dist/data/test-runner/copy.js +114 -0
  332. package/dist/data/test-runner/copy.js.map +1 -0
  333. package/dist/data/test-runner/index.d.ts +5 -2
  334. package/dist/data/test-runner/index.d.ts.map +1 -1
  335. package/dist/data/test-runner/marks.cjs +143 -0
  336. package/dist/data/test-runner/marks.cjs.map +1 -0
  337. package/dist/data/test-runner/marks.d.ts +30 -0
  338. package/dist/data/test-runner/marks.d.ts.map +1 -0
  339. package/dist/data/test-runner/marks.js +143 -0
  340. package/dist/data/test-runner/marks.js.map +1 -0
  341. package/dist/data/test-runner/status.cjs +27 -44
  342. package/dist/data/test-runner/status.cjs.map +1 -1
  343. package/dist/data/test-runner/status.d.ts +12 -3
  344. package/dist/data/test-runner/status.d.ts.map +1 -1
  345. package/dist/data/test-runner/status.js +27 -44
  346. package/dist/data/test-runner/status.js.map +1 -1
  347. package/dist/data/use-group-windows.cjs +50 -0
  348. package/dist/data/use-group-windows.cjs.map +1 -0
  349. package/dist/data/use-group-windows.d.ts +27 -0
  350. package/dist/data/use-group-windows.d.ts.map +1 -0
  351. package/dist/data/use-group-windows.js +50 -0
  352. package/dist/data/use-group-windows.js.map +1 -0
  353. package/dist/data/verification/adapterViews.cjs +16 -41
  354. package/dist/data/verification/adapterViews.cjs.map +1 -1
  355. package/dist/data/verification/adapterViews.d.ts.map +1 -1
  356. package/dist/data/verification/adapterViews.js +16 -41
  357. package/dist/data/verification/adapterViews.js.map +1 -1
  358. package/dist/data/verification/adapters.cjs +115 -3
  359. package/dist/data/verification/adapters.cjs.map +1 -1
  360. package/dist/data/verification/adapters.d.ts.map +1 -1
  361. package/dist/data/verification/adapters.js +115 -3
  362. package/dist/data/verification/adapters.js.map +1 -1
  363. package/dist/data/verification/verifyReportTests.cjs.map +1 -1
  364. package/dist/data/verification/verifyReportTests.js.map +1 -1
  365. package/dist/data/version-info.cjs +3 -3
  366. package/dist/data/version-info.js +3 -3
  367. package/dist/data.cjs +54 -3
  368. package/dist/data.cjs.map +1 -1
  369. package/dist/data.d.ts +6 -2
  370. package/dist/data.d.ts.map +1 -1
  371. package/dist/data.js +58 -7
  372. package/dist/data.js.map +1 -1
  373. package/dist/hooks/event-hub.cjs +229 -0
  374. package/dist/hooks/event-hub.cjs.map +1 -0
  375. package/dist/hooks/event-hub.d.ts +26 -0
  376. package/dist/hooks/event-hub.d.ts.map +1 -0
  377. package/dist/hooks/event-hub.js +229 -0
  378. package/dist/hooks/event-hub.js.map +1 -0
  379. package/dist/hooks.cjs +2 -0
  380. package/dist/hooks.cjs.map +1 -1
  381. package/dist/hooks.d.ts +1 -0
  382. package/dist/hooks.d.ts.map +1 -1
  383. package/dist/hooks.js +2 -0
  384. package/dist/hooks.js.map +1 -1
  385. package/dist/icons/components/UiLogoEslint.cjs +10 -0
  386. package/dist/icons/components/UiLogoEslint.cjs.map +1 -0
  387. package/dist/icons/components/UiLogoEslint.d.ts +9 -0
  388. package/dist/icons/components/UiLogoEslint.d.ts.map +1 -0
  389. package/dist/icons/components/UiLogoEslint.js +10 -0
  390. package/dist/icons/components/UiLogoEslint.js.map +1 -0
  391. package/dist/icons/components/UiLogoGo.cjs +10 -0
  392. package/dist/icons/components/UiLogoGo.cjs.map +1 -0
  393. package/dist/icons/components/UiLogoGo.d.ts +9 -0
  394. package/dist/icons/components/UiLogoGo.d.ts.map +1 -0
  395. package/dist/icons/components/UiLogoGo.js +10 -0
  396. package/dist/icons/components/UiLogoGo.js.map +1 -0
  397. package/dist/icons/components/UiLogoJest.cjs +10 -0
  398. package/dist/icons/components/UiLogoJest.cjs.map +1 -0
  399. package/dist/icons/components/UiLogoJest.d.ts +9 -0
  400. package/dist/icons/components/UiLogoJest.d.ts.map +1 -0
  401. package/dist/icons/components/UiLogoJest.js +10 -0
  402. package/dist/icons/components/UiLogoJest.js.map +1 -0
  403. package/dist/icons/components/UiLogoMarkdown.cjs +10 -0
  404. package/dist/icons/components/UiLogoMarkdown.cjs.map +1 -0
  405. package/dist/icons/components/UiLogoMarkdown.d.ts +9 -0
  406. package/dist/icons/components/UiLogoMarkdown.d.ts.map +1 -0
  407. package/dist/icons/components/UiLogoMarkdown.js +10 -0
  408. package/dist/icons/components/UiLogoMarkdown.js.map +1 -0
  409. package/dist/icons/components/UiLogoOxc.cjs +10 -0
  410. package/dist/icons/components/UiLogoOxc.cjs.map +1 -0
  411. package/dist/icons/components/UiLogoOxc.d.ts +9 -0
  412. package/dist/icons/components/UiLogoOxc.d.ts.map +1 -0
  413. package/dist/icons/components/UiLogoOxc.js +10 -0
  414. package/dist/icons/components/UiLogoOxc.js.map +1 -0
  415. package/dist/icons/components/UiLogoPlaywright.cjs +10 -0
  416. package/dist/icons/components/UiLogoPlaywright.cjs.map +1 -0
  417. package/dist/icons/components/UiLogoPlaywright.d.ts +9 -0
  418. package/dist/icons/components/UiLogoPlaywright.d.ts.map +1 -0
  419. package/dist/icons/components/UiLogoPlaywright.js +10 -0
  420. package/dist/icons/components/UiLogoPlaywright.js.map +1 -0
  421. package/dist/icons/components/UiLogoPython.cjs +10 -0
  422. package/dist/icons/components/UiLogoPython.cjs.map +1 -0
  423. package/dist/icons/components/UiLogoPython.d.ts +9 -0
  424. package/dist/icons/components/UiLogoPython.d.ts.map +1 -0
  425. package/dist/icons/components/UiLogoPython.js +10 -0
  426. package/dist/icons/components/UiLogoPython.js.map +1 -0
  427. package/dist/icons/components/UiLogoReact.cjs +10 -0
  428. package/dist/icons/components/UiLogoReact.cjs.map +1 -0
  429. package/dist/icons/components/UiLogoReact.d.ts +9 -0
  430. package/dist/icons/components/UiLogoReact.d.ts.map +1 -0
  431. package/dist/icons/components/UiLogoReact.js +10 -0
  432. package/dist/icons/components/UiLogoReact.js.map +1 -0
  433. package/dist/icons/components/UiLogoRuff.cjs +10 -0
  434. package/dist/icons/components/UiLogoRuff.cjs.map +1 -0
  435. package/dist/icons/components/UiLogoRuff.d.ts +9 -0
  436. package/dist/icons/components/UiLogoRuff.d.ts.map +1 -0
  437. package/dist/icons/components/UiLogoRuff.js +10 -0
  438. package/dist/icons/components/UiLogoRuff.js.map +1 -0
  439. package/dist/icons/components/UiLogoTypescript.cjs +10 -0
  440. package/dist/icons/components/UiLogoTypescript.cjs.map +1 -0
  441. package/dist/icons/components/UiLogoTypescript.d.ts +9 -0
  442. package/dist/icons/components/UiLogoTypescript.d.ts.map +1 -0
  443. package/dist/icons/components/UiLogoTypescript.js +10 -0
  444. package/dist/icons/components/UiLogoTypescript.js.map +1 -0
  445. package/dist/icons/components/UiLogoVitest.cjs +10 -0
  446. package/dist/icons/components/UiLogoVitest.cjs.map +1 -0
  447. package/dist/icons/components/UiLogoVitest.d.ts +9 -0
  448. package/dist/icons/components/UiLogoVitest.d.ts.map +1 -0
  449. package/dist/icons/components/UiLogoVitest.js +10 -0
  450. package/dist/icons/components/UiLogoVitest.js.map +1 -0
  451. package/dist/icons/index.d.ts +11 -0
  452. package/dist/icons/index.d.ts.map +1 -1
  453. package/dist/icons/registry.cjs +22 -0
  454. package/dist/icons/registry.cjs.map +1 -1
  455. package/dist/icons/registry.d.ts.map +1 -1
  456. package/dist/icons/registry.js +22 -0
  457. package/dist/icons/registry.js.map +1 -1
  458. package/dist/icons.cjs +22 -0
  459. package/dist/icons.cjs.map +1 -1
  460. package/dist/icons.js +22 -0
  461. package/dist/icons.js.map +1 -1
  462. package/dist/index.cjs +56 -3
  463. package/dist/index.cjs.map +1 -1
  464. package/dist/index.js +60 -7
  465. package/dist/index.js.map +1 -1
  466. package/dist/overlay/DropdownMenuSubmenu.cjs +4 -4
  467. package/dist/overlay/DropdownMenuSubmenu.cjs.map +1 -1
  468. package/dist/overlay/DropdownMenuSubmenu.js +4 -4
  469. package/dist/overlay/DropdownMenuSubmenu.js.map +1 -1
  470. package/dist/overlay/modalStack.cjs +13 -6
  471. package/dist/overlay/modalStack.cjs.map +1 -1
  472. package/dist/overlay/modalStack.d.ts.map +1 -1
  473. package/dist/overlay/modalStack.js +13 -6
  474. package/dist/overlay/modalStack.js.map +1 -1
  475. package/dist/rpc/InlineError.cjs +12 -43
  476. package/dist/rpc/InlineError.cjs.map +1 -1
  477. package/dist/rpc/InlineError.d.ts.map +1 -1
  478. package/dist/rpc/InlineError.js +13 -44
  479. package/dist/rpc/InlineError.js.map +1 -1
  480. package/dist/rpc/OperationScheduleDialog.cjs +63 -10
  481. package/dist/rpc/OperationScheduleDialog.cjs.map +1 -1
  482. package/dist/rpc/OperationScheduleDialog.d.ts +4 -0
  483. package/dist/rpc/OperationScheduleDialog.d.ts.map +1 -1
  484. package/dist/rpc/OperationScheduleDialog.js +63 -10
  485. package/dist/rpc/OperationScheduleDialog.js.map +1 -1
  486. package/dist/rpc/OperationSchedules.cjs +12 -2
  487. package/dist/rpc/OperationSchedules.cjs.map +1 -1
  488. package/dist/rpc/OperationSchedules.d.ts.map +1 -1
  489. package/dist/rpc/OperationSchedules.js +12 -2
  490. package/dist/rpc/OperationSchedules.js.map +1 -1
  491. package/dist/rpc/operation-schedule-model.cjs +2 -0
  492. package/dist/rpc/operation-schedule-model.cjs.map +1 -1
  493. package/dist/rpc/operation-schedule-model.d.ts.map +1 -1
  494. package/dist/rpc/operation-schedule-model.js +2 -0
  495. package/dist/rpc/operation-schedule-model.js.map +1 -1
  496. package/dist/rpc/operation-schedule-types.d.ts +7 -1
  497. package/dist/rpc/operation-schedule-types.d.ts.map +1 -1
  498. package/dist/styles.css +1 -1
  499. package/package.json +1 -1
  500. package/dist/data/test-runner/frameworkIcon.cjs +0 -27
  501. package/dist/data/test-runner/frameworkIcon.cjs.map +0 -1
  502. package/dist/data/test-runner/frameworkIcon.d.ts +0 -3
  503. package/dist/data/test-runner/frameworkIcon.d.ts.map +0 -1
  504. package/dist/data/test-runner/frameworkIcon.js +0 -27
  505. package/dist/data/test-runner/frameworkIcon.js.map +0 -1
@@ -18,8 +18,13 @@ export interface GraphDiagramProps {
18
18
  * "auto": a diagram with more than 32 edges is focused, a smaller one shows everything.
19
19
  */
20
20
  edgeFocus?: GraphDiagramEdgeFocus;
21
- /** "columns" layout: captions for the group rectangles. A group without an entry shows its id. */
21
+ /**
22
+ * "columns" layout: captions for the group rectangles. A group without an entry shows its id. A group
23
+ * with more than `GROUP_MEMBER_WINDOW` members in a column scrolls them in a window that many rows tall.
24
+ */
22
25
  groups?: GraphDiagramGroup[];
26
+ /** "columns" layout: the chevron of a group whose `collapsed` is set asks to collapse or expand it. */
27
+ onGroupToggle?: (groupId: string) => void;
23
28
  nodeWidth?: number;
24
29
  nodeHeight?: number;
25
30
  /**
@@ -27,6 +32,8 @@ export interface GraphDiagramProps {
27
32
  * compact nodes stacks them closer and pads them tighter. Defaults to 24.
28
33
  */
29
34
  compactNodeHeight?: number;
35
+ /** "columns" layout: height of a record group's header in px. Defaults to 24. */
36
+ recordHeaderHeight?: number;
30
37
  /** "columns" layout: horizontal gap between columns in px. Leave room for edge label pills. */
31
38
  columnGap?: number;
32
39
  /** "columns" layout: vertical gap between stacked nodes in px. */
@@ -47,5 +54,5 @@ export interface GraphDiagramProps {
47
54
  ariaLabel: string;
48
55
  className?: string;
49
56
  }
50
- export declare function GraphDiagram({ nodes, edges, layout, selectedId, onNodeSelect, onNodeExpand, selectedEdgeId, onEdgeSelect, edgeFocus, groups, nodeWidth, nodeHeight, compactNodeHeight, columnGap, rowGap, zoomable, wheelZoom, fitMinScale, focusId, maxHeight, ariaLabel, className, }: GraphDiagramProps): import("react").JSX.Element;
57
+ export declare function GraphDiagram({ nodes, edges, layout, selectedId, onNodeSelect, onNodeExpand, selectedEdgeId, onEdgeSelect, edgeFocus, groups, onGroupToggle, nodeWidth, nodeHeight, compactNodeHeight, recordHeaderHeight, columnGap, rowGap, zoomable, wheelZoom, fitMinScale, focusId, maxHeight, ariaLabel, className, }: GraphDiagramProps): import("react").JSX.Element;
51
58
  //# sourceMappingURL=GraphDiagram.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"GraphDiagram.d.ts","sourceRoot":"","sources":["../../src/data/GraphDiagram.tsx"],"names":[],"mappings":"AAQA,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EAEtB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAA6C,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3F,YAAY,EACV,gBAAgB,EAChB,qBAAqB,EACrB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,uBAAuB,CAAC;AAiB/B,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,mEAAmE;IACnE,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,qFAAqF;IACrF,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,sDAAsD;IACtD,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC;;;OAGG;IACH,SAAS,CAAC,EAAE,qBAAqB,CAAC;IAClC,kGAAkG;IAClG,MAAM,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,+FAA+F;IAC/F,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kEAAkE;IAClE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kGAAkG;IAClG,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sHAAsH;IACtH,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oGAAoG;IACpG,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAyGD,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,KAAK,EACL,MAAe,EACf,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,SAAkB,EAClB,MAAM,EACN,SAA8B,EAC9B,UAAgC,EAChC,iBAA+C,EAC/C,SAAS,EACT,MAAM,EACN,QAAgB,EAChB,SAAsB,EACtB,WAAW,EACX,OAAO,EACP,SAAS,EACT,SAAS,EACT,SAAS,GACV,EAAE,iBAAiB,+BA8EnB"}
1
+ {"version":3,"file":"GraphDiagram.d.ts","sourceRoot":"","sources":["../../src/data/GraphDiagram.tsx"],"names":[],"mappings":"AAUA,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EAEtB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAA6C,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3F,YAAY,EACV,gBAAgB,EAChB,qBAAqB,EACrB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,uBAAuB,CAAC;AAiB/B,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,mEAAmE;IACnE,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,qFAAqF;IACrF,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,sDAAsD;IACtD,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC;;;OAGG;IACH,SAAS,CAAC,EAAE,qBAAqB,CAAC;IAClC;;;OAGG;IACH,MAAM,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAC7B,uGAAuG;IACvG,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iFAAiF;IACjF,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,+FAA+F;IAC/F,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kEAAkE;IAClE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kGAAkG;IAClG,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sHAAsH;IACtH,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oGAAoG;IACpG,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAkID,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,KAAK,EACL,MAAe,EACf,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,SAAkB,EAClB,MAAM,EACN,aAAa,EACb,SAA8B,EAC9B,UAAgC,EAChC,iBAA+C,EAC/C,kBAAuB,EACvB,SAAS,EACT,MAAM,EACN,QAAgB,EAChB,SAAsB,EACtB,WAAW,EACX,OAAO,EACP,SAAS,EACT,SAAS,EACT,SAAS,GACV,EAAE,iBAAiB,+BAkGnB"}
@@ -5,7 +5,9 @@ import { IconButton } from "../components/IconButton.js";
5
5
  import { columnsLayout } from "./graph-columns-layout.js";
6
6
  import { ringLayout } from "./graph-layout.js";
7
7
  import { GraphDiagramEdgePaths, GraphDiagramEdgeLabels } from "./GraphDiagramEdges.js";
8
- import { GraphDiagramGroupBoxes, GraphDiagramNodes } from "./GraphDiagramNodes.js";
8
+ import { GraphDiagramGroupBoxes } from "./GraphDiagramGroups.js";
9
+ import { GraphDiagramNodes } from "./GraphDiagramNodes.js";
10
+ import { useGroupWindows } from "./use-group-windows.js";
9
11
  import { requireEntry } from "./graph-diagram-model.js";
10
12
  import { useEdgeFocus } from "./use-edge-focus.js";
11
13
  import { usePanZoom } from "./use-pan-zoom.js";
@@ -17,9 +19,23 @@ import { UiHome } from "../icons/components/UiHome.js";
17
19
  const DEFAULT_NODE_WIDTH = 168;
18
20
  const DEFAULT_NODE_HEIGHT = 60;
19
21
  const DEFAULT_COMPACT_NODE_HEIGHT = 24;
20
- function compactHeights(nodes, layout, compactNodeHeight) {
22
+ function compactHeights(nodes, layout, compactNodeHeight, standIns, headerHeight) {
21
23
  if (layout !== "columns") return {};
22
- return Object.fromEntries(nodes.filter((node) => node.size === "compact").map((node) => [node.id, compactNodeHeight]));
24
+ return Object.fromEntries(nodes.flatMap((node) => {
25
+ if (standIns.has(node.id)) return [[node.id, headerHeight]];
26
+ return node.size === "compact" ? [[node.id, compactNodeHeight]] : [];
27
+ }));
28
+ }
29
+ function collapsedStandIns(nodes, groups) {
30
+ const collapsed = new Set(groups == null ? void 0 : groups.filter((group) => group.collapsed === true).map((group) => group.id));
31
+ const standIns = /* @__PURE__ */ new Map();
32
+ for (const node of nodes) {
33
+ if (node.group === void 0 || !collapsed.has(node.group)) continue;
34
+ const held = standIns.get(node.group);
35
+ if (held !== void 0) throw new Error(`GraphDiagram: collapsed group "${node.group}" holds "${held}" and "${node.id}"; it draws one stand-in`);
36
+ standIns.set(node.group, node.id);
37
+ }
38
+ return standIns;
23
39
  }
24
40
  function assertEdgesReferenceKnownNodes(nodes, edges) {
25
41
  const ids = new Set(nodes.map((node) => node.id));
@@ -38,7 +54,7 @@ function requireLevel(node) {
38
54
  }
39
55
  return node.level;
40
56
  }
41
- function layoutNodes(nodes, edges, { layout, nodeWidth, nodeHeight, compactNodeHeight, columnGap, rowGap }) {
57
+ function layoutNodes(nodes, edges, { layout, nodeWidth, nodeHeight, compactNodeHeight, records, collapsed, recordHeaderHeight, columnGap, rowGap }) {
42
58
  switch (layout) {
43
59
  case "ring":
44
60
  return { ...ringLayout(nodes, { nodeWidth, nodeHeight }), groups: [] };
@@ -55,6 +71,9 @@ function layoutNodes(nodes, edges, { layout, nodeWidth, nodeHeight, compactNodeH
55
71
  nodeWidth,
56
72
  nodeHeight,
57
73
  compactNodeHeight,
74
+ records,
75
+ collapsed,
76
+ recordHeaderHeight,
58
77
  ...columnGap !== void 0 ? { columnGap } : {},
59
78
  ...rowGap !== void 0 ? { rowGap } : {}
60
79
  }
@@ -97,9 +116,11 @@ function GraphDiagram({
97
116
  onEdgeSelect,
98
117
  edgeFocus = "auto",
99
118
  groups,
119
+ onGroupToggle,
100
120
  nodeWidth = DEFAULT_NODE_WIDTH,
101
121
  nodeHeight = DEFAULT_NODE_HEIGHT,
102
122
  compactNodeHeight = DEFAULT_COMPACT_NODE_HEIGHT,
123
+ recordHeaderHeight = 24,
103
124
  columnGap,
104
125
  rowGap,
105
126
  zoomable = false,
@@ -112,22 +133,39 @@ function GraphDiagram({
112
133
  }) {
113
134
  assertEdgesReferenceKnownNodes(nodes, edges);
114
135
  const markerPrefix = `graph-diagram-${useId().replace(/[^a-zA-Z0-9_-]/g, "")}`;
115
- const { width, height, positions, groups: groupBoxes } = useMemo(
116
- () => layoutNodes(nodes, edges, { layout, nodeWidth, nodeHeight, compactNodeHeight, columnGap, rowGap }),
117
- [layout, nodes, edges, nodeWidth, nodeHeight, compactNodeHeight, columnGap, rowGap]
136
+ const records = useMemo(() => (groups == null ? void 0 : groups.filter((group) => group.variant === "record").map((group) => group.id)) ?? [], [groups]);
137
+ const recordNodes = useMemo(() => new Set(layout === "columns" ? nodes.filter((node) => node.group !== void 0 && records.includes(node.group)).map((node) => node.id) : []), [layout, nodes, records]);
138
+ const standIns = useMemo(() => layout === "columns" ? collapsedStandIns(nodes, groups) : /* @__PURE__ */ new Map(), [layout, nodes, groups]);
139
+ const collapsed = useMemo(() => [...standIns.keys()], [standIns]);
140
+ const { width, height, positions: laidOut, groups: groupBoxes } = useMemo(
141
+ () => layoutNodes(nodes, edges, { layout, nodeWidth, nodeHeight, compactNodeHeight, records, collapsed, recordHeaderHeight, columnGap, rowGap }),
142
+ [layout, nodes, edges, nodeWidth, nodeHeight, compactNodeHeight, records, collapsed, recordHeaderHeight, columnGap, rowGap]
118
143
  );
119
- const nodeHeights = useMemo(() => compactHeights(nodes, layout, compactNodeHeight), [nodes, layout, compactNodeHeight]);
120
- const routes = useMemo(
121
- () => routeEdges(edges, positions, { nodeWidth, nodeHeight, nodeHeights }, { anchor: layout === "columns" ? "side" : "center" }),
122
- [edges, positions, nodeWidth, nodeHeight, nodeHeights, layout]
144
+ const nodeHeights = useMemo(
145
+ () => compactHeights(nodes, layout, compactNodeHeight, new Set(standIns.values()), recordHeaderHeight),
146
+ [nodes, layout, compactNodeHeight, standIns, recordHeaderHeight]
123
147
  );
124
148
  const panZoom = usePanZoom({
125
149
  enabled: zoomable,
126
150
  wheel: wheelZoom,
127
151
  contentWidth: width,
128
152
  contentHeight: height,
129
- opening: openingFit(positions, fitMinScale, focusId)
153
+ opening: openingFit(laidOut, fitMinScale, focusId)
130
154
  });
155
+ const windows = useGroupWindows({ boxes: groupBoxes, positions: laidOut, reveal: selectedId ?? focusId, stageRef: panZoom.contentRef, scale: zoomable ? panZoom.transform.scale : 1 });
156
+ const { positions } = windows;
157
+ const routes = useMemo(
158
+ () => routeEdges(edges, positions, { nodeWidth, nodeHeight, nodeHeights }, { anchor: layout === "columns" ? "side" : "center" }),
159
+ [edges, positions, nodeWidth, nodeHeight, nodeHeights, layout]
160
+ );
161
+ const drawnNodes = useMemo(() => {
162
+ const standing = new Set(standIns.values());
163
+ return nodes.filter((node) => !windows.hidden.has(node.id) && !standing.has(node.id));
164
+ }, [nodes, windows.hidden, standIns]);
165
+ const windowOf = useMemo(
166
+ () => new Map(groupBoxes.flatMap((box) => box.window ? box.window.members.map((id) => [id, box.id]) : [])),
167
+ [groupBoxes]
168
+ );
131
169
  const natural = layout === "columns" || zoomable;
132
170
  const place = natural ? ({ x, y }) => ({ left: x, top: y }) : ({ x, y }) => ({ left: toPercent(x, width), top: toPercent(y, height) });
133
171
  const focus = useEdgeFocus({ mode: edgeFocus, edges, selectedId, selectedEdgeId });
@@ -153,7 +191,19 @@ function GraphDiagram({
153
191
  className: cn("relative", natural ? !zoomable && "mx-auto" : "w-full"),
154
192
  style: stageStyle({ width, height }, natural, zoomable ? panZoom : void 0),
155
193
  children: [
156
- /* @__PURE__ */ jsx(GraphDiagramGroupBoxes, { boxes: groupBoxes, groups }),
194
+ /* @__PURE__ */ jsx(
195
+ GraphDiagramGroupBoxes,
196
+ {
197
+ boxes: groupBoxes,
198
+ groups,
199
+ starts: windows.starts,
200
+ onScroll: windows.scroll,
201
+ onGroupToggle,
202
+ standIns,
203
+ selectedId,
204
+ onNodeSelect
205
+ }
206
+ ),
157
207
  /* @__PURE__ */ jsx(
158
208
  GraphDiagramEdgePaths,
159
209
  {
@@ -173,12 +223,14 @@ function GraphDiagram({
173
223
  /* @__PURE__ */ jsx(
174
224
  GraphDiagramNodes,
175
225
  {
176
- nodes,
226
+ nodes: drawnNodes,
177
227
  positions,
228
+ windowOf,
178
229
  place,
179
230
  nodeWidth,
180
231
  nodeHeight,
181
232
  nodeHeights,
233
+ recordNodes,
182
234
  selectedId,
183
235
  onNodeSelect,
184
236
  onNodeExpand,
@@ -1 +1 @@
1
- {"version":3,"file":"GraphDiagram.js","sources":["../../src/data/GraphDiagram.tsx"],"sourcesContent":["import { useId, useMemo, type CSSProperties } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { IconButton } from \"../components/IconButton\";\nimport { UiFullscreen, UiHome, UiZoomIn, UiZoomOut } from \"../icons\";\nimport { columnsLayout, type ColumnsLayoutResult } from \"./graph-columns-layout\";\nimport { ringLayout, routeEdges, type GraphLayoutPosition } from \"./graph-layout\";\nimport { GraphDiagramEdgeLabels, GraphDiagramEdgePaths } from \"./GraphDiagramEdges\";\nimport { GraphDiagramGroupBoxes, GraphDiagramNodes } from \"./GraphDiagramNodes\";\nimport {\n requireEntry,\n type GraphDiagramEdge,\n type GraphDiagramEdgeFocus,\n type GraphDiagramGroup,\n type GraphDiagramLayout,\n type GraphDiagramNode,\n type GraphPlacer,\n} from \"./graph-diagram-model\";\nimport { useEdgeFocus } from \"./use-edge-focus\";\nimport { usePanZoom, type FitOptions, type PanZoom, type WheelMode } from \"./use-pan-zoom\";\n\nexport type {\n GraphDiagramEdge,\n GraphDiagramEdgeFocus,\n GraphDiagramGroup,\n GraphDiagramLayout,\n GraphDiagramNode,\n} from \"./graph-diagram-model\";\n\n// GraphDiagram renders a generic, type-agnostic node/edge diagram. It knows\n// nothing about the domain: a producer maps its data into\n// GraphDiagramNode/GraphDiagramEdge and gets layout, edge routing and\n// selection behaviour.\n//\n// \"ring\" suits a small cycle of resources and processes — relationships with\n// back edges or reciprocal pairs. \"columns\" suits a directed graph with a\n// natural depth (a call graph, a dependency chain): nodes sit in the column of\n// their `level`, grouped and boxed by `group`.\n//\n// The \"columns\" layout, and any zoomable diagram, is drawn at its natural\n// pixel size so node boxes, edges and group boxes share one coordinate system\n// at every container width and zoom level. A non-zoomable \"ring\" keeps scaling\n// its node positions to the container width.\n\nexport interface GraphDiagramProps {\n nodes: GraphDiagramNode[];\n edges: GraphDiagramEdge[];\n /** Defaults to \"ring\". \"columns\" needs a `level` on every node. */\n layout?: GraphDiagramLayout;\n selectedId?: string;\n onNodeSelect?: (id: string) => void;\n /** Called by a node's `+N` control (see `expandCount`); does not select the node. */\n onNodeExpand?: (id: string) => void;\n selectedEdgeId?: string;\n /** Makes edges, and their label pills, selectable. */\n onEdgeSelect?: (id: string) => void;\n /**\n * Whether an edge shows its pill only while in focus, and fades while another is. Defaults to\n * \"auto\": a diagram with more than 32 edges is focused, a smaller one shows everything.\n */\n edgeFocus?: GraphDiagramEdgeFocus;\n /** \"columns\" layout: captions for the group rectangles. A group without an entry shows its id. */\n groups?: GraphDiagramGroup[];\n nodeWidth?: number;\n nodeHeight?: number;\n /**\n * \"columns\" layout: the height of a node with `size: \"compact\"`, drawn on one line. A group of only\n * compact nodes stacks them closer and pads them tighter. Defaults to 24.\n */\n compactNodeHeight?: number;\n /** \"columns\" layout: horizontal gap between columns in px. Leave room for edge label pills. */\n columnGap?: number;\n /** \"columns\" layout: vertical gap between stacked nodes in px. */\n rowGap?: number;\n /** Ctrl/meta + wheel (or pinch) zooms, dragging the background pans, and zoom controls appear. */\n zoomable?: boolean;\n /** Zoomable: \"zoom\" makes a plain mouse wheel zoom too, for a diagram that fills its pane. Defaults to \"modifier\". */\n wheelZoom?: WheelMode;\n /**\n * Zoomable: the smallest scale the diagram opens at, so its text stays readable. A diagram too\n * large for it opens overflowing, centred on `focusId`, and is panned to reach the rest. `Fit to\n * view` still shows everything, and `Reset view` returns here. Unset, the diagram opens whole.\n */\n fitMinScale?: number;\n /** Zoomable: the node an overflowing diagram opens centred on. Defaults to the diagram's centre. */\n focusId?: string;\n maxHeight?: number | string;\n ariaLabel: string;\n className?: string;\n}\n\nconst DEFAULT_NODE_WIDTH = 168;\nconst DEFAULT_NODE_HEIGHT = 60;\nconst DEFAULT_COMPACT_NODE_HEIGHT = 24;\n\ninterface LayoutOptions {\n layout: GraphDiagramLayout;\n nodeWidth: number;\n nodeHeight: number;\n compactNodeHeight: number;\n columnGap: number | undefined;\n rowGap: number | undefined;\n}\n\n/** The heights of the nodes not drawn at the node height: the compact ones, in the \"columns\" layout. */\nfunction compactHeights(nodes: GraphDiagramNode[], layout: GraphDiagramLayout, compactNodeHeight: number): Record<string, number> {\n if (layout !== \"columns\") return {};\n return Object.fromEntries(nodes.filter((node) => node.size === \"compact\").map((node) => [node.id, compactNodeHeight]));\n}\n\nfunction assertEdgesReferenceKnownNodes(nodes: GraphDiagramNode[], edges: GraphDiagramEdge[]): void {\n const ids = new Set(nodes.map((node) => node.id));\n for (const edge of edges) {\n if (!ids.has(edge.from)) {\n throw new Error(`GraphDiagram: edge \"${edge.id}\" references unknown node \"${edge.from}\"`);\n }\n if (!ids.has(edge.to)) {\n throw new Error(`GraphDiagram: edge \"${edge.id}\" references unknown node \"${edge.to}\"`);\n }\n }\n}\n\nfunction requireLevel(node: GraphDiagramNode): number {\n if (node.level === undefined || !Number.isFinite(node.level)) {\n throw new Error(`GraphDiagram: node \"${node.id}\" needs a finite level for the \"columns\" layout`);\n }\n return node.level;\n}\n\nfunction layoutNodes(\n nodes: GraphDiagramNode[],\n edges: GraphDiagramEdge[],\n { layout, nodeWidth, nodeHeight, compactNodeHeight, columnGap, rowGap }: LayoutOptions,\n): ColumnsLayoutResult {\n switch (layout) {\n case \"ring\":\n return { ...ringLayout(nodes, { nodeWidth, nodeHeight }), groups: [] };\n case \"columns\":\n return columnsLayout(\n nodes.map((node) => ({\n id: node.id,\n level: requireLevel(node),\n ...(node.group !== undefined ? { group: node.group } : {}),\n ...(node.size === \"compact\" ? { compact: true } : {}),\n })),\n edges,\n {\n nodeWidth,\n nodeHeight,\n compactNodeHeight,\n ...(columnGap !== undefined ? { columnGap } : {}),\n ...(rowGap !== undefined ? { rowGap } : {}),\n },\n );\n default:\n throw new Error(`GraphDiagram: unknown layout \"${layout satisfies never}\"`);\n }\n}\n\nfunction toPercent(value: number, extent: number): string {\n return `${(value / extent) * 100}%`;\n}\n\nfunction stageStyle(size: { width: number; height: number }, natural: boolean, panZoom: PanZoom | undefined): CSSProperties {\n if (!natural) return { aspectRatio: `${size.width} / ${size.height}` };\n if (!panZoom) return size;\n const { x, y, scale } = panZoom.transform;\n return { ...size, transform: `translate(${x}px, ${y}px) scale(${scale})`, transformOrigin: \"0 0\" };\n}\n\n/** `resettable`: the diagram opens at another view than the whole of it, so there is one to return to. */\nfunction ZoomControls({ panZoom, resettable }: { panZoom: PanZoom; resettable: boolean }) {\n return (\n <div className=\"absolute right-2 top-2 flex cursor-default gap-0.5 rounded-md border border-border bg-background p-0.5 shadow-sm\">\n <IconButton icon={UiZoomOut} label=\"Zoom out\" className=\"size-6\" onClick={panZoom.zoomOut} />\n <IconButton icon={UiZoomIn} label=\"Zoom in\" className=\"size-6\" onClick={panZoom.zoomIn} />\n <IconButton icon={UiFullscreen} label=\"Fit to view\" className=\"size-6\" onClick={panZoom.fit} />\n {resettable && <IconButton icon={UiHome} label=\"Reset view\" className=\"size-6\" onClick={panZoom.reset} />}\n </div>\n );\n}\n\n/** How a zoomable diagram opens: no smaller than `fitMinScale`, centred on the `focusId` node. */\nfunction openingFit(\n positions: Record<string, GraphLayoutPosition>,\n fitMinScale: number | undefined,\n focusId: string | undefined,\n): FitOptions {\n return {\n ...(fitMinScale !== undefined ? { minScale: fitMinScale } : {}),\n ...(focusId !== undefined ? { focus: requireEntry(positions, focusId, \"layout position\") } : {}),\n };\n}\n\nexport function GraphDiagram({\n nodes,\n edges,\n layout = \"ring\",\n selectedId,\n onNodeSelect,\n onNodeExpand,\n selectedEdgeId,\n onEdgeSelect,\n edgeFocus = \"auto\",\n groups,\n nodeWidth = DEFAULT_NODE_WIDTH,\n nodeHeight = DEFAULT_NODE_HEIGHT,\n compactNodeHeight = DEFAULT_COMPACT_NODE_HEIGHT,\n columnGap,\n rowGap,\n zoomable = false,\n wheelZoom = \"modifier\",\n fitMinScale,\n focusId,\n maxHeight,\n ariaLabel,\n className,\n}: GraphDiagramProps) {\n assertEdgesReferenceKnownNodes(nodes, edges);\n const markerPrefix = `graph-diagram-${useId().replace(/[^a-zA-Z0-9_-]/g, \"\")}`;\n\n const { width, height, positions, groups: groupBoxes } = useMemo(\n () => layoutNodes(nodes, edges, { layout, nodeWidth, nodeHeight, compactNodeHeight, columnGap, rowGap }),\n [layout, nodes, edges, nodeWidth, nodeHeight, compactNodeHeight, columnGap, rowGap],\n );\n const nodeHeights = useMemo(() => compactHeights(nodes, layout, compactNodeHeight), [nodes, layout, compactNodeHeight]);\n const routes = useMemo(\n () =>\n routeEdges(edges, positions, { nodeWidth, nodeHeight, nodeHeights }, { anchor: layout === \"columns\" ? \"side\" : \"center\" }),\n [edges, positions, nodeWidth, nodeHeight, nodeHeights, layout],\n );\n\n const panZoom = usePanZoom({\n enabled: zoomable,\n wheel: wheelZoom,\n contentWidth: width,\n contentHeight: height,\n opening: openingFit(positions, fitMinScale, focusId),\n });\n const natural = layout === \"columns\" || zoomable;\n const place: GraphPlacer = natural\n ? ({ x, y }) => ({ left: x, top: y })\n : ({ x, y }) => ({ left: toPercent(x, width), top: toPercent(y, height) });\n const focus = useEdgeFocus({ mode: edgeFocus, edges, selectedId, selectedEdgeId });\n const edgeSelection = { selectedEdgeId, onEdgeSelect, focus: focus.state };\n\n return (\n <div\n ref={panZoom.viewportRef}\n className={cn(\n \"w-full\",\n zoomable ? \"relative touch-none overflow-hidden\" : \"overflow-auto\",\n zoomable && (panZoom.panning ? \"cursor-grabbing select-none\" : \"cursor-grab\"),\n className,\n )}\n style={maxHeight != null ? { maxHeight } : undefined}\n {...panZoom.handlers}\n >\n <div\n ref={panZoom.contentRef}\n data-graph-stage=\"\"\n className={cn(\"relative\", natural ? !zoomable && \"mx-auto\" : \"w-full\")}\n style={stageStyle({ width, height }, natural, zoomable ? panZoom : undefined)}\n >\n <GraphDiagramGroupBoxes boxes={groupBoxes} groups={groups} />\n <GraphDiagramEdgePaths\n edges={edges}\n nodes={nodes}\n routes={routes}\n width={width}\n height={height}\n ariaLabel={ariaLabel}\n markerPrefix={markerPrefix}\n onEdgeHover={focus.onEdgeHover}\n {...edgeSelection}\n />\n <div className=\"pointer-events-none absolute inset-0\">\n <GraphDiagramEdgeLabels edges={edges} routes={routes} place={place} spread={natural} {...edgeSelection} />\n <GraphDiagramNodes\n nodes={nodes}\n positions={positions}\n place={place}\n nodeWidth={nodeWidth}\n nodeHeight={nodeHeight}\n nodeHeights={nodeHeights}\n selectedId={selectedId}\n onNodeSelect={onNodeSelect}\n onNodeExpand={onNodeExpand}\n onNodeHover={focus.onNodeHover}\n />\n </div>\n </div>\n {zoomable && <ZoomControls panZoom={panZoom} resettable={fitMinScale !== undefined} />}\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"GraphDiagram.js","sources":["../../src/data/GraphDiagram.tsx"],"sourcesContent":["import { useId, useMemo, type CSSProperties } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { IconButton } from \"../components/IconButton\";\nimport { UiFullscreen, UiHome, UiZoomIn, UiZoomOut } from \"../icons\";\nimport { columnsLayout, type ColumnsLayoutResult } from \"./graph-columns-layout\";\nimport { ringLayout, routeEdges, type GraphLayoutPosition } from \"./graph-layout\";\nimport { GraphDiagramEdgeLabels, GraphDiagramEdgePaths } from \"./GraphDiagramEdges\";\nimport { GraphDiagramGroupBoxes } from \"./GraphDiagramGroups\";\nimport { GraphDiagramNodes } from \"./GraphDiagramNodes\";\nimport { useGroupWindows } from \"./use-group-windows\";\nimport {\n requireEntry,\n type GraphDiagramEdge,\n type GraphDiagramEdgeFocus,\n type GraphDiagramGroup,\n type GraphDiagramLayout,\n type GraphDiagramNode,\n type GraphPlacer,\n} from \"./graph-diagram-model\";\nimport { useEdgeFocus } from \"./use-edge-focus\";\nimport { usePanZoom, type FitOptions, type PanZoom, type WheelMode } from \"./use-pan-zoom\";\n\nexport type {\n GraphDiagramEdge,\n GraphDiagramEdgeFocus,\n GraphDiagramGroup,\n GraphDiagramLayout,\n GraphDiagramNode,\n} from \"./graph-diagram-model\";\n\n// GraphDiagram renders a generic, type-agnostic node/edge diagram. It knows\n// nothing about the domain: a producer maps its data into\n// GraphDiagramNode/GraphDiagramEdge and gets layout, edge routing and\n// selection behaviour.\n//\n// \"ring\" suits a small cycle of resources and processes — relationships with\n// back edges or reciprocal pairs. \"columns\" suits a directed graph with a\n// natural depth (a call graph, a dependency chain): nodes sit in the column of\n// their `level`, grouped and boxed by `group`.\n//\n// The \"columns\" layout, and any zoomable diagram, is drawn at its natural\n// pixel size so node boxes, edges and group boxes share one coordinate system\n// at every container width and zoom level. A non-zoomable \"ring\" keeps scaling\n// its node positions to the container width.\n\nexport interface GraphDiagramProps {\n nodes: GraphDiagramNode[];\n edges: GraphDiagramEdge[];\n /** Defaults to \"ring\". \"columns\" needs a `level` on every node. */\n layout?: GraphDiagramLayout;\n selectedId?: string;\n onNodeSelect?: (id: string) => void;\n /** Called by a node's `+N` control (see `expandCount`); does not select the node. */\n onNodeExpand?: (id: string) => void;\n selectedEdgeId?: string;\n /** Makes edges, and their label pills, selectable. */\n onEdgeSelect?: (id: string) => void;\n /**\n * Whether an edge shows its pill only while in focus, and fades while another is. Defaults to\n * \"auto\": a diagram with more than 32 edges is focused, a smaller one shows everything.\n */\n edgeFocus?: GraphDiagramEdgeFocus;\n /**\n * \"columns\" layout: captions for the group rectangles. A group without an entry shows its id. A group\n * with more than `GROUP_MEMBER_WINDOW` members in a column scrolls them in a window that many rows tall.\n */\n groups?: GraphDiagramGroup[];\n /** \"columns\" layout: the chevron of a group whose `collapsed` is set asks to collapse or expand it. */\n onGroupToggle?: (groupId: string) => void;\n nodeWidth?: number;\n nodeHeight?: number;\n /**\n * \"columns\" layout: the height of a node with `size: \"compact\"`, drawn on one line. A group of only\n * compact nodes stacks them closer and pads them tighter. Defaults to 24.\n */\n compactNodeHeight?: number;\n /** \"columns\" layout: height of a record group's header in px. Defaults to 24. */\n recordHeaderHeight?: number;\n /** \"columns\" layout: horizontal gap between columns in px. Leave room for edge label pills. */\n columnGap?: number;\n /** \"columns\" layout: vertical gap between stacked nodes in px. */\n rowGap?: number;\n /** Ctrl/meta + wheel (or pinch) zooms, dragging the background pans, and zoom controls appear. */\n zoomable?: boolean;\n /** Zoomable: \"zoom\" makes a plain mouse wheel zoom too, for a diagram that fills its pane. Defaults to \"modifier\". */\n wheelZoom?: WheelMode;\n /**\n * Zoomable: the smallest scale the diagram opens at, so its text stays readable. A diagram too\n * large for it opens overflowing, centred on `focusId`, and is panned to reach the rest. `Fit to\n * view` still shows everything, and `Reset view` returns here. Unset, the diagram opens whole.\n */\n fitMinScale?: number;\n /** Zoomable: the node an overflowing diagram opens centred on. Defaults to the diagram's centre. */\n focusId?: string;\n maxHeight?: number | string;\n ariaLabel: string;\n className?: string;\n}\n\nconst DEFAULT_NODE_WIDTH = 168;\nconst DEFAULT_NODE_HEIGHT = 60;\nconst DEFAULT_COMPACT_NODE_HEIGHT = 24;\n\ninterface LayoutOptions {\n layout: GraphDiagramLayout;\n nodeWidth: number;\n nodeHeight: number;\n compactNodeHeight: number;\n records: readonly string[];\n collapsed: readonly string[];\n recordHeaderHeight: number;\n columnGap: number | undefined;\n rowGap: number | undefined;\n}\n\n/**\n * The heights of the nodes not drawn at the node height, in the \"columns\" layout: the compact ones, and\n * the stand-ins of collapsed groups, as tall as the header they are drawn as.\n */\nfunction compactHeights(nodes: GraphDiagramNode[], layout: GraphDiagramLayout, compactNodeHeight: number, standIns: ReadonlySet<string>, headerHeight: number): Record<string, number> {\n if (layout !== \"columns\") return {};\n return Object.fromEntries(nodes.flatMap((node): [string, number][] => {\n if (standIns.has(node.id)) return [[node.id, headerHeight]];\n return node.size === \"compact\" ? [[node.id, compactNodeHeight]] : [];\n }));\n}\n\n/** The one node each collapsed group holds, by group id. */\nfunction collapsedStandIns(nodes: GraphDiagramNode[], groups: GraphDiagramGroup[] | undefined): Map<string, string> {\n const collapsed = new Set(groups?.filter((group) => group.collapsed === true).map((group) => group.id));\n const standIns = new Map<string, string>();\n for (const node of nodes) {\n if (node.group === undefined || !collapsed.has(node.group)) continue;\n const held = standIns.get(node.group);\n if (held !== undefined) throw new Error(`GraphDiagram: collapsed group \"${node.group}\" holds \"${held}\" and \"${node.id}\"; it draws one stand-in`);\n standIns.set(node.group, node.id);\n }\n return standIns;\n}\n\nfunction assertEdgesReferenceKnownNodes(nodes: GraphDiagramNode[], edges: GraphDiagramEdge[]): void {\n const ids = new Set(nodes.map((node) => node.id));\n for (const edge of edges) {\n if (!ids.has(edge.from)) {\n throw new Error(`GraphDiagram: edge \"${edge.id}\" references unknown node \"${edge.from}\"`);\n }\n if (!ids.has(edge.to)) {\n throw new Error(`GraphDiagram: edge \"${edge.id}\" references unknown node \"${edge.to}\"`);\n }\n }\n}\n\nfunction requireLevel(node: GraphDiagramNode): number {\n if (node.level === undefined || !Number.isFinite(node.level)) {\n throw new Error(`GraphDiagram: node \"${node.id}\" needs a finite level for the \"columns\" layout`);\n }\n return node.level;\n}\n\nfunction layoutNodes(\n nodes: GraphDiagramNode[],\n edges: GraphDiagramEdge[],\n { layout, nodeWidth, nodeHeight, compactNodeHeight, records, collapsed, recordHeaderHeight, columnGap, rowGap }: LayoutOptions,\n): ColumnsLayoutResult {\n switch (layout) {\n case \"ring\":\n return { ...ringLayout(nodes, { nodeWidth, nodeHeight }), groups: [] };\n case \"columns\":\n return columnsLayout(\n nodes.map((node) => ({\n id: node.id,\n level: requireLevel(node),\n ...(node.group !== undefined ? { group: node.group } : {}),\n ...(node.size === \"compact\" ? { compact: true } : {}),\n })),\n edges,\n {\n nodeWidth,\n nodeHeight,\n compactNodeHeight,\n records,\n collapsed,\n recordHeaderHeight,\n ...(columnGap !== undefined ? { columnGap } : {}),\n ...(rowGap !== undefined ? { rowGap } : {}),\n },\n );\n default:\n throw new Error(`GraphDiagram: unknown layout \"${layout satisfies never}\"`);\n }\n}\n\nfunction toPercent(value: number, extent: number): string {\n return `${(value / extent) * 100}%`;\n}\n\nfunction stageStyle(size: { width: number; height: number }, natural: boolean, panZoom: PanZoom | undefined): CSSProperties {\n if (!natural) return { aspectRatio: `${size.width} / ${size.height}` };\n if (!panZoom) return size;\n const { x, y, scale } = panZoom.transform;\n return { ...size, transform: `translate(${x}px, ${y}px) scale(${scale})`, transformOrigin: \"0 0\" };\n}\n\n/** `resettable`: the diagram opens at another view than the whole of it, so there is one to return to. */\nfunction ZoomControls({ panZoom, resettable }: { panZoom: PanZoom; resettable: boolean }) {\n return (\n <div className=\"absolute right-2 top-2 flex cursor-default gap-0.5 rounded-md border border-border bg-background p-0.5 shadow-sm\">\n <IconButton icon={UiZoomOut} label=\"Zoom out\" className=\"size-6\" onClick={panZoom.zoomOut} />\n <IconButton icon={UiZoomIn} label=\"Zoom in\" className=\"size-6\" onClick={panZoom.zoomIn} />\n <IconButton icon={UiFullscreen} label=\"Fit to view\" className=\"size-6\" onClick={panZoom.fit} />\n {resettable && <IconButton icon={UiHome} label=\"Reset view\" className=\"size-6\" onClick={panZoom.reset} />}\n </div>\n );\n}\n\n/** How a zoomable diagram opens: no smaller than `fitMinScale`, centred on the `focusId` node. */\nfunction openingFit(\n positions: Record<string, GraphLayoutPosition>,\n fitMinScale: number | undefined,\n focusId: string | undefined,\n): FitOptions {\n return {\n ...(fitMinScale !== undefined ? { minScale: fitMinScale } : {}),\n ...(focusId !== undefined ? { focus: requireEntry(positions, focusId, \"layout position\") } : {}),\n };\n}\n\nexport function GraphDiagram({\n nodes,\n edges,\n layout = \"ring\",\n selectedId,\n onNodeSelect,\n onNodeExpand,\n selectedEdgeId,\n onEdgeSelect,\n edgeFocus = \"auto\",\n groups,\n onGroupToggle,\n nodeWidth = DEFAULT_NODE_WIDTH,\n nodeHeight = DEFAULT_NODE_HEIGHT,\n compactNodeHeight = DEFAULT_COMPACT_NODE_HEIGHT,\n recordHeaderHeight = 24,\n columnGap,\n rowGap,\n zoomable = false,\n wheelZoom = \"modifier\",\n fitMinScale,\n focusId,\n maxHeight,\n ariaLabel,\n className,\n}: GraphDiagramProps) {\n assertEdgesReferenceKnownNodes(nodes, edges);\n const markerPrefix = `graph-diagram-${useId().replace(/[^a-zA-Z0-9_-]/g, \"\")}`;\n const records = useMemo(() => groups?.filter((group) => group.variant === \"record\").map((group) => group.id) ?? [], [groups]);\n const recordNodes = useMemo(() => new Set(layout === \"columns\" ? nodes.filter((node) => node.group !== undefined && records.includes(node.group)).map((node) => node.id) : []), [layout, nodes, records]);\n const standIns = useMemo(() => (layout === \"columns\" ? collapsedStandIns(nodes, groups) : new Map<string, string>()), [layout, nodes, groups]);\n const collapsed = useMemo(() => [...standIns.keys()], [standIns]);\n\n const { width, height, positions: laidOut, groups: groupBoxes } = useMemo(\n () => layoutNodes(nodes, edges, { layout, nodeWidth, nodeHeight, compactNodeHeight, records, collapsed, recordHeaderHeight, columnGap, rowGap }),\n [layout, nodes, edges, nodeWidth, nodeHeight, compactNodeHeight, records, collapsed, recordHeaderHeight, columnGap, rowGap],\n );\n const nodeHeights = useMemo(\n () => compactHeights(nodes, layout, compactNodeHeight, new Set(standIns.values()), recordHeaderHeight),\n [nodes, layout, compactNodeHeight, standIns, recordHeaderHeight],\n );\n\n const panZoom = usePanZoom({\n enabled: zoomable,\n wheel: wheelZoom,\n contentWidth: width,\n contentHeight: height,\n opening: openingFit(laidOut, fitMinScale, focusId),\n });\n const windows = useGroupWindows({ boxes: groupBoxes, positions: laidOut, reveal: selectedId ?? focusId, stageRef: panZoom.contentRef, scale: zoomable ? panZoom.transform.scale : 1 });\n const { positions } = windows;\n const routes = useMemo(\n () =>\n routeEdges(edges, positions, { nodeWidth, nodeHeight, nodeHeights }, { anchor: layout === \"columns\" ? \"side\" : \"center\" }),\n [edges, positions, nodeWidth, nodeHeight, nodeHeights, layout],\n );\n const drawnNodes = useMemo(() => {\n const standing = new Set(standIns.values());\n return nodes.filter((node) => !windows.hidden.has(node.id) && !standing.has(node.id));\n }, [nodes, windows.hidden, standIns]);\n const windowOf = useMemo(\n () => new Map(groupBoxes.flatMap((box) => (box.window ? box.window.members.map((id): [string, string] => [id, box.id]) : []))),\n [groupBoxes],\n );\n const natural = layout === \"columns\" || zoomable;\n const place: GraphPlacer = natural\n ? ({ x, y }) => ({ left: x, top: y })\n : ({ x, y }) => ({ left: toPercent(x, width), top: toPercent(y, height) });\n const focus = useEdgeFocus({ mode: edgeFocus, edges, selectedId, selectedEdgeId });\n const edgeSelection = { selectedEdgeId, onEdgeSelect, focus: focus.state };\n\n return (\n <div\n ref={panZoom.viewportRef}\n className={cn(\n \"w-full\",\n zoomable ? \"relative touch-none overflow-hidden\" : \"overflow-auto\",\n zoomable && (panZoom.panning ? \"cursor-grabbing select-none\" : \"cursor-grab\"),\n className,\n )}\n style={maxHeight != null ? { maxHeight } : undefined}\n {...panZoom.handlers}\n >\n <div\n ref={panZoom.contentRef}\n data-graph-stage=\"\"\n className={cn(\"relative\", natural ? !zoomable && \"mx-auto\" : \"w-full\")}\n style={stageStyle({ width, height }, natural, zoomable ? panZoom : undefined)}\n >\n <GraphDiagramGroupBoxes boxes={groupBoxes} groups={groups} starts={windows.starts} onScroll={windows.scroll} onGroupToggle={onGroupToggle}\n standIns={standIns} selectedId={selectedId} onNodeSelect={onNodeSelect} />\n <GraphDiagramEdgePaths\n edges={edges}\n nodes={nodes}\n routes={routes}\n width={width}\n height={height}\n ariaLabel={ariaLabel}\n markerPrefix={markerPrefix}\n onEdgeHover={focus.onEdgeHover}\n {...edgeSelection}\n />\n <div className=\"pointer-events-none absolute inset-0\">\n <GraphDiagramEdgeLabels edges={edges} routes={routes} place={place} spread={natural} {...edgeSelection} />\n <GraphDiagramNodes\n nodes={drawnNodes}\n positions={positions}\n windowOf={windowOf}\n place={place}\n nodeWidth={nodeWidth}\n nodeHeight={nodeHeight}\n nodeHeights={nodeHeights}\n recordNodes={recordNodes}\n selectedId={selectedId}\n onNodeSelect={onNodeSelect}\n onNodeExpand={onNodeExpand}\n onNodeHover={focus.onNodeHover}\n />\n </div>\n </div>\n {zoomable && <ZoomControls panZoom={panZoom} resettable={fitMinScale !== undefined} />}\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const jsxRuntime = require("react/jsx-runtime");
4
+ const IconButton = require("../components/IconButton.cjs");
5
+ const utils = require("../lib/utils.cjs");
6
+ const graphGroupWindow = require("./graph-group-window.cjs");
7
+ const graphDiagramModel = require("./graph-diagram-model.cjs");
8
+ const UiChevronRight = require("../icons/components/UiChevronRight.cjs");
9
+ const UiChevronDown = require("../icons/components/UiChevronDown.cjs");
10
+ const UiChevronUp = require("../icons/components/UiChevronUp.cjs");
11
+ function Chevron({ group, name, onToggle }) {
12
+ const collapsed = group.collapsed === true;
13
+ return /* @__PURE__ */ jsxRuntime.jsx(
14
+ IconButton.IconButton,
15
+ {
16
+ icon: collapsed ? UiChevronRight.UiChevronRight : UiChevronDown.UiChevronDown,
17
+ label: `${collapsed ? "Expand" : "Collapse"} ${name}`,
18
+ "aria-expanded": !collapsed,
19
+ className: "pointer-events-auto size-4",
20
+ onClick: onToggle
21
+ }
22
+ );
23
+ }
24
+ function Header({ box, caption, title, chevron, aside, select }) {
25
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-graph-record-header": "", title, className: "pointer-events-auto flex items-center gap-1 bg-muted px-1.5 text-[11px] font-semibold", style: { height: box.headerHeight }, children: [
26
+ chevron,
27
+ select ? /* @__PURE__ */ jsxRuntime.jsx(
28
+ "button",
29
+ {
30
+ type: "button",
31
+ "aria-label": `Select ${select.name}`,
32
+ "aria-pressed": select.selected,
33
+ onClick: select.onSelect,
34
+ className: utils.cn("min-w-0 truncate rounded-sm text-left hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", select.selected && "text-primary"),
35
+ children: caption
36
+ }
37
+ ) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 truncate", children: caption }),
38
+ aside != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-auto shrink-0 pl-2 text-[10px] font-normal text-muted-foreground", children: aside })
39
+ ] });
40
+ }
41
+ function WindowFooter({ box, rows, start, name, onScroll }) {
42
+ const { first, last, total } = graphGroupWindow.windowRows(rows, start);
43
+ return /* @__PURE__ */ jsxRuntime.jsxs(
44
+ "div",
45
+ {
46
+ "data-graph-window-footer": "",
47
+ className: "pointer-events-auto absolute inset-x-0 flex items-center gap-1 px-2 text-[10px] text-muted-foreground",
48
+ style: { top: rows.top + rows.height - box.y, height: rows.footerHeight },
49
+ children: [
50
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "min-w-0 flex-1 truncate tabular-nums", children: [
51
+ "rows ",
52
+ first,
53
+ "–",
54
+ last,
55
+ " of ",
56
+ total
57
+ ] }),
58
+ /* @__PURE__ */ jsxRuntime.jsx(IconButton.IconButton, { icon: UiChevronUp.UiChevronUp, label: `Scroll ${name} up`, className: "size-4", disabled: first === 1, onClick: () => onScroll(-rows.rows) }),
59
+ /* @__PURE__ */ jsxRuntime.jsx(IconButton.IconButton, { icon: UiChevronDown.UiChevronDown, label: `Scroll ${name} down`, className: "size-4", disabled: last === total, onClick: () => onScroll(rows.rows) })
60
+ ]
61
+ }
62
+ );
63
+ }
64
+ function GraphDiagramGroupBoxes({ boxes, groups, starts, onScroll, onGroupToggle, standIns, selectedId, onNodeSelect }) {
65
+ const entries = new Map(groups == null ? void 0 : groups.map((group) => [group.id, group]));
66
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: boxes.map((box) => {
67
+ const group = entries.get(box.group);
68
+ const name = graphDiagramModel.groupName(group, box.group);
69
+ const caption = group ? group.label : box.group;
70
+ const chevron = group && group.collapsed !== void 0 && onGroupToggle ? /* @__PURE__ */ jsxRuntime.jsx(Chevron, { group, name, onToggle: () => onGroupToggle(box.group) }) : null;
71
+ const standIn = box.collapsed ? standIns.get(box.group) : void 0;
72
+ const select = standIn !== void 0 && onNodeSelect ? { name, selected: selectedId === standIn, onSelect: () => onNodeSelect(standIn) } : void 0;
73
+ return /* @__PURE__ */ jsxRuntime.jsxs(
74
+ "div",
75
+ {
76
+ "data-graph-group": box.id,
77
+ "data-graph-group-variant": box.record ? "record" : "box",
78
+ ...box.collapsed ? { "data-graph-group-collapsed": "" } : {},
79
+ ...box.window ? { "data-graph-window": box.id } : {},
80
+ className: utils.cn(
81
+ "absolute border border-border",
82
+ box.window ? "pointer-events-auto" : "pointer-events-none",
83
+ box.record || box.collapsed ? "overflow-hidden rounded-md bg-card shadow-sm" : "rounded-xl bg-muted/30",
84
+ !box.record && "border-dashed"
85
+ ),
86
+ style: { left: box.x, top: box.y, width: box.width, height: box.height },
87
+ children: [
88
+ box.record || box.collapsed ? /* @__PURE__ */ jsxRuntime.jsx(Header, { box, caption, title: group == null ? void 0 : group.title, chevron, aside: group == null ? void 0 : group.aside, select }) : /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pointer-events-auto absolute left-2 top-0 flex max-w-[calc(100%-1rem)] -translate-y-1/2 items-center gap-0.5 rounded border border-border bg-background px-1.5 text-[10px] font-medium leading-4 text-muted-foreground", children: [
89
+ chevron,
90
+ /* @__PURE__ */ jsxRuntime.jsx("span", { title: group == null ? void 0 : group.title, className: "pointer-events-auto min-w-0 truncate", children: caption })
91
+ ] }),
92
+ box.window && /* @__PURE__ */ jsxRuntime.jsx(WindowFooter, { box, rows: box.window, start: starts[box.id] ?? 0, name, onScroll: (rows) => onScroll(box.id, rows) })
93
+ ]
94
+ },
95
+ box.id
96
+ );
97
+ }) });
98
+ }
99
+ exports.GraphDiagramGroupBoxes = GraphDiagramGroupBoxes;
100
+ //# sourceMappingURL=GraphDiagramGroups.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GraphDiagramGroups.cjs","sources":["../../src/data/GraphDiagramGroups.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { IconButton } from \"../components/IconButton\";\nimport { UiChevronDown, UiChevronRight, UiChevronUp } from \"../icons\";\nimport { cn } from \"../lib/utils\";\nimport type { GraphLayoutGroupBox, GroupMemberWindow } from \"./graph-columns-layout\";\nimport { windowRows, type WindowStarts } from \"./graph-group-window\";\nimport { groupName, type GraphDiagramGroup } from \"./graph-diagram-model\";\n\nexport interface GraphDiagramGroupBoxesProps {\n boxes: GraphLayoutGroupBox[];\n groups: GraphDiagramGroup[] | undefined;\n /** Window starts by box id. */\n starts: WindowStarts;\n onScroll: (boxId: string, rows: number) => void;\n /** Shows a chevron on every group whose `collapsed` is set. */\n onGroupToggle: ((groupId: string) => void) | undefined;\n /** The stand-in node of each collapsed group, by group id: its header selects it. */\n standIns: ReadonlyMap<string, string>;\n selectedId: string | undefined;\n onNodeSelect: ((id: string) => void) | undefined;\n}\n\nfunction Chevron({ group, name, onToggle }: { group: GraphDiagramGroup; name: string; onToggle: () => void }) {\n const collapsed = group.collapsed === true;\n return (\n <IconButton icon={collapsed ? UiChevronRight : UiChevronDown} label={`${collapsed ? \"Expand\" : \"Collapse\"} ${name}`} aria-expanded={!collapsed}\n className=\"pointer-events-auto size-4\" onClick={onToggle} />\n );\n}\n\n/** A record's header, or a collapsed group's whole box: chevron, caption, and what it holds. */\nfunction Header({ box, caption, title, chevron, aside, select }: {\n box: GraphLayoutGroupBox;\n caption: ReactNode;\n title: string | undefined;\n chevron: ReactNode;\n aside: ReactNode;\n select: { name: string; selected: boolean; onSelect: () => void } | undefined;\n}) {\n return (\n <div data-graph-record-header=\"\" title={title} className=\"pointer-events-auto flex items-center gap-1 bg-muted px-1.5 text-[11px] font-semibold\" style={{ height: box.headerHeight }}>\n {chevron}\n {select ? (\n <button type=\"button\" aria-label={`Select ${select.name}`} aria-pressed={select.selected} onClick={select.onSelect}\n className={cn(\"min-w-0 truncate rounded-sm text-left hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\", select.selected && \"text-primary\")}>\n {caption}\n </button>\n ) : <span className=\"min-w-0 truncate\">{caption}</span>}\n {aside != null && <span className=\"ml-auto shrink-0 pl-2 text-[10px] font-normal text-muted-foreground\">{aside}</span>}\n </div>\n );\n}\n\n/** \"rows a–b of n\" under a windowed group's rows, with buttons that page it. */\nfunction WindowFooter({ box, rows, start, name, onScroll }: { box: GraphLayoutGroupBox; rows: GroupMemberWindow; start: number; name: string; onScroll: (rows: number) => void }) {\n const { first, last, total } = windowRows(rows, start);\n return (\n <div data-graph-window-footer=\"\" className=\"pointer-events-auto absolute inset-x-0 flex items-center gap-1 px-2 text-[10px] text-muted-foreground\"\n style={{ top: rows.top + rows.height - box.y, height: rows.footerHeight }}>\n <span className=\"min-w-0 flex-1 truncate tabular-nums\">rows {first}–{last} of {total}</span>\n <IconButton icon={UiChevronUp} label={`Scroll ${name} up`} className=\"size-4\" disabled={first === 1} onClick={() => onScroll(-rows.rows)} />\n <IconButton icon={UiChevronDown} label={`Scroll ${name} down`} className=\"size-4\" disabled={last === total} onClick={() => onScroll(rows.rows)} />\n </div>\n );\n}\n\n/**\n * Group rectangles, drawn behind the edges and nodes. A record is captioned by a header, a box on its top\n * border; a collapsed group is its header alone. A box lets the pointer through to the stage, so a click\n * inside it never lands on the box; only its caption, chevron and footer take the pointer. A windowed box\n * takes the wheel too, to scroll its members.\n */\nexport function GraphDiagramGroupBoxes({ boxes, groups, starts, onScroll, onGroupToggle, standIns, selectedId, onNodeSelect }: GraphDiagramGroupBoxesProps) {\n const entries = new Map(groups?.map((group) => [group.id, group]));\n return (\n <>\n {boxes.map((box) => {\n const group = entries.get(box.group);\n const name = groupName(group, box.group);\n const caption = group ? group.label : box.group;\n const chevron = group && group.collapsed !== undefined && onGroupToggle ? <Chevron group={group} name={name} onToggle={() => onGroupToggle(box.group)} /> : null;\n const standIn = box.collapsed ? standIns.get(box.group) : undefined;\n const select = standIn !== undefined && onNodeSelect ? { name, selected: selectedId === standIn, onSelect: () => onNodeSelect(standIn) } : undefined;\n return (\n <div\n key={box.id}\n data-graph-group={box.id}\n data-graph-group-variant={box.record ? \"record\" : \"box\"}\n {...(box.collapsed ? { \"data-graph-group-collapsed\": \"\" } : {})}\n {...(box.window ? { \"data-graph-window\": box.id } : {})}\n className={cn(\n \"absolute border border-border\",\n box.window ? \"pointer-events-auto\" : \"pointer-events-none\",\n box.record || box.collapsed ? \"overflow-hidden rounded-md bg-card shadow-sm\" : \"rounded-xl bg-muted/30\",\n !box.record && \"border-dashed\",\n )}\n style={{ left: box.x, top: box.y, width: box.width, height: box.height }}\n >\n {box.record || box.collapsed ? (\n <Header box={box} caption={caption} title={group?.title} chevron={chevron} aside={group?.aside} select={select} />\n ) : (\n <span className=\"pointer-events-auto absolute left-2 top-0 flex max-w-[calc(100%-1rem)] -translate-y-1/2 items-center gap-0.5 rounded border border-border bg-background px-1.5 text-[10px] font-medium leading-4 text-muted-foreground\">\n {chevron}\n <span title={group?.title} className=\"pointer-events-auto min-w-0 truncate\">{caption}</span>\n </span>\n )}\n {box.window && <WindowFooter box={box} rows={box.window} start={starts[box.id] ?? 0} name={name} onScroll={(rows) => onScroll(box.id, rows)} />}\n </div>\n );\n })}\n </>\n );\n}\n"],"names":["jsx","IconButton","UiChevronRight","UiChevronDown","jsxs","cn","windowRows","UiChevronUp","Fragment","groupName"],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { GraphLayoutGroupBox } from './graph-columns-layout.js';
2
+ import { WindowStarts } from './graph-group-window.js';
3
+ import { GraphDiagramGroup } from './graph-diagram-model.js';
4
+ export interface GraphDiagramGroupBoxesProps {
5
+ boxes: GraphLayoutGroupBox[];
6
+ groups: GraphDiagramGroup[] | undefined;
7
+ /** Window starts by box id. */
8
+ starts: WindowStarts;
9
+ onScroll: (boxId: string, rows: number) => void;
10
+ /** Shows a chevron on every group whose `collapsed` is set. */
11
+ onGroupToggle: ((groupId: string) => void) | undefined;
12
+ /** The stand-in node of each collapsed group, by group id: its header selects it. */
13
+ standIns: ReadonlyMap<string, string>;
14
+ selectedId: string | undefined;
15
+ onNodeSelect: ((id: string) => void) | undefined;
16
+ }
17
+ /**
18
+ * Group rectangles, drawn behind the edges and nodes. A record is captioned by a header, a box on its top
19
+ * border; a collapsed group is its header alone. A box lets the pointer through to the stage, so a click
20
+ * inside it never lands on the box; only its caption, chevron and footer take the pointer. A windowed box
21
+ * takes the wheel too, to scroll its members.
22
+ */
23
+ export declare function GraphDiagramGroupBoxes({ boxes, groups, starts, onScroll, onGroupToggle, standIns, selectedId, onNodeSelect }: GraphDiagramGroupBoxesProps): import("react").JSX.Element;
24
+ //# sourceMappingURL=GraphDiagramGroups.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GraphDiagramGroups.d.ts","sourceRoot":"","sources":["../../src/data/GraphDiagramGroups.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,mBAAmB,EAAqB,MAAM,wBAAwB,CAAC;AACrF,OAAO,EAAc,KAAK,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,EAAa,KAAK,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE1E,MAAM,WAAW,2BAA2B;IAC1C,KAAK,EAAE,mBAAmB,EAAE,CAAC;IAC7B,MAAM,EAAE,iBAAiB,EAAE,GAAG,SAAS,CAAC;IACxC,+BAA+B;IAC/B,MAAM,EAAE,YAAY,CAAC;IACrB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,+DAA+D;IAC/D,aAAa,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACvD,qFAAqF;IACrF,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,YAAY,EAAE,CAAC,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;CAClD;AA8CD;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,QAAQ,EAAE,UAAU,EAAE,YAAY,EAAE,EAAE,2BAA2B,+BAwCzJ"}
@@ -0,0 +1,100 @@
1
+ import { jsx, Fragment, jsxs } from "react/jsx-runtime";
2
+ import { IconButton } from "../components/IconButton.js";
3
+ import { cn } from "../lib/utils.js";
4
+ import { windowRows } from "./graph-group-window.js";
5
+ import { groupName } from "./graph-diagram-model.js";
6
+ import { UiChevronRight } from "../icons/components/UiChevronRight.js";
7
+ import { UiChevronDown } from "../icons/components/UiChevronDown.js";
8
+ import { UiChevronUp } from "../icons/components/UiChevronUp.js";
9
+ function Chevron({ group, name, onToggle }) {
10
+ const collapsed = group.collapsed === true;
11
+ return /* @__PURE__ */ jsx(
12
+ IconButton,
13
+ {
14
+ icon: collapsed ? UiChevronRight : UiChevronDown,
15
+ label: `${collapsed ? "Expand" : "Collapse"} ${name}`,
16
+ "aria-expanded": !collapsed,
17
+ className: "pointer-events-auto size-4",
18
+ onClick: onToggle
19
+ }
20
+ );
21
+ }
22
+ function Header({ box, caption, title, chevron, aside, select }) {
23
+ return /* @__PURE__ */ jsxs("div", { "data-graph-record-header": "", title, className: "pointer-events-auto flex items-center gap-1 bg-muted px-1.5 text-[11px] font-semibold", style: { height: box.headerHeight }, children: [
24
+ chevron,
25
+ select ? /* @__PURE__ */ jsx(
26
+ "button",
27
+ {
28
+ type: "button",
29
+ "aria-label": `Select ${select.name}`,
30
+ "aria-pressed": select.selected,
31
+ onClick: select.onSelect,
32
+ className: cn("min-w-0 truncate rounded-sm text-left hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", select.selected && "text-primary"),
33
+ children: caption
34
+ }
35
+ ) : /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children: caption }),
36
+ aside != null && /* @__PURE__ */ jsx("span", { className: "ml-auto shrink-0 pl-2 text-[10px] font-normal text-muted-foreground", children: aside })
37
+ ] });
38
+ }
39
+ function WindowFooter({ box, rows, start, name, onScroll }) {
40
+ const { first, last, total } = windowRows(rows, start);
41
+ return /* @__PURE__ */ jsxs(
42
+ "div",
43
+ {
44
+ "data-graph-window-footer": "",
45
+ className: "pointer-events-auto absolute inset-x-0 flex items-center gap-1 px-2 text-[10px] text-muted-foreground",
46
+ style: { top: rows.top + rows.height - box.y, height: rows.footerHeight },
47
+ children: [
48
+ /* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1 truncate tabular-nums", children: [
49
+ "rows ",
50
+ first,
51
+ "–",
52
+ last,
53
+ " of ",
54
+ total
55
+ ] }),
56
+ /* @__PURE__ */ jsx(IconButton, { icon: UiChevronUp, label: `Scroll ${name} up`, className: "size-4", disabled: first === 1, onClick: () => onScroll(-rows.rows) }),
57
+ /* @__PURE__ */ jsx(IconButton, { icon: UiChevronDown, label: `Scroll ${name} down`, className: "size-4", disabled: last === total, onClick: () => onScroll(rows.rows) })
58
+ ]
59
+ }
60
+ );
61
+ }
62
+ function GraphDiagramGroupBoxes({ boxes, groups, starts, onScroll, onGroupToggle, standIns, selectedId, onNodeSelect }) {
63
+ const entries = new Map(groups == null ? void 0 : groups.map((group) => [group.id, group]));
64
+ return /* @__PURE__ */ jsx(Fragment, { children: boxes.map((box) => {
65
+ const group = entries.get(box.group);
66
+ const name = groupName(group, box.group);
67
+ const caption = group ? group.label : box.group;
68
+ const chevron = group && group.collapsed !== void 0 && onGroupToggle ? /* @__PURE__ */ jsx(Chevron, { group, name, onToggle: () => onGroupToggle(box.group) }) : null;
69
+ const standIn = box.collapsed ? standIns.get(box.group) : void 0;
70
+ const select = standIn !== void 0 && onNodeSelect ? { name, selected: selectedId === standIn, onSelect: () => onNodeSelect(standIn) } : void 0;
71
+ return /* @__PURE__ */ jsxs(
72
+ "div",
73
+ {
74
+ "data-graph-group": box.id,
75
+ "data-graph-group-variant": box.record ? "record" : "box",
76
+ ...box.collapsed ? { "data-graph-group-collapsed": "" } : {},
77
+ ...box.window ? { "data-graph-window": box.id } : {},
78
+ className: cn(
79
+ "absolute border border-border",
80
+ box.window ? "pointer-events-auto" : "pointer-events-none",
81
+ box.record || box.collapsed ? "overflow-hidden rounded-md bg-card shadow-sm" : "rounded-xl bg-muted/30",
82
+ !box.record && "border-dashed"
83
+ ),
84
+ style: { left: box.x, top: box.y, width: box.width, height: box.height },
85
+ children: [
86
+ box.record || box.collapsed ? /* @__PURE__ */ jsx(Header, { box, caption, title: group == null ? void 0 : group.title, chevron, aside: group == null ? void 0 : group.aside, select }) : /* @__PURE__ */ jsxs("span", { className: "pointer-events-auto absolute left-2 top-0 flex max-w-[calc(100%-1rem)] -translate-y-1/2 items-center gap-0.5 rounded border border-border bg-background px-1.5 text-[10px] font-medium leading-4 text-muted-foreground", children: [
87
+ chevron,
88
+ /* @__PURE__ */ jsx("span", { title: group == null ? void 0 : group.title, className: "pointer-events-auto min-w-0 truncate", children: caption })
89
+ ] }),
90
+ box.window && /* @__PURE__ */ jsx(WindowFooter, { box, rows: box.window, start: starts[box.id] ?? 0, name, onScroll: (rows) => onScroll(box.id, rows) })
91
+ ]
92
+ },
93
+ box.id
94
+ );
95
+ }) });
96
+ }
97
+ export {
98
+ GraphDiagramGroupBoxes
99
+ };
100
+ //# sourceMappingURL=GraphDiagramGroups.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GraphDiagramGroups.js","sources":["../../src/data/GraphDiagramGroups.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { IconButton } from \"../components/IconButton\";\nimport { UiChevronDown, UiChevronRight, UiChevronUp } from \"../icons\";\nimport { cn } from \"../lib/utils\";\nimport type { GraphLayoutGroupBox, GroupMemberWindow } from \"./graph-columns-layout\";\nimport { windowRows, type WindowStarts } from \"./graph-group-window\";\nimport { groupName, type GraphDiagramGroup } from \"./graph-diagram-model\";\n\nexport interface GraphDiagramGroupBoxesProps {\n boxes: GraphLayoutGroupBox[];\n groups: GraphDiagramGroup[] | undefined;\n /** Window starts by box id. */\n starts: WindowStarts;\n onScroll: (boxId: string, rows: number) => void;\n /** Shows a chevron on every group whose `collapsed` is set. */\n onGroupToggle: ((groupId: string) => void) | undefined;\n /** The stand-in node of each collapsed group, by group id: its header selects it. */\n standIns: ReadonlyMap<string, string>;\n selectedId: string | undefined;\n onNodeSelect: ((id: string) => void) | undefined;\n}\n\nfunction Chevron({ group, name, onToggle }: { group: GraphDiagramGroup; name: string; onToggle: () => void }) {\n const collapsed = group.collapsed === true;\n return (\n <IconButton icon={collapsed ? UiChevronRight : UiChevronDown} label={`${collapsed ? \"Expand\" : \"Collapse\"} ${name}`} aria-expanded={!collapsed}\n className=\"pointer-events-auto size-4\" onClick={onToggle} />\n );\n}\n\n/** A record's header, or a collapsed group's whole box: chevron, caption, and what it holds. */\nfunction Header({ box, caption, title, chevron, aside, select }: {\n box: GraphLayoutGroupBox;\n caption: ReactNode;\n title: string | undefined;\n chevron: ReactNode;\n aside: ReactNode;\n select: { name: string; selected: boolean; onSelect: () => void } | undefined;\n}) {\n return (\n <div data-graph-record-header=\"\" title={title} className=\"pointer-events-auto flex items-center gap-1 bg-muted px-1.5 text-[11px] font-semibold\" style={{ height: box.headerHeight }}>\n {chevron}\n {select ? (\n <button type=\"button\" aria-label={`Select ${select.name}`} aria-pressed={select.selected} onClick={select.onSelect}\n className={cn(\"min-w-0 truncate rounded-sm text-left hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\", select.selected && \"text-primary\")}>\n {caption}\n </button>\n ) : <span className=\"min-w-0 truncate\">{caption}</span>}\n {aside != null && <span className=\"ml-auto shrink-0 pl-2 text-[10px] font-normal text-muted-foreground\">{aside}</span>}\n </div>\n );\n}\n\n/** \"rows a–b of n\" under a windowed group's rows, with buttons that page it. */\nfunction WindowFooter({ box, rows, start, name, onScroll }: { box: GraphLayoutGroupBox; rows: GroupMemberWindow; start: number; name: string; onScroll: (rows: number) => void }) {\n const { first, last, total } = windowRows(rows, start);\n return (\n <div data-graph-window-footer=\"\" className=\"pointer-events-auto absolute inset-x-0 flex items-center gap-1 px-2 text-[10px] text-muted-foreground\"\n style={{ top: rows.top + rows.height - box.y, height: rows.footerHeight }}>\n <span className=\"min-w-0 flex-1 truncate tabular-nums\">rows {first}–{last} of {total}</span>\n <IconButton icon={UiChevronUp} label={`Scroll ${name} up`} className=\"size-4\" disabled={first === 1} onClick={() => onScroll(-rows.rows)} />\n <IconButton icon={UiChevronDown} label={`Scroll ${name} down`} className=\"size-4\" disabled={last === total} onClick={() => onScroll(rows.rows)} />\n </div>\n );\n}\n\n/**\n * Group rectangles, drawn behind the edges and nodes. A record is captioned by a header, a box on its top\n * border; a collapsed group is its header alone. A box lets the pointer through to the stage, so a click\n * inside it never lands on the box; only its caption, chevron and footer take the pointer. A windowed box\n * takes the wheel too, to scroll its members.\n */\nexport function GraphDiagramGroupBoxes({ boxes, groups, starts, onScroll, onGroupToggle, standIns, selectedId, onNodeSelect }: GraphDiagramGroupBoxesProps) {\n const entries = new Map(groups?.map((group) => [group.id, group]));\n return (\n <>\n {boxes.map((box) => {\n const group = entries.get(box.group);\n const name = groupName(group, box.group);\n const caption = group ? group.label : box.group;\n const chevron = group && group.collapsed !== undefined && onGroupToggle ? <Chevron group={group} name={name} onToggle={() => onGroupToggle(box.group)} /> : null;\n const standIn = box.collapsed ? standIns.get(box.group) : undefined;\n const select = standIn !== undefined && onNodeSelect ? { name, selected: selectedId === standIn, onSelect: () => onNodeSelect(standIn) } : undefined;\n return (\n <div\n key={box.id}\n data-graph-group={box.id}\n data-graph-group-variant={box.record ? \"record\" : \"box\"}\n {...(box.collapsed ? { \"data-graph-group-collapsed\": \"\" } : {})}\n {...(box.window ? { \"data-graph-window\": box.id } : {})}\n className={cn(\n \"absolute border border-border\",\n box.window ? \"pointer-events-auto\" : \"pointer-events-none\",\n box.record || box.collapsed ? \"overflow-hidden rounded-md bg-card shadow-sm\" : \"rounded-xl bg-muted/30\",\n !box.record && \"border-dashed\",\n )}\n style={{ left: box.x, top: box.y, width: box.width, height: box.height }}\n >\n {box.record || box.collapsed ? (\n <Header box={box} caption={caption} title={group?.title} chevron={chevron} aside={group?.aside} select={select} />\n ) : (\n <span className=\"pointer-events-auto absolute left-2 top-0 flex max-w-[calc(100%-1rem)] -translate-y-1/2 items-center gap-0.5 rounded border border-border bg-background px-1.5 text-[10px] font-medium leading-4 text-muted-foreground\">\n {chevron}\n <span title={group?.title} className=\"pointer-events-auto min-w-0 truncate\">{caption}</span>\n </span>\n )}\n {box.window && <WindowFooter box={box} rows={box.window} start={starts[box.id] ?? 0} name={name} onScroll={(rows) => onScroll(box.id, rows)} />}\n </div>\n );\n })}\n </>\n );\n}\n"],"names":[],"mappings":"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"}