@misoto22/design 0.7.0 → 0.8.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 (369) hide show
  1. package/AGENTS.md +87 -0
  2. package/CLAUDE.md +1 -0
  3. package/README.md +50 -5
  4. package/bin/misoto22-design.mjs +59 -13
  5. package/dist/agent/Accordion.md +24 -1
  6. package/dist/agent/Alert.md +23 -1
  7. package/dist/agent/AppShell.md +30 -2
  8. package/dist/agent/ArchitectureFigure.md +25 -2
  9. package/dist/agent/AreaChart.md +27 -2
  10. package/dist/agent/Article.md +26 -3
  11. package/dist/agent/AspectRatio.md +57 -0
  12. package/dist/agent/Avatar.md +25 -5
  13. package/dist/agent/Badge.md +22 -1
  14. package/dist/agent/BarChart.md +29 -2
  15. package/dist/agent/BarList.md +27 -1
  16. package/dist/agent/BigNumber.md +26 -2
  17. package/dist/agent/BoxPlot.md +24 -1
  18. package/dist/agent/Breadcrumb.md +24 -2
  19. package/dist/agent/BulletChart.md +23 -1
  20. package/dist/agent/Button.md +25 -1
  21. package/dist/agent/Calendar.md +37 -3
  22. package/dist/agent/Card.md +24 -2
  23. package/dist/agent/Checkbox.md +23 -2
  24. package/dist/agent/Code.md +50 -0
  25. package/dist/agent/CodeBlock.md +74 -0
  26. package/dist/agent/Collapsible.md +22 -1
  27. package/dist/agent/Combobox.md +29 -3
  28. package/dist/agent/Command.md +25 -2
  29. package/dist/agent/ComposedChart.md +26 -2
  30. package/dist/agent/ContextMenu.md +37 -4
  31. package/dist/agent/DataflowFigure.md +22 -1
  32. package/dist/agent/DatePicker.md +34 -6
  33. package/dist/agent/DescriptionList.md +68 -0
  34. package/dist/agent/Diagram.md +27 -3
  35. package/dist/agent/DiagramCanvas.md +24 -1
  36. package/dist/agent/DiagramExportMenu.md +29 -3
  37. package/dist/agent/DiagramInspector.md +23 -1
  38. package/dist/agent/DiagramLegend.md +22 -1
  39. package/dist/agent/DiagramMinimap.md +24 -4
  40. package/dist/agent/DiagramToolbar.md +23 -1
  41. package/dist/agent/Dialog.md +26 -3
  42. package/dist/agent/DropdownMenu.md +45 -6
  43. package/dist/agent/EmptyState.md +26 -1
  44. package/dist/agent/ErrorState.md +27 -2
  45. package/dist/agent/Facet.md +25 -1
  46. package/dist/agent/Field.md +45 -4
  47. package/dist/agent/FigureBand.md +24 -1
  48. package/dist/agent/FloatingIconButton.md +23 -1
  49. package/dist/agent/FunnelChart.md +23 -1
  50. package/dist/agent/Heading.md +64 -0
  51. package/dist/agent/Heatmap.md +25 -1
  52. package/dist/agent/Histogram.md +26 -2
  53. package/dist/agent/Input.md +22 -1
  54. package/dist/agent/Kbd.md +19 -1
  55. package/dist/agent/LifecycleFigure.md +22 -1
  56. package/dist/agent/LineChart.md +26 -2
  57. package/dist/agent/LinkArrow.md +20 -1
  58. package/dist/agent/Markdown.md +68 -0
  59. package/dist/agent/NativeSelect.md +23 -2
  60. package/dist/agent/NavItem.md +21 -1
  61. package/dist/agent/Pagination.md +28 -2
  62. package/dist/agent/PieChart.md +26 -2
  63. package/dist/agent/Popover.md +23 -1
  64. package/dist/agent/Progress.md +27 -3
  65. package/dist/agent/RadarChart.md +26 -2
  66. package/dist/agent/RadialChart.md +26 -3
  67. package/dist/agent/RadioGroup.md +23 -2
  68. package/dist/agent/SankeyChart.md +25 -2
  69. package/dist/agent/ScatterChart.md +27 -2
  70. package/dist/agent/ScrollArea.md +24 -3
  71. package/dist/agent/SearchableMenu.md +23 -1
  72. package/dist/agent/Select.md +29 -3
  73. package/dist/agent/Separator.md +28 -4
  74. package/dist/agent/SequenceFigure.md +23 -1
  75. package/dist/agent/Sheet.md +25 -2
  76. package/dist/agent/Skeleton.md +24 -2
  77. package/dist/agent/Slider.md +27 -4
  78. package/dist/agent/Sparkline.md +23 -1
  79. package/dist/agent/Spinner.md +24 -2
  80. package/dist/agent/StatusDot.md +20 -1
  81. package/dist/agent/StatusPill.md +28 -2
  82. package/dist/agent/Steps.md +24 -1
  83. package/dist/agent/Switch.md +21 -1
  84. package/dist/agent/Table.md +26 -3
  85. package/dist/agent/Tabs.md +24 -2
  86. package/dist/agent/Tag.md +40 -9
  87. package/dist/agent/Text.md +65 -0
  88. package/dist/agent/Textarea.md +20 -1
  89. package/dist/agent/Timestamp.md +64 -0
  90. package/dist/agent/Toast.md +26 -2
  91. package/dist/agent/ToggleGroup.md +24 -2
  92. package/dist/agent/Toolbar.md +71 -0
  93. package/dist/agent/Tooltip.md +23 -1
  94. package/dist/agent/TreemapChart.md +24 -1
  95. package/dist/agent/WaterfallChart.md +24 -1
  96. package/dist/agent/WorkflowFigure.md +24 -2
  97. package/dist/agent/catalog.json +5602 -745
  98. package/dist/agent/index.md +13 -4
  99. package/dist/article.css +16 -4
  100. package/dist/charts/AreaChart/AreaChart.d.ts +9 -2
  101. package/dist/charts/AreaChart/AreaChart.js +12 -13
  102. package/dist/charts/AreaChart/AreaChart.js.map +1 -1
  103. package/dist/charts/BarChart/BarChart.d.ts +14 -3
  104. package/dist/charts/BarChart/BarChart.js +20 -12
  105. package/dist/charts/BarChart/BarChart.js.map +1 -1
  106. package/dist/charts/BarList/BarList.d.ts +9 -1
  107. package/dist/charts/BarList/BarList.js +9 -1
  108. package/dist/charts/BarList/BarList.js.map +1 -1
  109. package/dist/charts/BigNumber/BigNumber.d.ts +19 -3
  110. package/dist/charts/BigNumber/BigNumber.js +25 -5
  111. package/dist/charts/BigNumber/BigNumber.js.map +1 -1
  112. package/dist/charts/BoxPlot/BoxPlot.js +4 -2
  113. package/dist/charts/BoxPlot/BoxPlot.js.map +1 -1
  114. package/dist/charts/BulletChart/BulletChart.js +28 -7
  115. package/dist/charts/BulletChart/BulletChart.js.map +1 -1
  116. package/dist/charts/ComposedChart/ComposedChart.d.ts +9 -2
  117. package/dist/charts/ComposedChart/ComposedChart.js +10 -10
  118. package/dist/charts/ComposedChart/ComposedChart.js.map +1 -1
  119. package/dist/charts/FunnelChart/FunnelChart.d.ts +7 -2
  120. package/dist/charts/FunnelChart/FunnelChart.js +6 -16
  121. package/dist/charts/FunnelChart/FunnelChart.js.map +1 -1
  122. package/dist/charts/Heatmap/Heatmap.d.ts +17 -3
  123. package/dist/charts/Heatmap/Heatmap.js +20 -11
  124. package/dist/charts/Heatmap/Heatmap.js.map +1 -1
  125. package/dist/charts/Histogram/Histogram.d.ts +24 -1
  126. package/dist/charts/Histogram/Histogram.js +43 -11
  127. package/dist/charts/Histogram/Histogram.js.map +1 -1
  128. package/dist/charts/LineChart/LineChart.d.ts +9 -2
  129. package/dist/charts/LineChart/LineChart.js +11 -12
  130. package/dist/charts/LineChart/LineChart.js.map +1 -1
  131. package/dist/charts/PieChart/PieChart.d.ts +15 -3
  132. package/dist/charts/PieChart/PieChart.js +14 -6
  133. package/dist/charts/PieChart/PieChart.js.map +1 -1
  134. package/dist/charts/RadarChart/RadarChart.d.ts +15 -3
  135. package/dist/charts/RadarChart/RadarChart.js +11 -9
  136. package/dist/charts/RadarChart/RadarChart.js.map +1 -1
  137. package/dist/charts/RadialChart/RadialChart.d.ts +22 -4
  138. package/dist/charts/RadialChart/RadialChart.js +28 -6
  139. package/dist/charts/RadialChart/RadialChart.js.map +1 -1
  140. package/dist/charts/SankeyChart/SankeyChart.d.ts +16 -4
  141. package/dist/charts/SankeyChart/SankeyChart.js +14 -6
  142. package/dist/charts/SankeyChart/SankeyChart.js.map +1 -1
  143. package/dist/charts/ScatterChart/ScatterChart.d.ts +24 -3
  144. package/dist/charts/ScatterChart/ScatterChart.js +21 -15
  145. package/dist/charts/ScatterChart/ScatterChart.js.map +1 -1
  146. package/dist/charts/Sparkline/Sparkline.js +5 -3
  147. package/dist/charts/Sparkline/Sparkline.js.map +1 -1
  148. package/dist/charts/TreemapChart/TreemapChart.d.ts +7 -2
  149. package/dist/charts/TreemapChart/TreemapChart.js +20 -11
  150. package/dist/charts/TreemapChart/TreemapChart.js.map +1 -1
  151. package/dist/charts/WaterfallChart/WaterfallChart.js +4 -2
  152. package/dist/charts/WaterfallChart/WaterfallChart.js.map +1 -1
  153. package/dist/charts/lib/export.d.ts +1 -0
  154. package/dist/charts/lib/figure.d.ts +21 -1
  155. package/dist/charts/lib/figure.js +5 -2
  156. package/dist/charts/lib/figure.js.map +1 -1
  157. package/dist/charts/lib/scale.d.ts +23 -0
  158. package/dist/charts/lib/scale.js +13 -0
  159. package/dist/charts/lib/scale.js.map +1 -0
  160. package/dist/charts/lib/selection.d.ts +20 -0
  161. package/dist/charts/lib/selection.js +18 -0
  162. package/dist/charts/lib/selection.js.map +1 -0
  163. package/dist/charts/lib/toolbar.d.ts +1 -0
  164. package/dist/components/Accordion/Accordion.js +8 -1
  165. package/dist/components/Accordion/Accordion.js.map +1 -1
  166. package/dist/components/AppShell/AppShell.d.ts +6 -0
  167. package/dist/components/AppShell/AppShell.js +34 -4
  168. package/dist/components/AppShell/AppShell.js.map +1 -1
  169. package/dist/components/Article/Article.d.ts +11 -4
  170. package/dist/components/Article/Article.js +13 -0
  171. package/dist/components/Article/Article.js.map +1 -1
  172. package/dist/components/AspectRatio/AspectRatio.d.ts +46 -0
  173. package/dist/components/AspectRatio/AspectRatio.js +33 -0
  174. package/dist/components/AspectRatio/AspectRatio.js.map +1 -0
  175. package/dist/components/Avatar/Avatar.d.ts +12 -3
  176. package/dist/components/Avatar/Avatar.js +6 -1
  177. package/dist/components/Avatar/Avatar.js.map +1 -1
  178. package/dist/components/Breadcrumb/Breadcrumb.d.ts +6 -0
  179. package/dist/components/Breadcrumb/Breadcrumb.js +15 -0
  180. package/dist/components/Breadcrumb/Breadcrumb.js.map +1 -1
  181. package/dist/components/Button/Button.js +14 -0
  182. package/dist/components/Button/Button.js.map +1 -1
  183. package/dist/components/Calendar/Calendar.d.ts +29 -3
  184. package/dist/components/Calendar/Calendar.js +60 -12
  185. package/dist/components/Calendar/Calendar.js.map +1 -1
  186. package/dist/components/Card/Card.d.ts +6 -0
  187. package/dist/components/Card/Card.js +1 -1
  188. package/dist/components/Card/Card.js.map +1 -1
  189. package/dist/components/Checkbox/Checkbox.d.ts +5 -2
  190. package/dist/components/Checkbox/Checkbox.js +12 -2
  191. package/dist/components/Checkbox/Checkbox.js.map +1 -1
  192. package/dist/components/Code/Code.d.ts +30 -0
  193. package/dist/components/Code/Code.js +21 -0
  194. package/dist/components/Code/Code.js.map +1 -0
  195. package/dist/components/CodeBlock/CodeBlock.d.ts +141 -0
  196. package/dist/components/CodeBlock/CodeBlock.js +123 -0
  197. package/dist/components/CodeBlock/CodeBlock.js.map +1 -0
  198. package/dist/components/Collapsible/Collapsible.js +10 -2
  199. package/dist/components/Collapsible/Collapsible.js.map +1 -1
  200. package/dist/components/Combobox/Combobox.d.ts +15 -1
  201. package/dist/components/Combobox/Combobox.js +25 -5
  202. package/dist/components/Combobox/Combobox.js.map +1 -1
  203. package/dist/components/Command/Command.d.ts +4 -2
  204. package/dist/components/Command/Command.js +13 -1
  205. package/dist/components/Command/Command.js.map +1 -1
  206. package/dist/components/ContextMenu/ContextMenu.d.ts +30 -5
  207. package/dist/components/ContextMenu/ContextMenu.js +32 -2
  208. package/dist/components/ContextMenu/ContextMenu.js.map +1 -1
  209. package/dist/components/DatePicker/DatePicker.d.ts +36 -4
  210. package/dist/components/DatePicker/DatePicker.js +55 -12
  211. package/dist/components/DatePicker/DatePicker.js.map +1 -1
  212. package/dist/components/DescriptionList/DescriptionList.d.ts +73 -0
  213. package/dist/components/DescriptionList/DescriptionList.js +35 -0
  214. package/dist/components/DescriptionList/DescriptionList.js.map +1 -0
  215. package/dist/components/Diagram/Diagram.d.ts +8 -3
  216. package/dist/components/Diagram/Diagram.js +82 -10
  217. package/dist/components/Diagram/Diagram.js.map +1 -1
  218. package/dist/components/Dialog/Dialog.d.ts +18 -3
  219. package/dist/components/Dialog/Dialog.js +20 -2
  220. package/dist/components/Dialog/Dialog.js.map +1 -1
  221. package/dist/components/DropdownMenu/DropdownMenu.d.ts +49 -11
  222. package/dist/components/DropdownMenu/DropdownMenu.js +32 -2
  223. package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -1
  224. package/dist/components/EmptyState/EmptyState.d.ts +25 -1
  225. package/dist/components/EmptyState/EmptyState.js +3 -1
  226. package/dist/components/EmptyState/EmptyState.js.map +1 -1
  227. package/dist/components/ErrorState/ErrorState.d.ts +22 -1
  228. package/dist/components/ErrorState/ErrorState.js +11 -2
  229. package/dist/components/ErrorState/ErrorState.js.map +1 -1
  230. package/dist/components/Field/Field.d.ts +70 -3
  231. package/dist/components/Field/Field.js +53 -12
  232. package/dist/components/Field/Field.js.map +1 -1
  233. package/dist/components/Field/field-control.d.ts +31 -0
  234. package/dist/components/Field/field-control.js +12 -0
  235. package/dist/components/Field/field-control.js.map +1 -0
  236. package/dist/components/FloatingIconButton/FloatingIconButton.js +2 -0
  237. package/dist/components/FloatingIconButton/FloatingIconButton.js.map +1 -1
  238. package/dist/components/Heading/Heading.d.ts +62 -0
  239. package/dist/components/Heading/Heading.js +44 -0
  240. package/dist/components/Heading/Heading.js.map +1 -0
  241. package/dist/components/Markdown/Markdown.d.ts +139 -0
  242. package/dist/components/Markdown/Markdown.js +135 -0
  243. package/dist/components/Markdown/Markdown.js.map +1 -0
  244. package/dist/components/Markdown/inline.d.ts +29 -0
  245. package/dist/components/Markdown/inline.js +74 -0
  246. package/dist/components/Markdown/inline.js.map +1 -0
  247. package/dist/components/Markdown/nodes.d.ts +65 -0
  248. package/dist/components/Markdown/nodes.js +1 -0
  249. package/dist/components/Markdown/nodes.js.map +1 -0
  250. package/dist/components/Markdown/parse.d.ts +24 -0
  251. package/dist/components/Markdown/parse.js +110 -0
  252. package/dist/components/Markdown/parse.js.map +1 -0
  253. package/dist/components/Markdown/slug.d.ts +15 -0
  254. package/dist/components/Markdown/slug.js +7 -0
  255. package/dist/components/Markdown/slug.js.map +1 -0
  256. package/dist/components/NativeSelect/NativeSelect.d.ts +6 -0
  257. package/dist/components/NativeSelect/NativeSelect.js +2 -3
  258. package/dist/components/NativeSelect/NativeSelect.js.map +1 -1
  259. package/dist/components/Pagination/Pagination.d.ts +24 -1
  260. package/dist/components/Pagination/Pagination.js +6 -3
  261. package/dist/components/Pagination/Pagination.js.map +1 -1
  262. package/dist/components/Progress/Progress.d.ts +17 -5
  263. package/dist/components/Progress/Progress.js +18 -6
  264. package/dist/components/Progress/Progress.js.map +1 -1
  265. package/dist/components/RadioGroup/RadioGroup.d.ts +6 -0
  266. package/dist/components/RadioGroup/RadioGroup.js +11 -1
  267. package/dist/components/RadioGroup/RadioGroup.js.map +1 -1
  268. package/dist/components/ScrollArea/ScrollArea.d.ts +15 -0
  269. package/dist/components/ScrollArea/ScrollArea.js +2 -2
  270. package/dist/components/ScrollArea/ScrollArea.js.map +1 -1
  271. package/dist/components/SearchableMenu/SearchableMenu.d.ts +11 -2
  272. package/dist/components/SearchableMenu/SearchableMenu.js +24 -2
  273. package/dist/components/SearchableMenu/SearchableMenu.js.map +1 -1
  274. package/dist/components/Select/Select.d.ts +18 -2
  275. package/dist/components/Select/Select.js +20 -3
  276. package/dist/components/Select/Select.js.map +1 -1
  277. package/dist/components/Separator/Separator.d.ts +21 -3
  278. package/dist/components/Separator/Separator.js +9 -1
  279. package/dist/components/Separator/Separator.js.map +1 -1
  280. package/dist/components/Sheet/Sheet.d.ts +3 -0
  281. package/dist/components/Sheet/Sheet.js +11 -2
  282. package/dist/components/Sheet/Sheet.js.map +1 -1
  283. package/dist/components/Skeleton/Skeleton.d.ts +8 -1
  284. package/dist/components/Skeleton/Skeleton.js +1 -1
  285. package/dist/components/Skeleton/Skeleton.js.map +1 -1
  286. package/dist/components/Slider/Slider.d.ts +21 -3
  287. package/dist/components/Slider/Slider.js +54 -27
  288. package/dist/components/Slider/Slider.js.map +1 -1
  289. package/dist/components/Spinner/Spinner.d.ts +8 -0
  290. package/dist/components/Spinner/Spinner.js +3 -2
  291. package/dist/components/Spinner/Spinner.js.map +1 -1
  292. package/dist/components/StatusPill/StatusPill.d.ts +5 -0
  293. package/dist/components/StatusPill/StatusPill.js +6 -0
  294. package/dist/components/StatusPill/StatusPill.js.map +1 -1
  295. package/dist/components/Table/Table.d.ts +6 -0
  296. package/dist/components/Table/Table.js +3 -1
  297. package/dist/components/Table/Table.js.map +1 -1
  298. package/dist/components/Tag/Tag.d.ts +68 -9
  299. package/dist/components/Tag/Tag.js +50 -10
  300. package/dist/components/Tag/Tag.js.map +1 -1
  301. package/dist/components/Text/Text.d.ts +62 -0
  302. package/dist/components/Text/Text.js +30 -0
  303. package/dist/components/Text/Text.js.map +1 -0
  304. package/dist/components/Timestamp/Timestamp.d.ts +59 -0
  305. package/dist/components/Timestamp/Timestamp.js +56 -0
  306. package/dist/components/Timestamp/Timestamp.js.map +1 -0
  307. package/dist/components/Toast/Toast.d.ts +9 -1
  308. package/dist/components/Toast/Toast.js +27 -4
  309. package/dist/components/Toast/Toast.js.map +1 -1
  310. package/dist/components/ToggleGroup/ToggleGroup.d.ts +6 -1
  311. package/dist/components/ToggleGroup/ToggleGroup.js +11 -1
  312. package/dist/components/ToggleGroup/ToggleGroup.js.map +1 -1
  313. package/dist/components/Toolbar/Toolbar.d.ts +55 -0
  314. package/dist/components/Toolbar/Toolbar.js +43 -0
  315. package/dist/components/Toolbar/Toolbar.js.map +1 -0
  316. package/dist/diagrams/ArchitectureFigure/ArchitectureFigure.d.ts +6 -0
  317. package/dist/diagrams/ArchitectureFigure/ArchitectureFigure.js +48 -8
  318. package/dist/diagrams/ArchitectureFigure/ArchitectureFigure.js.map +1 -1
  319. package/dist/diagrams/DataflowFigure/DataflowFigure.js +21 -2
  320. package/dist/diagrams/DataflowFigure/DataflowFigure.js.map +1 -1
  321. package/dist/diagrams/DiagramCanvas/DiagramCanvas.d.ts +14 -0
  322. package/dist/diagrams/DiagramCanvas/DiagramCanvas.js +14 -7
  323. package/dist/diagrams/DiagramCanvas/DiagramCanvas.js.map +1 -1
  324. package/dist/diagrams/DiagramExportMenu/DiagramExportMenu.d.ts +38 -4
  325. package/dist/diagrams/DiagramExportMenu/DiagramExportMenu.js +14 -16
  326. package/dist/diagrams/DiagramExportMenu/DiagramExportMenu.js.map +1 -1
  327. package/dist/diagrams/DiagramInspector/DiagramInspector.js +2 -2
  328. package/dist/diagrams/DiagramInspector/DiagramInspector.js.map +1 -1
  329. package/dist/diagrams/DiagramMinimap/DiagramMinimap.d.ts +23 -7
  330. package/dist/diagrams/DiagramMinimap/DiagramMinimap.js +45 -18
  331. package/dist/diagrams/DiagramMinimap/DiagramMinimap.js.map +1 -1
  332. package/dist/diagrams/LifecycleFigure/LifecycleFigure.js +44 -12
  333. package/dist/diagrams/LifecycleFigure/LifecycleFigure.js.map +1 -1
  334. package/dist/diagrams/SequenceFigure/SequenceFigure.js +35 -5
  335. package/dist/diagrams/SequenceFigure/SequenceFigure.js.map +1 -1
  336. package/dist/diagrams/WorkflowFigure/WorkflowFigure.d.ts +3 -1
  337. package/dist/diagrams/WorkflowFigure/WorkflowFigure.js +76 -28
  338. package/dist/diagrams/WorkflowFigure/WorkflowFigure.js.map +1 -1
  339. package/dist/diagrams/index.d.ts +1 -0
  340. package/dist/diagrams/index.js +10 -0
  341. package/dist/diagrams/index.js.map +1 -1
  342. package/dist/diagrams/lib/dev.d.ts +61 -0
  343. package/dist/diagrams/lib/dev.js +96 -0
  344. package/dist/diagrams/lib/dev.js.map +1 -0
  345. package/dist/diagrams/lib/frame.d.ts +48 -7
  346. package/dist/diagrams/lib/frame.js +17 -2
  347. package/dist/diagrams/lib/frame.js.map +1 -1
  348. package/dist/diagrams/lib/wires.js.map +1 -1
  349. package/dist/diagrams/spec.d.ts +64 -12
  350. package/dist/index.d.ts +16 -4
  351. package/dist/index.js +9 -0
  352. package/dist/index.js.map +1 -1
  353. package/dist/keyframes.css +57 -3
  354. package/dist/lib/overlay-container.d.ts +14 -4
  355. package/dist/lib/overlay-container.js.map +1 -1
  356. package/dist/lib/warn.d.ts +73 -0
  357. package/dist/lib/warn.js +38 -0
  358. package/dist/lib/warn.js.map +1 -0
  359. package/dist/semantic.css +17 -6
  360. package/dist/styles.css +1 -1
  361. package/dist/tokens.css +20 -2
  362. package/dist/tokens.d.ts +1 -1
  363. package/dist/tokens.js +39 -36
  364. package/dist/tokens.json +39 -36
  365. package/llms.txt +35 -0
  366. package/package.json +5 -2
  367. package/skills/misoto22-design/evals/evals.json +84 -0
  368. package/skills/misoto22-design/rules/a11y.md +55 -3
  369. package/skills/misoto22-design/rules/forms.md +5 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/diagrams/WorkflowFigure/WorkflowFigure.tsx"],"sourcesContent":["'use client'\n\nimport { useId, useMemo } from 'react'\nimport { DiagramFrame, type FigureChrome, type FigureModel } from '../lib/frame'\nimport { inflate, round, textWidth, TYPE, union, wrapText, type Box } from '../lib/geometry'\nimport { resolveLegend, variantLegend } from '../lib/legend'\nimport { BandFrame, NodePlate, PLATE, plateHeight } from '../lib/marks'\nimport { renderWires, wiresFor, type Wire } from '../lib/wires'\nimport type { Variant, WorkflowEdge, WorkflowSpec } from '../spec'\n\nconst VARIANTS: (Variant | 'return')[] = ['default', 'emphasis', 'security', 'dashed']\n\nconst GRID = {\n /** The gutter the lane names live in. */\n railW: 118,\n originY: 74,\n colW: 168,\n gapX: 58,\n laneH: 92,\n laneGap: 40,\n}\n\nexport interface WorkflowFigureProps extends FigureChrome {\n spec: WorkflowSpec\n}\n\n/**\n * A process: who does what, in what order, and where it can go wrong.\n *\n * Three structures stacked on one grid, and they are three because they answer\n * three different questions a reader brings to a runbook.\n *\n * **Lanes** are rows and answer WHO. A lane marked `exception` is the one band\n * that gets a wash rather than a rule, and it earns the exception to the\n * frames-are-rules law because nothing routes across it — it IS the ground for\n * the failure path, not a frame drawn over the happy one.\n *\n * **Phases** are columns across every lane and answer WHEN. Printed as captions\n * on one header rule, because a phase is an axis label. **Groups** are frames\n * inside a single lane and answer WHAT BELONGS TOGETHER — a planning loop, an\n * evidence path.\n *\n * THE MAIN PATH IS HEAVIER, and that is the whole hierarchy. `mainPath` lists\n * the node ids a reader should be able to follow without thinking. Every edge\n * between two consecutive ids on it is drawn at the emphasis weight whatever\n * its own variant says, which is the one thing that turns fourteen boxes and\n * nineteen arrows into a diagram with a subject. An `error` role goes the other\n * way — dashed and soft — so the exception path recedes without disappearing.\n */\nexport function WorkflowFigure({\n spec,\n className,\n legend = 'auto',\n cards = true,\n heading = true,\n activeIds,\n onSelectNode,\n}: WorkflowFigureProps) {\n const uid = useId().replace(/:/g, '')\n const model = useMemo(\n () => buildModel(spec, uid, activeIds, onSelectNode),\n [spec, uid, activeIds, onSelectNode],\n )\n\n return (\n <DiagramFrame\n meta={spec.meta}\n model={model}\n cards={spec.cards}\n showCards={cards}\n heading={heading}\n legend={legend}\n className={className}\n activeIds={activeIds}\n onSelectNode={onSelectNode}\n />\n )\n}\n\n/** The x of a column's left edge, and of the whole span from `from` to `to`. */\nconst colX = (col: number) => GRID.railW + col * (GRID.colW + GRID.gapX)\nconst spanBox = (fromCol: number, toCol: number, y: number, h: number): Box => ({\n x: colX(fromCol),\n y,\n w: colX(toCol) + GRID.colW - colX(fromCol),\n h,\n})\n\nfunction buildModel(\n spec: WorkflowSpec,\n uid: string,\n activeIds: string[] | undefined,\n onSelectNode: ((id: string) => void) | undefined,\n): FigureModel {\n const laneIndex = new Map(spec.lanes.map((lane, index) => [lane.id, index]))\n const laneY = (index: number) => GRID.originY + index * (GRID.laneH + GRID.laneGap)\n\n const boxes = new Map<string, Box>()\n const placed = spec.nodes.map((node) => {\n const w = node.width ?? GRID.colW\n const lines = wrapText(node.label, TYPE.label, w - PLATE.padX * 2, 2)\n const h = plateHeight(lines.length, Boolean(node.sublabel), true, node.height ?? 0)\n const index = laneIndex.get(node.lane) ?? 0\n\n const box: Box = {\n x: colX(node.col),\n y: laneY(index) + (GRID.laneH - h) / 2 + (node.yOffset ?? 0),\n w,\n h,\n }\n boxes.set(node.id, box)\n return { node, box, lane: index }\n })\n\n // Consecutive pairs on the main path, so the edge between them can be drawn\n // at the weight that says \"follow this one\".\n const mainPairs = new Set<string>()\n for (let index = 0; index < (spec.mainPath?.length ?? 0) - 1; index += 1) {\n mainPairs.add(`${spec.mainPath![index]}→${spec.mainPath![index + 1]}`)\n }\n\n const wires = wiresFor(spec.edges, boxes, (edge: WorkflowEdge): Partial<Wire> => {\n const onMain = mainPairs.has(`${edge.from}→${edge.to}`)\n return {\n weight: onMain ? 2.1 : undefined,\n open: edge.role === 'return',\n }\n })\n const { paths, labels } = renderWires(wires, uid)\n\n // A lane's band spans what the lane actually holds. Starting it at the rail\n // instead ran the exception wash under the label gutter, which made the\n // gutter look like part of the band rather than like the axis it is.\n const laneBoxes = spec.lanes.map((lane, index) => {\n const inside = placed.filter((entry) => entry.lane === index).map((entry) => entry.box)\n const span = union(inside)\n const left = span ? span.x - 14 : GRID.railW - 14\n return {\n lane,\n index,\n box: {\n x: left,\n y: laneY(index) - 8,\n w: (span ? span.x + span.w + 14 : colX(0) + GRID.colW) - left,\n h: GRID.laneH + 16,\n } as Box,\n }\n })\n\n const drawn = [...boxes.values(), ...laneBoxes.map((entry) => entry.box)]\n const headerY = GRID.originY - 30\n\n // The frame has to hold what is printed OUTSIDE the boxes too: the lane names\n // in the gutter and the phase captions above the header rule. Sizing the\n // extent from the boxes alone clipped both — and a clipped axis label is the\n // one kind of overflow a reader reads as a broken renderer rather than as a\n // long word.\n const railTextW = Math.max(0, ...spec.lanes.map((lane) => textWidth(lane.label, 9)))\n const raw = union(drawn) ?? { x: 0, y: 0, w: 600, h: 300 }\n const left = Math.min(raw.x, GRID.railW - 26 - railTextW)\n const top = Math.min(raw.y, headerY - 14)\n const extent = inflate(\n { x: left, y: top, w: raw.x + raw.w - left, h: raw.y + raw.h - top },\n 24,\n )\n const active = activeIds && activeIds.length > 0 ? new Set(activeIds) : null\n\n const artwork = (\n <>\n {/* Phases: one header rule across the figure, with a caption per span. */}\n {(spec.phases ?? []).length > 0 && (\n <path\n d={`M ${round(GRID.railW)} ${round(headerY + 8)} H ${round(extent.x + extent.w - 20)}`}\n className=\"stroke-(--diagram-rule)\"\n strokeWidth={1}\n aria-hidden=\"true\"\n />\n )}\n {(spec.phases ?? []).map((phase) => (\n <text\n key={phase.id}\n x={round(colX(phase.fromCol))}\n y={round(headerY)}\n className=\"fill-(--diagram-ink-3) font-mono [font-size:9px] [letter-spacing:0.14em] uppercase\"\n aria-hidden=\"true\"\n >\n {phase.label}\n </text>\n ))}\n\n {/* Lanes. The exception band is the one wash in the system's diagrams. */}\n {laneBoxes.map(({ lane, box }) => (\n <g key={lane.id} aria-hidden=\"true\">\n {lane.variant === 'exception' && (\n <rect\n x={round(box.x)}\n y={round(box.y)}\n width={round(box.w)}\n height={round(box.h)}\n rx={10}\n className=\"fill-(--diagram-band) [rx:var(--radius-lg)] [ry:var(--radius-lg)]\"\n />\n )}\n <text\n x={round(GRID.railW - 26)}\n y={round(box.y + box.h / 2 + 3)}\n textAnchor=\"end\"\n className=\"fill-(--diagram-ink-3) font-mono [font-size:9px] [letter-spacing:0.14em] uppercase\"\n >\n {lane.label}\n </text>\n </g>\n ))}\n\n {/* Groups: a frame inside one lane. */}\n {(spec.groups ?? []).map((group) => {\n const index = laneIndex.get(group.lane) ?? 0\n return (\n <BandFrame\n key={group.id}\n box={spanBox(group.fromCol, group.toCol, laneY(index) - 2, GRID.laneH + 4)}\n label={group.label}\n dashed={group.variant === 'security'}\n />\n )\n })}\n\n {paths}\n\n {placed.map(({ node, box }) => (\n <NodePlate\n key={node.id}\n nodeId={node.id}\n box={box}\n label={node.label}\n sublabel={node.sublabel}\n tag={node.tag}\n kind={node.type}\n active={active?.has(node.id)}\n dimmed={active ? !active.has(node.id) : false}\n onSelect={onSelectNode ? () => onSelectNode(node.id) : undefined}\n />\n ))}\n\n {labels}\n </>\n )\n\n const used = [...new Set((spec.edges ?? []).map((edge) => edge.variant ?? 'default'))]\n\n return {\n extent,\n artwork,\n nodes: spec.nodes.map((node) => ({\n id: node.id,\n label: node.label,\n sublabel: node.sublabel,\n kind: node.type,\n })),\n edges: (spec.edges ?? []).map((edge) => ({\n from: edge.from,\n to: edge.to,\n label: edge.label,\n })),\n legend: variantLegend(\n resolveLegend(used, spec.meta.legend?.mode, VARIANTS, spec.meta.legend?.entries),\n spec.meta.legend?.entries,\n ),\n }\n}\n\nexport default WorkflowFigure\n"],"mappings":"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","names":["left"]}
1
+ {"version":3,"sources":["../../../src/diagrams/WorkflowFigure/WorkflowFigure.tsx"],"sourcesContent":["'use client'\n\nimport { useId, useMemo } from 'react'\nimport { liveEdges, useSpecIdentity, warnUnknownLane } from '../lib/dev'\nimport { DiagramFrame, type FigureBand, type FigureChrome, type FigureModel } from '../lib/frame'\nimport { inflate, round, textWidth, TYPE, union, wrapText, type Box } from '../lib/geometry'\nimport { resolveLegend, variantLegend } from '../lib/legend'\nimport { BandFrame, NodePlate, PLATE, plateHeight } from '../lib/marks'\nimport { renderWires, wiresFor, type Wire } from '../lib/wires'\nimport type { Variant, WorkflowEdge, WorkflowEdgeRole, WorkflowSpec } from '../spec'\n\nconst VARIANTS: (Variant | 'return')[] = ['default', 'emphasis', 'security', 'dashed']\n\n/**\n * What a ROLE does to the line, where the author did not say it with a variant.\n *\n * `role` is about meaning and `variant` is about drawing, and for three of the\n * five roles the two answers coincide: an asynchronous hop and a path to the\n * exception lane are both the quiet line this system already has. `main` and\n * `branch` are deliberately absent — a main edge is heavier because `mainPath`\n * lists it, and a branch is simply an edge that is not on it, so both are\n * already carried by weight rather than by a second dash pattern.\n *\n * An explicit `variant` always wins: the author drew it on purpose.\n */\nconst ROLE_VARIANT: Partial<Record<WorkflowEdgeRole, Variant>> = {\n async: 'dashed',\n error: 'dashed',\n}\n\n/** How a line is drawn, once its role has had its say. */\nconst variantOf = (edge: WorkflowEdge): Variant | undefined =>\n edge.variant ?? (edge.role ? ROLE_VARIANT[edge.role] : undefined)\n\nconst GRID = {\n /** The gutter the lane names live in. */\n railW: 118,\n originY: 74,\n colW: 168,\n gapX: 58,\n laneH: 92,\n laneGap: 40,\n}\n\nexport interface WorkflowFigureProps extends FigureChrome {\n spec: WorkflowSpec\n}\n\n/**\n * A process: who does what, in what order, and where it can go wrong.\n *\n * Three structures stacked on one grid, and they are three because they answer\n * three different questions a reader brings to a runbook.\n *\n * **Lanes** are rows and answer WHO. A lane marked `exception` is the one band\n * that gets a wash rather than a rule, and it earns the exception to the\n * frames-are-rules law because nothing routes across it — it IS the ground for\n * the failure path, not a frame drawn over the happy one.\n *\n * **Phases** are columns across every lane and answer WHEN. Printed as captions\n * on one header rule, because a phase is an axis label. **Groups** are frames\n * inside a single lane and answer WHAT BELONGS TOGETHER — a planning loop, an\n * evidence path.\n *\n * THE MAIN PATH IS HEAVIER, and that is the whole hierarchy. `mainPath` lists\n * the node ids a reader should be able to follow without thinking. Every edge\n * between two consecutive ids on it is drawn at the emphasis weight whatever\n * its own variant says, which is the one thing that turns fourteen boxes and\n * nineteen arrows into a diagram with a subject. An `error` role goes the other\n * way — dashed and soft — so the exception path recedes without disappearing,\n * and so does `async`. `branch` adds no stroke of its own: a branch is an edge\n * the main path does not list, and that is already the difference on the page.\n */\nexport function WorkflowFigure({\n spec,\n className,\n legend = 'auto',\n cards = true,\n heading = true,\n activeIds,\n onSelectNode,\n}: WorkflowFigureProps) {\n const uid = useId().replace(/:/g, '')\n useSpecIdentity(spec, 'WorkflowFigure')\n const model = useMemo(\n () => buildModel(spec, uid, activeIds, onSelectNode),\n [spec, uid, activeIds, onSelectNode],\n )\n\n return (\n <DiagramFrame\n meta={spec.meta}\n model={model}\n cards={spec.cards}\n showCards={cards}\n heading={heading}\n legend={legend}\n className={className}\n activeIds={activeIds}\n onSelectNode={onSelectNode}\n />\n )\n}\n\n/** The x of a column's left edge, and of the whole span from `from` to `to`. */\nconst colX = (col: number) => GRID.railW + col * (GRID.colW + GRID.gapX)\nconst spanBox = (fromCol: number, toCol: number, y: number, h: number): Box => ({\n x: colX(fromCol),\n y,\n w: colX(toCol) + GRID.colW - colX(fromCol),\n h,\n})\n\nfunction buildModel(\n spec: WorkflowSpec,\n uid: string,\n activeIds: string[] | undefined,\n onSelectNode: ((id: string) => void) | undefined,\n): FigureModel {\n const laneIndex = new Map(spec.lanes.map((lane, index) => [lane.id, index]))\n const laneY = (index: number) => GRID.originY + index * (GRID.laneH + GRID.laneGap)\n\n // A lane id nothing declares still resolves to a row — there is nowhere else\n // to put the box — so the only thing that separates \"I meant lane 0\" from\n // \"the renderer gave up\" is being told.\n const laneOf = (id: string, owner: string) => {\n const index = laneIndex.get(id)\n if (index !== undefined) return index\n warnUnknownLane('WorkflowFigure', owner, id)\n return 0\n }\n\n const boxes = new Map<string, Box>()\n const placed = spec.nodes.map((node) => {\n const w = node.width ?? GRID.colW\n const lines = wrapText(node.label, TYPE.label, w - PLATE.padX * 2, 2)\n const h = plateHeight(lines.length, Boolean(node.sublabel), true, node.height ?? 0)\n const index = laneOf(node.lane, node.id)\n\n const box: Box = {\n x: colX(node.col),\n y: laneY(index) + (GRID.laneH - h) / 2 + (node.yOffset ?? 0),\n w,\n h,\n }\n boxes.set(node.id, box)\n return { node, box, lane: index }\n })\n\n // Consecutive pairs on the main path, so the edge between them can be drawn\n // at the weight that says \"follow this one\".\n const mainPairs = new Set<string>()\n for (let index = 0; index < (spec.mainPath?.length ?? 0) - 1; index += 1) {\n mainPairs.add(`${spec.mainPath![index]}→${spec.mainPath![index + 1]}`)\n }\n\n const edges = liveEdges('WorkflowFigure', spec.edges, (id) => boxes.has(id))\n const wires = wiresFor(edges, boxes, (edge: WorkflowEdge): Partial<Wire> => {\n const onMain = mainPairs.has(`${edge.from}→${edge.to}`)\n const variant = variantOf(edge)\n return {\n edge: variant === edge.variant ? edge : { ...edge, variant },\n weight: onMain ? 2.1 : undefined,\n open: edge.role === 'return',\n }\n })\n const { paths, labels } = renderWires(wires, uid)\n\n // A lane's band spans what the lane actually holds. Starting it at the rail\n // instead ran the exception wash under the label gutter, which made the\n // gutter look like part of the band rather than like the axis it is.\n const laneBoxes = spec.lanes.map((lane, index) => {\n const inside = placed.filter((entry) => entry.lane === index).map((entry) => entry.box)\n const span = union(inside)\n const left = span ? span.x - 14 : GRID.railW - 14\n return {\n lane,\n index,\n box: {\n x: left,\n y: laneY(index) - 8,\n w: (span ? span.x + span.w + 14 : colX(0) + GRID.colW) - left,\n h: GRID.laneH + 16,\n } as Box,\n }\n })\n\n const drawn = [...boxes.values(), ...laneBoxes.map((entry) => entry.box)]\n const headerY = GRID.originY - 30\n\n // The frame has to hold what is printed OUTSIDE the boxes too: the lane names\n // in the gutter and the phase captions above the header rule. Sizing the\n // extent from the boxes alone clipped both — and a clipped axis label is the\n // one kind of overflow a reader reads as a broken renderer rather than as a\n // long word.\n const railTextW = Math.max(0, ...spec.lanes.map((lane) => textWidth(lane.label, 9)))\n const raw = union(drawn) ?? { x: 0, y: 0, w: 600, h: 300 }\n const left = Math.min(raw.x, GRID.railW - 26 - railTextW)\n const top = Math.min(raw.y, headerY - 14)\n const extent = inflate(\n { x: left, y: top, w: raw.x + raw.w - left, h: raw.y + raw.h - top },\n 24,\n )\n const active = activeIds && activeIds.length > 0 ? new Set(activeIds) : null\n\n const artwork = (\n <>\n {/* Phases: one rule per phase, drawn across the columns that phase\n claims. A single rule spanning the figure made `toCol` a field the\n type accepted and the picture could not show — two phases starting in\n the same column printed their captions on top of each other, and a\n phase's extent was not a thing a reader could see. */}\n {(spec.phases ?? []).map((phase) => {\n const span = spanBox(phase.fromCol, Math.max(phase.fromCol, phase.toCol), headerY + 8, 0)\n const dashed = phase.variant === 'security' || phase.variant === 'dashed'\n return (\n <g key={phase.id} data-phase={phase.id} aria-hidden=\"true\">\n <path\n d={`M ${round(span.x)} ${round(span.y)} H ${round(span.x + span.w)}`}\n className={\n phase.variant === 'emphasis'\n ? 'stroke-(--diagram-rule-hard)'\n : 'stroke-(--diagram-rule)'\n }\n strokeWidth={phase.variant === 'emphasis' ? 1.6 : 1}\n strokeDasharray={dashed ? '7 4' : undefined}\n />\n <text\n x={round(span.x)}\n y={round(headerY)}\n className=\"fill-(--diagram-ink-3) font-mono [font-size:9px] [letter-spacing:0.14em] uppercase\"\n >\n {phase.label}\n </text>\n </g>\n )\n })}\n\n {/* Lanes. The exception band is the one wash in the system's diagrams. */}\n {laneBoxes.map(({ lane, box }) => (\n <g key={lane.id} aria-hidden=\"true\">\n {lane.variant === 'exception' && (\n <rect\n x={round(box.x)}\n y={round(box.y)}\n width={round(box.w)}\n height={round(box.h)}\n rx={10}\n className=\"fill-(--diagram-band) [rx:var(--radius-lg)] [ry:var(--radius-lg)]\"\n />\n )}\n <text\n x={round(GRID.railW - 26)}\n y={round(box.y + box.h / 2 + 3)}\n textAnchor=\"end\"\n className=\"fill-(--diagram-ink-3) font-mono [font-size:9px] [letter-spacing:0.14em] uppercase\"\n >\n {lane.label}\n </text>\n </g>\n ))}\n\n {/* Groups: a frame inside one lane. */}\n {(spec.groups ?? []).map((group) => {\n const index = laneOf(group.lane, group.id)\n return (\n <BandFrame\n key={group.id}\n box={spanBox(group.fromCol, group.toCol, laneY(index) - 2, GRID.laneH + 4)}\n label={group.label}\n dashed={group.variant === 'security'}\n />\n )\n })}\n\n {paths}\n\n {placed.map(({ node, box }) => (\n <NodePlate\n key={node.id}\n nodeId={node.id}\n box={box}\n label={node.label}\n sublabel={node.sublabel}\n tag={node.tag}\n kind={node.type}\n active={active?.has(node.id)}\n dimmed={active ? !active.has(node.id) : false}\n onSelect={onSelectNode ? () => onSelectNode(node.id) : undefined}\n />\n ))}\n\n {labels}\n </>\n )\n\n const used = [...new Set(edges.map((edge) => variantOf(edge) ?? 'default'))]\n\n // The lanes ARE the list's structure, not a phrase repeated on every row.\n // WHO does a step is half of where the step sits, and it was drawn only in a\n // gutter inside artwork a screen reader is told to skip.\n const bands: FigureBand[] = spec.lanes.map((lane, index) => ({\n kind: lane.variant === 'exception' ? 'Exception lane' : 'Lane',\n label: lane.label,\n ids: placed\n .filter((entry) => entry.lane === index)\n .sort((a, b) => a.node.col - b.node.col)\n .map((entry) => entry.node.id),\n }))\n\n return {\n extent,\n artwork,\n nodes: spec.nodes.map((node) => ({\n id: node.id,\n label: node.label,\n sublabel: node.sublabel,\n kind: node.type,\n })),\n edges: edges.map((edge) => ({\n from: edge.from,\n to: edge.to,\n label: edge.label,\n })),\n bands,\n // A phase and a group both cut ACROSS the lanes, so neither can be the\n // list's structure without publishing a node twice. They are sentences.\n notes: [\n ...(spec.phases ?? []).map((phase) =>\n span('Phase', phase.label, phase.fromCol, phase.toCol, spec.nodes, ''),\n ),\n ...(spec.groups ?? []).map((group) =>\n span(\n 'Group',\n group.label,\n group.fromCol,\n group.toCol,\n spec.nodes.filter((node) => node.lane === group.lane),\n ` in lane ${spec.lanes[laneIndex.get(group.lane) ?? 0]?.label ?? group.lane}`,\n ),\n ),\n ],\n legend: variantLegend(\n resolveLegend(used, spec.meta.legend?.mode, VARIANTS, spec.meta.legend?.entries),\n spec.meta.legend?.entries,\n ),\n }\n}\n\n/** One phase or group, written out: what it covers, and what is inside it. */\nfunction span(\n kind: string,\n label: string,\n fromCol: number,\n toCol: number,\n nodes: { col: number; label: string }[],\n where: string,\n): string {\n const inside = nodes.filter((node) => node.col >= fromCol && node.col <= toCol)\n const held = inside.length > 0 ? `: ${inside.map((node) => node.label).join(', ')}` : ''\n return `${kind} ${label} covers columns ${fromCol} to ${toCol}${where}${held}.`\n}\n\nexport default WorkflowFigure\n"],"mappings":"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","names":["span","left"]}
@@ -10,6 +10,7 @@ export { DiagramExportMenu, DiagramExportMenuProps, ExportFormat, ExportResult,
10
10
  export { DiagramInspector, DiagramInspectorProps, InspectorFact, InspectorLink } from './DiagramInspector/DiagramInspector.js';
11
11
  export { DiagramMinimap, DiagramMinimapProps } from './DiagramMinimap/DiagramMinimap.js';
12
12
  export { DiagramLegend, DiagramLegendEntry, DiagramLegendProps } from './DiagramLegend/DiagramLegend.js';
13
+ export { RasterFormat, RasterOptions, SerializeOptions, downloadBlob, exportFilename, rasterize, serializeSvg } from '../lib/svg-export.js';
13
14
  export { LegendEntry, kindLegend, resolveLegend, stateLegend, variantLegend } from './lib/legend.js';
14
15
  export { FigureChrome } from './lib/frame.js';
15
16
  import 'react';
@@ -9,10 +9,20 @@ export * from "./DiagramExportMenu/DiagramExportMenu.js";
9
9
  export * from "./DiagramInspector/DiagramInspector.js";
10
10
  export * from "./DiagramMinimap/DiagramMinimap.js";
11
11
  export * from "./DiagramLegend/DiagramLegend.js";
12
+ import {
13
+ downloadBlob,
14
+ exportFilename,
15
+ rasterize,
16
+ serializeSvg
17
+ } from "../lib/svg-export.js";
12
18
  import { kindLegend, resolveLegend, stateLegend, variantLegend } from "./lib/legend.js";
13
19
  export {
20
+ downloadBlob,
21
+ exportFilename,
14
22
  kindLegend,
23
+ rasterize,
15
24
  resolveLegend,
25
+ serializeSvg,
16
26
  stateLegend,
17
27
  variantLegend
18
28
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/diagrams/index.ts"],"sourcesContent":["/**\n * @misoto22/design/diagrams — the public entry.\n *\n * Five renderers for the five diagram shapes software actually needs, plus the\n * chrome a reader explores one with. They ship from their own entry point\n * rather than from the package root for one reason: a page that renders a Badge\n * should not be paying for a routing engine. Nothing under `src/components`\n * imports anything here, so the main barrel stays the size it was.\n *\n * The specification types mirror\n * [archify](https://github.com/tt-a1i/archify)'s published JSON schemas, so a\n * document authored for that tool renders here with no translation step — in\n * this system's own monochrome terms rather than in archify's palette.\n *\n * The look ships with the rest of the package:\n *\n * import '@misoto22/design/styles.css'\n *\n * Everything below is a consumer contract. Adding an export is cheap; changing\n * or removing one is a breaking change (DESIGN-API-001).\n */\n\n// ─── Specifications ───\nexport type {\n ArchitectureBoundary,\n ArchitectureComponent,\n ArchitectureSpec,\n DataflowEdge,\n DataflowNode,\n DataflowSpec,\n DataflowStage,\n DiagramCard,\n DiagramMeta,\n DiagramSpecAny,\n DiagramView,\n EdgeBase,\n LegendMode,\n LifecycleLane,\n LifecycleSpec,\n LifecycleState,\n LifecycleStateKind,\n LifecycleTransition,\n NodeBase,\n NodeKind,\n Point,\n RouteMode,\n SequenceActivation,\n SequenceMessage,\n SequenceParticipant,\n SequenceSegment,\n SequenceSpec,\n Side,\n SourceRef,\n Variant,\n WorkflowEdge,\n WorkflowEdgeRole,\n WorkflowGroup,\n WorkflowLane,\n WorkflowNode,\n WorkflowPhase,\n WorkflowSpec,\n} from './spec'\n\n// ─── Figures ───\nexport * from './ArchitectureFigure/ArchitectureFigure'\nexport * from './WorkflowFigure/WorkflowFigure'\nexport * from './SequenceFigure/SequenceFigure'\nexport * from './DataflowFigure/DataflowFigure'\nexport * from './LifecycleFigure/LifecycleFigure'\n\n// ─── Chrome ───\nexport * from './DiagramCanvas/DiagramCanvas'\nexport * from './DiagramToolbar/DiagramToolbar'\nexport * from './DiagramExportMenu/DiagramExportMenu'\nexport * from './DiagramInspector/DiagramInspector'\nexport * from './DiagramMinimap/DiagramMinimap'\nexport * from './DiagramLegend/DiagramLegend'\n\n// ─── Building a key ───\nexport { kindLegend, resolveLegend, stateLegend, variantLegend } from './lib/legend'\nexport type { LegendEntry } from './lib/legend'\n\n// ─── Shared chrome types ───\nexport type { FigureChrome } from './lib/frame'\n"],"mappings":"AAgEA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,SAAS,YAAY,eAAe,aAAa,qBAAqB;","names":[]}
1
+ {"version":3,"sources":["../../src/diagrams/index.ts"],"sourcesContent":["/**\n * @misoto22/design/diagrams — the public entry.\n *\n * Five renderers for the five diagram shapes software actually needs, plus the\n * chrome a reader explores one with. They ship from their own entry point\n * rather than from the package root for one reason: a page that renders a Badge\n * should not be paying for a routing engine. Nothing under `src/components`\n * imports anything here, so the main barrel stays the size it was.\n *\n * The specification types mirror\n * [archify](https://github.com/tt-a1i/archify)'s published JSON schemas, so a\n * document authored for that tool renders here with no translation step — in\n * this system's own monochrome terms rather than in archify's palette.\n *\n * The look ships with the rest of the package:\n *\n * import '@misoto22/design/styles.css'\n *\n * Everything below is a consumer contract. Adding an export is cheap; changing\n * or removing one is a breaking change (DESIGN-API-001).\n */\n\n// ─── Specifications ───\nexport type {\n ArchitectureBoundary,\n ArchitectureComponent,\n ArchitectureSpec,\n DataflowEdge,\n DataflowNode,\n DataflowSpec,\n DataflowStage,\n DiagramCard,\n DiagramMeta,\n DiagramSpecAny,\n DiagramView,\n EdgeBase,\n LegendMode,\n LifecycleLane,\n LifecycleSpec,\n LifecycleState,\n LifecycleStateKind,\n LifecycleTransition,\n NodeBase,\n NodeKind,\n Point,\n RouteMode,\n SequenceActivation,\n SequenceMessage,\n SequenceParticipant,\n SequenceSegment,\n SequenceSpec,\n Side,\n SourceRef,\n Variant,\n WorkflowEdge,\n WorkflowEdgeRole,\n WorkflowGroup,\n WorkflowLane,\n WorkflowNode,\n WorkflowPhase,\n WorkflowSpec,\n} from './spec'\n\n// ─── Figures ───\nexport * from './ArchitectureFigure/ArchitectureFigure'\nexport * from './WorkflowFigure/WorkflowFigure'\nexport * from './SequenceFigure/SequenceFigure'\nexport * from './DataflowFigure/DataflowFigure'\nexport * from './LifecycleFigure/LifecycleFigure'\n\n// ─── Chrome ───\nexport * from './DiagramCanvas/DiagramCanvas'\nexport * from './DiagramToolbar/DiagramToolbar'\nexport * from './DiagramExportMenu/DiagramExportMenu'\nexport * from './DiagramInspector/DiagramInspector'\nexport * from './DiagramMinimap/DiagramMinimap'\nexport * from './DiagramLegend/DiagramLegend'\n\n// ─── Taking a figure off the page ───\n/**\n * The export pipeline the menu runs, for a caller who needs a different one.\n *\n * `DiagramExportMenu` is five decisions already made — a plate behind the\n * artwork, 2× raster, a 1200 × 630 share card — and a caller who wants any of\n * them differently had nothing to build on: the serialiser is where the hard\n * half lives (resolving `var(--ink)` against the live element, so the file is\n * not an invisible rectangle), and it was private.\n */\nexport {\n downloadBlob,\n exportFilename,\n rasterize,\n serializeSvg,\n} from '../lib/svg-export'\nexport type { RasterFormat, RasterOptions, SerializeOptions } from '../lib/svg-export'\n\n// ─── Building a key ───\nexport { kindLegend, resolveLegend, stateLegend, variantLegend } from './lib/legend'\nexport type { LegendEntry } from './lib/legend'\n\n// ─── Shared chrome types ───\nexport type { FigureChrome } from './lib/frame'\n"],"mappings":"AAgEA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAYd;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAIP,SAAS,YAAY,eAAe,aAAa,qBAAqB;","names":[]}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * The ways a diagram specification can typecheck and draw something else.
3
+ *
4
+ * A figure has no runtime validator and should not grow one: the specification
5
+ * is a plain object, the layout is arithmetic on numbers it already carries,
6
+ * and a schema check would be a second copy of the types. What it needs instead
7
+ * is the same thing the components have — a word at the moment the arithmetic
8
+ * is asked to do something the author cannot have meant.
9
+ *
10
+ * Every case here shares one shape: the renderer CAN produce a picture, so
11
+ * nothing throws, and the picture is not the one the specification describes.
12
+ * A lane id nothing declares resolves to lane 0 and the step is drawn in the
13
+ * wrong band; a stage past the last heading is drawn past the last heading; a
14
+ * message to a participant that does not exist is drawn nowhere at all. Each of
15
+ * those used to be silent, and silence is the one outcome ruled out: an author
16
+ * who cannot see the difference between "I placed this" and "the renderer gave
17
+ * up" has no way to find the mistake except by knowing what the picture should
18
+ * have looked like.
19
+ *
20
+ * All of it goes through `lib/warn`, so it is dev-only, printed once per
21
+ * problem, and dropped from a production bundle by the consumer's own bundler.
22
+ */
23
+ /**
24
+ * Says so when a figure is handed the same object it was handed last time, with
25
+ * different contents inside it.
26
+ *
27
+ * Every figure memoises its model on the specification's IDENTITY, which is the
28
+ * only key that costs nothing to compare — and which a `spec.components.push()`
29
+ * does not change. The figure then goes on drawing the picture it was first
30
+ * given, through any number of re-renders, with no error and no clue.
31
+ *
32
+ * The fingerprint is only computed in development, and only ever compared with
33
+ * the previous render's: it is a diagnostic, not the memo key. Making it the
34
+ * memo key would put a `JSON.stringify` of the whole specification in front of
35
+ * every production render, which is a far worse trade than asking the author to
36
+ * build a new object.
37
+ */
38
+ declare function useSpecIdentity(spec: unknown, component: string): void;
39
+ /** Says so when a node names a lane the specification never declared. */
40
+ declare function warnUnknownLane(component: string, nodeId: string, lane: string): void;
41
+ /** Says so when a data-flow node sits past the last stage heading. */
42
+ declare function warnStageOutOfRange(component: string, nodeId: string, stage: number, stages: number): void;
43
+ /** Says so when two boxes were placed on exactly the same coordinate. */
44
+ declare function warnCollision(component: string, ids: string[]): void;
45
+ /**
46
+ * The edges whose two ends exist, with a word about the ones that do not.
47
+ *
48
+ * Routing already drops a line it cannot place — there is no box to draw it
49
+ * between — and the summary list used to iterate the specification instead, so
50
+ * the picture and its text equivalent disagreed: one showed nothing, the other
51
+ * reported a relationship to an id no node claims. Both halves now read this,
52
+ * which is what makes them agree by construction rather than by inspection.
53
+ */
54
+ declare function liveEdges<E extends {
55
+ from: string;
56
+ to: string;
57
+ }>(component: string, edges: E[] | undefined, known: (id: string) => boolean): E[];
58
+ /** Says so when anything else in the spec points at an id nothing declares. */
59
+ declare function warnUnknownRef(component: string, field: string, id: string, effect: string): void;
60
+
61
+ export { liveEdges, useSpecIdentity, warnCollision, warnStageOutOfRange, warnUnknownLane, warnUnknownRef };
@@ -0,0 +1,96 @@
1
+ "use client";
2
+ import { useRef } from "react";
3
+ import { DEV, warn } from "../../lib/warn.js";
4
+ function useSpecIdentity(spec, component) {
5
+ const last = useRef(null);
6
+ if (!DEV) return;
7
+ const print = fingerprint(spec);
8
+ const previous = last.current;
9
+ last.current = { spec, print };
10
+ if (previous && previous.spec === spec && previous.print !== print) {
11
+ warn({
12
+ code: "DIAGRAM_SPEC_MUTATED",
13
+ problem: `${component} was given the same spec object with different contents. The model is memoised on the object's identity, so the figure is still drawing what that object held on the first render.`,
14
+ field: `${component}.spec`,
15
+ fix: "Build a new spec object for the change \u2014 { ...spec, nodes: [...] } \u2014 rather than mutating the one already passed.",
16
+ component
17
+ });
18
+ }
19
+ }
20
+ function fingerprint(value) {
21
+ try {
22
+ return JSON.stringify(value) ?? "";
23
+ } catch {
24
+ return "";
25
+ }
26
+ }
27
+ function warnUnknownLane(component, nodeId, lane) {
28
+ if (!DEV) return;
29
+ warn({
30
+ code: "DIAGRAM_LANE_UNKNOWN",
31
+ problem: `${component} was given the lane "${lane}" on "${nodeId}", which no lane in the specification declares. It falls back to the first lane, so the node is drawn in the right column and the wrong band.`,
32
+ field: `${component}.nodes[${nodeId}].lane`,
33
+ fix: `Use one of the ids in spec.lanes, or add a lane whose id is "${lane}".`,
34
+ component
35
+ });
36
+ }
37
+ function warnStageOutOfRange(component, nodeId, stage, stages) {
38
+ if (!DEV) return;
39
+ warn({
40
+ code: "DIAGRAM_STAGE_OUT_OF_RANGE",
41
+ problem: `${component} was given stage ${stage} on "${nodeId}" against ${stages} declared stages. A node's x is computed from its own index, so it is drawn past the last heading \u2014 in a column the axis does not label.`,
42
+ field: `${component}.nodes[${nodeId}].stage`,
43
+ fix: `Use a stage between 0 and ${Math.max(0, stages - 1)}, or declare the stages the pipeline actually has.`,
44
+ component
45
+ });
46
+ }
47
+ function warnCollision(component, ids) {
48
+ if (!DEV) return;
49
+ warn({
50
+ code: "DIAGRAM_CELL_COLLISION",
51
+ problem: `${component} placed ${ids.map((id) => `"${id}"`).join(" and ")} at the same coordinate, so one plate is drawn on top of the other. Both are still in the summary list, so the mistake exists only in the picture.`,
52
+ field: `${component}.components[${ids[0]}]`,
53
+ fix: "Give each of them its own row and col, or its own pos.",
54
+ component
55
+ });
56
+ }
57
+ function liveEdges(component, edges, known) {
58
+ if (!edges) return [];
59
+ const out = [];
60
+ for (const edge of edges) {
61
+ const missing = [edge.from, edge.to].filter((id) => !known(id));
62
+ if (missing.length === 0) {
63
+ out.push(edge);
64
+ continue;
65
+ }
66
+ if (DEV) {
67
+ warn({
68
+ code: "DIAGRAM_EDGE_DANGLING",
69
+ problem: `${component} was given a relationship ${edge.from} \u2192 ${edge.to}, and ${missing.map((id) => `"${id}"`).join(" and ")} is not a node the specification declares. There is nothing to draw it between, so it is left out of the picture and out of the summary.`,
70
+ field: `${component}.edges[${edge.from}\u2192${edge.to}]`,
71
+ fix: "Correct the id, or add the node it names.",
72
+ component
73
+ });
74
+ }
75
+ }
76
+ return out;
77
+ }
78
+ function warnUnknownRef(component, field, id, effect) {
79
+ if (!DEV) return;
80
+ warn({
81
+ code: "DIAGRAM_REF_UNKNOWN",
82
+ problem: `${component} was given "${id}" in ${field}, which no node in the specification declares, so ${effect}.`,
83
+ field: `${component}.${field}`,
84
+ fix: "Correct the id, or add the node it names.",
85
+ component
86
+ });
87
+ }
88
+ export {
89
+ liveEdges,
90
+ useSpecIdentity,
91
+ warnCollision,
92
+ warnStageOutOfRange,
93
+ warnUnknownLane,
94
+ warnUnknownRef
95
+ };
96
+ //# sourceMappingURL=dev.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/diagrams/lib/dev.ts"],"sourcesContent":["'use client'\n\nimport { useRef } from 'react'\nimport { DEV, warn } from '../../lib/warn'\n\n/**\n * The ways a diagram specification can typecheck and draw something else.\n *\n * A figure has no runtime validator and should not grow one: the specification\n * is a plain object, the layout is arithmetic on numbers it already carries,\n * and a schema check would be a second copy of the types. What it needs instead\n * is the same thing the components have — a word at the moment the arithmetic\n * is asked to do something the author cannot have meant.\n *\n * Every case here shares one shape: the renderer CAN produce a picture, so\n * nothing throws, and the picture is not the one the specification describes.\n * A lane id nothing declares resolves to lane 0 and the step is drawn in the\n * wrong band; a stage past the last heading is drawn past the last heading; a\n * message to a participant that does not exist is drawn nowhere at all. Each of\n * those used to be silent, and silence is the one outcome ruled out: an author\n * who cannot see the difference between \"I placed this\" and \"the renderer gave\n * up\" has no way to find the mistake except by knowing what the picture should\n * have looked like.\n *\n * All of it goes through `lib/warn`, so it is dev-only, printed once per\n * problem, and dropped from a production bundle by the consumer's own bundler.\n */\n\n/**\n * Says so when a figure is handed the same object it was handed last time, with\n * different contents inside it.\n *\n * Every figure memoises its model on the specification's IDENTITY, which is the\n * only key that costs nothing to compare — and which a `spec.components.push()`\n * does not change. The figure then goes on drawing the picture it was first\n * given, through any number of re-renders, with no error and no clue.\n *\n * The fingerprint is only computed in development, and only ever compared with\n * the previous render's: it is a diagnostic, not the memo key. Making it the\n * memo key would put a `JSON.stringify` of the whole specification in front of\n * every production render, which is a far worse trade than asking the author to\n * build a new object.\n */\nexport function useSpecIdentity(spec: unknown, component: string): void {\n const last = useRef<{ spec: unknown; print: string } | null>(null)\n if (!DEV) return\n\n const print = fingerprint(spec)\n const previous = last.current\n last.current = { spec, print }\n\n if (previous && previous.spec === spec && previous.print !== print) {\n warn({\n code: 'DIAGRAM_SPEC_MUTATED',\n problem: `${component} was given the same spec object with different contents. The model is memoised on the object's identity, so the figure is still drawing what that object held on the first render.`,\n field: `${component}.spec`,\n fix: 'Build a new spec object for the change — { ...spec, nodes: [...] } — rather than mutating the one already passed.',\n component,\n })\n }\n}\n\nfunction fingerprint(value: unknown): string {\n try {\n return JSON.stringify(value) ?? ''\n } catch {\n // A spec that cannot be serialised cannot be fingerprinted either. It is\n // not this function's job to complain about that.\n return ''\n }\n}\n\n/** Says so when a node names a lane the specification never declared. */\nexport function warnUnknownLane(component: string, nodeId: string, lane: string): void {\n if (!DEV) return\n warn({\n code: 'DIAGRAM_LANE_UNKNOWN',\n problem: `${component} was given the lane \"${lane}\" on \"${nodeId}\", which no lane in the specification declares. It falls back to the first lane, so the node is drawn in the right column and the wrong band.`,\n field: `${component}.nodes[${nodeId}].lane`,\n fix: `Use one of the ids in spec.lanes, or add a lane whose id is \"${lane}\".`,\n component,\n })\n}\n\n/** Says so when a data-flow node sits past the last stage heading. */\nexport function warnStageOutOfRange(\n component: string,\n nodeId: string,\n stage: number,\n stages: number,\n): void {\n if (!DEV) return\n warn({\n code: 'DIAGRAM_STAGE_OUT_OF_RANGE',\n problem: `${component} was given stage ${stage} on \"${nodeId}\" against ${stages} declared stages. A node's x is computed from its own index, so it is drawn past the last heading — in a column the axis does not label.`,\n field: `${component}.nodes[${nodeId}].stage`,\n fix: `Use a stage between 0 and ${Math.max(0, stages - 1)}, or declare the stages the pipeline actually has.`,\n component,\n })\n}\n\n/** Says so when two boxes were placed on exactly the same coordinate. */\nexport function warnCollision(component: string, ids: string[]): void {\n if (!DEV) return\n warn({\n code: 'DIAGRAM_CELL_COLLISION',\n problem: `${component} placed ${ids.map((id) => `\"${id}\"`).join(' and ')} at the same coordinate, so one plate is drawn on top of the other. Both are still in the summary list, so the mistake exists only in the picture.`,\n field: `${component}.components[${ids[0]}]`,\n fix: 'Give each of them its own row and col, or its own pos.',\n component,\n })\n}\n\n/**\n * The edges whose two ends exist, with a word about the ones that do not.\n *\n * Routing already drops a line it cannot place — there is no box to draw it\n * between — and the summary list used to iterate the specification instead, so\n * the picture and its text equivalent disagreed: one showed nothing, the other\n * reported a relationship to an id no node claims. Both halves now read this,\n * which is what makes them agree by construction rather than by inspection.\n */\nexport function liveEdges<E extends { from: string; to: string }>(\n component: string,\n edges: E[] | undefined,\n known: (id: string) => boolean,\n): E[] {\n if (!edges) return []\n const out: E[] = []\n for (const edge of edges) {\n const missing = [edge.from, edge.to].filter((id) => !known(id))\n if (missing.length === 0) {\n out.push(edge)\n continue\n }\n if (DEV) {\n warn({\n code: 'DIAGRAM_EDGE_DANGLING',\n problem: `${component} was given a relationship ${edge.from} → ${edge.to}, and ${missing.map((id) => `\"${id}\"`).join(' and ')} is not a node the specification declares. There is nothing to draw it between, so it is left out of the picture and out of the summary.`,\n field: `${component}.edges[${edge.from}→${edge.to}]`,\n fix: 'Correct the id, or add the node it names.',\n component,\n })\n }\n }\n return out\n}\n\n/** Says so when anything else in the spec points at an id nothing declares. */\nexport function warnUnknownRef(\n component: string,\n field: string,\n id: string,\n effect: string,\n): void {\n if (!DEV) return\n warn({\n code: 'DIAGRAM_REF_UNKNOWN',\n problem: `${component} was given \"${id}\" in ${field}, which no node in the specification declares, so ${effect}.`,\n field: `${component}.${field}`,\n fix: 'Correct the id, or add the node it names.',\n component,\n })\n}\n"],"mappings":";AAEA,SAAS,cAAc;AACvB,SAAS,KAAK,YAAY;AAwCnB,SAAS,gBAAgB,MAAe,WAAyB;AACtE,QAAM,OAAO,OAAgD,IAAI;AACjE,MAAI,CAAC,IAAK;AAEV,QAAM,QAAQ,YAAY,IAAI;AAC9B,QAAM,WAAW,KAAK;AACtB,OAAK,UAAU,EAAE,MAAM,MAAM;AAE7B,MAAI,YAAY,SAAS,SAAS,QAAQ,SAAS,UAAU,OAAO;AAClE,SAAK;AAAA,MACH,MAAM;AAAA,MACN,SAAS,GAAG,SAAS;AAAA,MACrB,OAAO,GAAG,SAAS;AAAA,MACnB,KAAK;AAAA,MACL;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAEA,SAAS,YAAY,OAAwB;AAC3C,MAAI;AACF,WAAO,KAAK,UAAU,KAAK,KAAK;AAAA,EAClC,QAAQ;AAGN,WAAO;AAAA,EACT;AACF;AAGO,SAAS,gBAAgB,WAAmB,QAAgB,MAAoB;AACrF,MAAI,CAAC,IAAK;AACV,OAAK;AAAA,IACH,MAAM;AAAA,IACN,SAAS,GAAG,SAAS,wBAAwB,IAAI,SAAS,MAAM;AAAA,IAChE,OAAO,GAAG,SAAS,UAAU,MAAM;AAAA,IACnC,KAAK,gEAAgE,IAAI;AAAA,IACzE;AAAA,EACF,CAAC;AACH;AAGO,SAAS,oBACd,WACA,QACA,OACA,QACM;AACN,MAAI,CAAC,IAAK;AACV,OAAK;AAAA,IACH,MAAM;AAAA,IACN,SAAS,GAAG,SAAS,oBAAoB,KAAK,QAAQ,MAAM,aAAa,MAAM;AAAA,IAC/E,OAAO,GAAG,SAAS,UAAU,MAAM;AAAA,IACnC,KAAK,6BAA6B,KAAK,IAAI,GAAG,SAAS,CAAC,CAAC;AAAA,IACzD;AAAA,EACF,CAAC;AACH;AAGO,SAAS,cAAc,WAAmB,KAAqB;AACpE,MAAI,CAAC,IAAK;AACV,OAAK;AAAA,IACH,MAAM;AAAA,IACN,SAAS,GAAG,SAAS,WAAW,IAAI,IAAI,CAAC,OAAO,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC;AAAA,IACxE,OAAO,GAAG,SAAS,eAAe,IAAI,CAAC,CAAC;AAAA,IACxC,KAAK;AAAA,IACL;AAAA,EACF,CAAC;AACH;AAWO,SAAS,UACd,WACA,OACA,OACK;AACL,MAAI,CAAC,MAAO,QAAO,CAAC;AACpB,QAAM,MAAW,CAAC;AAClB,aAAW,QAAQ,OAAO;AACxB,UAAM,UAAU,CAAC,KAAK,MAAM,KAAK,EAAE,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;AAC9D,QAAI,QAAQ,WAAW,GAAG;AACxB,UAAI,KAAK,IAAI;AACb;AAAA,IACF;AACA,QAAI,KAAK;AACP,WAAK;AAAA,QACH,MAAM;AAAA,QACN,SAAS,GAAG,SAAS,6BAA6B,KAAK,IAAI,WAAM,KAAK,EAAE,SAAS,QAAQ,IAAI,CAAC,OAAO,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC;AAAA,QAC7H,OAAO,GAAG,SAAS,UAAU,KAAK,IAAI,SAAI,KAAK,EAAE;AAAA,QACjD,KAAK;AAAA,QACL;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACA,SAAO;AACT;AAGO,SAAS,eACd,WACA,OACA,IACA,QACM;AACN,MAAI,CAAC,IAAK;AACV,OAAK;AAAA,IACH,MAAM;AAAA,IACN,SAAS,GAAG,SAAS,eAAe,EAAE,QAAQ,KAAK,qDAAqD,MAAM;AAAA,IAC9G,OAAO,GAAG,SAAS,IAAI,KAAK;AAAA,IAC5B,KAAK;AAAA,IACL;AAAA,EACF,CAAC;AACH;","names":[]}
@@ -16,12 +16,7 @@ interface FigureModel {
16
16
  extent: Box;
17
17
  artwork: ReactNode;
18
18
  /** Every drawn box, for the summary list. */
19
- nodes: {
20
- id: string;
21
- label: string;
22
- sublabel?: string;
23
- kind?: string;
24
- }[];
19
+ nodes: FigureNode[];
25
20
  /** Every drawn line, for the summary list. */
26
21
  edges: {
27
22
  from: string;
@@ -34,6 +29,45 @@ interface FigureModel {
34
29
  label: string;
35
30
  sample: ReactNode;
36
31
  }[];
32
+ /**
33
+ * The figure's second axis, as a PARTITION of the nodes above.
34
+ *
35
+ * A workflow's lanes and a data flow's stages are not decoration around the
36
+ * boxes — they are the other half of every box's position, and a summary that
37
+ * lists the boxes alone has published one dimension of a two-dimensional
38
+ * picture. Giving the list this structure says it once, in the place a screen
39
+ * reader already walks, rather than repeating "in the CI lane" on every row.
40
+ *
41
+ * A node may appear in at most one band: the list is the keyboard's only
42
+ * route to a selection, and a node in two bands is two controls that do the
43
+ * same thing. Anything left out of every band is published after them.
44
+ */
45
+ bands?: FigureBand[];
46
+ /**
47
+ * What the picture says that is neither a box nor a line.
48
+ *
49
+ * Boundaries, phase captions, segment captions, activation bars: each is a
50
+ * real statement drawn inside an `aria-hidden` `<svg>`, and each is a
51
+ * sentence rather than a row, so each figure writes its own.
52
+ */
53
+ notes?: string[];
54
+ }
55
+ /** One drawn box, as the summary publishes it. */
56
+ interface FigureNode {
57
+ id: string;
58
+ label: string;
59
+ sublabel?: string;
60
+ kind?: string;
61
+ /** A short phrase the picture prints on the box: a step number. */
62
+ detail?: string;
63
+ }
64
+ /** One band of a figure's second axis: a lane, a stage. */
65
+ interface FigureBand {
66
+ /** What KIND of band this is — "Lane", "Stage" — since the label is a name. */
67
+ kind: string;
68
+ label: string;
69
+ /** The nodes inside it, in the order the figure draws them. */
70
+ ids: string[];
37
71
  }
38
72
  interface FigureChrome {
39
73
  className?: string;
@@ -71,6 +105,13 @@ interface FigureChrome {
71
105
  * picture, and it is why this component takes a model rather than markup — a
72
106
  * frame handed a finished `<svg>` could not have written it.
73
107
  *
108
+ * The list carries the figure's SECOND AXIS as its own structure. A workflow's
109
+ * lanes and a data flow's stages are half of where every box sits, and they are
110
+ * drawn inside the presentational `<svg>` — so a flat list of boxes published
111
+ * one dimension of a two-dimensional picture and called it the content. Nodes
112
+ * are grouped by their band, and the statements that group nothing — a
113
+ * boundary, a phase caption, an activation bar — follow as sentences.
114
+ *
74
115
  * The list is visually hidden by default and NOT hidden from assistive
75
116
  * technology, which is the opposite of what `aria-hidden` would do and the
76
117
  * whole point.
@@ -94,4 +135,4 @@ declare function CardGrid({ cards, className }: {
94
135
  className?: string;
95
136
  }): react.JSX.Element;
96
137
 
97
- export { CardGrid, DiagramFrame, type FigureChrome, type FigureModel };
138
+ export { CardGrid, DiagramFrame, type FigureBand, type FigureChrome, type FigureModel, type FigureNode };
@@ -22,6 +22,10 @@ function DiagramFrame({
22
22
  const byId = new Map(model.nodes.map((node) => [node.id, node]));
23
23
  const description = `${model.nodes.length} elements and ${model.edges.length} relationships. ${meta.subtitle ?? ""}`.trim();
24
24
  const showLegend = legend !== "hidden" && model.legend.length > 0;
25
+ const bands = model.bands ?? [];
26
+ const banded = new Set(bands.flatMap((band) => band.ids));
27
+ const loose = bands.length > 0 ? model.nodes.filter((node) => !banded.has(node.id)) : [];
28
+ const row = (node) => /* @__PURE__ */ jsx("li", { children: onSelectNode ? /* @__PURE__ */ jsx("button", { type: "button", onClick: () => onSelectNode(node.id), children: summaryLine(node) }) : summaryLine(node) }, node.id);
25
29
  return /* @__PURE__ */ jsxs("figure", { className: cn("m-0 flex flex-col gap-5", className), children: [
26
30
  heading && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
27
31
  /* @__PURE__ */ jsx("h3", { className: "m-0 font-heading text-[length:var(--fs-sub)] font-normal leading-[1.15] tracking-[-0.015em] text-(--ink)", children: meta.title }),
@@ -45,13 +49,23 @@ function DiagramFrame({
45
49
  ) }),
46
50
  /* @__PURE__ */ jsxs("div", { className: "sr-only", children: [
47
51
  /* @__PURE__ */ jsx("p", { children: description }),
48
- /* @__PURE__ */ jsx("ul", { children: model.nodes.map((node) => /* @__PURE__ */ jsx("li", { children: onSelectNode ? /* @__PURE__ */ jsx("button", { type: "button", onClick: () => onSelectNode(node.id), children: summaryLine(node) }) : summaryLine(node) }, node.id)) }),
52
+ bands.length > 0 ? /* @__PURE__ */ jsxs("ul", { children: [
53
+ bands.map((band, index) => /* @__PURE__ */ jsxs("li", { children: [
54
+ /* @__PURE__ */ jsx("span", { children: `${band.kind}: ${band.label}` }),
55
+ /* @__PURE__ */ jsx("ul", { children: band.ids.flatMap((id) => {
56
+ const node = byId.get(id);
57
+ return node ? [row(node)] : [];
58
+ }) })
59
+ ] }, `${band.label}-${index}`)),
60
+ loose.length > 0 && /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("ul", { children: loose.map(row) }) })
61
+ ] }) : /* @__PURE__ */ jsx("ul", { children: model.nodes.map(row) }),
49
62
  model.edges.length > 0 && /* @__PURE__ */ jsx("ul", { children: model.edges.map((edge, index) => /* @__PURE__ */ jsxs("li", { children: [
50
63
  byId.get(edge.from)?.label ?? edge.from,
51
64
  " \u2192 ",
52
65
  byId.get(edge.to)?.label ?? edge.to,
53
66
  edge.label ? `: ${edge.label}` : ""
54
- ] }, index)) })
67
+ ] }, index)) }),
68
+ model.notes && model.notes.length > 0 && /* @__PURE__ */ jsx("ul", { children: model.notes.map((note, index) => /* @__PURE__ */ jsx("li", { children: note }, index)) })
55
69
  ] }),
56
70
  showLegend && /* @__PURE__ */ jsx(DiagramLegend, { entries: model.legend }),
57
71
  showCards && cards && cards.length > 0 && /* @__PURE__ */ jsx(CardGrid, { cards }),
@@ -62,6 +76,7 @@ function summaryLine(node) {
62
76
  const parts = [node.label];
63
77
  if (node.kind) parts.push(`(${node.kind})`);
64
78
  if (node.sublabel) parts.push(`\u2014 ${node.sublabel}`);
79
+ if (node.detail) parts.push(`\u2014 ${node.detail}`);
65
80
  return parts.join(" ");
66
81
  }
67
82
  function CardGrid({ cards, className }) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/diagrams/lib/frame.tsx"],"sourcesContent":["'use client'\n\nimport { useId, type ReactNode } from 'react'\nimport { cn } from '../../lib/cn'\nimport type { DiagramCard, DiagramMeta, LegendMode } from '../spec'\nimport { viewBoxOf, type Box } from './geometry'\nimport { DiagramLegend } from '../DiagramLegend/DiagramLegend'\nimport { DiagramDefs } from './marks'\n\n/**\n * What a figure hands the frame around it.\n *\n * Five renderers produce this one shape, which is what lets the title, the\n * accessible summary, the key and the conclusion cards be written once. A\n * renderer's only job is placing marks; everything a reader needs AROUND the\n * picture is the same question in all five cases.\n */\nexport interface FigureModel {\n /** The extent the artwork was drawn into. */\n extent: Box\n artwork: ReactNode\n /** Every drawn box, for the summary list. */\n nodes: { id: string; label: string; sublabel?: string; kind?: string }[]\n /** Every drawn line, for the summary list. */\n edges: { from: string; to: string; label?: string }[]\n /** The kinds actually used, and how each is drawn. */\n legend: { key: string; label: string; sample: ReactNode }[]\n}\n\nexport interface FigureChrome {\n className?: string\n /** Prints the key under the figure. `auto` shows only the kinds in use. */\n legend?: LegendMode\n /** Prints the conclusion cards under the figure. Defaults to true. */\n cards?: boolean\n /** Prints the title and subtitle over the figure. Defaults to true. */\n heading?: boolean\n /** Node ids currently lit. Everything else is dimmed. */\n activeIds?: string[]\n /**\n * Called when a reader picks a node.\n *\n * Giving this turns the summary list from a description into a control: the\n * same list a screen reader reads becomes the keyboard's route to selection,\n * and the plates in the picture become the pointer's route to the same thing.\n */\n onSelectNode?: (id: string) => void\n}\n\n/**\n * The shell every figure sits in: a heading, the picture, a key, the cards, and\n * the part that makes the picture mean anything to a reader who cannot see it.\n *\n * ## The accessibility decision, stated rather than implied\n *\n * The `<svg>` carries `role=\"img\"` and a label, which makes its whole subtree\n * presentational. That is the honest description of what it is — a picture —\n * and it is what stops a screen reader from walking two hundred `<text>`\n * elements in drawing order, which is neither reading order nor useful.\n *\n * The diagram's CONTENT is then published beside it as an ordinary list: every\n * node with what kind of thing it is, and every relationship as \"A → B: over\n * HTTPS\". That list is where the meaning lives for anyone not looking at the\n * picture, and it is why this component takes a model rather than markup — a\n * frame handed a finished `<svg>` could not have written it.\n *\n * The list is visually hidden by default and NOT hidden from assistive\n * technology, which is the opposite of what `aria-hidden` would do and the\n * whole point.\n */\nexport function DiagramFrame({\n meta,\n model,\n cards,\n className,\n legend = 'auto',\n showCards = true,\n heading = true,\n activeIds,\n onSelectNode,\n}: {\n meta: DiagramMeta\n model: FigureModel\n cards?: DiagramCard[]\n showCards?: boolean\n} & Omit<FigureChrome, 'cards'>) {\n const uid = useId().replace(/:/g, '')\n const titleId = `${uid}-title`\n const descId = `${uid}-desc`\n\n const byId = new Map(model.nodes.map((node) => [node.id, node]))\n const description = `${model.nodes.length} elements and ${model.edges.length} relationships. ${\n meta.subtitle ?? ''\n }`.trim()\n\n const showLegend = legend !== 'hidden' && model.legend.length > 0\n\n return (\n <figure className={cn('m-0 flex flex-col gap-5', className)}>\n {/* The title is set in the editorial serif, which is the system's own\n answer to \"this is a heading\" — and it is what stops a figure from\n reading as a screenshot dropped into the page. The subtitle stays in\n the meta voice underneath it. */}\n {heading && (\n <div className=\"flex flex-col gap-1.5\">\n <h3 className=\"m-0 font-heading text-[length:var(--fs-sub)] font-normal leading-[1.15] tracking-[-0.015em] text-(--ink)\">\n {meta.title}\n </h3>\n {meta.subtitle && <span className=\"mono-meta text-(--ink-3-aa)\">{meta.subtitle}</span>}\n </div>\n )}\n\n <div className=\"overflow-x-auto rounded-(--radius-lg) border border-(--rule) bg-(--diagram-surface) p-[clamp(0.75rem,calc(1.6*var(--fluid)),1.25rem)] scroll-slim\">\n <svg\n viewBox={viewBoxOf(model.extent)}\n role=\"img\"\n aria-labelledby={`${titleId} ${descId}`}\n className=\"block h-auto w-full max-w-full font-sans\"\n data-diagram-artwork=\"\"\n >\n <title id={titleId}>{meta.title}</title>\n <desc id={descId}>{description}</desc>\n <DiagramDefs uid={uid} />\n {model.artwork}\n </svg>\n </div>\n\n {/* The picture's content, for anyone not looking at the picture. */}\n <div className=\"sr-only\">\n <p>{description}</p>\n <ul>\n {model.nodes.map((node) => (\n <li key={node.id}>\n {onSelectNode ? (\n <button type=\"button\" onClick={() => onSelectNode(node.id)}>\n {summaryLine(node)}\n </button>\n ) : (\n summaryLine(node)\n )}\n </li>\n ))}\n </ul>\n {model.edges.length > 0 && (\n <ul>\n {model.edges.map((edge, index) => (\n <li key={index}>\n {(byId.get(edge.from)?.label ?? edge.from)} → {(byId.get(edge.to)?.label ?? edge.to)}\n {edge.label ? `: ${edge.label}` : ''}\n </li>\n ))}\n </ul>\n )}\n </div>\n\n {showLegend && <DiagramLegend entries={model.legend} />}\n\n {showCards && cards && cards.length > 0 && <CardGrid cards={cards} />}\n\n {activeIds && activeIds.length > 0 && <span className=\"sr-only\" role=\"status\">{`${activeIds.length} highlighted`}</span>}\n </figure>\n )\n}\n\nfunction summaryLine(node: { label: string; sublabel?: string; kind?: string }): string {\n const parts = [node.label]\n if (node.kind) parts.push(`(${node.kind})`)\n if (node.sublabel) parts.push(`— ${node.sublabel}`)\n return parts.join(' ')\n}\n\n/**\n * The conclusion cards under a figure.\n *\n * Archify keys these by hue — cyan, emerald, rose. Here the key selects a MARK:\n * a filled square, a ring, a bar, a diagonal. Seven cards in a row stay seven\n * distinguishable cards on paper-white, and the same row survives being\n * printed.\n */\nexport function CardGrid({ cards, className }: { cards: DiagramCard[]; className?: string }) {\n return (\n <div\n className={cn(\n 'grid gap-3 sm:grid-cols-2 lg:grid-cols-3',\n className,\n )}\n >\n {cards.map((card) => (\n <div key={card.title} className=\"flex flex-col gap-2.5 border-t border-(--ink) pt-3\">\n <div className=\"flex items-center gap-2\">\n <CardMark shape={card.dot} />\n <span className=\"font-sans text-[13.5px] leading-[1.35] text-(--ink)\">{card.title}</span>\n </div>\n <ul className=\"m-0 flex list-none flex-col gap-1.5 p-0\">\n {card.items.map((item, index) => (\n <li\n key={index}\n className=\"text-[12.5px] leading-[1.55] text-(--ink-2) ps-3 -indent-3 before:content-['—'] before:pe-1.5 before:text-(--ink-3-aa)\"\n >\n {item}\n </li>\n ))}\n </ul>\n </div>\n ))}\n </div>\n )\n}\n\n/** Seven marks, one per archify dot name, and not one of them a hue. */\nfunction CardMark({ shape }: { shape: DiagramCard['dot'] }) {\n const common = 'size-2.5 shrink-0'\n switch (shape) {\n case 'cyan':\n return <span aria-hidden className={cn(common, 'bg-(--ink)')} />\n case 'emerald':\n return <span aria-hidden className={cn(common, 'rounded-full bg-(--ink)')} />\n case 'violet':\n return <span aria-hidden className={cn(common, 'rounded-full border border-(--ink)')} />\n case 'amber':\n return <span aria-hidden className={cn(common, 'border border-(--ink)')} />\n case 'rose':\n return <span aria-hidden className={cn(common, 'rotate-45 bg-(--ink)')} />\n case 'orange':\n return <span aria-hidden className={cn(common, 'rotate-45 border border-(--ink)')} />\n case 'slate':\n default:\n return <span aria-hidden className={cn('h-1 w-2.5 shrink-0 bg-(--ink-3-aa)')} />\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/diagrams/lib/frame.tsx"],"sourcesContent":["'use client'\n\nimport { useId, type ReactNode } from 'react'\nimport { cn } from '../../lib/cn'\nimport type { DiagramCard, DiagramMeta, LegendMode } from '../spec'\nimport { viewBoxOf, type Box } from './geometry'\nimport { DiagramLegend } from '../DiagramLegend/DiagramLegend'\nimport { DiagramDefs } from './marks'\n\n/**\n * What a figure hands the frame around it.\n *\n * Five renderers produce this one shape, which is what lets the title, the\n * accessible summary, the key and the conclusion cards be written once. A\n * renderer's only job is placing marks; everything a reader needs AROUND the\n * picture is the same question in all five cases.\n */\nexport interface FigureModel {\n /** The extent the artwork was drawn into. */\n extent: Box\n artwork: ReactNode\n /** Every drawn box, for the summary list. */\n nodes: FigureNode[]\n /** Every drawn line, for the summary list. */\n edges: { from: string; to: string; label?: string }[]\n /** The kinds actually used, and how each is drawn. */\n legend: { key: string; label: string; sample: ReactNode }[]\n /**\n * The figure's second axis, as a PARTITION of the nodes above.\n *\n * A workflow's lanes and a data flow's stages are not decoration around the\n * boxes — they are the other half of every box's position, and a summary that\n * lists the boxes alone has published one dimension of a two-dimensional\n * picture. Giving the list this structure says it once, in the place a screen\n * reader already walks, rather than repeating \"in the CI lane\" on every row.\n *\n * A node may appear in at most one band: the list is the keyboard's only\n * route to a selection, and a node in two bands is two controls that do the\n * same thing. Anything left out of every band is published after them.\n */\n bands?: FigureBand[]\n /**\n * What the picture says that is neither a box nor a line.\n *\n * Boundaries, phase captions, segment captions, activation bars: each is a\n * real statement drawn inside an `aria-hidden` `<svg>`, and each is a\n * sentence rather than a row, so each figure writes its own.\n */\n notes?: string[]\n}\n\n/** One drawn box, as the summary publishes it. */\nexport interface FigureNode {\n id: string\n label: string\n sublabel?: string\n kind?: string\n /** A short phrase the picture prints on the box: a step number. */\n detail?: string\n}\n\n/** One band of a figure's second axis: a lane, a stage. */\nexport interface FigureBand {\n /** What KIND of band this is — \"Lane\", \"Stage\" — since the label is a name. */\n kind: string\n label: string\n /** The nodes inside it, in the order the figure draws them. */\n ids: string[]\n}\n\nexport interface FigureChrome {\n className?: string\n /** Prints the key under the figure. `auto` shows only the kinds in use. */\n legend?: LegendMode\n /** Prints the conclusion cards under the figure. Defaults to true. */\n cards?: boolean\n /** Prints the title and subtitle over the figure. Defaults to true. */\n heading?: boolean\n /** Node ids currently lit. Everything else is dimmed. */\n activeIds?: string[]\n /**\n * Called when a reader picks a node.\n *\n * Giving this turns the summary list from a description into a control: the\n * same list a screen reader reads becomes the keyboard's route to selection,\n * and the plates in the picture become the pointer's route to the same thing.\n */\n onSelectNode?: (id: string) => void\n}\n\n/**\n * The shell every figure sits in: a heading, the picture, a key, the cards, and\n * the part that makes the picture mean anything to a reader who cannot see it.\n *\n * ## The accessibility decision, stated rather than implied\n *\n * The `<svg>` carries `role=\"img\"` and a label, which makes its whole subtree\n * presentational. That is the honest description of what it is — a picture —\n * and it is what stops a screen reader from walking two hundred `<text>`\n * elements in drawing order, which is neither reading order nor useful.\n *\n * The diagram's CONTENT is then published beside it as an ordinary list: every\n * node with what kind of thing it is, and every relationship as \"A → B: over\n * HTTPS\". That list is where the meaning lives for anyone not looking at the\n * picture, and it is why this component takes a model rather than markup — a\n * frame handed a finished `<svg>` could not have written it.\n *\n * The list carries the figure's SECOND AXIS as its own structure. A workflow's\n * lanes and a data flow's stages are half of where every box sits, and they are\n * drawn inside the presentational `<svg>` — so a flat list of boxes published\n * one dimension of a two-dimensional picture and called it the content. Nodes\n * are grouped by their band, and the statements that group nothing — a\n * boundary, a phase caption, an activation bar — follow as sentences.\n *\n * The list is visually hidden by default and NOT hidden from assistive\n * technology, which is the opposite of what `aria-hidden` would do and the\n * whole point.\n */\nexport function DiagramFrame({\n meta,\n model,\n cards,\n className,\n legend = 'auto',\n showCards = true,\n heading = true,\n activeIds,\n onSelectNode,\n}: {\n meta: DiagramMeta\n model: FigureModel\n cards?: DiagramCard[]\n showCards?: boolean\n} & Omit<FigureChrome, 'cards'>) {\n const uid = useId().replace(/:/g, '')\n const titleId = `${uid}-title`\n const descId = `${uid}-desc`\n\n const byId = new Map(model.nodes.map((node) => [node.id, node]))\n const description = `${model.nodes.length} elements and ${model.edges.length} relationships. ${\n meta.subtitle ?? ''\n }`.trim()\n\n const showLegend = legend !== 'hidden' && model.legend.length > 0\n\n // Bands partition the nodes; anything a figure left out of every band is\n // still published, after them. A node dropped from the list entirely would be\n // a node a keyboard cannot reach.\n const bands = model.bands ?? []\n const banded = new Set(bands.flatMap((band) => band.ids))\n const loose = bands.length > 0 ? model.nodes.filter((node) => !banded.has(node.id)) : []\n\n const row = (node: FigureNode) => (\n <li key={node.id}>\n {onSelectNode ? (\n <button type=\"button\" onClick={() => onSelectNode(node.id)}>\n {summaryLine(node)}\n </button>\n ) : (\n summaryLine(node)\n )}\n </li>\n )\n\n return (\n <figure className={cn('m-0 flex flex-col gap-5', className)}>\n {/* The title is set in the editorial serif, which is the system's own\n answer to \"this is a heading\" — and it is what stops a figure from\n reading as a screenshot dropped into the page. The subtitle stays in\n the meta voice underneath it. */}\n {heading && (\n <div className=\"flex flex-col gap-1.5\">\n <h3 className=\"m-0 font-heading text-[length:var(--fs-sub)] font-normal leading-[1.15] tracking-[-0.015em] text-(--ink)\">\n {meta.title}\n </h3>\n {meta.subtitle && <span className=\"mono-meta text-(--ink-3-aa)\">{meta.subtitle}</span>}\n </div>\n )}\n\n <div className=\"overflow-x-auto rounded-(--radius-lg) border border-(--rule) bg-(--diagram-surface) p-[clamp(0.75rem,calc(1.6*var(--fluid)),1.25rem)] scroll-slim\">\n <svg\n viewBox={viewBoxOf(model.extent)}\n role=\"img\"\n aria-labelledby={`${titleId} ${descId}`}\n className=\"block h-auto w-full max-w-full font-sans\"\n data-diagram-artwork=\"\"\n >\n <title id={titleId}>{meta.title}</title>\n <desc id={descId}>{description}</desc>\n <DiagramDefs uid={uid} />\n {model.artwork}\n </svg>\n </div>\n\n {/* The picture's content, for anyone not looking at the picture. */}\n <div className=\"sr-only\">\n <p>{description}</p>\n {bands.length > 0 ? (\n <ul>\n {bands.map((band, index) => (\n <li key={`${band.label}-${index}`}>\n <span>{`${band.kind}: ${band.label}`}</span>\n <ul>\n {band.ids.flatMap((id) => {\n const node = byId.get(id)\n return node ? [row(node)] : []\n })}\n </ul>\n </li>\n ))}\n {loose.length > 0 && (\n <li>\n <ul>{loose.map(row)}</ul>\n </li>\n )}\n </ul>\n ) : (\n <ul>{model.nodes.map(row)}</ul>\n )}\n {model.edges.length > 0 && (\n <ul>\n {model.edges.map((edge, index) => (\n <li key={index}>\n {(byId.get(edge.from)?.label ?? edge.from)} → {(byId.get(edge.to)?.label ?? edge.to)}\n {edge.label ? `: ${edge.label}` : ''}\n </li>\n ))}\n </ul>\n )}\n {model.notes && model.notes.length > 0 && (\n <ul>\n {model.notes.map((note, index) => (\n <li key={index}>{note}</li>\n ))}\n </ul>\n )}\n </div>\n\n {showLegend && <DiagramLegend entries={model.legend} />}\n\n {showCards && cards && cards.length > 0 && <CardGrid cards={cards} />}\n\n {activeIds && activeIds.length > 0 && <span className=\"sr-only\" role=\"status\">{`${activeIds.length} highlighted`}</span>}\n </figure>\n )\n}\n\nfunction summaryLine(node: FigureNode): string {\n const parts = [node.label]\n if (node.kind) parts.push(`(${node.kind})`)\n if (node.sublabel) parts.push(`— ${node.sublabel}`)\n if (node.detail) parts.push(`— ${node.detail}`)\n return parts.join(' ')\n}\n\n/**\n * The conclusion cards under a figure.\n *\n * Archify keys these by hue — cyan, emerald, rose. Here the key selects a MARK:\n * a filled square, a ring, a bar, a diagonal. Seven cards in a row stay seven\n * distinguishable cards on paper-white, and the same row survives being\n * printed.\n */\nexport function CardGrid({ cards, className }: { cards: DiagramCard[]; className?: string }) {\n return (\n <div\n className={cn(\n 'grid gap-3 sm:grid-cols-2 lg:grid-cols-3',\n className,\n )}\n >\n {cards.map((card) => (\n <div key={card.title} className=\"flex flex-col gap-2.5 border-t border-(--ink) pt-3\">\n <div className=\"flex items-center gap-2\">\n <CardMark shape={card.dot} />\n <span className=\"font-sans text-[13.5px] leading-[1.35] text-(--ink)\">{card.title}</span>\n </div>\n <ul className=\"m-0 flex list-none flex-col gap-1.5 p-0\">\n {card.items.map((item, index) => (\n <li\n key={index}\n className=\"text-[12.5px] leading-[1.55] text-(--ink-2) ps-3 -indent-3 before:content-['—'] before:pe-1.5 before:text-(--ink-3-aa)\"\n >\n {item}\n </li>\n ))}\n </ul>\n </div>\n ))}\n </div>\n )\n}\n\n/** Seven marks, one per archify dot name, and not one of them a hue. */\nfunction CardMark({ shape }: { shape: DiagramCard['dot'] }) {\n const common = 'size-2.5 shrink-0'\n switch (shape) {\n case 'cyan':\n return <span aria-hidden className={cn(common, 'bg-(--ink)')} />\n case 'emerald':\n return <span aria-hidden className={cn(common, 'rounded-full bg-(--ink)')} />\n case 'violet':\n return <span aria-hidden className={cn(common, 'rounded-full border border-(--ink)')} />\n case 'amber':\n return <span aria-hidden className={cn(common, 'border border-(--ink)')} />\n case 'rose':\n return <span aria-hidden className={cn(common, 'rotate-45 bg-(--ink)')} />\n case 'orange':\n return <span aria-hidden className={cn(common, 'rotate-45 border border-(--ink)')} />\n case 'slate':\n default:\n return <span aria-hidden className={cn('h-1 w-2.5 shrink-0 bg-(--ink-3-aa)')} />\n }\n}\n"],"mappings":"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","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/diagrams/lib/wires.tsx"],"sourcesContent":["import type { ReactNode } from 'react'\nimport type { EdgeBase, Side, Variant } from '../spec'\nimport type { Box } from './geometry'\nimport { edgeClasses, EdgeLabel, edgeMarker, edgeStroke } from './marks'\nimport { routeEdge, spreadPorts, type PortUse } from './route'\n\n/** One line to draw, once its two boxes are known. */\nexport interface Wire {\n edge: EdgeBase & { variant?: Variant | 'return'; classification?: string; note?: string }\n from: Box\n to: Box\n /** Overrides the variant's own stroke weight — a main path drawn heavier. */\n weight?: number\n /** An open arrowhead rather than a filled one. */\n open?: boolean\n /**\n * Whether this line's `via` / `channelX` / `channelY` mean anything here.\n *\n * A waypoint is an ABSOLUTE coordinate in whatever space the author's nodes\n * were placed in. When a specification pins its nodes with `pos`, that space\n * is this renderer's space too and the waypoints land exactly where they were\n * meant to. When the nodes are placed from a lane and a column, this renderer\n * chose the coordinates — so the author's waypoints refer to a grid that does\n * not exist here, and following them drags lines across unrelated nodes.\n *\n * So the rule is per line and not per figure: honour the waypoints when both\n * of a line's endpoints were placed absolutely, and route automatically\n * otherwise. Defaults to false, which is the safe half.\n */\n keepWaypoints?: boolean\n}\n\n/**\n * Every line in a figure, routed together.\n *\n * Together rather than one at a time, because port spreading is a property of a\n * FACE and not of a line: how far off centre a given arrow sits depends on how\n * many others land on the same face, which no single line can know. Routing\n * them independently is what produces three arrowheads stacked on one point.\n *\n * Lines that pin their own geometry — `via`, a channel, an explicit side — opt\n * out of the spread. An author who placed a line has already answered the\n * question the spread exists to answer, and moving it afterwards makes the\n * control useless.\n *\n * Returns the paths and the labels separately because ORDER IS THE MASK: a\n * label's plate has to be painted over every line in the figure, not merely\n * over its own. Interleaving them puts the third line on top of the first\n * line's label.\n */\nexport function renderWires(\n wires: Wire[],\n uid: string,\n): { paths: ReactNode; labels: ReactNode } {\n const uses: PortUse[] = []\n\n wires.forEach((wire, index) => {\n const { edge } = wire\n const pinned =\n wire.keepWaypoints === true &&\n Boolean(edge.via?.length || edge.channelX !== undefined || edge.channelY !== undefined)\n if (pinned) return\n if (edge.fromSide) uses.push({ face: `${edge.from}:${edge.fromSide}`, ref: `${index}:from` })\n if (edge.toSide) uses.push({ face: `${edge.to}:${edge.toSide}`, ref: `${index}:to` })\n if (!edge.fromSide) uses.push({ face: `${edge.from}:auto`, ref: `${index}:from` })\n if (!edge.toSide) uses.push({ face: `${edge.to}:auto`, ref: `${index}:to` })\n })\n\n const offsets = spreadPorts(uses)\n\n const routed = wires.map((wire, index) => {\n const { edge } = wire\n const keep = wire.keepWaypoints === true\n return {\n wire,\n index,\n route: routeEdge({\n from: wire.from,\n to: wire.to,\n fromSide: edge.fromSide as Side | undefined,\n toSide: edge.toSide as Side | undefined,\n mode: edge.route,\n via: keep ? edge.via : undefined,\n channelX: keep ? edge.channelX : undefined,\n channelY: keep ? edge.channelY : undefined,\n fromOffset: offsets.get(`${index}:from`),\n toOffset: offsets.get(`${index}:to`),\n }),\n }\n })\n\n return {\n paths: (\n <g data-diagram-wires=\"\">\n {routed.map(({ wire, index, route }) => (\n <path\n key={wire.edge.id ?? index}\n d={route.d}\n fill=\"none\"\n data-edge={wire.edge.id}\n markerEnd={`url(#${uid}-${wire.open ? 'arrow-open' : edgeMarker(wire.edge.variant)})`}\n className={edgeClasses(wire.edge.variant)}\n {...edgeStroke(wire.edge.variant, wire.weight)}\n />\n ))}\n </g>\n ),\n labels: (\n <g data-diagram-wire-labels=\"\">\n {routed.map(({ wire, index, route }) =>\n wire.edge.label ? (\n /* `labelDx` / `labelDy` / `labelAt` are deliberately NOT applied.\n They are collision repairs authored against archify's router,\n measured in the positions THAT router produced — and this one\n does not produce the same collisions, so honouring them moves\n labels off clear ground and onto the nodes they were nudged away\n from. Dropping the nudge and keeping the wording is the reading\n that preserves the meaning; the field stays in the type so a\n specification carrying it still typechecks. */\n <EdgeLabel\n key={wire.edge.id ?? index}\n x={route.label.x}\n y={route.label.y}\n axis={route.label.axis}\n text={wire.edge.label}\n chip={wire.edge.classification}\n note={wire.edge.note}\n />\n ) : null,\n )}\n </g>\n ),\n }\n}\n\n/** Resolves an edge's endpoints against a box index, dropping any that dangle. */\nexport function wiresFor<E extends EdgeBase>(\n edges: E[] | undefined,\n boxes: Map<string, Box>,\n decorate?: (edge: E) => Partial<Wire>,\n): Wire[] {\n if (!edges) return []\n const out: Wire[] = []\n for (const edge of edges) {\n const from = boxes.get(edge.from)\n const to = boxes.get(edge.to)\n // A relationship naming a node that is not in the figure is a specification\n // error, and drawing it from nowhere to nowhere would hide that. Dropping\n // it leaves the summary list which iterates the same array as the place\n // the mistake shows up as a line pointing at an id no node claims.\n if (!from || !to) continue\n out.push({ edge, from, to, ...decorate?.(edge) })\n }\n return out\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/diagrams/lib/wires.tsx"],"sourcesContent":["import type { ReactNode } from 'react'\nimport type { EdgeBase, Side, Variant } from '../spec'\nimport type { Box } from './geometry'\nimport { edgeClasses, EdgeLabel, edgeMarker, edgeStroke } from './marks'\nimport { routeEdge, spreadPorts, type PortUse } from './route'\n\n/** One line to draw, once its two boxes are known. */\nexport interface Wire {\n edge: EdgeBase & { variant?: Variant | 'return'; classification?: string; note?: string }\n from: Box\n to: Box\n /** Overrides the variant's own stroke weight — a main path drawn heavier. */\n weight?: number\n /** An open arrowhead rather than a filled one. */\n open?: boolean\n /**\n * Whether this line's `via` / `channelX` / `channelY` mean anything here.\n *\n * A waypoint is an ABSOLUTE coordinate in whatever space the author's nodes\n * were placed in. When a specification pins its nodes with `pos`, that space\n * is this renderer's space too and the waypoints land exactly where they were\n * meant to. When the nodes are placed from a lane and a column, this renderer\n * chose the coordinates — so the author's waypoints refer to a grid that does\n * not exist here, and following them drags lines across unrelated nodes.\n *\n * So the rule is per line and not per figure: honour the waypoints when both\n * of a line's endpoints were placed absolutely, and route automatically\n * otherwise. Defaults to false, which is the safe half.\n */\n keepWaypoints?: boolean\n}\n\n/**\n * Every line in a figure, routed together.\n *\n * Together rather than one at a time, because port spreading is a property of a\n * FACE and not of a line: how far off centre a given arrow sits depends on how\n * many others land on the same face, which no single line can know. Routing\n * them independently is what produces three arrowheads stacked on one point.\n *\n * Lines that pin their own geometry — `via`, a channel, an explicit side — opt\n * out of the spread. An author who placed a line has already answered the\n * question the spread exists to answer, and moving it afterwards makes the\n * control useless.\n *\n * Returns the paths and the labels separately because ORDER IS THE MASK: a\n * label's plate has to be painted over every line in the figure, not merely\n * over its own. Interleaving them puts the third line on top of the first\n * line's label.\n */\nexport function renderWires(\n wires: Wire[],\n uid: string,\n): { paths: ReactNode; labels: ReactNode } {\n const uses: PortUse[] = []\n\n wires.forEach((wire, index) => {\n const { edge } = wire\n const pinned =\n wire.keepWaypoints === true &&\n Boolean(edge.via?.length || edge.channelX !== undefined || edge.channelY !== undefined)\n if (pinned) return\n if (edge.fromSide) uses.push({ face: `${edge.from}:${edge.fromSide}`, ref: `${index}:from` })\n if (edge.toSide) uses.push({ face: `${edge.to}:${edge.toSide}`, ref: `${index}:to` })\n if (!edge.fromSide) uses.push({ face: `${edge.from}:auto`, ref: `${index}:from` })\n if (!edge.toSide) uses.push({ face: `${edge.to}:auto`, ref: `${index}:to` })\n })\n\n const offsets = spreadPorts(uses)\n\n const routed = wires.map((wire, index) => {\n const { edge } = wire\n const keep = wire.keepWaypoints === true\n return {\n wire,\n index,\n route: routeEdge({\n from: wire.from,\n to: wire.to,\n fromSide: edge.fromSide as Side | undefined,\n toSide: edge.toSide as Side | undefined,\n mode: edge.route,\n via: keep ? edge.via : undefined,\n channelX: keep ? edge.channelX : undefined,\n channelY: keep ? edge.channelY : undefined,\n fromOffset: offsets.get(`${index}:from`),\n toOffset: offsets.get(`${index}:to`),\n }),\n }\n })\n\n return {\n paths: (\n <g data-diagram-wires=\"\">\n {routed.map(({ wire, index, route }) => (\n <path\n key={wire.edge.id ?? index}\n d={route.d}\n fill=\"none\"\n data-edge={wire.edge.id}\n markerEnd={`url(#${uid}-${wire.open ? 'arrow-open' : edgeMarker(wire.edge.variant)})`}\n className={edgeClasses(wire.edge.variant)}\n {...edgeStroke(wire.edge.variant, wire.weight)}\n />\n ))}\n </g>\n ),\n labels: (\n <g data-diagram-wire-labels=\"\">\n {routed.map(({ wire, index, route }) =>\n wire.edge.label ? (\n /* `labelDx` / `labelDy` / `labelAt` are deliberately NOT applied.\n They are collision repairs authored against archify's router,\n measured in the positions THAT router produced — and this one\n does not produce the same collisions, so honouring them moves\n labels off clear ground and onto the nodes they were nudged away\n from. Dropping the nudge and keeping the wording is the reading\n that preserves the meaning; the field stays in the type so a\n specification carrying it still typechecks. */\n <EdgeLabel\n key={wire.edge.id ?? index}\n x={route.label.x}\n y={route.label.y}\n axis={route.label.axis}\n text={wire.edge.label}\n chip={wire.edge.classification}\n note={wire.edge.note}\n />\n ) : null,\n )}\n </g>\n ),\n }\n}\n\n/** Resolves an edge's endpoints against a box index, dropping any that dangle. */\nexport function wiresFor<E extends EdgeBase>(\n edges: E[] | undefined,\n boxes: Map<string, Box>,\n decorate?: (edge: E) => Partial<Wire>,\n): Wire[] {\n if (!edges) return []\n const out: Wire[] = []\n for (const edge of edges) {\n const from = boxes.get(edge.from)\n const to = boxes.get(edge.to)\n // A relationship naming a node that is not in the figure is a specification\n // error, and drawing it from nowhere to nowhere would hide that. The\n // figures filter the same edges through `liveEdges` before they get here,\n // so the drop is announced once in development and the summary list agrees\n // with the picture; this guard is what makes that agreement structural\n // rather than a convention every renderer has to remember.\n if (!from || !to) continue\n out.push({ edge, from, to, ...decorate?.(edge) })\n }\n return out\n}\n"],"mappings":"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","names":[]}