@misoto22/design 0.7.0 → 0.9.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 (398) 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/ColorPicker.md +75 -0
  28. package/dist/agent/Combobox.md +29 -3
  29. package/dist/agent/Command.md +25 -2
  30. package/dist/agent/ComposedChart.md +26 -2
  31. package/dist/agent/ContextMenu.md +37 -4
  32. package/dist/agent/DataflowFigure.md +22 -1
  33. package/dist/agent/DatePicker.md +34 -6
  34. package/dist/agent/DescriptionList.md +68 -0
  35. package/dist/agent/Diagram.md +27 -3
  36. package/dist/agent/DiagramCanvas.md +24 -1
  37. package/dist/agent/DiagramExportMenu.md +29 -3
  38. package/dist/agent/DiagramInspector.md +23 -1
  39. package/dist/agent/DiagramLegend.md +22 -1
  40. package/dist/agent/DiagramMinimap.md +24 -4
  41. package/dist/agent/DiagramToolbar.md +23 -1
  42. package/dist/agent/Dialog.md +26 -3
  43. package/dist/agent/DropdownMenu.md +45 -6
  44. package/dist/agent/EmptyState.md +26 -1
  45. package/dist/agent/ErrorState.md +27 -2
  46. package/dist/agent/Facet.md +25 -1
  47. package/dist/agent/Field.md +45 -4
  48. package/dist/agent/FigureBand.md +24 -1
  49. package/dist/agent/FloatingIconButton.md +23 -1
  50. package/dist/agent/FunnelChart.md +23 -1
  51. package/dist/agent/Heading.md +64 -0
  52. package/dist/agent/Heatmap.md +25 -1
  53. package/dist/agent/Histogram.md +26 -2
  54. package/dist/agent/Input.md +22 -1
  55. package/dist/agent/Kbd.md +19 -1
  56. package/dist/agent/LifecycleFigure.md +22 -1
  57. package/dist/agent/LineChart.md +26 -2
  58. package/dist/agent/LinkArrow.md +20 -1
  59. package/dist/agent/Markdown.md +68 -0
  60. package/dist/agent/NativeSelect.md +23 -2
  61. package/dist/agent/NavItem.md +21 -1
  62. package/dist/agent/NumberField.md +72 -0
  63. package/dist/agent/Pagination.md +28 -2
  64. package/dist/agent/PieChart.md +26 -2
  65. package/dist/agent/Popover.md +23 -1
  66. package/dist/agent/Progress.md +27 -3
  67. package/dist/agent/RadarChart.md +26 -2
  68. package/dist/agent/RadialChart.md +26 -3
  69. package/dist/agent/RadioGroup.md +23 -2
  70. package/dist/agent/SankeyChart.md +25 -2
  71. package/dist/agent/ScatterChart.md +27 -2
  72. package/dist/agent/ScrollArea.md +24 -3
  73. package/dist/agent/SearchableMenu.md +23 -1
  74. package/dist/agent/Select.md +29 -3
  75. package/dist/agent/Separator.md +28 -4
  76. package/dist/agent/SequenceFigure.md +23 -1
  77. package/dist/agent/Sheet.md +25 -2
  78. package/dist/agent/Sidebar.md +193 -0
  79. package/dist/agent/Skeleton.md +24 -2
  80. package/dist/agent/Slider.md +31 -4
  81. package/dist/agent/Sparkline.md +23 -1
  82. package/dist/agent/Spinner.md +24 -2
  83. package/dist/agent/StatusDot.md +20 -1
  84. package/dist/agent/StatusPill.md +28 -2
  85. package/dist/agent/Steps.md +24 -1
  86. package/dist/agent/Switch.md +21 -1
  87. package/dist/agent/Table.md +28 -3
  88. package/dist/agent/Tabs.md +24 -2
  89. package/dist/agent/Tag.md +40 -9
  90. package/dist/agent/Text.md +65 -0
  91. package/dist/agent/Textarea.md +20 -1
  92. package/dist/agent/Timestamp.md +64 -0
  93. package/dist/agent/Toast.md +26 -2
  94. package/dist/agent/ToggleGroup.md +24 -2
  95. package/dist/agent/Toolbar.md +71 -0
  96. package/dist/agent/Tooltip.md +23 -1
  97. package/dist/agent/TreemapChart.md +24 -1
  98. package/dist/agent/WaterfallChart.md +24 -1
  99. package/dist/agent/WorkflowFigure.md +24 -2
  100. package/dist/agent/catalog.json +5915 -699
  101. package/dist/agent/index.md +20 -8
  102. package/dist/article.css +16 -4
  103. package/dist/charts/AreaChart/AreaChart.d.ts +9 -2
  104. package/dist/charts/AreaChart/AreaChart.js +12 -13
  105. package/dist/charts/AreaChart/AreaChart.js.map +1 -1
  106. package/dist/charts/BarChart/BarChart.d.ts +14 -3
  107. package/dist/charts/BarChart/BarChart.js +20 -12
  108. package/dist/charts/BarChart/BarChart.js.map +1 -1
  109. package/dist/charts/BarList/BarList.d.ts +9 -1
  110. package/dist/charts/BarList/BarList.js +9 -1
  111. package/dist/charts/BarList/BarList.js.map +1 -1
  112. package/dist/charts/BigNumber/BigNumber.d.ts +19 -3
  113. package/dist/charts/BigNumber/BigNumber.js +25 -5
  114. package/dist/charts/BigNumber/BigNumber.js.map +1 -1
  115. package/dist/charts/BoxPlot/BoxPlot.js +4 -2
  116. package/dist/charts/BoxPlot/BoxPlot.js.map +1 -1
  117. package/dist/charts/BulletChart/BulletChart.js +44 -9
  118. package/dist/charts/BulletChart/BulletChart.js.map +1 -1
  119. package/dist/charts/ComposedChart/ComposedChart.d.ts +9 -2
  120. package/dist/charts/ComposedChart/ComposedChart.js +10 -10
  121. package/dist/charts/ComposedChart/ComposedChart.js.map +1 -1
  122. package/dist/charts/FunnelChart/FunnelChart.d.ts +7 -2
  123. package/dist/charts/FunnelChart/FunnelChart.js +6 -16
  124. package/dist/charts/FunnelChart/FunnelChart.js.map +1 -1
  125. package/dist/charts/Heatmap/Heatmap.d.ts +17 -3
  126. package/dist/charts/Heatmap/Heatmap.js +20 -11
  127. package/dist/charts/Heatmap/Heatmap.js.map +1 -1
  128. package/dist/charts/Histogram/Histogram.d.ts +24 -1
  129. package/dist/charts/Histogram/Histogram.js +43 -11
  130. package/dist/charts/Histogram/Histogram.js.map +1 -1
  131. package/dist/charts/LineChart/LineChart.d.ts +9 -2
  132. package/dist/charts/LineChart/LineChart.js +11 -12
  133. package/dist/charts/LineChart/LineChart.js.map +1 -1
  134. package/dist/charts/PieChart/PieChart.d.ts +15 -3
  135. package/dist/charts/PieChart/PieChart.js +14 -6
  136. package/dist/charts/PieChart/PieChart.js.map +1 -1
  137. package/dist/charts/RadarChart/RadarChart.d.ts +15 -3
  138. package/dist/charts/RadarChart/RadarChart.js +15 -11
  139. package/dist/charts/RadarChart/RadarChart.js.map +1 -1
  140. package/dist/charts/RadialChart/RadialChart.d.ts +22 -4
  141. package/dist/charts/RadialChart/RadialChart.js +28 -6
  142. package/dist/charts/RadialChart/RadialChart.js.map +1 -1
  143. package/dist/charts/SankeyChart/SankeyChart.d.ts +16 -4
  144. package/dist/charts/SankeyChart/SankeyChart.js +14 -6
  145. package/dist/charts/SankeyChart/SankeyChart.js.map +1 -1
  146. package/dist/charts/ScatterChart/ScatterChart.d.ts +24 -3
  147. package/dist/charts/ScatterChart/ScatterChart.js +21 -15
  148. package/dist/charts/ScatterChart/ScatterChart.js.map +1 -1
  149. package/dist/charts/Sparkline/Sparkline.js +5 -3
  150. package/dist/charts/Sparkline/Sparkline.js.map +1 -1
  151. package/dist/charts/TreemapChart/TreemapChart.d.ts +7 -2
  152. package/dist/charts/TreemapChart/TreemapChart.js +20 -11
  153. package/dist/charts/TreemapChart/TreemapChart.js.map +1 -1
  154. package/dist/charts/WaterfallChart/WaterfallChart.js +4 -2
  155. package/dist/charts/WaterfallChart/WaterfallChart.js.map +1 -1
  156. package/dist/charts/lib/export.d.ts +1 -0
  157. package/dist/charts/lib/figure.d.ts +21 -1
  158. package/dist/charts/lib/figure.js +5 -2
  159. package/dist/charts/lib/figure.js.map +1 -1
  160. package/dist/charts/lib/scale.d.ts +23 -0
  161. package/dist/charts/lib/scale.js +13 -0
  162. package/dist/charts/lib/scale.js.map +1 -0
  163. package/dist/charts/lib/selection.d.ts +20 -0
  164. package/dist/charts/lib/selection.js +18 -0
  165. package/dist/charts/lib/selection.js.map +1 -0
  166. package/dist/charts/lib/toolbar.d.ts +1 -0
  167. package/dist/components/Accordion/Accordion.js +8 -1
  168. package/dist/components/Accordion/Accordion.js.map +1 -1
  169. package/dist/components/AppShell/AppShell.d.ts +6 -0
  170. package/dist/components/AppShell/AppShell.js +34 -4
  171. package/dist/components/AppShell/AppShell.js.map +1 -1
  172. package/dist/components/Article/Article.d.ts +11 -4
  173. package/dist/components/Article/Article.js +13 -0
  174. package/dist/components/Article/Article.js.map +1 -1
  175. package/dist/components/AspectRatio/AspectRatio.d.ts +46 -0
  176. package/dist/components/AspectRatio/AspectRatio.js +33 -0
  177. package/dist/components/AspectRatio/AspectRatio.js.map +1 -0
  178. package/dist/components/Avatar/Avatar.d.ts +12 -3
  179. package/dist/components/Avatar/Avatar.js +6 -1
  180. package/dist/components/Avatar/Avatar.js.map +1 -1
  181. package/dist/components/Breadcrumb/Breadcrumb.d.ts +6 -0
  182. package/dist/components/Breadcrumb/Breadcrumb.js +15 -0
  183. package/dist/components/Breadcrumb/Breadcrumb.js.map +1 -1
  184. package/dist/components/Button/Button.js +14 -0
  185. package/dist/components/Button/Button.js.map +1 -1
  186. package/dist/components/Calendar/Calendar.d.ts +29 -3
  187. package/dist/components/Calendar/Calendar.js +60 -12
  188. package/dist/components/Calendar/Calendar.js.map +1 -1
  189. package/dist/components/Card/Card.d.ts +6 -0
  190. package/dist/components/Card/Card.js +1 -1
  191. package/dist/components/Card/Card.js.map +1 -1
  192. package/dist/components/Checkbox/Checkbox.d.ts +5 -2
  193. package/dist/components/Checkbox/Checkbox.js +12 -2
  194. package/dist/components/Checkbox/Checkbox.js.map +1 -1
  195. package/dist/components/Code/Code.d.ts +30 -0
  196. package/dist/components/Code/Code.js +21 -0
  197. package/dist/components/Code/Code.js.map +1 -0
  198. package/dist/components/CodeBlock/CodeBlock.d.ts +141 -0
  199. package/dist/components/CodeBlock/CodeBlock.js +123 -0
  200. package/dist/components/CodeBlock/CodeBlock.js.map +1 -0
  201. package/dist/components/Collapsible/Collapsible.js +10 -2
  202. package/dist/components/Collapsible/Collapsible.js.map +1 -1
  203. package/dist/components/ColorPicker/ColorPicker.d.ts +67 -0
  204. package/dist/components/ColorPicker/ColorPicker.js +334 -0
  205. package/dist/components/ColorPicker/ColorPicker.js.map +1 -0
  206. package/dist/components/Combobox/Combobox.d.ts +15 -1
  207. package/dist/components/Combobox/Combobox.js +25 -5
  208. package/dist/components/Combobox/Combobox.js.map +1 -1
  209. package/dist/components/Command/Command.d.ts +4 -2
  210. package/dist/components/Command/Command.js +14 -2
  211. package/dist/components/Command/Command.js.map +1 -1
  212. package/dist/components/ContextMenu/ContextMenu.d.ts +30 -5
  213. package/dist/components/ContextMenu/ContextMenu.js +33 -3
  214. package/dist/components/ContextMenu/ContextMenu.js.map +1 -1
  215. package/dist/components/DatePicker/DatePicker.d.ts +36 -4
  216. package/dist/components/DatePicker/DatePicker.js +55 -12
  217. package/dist/components/DatePicker/DatePicker.js.map +1 -1
  218. package/dist/components/DescriptionList/DescriptionList.d.ts +73 -0
  219. package/dist/components/DescriptionList/DescriptionList.js +35 -0
  220. package/dist/components/DescriptionList/DescriptionList.js.map +1 -0
  221. package/dist/components/Diagram/Diagram.d.ts +8 -3
  222. package/dist/components/Diagram/Diagram.js +82 -10
  223. package/dist/components/Diagram/Diagram.js.map +1 -1
  224. package/dist/components/Dialog/Dialog.d.ts +18 -3
  225. package/dist/components/Dialog/Dialog.js +21 -3
  226. package/dist/components/Dialog/Dialog.js.map +1 -1
  227. package/dist/components/DropdownMenu/DropdownMenu.d.ts +49 -11
  228. package/dist/components/DropdownMenu/DropdownMenu.js +33 -3
  229. package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -1
  230. package/dist/components/EmptyState/EmptyState.d.ts +25 -1
  231. package/dist/components/EmptyState/EmptyState.js +3 -1
  232. package/dist/components/EmptyState/EmptyState.js.map +1 -1
  233. package/dist/components/ErrorState/ErrorState.d.ts +22 -1
  234. package/dist/components/ErrorState/ErrorState.js +12 -3
  235. package/dist/components/ErrorState/ErrorState.js.map +1 -1
  236. package/dist/components/Field/Field.d.ts +70 -3
  237. package/dist/components/Field/Field.js +53 -12
  238. package/dist/components/Field/Field.js.map +1 -1
  239. package/dist/components/Field/field-control.d.ts +31 -0
  240. package/dist/components/Field/field-control.js +12 -0
  241. package/dist/components/Field/field-control.js.map +1 -0
  242. package/dist/components/FloatingIconButton/FloatingIconButton.js +2 -0
  243. package/dist/components/FloatingIconButton/FloatingIconButton.js.map +1 -1
  244. package/dist/components/Heading/Heading.d.ts +62 -0
  245. package/dist/components/Heading/Heading.js +44 -0
  246. package/dist/components/Heading/Heading.js.map +1 -0
  247. package/dist/components/Markdown/Markdown.d.ts +139 -0
  248. package/dist/components/Markdown/Markdown.js +135 -0
  249. package/dist/components/Markdown/Markdown.js.map +1 -0
  250. package/dist/components/Markdown/inline.d.ts +29 -0
  251. package/dist/components/Markdown/inline.js +74 -0
  252. package/dist/components/Markdown/inline.js.map +1 -0
  253. package/dist/components/Markdown/nodes.d.ts +65 -0
  254. package/dist/components/Markdown/nodes.js +1 -0
  255. package/dist/components/Markdown/nodes.js.map +1 -0
  256. package/dist/components/Markdown/parse.d.ts +24 -0
  257. package/dist/components/Markdown/parse.js +110 -0
  258. package/dist/components/Markdown/parse.js.map +1 -0
  259. package/dist/components/Markdown/slug.d.ts +15 -0
  260. package/dist/components/Markdown/slug.js +7 -0
  261. package/dist/components/Markdown/slug.js.map +1 -0
  262. package/dist/components/NativeSelect/NativeSelect.d.ts +6 -0
  263. package/dist/components/NativeSelect/NativeSelect.js +2 -3
  264. package/dist/components/NativeSelect/NativeSelect.js.map +1 -1
  265. package/dist/components/NavItem/NavItem.js +1 -1
  266. package/dist/components/NavItem/NavItem.js.map +1 -1
  267. package/dist/components/NumberField/NumberField.d.ts +69 -0
  268. package/dist/components/NumberField/NumberField.js +162 -0
  269. package/dist/components/NumberField/NumberField.js.map +1 -0
  270. package/dist/components/Pagination/Pagination.d.ts +24 -1
  271. package/dist/components/Pagination/Pagination.js +6 -3
  272. package/dist/components/Pagination/Pagination.js.map +1 -1
  273. package/dist/components/Popover/Popover.js +1 -1
  274. package/dist/components/Popover/Popover.js.map +1 -1
  275. package/dist/components/Progress/Progress.d.ts +17 -5
  276. package/dist/components/Progress/Progress.js +18 -6
  277. package/dist/components/Progress/Progress.js.map +1 -1
  278. package/dist/components/RadioGroup/RadioGroup.d.ts +6 -0
  279. package/dist/components/RadioGroup/RadioGroup.js +11 -1
  280. package/dist/components/RadioGroup/RadioGroup.js.map +1 -1
  281. package/dist/components/ScrollArea/ScrollArea.d.ts +15 -0
  282. package/dist/components/ScrollArea/ScrollArea.js +2 -2
  283. package/dist/components/ScrollArea/ScrollArea.js.map +1 -1
  284. package/dist/components/SearchableMenu/SearchableMenu.d.ts +11 -2
  285. package/dist/components/SearchableMenu/SearchableMenu.js +24 -2
  286. package/dist/components/SearchableMenu/SearchableMenu.js.map +1 -1
  287. package/dist/components/Select/Select.d.ts +18 -2
  288. package/dist/components/Select/Select.js +21 -4
  289. package/dist/components/Select/Select.js.map +1 -1
  290. package/dist/components/Separator/Separator.d.ts +21 -3
  291. package/dist/components/Separator/Separator.js +9 -1
  292. package/dist/components/Separator/Separator.js.map +1 -1
  293. package/dist/components/Sheet/Sheet.d.ts +3 -0
  294. package/dist/components/Sheet/Sheet.js +12 -3
  295. package/dist/components/Sheet/Sheet.js.map +1 -1
  296. package/dist/components/Sidebar/Sidebar.d.ts +349 -0
  297. package/dist/components/Sidebar/Sidebar.js +455 -0
  298. package/dist/components/Sidebar/Sidebar.js.map +1 -0
  299. package/dist/components/Skeleton/Skeleton.d.ts +8 -1
  300. package/dist/components/Skeleton/Skeleton.js +1 -1
  301. package/dist/components/Skeleton/Skeleton.js.map +1 -1
  302. package/dist/components/Slider/Slider.d.ts +42 -3
  303. package/dist/components/Slider/Slider.js +121 -30
  304. package/dist/components/Slider/Slider.js.map +1 -1
  305. package/dist/components/Spinner/Spinner.d.ts +8 -0
  306. package/dist/components/Spinner/Spinner.js +3 -2
  307. package/dist/components/Spinner/Spinner.js.map +1 -1
  308. package/dist/components/StatusPill/StatusPill.d.ts +5 -0
  309. package/dist/components/StatusPill/StatusPill.js +6 -0
  310. package/dist/components/StatusPill/StatusPill.js.map +1 -1
  311. package/dist/components/Table/Table.d.ts +20 -0
  312. package/dist/components/Table/Table.js +3 -1
  313. package/dist/components/Table/Table.js.map +1 -1
  314. package/dist/components/Tabs/Tabs.js +7 -1
  315. package/dist/components/Tabs/Tabs.js.map +1 -1
  316. package/dist/components/Tag/Tag.d.ts +68 -9
  317. package/dist/components/Tag/Tag.js +50 -10
  318. package/dist/components/Tag/Tag.js.map +1 -1
  319. package/dist/components/Text/Text.d.ts +62 -0
  320. package/dist/components/Text/Text.js +30 -0
  321. package/dist/components/Text/Text.js.map +1 -0
  322. package/dist/components/Timestamp/Timestamp.d.ts +59 -0
  323. package/dist/components/Timestamp/Timestamp.js +56 -0
  324. package/dist/components/Timestamp/Timestamp.js.map +1 -0
  325. package/dist/components/Toast/Toast.d.ts +9 -1
  326. package/dist/components/Toast/Toast.js +27 -4
  327. package/dist/components/Toast/Toast.js.map +1 -1
  328. package/dist/components/ToggleGroup/ToggleGroup.d.ts +6 -1
  329. package/dist/components/ToggleGroup/ToggleGroup.js +11 -1
  330. package/dist/components/ToggleGroup/ToggleGroup.js.map +1 -1
  331. package/dist/components/Toolbar/Toolbar.d.ts +55 -0
  332. package/dist/components/Toolbar/Toolbar.js +43 -0
  333. package/dist/components/Toolbar/Toolbar.js.map +1 -0
  334. package/dist/diagrams/ArchitectureFigure/ArchitectureFigure.d.ts +6 -0
  335. package/dist/diagrams/ArchitectureFigure/ArchitectureFigure.js +48 -8
  336. package/dist/diagrams/ArchitectureFigure/ArchitectureFigure.js.map +1 -1
  337. package/dist/diagrams/DataflowFigure/DataflowFigure.js +21 -2
  338. package/dist/diagrams/DataflowFigure/DataflowFigure.js.map +1 -1
  339. package/dist/diagrams/DiagramCanvas/DiagramCanvas.d.ts +14 -0
  340. package/dist/diagrams/DiagramCanvas/DiagramCanvas.js +14 -7
  341. package/dist/diagrams/DiagramCanvas/DiagramCanvas.js.map +1 -1
  342. package/dist/diagrams/DiagramExportMenu/DiagramExportMenu.d.ts +38 -4
  343. package/dist/diagrams/DiagramExportMenu/DiagramExportMenu.js +14 -16
  344. package/dist/diagrams/DiagramExportMenu/DiagramExportMenu.js.map +1 -1
  345. package/dist/diagrams/DiagramInspector/DiagramInspector.js +2 -2
  346. package/dist/diagrams/DiagramInspector/DiagramInspector.js.map +1 -1
  347. package/dist/diagrams/DiagramMinimap/DiagramMinimap.d.ts +23 -7
  348. package/dist/diagrams/DiagramMinimap/DiagramMinimap.js +45 -18
  349. package/dist/diagrams/DiagramMinimap/DiagramMinimap.js.map +1 -1
  350. package/dist/diagrams/LifecycleFigure/LifecycleFigure.js +44 -12
  351. package/dist/diagrams/LifecycleFigure/LifecycleFigure.js.map +1 -1
  352. package/dist/diagrams/SequenceFigure/SequenceFigure.js +35 -5
  353. package/dist/diagrams/SequenceFigure/SequenceFigure.js.map +1 -1
  354. package/dist/diagrams/WorkflowFigure/WorkflowFigure.d.ts +3 -1
  355. package/dist/diagrams/WorkflowFigure/WorkflowFigure.js +76 -28
  356. package/dist/diagrams/WorkflowFigure/WorkflowFigure.js.map +1 -1
  357. package/dist/diagrams/index.d.ts +1 -0
  358. package/dist/diagrams/index.js +10 -0
  359. package/dist/diagrams/index.js.map +1 -1
  360. package/dist/diagrams/lib/dev.d.ts +61 -0
  361. package/dist/diagrams/lib/dev.js +96 -0
  362. package/dist/diagrams/lib/dev.js.map +1 -0
  363. package/dist/diagrams/lib/frame.d.ts +48 -7
  364. package/dist/diagrams/lib/frame.js +17 -2
  365. package/dist/diagrams/lib/frame.js.map +1 -1
  366. package/dist/diagrams/lib/route.d.ts +22 -1
  367. package/dist/diagrams/lib/route.js +24 -1
  368. package/dist/diagrams/lib/route.js.map +1 -1
  369. package/dist/diagrams/lib/wires.js +9 -5
  370. package/dist/diagrams/lib/wires.js.map +1 -1
  371. package/dist/diagrams/spec.d.ts +64 -12
  372. package/dist/index.d.ts +19 -4
  373. package/dist/index.js +12 -0
  374. package/dist/index.js.map +1 -1
  375. package/dist/keyframes.css +57 -3
  376. package/dist/lib/color.d.ts +80 -0
  377. package/dist/lib/color.js +189 -0
  378. package/dist/lib/color.js.map +1 -0
  379. package/dist/lib/numeric.d.ts +35 -0
  380. package/dist/lib/numeric.js +29 -0
  381. package/dist/lib/numeric.js.map +1 -0
  382. package/dist/lib/overlay-container.d.ts +14 -4
  383. package/dist/lib/overlay-container.js.map +1 -1
  384. package/dist/lib/warn.d.ts +73 -0
  385. package/dist/lib/warn.js +38 -0
  386. package/dist/lib/warn.js.map +1 -0
  387. package/dist/semantic.css +17 -6
  388. package/dist/styles.css +1 -1
  389. package/dist/themes.css +8 -0
  390. package/dist/tokens.css +86 -5
  391. package/dist/tokens.d.ts +4 -1
  392. package/dist/tokens.js +56 -36
  393. package/dist/tokens.json +56 -36
  394. package/llms.txt +35 -0
  395. package/package.json +5 -2
  396. package/skills/misoto22-design/evals/evals.json +84 -0
  397. package/skills/misoto22-design/rules/a11y.md +55 -3
  398. package/skills/misoto22-design/rules/forms.md +8 -1
@@ -4,7 +4,7 @@ A date — or a span of them — chosen from a calendar.
4
4
 
5
5
  - Group: Forms
6
6
  - Import: `import { DatePicker } from '@misoto22/design'`
7
- - Version: 0.7.0
7
+ - Version: 0.9.0
8
8
  - Docs: https://ui.misoto22.com/components/date-picker/
9
9
  - Related: calendar, field
10
10
 
@@ -12,9 +12,31 @@ A date — or a span of them — chosen from a calendar.
12
12
 
13
13
  Deliberately not a text input with a calendar attached: parsing a typed date needs a format, and 03/04 is March the fourth in one country and the third of April in the next. When the date is a long way back, the calendar’s month and year are dropdowns.
14
14
 
15
+ ## Anatomy
16
+
17
+ - **Trigger** (required) — A <button> printing format(value) or the placeholder, with a calendar glyph pinned at the end. It is named by the label and the printed date together, so the format is heard as well as seen.
18
+ - **Panel** — A Popover holding the rail and the grid — side by side from sm up, stacked below it, where two months would not fit anyway.
19
+ - **Preset rail** — A role="group" of plain buttons, present only when presets is set: on by default for DateRangePicker, off by default for DatePicker. A shortcut that lands on a disabledDates day is drawn unavailable and refuses the click.
20
+ - **Calendar grid** — The shared Calendar, autoFocus on open so the keyboard lands in the month rather than back at the trigger. Two months at once on the range picker, from months.
21
+ - **Half-range text** — The range trigger prints “from – …” while only one end is chosen, so a half-answered range says so on the closed control instead of looking finished.
22
+
23
+ ## Best practices
24
+
25
+ ### Do
26
+
27
+ - Put the restriction in disabledDates rather than in your own handler. The rail asks it too, so a shortcut on a blocked day is disabled instead of committing a date the grid beside it refuses — a range preset is tested at its ENDS, so one straddling a blocked day is still offered, exactly as the grid still allows it.
28
+ - Pick controlled or uncontrolled and stay there. The current value is value ?? uncontrolled, so a controlled picker that clears by setting value to undefined falls through to whatever defaultValue seeded and the old date reappears.
29
+ - Validate a range before you use it: half a range is a legal state here — from set, to undefined — so a submit handler that reads value.to without checking gets undefined from a reader who simply closed the panel early.
30
+
31
+ ### Don’t
32
+
33
+ - A Field’s required does not reach the trigger. It is a plain <button>, a role with nowhere to put aria-required, so the asterisk above is the whole of the marking and a screen reader meets an ordinary optional field.
34
+ - Do not reach for it for a birth date. There is no defaultMonth to pass: the panel always opens on the current month, so a date decades back begins with every reader in the month-and-year picker.
35
+ - Do not disable it to show a fixed date. disabled takes the trigger out of the tab order and blocks its pointer events, and the trigger is the only place the chosen date is printed at all.
36
+
15
37
  ## Accessibility
16
38
 
17
- - The trigger prints the date in the visitor’s own locale, not a fixed dd/mm/yyyy.
39
+ - The trigger prints the date in the visitor’s own locale, not a fixed dd/mm/yyyy, and announces it as part of its own name — so format reaches a screen reader too.
18
40
  - DateRangePicker keeps the panel open until both ends are chosen — a range is not a value until it has a second date.
19
41
  - The shortcut rail is plain buttons, not a menu: they set the same value the grid beside them sets, so they belong to one control and Tab in the same pass.
20
42
  - Presets are computed on click, so “today” means today even on a tab left open overnight.
@@ -41,13 +63,16 @@ A date, chosen from a calendar. A trigger and a `Calendar` in a `Popover` — no
41
63
  - `value` — `Date`.
42
64
  - `defaultValue` — `Date`.
43
65
  - `onValueChange` — `(value: Date | undefined) => void`.
44
- - `label` (required) — `string`. Names the control. Required — the trigger's text is a value, not a label.
66
+ - `label` (required) — `string`. Names the control. Required — the trigger's text is a value, not a label. Announced together with the printed date rather than instead of it, so `format` reaches a screen reader as well as the screen. Inside a `Field` with a label, that label names the trigger and this one is not repeated.
45
67
  - `placeholder` — `string` default `'Pick a date'`.
46
68
  - `disabled` — `boolean` default `false`.
47
- - `disabledDates` — `ComponentProps<typeof Calendar>['disabled']`. Days the reader may not choose. Passed straight to the calendar.
69
+ - `disabledDates` — `ComponentProps<typeof Calendar>['disabled']`. Days the reader may not choose. Reaches the calendar AND the shortcut rail: a preset landing on a blocked day is drawn unavailable and refuses the click, rather than committing a value the grid beside it would not accept.
48
70
  - `format` — `(date: Date) => string` default `formatDate`. How the chosen date is printed on the trigger.
49
71
  - `presets` — `boolean | DatePreset<Date>[]`. Shortcuts shown beside the grid. Pass `true` for the built-in set, an array for your own, or leave it off for none.
50
72
  - `className` — `string`.
73
+ - `id` — `string`. The TRIGGER's id — the element a label points at. A `Field` sets it.
74
+ - `aria-describedby` — `string`. Ids of the copy describing the control. A `Field` sets it from hint, error and description.
75
+ - `aria-invalid` — `boolean | 'true' | 'false'`. Announced on the trigger. A `Field` sets it from `error`.
51
76
 
52
77
  ## DateRangePicker
53
78
 
@@ -58,14 +83,17 @@ A span of dates — a stay, a reporting period, a filter. Two months side by sid
58
83
  - `value` — `DateRange`.
59
84
  - `defaultValue` — `DateRange`.
60
85
  - `onValueChange` — `(value: DateRange | undefined) => void`.
61
- - `label` (required) — `string`.
86
+ - `label` (required) — `string`. Names the control. Announced together with the printed range, not instead of it.
62
87
  - `placeholder` — `string` default `'Pick a range'`.
63
88
  - `disabled` — `boolean` default `false`.
64
- - `disabledDates` — `ComponentProps<typeof Calendar>['disabled']`.
89
+ - `disabledDates` — `ComponentProps<typeof Calendar>['disabled']`. Days the reader may not choose. Reaches the shortcut rail as well as the grid, at the ENDS of each preset range — a shortcut whose interior straddles a blocked day is still offered, the way the grid still lets a reader drag a range across one.
65
90
  - `months` — `number` default `2`. How many months are shown side by side. Falls back to one under `sm`.
66
91
  - `format` — `(date: Date) => string` default `formatDate`.
67
92
  - `presets` — `boolean | DatePreset<DateRange>[]` default `true`. Shortcuts shown beside the grid — Last 30 days and its neighbours. `true` for the built-in set, an array for your own. On by default here and off on the single picker, because "last 30 days" is most of what a range picker is ever asked for, while a single date is usually a specific one.
68
93
  - `className` — `string`.
94
+ - `id` — `string`. The TRIGGER's id — the element a label points at. A `Field` sets it.
95
+ - `aria-describedby` — `string`. Ids of the copy describing the control. A `Field` sets it from hint, error and description.
96
+ - `aria-invalid` — `boolean | 'true' | 'false'`. Announced on the trigger. A `Field` sets it from `error`.
69
97
 
70
98
  ## Examples
71
99
 
@@ -0,0 +1,68 @@
1
+ # DescriptionList
2
+
3
+ One record’s fields, as a real <dl> rather than a grid of divs.
4
+
5
+ - Group: Surfaces
6
+ - Import: `import { DescriptionList } from '@misoto22/design'`
7
+ - Version: 0.9.0
8
+ - Docs: https://ui.misoto22.com/components/description-list/
9
+ - Related: table, card, timestamp
10
+
11
+ ## When to reach for it
12
+
13
+ One record seen from the front — a detail page, a summary panel. Several records seen from above is a Table.
14
+
15
+ ## Anatomy
16
+
17
+ - **List** (required) — The <dl>. It is the element that carries the pairing: a grid of divs looks identical and tells a screen reader there are two columns of unrelated text.
18
+ - **Pair** (required) — A <div> around each dt/dd, which the HTML specification allows inside a <dl> precisely so a pair can be laid out as a unit. It is what the hairline is drawn on, so the rule crosses the whole row rather than stopping in the column gap.
19
+ - **Term** (required) — item.term, rendered as <dt> at --ink-3-aa. In the row layout it holds a 12rem column at sm and above and stacks below it, because a 12rem label column on a phone leaves the value about eight characters wide.
20
+ - **Description** (required) — item.description, rendered as <dd> at --ink-2 with its browser margin reset. It takes a node, not a string, so a value can be a Badge, a link or a Timestamp.
21
+ - **Hairline** — divided, on by default: a --rule under every pair but the last. Turn it off inside a Card, which already has an edge of its own.
22
+
23
+ ## Best practices
24
+
25
+ ### Do
26
+
27
+ - Let it render nothing when items is empty. It returns null rather than an empty bordered box, so the page above is free to show an EmptyState instead of a hairline around no content.
28
+ - Put an element in description when the value is a state or a link — it is a <dd>, so a Badge, an anchor or a Timestamp belongs there and a string of text does not have to be faked into one.
29
+ - Pass id on each item when rows are added, removed or reordered. The index is the key without one, which is right for the fixed field list a record page renders and wrong for a list that changes shape.
30
+
31
+ ### Don’t
32
+
33
+ - Do not reach for it to show several records. Every dt would repeat down the page and a reader comparing two records has to hold both in their head — that is what a Table’s column headings exist to avoid.
34
+ - Do not use layout="row" inside a narrow sidebar. It only collapses on the sm breakpoint, which is the viewport, not the container — a 12rem label column inside a 20rem panel leaves nothing for the value. Use layout="stacked" there.
35
+
36
+ ## Accessibility
37
+
38
+ - A real <dl>, <dt> and <dd>, which is what tells a screen reader that a label names the value beside it.
39
+ - Each pair is grouped in a <div>, which the specification permits inside a <dl> and which assistive technology reads through.
40
+ - An empty list renders null rather than an empty <dl>, so nothing announces a list with no items in it.
41
+
42
+ ## DescriptionList
43
+
44
+ A record's fields: label, value, label, value. The single most repeated shape in any detail page, and the one most often hand-built out of a `<div>` grid — which loses the only thing the markup was carrying. A `<dl>` tells a screen reader that "Owner" names the thing beside it; a grid of divs tells it there are two columns of unrelated text, and the reader has to infer the pairing from reading order alone. Reach for `Table` instead when there are several records. This is one record seen from the front; a table is many records seen from above. Each pair is wrapped in a `<div>` — which the HTML specification allows inside a `<dl>` precisely so a pair can be laid out as a unit — so the hairline runs the full width of the row rather than stopping in the column gap. An empty `items` renders `null` rather than an empty bordered box. A record with no fields is a state the page above should be handling with an `EmptyState`, and a hairline around nothing looks like a component that failed to load.
45
+
46
+ ### Props
47
+
48
+ - `items` (required) — `DescriptionListItem[]`. The pairs, in the order they should read. An empty array renders nothing.
49
+ - `layout` — `DescriptionListLayout` default `'row'`. How the value sits relative to its label. See DescriptionListLayout.
50
+ - `divided` — `boolean` default `true`. Draws a hairline under every pair but the last. Off for a list inside a card that already has an edge, on for a list that is the page's structure.
51
+
52
+ Also accepts: `HTMLAttributes<HTMLDListElement>`.
53
+
54
+ ## Types
55
+
56
+ - `DescriptionListLayout` = `'row' | 'stacked'`
57
+
58
+ ## Examples
59
+
60
+ ```tsx
61
+ <DescriptionList
62
+ items={[
63
+ { term: 'Owner', description: 'Henry Chen' },
64
+ { term: 'Status', description: <Badge tone="success">Deployed</Badge> },
65
+ ]}
66
+ />
67
+ <DescriptionList layout="stacked" divided={false} items={fields} />
68
+ ```
@@ -4,7 +4,7 @@ A flow or architecture figure, drawn out of the system’s own parts.
4
4
 
5
5
  - Group: Display
6
6
  - Import: `import { Diagram } from '@misoto22/design'`
7
- - Version: 0.7.0
7
+ - Version: 0.9.0
8
8
  - Docs: https://ui.misoto22.com/components/diagram/
9
9
  - Related: card, figure-band
10
10
 
@@ -12,11 +12,35 @@ A flow or architecture figure, drawn out of the system’s own parts.
12
12
 
13
13
  A picture of structure, in a page rather than in a terminal. Nesting is containment and an edge is a step between siblings — a diagram that needs arbitrary wiring wants a drawing, not this.
14
14
 
15
+ ## Anatomy
16
+
17
+ - **Frame** (required) — The <figure role="group"> and the panel inside it: a --rule hairline on the --radius-lg corner over --paper-2, with fluid padding and overflow-x-auto on a hairline scrollbar — so a wide figure scrolls inside its own box instead of widening the page.
18
+ - **Leaf plate** — A node with NO children: a bordered card on --paper, or filled with --accent when accent is set. Its label breaks inside itself, because an identifier like TenantMainMiddleware has no break opportunity and would otherwise run into the plate’s edge.
19
+ - **Container band** — A node WITH children: a labelled hairline — ink at the top rank, --rule-2 below it — with its children underneath and no frame of its own. That is the whole design: drawing a container as another box puts three borders around anything two levels deep.
20
+ - **Node note** — node.note, a mono line beside a band’s label or under a plate’s. One short line, a step back from the name.
21
+ - **Edge mark** — The arrow between two adjacent siblings an edge names, with the edge’s label under it. aria-hidden, and rotated a quarter turn below the sm breakpoint, where a row of nodes stacks into a column and the arrow has to point the way the layout actually runs.
22
+ - **Caption** — spec.caption, printed under the frame — as a <div>, not a <figcaption>, because an article stylesheet styles figcaption unlayered and an unlayered rule beats a utility whatever the specificity.
23
+
24
+ ## Best practices
25
+
26
+ ### Do
27
+
28
+ - Write an edge from a node to the node immediately after it in the same rank, in that order. An edge between non-adjacent nodes, or one written to→from, draws no arrow — and now says so in the console rather than leaving the author to spot a missing arrow in a picture that otherwise looks finished.
29
+ - Keep ids unique across the whole spec. Each edge is now spent at the first pair that matches it, so a reused pair no longer draws the arrow twice — but the arrow lands on whichever pair comes first, which is a diagram asserting something nobody wrote.
30
+ - Give the spec a caption or a label. The figure’s role="group" is named by whichever is present, and with neither the reader is told there is a group and never told what of.
31
+
32
+ ### Don’t
33
+
34
+ - accent is read only in the plate branch, so setting it on a node with children compiles, type-checks and paints nothing — a container is a band, and a band has no fill to take. Development says so; a production build does not.
35
+ - direction is read only from a node that HAS children. Set on a leaf it is ignored, because the axis a leaf sits on belongs to its parent — and, like accent on a band, it is reported in development rather than silently dropped.
36
+ - Do not put six nodes across the top rank. A row is flex-col below sm and only flex-row above it, so a figure that reads as a pipeline on a desktop is six stacked plates and five arrows on a phone.
37
+
15
38
  ## Accessibility
16
39
 
17
40
  - A <figure> with role="group", named by its caption, so the whole picture is one thing a reader can skip.
18
41
  - Arrows are aria-hidden: assistive tech reads the nodes in document order and has no use for a glyph pointing at the next one.
19
42
  - Server-rendered markup, not a canvas — every label is real text a screen reader and a search engine can read.
43
+ - A spec the renderer cannot honour — an unmatched edge, a duplicate id, accent on a band, direction on a leaf — prints a named warning in development, because the alternative is a confident picture of something else.
20
44
 
21
45
  ## Diagram
22
46
 
@@ -36,8 +60,8 @@ A flow or architecture diagram, drawn out of the system's own parts. The alterna
36
60
  edges: [{ from: 'edge', to: 'app', label: 'HTTPS' }],
37
61
  nodes: [
38
62
  { id: 'edge', label: 'Edge', note: 'CDN' },
39
- { id: 'app', label: 'Application', accent: true, children: [
40
- { label: 'Router' },
63
+ { id: 'app', label: 'Application', children: [
64
+ { label: 'Router', accent: true },
41
65
  { label: 'Handlers' },
42
66
  ] },
43
67
  ],
@@ -4,7 +4,7 @@ A frame that a picture larger than it can be panned and zoomed inside.
4
4
 
5
5
  - Group: Diagrams
6
6
  - Import: `import { DiagramCanvas } from '@misoto22/design/diagrams'`
7
- - Version: 0.7.0
7
+ - Version: 0.9.0
8
8
  - Docs: https://ui.misoto22.com/components/diagram-canvas/
9
9
  - Related: diagram-minimap, architecture-figure, scroll-area
10
10
 
@@ -12,6 +12,29 @@ A frame that a picture larger than it can be panned and zoomed inside.
12
12
 
13
13
  Any oversized figure — an SVG, an image, a table that will not fold. It knows nothing about nodes, which is what makes it reusable.
14
14
 
15
+ ## Anatomy
16
+
17
+ - **Frame** (required) — The outer box: a fixed height — 24rem unless height says otherwise — a hairline, the diagram ground, and overflow hidden. It is the window the artwork is bigger than.
18
+ - **Viewport** (required) — The focusable layer inside it: role="group" with a name, tabIndex 0, the drag handlers, the key handler and a focus ring drawn inside the frame. This is the tab stop, and it is what makes the keys pressable at all.
19
+ - **Stage** (required) — The wrapper the translate and scale are applied to. The transform is on the wrapper and never on the child, so the figure inside keeps its own coordinate space and every measurement taken inside it stays true.
20
+ - **Zoom controls** — The cluster pinned to the bottom corner: zoom out, the current percentage — which is also the reset button, named for what it does — and zoom in. controls={false} removes the cluster and leaves the keys.
21
+ - **Keyboard hint** (required) — A visually hidden paragraph, referenced by aria-describedby, saying that the frame drags and which keys pan, zoom and reset. Nothing on screen carries that sentence.
22
+
23
+ ## Best practices
24
+
25
+ ### Do
26
+
27
+ - Name it. label is the group’s accessible name and it defaults to "Diagram canvas", so two canvases on one page announce the same thing until each is given its own.
28
+ - Strip the figure inside to its artwork with heading={false}, legend="hidden" and cards={false}. Everything in the frame pans and zooms together, so a title left on travels away from the diagram it names and a key leaves the frame at exactly the zoom that made a reader want it.
29
+ - Move the view through the ref — zoomIn, zoomOut, reset, centerOn — rather than re-rendering the child at a new size. centerOn takes a point in the content’s own coordinates, which is what a minimap reports back.
30
+ - Hand onViewChange straight to a minimap. Each view carries the frame it was measured against as well as the scale and the offset, and that pair is the whole of the arithmetic a viewport rectangle is — the frame being the one number nothing outside the canvas can measure.
31
+
32
+ ### Don’t
33
+
34
+ - Nothing clamps the pan. The offset is whatever the drag or the arrow keys left it at, so the artwork can be pushed entirely outside the frame; 0 and the reset button are the whole way back, and controls={false} without a replacement takes the pointer’s half of that away.
35
+ - The scale stops at 0.35. A figure more than about three times the frame cannot be zoomed out far enough to be seen whole, so the frame has to be sized for the diagram — a minimap answers where you are, never what is there.
36
+ - The wheel is left alone and the thumb is not: the frame sets touch-action to none, so a finger dragged inside it pans the diagram and never scrolls the page. A full-width canvas in an article is a band a touch reader has to swipe around rather than through, which is the argument for giving it a height short enough to leave page beside it.
37
+
15
38
  ## Accessibility
16
39
 
17
40
  - The frame is a real tab stop, so the keyboard controls can be pressed at all.
@@ -4,7 +4,7 @@ Taking the figure off the page: PNG, JPEG, WebP, SVG and a 1200×630 share card.
4
4
 
5
5
  - Group: Diagrams
6
6
  - Import: `import { DiagramExportMenu } from '@misoto22/design/diagrams'`
7
- - Version: 0.7.0
7
+ - Version: 0.9.0
8
8
  - Docs: https://ui.misoto22.com/components/diagram-export-menu/
9
9
  - Related: dropdown-menu, diagram-toolbar
10
10
 
@@ -12,13 +12,38 @@ Taking the figure off the page: PNG, JPEG, WebP, SVG and a 1200×630 share card.
12
12
 
13
13
  It does the export rather than emitting a format name, because the interesting half — baking custom properties into real colours before serialising — is the half a caller would not know to write.
14
14
 
15
+ ## Anatomy
16
+
17
+ - **Trigger** (required) — A small secondary button reading Export, or whatever trigger replaces it — the replacement is slotted, so it becomes the menu’s own control rather than sitting next to one.
18
+ - **Menu** (required) — A dropdown aligned to the trigger’s end, in three labelled groups separated by rules: Image, Vector, Share. The grouping is the answer to "which of these five do I want".
19
+ - **Format row** (required) — One menu row per format, with its name and a mono hint under it — "Lossless, 2× for retina", "Compact, flattened onto paper". Real menu rows, so the arrow keys walk them, typing jumps to one, and picking one closes the menu over the file it just wrote. The running one gains an ellipsis and every row is disabled until it finishes, so a second click cannot start a second export.
20
+ - **Serialiser** (required) — The part with nothing to point at: the artwork is cloned, every node’s computed paint is written inline, and the clone is placed on a plate the size of the picture plus its padding. It is what stops var(--ink) arriving in a document with no stylesheet and painting nothing.
21
+ - **Share card** — A fixed 1200 × 630 frame with the title printed on it and the whole diagram letterboxed inside — never cropped to fill, because a card cropped to fill is a picture of a different diagram.
22
+ - **Result** — onResult, called with the format, an ok or the Error, and the source that produced it. It is the only place a failed export is reported.
23
+
24
+ ## Best practices
25
+
26
+ ### Do
27
+
28
+ - Point targetRef at the wrapper rather than at an svg you found yourself. The export looks for the artwork marker first, which is what stops a page whose toolbar sits inside the same wrapper from exporting a picture of a chevron.
29
+ - Export after the artwork has been measured. The serialiser reads the element’s box and throws when it is still zero, so a call made in the same tick as the mount fails loudly instead of writing an empty file.
30
+ - Take onResult and put a failure in front of the reader. An unmeasured figure, a canvas tainted by a cross-origin image, a browser that returned no 2D context — each is reported there rather than thrown at the click, and the alternative is a menu item that quietly does nothing.
31
+ - Read source alongside ok. built-in says a file reached the browser; caller says your own onExport resolved, which is exactly what a handler that did nothing also does — the menu cannot see inside your pipeline and no longer reports as though it can.
32
+ - Pass background={null} for a figure going onto a coloured page. Every other export paints the reader’s own surface behind the artwork, and JPEG is flattened onto that surface whatever this says, because a transparent JPEG is a black one.
33
+
34
+ ### Don’t
35
+
36
+ - The file is the artwork and the theme the reader was in. Paint is read off the live element, so a figure exported from a dark page is a dark image in a light document; and the toolbar, the inspector and the figure’s own hidden summary list are HTML, so none of them travels with it.
37
+ - Do not treat the SVG as a pixel-exact record. The isolated document cannot fetch the page’s web fonts, so the type falls back to what the machine has — the words and the line breaks are already fixed, but a name that just fitted its plate on screen can overrun its own rule in the file.
38
+ - The output is sized from the artwork’s box ON SCREEN rather than from its viewBox, so a figure sitting at 4× inside a DiagramCanvas serialises four times larger and then rasterises at 2× on top of that. Reset the view before exporting, or a reader gets a file whose dimensions record where the zoom happened to be.
39
+
15
40
  ## Accessibility
16
41
 
17
42
  - A failed export is reported through onResult rather than swallowed: a click that quietly does nothing is indistinguishable from a broken button.
18
43
 
19
44
  ## DiagramExportMenu
20
45
 
21
- Taking the figure off the page: five files, one menu. WHY THE MENU DOES THE WORK rather than handing back a format: every one of these exports is the same six steps — find the `<svg>`, walk it with `getComputedStyle` to bake the custom properties into real colours, serialise, rasterise, name the file, hand it to the browser — and only the last two differ between them. A menu that emitted `'png'` and left the caller to do the rest would be a menu that every consumer reimplements, badly, and the interesting half (a serialised SVG resolves `var(--ink)` to nothing and comes out invisible) is exactly the half a caller would not know to write. `onExport` is still there for a page with its own pipeline — a server-side renderer, a different frame size — and taking it turns everything below into a no-op. What each format actually is, stated rather than implied. **SVG** is the artwork with resolved colours. It is editable and it is the only lossless one, but it carries no web fonts: a machine without the family renders it in a fallback, so type metrics will differ. **PNG, JPEG and WebP** are the browser's own rasteriser re-drawing that SVG at 2×. Not a screenshot — antialiasing and any effect a page stylesheet applied from OUTSIDE the `<svg>` are not in it. **JPEG has no alpha**, so it is flattened onto the resolved paper colour rather than onto black, which is what a transparent PNG becomes when a format with no transparency is asked to hold it. **The share card** is a 1200 × 630 frame with the title on it and the whole diagram letterboxed inside — never cropped. A card that cropped to fill the frame would be a picture of a different diagram.
46
+ Taking the figure off the page: five files, one menu. WHY THE MENU DOES THE WORK rather than handing back a format: every one of these exports is the same six steps — find the `<svg>`, walk it with `getComputedStyle` to bake the custom properties into real colours, serialise, rasterise, name the file, hand it to the browser — and only the last two differ between them. A menu that emitted `'png'` and left the caller to do the rest would be a menu that every consumer reimplements, badly, and the interesting half (a serialised SVG resolves `var(--ink)` to nothing and comes out invisible) is exactly the half a caller would not know to write. `onExport` is still there for a page with its own pipeline — a server-side renderer, a different frame size — and taking it turns everything below into a no-op, which is why a result from that path says `source: 'caller'`: this component cannot see whether the handler produced a file, so it does not report that it did. What each format actually is, stated rather than implied. **SVG** is the artwork with resolved colours. It is editable and it is the only lossless one, but it carries no web fonts: a machine without the family renders it in a fallback, so type metrics will differ. **The ground** is the reader's own surface unless `background` says otherwise. `background={null}` exports on transparency — for a figure being dropped onto a coloured page — except in JPEG, which has no alpha and is flattened onto paper whatever is asked for. **PNG, JPEG and WebP** are the browser's own rasteriser re-drawing that SVG at 2×. Not a screenshot — antialiasing and any effect a page stylesheet applied from OUTSIDE the `<svg>` are not in it. **JPEG has no alpha**, so it is flattened onto the resolved paper colour rather than onto black, which is what a transparent PNG becomes when a format with no transparency is asked to hold it. **The share card** is a 1200 × 630 frame with the title on it and the whole diagram letterboxed inside — never cropped. A card that cropped to fill the frame would be a picture of a different diagram.
22
47
 
23
48
  ### Props
24
49
 
@@ -26,8 +51,9 @@ Taking the figure off the page: five files, one menu. WHY THE MENU DOES THE WORK
26
51
  - `title` (required) — `string`. Names the file, and is printed on the share card.
27
52
  - `trigger` — `ReactNode`. Replaces the trigger.
28
53
  - `className` — `string`.
29
- - `onExport` — `(format: ExportFormat) => void | Promise<void>`. Runs instead of the built-in export — for a caller with its own pipeline.
54
+ - `onExport` — `(format: ExportFormat) => void | Promise<void>`. Runs instead of the built-in export — for a caller with its own pipeline. Taking it turns everything below into a no-op, INCLUDING the part that knows whether a file was produced: a result from this path reports `source: 'caller'` and an `ok` that means only "your handler resolved".
30
55
  - `onResult` — `(result: ExportResult) => void`. Told what happened, so a page can raise a toast.
56
+ - `background` — `string | null`. Painted behind the artwork. Defaults to the surface the reader is looking at; `null` exports on a transparent ground. JPEG has no alpha channel, so it is flattened onto the reader's own paper whatever this says — a transparent JPEG is a black one.
31
57
 
32
58
  ## exportFigure
33
59
 
@@ -4,7 +4,7 @@ What the reader just picked, written out beside the picture.
4
4
 
5
5
  - Group: Diagrams
6
6
  - Import: `import { DiagramInspector } from '@misoto22/design/diagrams'`
7
- - Version: 0.7.0
7
+ - Version: 0.9.0
8
8
  - Docs: https://ui.misoto22.com/components/diagram-inspector/
9
9
  - Related: card, diagram-canvas
10
10
 
@@ -12,6 +12,28 @@ What the reader just picked, written out beside the picture.
12
12
 
13
13
  A node holds about eight words before it stops being a node. Everything past those — the port, the owner, the six relationships — belongs here.
14
14
 
15
+ ## Anatomy
16
+
17
+ - **Region** (required) — A <section> named "<title> details" with aria-live="polite", on a panel plate. A region and not a dialog: nothing traps focus and nothing demands dismissal, because the reader clicked a node rather than opening a window.
18
+ - **Heading** (required) — The eyebrow over the title — what KIND of thing this is, then what it is called. The eyebrow is where the plate’s own kicker word belongs, so the panel and the picture say the same thing about the same node.
19
+ - **Facts** — A definition list, one term and value per row, the value settable in mono for an id, a path, a port. A list rather than a grid of divs, because a grid tells a screen reader nothing about which value belongs to which label.
20
+ - **Relationships** — One row per edge the node takes part in, each becoming a real button when it carries onSelect. The arrow glyph is hidden and the direction spelled out beside it, so "to" and "from" are heard rather than guessed.
21
+ - **Close** — A small control named for what it does — clearing the selection, not closing a window. It is the only thing that can empty the panel.
22
+ - **Actions** — A wrap of caller-supplied buttons under the facts: copy the id, open the source the node was read out of.
23
+
24
+ ## Best practices
25
+
26
+ ### Do
27
+
28
+ - Pair it with the figure’s onSelectNode. That is what turns the hidden summary list into real buttons, and without it the panel can only ever be filled by a pointer — the plates in the picture are presentational by construction.
29
+ - Give every relationship an onSelect. The rows become buttons and the graph becomes walkable peer by peer, which is how a keyboard reader gets from a node to the node it is connected to without going back through the list.
30
+ - Move the long facts here and leave about eight words on the plate. A box holding a port, an owning team and a file path grows to fit all three rather than clipping them, and a figure of boxes that size is a document with lines drawn on it.
31
+
32
+ ### Don’t
33
+
34
+ - Two facts sharing a label are two rows, and neither says which is which. They are keyed by position, so both render — and a panel with "Source" twice leaves the reader deducing from the values what the labels should have said. Name them apart when they mean different things.
35
+ - floating pins the panel over the surface, so it covers that corner of the diagram for as long as it is mounted. It has no dismissal contract of its own — passing no onClose leaves the reader nothing to press and the corner hidden until the selection changes.
36
+
15
37
  ## Accessibility
16
38
 
17
39
  - A labelled region with aria-live="polite", not a dialog: the reader clicked a node, they did not open anything, so focus is never trapped or demanded.
@@ -4,7 +4,7 @@ The key: which drawn form means which kind of thing.
4
4
 
5
5
  - Group: Diagrams
6
6
  - Import: `import { DiagramLegend } from '@misoto22/design/diagrams'`
7
- - Version: 0.7.0
7
+ - Version: 0.9.0
8
8
  - Docs: https://ui.misoto22.com/components/diagram-legend/
9
9
  - Related: architecture-figure, lifecycle-figure
10
10
 
@@ -12,6 +12,27 @@ The key: which drawn form means which kind of thing.
12
12
 
13
13
  Not optional furniture in a monochrome system. When a queue and a cache differ by a sigil rather than a colour, this is the only place a reader is told what the sigil means.
14
14
 
15
+ ## Anatomy
16
+
17
+ - **Row** (required) — A wrapping, baseline-aligned row over a top rule. Inside a figure it sits between the picture and the conclusion cards, which is where a reader looks after failing to recognise a mark.
18
+ - **Kicker** — The word Key before the row. title={null} drops it for a bare row, and the list keeps that word as its own accessible name either way.
19
+ - **List** (required) — A <ul> of pairs rather than a row of spans, so the count is part of what a screen reader says about it — "list, six items" is the first useful fact about a key.
20
+ - **Sample** (required) — A 14 × 14 svg carrying the entry’s own markup, hidden from assistive technology. Markup rather than a name from a fixed list, because a key has to show the SAME mark the figure drew.
21
+ - **Label** (required) — The word beside the mark, in the meta voice. The standard builders take it from the same table the plate’s eyebrow prints, so a plate reading SERVICE is never explained by a key reading Datastore.
22
+
23
+ ## Best practices
24
+
25
+ ### Do
26
+
27
+ - Build the entries with kindLegend, variantLegend or stateLegend. They are made out of the renderers’ own drawing code, so the key cannot come to show a mark the figure does not draw or a word the plate does not print.
28
+ - Leave a figure’s legend at "auto". It lists only the kinds actually drawn; "all" prints seven kinds beside a figure using three, which is four claims the picture does not support.
29
+ - Pass title={null} when the key sits under a caption that already says what it is. The list keeps Key as its accessible name, so the kicker can go without the row losing its name.
30
+
31
+ ### Don’t
32
+
33
+ - A key is not where a distinction is MADE. The two state tokens are the only hues these figures spend and each terminal is also its own plate shape — a difference carried by colour alone is one a reader can only look up, an entry at a time, after noticing there is a key at all.
34
+ - legend="hidden" is not free on a figure of tagged plates. A plate prints its tag OR the kind word in the same eyebrow slot and the tag wins, so on a tagged plate the kind is carried by the sigil alone — hiding the key takes the only thing that teaches that sigil off the page.
35
+
15
36
  ## Accessibility
16
37
 
17
38
  - A list of pairs rather than a row of spans, so the count is part of what a screen reader says about it.
@@ -4,7 +4,7 @@ Where you are in something bigger than the window.
4
4
 
5
5
  - Group: Diagrams
6
6
  - Import: `import { DiagramMinimap } from '@misoto22/design/diagrams'`
7
- - Version: 0.7.0
7
+ - Version: 0.9.0
8
8
  - Docs: https://ui.misoto22.com/components/diagram-minimap/
9
9
  - Related: diagram-canvas
10
10
 
@@ -12,18 +12,39 @@ Where you are in something bigger than the window.
12
12
 
13
13
  Pairs with DiagramCanvas. The viewport rectangle is derived from the canvas’s own view, never stored — a map that disagrees with its territory is worse than none.
14
14
 
15
+ ## Anatomy
16
+
17
+ - **Map frame** (required) — A fixed-width plate — 200px unless width says otherwise — whose height follows the artwork’s own aspect ratio, named as a group so it is not an unlabelled box beside the figure.
18
+ - **Miniature** (required) — The children under a CSS scale of width over content.width, anchored top-left, hidden from assistive technology and transparent to the pointer. Drawn only once content has a size — at width 0 the scale would be 1 and the miniature would be the artwork’s top-left corner at full size. It answers "what is there" at a glance and nothing more.
19
+ - **Viewport rectangle** (required) — An accent-washed rectangle computed from the canvas’s view and the map’s scale, clipped to the plate so a viewport panned past the artwork stops claiming a map that reaches further, and floored at a few pixels so a deep zoom still leaves something on screen to see. It is derived on every render and never stored.
20
+ - **Seek layer** — The transparent layer over the map that turns a press, or a drag that STARTED on it, into a point in CONTENT coordinates and hands it to onSeek. A button pressed elsewhere and dragged across it moves nothing. Nor does the map itself — it has no authority over the view.
21
+
22
+ ## Best practices
23
+
24
+ ### Do
25
+
26
+ - Feed it the canvas’s own onViewChange. The rectangle is arithmetic on those three numbers, so a map wired that way cannot disagree with the frame it maps — and keeping a second copy of where the viewport is, is exactly how one comes to.
27
+ - Measure content at the artwork’s natural CSS size. Everything here is scaled by width over content.width, so a wrong content width scales the miniature and the rectangle by the same wrong factor: the map still looks plausible and points at the wrong part of the picture. A width of 0 draws an empty plate instead, which is what a measurement that has not landed yet should look like.
28
+ - Let the canvas say how big the frame is. Every view a DiagramCanvas emits carries the frame it was measured against, so passing onViewChange through is enough — the frame prop is for a frame this component cannot be told about, and a hand-declared one is the single number that makes the rectangle lie.
29
+ - Send onSeek straight to the canvas handle’s centerOn. The point arrives in content coordinates, which is the space centerOn already takes, so recentring needs no conversion of your own.
30
+
31
+ ### Don’t
32
+
33
+ - It is pointer-only and hidden from assistive technology: no tab stop, no keys, and the miniature deliberately publishes nothing because the figure it mirrors already does. The canvas’s arrow keys stay the keyboard’s route to a far corner, so the minimap must never be the only way to reach one.
34
+ - The miniature is the same markup shrunk, not a simplified drawing — every label goes down with it, so a wide figure at 200px is a shape rather than a reading copy. It answers where you are; what a node says is the figure’s job.
35
+
15
36
  ## Accessibility
16
37
 
17
38
  - The miniature is aria-hidden. The figure it mirrors already publishes its own summary, and a second copy would read the whole diagram out twice.
18
39
 
19
40
  ## DiagramMinimap
20
41
 
21
- Where you are in something bigger than the window. Two things at once, and both are needed: a miniature of the whole artwork, and a rectangle showing which part of it the frame is currently over. The miniature alone answers "what is there"; the rectangle answers "and where am I", which is the question a reader who has just panned twice actually has. THE RECTANGLE IS DERIVED, never stored. Its position comes out of the canvas's own view — the same three numbers the canvas is already transforming by — divided by the map's scale. Keeping a second copy of "where the viewport is" is how a minimap comes to disagree with the thing it is a map of, and a map that disagrees is worse than none. CLICKING RECENTRES rather than jumping. `onSeek` reports a point in CONTENT coordinates, which is what a canvas's `centerOn` takes. The minimap does not move anything itself: it has no authority over the view, it only says where the reader pointed.
42
+ Where you are in something bigger than the window. Two things at once, and both are needed: a miniature of the whole artwork, and a rectangle showing which part of it the frame is currently over. The miniature alone answers "what is there"; the rectangle answers "and where am I", which is the question a reader who has just panned twice actually has. THE RECTANGLE IS DERIVED, never stored. Its position comes out of the canvas's own view — the same three numbers the canvas is already transforming by — divided by the map's scale, and clamped to the plate: a viewport that has been panned past the edge of the artwork is a viewport half over blank paper, and drawing the rectangle out there claims the map extends somewhere it does not. Keeping a second copy of "where the viewport is" is how a minimap comes to disagree with the thing it is a map of, and a map that disagrees is worse than none. NOTHING IS DRAWN UNTIL THE ARTWORK HAS A SIZE. `content` is usually a measurement, and a measurement's first value is zero — so the scale would be 1, the miniature would be the artwork's top-left corner at full size, and the rectangle would sit over it meaning nothing. An empty plate for one frame is the honest version of "not yet". CLICKING RECENTRES rather than jumping. `onSeek` reports a point in CONTENT coordinates, which is what a canvas's `centerOn` takes. The minimap does not move anything itself: it has no authority over the view, it only says where the reader pointed. A drag keeps seeking, and only a drag that STARTED on the map does — a button held down somewhere else and dragged across is not this component's gesture to answer.
22
43
 
23
44
  ### Props
24
45
 
25
46
  - `content` (required) — `{ width: number; height: number }`. The whole artwork, at its natural size in CSS pixels.
26
- - `frame` (required) — `{ width: number; height: number }`. The frame the artwork is being looked at through, in CSS pixels.
47
+ - `frame` — `{ width: number; height: number }`. The frame the artwork is being looked at through, in CSS pixels. Optional because a `DiagramCanvas` now reports its own frame on every view it emits: wire `onViewChange` straight through and this is already right. Pass it only for a frame this component cannot be told about.
27
48
  - `view` (required) — `CanvasView`. Where that frame currently sits — a `DiagramCanvas`'s `onViewChange`.
28
49
  - `children` — `ReactNode`. A miniature of the artwork. Usually the same figure, rendered again.
29
50
  - `onSeek` — `(x: number, y: number) => void`. Called with a point in CONTENT coordinates when the reader picks one.
@@ -39,7 +60,6 @@ const [view, setView] = useState({ scale: 1, x: 0, y: 0 })
39
60
  // …
40
61
  <DiagramMinimap
41
62
  content={{ width: 1400, height: 620 }}
42
- frame={{ width: 720, height: 400 }}
43
63
  view={view}
44
64
  onSeek={(x, y) => canvas.current?.centerOn(x, y)}
45
65
  >
@@ -4,7 +4,7 @@ A bar of actions belonging to the surface underneath them.
4
4
 
5
5
  - Group: Diagrams
6
6
  - Import: `import { DiagramToolbar } from '@misoto22/design/diagrams'`
7
- - Version: 0.7.0
7
+ - Version: 0.9.0
8
8
  - Docs: https://ui.misoto22.com/components/diagram-toolbar/
9
9
  - Related: floating-icon-button, diagram-export-menu
10
10
 
@@ -12,6 +12,28 @@ A bar of actions belonging to the surface underneath them.
12
12
 
13
13
  FloatingIconButton is one pinned action. This is the container for several, so they read as one object rather than as a scatter.
14
14
 
15
+ ## Anatomy
16
+
17
+ - **Bar** (required) — role="toolbar" with a horizontal orientation, on a panel plate with a hairline and the system’s corner. One plate and one border is what makes six pinned buttons read as one object instead of as six.
18
+ - **Name** (required) — label, which becomes the bar’s accessible name. It is a required prop with no default, because a toolbar that announces its role and nothing else is a group a screen reader cannot tell from the next one.
19
+ - **Group** (required) — DiagramToolbarGroup: one run of related controls, divided by a hairline on its leading edge rather than by space. The first group carries no rule, so the bar does not open with a divider.
20
+ - **Controls** (required) — The children, at whatever size the caller gives them. The bar sets the gap and paints no state of its own — a button in here is the same button it is anywhere else.
21
+ - **Pin** — placement="floating" takes the bar out of the flow and pins it to the top edge of the nearest POSITIONED ancestor, at the sticky rank — under every anchored panel and every dialog — with align choosing the corner. placement="inline" leaves it in the flow and pins nothing.
22
+
23
+ ## Best practices
24
+
25
+ ### Do
26
+
27
+ - Give label the bar’s job rather than its shape — "Diagram actions", not "Toolbar" — because a page with a figure and a table otherwise announces two toolbars and distinguishes neither.
28
+ - Divide with DiagramToolbarGroup rather than with a gap. The rule is drawn on the group, and a gap wide enough to read as a boundary is also wide enough to stop the bar reading as one object, which is the reason the controls were collected at all.
29
+ - Keep it to a handful of controls. There is no roving focus here, so Tab visits every one of them: ten actions in the bar is ten stops between the reader and the rest of the page.
30
+
31
+ ### Don’t
32
+
33
+ - A floating bar sits over the surface, not beside it. Whatever is in that corner of the figure is underneath it — pad the surface, or use placement="inline" and let the bar take its own row.
34
+ - role="toolbar" is a promise about the keyboard as well as a name: a reader is told this is a toolbar and expects the arrow keys to move inside it. For two buttons that merely sit next to each other, a plain div makes no promise this component then has to keep.
35
+ - A floating bar is a SIBLING of the canvas inside a positioned wrapper, never a child of it. Everything handed to DiagramCanvas renders inside the transformed stage, so a bar passed as a child zooms and pans away with the diagram it was put there to control — and with no positioned ancestor at all it pins to whichever box further up the page happens to be one.
36
+
15
37
  ## Accessibility
16
38
 
17
39
  - role="toolbar" announces a toolbar rather than six unrelated buttons. It does not implement roving focus — Tab visits every control, which is honest for a bar of three.
@@ -4,10 +4,33 @@ A modal surface: portal, scrim, centred panel.
4
4
 
5
5
  - Group: Overlays
6
6
  - Import: `import { Dialog } from '@misoto22/design'`
7
- - Version: 0.7.0
7
+ - Version: 0.9.0
8
8
  - Docs: https://ui.misoto22.com/components/dialog/
9
9
  - Related: dropdown-menu, tooltip
10
10
 
11
+ ## Anatomy
12
+
13
+ - **Scrim** (required) — The full-viewport --scrim layer at --z-overlay (200). It is what a click outside lands on, and it paints over everything the page had pinned below that rank — a FloatingIconButton at 100 included. Not over an anchored panel: those sit at 220 precisely so a Select opened inside this dialog is still reachable.
14
+ - **Panel** (required) — The centred box at --z-modal (210), capped at min(92vw, 32rem) wide and 85vh tall, scrolling its own body past that. It centres itself with a translate, which has consequences for anything fixed inside it.
15
+ - **Title** (required) — title, rendered as the Radix Title. Always present: when title is omitted a visually hidden one is rendered reading the literal word “Dialog”, and development warns DIALOG_TITLE_MISSING — the fallback exists so an unnamed modal is not shipped, not so one can be.
16
+ - **Description** — description, a quiet line under the title. It shares one wrapper with the title, so hideTitle hides both.
17
+ - **Close** — The 36px X in the top-end corner, rendered while showClose is true (the default) and carrying its own aria-label of “Close”.
18
+
19
+ ## Best practices
20
+
21
+ ### Do
22
+
23
+ - Pass title even when you set hideTitle: with no title at all the fallback accessible name is the literal string “Dialog”, so every unnamed modal in the app is announced as the same thing — and it passes an automated accessibility check while doing it, which is why development warns instead of leaving it to a review.
24
+ - Wrap the cancelling control in DialogClose rather than flipping your own state — the close then runs through Radix, which returns focus to the trigger instead of dropping it at the top of the document.
25
+ - Keep it to what fits. The panel stops at 32rem by 85vh and scrolls its own body past that, so a form long enough to scroll has become a Sheet, which gets the full height of the viewport, or a page.
26
+ - Leave showClose on unless the panel supplies its own exit: Escape and the scrim are the only other ways out and neither is visible, so showClose={false} on a dialog full of content is a room with an unmarked door.
27
+
28
+ ### Don’t
29
+
30
+ - An OverlayContainer whose element is not positioned hands the dialog the wrong box: naming a container switches the panel from fixed to absolute, and an unpositioned container sends it to the nearest positioned ancestor instead — usually the page, which looks like the container was ignored.
31
+ - Two dialogs open at once are ordered by the DOM, not by a rank: both sit at --z-modal, so the one mounted last paints over the first — a command palette summoned over a dialog lands on top because it opened second, and reversing that order reverses the picture.
32
+ - The panel centres itself with a transform, which makes it the containing block for every position: fixed descendant — a FloatingIconButton dropped inside a dialog pins to the panel’s corner rather than the screen’s.
33
+
11
34
  ## Accessibility
12
35
 
13
36
  - Radix owns the focus trap, Escape, the scroll lock and aria-modal.
@@ -28,11 +51,11 @@ Radix Dialog root + trigger + close, re-exported as typed passthroughs.
28
51
 
29
52
  ## DialogContent
30
53
 
31
- A modal surface: portal → scrim → centred panel. Radix owns the focus trap, the escape key, the scroll lock and the `aria-modal` wiring — all of which a hand-rolled dialog gets subtly wrong, usually by leaving focus behind in the page underneath. Radix requires a `Dialog.Title` whether or not one is shown, so a dialog without a visible heading still renders a hidden one rather than logging a warning and shipping an unnamed modal.
54
+ A modal surface: portal → scrim → centred panel. Radix owns the focus trap, the escape key, the scroll lock and the `aria-modal` wiring — all of which a hand-rolled dialog gets subtly wrong, usually by leaving focus behind in the page underneath. Radix requires a `Dialog.Title` whether or not one is shown, so a dialog without a visible heading still renders a hidden one rather than shipping an unnamed modal — and warns in development, because the fallback it renders is the literal word "Dialog" and a placeholder that passes an accessibility check is how the problem survives a review. Portals into the element an enclosing `OverlayContainer` names, and switches from viewport positioning to container positioning when there is one. A `fixed` panel covers the page whatever it is portalled into, so honouring the container without that swap would have moved the markup and left the picture unchanged.
32
55
 
33
56
  ### Props
34
57
 
35
- - `title` — `ReactNode`. Heading text. When omitted, a visually-hidden title is rendered for a11y.
58
+ - `title` — `ReactNode`. Heading text. Pass one even when `hideTitle` is set. Radix requires a title, so omitting it renders a hidden fallback reading the literal word "Dialog" — which satisfies an automated accessibility check and announces every unnamed modal in the application as the same thing. Development says so out loud.
36
59
  - `description` — `ReactNode`. Sub-heading under the title.
37
60
  - `className` — `string`.
38
61
  - `showClose` — `boolean` default `true`. Show the top-right close control (default true).