@flanksource/clicky-ui 0.3.43 → 0.3.45

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 (483) hide show
  1. package/README.md +2 -0
  2. package/dist/ai.cjs +4 -2
  3. package/dist/ai.cjs.map +1 -1
  4. package/dist/ai.js +3 -1
  5. package/dist/components/MdxEditorField.cjs +40 -22
  6. package/dist/components/MdxEditorField.cjs.map +1 -1
  7. package/dist/components/MdxEditorField.d.ts.map +1 -1
  8. package/dist/components/MdxEditorField.js +41 -23
  9. package/dist/components/MdxEditorField.js.map +1 -1
  10. package/dist/components/json-schema-form-item-summary.cjs +6 -1
  11. package/dist/components/json-schema-form-item-summary.cjs.map +1 -1
  12. package/dist/components/json-schema-form-item-summary.d.ts.map +1 -1
  13. package/dist/components/json-schema-form-item-summary.js +6 -1
  14. package/dist/components/json-schema-form-item-summary.js.map +1 -1
  15. package/dist/data/CodeBlock.cjs +3 -2
  16. package/dist/data/CodeBlock.cjs.map +1 -1
  17. package/dist/data/CodeBlock.d.ts +3 -1
  18. package/dist/data/CodeBlock.d.ts.map +1 -1
  19. package/dist/data/CodeBlock.js +3 -2
  20. package/dist/data/CodeBlock.js.map +1 -1
  21. package/dist/data/CodeLine.cjs +22 -0
  22. package/dist/data/CodeLine.cjs.map +1 -0
  23. package/dist/data/CodeLine.d.ts +8 -0
  24. package/dist/data/CodeLine.d.ts.map +1 -0
  25. package/dist/data/CodeLine.js +22 -0
  26. package/dist/data/CodeLine.js.map +1 -0
  27. package/dist/data/GraphDiagram.cjs +18 -6
  28. package/dist/data/GraphDiagram.cjs.map +1 -1
  29. package/dist/data/GraphDiagram.d.ts +9 -1
  30. package/dist/data/GraphDiagram.d.ts.map +1 -1
  31. package/dist/data/GraphDiagram.js +18 -6
  32. package/dist/data/GraphDiagram.js.map +1 -1
  33. package/dist/data/GraphDiagramNodes.cjs +38 -29
  34. package/dist/data/GraphDiagramNodes.cjs.map +1 -1
  35. package/dist/data/GraphDiagramNodes.d.ts +8 -2
  36. package/dist/data/GraphDiagramNodes.d.ts.map +1 -1
  37. package/dist/data/GraphDiagramNodes.js +38 -29
  38. package/dist/data/GraphDiagramNodes.js.map +1 -1
  39. package/dist/data/JsonView.cjs +118 -49
  40. package/dist/data/JsonView.cjs.map +1 -1
  41. package/dist/data/JsonView.d.ts +13 -10
  42. package/dist/data/JsonView.d.ts.map +1 -1
  43. package/dist/data/JsonView.js +118 -49
  44. package/dist/data/JsonView.js.map +1 -1
  45. package/dist/data/MarkdownEditor.cjs +2 -2
  46. package/dist/data/MarkdownEditor.cjs.map +1 -1
  47. package/dist/data/MarkdownEditor.js +2 -2
  48. package/dist/data/MarkdownEditor.js.map +1 -1
  49. package/dist/data/ai/AdvancedChatConfig.cjs +90 -249
  50. package/dist/data/ai/AdvancedChatConfig.cjs.map +1 -1
  51. package/dist/data/ai/AdvancedChatConfig.d.ts +2 -5
  52. package/dist/data/ai/AdvancedChatConfig.d.ts.map +1 -1
  53. package/dist/data/ai/AdvancedChatConfig.js +91 -250
  54. package/dist/data/ai/AdvancedChatConfig.js.map +1 -1
  55. package/dist/data/ai/ChatButton.cjs +2 -0
  56. package/dist/data/ai/ChatButton.cjs.map +1 -1
  57. package/dist/data/ai/ChatButton.d.ts +1 -1
  58. package/dist/data/ai/ChatButton.d.ts.map +1 -1
  59. package/dist/data/ai/ChatButton.js +2 -0
  60. package/dist/data/ai/ChatButton.js.map +1 -1
  61. package/dist/data/ai/ChatFab.cjs +5 -1
  62. package/dist/data/ai/ChatFab.cjs.map +1 -1
  63. package/dist/data/ai/ChatFab.d.ts +5 -1
  64. package/dist/data/ai/ChatFab.d.ts.map +1 -1
  65. package/dist/data/ai/ChatFab.js +5 -1
  66. package/dist/data/ai/ChatFab.js.map +1 -1
  67. package/dist/data/ai/ChatWindow.cjs +2 -8
  68. package/dist/data/ai/ChatWindow.cjs.map +1 -1
  69. package/dist/data/ai/ChatWindow.d.ts.map +1 -1
  70. package/dist/data/ai/ChatWindow.js +2 -8
  71. package/dist/data/ai/ChatWindow.js.map +1 -1
  72. package/dist/data/ai/ChatWindow.runtime.cjs +0 -5
  73. package/dist/data/ai/ChatWindow.runtime.cjs.map +1 -1
  74. package/dist/data/ai/ChatWindow.runtime.d.ts +0 -2
  75. package/dist/data/ai/ChatWindow.runtime.d.ts.map +1 -1
  76. package/dist/data/ai/ChatWindow.runtime.js +0 -5
  77. package/dist/data/ai/ChatWindow.runtime.js.map +1 -1
  78. package/dist/data/ai/PromptRunEditor/runtimeActions.cjs +2 -2
  79. package/dist/data/ai/PromptRunEditor/runtimeActions.cjs.map +1 -1
  80. package/dist/data/ai/PromptRunEditor/runtimeActions.d.ts.map +1 -1
  81. package/dist/data/ai/PromptRunEditor/runtimeActions.js +2 -2
  82. package/dist/data/ai/PromptRunEditor/runtimeActions.js.map +1 -1
  83. package/dist/data/ai/SessionInspector.approvals.cjs +3 -6
  84. package/dist/data/ai/SessionInspector.approvals.cjs.map +1 -1
  85. package/dist/data/ai/SessionInspector.approvals.js +3 -6
  86. package/dist/data/ai/SessionInspector.approvals.js.map +1 -1
  87. package/dist/data/ai/SessionViewer.cjs +13 -4
  88. package/dist/data/ai/SessionViewer.cjs.map +1 -1
  89. package/dist/data/ai/SessionViewer.d.ts +5 -1
  90. package/dist/data/ai/SessionViewer.d.ts.map +1 -1
  91. package/dist/data/ai/SessionViewer.header.cjs +1 -1
  92. package/dist/data/ai/SessionViewer.header.cjs.map +1 -1
  93. package/dist/data/ai/SessionViewer.header.js +1 -1
  94. package/dist/data/ai/SessionViewer.header.js.map +1 -1
  95. package/dist/data/ai/SessionViewer.js +13 -4
  96. package/dist/data/ai/SessionViewer.js.map +1 -1
  97. package/dist/data/ai/SessionViewer.model.cjs +2 -0
  98. package/dist/data/ai/SessionViewer.model.cjs.map +1 -1
  99. package/dist/data/ai/SessionViewer.model.d.ts +1 -0
  100. package/dist/data/ai/SessionViewer.model.d.ts.map +1 -1
  101. package/dist/data/ai/SessionViewer.model.js +2 -0
  102. package/dist/data/ai/SessionViewer.model.js.map +1 -1
  103. package/dist/data/ai/SessionViewer.rows.cjs +41 -27
  104. package/dist/data/ai/SessionViewer.rows.cjs.map +1 -1
  105. package/dist/data/ai/SessionViewer.rows.d.ts +4 -2
  106. package/dist/data/ai/SessionViewer.rows.d.ts.map +1 -1
  107. package/dist/data/ai/SessionViewer.rows.js +41 -27
  108. package/dist/data/ai/SessionViewer.rows.js.map +1 -1
  109. package/dist/data/ai/SessionViewer.tokens.cjs +35 -0
  110. package/dist/data/ai/SessionViewer.tokens.cjs.map +1 -0
  111. package/dist/data/ai/SessionViewer.tokens.d.ts +5 -0
  112. package/dist/data/ai/SessionViewer.tokens.d.ts.map +1 -0
  113. package/dist/data/ai/SessionViewer.tokens.js +35 -0
  114. package/dist/data/ai/SessionViewer.tokens.js.map +1 -0
  115. package/dist/data/ai/SessionViewer.tool-cost.cjs +128 -0
  116. package/dist/data/ai/SessionViewer.tool-cost.cjs.map +1 -0
  117. package/dist/data/ai/SessionViewer.tool-cost.d.ts +6 -0
  118. package/dist/data/ai/SessionViewer.tool-cost.d.ts.map +1 -0
  119. package/dist/data/ai/SessionViewer.tool-cost.js +128 -0
  120. package/dist/data/ai/SessionViewer.tool-cost.js.map +1 -0
  121. package/dist/data/ai/SessionViewer.tool-details.cjs +3 -1
  122. package/dist/data/ai/SessionViewer.tool-details.cjs.map +1 -1
  123. package/dist/data/ai/SessionViewer.tool-details.d.ts.map +1 -1
  124. package/dist/data/ai/SessionViewer.tool-details.js +3 -1
  125. package/dist/data/ai/SessionViewer.tool-details.js.map +1 -1
  126. package/dist/data/ai/SessionViewer.tool-row.cjs +55 -35
  127. package/dist/data/ai/SessionViewer.tool-row.cjs.map +1 -1
  128. package/dist/data/ai/SessionViewer.tool-row.d.ts +2 -1
  129. package/dist/data/ai/SessionViewer.tool-row.d.ts.map +1 -1
  130. package/dist/data/ai/SessionViewer.tool-row.js +55 -35
  131. package/dist/data/ai/SessionViewer.tool-row.js.map +1 -1
  132. package/dist/data/ai/SessionViewer.unified.d.ts +4 -0
  133. package/dist/data/ai/SessionViewer.unified.d.ts.map +1 -1
  134. package/dist/data/ai/SessionViewerMenu.cjs +18 -1
  135. package/dist/data/ai/SessionViewerMenu.cjs.map +1 -1
  136. package/dist/data/ai/SessionViewerMenu.d.ts +6 -1
  137. package/dist/data/ai/SessionViewerMenu.d.ts.map +1 -1
  138. package/dist/data/ai/SessionViewerMenu.js +18 -1
  139. package/dist/data/ai/SessionViewerMenu.js.map +1 -1
  140. package/dist/data/ai/ToolPreferences.cjs +149 -143
  141. package/dist/data/ai/ToolPreferences.cjs.map +1 -1
  142. package/dist/data/ai/ToolPreferences.d.ts +20 -6
  143. package/dist/data/ai/ToolPreferences.d.ts.map +1 -1
  144. package/dist/data/ai/ToolPreferences.js +151 -146
  145. package/dist/data/ai/ToolPreferences.js.map +1 -1
  146. package/dist/data/ai/ToolPreferences.model.cjs +14 -10
  147. package/dist/data/ai/ToolPreferences.model.cjs.map +1 -1
  148. package/dist/data/ai/ToolPreferences.model.d.ts +1 -0
  149. package/dist/data/ai/ToolPreferences.model.d.ts.map +1 -1
  150. package/dist/data/ai/ToolPreferences.model.js +15 -11
  151. package/dist/data/ai/ToolPreferences.model.js.map +1 -1
  152. package/dist/data/ai/ToolPreferencesList.cjs +1 -0
  153. package/dist/data/ai/ToolPreferencesList.cjs.map +1 -1
  154. package/dist/data/ai/ToolPreferencesList.d.ts +4 -1
  155. package/dist/data/ai/ToolPreferencesList.d.ts.map +1 -1
  156. package/dist/data/ai/ToolPreferencesList.js +2 -1
  157. package/dist/data/ai/ToolPreferencesList.js.map +1 -1
  158. package/dist/data/ai/ToolSchemaBrowser.cjs +52 -53
  159. package/dist/data/ai/ToolSchemaBrowser.cjs.map +1 -1
  160. package/dist/data/ai/ToolSchemaBrowser.d.ts +6 -3
  161. package/dist/data/ai/ToolSchemaBrowser.d.ts.map +1 -1
  162. package/dist/data/ai/ToolSchemaBrowser.directory-header.cjs +9 -13
  163. package/dist/data/ai/ToolSchemaBrowser.directory-header.cjs.map +1 -1
  164. package/dist/data/ai/ToolSchemaBrowser.directory-header.d.ts +5 -2
  165. package/dist/data/ai/ToolSchemaBrowser.directory-header.d.ts.map +1 -1
  166. package/dist/data/ai/ToolSchemaBrowser.directory-header.js +9 -13
  167. package/dist/data/ai/ToolSchemaBrowser.directory-header.js.map +1 -1
  168. package/dist/data/ai/ToolSchemaBrowser.js +53 -54
  169. package/dist/data/ai/ToolSchemaBrowser.js.map +1 -1
  170. package/dist/data/ai/ToolSchemaBrowser.model.cjs +19 -27
  171. package/dist/data/ai/ToolSchemaBrowser.model.cjs.map +1 -1
  172. package/dist/data/ai/ToolSchemaBrowser.model.d.ts +9 -6
  173. package/dist/data/ai/ToolSchemaBrowser.model.d.ts.map +1 -1
  174. package/dist/data/ai/ToolSchemaBrowser.model.js +20 -28
  175. package/dist/data/ai/ToolSchemaBrowser.model.js.map +1 -1
  176. package/dist/data/ai/ToolSchemaBrowser.sidebar.cjs +12 -213
  177. package/dist/data/ai/ToolSchemaBrowser.sidebar.cjs.map +1 -1
  178. package/dist/data/ai/ToolSchemaBrowser.sidebar.d.ts +1 -3
  179. package/dist/data/ai/ToolSchemaBrowser.sidebar.d.ts.map +1 -1
  180. package/dist/data/ai/ToolSchemaBrowser.sidebar.js +13 -214
  181. package/dist/data/ai/ToolSchemaBrowser.sidebar.js.map +1 -1
  182. package/dist/data/ai/ToolSchemaBrowser.strategies.cjs +54 -0
  183. package/dist/data/ai/ToolSchemaBrowser.strategies.cjs.map +1 -0
  184. package/dist/data/ai/ToolSchemaBrowser.strategies.d.ts +9 -0
  185. package/dist/data/ai/ToolSchemaBrowser.strategies.d.ts.map +1 -0
  186. package/dist/data/ai/ToolSchemaBrowser.strategies.js +54 -0
  187. package/dist/data/ai/ToolSchemaBrowser.strategies.js.map +1 -0
  188. package/dist/data/ai/ToolSchemaBrowser.tree.cjs +179 -0
  189. package/dist/data/ai/ToolSchemaBrowser.tree.cjs.map +1 -0
  190. package/dist/data/ai/ToolSchemaBrowser.tree.d.ts +20 -0
  191. package/dist/data/ai/ToolSchemaBrowser.tree.d.ts.map +1 -0
  192. package/dist/data/ai/ToolSchemaBrowser.tree.js +179 -0
  193. package/dist/data/ai/ToolSchemaBrowser.tree.js.map +1 -0
  194. package/dist/data/ai/index.d.ts +2 -2
  195. package/dist/data/ai/index.d.ts.map +1 -1
  196. package/dist/data/ai/runtime-profiles/PermissionStrategiesEditor.cjs +8 -28
  197. package/dist/data/ai/runtime-profiles/PermissionStrategiesEditor.cjs.map +1 -1
  198. package/dist/data/ai/runtime-profiles/PermissionStrategiesEditor.d.ts.map +1 -1
  199. package/dist/data/ai/runtime-profiles/PermissionStrategiesEditor.js +9 -29
  200. package/dist/data/ai/runtime-profiles/PermissionStrategiesEditor.js.map +1 -1
  201. package/dist/data/ai/session-token-sizing.d.ts +32 -0
  202. package/dist/data/ai/session-token-sizing.d.ts.map +1 -0
  203. package/dist/data/ai/use-session-token-sizing.cjs +73 -0
  204. package/dist/data/ai/use-session-token-sizing.cjs.map +1 -0
  205. package/dist/data/ai/use-session-token-sizing.d.ts +21 -0
  206. package/dist/data/ai/use-session-token-sizing.d.ts.map +1 -0
  207. package/dist/data/ai/use-session-token-sizing.js +73 -0
  208. package/dist/data/ai/use-session-token-sizing.js.map +1 -0
  209. package/dist/data/call-graph/CallGraph.cjs +250 -0
  210. package/dist/data/call-graph/CallGraph.cjs.map +1 -0
  211. package/dist/data/call-graph/CallGraph.d.ts +69 -0
  212. package/dist/data/call-graph/CallGraph.d.ts.map +1 -0
  213. package/dist/data/call-graph/CallGraph.js +250 -0
  214. package/dist/data/call-graph/CallGraph.js.map +1 -0
  215. package/dist/data/call-graph/CallGraphGlyphs.cjs +39 -0
  216. package/dist/data/call-graph/CallGraphGlyphs.cjs.map +1 -0
  217. package/dist/data/call-graph/CallGraphGlyphs.d.ts +19 -0
  218. package/dist/data/call-graph/CallGraphGlyphs.d.ts.map +1 -0
  219. package/dist/data/call-graph/CallGraphGlyphs.js +39 -0
  220. package/dist/data/call-graph/CallGraphGlyphs.js.map +1 -0
  221. package/dist/data/call-graph/CallGraphMembers.cjs +50 -0
  222. package/dist/data/call-graph/CallGraphMembers.cjs.map +1 -0
  223. package/dist/data/call-graph/CallGraphMembers.d.ts +22 -0
  224. package/dist/data/call-graph/CallGraphMembers.d.ts.map +1 -0
  225. package/dist/data/call-graph/CallGraphMembers.js +50 -0
  226. package/dist/data/call-graph/CallGraphMembers.js.map +1 -0
  227. package/dist/data/call-graph/CallGraphParts.cjs +204 -0
  228. package/dist/data/call-graph/CallGraphParts.cjs.map +1 -0
  229. package/dist/data/call-graph/CallGraphParts.d.ts +44 -0
  230. package/dist/data/call-graph/CallGraphParts.d.ts.map +1 -0
  231. package/dist/data/call-graph/CallGraphParts.js +204 -0
  232. package/dist/data/call-graph/CallGraphParts.js.map +1 -0
  233. package/dist/data/call-graph/CallGraphToolbar.cjs +186 -0
  234. package/dist/data/call-graph/CallGraphToolbar.cjs.map +1 -0
  235. package/dist/data/call-graph/CallGraphToolbar.d.ts +45 -0
  236. package/dist/data/call-graph/CallGraphToolbar.d.ts.map +1 -0
  237. package/dist/data/call-graph/CallGraphToolbar.js +186 -0
  238. package/dist/data/call-graph/CallGraphToolbar.js.map +1 -0
  239. package/dist/data/call-graph/call-graph-exclude.cjs +75 -0
  240. package/dist/data/call-graph/call-graph-exclude.cjs.map +1 -0
  241. package/dist/data/call-graph/call-graph-exclude.d.ts +31 -0
  242. package/dist/data/call-graph/call-graph-exclude.d.ts.map +1 -0
  243. package/dist/data/call-graph/call-graph-exclude.js +75 -0
  244. package/dist/data/call-graph/call-graph-exclude.js.map +1 -0
  245. package/dist/data/call-graph/call-graph-labels.cjs +96 -0
  246. package/dist/data/call-graph/call-graph-labels.cjs.map +1 -0
  247. package/dist/data/call-graph/call-graph-labels.d.ts +53 -0
  248. package/dist/data/call-graph/call-graph-labels.d.ts.map +1 -0
  249. package/dist/data/call-graph/call-graph-labels.js +96 -0
  250. package/dist/data/call-graph/call-graph-labels.js.map +1 -0
  251. package/dist/data/call-graph/call-graph-model.cjs +161 -0
  252. package/dist/data/call-graph/call-graph-model.cjs.map +1 -0
  253. package/dist/data/call-graph/call-graph-model.d.ts +102 -0
  254. package/dist/data/call-graph/call-graph-model.d.ts.map +1 -0
  255. package/dist/data/call-graph/call-graph-model.js +161 -0
  256. package/dist/data/call-graph/call-graph-model.js.map +1 -0
  257. package/dist/data/call-graph/call-graph-vocabulary.cjs +177 -0
  258. package/dist/data/call-graph/call-graph-vocabulary.cjs.map +1 -0
  259. package/dist/data/call-graph/call-graph-vocabulary.d.ts +72 -0
  260. package/dist/data/call-graph/call-graph-vocabulary.d.ts.map +1 -0
  261. package/dist/data/call-graph/call-graph-vocabulary.js +177 -0
  262. package/dist/data/call-graph/call-graph-vocabulary.js.map +1 -0
  263. package/dist/data/call-graph/call-graph.fixtures.d.ts +63 -0
  264. package/dist/data/call-graph/call-graph.fixtures.d.ts.map +1 -0
  265. package/dist/data/call-graph/index.d.ts +7 -0
  266. package/dist/data/call-graph/index.d.ts.map +1 -0
  267. package/dist/data/call-graph/types.cjs +5 -0
  268. package/dist/data/call-graph/types.cjs.map +1 -0
  269. package/dist/data/call-graph/types.d.ts +135 -0
  270. package/dist/data/call-graph/types.d.ts.map +1 -0
  271. package/dist/data/call-graph/types.js +5 -0
  272. package/dist/data/call-graph/types.js.map +1 -0
  273. package/dist/data/call-graph/use-call-graph.cjs +93 -0
  274. package/dist/data/call-graph/use-call-graph.cjs.map +1 -0
  275. package/dist/data/call-graph/use-call-graph.d.ts +24 -0
  276. package/dist/data/call-graph/use-call-graph.d.ts.map +1 -0
  277. package/dist/data/call-graph/use-call-graph.js +93 -0
  278. package/dist/data/call-graph/use-call-graph.js.map +1 -0
  279. package/dist/data/chat/Chat.cjs +39 -15
  280. package/dist/data/chat/Chat.cjs.map +1 -1
  281. package/dist/data/chat/Chat.d.ts.map +1 -1
  282. package/dist/data/chat/Chat.fixtures.cjs +2 -2
  283. package/dist/data/chat/Chat.fixtures.cjs.map +1 -1
  284. package/dist/data/chat/Chat.fixtures.js +2 -2
  285. package/dist/data/chat/Chat.fixtures.js.map +1 -1
  286. package/dist/data/chat/Chat.js +40 -16
  287. package/dist/data/chat/Chat.js.map +1 -1
  288. package/dist/data/chat/ChatRuntimeToolbar.cjs +3 -6
  289. package/dist/data/chat/ChatRuntimeToolbar.cjs.map +1 -1
  290. package/dist/data/chat/ChatRuntimeToolbar.d.ts.map +1 -1
  291. package/dist/data/chat/ChatRuntimeToolbar.js +3 -6
  292. package/dist/data/chat/ChatRuntimeToolbar.js.map +1 -1
  293. package/dist/data/chat/ContextMeter.bar.cjs +5 -8
  294. package/dist/data/chat/ContextMeter.bar.cjs.map +1 -1
  295. package/dist/data/chat/ContextMeter.bar.d.ts +1 -1
  296. package/dist/data/chat/ContextMeter.bar.d.ts.map +1 -1
  297. package/dist/data/chat/ContextMeter.bar.js +5 -8
  298. package/dist/data/chat/ContextMeter.bar.js.map +1 -1
  299. package/dist/data/chat/ContextMeter.cjs +18 -19
  300. package/dist/data/chat/ContextMeter.cjs.map +1 -1
  301. package/dist/data/chat/ContextMeter.d.ts +1 -1
  302. package/dist/data/chat/ContextMeter.d.ts.map +1 -1
  303. package/dist/data/chat/ContextMeter.js +18 -19
  304. package/dist/data/chat/ContextMeter.js.map +1 -1
  305. package/dist/data/chat/Conversation.cjs +2 -1
  306. package/dist/data/chat/Conversation.cjs.map +1 -1
  307. package/dist/data/chat/Conversation.d.ts +4 -1
  308. package/dist/data/chat/Conversation.d.ts.map +1 -1
  309. package/dist/data/chat/Conversation.js +2 -1
  310. package/dist/data/chat/Conversation.js.map +1 -1
  311. package/dist/data/chat/Message.cjs +39 -12
  312. package/dist/data/chat/Message.cjs.map +1 -1
  313. package/dist/data/chat/Message.d.ts +1 -1
  314. package/dist/data/chat/Message.d.ts.map +1 -1
  315. package/dist/data/chat/Message.js +40 -13
  316. package/dist/data/chat/Message.js.map +1 -1
  317. package/dist/data/chat/ToolCall.cjs +60 -5
  318. package/dist/data/chat/ToolCall.cjs.map +1 -1
  319. package/dist/data/chat/ToolCall.d.ts +7 -2
  320. package/dist/data/chat/ToolCall.d.ts.map +1 -1
  321. package/dist/data/chat/ToolCall.js +60 -5
  322. package/dist/data/chat/ToolCall.js.map +1 -1
  323. package/dist/data/chat/approval.cjs.map +1 -1
  324. package/dist/data/chat/approval.d.ts +2 -2
  325. package/dist/data/chat/approval.d.ts.map +1 -1
  326. package/dist/data/chat/approval.js.map +1 -1
  327. package/dist/data/chat/tool-policy.cjs +59 -2
  328. package/dist/data/chat/tool-policy.cjs.map +1 -1
  329. package/dist/data/chat/tool-policy.d.ts +9 -0
  330. package/dist/data/chat/tool-policy.d.ts.map +1 -1
  331. package/dist/data/chat/tool-policy.js +59 -2
  332. package/dist/data/chat/tool-policy.js.map +1 -1
  333. package/dist/data/chat/types.cjs +6 -0
  334. package/dist/data/chat/types.cjs.map +1 -1
  335. package/dist/data/chat/types.d.ts +13 -4
  336. package/dist/data/chat/types.d.ts.map +1 -1
  337. package/dist/data/chat/types.js +7 -1
  338. package/dist/data/chat/types.js.map +1 -1
  339. package/dist/data/chat/usage-snapshot.cjs +11 -6
  340. package/dist/data/chat/usage-snapshot.cjs.map +1 -1
  341. package/dist/data/chat/usage-snapshot.d.ts +0 -1
  342. package/dist/data/chat/usage-snapshot.d.ts.map +1 -1
  343. package/dist/data/chat/usage-snapshot.js +11 -6
  344. package/dist/data/chat/usage-snapshot.js.map +1 -1
  345. package/dist/data/diagnostics/RenderedStackTrace.cjs +2 -1
  346. package/dist/data/diagnostics/RenderedStackTrace.cjs.map +1 -1
  347. package/dist/data/diagnostics/RenderedStackTrace.d.ts +3 -1
  348. package/dist/data/diagnostics/RenderedStackTrace.d.ts.map +1 -1
  349. package/dist/data/diagnostics/RenderedStackTrace.js +2 -1
  350. package/dist/data/diagnostics/RenderedStackTrace.js.map +1 -1
  351. package/dist/data/diagnostics/StackFrameRow.cjs +3 -3
  352. package/dist/data/diagnostics/StackFrameRow.cjs.map +1 -1
  353. package/dist/data/diagnostics/StackFrameRow.js +3 -3
  354. package/dist/data/diagnostics/StackFrameRow.js.map +1 -1
  355. package/dist/data/graph-columns-layout.cjs +26 -10
  356. package/dist/data/graph-columns-layout.cjs.map +1 -1
  357. package/dist/data/graph-columns-layout.d.ts +8 -0
  358. package/dist/data/graph-columns-layout.d.ts.map +1 -1
  359. package/dist/data/graph-columns-layout.js +26 -10
  360. package/dist/data/graph-columns-layout.js.map +1 -1
  361. package/dist/data/graph-diagram-model.cjs.map +1 -1
  362. package/dist/data/graph-diagram-model.d.ts +5 -0
  363. package/dist/data/graph-diagram-model.d.ts.map +1 -1
  364. package/dist/data/graph-diagram-model.js.map +1 -1
  365. package/dist/data/graph-edge-routing.cjs +9 -3
  366. package/dist/data/graph-edge-routing.cjs.map +1 -1
  367. package/dist/data/graph-edge-routing.d.ts +2 -0
  368. package/dist/data/graph-edge-routing.d.ts.map +1 -1
  369. package/dist/data/graph-edge-routing.js +9 -3
  370. package/dist/data/graph-edge-routing.js.map +1 -1
  371. package/dist/data/json-view/JsonSource.cjs +84 -0
  372. package/dist/data/json-view/JsonSource.cjs.map +1 -0
  373. package/dist/data/json-view/JsonSource.d.ts +7 -0
  374. package/dist/data/json-view/JsonSource.d.ts.map +1 -0
  375. package/dist/data/json-view/JsonSource.js +84 -0
  376. package/dist/data/json-view/JsonSource.js.map +1 -0
  377. package/dist/data/json-view/parse-prefix.cjs +132 -0
  378. package/dist/data/json-view/parse-prefix.cjs.map +1 -0
  379. package/dist/data/json-view/parse-prefix.d.ts +11 -0
  380. package/dist/data/json-view/parse-prefix.d.ts.map +1 -0
  381. package/dist/data/json-view/parse-prefix.js +132 -0
  382. package/dist/data/json-view/parse-prefix.js.map +1 -0
  383. package/dist/data/json-view/parse-source.cjs +62 -0
  384. package/dist/data/json-view/parse-source.cjs.map +1 -0
  385. package/dist/data/json-view/parse-source.d.ts +16 -0
  386. package/dist/data/json-view/parse-source.d.ts.map +1 -0
  387. package/dist/data/json-view/parse-source.js +62 -0
  388. package/dist/data/json-view/parse-source.js.map +1 -0
  389. package/dist/data/json-view/story-fixtures.d.ts +6 -0
  390. package/dist/data/json-view/story-fixtures.d.ts.map +1 -0
  391. package/dist/data/json-view/types.d.ts +14 -0
  392. package/dist/data/json-view/types.d.ts.map +1 -0
  393. package/dist/data/runtime/RuntimeBar.cjs +2 -5
  394. package/dist/data/runtime/RuntimeBar.cjs.map +1 -1
  395. package/dist/data/runtime/RuntimeBar.d.ts +2 -4
  396. package/dist/data/runtime/RuntimeBar.d.ts.map +1 -1
  397. package/dist/data/runtime/RuntimeBar.fields.cjs +2 -2
  398. package/dist/data/runtime/RuntimeBar.fields.cjs.map +1 -1
  399. package/dist/data/runtime/RuntimeBar.fields.js +2 -2
  400. package/dist/data/runtime/RuntimeBar.fields.js.map +1 -1
  401. package/dist/data/runtime/RuntimeBar.js +2 -5
  402. package/dist/data/runtime/RuntimeBar.js.map +1 -1
  403. package/dist/data/runtime/RuntimeBar.selection.cjs +4 -1
  404. package/dist/data/runtime/RuntimeBar.selection.cjs.map +1 -1
  405. package/dist/data/runtime/RuntimeBar.selection.d.ts.map +1 -1
  406. package/dist/data/runtime/RuntimeBar.selection.js +5 -2
  407. package/dist/data/runtime/RuntimeBar.selection.js.map +1 -1
  408. package/dist/data/runtime/RuntimeBarActions.cjs +1 -5
  409. package/dist/data/runtime/RuntimeBarActions.cjs.map +1 -1
  410. package/dist/data/runtime/RuntimeBarActions.d.ts +1 -1
  411. package/dist/data/runtime/RuntimeBarActions.d.ts.map +1 -1
  412. package/dist/data/runtime/RuntimeBarActions.js +1 -5
  413. package/dist/data/runtime/RuntimeBarActions.js.map +1 -1
  414. package/dist/data/runtime/RuntimeBarIdentity.cjs +6 -14
  415. package/dist/data/runtime/RuntimeBarIdentity.cjs.map +1 -1
  416. package/dist/data/runtime/RuntimeBarIdentity.d.ts +0 -1
  417. package/dist/data/runtime/RuntimeBarIdentity.d.ts.map +1 -1
  418. package/dist/data/runtime/RuntimeBarIdentity.js +6 -14
  419. package/dist/data/runtime/RuntimeBarIdentity.js.map +1 -1
  420. package/dist/data/runtime/RuntimeBarLayout.cjs +8 -27
  421. package/dist/data/runtime/RuntimeBarLayout.cjs.map +1 -1
  422. package/dist/data/runtime/RuntimeBarLayout.d.ts.map +1 -1
  423. package/dist/data/runtime/RuntimeBarLayout.js +8 -27
  424. package/dist/data/runtime/RuntimeBarLayout.js.map +1 -1
  425. package/dist/data/runtime/RuntimeBarSegment.cjs +1 -5
  426. package/dist/data/runtime/RuntimeBarSegment.cjs.map +1 -1
  427. package/dist/data/runtime/RuntimeBarSegment.d.ts.map +1 -1
  428. package/dist/data/runtime/RuntimeBarSegment.js +1 -5
  429. package/dist/data/runtime/RuntimeBarSegment.js.map +1 -1
  430. package/dist/data/runtime/use-runtime-bar-overflow.cjs +4 -10
  431. package/dist/data/runtime/use-runtime-bar-overflow.cjs.map +1 -1
  432. package/dist/data/runtime/use-runtime-bar-overflow.d.ts +1 -2
  433. package/dist/data/runtime/use-runtime-bar-overflow.d.ts.map +1 -1
  434. package/dist/data/runtime/use-runtime-bar-overflow.js +4 -10
  435. package/dist/data/runtime/use-runtime-bar-overflow.js.map +1 -1
  436. package/dist/data/test-runner/TestRunner.fixtures.d.ts +0 -20
  437. package/dist/data/test-runner/TestRunner.fixtures.d.ts.map +1 -1
  438. package/dist/data/test-runner/TestRunner.large-fixtures.d.ts +22 -0
  439. package/dist/data/test-runner/TestRunner.large-fixtures.d.ts.map +1 -0
  440. package/dist/data/use-pan-zoom.cjs +23 -10
  441. package/dist/data/use-pan-zoom.cjs.map +1 -1
  442. package/dist/data/use-pan-zoom.d.ts +16 -2
  443. package/dist/data/use-pan-zoom.d.ts.map +1 -1
  444. package/dist/data/use-pan-zoom.js +23 -10
  445. package/dist/data/use-pan-zoom.js.map +1 -1
  446. package/dist/data/version-info.cjs +3 -3
  447. package/dist/data/version-info.js +3 -3
  448. package/dist/data.cjs +28 -2
  449. package/dist/data.cjs.map +1 -1
  450. package/dist/data.d.ts +2 -0
  451. package/dist/data.d.ts.map +1 -1
  452. package/dist/data.js +26 -0
  453. package/dist/data.js.map +1 -1
  454. package/dist/index.cjs +30 -4
  455. package/dist/index.cjs.map +1 -1
  456. package/dist/index.js +26 -0
  457. package/dist/index.js.map +1 -1
  458. package/dist/layout/Workspace.cjs +13 -4
  459. package/dist/layout/Workspace.cjs.map +1 -1
  460. package/dist/layout/Workspace.d.ts +7 -2
  461. package/dist/layout/Workspace.d.ts.map +1 -1
  462. package/dist/layout/Workspace.js +13 -4
  463. package/dist/layout/Workspace.js.map +1 -1
  464. package/dist/lib/permission-strategies.cjs +71 -11
  465. package/dist/lib/permission-strategies.cjs.map +1 -1
  466. package/dist/lib/permission-strategies.d.ts +3 -0
  467. package/dist/lib/permission-strategies.d.ts.map +1 -1
  468. package/dist/lib/permission-strategies.js +71 -11
  469. package/dist/lib/permission-strategies.js.map +1 -1
  470. package/dist/styles.css +1 -1
  471. package/package.json +5 -3
  472. package/dist/data/ai/ToolSchemaBrowser.selection-toolbar.cjs +0 -57
  473. package/dist/data/ai/ToolSchemaBrowser.selection-toolbar.cjs.map +0 -1
  474. package/dist/data/ai/ToolSchemaBrowser.selection-toolbar.d.ts +0 -7
  475. package/dist/data/ai/ToolSchemaBrowser.selection-toolbar.d.ts.map +0 -1
  476. package/dist/data/ai/ToolSchemaBrowser.selection-toolbar.js +0 -57
  477. package/dist/data/ai/ToolSchemaBrowser.selection-toolbar.js.map +0 -1
  478. package/dist/data/runtime/RuntimeBar.context.cjs +0 -8
  479. package/dist/data/runtime/RuntimeBar.context.cjs.map +0 -1
  480. package/dist/data/runtime/RuntimeBar.context.d.ts +0 -2
  481. package/dist/data/runtime/RuntimeBar.context.d.ts.map +0 -1
  482. package/dist/data/runtime/RuntimeBar.context.js +0 -8
  483. package/dist/data/runtime/RuntimeBar.context.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"RenderedStackTrace.cjs","sources":["../../../src/data/diagnostics/RenderedStackTrace.tsx"],"sourcesContent":["import { useMemo, type ReactNode } from \"react\";\nimport {\n parseJavaStackTrace,\n type ParsedStackFrame,\n type ParsedStackTrace,\n} from \"./stacktrace-parse\";\nimport { Icon } from \"../Icon\";\nimport { UiStackFrameDot, UiError } from \"../../icons\";\nimport {\n StackFrameRow,\n type StackFrameActions,\n type StackFrameActionsVisibility,\n type StackFrameDetailRenderer,\n type StackFramePartRenderer,\n} from \"./StackFrameRow\";\nimport type { FrameSource } from \"./FrameSourceWindow.utils\";\n\n// SourceResolver matches the Go clicky.SourceResolver interface: given a\n// frame, return surrounding source lines so the renderer can display inline\n// context. Failures must be silent (return undefined) so a missing class\n// never blocks the rest of the trace.\n//\n// The return shape is `FrameSource` — the same shape the source window\n// consumes and the same one the JVM thread-dump resolver returns, so a caller\n// that can resolve source for one surface can resolve it for both.\nexport type StackTraceSourceResolver = (\n frame: ParsedStackFrame,\n contextLines: number,\n) => FrameSource | undefined;\n\nexport interface StackTraceProps {\n /**\n * Raw Java stack-trace string or a pre-parsed ParsedStackTrace\n * from a backend/parser.\n */\n input: string | ParsedStackTrace;\n /** Parser language. Currently Java stack traces are supported. */\n language?: \"java\";\n /** Optional source-line resolver for inline context under frames. */\n resolver?: StackTraceSourceResolver;\n /** Number of source lines to request around each frame. */\n contextLines?: number;\n /** Hide frames known to be runtime/library-only. */\n hideRuntimeOnly?: boolean;\n /** Only show frames whose class starts with one of these prefixes. */\n include?: string[];\n /** Hide frames whose class starts with one of these prefixes. */\n exclude?: string[];\n /** Trailing per-frame actions, revealed on hover/focus. */\n frameActions?: StackFrameActions;\n /** Replace method, class, and location labels with application-owned renderers. */\n renderFramePart?: StackFramePartRenderer;\n /** Render application-owned detail below each visible frame. */\n renderFrameDetail?: StackFrameDetailRenderer;\n /** Control whether per-frame actions are hover-only or always visible. */\n frameActionsVisibility?: StackFrameActionsVisibility;\n /** Additional application-owned frame predicate. */\n frameFilter?: (frame: ParsedStackFrame) => boolean;\n /** Render application-owned detail below a parsed cause. */\n renderCauseDetail?: (cause: string, index: number) => ReactNode;\n /** Classes applied to the stack-trace shell. */\n className?: string;\n}\n\n// StackTrace is the React counterpart to Go's clicky.StackTrace builder. Pass\n// a raw exception dump and it parses + renders frames; pass a SourceResolver\n// to get inline source context (±N lines) under each frame, with the focal\n// line highlighted. Frames themselves are rendered by the shared StackFrameRow.\nexport function StackTrace({\n input,\n language = \"java\",\n resolver,\n contextLines = 3,\n hideRuntimeOnly = false,\n include,\n exclude,\n frameActions,\n renderFramePart,\n renderFrameDetail,\n frameActionsVisibility = \"hover\",\n frameFilter,\n renderCauseDetail,\n className,\n}: StackTraceProps) {\n const parsed = useMemo<ParsedStackTrace>(() => {\n if (typeof input === \"string\") {\n return parseJavaStackTrace(input);\n }\n return input;\n }, [input, language]);\n\n const enrichedFrames = useMemo<ParsedStackFrame[]>(() => {\n if (!resolver) return parsed.frames;\n return parsed.frames.map((frame): ParsedStackFrame => {\n if (frame.sourceLines && frame.sourceLines.length > 0) return frame;\n const resolved = resolver(frame, contextLines);\n if (!resolved) return frame;\n // `line` stays the frame's own — it is what the window highlights, and a\n // resolver returning one would silently move the focal line off the throw.\n const { line: _ignored, ...source } = resolved;\n return { ...frame, ...source };\n });\n }, [parsed.frames, resolver, contextLines]);\n\n const visibleFrames = useMemo(() => {\n return enrichedFrames.filter((frame) => {\n if (hideRuntimeOnly && frame.runtime) return false;\n if (frameFilter && !frameFilter(frame)) return false;\n if (exclude && exclude.some((p) => frame.class?.startsWith(p))) return false;\n if (include && include.length > 0) {\n return include.some((p) => frame.class?.startsWith(p));\n }\n return true;\n });\n }, [enrichedFrames, hideRuntimeOnly, include, exclude, frameFilter]);\n\n if (visibleFrames.length === 0 && !parsed.exceptionClass) return null;\n\n const hasFilteredFrames = visibleFrames.length !== enrichedFrames.length;\n\n return (\n <div\n className={[\n \"overflow-hidden rounded-md border border-border bg-background text-foreground\",\n className,\n ]\n .filter(Boolean)\n .join(\" \")}\n >\n {(parsed.exceptionClass || parsed.message) && (\n <div className=\"border-b border-border bg-red-500/5 px-3 py-2\">\n <div className=\"flex min-w-0 items-start gap-2\">\n <Icon\n icon={UiError}\n className=\"mt-0.5 shrink-0 text-sm text-red-600 dark:text-red-400\"\n />\n <div className=\"min-w-0 flex-1\">\n {parsed.exceptionClass && (\n <div className=\"break-all font-mono text-xs font-semibold text-red-700 dark:text-red-300\">\n {parsed.exceptionClass}\n </div>\n )}\n {parsed.message && (\n <div className=\"mt-0.5 whitespace-pre-wrap break-words text-xs text-foreground\">\n {parsed.message}\n </div>\n )}\n </div>\n </div>\n </div>\n )}\n {parsed.causedBy.length > 0 && (\n <div className=\"space-y-1 border-b border-border bg-orange-500/5 px-3 py-2\">\n {parsed.causedBy.map((cause, i) => {\n const detail = renderCauseDetail?.(cause, i);\n return (\n <div key={i} data-cause-index={i} className=\"min-w-0\">\n <div className=\"flex min-w-0 items-start gap-2 font-mono text-[11px] text-orange-700 dark:text-orange-300\">\n <Icon icon={UiStackFrameDot} className=\"mt-0.5 shrink-0 text-xs\" />\n <span className=\"shrink-0 opacity-75\">Caused by</span>\n <span className=\"min-w-0 break-all\">{cause}</span>\n </div>\n {detail ? <div className=\"mt-1 pl-5\">{detail}</div> : null}\n </div>\n );\n })}\n </div>\n )}\n <div className=\"divide-y divide-border/60\">\n {visibleFrames.map((frame, idx) => (\n <StackFrameRow\n key={`${frame.functionName}-${idx}`}\n frame={frame}\n index={idx}\n showIndex\n {...(frameActions ? { frameActions } : {})}\n {...(renderFramePart ? { renderFramePart } : {})}\n {...(renderFrameDetail ? { renderFrameDetail } : {})}\n frameActionsVisibility={frameActionsVisibility}\n />\n ))}\n </div>\n {hasFilteredFrames && (\n <div className=\"border-t border-border bg-muted/30 px-3 py-1.5 text-[11px] text-muted-foreground\">\n Showing {visibleFrames.length} of {enrichedFrames.length} frames\n </div>\n )}\n </div>\n );\n}\n"],"names":["useMemo","parseJavaStackTrace","jsxs","jsx","Icon","UiError","UiStackFrameDot","StackFrameRow"],"mappings":"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"}
1
+ {"version":3,"file":"RenderedStackTrace.cjs","sources":["../../../src/data/diagnostics/RenderedStackTrace.tsx"],"sourcesContent":["import { useMemo, type ReactNode } from \"react\";\nimport {\n parseJavaStackTrace,\n type ParsedStackFrame,\n type ParsedStackTrace,\n} from \"./stacktrace-parse\";\nimport { Icon } from \"../Icon\";\nimport { UiStackFrameDot, UiError } from \"../../icons\";\nimport {\n StackFrameRow,\n type StackFrameActions,\n type StackFrameActionsVisibility,\n type StackFrameDetailRenderer,\n type StackFramePartRenderer,\n} from \"./StackFrameRow\";\nimport type { FrameSource } from \"./FrameSourceWindow.utils\";\n\n// SourceResolver matches the Go clicky.SourceResolver interface: given a\n// frame, return surrounding source lines so the renderer can display inline\n// context. Failures must be silent (return undefined) so a missing class\n// never blocks the rest of the trace.\n//\n// The return shape is `FrameSource` — the same shape the source window\n// consumes and the same one the JVM thread-dump resolver returns, so a caller\n// that can resolve source for one surface can resolve it for both.\nexport type StackTraceSourceResolver = (\n frame: ParsedStackFrame,\n contextLines: number,\n) => FrameSource | undefined;\n\nexport interface StackTraceProps {\n /**\n * Raw Java stack-trace string or a pre-parsed ParsedStackTrace\n * from a backend/parser.\n */\n input: string | ParsedStackTrace;\n /** Parser language. Currently Java stack traces are supported. */\n language?: \"java\";\n /** Optional source-line resolver for inline context under frames. */\n resolver?: StackTraceSourceResolver;\n /** Number of source lines to request around each frame. */\n contextLines?: number;\n /** Hide frames known to be runtime/library-only. */\n hideRuntimeOnly?: boolean;\n /** Only show frames whose class starts with one of these prefixes. */\n include?: string[];\n /** Hide frames whose class starts with one of these prefixes. */\n exclude?: string[];\n /** Trailing per-frame actions, revealed on hover/focus. */\n frameActions?: StackFrameActions;\n /** Replace method, class, and location labels with application-owned renderers. */\n renderFramePart?: StackFramePartRenderer;\n /** Render application-owned detail below each visible frame. */\n renderFrameDetail?: StackFrameDetailRenderer;\n /** Control whether per-frame actions are hover-only or always visible. */\n frameActionsVisibility?: StackFrameActionsVisibility;\n /** Show each frame's 1-based ordinal in the gutter. Defaults to true. */\n showFrameIndex?: boolean;\n /** Additional application-owned frame predicate. */\n frameFilter?: (frame: ParsedStackFrame) => boolean;\n /** Render application-owned detail below a parsed cause. */\n renderCauseDetail?: (cause: string, index: number) => ReactNode;\n /** Classes applied to the stack-trace shell. */\n className?: string;\n}\n\n// StackTrace is the React counterpart to Go's clicky.StackTrace builder. Pass\n// a raw exception dump and it parses + renders frames; pass a SourceResolver\n// to get inline source context (±N lines) under each frame, with the focal\n// line highlighted. Frames themselves are rendered by the shared StackFrameRow.\nexport function StackTrace({\n input,\n language = \"java\",\n resolver,\n contextLines = 3,\n hideRuntimeOnly = false,\n include,\n exclude,\n frameActions,\n renderFramePart,\n renderFrameDetail,\n frameActionsVisibility = \"hover\",\n showFrameIndex = true,\n frameFilter,\n renderCauseDetail,\n className,\n}: StackTraceProps) {\n const parsed = useMemo<ParsedStackTrace>(() => {\n if (typeof input === \"string\") {\n return parseJavaStackTrace(input);\n }\n return input;\n }, [input, language]);\n\n const enrichedFrames = useMemo<ParsedStackFrame[]>(() => {\n if (!resolver) return parsed.frames;\n return parsed.frames.map((frame): ParsedStackFrame => {\n if (frame.sourceLines && frame.sourceLines.length > 0) return frame;\n const resolved = resolver(frame, contextLines);\n if (!resolved) return frame;\n // `line` stays the frame's own — it is what the window highlights, and a\n // resolver returning one would silently move the focal line off the throw.\n const { line: _ignored, ...source } = resolved;\n return { ...frame, ...source };\n });\n }, [parsed.frames, resolver, contextLines]);\n\n const visibleFrames = useMemo(() => {\n return enrichedFrames.filter((frame) => {\n if (hideRuntimeOnly && frame.runtime) return false;\n if (frameFilter && !frameFilter(frame)) return false;\n if (exclude && exclude.some((p) => frame.class?.startsWith(p))) return false;\n if (include && include.length > 0) {\n return include.some((p) => frame.class?.startsWith(p));\n }\n return true;\n });\n }, [enrichedFrames, hideRuntimeOnly, include, exclude, frameFilter]);\n\n if (visibleFrames.length === 0 && !parsed.exceptionClass) return null;\n\n const hasFilteredFrames = visibleFrames.length !== enrichedFrames.length;\n\n return (\n <div\n className={[\n \"overflow-hidden rounded-md border border-border bg-background text-foreground\",\n className,\n ]\n .filter(Boolean)\n .join(\" \")}\n >\n {(parsed.exceptionClass || parsed.message) && (\n <div className=\"border-b border-border bg-red-500/5 px-3 py-2\">\n <div className=\"flex min-w-0 items-start gap-2\">\n <Icon\n icon={UiError}\n className=\"mt-0.5 shrink-0 text-sm text-red-600 dark:text-red-400\"\n />\n <div className=\"min-w-0 flex-1\">\n {parsed.exceptionClass && (\n <div className=\"break-all font-mono text-xs font-semibold text-red-700 dark:text-red-300\">\n {parsed.exceptionClass}\n </div>\n )}\n {parsed.message && (\n <div className=\"mt-0.5 whitespace-pre-wrap break-words text-xs text-foreground\">\n {parsed.message}\n </div>\n )}\n </div>\n </div>\n </div>\n )}\n {parsed.causedBy.length > 0 && (\n <div className=\"space-y-1 border-b border-border bg-orange-500/5 px-3 py-2\">\n {parsed.causedBy.map((cause, i) => {\n const detail = renderCauseDetail?.(cause, i);\n return (\n <div key={i} data-cause-index={i} className=\"min-w-0\">\n <div className=\"flex min-w-0 items-start gap-2 font-mono text-[11px] text-orange-700 dark:text-orange-300\">\n <Icon icon={UiStackFrameDot} className=\"mt-0.5 shrink-0 text-xs\" />\n <span className=\"shrink-0 opacity-75\">Caused by</span>\n <span className=\"min-w-0 break-all\">{cause}</span>\n </div>\n {detail ? <div className=\"mt-1 pl-5\">{detail}</div> : null}\n </div>\n );\n })}\n </div>\n )}\n <div className=\"divide-y divide-border/60\">\n {visibleFrames.map((frame, idx) => (\n <StackFrameRow\n key={`${frame.functionName}-${idx}`}\n frame={frame}\n index={idx}\n showIndex={showFrameIndex}\n {...(frameActions ? { frameActions } : {})}\n {...(renderFramePart ? { renderFramePart } : {})}\n {...(renderFrameDetail ? { renderFrameDetail } : {})}\n frameActionsVisibility={frameActionsVisibility}\n />\n ))}\n </div>\n {hasFilteredFrames && (\n <div className=\"border-t border-border bg-muted/30 px-3 py-1.5 text-[11px] text-muted-foreground\">\n Showing {visibleFrames.length} of {enrichedFrames.length} frames\n </div>\n )}\n </div>\n );\n}\n"],"names":["useMemo","parseJavaStackTrace","jsxs","jsx","Icon","UiError","UiStackFrameDot","StackFrameRow"],"mappings":"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"}
@@ -29,6 +29,8 @@ export interface StackTraceProps {
29
29
  renderFrameDetail?: StackFrameDetailRenderer;
30
30
  /** Control whether per-frame actions are hover-only or always visible. */
31
31
  frameActionsVisibility?: StackFrameActionsVisibility;
32
+ /** Show each frame's 1-based ordinal in the gutter. Defaults to true. */
33
+ showFrameIndex?: boolean;
32
34
  /** Additional application-owned frame predicate. */
33
35
  frameFilter?: (frame: ParsedStackFrame) => boolean;
34
36
  /** Render application-owned detail below a parsed cause. */
@@ -36,5 +38,5 @@ export interface StackTraceProps {
36
38
  /** Classes applied to the stack-trace shell. */
37
39
  className?: string;
38
40
  }
39
- export declare function StackTrace({ input, language, resolver, contextLines, hideRuntimeOnly, include, exclude, frameActions, renderFramePart, renderFrameDetail, frameActionsVisibility, frameFilter, renderCauseDetail, className, }: StackTraceProps): import("react").JSX.Element | null;
41
+ export declare function StackTrace({ input, language, resolver, contextLines, hideRuntimeOnly, include, exclude, frameActions, renderFramePart, renderFrameDetail, frameActionsVisibility, showFrameIndex, frameFilter, renderCauseDetail, className, }: StackTraceProps): import("react").JSX.Element | null;
40
42
  //# sourceMappingURL=RenderedStackTrace.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"RenderedStackTrace.d.ts","sourceRoot":"","sources":["../../../src/data/diagnostics/RenderedStackTrace.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAChD,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACtB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,2BAA2B,EAChC,KAAK,wBAAwB,EAC7B,KAAK,sBAAsB,EAC5B,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAU7D,MAAM,MAAM,wBAAwB,GAAG,CACrC,KAAK,EAAE,gBAAgB,EACvB,YAAY,EAAE,MAAM,KACjB,WAAW,GAAG,SAAS,CAAC;AAE7B,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,KAAK,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACjC,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,wBAAwB,CAAC;IACpC,2DAA2D;IAC3D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oDAAoD;IACpD,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,iEAAiE;IACjE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,2DAA2D;IAC3D,YAAY,CAAC,EAAE,iBAAiB,CAAC;IACjC,mFAAmF;IACnF,eAAe,CAAC,EAAE,sBAAsB,CAAC;IACzC,gEAAgE;IAChE,iBAAiB,CAAC,EAAE,wBAAwB,CAAC;IAC7C,0EAA0E;IAC1E,sBAAsB,CAAC,EAAE,2BAA2B,CAAC;IACrD,oDAAoD;IACpD,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,OAAO,CAAC;IACnD,4DAA4D;IAC5D,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,SAAS,CAAC;IAChE,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAMD,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,QAAiB,EACjB,QAAQ,EACR,YAAgB,EAChB,eAAuB,EACvB,OAAO,EACP,OAAO,EACP,YAAY,EACZ,eAAe,EACf,iBAAiB,EACjB,sBAAgC,EAChC,WAAW,EACX,iBAAiB,EACjB,SAAS,GACV,EAAE,eAAe,sCA0GjB"}
1
+ {"version":3,"file":"RenderedStackTrace.d.ts","sourceRoot":"","sources":["../../../src/data/diagnostics/RenderedStackTrace.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAChD,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACtB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,2BAA2B,EAChC,KAAK,wBAAwB,EAC7B,KAAK,sBAAsB,EAC5B,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAU7D,MAAM,MAAM,wBAAwB,GAAG,CACrC,KAAK,EAAE,gBAAgB,EACvB,YAAY,EAAE,MAAM,KACjB,WAAW,GAAG,SAAS,CAAC;AAE7B,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,KAAK,EAAE,MAAM,GAAG,gBAAgB,CAAC;IACjC,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,wBAAwB,CAAC;IACpC,2DAA2D;IAC3D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oDAAoD;IACpD,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,iEAAiE;IACjE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,2DAA2D;IAC3D,YAAY,CAAC,EAAE,iBAAiB,CAAC;IACjC,mFAAmF;IACnF,eAAe,CAAC,EAAE,sBAAsB,CAAC;IACzC,gEAAgE;IAChE,iBAAiB,CAAC,EAAE,wBAAwB,CAAC;IAC7C,0EAA0E;IAC1E,sBAAsB,CAAC,EAAE,2BAA2B,CAAC;IACrD,yEAAyE;IACzE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,oDAAoD;IACpD,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,OAAO,CAAC;IACnD,4DAA4D;IAC5D,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,SAAS,CAAC;IAChE,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAMD,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,QAAiB,EACjB,QAAQ,EACR,YAAgB,EAChB,eAAuB,EACvB,OAAO,EACP,OAAO,EACP,YAAY,EACZ,eAAe,EACf,iBAAiB,EACjB,sBAAgC,EAChC,cAAqB,EACrB,WAAW,EACX,iBAAiB,EACjB,SAAS,GACV,EAAE,eAAe,sCA0GjB"}
@@ -17,6 +17,7 @@ function StackTrace({
17
17
  renderFramePart,
18
18
  renderFrameDetail,
19
19
  frameActionsVisibility = "hover",
20
+ showFrameIndex = true,
20
21
  frameFilter,
21
22
  renderCauseDetail,
22
23
  className
@@ -93,7 +94,7 @@ function StackTrace({
93
94
  {
94
95
  frame,
95
96
  index: idx,
96
- showIndex: true,
97
+ showIndex: showFrameIndex,
97
98
  ...frameActions ? { frameActions } : {},
98
99
  ...renderFramePart ? { renderFramePart } : {},
99
100
  ...renderFrameDetail ? { renderFrameDetail } : {},
@@ -1 +1 @@
1
- {"version":3,"file":"RenderedStackTrace.js","sources":["../../../src/data/diagnostics/RenderedStackTrace.tsx"],"sourcesContent":["import { useMemo, type ReactNode } from \"react\";\nimport {\n parseJavaStackTrace,\n type ParsedStackFrame,\n type ParsedStackTrace,\n} from \"./stacktrace-parse\";\nimport { Icon } from \"../Icon\";\nimport { UiStackFrameDot, UiError } from \"../../icons\";\nimport {\n StackFrameRow,\n type StackFrameActions,\n type StackFrameActionsVisibility,\n type StackFrameDetailRenderer,\n type StackFramePartRenderer,\n} from \"./StackFrameRow\";\nimport type { FrameSource } from \"./FrameSourceWindow.utils\";\n\n// SourceResolver matches the Go clicky.SourceResolver interface: given a\n// frame, return surrounding source lines so the renderer can display inline\n// context. Failures must be silent (return undefined) so a missing class\n// never blocks the rest of the trace.\n//\n// The return shape is `FrameSource` — the same shape the source window\n// consumes and the same one the JVM thread-dump resolver returns, so a caller\n// that can resolve source for one surface can resolve it for both.\nexport type StackTraceSourceResolver = (\n frame: ParsedStackFrame,\n contextLines: number,\n) => FrameSource | undefined;\n\nexport interface StackTraceProps {\n /**\n * Raw Java stack-trace string or a pre-parsed ParsedStackTrace\n * from a backend/parser.\n */\n input: string | ParsedStackTrace;\n /** Parser language. Currently Java stack traces are supported. */\n language?: \"java\";\n /** Optional source-line resolver for inline context under frames. */\n resolver?: StackTraceSourceResolver;\n /** Number of source lines to request around each frame. */\n contextLines?: number;\n /** Hide frames known to be runtime/library-only. */\n hideRuntimeOnly?: boolean;\n /** Only show frames whose class starts with one of these prefixes. */\n include?: string[];\n /** Hide frames whose class starts with one of these prefixes. */\n exclude?: string[];\n /** Trailing per-frame actions, revealed on hover/focus. */\n frameActions?: StackFrameActions;\n /** Replace method, class, and location labels with application-owned renderers. */\n renderFramePart?: StackFramePartRenderer;\n /** Render application-owned detail below each visible frame. */\n renderFrameDetail?: StackFrameDetailRenderer;\n /** Control whether per-frame actions are hover-only or always visible. */\n frameActionsVisibility?: StackFrameActionsVisibility;\n /** Additional application-owned frame predicate. */\n frameFilter?: (frame: ParsedStackFrame) => boolean;\n /** Render application-owned detail below a parsed cause. */\n renderCauseDetail?: (cause: string, index: number) => ReactNode;\n /** Classes applied to the stack-trace shell. */\n className?: string;\n}\n\n// StackTrace is the React counterpart to Go's clicky.StackTrace builder. Pass\n// a raw exception dump and it parses + renders frames; pass a SourceResolver\n// to get inline source context (±N lines) under each frame, with the focal\n// line highlighted. Frames themselves are rendered by the shared StackFrameRow.\nexport function StackTrace({\n input,\n language = \"java\",\n resolver,\n contextLines = 3,\n hideRuntimeOnly = false,\n include,\n exclude,\n frameActions,\n renderFramePart,\n renderFrameDetail,\n frameActionsVisibility = \"hover\",\n frameFilter,\n renderCauseDetail,\n className,\n}: StackTraceProps) {\n const parsed = useMemo<ParsedStackTrace>(() => {\n if (typeof input === \"string\") {\n return parseJavaStackTrace(input);\n }\n return input;\n }, [input, language]);\n\n const enrichedFrames = useMemo<ParsedStackFrame[]>(() => {\n if (!resolver) return parsed.frames;\n return parsed.frames.map((frame): ParsedStackFrame => {\n if (frame.sourceLines && frame.sourceLines.length > 0) return frame;\n const resolved = resolver(frame, contextLines);\n if (!resolved) return frame;\n // `line` stays the frame's own — it is what the window highlights, and a\n // resolver returning one would silently move the focal line off the throw.\n const { line: _ignored, ...source } = resolved;\n return { ...frame, ...source };\n });\n }, [parsed.frames, resolver, contextLines]);\n\n const visibleFrames = useMemo(() => {\n return enrichedFrames.filter((frame) => {\n if (hideRuntimeOnly && frame.runtime) return false;\n if (frameFilter && !frameFilter(frame)) return false;\n if (exclude && exclude.some((p) => frame.class?.startsWith(p))) return false;\n if (include && include.length > 0) {\n return include.some((p) => frame.class?.startsWith(p));\n }\n return true;\n });\n }, [enrichedFrames, hideRuntimeOnly, include, exclude, frameFilter]);\n\n if (visibleFrames.length === 0 && !parsed.exceptionClass) return null;\n\n const hasFilteredFrames = visibleFrames.length !== enrichedFrames.length;\n\n return (\n <div\n className={[\n \"overflow-hidden rounded-md border border-border bg-background text-foreground\",\n className,\n ]\n .filter(Boolean)\n .join(\" \")}\n >\n {(parsed.exceptionClass || parsed.message) && (\n <div className=\"border-b border-border bg-red-500/5 px-3 py-2\">\n <div className=\"flex min-w-0 items-start gap-2\">\n <Icon\n icon={UiError}\n className=\"mt-0.5 shrink-0 text-sm text-red-600 dark:text-red-400\"\n />\n <div className=\"min-w-0 flex-1\">\n {parsed.exceptionClass && (\n <div className=\"break-all font-mono text-xs font-semibold text-red-700 dark:text-red-300\">\n {parsed.exceptionClass}\n </div>\n )}\n {parsed.message && (\n <div className=\"mt-0.5 whitespace-pre-wrap break-words text-xs text-foreground\">\n {parsed.message}\n </div>\n )}\n </div>\n </div>\n </div>\n )}\n {parsed.causedBy.length > 0 && (\n <div className=\"space-y-1 border-b border-border bg-orange-500/5 px-3 py-2\">\n {parsed.causedBy.map((cause, i) => {\n const detail = renderCauseDetail?.(cause, i);\n return (\n <div key={i} data-cause-index={i} className=\"min-w-0\">\n <div className=\"flex min-w-0 items-start gap-2 font-mono text-[11px] text-orange-700 dark:text-orange-300\">\n <Icon icon={UiStackFrameDot} className=\"mt-0.5 shrink-0 text-xs\" />\n <span className=\"shrink-0 opacity-75\">Caused by</span>\n <span className=\"min-w-0 break-all\">{cause}</span>\n </div>\n {detail ? <div className=\"mt-1 pl-5\">{detail}</div> : null}\n </div>\n );\n })}\n </div>\n )}\n <div className=\"divide-y divide-border/60\">\n {visibleFrames.map((frame, idx) => (\n <StackFrameRow\n key={`${frame.functionName}-${idx}`}\n frame={frame}\n index={idx}\n showIndex\n {...(frameActions ? { frameActions } : {})}\n {...(renderFramePart ? { renderFramePart } : {})}\n {...(renderFrameDetail ? { renderFrameDetail } : {})}\n frameActionsVisibility={frameActionsVisibility}\n />\n ))}\n </div>\n {hasFilteredFrames && (\n <div className=\"border-t border-border bg-muted/30 px-3 py-1.5 text-[11px] text-muted-foreground\">\n Showing {visibleFrames.length} of {enrichedFrames.length} frames\n </div>\n )}\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"RenderedStackTrace.js","sources":["../../../src/data/diagnostics/RenderedStackTrace.tsx"],"sourcesContent":["import { useMemo, type ReactNode } from \"react\";\nimport {\n parseJavaStackTrace,\n type ParsedStackFrame,\n type ParsedStackTrace,\n} from \"./stacktrace-parse\";\nimport { Icon } from \"../Icon\";\nimport { UiStackFrameDot, UiError } from \"../../icons\";\nimport {\n StackFrameRow,\n type StackFrameActions,\n type StackFrameActionsVisibility,\n type StackFrameDetailRenderer,\n type StackFramePartRenderer,\n} from \"./StackFrameRow\";\nimport type { FrameSource } from \"./FrameSourceWindow.utils\";\n\n// SourceResolver matches the Go clicky.SourceResolver interface: given a\n// frame, return surrounding source lines so the renderer can display inline\n// context. Failures must be silent (return undefined) so a missing class\n// never blocks the rest of the trace.\n//\n// The return shape is `FrameSource` — the same shape the source window\n// consumes and the same one the JVM thread-dump resolver returns, so a caller\n// that can resolve source for one surface can resolve it for both.\nexport type StackTraceSourceResolver = (\n frame: ParsedStackFrame,\n contextLines: number,\n) => FrameSource | undefined;\n\nexport interface StackTraceProps {\n /**\n * Raw Java stack-trace string or a pre-parsed ParsedStackTrace\n * from a backend/parser.\n */\n input: string | ParsedStackTrace;\n /** Parser language. Currently Java stack traces are supported. */\n language?: \"java\";\n /** Optional source-line resolver for inline context under frames. */\n resolver?: StackTraceSourceResolver;\n /** Number of source lines to request around each frame. */\n contextLines?: number;\n /** Hide frames known to be runtime/library-only. */\n hideRuntimeOnly?: boolean;\n /** Only show frames whose class starts with one of these prefixes. */\n include?: string[];\n /** Hide frames whose class starts with one of these prefixes. */\n exclude?: string[];\n /** Trailing per-frame actions, revealed on hover/focus. */\n frameActions?: StackFrameActions;\n /** Replace method, class, and location labels with application-owned renderers. */\n renderFramePart?: StackFramePartRenderer;\n /** Render application-owned detail below each visible frame. */\n renderFrameDetail?: StackFrameDetailRenderer;\n /** Control whether per-frame actions are hover-only or always visible. */\n frameActionsVisibility?: StackFrameActionsVisibility;\n /** Show each frame's 1-based ordinal in the gutter. Defaults to true. */\n showFrameIndex?: boolean;\n /** Additional application-owned frame predicate. */\n frameFilter?: (frame: ParsedStackFrame) => boolean;\n /** Render application-owned detail below a parsed cause. */\n renderCauseDetail?: (cause: string, index: number) => ReactNode;\n /** Classes applied to the stack-trace shell. */\n className?: string;\n}\n\n// StackTrace is the React counterpart to Go's clicky.StackTrace builder. Pass\n// a raw exception dump and it parses + renders frames; pass a SourceResolver\n// to get inline source context (±N lines) under each frame, with the focal\n// line highlighted. Frames themselves are rendered by the shared StackFrameRow.\nexport function StackTrace({\n input,\n language = \"java\",\n resolver,\n contextLines = 3,\n hideRuntimeOnly = false,\n include,\n exclude,\n frameActions,\n renderFramePart,\n renderFrameDetail,\n frameActionsVisibility = \"hover\",\n showFrameIndex = true,\n frameFilter,\n renderCauseDetail,\n className,\n}: StackTraceProps) {\n const parsed = useMemo<ParsedStackTrace>(() => {\n if (typeof input === \"string\") {\n return parseJavaStackTrace(input);\n }\n return input;\n }, [input, language]);\n\n const enrichedFrames = useMemo<ParsedStackFrame[]>(() => {\n if (!resolver) return parsed.frames;\n return parsed.frames.map((frame): ParsedStackFrame => {\n if (frame.sourceLines && frame.sourceLines.length > 0) return frame;\n const resolved = resolver(frame, contextLines);\n if (!resolved) return frame;\n // `line` stays the frame's own — it is what the window highlights, and a\n // resolver returning one would silently move the focal line off the throw.\n const { line: _ignored, ...source } = resolved;\n return { ...frame, ...source };\n });\n }, [parsed.frames, resolver, contextLines]);\n\n const visibleFrames = useMemo(() => {\n return enrichedFrames.filter((frame) => {\n if (hideRuntimeOnly && frame.runtime) return false;\n if (frameFilter && !frameFilter(frame)) return false;\n if (exclude && exclude.some((p) => frame.class?.startsWith(p))) return false;\n if (include && include.length > 0) {\n return include.some((p) => frame.class?.startsWith(p));\n }\n return true;\n });\n }, [enrichedFrames, hideRuntimeOnly, include, exclude, frameFilter]);\n\n if (visibleFrames.length === 0 && !parsed.exceptionClass) return null;\n\n const hasFilteredFrames = visibleFrames.length !== enrichedFrames.length;\n\n return (\n <div\n className={[\n \"overflow-hidden rounded-md border border-border bg-background text-foreground\",\n className,\n ]\n .filter(Boolean)\n .join(\" \")}\n >\n {(parsed.exceptionClass || parsed.message) && (\n <div className=\"border-b border-border bg-red-500/5 px-3 py-2\">\n <div className=\"flex min-w-0 items-start gap-2\">\n <Icon\n icon={UiError}\n className=\"mt-0.5 shrink-0 text-sm text-red-600 dark:text-red-400\"\n />\n <div className=\"min-w-0 flex-1\">\n {parsed.exceptionClass && (\n <div className=\"break-all font-mono text-xs font-semibold text-red-700 dark:text-red-300\">\n {parsed.exceptionClass}\n </div>\n )}\n {parsed.message && (\n <div className=\"mt-0.5 whitespace-pre-wrap break-words text-xs text-foreground\">\n {parsed.message}\n </div>\n )}\n </div>\n </div>\n </div>\n )}\n {parsed.causedBy.length > 0 && (\n <div className=\"space-y-1 border-b border-border bg-orange-500/5 px-3 py-2\">\n {parsed.causedBy.map((cause, i) => {\n const detail = renderCauseDetail?.(cause, i);\n return (\n <div key={i} data-cause-index={i} className=\"min-w-0\">\n <div className=\"flex min-w-0 items-start gap-2 font-mono text-[11px] text-orange-700 dark:text-orange-300\">\n <Icon icon={UiStackFrameDot} className=\"mt-0.5 shrink-0 text-xs\" />\n <span className=\"shrink-0 opacity-75\">Caused by</span>\n <span className=\"min-w-0 break-all\">{cause}</span>\n </div>\n {detail ? <div className=\"mt-1 pl-5\">{detail}</div> : null}\n </div>\n );\n })}\n </div>\n )}\n <div className=\"divide-y divide-border/60\">\n {visibleFrames.map((frame, idx) => (\n <StackFrameRow\n key={`${frame.functionName}-${idx}`}\n frame={frame}\n index={idx}\n showIndex={showFrameIndex}\n {...(frameActions ? { frameActions } : {})}\n {...(renderFramePart ? { renderFramePart } : {})}\n {...(renderFrameDetail ? { renderFrameDetail } : {})}\n frameActionsVisibility={frameActionsVisibility}\n />\n ))}\n </div>\n {hasFilteredFrames && (\n <div className=\"border-t border-border bg-muted/30 px-3 py-1.5 text-[11px] text-muted-foreground\">\n Showing {visibleFrames.length} of {enrichedFrames.length} frames\n </div>\n )}\n </div>\n );\n}\n"],"names":[],"mappings":";;;;;;;AAsEO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA,eAAe;AAAA,EACf,kBAAkB;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,yBAAyB;AAAA,EACzB,iBAAiB;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AACF,GAAoB;AAClB,QAAM,SAAS,QAA0B,MAAM;AAC7C,QAAI,OAAO,UAAU,UAAU;AAC7B,aAAO,oBAAoB,KAAK;AAAA,IAClC;AACA,WAAO;AAAA,EACT,GAAG,CAAC,OAAO,QAAQ,CAAC;AAEpB,QAAM,iBAAiB,QAA4B,MAAM;AACvD,QAAI,CAAC,SAAU,QAAO,OAAO;AAC7B,WAAO,OAAO,OAAO,IAAI,CAAC,UAA4B;AACpD,UAAI,MAAM,eAAe,MAAM,YAAY,SAAS,EAAG,QAAO;AAC9D,YAAM,WAAW,SAAS,OAAO,YAAY;AAC7C,UAAI,CAAC,SAAU,QAAO;AAGtB,YAAM,EAAE,MAAM,UAAU,GAAG,WAAW;AACtC,aAAO,EAAE,GAAG,OAAO,GAAG,OAAA;AAAA,IACxB,CAAC;AAAA,EACH,GAAG,CAAC,OAAO,QAAQ,UAAU,YAAY,CAAC;AAE1C,QAAM,gBAAgB,QAAQ,MAAM;AAClC,WAAO,eAAe,OAAO,CAAC,UAAU;AACtC,UAAI,mBAAmB,MAAM,QAAS,QAAO;AAC7C,UAAI,eAAe,CAAC,YAAY,KAAK,EAAG,QAAO;AAC/C,UAAI,WAAW,QAAQ,KAAK,CAAC,MAAA;;AAAM,2BAAM,UAAN,mBAAa,WAAW;AAAA,OAAE,EAAG,QAAO;AACvE,UAAI,WAAW,QAAQ,SAAS,GAAG;AACjC,eAAO,QAAQ,KAAK,CAAC,MAAA;;AAAM,6BAAM,UAAN,mBAAa,WAAW;AAAA,SAAE;AAAA,MACvD;AACA,aAAO;AAAA,IACT,CAAC;AAAA,EACH,GAAG,CAAC,gBAAgB,iBAAiB,SAAS,SAAS,WAAW,CAAC;AAEnE,MAAI,cAAc,WAAW,KAAK,CAAC,OAAO,eAAgB,QAAO;AAEjE,QAAM,oBAAoB,cAAc,WAAW,eAAe;AAElE,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MAAA,EAEC,OAAO,OAAO,EACd,KAAK,GAAG;AAAA,MAET,UAAA;AAAA,SAAA,OAAO,kBAAkB,OAAO,YAChC,oBAAC,OAAA,EAAI,WAAU,iDACb,UAAA,qBAAC,OAAA,EAAI,WAAU,kCACb,UAAA;AAAA,UAAA;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,MAAM;AAAA,cACN,WAAU;AAAA,YAAA;AAAA,UAAA;AAAA,UAEZ,qBAAC,OAAA,EAAI,WAAU,kBACZ,UAAA;AAAA,YAAA,OAAO,kBACN,oBAAC,OAAA,EAAI,WAAU,4EACZ,iBAAO,gBACV;AAAA,YAED,OAAO,WACN,oBAAC,SAAI,WAAU,kEACZ,iBAAO,QAAA,CACV;AAAA,UAAA,EAAA,CAEJ;AAAA,QAAA,EAAA,CACF,EAAA,CACF;AAAA,QAED,OAAO,SAAS,SAAS,KACxB,oBAAC,OAAA,EAAI,WAAU,8DACZ,UAAA,OAAO,SAAS,IAAI,CAAC,OAAO,MAAM;AACjC,gBAAM,SAAS,uDAAoB,OAAO;AAC1C,iBACE,qBAAC,OAAA,EAAY,oBAAkB,GAAG,WAAU,WAC1C,UAAA;AAAA,YAAA,qBAAC,OAAA,EAAI,WAAU,6FACb,UAAA;AAAA,cAAA,oBAAC,MAAA,EAAK,MAAM,iBAAiB,WAAU,2BAA0B;AAAA,cACjE,oBAAC,QAAA,EAAK,WAAU,uBAAsB,UAAA,aAAS;AAAA,cAC/C,oBAAC,QAAA,EAAK,WAAU,qBAAqB,UAAA,MAAA,CAAM;AAAA,YAAA,GAC7C;AAAA,YACC,SAAS,oBAAC,OAAA,EAAI,WAAU,aAAa,kBAAO,IAAS;AAAA,UAAA,EAAA,GAN9C,CAOV;AAAA,QAEJ,CAAC,EAAA,CACH;AAAA,QAEF,oBAAC,SAAI,WAAU,6BACZ,wBAAc,IAAI,CAAC,OAAO,QACzB;AAAA,UAAC;AAAA,UAAA;AAAA,YAEC;AAAA,YACA,OAAO;AAAA,YACP,WAAW;AAAA,YACV,GAAI,eAAe,EAAE,aAAA,IAAiB,CAAA;AAAA,YACtC,GAAI,kBAAkB,EAAE,gBAAA,IAAoB,CAAA;AAAA,YAC5C,GAAI,oBAAoB,EAAE,kBAAA,IAAsB,CAAA;AAAA,YACjD;AAAA,UAAA;AAAA,UAPK,GAAG,MAAM,YAAY,IAAI,GAAG;AAAA,QAAA,CASpC,GACH;AAAA,QACC,qBACC,qBAAC,OAAA,EAAI,WAAU,oFAAmF,UAAA;AAAA,UAAA;AAAA,UACvF,cAAc;AAAA,UAAO;AAAA,UAAK,eAAe;AAAA,UAAO;AAAA,QAAA,EAAA,CAC3D;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAIR;"}
@@ -28,13 +28,13 @@ function StackFrameRow({
28
28
  "div",
29
29
  {
30
30
  className: [
31
- "group grid gap-2 px-3 py-1.5 text-xs",
31
+ "group grid gap-x-2 gap-y-0.5 px-3 py-0.5 text-xs",
32
32
  showIndex ? "grid-cols-[2rem_minmax(0,1fr)_auto]" : "grid-cols-[1.25rem_minmax(0,1fr)_auto]",
33
33
  frame.runtime ? "text-muted-foreground" : "text-foreground"
34
34
  ].join(" "),
35
35
  children: [
36
36
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-end gap-1 pt-0.5 font-mono text-[10px] text-muted-foreground", children: [
37
- showIndex && /* @__PURE__ */ jsxRuntime.jsx("span", { children: index + 1 }),
37
+ showIndex && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-frame-index": true, children: index + 1 }),
38
38
  /* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { icon: frameIcon(frame), className: "mt-px shrink-0 text-[11px]" })
39
39
  ] }),
40
40
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-w-0 flex-wrap items-baseline gap-x-2 gap-y-0.5", children: isAnnotation ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
@@ -56,7 +56,7 @@ function StackFrameRow({
56
56
  }
57
57
  ) : /* @__PURE__ */ jsxRuntime.jsx("div", {}),
58
58
  !isAnnotation && FrameSourceWindow_utils.frameHasSource(frame) ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-3", children: /* @__PURE__ */ jsxRuntime.jsx(FrameSourceWindow.FrameSourceWindow, { frame }) }) : null,
59
- detail ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-span-3", children: detail }) : null
59
+ detail ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "col-start-2 col-span-2 min-w-0", children: detail }) : null
60
60
  ]
61
61
  }
62
62
  );
@@ -1 +1 @@
1
- {"version":3,"file":"StackFrameRow.cjs","sources":["../../../src/data/diagnostics/StackFrameRow.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { Icon } from \"../Icon\";\nimport {\n UiChip,\n UiDebugStepOver,\n UiLock,\n UiMethod,\n UiStackFrameDot,\n UiSync,\n UiWatch,\n} from \"../../icons\";\nimport { FrameSourceWindow } from \"./FrameSourceWindow\";\nimport { frameHasSource } from \"./FrameSourceWindow.utils\";\nimport type { ParsedThreadFrame } from \"./jvm-stacktrace\";\n\n// StackFrameActions renders trailing per-frame affordances. It is a slot: the\n// shared library never knows what the actions do, only where they go.\nexport type StackFrameActions = (frame: ParsedThreadFrame, index: number) => ReactNode;\nexport type StackFramePart = \"method\" | \"class\" | \"location\";\nexport type StackFramePartRenderer = (\n part: StackFramePart,\n frame: ParsedThreadFrame,\n index: number,\n) => ReactNode;\nexport type StackFrameDetailRenderer = (frame: ParsedThreadFrame, index: number) => ReactNode;\nexport type StackFrameActionsVisibility = \"hover\" | \"always\";\n\nexport interface StackFrameRowProps {\n frame: ParsedThreadFrame;\n index: number;\n /** Show the 1-based frame ordinal in the gutter. */\n showIndex?: boolean;\n /** Trailing actions for this frame, revealed on hover/focus. */\n frameActions?: StackFrameActions;\n /** Replace the method, class, or location label while preserving row layout. */\n renderFramePart?: StackFramePartRenderer;\n /** Additional detail rendered below an ordinary frame. */\n renderFrameDetail?: StackFrameDetailRenderer;\n /** Whether actions are hover-only or permanently visible. */\n frameActionsVisibility?: StackFrameActionsVisibility;\n}\n\n// StackFrameRow is THE stack-frame renderer. Both an exception dump (via\n// StackTrace) and a JVM thread dump (via JvmStackTrace) render their frames\n// through it, so a frame looks and behaves the same wherever it is shown.\n//\n// Thread dumps carry lock/monitor annotation entries alongside real frames —\n// `frame.kind !== \"frame\"` — which are rendered as their own muted rows with a\n// lock/wait icon and no source window. An exception dump simply never produces\n// them.\nexport function StackFrameRow({\n frame,\n index,\n showIndex = false,\n frameActions,\n renderFramePart,\n renderFrameDetail,\n frameActionsVisibility = \"hover\",\n}: StackFrameRowProps) {\n const isAnnotation = frame.kind !== \"frame\";\n const methodName = frame.displayName || frame.method || frame.functionName;\n const actions = frameActions?.(frame, index);\n const detail = !isAnnotation ? renderFrameDetail?.(frame, index) : null;\n\n return (\n <div\n className={[\n \"group grid gap-2 px-3 py-1.5 text-xs\",\n showIndex ? \"grid-cols-[2rem_minmax(0,1fr)_auto]\" : \"grid-cols-[1.25rem_minmax(0,1fr)_auto]\",\n frame.runtime ? \"text-muted-foreground\" : \"text-foreground\",\n ].join(\" \")}\n >\n <div className=\"flex items-start justify-end gap-1 pt-0.5 font-mono text-[10px] text-muted-foreground\">\n {showIndex && <span>{index + 1}</span>}\n <Icon icon={frameIcon(frame)} className=\"mt-px shrink-0 text-[11px]\" />\n </div>\n\n <div className=\"min-w-0\">\n <div className=\"flex min-w-0 flex-wrap items-baseline gap-x-2 gap-y-0.5\">\n {isAnnotation ? (\n <>\n <span className=\"min-w-0 break-all font-mono font-semibold leading-4 opacity-70\">\n {frame.functionName}\n </span>\n {frame.annotationText && (\n <span className=\"min-w-0 break-all font-mono text-[11px] font-normal opacity-80\">\n {frame.annotationText}\n </span>\n )}\n </>\n ) : (\n <>\n {renderFramePart ? (\n renderFramePart(\"method\", frame, index)\n ) : (\n <span className=\"min-w-0 break-all font-mono font-semibold leading-4\">\n {methodName}\n </span>\n )}\n {frame.class && (\n renderFramePart ? (\n renderFramePart(\"class\", frame, index)\n ) : (\n <span className=\"min-w-0 break-all font-mono text-[11px] text-muted-foreground\">\n {frame.class}\n </span>\n )\n )}\n {frame.location && (\n renderFramePart ? (\n renderFramePart(\"location\", frame, index)\n ) : (\n <span className=\"rounded border border-border bg-muted/40 px-1.5 py-px font-mono text-[10px] text-muted-foreground\">\n {frame.location}\n </span>\n )\n )}\n </>\n )}\n </div>\n </div>\n\n {actions ? (\n <div\n className={[\n \"flex shrink-0 items-start gap-1\",\n frameActionsVisibility === \"hover\"\n ? \"opacity-0 transition-opacity focus-within:opacity-100 group-hover:opacity-100\"\n : \"opacity-100\",\n ].join(\" \")}\n >\n {actions}\n </div>\n ) : (\n <div />\n )}\n\n {!isAnnotation && frameHasSource(frame) ? (\n <div className=\"col-span-3\">\n <FrameSourceWindow frame={frame} />\n </div>\n ) : null}\n {detail ? <div className=\"col-span-3\">{detail}</div> : null}\n </div>\n );\n}\n\nfunction frameIcon(frame: ParsedThreadFrame) {\n switch (frame.kind) {\n case \"locked\":\n return UiLock;\n case \"waiting_to_lock\":\n return UiSync;\n case \"waiting_on\":\n case \"parking\":\n return UiWatch;\n default:\n break;\n }\n if (frame.nativeMethod) return UiChip;\n if (frame.runtime) return UiDebugStepOver;\n return frame.method || frame.class ? UiMethod : UiStackFrameDot;\n}\n"],"names":["jsxs","jsx","Icon","Fragment","frameHasSource","FrameSourceWindow","UiLock","UiSync","UiWatch","UiChip","UiDebugStepOver","UiMethod","UiStackFrameDot"],"mappings":";;;;;;;;;;;;;AAkDO,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA,yBAAyB;AAC3B,GAAuB;AACrB,QAAM,eAAe,MAAM,SAAS;AACpC,QAAM,aAAa,MAAM,eAAe,MAAM,UAAU,MAAM;AAC9D,QAAM,UAAU,6CAAe,OAAO;AACtC,QAAM,SAAS,CAAC,eAAe,uDAAoB,OAAO,SAAS;AAEnE,SACEA,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA,YAAY,wCAAwC;AAAA,QACpD,MAAM,UAAU,0BAA0B;AAAA,MAAA,EAC1C,KAAK,GAAG;AAAA,MAEV,UAAA;AAAA,QAAAA,2BAAAA,KAAC,OAAA,EAAI,WAAU,yFACZ,UAAA;AAAA,UAAA,aAAaC,2BAAAA,IAAC,QAAA,EAAM,UAAA,QAAQ,GAAE;AAAA,yCAC9BC,KAAAA,MAAA,EAAK,MAAM,UAAU,KAAK,GAAG,WAAU,6BAAA,CAA6B;AAAA,QAAA,GACvE;AAAA,QAEAD,2BAAAA,IAAC,SAAI,WAAU,WACb,yCAAC,OAAA,EAAI,WAAU,2DACZ,UAAA,eACCD,2BAAAA,KAAAG,WAAAA,UAAA,EACE,UAAA;AAAA,UAAAF,2BAAAA,IAAC,QAAA,EAAK,WAAU,kEACb,UAAA,MAAM,cACT;AAAA,UACC,MAAM,kBACLA,2BAAAA,IAAC,UAAK,WAAU,kEACb,gBAAM,eAAA,CACT;AAAA,QAAA,EAAA,CAEJ,IAEAD,2BAAAA,KAAAG,WAAAA,UAAA,EACG,UAAA;AAAA,UAAA,kBACC,gBAAgB,UAAU,OAAO,KAAK,IAEtCF,2BAAAA,IAAC,QAAA,EAAK,WAAU,uDACb,UAAA,WAAA,CACH;AAAA,UAED,MAAM,UACL,kBACE,gBAAgB,SAAS,OAAO,KAAK,IAErCA,2BAAAA,IAAC,QAAA,EAAK,WAAU,iEACb,gBAAM,MAAA,CACT;AAAA,UAGH,MAAM,aACL,kBACE,gBAAgB,YAAY,OAAO,KAAK,IAExCA,2BAAAA,IAAC,QAAA,EAAK,WAAU,qGACb,gBAAM,UACT;AAAA,QAAA,EAAA,CAGN,GAEJ,GACF;AAAA,QAEC,UACCA,2BAAAA;AAAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAW;AAAA,cACT;AAAA,cACA,2BAA2B,UACvB,kFACA;AAAA,YAAA,EACJ,KAAK,GAAG;AAAA,YAET,UAAA;AAAA,UAAA;AAAA,QAAA,mCAGF,OAAA,EAAI;AAAA,QAGN,CAAC,gBAAgBG,wBAAAA,eAAe,KAAK,IACpCH,2BAAAA,IAAC,OAAA,EAAI,WAAU,cACb,UAAAA,2BAAAA,IAACI,kBAAAA,mBAAA,EAAkB,MAAA,CAAc,GACnC,IACE;AAAA,QACH,SAASJ,2BAAAA,IAAC,OAAA,EAAI,WAAU,cAAc,kBAAO,IAAS;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAG7D;AAEA,SAAS,UAAU,OAA0B;AAC3C,UAAQ,MAAM,MAAA;AAAA,IACZ,KAAK;AACH,aAAOK,OAAAA;AAAAA,IACT,KAAK;AACH,aAAOC,OAAAA;AAAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAOC,QAAAA;AAAAA,EAEP;AAEJ,MAAI,MAAM,aAAc,QAAOC,OAAAA;AAC/B,MAAI,MAAM,QAAS,QAAOC,gBAAAA;AAC1B,SAAO,MAAM,UAAU,MAAM,QAAQC,SAAAA,WAAWC,gBAAAA;AAClD;;"}
1
+ {"version":3,"file":"StackFrameRow.cjs","sources":["../../../src/data/diagnostics/StackFrameRow.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { Icon } from \"../Icon\";\nimport {\n UiChip,\n UiDebugStepOver,\n UiLock,\n UiMethod,\n UiStackFrameDot,\n UiSync,\n UiWatch,\n} from \"../../icons\";\nimport { FrameSourceWindow } from \"./FrameSourceWindow\";\nimport { frameHasSource } from \"./FrameSourceWindow.utils\";\nimport type { ParsedThreadFrame } from \"./jvm-stacktrace\";\n\n// StackFrameActions renders trailing per-frame affordances. It is a slot: the\n// shared library never knows what the actions do, only where they go.\nexport type StackFrameActions = (frame: ParsedThreadFrame, index: number) => ReactNode;\nexport type StackFramePart = \"method\" | \"class\" | \"location\";\nexport type StackFramePartRenderer = (\n part: StackFramePart,\n frame: ParsedThreadFrame,\n index: number,\n) => ReactNode;\nexport type StackFrameDetailRenderer = (frame: ParsedThreadFrame, index: number) => ReactNode;\nexport type StackFrameActionsVisibility = \"hover\" | \"always\";\n\nexport interface StackFrameRowProps {\n frame: ParsedThreadFrame;\n index: number;\n /** Show the 1-based frame ordinal in the gutter. */\n showIndex?: boolean;\n /** Trailing actions for this frame, revealed on hover/focus. */\n frameActions?: StackFrameActions;\n /** Replace the method, class, or location label while preserving row layout. */\n renderFramePart?: StackFramePartRenderer;\n /** Additional detail rendered below an ordinary frame. */\n renderFrameDetail?: StackFrameDetailRenderer;\n /** Whether actions are hover-only or permanently visible. */\n frameActionsVisibility?: StackFrameActionsVisibility;\n}\n\n// StackFrameRow is THE stack-frame renderer. Both an exception dump (via\n// StackTrace) and a JVM thread dump (via JvmStackTrace) render their frames\n// through it, so a frame looks and behaves the same wherever it is shown.\n//\n// Thread dumps carry lock/monitor annotation entries alongside real frames —\n// `frame.kind !== \"frame\"` — which are rendered as their own muted rows with a\n// lock/wait icon and no source window. An exception dump simply never produces\n// them.\nexport function StackFrameRow({\n frame,\n index,\n showIndex = false,\n frameActions,\n renderFramePart,\n renderFrameDetail,\n frameActionsVisibility = \"hover\",\n}: StackFrameRowProps) {\n const isAnnotation = frame.kind !== \"frame\";\n const methodName = frame.displayName || frame.method || frame.functionName;\n const actions = frameActions?.(frame, index);\n const detail = !isAnnotation ? renderFrameDetail?.(frame, index) : null;\n\n return (\n <div\n className={[\n \"group grid gap-x-2 gap-y-0.5 px-3 py-0.5 text-xs\",\n showIndex ? \"grid-cols-[2rem_minmax(0,1fr)_auto]\" : \"grid-cols-[1.25rem_minmax(0,1fr)_auto]\",\n frame.runtime ? \"text-muted-foreground\" : \"text-foreground\",\n ].join(\" \")}\n >\n <div className=\"flex items-start justify-end gap-1 pt-0.5 font-mono text-[10px] text-muted-foreground\">\n {showIndex && <span data-frame-index>{index + 1}</span>}\n <Icon icon={frameIcon(frame)} className=\"mt-px shrink-0 text-[11px]\" />\n </div>\n\n <div className=\"min-w-0\">\n <div className=\"flex min-w-0 flex-wrap items-baseline gap-x-2 gap-y-0.5\">\n {isAnnotation ? (\n <>\n <span className=\"min-w-0 break-all font-mono font-semibold leading-4 opacity-70\">\n {frame.functionName}\n </span>\n {frame.annotationText && (\n <span className=\"min-w-0 break-all font-mono text-[11px] font-normal opacity-80\">\n {frame.annotationText}\n </span>\n )}\n </>\n ) : (\n <>\n {renderFramePart ? (\n renderFramePart(\"method\", frame, index)\n ) : (\n <span className=\"min-w-0 break-all font-mono font-semibold leading-4\">\n {methodName}\n </span>\n )}\n {frame.class && (\n renderFramePart ? (\n renderFramePart(\"class\", frame, index)\n ) : (\n <span className=\"min-w-0 break-all font-mono text-[11px] text-muted-foreground\">\n {frame.class}\n </span>\n )\n )}\n {frame.location && (\n renderFramePart ? (\n renderFramePart(\"location\", frame, index)\n ) : (\n <span className=\"rounded border border-border bg-muted/40 px-1.5 py-px font-mono text-[10px] text-muted-foreground\">\n {frame.location}\n </span>\n )\n )}\n </>\n )}\n </div>\n </div>\n\n {actions ? (\n <div\n className={[\n \"flex shrink-0 items-start gap-1\",\n frameActionsVisibility === \"hover\"\n ? \"opacity-0 transition-opacity focus-within:opacity-100 group-hover:opacity-100\"\n : \"opacity-100\",\n ].join(\" \")}\n >\n {actions}\n </div>\n ) : (\n <div />\n )}\n\n {!isAnnotation && frameHasSource(frame) ? (\n <div className=\"col-span-3\">\n <FrameSourceWindow frame={frame} />\n </div>\n ) : null}\n {detail ? <div className=\"col-start-2 col-span-2 min-w-0\">{detail}</div> : null}\n </div>\n );\n}\n\nfunction frameIcon(frame: ParsedThreadFrame) {\n switch (frame.kind) {\n case \"locked\":\n return UiLock;\n case \"waiting_to_lock\":\n return UiSync;\n case \"waiting_on\":\n case \"parking\":\n return UiWatch;\n default:\n break;\n }\n if (frame.nativeMethod) return UiChip;\n if (frame.runtime) return UiDebugStepOver;\n return frame.method || frame.class ? UiMethod : UiStackFrameDot;\n}\n"],"names":["jsxs","jsx","Icon","Fragment","frameHasSource","FrameSourceWindow","UiLock","UiSync","UiWatch","UiChip","UiDebugStepOver","UiMethod","UiStackFrameDot"],"mappings":";;;;;;;;;;;;;AAkDO,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA,yBAAyB;AAC3B,GAAuB;AACrB,QAAM,eAAe,MAAM,SAAS;AACpC,QAAM,aAAa,MAAM,eAAe,MAAM,UAAU,MAAM;AAC9D,QAAM,UAAU,6CAAe,OAAO;AACtC,QAAM,SAAS,CAAC,eAAe,uDAAoB,OAAO,SAAS;AAEnE,SACEA,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA,YAAY,wCAAwC;AAAA,QACpD,MAAM,UAAU,0BAA0B;AAAA,MAAA,EAC1C,KAAK,GAAG;AAAA,MAEV,UAAA;AAAA,QAAAA,2BAAAA,KAAC,OAAA,EAAI,WAAU,yFACZ,UAAA;AAAA,UAAA,aAAaC,2BAAAA,IAAC,QAAA,EAAK,oBAAgB,MAAE,kBAAQ,GAAE;AAAA,yCAC/CC,KAAAA,MAAA,EAAK,MAAM,UAAU,KAAK,GAAG,WAAU,6BAAA,CAA6B;AAAA,QAAA,GACvE;AAAA,QAEAD,2BAAAA,IAAC,SAAI,WAAU,WACb,yCAAC,OAAA,EAAI,WAAU,2DACZ,UAAA,eACCD,2BAAAA,KAAAG,WAAAA,UAAA,EACE,UAAA;AAAA,UAAAF,2BAAAA,IAAC,QAAA,EAAK,WAAU,kEACb,UAAA,MAAM,cACT;AAAA,UACC,MAAM,kBACLA,2BAAAA,IAAC,UAAK,WAAU,kEACb,gBAAM,eAAA,CACT;AAAA,QAAA,EAAA,CAEJ,IAEAD,2BAAAA,KAAAG,WAAAA,UAAA,EACG,UAAA;AAAA,UAAA,kBACC,gBAAgB,UAAU,OAAO,KAAK,IAEtCF,2BAAAA,IAAC,QAAA,EAAK,WAAU,uDACb,UAAA,WAAA,CACH;AAAA,UAED,MAAM,UACL,kBACE,gBAAgB,SAAS,OAAO,KAAK,IAErCA,2BAAAA,IAAC,QAAA,EAAK,WAAU,iEACb,gBAAM,MAAA,CACT;AAAA,UAGH,MAAM,aACL,kBACE,gBAAgB,YAAY,OAAO,KAAK,IAExCA,2BAAAA,IAAC,QAAA,EAAK,WAAU,qGACb,gBAAM,UACT;AAAA,QAAA,EAAA,CAGN,GAEJ,GACF;AAAA,QAEC,UACCA,2BAAAA;AAAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAW;AAAA,cACT;AAAA,cACA,2BAA2B,UACvB,kFACA;AAAA,YAAA,EACJ,KAAK,GAAG;AAAA,YAET,UAAA;AAAA,UAAA;AAAA,QAAA,mCAGF,OAAA,EAAI;AAAA,QAGN,CAAC,gBAAgBG,wBAAAA,eAAe,KAAK,IACpCH,2BAAAA,IAAC,OAAA,EAAI,WAAU,cACb,UAAAA,2BAAAA,IAACI,kBAAAA,mBAAA,EAAkB,MAAA,CAAc,GACnC,IACE;AAAA,QACH,SAASJ,2BAAAA,IAAC,OAAA,EAAI,WAAU,kCAAkC,kBAAO,IAAS;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGjF;AAEA,SAAS,UAAU,OAA0B;AAC3C,UAAQ,MAAM,MAAA;AAAA,IACZ,KAAK;AACH,aAAOK,OAAAA;AAAAA,IACT,KAAK;AACH,aAAOC,OAAAA;AAAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAOC,QAAAA;AAAAA,EAEP;AAEJ,MAAI,MAAM,aAAc,QAAOC,OAAAA;AAC/B,MAAI,MAAM,QAAS,QAAOC,gBAAAA;AAC1B,SAAO,MAAM,UAAU,MAAM,QAAQC,SAAAA,WAAWC,gBAAAA;AAClD;;"}
@@ -26,13 +26,13 @@ function StackFrameRow({
26
26
  "div",
27
27
  {
28
28
  className: [
29
- "group grid gap-2 px-3 py-1.5 text-xs",
29
+ "group grid gap-x-2 gap-y-0.5 px-3 py-0.5 text-xs",
30
30
  showIndex ? "grid-cols-[2rem_minmax(0,1fr)_auto]" : "grid-cols-[1.25rem_minmax(0,1fr)_auto]",
31
31
  frame.runtime ? "text-muted-foreground" : "text-foreground"
32
32
  ].join(" "),
33
33
  children: [
34
34
  /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-end gap-1 pt-0.5 font-mono text-[10px] text-muted-foreground", children: [
35
- showIndex && /* @__PURE__ */ jsx("span", { children: index + 1 }),
35
+ showIndex && /* @__PURE__ */ jsx("span", { "data-frame-index": true, children: index + 1 }),
36
36
  /* @__PURE__ */ jsx(Icon, { icon: frameIcon(frame), className: "mt-px shrink-0 text-[11px]" })
37
37
  ] }),
38
38
  /* @__PURE__ */ jsx("div", { className: "min-w-0", children: /* @__PURE__ */ jsx("div", { className: "flex min-w-0 flex-wrap items-baseline gap-x-2 gap-y-0.5", children: isAnnotation ? /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -54,7 +54,7 @@ function StackFrameRow({
54
54
  }
55
55
  ) : /* @__PURE__ */ jsx("div", {}),
56
56
  !isAnnotation && frameHasSource(frame) ? /* @__PURE__ */ jsx("div", { className: "col-span-3", children: /* @__PURE__ */ jsx(FrameSourceWindow, { frame }) }) : null,
57
- detail ? /* @__PURE__ */ jsx("div", { className: "col-span-3", children: detail }) : null
57
+ detail ? /* @__PURE__ */ jsx("div", { className: "col-start-2 col-span-2 min-w-0", children: detail }) : null
58
58
  ]
59
59
  }
60
60
  );
@@ -1 +1 @@
1
- {"version":3,"file":"StackFrameRow.js","sources":["../../../src/data/diagnostics/StackFrameRow.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { Icon } from \"../Icon\";\nimport {\n UiChip,\n UiDebugStepOver,\n UiLock,\n UiMethod,\n UiStackFrameDot,\n UiSync,\n UiWatch,\n} from \"../../icons\";\nimport { FrameSourceWindow } from \"./FrameSourceWindow\";\nimport { frameHasSource } from \"./FrameSourceWindow.utils\";\nimport type { ParsedThreadFrame } from \"./jvm-stacktrace\";\n\n// StackFrameActions renders trailing per-frame affordances. It is a slot: the\n// shared library never knows what the actions do, only where they go.\nexport type StackFrameActions = (frame: ParsedThreadFrame, index: number) => ReactNode;\nexport type StackFramePart = \"method\" | \"class\" | \"location\";\nexport type StackFramePartRenderer = (\n part: StackFramePart,\n frame: ParsedThreadFrame,\n index: number,\n) => ReactNode;\nexport type StackFrameDetailRenderer = (frame: ParsedThreadFrame, index: number) => ReactNode;\nexport type StackFrameActionsVisibility = \"hover\" | \"always\";\n\nexport interface StackFrameRowProps {\n frame: ParsedThreadFrame;\n index: number;\n /** Show the 1-based frame ordinal in the gutter. */\n showIndex?: boolean;\n /** Trailing actions for this frame, revealed on hover/focus. */\n frameActions?: StackFrameActions;\n /** Replace the method, class, or location label while preserving row layout. */\n renderFramePart?: StackFramePartRenderer;\n /** Additional detail rendered below an ordinary frame. */\n renderFrameDetail?: StackFrameDetailRenderer;\n /** Whether actions are hover-only or permanently visible. */\n frameActionsVisibility?: StackFrameActionsVisibility;\n}\n\n// StackFrameRow is THE stack-frame renderer. Both an exception dump (via\n// StackTrace) and a JVM thread dump (via JvmStackTrace) render their frames\n// through it, so a frame looks and behaves the same wherever it is shown.\n//\n// Thread dumps carry lock/monitor annotation entries alongside real frames —\n// `frame.kind !== \"frame\"` — which are rendered as their own muted rows with a\n// lock/wait icon and no source window. An exception dump simply never produces\n// them.\nexport function StackFrameRow({\n frame,\n index,\n showIndex = false,\n frameActions,\n renderFramePart,\n renderFrameDetail,\n frameActionsVisibility = \"hover\",\n}: StackFrameRowProps) {\n const isAnnotation = frame.kind !== \"frame\";\n const methodName = frame.displayName || frame.method || frame.functionName;\n const actions = frameActions?.(frame, index);\n const detail = !isAnnotation ? renderFrameDetail?.(frame, index) : null;\n\n return (\n <div\n className={[\n \"group grid gap-2 px-3 py-1.5 text-xs\",\n showIndex ? \"grid-cols-[2rem_minmax(0,1fr)_auto]\" : \"grid-cols-[1.25rem_minmax(0,1fr)_auto]\",\n frame.runtime ? \"text-muted-foreground\" : \"text-foreground\",\n ].join(\" \")}\n >\n <div className=\"flex items-start justify-end gap-1 pt-0.5 font-mono text-[10px] text-muted-foreground\">\n {showIndex && <span>{index + 1}</span>}\n <Icon icon={frameIcon(frame)} className=\"mt-px shrink-0 text-[11px]\" />\n </div>\n\n <div className=\"min-w-0\">\n <div className=\"flex min-w-0 flex-wrap items-baseline gap-x-2 gap-y-0.5\">\n {isAnnotation ? (\n <>\n <span className=\"min-w-0 break-all font-mono font-semibold leading-4 opacity-70\">\n {frame.functionName}\n </span>\n {frame.annotationText && (\n <span className=\"min-w-0 break-all font-mono text-[11px] font-normal opacity-80\">\n {frame.annotationText}\n </span>\n )}\n </>\n ) : (\n <>\n {renderFramePart ? (\n renderFramePart(\"method\", frame, index)\n ) : (\n <span className=\"min-w-0 break-all font-mono font-semibold leading-4\">\n {methodName}\n </span>\n )}\n {frame.class && (\n renderFramePart ? (\n renderFramePart(\"class\", frame, index)\n ) : (\n <span className=\"min-w-0 break-all font-mono text-[11px] text-muted-foreground\">\n {frame.class}\n </span>\n )\n )}\n {frame.location && (\n renderFramePart ? (\n renderFramePart(\"location\", frame, index)\n ) : (\n <span className=\"rounded border border-border bg-muted/40 px-1.5 py-px font-mono text-[10px] text-muted-foreground\">\n {frame.location}\n </span>\n )\n )}\n </>\n )}\n </div>\n </div>\n\n {actions ? (\n <div\n className={[\n \"flex shrink-0 items-start gap-1\",\n frameActionsVisibility === \"hover\"\n ? \"opacity-0 transition-opacity focus-within:opacity-100 group-hover:opacity-100\"\n : \"opacity-100\",\n ].join(\" \")}\n >\n {actions}\n </div>\n ) : (\n <div />\n )}\n\n {!isAnnotation && frameHasSource(frame) ? (\n <div className=\"col-span-3\">\n <FrameSourceWindow frame={frame} />\n </div>\n ) : null}\n {detail ? <div className=\"col-span-3\">{detail}</div> : null}\n </div>\n );\n}\n\nfunction frameIcon(frame: ParsedThreadFrame) {\n switch (frame.kind) {\n case \"locked\":\n return UiLock;\n case \"waiting_to_lock\":\n return UiSync;\n case \"waiting_on\":\n case \"parking\":\n return UiWatch;\n default:\n break;\n }\n if (frame.nativeMethod) return UiChip;\n if (frame.runtime) return UiDebugStepOver;\n return frame.method || frame.class ? UiMethod : UiStackFrameDot;\n}\n"],"names":[],"mappings":";;;;;;;;;;;AAkDO,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA,yBAAyB;AAC3B,GAAuB;AACrB,QAAM,eAAe,MAAM,SAAS;AACpC,QAAM,aAAa,MAAM,eAAe,MAAM,UAAU,MAAM;AAC9D,QAAM,UAAU,6CAAe,OAAO;AACtC,QAAM,SAAS,CAAC,eAAe,uDAAoB,OAAO,SAAS;AAEnE,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA,YAAY,wCAAwC;AAAA,QACpD,MAAM,UAAU,0BAA0B;AAAA,MAAA,EAC1C,KAAK,GAAG;AAAA,MAEV,UAAA;AAAA,QAAA,qBAAC,OAAA,EAAI,WAAU,yFACZ,UAAA;AAAA,UAAA,aAAa,oBAAC,QAAA,EAAM,UAAA,QAAQ,GAAE;AAAA,8BAC9B,MAAA,EAAK,MAAM,UAAU,KAAK,GAAG,WAAU,6BAAA,CAA6B;AAAA,QAAA,GACvE;AAAA,QAEA,oBAAC,SAAI,WAAU,WACb,8BAAC,OAAA,EAAI,WAAU,2DACZ,UAAA,eACC,qBAAA,UAAA,EACE,UAAA;AAAA,UAAA,oBAAC,QAAA,EAAK,WAAU,kEACb,UAAA,MAAM,cACT;AAAA,UACC,MAAM,kBACL,oBAAC,UAAK,WAAU,kEACb,gBAAM,eAAA,CACT;AAAA,QAAA,EAAA,CAEJ,IAEA,qBAAA,UAAA,EACG,UAAA;AAAA,UAAA,kBACC,gBAAgB,UAAU,OAAO,KAAK,IAEtC,oBAAC,QAAA,EAAK,WAAU,uDACb,UAAA,WAAA,CACH;AAAA,UAED,MAAM,UACL,kBACE,gBAAgB,SAAS,OAAO,KAAK,IAErC,oBAAC,QAAA,EAAK,WAAU,iEACb,gBAAM,MAAA,CACT;AAAA,UAGH,MAAM,aACL,kBACE,gBAAgB,YAAY,OAAO,KAAK,IAExC,oBAAC,QAAA,EAAK,WAAU,qGACb,gBAAM,UACT;AAAA,QAAA,EAAA,CAGN,GAEJ,GACF;AAAA,QAEC,UACC;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAW;AAAA,cACT;AAAA,cACA,2BAA2B,UACvB,kFACA;AAAA,YAAA,EACJ,KAAK,GAAG;AAAA,YAET,UAAA;AAAA,UAAA;AAAA,QAAA,wBAGF,OAAA,EAAI;AAAA,QAGN,CAAC,gBAAgB,eAAe,KAAK,IACpC,oBAAC,OAAA,EAAI,WAAU,cACb,UAAA,oBAAC,mBAAA,EAAkB,MAAA,CAAc,GACnC,IACE;AAAA,QACH,SAAS,oBAAC,OAAA,EAAI,WAAU,cAAc,kBAAO,IAAS;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAG7D;AAEA,SAAS,UAAU,OAA0B;AAC3C,UAAQ,MAAM,MAAA;AAAA,IACZ,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,EAEP;AAEJ,MAAI,MAAM,aAAc,QAAO;AAC/B,MAAI,MAAM,QAAS,QAAO;AAC1B,SAAO,MAAM,UAAU,MAAM,QAAQ,WAAW;AAClD;"}
1
+ {"version":3,"file":"StackFrameRow.js","sources":["../../../src/data/diagnostics/StackFrameRow.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { Icon } from \"../Icon\";\nimport {\n UiChip,\n UiDebugStepOver,\n UiLock,\n UiMethod,\n UiStackFrameDot,\n UiSync,\n UiWatch,\n} from \"../../icons\";\nimport { FrameSourceWindow } from \"./FrameSourceWindow\";\nimport { frameHasSource } from \"./FrameSourceWindow.utils\";\nimport type { ParsedThreadFrame } from \"./jvm-stacktrace\";\n\n// StackFrameActions renders trailing per-frame affordances. It is a slot: the\n// shared library never knows what the actions do, only where they go.\nexport type StackFrameActions = (frame: ParsedThreadFrame, index: number) => ReactNode;\nexport type StackFramePart = \"method\" | \"class\" | \"location\";\nexport type StackFramePartRenderer = (\n part: StackFramePart,\n frame: ParsedThreadFrame,\n index: number,\n) => ReactNode;\nexport type StackFrameDetailRenderer = (frame: ParsedThreadFrame, index: number) => ReactNode;\nexport type StackFrameActionsVisibility = \"hover\" | \"always\";\n\nexport interface StackFrameRowProps {\n frame: ParsedThreadFrame;\n index: number;\n /** Show the 1-based frame ordinal in the gutter. */\n showIndex?: boolean;\n /** Trailing actions for this frame, revealed on hover/focus. */\n frameActions?: StackFrameActions;\n /** Replace the method, class, or location label while preserving row layout. */\n renderFramePart?: StackFramePartRenderer;\n /** Additional detail rendered below an ordinary frame. */\n renderFrameDetail?: StackFrameDetailRenderer;\n /** Whether actions are hover-only or permanently visible. */\n frameActionsVisibility?: StackFrameActionsVisibility;\n}\n\n// StackFrameRow is THE stack-frame renderer. Both an exception dump (via\n// StackTrace) and a JVM thread dump (via JvmStackTrace) render their frames\n// through it, so a frame looks and behaves the same wherever it is shown.\n//\n// Thread dumps carry lock/monitor annotation entries alongside real frames —\n// `frame.kind !== \"frame\"` — which are rendered as their own muted rows with a\n// lock/wait icon and no source window. An exception dump simply never produces\n// them.\nexport function StackFrameRow({\n frame,\n index,\n showIndex = false,\n frameActions,\n renderFramePart,\n renderFrameDetail,\n frameActionsVisibility = \"hover\",\n}: StackFrameRowProps) {\n const isAnnotation = frame.kind !== \"frame\";\n const methodName = frame.displayName || frame.method || frame.functionName;\n const actions = frameActions?.(frame, index);\n const detail = !isAnnotation ? renderFrameDetail?.(frame, index) : null;\n\n return (\n <div\n className={[\n \"group grid gap-x-2 gap-y-0.5 px-3 py-0.5 text-xs\",\n showIndex ? \"grid-cols-[2rem_minmax(0,1fr)_auto]\" : \"grid-cols-[1.25rem_minmax(0,1fr)_auto]\",\n frame.runtime ? \"text-muted-foreground\" : \"text-foreground\",\n ].join(\" \")}\n >\n <div className=\"flex items-start justify-end gap-1 pt-0.5 font-mono text-[10px] text-muted-foreground\">\n {showIndex && <span data-frame-index>{index + 1}</span>}\n <Icon icon={frameIcon(frame)} className=\"mt-px shrink-0 text-[11px]\" />\n </div>\n\n <div className=\"min-w-0\">\n <div className=\"flex min-w-0 flex-wrap items-baseline gap-x-2 gap-y-0.5\">\n {isAnnotation ? (\n <>\n <span className=\"min-w-0 break-all font-mono font-semibold leading-4 opacity-70\">\n {frame.functionName}\n </span>\n {frame.annotationText && (\n <span className=\"min-w-0 break-all font-mono text-[11px] font-normal opacity-80\">\n {frame.annotationText}\n </span>\n )}\n </>\n ) : (\n <>\n {renderFramePart ? (\n renderFramePart(\"method\", frame, index)\n ) : (\n <span className=\"min-w-0 break-all font-mono font-semibold leading-4\">\n {methodName}\n </span>\n )}\n {frame.class && (\n renderFramePart ? (\n renderFramePart(\"class\", frame, index)\n ) : (\n <span className=\"min-w-0 break-all font-mono text-[11px] text-muted-foreground\">\n {frame.class}\n </span>\n )\n )}\n {frame.location && (\n renderFramePart ? (\n renderFramePart(\"location\", frame, index)\n ) : (\n <span className=\"rounded border border-border bg-muted/40 px-1.5 py-px font-mono text-[10px] text-muted-foreground\">\n {frame.location}\n </span>\n )\n )}\n </>\n )}\n </div>\n </div>\n\n {actions ? (\n <div\n className={[\n \"flex shrink-0 items-start gap-1\",\n frameActionsVisibility === \"hover\"\n ? \"opacity-0 transition-opacity focus-within:opacity-100 group-hover:opacity-100\"\n : \"opacity-100\",\n ].join(\" \")}\n >\n {actions}\n </div>\n ) : (\n <div />\n )}\n\n {!isAnnotation && frameHasSource(frame) ? (\n <div className=\"col-span-3\">\n <FrameSourceWindow frame={frame} />\n </div>\n ) : null}\n {detail ? <div className=\"col-start-2 col-span-2 min-w-0\">{detail}</div> : null}\n </div>\n );\n}\n\nfunction frameIcon(frame: ParsedThreadFrame) {\n switch (frame.kind) {\n case \"locked\":\n return UiLock;\n case \"waiting_to_lock\":\n return UiSync;\n case \"waiting_on\":\n case \"parking\":\n return UiWatch;\n default:\n break;\n }\n if (frame.nativeMethod) return UiChip;\n if (frame.runtime) return UiDebugStepOver;\n return frame.method || frame.class ? UiMethod : UiStackFrameDot;\n}\n"],"names":[],"mappings":";;;;;;;;;;;AAkDO,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA,yBAAyB;AAC3B,GAAuB;AACrB,QAAM,eAAe,MAAM,SAAS;AACpC,QAAM,aAAa,MAAM,eAAe,MAAM,UAAU,MAAM;AAC9D,QAAM,UAAU,6CAAe,OAAO;AACtC,QAAM,SAAS,CAAC,eAAe,uDAAoB,OAAO,SAAS;AAEnE,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA,YAAY,wCAAwC;AAAA,QACpD,MAAM,UAAU,0BAA0B;AAAA,MAAA,EAC1C,KAAK,GAAG;AAAA,MAEV,UAAA;AAAA,QAAA,qBAAC,OAAA,EAAI,WAAU,yFACZ,UAAA;AAAA,UAAA,aAAa,oBAAC,QAAA,EAAK,oBAAgB,MAAE,kBAAQ,GAAE;AAAA,8BAC/C,MAAA,EAAK,MAAM,UAAU,KAAK,GAAG,WAAU,6BAAA,CAA6B;AAAA,QAAA,GACvE;AAAA,QAEA,oBAAC,SAAI,WAAU,WACb,8BAAC,OAAA,EAAI,WAAU,2DACZ,UAAA,eACC,qBAAA,UAAA,EACE,UAAA;AAAA,UAAA,oBAAC,QAAA,EAAK,WAAU,kEACb,UAAA,MAAM,cACT;AAAA,UACC,MAAM,kBACL,oBAAC,UAAK,WAAU,kEACb,gBAAM,eAAA,CACT;AAAA,QAAA,EAAA,CAEJ,IAEA,qBAAA,UAAA,EACG,UAAA;AAAA,UAAA,kBACC,gBAAgB,UAAU,OAAO,KAAK,IAEtC,oBAAC,QAAA,EAAK,WAAU,uDACb,UAAA,WAAA,CACH;AAAA,UAED,MAAM,UACL,kBACE,gBAAgB,SAAS,OAAO,KAAK,IAErC,oBAAC,QAAA,EAAK,WAAU,iEACb,gBAAM,MAAA,CACT;AAAA,UAGH,MAAM,aACL,kBACE,gBAAgB,YAAY,OAAO,KAAK,IAExC,oBAAC,QAAA,EAAK,WAAU,qGACb,gBAAM,UACT;AAAA,QAAA,EAAA,CAGN,GAEJ,GACF;AAAA,QAEC,UACC;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAW;AAAA,cACT;AAAA,cACA,2BAA2B,UACvB,kFACA;AAAA,YAAA,EACJ,KAAK,GAAG;AAAA,YAET,UAAA;AAAA,UAAA;AAAA,QAAA,wBAGF,OAAA,EAAI;AAAA,QAGN,CAAC,gBAAgB,eAAe,KAAK,IACpC,oBAAC,OAAA,EAAI,WAAU,cACb,UAAA,oBAAC,mBAAA,EAAkB,MAAA,CAAc,GACnC,IACE;AAAA,QACH,SAAS,oBAAC,OAAA,EAAI,WAAU,kCAAkC,kBAAO,IAAS;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGjF;AAEA,SAAS,UAAU,OAA0B;AAC3C,UAAQ,MAAM,MAAA;AAAA,IACZ,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,EAEP;AAEJ,MAAI,MAAM,aAAc,QAAO;AAC/B,MAAI,MAAM,QAAS,QAAO;AAC1B,SAAO,MAAM,UAAU,MAAM,QAAQ,WAAW;AAClD;"}
@@ -6,6 +6,9 @@ const DEFAULT_NODE_HEIGHT = 60;
6
6
  const DEFAULT_COLUMN_GAP = 96;
7
7
  const DEFAULT_ROW_GAP = 20;
8
8
  const DEFAULT_GROUP_PADDING = 12;
9
+ const DEFAULT_COMPACT_NODE_HEIGHT = 24;
10
+ const DEFAULT_COMPACT_ROW_GAP = 4;
11
+ const DEFAULT_COMPACT_GROUP_PADDING = 8;
9
12
  const DEFAULT_PADDING = 24;
10
13
  const DEFAULT_SWEEPS = 4;
11
14
  function mustGet(map, key, what) {
@@ -22,6 +25,9 @@ function columnMetrics(options) {
22
25
  columnGap: options.columnGap ?? DEFAULT_COLUMN_GAP,
23
26
  rowGap: options.rowGap ?? DEFAULT_ROW_GAP,
24
27
  groupPadding: options.groupPadding ?? DEFAULT_GROUP_PADDING,
28
+ compactNodeHeight: options.compactNodeHeight ?? DEFAULT_COMPACT_NODE_HEIGHT,
29
+ compactRowGap: options.compactRowGap ?? DEFAULT_COMPACT_ROW_GAP,
30
+ compactGroupPadding: options.compactGroupPadding ?? DEFAULT_COMPACT_GROUP_PADDING,
25
31
  padding: options.padding ?? DEFAULT_PADDING,
26
32
  sweeps: options.sweeps ?? DEFAULT_SWEEPS
27
33
  };
@@ -57,10 +63,19 @@ function indexNeighbours(nodes, edges) {
57
63
  }
58
64
  return neighbours;
59
65
  }
66
+ function runMetrics(group, nodes, m) {
67
+ const compact = group !== void 0 && nodes.every((node) => node.compact === true);
68
+ const pad = group === void 0 ? 0 : compact ? m.compactGroupPadding : m.groupPadding;
69
+ const gap = compact ? m.compactRowGap : m.rowGap;
70
+ const heightOf = (node) => node.compact ? m.compactNodeHeight : m.nodeHeight;
71
+ const height = nodes.reduce((sum, node) => sum + heightOf(node), 0) + (nodes.length - 1) * gap + 2 * pad;
72
+ return { pad, gap, heightOf, height };
73
+ }
60
74
  function columnHeight(column, m) {
61
- const groups = new Set(column.map((node) => node.group));
62
- groups.delete(void 0);
63
- return column.length * m.nodeHeight + (column.length - 1) * m.rowGap + 2 * m.groupPadding * groups.size;
75
+ const runs = /* @__PURE__ */ new Map();
76
+ for (const node of column) runs.set(node.group, [...runs.get(node.group) ?? [], node]);
77
+ const stacked = [...runs].reduce((sum, [group, nodes]) => sum + runMetrics(group, nodes, m).height, 0);
78
+ return stacked + (runs.size - 1) * m.rowGap;
64
79
  }
65
80
  function orderColumn(column, groupRank, weight) {
66
81
  const runs = /* @__PURE__ */ new Map();
@@ -84,12 +99,12 @@ function stackColumn(runs, origin, m, placed) {
84
99
  const boxes = [];
85
100
  let cursor = origin.top;
86
101
  for (const { group, nodes } of runs) {
87
- const pad = group === void 0 ? 0 : m.groupPadding;
88
- const height = nodes.length * m.nodeHeight + (nodes.length - 1) * m.rowGap + 2 * pad;
89
- nodes.forEach((node, index) => {
90
- const top = cursor + pad + index * (m.nodeHeight + m.rowGap);
91
- placed.set(node.id, { x: origin.x, y: top + m.nodeHeight / 2 });
92
- });
102
+ const { pad, gap, heightOf, height } = runMetrics(group, nodes, m);
103
+ let top = cursor + pad;
104
+ for (const node of nodes) {
105
+ placed.set(node.id, { x: origin.x, y: top + heightOf(node) / 2 });
106
+ top += heightOf(node) + gap;
107
+ }
93
108
  if (group !== void 0) {
94
109
  boxes.push({
95
110
  id: `${origin.level}:${group}`,
@@ -203,7 +218,8 @@ function columnsLayout(nodes, edges, options = {}) {
203
218
  level
204
219
  })
205
220
  });
206
- const room = graphEdgeRouting.loopOverhang(edges, Object.fromEntries(placed), m);
221
+ const nodeHeights = Object.fromEntries(nodes.filter((node) => node.compact).map((node) => [node.id, m.compactNodeHeight]));
222
+ const room = graphEdgeRouting.loopOverhang(edges, Object.fromEntries(placed), { ...m, nodeHeights });
207
223
  const span = (Math.max(...levels) - minLevel) * (m.nodeWidth + m.columnGap) + m.nodeWidth;
208
224
  return {
209
225
  width: room.left + 2 * inset + span + room.right,
@@ -1 +1 @@
1
- {"version":3,"file":"graph-columns-layout.cjs","sources":["../../src/data/graph-columns-layout.ts"],"sourcesContent":["// Level-column layout for GraphDiagram: pure math, no React. Split from\n// graph-layout.ts, which owns the shared types and `ringLayout`.\n\nimport { loopOverhang } from \"./graph-edge-routing\";\nimport type { GraphLayoutEdge, GraphLayoutNode, GraphLayoutPosition, GraphLayoutResult } from \"./graph-layout\";\n\nexport interface ColumnsLayoutNode extends GraphLayoutNode {\n /** Column of the node. May be negative: the lowest level is the first column. */\n level: number;\n /** Nodes sharing a group stay contiguous within their column and are boxed together. */\n group?: string;\n}\n\nexport interface ColumnsLayoutOptions {\n /** Node bounding-box width in px. Defaults to 168. */\n nodeWidth?: number;\n /** Node bounding-box height in px. Defaults to 60. */\n nodeHeight?: number;\n /** Horizontal gap between the node boxes of adjacent columns in px. Defaults to 96. */\n columnGap?: number;\n /** Vertical gap between stacked nodes, and between group rectangles, in px. Defaults to 20. */\n rowGap?: number;\n /** Space between a group's nodes and its rectangle in px. Defaults to 12. */\n groupPadding?: number;\n /** Space reserved around the columns before the viewport edge. Defaults to 24. */\n padding?: number;\n /**\n * Re-ordering passes over all columns after the first placement, alternating direction; a pass\n * is kept only if it leaves fewer crossings. Defaults to 4. 0 keeps the first placement.\n */\n sweeps?: number;\n}\n\nexport interface GraphLayoutGroupBox {\n /** `${level}:${group}` — a group spanning several columns gets one rectangle per column. */\n id: string;\n group: string;\n level: number;\n /** Top-left corner, in the same coordinate space as the layout's `width`/`height`. */\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport interface ColumnsLayoutResult extends GraphLayoutResult {\n groups: GraphLayoutGroupBox[];\n}\n\ntype ColumnMetrics = Required<ColumnsLayoutOptions>;\n\ninterface GroupRun {\n group: string | undefined;\n nodes: ColumnsLayoutNode[];\n}\n\n/** One ordering of every column, stacked: the node centres and group rectangles it gives. */\ninterface Arrangement {\n order: Map<number, ColumnsLayoutNode[]>;\n placed: Map<string, GraphLayoutPosition>;\n boxes: Map<number, GraphLayoutGroupBox[]>;\n}\n\n/** What stays fixed while columns are re-ordered. */\ninterface ColumnsContext {\n m: ColumnMetrics;\n levels: number[];\n levelOf: Map<string, number>;\n groupRank: Map<string | undefined, number>;\n neighbours: Map<string, string[]>;\n edges: readonly GraphLayoutEdge[];\n /** Centre x and top y of a level's column. */\n origin: (level: number) => { x: number; top: number; level: number };\n}\n\nconst DEFAULT_NODE_WIDTH = 168;\nconst DEFAULT_NODE_HEIGHT = 60;\nconst DEFAULT_COLUMN_GAP = 96;\nconst DEFAULT_ROW_GAP = 20;\nconst DEFAULT_GROUP_PADDING = 12;\nconst DEFAULT_PADDING = 24;\nconst DEFAULT_SWEEPS = 4;\n\nfunction mustGet<K, V>(map: ReadonlyMap<K, V>, key: K, what: string): V {\n const value = map.get(key);\n if (value === undefined) {\n throw new Error(`columnsLayout: no ${what} for \"${String(key)}\"`);\n }\n return value;\n}\n\nfunction columnMetrics(options: ColumnsLayoutOptions): ColumnMetrics {\n return {\n nodeWidth: options.nodeWidth ?? DEFAULT_NODE_WIDTH,\n nodeHeight: options.nodeHeight ?? DEFAULT_NODE_HEIGHT,\n columnGap: options.columnGap ?? DEFAULT_COLUMN_GAP,\n rowGap: options.rowGap ?? DEFAULT_ROW_GAP,\n groupPadding: options.groupPadding ?? DEFAULT_GROUP_PADDING,\n padding: options.padding ?? DEFAULT_PADDING,\n sweeps: options.sweeps ?? DEFAULT_SWEEPS,\n };\n}\n\nfunction indexColumns(nodes: readonly ColumnsLayoutNode[]) {\n const columns = new Map<number, ColumnsLayoutNode[]>();\n const groupRank = new Map<string | undefined, number>();\n for (const node of nodes) {\n if (!Number.isFinite(node.level)) {\n throw new Error(`columnsLayout: node \"${node.id}\" has no finite level (got ${node.level})`);\n }\n if (!groupRank.has(node.group)) groupRank.set(node.group, groupRank.size);\n const column = columns.get(node.level);\n if (column) {\n column.push(node);\n } else {\n columns.set(node.level, [node]);\n }\n }\n return { columns, groupRank };\n}\n\nfunction indexNeighbours(\n nodes: readonly ColumnsLayoutNode[],\n edges: readonly GraphLayoutEdge[],\n): Map<string, string[]> {\n const neighbours = new Map<string, string[]>(nodes.map((node) => [node.id, []]));\n for (const edge of edges) {\n const from = neighbours.get(edge.from);\n const to = neighbours.get(edge.to);\n if (!from || !to) {\n const missing = from ? edge.to : edge.from;\n throw new Error(`columnsLayout: edge \"${edge.id}\" references unknown node \"${missing}\"`);\n }\n from.push(edge.to);\n to.push(edge.from);\n }\n return neighbours;\n}\n\nfunction columnHeight(column: readonly ColumnsLayoutNode[], m: ColumnMetrics): number {\n const groups = new Set(column.map((node) => node.group));\n groups.delete(undefined);\n return column.length * m.nodeHeight + (column.length - 1) * m.rowGap + 2 * m.groupPadding * groups.size;\n}\n\n/** Groups in order of first appearance; within a group by ascending weight, the column's order on ties. */\nfunction orderColumn(\n column: readonly ColumnsLayoutNode[],\n groupRank: ReadonlyMap<string | undefined, number>,\n weight: (node: ColumnsLayoutNode) => number,\n): GroupRun[] {\n const runs = new Map<number, { node: ColumnsLayoutNode; index: number; weight: number }[]>();\n column.forEach((node, index) => {\n const rank = mustGet(groupRank, node.group, \"group rank\");\n const entry = { node, index, weight: weight(node) };\n const run = runs.get(rank);\n if (run) {\n run.push(entry);\n } else {\n runs.set(rank, [entry]);\n }\n });\n return [...runs.entries()]\n .sort(([a], [b]) => a - b)\n .map(([, run]) => {\n // Infinity - Infinity is NaN, which falls through to the column-order tiebreak.\n const nodes = run.sort((a, b) => a.weight - b.weight || a.index - b.index).map((entry) => entry.node);\n return { group: nodes[0]?.group, nodes };\n });\n}\n\nfunction stackColumn(\n runs: readonly GroupRun[],\n origin: { x: number; top: number; level: number },\n m: ColumnMetrics,\n placed: Map<string, GraphLayoutPosition>,\n): GraphLayoutGroupBox[] {\n const boxes: GraphLayoutGroupBox[] = [];\n let cursor = origin.top;\n for (const { group, nodes } of runs) {\n const pad = group === undefined ? 0 : m.groupPadding;\n const height = nodes.length * m.nodeHeight + (nodes.length - 1) * m.rowGap + 2 * pad;\n nodes.forEach((node, index) => {\n const top = cursor + pad + index * (m.nodeHeight + m.rowGap);\n placed.set(node.id, { x: origin.x, y: top + m.nodeHeight / 2 });\n });\n if (group !== undefined) {\n boxes.push({\n id: `${origin.level}:${group}`,\n group,\n level: origin.level,\n x: origin.x - m.nodeWidth / 2 - pad,\n y: cursor,\n width: m.nodeWidth + 2 * pad,\n height,\n });\n }\n cursor += height + m.rowGap;\n }\n return boxes;\n}\n\nfunction meanY(ids: readonly string[], placed: ReadonlyMap<string, GraphLayoutPosition>): number {\n if (ids.length === 0) return Number.POSITIVE_INFINITY;\n return ids.reduce((sum, id) => sum + mustGet(placed, id, \"position\").y, 0) / ids.length;\n}\n\n/**\n * Levels in the order they are first laid out — the one nearest 0, then\n * outward on each side — each paired with the already-placed adjacent level\n * its nodes are ordered against.\n */\nfunction placementOrder(levels: readonly number[]): [level: number, reference: number | undefined][] {\n const anchor = levels.reduce((best, level) => (Math.abs(level) < Math.abs(best) ? level : best));\n const outward = (side: readonly number[]) =>\n side.map((level, index): [number, number] => [level, side[index - 1] ?? anchor]);\n return [\n [anchor, undefined],\n ...outward(levels.filter((level) => level > anchor)),\n ...outward(levels.filter((level) => level < anchor).reverse()),\n ];\n}\n\n/** Orders one column by the mean y of its nodes' neighbours in the `references` levels, and stacks it. */\nfunction placeColumn(level: number, references: readonly number[], ctx: ColumnsContext, into: Arrangement): void {\n const runs = orderColumn(mustGet(into.order, level, \"column\"), ctx.groupRank, (node) =>\n meanY(\n mustGet(ctx.neighbours, node.id, \"neighbours\").filter((id) =>\n references.includes(mustGet(ctx.levelOf, id, \"level\")),\n ),\n into.placed,\n ),\n );\n into.order.set(\n level,\n runs.flatMap((run) => run.nodes),\n );\n into.boxes.set(level, stackColumn(runs, ctx.origin(level), ctx.m, into.placed));\n}\n\n/** Pairs of edges between adjacent columns that cross, taking each edge as a straight line. */\nfunction countCrossings(ctx: ColumnsContext, placed: ReadonlyMap<string, GraphLayoutPosition>): number {\n const spans = new Map<number, [lower: number, upper: number][]>();\n for (const edge of ctx.edges) {\n const levels = [mustGet(ctx.levelOf, edge.from, \"level\"), mustGet(ctx.levelOf, edge.to, \"level\")] as const;\n const [lower, upper] = levels[0] < levels[1] ? [edge.from, edge.to] : [edge.to, edge.from];\n const index = ctx.levels.indexOf(Math.min(...levels));\n if (levels[0] === levels[1] || ctx.levels[index + 1] !== Math.max(...levels)) continue;\n const span: [number, number] = [mustGet(placed, lower, \"position\").y, mustGet(placed, upper, \"position\").y];\n spans.set(index, [...(spans.get(index) ?? []), span]);\n }\n let crossings = 0;\n for (const gap of spans.values()) {\n gap.forEach((a, index) => {\n crossings += gap.slice(index + 1).filter((b) => (a[0] - b[0]) * (a[1] - b[1]) < 0).length;\n });\n }\n return crossings;\n}\n\n/** A copy of `from` with every column re-ordered against both its neighbours, in the order given. */\nfunction sweep(from: Arrangement, sequence: readonly number[], ctx: ColumnsContext): Arrangement {\n const next: Arrangement = { order: new Map(from.order), placed: new Map(from.placed), boxes: new Map(from.boxes) };\n for (const level of sequence) {\n const index = ctx.levels.indexOf(level);\n const adjacent = [ctx.levels[index - 1], ctx.levels[index + 1]].filter((other): other is number => other !== undefined);\n placeColumn(level, adjacent, ctx, next);\n }\n return next;\n}\n\n/**\n * Orders the columns. The first pass places the level nearest 0 and works\n * outward, ordering each column against the one just placed. Then up to\n * `sweeps` passes re-order every column against both its neighbours, inward\n * then outward, and the arrangement with the fewest crossings is kept: the\n * first pass's unless a later one strictly beats it.\n */\nfunction arrange(columns: ReadonlyMap<number, ColumnsLayoutNode[]>, ctx: ColumnsContext): Arrangement {\n let current: Arrangement = { order: new Map(columns), placed: new Map(), boxes: new Map() };\n for (const [level, reference] of placementOrder(ctx.levels)) {\n placeColumn(level, reference === undefined ? [] : [reference], ctx, current);\n }\n let best = current;\n let fewest = countCrossings(ctx, best.placed);\n for (let pass = 0; pass < ctx.m.sweeps && fewest > 0; pass++) {\n current = sweep(current, pass % 2 === 0 ? [...ctx.levels].reverse() : ctx.levels, ctx);\n const crossings = countCrossings(ctx, current.placed);\n if (crossings < fewest) {\n best = current;\n fewest = crossings;\n }\n }\n return best;\n}\n\n/**\n * Places nodes in left-to-right columns by `level` (the lowest level first),\n * stacking each column top to bottom and centring it against the tallest one.\n *\n * Within a column, nodes of one group are contiguous, groups appearing in the\n * order they first occur in `nodes`. Inside a group nodes are ordered by the\n * mean y of their neighbours in the adjacent columns, so edges between columns\n * cross less (see `arrange`); nodes with no neighbour there go last, and ties\n * keep input order.\n *\n * Returns node centres plus one rectangle per (column, group). Extra width is\n * reserved on each side for the loops `routeEdges` draws outside the first and\n * last columns.\n */\nexport function columnsLayout(\n nodes: readonly ColumnsLayoutNode[],\n edges: readonly GraphLayoutEdge[],\n options: ColumnsLayoutOptions = {},\n): ColumnsLayoutResult {\n const m = columnMetrics(options);\n const { columns, groupRank } = indexColumns(nodes);\n const neighbours = indexNeighbours(nodes, edges);\n const levels = [...columns.keys()].sort((a, b) => a - b);\n if (levels.length === 0) {\n return { width: 2 * m.padding, height: 2 * m.padding, positions: {}, groups: [] };\n }\n\n const minLevel = Math.min(...levels);\n const tallest = Math.max(...[...columns.values()].map((column) => columnHeight(column, m)));\n const inset = m.padding + (nodes.some((node) => node.group !== undefined) ? m.groupPadding : 0);\n const { placed, boxes } = arrange(columns, {\n m,\n levels,\n levelOf: new Map(nodes.map((node) => [node.id, node.level])),\n groupRank,\n neighbours,\n edges,\n origin: (level) => ({\n x: inset + m.nodeWidth / 2 + (level - minLevel) * (m.nodeWidth + m.columnGap),\n top: m.padding + (tallest - columnHeight(mustGet(columns, level, \"column\"), m)) / 2,\n level,\n }),\n });\n\n const room = loopOverhang(edges, Object.fromEntries(placed), m);\n const span = (Math.max(...levels) - minLevel) * (m.nodeWidth + m.columnGap) + m.nodeWidth;\n return {\n width: room.left + 2 * inset + span + room.right,\n height: tallest + 2 * m.padding,\n positions: Object.fromEntries([...placed].map(([id, { x, y }]) => [id, { x: x + room.left, y }])),\n groups: [...boxes.values()]\n .flat()\n .map((box) => ({ ...box, x: box.x + room.left }))\n .sort((a, b) => a.level - b.level || a.y - b.y),\n };\n}\n"],"names":["loopOverhang"],"mappings":";;;AA2EA,MAAM,qBAAqB;AAC3B,MAAM,sBAAsB;AAC5B,MAAM,qBAAqB;AAC3B,MAAM,kBAAkB;AACxB,MAAM,wBAAwB;AAC9B,MAAM,kBAAkB;AACxB,MAAM,iBAAiB;AAEvB,SAAS,QAAc,KAAwB,KAAQ,MAAiB;AACtE,QAAM,QAAQ,IAAI,IAAI,GAAG;AACzB,MAAI,UAAU,QAAW;AACvB,UAAM,IAAI,MAAM,qBAAqB,IAAI,SAAS,OAAO,GAAG,CAAC,GAAG;AAAA,EAClE;AACA,SAAO;AACT;AAEA,SAAS,cAAc,SAA8C;AACnE,SAAO;AAAA,IACL,WAAW,QAAQ,aAAa;AAAA,IAChC,YAAY,QAAQ,cAAc;AAAA,IAClC,WAAW,QAAQ,aAAa;AAAA,IAChC,QAAQ,QAAQ,UAAU;AAAA,IAC1B,cAAc,QAAQ,gBAAgB;AAAA,IACtC,SAAS,QAAQ,WAAW;AAAA,IAC5B,QAAQ,QAAQ,UAAU;AAAA,EAAA;AAE9B;AAEA,SAAS,aAAa,OAAqC;AACzD,QAAM,8BAAc,IAAA;AACpB,QAAM,gCAAgB,IAAA;AACtB,aAAW,QAAQ,OAAO;AACxB,QAAI,CAAC,OAAO,SAAS,KAAK,KAAK,GAAG;AAChC,YAAM,IAAI,MAAM,wBAAwB,KAAK,EAAE,8BAA8B,KAAK,KAAK,GAAG;AAAA,IAC5F;AACA,QAAI,CAAC,UAAU,IAAI,KAAK,KAAK,EAAG,WAAU,IAAI,KAAK,OAAO,UAAU,IAAI;AACxE,UAAM,SAAS,QAAQ,IAAI,KAAK,KAAK;AACrC,QAAI,QAAQ;AACV,aAAO,KAAK,IAAI;AAAA,IAClB,OAAO;AACL,cAAQ,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC;AAAA,IAChC;AAAA,EACF;AACA,SAAO,EAAE,SAAS,UAAA;AACpB;AAEA,SAAS,gBACP,OACA,OACuB;AACvB,QAAM,aAAa,IAAI,IAAsB,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,IAAI,CAAA,CAAE,CAAC,CAAC;AAC/E,aAAW,QAAQ,OAAO;AACxB,UAAM,OAAO,WAAW,IAAI,KAAK,IAAI;AACrC,UAAM,KAAK,WAAW,IAAI,KAAK,EAAE;AACjC,QAAI,CAAC,QAAQ,CAAC,IAAI;AAChB,YAAM,UAAU,OAAO,KAAK,KAAK,KAAK;AACtC,YAAM,IAAI,MAAM,wBAAwB,KAAK,EAAE,8BAA8B,OAAO,GAAG;AAAA,IACzF;AACA,SAAK,KAAK,KAAK,EAAE;AACjB,OAAG,KAAK,KAAK,IAAI;AAAA,EACnB;AACA,SAAO;AACT;AAEA,SAAS,aAAa,QAAsC,GAA0B;AACpF,QAAM,SAAS,IAAI,IAAI,OAAO,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC;AACvD,SAAO,OAAO,MAAS;AACvB,SAAO,OAAO,SAAS,EAAE,cAAc,OAAO,SAAS,KAAK,EAAE,SAAS,IAAI,EAAE,eAAe,OAAO;AACrG;AAGA,SAAS,YACP,QACA,WACA,QACY;AACZ,QAAM,2BAAW,IAAA;AACjB,SAAO,QAAQ,CAAC,MAAM,UAAU;AAC9B,UAAM,OAAO,QAAQ,WAAW,KAAK,OAAO,YAAY;AACxD,UAAM,QAAQ,EAAE,MAAM,OAAO,QAAQ,OAAO,IAAI,EAAA;AAChD,UAAM,MAAM,KAAK,IAAI,IAAI;AACzB,QAAI,KAAK;AACP,UAAI,KAAK,KAAK;AAAA,IAChB,OAAO;AACL,WAAK,IAAI,MAAM,CAAC,KAAK,CAAC;AAAA,IACxB;AAAA,EACF,CAAC;AACD,SAAO,CAAC,GAAG,KAAK,QAAA,CAAS,EACtB,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,EACxB,IAAI,CAAC,CAAA,EAAG,GAAG,MAAM;;AAEhB,UAAM,QAAQ,IAAI,KAAK,CAAC,GAAG,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,UAAU,MAAM,IAAI;AACpG,WAAO,EAAE,QAAO,WAAM,CAAC,MAAP,mBAAU,OAAO,MAAA;AAAA,EACnC,CAAC;AACL;AAEA,SAAS,YACP,MACA,QACA,GACA,QACuB;AACvB,QAAM,QAA+B,CAAA;AACrC,MAAI,SAAS,OAAO;AACpB,aAAW,EAAE,OAAO,MAAA,KAAW,MAAM;AACnC,UAAM,MAAM,UAAU,SAAY,IAAI,EAAE;AACxC,UAAM,SAAS,MAAM,SAAS,EAAE,cAAc,MAAM,SAAS,KAAK,EAAE,SAAS,IAAI;AACjF,UAAM,QAAQ,CAAC,MAAM,UAAU;AAC7B,YAAM,MAAM,SAAS,MAAM,SAAS,EAAE,aAAa,EAAE;AACrD,aAAO,IAAI,KAAK,IAAI,EAAE,GAAG,OAAO,GAAG,GAAG,MAAM,EAAE,aAAa,EAAA,CAAG;AAAA,IAChE,CAAC;AACD,QAAI,UAAU,QAAW;AACvB,YAAM,KAAK;AAAA,QACT,IAAI,GAAG,OAAO,KAAK,IAAI,KAAK;AAAA,QAC5B;AAAA,QACA,OAAO,OAAO;AAAA,QACd,GAAG,OAAO,IAAI,EAAE,YAAY,IAAI;AAAA,QAChC,GAAG;AAAA,QACH,OAAO,EAAE,YAAY,IAAI;AAAA,QACzB;AAAA,MAAA,CACD;AAAA,IACH;AACA,cAAU,SAAS,EAAE;AAAA,EACvB;AACA,SAAO;AACT;AAEA,SAAS,MAAM,KAAwB,QAA0D;AAC/F,MAAI,IAAI,WAAW,EAAG,QAAO,OAAO;AACpC,SAAO,IAAI,OAAO,CAAC,KAAK,OAAO,MAAM,QAAQ,QAAQ,IAAI,UAAU,EAAE,GAAG,CAAC,IAAI,IAAI;AACnF;AAOA,SAAS,eAAe,QAA6E;AACnG,QAAM,SAAS,OAAO,OAAO,CAAC,MAAM,UAAW,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,IAAI,IAAI,QAAQ,IAAK;AAC/F,QAAM,UAAU,CAAC,SACf,KAAK,IAAI,CAAC,OAAO,UAA4B,CAAC,OAAO,KAAK,QAAQ,CAAC,KAAK,MAAM,CAAC;AACjF,SAAO;AAAA,IACL,CAAC,QAAQ,MAAS;AAAA,IAClB,GAAG,QAAQ,OAAO,OAAO,CAAC,UAAU,QAAQ,MAAM,CAAC;AAAA,IACnD,GAAG,QAAQ,OAAO,OAAO,CAAC,UAAU,QAAQ,MAAM,EAAE,QAAA,CAAS;AAAA,EAAA;AAEjE;AAGA,SAAS,YAAY,OAAe,YAA+B,KAAqB,MAAyB;AAC/G,QAAM,OAAO;AAAA,IAAY,QAAQ,KAAK,OAAO,OAAO,QAAQ;AAAA,IAAG,IAAI;AAAA,IAAW,CAAC,SAC7E;AAAA,MACE,QAAQ,IAAI,YAAY,KAAK,IAAI,YAAY,EAAE;AAAA,QAAO,CAAC,OACrD,WAAW,SAAS,QAAQ,IAAI,SAAS,IAAI,OAAO,CAAC;AAAA,MAAA;AAAA,MAEvD,KAAK;AAAA,IAAA;AAAA,EACP;AAEF,OAAK,MAAM;AAAA,IACT;AAAA,IACA,KAAK,QAAQ,CAAC,QAAQ,IAAI,KAAK;AAAA,EAAA;AAEjC,OAAK,MAAM,IAAI,OAAO,YAAY,MAAM,IAAI,OAAO,KAAK,GAAG,IAAI,GAAG,KAAK,MAAM,CAAC;AAChF;AAGA,SAAS,eAAe,KAAqB,QAA0D;AACrG,QAAM,4BAAY,IAAA;AAClB,aAAW,QAAQ,IAAI,OAAO;AAC5B,UAAM,SAAS,CAAC,QAAQ,IAAI,SAAS,KAAK,MAAM,OAAO,GAAG,QAAQ,IAAI,SAAS,KAAK,IAAI,OAAO,CAAC;AAChG,UAAM,CAAC,OAAO,KAAK,IAAI,OAAO,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,MAAM,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,KAAK,IAAI;AACzF,UAAM,QAAQ,IAAI,OAAO,QAAQ,KAAK,IAAI,GAAG,MAAM,CAAC;AACpD,QAAI,OAAO,CAAC,MAAM,OAAO,CAAC,KAAK,IAAI,OAAO,QAAQ,CAAC,MAAM,KAAK,IAAI,GAAG,MAAM,EAAG;AAC9E,UAAM,OAAyB,CAAC,QAAQ,QAAQ,OAAO,UAAU,EAAE,GAAG,QAAQ,QAAQ,OAAO,UAAU,EAAE,CAAC;AAC1G,UAAM,IAAI,OAAO,CAAC,GAAI,MAAM,IAAI,KAAK,KAAK,IAAK,IAAI,CAAC;AAAA,EACtD;AACA,MAAI,YAAY;AAChB,aAAW,OAAO,MAAM,UAAU;AAChC,QAAI,QAAQ,CAAC,GAAG,UAAU;AACxB,mBAAa,IAAI,MAAM,QAAQ,CAAC,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,EAAE;AAAA,IACrF,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAGA,SAAS,MAAM,MAAmB,UAA6B,KAAkC;AAC/F,QAAM,OAAoB,EAAE,OAAO,IAAI,IAAI,KAAK,KAAK,GAAG,QAAQ,IAAI,IAAI,KAAK,MAAM,GAAG,OAAO,IAAI,IAAI,KAAK,KAAK,EAAA;AAC/G,aAAW,SAAS,UAAU;AAC5B,UAAM,QAAQ,IAAI,OAAO,QAAQ,KAAK;AACtC,UAAM,WAAW,CAAC,IAAI,OAAO,QAAQ,CAAC,GAAG,IAAI,OAAO,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC,UAA2B,UAAU,MAAS;AACtH,gBAAY,OAAO,UAAU,KAAK,IAAI;AAAA,EACxC;AACA,SAAO;AACT;AASA,SAAS,QAAQ,SAAmD,KAAkC;AACpG,MAAI,UAAuB,EAAE,OAAO,IAAI,IAAI,OAAO,GAAG,QAAQ,oBAAI,IAAA,GAAO,OAAO,oBAAI,MAAI;AACxF,aAAW,CAAC,OAAO,SAAS,KAAK,eAAe,IAAI,MAAM,GAAG;AAC3D,gBAAY,OAAO,cAAc,SAAY,CAAA,IAAK,CAAC,SAAS,GAAG,KAAK,OAAO;AAAA,EAC7E;AACA,MAAI,OAAO;AACX,MAAI,SAAS,eAAe,KAAK,KAAK,MAAM;AAC5C,WAAS,OAAO,GAAG,OAAO,IAAI,EAAE,UAAU,SAAS,GAAG,QAAQ;AAC5D,cAAU,MAAM,SAAS,OAAO,MAAM,IAAI,CAAC,GAAG,IAAI,MAAM,EAAE,QAAA,IAAY,IAAI,QAAQ,GAAG;AACrF,UAAM,YAAY,eAAe,KAAK,QAAQ,MAAM;AACpD,QAAI,YAAY,QAAQ;AACtB,aAAO;AACP,eAAS;AAAA,IACX;AAAA,EACF;AACA,SAAO;AACT;AAgBO,SAAS,cACd,OACA,OACA,UAAgC,CAAA,GACX;AACrB,QAAM,IAAI,cAAc,OAAO;AAC/B,QAAM,EAAE,SAAS,cAAc,aAAa,KAAK;AACjD,QAAM,aAAa,gBAAgB,OAAO,KAAK;AAC/C,QAAM,SAAS,CAAC,GAAG,QAAQ,KAAA,CAAM,EAAE,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC;AACvD,MAAI,OAAO,WAAW,GAAG;AACvB,WAAO,EAAE,OAAO,IAAI,EAAE,SAAS,QAAQ,IAAI,EAAE,SAAS,WAAW,CAAA,GAAI,QAAQ,CAAA,EAAC;AAAA,EAChF;AAEA,QAAM,WAAW,KAAK,IAAI,GAAG,MAAM;AACnC,QAAM,UAAU,KAAK,IAAI,GAAG,CAAC,GAAG,QAAQ,OAAA,CAAQ,EAAE,IAAI,CAAC,WAAW,aAAa,QAAQ,CAAC,CAAC,CAAC;AAC1F,QAAM,QAAQ,EAAE,WAAW,MAAM,KAAK,CAAC,SAAS,KAAK,UAAU,MAAS,IAAI,EAAE,eAAe;AAC7F,QAAM,EAAE,QAAQ,UAAU,QAAQ,SAAS;AAAA,IACzC;AAAA,IACA;AAAA,IACA,SAAS,IAAI,IAAI,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,IAAI,KAAK,KAAK,CAAC,CAAC;AAAA,IAC3D;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ,CAAC,WAAW;AAAA,MAClB,GAAG,QAAQ,EAAE,YAAY,KAAK,QAAQ,aAAa,EAAE,YAAY,EAAE;AAAA,MACnE,KAAK,EAAE,WAAW,UAAU,aAAa,QAAQ,SAAS,OAAO,QAAQ,GAAG,CAAC,KAAK;AAAA,MAClF;AAAA,IAAA;AAAA,EACF,CACD;AAED,QAAM,OAAOA,iBAAAA,aAAa,OAAO,OAAO,YAAY,MAAM,GAAG,CAAC;AAC9D,QAAM,QAAQ,KAAK,IAAI,GAAG,MAAM,IAAI,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE;AAChF,SAAO;AAAA,IACL,OAAO,KAAK,OAAO,IAAI,QAAQ,OAAO,KAAK;AAAA,IAC3C,QAAQ,UAAU,IAAI,EAAE;AAAA,IACxB,WAAW,OAAO,YAAY,CAAC,GAAG,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,EAAE,GAAG,GAAG,MAAM,CAAC,IAAI,EAAE,GAAG,IAAI,KAAK,MAAM,EAAA,CAAG,CAAC,CAAC;AAAA,IAChG,QAAQ,CAAC,GAAG,MAAM,QAAQ,EACvB,KAAA,EACA,IAAI,CAAC,SAAS,EAAE,GAAG,KAAK,GAAG,IAAI,IAAI,KAAK,KAAA,EAAO,EAC/C,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;AAAA,EAAA;AAEpD;;"}
1
+ {"version":3,"file":"graph-columns-layout.cjs","sources":["../../src/data/graph-columns-layout.ts"],"sourcesContent":["// Level-column layout for GraphDiagram: pure math, no React. Split from\n// graph-layout.ts, which owns the shared types and `ringLayout`.\n\nimport { loopOverhang } from \"./graph-edge-routing\";\nimport type { GraphLayoutEdge, GraphLayoutNode, GraphLayoutPosition, GraphLayoutResult } from \"./graph-layout\";\n\nexport interface ColumnsLayoutNode extends GraphLayoutNode {\n /** Column of the node. May be negative: the lowest level is the first column. */\n level: number;\n /** Nodes sharing a group stay contiguous within their column and are boxed together. */\n group?: string;\n /** Drawn at `compactNodeHeight`; a group of only compact nodes stacks them at the compact gap and padding. */\n compact?: boolean;\n}\n\nexport interface ColumnsLayoutOptions {\n /** Node bounding-box width in px. Defaults to 168. */\n nodeWidth?: number;\n /** Node bounding-box height in px. Defaults to 60. */\n nodeHeight?: number;\n /** Horizontal gap between the node boxes of adjacent columns in px. Defaults to 96. */\n columnGap?: number;\n /** Vertical gap between stacked nodes, and between group rectangles, in px. Defaults to 20. */\n rowGap?: number;\n /** Space between a group's nodes and its rectangle in px. Defaults to 12. */\n groupPadding?: number;\n /** Height of a compact node in px. Defaults to 24. */\n compactNodeHeight?: number;\n /** Vertical gap between the nodes of a group of only compact nodes in px. Defaults to 4. */\n compactRowGap?: number;\n /** Space between a group of only compact nodes and its rectangle in px. Defaults to 8. */\n compactGroupPadding?: number;\n /** Space reserved around the columns before the viewport edge. Defaults to 24. */\n padding?: number;\n /**\n * Re-ordering passes over all columns after the first placement, alternating direction; a pass\n * is kept only if it leaves fewer crossings. Defaults to 4. 0 keeps the first placement.\n */\n sweeps?: number;\n}\n\nexport interface GraphLayoutGroupBox {\n /** `${level}:${group}` — a group spanning several columns gets one rectangle per column. */\n id: string;\n group: string;\n level: number;\n /** Top-left corner, in the same coordinate space as the layout's `width`/`height`. */\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport interface ColumnsLayoutResult extends GraphLayoutResult {\n groups: GraphLayoutGroupBox[];\n}\n\ntype ColumnMetrics = Required<ColumnsLayoutOptions>;\n\ninterface GroupRun {\n group: string | undefined;\n nodes: ColumnsLayoutNode[];\n}\n\n/** One ordering of every column, stacked: the node centres and group rectangles it gives. */\ninterface Arrangement {\n order: Map<number, ColumnsLayoutNode[]>;\n placed: Map<string, GraphLayoutPosition>;\n boxes: Map<number, GraphLayoutGroupBox[]>;\n}\n\n/** What stays fixed while columns are re-ordered. */\ninterface ColumnsContext {\n m: ColumnMetrics;\n levels: number[];\n levelOf: Map<string, number>;\n groupRank: Map<string | undefined, number>;\n neighbours: Map<string, string[]>;\n edges: readonly GraphLayoutEdge[];\n /** Centre x and top y of a level's column. */\n origin: (level: number) => { x: number; top: number; level: number };\n}\n\nconst DEFAULT_NODE_WIDTH = 168;\nconst DEFAULT_NODE_HEIGHT = 60;\nconst DEFAULT_COLUMN_GAP = 96;\nconst DEFAULT_ROW_GAP = 20;\nconst DEFAULT_GROUP_PADDING = 12;\nconst DEFAULT_COMPACT_NODE_HEIGHT = 24;\nconst DEFAULT_COMPACT_ROW_GAP = 4;\nconst DEFAULT_COMPACT_GROUP_PADDING = 8;\nconst DEFAULT_PADDING = 24;\nconst DEFAULT_SWEEPS = 4;\n\nfunction mustGet<K, V>(map: ReadonlyMap<K, V>, key: K, what: string): V {\n const value = map.get(key);\n if (value === undefined) {\n throw new Error(`columnsLayout: no ${what} for \"${String(key)}\"`);\n }\n return value;\n}\n\nfunction columnMetrics(options: ColumnsLayoutOptions): ColumnMetrics {\n return {\n nodeWidth: options.nodeWidth ?? DEFAULT_NODE_WIDTH,\n nodeHeight: options.nodeHeight ?? DEFAULT_NODE_HEIGHT,\n columnGap: options.columnGap ?? DEFAULT_COLUMN_GAP,\n rowGap: options.rowGap ?? DEFAULT_ROW_GAP,\n groupPadding: options.groupPadding ?? DEFAULT_GROUP_PADDING,\n compactNodeHeight: options.compactNodeHeight ?? DEFAULT_COMPACT_NODE_HEIGHT,\n compactRowGap: options.compactRowGap ?? DEFAULT_COMPACT_ROW_GAP,\n compactGroupPadding: options.compactGroupPadding ?? DEFAULT_COMPACT_GROUP_PADDING,\n padding: options.padding ?? DEFAULT_PADDING,\n sweeps: options.sweeps ?? DEFAULT_SWEEPS,\n };\n}\n\nfunction indexColumns(nodes: readonly ColumnsLayoutNode[]) {\n const columns = new Map<number, ColumnsLayoutNode[]>();\n const groupRank = new Map<string | undefined, number>();\n for (const node of nodes) {\n if (!Number.isFinite(node.level)) {\n throw new Error(`columnsLayout: node \"${node.id}\" has no finite level (got ${node.level})`);\n }\n if (!groupRank.has(node.group)) groupRank.set(node.group, groupRank.size);\n const column = columns.get(node.level);\n if (column) {\n column.push(node);\n } else {\n columns.set(node.level, [node]);\n }\n }\n return { columns, groupRank };\n}\n\nfunction indexNeighbours(\n nodes: readonly ColumnsLayoutNode[],\n edges: readonly GraphLayoutEdge[],\n): Map<string, string[]> {\n const neighbours = new Map<string, string[]>(nodes.map((node) => [node.id, []]));\n for (const edge of edges) {\n const from = neighbours.get(edge.from);\n const to = neighbours.get(edge.to);\n if (!from || !to) {\n const missing = from ? edge.to : edge.from;\n throw new Error(`columnsLayout: edge \"${edge.id}\" references unknown node \"${missing}\"`);\n }\n from.push(edge.to);\n to.push(edge.from);\n }\n return neighbours;\n}\n\n/**\n * How a run of nodes stacks: each node's height, the gap between them and the padding inside the run's\n * rectangle. A grouped run of only compact nodes takes the compact gap and padding; any other run the\n * regular ones, whatever its order, so a column's height does not depend on how it is ordered.\n */\nfunction runMetrics(group: string | undefined, nodes: readonly ColumnsLayoutNode[], m: ColumnMetrics) {\n const compact = group !== undefined && nodes.every((node) => node.compact === true);\n const pad = group === undefined ? 0 : compact ? m.compactGroupPadding : m.groupPadding;\n const gap = compact ? m.compactRowGap : m.rowGap;\n const heightOf = (node: ColumnsLayoutNode) => (node.compact ? m.compactNodeHeight : m.nodeHeight);\n const height = nodes.reduce((sum, node) => sum + heightOf(node), 0) + (nodes.length - 1) * gap + 2 * pad;\n return { pad, gap, heightOf, height };\n}\n\nfunction columnHeight(column: readonly ColumnsLayoutNode[], m: ColumnMetrics): number {\n const runs = new Map<string | undefined, ColumnsLayoutNode[]>();\n for (const node of column) runs.set(node.group, [...(runs.get(node.group) ?? []), node]);\n const stacked = [...runs].reduce((sum, [group, nodes]) => sum + runMetrics(group, nodes, m).height, 0);\n return stacked + (runs.size - 1) * m.rowGap;\n}\n\n/** Groups in order of first appearance; within a group by ascending weight, the column's order on ties. */\nfunction orderColumn(\n column: readonly ColumnsLayoutNode[],\n groupRank: ReadonlyMap<string | undefined, number>,\n weight: (node: ColumnsLayoutNode) => number,\n): GroupRun[] {\n const runs = new Map<number, { node: ColumnsLayoutNode; index: number; weight: number }[]>();\n column.forEach((node, index) => {\n const rank = mustGet(groupRank, node.group, \"group rank\");\n const entry = { node, index, weight: weight(node) };\n const run = runs.get(rank);\n if (run) {\n run.push(entry);\n } else {\n runs.set(rank, [entry]);\n }\n });\n return [...runs.entries()]\n .sort(([a], [b]) => a - b)\n .map(([, run]) => {\n // Infinity - Infinity is NaN, which falls through to the column-order tiebreak.\n const nodes = run.sort((a, b) => a.weight - b.weight || a.index - b.index).map((entry) => entry.node);\n return { group: nodes[0]?.group, nodes };\n });\n}\n\nfunction stackColumn(\n runs: readonly GroupRun[],\n origin: { x: number; top: number; level: number },\n m: ColumnMetrics,\n placed: Map<string, GraphLayoutPosition>,\n): GraphLayoutGroupBox[] {\n const boxes: GraphLayoutGroupBox[] = [];\n let cursor = origin.top;\n for (const { group, nodes } of runs) {\n const { pad, gap, heightOf, height } = runMetrics(group, nodes, m);\n let top = cursor + pad;\n for (const node of nodes) {\n placed.set(node.id, { x: origin.x, y: top + heightOf(node) / 2 });\n top += heightOf(node) + gap;\n }\n if (group !== undefined) {\n boxes.push({\n id: `${origin.level}:${group}`,\n group,\n level: origin.level,\n x: origin.x - m.nodeWidth / 2 - pad,\n y: cursor,\n width: m.nodeWidth + 2 * pad,\n height,\n });\n }\n cursor += height + m.rowGap;\n }\n return boxes;\n}\n\nfunction meanY(ids: readonly string[], placed: ReadonlyMap<string, GraphLayoutPosition>): number {\n if (ids.length === 0) return Number.POSITIVE_INFINITY;\n return ids.reduce((sum, id) => sum + mustGet(placed, id, \"position\").y, 0) / ids.length;\n}\n\n/**\n * Levels in the order they are first laid out — the one nearest 0, then\n * outward on each side — each paired with the already-placed adjacent level\n * its nodes are ordered against.\n */\nfunction placementOrder(levels: readonly number[]): [level: number, reference: number | undefined][] {\n const anchor = levels.reduce((best, level) => (Math.abs(level) < Math.abs(best) ? level : best));\n const outward = (side: readonly number[]) =>\n side.map((level, index): [number, number] => [level, side[index - 1] ?? anchor]);\n return [\n [anchor, undefined],\n ...outward(levels.filter((level) => level > anchor)),\n ...outward(levels.filter((level) => level < anchor).reverse()),\n ];\n}\n\n/** Orders one column by the mean y of its nodes' neighbours in the `references` levels, and stacks it. */\nfunction placeColumn(level: number, references: readonly number[], ctx: ColumnsContext, into: Arrangement): void {\n const runs = orderColumn(mustGet(into.order, level, \"column\"), ctx.groupRank, (node) =>\n meanY(\n mustGet(ctx.neighbours, node.id, \"neighbours\").filter((id) =>\n references.includes(mustGet(ctx.levelOf, id, \"level\")),\n ),\n into.placed,\n ),\n );\n into.order.set(\n level,\n runs.flatMap((run) => run.nodes),\n );\n into.boxes.set(level, stackColumn(runs, ctx.origin(level), ctx.m, into.placed));\n}\n\n/** Pairs of edges between adjacent columns that cross, taking each edge as a straight line. */\nfunction countCrossings(ctx: ColumnsContext, placed: ReadonlyMap<string, GraphLayoutPosition>): number {\n const spans = new Map<number, [lower: number, upper: number][]>();\n for (const edge of ctx.edges) {\n const levels = [mustGet(ctx.levelOf, edge.from, \"level\"), mustGet(ctx.levelOf, edge.to, \"level\")] as const;\n const [lower, upper] = levels[0] < levels[1] ? [edge.from, edge.to] : [edge.to, edge.from];\n const index = ctx.levels.indexOf(Math.min(...levels));\n if (levels[0] === levels[1] || ctx.levels[index + 1] !== Math.max(...levels)) continue;\n const span: [number, number] = [mustGet(placed, lower, \"position\").y, mustGet(placed, upper, \"position\").y];\n spans.set(index, [...(spans.get(index) ?? []), span]);\n }\n let crossings = 0;\n for (const gap of spans.values()) {\n gap.forEach((a, index) => {\n crossings += gap.slice(index + 1).filter((b) => (a[0] - b[0]) * (a[1] - b[1]) < 0).length;\n });\n }\n return crossings;\n}\n\n/** A copy of `from` with every column re-ordered against both its neighbours, in the order given. */\nfunction sweep(from: Arrangement, sequence: readonly number[], ctx: ColumnsContext): Arrangement {\n const next: Arrangement = { order: new Map(from.order), placed: new Map(from.placed), boxes: new Map(from.boxes) };\n for (const level of sequence) {\n const index = ctx.levels.indexOf(level);\n const adjacent = [ctx.levels[index - 1], ctx.levels[index + 1]].filter((other): other is number => other !== undefined);\n placeColumn(level, adjacent, ctx, next);\n }\n return next;\n}\n\n/**\n * Orders the columns. The first pass places the level nearest 0 and works\n * outward, ordering each column against the one just placed. Then up to\n * `sweeps` passes re-order every column against both its neighbours, inward\n * then outward, and the arrangement with the fewest crossings is kept: the\n * first pass's unless a later one strictly beats it.\n */\nfunction arrange(columns: ReadonlyMap<number, ColumnsLayoutNode[]>, ctx: ColumnsContext): Arrangement {\n let current: Arrangement = { order: new Map(columns), placed: new Map(), boxes: new Map() };\n for (const [level, reference] of placementOrder(ctx.levels)) {\n placeColumn(level, reference === undefined ? [] : [reference], ctx, current);\n }\n let best = current;\n let fewest = countCrossings(ctx, best.placed);\n for (let pass = 0; pass < ctx.m.sweeps && fewest > 0; pass++) {\n current = sweep(current, pass % 2 === 0 ? [...ctx.levels].reverse() : ctx.levels, ctx);\n const crossings = countCrossings(ctx, current.placed);\n if (crossings < fewest) {\n best = current;\n fewest = crossings;\n }\n }\n return best;\n}\n\n/**\n * Places nodes in left-to-right columns by `level` (the lowest level first),\n * stacking each column top to bottom and centring it against the tallest one.\n *\n * Within a column, nodes of one group are contiguous, groups appearing in the\n * order they first occur in `nodes`. Inside a group nodes are ordered by the\n * mean y of their neighbours in the adjacent columns, so edges between columns\n * cross less (see `arrange`); nodes with no neighbour there go last, and ties\n * keep input order.\n *\n * Returns node centres plus one rectangle per (column, group). Extra width is\n * reserved on each side for the loops `routeEdges` draws outside the first and\n * last columns.\n */\nexport function columnsLayout(\n nodes: readonly ColumnsLayoutNode[],\n edges: readonly GraphLayoutEdge[],\n options: ColumnsLayoutOptions = {},\n): ColumnsLayoutResult {\n const m = columnMetrics(options);\n const { columns, groupRank } = indexColumns(nodes);\n const neighbours = indexNeighbours(nodes, edges);\n const levels = [...columns.keys()].sort((a, b) => a - b);\n if (levels.length === 0) {\n return { width: 2 * m.padding, height: 2 * m.padding, positions: {}, groups: [] };\n }\n\n const minLevel = Math.min(...levels);\n const tallest = Math.max(...[...columns.values()].map((column) => columnHeight(column, m)));\n const inset = m.padding + (nodes.some((node) => node.group !== undefined) ? m.groupPadding : 0);\n const { placed, boxes } = arrange(columns, {\n m,\n levels,\n levelOf: new Map(nodes.map((node) => [node.id, node.level])),\n groupRank,\n neighbours,\n edges,\n origin: (level) => ({\n x: inset + m.nodeWidth / 2 + (level - minLevel) * (m.nodeWidth + m.columnGap),\n top: m.padding + (tallest - columnHeight(mustGet(columns, level, \"column\"), m)) / 2,\n level,\n }),\n });\n\n const nodeHeights = Object.fromEntries(nodes.filter((node) => node.compact).map((node) => [node.id, m.compactNodeHeight]));\n const room = loopOverhang(edges, Object.fromEntries(placed), { ...m, nodeHeights });\n const span = (Math.max(...levels) - minLevel) * (m.nodeWidth + m.columnGap) + m.nodeWidth;\n return {\n width: room.left + 2 * inset + span + room.right,\n height: tallest + 2 * m.padding,\n positions: Object.fromEntries([...placed].map(([id, { x, y }]) => [id, { x: x + room.left, y }])),\n groups: [...boxes.values()]\n .flat()\n .map((box) => ({ ...box, x: box.x + room.left }))\n .sort((a, b) => a.level - b.level || a.y - b.y),\n };\n}\n"],"names":["loopOverhang"],"mappings":"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"}
@@ -4,6 +4,8 @@ export interface ColumnsLayoutNode extends GraphLayoutNode {
4
4
  level: number;
5
5
  /** Nodes sharing a group stay contiguous within their column and are boxed together. */
6
6
  group?: string;
7
+ /** Drawn at `compactNodeHeight`; a group of only compact nodes stacks them at the compact gap and padding. */
8
+ compact?: boolean;
7
9
  }
8
10
  export interface ColumnsLayoutOptions {
9
11
  /** Node bounding-box width in px. Defaults to 168. */
@@ -16,6 +18,12 @@ export interface ColumnsLayoutOptions {
16
18
  rowGap?: number;
17
19
  /** Space between a group's nodes and its rectangle in px. Defaults to 12. */
18
20
  groupPadding?: number;
21
+ /** Height of a compact node in px. Defaults to 24. */
22
+ compactNodeHeight?: number;
23
+ /** Vertical gap between the nodes of a group of only compact nodes in px. Defaults to 4. */
24
+ compactRowGap?: number;
25
+ /** Space between a group of only compact nodes and its rectangle in px. Defaults to 8. */
26
+ compactGroupPadding?: number;
19
27
  /** Space reserved around the columns before the viewport edge. Defaults to 24. */
20
28
  padding?: number;
21
29
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"graph-columns-layout.d.ts","sourceRoot":"","sources":["../../src/data/graph-columns-layout.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAuB,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAE/G,MAAM,WAAW,iBAAkB,SAAQ,eAAe;IACxD,iFAAiF;IACjF,KAAK,EAAE,MAAM,CAAC;IACd,wFAAwF;IACxF,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,oBAAoB;IACnC,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sDAAsD;IACtD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uFAAuF;IACvF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+FAA+F;IAC/F,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6EAA6E;IAC7E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kFAAkF;IAClF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,4FAA4F;IAC5F,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,sFAAsF;IACtF,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,mBAAoB,SAAQ,iBAAiB;IAC5D,MAAM,EAAE,mBAAmB,EAAE,CAAC;CAC/B;AAyPD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,SAAS,iBAAiB,EAAE,EACnC,KAAK,EAAE,SAAS,eAAe,EAAE,EACjC,OAAO,GAAE,oBAAyB,GACjC,mBAAmB,CAqCrB"}
1
+ {"version":3,"file":"graph-columns-layout.d.ts","sourceRoot":"","sources":["../../src/data/graph-columns-layout.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAuB,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAE/G,MAAM,WAAW,iBAAkB,SAAQ,eAAe;IACxD,iFAAiF;IACjF,KAAK,EAAE,MAAM,CAAC;IACd,wFAAwF;IACxF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8GAA8G;IAC9G,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sDAAsD;IACtD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uFAAuF;IACvF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+FAA+F;IAC/F,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6EAA6E;IAC7E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sDAAsD;IACtD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,4FAA4F;IAC5F,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,0FAA0F;IAC1F,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,kFAAkF;IAClF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,4FAA4F;IAC5F,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,sFAAsF;IACtF,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,mBAAoB,SAAQ,iBAAiB;IAC5D,MAAM,EAAE,mBAAmB,EAAE,CAAC;CAC/B;AA8QD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,SAAS,iBAAiB,EAAE,EACnC,KAAK,EAAE,SAAS,eAAe,EAAE,EACjC,OAAO,GAAE,oBAAyB,GACjC,mBAAmB,CAsCrB"}
@@ -4,6 +4,9 @@ const DEFAULT_NODE_HEIGHT = 60;
4
4
  const DEFAULT_COLUMN_GAP = 96;
5
5
  const DEFAULT_ROW_GAP = 20;
6
6
  const DEFAULT_GROUP_PADDING = 12;
7
+ const DEFAULT_COMPACT_NODE_HEIGHT = 24;
8
+ const DEFAULT_COMPACT_ROW_GAP = 4;
9
+ const DEFAULT_COMPACT_GROUP_PADDING = 8;
7
10
  const DEFAULT_PADDING = 24;
8
11
  const DEFAULT_SWEEPS = 4;
9
12
  function mustGet(map, key, what) {
@@ -20,6 +23,9 @@ function columnMetrics(options) {
20
23
  columnGap: options.columnGap ?? DEFAULT_COLUMN_GAP,
21
24
  rowGap: options.rowGap ?? DEFAULT_ROW_GAP,
22
25
  groupPadding: options.groupPadding ?? DEFAULT_GROUP_PADDING,
26
+ compactNodeHeight: options.compactNodeHeight ?? DEFAULT_COMPACT_NODE_HEIGHT,
27
+ compactRowGap: options.compactRowGap ?? DEFAULT_COMPACT_ROW_GAP,
28
+ compactGroupPadding: options.compactGroupPadding ?? DEFAULT_COMPACT_GROUP_PADDING,
23
29
  padding: options.padding ?? DEFAULT_PADDING,
24
30
  sweeps: options.sweeps ?? DEFAULT_SWEEPS
25
31
  };
@@ -55,10 +61,19 @@ function indexNeighbours(nodes, edges) {
55
61
  }
56
62
  return neighbours;
57
63
  }
64
+ function runMetrics(group, nodes, m) {
65
+ const compact = group !== void 0 && nodes.every((node) => node.compact === true);
66
+ const pad = group === void 0 ? 0 : compact ? m.compactGroupPadding : m.groupPadding;
67
+ const gap = compact ? m.compactRowGap : m.rowGap;
68
+ const heightOf = (node) => node.compact ? m.compactNodeHeight : m.nodeHeight;
69
+ const height = nodes.reduce((sum, node) => sum + heightOf(node), 0) + (nodes.length - 1) * gap + 2 * pad;
70
+ return { pad, gap, heightOf, height };
71
+ }
58
72
  function columnHeight(column, m) {
59
- const groups = new Set(column.map((node) => node.group));
60
- groups.delete(void 0);
61
- return column.length * m.nodeHeight + (column.length - 1) * m.rowGap + 2 * m.groupPadding * groups.size;
73
+ const runs = /* @__PURE__ */ new Map();
74
+ for (const node of column) runs.set(node.group, [...runs.get(node.group) ?? [], node]);
75
+ const stacked = [...runs].reduce((sum, [group, nodes]) => sum + runMetrics(group, nodes, m).height, 0);
76
+ return stacked + (runs.size - 1) * m.rowGap;
62
77
  }
63
78
  function orderColumn(column, groupRank, weight) {
64
79
  const runs = /* @__PURE__ */ new Map();
@@ -82,12 +97,12 @@ function stackColumn(runs, origin, m, placed) {
82
97
  const boxes = [];
83
98
  let cursor = origin.top;
84
99
  for (const { group, nodes } of runs) {
85
- const pad = group === void 0 ? 0 : m.groupPadding;
86
- const height = nodes.length * m.nodeHeight + (nodes.length - 1) * m.rowGap + 2 * pad;
87
- nodes.forEach((node, index) => {
88
- const top = cursor + pad + index * (m.nodeHeight + m.rowGap);
89
- placed.set(node.id, { x: origin.x, y: top + m.nodeHeight / 2 });
90
- });
100
+ const { pad, gap, heightOf, height } = runMetrics(group, nodes, m);
101
+ let top = cursor + pad;
102
+ for (const node of nodes) {
103
+ placed.set(node.id, { x: origin.x, y: top + heightOf(node) / 2 });
104
+ top += heightOf(node) + gap;
105
+ }
91
106
  if (group !== void 0) {
92
107
  boxes.push({
93
108
  id: `${origin.level}:${group}`,
@@ -201,7 +216,8 @@ function columnsLayout(nodes, edges, options = {}) {
201
216
  level
202
217
  })
203
218
  });
204
- const room = loopOverhang(edges, Object.fromEntries(placed), m);
219
+ const nodeHeights = Object.fromEntries(nodes.filter((node) => node.compact).map((node) => [node.id, m.compactNodeHeight]));
220
+ const room = loopOverhang(edges, Object.fromEntries(placed), { ...m, nodeHeights });
205
221
  const span = (Math.max(...levels) - minLevel) * (m.nodeWidth + m.columnGap) + m.nodeWidth;
206
222
  return {
207
223
  width: room.left + 2 * inset + span + room.right,