@flanksource/clicky-ui 0.3.41 → 0.3.42

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 (472) hide show
  1. package/dist/ai.cjs +4 -0
  2. package/dist/ai.cjs.map +1 -1
  3. package/dist/ai.js +4 -0
  4. package/dist/ai.js.map +1 -1
  5. package/dist/comments/CommentCard.cjs +3 -1
  6. package/dist/comments/CommentCard.cjs.map +1 -1
  7. package/dist/comments/CommentCard.d.ts.map +1 -1
  8. package/dist/comments/CommentCard.js +4 -2
  9. package/dist/comments/CommentCard.js.map +1 -1
  10. package/dist/comments/CommentCardParts.cjs +16 -0
  11. package/dist/comments/CommentCardParts.cjs.map +1 -1
  12. package/dist/comments/CommentCardParts.d.ts +4 -1
  13. package/dist/comments/CommentCardParts.d.ts.map +1 -1
  14. package/dist/comments/CommentCardParts.js +16 -0
  15. package/dist/comments/CommentCardParts.js.map +1 -1
  16. package/dist/comments/comment-types.cjs.map +1 -1
  17. package/dist/comments/comment-types.d.ts +4 -0
  18. package/dist/comments/comment-types.d.ts.map +1 -1
  19. package/dist/comments/comment-types.js.map +1 -1
  20. package/dist/components/Combobox.cjs +54 -8
  21. package/dist/components/Combobox.cjs.map +1 -1
  22. package/dist/components/Combobox.d.ts.map +1 -1
  23. package/dist/components/Combobox.js +56 -10
  24. package/dist/components/Combobox.js.map +1 -1
  25. package/dist/components/ComboboxMenu.cjs +139 -113
  26. package/dist/components/ComboboxMenu.cjs.map +1 -1
  27. package/dist/components/ComboboxMenu.d.ts +3 -1
  28. package/dist/components/ComboboxMenu.d.ts.map +1 -1
  29. package/dist/components/ComboboxMenu.js +139 -113
  30. package/dist/components/ComboboxMenu.js.map +1 -1
  31. package/dist/components/ComboboxMenuTrigger.cjs +87 -0
  32. package/dist/components/ComboboxMenuTrigger.cjs.map +1 -0
  33. package/dist/components/ComboboxMenuTrigger.d.ts +23 -0
  34. package/dist/components/ComboboxMenuTrigger.d.ts.map +1 -0
  35. package/dist/components/ComboboxMenuTrigger.js +87 -0
  36. package/dist/components/ComboboxMenuTrigger.js.map +1 -0
  37. package/dist/components/JsonSchemaForm.cjs +30 -7
  38. package/dist/components/JsonSchemaForm.cjs.map +1 -1
  39. package/dist/components/JsonSchemaForm.d.ts.map +1 -1
  40. package/dist/components/JsonSchemaForm.js +30 -7
  41. package/dist/components/JsonSchemaForm.js.map +1 -1
  42. package/dist/components/SegmentedControl.cjs +20 -3
  43. package/dist/components/SegmentedControl.cjs.map +1 -1
  44. package/dist/components/SegmentedControl.d.ts +11 -0
  45. package/dist/components/SegmentedControl.d.ts.map +1 -1
  46. package/dist/components/SegmentedControl.js +21 -4
  47. package/dist/components/SegmentedControl.js.map +1 -1
  48. package/dist/components/combobox-types.d.ts +8 -0
  49. package/dist/components/combobox-types.d.ts.map +1 -1
  50. package/dist/components/json-schema-form-debug-badge.cjs +108 -0
  51. package/dist/components/json-schema-form-debug-badge.cjs.map +1 -0
  52. package/dist/components/json-schema-form-debug-badge.d.ts +10 -0
  53. package/dist/components/json-schema-form-debug-badge.d.ts.map +1 -0
  54. package/dist/components/json-schema-form-debug-badge.js +108 -0
  55. package/dist/components/json-schema-form-debug-badge.js.map +1 -0
  56. package/dist/components/json-schema-form-debug-glyph-map.cjs +129 -0
  57. package/dist/components/json-schema-form-debug-glyph-map.cjs.map +1 -0
  58. package/dist/components/json-schema-form-debug-glyph-map.d.ts +20 -0
  59. package/dist/components/json-schema-form-debug-glyph-map.d.ts.map +1 -0
  60. package/dist/components/json-schema-form-debug-glyph-map.js +129 -0
  61. package/dist/components/json-schema-form-debug-glyph-map.js.map +1 -0
  62. package/dist/components/json-schema-form-debug-glyph.cjs +13 -0
  63. package/dist/components/json-schema-form-debug-glyph.cjs.map +1 -0
  64. package/dist/components/json-schema-form-debug-glyph.d.ts +6 -0
  65. package/dist/components/json-schema-form-debug-glyph.d.ts.map +1 -0
  66. package/dist/components/json-schema-form-debug-glyph.js +13 -0
  67. package/dist/components/json-schema-form-debug-glyph.js.map +1 -0
  68. package/dist/components/json-schema-form-debug-groups.cjs +56 -0
  69. package/dist/components/json-schema-form-debug-groups.cjs.map +1 -0
  70. package/dist/components/json-schema-form-debug-groups.d.ts +8 -0
  71. package/dist/components/json-schema-form-debug-groups.d.ts.map +1 -0
  72. package/dist/components/json-schema-form-debug-groups.js +56 -0
  73. package/dist/components/json-schema-form-debug-groups.js.map +1 -0
  74. package/dist/components/json-schema-form-debug-keywords.cjs +159 -0
  75. package/dist/components/json-schema-form-debug-keywords.cjs.map +1 -0
  76. package/dist/components/json-schema-form-debug-keywords.d.ts +6 -0
  77. package/dist/components/json-schema-form-debug-keywords.d.ts.map +1 -0
  78. package/dist/components/json-schema-form-debug-keywords.js +159 -0
  79. package/dist/components/json-schema-form-debug-keywords.js.map +1 -0
  80. package/dist/components/json-schema-form-debug-listeners.cjs +102 -0
  81. package/dist/components/json-schema-form-debug-listeners.cjs.map +1 -0
  82. package/dist/components/json-schema-form-debug-listeners.d.ts +6 -0
  83. package/dist/components/json-schema-form-debug-listeners.d.ts.map +1 -0
  84. package/dist/components/json-schema-form-debug-listeners.js +102 -0
  85. package/dist/components/json-schema-form-debug-listeners.js.map +1 -0
  86. package/dist/components/json-schema-form-debug.cjs +31 -0
  87. package/dist/components/json-schema-form-debug.cjs.map +1 -0
  88. package/dist/components/json-schema-form-debug.d.ts +11 -0
  89. package/dist/components/json-schema-form-debug.d.ts.map +1 -0
  90. package/dist/components/json-schema-form-debug.js +31 -0
  91. package/dist/components/json-schema-form-debug.js.map +1 -0
  92. package/dist/components/json-schema-form-enum-choice.cjs +114 -0
  93. package/dist/components/json-schema-form-enum-choice.cjs.map +1 -0
  94. package/dist/components/json-schema-form-enum-choice.d.ts +14 -0
  95. package/dist/components/json-schema-form-enum-choice.d.ts.map +1 -0
  96. package/dist/components/json-schema-form-enum-choice.js +114 -0
  97. package/dist/components/json-schema-form-enum-choice.js.map +1 -0
  98. package/dist/components/json-schema-form-fields.cjs +3 -93
  99. package/dist/components/json-schema-form-fields.cjs.map +1 -1
  100. package/dist/components/json-schema-form-fields.d.ts.map +1 -1
  101. package/dist/components/json-schema-form-fields.js +1 -91
  102. package/dist/components/json-schema-form-fields.js.map +1 -1
  103. package/dist/components/json-schema-form-listeners.cjs +7 -1
  104. package/dist/components/json-schema-form-listeners.cjs.map +1 -1
  105. package/dist/components/json-schema-form-listeners.d.ts.map +1 -1
  106. package/dist/components/json-schema-form-listeners.js +7 -1
  107. package/dist/components/json-schema-form-listeners.js.map +1 -1
  108. package/dist/components/json-schema-form-preferences.cjs +1 -0
  109. package/dist/components/json-schema-form-preferences.cjs.map +1 -1
  110. package/dist/components/json-schema-form-preferences.d.ts +1 -0
  111. package/dist/components/json-schema-form-preferences.d.ts.map +1 -1
  112. package/dist/components/json-schema-form-preferences.js +1 -0
  113. package/dist/components/json-schema-form-preferences.js.map +1 -1
  114. package/dist/components/json-schema-form-render.cjs +21 -5
  115. package/dist/components/json-schema-form-render.cjs.map +1 -1
  116. package/dist/components/json-schema-form-render.d.ts.map +1 -1
  117. package/dist/components/json-schema-form-render.js +21 -5
  118. package/dist/components/json-schema-form-render.js.map +1 -1
  119. package/dist/components/json-schema-form-runtime-types.d.ts +1 -0
  120. package/dist/components/json-schema-form-runtime-types.d.ts.map +1 -1
  121. package/dist/components/json-schema-form-tone.cjs +12 -0
  122. package/dist/components/json-schema-form-tone.cjs.map +1 -1
  123. package/dist/components/json-schema-form-tone.js +12 -0
  124. package/dist/components/json-schema-form-tone.js.map +1 -1
  125. package/dist/components/json-schema-form-types.d.ts +1 -0
  126. package/dist/components/json-schema-form-types.d.ts.map +1 -1
  127. package/dist/data/GraphDiagram.cjs +125 -138
  128. package/dist/data/GraphDiagram.cjs.map +1 -1
  129. package/dist/data/GraphDiagram.d.ts +30 -23
  130. package/dist/data/GraphDiagram.d.ts.map +1 -1
  131. package/dist/data/GraphDiagram.js +128 -141
  132. package/dist/data/GraphDiagram.js.map +1 -1
  133. package/dist/data/GraphDiagramEdges.cjs +208 -0
  134. package/dist/data/GraphDiagramEdges.cjs.map +1 -0
  135. package/dist/data/GraphDiagramEdges.d.ts +40 -0
  136. package/dist/data/GraphDiagramEdges.d.ts.map +1 -0
  137. package/dist/data/GraphDiagramEdges.js +208 -0
  138. package/dist/data/GraphDiagramEdges.js.map +1 -0
  139. package/dist/data/GraphDiagramNodes.cjs +142 -0
  140. package/dist/data/GraphDiagramNodes.cjs.map +1 -0
  141. package/dist/data/GraphDiagramNodes.d.ts +22 -0
  142. package/dist/data/GraphDiagramNodes.d.ts.map +1 -0
  143. package/dist/data/GraphDiagramNodes.js +142 -0
  144. package/dist/data/GraphDiagramNodes.js.map +1 -0
  145. package/dist/data/ai/PromptRunEditor/RuntimeRows.cjs +8 -3
  146. package/dist/data/ai/PromptRunEditor/RuntimeRows.cjs.map +1 -1
  147. package/dist/data/ai/PromptRunEditor/RuntimeRows.d.ts.map +1 -1
  148. package/dist/data/ai/PromptRunEditor/RuntimeRows.js +8 -3
  149. package/dist/data/ai/PromptRunEditor/RuntimeRows.js.map +1 -1
  150. package/dist/data/ai/PromptRunEditor/index.cjs +37 -43
  151. package/dist/data/ai/PromptRunEditor/index.cjs.map +1 -1
  152. package/dist/data/ai/PromptRunEditor/index.d.ts +3 -1
  153. package/dist/data/ai/PromptRunEditor/index.d.ts.map +1 -1
  154. package/dist/data/ai/PromptRunEditor/index.js +38 -44
  155. package/dist/data/ai/PromptRunEditor/index.js.map +1 -1
  156. package/dist/data/ai/PromptRunEditor/runtimeActions.cjs +16 -5
  157. package/dist/data/ai/PromptRunEditor/runtimeActions.cjs.map +1 -1
  158. package/dist/data/ai/PromptRunEditor/runtimeActions.d.ts +4 -1
  159. package/dist/data/ai/PromptRunEditor/runtimeActions.d.ts.map +1 -1
  160. package/dist/data/ai/PromptRunEditor/runtimeActions.js +17 -6
  161. package/dist/data/ai/PromptRunEditor/runtimeActions.js.map +1 -1
  162. package/dist/data/ai/SessionInspector.approvals-model.cjs +12 -0
  163. package/dist/data/ai/SessionInspector.approvals-model.cjs.map +1 -1
  164. package/dist/data/ai/SessionInspector.approvals-model.d.ts +11 -2
  165. package/dist/data/ai/SessionInspector.approvals-model.d.ts.map +1 -1
  166. package/dist/data/ai/SessionInspector.approvals-model.js +12 -0
  167. package/dist/data/ai/SessionInspector.approvals-model.js.map +1 -1
  168. package/dist/data/ai/SessionInspector.approvals.cjs +25 -1
  169. package/dist/data/ai/SessionInspector.approvals.cjs.map +1 -1
  170. package/dist/data/ai/SessionInspector.approvals.d.ts.map +1 -1
  171. package/dist/data/ai/SessionInspector.approvals.js +26 -2
  172. package/dist/data/ai/SessionInspector.approvals.js.map +1 -1
  173. package/dist/data/ai/SessionInspector.summary.cjs +9 -3
  174. package/dist/data/ai/SessionInspector.summary.cjs.map +1 -1
  175. package/dist/data/ai/SessionInspector.summary.d.ts.map +1 -1
  176. package/dist/data/ai/SessionInspector.summary.js +9 -3
  177. package/dist/data/ai/SessionInspector.summary.js.map +1 -1
  178. package/dist/data/ai/SessionInspector.transcript.cjs +4 -0
  179. package/dist/data/ai/SessionInspector.transcript.cjs.map +1 -1
  180. package/dist/data/ai/SessionInspector.transcript.d.ts.map +1 -1
  181. package/dist/data/ai/SessionInspector.transcript.js +4 -0
  182. package/dist/data/ai/SessionInspector.transcript.js.map +1 -1
  183. package/dist/data/ai/SessionViewer.approval-body.cjs +146 -0
  184. package/dist/data/ai/SessionViewer.approval-body.cjs.map +1 -0
  185. package/dist/data/ai/SessionViewer.approval-body.d.ts +11 -0
  186. package/dist/data/ai/SessionViewer.approval-body.d.ts.map +1 -0
  187. package/dist/data/ai/SessionViewer.approval-body.js +146 -0
  188. package/dist/data/ai/SessionViewer.approval-body.js.map +1 -0
  189. package/dist/data/ai/SessionViewer.approval-forms.cjs +150 -0
  190. package/dist/data/ai/SessionViewer.approval-forms.cjs.map +1 -0
  191. package/dist/data/ai/SessionViewer.approval-forms.d.ts +23 -0
  192. package/dist/data/ai/SessionViewer.approval-forms.d.ts.map +1 -0
  193. package/dist/data/ai/SessionViewer.approval-forms.js +150 -0
  194. package/dist/data/ai/SessionViewer.approval-forms.js.map +1 -0
  195. package/dist/data/ai/SessionViewer.cjs +57 -20
  196. package/dist/data/ai/SessionViewer.cjs.map +1 -1
  197. package/dist/data/ai/SessionViewer.d.ts +13 -3
  198. package/dist/data/ai/SessionViewer.d.ts.map +1 -1
  199. package/dist/data/ai/SessionViewer.decision-controls.cjs +313 -0
  200. package/dist/data/ai/SessionViewer.decision-controls.cjs.map +1 -0
  201. package/dist/data/ai/SessionViewer.decision-controls.d.ts +43 -0
  202. package/dist/data/ai/SessionViewer.decision-controls.d.ts.map +1 -0
  203. package/dist/data/ai/SessionViewer.decision-controls.js +313 -0
  204. package/dist/data/ai/SessionViewer.decision-controls.js.map +1 -0
  205. package/dist/data/ai/SessionViewer.decision.cjs +21 -0
  206. package/dist/data/ai/SessionViewer.decision.cjs.map +1 -0
  207. package/dist/data/ai/SessionViewer.decision.d.ts +12 -0
  208. package/dist/data/ai/SessionViewer.decision.d.ts.map +1 -0
  209. package/dist/data/ai/SessionViewer.decision.js +21 -0
  210. package/dist/data/ai/SessionViewer.decision.js.map +1 -0
  211. package/dist/data/ai/SessionViewer.input.cjs +14 -0
  212. package/dist/data/ai/SessionViewer.input.cjs.map +1 -1
  213. package/dist/data/ai/SessionViewer.input.d.ts +5 -0
  214. package/dist/data/ai/SessionViewer.input.d.ts.map +1 -1
  215. package/dist/data/ai/SessionViewer.input.js +14 -0
  216. package/dist/data/ai/SessionViewer.input.js.map +1 -1
  217. package/dist/data/ai/SessionViewer.js +58 -21
  218. package/dist/data/ai/SessionViewer.js.map +1 -1
  219. package/dist/data/ai/SessionViewer.model.cjs.map +1 -1
  220. package/dist/data/ai/SessionViewer.model.d.ts +4 -0
  221. package/dist/data/ai/SessionViewer.model.d.ts.map +1 -1
  222. package/dist/data/ai/SessionViewer.model.js.map +1 -1
  223. package/dist/data/ai/SessionViewer.rows.cjs +6 -3
  224. package/dist/data/ai/SessionViewer.rows.cjs.map +1 -1
  225. package/dist/data/ai/SessionViewer.rows.d.ts +2 -1
  226. package/dist/data/ai/SessionViewer.rows.d.ts.map +1 -1
  227. package/dist/data/ai/SessionViewer.rows.js +6 -3
  228. package/dist/data/ai/SessionViewer.rows.js.map +1 -1
  229. package/dist/data/ai/SessionViewer.tool-row.cjs +29 -237
  230. package/dist/data/ai/SessionViewer.tool-row.cjs.map +1 -1
  231. package/dist/data/ai/SessionViewer.tool-row.d.ts.map +1 -1
  232. package/dist/data/ai/SessionViewer.tool-row.js +27 -235
  233. package/dist/data/ai/SessionViewer.tool-row.js.map +1 -1
  234. package/dist/data/ai/SessionViewer.unified.d.ts +4 -0
  235. package/dist/data/ai/SessionViewer.unified.d.ts.map +1 -1
  236. package/dist/data/ai/SessionViewerMenu.cjs +8 -2
  237. package/dist/data/ai/SessionViewerMenu.cjs.map +1 -1
  238. package/dist/data/ai/SessionViewerMenu.d.ts +4 -1
  239. package/dist/data/ai/SessionViewerMenu.d.ts.map +1 -1
  240. package/dist/data/ai/SessionViewerMenu.js +8 -2
  241. package/dist/data/ai/SessionViewerMenu.js.map +1 -1
  242. package/dist/data/ai/SpecRuntimeEditor/CommitSection.cjs +28 -17
  243. package/dist/data/ai/SpecRuntimeEditor/CommitSection.cjs.map +1 -1
  244. package/dist/data/ai/SpecRuntimeEditor/CommitSection.d.ts +10 -2
  245. package/dist/data/ai/SpecRuntimeEditor/CommitSection.d.ts.map +1 -1
  246. package/dist/data/ai/SpecRuntimeEditor/CommitSection.js +29 -18
  247. package/dist/data/ai/SpecRuntimeEditor/CommitSection.js.map +1 -1
  248. package/dist/data/ai/SpecRuntimeEditor/index.cjs +9 -1
  249. package/dist/data/ai/SpecRuntimeEditor/index.cjs.map +1 -1
  250. package/dist/data/ai/SpecRuntimeEditor/index.d.ts +9 -2
  251. package/dist/data/ai/SpecRuntimeEditor/index.d.ts.map +1 -1
  252. package/dist/data/ai/SpecRuntimeEditor/index.js +9 -1
  253. package/dist/data/ai/SpecRuntimeEditor/index.js.map +1 -1
  254. package/dist/data/ai/SpecRuntimeEditor/permission-mode-visuals.cjs +1 -1
  255. package/dist/data/ai/SpecRuntimeEditor/permission-mode-visuals.js +1 -1
  256. package/dist/data/ai/SpecRuntimeEditor/summaries.cjs.map +1 -1
  257. package/dist/data/ai/SpecRuntimeEditor/summaries.d.ts +8 -2
  258. package/dist/data/ai/SpecRuntimeEditor/summaries.d.ts.map +1 -1
  259. package/dist/data/ai/SpecRuntimeEditor/summaries.js.map +1 -1
  260. package/dist/data/ai/SpecRuntimeEditor/update.cjs +14 -6
  261. package/dist/data/ai/SpecRuntimeEditor/update.cjs.map +1 -1
  262. package/dist/data/ai/SpecRuntimeEditor/update.d.ts +1 -0
  263. package/dist/data/ai/SpecRuntimeEditor/update.d.ts.map +1 -1
  264. package/dist/data/ai/SpecRuntimeEditor/update.js +14 -6
  265. package/dist/data/ai/SpecRuntimeEditor/update.js.map +1 -1
  266. package/dist/data/ai/approval-request.cjs +75 -0
  267. package/dist/data/ai/approval-request.cjs.map +1 -0
  268. package/dist/data/ai/approval-request.d.ts +155 -0
  269. package/dist/data/ai/approval-request.d.ts.map +1 -0
  270. package/dist/data/ai/approval-request.js +75 -0
  271. package/dist/data/ai/approval-request.js.map +1 -0
  272. package/dist/data/ai/index.d.ts +3 -0
  273. package/dist/data/ai/index.d.ts.map +1 -1
  274. package/dist/data/ai/runtime-preset-menu/SavePresetDialog.cjs +125 -0
  275. package/dist/data/ai/runtime-preset-menu/SavePresetDialog.cjs.map +1 -0
  276. package/dist/data/ai/runtime-preset-menu/SavePresetDialog.d.ts +11 -0
  277. package/dist/data/ai/runtime-preset-menu/SavePresetDialog.d.ts.map +1 -0
  278. package/dist/data/ai/runtime-preset-menu/SavePresetDialog.js +125 -0
  279. package/dist/data/ai/runtime-preset-menu/SavePresetDialog.js.map +1 -0
  280. package/dist/data/ai/runtime-preset-menu/index.d.ts +3 -0
  281. package/dist/data/ai/runtime-preset-menu/index.d.ts.map +1 -0
  282. package/dist/data/ai/runtime-preset-menu/model.cjs +73 -0
  283. package/dist/data/ai/runtime-preset-menu/model.cjs.map +1 -0
  284. package/dist/data/ai/runtime-preset-menu/model.d.ts +13 -0
  285. package/dist/data/ai/runtime-preset-menu/model.d.ts.map +1 -0
  286. package/dist/data/ai/runtime-preset-menu/model.js +73 -0
  287. package/dist/data/ai/runtime-preset-menu/model.js.map +1 -0
  288. package/dist/data/ai/runtime-preset-menu/use-runtime-preset-menu.cjs +149 -0
  289. package/dist/data/ai/runtime-preset-menu/use-runtime-preset-menu.cjs.map +1 -0
  290. package/dist/data/ai/runtime-preset-menu/use-runtime-preset-menu.d.ts +15 -0
  291. package/dist/data/ai/runtime-preset-menu/use-runtime-preset-menu.d.ts.map +1 -0
  292. package/dist/data/ai/runtime-preset-menu/use-runtime-preset-menu.js +149 -0
  293. package/dist/data/ai/runtime-preset-menu/use-runtime-preset-menu.js.map +1 -0
  294. package/dist/data/ai/runtime-spec-fields.cjs +166 -0
  295. package/dist/data/ai/runtime-spec-fields.cjs.map +1 -0
  296. package/dist/data/ai/runtime-spec-fields.d.ts +13 -0
  297. package/dist/data/ai/runtime-spec-fields.d.ts.map +1 -0
  298. package/dist/data/ai/runtime-spec-fields.js +166 -0
  299. package/dist/data/ai/runtime-spec-fields.js.map +1 -0
  300. package/dist/data/ai/session-categories.cjs +4 -0
  301. package/dist/data/ai/session-categories.cjs.map +1 -1
  302. package/dist/data/ai/session-categories.d.ts +1 -0
  303. package/dist/data/ai/session-categories.d.ts.map +1 -1
  304. package/dist/data/ai/session-categories.js +4 -0
  305. package/dist/data/ai/session-categories.js.map +1 -1
  306. package/dist/data/ai/use-session-scroll.cjs +49 -21
  307. package/dist/data/ai/use-session-scroll.cjs.map +1 -1
  308. package/dist/data/ai/use-session-scroll.d.ts +2 -0
  309. package/dist/data/ai/use-session-scroll.d.ts.map +1 -1
  310. package/dist/data/ai/use-session-scroll.js +49 -21
  311. package/dist/data/ai/use-session-scroll.js.map +1 -1
  312. package/dist/data/chat/Chat.runtime.cjs +1 -1
  313. package/dist/data/chat/Chat.runtime.cjs.map +1 -1
  314. package/dist/data/chat/Chat.runtime.d.ts.map +1 -1
  315. package/dist/data/chat/Chat.runtime.js +1 -1
  316. package/dist/data/chat/Chat.runtime.js.map +1 -1
  317. package/dist/data/graph-columns-layout.cjs +216 -0
  318. package/dist/data/graph-columns-layout.cjs.map +1 -0
  319. package/dist/data/graph-columns-layout.d.ts +56 -0
  320. package/dist/data/graph-columns-layout.d.ts.map +1 -0
  321. package/dist/data/graph-columns-layout.js +216 -0
  322. package/dist/data/graph-columns-layout.js.map +1 -0
  323. package/dist/data/graph-diagram-model.cjs +73 -0
  324. package/dist/data/graph-diagram-model.cjs.map +1 -0
  325. package/dist/data/graph-diagram-model.d.ts +90 -0
  326. package/dist/data/graph-diagram-model.d.ts.map +1 -0
  327. package/dist/data/graph-diagram-model.js +73 -0
  328. package/dist/data/graph-diagram-model.js.map +1 -0
  329. package/dist/data/graph-edge-routing.cjs +235 -0
  330. package/dist/data/graph-edge-routing.cjs.map +1 -0
  331. package/dist/data/graph-edge-routing.d.ts +73 -0
  332. package/dist/data/graph-edge-routing.d.ts.map +1 -0
  333. package/dist/data/graph-edge-routing.js +235 -0
  334. package/dist/data/graph-edge-routing.js.map +1 -0
  335. package/dist/data/graph-layout.cjs +0 -82
  336. package/dist/data/graph-layout.cjs.map +1 -1
  337. package/dist/data/graph-layout.d.ts +1 -28
  338. package/dist/data/graph-layout.d.ts.map +1 -1
  339. package/dist/data/graph-layout.js +1 -83
  340. package/dist/data/graph-layout.js.map +1 -1
  341. package/dist/data/har/HarPanel.cjs +129 -33
  342. package/dist/data/har/HarPanel.cjs.map +1 -1
  343. package/dist/data/har/HarPanel.d.ts +13 -1
  344. package/dist/data/har/HarPanel.d.ts.map +1 -1
  345. package/dist/data/har/HarPanel.js +130 -34
  346. package/dist/data/har/HarPanel.js.map +1 -1
  347. package/dist/data/har/fixtures.d.ts +12 -0
  348. package/dist/data/har/fixtures.d.ts.map +1 -1
  349. package/dist/data/har/types.d.ts +12 -0
  350. package/dist/data/har/types.d.ts.map +1 -1
  351. package/dist/data/runtime/RuntimeBar.cjs +67 -84
  352. package/dist/data/runtime/RuntimeBar.cjs.map +1 -1
  353. package/dist/data/runtime/RuntimeBar.d.ts +4 -5
  354. package/dist/data/runtime/RuntimeBar.d.ts.map +1 -1
  355. package/dist/data/runtime/RuntimeBar.fields.cjs +170 -0
  356. package/dist/data/runtime/RuntimeBar.fields.cjs.map +1 -0
  357. package/dist/data/runtime/RuntimeBar.fields.d.ts +16 -0
  358. package/dist/data/runtime/RuntimeBar.fields.d.ts.map +1 -0
  359. package/dist/data/runtime/RuntimeBar.fields.js +170 -0
  360. package/dist/data/runtime/RuntimeBar.fields.js.map +1 -0
  361. package/dist/data/runtime/RuntimeBar.js +70 -87
  362. package/dist/data/runtime/RuntimeBar.js.map +1 -1
  363. package/dist/data/runtime/RuntimeBar.selection.cjs +56 -0
  364. package/dist/data/runtime/RuntimeBar.selection.cjs.map +1 -0
  365. package/dist/data/runtime/RuntimeBar.selection.d.ts +20 -0
  366. package/dist/data/runtime/RuntimeBar.selection.d.ts.map +1 -0
  367. package/dist/data/runtime/RuntimeBar.selection.js +56 -0
  368. package/dist/data/runtime/RuntimeBar.selection.js.map +1 -0
  369. package/dist/data/runtime/RuntimeBarActions.cjs +10 -6
  370. package/dist/data/runtime/RuntimeBarActions.cjs.map +1 -1
  371. package/dist/data/runtime/RuntimeBarActions.d.ts +8 -1
  372. package/dist/data/runtime/RuntimeBarActions.d.ts.map +1 -1
  373. package/dist/data/runtime/RuntimeBarActions.js +10 -6
  374. package/dist/data/runtime/RuntimeBarActions.js.map +1 -1
  375. package/dist/data/runtime/RuntimeBarIdentity.cjs +166 -0
  376. package/dist/data/runtime/RuntimeBarIdentity.cjs.map +1 -0
  377. package/dist/data/runtime/RuntimeBarIdentity.d.ts +25 -0
  378. package/dist/data/runtime/RuntimeBarIdentity.d.ts.map +1 -0
  379. package/dist/data/runtime/RuntimeBarIdentity.js +166 -0
  380. package/dist/data/runtime/RuntimeBarIdentity.js.map +1 -0
  381. package/dist/data/runtime/RuntimeBarLayout.cjs +95 -0
  382. package/dist/data/runtime/RuntimeBarLayout.cjs.map +1 -0
  383. package/dist/data/runtime/RuntimeBarLayout.d.ts +9 -0
  384. package/dist/data/runtime/RuntimeBarLayout.d.ts.map +1 -0
  385. package/dist/data/runtime/RuntimeBarLayout.js +95 -0
  386. package/dist/data/runtime/RuntimeBarLayout.js.map +1 -0
  387. package/dist/data/runtime/RuntimeBarSegment.cjs +25 -14
  388. package/dist/data/runtime/RuntimeBarSegment.cjs.map +1 -1
  389. package/dist/data/runtime/RuntimeBarSegment.d.ts +4 -0
  390. package/dist/data/runtime/RuntimeBarSegment.d.ts.map +1 -1
  391. package/dist/data/runtime/RuntimeBarSegment.js +25 -14
  392. package/dist/data/runtime/RuntimeBarSegment.js.map +1 -1
  393. package/dist/data/runtime/RuntimeLimitInput.cjs +41 -0
  394. package/dist/data/runtime/RuntimeLimitInput.cjs.map +1 -0
  395. package/dist/data/runtime/RuntimeLimitInput.d.ts +9 -0
  396. package/dist/data/runtime/RuntimeLimitInput.d.ts.map +1 -0
  397. package/dist/data/runtime/RuntimeLimitInput.js +41 -0
  398. package/dist/data/runtime/RuntimeLimitInput.js.map +1 -0
  399. package/dist/data/runtime/use-runtime-bar-overflow.cjs +70 -0
  400. package/dist/data/runtime/use-runtime-bar-overflow.cjs.map +1 -0
  401. package/dist/data/runtime/use-runtime-bar-overflow.d.ts +13 -0
  402. package/dist/data/runtime/use-runtime-bar-overflow.d.ts.map +1 -0
  403. package/dist/data/runtime/use-runtime-bar-overflow.js +70 -0
  404. package/dist/data/runtime/use-runtime-bar-overflow.js.map +1 -0
  405. package/dist/data/use-edge-focus.cjs +20 -0
  406. package/dist/data/use-edge-focus.cjs.map +1 -0
  407. package/dist/data/use-edge-focus.d.ts +23 -0
  408. package/dist/data/use-edge-focus.d.ts.map +1 -0
  409. package/dist/data/use-edge-focus.js +20 -0
  410. package/dist/data/use-edge-focus.js.map +1 -0
  411. package/dist/data/use-pan-zoom.cjs +159 -0
  412. package/dist/data/use-pan-zoom.cjs.map +1 -0
  413. package/dist/data/use-pan-zoom.d.ts +79 -0
  414. package/dist/data/use-pan-zoom.d.ts.map +1 -0
  415. package/dist/data/use-pan-zoom.js +159 -0
  416. package/dist/data/use-pan-zoom.js.map +1 -0
  417. package/dist/data/version-info.cjs +3 -3
  418. package/dist/data/version-info.js +3 -3
  419. package/dist/data.cjs +5 -1
  420. package/dist/data.cjs.map +1 -1
  421. package/dist/data.d.ts +4 -3
  422. package/dist/data.d.ts.map +1 -1
  423. package/dist/data.js +6 -2
  424. package/dist/data.js.map +1 -1
  425. package/dist/index.cjs +5 -1
  426. package/dist/index.cjs.map +1 -1
  427. package/dist/index.js +6 -2
  428. package/dist/index.js.map +1 -1
  429. package/dist/overlay/DropdownMenu.cjs +1 -0
  430. package/dist/overlay/DropdownMenu.cjs.map +1 -1
  431. package/dist/overlay/DropdownMenu.d.ts +4 -0
  432. package/dist/overlay/DropdownMenu.d.ts.map +1 -1
  433. package/dist/overlay/DropdownMenu.js +1 -0
  434. package/dist/overlay/DropdownMenu.js.map +1 -1
  435. package/dist/overlay/DropdownMenuSubmenu.cjs +31 -15
  436. package/dist/overlay/DropdownMenuSubmenu.cjs.map +1 -1
  437. package/dist/overlay/DropdownMenuSubmenu.d.ts.map +1 -1
  438. package/dist/overlay/DropdownMenuSubmenu.js +31 -15
  439. package/dist/overlay/DropdownMenuSubmenu.js.map +1 -1
  440. package/dist/rpc/OperationCatalog.cjs +3 -1
  441. package/dist/rpc/OperationCatalog.cjs.map +1 -1
  442. package/dist/rpc/OperationCatalog.d.ts +3 -1
  443. package/dist/rpc/OperationCatalog.d.ts.map +1 -1
  444. package/dist/rpc/OperationCatalog.js +3 -1
  445. package/dist/rpc/OperationCatalog.js.map +1 -1
  446. package/dist/rpc/useOperationPages.cjs +6 -1
  447. package/dist/rpc/useOperationPages.cjs.map +1 -1
  448. package/dist/rpc/useOperationPages.d.ts +3 -1
  449. package/dist/rpc/useOperationPages.d.ts.map +1 -1
  450. package/dist/rpc/useOperationPages.js +6 -1
  451. package/dist/rpc/useOperationPages.js.map +1 -1
  452. package/dist/styles.css +1 -1
  453. package/package.json +1 -1
  454. package/schemas/json-schema-form.schema.json +5 -0
  455. package/dist/data/runtime/RuntimeBarCombo.cjs +0 -423
  456. package/dist/data/runtime/RuntimeBarCombo.cjs.map +0 -1
  457. package/dist/data/runtime/RuntimeBarCombo.d.ts +0 -33
  458. package/dist/data/runtime/RuntimeBarCombo.d.ts.map +0 -1
  459. package/dist/data/runtime/RuntimeBarCombo.js +0 -423
  460. package/dist/data/runtime/RuntimeBarCombo.js.map +0 -1
  461. package/dist/data/runtime/RuntimeBarLimits.cjs +0 -262
  462. package/dist/data/runtime/RuntimeBarLimits.cjs.map +0 -1
  463. package/dist/data/runtime/RuntimeBarLimits.d.ts +0 -17
  464. package/dist/data/runtime/RuntimeBarLimits.d.ts.map +0 -1
  465. package/dist/data/runtime/RuntimeBarLimits.js +0 -262
  466. package/dist/data/runtime/RuntimeBarLimits.js.map +0 -1
  467. package/dist/data/runtime/RuntimeBarSegments.cjs +0 -346
  468. package/dist/data/runtime/RuntimeBarSegments.cjs.map +0 -1
  469. package/dist/data/runtime/RuntimeBarSegments.d.ts +0 -37
  470. package/dist/data/runtime/RuntimeBarSegments.d.ts.map +0 -1
  471. package/dist/data/runtime/RuntimeBarSegments.js +0 -346
  472. package/dist/data/runtime/RuntimeBarSegments.js.map +0 -1
@@ -1,23 +1,21 @@
1
- import { jsx, jsxs } from "react/jsx-runtime";
2
- import { useMemo } from "react";
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { useId, useMemo } from "react";
3
3
  import { cn } from "../lib/utils.js";
4
- import { routeEdges, ringLayout } from "./graph-layout.js";
4
+ import { IconButton } from "../components/IconButton.js";
5
+ import { columnsLayout } from "./graph-columns-layout.js";
6
+ import { ringLayout } from "./graph-layout.js";
7
+ import { GraphDiagramEdgePaths, GraphDiagramEdgeLabels } from "./GraphDiagramEdges.js";
8
+ import { GraphDiagramGroupBoxes, GraphDiagramNodes } from "./GraphDiagramNodes.js";
9
+ import { requireEntry } from "./graph-diagram-model.js";
10
+ import { useEdgeFocus } from "./use-edge-focus.js";
11
+ import { usePanZoom } from "./use-pan-zoom.js";
12
+ import { routeEdges } from "./graph-edge-routing.js";
13
+ import { UiZoomOut } from "../icons/components/UiZoomOut.js";
14
+ import { UiZoomIn } from "../icons/components/UiZoomIn.js";
15
+ import { UiFullscreen } from "../icons/components/UiFullscreen.js";
16
+ import { UiHome } from "../icons/components/UiHome.js";
5
17
  const DEFAULT_NODE_WIDTH = 168;
6
18
  const DEFAULT_NODE_HEIGHT = 60;
7
- const TONE_TEXT_CLASS = {
8
- neutral: "text-muted-foreground",
9
- success: "text-emerald-600 dark:text-emerald-400",
10
- danger: "text-red-600 dark:text-red-400",
11
- warning: "text-amber-600 dark:text-amber-400",
12
- info: "text-sky-600 dark:text-sky-400"
13
- };
14
- const TONE_NODE_CLASS = {
15
- neutral: "border-border bg-card text-foreground",
16
- success: "border-emerald-500/50 bg-emerald-500/10 text-foreground",
17
- danger: "border-red-500/50 bg-red-500/10 text-foreground",
18
- warning: "border-amber-500/50 bg-amber-500/10 text-foreground",
19
- info: "border-sky-500/50 bg-sky-500/10 text-foreground"
20
- };
21
19
  function assertEdgesReferenceKnownNodes(nodes, edges) {
22
20
  const ids = new Set(nodes.map((node) => node.id));
23
21
  for (const edge of edges) {
@@ -29,10 +27,31 @@ function assertEdgesReferenceKnownNodes(nodes, edges) {
29
27
  }
30
28
  }
31
29
  }
32
- function layoutNodes(layout, nodes, nodeWidth, nodeHeight) {
30
+ function requireLevel(node) {
31
+ if (node.level === void 0 || !Number.isFinite(node.level)) {
32
+ throw new Error(`GraphDiagram: node "${node.id}" needs a finite level for the "columns" layout`);
33
+ }
34
+ return node.level;
35
+ }
36
+ function layoutNodes(nodes, edges, { layout, nodeWidth, nodeHeight, columnGap, rowGap }) {
33
37
  switch (layout) {
34
38
  case "ring":
35
- return ringLayout(nodes, { nodeWidth, nodeHeight });
39
+ return { ...ringLayout(nodes, { nodeWidth, nodeHeight }), groups: [] };
40
+ case "columns":
41
+ return columnsLayout(
42
+ nodes.map((node) => ({
43
+ id: node.id,
44
+ level: requireLevel(node),
45
+ ...node.group !== void 0 ? { group: node.group } : {}
46
+ })),
47
+ edges,
48
+ {
49
+ nodeWidth,
50
+ nodeHeight,
51
+ ...columnGap !== void 0 ? { columnGap } : {},
52
+ ...rowGap !== void 0 ? { rowGap } : {}
53
+ }
54
+ );
36
55
  default:
37
56
  throw new Error(`GraphDiagram: unknown layout "${layout}"`);
38
57
  }
@@ -40,25 +59,25 @@ function layoutNodes(layout, nodes, nodeWidth, nodeHeight) {
40
59
  function toPercent(value, extent) {
41
60
  return `${value / extent * 100}%`;
42
61
  }
43
- function requireRoute(routes, edgeId) {
44
- const route = routes[edgeId];
45
- if (!route) {
46
- throw new Error(`GraphDiagram: no route computed for edge "${edgeId}"`);
47
- }
48
- return route;
62
+ function stageStyle(size, natural, panZoom) {
63
+ if (!natural) return { aspectRatio: `${size.width} / ${size.height}` };
64
+ if (!panZoom) return size;
65
+ const { x, y, scale } = panZoom.transform;
66
+ return { ...size, transform: `translate(${x}px, ${y}px) scale(${scale})`, transformOrigin: "0 0" };
49
67
  }
50
- function requirePosition(positions, nodeId) {
51
- const position = positions[nodeId];
52
- if (!position) {
53
- throw new Error(`GraphDiagram: no layout position computed for node "${nodeId}"`);
54
- }
55
- return position;
68
+ function ZoomControls({ panZoom, resettable }) {
69
+ return /* @__PURE__ */ jsxs("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", children: [
70
+ /* @__PURE__ */ jsx(IconButton, { icon: UiZoomOut, label: "Zoom out", className: "size-6", onClick: panZoom.zoomOut }),
71
+ /* @__PURE__ */ jsx(IconButton, { icon: UiZoomIn, label: "Zoom in", className: "size-6", onClick: panZoom.zoomIn }),
72
+ /* @__PURE__ */ jsx(IconButton, { icon: UiFullscreen, label: "Fit to view", className: "size-6", onClick: panZoom.fit }),
73
+ resettable && /* @__PURE__ */ jsx(IconButton, { icon: UiHome, label: "Reset view", className: "size-6", onClick: panZoom.reset })
74
+ ] });
56
75
  }
57
- function handleNodeKeyDown(event, select) {
58
- if (event.key === "Enter" || event.key === " ") {
59
- event.preventDefault();
60
- select();
61
- }
76
+ function openingFit(positions, fitMinScale, focusId) {
77
+ return {
78
+ ...fitMinScale !== void 0 ? { minScale: fitMinScale } : {},
79
+ ...focusId !== void 0 ? { focus: requireEntry(positions, focusId, "layout position") } : {}
80
+ };
62
81
  }
63
82
  function GraphDiagram({
64
83
  nodes,
@@ -66,132 +85,100 @@ function GraphDiagram({
66
85
  layout = "ring",
67
86
  selectedId,
68
87
  onNodeSelect,
88
+ onNodeExpand,
89
+ selectedEdgeId,
90
+ onEdgeSelect,
91
+ edgeFocus = "auto",
92
+ groups,
69
93
  nodeWidth = DEFAULT_NODE_WIDTH,
70
94
  nodeHeight = DEFAULT_NODE_HEIGHT,
95
+ columnGap,
96
+ rowGap,
97
+ zoomable = false,
98
+ fitMinScale,
99
+ focusId,
71
100
  maxHeight,
72
101
  ariaLabel,
73
102
  className
74
103
  }) {
75
104
  assertEdgesReferenceKnownNodes(nodes, edges);
76
- const { width, height, positions } = useMemo(
77
- () => layoutNodes(layout, nodes, nodeWidth, nodeHeight),
78
- [layout, nodes, nodeWidth, nodeHeight]
105
+ const markerPrefix = `graph-diagram-${useId().replace(/[^a-zA-Z0-9_-]/g, "")}`;
106
+ const { width, height, positions, groups: groupBoxes } = useMemo(
107
+ () => layoutNodes(nodes, edges, { layout, nodeWidth, nodeHeight, columnGap, rowGap }),
108
+ [layout, nodes, edges, nodeWidth, nodeHeight, columnGap, rowGap]
79
109
  );
80
110
  const routes = useMemo(
81
- () => routeEdges(edges, positions, { nodeWidth, nodeHeight }),
82
- [edges, positions, nodeWidth, nodeHeight]
83
- );
84
- const tones = useMemo(
85
- () => Array.from(new Set(edges.map((edge) => edge.tone ?? "neutral"))),
86
- [edges]
111
+ () => routeEdges(edges, positions, { nodeWidth, nodeHeight }, { anchor: layout === "columns" ? "side" : "center" }),
112
+ [edges, positions, nodeWidth, nodeHeight, layout]
87
113
  );
88
- return /* @__PURE__ */ jsx(
114
+ const panZoom = usePanZoom({
115
+ enabled: zoomable,
116
+ contentWidth: width,
117
+ contentHeight: height,
118
+ opening: openingFit(positions, fitMinScale, focusId)
119
+ });
120
+ const natural = layout === "columns" || zoomable;
121
+ const place = natural ? ({ x, y }) => ({ left: x, top: y }) : ({ x, y }) => ({ left: toPercent(x, width), top: toPercent(y, height) });
122
+ const focus = useEdgeFocus({ mode: edgeFocus, edges, selectedId, selectedEdgeId });
123
+ const edgeSelection = { selectedEdgeId, onEdgeSelect, focus: focus.state };
124
+ return /* @__PURE__ */ jsxs(
89
125
  "div",
90
126
  {
91
- className: cn("w-full overflow-auto", className),
127
+ ref: panZoom.viewportRef,
128
+ className: cn(
129
+ "w-full",
130
+ zoomable ? "relative touch-none overflow-hidden" : "overflow-auto",
131
+ zoomable && (panZoom.panning ? "cursor-grabbing select-none" : "cursor-grab"),
132
+ className
133
+ ),
92
134
  style: maxHeight != null ? { maxHeight } : void 0,
93
- children: /* @__PURE__ */ jsxs("div", { className: "relative w-full", style: { aspectRatio: `${width} / ${height}` }, children: [
135
+ ...panZoom.handlers,
136
+ children: [
94
137
  /* @__PURE__ */ jsxs(
95
- "svg",
138
+ "div",
96
139
  {
97
- viewBox: `0 0 ${width} ${height}`,
98
- preserveAspectRatio: "xMidYMid meet",
99
- role: "img",
100
- "aria-label": ariaLabel,
101
- className: "absolute inset-0 h-full w-full",
140
+ ref: panZoom.contentRef,
141
+ "data-graph-stage": "",
142
+ className: cn("relative", natural ? !zoomable && "mx-auto" : "w-full"),
143
+ style: stageStyle({ width, height }, natural, zoomable ? panZoom : void 0),
102
144
  children: [
103
- /* @__PURE__ */ jsx("defs", { children: tones.map((tone) => /* @__PURE__ */ jsx(
104
- "marker",
145
+ /* @__PURE__ */ jsx(GraphDiagramGroupBoxes, { boxes: groupBoxes, groups }),
146
+ /* @__PURE__ */ jsx(
147
+ GraphDiagramEdgePaths,
105
148
  {
106
- id: `graph-diagram-arrow-${tone}`,
107
- viewBox: "0 0 10 10",
108
- refX: 8,
109
- refY: 5,
110
- markerWidth: 7,
111
- markerHeight: 7,
112
- orient: "auto-start-reverse",
113
- children: /* @__PURE__ */ jsx("path", { d: "M0,0 L10,5 L0,10 z", className: cn(TONE_TEXT_CLASS[tone], "fill-current") })
114
- },
115
- tone
116
- )) }),
117
- edges.map((edge) => {
118
- const tone = edge.tone ?? "neutral";
119
- return /* @__PURE__ */ jsx(
120
- "path",
149
+ edges,
150
+ nodes,
151
+ routes,
152
+ width,
153
+ height,
154
+ ariaLabel,
155
+ markerPrefix,
156
+ onEdgeHover: focus.onEdgeHover,
157
+ ...edgeSelection
158
+ }
159
+ ),
160
+ /* @__PURE__ */ jsxs("div", { className: "pointer-events-none absolute inset-0", children: [
161
+ /* @__PURE__ */ jsx(GraphDiagramEdgeLabels, { edges, routes, place, spread: natural, ...edgeSelection }),
162
+ /* @__PURE__ */ jsx(
163
+ GraphDiagramNodes,
121
164
  {
122
- d: requireRoute(routes, edge.id).path,
123
- fill: "none",
124
- stroke: "currentColor",
125
- strokeWidth: 1.5,
126
- strokeDasharray: edge.dashed ? "5 4" : void 0,
127
- markerEnd: `url(#graph-diagram-arrow-${tone})`,
128
- className: TONE_TEXT_CLASS[tone]
129
- },
130
- edge.id
131
- );
132
- })
165
+ nodes,
166
+ positions,
167
+ place,
168
+ nodeWidth,
169
+ nodeHeight,
170
+ selectedId,
171
+ onNodeSelect,
172
+ onNodeExpand,
173
+ onNodeHover: focus.onNodeHover
174
+ }
175
+ )
176
+ ] })
133
177
  ]
134
178
  }
135
179
  ),
136
- /* @__PURE__ */ jsxs("div", { className: "absolute inset-0", children: [
137
- edges.map((edge) => {
138
- if (!edge.label) return null;
139
- const route = requireRoute(routes, edge.id);
140
- const tone = edge.tone ?? "neutral";
141
- return /* @__PURE__ */ jsx(
142
- "span",
143
- {
144
- className: cn(
145
- "absolute -translate-x-1/2 -translate-y-1/2 whitespace-nowrap rounded-full border border-border bg-background px-1.5 py-0.5 text-[10px] font-medium shadow-sm",
146
- TONE_TEXT_CLASS[tone]
147
- ),
148
- style: { left: toPercent(route.labelX, width), top: toPercent(route.labelY, height) },
149
- children: edge.label
150
- },
151
- `label-${edge.id}`
152
- );
153
- }),
154
- nodes.map((node) => {
155
- const position = requirePosition(positions, node.id);
156
- const selected = selectedId != null && node.id === selectedId;
157
- const tone = node.tone ?? "neutral";
158
- const shapeClass = node.shape === "pill" ? "rounded-full" : "rounded-lg";
159
- const interactive = onNodeSelect != null;
160
- return /* @__PURE__ */ jsxs(
161
- "div",
162
- {
163
- className: cn(
164
- "absolute flex -translate-x-1/2 -translate-y-1/2 flex-col items-center justify-center gap-0.5 border px-3 py-1.5 text-center text-xs shadow-sm",
165
- shapeClass,
166
- TONE_NODE_CLASS[tone],
167
- selected && "ring-2 ring-primary ring-offset-2 ring-offset-background",
168
- interactive && "cursor-pointer"
169
- ),
170
- style: {
171
- left: toPercent(position.x, width),
172
- top: toPercent(position.y, height),
173
- width: nodeWidth,
174
- height: nodeHeight
175
- },
176
- ...interactive ? {
177
- role: "button",
178
- tabIndex: 0,
179
- "aria-pressed": selected,
180
- onClick: () => onNodeSelect(node.id),
181
- onKeyDown: (event) => handleNodeKeyDown(event, () => onNodeSelect(node.id))
182
- } : {},
183
- "aria-label": node.ariaLabel,
184
- children: [
185
- /* @__PURE__ */ jsx("span", { className: "line-clamp-2 font-medium leading-tight", children: node.label }),
186
- node.detail != null && /* @__PURE__ */ jsx("span", { className: "line-clamp-1 text-[10px] leading-tight text-muted-foreground", children: node.detail }),
187
- node.badge != null && /* @__PURE__ */ jsx("span", { className: "mt-0.5", children: node.badge })
188
- ]
189
- },
190
- node.id
191
- );
192
- })
193
- ] })
194
- ] })
180
+ zoomable && /* @__PURE__ */ jsx(ZoomControls, { panZoom, resettable: fitMinScale !== void 0 })
181
+ ]
195
182
  }
196
183
  );
197
184
  }
@@ -1 +1 @@
1
- {"version":3,"file":"GraphDiagram.js","sources":["../../src/data/GraphDiagram.tsx"],"sourcesContent":["import { useMemo, type KeyboardEvent, type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport type { BadgeTone } from \"./Badge\";\nimport { ringLayout, routeEdges, type GraphLayoutPosition } from \"./graph-layout\";\n\n// GraphDiagram renders a generic, type-agnostic node/edge diagram — a small\n// cycle of resources and processes, a dependency graph, any relationship that\n// doesn't read well as a left-to-right column layout because it has back\n// edges or reciprocal pairs. It knows nothing about the domain: a producer\n// maps its data into GraphDiagramNode/GraphDiagramEdge and gets the same\n// ring layout, curved-edge routing, and selection behaviour.\n\nexport interface GraphDiagramNode {\n id: string;\n label: ReactNode;\n detail?: ReactNode;\n badge?: ReactNode;\n tone?: BadgeTone;\n shape?: \"pill\" | \"rect\";\n /** Accessible name for the node, when `label` alone isn't enough. */\n ariaLabel?: string;\n}\n\nexport interface GraphDiagramEdge {\n id: string;\n from: string;\n to: string;\n label?: string;\n tone?: BadgeTone;\n dashed?: boolean;\n}\n\nexport type GraphDiagramLayout = \"ring\";\n\nexport interface GraphDiagramProps {\n nodes: GraphDiagramNode[];\n edges: GraphDiagramEdge[];\n /** Only \"ring\" today; a \"columns\" layout is planned. */\n layout?: GraphDiagramLayout;\n selectedId?: string;\n onNodeSelect?: (id: string) => void;\n nodeWidth?: number;\n nodeHeight?: number;\n maxHeight?: number | string;\n ariaLabel: string;\n className?: string;\n}\n\nconst DEFAULT_NODE_WIDTH = 168;\nconst DEFAULT_NODE_HEIGHT = 60;\n\nconst TONE_TEXT_CLASS: Record<BadgeTone, string> = {\n neutral: \"text-muted-foreground\",\n success: \"text-emerald-600 dark:text-emerald-400\",\n danger: \"text-red-600 dark:text-red-400\",\n warning: \"text-amber-600 dark:text-amber-400\",\n info: \"text-sky-600 dark:text-sky-400\",\n};\n\nconst TONE_NODE_CLASS: Record<BadgeTone, string> = {\n neutral: \"border-border bg-card text-foreground\",\n success: \"border-emerald-500/50 bg-emerald-500/10 text-foreground\",\n danger: \"border-red-500/50 bg-red-500/10 text-foreground\",\n warning: \"border-amber-500/50 bg-amber-500/10 text-foreground\",\n info: \"border-sky-500/50 bg-sky-500/10 text-foreground\",\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 layoutNodes(\n layout: GraphDiagramLayout,\n nodes: GraphDiagramNode[],\n nodeWidth: number,\n nodeHeight: number,\n): { width: number; height: number; positions: Record<string, GraphLayoutPosition> } {\n switch (layout) {\n case \"ring\":\n return ringLayout(nodes, { nodeWidth, nodeHeight });\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 requireRoute<T>(routes: Record<string, T>, edgeId: string): T {\n const route = routes[edgeId];\n if (!route) {\n throw new Error(`GraphDiagram: no route computed for edge \"${edgeId}\"`);\n }\n return route;\n}\n\nfunction requirePosition(\n positions: Record<string, GraphLayoutPosition>,\n nodeId: string,\n): GraphLayoutPosition {\n const position = positions[nodeId];\n if (!position) {\n throw new Error(`GraphDiagram: no layout position computed for node \"${nodeId}\"`);\n }\n return position;\n}\n\nfunction handleNodeKeyDown(event: KeyboardEvent<HTMLDivElement>, select: () => void): void {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n select();\n }\n}\n\nexport function GraphDiagram({\n nodes,\n edges,\n layout = \"ring\",\n selectedId,\n onNodeSelect,\n nodeWidth = DEFAULT_NODE_WIDTH,\n nodeHeight = DEFAULT_NODE_HEIGHT,\n maxHeight,\n ariaLabel,\n className,\n}: GraphDiagramProps) {\n assertEdgesReferenceKnownNodes(nodes, edges);\n\n const { width, height, positions } = useMemo(\n () => layoutNodes(layout, nodes, nodeWidth, nodeHeight),\n [layout, nodes, nodeWidth, nodeHeight],\n );\n\n const routes = useMemo(\n () => routeEdges(edges, positions, { nodeWidth, nodeHeight }),\n [edges, positions, nodeWidth, nodeHeight],\n );\n\n const tones = useMemo(\n () => Array.from(new Set(edges.map((edge) => edge.tone ?? \"neutral\"))),\n [edges],\n );\n\n return (\n <div\n className={cn(\"w-full overflow-auto\", className)}\n style={maxHeight != null ? { maxHeight } : undefined}\n >\n <div className=\"relative w-full\" style={{ aspectRatio: `${width} / ${height}` }}>\n <svg\n viewBox={`0 0 ${width} ${height}`}\n preserveAspectRatio=\"xMidYMid meet\"\n role=\"img\"\n aria-label={ariaLabel}\n className=\"absolute inset-0 h-full w-full\"\n >\n <defs>\n {tones.map((tone) => (\n <marker\n key={tone}\n id={`graph-diagram-arrow-${tone}`}\n viewBox=\"0 0 10 10\"\n refX={8}\n refY={5}\n markerWidth={7}\n markerHeight={7}\n orient=\"auto-start-reverse\"\n >\n <path d=\"M0,0 L10,5 L0,10 z\" className={cn(TONE_TEXT_CLASS[tone], \"fill-current\")} />\n </marker>\n ))}\n </defs>\n {edges.map((edge) => {\n const tone = edge.tone ?? \"neutral\";\n return (\n <path\n key={edge.id}\n d={requireRoute(routes, edge.id).path}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={1.5}\n strokeDasharray={edge.dashed ? \"5 4\" : undefined}\n markerEnd={`url(#graph-diagram-arrow-${tone})`}\n className={TONE_TEXT_CLASS[tone]}\n />\n );\n })}\n </svg>\n\n <div className=\"absolute inset-0\">\n {edges.map((edge) => {\n if (!edge.label) return null;\n const route = requireRoute(routes, edge.id);\n const tone = edge.tone ?? \"neutral\";\n return (\n <span\n key={`label-${edge.id}`}\n className={cn(\n \"absolute -translate-x-1/2 -translate-y-1/2 whitespace-nowrap rounded-full border border-border bg-background px-1.5 py-0.5 text-[10px] font-medium shadow-sm\",\n TONE_TEXT_CLASS[tone],\n )}\n style={{ left: toPercent(route.labelX, width), top: toPercent(route.labelY, height) }}\n >\n {edge.label}\n </span>\n );\n })}\n\n {nodes.map((node) => {\n const position = requirePosition(positions, node.id);\n const selected = selectedId != null && node.id === selectedId;\n const tone = node.tone ?? \"neutral\";\n const shapeClass = node.shape === \"pill\" ? \"rounded-full\" : \"rounded-lg\";\n const interactive = onNodeSelect != null;\n\n return (\n <div\n key={node.id}\n className={cn(\n \"absolute flex -translate-x-1/2 -translate-y-1/2 flex-col items-center justify-center gap-0.5 border px-3 py-1.5 text-center text-xs shadow-sm\",\n shapeClass,\n TONE_NODE_CLASS[tone],\n selected && \"ring-2 ring-primary ring-offset-2 ring-offset-background\",\n interactive && \"cursor-pointer\",\n )}\n style={{\n left: toPercent(position.x, width),\n top: toPercent(position.y, height),\n width: nodeWidth,\n height: nodeHeight,\n }}\n {...(interactive\n ? {\n role: \"button\" as const,\n tabIndex: 0,\n \"aria-pressed\": selected,\n onClick: () => onNodeSelect(node.id),\n onKeyDown: (event: KeyboardEvent<HTMLDivElement>) =>\n handleNodeKeyDown(event, () => onNodeSelect(node.id)),\n }\n : {})}\n aria-label={node.ariaLabel}\n >\n <span className=\"line-clamp-2 font-medium leading-tight\">{node.label}</span>\n {node.detail != null && (\n <span className=\"line-clamp-1 text-[10px] leading-tight text-muted-foreground\">\n {node.detail}\n </span>\n )}\n {node.badge != null && <span className=\"mt-0.5\">{node.badge}</span>}\n </div>\n );\n })}\n </div>\n </div>\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"GraphDiagram.js","sources":["../../src/data/GraphDiagram.tsx"],"sourcesContent":["import { useId, useMemo, type CSSProperties } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { IconButton } from \"../components/IconButton\";\nimport { UiFullscreen, UiHome, UiZoomIn, UiZoomOut } from \"../icons\";\nimport { columnsLayout, type ColumnsLayoutResult } from \"./graph-columns-layout\";\nimport { ringLayout, routeEdges, type GraphLayoutPosition } from \"./graph-layout\";\nimport { GraphDiagramEdgeLabels, GraphDiagramEdgePaths } from \"./GraphDiagramEdges\";\nimport { GraphDiagramGroupBoxes, 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":[],"mappings":"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"}
@@ -0,0 +1,208 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const jsxRuntime = require("react/jsx-runtime");
4
+ const utils = require("../lib/utils.cjs");
5
+ const graphEdgeRouting = require("./graph-edge-routing.cjs");
6
+ const graphDiagramModel = require("./graph-diagram-model.cjs");
7
+ const ARROW_SIZE = 10.5;
8
+ const EDGE_STROKE = 1.5;
9
+ const SELECTED_EDGE_STROKE = 2.75;
10
+ const HIT_STROKE = 14;
11
+ function EdgePath({
12
+ edge,
13
+ d,
14
+ markerId,
15
+ name,
16
+ selected,
17
+ dimmed,
18
+ onSelect,
19
+ onHover
20
+ }) {
21
+ return /* @__PURE__ */ jsxRuntime.jsxs(
22
+ "g",
23
+ {
24
+ "data-graph-edge": edge.id,
25
+ className: utils.cn("transition-opacity", dimmed && "opacity-20"),
26
+ ...dimmed ? { "data-graph-edge-dimmed": "" } : {},
27
+ ...onHover ? graphDiagramModel.hoverHandlers(edge.id, onHover) : {},
28
+ children: [
29
+ edge.title !== void 0 && /* @__PURE__ */ jsxRuntime.jsx("title", { children: edge.title }),
30
+ /* @__PURE__ */ jsxRuntime.jsx(
31
+ "path",
32
+ {
33
+ d,
34
+ fill: "none",
35
+ stroke: "currentColor",
36
+ strokeWidth: selected ? SELECTED_EDGE_STROKE : EDGE_STROKE,
37
+ strokeDasharray: edge.dashed ? "5 4" : void 0,
38
+ pointerEvents: "visibleStroke",
39
+ markerEnd: `url(#${markerId})`,
40
+ className: graphDiagramModel.TONE_TEXT_CLASS[edge.tone ?? "neutral"]
41
+ }
42
+ ),
43
+ onSelect && /* @__PURE__ */ jsxRuntime.jsx(
44
+ "path",
45
+ {
46
+ d,
47
+ fill: "none",
48
+ stroke: "transparent",
49
+ strokeWidth: HIT_STROKE,
50
+ strokeLinecap: "round",
51
+ pointerEvents: "stroke",
52
+ role: "button",
53
+ tabIndex: 0,
54
+ "aria-label": name,
55
+ "aria-pressed": selected,
56
+ className: utils.cn(
57
+ "cursor-pointer outline-none hover:stroke-primary/15 focus-visible:stroke-primary/30",
58
+ selected && "stroke-primary/15"
59
+ ),
60
+ onClick: onSelect,
61
+ onKeyDown: (event) => graphDiagramModel.activateOnKey(event, onSelect)
62
+ }
63
+ )
64
+ ]
65
+ }
66
+ );
67
+ }
68
+ function GraphDiagramEdgePaths({
69
+ edges,
70
+ nodes,
71
+ routes,
72
+ width,
73
+ height,
74
+ ariaLabel,
75
+ markerPrefix,
76
+ selectedEdgeId,
77
+ onEdgeSelect,
78
+ focus,
79
+ onEdgeHover
80
+ }) {
81
+ const tones = Array.from(new Set(edges.map((edge) => edge.tone ?? "neutral")));
82
+ const names = Object.fromEntries(nodes.map((node) => [node.id, graphDiagramModel.nodeName(node)]));
83
+ return /* @__PURE__ */ jsxRuntime.jsxs(
84
+ "svg",
85
+ {
86
+ viewBox: `0 0 ${width} ${height}`,
87
+ preserveAspectRatio: "xMidYMid meet",
88
+ role: onEdgeSelect ? "group" : "img",
89
+ "aria-label": ariaLabel,
90
+ className: "pointer-events-none absolute inset-0 h-full w-full",
91
+ children: [
92
+ /* @__PURE__ */ jsxRuntime.jsx("defs", { children: tones.map((tone) => /* @__PURE__ */ jsxRuntime.jsx(
93
+ "marker",
94
+ {
95
+ id: `${markerPrefix}-arrow-${tone}`,
96
+ viewBox: "0 0 10 10",
97
+ refX: 8,
98
+ refY: 5,
99
+ markerUnits: "userSpaceOnUse",
100
+ markerWidth: ARROW_SIZE,
101
+ markerHeight: ARROW_SIZE,
102
+ orient: "auto-start-reverse",
103
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M0,0 L10,5 L0,10 z", className: utils.cn(graphDiagramModel.TONE_TEXT_CLASS[tone], "fill-current") })
104
+ },
105
+ tone
106
+ )) }),
107
+ edges.map((edge) => /* @__PURE__ */ jsxRuntime.jsx(
108
+ EdgePath,
109
+ {
110
+ edge,
111
+ d: graphDiagramModel.requireEntry(routes, edge.id, "route").path,
112
+ markerId: `${markerPrefix}-arrow-${edge.tone ?? "neutral"}`,
113
+ name: graphDiagramModel.edgeName(edge, names),
114
+ selected: edge.id === selectedEdgeId,
115
+ dimmed: focus !== void 0 && focus.focused.size > 0 && !focus.focused.has(edge.id),
116
+ onSelect: onEdgeSelect ? () => onEdgeSelect(edge.id) : void 0,
117
+ onHover: onEdgeHover
118
+ },
119
+ edge.id
120
+ ))
121
+ ]
122
+ }
123
+ );
124
+ }
125
+ const LABEL_HEIGHT = 19;
126
+ const LABEL_LOOP_GAP = 6;
127
+ const FOCUS_LABEL_T = 0.65;
128
+ const LABEL_NODE_GAP = 4;
129
+ const ANCHOR_CLASS = {
130
+ start: "translate-x-1.5",
131
+ end: "-translate-x-[calc(100%+0.375rem)]",
132
+ center: "-translate-x-1/2"
133
+ };
134
+ function hasPill(edge) {
135
+ return Boolean(edge.label) || edge.icon != null;
136
+ }
137
+ function labelPoint(edge, route, focus) {
138
+ const middle = { x: route.labelX, y: route.labelY };
139
+ if (!route.curve || !focus || focus.nodes.has(edge.from) === focus.nodes.has(edge.to)) return middle;
140
+ const point = graphEdgeRouting.pointOnCurve(route.curve, focus.nodes.has(edge.from) ? FOCUS_LABEL_T : 1 - FOCUS_LABEL_T);
141
+ const reserved = graphDiagramModel.edgeLabelWidth(edge) / 2 + LABEL_NODE_GAP;
142
+ const left = Math.min(route.curve[0].x, route.curve[3].x) + reserved;
143
+ const right = Math.max(route.curve[0].x, route.curve[3].x) - reserved;
144
+ return left > right ? { x: middle.x, y: point.y } : { x: Math.min(right, Math.max(left, point.x)), y: point.y };
145
+ }
146
+ function labelYs(edges, routes, points) {
147
+ return graphEdgeRouting.spreadLabels(
148
+ edges.map((edge) => {
149
+ const { labelAnchor } = graphDiagramModel.requireEntry(routes, edge.id, "route");
150
+ const point = graphDiagramModel.requireEntry(points, edge.id, "label point");
151
+ const outside = labelAnchor === void 0 ? 0 : labelAnchor === "start" ? LABEL_LOOP_GAP : -LABEL_LOOP_GAP;
152
+ return {
153
+ id: edge.id,
154
+ x: point.x + outside,
155
+ y: point.y,
156
+ width: graphDiagramModel.edgeLabelWidth(edge),
157
+ height: LABEL_HEIGHT,
158
+ ...labelAnchor ? { anchor: labelAnchor } : {}
159
+ };
160
+ })
161
+ );
162
+ }
163
+ function GraphDiagramEdgeLabels({
164
+ edges,
165
+ routes,
166
+ place,
167
+ spread,
168
+ selectedEdgeId,
169
+ onEdgeSelect,
170
+ focus
171
+ }) {
172
+ const labelled = edges.filter((edge) => hasPill(edge) && (!focus || focus.focused.has(edge.id)));
173
+ const points = Object.fromEntries(
174
+ labelled.map((edge) => [edge.id, labelPoint(edge, graphDiagramModel.requireEntry(routes, edge.id, "route"), focus)])
175
+ );
176
+ const ys = spread ? labelYs(labelled, routes, points) : void 0;
177
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: labelled.map((edge) => {
178
+ const route = graphDiagramModel.requireEntry(routes, edge.id, "route");
179
+ const point = graphDiagramModel.requireEntry(points, edge.id, "label point");
180
+ return /* @__PURE__ */ jsxRuntime.jsxs(
181
+ "span",
182
+ {
183
+ "data-graph-edge-label": edge.id,
184
+ title: edge.title,
185
+ className: utils.cn(
186
+ "absolute -translate-y-1/2 whitespace-nowrap rounded-full border border-border bg-background px-1.5 py-0.5 text-[10px] font-medium shadow-sm",
187
+ // A pill that only hover put there would take the pointer off what is hovered, and flicker.
188
+ focus && !focus.pinned.has(edge.id) ? "pointer-events-none" : "pointer-events-auto",
189
+ edge.icon != null && "flex items-center gap-1",
190
+ ANCHOR_CLASS[route.labelAnchor ?? "center"],
191
+ graphDiagramModel.TONE_TEXT_CLASS[edge.tone ?? "neutral"],
192
+ onEdgeSelect && "cursor-pointer hover:bg-accent",
193
+ edge.id === selectedEdgeId && "border-primary ring-2 ring-primary/40"
194
+ ),
195
+ style: place({ x: point.x, y: ys ? graphDiagramModel.requireEntry(ys, edge.id, "label position") : point.y }),
196
+ ...onEdgeSelect ? { "aria-hidden": true, onClick: () => onEdgeSelect(edge.id) } : {},
197
+ children: [
198
+ edge.icon != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex shrink-0 text-sm leading-none", children: edge.icon }),
199
+ edge.label
200
+ ]
201
+ },
202
+ `label-${edge.id}`
203
+ );
204
+ }) });
205
+ }
206
+ exports.GraphDiagramEdgeLabels = GraphDiagramEdgeLabels;
207
+ exports.GraphDiagramEdgePaths = GraphDiagramEdgePaths;
208
+ //# sourceMappingURL=GraphDiagramEdges.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GraphDiagramEdges.cjs","sources":["../../src/data/GraphDiagramEdges.tsx"],"sourcesContent":["import { cn } from \"../lib/utils\";\nimport { pointOnCurve, spreadLabels, type EdgeRoute } from \"./graph-edge-routing\";\nimport type { GraphLayoutPosition } from \"./graph-layout\";\nimport type { EdgeFocusState } from \"./use-edge-focus\";\nimport {\n activateOnKey,\n edgeLabelWidth,\n edgeName,\n hoverHandlers,\n nodeName,\n requireEntry,\n TONE_TEXT_CLASS,\n type GraphDiagramEdge,\n type GraphDiagramNode,\n type GraphPlacer,\n} from \"./graph-diagram-model\";\n\n// Arrowhead size in layout px. Fixed (userSpaceOnUse) so a thicker, selected\n// edge does not also grow its arrowhead.\nconst ARROW_SIZE = 10.5;\nconst EDGE_STROKE = 1.5;\nconst SELECTED_EDGE_STROKE = 2.75;\nconst HIT_STROKE = 14;\n\ninterface EdgeSelection {\n selectedEdgeId: string | undefined;\n onEdgeSelect: ((id: string) => void) | undefined;\n /** Set when the diagram is focused: see `GraphDiagramEdgeFocus`. */\n focus: EdgeFocusState | undefined;\n}\n\nexport interface GraphDiagramEdgePathsProps extends EdgeSelection {\n edges: GraphDiagramEdge[];\n nodes: GraphDiagramNode[];\n routes: Record<string, EdgeRoute>;\n width: number;\n height: number;\n ariaLabel: string;\n /** Unique per diagram instance, so two diagrams on a page never share marker ids. */\n markerPrefix: string;\n onEdgeHover: ((id: string | undefined) => void) | undefined;\n}\n\nfunction EdgePath({\n edge,\n d,\n markerId,\n name,\n selected,\n dimmed,\n onSelect,\n onHover,\n}: {\n edge: GraphDiagramEdge;\n d: string;\n markerId: string;\n name: string;\n selected: boolean;\n /** Out of focus while another edge is in it. */\n dimmed: boolean;\n onSelect: (() => void) | undefined;\n onHover: ((id: string | undefined) => void) | undefined;\n}) {\n return (\n <g\n data-graph-edge={edge.id}\n className={cn(\"transition-opacity\", dimmed && \"opacity-20\")}\n {...(dimmed ? { \"data-graph-edge-dimmed\": \"\" } : {})}\n {...(onHover ? hoverHandlers(edge.id, onHover) : {})}\n >\n {edge.title !== undefined && <title>{edge.title}</title>}\n <path\n d={d}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={selected ? SELECTED_EDGE_STROKE : EDGE_STROKE}\n strokeDasharray={edge.dashed ? \"5 4\" : undefined}\n pointerEvents=\"visibleStroke\"\n markerEnd={`url(#${markerId})`}\n className={TONE_TEXT_CLASS[edge.tone ?? \"neutral\"]}\n />\n {onSelect && (\n <path\n d={d}\n fill=\"none\"\n stroke=\"transparent\"\n strokeWidth={HIT_STROKE}\n strokeLinecap=\"round\"\n pointerEvents=\"stroke\"\n role=\"button\"\n tabIndex={0}\n aria-label={name}\n aria-pressed={selected}\n className={cn(\n \"cursor-pointer outline-none hover:stroke-primary/15 focus-visible:stroke-primary/30\",\n selected && \"stroke-primary/15\",\n )}\n onClick={onSelect}\n onKeyDown={(event) => activateOnKey(event, onSelect)}\n />\n )}\n </g>\n );\n}\n\nexport function GraphDiagramEdgePaths({\n edges,\n nodes,\n routes,\n width,\n height,\n ariaLabel,\n markerPrefix,\n selectedEdgeId,\n onEdgeSelect,\n focus,\n onEdgeHover,\n}: GraphDiagramEdgePathsProps) {\n const tones = Array.from(new Set(edges.map((edge) => edge.tone ?? \"neutral\")));\n const names = Object.fromEntries(nodes.map((node) => [node.id, nodeName(node)]));\n\n // The layer covers the whole stage, so it lets the pointer through: only an edge's own stroke\n // takes it, and the group captions under the layer keep their tooltips.\n return (\n <svg\n viewBox={`0 0 ${width} ${height}`}\n preserveAspectRatio=\"xMidYMid meet\"\n role={onEdgeSelect ? \"group\" : \"img\"}\n aria-label={ariaLabel}\n className=\"pointer-events-none absolute inset-0 h-full w-full\"\n >\n <defs>\n {tones.map((tone) => (\n <marker\n key={tone}\n id={`${markerPrefix}-arrow-${tone}`}\n viewBox=\"0 0 10 10\"\n refX={8}\n refY={5}\n markerUnits=\"userSpaceOnUse\"\n markerWidth={ARROW_SIZE}\n markerHeight={ARROW_SIZE}\n orient=\"auto-start-reverse\"\n >\n <path d=\"M0,0 L10,5 L0,10 z\" className={cn(TONE_TEXT_CLASS[tone], \"fill-current\")} />\n </marker>\n ))}\n </defs>\n {edges.map((edge) => (\n <EdgePath\n key={edge.id}\n edge={edge}\n d={requireEntry(routes, edge.id, \"route\").path}\n markerId={`${markerPrefix}-arrow-${edge.tone ?? \"neutral\"}`}\n name={edgeName(edge, names)}\n selected={edge.id === selectedEdgeId}\n dimmed={focus !== undefined && focus.focused.size > 0 && !focus.focused.has(edge.id)}\n onSelect={onEdgeSelect ? () => onEdgeSelect(edge.id) : undefined}\n onHover={onEdgeHover}\n />\n ))}\n </svg>\n );\n}\n\nexport interface GraphDiagramEdgeLabelsProps extends EdgeSelection {\n edges: GraphDiagramEdge[];\n routes: Record<string, EdgeRoute>;\n place: GraphPlacer;\n /**\n * Move pills that would cover one another apart. Only meaningful when the\n * stage is drawn at its natural size, where a pill's px size and the layout\n * share one coordinate system.\n */\n spread: boolean;\n}\n\nconst LABEL_HEIGHT = 19;\n/** A loop's pill sits this far outside its point (the `translate-x` classes below). */\nconst LABEL_LOOP_GAP = 6;\n/** How far along its edge, from the node in focus, a pill sits: past the middle, where a fan has spread out. */\nconst FOCUS_LABEL_T = 0.65;\n/** Air kept between a slid pill and the nodes at either end of its edge. */\nconst LABEL_NODE_GAP = 4;\n\nconst ANCHOR_CLASS = {\n start: \"translate-x-1.5\",\n end: \"-translate-x-[calc(100%+0.375rem)]\",\n center: \"-translate-x-1/2\",\n} as const;\n\nfunction hasPill(edge: GraphDiagramEdge): boolean {\n return Boolean(edge.label) || edge.icon != null;\n}\n\n/**\n * Where an edge's pill is centred: the route's midpoint, unless exactly one\n * end of the edge is a node in focus. Then every pill of that node would sit\n * in one stack beside it, so each moves toward its own far end, kept between\n * the two nodes.\n */\nfunction labelPoint(edge: GraphDiagramEdge, route: EdgeRoute, focus: EdgeFocusState | undefined): GraphLayoutPosition {\n const middle = { x: route.labelX, y: route.labelY };\n if (!route.curve || !focus || focus.nodes.has(edge.from) === focus.nodes.has(edge.to)) return middle;\n const point = pointOnCurve(route.curve, focus.nodes.has(edge.from) ? FOCUS_LABEL_T : 1 - FOCUS_LABEL_T);\n const reserved = edgeLabelWidth(edge) / 2 + LABEL_NODE_GAP;\n const left = Math.min(route.curve[0].x, route.curve[3].x) + reserved;\n const right = Math.max(route.curve[0].x, route.curve[3].x) - reserved;\n return left > right ? { x: middle.x, y: point.y } : { x: Math.min(right, Math.max(left, point.x)), y: point.y };\n}\n\nfunction labelYs(\n edges: GraphDiagramEdge[],\n routes: Record<string, EdgeRoute>,\n points: Record<string, GraphLayoutPosition>,\n): Record<string, number> {\n return spreadLabels(\n edges.map((edge) => {\n const { labelAnchor } = requireEntry(routes, edge.id, \"route\");\n const point = requireEntry(points, edge.id, \"label point\");\n const outside = labelAnchor === undefined ? 0 : labelAnchor === \"start\" ? LABEL_LOOP_GAP : -LABEL_LOOP_GAP;\n return {\n id: edge.id,\n x: point.x + outside,\n y: point.y,\n width: edgeLabelWidth(edge),\n height: LABEL_HEIGHT,\n ...(labelAnchor ? { anchor: labelAnchor } : {}),\n };\n }),\n );\n}\n\n/**\n * The label pills, drawn as HTML over the edges. With `onEdgeSelect` a pill is\n * a pointer shortcut for its edge; the edge's own path stays the one\n * keyboard and screen-reader target, so the pill is hidden from both.\n */\nexport function GraphDiagramEdgeLabels({\n edges,\n routes,\n place,\n spread,\n selectedEdgeId,\n onEdgeSelect,\n focus,\n}: GraphDiagramEdgeLabelsProps) {\n const labelled = edges.filter((edge) => hasPill(edge) && (!focus || focus.focused.has(edge.id)));\n const points = Object.fromEntries(\n labelled.map((edge) => [edge.id, labelPoint(edge, requireEntry(routes, edge.id, \"route\"), focus)]),\n );\n const ys = spread ? labelYs(labelled, routes, points) : undefined;\n return (\n <>\n {labelled.map((edge) => {\n const route = requireEntry(routes, edge.id, \"route\");\n const point = requireEntry(points, edge.id, \"label point\");\n return (\n <span\n key={`label-${edge.id}`}\n data-graph-edge-label={edge.id}\n title={edge.title}\n className={cn(\n \"absolute -translate-y-1/2 whitespace-nowrap rounded-full border border-border bg-background px-1.5 py-0.5 text-[10px] font-medium shadow-sm\",\n // A pill that only hover put there would take the pointer off what is hovered, and flicker.\n focus && !focus.pinned.has(edge.id) ? \"pointer-events-none\" : \"pointer-events-auto\",\n edge.icon != null && \"flex items-center gap-1\",\n ANCHOR_CLASS[route.labelAnchor ?? \"center\"],\n TONE_TEXT_CLASS[edge.tone ?? \"neutral\"],\n onEdgeSelect && \"cursor-pointer hover:bg-accent\",\n edge.id === selectedEdgeId && \"border-primary ring-2 ring-primary/40\",\n )}\n style={place({ x: point.x, y: ys ? requireEntry(ys, edge.id, \"label position\") : point.y })}\n {...(onEdgeSelect\n ? { \"aria-hidden\": true, onClick: () => onEdgeSelect(edge.id) }\n : {})}\n >\n {edge.icon != null && <span className=\"flex shrink-0 text-sm leading-none\">{edge.icon}</span>}\n {edge.label}\n </span>\n );\n })}\n </>\n );\n}\n"],"names":["jsxs","cn","hoverHandlers","jsx","TONE_TEXT_CLASS","activateOnKey","nodeName","requireEntry","edgeName","pointOnCurve","edgeLabelWidth","spreadLabels","Fragment"],"mappings":"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"}