@joewinke/jatui 0.37.0 → 0.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (266) hide show
  1. package/dist/artifact-blocks/AttachmentChip.svelte +66 -0
  2. package/dist/artifact-blocks/AttachmentChip.svelte.d.ts +7 -0
  3. package/dist/artifact-blocks/BlockComments.svelte +309 -0
  4. package/dist/artifact-blocks/BlockComments.svelte.d.ts +33 -0
  5. package/dist/artifact-blocks/BlockRenderer.svelte +674 -0
  6. package/dist/artifact-blocks/BlockRenderer.svelte.d.ts +55 -0
  7. package/dist/artifact-blocks/BlockVerdict.svelte +151 -0
  8. package/dist/artifact-blocks/BlockVerdict.svelte.d.ts +13 -0
  9. package/dist/artifact-blocks/BlocksArtifactView.svelte +1616 -0
  10. package/dist/artifact-blocks/BlocksArtifactView.svelte.d.ts +113 -0
  11. package/dist/artifact-blocks/CONTRACT.md +225 -0
  12. package/dist/artifact-blocks/CommentPill.svelte +49 -0
  13. package/dist/artifact-blocks/CommentPill.svelte.d.ts +16 -0
  14. package/dist/artifact-blocks/FoldedRounds.svelte +95 -0
  15. package/dist/artifact-blocks/FoldedRounds.svelte.d.ts +9 -0
  16. package/dist/artifact-blocks/Glyph.svelte +54 -0
  17. package/dist/artifact-blocks/Glyph.svelte.d.ts +10 -0
  18. package/dist/artifact-blocks/HistoryScrubber.svelte +500 -0
  19. package/dist/artifact-blocks/HistoryScrubber.svelte.d.ts +15 -0
  20. package/dist/artifact-blocks/Markdown.svelte +186 -0
  21. package/dist/artifact-blocks/Markdown.svelte.d.ts +30 -0
  22. package/dist/artifact-blocks/NoteComposer.svelte +31 -0
  23. package/dist/artifact-blocks/NoteComposer.svelte.d.ts +8 -0
  24. package/dist/artifact-blocks/PlainComposer.svelte +200 -0
  25. package/dist/artifact-blocks/PlainComposer.svelte.d.ts +15 -0
  26. package/dist/artifact-blocks/SectionTools.svelte +102 -0
  27. package/dist/artifact-blocks/SectionTools.svelte.d.ts +19 -0
  28. package/dist/artifact-blocks/adapter.d.ts +13 -0
  29. package/dist/artifact-blocks/adapter.js +31 -0
  30. package/dist/artifact-blocks/autoSend.d.ts +49 -0
  31. package/dist/artifact-blocks/autoSend.js +103 -0
  32. package/dist/artifact-blocks/blocks/actions/ActionsBlock.svelte +557 -0
  33. package/dist/artifact-blocks/blocks/actions/ActionsBlock.svelte.d.ts +48 -0
  34. package/dist/artifact-blocks/blocks/actions/block.d.ts +8 -0
  35. package/dist/artifact-blocks/blocks/actions/block.js +74 -0
  36. package/dist/artifact-blocks/blocks/actions/requests.d.ts +62 -0
  37. package/dist/artifact-blocks/blocks/actions/requests.js +26 -0
  38. package/dist/artifact-blocks/blocks/actions/schema.d.ts +168 -0
  39. package/dist/artifact-blocks/blocks/actions/schema.js +253 -0
  40. package/dist/artifact-blocks/blocks/callout/CalloutBlock.svelte +779 -0
  41. package/dist/artifact-blocks/blocks/callout/CalloutBlock.svelte.d.ts +40 -0
  42. package/dist/artifact-blocks/blocks/callout/block.d.ts +7 -0
  43. package/dist/artifact-blocks/blocks/callout/block.js +39 -0
  44. package/dist/artifact-blocks/blocks/callout/schema.d.ts +72 -0
  45. package/dist/artifact-blocks/blocks/callout/schema.js +115 -0
  46. package/dist/artifact-blocks/blocks/chart/ChartBlock.svelte +875 -0
  47. package/dist/artifact-blocks/blocks/chart/ChartBlock.svelte.d.ts +59 -0
  48. package/dist/artifact-blocks/blocks/chart/block.d.ts +9 -0
  49. package/dist/artifact-blocks/blocks/chart/block.js +70 -0
  50. package/dist/artifact-blocks/blocks/chart/schema.d.ts +171 -0
  51. package/dist/artifact-blocks/blocks/chart/schema.js +498 -0
  52. package/dist/artifact-blocks/blocks/chart/thumb.d.ts +2 -0
  53. package/dist/artifact-blocks/blocks/chart/thumb.js +201 -0
  54. package/dist/artifact-blocks/blocks/checklist/ChecklistBlock.svelte +1048 -0
  55. package/dist/artifact-blocks/blocks/checklist/ChecklistBlock.svelte.d.ts +16 -0
  56. package/dist/artifact-blocks/blocks/checklist/Icon.svelte +105 -0
  57. package/dist/artifact-blocks/blocks/checklist/Icon.svelte.d.ts +17 -0
  58. package/dist/artifact-blocks/blocks/checklist/block.d.ts +10 -0
  59. package/dist/artifact-blocks/blocks/checklist/block.js +63 -0
  60. package/dist/artifact-blocks/blocks/checklist/itemReview.d.ts +16 -0
  61. package/dist/artifact-blocks/blocks/checklist/itemReview.js +63 -0
  62. package/dist/artifact-blocks/blocks/checklist/labels.d.ts +62 -0
  63. package/dist/artifact-blocks/blocks/checklist/labels.js +96 -0
  64. package/dist/artifact-blocks/blocks/checklist/retest.d.ts +43 -0
  65. package/dist/artifact-blocks/blocks/checklist/retest.js +68 -0
  66. package/dist/artifact-blocks/blocks/checklist/schema.d.ts +84 -0
  67. package/dist/artifact-blocks/blocks/checklist/schema.js +91 -0
  68. package/dist/artifact-blocks/blocks/code/CodeBlock.svelte +128 -0
  69. package/dist/artifact-blocks/blocks/code/CodeBlock.svelte.d.ts +12 -0
  70. package/dist/artifact-blocks/blocks/code/block.d.ts +8 -0
  71. package/dist/artifact-blocks/blocks/code/block.js +31 -0
  72. package/dist/artifact-blocks/blocks/code/highlight.d.ts +34 -0
  73. package/dist/artifact-blocks/blocks/code/highlight.js +280 -0
  74. package/dist/artifact-blocks/blocks/code/schema.d.ts +32 -0
  75. package/dist/artifact-blocks/blocks/code/schema.js +39 -0
  76. package/dist/artifact-blocks/blocks/collage/CollageBlock.svelte +290 -0
  77. package/dist/artifact-blocks/blocks/collage/CollageBlock.svelte.d.ts +29 -0
  78. package/dist/artifact-blocks/blocks/collage/block.d.ts +9 -0
  79. package/dist/artifact-blocks/blocks/collage/block.js +29 -0
  80. package/dist/artifact-blocks/blocks/collage/schema.d.ts +52 -0
  81. package/dist/artifact-blocks/blocks/collage/schema.js +86 -0
  82. package/dist/artifact-blocks/blocks/compare/CompareBlock.svelte +484 -0
  83. package/dist/artifact-blocks/blocks/compare/CompareBlock.svelte.d.ts +25 -0
  84. package/dist/artifact-blocks/blocks/compare/block.d.ts +9 -0
  85. package/dist/artifact-blocks/blocks/compare/block.js +32 -0
  86. package/dist/artifact-blocks/blocks/compare/schema.d.ts +74 -0
  87. package/dist/artifact-blocks/blocks/compare/schema.js +148 -0
  88. package/dist/artifact-blocks/blocks/diagram/DiagramBlock.svelte +392 -0
  89. package/dist/artifact-blocks/blocks/diagram/DiagramBlock.svelte.d.ts +30 -0
  90. package/dist/artifact-blocks/blocks/diagram/block.d.ts +9 -0
  91. package/dist/artifact-blocks/blocks/diagram/block.js +50 -0
  92. package/dist/artifact-blocks/blocks/diagram/constants.d.ts +48 -0
  93. package/dist/artifact-blocks/blocks/diagram/constants.js +53 -0
  94. package/dist/artifact-blocks/blocks/diagram/schema.d.ts +161 -0
  95. package/dist/artifact-blocks/blocks/diagram/schema.js +621 -0
  96. package/dist/artifact-blocks/blocks/diagram/thumb.d.ts +2 -0
  97. package/dist/artifact-blocks/blocks/diagram/thumb.js +157 -0
  98. package/dist/artifact-blocks/blocks/diagram/types.d.ts +74 -0
  99. package/dist/artifact-blocks/blocks/diagram/types.js +1 -0
  100. package/dist/artifact-blocks/blocks/diff/DiffBlock.svelte +81 -0
  101. package/dist/artifact-blocks/blocks/diff/DiffBlock.svelte.d.ts +10 -0
  102. package/dist/artifact-blocks/blocks/diff/block.d.ts +7 -0
  103. package/dist/artifact-blocks/blocks/diff/block.js +36 -0
  104. package/dist/artifact-blocks/blocks/diff/schema.d.ts +18 -0
  105. package/dist/artifact-blocks/blocks/diff/schema.js +35 -0
  106. package/dist/artifact-blocks/blocks/diff-review/DiffReviewBlock.svelte +1055 -0
  107. package/dist/artifact-blocks/blocks/diff-review/DiffReviewBlock.svelte.d.ts +5 -0
  108. package/dist/artifact-blocks/blocks/diff-review/block.d.ts +15 -0
  109. package/dist/artifact-blocks/blocks/diff-review/block.js +64 -0
  110. package/dist/artifact-blocks/blocks/diff-review/decisions.d.ts +57 -0
  111. package/dist/artifact-blocks/blocks/diff-review/decisions.js +80 -0
  112. package/dist/artifact-blocks/blocks/diff-review/schema.d.ts +13 -0
  113. package/dist/artifact-blocks/blocks/diff-review/schema.js +84 -0
  114. package/dist/artifact-blocks/blocks/diff-review/types.d.ts +35 -0
  115. package/dist/artifact-blocks/blocks/diff-review/types.js +1 -0
  116. package/dist/artifact-blocks/blocks/explainer/ExplainerBlock.svelte +145 -0
  117. package/dist/artifact-blocks/blocks/explainer/ExplainerBlock.svelte.d.ts +5 -0
  118. package/dist/artifact-blocks/blocks/explainer/block.d.ts +8 -0
  119. package/dist/artifact-blocks/blocks/explainer/block.js +21 -0
  120. package/dist/artifact-blocks/blocks/explainer/schema.d.ts +26 -0
  121. package/dist/artifact-blocks/blocks/explainer/schema.js +69 -0
  122. package/dist/artifact-blocks/blocks/group-content.d.ts +10 -0
  123. package/dist/artifact-blocks/blocks/group-content.js +16 -0
  124. package/dist/artifact-blocks/blocks/group-data.d.ts +10 -0
  125. package/dist/artifact-blocks/blocks/group-data.js +7 -0
  126. package/dist/artifact-blocks/blocks/group-review.d.ts +10 -0
  127. package/dist/artifact-blocks/blocks/group-review.js +12 -0
  128. package/dist/artifact-blocks/blocks/group-visual.d.ts +17 -0
  129. package/dist/artifact-blocks/blocks/group-visual.js +14 -0
  130. package/dist/artifact-blocks/blocks/map/MapBlock.svelte +413 -0
  131. package/dist/artifact-blocks/blocks/map/MapBlock.svelte.d.ts +53 -0
  132. package/dist/artifact-blocks/blocks/map/block.d.ts +9 -0
  133. package/dist/artifact-blocks/blocks/map/block.js +62 -0
  134. package/dist/artifact-blocks/blocks/map/schema.d.ts +123 -0
  135. package/dist/artifact-blocks/blocks/map/schema.js +113 -0
  136. package/dist/artifact-blocks/blocks/map/thumb.d.ts +2 -0
  137. package/dist/artifact-blocks/blocks/map/thumb.js +69 -0
  138. package/dist/artifact-blocks/blocks/markdown/MarkdownBlock.svelte +33 -0
  139. package/dist/artifact-blocks/blocks/markdown/MarkdownBlock.svelte.d.ts +15 -0
  140. package/dist/artifact-blocks/blocks/markdown/block.d.ts +7 -0
  141. package/dist/artifact-blocks/blocks/markdown/block.js +28 -0
  142. package/dist/artifact-blocks/blocks/markdown/render.d.ts +17 -0
  143. package/dist/artifact-blocks/blocks/markdown/render.js +115 -0
  144. package/dist/artifact-blocks/blocks/markdown/schema.d.ts +10 -0
  145. package/dist/artifact-blocks/blocks/markdown/schema.js +23 -0
  146. package/dist/artifact-blocks/blocks/media-picker/MediaPickerBlock.svelte +2112 -0
  147. package/dist/artifact-blocks/blocks/media-picker/MediaPickerBlock.svelte.d.ts +5 -0
  148. package/dist/artifact-blocks/blocks/media-picker/block.d.ts +24 -0
  149. package/dist/artifact-blocks/blocks/media-picker/block.js +137 -0
  150. package/dist/artifact-blocks/blocks/media-picker/choices.d.ts +28 -0
  151. package/dist/artifact-blocks/blocks/media-picker/choices.js +35 -0
  152. package/dist/artifact-blocks/blocks/media-picker/decisions.d.ts +51 -0
  153. package/dist/artifact-blocks/blocks/media-picker/decisions.js +75 -0
  154. package/dist/artifact-blocks/blocks/media-picker/schema.d.ts +7 -0
  155. package/dist/artifact-blocks/blocks/media-picker/schema.js +199 -0
  156. package/dist/artifact-blocks/blocks/media-picker/types.d.ts +92 -0
  157. package/dist/artifact-blocks/blocks/media-picker/types.js +1 -0
  158. package/dist/artifact-blocks/blocks/media-picker/versions.d.ts +51 -0
  159. package/dist/artifact-blocks/blocks/media-picker/versions.js +118 -0
  160. package/dist/artifact-blocks/blocks/mockup/MockupBlock.svelte +213 -0
  161. package/dist/artifact-blocks/blocks/mockup/MockupBlock.svelte.d.ts +5 -0
  162. package/dist/artifact-blocks/blocks/mockup/block.d.ts +26 -0
  163. package/dist/artifact-blocks/blocks/mockup/block.js +52 -0
  164. package/dist/artifact-blocks/blocks/mockup/doc.d.ts +24 -0
  165. package/dist/artifact-blocks/blocks/mockup/doc.js +44 -0
  166. package/dist/artifact-blocks/blocks/mockup/sandbox.d.ts +21 -0
  167. package/dist/artifact-blocks/blocks/mockup/sandbox.js +27 -0
  168. package/dist/artifact-blocks/blocks/mockup/schema.d.ts +7 -0
  169. package/dist/artifact-blocks/blocks/mockup/schema.js +90 -0
  170. package/dist/artifact-blocks/blocks/mockup/types.d.ts +36 -0
  171. package/dist/artifact-blocks/blocks/mockup/types.js +17 -0
  172. package/dist/artifact-blocks/blocks/program/ProgramBlock.svelte +359 -0
  173. package/dist/artifact-blocks/blocks/program/ProgramBlock.svelte.d.ts +32 -0
  174. package/dist/artifact-blocks/blocks/program/block.d.ts +35 -0
  175. package/dist/artifact-blocks/blocks/program/block.js +68 -0
  176. package/dist/artifact-blocks/blocks/program/schema.d.ts +132 -0
  177. package/dist/artifact-blocks/blocks/program/schema.js +268 -0
  178. package/dist/artifact-blocks/blocks/stats/StatsBlock.svelte +315 -0
  179. package/dist/artifact-blocks/blocks/stats/StatsBlock.svelte.d.ts +24 -0
  180. package/dist/artifact-blocks/blocks/stats/block.d.ts +7 -0
  181. package/dist/artifact-blocks/blocks/stats/block.js +49 -0
  182. package/dist/artifact-blocks/blocks/stats/schema.d.ts +82 -0
  183. package/dist/artifact-blocks/blocks/stats/schema.js +43 -0
  184. package/dist/artifact-blocks/blocks/stats/thumb.d.ts +2 -0
  185. package/dist/artifact-blocks/blocks/stats/thumb.js +102 -0
  186. package/dist/artifact-blocks/blocks/table/TableBlock.svelte +490 -0
  187. package/dist/artifact-blocks/blocks/table/TableBlock.svelte.d.ts +28 -0
  188. package/dist/artifact-blocks/blocks/table/block.d.ts +9 -0
  189. package/dist/artifact-blocks/blocks/table/block.js +100 -0
  190. package/dist/artifact-blocks/blocks/table/schema.d.ts +143 -0
  191. package/dist/artifact-blocks/blocks/table/schema.js +278 -0
  192. package/dist/artifact-blocks/blocks/timeline/TimelineBlock.svelte +347 -0
  193. package/dist/artifact-blocks/blocks/timeline/TimelineBlock.svelte.d.ts +42 -0
  194. package/dist/artifact-blocks/blocks/timeline/block.d.ts +9 -0
  195. package/dist/artifact-blocks/blocks/timeline/block.js +96 -0
  196. package/dist/artifact-blocks/blocks/timeline/constants.d.ts +26 -0
  197. package/dist/artifact-blocks/blocks/timeline/constants.js +27 -0
  198. package/dist/artifact-blocks/blocks/timeline/schema.d.ts +102 -0
  199. package/dist/artifact-blocks/blocks/timeline/schema.js +405 -0
  200. package/dist/artifact-blocks/blocks/timeline/thumb.d.ts +2 -0
  201. package/dist/artifact-blocks/blocks/timeline/thumb.js +117 -0
  202. package/dist/artifact-blocks/blocks/timeline/types.d.ts +66 -0
  203. package/dist/artifact-blocks/blocks/timeline/types.js +1 -0
  204. package/dist/artifact-blocks/blocks/transcript/TranscriptBlock.svelte +169 -0
  205. package/dist/artifact-blocks/blocks/transcript/TranscriptBlock.svelte.d.ts +26 -0
  206. package/dist/artifact-blocks/blocks/transcript/block.d.ts +9 -0
  207. package/dist/artifact-blocks/blocks/transcript/block.js +86 -0
  208. package/dist/artifact-blocks/blocks/transcript/schema.d.ts +114 -0
  209. package/dist/artifact-blocks/blocks/transcript/schema.js +126 -0
  210. package/dist/artifact-blocks/builtins.d.ts +40 -0
  211. package/dist/artifact-blocks/builtins.js +22 -0
  212. package/dist/artifact-blocks/contractBlocks.d.ts +92 -0
  213. package/dist/artifact-blocks/contractBlocks.js +279 -0
  214. package/dist/artifact-blocks/history.d.ts +140 -0
  215. package/dist/artifact-blocks/history.js +363 -0
  216. package/dist/artifact-blocks/index.d.ts +40 -0
  217. package/dist/artifact-blocks/index.js +46 -0
  218. package/dist/artifact-blocks/listen/context.d.ts +30 -0
  219. package/dist/artifact-blocks/listen/context.js +30 -0
  220. package/dist/artifact-blocks/liveData.d.ts +78 -0
  221. package/dist/artifact-blocks/liveData.js +137 -0
  222. package/dist/artifact-blocks/liveDataPoller.d.ts +41 -0
  223. package/dist/artifact-blocks/liveDataPoller.js +140 -0
  224. package/dist/artifact-blocks/openNav.d.ts +46 -0
  225. package/dist/artifact-blocks/openNav.js +106 -0
  226. package/dist/artifact-blocks/pageReviewKeys.d.ts +17 -0
  227. package/dist/artifact-blocks/pageReviewKeys.js +115 -0
  228. package/dist/artifact-blocks/params.d.ts +98 -0
  229. package/dist/artifact-blocks/params.js +159 -0
  230. package/dist/artifact-blocks/registry.d.ts +27 -0
  231. package/dist/artifact-blocks/registry.js +83 -0
  232. package/dist/artifact-blocks/review/BlockIcon.svelte +99 -0
  233. package/dist/artifact-blocks/review/BlockIcon.svelte.d.ts +17 -0
  234. package/dist/artifact-blocks/review/BulkRejectForm.svelte +94 -0
  235. package/dist/artifact-blocks/review/BulkRejectForm.svelte.d.ts +11 -0
  236. package/dist/artifact-blocks/review/BulkUndoBar.svelte +40 -0
  237. package/dist/artifact-blocks/review/BulkUndoBar.svelte.d.ts +9 -0
  238. package/dist/artifact-blocks/review/ItemNote.svelte +193 -0
  239. package/dist/artifact-blocks/review/ItemNote.svelte.d.ts +33 -0
  240. package/dist/artifact-blocks/review/NoteToggle.svelte +52 -0
  241. package/dist/artifact-blocks/review/NoteToggle.svelte.d.ts +12 -0
  242. package/dist/artifact-blocks/review/TeamChip.svelte +71 -0
  243. package/dist/artifact-blocks/review/TeamChip.svelte.d.ts +8 -0
  244. package/dist/artifact-blocks/review/attachments.d.ts +10 -0
  245. package/dist/artifact-blocks/review/attachments.js +37 -0
  246. package/dist/artifact-blocks/review/bulk.d.ts +52 -0
  247. package/dist/artifact-blocks/review/bulk.js +61 -0
  248. package/dist/artifact-blocks/review/itemReview.d.ts +33 -0
  249. package/dist/artifact-blocks/review/itemReview.js +112 -0
  250. package/dist/artifact-blocks/review/roundLines.d.ts +14 -0
  251. package/dist/artifact-blocks/review/roundLines.js +20 -0
  252. package/dist/artifact-blocks/review/rounds.d.ts +86 -0
  253. package/dist/artifact-blocks/review/rounds.js +302 -0
  254. package/dist/artifact-blocks/review/saver.d.ts +23 -0
  255. package/dist/artifact-blocks/review/saver.js +48 -0
  256. package/dist/artifact-blocks/review/team.d.ts +31 -0
  257. package/dist/artifact-blocks/review/team.js +42 -0
  258. package/dist/artifact-blocks/review/visualOrder.d.ts +29 -0
  259. package/dist/artifact-blocks/review/visualOrder.js +66 -0
  260. package/dist/artifact-blocks/review.d.ts +180 -0
  261. package/dist/artifact-blocks/review.js +716 -0
  262. package/dist/artifact-blocks/thumb-kit.d.ts +80 -0
  263. package/dist/artifact-blocks/thumb-kit.js +149 -0
  264. package/dist/artifact-blocks/types.d.ts +513 -0
  265. package/dist/artifact-blocks/types.js +1 -0
  266. package/package.json +11 -2
@@ -0,0 +1,621 @@
1
+ /**
2
+ * Diagram block — params schema, validation and layout (mos-d70v4).
3
+ *
4
+ * Pure functions only (no DOM, no canvas): box sizing comes from a
5
+ * deterministic char-count estimate so SSR and the client agree without a
6
+ * measurement pass, and colors NEVER appear here — the renderer maps tones
7
+ * to theme-token classes. dagre is NOT imported at module level: the
8
+ * renderer resolves it (resolveDagre) and passes the engine in, so this
9
+ * file stays testable without the dependency and the build doesn't hard-
10
+ * wire a transitive package. The layered fallback (layoutLayered) keeps
11
+ * publishing alive even if dagre is unavailable.
12
+ *
13
+ * Untrusted-input rules (CONTRACT.md): text params are length-capped
14
+ * strings, arrays are capped (50 nodes / 80 edges), ids are validated.
15
+ */
16
+ import { z } from "zod";
17
+ import { toneSchema } from "../../params";
18
+ import { MAX_EDGES, MAX_NODES, NODE_TEXT_MAX, EDGE_TEXT_MAX, DEFAULT_RANKSEP, DEFAULT_NODESEP, DEFAULT_EDGESEP, MIN_RANKSEP, MIN_NODESEP, NODE_PAD_X, NODE_PAD_Y, NODE_LINE_H, NODE_CHAR_W, SUB_CHAR_W, NODE_MAX_LINES, NODE_MIN_W, NODE_MAX_W, NODE_MIN_H, DIAMOND_TEXT_FACTOR, CIRCLE_MIN, SEQ_ACTOR_H, SEQ_ACTOR_PAD_X, SEQ_ACTOR_MIN_W, SEQ_ACTOR_MAX_W, SEQ_MSG_GAP_DEFAULT, SEQ_MSG_GAP_MIN, SEQ_ROW_PAD, SEQ_PAD_X, SEQ_COL_MIN, SEQ_LABEL_CHAR_W, SEQ_WIDTH_DEFAULT, SEQ_WIDTH_MIN, SEQ_WIDTH_MAX, EDGE_LABEL_W, EDGE_LABEL_H, VIEW_PAD, } from "./constants";
19
+ // ── Schemas ───────────────────────────────────────────────────────────────
20
+ /** ids accept the block-id charset; duplicates are rejected in the refine. */
21
+ const diagramIdSchema = z
22
+ .string()
23
+ .min(1)
24
+ .max(64)
25
+ .regex(/^[a-zA-Z0-9][a-zA-Z0-9_.-]*$/);
26
+ const nodeShapeValues = [
27
+ "rect",
28
+ "pill",
29
+ "diamond",
30
+ "circle",
31
+ "stadium",
32
+ ];
33
+ const nodeKindValues = [
34
+ "default",
35
+ "input",
36
+ "output",
37
+ "decision",
38
+ "terminal",
39
+ "process",
40
+ "data",
41
+ "subroutine",
42
+ "external",
43
+ "note",
44
+ ];
45
+ const diagramNodeSchema = z.object({
46
+ id: diagramIdSchema,
47
+ label: z.string().min(1).max(NODE_TEXT_MAX),
48
+ sublabel: z.string().max(NODE_TEXT_MAX).optional(),
49
+ kind: z.enum(nodeKindValues).optional(),
50
+ tone: toneSchema.optional(),
51
+ shape: z.enum(nodeShapeValues).optional(),
52
+ });
53
+ const diagramEdgeSchema = z.object({
54
+ from: diagramIdSchema,
55
+ to: diagramIdSchema,
56
+ label: z.string().max(EDGE_TEXT_MAX).optional(),
57
+ dashed: z.boolean().optional(),
58
+ tone: toneSchema.optional(),
59
+ });
60
+ export const diagramParamsSchema = z
61
+ .object({
62
+ mode: z.enum(["flow", "sequence"]).default("flow"),
63
+ title: z.string().max(200).optional(),
64
+ subtitle: z.string().max(300).optional(),
65
+ direction: z.enum(["LR", "RL", "TB", "BT"]).default("LR"),
66
+ nodes: z.array(diagramNodeSchema).min(1).max(MAX_NODES),
67
+ edges: z.array(diagramEdgeSchema).max(MAX_EDGES).default([]),
68
+ edgeLabels: z.boolean().default(true),
69
+ ranksep: z.number().min(MIN_RANKSEP).max(400).optional(),
70
+ nodesep: z.number().min(MIN_NODESEP).max(300).optional(),
71
+ edgesep: z.number().min(4).max(200).optional(),
72
+ sequenceWidth: z
73
+ .number()
74
+ .int()
75
+ .min(SEQ_WIDTH_MIN)
76
+ .max(SEQ_WIDTH_MAX)
77
+ .optional(),
78
+ msgGap: z.number().min(SEQ_MSG_GAP_MIN).max(200).optional(),
79
+ })
80
+ .superRefine((p, ctx) => {
81
+ const ids = new Set();
82
+ for (const [i, n] of p.nodes.entries()) {
83
+ if (ids.has(n.id)) {
84
+ ctx.addIssue({
85
+ code: "custom",
86
+ message: `Duplicate node id "${n.id}" (node ${i})`,
87
+ path: ["nodes", i, "id"],
88
+ });
89
+ }
90
+ ids.add(n.id);
91
+ }
92
+ p.edges.forEach((e, i) => {
93
+ for (const key of ["from", "to"]) {
94
+ if (!ids.has(e[key])) {
95
+ ctx.addIssue({
96
+ code: "custom",
97
+ message: `Edge ${i} ${key} "${e[key]}" has no node`,
98
+ path: ["edges", i, key],
99
+ });
100
+ }
101
+ }
102
+ if (e.from === e.to) {
103
+ ctx.addIssue({
104
+ code: "custom",
105
+ message: `Edge ${i} is a self-loop (from === to)`,
106
+ path: ["edges", i],
107
+ });
108
+ }
109
+ // flow only: duplicate (from,to) pairs render as one line — refuse
110
+ // them. In sequence mode repeated actor pairs are the NORM (each is a
111
+ // row), so the check is mode-gated.
112
+ if (p.mode === "flow") {
113
+ for (let j = 0; j < i; j++) {
114
+ const other = p.edges[j];
115
+ if (other.from === e.from && other.to === e.to) {
116
+ ctx.addIssue({
117
+ code: "custom",
118
+ message: `Edge ${i} duplicates edge ${j} (${e.from} → ${e.to})`,
119
+ path: ["edges", i],
120
+ });
121
+ }
122
+ }
123
+ }
124
+ });
125
+ if (p.mode === "sequence") {
126
+ if (p.nodes.length < 2) {
127
+ ctx.addIssue({
128
+ code: "custom",
129
+ message: "Sequence needs at least 2 actors (nodes)",
130
+ path: ["nodes"],
131
+ });
132
+ }
133
+ const labels = new Set();
134
+ for (const [i, n] of p.nodes.entries()) {
135
+ if (labels.has(n.label)) {
136
+ ctx.addIssue({
137
+ code: "custom",
138
+ message: `Duplicate actor label "${n.label}" (node ${i})`,
139
+ path: ["nodes", i, "label"],
140
+ });
141
+ }
142
+ labels.add(n.label);
143
+ }
144
+ }
145
+ });
146
+ /**
147
+ * Pull the dagre engine out of whatever the renderer imported. Handles both
148
+ * the ESM default export (`{ graphlib, layout }` — what @dagrejs/dagre
149
+ * actually ships) and a namespace import. Returns null when dagre isn't
150
+ * there — the caller falls back to the layered layout.
151
+ */
152
+ export function resolveDagre(mod) {
153
+ const d = mod?.default ?? mod;
154
+ if (!d || typeof d !== "object")
155
+ return null;
156
+ const eng = d;
157
+ if (!eng.graphlib ||
158
+ typeof eng.graphlib.Graph !== "function" ||
159
+ typeof eng.layout !== "function")
160
+ return null;
161
+ return d;
162
+ }
163
+ // ── Deterministic text estimate (no canvas — SSR == client) ───────────────
164
+ /** Char-count text width estimate. Deliberately NOT a canvas measure: the
165
+ * layout must be byte-identical between SSR and hydration. */
166
+ export function textWidth(text, charW) {
167
+ return text.length * charW;
168
+ }
169
+ /** Greedy word wrap on the estimate. Long single words hard-split. */
170
+ function wrapText(text, maxWidth, charW, maxLines) {
171
+ const words = text.split(/\s+/).filter(Boolean);
172
+ const lines = [];
173
+ let cur = "";
174
+ for (const w of words) {
175
+ const candidate = cur ? `${cur} ${w}` : w;
176
+ if (textWidth(candidate, charW) <= maxWidth || !cur) {
177
+ cur = candidate;
178
+ }
179
+ else {
180
+ lines.push(cur);
181
+ cur = w;
182
+ if (lines.length >= maxLines)
183
+ break;
184
+ }
185
+ }
186
+ if (cur && lines.length < maxLines)
187
+ lines.push(cur);
188
+ if (lines.length === maxLines && words.length > 0) {
189
+ // overflow: hard-truncate the last line
190
+ const rest = words.slice(lines.join(" ").split(" ").length).join(" ");
191
+ if (rest) {
192
+ let last = rest;
193
+ while (textWidth(last, charW) > maxWidth && last.length > 1)
194
+ last = last.slice(0, -1);
195
+ lines[maxLines - 1] = `${last}…`;
196
+ }
197
+ }
198
+ return lines.length ? lines : [text];
199
+ }
200
+ /** Default shape for a node kind (explicit `shape` wins). */
201
+ export function kindShape(kind) {
202
+ switch (kind) {
203
+ case "decision":
204
+ return "diamond";
205
+ case "terminal":
206
+ return "stadium";
207
+ case "input":
208
+ case "output":
209
+ return "pill";
210
+ case "external":
211
+ case "note":
212
+ return "rect";
213
+ default:
214
+ return "rect";
215
+ }
216
+ }
217
+ /** Dashed border for note/external kinds unless the shape is a diamond. */
218
+ export function kindDashed(kind) {
219
+ return kind === "note" || kind === "external";
220
+ }
221
+ /** Box size for a node from the deterministic estimate. */
222
+ function nodeSizeFor(node) {
223
+ const shape = node.shape ?? kindShape(node.kind);
224
+ if (shape === "diamond") {
225
+ const lines = wrapText(node.label, NODE_MAX_W * DIAMOND_TEXT_FACTOR, NODE_CHAR_W, 2);
226
+ const widest = Math.max(...lines.map((l) => textWidth(l, NODE_CHAR_W)));
227
+ const w = Math.min(Math.max(widest / DIAMOND_TEXT_FACTOR + 32, 130), 340);
228
+ const h = Math.min(Math.max(lines.length * NODE_LINE_H * 2 + 26, 76), 180);
229
+ return { w, h };
230
+ }
231
+ if (shape === "circle") {
232
+ const lines = wrapText(node.label, 120, NODE_CHAR_W, 2);
233
+ const widest = Math.max(...lines.map((l) => textWidth(l, NODE_CHAR_W)));
234
+ const side = Math.min(Math.max(Math.max(widest, 16) + 40, CIRCLE_MIN), 170);
235
+ return { w: side, h: side };
236
+ }
237
+ const inner = NODE_MAX_W - NODE_PAD_X * 2;
238
+ const labelLines = wrapText(node.label, inner, NODE_CHAR_W, NODE_MAX_LINES);
239
+ const widestLabel = Math.max(...labelLines.map((l) => textWidth(l, NODE_CHAR_W)));
240
+ const subLines = node.sublabel
241
+ ? wrapText(node.sublabel, inner, SUB_CHAR_W, 2)
242
+ : [];
243
+ const widestSub = subLines.length
244
+ ? Math.max(...subLines.map((l) => textWidth(l, SUB_CHAR_W)))
245
+ : 0;
246
+ const w = Math.min(Math.max(Math.max(widestLabel, widestSub) + NODE_PAD_X * 2, NODE_MIN_W), NODE_MAX_W);
247
+ const h = Math.max(labelLines.length * NODE_LINE_H +
248
+ subLines.length * (NODE_LINE_H - 4) +
249
+ NODE_PAD_Y * 2 +
250
+ (subLines.length ? 4 : 0), NODE_MIN_H);
251
+ return { w, h };
252
+ }
253
+ /** Text lines the renderer paints for a node (same budgets as nodeSizeFor
254
+ * so the box always fits its text). */
255
+ export function nodeTextLines(node, size) {
256
+ const shape = node.shape ?? kindShape(node.kind);
257
+ if (shape === "diamond")
258
+ return {
259
+ label: wrapText(node.label, size.w * DIAMOND_TEXT_FACTOR - 12, NODE_CHAR_W, 2),
260
+ sub: [],
261
+ };
262
+ if (shape === "circle")
263
+ return { label: wrapText(node.label, size.w - 26, NODE_CHAR_W, 2), sub: [] };
264
+ const inner = size.w - NODE_PAD_X * 2;
265
+ return {
266
+ label: wrapText(node.label, inner, NODE_CHAR_W, NODE_MAX_LINES),
267
+ sub: node.sublabel ? wrapText(node.sublabel, inner, SUB_CHAR_W, 2) : [],
268
+ };
269
+ }
270
+ // ── Flow layout (dagre, with layered fallback) ────────────────────────────
271
+ function padLayout(boxes, edges) {
272
+ const minX = Math.min(VIEW_PAD, ...boxes.map((b) => b.x), ...edges.flatMap((e) => e.points.map((p) => p.x)));
273
+ const minY = Math.min(VIEW_PAD, ...boxes.map((b) => b.y), ...edges.flatMap((e) => e.points.map((p) => p.y)));
274
+ const dx = VIEW_PAD - minX;
275
+ const dy = VIEW_PAD - minY;
276
+ for (const b of boxes) {
277
+ b.x += dx;
278
+ b.y += dy;
279
+ }
280
+ for (const e of edges) {
281
+ for (const pt of e.points) {
282
+ pt.x += dx;
283
+ pt.y += dy;
284
+ }
285
+ if (e.labelPoint) {
286
+ e.labelPoint.x += dx;
287
+ e.labelPoint.y += dy;
288
+ }
289
+ }
290
+ const width = Math.max(VIEW_PAD, ...boxes.map((b) => b.x + b.w), ...edges.flatMap((e) => e.points.map((p) => p.x))) + VIEW_PAD;
291
+ const height = Math.max(VIEW_PAD, ...boxes.map((b) => b.y + b.h), ...edges.flatMap((e) => e.points.map((p) => p.y))) + VIEW_PAD;
292
+ return { boxes, edges, width, height, engine: "dagre" };
293
+ }
294
+ function layoutDagre(p, engine) {
295
+ const g = new engine.graphlib.Graph();
296
+ g.setGraph({
297
+ rankdir: p.direction,
298
+ ranksep: p.ranksep ?? DEFAULT_RANKSEP,
299
+ nodesep: p.nodesep ?? DEFAULT_NODESEP,
300
+ edgesep: p.edgesep ?? DEFAULT_EDGESEP,
301
+ marginx: 0,
302
+ marginy: 0,
303
+ });
304
+ g.setDefaultEdgeLabel(() => ({}));
305
+ for (const n of p.nodes) {
306
+ const { w, h } = nodeSizeFor(n);
307
+ g.setNode(n.id, { width: w, height: h });
308
+ }
309
+ for (const e of p.edges) {
310
+ g.setEdge(e.from, e.to, p.edgeLabels && e.label
311
+ ? {
312
+ label: e.label,
313
+ width: EDGE_LABEL_W,
314
+ height: EDGE_LABEL_H,
315
+ labelpos: "c",
316
+ }
317
+ : {});
318
+ }
319
+ engine.layout(g);
320
+ const byId = new Map();
321
+ for (const n of p.nodes) {
322
+ const meta = g.node(n.id);
323
+ if (!meta ||
324
+ typeof meta.x !== "number" ||
325
+ typeof meta.y !== "number" ||
326
+ !Number.isFinite(meta.x) ||
327
+ !Number.isFinite(meta.y))
328
+ throw new Error("dagre layout produced no position");
329
+ const size = nodeSizeFor(n);
330
+ byId.set(n.id, {
331
+ ...n,
332
+ x: meta.x - size.w / 2,
333
+ y: meta.y - size.h / 2,
334
+ w: size.w,
335
+ h: size.h,
336
+ });
337
+ }
338
+ const edges = [];
339
+ for (const e of p.edges) {
340
+ const meta = g.edge(e.from, e.to);
341
+ const points = meta?.points;
342
+ if (!points || points.length === 0)
343
+ throw new Error("no edge points");
344
+ let labelPoint = null;
345
+ if (p.edgeLabels && e.label && meta) {
346
+ if (typeof meta.x === "number" &&
347
+ typeof meta.y === "number" &&
348
+ Number.isFinite(meta.x) &&
349
+ Number.isFinite(meta.y))
350
+ labelPoint = { x: meta.x, y: meta.y };
351
+ }
352
+ edges.push({
353
+ from: e.from,
354
+ to: e.to,
355
+ label: e.label,
356
+ dashed: e.dashed,
357
+ tone: e.tone,
358
+ points,
359
+ labelPoint: labelPoint ?? midpoint(points),
360
+ labelW: EDGE_LABEL_W,
361
+ labelH: EDGE_LABEL_H,
362
+ });
363
+ }
364
+ const gr = g.graph();
365
+ const width = typeof gr.width === "number" ? gr.width : 0;
366
+ const height = typeof gr.height === "number" ? gr.height : 0;
367
+ if (width <= 0 || height <= 0)
368
+ throw new Error("dagre graph has no extent");
369
+ return padLayout([...byId.values()], edges);
370
+ }
371
+ /** Layered fallback: longest-path layering (cycle-safe) + insertion order
372
+ * within layers. Plain straight-edge routing. Pure, no dagre. */
373
+ function layoutLayered(p) {
374
+ const vertical = p.direction === "TB" || p.direction === "BT";
375
+ const reverse = p.direction === "RL" || p.direction === "BT";
376
+ const rankSep = p.ranksep ?? DEFAULT_RANKSEP;
377
+ const nodeSep = p.nodesep ?? DEFAULT_NODESEP;
378
+ const sizes = new Map();
379
+ for (const n of p.nodes)
380
+ sizes.set(n.id, nodeSizeFor(n));
381
+ // longest-path layering (cycle-safe: Kahn first, leftovers in input order)
382
+ const layer = new Map();
383
+ const preds = new Map();
384
+ for (const n of p.nodes)
385
+ preds.set(n.id, []);
386
+ for (const e of p.edges)
387
+ preds.get(e.to)?.push(e.from);
388
+ const indeg = new Map();
389
+ for (const n of p.nodes)
390
+ indeg.set(n.id, (preds.get(n.id) ?? []).filter((f) => f !== n.id).length);
391
+ const queue = p.nodes
392
+ .filter((n) => (indeg.get(n.id) ?? 0) === 0)
393
+ .map((n) => n.id);
394
+ for (const id of queue)
395
+ layer.set(id, 0);
396
+ while (queue.length) {
397
+ const id = queue.shift();
398
+ for (const e of p.edges) {
399
+ if (e.from !== id)
400
+ continue;
401
+ const next = (layer.get(id) ?? 0) + 1;
402
+ if (!layer.has(e.to) || layer.get(e.to) < next) {
403
+ layer.set(e.to, next);
404
+ if ((indeg.get(e.to) ?? 0) > 0)
405
+ indeg.set(e.to, indeg.get(e.to) - 1);
406
+ queue.push(e.to);
407
+ }
408
+ }
409
+ }
410
+ for (const n of p.nodes)
411
+ if (!layer.has(n.id)) {
412
+ const pl = (preds.get(n.id) ?? [])
413
+ .map((f) => layer.get(f))
414
+ .filter((v) => v !== undefined);
415
+ layer.set(n.id, pl.length ? Math.max(...pl) + 1 : 0);
416
+ }
417
+ const layers = new Map();
418
+ for (const n of p.nodes) {
419
+ const l = layer.get(n.id) ?? 0;
420
+ if (!layers.has(l))
421
+ layers.set(l, []);
422
+ layers.get(l)?.push(n.id);
423
+ }
424
+ const sorted = [...layers.keys()].sort((a, b) => a - b);
425
+ const boxes = [];
426
+ const byId = new Map();
427
+ let primary = VIEW_PAD;
428
+ for (const l of sorted) {
429
+ let secondary = VIEW_PAD;
430
+ let layerMax = 0;
431
+ for (const id of layers.get(l) ?? []) {
432
+ const n = p.nodes.find((nn) => nn.id === id);
433
+ if (!n)
434
+ continue;
435
+ const { w, h } = sizes.get(id);
436
+ const box = {
437
+ ...n,
438
+ x: vertical ? secondary : primary,
439
+ y: vertical ? primary : secondary,
440
+ w,
441
+ h,
442
+ };
443
+ boxes.push(box);
444
+ byId.set(id, box);
445
+ secondary += (vertical ? w : h) + nodeSep;
446
+ layerMax = Math.max(layerMax, vertical ? w : h);
447
+ }
448
+ primary += (vertical ? layerMax : 0) + rankSep + (vertical ? 0 : 44);
449
+ }
450
+ // horizontal mode: primary advances per layer by ranksep; recompute
451
+ if (!vertical) {
452
+ let x = VIEW_PAD;
453
+ for (const l of sorted) {
454
+ let maxW = 0;
455
+ for (const b of boxes) {
456
+ if ((layer.get(b.id) ?? 0) !== l)
457
+ continue;
458
+ b.x = x;
459
+ maxW = Math.max(maxW, b.w);
460
+ }
461
+ x += maxW + rankSep;
462
+ }
463
+ }
464
+ if (reverse) {
465
+ const extent = Math.max(...boxes.map((b) => (vertical ? b.y + b.h : b.x + b.w)));
466
+ for (const b of boxes) {
467
+ if (vertical)
468
+ b.y = extent - b.y - b.h;
469
+ else
470
+ b.x = extent - b.x - b.w;
471
+ }
472
+ }
473
+ const edges = [];
474
+ for (const e of p.edges) {
475
+ const a = byId.get(e.from);
476
+ const b = byId.get(e.to);
477
+ if (!a || !b)
478
+ continue;
479
+ const points = borderPoints(a, b);
480
+ edges.push({
481
+ from: e.from,
482
+ to: e.to,
483
+ label: e.label,
484
+ dashed: e.dashed,
485
+ tone: e.tone,
486
+ points,
487
+ labelPoint: midpoint(points),
488
+ labelW: EDGE_LABEL_W,
489
+ labelH: EDGE_LABEL_H,
490
+ });
491
+ }
492
+ const width = Math.max(...boxes.map((b) => b.x + b.w)) + VIEW_PAD;
493
+ const height = Math.max(...boxes.map((b) => b.y + b.h)) + VIEW_PAD;
494
+ return { boxes, edges, width, height, engine: "layered" };
495
+ }
496
+ /** Border intersection points between two boxes (center → center clipped). */
497
+ function borderPoints(a, b) {
498
+ const ac = { x: a.x + a.w / 2, y: a.y + a.h / 2 };
499
+ const bc = { x: b.x + b.w / 2, y: b.y + b.h / 2 };
500
+ return [clipToBox(ac, bc, a), clipToBox(bc, ac, b)];
501
+ }
502
+ function clipToBox(from, toward, box) {
503
+ const dx = toward.x - from.x;
504
+ const dy = toward.y - from.y;
505
+ if (dx === 0 && dy === 0)
506
+ return { x: box.x + box.w / 2, y: box.y + box.h / 2 };
507
+ const scale = Math.min(dx !== 0
508
+ ? (dx > 0 ? box.x + box.w - from.x : box.x - from.x) / dx
509
+ : Infinity, dy !== 0
510
+ ? (dy > 0 ? box.y + box.h - from.y : box.y - from.y) / dy
511
+ : Infinity);
512
+ return { x: from.x + dx * scale, y: from.y + dy * scale };
513
+ }
514
+ function midpoint(points) {
515
+ if (!points.length)
516
+ return { x: 0, y: 0 };
517
+ const total = points
518
+ .slice(1)
519
+ .reduce((acc, p, i) => acc + Math.hypot(p.x - points[i].x, p.y - points[i].y), 0);
520
+ let acc = 0;
521
+ for (let i = 1; i < points.length; i++) {
522
+ const seg = Math.hypot(points[i].x - points[i - 1].x, points[i].y - points[i - 1].y);
523
+ if (acc + seg >= total / 2 || i === points.length - 1) {
524
+ const t = seg === 0 ? 0 : (total / 2 - acc) / seg;
525
+ return {
526
+ x: points[i - 1].x + (points[i].x - points[i - 1].x) * t,
527
+ y: points[i - 1].y + (points[i].y - points[i - 1].y) * t,
528
+ };
529
+ }
530
+ acc += seg;
531
+ }
532
+ return points[Math.floor(points.length / 2)];
533
+ }
534
+ /** Flow layout: dagre when an engine resolves, layered otherwise. */
535
+ export function layoutFlow(p, engine) {
536
+ if (engine) {
537
+ try {
538
+ return layoutDagre(p, engine);
539
+ }
540
+ catch {
541
+ // fall through to the layered fallback — a layout engine must
542
+ // never take the artifact page down.
543
+ }
544
+ }
545
+ return layoutLayered(p);
546
+ }
547
+ // ── Sequence layout ───────────────────────────────────────────────────────
548
+ export function layoutSequence(p) {
549
+ const gap = p.msgGap ?? SEQ_MSG_GAP_DEFAULT;
550
+ const width = p.sequenceWidth ?? SEQ_WIDTH_DEFAULT;
551
+ const n = Math.max(2, p.nodes.length);
552
+ const inner = Math.max(width - SEQ_PAD_X * 2, SEQ_COL_MIN * n);
553
+ const colW = Math.max(inner / n, SEQ_COL_MIN);
554
+ const actors = p.nodes.map((n, i) => {
555
+ const w = Math.min(Math.max(textWidth(n.label, SEQ_LABEL_CHAR_W) + SEQ_ACTOR_PAD_X * 2, SEQ_ACTOR_MIN_W), Math.min(SEQ_ACTOR_MAX_W, colW - 12));
556
+ return {
557
+ id: n.id,
558
+ label: n.label,
559
+ tone: n.tone,
560
+ x: SEQ_PAD_X + colW * (i + 0.5),
561
+ w,
562
+ };
563
+ });
564
+ const byId = new Map(actors.map((a) => [a.id, a]));
565
+ const messages = [];
566
+ for (const [i, e] of p.edges.entries()) {
567
+ const a = byId.get(e.from);
568
+ const b = byId.get(e.to);
569
+ if (!a || !b)
570
+ continue;
571
+ messages.push({
572
+ from: e.from,
573
+ to: e.to,
574
+ label: e.label,
575
+ dashed: e.dashed,
576
+ tone: e.tone,
577
+ y: SEQ_ACTOR_H + SEQ_ROW_PAD + i * gap + gap / 2,
578
+ x1: a.x,
579
+ x2: b.x,
580
+ });
581
+ }
582
+ const height = SEQ_ACTOR_H +
583
+ SEQ_ROW_PAD * 2 +
584
+ p.edges.length * gap +
585
+ (messages.length === 0 ? 24 : 0);
586
+ return {
587
+ actors,
588
+ messages,
589
+ width: Math.max(width, SEQ_PAD_X * 2 + colW * n),
590
+ height,
591
+ };
592
+ }
593
+ /** Flat rows for the accessible data fallback (sr-only table). */
594
+ export function diagramRows(params) {
595
+ const rows = [];
596
+ const labelOf = (id) => params.nodes.find((n) => n.id === id)?.label ?? id;
597
+ if (params.mode === "sequence") {
598
+ for (const n of params.nodes)
599
+ rows.push({ kind: "node", label: n.label, detail: "actor" });
600
+ for (const e of params.edges)
601
+ rows.push({
602
+ kind: "edge",
603
+ label: `${labelOf(e.from)} → ${labelOf(e.to)}`,
604
+ detail: e.label ?? (e.dashed ? "return message" : "message"),
605
+ });
606
+ return rows;
607
+ }
608
+ for (const n of params.nodes)
609
+ rows.push({
610
+ kind: "node",
611
+ label: n.label,
612
+ detail: [n.kind, n.tone].filter(Boolean).join(", ") || "node",
613
+ });
614
+ for (const e of params.edges)
615
+ rows.push({
616
+ kind: "edge",
617
+ label: `${labelOf(e.from)} → ${labelOf(e.to)}`,
618
+ detail: e.label ?? (e.dashed ? "dashed edge" : "edge"),
619
+ });
620
+ return rows;
621
+ }
@@ -0,0 +1,2 @@
1
+ import { type ThumbPalette } from "../../thumb-kit.js";
2
+ export declare function drawDiagramThumb(raw: unknown, palette: ThumbPalette): string | null;