@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,148 @@
1
+ /**
2
+ * Compare block — params schema + pure helpers (before/after slider).
3
+ *
4
+ * Pure functions only (no DOM) so `block.test.ts` can exercise them and
5
+ * `CompareBlock.svelte` stays a thin renderer. Untrusted input rules
6
+ * (CONTRACT.md): URLs go through the shared `urlSchema` (https:// or
7
+ * root-relative — never data:/javascript:/http://), every string is
8
+ * length-capped, media is by URL only (never base64).
9
+ */
10
+ import { z } from "zod";
11
+ import { shortTextSchema, urlSchema } from "../../params.js";
12
+ const COMPARE_SIDES = ["a", "b"];
13
+ /** Video extensions the renderer recognizes when `kind` is not given. */
14
+ const VIDEO_EXTENSIONS = /\.(mp4|webm|mov|m4v|ogv)(\?|#|$)/i;
15
+ /** Percent bounds the DIVIDER can be dragged to (start is tighter, 5-95). */
16
+ const DIVIDER_MIN = 0;
17
+ const DIVIDER_MAX = 100;
18
+ /** Bounds for the authored `startPercent` — never open nearly-shut. */
19
+ const START_MIN = 5;
20
+ const START_MAX = 95;
21
+ /** Divider keyboard step, in percent. */
22
+ const ARROW_STEP = 4;
23
+ const SHIFT_STEP = 12;
24
+ const DEFAULT_LABELS = {
25
+ a: "Before",
26
+ b: "After",
27
+ };
28
+ const mediaSchema = z.object({
29
+ src: urlSchema,
30
+ /**
31
+ * Force the renderer kind; when omitted it is inferred from the src
32
+ * extension (mp4/webm/mov/m4v/ogv → video, else image).
33
+ */
34
+ kind: z.enum(["image", "video"]).optional(),
35
+ /** Chip over the media. Defaults to "Before" (a) / "After" (b). */
36
+ label: shortTextSchema.optional(),
37
+ /** Alt text for the media; defaults to the effective label. */
38
+ alt: shortTextSchema.optional(),
39
+ });
40
+ export const compareSchema = z
41
+ .object({
42
+ title: shortTextSchema.optional(),
43
+ /** First side — the one shown when the divider is fully left/top. */
44
+ a: mediaSchema,
45
+ /** Second side — revealed from the right/bottom of the divider. */
46
+ b: mediaSchema,
47
+ /** Divider start position, % from the left/top (5-95). */
48
+ startPercent: z.number().finite().min(START_MIN).max(START_MAX).default(50),
49
+ /**
50
+ * `vertical` (default): a vertical divider dragged left/right — the
51
+ * classic before/after wipe. `horizontal`: a horizontal divider dragged
52
+ * up/down, for top/bottom comparisons.
53
+ */
54
+ orientation: z.enum(["vertical", "horizontal"]).default("vertical"),
55
+ /**
56
+ * Stage height in px (160-800). The fallback stacks the two sides
57
+ * side-by-side at narrow widths using the same height budget.
58
+ */
59
+ height: z.number().int().min(160).max(800).default(420),
60
+ /**
61
+ * Optional interactive verdict: when set and the surface can save, the
62
+ * viewer picks A or B ({ pick: "a" | "b" } via ctx.saveState).
63
+ */
64
+ pick: z
65
+ .object({
66
+ question: z.string().min(1).max(500),
67
+ })
68
+ .optional(),
69
+ /** Phase-3 live data: key into ctx.data whose value replaces params. */
70
+ dataKey: z.string().max(80).optional(),
71
+ })
72
+ .superRefine((v, ctx) => {
73
+ if (v.a.src === v.b.src)
74
+ ctx.addIssue({
75
+ code: "custom",
76
+ path: ["b"],
77
+ message: "a and b must be different media (same src twice)",
78
+ });
79
+ });
80
+ // ── Pure helpers ──────────────────────────────────────────────────────────
81
+ /** The renderer kind for a side: explicit param wins, else the extension. */
82
+ export function kindOf(media) {
83
+ if (media.kind)
84
+ return media.kind;
85
+ return VIDEO_EXTENSIONS.test(media.src) ? "video" : "image";
86
+ }
87
+ /** Effective chip label for a side: authored, else Before/After. */
88
+ export function labelOf(media, side) {
89
+ return media.label ?? DEFAULT_LABELS[side];
90
+ }
91
+ /** Effective alt text: authored alt, else the chip label, else the side. */
92
+ export function altOf(media, side) {
93
+ return media.alt ?? labelOf(media, side);
94
+ }
95
+ /** Clamp a divider position into [DIVIDER_MIN, DIVIDER_MAX]. */
96
+ export function clampPercent(p) {
97
+ if (!Number.isFinite(p))
98
+ return 50;
99
+ return Math.min(DIVIDER_MAX, Math.max(DIVIDER_MIN, p));
100
+ }
101
+ /** Next divider position for a key press (undefined = key does nothing). */
102
+ export function stepFor(key, orientation, shift, current) {
103
+ const step = shift ? SHIFT_STEP : ARROW_STEP;
104
+ const horizontal = orientation === "horizontal";
105
+ switch (key) {
106
+ case "ArrowRight":
107
+ return horizontal ? undefined : clampPercent(current + step);
108
+ case "ArrowLeft":
109
+ return horizontal ? undefined : clampPercent(current - step);
110
+ case "ArrowDown":
111
+ return horizontal ? clampPercent(current + step) : undefined;
112
+ case "ArrowUp":
113
+ return horizontal ? clampPercent(current - step) : undefined;
114
+ case "Home":
115
+ return DIVIDER_MIN;
116
+ case "End":
117
+ return DIVIDER_MAX;
118
+ default:
119
+ return undefined;
120
+ }
121
+ }
122
+ /** Accessible description of the divider position for aria-valuetext. */
123
+ export function dividerValueText(percent, labels) {
124
+ const p = Math.round(clampPercent(percent));
125
+ return `Divider at ${p}% — ${labels.a} ${p}%, ${labels.b} ${100 - p}%`;
126
+ }
127
+ /**
128
+ * clip-path insets that reveal side B from the right (vertical divider) or
129
+ * the bottom (horizontal) while side A sits fully underneath. Both sides
130
+ * always render; the clip does the reveal.
131
+ */
132
+ export function clipFor(percent, orientation) {
133
+ const p = clampPercent(percent);
134
+ return orientation === "vertical"
135
+ ? `inset(0 0 0 ${p}%)`
136
+ : `inset(${p}% 0 0 0)`;
137
+ }
138
+ /** Read untrusted saved state into a pick — junk in, null out. */
139
+ export function parsePick(state) {
140
+ if (typeof state === "object" &&
141
+ state !== null &&
142
+ "pick" in state &&
143
+ (state.pick === "a" ||
144
+ state.pick === "b")) {
145
+ return state.pick;
146
+ }
147
+ return null;
148
+ }
@@ -0,0 +1,392 @@
1
+ <script lang="ts">
2
+ /**
3
+ * DiagramBlock — SVG flow / org / architecture / sequence renderer
4
+ * (block type "diagram").
5
+ *
6
+ * Layout lives in ./schema.ts (pure, unit-tested): dagre positions the
7
+ * flow graph when the engine resolves (resolved here via resolveDagre and
8
+ * injected, so schema.ts never imports the transitive package), with a
9
+ * deterministic layered fallback. This file is the render layer: shapes,
10
+ * tone classes, edge arrows, and the accessible structure table.
11
+ *
12
+ * Token discipline: every color is a DaisyUI token class resolved through
13
+ * a STATIC map (dynamic `text-${tone}` patterns are forbidden — they break
14
+ * Tailwind extraction). Text is text; no {@html} anywhere.
15
+ */
16
+ import * as dagreNs from "@dagrejs/dagre"
17
+ import type { BlockProps } from "../../types.js"
18
+ import type { ToneToken } from "../../params"
19
+ import {
20
+ diagramParamsSchema,
21
+ resolveDagre,
22
+ layoutFlow,
23
+ layoutSequence,
24
+ kindShape,
25
+ kindDashed,
26
+ nodeTextLines,
27
+ diagramRows,
28
+ type DiagramParams,
29
+ type ToneToken as ToneTokenType,
30
+ } from "./schema.js"
31
+ import {
32
+ NODE_CHAR_W,
33
+ NODE_LINE_H,
34
+ NODE_PAD_X,
35
+ SEQ_ACTOR_H,
36
+ VIEW_PAD,
37
+ } from "./constants"
38
+ import SectionTools from "../../SectionTools.svelte"
39
+
40
+ let { params: rawParams, ctx }: BlockProps<DiagramParams> = $props()
41
+
42
+ /** Params are parsed here, not assumed pre-parsed: the host validates at
43
+ * publish but stores what was sent. Corrupt params fall back to an empty
44
+ * render — a bad agent payload must never throw inside the artifact page. */
45
+ const EMPTY_PARAMS: DiagramParams = {
46
+ mode: "flow",
47
+ direction: "LR",
48
+ nodes: [],
49
+ edges: [],
50
+ edgeLabels: true,
51
+ }
52
+ const parsed = $derived(diagramParamsSchema.safeParse(rawParams))
53
+ const params = $derived(parsed.success ? parsed.data : EMPTY_PARAMS)
54
+
55
+ // ── Tone classes (STATIC maps — token-only theming, no dynamic classes) ──
56
+ const NODE_FILL: Record<ToneTokenType, string> = {
57
+ primary: "fill-primary/12",
58
+ secondary: "fill-secondary/12",
59
+ accent: "fill-accent/12",
60
+ neutral: "fill-base-200",
61
+ info: "fill-info/12",
62
+ success: "fill-success/15",
63
+ warning: "fill-warning/15",
64
+ error: "fill-error/12",
65
+ }
66
+ const NODE_STROKE: Record<ToneTokenType, string> = {
67
+ primary: "stroke-primary/60",
68
+ secondary: "stroke-secondary/60",
69
+ accent: "stroke-accent/60",
70
+ neutral: "stroke-base-content/30",
71
+ info: "stroke-info/60",
72
+ success: "stroke-success/60",
73
+ warning: "stroke-warning/70",
74
+ error: "stroke-error/60",
75
+ }
76
+ const EDGE_STROKE: Record<ToneTokenType, string> = {
77
+ primary: "stroke-primary/70",
78
+ secondary: "stroke-secondary/70",
79
+ accent: "stroke-accent/70",
80
+ neutral: "stroke-base-content/40",
81
+ info: "stroke-info/70",
82
+ success: "stroke-success/70",
83
+ warning: "stroke-warning/80",
84
+ error: "stroke-error/80",
85
+ }
86
+ const HEAD_FILL: Record<ToneTokenType, string> = {
87
+ primary: "fill-primary/80",
88
+ secondary: "fill-secondary/80",
89
+ accent: "fill-accent/80",
90
+ neutral: "fill-base-content/50",
91
+ info: "fill-info/80",
92
+ success: "fill-success/80",
93
+ warning: "fill-warning/90",
94
+ error: "fill-error/80",
95
+ }
96
+
97
+ const nodeTone = (t?: ToneToken): ToneTokenType => t ?? "neutral"
98
+ const nodeClasses = (n: { tone?: ToneToken }) =>
99
+ `${NODE_FILL[nodeTone(n.tone)]} ${NODE_STROKE[nodeTone(n.tone)]}`
100
+ const edgeStroke = (e: { tone?: ToneToken }) => EDGE_STROKE[nodeTone(e.tone)]
101
+ const edgeHead = (e: { tone?: ToneToken }) => HEAD_FILL[nodeTone(e.tone)]
102
+
103
+ // ── Layout ────────────────────────────────────────────────────────────────
104
+ const dagre = resolveDagre(dagreNs)
105
+ const isSeq = $derived(params.mode === "sequence")
106
+ const seq = $derived(isSeq ? layoutSequence(params) : null)
107
+ const flow = $derived(isSeq ? null : layoutFlow(params, dagre))
108
+
109
+ const W = $derived(Math.max(80, (seq ?? flow)?.width ?? 80))
110
+ const H = $derived(Math.max(60, (seq ?? flow)?.height ?? 60))
111
+
112
+ const ariaLabel = $derived.by(() => {
113
+ if (isSeq)
114
+ return `sequence diagram${params.title ? `: ${params.title}` : ""}. Actors: ${params.nodes.map((n) => n.label).join(", ")}. ${params.edges.length} messages.`
115
+ return `diagram${params.title ? `: ${params.title}` : ""}. ${params.nodes.length} nodes, ${params.edges.length} edges.`
116
+ })
117
+
118
+ // ── Path helpers ──────────────────────────────────────────────────────────
119
+ const r1 = (n: number) => Math.round(n * 10) / 10
120
+ function polylineD(points: { x: number; y: number }[]): string {
121
+ if (!points.length) return ""
122
+ return points
123
+ .map((p, i) => `${i ? "L" : "M"} ${r1(p.x)} ${r1(p.y)}`)
124
+ .join(" ")
125
+ }
126
+ /** Arrowhead triangle at the end of a polyline (oriented along the last
127
+ * segment). Returned as an SVG polygon points string. */
128
+ function headPoints(points: { x: number; y: number }[]): string {
129
+ const n = points.length
130
+ if (n < 2) return ""
131
+ const a = points[n - 2]
132
+ const b = points[n - 1]
133
+ const ang = Math.atan2(b.y - a.y, b.x - a.x)
134
+ const size = 8
135
+ const p1 = {
136
+ x: b.x - size * Math.cos(ang - 0.45),
137
+ y: b.y - size * Math.sin(ang - 0.45),
138
+ }
139
+ const p2 = {
140
+ x: b.x - size * Math.cos(ang + 0.45),
141
+ y: b.y - size * Math.sin(ang + 0.45),
142
+ }
143
+ return `${r1(b.x)},${r1(b.y)} ${r1(p1.x)},${r1(p1.y)} ${r1(p2.x)},${r1(p2.y)}`
144
+ }
145
+
146
+ // ── A11y data fallback ────────────────────────────────────────────────────
147
+ let dataOpen = $state(false)
148
+ const tableId = $derived(`block-data-${ctx.blockId || "diagram"}`)
149
+ const rows = $derived(diagramRows(params))
150
+ </script>
151
+
152
+ <figure class="w-full" data-block-type="diagram">
153
+ {#if params.title || params.subtitle}
154
+ <div class="mb-1">
155
+ {#if params.title}
156
+ <div class="flex items-center gap-2">
157
+ <h4 class="min-w-0 text-sm font-semibold text-base-content">
158
+ {params.title}
159
+ </h4>
160
+ <SectionTools {ctx} inline />
161
+ </div>
162
+ {/if}
163
+ {#if params.subtitle}
164
+ <p class="text-xs text-base-content/60">{params.subtitle}</p>
165
+ {/if}
166
+ </div>
167
+ {/if}
168
+
169
+ {#if params.nodes.length === 0}
170
+ <p class="text-sm text-base-content/45">No diagram to draw.</p>
171
+ {:else}
172
+ <div class="w-full overflow-x-auto">
173
+ <svg
174
+ viewBox="0 0 {W} {H}"
175
+ class="block h-auto w-full"
176
+ role="img"
177
+ aria-label={ariaLabel}
178
+ >
179
+ {#if isSeq && seq}
180
+ <!-- sequence: actor pills + lifelines + messages -->
181
+ {@const lifelineBottom = H - VIEW_PAD}
182
+ {#each seq.actors as a (a.id)}
183
+ <g transform="translate({r1(a.x - a.w / 2)}, {VIEW_PAD})">
184
+ <rect
185
+ width={r1(a.w)}
186
+ height={SEQ_ACTOR_H}
187
+ rx={SEQ_ACTOR_H / 2}
188
+ class={nodeClasses(a)}
189
+ stroke-width="1.5"
190
+ ></rect>
191
+ <text
192
+ x={r1(a.w / 2)}
193
+ y={VIEW_PAD + SEQ_ACTOR_H / 2 + 4}
194
+ text-anchor="middle"
195
+ class="fill-base-content text-xs font-semibold"
196
+ >
197
+ {a.label}
198
+ </text>
199
+ </g>
200
+ <line
201
+ x1={r1(a.x)}
202
+ x2={r1(a.x)}
203
+ y1={VIEW_PAD + SEQ_ACTOR_H}
204
+ y2={lifelineBottom}
205
+ class="stroke-base-content/25"
206
+ stroke-dasharray="4 4"
207
+ ></line>
208
+ {/each}
209
+ {#each seq.messages as m, mi (mi)}
210
+ {@const toRight = m.x2 >= m.x1}
211
+ {@const xStart = toRight ? m.x1 : m.x2}
212
+ {@const xEnd = toRight ? m.x2 : m.x1}
213
+ <line
214
+ x1={r1(xStart)}
215
+ x2={r1(toRight ? xEnd - 6 : xEnd + 6)}
216
+ y1={r1(m.y)}
217
+ y2={r1(m.y)}
218
+ class={edgeStroke(m)}
219
+ stroke-width="1.5"
220
+ stroke-dasharray={m.dashed ? "5 4" : undefined}
221
+ ></line>
222
+ <polygon
223
+ points="{r1(xEnd)},{r1(m.y)} {r1(
224
+ toRight ? xEnd - 8 : xEnd + 8,
225
+ )},{r1(m.y - 3.5)} {r1(toRight ? xEnd - 8 : xEnd + 8)},{r1(
226
+ m.y + 3.5,
227
+ )}"
228
+ class={edgeHead(m)}
229
+ ></polygon>
230
+ {#if m.label}
231
+ <text
232
+ x={r1((xStart + xEnd) / 2)}
233
+ y={r1(m.y - 6)}
234
+ text-anchor="middle"
235
+ class="fill-base-content/70 text-2xs"
236
+ style="paint-order: stroke; stroke: var(--color-base-100); stroke-width: 3px; stroke-linejoin: round"
237
+ >
238
+ {m.label}
239
+ </text>
240
+ {/if}
241
+ {/each}
242
+ {:else if flow}
243
+ <!-- flow: layered graph -->
244
+ {#each flow.edges as e, ei (ei)}
245
+ <path
246
+ d={polylineD(e.points)}
247
+ fill="none"
248
+ class={edgeStroke(e)}
249
+ stroke-width="1.5"
250
+ stroke-dasharray={e.dashed ? "5 4" : undefined}
251
+ ></path>
252
+ <polygon points={headPoints(e.points)} class={edgeHead(e)}
253
+ ></polygon>
254
+ {#if params.edgeLabels && e.label && e.labelPoint}
255
+ <text
256
+ x={r1(e.labelPoint.x)}
257
+ y={r1(e.labelPoint.y + 4)}
258
+ text-anchor="middle"
259
+ class="fill-base-content/70 text-2xs"
260
+ style="paint-order: stroke; stroke: var(--color-base-100); stroke-width: 3px; stroke-linejoin: round"
261
+ >
262
+ {e.label}
263
+ </text>
264
+ {/if}
265
+ {/each}
266
+ {#each flow.boxes as b (b.id)}
267
+ {@const shape = b.shape ?? kindShape(b.kind)}
268
+ {@const text = nodeTextLines(b, { w: b.w, h: b.h })}
269
+ {@const labelLines = text.label}
270
+ {@const subLines = text.sub}
271
+ {@const textH =
272
+ labelLines.length * NODE_LINE_H +
273
+ (subLines.length ? subLines.length * (NODE_LINE_H - 4) + 4 : 0)}
274
+ {@const textTop = b.y + b.h / 2 - textH / 2}
275
+ <g>
276
+ {#if shape === "diamond"}
277
+ <polygon
278
+ points="{r1(b.x + b.w / 2)},{r1(b.y)} {r1(b.x + b.w)},{r1(
279
+ b.y + b.h / 2,
280
+ )} {r1(b.x + b.w / 2)},{r1(b.y + b.h)} {r1(b.x)},{r1(
281
+ b.y + b.h / 2,
282
+ )}"
283
+ class={nodeClasses(b)}
284
+ stroke-width="1.5"
285
+ ></polygon>
286
+ {:else if shape === "circle"}
287
+ <ellipse
288
+ cx={r1(b.x + b.w / 2)}
289
+ cy={r1(b.y + b.h / 2)}
290
+ rx={r1(b.w / 2)}
291
+ ry={r1(b.h / 2)}
292
+ class={nodeClasses(b)}
293
+ stroke-width="1.5"
294
+ ></ellipse>
295
+ {:else}
296
+ <rect
297
+ x={r1(b.x)}
298
+ y={r1(b.y)}
299
+ width={r1(b.w)}
300
+ height={r1(b.h)}
301
+ rx={shape === "pill" || shape === "stadium"
302
+ ? Math.min(b.h / 2, 18)
303
+ : 6}
304
+ class={nodeClasses(b)}
305
+ stroke-width="1.5"
306
+ stroke-dasharray={kindDashed(b.kind) ? "5 4" : undefined}
307
+ ></rect>
308
+ {/if}
309
+ <text
310
+ x={r1(b.x + b.w / 2)}
311
+ y={r1(textTop + NODE_LINE_H / 2 + 4)}
312
+ text-anchor="middle"
313
+ class="fill-base-content text-xs font-semibold"
314
+ >
315
+ {#each labelLines as line, li (li)}
316
+ <tspan
317
+ x={r1(b.x + b.w / 2)}
318
+ y={r1(textTop + NODE_LINE_H * li + NODE_LINE_H / 2 + 4)}
319
+ >
320
+ {line}
321
+ </tspan>
322
+ {/each}
323
+ </text>
324
+ {#each subLines as line, si (si)}
325
+ <text
326
+ x={r1(b.x + b.w / 2)}
327
+ y={r1(
328
+ textTop +
329
+ labelLines.length * NODE_LINE_H +
330
+ 4 +
331
+ (NODE_LINE_H - 4) * si +
332
+ 4,
333
+ )}
334
+ text-anchor="middle"
335
+ class="fill-base-content/60 text-2xs"
336
+ >
337
+ {line}
338
+ </text>
339
+ {/each}
340
+ <title
341
+ >{b.sublabel ? `${b.label} (${b.sublabel})` : b.label}</title
342
+ >
343
+ </g>
344
+ {/each}
345
+ {/if}
346
+ </svg>
347
+ </div>
348
+ {/if}
349
+
350
+ <!-- accessible structure fallback: sr-only table always; expandable -->
351
+ <div class="mt-1.5 flex items-center justify-between gap-2">
352
+ <span class="text-2xs text-base-content/45">
353
+ {isSeq
354
+ ? `${params.nodes.length} actors · ${params.edges.length} messages`
355
+ : `${params.nodes.length} nodes · ${params.edges.length} edges`}
356
+ </span>
357
+ <button
358
+ type="button"
359
+ class="btn btn-ghost btn-xs text-base-content/70"
360
+ aria-expanded={dataOpen}
361
+ aria-controls={tableId}
362
+ onclick={() => (dataOpen = !dataOpen)}
363
+ >
364
+ {dataOpen ? "Hide structure" : "View structure"}
365
+ </button>
366
+ </div>
367
+ <div
368
+ class={dataOpen
369
+ ? "mt-1 max-h-64 overflow-auto rounded-box border border-base-content/10"
370
+ : ""}
371
+ >
372
+ <table id={tableId} class={dataOpen ? "table table-sm" : "sr-only"}>
373
+ <caption class="sr-only">
374
+ Diagram structure{params.title ? `: ${params.title}` : ""}
375
+ </caption>
376
+ <thead>
377
+ <tr>
378
+ <th scope="col" class="text-left">Element</th>
379
+ <th scope="col" class="text-left">Detail</th>
380
+ </tr>
381
+ </thead>
382
+ <tbody>
383
+ {#each rows as row, ri (ri)}
384
+ <tr>
385
+ <th scope="row" class="text-left font-normal">{row.label}</th>
386
+ <td class="text-left">{row.detail}</td>
387
+ </tr>
388
+ {/each}
389
+ </tbody>
390
+ </table>
391
+ </div>
392
+ </figure>
@@ -0,0 +1,30 @@
1
+ import type { BlockProps } from "../../types.js";
2
+ declare const DiagramBlock: import("svelte").Component<BlockProps<{
3
+ mode: "flow" | "sequence";
4
+ direction: "BT" | "LR" | "RL" | "TB";
5
+ nodes: {
6
+ id: string;
7
+ label: string;
8
+ sublabel?: string | undefined;
9
+ kind?: "data" | "input" | "output" | "note" | "default" | "decision" | "external" | "terminal" | "process" | "subroutine" | undefined;
10
+ tone?: "error" | "warning" | "info" | "success" | "primary" | "secondary" | "neutral" | "accent" | undefined;
11
+ shape?: "circle" | "rect" | "stadium" | "pill" | "diamond" | undefined;
12
+ }[];
13
+ edges: {
14
+ from: string;
15
+ to: string;
16
+ label?: string | undefined;
17
+ dashed?: boolean | undefined;
18
+ tone?: "error" | "warning" | "info" | "success" | "primary" | "secondary" | "neutral" | "accent" | undefined;
19
+ }[];
20
+ edgeLabels: boolean;
21
+ title?: string | undefined;
22
+ subtitle?: string | undefined;
23
+ ranksep?: number | undefined;
24
+ nodesep?: number | undefined;
25
+ edgesep?: number | undefined;
26
+ sequenceWidth?: number | undefined;
27
+ msgGap?: number | undefined;
28
+ }>, {}, "">;
29
+ type DiagramBlock = ReturnType<typeof DiagramBlock>;
30
+ export default DiagramBlock;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Diagram block definition (block type "diagram").
3
+ * Contract: src/lib/artifact-blocks/CONTRACT.md — registry.ts discovers this
4
+ * folder; nothing else registers a block.
5
+ */
6
+ import type { ArtifactBlockDef } from "../../types.js";
7
+ import { type DiagramParams } from "./schema.js";
8
+ declare const def: ArtifactBlockDef<DiagramParams>;
9
+ export default def;
@@ -0,0 +1,50 @@
1
+ import { diagramParamsSchema as diagramSchema, } from "./schema.js";
2
+ import DiagramBlock from "./DiagramBlock.svelte";
3
+ const EXAMPLE = {
4
+ mode: "flow",
5
+ direction: "LR",
6
+ title: "Release pipeline",
7
+ subtitle: "PR merge → production deploy",
8
+ edgeLabels: true,
9
+ nodes: [
10
+ { id: "pr", label: "PR opened", kind: "terminal", tone: "primary" },
11
+ { id: "ci", label: "CI green?", kind: "decision", tone: "warning" },
12
+ { id: "fix", label: "Fix and re-push", kind: "process" },
13
+ { id: "stage", label: "Deploy to staging", kind: "process", tone: "info" },
14
+ { id: "smoke", label: "Smoke test", kind: "process", tone: "info" },
15
+ { id: "prod", label: "Promote to prod", kind: "terminal", tone: "success" },
16
+ ],
17
+ edges: [
18
+ { from: "pr", to: "ci", label: "push" },
19
+ { from: "ci", to: "fix", label: "red", tone: "error", dashed: true },
20
+ { from: "fix", to: "ci", label: "retry", dashed: true },
21
+ { from: "ci", to: "stage", label: "green" },
22
+ { from: "stage", to: "smoke" },
23
+ { from: "smoke", to: "prod", label: "pass" },
24
+ ],
25
+ };
26
+ const def = {
27
+ type: "diagram",
28
+ title: "Diagram (flow / org / sequence)",
29
+ description: "Nodes + edges as a read-only SVG diagram with automatic layered layout. " +
30
+ "mode 'flow' (default) draws flowcharts, org charts and architecture maps: nodes are " +
31
+ "{ id, label, sublabel?, kind?, tone?, shape? } and edges { from, to, label?, dashed?, tone? } " +
32
+ "(from/to reference node ids; every edge endpoint must exist; no self-loops). " +
33
+ "kind picks a default shape — decision=diamond, terminal=stadium, input/output=pill, " +
34
+ "others=rect — or set shape explicitly (rect | pill | diamond | circle | stadium). " +
35
+ "tone is a theme token (primary/secondary/accent/neutral/info/success/warning/error); " +
36
+ "neutral is the default and the safest for big diagrams. direction LR (default), RL, TB or BT. " +
37
+ "Edge labels render with a page-colored halo when edgeLabels is true (default). " +
38
+ "mode 'sequence' draws the SAME nodes as actors (labels must be unique) and the edges as " +
39
+ "lifeline messages top-to-bottom — dashed:true reads as a return/async message. " +
40
+ "Caps: 50 nodes, 80 edges; labels ≤200 chars; spacing tunable via ranksep/nodesep (flow) " +
41
+ "and sequenceWidth/msgGap (sequence). An accessible structure table is built in ('View data') " +
42
+ "— don't pair a diagram with a duplicate node list. Tip: keep labels under ~4 words so boxes " +
43
+ "stay small; use tone sparingly to mark the one path that matters.",
44
+ schema: diagramSchema,
45
+ component: DiagramBlock,
46
+ // mos-8fvt9: the section's Listen + comment sit on the heading row.
47
+ hostsTools: (p) => Boolean(p.title),
48
+ example: EXAMPLE,
49
+ };
50
+ export default def;
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Diagram block — layout constants (pure numbers, no colors).
3
+ *
4
+ * schema.ts sizes boxes from a deterministic text estimate so SSR and the
5
+ * client agree byte-for-byte without a canvas; the renderer maps tones to
6
+ * theme-token classes (never literals). All values are px unless noted.
7
+ */
8
+ export declare const MAX_NODES = 50;
9
+ export declare const MAX_EDGES = 80;
10
+ /** Node label / sublabel and edge label text caps (chars). */
11
+ export declare const NODE_TEXT_MAX = 200;
12
+ export declare const EDGE_TEXT_MAX = 200;
13
+ export declare const DEFAULT_RANKSEP = 60;
14
+ export declare const DEFAULT_NODESEP = 28;
15
+ export declare const DEFAULT_EDGESEP = 14;
16
+ export declare const MIN_RANKSEP = 24;
17
+ export declare const MIN_NODESEP = 12;
18
+ export declare const NODE_PAD_X = 16;
19
+ export declare const NODE_PAD_Y = 11;
20
+ export declare const NODE_LINE_H = 18;
21
+ /** ≈ average glyph width of 13px system-ui semibold. */
22
+ export declare const NODE_CHAR_W = 7;
23
+ /** ≈ average glyph width of the 11px regular sublabel. */
24
+ export declare const SUB_CHAR_W = 6;
25
+ export declare const NODE_MAX_LINES = 3;
26
+ export declare const NODE_MIN_W = 92;
27
+ export declare const NODE_MAX_W = 280;
28
+ export declare const NODE_MIN_H = 36;
29
+ /** Fraction of a diamond's width the centered text may occupy. */
30
+ export declare const DIAMOND_TEXT_FACTOR = 0.6;
31
+ export declare const CIRCLE_MIN = 72;
32
+ export declare const SEQ_ACTOR_H = 36;
33
+ export declare const SEQ_ACTOR_PAD_X = 18;
34
+ export declare const SEQ_ACTOR_MIN_W = 96;
35
+ export declare const SEQ_ACTOR_MAX_W = 220;
36
+ export declare const SEQ_MSG_GAP_DEFAULT = 48;
37
+ export declare const SEQ_MSG_GAP_MIN = 24;
38
+ export declare const SEQ_ROW_PAD = 18;
39
+ export declare const SEQ_PAD_X = 20;
40
+ export declare const SEQ_COL_MIN = 150;
41
+ export declare const SEQ_LABEL_CHAR_W = 5.9;
42
+ export declare const SEQ_WIDTH_DEFAULT = 900;
43
+ export declare const SEQ_WIDTH_MIN = 320;
44
+ export declare const SEQ_WIDTH_MAX = 2200;
45
+ export declare const EDGE_LABEL_W = 80;
46
+ export declare const EDGE_LABEL_H = 20;
47
+ /** Viewport padding around the laid-out graph. */
48
+ export declare const VIEW_PAD = 14;