@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":"CodeBlock.cjs","sources":["../../src/data/CodeBlock.tsx"],"sourcesContent":["import { useEffect, useMemo, useState, type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { useResolvedTheme, type ResolvedTheme } from \"../hooks/use-theme\";\nimport { CodeBlockActions } from \"./code-block-actions\";\nimport { CodeDiff } from \"./CodeDiff\";\nimport { JsonView } from \"./JsonView\";\nimport { highlightCode } from \"./code-highlight\";\nimport { sanitizeHtml } from \"./html-utils\";\n\nexport type CodeBlockProps = {\n /** Language label and highlighter hint, e.g. `json`, `tsx`, or `bash`. */\n language?: string | undefined;\n /** Raw source code to render or highlight. */\n source?: string | undefined;\n /** Trusted server-rendered highlighted HTML, sanitized before rendering. */\n highlightedHtml?: string | undefined;\n /** Classes applied to the code block shell. */\n className?: string | undefined;\n /** Default expansion depth when rendering JSON as a tree. */\n jsonDefaultOpenDepth?: number | undefined;\n /** Render only the code — no border, background, or language header. */\n bare?: boolean | undefined;\n /** Show a copy-to-clipboard button in the header (ignored when `bare`). */\n copyable?: boolean | undefined;\n /** Show a download button in the header (ignored when `bare`). */\n downloadable?: boolean | undefined;\n /** Name of the downloaded file. Defaults to `snippet.<extension of language>`. */\n downloadFilename?: string | undefined;\n /** Show a per-block light/dark theme toggle in the header (ignored when `bare`). */\n themeToggle?: boolean | undefined;\n /** Render a language-aware diff instead of highlighting `source`. */\n diff?: { original: string; modified: string } | { unified: string } | undefined;\n /** Diff layout when `diff` is set. Defaults to `unified`. */\n diffView?: \"unified\" | \"split\" | undefined;\n /**\n * Render as a single truncated line for a table cell: no border, header, or\n * wrap, whitespace collapsed to one line, syntax-colored when highlighting\n * is available, with the collapsed source (up to 2,000 chars) in a title\n * tooltip. Only the leading 500 chars are rendered and highlighted — the\n * cell clips long before that. The full block is what a row-detail dialog\n * should show instead.\n */\n inline?: boolean | undefined;\n};\n\n// A captured SQL statement can run to tens of thousands of characters on one\n// line; highlighting all of it for a one-line cell cost ~220 ms a statement.\nconst INLINE_RENDER_CHARS = 500;\nconst INLINE_TITLE_CHARS = 2000;\n\nexport function CodeBlock({\n language: languageProp,\n source = \"\",\n highlightedHtml,\n className,\n jsonDefaultOpenDepth = 2,\n bare = false,\n copyable = false,\n downloadable = false,\n downloadFilename,\n themeToggle = false,\n diff,\n diffView,\n inline = false,\n}: CodeBlockProps) {\n const language = (languageProp ?? \"\").toLowerCase().replace(/^\\.+/, \"\");\n const chromaHtml = highlightedHtml ? sanitizeHtml(highlightedHtml) : \"\";\n const parsedJson = useMemo(\n () => (language === \"json\" ? tryParseJson(source) : JSON_PARSE_FAILED),\n [language, source],\n );\n // The block follows the global app theme by default; a per-block override\n // (set by the header toggle) wins over it and re-highlights just this block.\n const globalTheme = useResolvedTheme();\n const [themeOverride, setThemeOverride] = useState<ResolvedTheme | null>(null);\n const effectiveTheme = themeOverride ?? globalTheme;\n const [shikiHtml, setShikiHtml] = useState<string | null>(null);\n const wantsClientHighlight =\n parsedJson === JSON_PARSE_FAILED && !chromaHtml && !!language && !!source;\n const singleLine = useMemo(\n () => (inline ? source.replace(/\\s+/g, \" \").trim() : \"\"),\n [inline, source],\n );\n const highlightSource = inline ? singleLine.slice(0, INLINE_RENDER_CHARS) : source;\n\n useEffect(() => {\n if (!wantsClientHighlight) {\n setShikiHtml(null);\n return;\n }\n\n let cancelled = false;\n const theme = effectiveTheme === \"dark\" ? \"github-dark\" : \"github-light\";\n highlightCode(highlightSource, { lang: language, theme }).then((out) => {\n if (!cancelled) setShikiHtml(out);\n });\n\n return () => {\n cancelled = true;\n };\n }, [wantsClientHighlight, language, highlightSource, effectiveTheme]);\n\n const headerActions = (\n <CodeBlockActions\n source={source}\n language={languageProp}\n copyable={copyable}\n downloadable={downloadable}\n downloadFilename={downloadFilename}\n theme={effectiveTheme}\n {...(themeToggle\n ? { onToggleTheme: () => setThemeOverride(effectiveTheme === \"dark\" ? \"light\" : \"dark\") }\n : {})}\n />\n );\n // Re-scope theme tokens (shell background/border/label) to the override so an\n // overridden block stays visually coherent with its re-highlighted code.\n const overrideAttrs = themeOverride ? { \"data-theme\": themeOverride } : {};\n\n if (inline) {\n const html = chromaHtml || shikiHtml;\n const title =\n singleLine.length > INLINE_TITLE_CHARS\n ? `${singleLine.slice(0, INLINE_TITLE_CHARS)}…`\n : singleLine;\n return (\n <code\n className={cn(\n \"block max-w-full truncate font-mono text-xs text-foreground\",\n className,\n html && \"[&_pre]:inline [&_pre]:whitespace-pre [&_.chroma]:bg-transparent\",\n )}\n title={title}\n >\n {html ? <span dangerouslySetInnerHTML={{ __html: html }} /> : highlightSource}\n </code>\n );\n }\n\n if (diff) {\n return (\n <CodeDiff\n language={languageProp}\n view={diffView}\n bare={bare}\n className={className}\n {...diff}\n />\n );\n }\n\n if (parsedJson !== JSON_PARSE_FAILED) {\n const tree = <JsonView data={parsedJson} defaultOpenDepth={jsonDefaultOpenDepth} />;\n if (bare) return <div className={cn(\"overflow-auto text-xs\", className)}>{tree}</div>;\n return (\n <div\n className={cn(\"overflow-hidden rounded-md border border-border bg-muted/40\", className)}\n {...overrideAttrs}\n >\n <CodeBlockHeader label=\"json\" actions={headerActions} />\n <div className=\"overflow-auto p-3 text-xs\">{tree}</div>\n </div>\n );\n }\n\n const xmlClasses =\n language === \"xml\" || language === \"xslt\" || language === \"html\"\n ? \" [&_.chroma_.nt]:text-pink-700 [&_.chroma_.nt]:dark:text-pink-300 [&_.chroma_.nt]:font-semibold\" +\n \" [&_.chroma_.na]:text-amber-700 [&_.chroma_.na]:dark:text-amber-300\" +\n \" [&_.chroma_.s]:text-emerald-700 [&_.chroma_.s]:dark:text-emerald-300\" +\n \" [&_.chroma_.c]:text-slate-500 [&_.chroma_.c]:italic\" +\n \" [&_.chroma_.cp]:text-slate-500 [&_.chroma_.cp]:italic\" +\n \" [&_pre]:leading-relaxed\"\n : \"\";\n\n const pad = bare ? undefined : \"p-3\";\n const body = chromaHtml ? (\n <div\n className={cn(\n \"overflow-auto text-xs font-mono [&_.chroma]:bg-transparent [&_pre]:m-0 [&_pre]:whitespace-pre-wrap [&_pre]:bg-transparent\" +\n xmlClasses,\n pad,\n bare && className,\n )}\n dangerouslySetInnerHTML={{ __html: chromaHtml }}\n />\n ) : shikiHtml ? (\n <div\n className={cn(\n \"overflow-auto text-xs font-mono [&_pre]:m-0 [&_pre.shiki]:!bg-transparent [&_pre]:whitespace-pre-wrap\",\n pad,\n bare && className,\n )}\n dangerouslySetInnerHTML={{ __html: shikiHtml }}\n />\n ) : (\n <pre\n className={cn(\n \"overflow-auto whitespace-pre-wrap break-words text-xs font-mono text-foreground\",\n pad,\n bare && className,\n )}\n >\n {source}\n </pre>\n );\n\n if (bare) return body;\n return (\n <div\n className={cn(\"overflow-hidden rounded-md border border-border bg-muted/40\", className)}\n {...overrideAttrs}\n >\n <CodeBlockHeader label={languageProp || \"text\"} actions={headerActions} />\n {body}\n </div>\n );\n}\n\nfunction CodeBlockHeader({ label, actions }: { label: string; actions: ReactNode }) {\n return (\n <div className=\"flex items-center justify-between gap-2 border-b border-border px-3 py-1.5\">\n <span className=\"text-[11px] uppercase tracking-wide text-muted-foreground\">{label}</span>\n {actions}\n </div>\n );\n}\n\nconst JSON_PARSE_FAILED: unique symbol = Symbol(\"json-parse-failed\");\n\nfunction tryParseJson(source: string): unknown | typeof JSON_PARSE_FAILED {\n const trimmed = source.trim();\n if (!trimmed) return JSON_PARSE_FAILED;\n try {\n return JSON.parse(trimmed);\n } catch {\n return JSON_PARSE_FAILED;\n }\n}\n"],"names":["sanitizeHtml","useMemo","useResolvedTheme","useState","useEffect","highlightCode","jsx","CodeBlockActions","cn","CodeDiff","JsonView","jsxs"],"mappings":"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"}
1
+ {"version":3,"file":"CodeBlock.cjs","sources":["../../src/data/CodeBlock.tsx"],"sourcesContent":["import { useEffect, useMemo, useState, type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { useResolvedTheme, type ResolvedTheme } from \"../hooks/use-theme\";\nimport { CodeBlockActions } from \"./code-block-actions\";\nimport { CodeDiff } from \"./CodeDiff\";\nimport { JsonView } from \"./JsonView\";\nimport { highlightCode } from \"./code-highlight\";\nimport { sanitizeHtml } from \"./html-utils\";\n\nexport type CodeBlockProps = {\n /** Language label and highlighter hint, e.g. `json`, `tsx`, or `bash`. */\n language?: string | undefined;\n /** Raw source code to render or highlight. */\n source?: string | undefined;\n /** Trusted server-rendered highlighted HTML, sanitized before rendering. */\n highlightedHtml?: string | undefined;\n /** Classes applied to the code block shell. */\n className?: string | undefined;\n /** Default expansion depth when rendering JSON as a tree. */\n jsonDefaultOpenDepth?: number | undefined;\n /** Display format for parsed JSON values. */\n jsonFormat?: \"json\" | \"yaml\" | undefined;\n /** Render only the code — no border, background, or language header. */\n bare?: boolean | undefined;\n /** Show a copy-to-clipboard button in the header (ignored when `bare`). */\n copyable?: boolean | undefined;\n /** Show a download button in the header (ignored when `bare`). */\n downloadable?: boolean | undefined;\n /** Name of the downloaded file. Defaults to `snippet.<extension of language>`. */\n downloadFilename?: string | undefined;\n /** Show a per-block light/dark theme toggle in the header (ignored when `bare`). */\n themeToggle?: boolean | undefined;\n /** Render a language-aware diff instead of highlighting `source`. */\n diff?: { original: string; modified: string } | { unified: string } | undefined;\n /** Diff layout when `diff` is set. Defaults to `unified`. */\n diffView?: \"unified\" | \"split\" | undefined;\n /**\n * Render as a single truncated line for a table cell: no border, header, or\n * wrap, whitespace collapsed to one line, syntax-colored when highlighting\n * is available, with the collapsed source (up to 2,000 chars) in a title\n * tooltip. Only the leading 500 chars are rendered and highlighted — the\n * cell clips long before that. The full block is what a row-detail dialog\n * should show instead.\n */\n inline?: boolean | undefined;\n};\n\n// A captured SQL statement can run to tens of thousands of characters on one\n// line; highlighting all of it for a one-line cell cost ~220 ms a statement.\nconst INLINE_RENDER_CHARS = 500;\nconst INLINE_TITLE_CHARS = 2000;\n\nexport function CodeBlock({\n language: languageProp,\n source = \"\",\n highlightedHtml,\n className,\n jsonDefaultOpenDepth = 2,\n jsonFormat = \"json\",\n bare = false,\n copyable = false,\n downloadable = false,\n downloadFilename,\n themeToggle = false,\n diff,\n diffView,\n inline = false,\n}: CodeBlockProps) {\n const language = (languageProp ?? \"\").toLowerCase().replace(/^\\.+/, \"\");\n const chromaHtml = highlightedHtml ? sanitizeHtml(highlightedHtml) : \"\";\n const parsedJson = useMemo(\n () => (language === \"json\" ? tryParseJson(source) : JSON_PARSE_FAILED),\n [language, source],\n );\n // The block follows the global app theme by default; a per-block override\n // (set by the header toggle) wins over it and re-highlights just this block.\n const globalTheme = useResolvedTheme();\n const [themeOverride, setThemeOverride] = useState<ResolvedTheme | null>(null);\n const effectiveTheme = themeOverride ?? globalTheme;\n const [shikiHtml, setShikiHtml] = useState<string | null>(null);\n const wantsClientHighlight =\n parsedJson === JSON_PARSE_FAILED && !chromaHtml && !!language && !!source;\n const singleLine = useMemo(\n () => (inline ? source.replace(/\\s+/g, \" \").trim() : \"\"),\n [inline, source],\n );\n const highlightSource = inline ? singleLine.slice(0, INLINE_RENDER_CHARS) : source;\n\n useEffect(() => {\n if (!wantsClientHighlight) {\n setShikiHtml(null);\n return;\n }\n\n let cancelled = false;\n const theme = effectiveTheme === \"dark\" ? \"github-dark\" : \"github-light\";\n highlightCode(highlightSource, { lang: language, theme }).then((out) => {\n if (!cancelled) setShikiHtml(out);\n });\n\n return () => {\n cancelled = true;\n };\n }, [wantsClientHighlight, language, highlightSource, effectiveTheme]);\n\n const headerActions = (\n <CodeBlockActions\n source={source}\n language={languageProp}\n copyable={copyable}\n downloadable={downloadable}\n downloadFilename={downloadFilename}\n theme={effectiveTheme}\n {...(themeToggle\n ? { onToggleTheme: () => setThemeOverride(effectiveTheme === \"dark\" ? \"light\" : \"dark\") }\n : {})}\n />\n );\n // Re-scope theme tokens (shell background/border/label) to the override so an\n // overridden block stays visually coherent with its re-highlighted code.\n const overrideAttrs = themeOverride ? { \"data-theme\": themeOverride } : {};\n\n if (inline) {\n const html = chromaHtml || shikiHtml;\n const title =\n singleLine.length > INLINE_TITLE_CHARS\n ? `${singleLine.slice(0, INLINE_TITLE_CHARS)}…`\n : singleLine;\n return (\n <code\n className={cn(\n \"block max-w-full truncate font-mono text-xs text-foreground\",\n className,\n html && \"[&_pre]:inline [&_pre]:whitespace-pre [&_.chroma]:bg-transparent\",\n )}\n title={title}\n >\n {html ? <span dangerouslySetInnerHTML={{ __html: html }} /> : highlightSource}\n </code>\n );\n }\n\n if (diff) {\n return (\n <CodeDiff\n language={languageProp}\n view={diffView}\n bare={bare}\n className={className}\n {...diff}\n />\n );\n }\n\n if (parsedJson !== JSON_PARSE_FAILED) {\n const tree = <JsonView data={parsedJson} format={jsonFormat} defaultOpenDepth={jsonDefaultOpenDepth} />;\n if (bare) return <div className={cn(\"overflow-auto text-xs\", className)}>{tree}</div>;\n return (\n <div\n className={cn(\"overflow-hidden rounded-md border border-border bg-muted/40\", className)}\n {...overrideAttrs}\n >\n <CodeBlockHeader label={jsonFormat} actions={headerActions} />\n <div className=\"overflow-auto p-3 text-xs\">{tree}</div>\n </div>\n );\n }\n\n const xmlClasses =\n language === \"xml\" || language === \"xslt\" || language === \"html\"\n ? \" [&_.chroma_.nt]:text-pink-700 [&_.chroma_.nt]:dark:text-pink-300 [&_.chroma_.nt]:font-semibold\" +\n \" [&_.chroma_.na]:text-amber-700 [&_.chroma_.na]:dark:text-amber-300\" +\n \" [&_.chroma_.s]:text-emerald-700 [&_.chroma_.s]:dark:text-emerald-300\" +\n \" [&_.chroma_.c]:text-slate-500 [&_.chroma_.c]:italic\" +\n \" [&_.chroma_.cp]:text-slate-500 [&_.chroma_.cp]:italic\" +\n \" [&_pre]:leading-relaxed\"\n : \"\";\n\n const pad = bare ? undefined : \"p-3\";\n const body = chromaHtml ? (\n <div\n className={cn(\n \"overflow-auto text-xs font-mono [&_.chroma]:bg-transparent [&_pre]:m-0 [&_pre]:whitespace-pre-wrap [&_pre]:bg-transparent\" +\n xmlClasses,\n pad,\n bare && className,\n )}\n dangerouslySetInnerHTML={{ __html: chromaHtml }}\n />\n ) : shikiHtml ? (\n <div\n className={cn(\n \"overflow-auto text-xs font-mono [&_pre]:m-0 [&_pre.shiki]:!bg-transparent [&_pre]:whitespace-pre-wrap\",\n pad,\n bare && className,\n )}\n dangerouslySetInnerHTML={{ __html: shikiHtml }}\n />\n ) : (\n <pre\n className={cn(\n \"overflow-auto whitespace-pre-wrap break-words text-xs font-mono text-foreground\",\n pad,\n bare && className,\n )}\n >\n {source}\n </pre>\n );\n\n if (bare) return body;\n return (\n <div\n className={cn(\"overflow-hidden rounded-md border border-border bg-muted/40\", className)}\n {...overrideAttrs}\n >\n <CodeBlockHeader label={languageProp || \"text\"} actions={headerActions} />\n {body}\n </div>\n );\n}\n\nfunction CodeBlockHeader({ label, actions }: { label: string; actions: ReactNode }) {\n return (\n <div className=\"flex items-center justify-between gap-2 border-b border-border px-3 py-1.5\">\n <span className=\"text-[11px] uppercase tracking-wide text-muted-foreground\">{label}</span>\n {actions}\n </div>\n );\n}\n\nconst JSON_PARSE_FAILED: unique symbol = Symbol(\"json-parse-failed\");\n\nfunction tryParseJson(source: string): unknown | typeof JSON_PARSE_FAILED {\n const trimmed = source.trim();\n if (!trimmed) return JSON_PARSE_FAILED;\n try {\n return JSON.parse(trimmed);\n } catch {\n return JSON_PARSE_FAILED;\n }\n}\n"],"names":["sanitizeHtml","useMemo","useResolvedTheme","useState","useEffect","highlightCode","jsx","CodeBlockActions","cn","CodeDiff","JsonView","jsxs"],"mappings":"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"}
@@ -9,6 +9,8 @@ export type CodeBlockProps = {
9
9
  className?: string | undefined;
10
10
  /** Default expansion depth when rendering JSON as a tree. */
11
11
  jsonDefaultOpenDepth?: number | undefined;
12
+ /** Display format for parsed JSON values. */
13
+ jsonFormat?: "json" | "yaml" | undefined;
12
14
  /** Render only the code — no border, background, or language header. */
13
15
  bare?: boolean | undefined;
14
16
  /** Show a copy-to-clipboard button in the header (ignored when `bare`). */
@@ -38,5 +40,5 @@ export type CodeBlockProps = {
38
40
  */
39
41
  inline?: boolean | undefined;
40
42
  };
41
- export declare function CodeBlock({ language: languageProp, source, highlightedHtml, className, jsonDefaultOpenDepth, bare, copyable, downloadable, downloadFilename, themeToggle, diff, diffView, inline, }: CodeBlockProps): import("react").JSX.Element;
43
+ export declare function CodeBlock({ language: languageProp, source, highlightedHtml, className, jsonDefaultOpenDepth, jsonFormat, bare, copyable, downloadable, downloadFilename, themeToggle, diff, diffView, inline, }: CodeBlockProps): import("react").JSX.Element;
42
44
  //# sourceMappingURL=CodeBlock.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"CodeBlock.d.ts","sourceRoot":"","sources":["../../src/data/CodeBlock.tsx"],"names":[],"mappings":"AASA,MAAM,MAAM,cAAc,GAAG;IAC3B,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,8CAA8C;IAC9C,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,4EAA4E;IAC5E,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,6DAA6D;IAC7D,oBAAoB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,wEAAwE;IACxE,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC3B,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC/B,kEAAkE;IAClE,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACnC,kFAAkF;IAClF,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,oFAAoF;IACpF,WAAW,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAClC,qEAAqE;IACrE,IAAI,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;IAChF,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;IAC3C;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC9B,CAAC;AAOF,wBAAgB,SAAS,CAAC,EACxB,QAAQ,EAAE,YAAY,EACtB,MAAW,EACX,eAAe,EACf,SAAS,EACT,oBAAwB,EACxB,IAAY,EACZ,QAAgB,EAChB,YAAoB,EACpB,gBAAgB,EAChB,WAAmB,EACnB,IAAI,EACJ,QAAQ,EACR,MAAc,GACf,EAAE,cAAc,+BAyJhB"}
1
+ {"version":3,"file":"CodeBlock.d.ts","sourceRoot":"","sources":["../../src/data/CodeBlock.tsx"],"names":[],"mappings":"AASA,MAAM,MAAM,cAAc,GAAG;IAC3B,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,8CAA8C;IAC9C,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,4EAA4E;IAC5E,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,6DAA6D;IAC7D,oBAAoB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACzC,wEAAwE;IACxE,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC3B,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC/B,kEAAkE;IAClE,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACnC,kFAAkF;IAClF,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,oFAAoF;IACpF,WAAW,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAClC,qEAAqE;IACrE,IAAI,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;IAChF,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;IAC3C;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC9B,CAAC;AAOF,wBAAgB,SAAS,CAAC,EACxB,QAAQ,EAAE,YAAY,EACtB,MAAW,EACX,eAAe,EACf,SAAS,EACT,oBAAwB,EACxB,UAAmB,EACnB,IAAY,EACZ,QAAgB,EAChB,YAAoB,EACpB,gBAAgB,EAChB,WAAmB,EACnB,IAAI,EACJ,QAAQ,EACR,MAAc,GACf,EAAE,cAAc,+BAyJhB"}
@@ -15,6 +15,7 @@ function CodeBlock({
15
15
  highlightedHtml,
16
16
  className,
17
17
  jsonDefaultOpenDepth = 2,
18
+ jsonFormat = "json",
18
19
  bare = false,
19
20
  copyable = false,
20
21
  downloadable = false,
@@ -96,7 +97,7 @@ function CodeBlock({
96
97
  );
97
98
  }
98
99
  if (parsedJson !== JSON_PARSE_FAILED) {
99
- const tree = /* @__PURE__ */ jsx(JsonView, { data: parsedJson, defaultOpenDepth: jsonDefaultOpenDepth });
100
+ const tree = /* @__PURE__ */ jsx(JsonView, { data: parsedJson, format: jsonFormat, defaultOpenDepth: jsonDefaultOpenDepth });
100
101
  if (bare) return /* @__PURE__ */ jsx("div", { className: cn("overflow-auto text-xs", className), children: tree });
101
102
  return /* @__PURE__ */ jsxs(
102
103
  "div",
@@ -104,7 +105,7 @@ function CodeBlock({
104
105
  className: cn("overflow-hidden rounded-md border border-border bg-muted/40", className),
105
106
  ...overrideAttrs,
106
107
  children: [
107
- /* @__PURE__ */ jsx(CodeBlockHeader, { label: "json", actions: headerActions }),
108
+ /* @__PURE__ */ jsx(CodeBlockHeader, { label: jsonFormat, actions: headerActions }),
108
109
  /* @__PURE__ */ jsx("div", { className: "overflow-auto p-3 text-xs", children: tree })
109
110
  ]
110
111
  }
@@ -1 +1 @@
1
- {"version":3,"file":"CodeBlock.js","sources":["../../src/data/CodeBlock.tsx"],"sourcesContent":["import { useEffect, useMemo, useState, type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { useResolvedTheme, type ResolvedTheme } from \"../hooks/use-theme\";\nimport { CodeBlockActions } from \"./code-block-actions\";\nimport { CodeDiff } from \"./CodeDiff\";\nimport { JsonView } from \"./JsonView\";\nimport { highlightCode } from \"./code-highlight\";\nimport { sanitizeHtml } from \"./html-utils\";\n\nexport type CodeBlockProps = {\n /** Language label and highlighter hint, e.g. `json`, `tsx`, or `bash`. */\n language?: string | undefined;\n /** Raw source code to render or highlight. */\n source?: string | undefined;\n /** Trusted server-rendered highlighted HTML, sanitized before rendering. */\n highlightedHtml?: string | undefined;\n /** Classes applied to the code block shell. */\n className?: string | undefined;\n /** Default expansion depth when rendering JSON as a tree. */\n jsonDefaultOpenDepth?: number | undefined;\n /** Render only the code — no border, background, or language header. */\n bare?: boolean | undefined;\n /** Show a copy-to-clipboard button in the header (ignored when `bare`). */\n copyable?: boolean | undefined;\n /** Show a download button in the header (ignored when `bare`). */\n downloadable?: boolean | undefined;\n /** Name of the downloaded file. Defaults to `snippet.<extension of language>`. */\n downloadFilename?: string | undefined;\n /** Show a per-block light/dark theme toggle in the header (ignored when `bare`). */\n themeToggle?: boolean | undefined;\n /** Render a language-aware diff instead of highlighting `source`. */\n diff?: { original: string; modified: string } | { unified: string } | undefined;\n /** Diff layout when `diff` is set. Defaults to `unified`. */\n diffView?: \"unified\" | \"split\" | undefined;\n /**\n * Render as a single truncated line for a table cell: no border, header, or\n * wrap, whitespace collapsed to one line, syntax-colored when highlighting\n * is available, with the collapsed source (up to 2,000 chars) in a title\n * tooltip. Only the leading 500 chars are rendered and highlighted — the\n * cell clips long before that. The full block is what a row-detail dialog\n * should show instead.\n */\n inline?: boolean | undefined;\n};\n\n// A captured SQL statement can run to tens of thousands of characters on one\n// line; highlighting all of it for a one-line cell cost ~220 ms a statement.\nconst INLINE_RENDER_CHARS = 500;\nconst INLINE_TITLE_CHARS = 2000;\n\nexport function CodeBlock({\n language: languageProp,\n source = \"\",\n highlightedHtml,\n className,\n jsonDefaultOpenDepth = 2,\n bare = false,\n copyable = false,\n downloadable = false,\n downloadFilename,\n themeToggle = false,\n diff,\n diffView,\n inline = false,\n}: CodeBlockProps) {\n const language = (languageProp ?? \"\").toLowerCase().replace(/^\\.+/, \"\");\n const chromaHtml = highlightedHtml ? sanitizeHtml(highlightedHtml) : \"\";\n const parsedJson = useMemo(\n () => (language === \"json\" ? tryParseJson(source) : JSON_PARSE_FAILED),\n [language, source],\n );\n // The block follows the global app theme by default; a per-block override\n // (set by the header toggle) wins over it and re-highlights just this block.\n const globalTheme = useResolvedTheme();\n const [themeOverride, setThemeOverride] = useState<ResolvedTheme | null>(null);\n const effectiveTheme = themeOverride ?? globalTheme;\n const [shikiHtml, setShikiHtml] = useState<string | null>(null);\n const wantsClientHighlight =\n parsedJson === JSON_PARSE_FAILED && !chromaHtml && !!language && !!source;\n const singleLine = useMemo(\n () => (inline ? source.replace(/\\s+/g, \" \").trim() : \"\"),\n [inline, source],\n );\n const highlightSource = inline ? singleLine.slice(0, INLINE_RENDER_CHARS) : source;\n\n useEffect(() => {\n if (!wantsClientHighlight) {\n setShikiHtml(null);\n return;\n }\n\n let cancelled = false;\n const theme = effectiveTheme === \"dark\" ? \"github-dark\" : \"github-light\";\n highlightCode(highlightSource, { lang: language, theme }).then((out) => {\n if (!cancelled) setShikiHtml(out);\n });\n\n return () => {\n cancelled = true;\n };\n }, [wantsClientHighlight, language, highlightSource, effectiveTheme]);\n\n const headerActions = (\n <CodeBlockActions\n source={source}\n language={languageProp}\n copyable={copyable}\n downloadable={downloadable}\n downloadFilename={downloadFilename}\n theme={effectiveTheme}\n {...(themeToggle\n ? { onToggleTheme: () => setThemeOverride(effectiveTheme === \"dark\" ? \"light\" : \"dark\") }\n : {})}\n />\n );\n // Re-scope theme tokens (shell background/border/label) to the override so an\n // overridden block stays visually coherent with its re-highlighted code.\n const overrideAttrs = themeOverride ? { \"data-theme\": themeOverride } : {};\n\n if (inline) {\n const html = chromaHtml || shikiHtml;\n const title =\n singleLine.length > INLINE_TITLE_CHARS\n ? `${singleLine.slice(0, INLINE_TITLE_CHARS)}…`\n : singleLine;\n return (\n <code\n className={cn(\n \"block max-w-full truncate font-mono text-xs text-foreground\",\n className,\n html && \"[&_pre]:inline [&_pre]:whitespace-pre [&_.chroma]:bg-transparent\",\n )}\n title={title}\n >\n {html ? <span dangerouslySetInnerHTML={{ __html: html }} /> : highlightSource}\n </code>\n );\n }\n\n if (diff) {\n return (\n <CodeDiff\n language={languageProp}\n view={diffView}\n bare={bare}\n className={className}\n {...diff}\n />\n );\n }\n\n if (parsedJson !== JSON_PARSE_FAILED) {\n const tree = <JsonView data={parsedJson} defaultOpenDepth={jsonDefaultOpenDepth} />;\n if (bare) return <div className={cn(\"overflow-auto text-xs\", className)}>{tree}</div>;\n return (\n <div\n className={cn(\"overflow-hidden rounded-md border border-border bg-muted/40\", className)}\n {...overrideAttrs}\n >\n <CodeBlockHeader label=\"json\" actions={headerActions} />\n <div className=\"overflow-auto p-3 text-xs\">{tree}</div>\n </div>\n );\n }\n\n const xmlClasses =\n language === \"xml\" || language === \"xslt\" || language === \"html\"\n ? \" [&_.chroma_.nt]:text-pink-700 [&_.chroma_.nt]:dark:text-pink-300 [&_.chroma_.nt]:font-semibold\" +\n \" [&_.chroma_.na]:text-amber-700 [&_.chroma_.na]:dark:text-amber-300\" +\n \" [&_.chroma_.s]:text-emerald-700 [&_.chroma_.s]:dark:text-emerald-300\" +\n \" [&_.chroma_.c]:text-slate-500 [&_.chroma_.c]:italic\" +\n \" [&_.chroma_.cp]:text-slate-500 [&_.chroma_.cp]:italic\" +\n \" [&_pre]:leading-relaxed\"\n : \"\";\n\n const pad = bare ? undefined : \"p-3\";\n const body = chromaHtml ? (\n <div\n className={cn(\n \"overflow-auto text-xs font-mono [&_.chroma]:bg-transparent [&_pre]:m-0 [&_pre]:whitespace-pre-wrap [&_pre]:bg-transparent\" +\n xmlClasses,\n pad,\n bare && className,\n )}\n dangerouslySetInnerHTML={{ __html: chromaHtml }}\n />\n ) : shikiHtml ? (\n <div\n className={cn(\n \"overflow-auto text-xs font-mono [&_pre]:m-0 [&_pre.shiki]:!bg-transparent [&_pre]:whitespace-pre-wrap\",\n pad,\n bare && className,\n )}\n dangerouslySetInnerHTML={{ __html: shikiHtml }}\n />\n ) : (\n <pre\n className={cn(\n \"overflow-auto whitespace-pre-wrap break-words text-xs font-mono text-foreground\",\n pad,\n bare && className,\n )}\n >\n {source}\n </pre>\n );\n\n if (bare) return body;\n return (\n <div\n className={cn(\"overflow-hidden rounded-md border border-border bg-muted/40\", className)}\n {...overrideAttrs}\n >\n <CodeBlockHeader label={languageProp || \"text\"} actions={headerActions} />\n {body}\n </div>\n );\n}\n\nfunction CodeBlockHeader({ label, actions }: { label: string; actions: ReactNode }) {\n return (\n <div className=\"flex items-center justify-between gap-2 border-b border-border px-3 py-1.5\">\n <span className=\"text-[11px] uppercase tracking-wide text-muted-foreground\">{label}</span>\n {actions}\n </div>\n );\n}\n\nconst JSON_PARSE_FAILED: unique symbol = Symbol(\"json-parse-failed\");\n\nfunction tryParseJson(source: string): unknown | typeof JSON_PARSE_FAILED {\n const trimmed = source.trim();\n if (!trimmed) return JSON_PARSE_FAILED;\n try {\n return JSON.parse(trimmed);\n } catch {\n return JSON_PARSE_FAILED;\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"CodeBlock.js","sources":["../../src/data/CodeBlock.tsx"],"sourcesContent":["import { useEffect, useMemo, useState, type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { useResolvedTheme, type ResolvedTheme } from \"../hooks/use-theme\";\nimport { CodeBlockActions } from \"./code-block-actions\";\nimport { CodeDiff } from \"./CodeDiff\";\nimport { JsonView } from \"./JsonView\";\nimport { highlightCode } from \"./code-highlight\";\nimport { sanitizeHtml } from \"./html-utils\";\n\nexport type CodeBlockProps = {\n /** Language label and highlighter hint, e.g. `json`, `tsx`, or `bash`. */\n language?: string | undefined;\n /** Raw source code to render or highlight. */\n source?: string | undefined;\n /** Trusted server-rendered highlighted HTML, sanitized before rendering. */\n highlightedHtml?: string | undefined;\n /** Classes applied to the code block shell. */\n className?: string | undefined;\n /** Default expansion depth when rendering JSON as a tree. */\n jsonDefaultOpenDepth?: number | undefined;\n /** Display format for parsed JSON values. */\n jsonFormat?: \"json\" | \"yaml\" | undefined;\n /** Render only the code — no border, background, or language header. */\n bare?: boolean | undefined;\n /** Show a copy-to-clipboard button in the header (ignored when `bare`). */\n copyable?: boolean | undefined;\n /** Show a download button in the header (ignored when `bare`). */\n downloadable?: boolean | undefined;\n /** Name of the downloaded file. Defaults to `snippet.<extension of language>`. */\n downloadFilename?: string | undefined;\n /** Show a per-block light/dark theme toggle in the header (ignored when `bare`). */\n themeToggle?: boolean | undefined;\n /** Render a language-aware diff instead of highlighting `source`. */\n diff?: { original: string; modified: string } | { unified: string } | undefined;\n /** Diff layout when `diff` is set. Defaults to `unified`. */\n diffView?: \"unified\" | \"split\" | undefined;\n /**\n * Render as a single truncated line for a table cell: no border, header, or\n * wrap, whitespace collapsed to one line, syntax-colored when highlighting\n * is available, with the collapsed source (up to 2,000 chars) in a title\n * tooltip. Only the leading 500 chars are rendered and highlighted — the\n * cell clips long before that. The full block is what a row-detail dialog\n * should show instead.\n */\n inline?: boolean | undefined;\n};\n\n// A captured SQL statement can run to tens of thousands of characters on one\n// line; highlighting all of it for a one-line cell cost ~220 ms a statement.\nconst INLINE_RENDER_CHARS = 500;\nconst INLINE_TITLE_CHARS = 2000;\n\nexport function CodeBlock({\n language: languageProp,\n source = \"\",\n highlightedHtml,\n className,\n jsonDefaultOpenDepth = 2,\n jsonFormat = \"json\",\n bare = false,\n copyable = false,\n downloadable = false,\n downloadFilename,\n themeToggle = false,\n diff,\n diffView,\n inline = false,\n}: CodeBlockProps) {\n const language = (languageProp ?? \"\").toLowerCase().replace(/^\\.+/, \"\");\n const chromaHtml = highlightedHtml ? sanitizeHtml(highlightedHtml) : \"\";\n const parsedJson = useMemo(\n () => (language === \"json\" ? tryParseJson(source) : JSON_PARSE_FAILED),\n [language, source],\n );\n // The block follows the global app theme by default; a per-block override\n // (set by the header toggle) wins over it and re-highlights just this block.\n const globalTheme = useResolvedTheme();\n const [themeOverride, setThemeOverride] = useState<ResolvedTheme | null>(null);\n const effectiveTheme = themeOverride ?? globalTheme;\n const [shikiHtml, setShikiHtml] = useState<string | null>(null);\n const wantsClientHighlight =\n parsedJson === JSON_PARSE_FAILED && !chromaHtml && !!language && !!source;\n const singleLine = useMemo(\n () => (inline ? source.replace(/\\s+/g, \" \").trim() : \"\"),\n [inline, source],\n );\n const highlightSource = inline ? singleLine.slice(0, INLINE_RENDER_CHARS) : source;\n\n useEffect(() => {\n if (!wantsClientHighlight) {\n setShikiHtml(null);\n return;\n }\n\n let cancelled = false;\n const theme = effectiveTheme === \"dark\" ? \"github-dark\" : \"github-light\";\n highlightCode(highlightSource, { lang: language, theme }).then((out) => {\n if (!cancelled) setShikiHtml(out);\n });\n\n return () => {\n cancelled = true;\n };\n }, [wantsClientHighlight, language, highlightSource, effectiveTheme]);\n\n const headerActions = (\n <CodeBlockActions\n source={source}\n language={languageProp}\n copyable={copyable}\n downloadable={downloadable}\n downloadFilename={downloadFilename}\n theme={effectiveTheme}\n {...(themeToggle\n ? { onToggleTheme: () => setThemeOverride(effectiveTheme === \"dark\" ? \"light\" : \"dark\") }\n : {})}\n />\n );\n // Re-scope theme tokens (shell background/border/label) to the override so an\n // overridden block stays visually coherent with its re-highlighted code.\n const overrideAttrs = themeOverride ? { \"data-theme\": themeOverride } : {};\n\n if (inline) {\n const html = chromaHtml || shikiHtml;\n const title =\n singleLine.length > INLINE_TITLE_CHARS\n ? `${singleLine.slice(0, INLINE_TITLE_CHARS)}…`\n : singleLine;\n return (\n <code\n className={cn(\n \"block max-w-full truncate font-mono text-xs text-foreground\",\n className,\n html && \"[&_pre]:inline [&_pre]:whitespace-pre [&_.chroma]:bg-transparent\",\n )}\n title={title}\n >\n {html ? <span dangerouslySetInnerHTML={{ __html: html }} /> : highlightSource}\n </code>\n );\n }\n\n if (diff) {\n return (\n <CodeDiff\n language={languageProp}\n view={diffView}\n bare={bare}\n className={className}\n {...diff}\n />\n );\n }\n\n if (parsedJson !== JSON_PARSE_FAILED) {\n const tree = <JsonView data={parsedJson} format={jsonFormat} defaultOpenDepth={jsonDefaultOpenDepth} />;\n if (bare) return <div className={cn(\"overflow-auto text-xs\", className)}>{tree}</div>;\n return (\n <div\n className={cn(\"overflow-hidden rounded-md border border-border bg-muted/40\", className)}\n {...overrideAttrs}\n >\n <CodeBlockHeader label={jsonFormat} actions={headerActions} />\n <div className=\"overflow-auto p-3 text-xs\">{tree}</div>\n </div>\n );\n }\n\n const xmlClasses =\n language === \"xml\" || language === \"xslt\" || language === \"html\"\n ? \" [&_.chroma_.nt]:text-pink-700 [&_.chroma_.nt]:dark:text-pink-300 [&_.chroma_.nt]:font-semibold\" +\n \" [&_.chroma_.na]:text-amber-700 [&_.chroma_.na]:dark:text-amber-300\" +\n \" [&_.chroma_.s]:text-emerald-700 [&_.chroma_.s]:dark:text-emerald-300\" +\n \" [&_.chroma_.c]:text-slate-500 [&_.chroma_.c]:italic\" +\n \" [&_.chroma_.cp]:text-slate-500 [&_.chroma_.cp]:italic\" +\n \" [&_pre]:leading-relaxed\"\n : \"\";\n\n const pad = bare ? undefined : \"p-3\";\n const body = chromaHtml ? (\n <div\n className={cn(\n \"overflow-auto text-xs font-mono [&_.chroma]:bg-transparent [&_pre]:m-0 [&_pre]:whitespace-pre-wrap [&_pre]:bg-transparent\" +\n xmlClasses,\n pad,\n bare && className,\n )}\n dangerouslySetInnerHTML={{ __html: chromaHtml }}\n />\n ) : shikiHtml ? (\n <div\n className={cn(\n \"overflow-auto text-xs font-mono [&_pre]:m-0 [&_pre.shiki]:!bg-transparent [&_pre]:whitespace-pre-wrap\",\n pad,\n bare && className,\n )}\n dangerouslySetInnerHTML={{ __html: shikiHtml }}\n />\n ) : (\n <pre\n className={cn(\n \"overflow-auto whitespace-pre-wrap break-words text-xs font-mono text-foreground\",\n pad,\n bare && className,\n )}\n >\n {source}\n </pre>\n );\n\n if (bare) return body;\n return (\n <div\n className={cn(\"overflow-hidden rounded-md border border-border bg-muted/40\", className)}\n {...overrideAttrs}\n >\n <CodeBlockHeader label={languageProp || \"text\"} actions={headerActions} />\n {body}\n </div>\n );\n}\n\nfunction CodeBlockHeader({ label, actions }: { label: string; actions: ReactNode }) {\n return (\n <div className=\"flex items-center justify-between gap-2 border-b border-border px-3 py-1.5\">\n <span className=\"text-[11px] uppercase tracking-wide text-muted-foreground\">{label}</span>\n {actions}\n </div>\n );\n}\n\nconst JSON_PARSE_FAILED: unique symbol = Symbol(\"json-parse-failed\");\n\nfunction tryParseJson(source: string): unknown | typeof JSON_PARSE_FAILED {\n const trimmed = source.trim();\n if (!trimmed) return JSON_PARSE_FAILED;\n try {\n return JSON.parse(trimmed);\n } catch {\n return JSON_PARSE_FAILED;\n }\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const jsxRuntime = require("react/jsx-runtime");
4
+ const react = require("react");
5
+ const codeHighlight = require("./code-highlight.cjs");
6
+ const HighlightedTokens = require("./HighlightedTokens.cjs");
7
+ function CodeLine({ code, language, className }) {
8
+ const [tokens, setTokens] = react.useState(void 0);
9
+ react.useEffect(() => {
10
+ let cancelled = false;
11
+ setTokens(void 0);
12
+ codeHighlight.highlightToLines(code, { lang: language }).then((out) => {
13
+ if (!cancelled) setTokens(out == null ? void 0 : out[0]);
14
+ });
15
+ return () => {
16
+ cancelled = true;
17
+ };
18
+ }, [code, language]);
19
+ return /* @__PURE__ */ jsxRuntime.jsx("code", { className: ["whitespace-pre font-mono", className].filter(Boolean).join(" "), children: /* @__PURE__ */ jsxRuntime.jsx(HighlightedTokens.HighlightedTokens, { tokens, content: code }) });
20
+ }
21
+ exports.CodeLine = CodeLine;
22
+ //# sourceMappingURL=CodeLine.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CodeLine.cjs","sources":["../../src/data/CodeLine.tsx"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport { highlightToLines, type HighlightedLine } from \"./code-highlight\";\nimport { HighlightedTokens } from \"./HighlightedTokens\";\n\nexport interface CodeLineProps {\n code: string;\n /** Shiki language id; without one the line renders as plain text. */\n language?: string;\n className?: string;\n}\n\n// CodeLine paints a single source line, syntax-highlighted, inline — the line a\n// stack frame or trace node ran, shown without the gutter and frame of a block.\nexport function CodeLine({ code, language, className }: CodeLineProps) {\n const [tokens, setTokens] = useState<HighlightedLine | undefined>(undefined);\n\n useEffect(() => {\n let cancelled = false;\n setTokens(undefined);\n highlightToLines(code, { lang: language }).then((out) => {\n if (!cancelled) setTokens(out?.[0]);\n });\n return () => {\n cancelled = true;\n };\n }, [code, language]);\n\n return (\n <code className={[\"whitespace-pre font-mono\", className].filter(Boolean).join(\" \")}>\n <HighlightedTokens tokens={tokens} content={code} />\n </code>\n );\n}\n"],"names":["useState","useEffect","highlightToLines","jsx","HighlightedTokens"],"mappings":";;;;;;AAaO,SAAS,SAAS,EAAE,MAAM,UAAU,aAA4B;AACrE,QAAM,CAAC,QAAQ,SAAS,IAAIA,MAAAA,SAAsC,MAAS;AAE3EC,QAAAA,UAAU,MAAM;AACd,QAAI,YAAY;AAChB,cAAU,MAAS;AACnBC,kBAAAA,iBAAiB,MAAM,EAAE,MAAM,SAAA,CAAU,EAAE,KAAK,CAAC,QAAQ;AACvD,UAAI,CAAC,UAAW,WAAU,2BAAM,EAAE;AAAA,IACpC,CAAC;AACD,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,MAAM,QAAQ,CAAC;AAEnB,wCACG,QAAA,EAAK,WAAW,CAAC,4BAA4B,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,GAC/E,UAAAC,2BAAAA,IAACC,kBAAAA,qBAAkB,QAAgB,SAAS,MAAM,GACpD;AAEJ;;"}
@@ -0,0 +1,8 @@
1
+ export interface CodeLineProps {
2
+ code: string;
3
+ /** Shiki language id; without one the line renders as plain text. */
4
+ language?: string;
5
+ className?: string;
6
+ }
7
+ export declare function CodeLine({ code, language, className }: CodeLineProps): import("react").JSX.Element;
8
+ //# sourceMappingURL=CodeLine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CodeLine.d.ts","sourceRoot":"","sources":["../../src/data/CodeLine.tsx"],"names":[],"mappings":"AAIA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAID,wBAAgB,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,aAAa,+BAmBpE"}
@@ -0,0 +1,22 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { useState, useEffect } from "react";
3
+ import { highlightToLines } from "./code-highlight.js";
4
+ import { HighlightedTokens } from "./HighlightedTokens.js";
5
+ function CodeLine({ code, language, className }) {
6
+ const [tokens, setTokens] = useState(void 0);
7
+ useEffect(() => {
8
+ let cancelled = false;
9
+ setTokens(void 0);
10
+ highlightToLines(code, { lang: language }).then((out) => {
11
+ if (!cancelled) setTokens(out == null ? void 0 : out[0]);
12
+ });
13
+ return () => {
14
+ cancelled = true;
15
+ };
16
+ }, [code, language]);
17
+ return /* @__PURE__ */ jsx("code", { className: ["whitespace-pre font-mono", className].filter(Boolean).join(" "), children: /* @__PURE__ */ jsx(HighlightedTokens, { tokens, content: code }) });
18
+ }
19
+ export {
20
+ CodeLine
21
+ };
22
+ //# sourceMappingURL=CodeLine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CodeLine.js","sources":["../../src/data/CodeLine.tsx"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport { highlightToLines, type HighlightedLine } from \"./code-highlight\";\nimport { HighlightedTokens } from \"./HighlightedTokens\";\n\nexport interface CodeLineProps {\n code: string;\n /** Shiki language id; without one the line renders as plain text. */\n language?: string;\n className?: string;\n}\n\n// CodeLine paints a single source line, syntax-highlighted, inline — the line a\n// stack frame or trace node ran, shown without the gutter and frame of a block.\nexport function CodeLine({ code, language, className }: CodeLineProps) {\n const [tokens, setTokens] = useState<HighlightedLine | undefined>(undefined);\n\n useEffect(() => {\n let cancelled = false;\n setTokens(undefined);\n highlightToLines(code, { lang: language }).then((out) => {\n if (!cancelled) setTokens(out?.[0]);\n });\n return () => {\n cancelled = true;\n };\n }, [code, language]);\n\n return (\n <code className={[\"whitespace-pre font-mono\", className].filter(Boolean).join(\" \")}>\n <HighlightedTokens tokens={tokens} content={code} />\n </code>\n );\n}\n"],"names":[],"mappings":";;;;AAaO,SAAS,SAAS,EAAE,MAAM,UAAU,aAA4B;AACrE,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAsC,MAAS;AAE3E,YAAU,MAAM;AACd,QAAI,YAAY;AAChB,cAAU,MAAS;AACnB,qBAAiB,MAAM,EAAE,MAAM,SAAA,CAAU,EAAE,KAAK,CAAC,QAAQ;AACvD,UAAI,CAAC,UAAW,WAAU,2BAAM,EAAE;AAAA,IACpC,CAAC;AACD,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,MAAM,QAAQ,CAAC;AAEnB,6BACG,QAAA,EAAK,WAAW,CAAC,4BAA4B,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,GAC/E,UAAA,oBAAC,qBAAkB,QAAgB,SAAS,MAAM,GACpD;AAEJ;"}
@@ -18,6 +18,11 @@ const UiFullscreen = require("../icons/components/UiFullscreen.cjs");
18
18
  const UiHome = require("../icons/components/UiHome.cjs");
19
19
  const DEFAULT_NODE_WIDTH = 168;
20
20
  const DEFAULT_NODE_HEIGHT = 60;
21
+ const DEFAULT_COMPACT_NODE_HEIGHT = 24;
22
+ function compactHeights(nodes, layout, compactNodeHeight) {
23
+ if (layout !== "columns") return {};
24
+ return Object.fromEntries(nodes.filter((node) => node.size === "compact").map((node) => [node.id, compactNodeHeight]));
25
+ }
21
26
  function assertEdgesReferenceKnownNodes(nodes, edges) {
22
27
  const ids = new Set(nodes.map((node) => node.id));
23
28
  for (const edge of edges) {
@@ -35,7 +40,7 @@ function requireLevel(node) {
35
40
  }
36
41
  return node.level;
37
42
  }
38
- function layoutNodes(nodes, edges, { layout, nodeWidth, nodeHeight, columnGap, rowGap }) {
43
+ function layoutNodes(nodes, edges, { layout, nodeWidth, nodeHeight, compactNodeHeight, columnGap, rowGap }) {
39
44
  switch (layout) {
40
45
  case "ring":
41
46
  return { ...graphLayout.ringLayout(nodes, { nodeWidth, nodeHeight }), groups: [] };
@@ -44,12 +49,14 @@ function layoutNodes(nodes, edges, { layout, nodeWidth, nodeHeight, columnGap, r
44
49
  nodes.map((node) => ({
45
50
  id: node.id,
46
51
  level: requireLevel(node),
47
- ...node.group !== void 0 ? { group: node.group } : {}
52
+ ...node.group !== void 0 ? { group: node.group } : {},
53
+ ...node.size === "compact" ? { compact: true } : {}
48
54
  })),
49
55
  edges,
50
56
  {
51
57
  nodeWidth,
52
58
  nodeHeight,
59
+ compactNodeHeight,
53
60
  ...columnGap !== void 0 ? { columnGap } : {},
54
61
  ...rowGap !== void 0 ? { rowGap } : {}
55
62
  }
@@ -94,9 +101,11 @@ function GraphDiagram({
94
101
  groups,
95
102
  nodeWidth = DEFAULT_NODE_WIDTH,
96
103
  nodeHeight = DEFAULT_NODE_HEIGHT,
104
+ compactNodeHeight = DEFAULT_COMPACT_NODE_HEIGHT,
97
105
  columnGap,
98
106
  rowGap,
99
107
  zoomable = false,
108
+ wheelZoom = "modifier",
100
109
  fitMinScale,
101
110
  focusId,
102
111
  maxHeight,
@@ -106,15 +115,17 @@ function GraphDiagram({
106
115
  assertEdgesReferenceKnownNodes(nodes, edges);
107
116
  const markerPrefix = `graph-diagram-${react.useId().replace(/[^a-zA-Z0-9_-]/g, "")}`;
108
117
  const { width, height, positions, groups: groupBoxes } = react.useMemo(
109
- () => layoutNodes(nodes, edges, { layout, nodeWidth, nodeHeight, columnGap, rowGap }),
110
- [layout, nodes, edges, nodeWidth, nodeHeight, columnGap, rowGap]
118
+ () => layoutNodes(nodes, edges, { layout, nodeWidth, nodeHeight, compactNodeHeight, columnGap, rowGap }),
119
+ [layout, nodes, edges, nodeWidth, nodeHeight, compactNodeHeight, columnGap, rowGap]
111
120
  );
121
+ const nodeHeights = react.useMemo(() => compactHeights(nodes, layout, compactNodeHeight), [nodes, layout, compactNodeHeight]);
112
122
  const routes = react.useMemo(
113
- () => graphEdgeRouting.routeEdges(edges, positions, { nodeWidth, nodeHeight }, { anchor: layout === "columns" ? "side" : "center" }),
114
- [edges, positions, nodeWidth, nodeHeight, layout]
123
+ () => graphEdgeRouting.routeEdges(edges, positions, { nodeWidth, nodeHeight, nodeHeights }, { anchor: layout === "columns" ? "side" : "center" }),
124
+ [edges, positions, nodeWidth, nodeHeight, nodeHeights, layout]
115
125
  );
116
126
  const panZoom = usePanZoom.usePanZoom({
117
127
  enabled: zoomable,
128
+ wheel: wheelZoom,
118
129
  contentWidth: width,
119
130
  contentHeight: height,
120
131
  opening: openingFit(positions, fitMinScale, focusId)
@@ -169,6 +180,7 @@ function GraphDiagram({
169
180
  place,
170
181
  nodeWidth,
171
182
  nodeHeight,
183
+ nodeHeights,
172
184
  selectedId,
173
185
  onNodeSelect,
174
186
  onNodeExpand,
@@ -1 +1 @@
1
- {"version":3,"file":"GraphDiagram.cjs","sources":["../../src/data/GraphDiagram.tsx"],"sourcesContent":["import { useId, useMemo, type CSSProperties } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { IconButton } from \"../components/IconButton\";\nimport { UiFullscreen, UiHome, UiZoomIn, UiZoomOut } from \"../icons\";\nimport { columnsLayout, type ColumnsLayoutResult } from \"./graph-columns-layout\";\nimport { ringLayout, routeEdges, type GraphLayoutPosition } from \"./graph-layout\";\nimport { GraphDiagramEdgeLabels, GraphDiagramEdgePaths } from \"./GraphDiagramEdges\";\nimport { GraphDiagramGroupBoxes, GraphDiagramNodes } from \"./GraphDiagramNodes\";\nimport {\n requireEntry,\n type GraphDiagramEdge,\n type GraphDiagramEdgeFocus,\n type GraphDiagramGroup,\n type GraphDiagramLayout,\n type GraphDiagramNode,\n type GraphPlacer,\n} from \"./graph-diagram-model\";\nimport { useEdgeFocus } from \"./use-edge-focus\";\nimport { usePanZoom, type FitOptions, type PanZoom } from \"./use-pan-zoom\";\n\nexport type {\n GraphDiagramEdge,\n GraphDiagramEdgeFocus,\n GraphDiagramGroup,\n GraphDiagramLayout,\n GraphDiagramNode,\n} from \"./graph-diagram-model\";\n\n// GraphDiagram renders a generic, type-agnostic node/edge diagram. It knows\n// nothing about the domain: a producer maps its data into\n// GraphDiagramNode/GraphDiagramEdge and gets layout, edge routing and\n// selection behaviour.\n//\n// \"ring\" suits a small cycle of resources and processes — relationships with\n// back edges or reciprocal pairs. \"columns\" suits a directed graph with a\n// natural depth (a call graph, a dependency chain): nodes sit in the column of\n// their `level`, grouped and boxed by `group`.\n//\n// The \"columns\" layout, and any zoomable diagram, is drawn at its natural\n// pixel size so node boxes, edges and group boxes share one coordinate system\n// at every container width and zoom level. A non-zoomable \"ring\" keeps scaling\n// its node positions to the container width.\n\nexport interface GraphDiagramProps {\n nodes: GraphDiagramNode[];\n edges: GraphDiagramEdge[];\n /** Defaults to \"ring\". \"columns\" needs a `level` on every node. */\n layout?: GraphDiagramLayout;\n selectedId?: string;\n onNodeSelect?: (id: string) => void;\n /** Called by a node's `+N` control (see `expandCount`); does not select the node. */\n onNodeExpand?: (id: string) => void;\n selectedEdgeId?: string;\n /** Makes edges, and their label pills, selectable. */\n onEdgeSelect?: (id: string) => void;\n /**\n * Whether an edge shows its pill only while in focus, and fades while another is. Defaults to\n * \"auto\": a diagram with more than 32 edges is focused, a smaller one shows everything.\n */\n edgeFocus?: GraphDiagramEdgeFocus;\n /** \"columns\" layout: captions for the group rectangles. A group without an entry shows its id. */\n groups?: GraphDiagramGroup[];\n nodeWidth?: number;\n nodeHeight?: number;\n /** \"columns\" layout: horizontal gap between columns in px. Leave room for edge label pills. */\n columnGap?: number;\n /** \"columns\" layout: vertical gap between stacked nodes in px. */\n rowGap?: number;\n /** Ctrl/meta + wheel (or pinch) zooms, dragging the background pans, and zoom controls appear. */\n zoomable?: boolean;\n /**\n * Zoomable: the smallest scale the diagram opens at, so its text stays readable. A diagram too\n * large for it opens overflowing, centred on `focusId`, and is panned to reach the rest. `Fit to\n * view` still shows everything, and `Reset view` returns here. Unset, the diagram opens whole.\n */\n fitMinScale?: number;\n /** Zoomable: the node an overflowing diagram opens centred on. Defaults to the diagram's centre. */\n focusId?: string;\n maxHeight?: number | string;\n ariaLabel: string;\n className?: string;\n}\n\nconst DEFAULT_NODE_WIDTH = 168;\nconst DEFAULT_NODE_HEIGHT = 60;\n\ninterface LayoutOptions {\n layout: GraphDiagramLayout;\n nodeWidth: number;\n nodeHeight: number;\n columnGap: number | undefined;\n rowGap: number | undefined;\n}\n\nfunction assertEdgesReferenceKnownNodes(nodes: GraphDiagramNode[], edges: GraphDiagramEdge[]): void {\n const ids = new Set(nodes.map((node) => node.id));\n for (const edge of edges) {\n if (!ids.has(edge.from)) {\n throw new Error(`GraphDiagram: edge \"${edge.id}\" references unknown node \"${edge.from}\"`);\n }\n if (!ids.has(edge.to)) {\n throw new Error(`GraphDiagram: edge \"${edge.id}\" references unknown node \"${edge.to}\"`);\n }\n }\n}\n\nfunction requireLevel(node: GraphDiagramNode): number {\n if (node.level === undefined || !Number.isFinite(node.level)) {\n throw new Error(`GraphDiagram: node \"${node.id}\" needs a finite level for the \"columns\" layout`);\n }\n return node.level;\n}\n\nfunction layoutNodes(\n nodes: GraphDiagramNode[],\n edges: GraphDiagramEdge[],\n { layout, nodeWidth, nodeHeight, columnGap, rowGap }: LayoutOptions,\n): ColumnsLayoutResult {\n switch (layout) {\n case \"ring\":\n return { ...ringLayout(nodes, { nodeWidth, nodeHeight }), groups: [] };\n case \"columns\":\n return columnsLayout(\n nodes.map((node) => ({\n id: node.id,\n level: requireLevel(node),\n ...(node.group !== undefined ? { group: node.group } : {}),\n })),\n edges,\n {\n nodeWidth,\n nodeHeight,\n ...(columnGap !== undefined ? { columnGap } : {}),\n ...(rowGap !== undefined ? { rowGap } : {}),\n },\n );\n default:\n throw new Error(`GraphDiagram: unknown layout \"${layout satisfies never}\"`);\n }\n}\n\nfunction toPercent(value: number, extent: number): string {\n return `${(value / extent) * 100}%`;\n}\n\nfunction stageStyle(size: { width: number; height: number }, natural: boolean, panZoom: PanZoom | undefined): CSSProperties {\n if (!natural) return { aspectRatio: `${size.width} / ${size.height}` };\n if (!panZoom) return size;\n const { x, y, scale } = panZoom.transform;\n return { ...size, transform: `translate(${x}px, ${y}px) scale(${scale})`, transformOrigin: \"0 0\" };\n}\n\n/** `resettable`: the diagram opens at another view than the whole of it, so there is one to return to. */\nfunction ZoomControls({ panZoom, resettable }: { panZoom: PanZoom; resettable: boolean }) {\n return (\n <div className=\"absolute right-2 top-2 flex cursor-default gap-0.5 rounded-md border border-border bg-background p-0.5 shadow-sm\">\n <IconButton icon={UiZoomOut} label=\"Zoom out\" className=\"size-6\" onClick={panZoom.zoomOut} />\n <IconButton icon={UiZoomIn} label=\"Zoom in\" className=\"size-6\" onClick={panZoom.zoomIn} />\n <IconButton icon={UiFullscreen} label=\"Fit to view\" className=\"size-6\" onClick={panZoom.fit} />\n {resettable && <IconButton icon={UiHome} label=\"Reset view\" className=\"size-6\" onClick={panZoom.reset} />}\n </div>\n );\n}\n\n/** How a zoomable diagram opens: no smaller than `fitMinScale`, centred on the `focusId` node. */\nfunction openingFit(\n positions: Record<string, GraphLayoutPosition>,\n fitMinScale: number | undefined,\n focusId: string | undefined,\n): FitOptions {\n return {\n ...(fitMinScale !== undefined ? { minScale: fitMinScale } : {}),\n ...(focusId !== undefined ? { focus: requireEntry(positions, focusId, \"layout position\") } : {}),\n };\n}\n\nexport function GraphDiagram({\n nodes,\n edges,\n layout = \"ring\",\n selectedId,\n onNodeSelect,\n onNodeExpand,\n selectedEdgeId,\n onEdgeSelect,\n edgeFocus = \"auto\",\n groups,\n nodeWidth = DEFAULT_NODE_WIDTH,\n nodeHeight = DEFAULT_NODE_HEIGHT,\n columnGap,\n rowGap,\n zoomable = false,\n fitMinScale,\n focusId,\n maxHeight,\n ariaLabel,\n className,\n}: GraphDiagramProps) {\n assertEdgesReferenceKnownNodes(nodes, edges);\n const markerPrefix = `graph-diagram-${useId().replace(/[^a-zA-Z0-9_-]/g, \"\")}`;\n\n const { width, height, positions, groups: groupBoxes } = useMemo(\n () => layoutNodes(nodes, edges, { layout, nodeWidth, nodeHeight, columnGap, rowGap }),\n [layout, nodes, edges, nodeWidth, nodeHeight, columnGap, rowGap],\n );\n const routes = useMemo(\n () =>\n routeEdges(edges, positions, { nodeWidth, nodeHeight }, { anchor: layout === \"columns\" ? \"side\" : \"center\" }),\n [edges, positions, nodeWidth, nodeHeight, layout],\n );\n\n const panZoom = usePanZoom({\n enabled: zoomable,\n contentWidth: width,\n contentHeight: height,\n opening: openingFit(positions, fitMinScale, focusId),\n });\n const natural = layout === \"columns\" || zoomable;\n const place: GraphPlacer = natural\n ? ({ x, y }) => ({ left: x, top: y })\n : ({ x, y }) => ({ left: toPercent(x, width), top: toPercent(y, height) });\n const focus = useEdgeFocus({ mode: edgeFocus, edges, selectedId, selectedEdgeId });\n const edgeSelection = { selectedEdgeId, onEdgeSelect, focus: focus.state };\n\n return (\n <div\n ref={panZoom.viewportRef}\n className={cn(\n \"w-full\",\n zoomable ? \"relative touch-none overflow-hidden\" : \"overflow-auto\",\n zoomable && (panZoom.panning ? \"cursor-grabbing select-none\" : \"cursor-grab\"),\n className,\n )}\n style={maxHeight != null ? { maxHeight } : undefined}\n {...panZoom.handlers}\n >\n <div\n ref={panZoom.contentRef}\n data-graph-stage=\"\"\n className={cn(\"relative\", natural ? !zoomable && \"mx-auto\" : \"w-full\")}\n style={stageStyle({ width, height }, natural, zoomable ? panZoom : undefined)}\n >\n <GraphDiagramGroupBoxes boxes={groupBoxes} groups={groups} />\n <GraphDiagramEdgePaths\n edges={edges}\n nodes={nodes}\n routes={routes}\n width={width}\n height={height}\n ariaLabel={ariaLabel}\n markerPrefix={markerPrefix}\n onEdgeHover={focus.onEdgeHover}\n {...edgeSelection}\n />\n <div className=\"pointer-events-none absolute inset-0\">\n <GraphDiagramEdgeLabels edges={edges} routes={routes} place={place} spread={natural} {...edgeSelection} />\n <GraphDiagramNodes\n nodes={nodes}\n positions={positions}\n place={place}\n nodeWidth={nodeWidth}\n nodeHeight={nodeHeight}\n selectedId={selectedId}\n onNodeSelect={onNodeSelect}\n onNodeExpand={onNodeExpand}\n onNodeHover={focus.onNodeHover}\n />\n </div>\n </div>\n {zoomable && <ZoomControls panZoom={panZoom} resettable={fitMinScale !== undefined} />}\n </div>\n );\n}\n"],"names":["ringLayout","columnsLayout","jsxs","jsx","IconButton","UiZoomOut","UiZoomIn","UiFullscreen","UiHome","requireEntry","useId","useMemo","routeEdges","usePanZoom","useEdgeFocus","cn","GraphDiagramGroupBoxes","GraphDiagramEdgePaths","GraphDiagramEdgeLabels","GraphDiagramNodes"],"mappings":"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"}
1
+ {"version":3,"file":"GraphDiagram.cjs","sources":["../../src/data/GraphDiagram.tsx"],"sourcesContent":["import { useId, useMemo, type CSSProperties } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { IconButton } from \"../components/IconButton\";\nimport { UiFullscreen, UiHome, UiZoomIn, UiZoomOut } from \"../icons\";\nimport { columnsLayout, type ColumnsLayoutResult } from \"./graph-columns-layout\";\nimport { ringLayout, routeEdges, type GraphLayoutPosition } from \"./graph-layout\";\nimport { GraphDiagramEdgeLabels, GraphDiagramEdgePaths } from \"./GraphDiagramEdges\";\nimport { GraphDiagramGroupBoxes, GraphDiagramNodes } from \"./GraphDiagramNodes\";\nimport {\n requireEntry,\n type GraphDiagramEdge,\n type GraphDiagramEdgeFocus,\n type GraphDiagramGroup,\n type GraphDiagramLayout,\n type GraphDiagramNode,\n type GraphPlacer,\n} from \"./graph-diagram-model\";\nimport { useEdgeFocus } from \"./use-edge-focus\";\nimport { usePanZoom, type FitOptions, type PanZoom, type WheelMode } from \"./use-pan-zoom\";\n\nexport type {\n GraphDiagramEdge,\n GraphDiagramEdgeFocus,\n GraphDiagramGroup,\n GraphDiagramLayout,\n GraphDiagramNode,\n} from \"./graph-diagram-model\";\n\n// GraphDiagram renders a generic, type-agnostic node/edge diagram. It knows\n// nothing about the domain: a producer maps its data into\n// GraphDiagramNode/GraphDiagramEdge and gets layout, edge routing and\n// selection behaviour.\n//\n// \"ring\" suits a small cycle of resources and processes — relationships with\n// back edges or reciprocal pairs. \"columns\" suits a directed graph with a\n// natural depth (a call graph, a dependency chain): nodes sit in the column of\n// their `level`, grouped and boxed by `group`.\n//\n// The \"columns\" layout, and any zoomable diagram, is drawn at its natural\n// pixel size so node boxes, edges and group boxes share one coordinate system\n// at every container width and zoom level. A non-zoomable \"ring\" keeps scaling\n// its node positions to the container width.\n\nexport interface GraphDiagramProps {\n nodes: GraphDiagramNode[];\n edges: GraphDiagramEdge[];\n /** Defaults to \"ring\". \"columns\" needs a `level` on every node. */\n layout?: GraphDiagramLayout;\n selectedId?: string;\n onNodeSelect?: (id: string) => void;\n /** Called by a node's `+N` control (see `expandCount`); does not select the node. */\n onNodeExpand?: (id: string) => void;\n selectedEdgeId?: string;\n /** Makes edges, and their label pills, selectable. */\n onEdgeSelect?: (id: string) => void;\n /**\n * Whether an edge shows its pill only while in focus, and fades while another is. Defaults to\n * \"auto\": a diagram with more than 32 edges is focused, a smaller one shows everything.\n */\n edgeFocus?: GraphDiagramEdgeFocus;\n /** \"columns\" layout: captions for the group rectangles. A group without an entry shows its id. */\n groups?: GraphDiagramGroup[];\n nodeWidth?: number;\n nodeHeight?: number;\n /**\n * \"columns\" layout: the height of a node with `size: \"compact\"`, drawn on one line. A group of only\n * compact nodes stacks them closer and pads them tighter. Defaults to 24.\n */\n compactNodeHeight?: number;\n /** \"columns\" layout: horizontal gap between columns in px. Leave room for edge label pills. */\n columnGap?: number;\n /** \"columns\" layout: vertical gap between stacked nodes in px. */\n rowGap?: number;\n /** Ctrl/meta + wheel (or pinch) zooms, dragging the background pans, and zoom controls appear. */\n zoomable?: boolean;\n /** Zoomable: \"zoom\" makes a plain mouse wheel zoom too, for a diagram that fills its pane. Defaults to \"modifier\". */\n wheelZoom?: WheelMode;\n /**\n * Zoomable: the smallest scale the diagram opens at, so its text stays readable. A diagram too\n * large for it opens overflowing, centred on `focusId`, and is panned to reach the rest. `Fit to\n * view` still shows everything, and `Reset view` returns here. Unset, the diagram opens whole.\n */\n fitMinScale?: number;\n /** Zoomable: the node an overflowing diagram opens centred on. Defaults to the diagram's centre. */\n focusId?: string;\n maxHeight?: number | string;\n ariaLabel: string;\n className?: string;\n}\n\nconst DEFAULT_NODE_WIDTH = 168;\nconst DEFAULT_NODE_HEIGHT = 60;\nconst DEFAULT_COMPACT_NODE_HEIGHT = 24;\n\ninterface LayoutOptions {\n layout: GraphDiagramLayout;\n nodeWidth: number;\n nodeHeight: number;\n compactNodeHeight: number;\n columnGap: number | undefined;\n rowGap: number | undefined;\n}\n\n/** The heights of the nodes not drawn at the node height: the compact ones, in the \"columns\" layout. */\nfunction compactHeights(nodes: GraphDiagramNode[], layout: GraphDiagramLayout, compactNodeHeight: number): Record<string, number> {\n if (layout !== \"columns\") return {};\n return Object.fromEntries(nodes.filter((node) => node.size === \"compact\").map((node) => [node.id, compactNodeHeight]));\n}\n\nfunction assertEdgesReferenceKnownNodes(nodes: GraphDiagramNode[], edges: GraphDiagramEdge[]): void {\n const ids = new Set(nodes.map((node) => node.id));\n for (const edge of edges) {\n if (!ids.has(edge.from)) {\n throw new Error(`GraphDiagram: edge \"${edge.id}\" references unknown node \"${edge.from}\"`);\n }\n if (!ids.has(edge.to)) {\n throw new Error(`GraphDiagram: edge \"${edge.id}\" references unknown node \"${edge.to}\"`);\n }\n }\n}\n\nfunction requireLevel(node: GraphDiagramNode): number {\n if (node.level === undefined || !Number.isFinite(node.level)) {\n throw new Error(`GraphDiagram: node \"${node.id}\" needs a finite level for the \"columns\" layout`);\n }\n return node.level;\n}\n\nfunction layoutNodes(\n nodes: GraphDiagramNode[],\n edges: GraphDiagramEdge[],\n { layout, nodeWidth, nodeHeight, compactNodeHeight, columnGap, rowGap }: LayoutOptions,\n): ColumnsLayoutResult {\n switch (layout) {\n case \"ring\":\n return { ...ringLayout(nodes, { nodeWidth, nodeHeight }), groups: [] };\n case \"columns\":\n return columnsLayout(\n nodes.map((node) => ({\n id: node.id,\n level: requireLevel(node),\n ...(node.group !== undefined ? { group: node.group } : {}),\n ...(node.size === \"compact\" ? { compact: true } : {}),\n })),\n edges,\n {\n nodeWidth,\n nodeHeight,\n compactNodeHeight,\n ...(columnGap !== undefined ? { columnGap } : {}),\n ...(rowGap !== undefined ? { rowGap } : {}),\n },\n );\n default:\n throw new Error(`GraphDiagram: unknown layout \"${layout satisfies never}\"`);\n }\n}\n\nfunction toPercent(value: number, extent: number): string {\n return `${(value / extent) * 100}%`;\n}\n\nfunction stageStyle(size: { width: number; height: number }, natural: boolean, panZoom: PanZoom | undefined): CSSProperties {\n if (!natural) return { aspectRatio: `${size.width} / ${size.height}` };\n if (!panZoom) return size;\n const { x, y, scale } = panZoom.transform;\n return { ...size, transform: `translate(${x}px, ${y}px) scale(${scale})`, transformOrigin: \"0 0\" };\n}\n\n/** `resettable`: the diagram opens at another view than the whole of it, so there is one to return to. */\nfunction ZoomControls({ panZoom, resettable }: { panZoom: PanZoom; resettable: boolean }) {\n return (\n <div className=\"absolute right-2 top-2 flex cursor-default gap-0.5 rounded-md border border-border bg-background p-0.5 shadow-sm\">\n <IconButton icon={UiZoomOut} label=\"Zoom out\" className=\"size-6\" onClick={panZoom.zoomOut} />\n <IconButton icon={UiZoomIn} label=\"Zoom in\" className=\"size-6\" onClick={panZoom.zoomIn} />\n <IconButton icon={UiFullscreen} label=\"Fit to view\" className=\"size-6\" onClick={panZoom.fit} />\n {resettable && <IconButton icon={UiHome} label=\"Reset view\" className=\"size-6\" onClick={panZoom.reset} />}\n </div>\n );\n}\n\n/** How a zoomable diagram opens: no smaller than `fitMinScale`, centred on the `focusId` node. */\nfunction openingFit(\n positions: Record<string, GraphLayoutPosition>,\n fitMinScale: number | undefined,\n focusId: string | undefined,\n): FitOptions {\n return {\n ...(fitMinScale !== undefined ? { minScale: fitMinScale } : {}),\n ...(focusId !== undefined ? { focus: requireEntry(positions, focusId, \"layout position\") } : {}),\n };\n}\n\nexport function GraphDiagram({\n nodes,\n edges,\n layout = \"ring\",\n selectedId,\n onNodeSelect,\n onNodeExpand,\n selectedEdgeId,\n onEdgeSelect,\n edgeFocus = \"auto\",\n groups,\n nodeWidth = DEFAULT_NODE_WIDTH,\n nodeHeight = DEFAULT_NODE_HEIGHT,\n compactNodeHeight = DEFAULT_COMPACT_NODE_HEIGHT,\n columnGap,\n rowGap,\n zoomable = false,\n wheelZoom = \"modifier\",\n fitMinScale,\n focusId,\n maxHeight,\n ariaLabel,\n className,\n}: GraphDiagramProps) {\n assertEdgesReferenceKnownNodes(nodes, edges);\n const markerPrefix = `graph-diagram-${useId().replace(/[^a-zA-Z0-9_-]/g, \"\")}`;\n\n const { width, height, positions, groups: groupBoxes } = useMemo(\n () => layoutNodes(nodes, edges, { layout, nodeWidth, nodeHeight, compactNodeHeight, columnGap, rowGap }),\n [layout, nodes, edges, nodeWidth, nodeHeight, compactNodeHeight, columnGap, rowGap],\n );\n const nodeHeights = useMemo(() => compactHeights(nodes, layout, compactNodeHeight), [nodes, layout, compactNodeHeight]);\n const routes = useMemo(\n () =>\n routeEdges(edges, positions, { nodeWidth, nodeHeight, nodeHeights }, { anchor: layout === \"columns\" ? \"side\" : \"center\" }),\n [edges, positions, nodeWidth, nodeHeight, nodeHeights, layout],\n );\n\n const panZoom = usePanZoom({\n enabled: zoomable,\n wheel: wheelZoom,\n contentWidth: width,\n contentHeight: height,\n opening: openingFit(positions, fitMinScale, focusId),\n });\n const natural = layout === \"columns\" || zoomable;\n const place: GraphPlacer = natural\n ? ({ x, y }) => ({ left: x, top: y })\n : ({ x, y }) => ({ left: toPercent(x, width), top: toPercent(y, height) });\n const focus = useEdgeFocus({ mode: edgeFocus, edges, selectedId, selectedEdgeId });\n const edgeSelection = { selectedEdgeId, onEdgeSelect, focus: focus.state };\n\n return (\n <div\n ref={panZoom.viewportRef}\n className={cn(\n \"w-full\",\n zoomable ? \"relative touch-none overflow-hidden\" : \"overflow-auto\",\n zoomable && (panZoom.panning ? \"cursor-grabbing select-none\" : \"cursor-grab\"),\n className,\n )}\n style={maxHeight != null ? { maxHeight } : undefined}\n {...panZoom.handlers}\n >\n <div\n ref={panZoom.contentRef}\n data-graph-stage=\"\"\n className={cn(\"relative\", natural ? !zoomable && \"mx-auto\" : \"w-full\")}\n style={stageStyle({ width, height }, natural, zoomable ? panZoom : undefined)}\n >\n <GraphDiagramGroupBoxes boxes={groupBoxes} groups={groups} />\n <GraphDiagramEdgePaths\n edges={edges}\n nodes={nodes}\n routes={routes}\n width={width}\n height={height}\n ariaLabel={ariaLabel}\n markerPrefix={markerPrefix}\n onEdgeHover={focus.onEdgeHover}\n {...edgeSelection}\n />\n <div className=\"pointer-events-none absolute inset-0\">\n <GraphDiagramEdgeLabels edges={edges} routes={routes} place={place} spread={natural} {...edgeSelection} />\n <GraphDiagramNodes\n nodes={nodes}\n positions={positions}\n place={place}\n nodeWidth={nodeWidth}\n nodeHeight={nodeHeight}\n nodeHeights={nodeHeights}\n selectedId={selectedId}\n onNodeSelect={onNodeSelect}\n onNodeExpand={onNodeExpand}\n onNodeHover={focus.onNodeHover}\n />\n </div>\n </div>\n {zoomable && <ZoomControls panZoom={panZoom} resettable={fitMinScale !== undefined} />}\n </div>\n );\n}\n"],"names":["ringLayout","columnsLayout","jsxs","jsx","IconButton","UiZoomOut","UiZoomIn","UiFullscreen","UiHome","requireEntry","useId","useMemo","routeEdges","usePanZoom","useEdgeFocus","cn","GraphDiagramGroupBoxes","GraphDiagramEdgePaths","GraphDiagramEdgeLabels","GraphDiagramNodes"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { GraphDiagramEdge, GraphDiagramEdgeFocus, GraphDiagramGroup, GraphDiagramLayout, GraphDiagramNode } from './graph-diagram-model.js';
2
+ import { WheelMode } from './use-pan-zoom.js';
2
3
  export type { GraphDiagramEdge, GraphDiagramEdgeFocus, GraphDiagramGroup, GraphDiagramLayout, GraphDiagramNode, } from './graph-diagram-model.js';
3
4
  export interface GraphDiagramProps {
4
5
  nodes: GraphDiagramNode[];
@@ -21,12 +22,19 @@ export interface GraphDiagramProps {
21
22
  groups?: GraphDiagramGroup[];
22
23
  nodeWidth?: number;
23
24
  nodeHeight?: number;
25
+ /**
26
+ * "columns" layout: the height of a node with `size: "compact"`, drawn on one line. A group of only
27
+ * compact nodes stacks them closer and pads them tighter. Defaults to 24.
28
+ */
29
+ compactNodeHeight?: number;
24
30
  /** "columns" layout: horizontal gap between columns in px. Leave room for edge label pills. */
25
31
  columnGap?: number;
26
32
  /** "columns" layout: vertical gap between stacked nodes in px. */
27
33
  rowGap?: number;
28
34
  /** Ctrl/meta + wheel (or pinch) zooms, dragging the background pans, and zoom controls appear. */
29
35
  zoomable?: boolean;
36
+ /** Zoomable: "zoom" makes a plain mouse wheel zoom too, for a diagram that fills its pane. Defaults to "modifier". */
37
+ wheelZoom?: WheelMode;
30
38
  /**
31
39
  * Zoomable: the smallest scale the diagram opens at, so its text stays readable. A diagram too
32
40
  * large for it opens overflowing, centred on `focusId`, and is panned to reach the rest. `Fit to
@@ -39,5 +47,5 @@ export interface GraphDiagramProps {
39
47
  ariaLabel: string;
40
48
  className?: string;
41
49
  }
42
- export declare function GraphDiagram({ nodes, edges, layout, selectedId, onNodeSelect, onNodeExpand, selectedEdgeId, onEdgeSelect, edgeFocus, groups, nodeWidth, nodeHeight, columnGap, rowGap, zoomable, fitMinScale, focusId, maxHeight, ariaLabel, className, }: GraphDiagramProps): import("react").JSX.Element;
50
+ export declare function GraphDiagram({ nodes, edges, layout, selectedId, onNodeSelect, onNodeExpand, selectedEdgeId, onEdgeSelect, edgeFocus, groups, nodeWidth, nodeHeight, compactNodeHeight, columnGap, rowGap, zoomable, wheelZoom, fitMinScale, focusId, maxHeight, ariaLabel, className, }: GraphDiagramProps): import("react").JSX.Element;
43
51
  //# sourceMappingURL=GraphDiagram.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"GraphDiagram.d.ts","sourceRoot":"","sources":["../../src/data/GraphDiagram.tsx"],"names":[],"mappings":"AAQA,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EAEtB,MAAM,uBAAuB,CAAC;AAI/B,YAAY,EACV,gBAAgB,EAChB,qBAAqB,EACrB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,uBAAuB,CAAC;AAiB/B,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,mEAAmE;IACnE,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,qFAAqF;IACrF,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,sDAAsD;IACtD,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC;;;OAGG;IACH,SAAS,CAAC,EAAE,qBAAqB,CAAC;IAClC,kGAAkG;IAClG,MAAM,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+FAA+F;IAC/F,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kEAAkE;IAClE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kGAAkG;IAClG,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oGAAoG;IACpG,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA+FD,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,KAAK,EACL,MAAe,EACf,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,SAAkB,EAClB,MAAM,EACN,SAA8B,EAC9B,UAAgC,EAChC,SAAS,EACT,MAAM,EACN,QAAgB,EAChB,WAAW,EACX,OAAO,EACP,SAAS,EACT,SAAS,EACT,SAAS,GACV,EAAE,iBAAiB,+BA2EnB"}
1
+ {"version":3,"file":"GraphDiagram.d.ts","sourceRoot":"","sources":["../../src/data/GraphDiagram.tsx"],"names":[],"mappings":"AAQA,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EAEtB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAA6C,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3F,YAAY,EACV,gBAAgB,EAChB,qBAAqB,EACrB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,uBAAuB,CAAC;AAiB/B,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,mEAAmE;IACnE,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,qFAAqF;IACrF,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,sDAAsD;IACtD,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC;;;OAGG;IACH,SAAS,CAAC,EAAE,qBAAqB,CAAC;IAClC,kGAAkG;IAClG,MAAM,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,+FAA+F;IAC/F,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kEAAkE;IAClE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kGAAkG;IAClG,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sHAAsH;IACtH,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oGAAoG;IACpG,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAyGD,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,KAAK,EACL,MAAe,EACf,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,SAAkB,EAClB,MAAM,EACN,SAA8B,EAC9B,UAAgC,EAChC,iBAA+C,EAC/C,SAAS,EACT,MAAM,EACN,QAAgB,EAChB,SAAsB,EACtB,WAAW,EACX,OAAO,EACP,SAAS,EACT,SAAS,EACT,SAAS,GACV,EAAE,iBAAiB,+BA8EnB"}
@@ -16,6 +16,11 @@ import { UiFullscreen } from "../icons/components/UiFullscreen.js";
16
16
  import { UiHome } from "../icons/components/UiHome.js";
17
17
  const DEFAULT_NODE_WIDTH = 168;
18
18
  const DEFAULT_NODE_HEIGHT = 60;
19
+ const DEFAULT_COMPACT_NODE_HEIGHT = 24;
20
+ function compactHeights(nodes, layout, compactNodeHeight) {
21
+ if (layout !== "columns") return {};
22
+ return Object.fromEntries(nodes.filter((node) => node.size === "compact").map((node) => [node.id, compactNodeHeight]));
23
+ }
19
24
  function assertEdgesReferenceKnownNodes(nodes, edges) {
20
25
  const ids = new Set(nodes.map((node) => node.id));
21
26
  for (const edge of edges) {
@@ -33,7 +38,7 @@ function requireLevel(node) {
33
38
  }
34
39
  return node.level;
35
40
  }
36
- function layoutNodes(nodes, edges, { layout, nodeWidth, nodeHeight, columnGap, rowGap }) {
41
+ function layoutNodes(nodes, edges, { layout, nodeWidth, nodeHeight, compactNodeHeight, columnGap, rowGap }) {
37
42
  switch (layout) {
38
43
  case "ring":
39
44
  return { ...ringLayout(nodes, { nodeWidth, nodeHeight }), groups: [] };
@@ -42,12 +47,14 @@ function layoutNodes(nodes, edges, { layout, nodeWidth, nodeHeight, columnGap, r
42
47
  nodes.map((node) => ({
43
48
  id: node.id,
44
49
  level: requireLevel(node),
45
- ...node.group !== void 0 ? { group: node.group } : {}
50
+ ...node.group !== void 0 ? { group: node.group } : {},
51
+ ...node.size === "compact" ? { compact: true } : {}
46
52
  })),
47
53
  edges,
48
54
  {
49
55
  nodeWidth,
50
56
  nodeHeight,
57
+ compactNodeHeight,
51
58
  ...columnGap !== void 0 ? { columnGap } : {},
52
59
  ...rowGap !== void 0 ? { rowGap } : {}
53
60
  }
@@ -92,9 +99,11 @@ function GraphDiagram({
92
99
  groups,
93
100
  nodeWidth = DEFAULT_NODE_WIDTH,
94
101
  nodeHeight = DEFAULT_NODE_HEIGHT,
102
+ compactNodeHeight = DEFAULT_COMPACT_NODE_HEIGHT,
95
103
  columnGap,
96
104
  rowGap,
97
105
  zoomable = false,
106
+ wheelZoom = "modifier",
98
107
  fitMinScale,
99
108
  focusId,
100
109
  maxHeight,
@@ -104,15 +113,17 @@ function GraphDiagram({
104
113
  assertEdgesReferenceKnownNodes(nodes, edges);
105
114
  const markerPrefix = `graph-diagram-${useId().replace(/[^a-zA-Z0-9_-]/g, "")}`;
106
115
  const { width, height, positions, groups: groupBoxes } = useMemo(
107
- () => layoutNodes(nodes, edges, { layout, nodeWidth, nodeHeight, columnGap, rowGap }),
108
- [layout, nodes, edges, nodeWidth, nodeHeight, columnGap, rowGap]
116
+ () => layoutNodes(nodes, edges, { layout, nodeWidth, nodeHeight, compactNodeHeight, columnGap, rowGap }),
117
+ [layout, nodes, edges, nodeWidth, nodeHeight, compactNodeHeight, columnGap, rowGap]
109
118
  );
119
+ const nodeHeights = useMemo(() => compactHeights(nodes, layout, compactNodeHeight), [nodes, layout, compactNodeHeight]);
110
120
  const routes = useMemo(
111
- () => routeEdges(edges, positions, { nodeWidth, nodeHeight }, { anchor: layout === "columns" ? "side" : "center" }),
112
- [edges, positions, nodeWidth, nodeHeight, layout]
121
+ () => routeEdges(edges, positions, { nodeWidth, nodeHeight, nodeHeights }, { anchor: layout === "columns" ? "side" : "center" }),
122
+ [edges, positions, nodeWidth, nodeHeight, nodeHeights, layout]
113
123
  );
114
124
  const panZoom = usePanZoom({
115
125
  enabled: zoomable,
126
+ wheel: wheelZoom,
116
127
  contentWidth: width,
117
128
  contentHeight: height,
118
129
  opening: openingFit(positions, fitMinScale, focusId)
@@ -167,6 +178,7 @@ function GraphDiagram({
167
178
  place,
168
179
  nodeWidth,
169
180
  nodeHeight,
181
+ nodeHeights,
170
182
  selectedId,
171
183
  onNodeSelect,
172
184
  onNodeExpand,