@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 ruled data table — alignment, sorting and rules all per column.
4
4
 
5
5
  - Group: Data
6
6
  - Import: `import { Table } from '@misoto22/design'`
7
- - Version: 0.7.0
7
+ - Version: 0.9.0
8
8
  - Docs: https://ui.misoto22.com/components/table/
9
9
  - Related: card, figure-band
10
10
 
@@ -12,6 +12,28 @@ A ruled data table — alignment, sorting and rules all per column.
12
12
 
13
13
  Alignment is per column and numbers belong at the end edge, so digits line up. Sorting is opt-in per column: a table where every header is a button invites sorting a column the data cannot be ordered by.
14
14
 
15
+ ## Anatomy
16
+
17
+ - **Scroll region** (required) — The focusable <div role="region"> around the table, named by caption. It carries the border setting and the density attribute, and it is what scrolls sideways — so the table exceeds the measure and the page does not. It is also positioned, which is what keeps an sr-only label inside a cell from resolving against the document and dragging the page sideways with it.
18
+ - **Caption** (required) — A real <caption>, visually hidden unless showCaption prints it as an eyebrow above the table. The same string is the scroll region’s accessible name, so it is heard on the way in and again from the table.
19
+ - **Column label** (required) — TH — mono and uppercase so it never reads as data, aligned per column, and always emitting scope="col" unless a call site overrides it.
20
+ - **Sort control** — On a sortable header only: a <button> INSIDE the th, with ArrowUp, ArrowDown or a dimmed ChevronsUpDown beside the label, and aria-sort on the th set from sortDirection.
21
+ - **Cells** (required) — TD — top-aligned at --ink-2, sharing --table-pad-x with the header so the columns line up, and taking their row height from --table-pad-y, which density halves from 14px to 8px.
22
+
23
+ ## Best practices
24
+
25
+ ### Do
26
+
27
+ - Bound the height from outside for stickyHeader: className and every other prop land on the <table>, not on the scrolling div around it, so only a constraining parent — a flex column with a height — gives that div something to stick within. A max-height on a plain wrapper does not, and the header simply travels with the page.
28
+ - Pass scope="row" on a row’s first cell — TH writes scope="col" and your props are spread after it, so the override lands; without it every row header claims to head a column and a cell traced back reaches the wrong label.
29
+ - Reset the other columns to sortDirection="none" when the sort moves: each header carries its own aria-sort and nothing coordinates them, so a table can end up announcing two columns as sorted at once.
30
+ - Give TD the same align as its TH — alignment is per cell, not inherited down the column, and end-aligned numbers under a start-aligned label is a column whose digits stop lining up with their own heading.
31
+
32
+ ### Don’t
33
+
34
+ - aria-sort tells a reader how the table is ordered once they reach the header; it announces nothing at the moment the button is pressed. A table that re-orders under a screen reader has to say so somewhere the reader already is, or every row silently changes and nothing is said.
35
+ - Do not expect it to reflow on a phone: nothing stacks, the region scrolls sideways behind a hairline scrollbar, and a column past the fold is reachable only by a reader who works out that it scrolls. Eight columns at 375px wants a different presentation, not a smaller font.
36
+
15
37
  ## Accessibility
16
38
 
17
39
  - caption is required: an unnamed table on a page with three tables is unnavigable.
@@ -19,6 +41,7 @@ Alignment is per column and numbers belong at the end edge, so digits line up. S
19
41
  - A sortable header is a button INSIDE the th, not a click handler on the cell — a cell with an onClick is not focusable and not announced, so the sort would exist only for a mouse.
20
42
  - aria-sort is set from sortDirection, which is the only way a screen reader learns the table is ordered at all.
21
43
  - No zebra striping at any border setting: in a monochrome system a striped row is a second surface competing with the page ground.
44
+ - The scroll region is a containing block, so a visually-hidden label in a cell stays inside the table rather than escaping it and widening the page.
22
45
 
23
46
  ## Keyboard
24
47
 
@@ -27,14 +50,14 @@ Alignment is per column and numbers belong at the end edge, so digits line up. S
27
50
 
28
51
  ## Table
29
52
 
30
- A ruled data table. Wrapped in its own horizontally scrolling container, because a table is the one block that legitimately exceeds the measure — and a page that scrolls sideways as a whole is a layout bug, while a table that does is a table. That container is focusable, and it has to be. A scrollable region whose contents are not themselves focusable is unreachable by keyboard: there is no element to Tab to and therefore no way to press an arrow key at it, so the columns past the fold simply do not exist for anyone not using a mouse. No zebra striping at any border setting. In a monochrome system a striped row is a second surface competing with the page ground, and the hairline between rows is already enough to track a line across.
53
+ A ruled data table. Wrapped in its own horizontally scrolling container, because a table is the one block that legitimately exceeds the measure — and a page that scrolls sideways as a whole is a layout bug, while a table that does is a table. That container is focusable, and it has to be. A scrollable region whose contents are not themselves focusable is unreachable by keyboard: there is no element to Tab to and therefore no way to press an arrow key at it, so the columns past the fold simply do not exist for anyone not using a mouse. It is also POSITIONED, which is not decoration. `sr-only` is `position: absolute`, so a visually-hidden label in a cell resolves against the nearest positioned ancestor — and with none between it and the document, it escapes the scroll container and every `overflow-hidden` around it, and widens the page by however far the table happens to be scrolled. No zebra striping at any border setting. In a monochrome system a striped row is a second surface competing with the page ground, and the hairline between rows is already enough to track a line across.
31
54
 
32
55
  ### Props
33
56
 
34
57
  - `caption` (required) — `string`. Describes the table for a screen reader, which cannot see the heading above it. Rendered as a visually-hidden `<caption>` — required, because an unnamed table in a page with three tables is unnavigable.
35
58
  - `showCaption` — `boolean` default `false`. Prints the caption instead of hiding it.
36
59
  - `stickyHeader` — `boolean` default `false`. Pins the header row while the body scrolls. Needs a bounded height on the container — otherwise the page scrolls, not the table, and nothing sticks.
37
- - `borders` — `TableBorders` default `'rows'`. Which rules to draw. See .
60
+ - `borders` — `TableBorders` default `'rows'`. Which rules to draw. See TableBorders.
38
61
  - `density` — `'comfortable' | 'compact'` default `'comfortable'`. Tightens the row padding, for a table that is mostly numbers.
39
62
 
40
63
  Also accepts: `TableHTMLAttributes<HTMLTableElement>`.
@@ -62,6 +85,8 @@ Also accepts: `Omit<ThHTMLAttributes<HTMLTableCellElement>, 'align'>`.
62
85
 
63
86
  ## TD
64
87
 
88
+ A body cell. TOP-aligned, and that is a choice about which kind of table is the common one here: a cell holding a paragraph. Top is what lines the first lines of a row up with each other, and centring a two-word term against a four-line description puts the term in the middle of nothing. It is the wrong default for the other kind — a row of one-line values with a control in it. A 36px button next to 16px of text makes a 52px row, and every other cell then hangs at the top of it with twenty pixels of nothing underneath, which reads as a column that has slipped. Pass `className="align-middle"` on those rows; the data-table template does.
89
+
65
90
  ### Props
66
91
 
67
92
  - `align` — `TableAlign` default `'start'`. Which edge the cell's contents sit against. Match the column's header.
@@ -4,10 +4,32 @@ One strip, several panels.
4
4
 
5
5
  - Group: Navigation
6
6
  - Import: `import { Tabs } from '@misoto22/design'`
7
- - Version: 0.7.0
7
+ - Version: 0.9.0
8
8
  - Docs: https://ui.misoto22.com/components/tabs/
9
9
  - Related: accordion
10
10
 
11
+ ## Anatomy
12
+
13
+ - **Root** (required) — Tabs — Radix’s root, re-exported. It draws nothing and owns everything: value or defaultValue, and activationMode. With neither value nor defaultValue no tab is selected and no panel is mounted.
14
+ - **Tab strip** (required) — TabsList — the role="tablist" row, sitting on one hairline rule and scrolling on its own axis with scroll-slim. It has no accessible name unless you give it one.
15
+ - **Tab** (required) — TabsTrigger, at the md control height with its label on one line. Every tab carries the 2px active marker, transparent until it is the selected one; the marker is pulled onto the strip’s own border with -mb-px so the two share a line rather than stacking into a 3px edge.
16
+ - **Panel** — TabsContent, paired to its tab by matching value. Mounted only while it is the selected one, and marked data-m22-animated so its entrance is dropped for a reader who asked for less motion.
17
+
18
+ ## Best practices
19
+
20
+ ### Do
21
+
22
+ - Give the root a defaultValue or a value: with neither, nothing matches, every panel stays unmounted, and the page renders a strip above an empty space with nothing to say what is missing.
23
+ - Match each trigger’s value to a panel’s value exactly — the pairing is string equality, and a typo is not an error but a tab that opens onto nothing.
24
+ - Pass activationMode="manual" when a panel fetches or renders something expensive: the default is automatic, so ← and → select as they move and arrowing across four tabs starts four loads before the reader has stopped.
25
+ - Give TabsList an aria-label on a page with more than one set: Radix names the tablist after nothing, and two unnamed tablists are two “tab list”s a reader cannot tell apart.
26
+
27
+ ### Don’t
28
+
29
+ - An unselected panel is unmounted, not hidden — find-in-page cannot reach its text, a print takes only the panel that was open, and a half-filled form in another tab has lost what was typed into it by the time the reader comes back.
30
+ - The selected tab lives in React state, not in the URL: a reader who reloads or shares the page lands on the first panel, so anything worth linking to needs value lifted into a query parameter.
31
+ - Tabs are not a way to fit more in: the strip scrolls silently, and a sixth tab past the fold looks exactly like a page that only has five.
32
+
11
33
  ## Accessibility
12
34
 
13
35
  - The strip scrolls rather than wrapping: a wrapped second row moves every tab below it and the reader loses the one they were about to click.
@@ -33,7 +55,7 @@ One tab. The active marker is a 2px ink rule pulled onto the strip's own border
33
55
 
34
56
  ## TabsContent
35
57
 
36
- The panel paired to a by matching `value`.
58
+ The panel paired to a TabsTrigger by matching `value`.
37
59
 
38
60
  ## Examples
39
61
 
package/dist/agent/Tag.md CHANGED
@@ -1,35 +1,66 @@
1
1
  # Tag
2
2
 
3
- A subject label — a topic, a technology, a filter facet.
3
+ A subject label — a topic, a technology, a filter facet — that filters with onClick and is dismissed with onRemove.
4
4
 
5
5
  - Group: Display
6
6
  - Import: `import { Tag } from '@misoto22/design'`
7
- - Version: 0.7.0
7
+ - Version: 0.9.0
8
8
  - Docs: https://ui.misoto22.com/components/tag/
9
- - Related: badge
9
+ - Related: badge, status-pill
10
10
 
11
11
  ## When to reach for it
12
12
 
13
- Several sit together and the reader scans them. One fact about one record is a Badge.
13
+ Several sit together and the reader scans them. One fact about one record is a Badge. A chip the reader can toggle or dismiss is this one with onClick or onRemove, not a fourth component.
14
+
15
+ ## Anatomy
16
+
17
+ - **Chip** (required) — The <span>: the same --radius-sm corner, the same 10px by 4px padding and the same 12px mono as a Badge, with no border of its own.
18
+ - **Ground** (required) — --stone at rest, --accent once active, cross-fading over --duration-fast. The accent is the system’s one pointer at a choice, which is why it is what selection is drawn in.
19
+ - **Label** (required) — children, in --ink-3-aa — the AA floor rather than a light grey — and in --accent-foreground once active.
20
+ - **Remove button** — On onRemove only: a real <button type="button"> after the label, holding a 12px X and named by removeLabel. The drawn box is 16px, under the 24px WCAG 2.5.8 floor, so an inset pseudo-element takes the hit area out to 24 without changing the drawing or pushing the chips apart.
21
+ - **Filter control** — On onClick only: the chip itself becomes the <button>, carrying aria-pressed from active. Given onRemove as well, the label splits into its own button beside the X — two siblings, never one inside the other — and takes the leading padding with it so the target is the chip up to the X rather than just the words.
22
+
23
+ ## Best practices
24
+
25
+ ### Do
26
+
27
+ - Filter with onClick, not with a wrapper. The chip becomes the button itself, so the padding is part of the target and the focus ring is drawn around what the reader sees — and a removable chip does not end up with a button inside a button.
28
+ - Pass active on a chip that toggles, and leave it off one that does not. aria-pressed is read off that same value, so the accent fill and the state assistive tech hears cannot drift apart; omitted, nothing is announced, which is the right answer for a chip that navigates rather than toggles.
29
+ - Give a filter row an off state to come back to — active is the accent, and a row in which every tag is active spends the mark that means “this one” on all of them.
30
+ - Name the subject in removeLabel — "Remove Rust filter", not "Remove". It is required alongside onRemove because eight chips whose controls are all called Remove is eight controls a screen reader cannot tell apart.
31
+
32
+ ### Don’t
33
+
34
+ - It carries no tone at all, so a tag cannot say success or danger. Colouring one in through className puts a hue into the system by hand and leaves the accent as the only thing that still reads as selected.
35
+ - One tag on its own is a Badge that lost its tone. The component is built to be scanned in a row, and a single chip beside a record is one fact about one record.
36
+ - Do not wrap it in a button of your own. Around a removable chip that is a button inside a button — invalid markup a parser splits into siblings, leaving a DOM neither the author nor the accessibility tree expects. onClick is what that wrapper was for.
14
37
 
15
38
  ## Accessibility
16
39
 
17
- - Presentational. To filter with it, wrap it in a button and pass active, so the focus ring and the pressed state stay with the element that owns them.
40
+ - Presentational until it is given a handler. onClick makes the chip a real button carrying aria-pressed from active, so the focus ring and the pressed state stay on the element that draws them.
41
+ - Both controls are real <button type="button">s and siblings, so Tab reaches each, Enter and Space fire each, and neither submits the form it happens to sit in.
42
+ - removeLabel is required with onRemove and is the button’s whole accessible name — the X itself is aria-hidden.
18
43
 
19
44
  ## Tag
20
45
 
21
- A subject label — a topic, a technology, a filter facet. Distinct from `Badge`, which carries a state or a count. A tag names what something is ABOUT, so several sit together in a row and the reader scans them; a badge is one fact about one record. Presentational on purpose. To make a tag filter a list, wrap it in a button or a link at the call site and pass `active` that keeps the focus ring, the pressed state and the keyboard handling with the element that actually owns them.
46
+ A subject label — a topic, a technology, a filter facet — that can filter with `onClick` and be dismissed with `onRemove`. Distinct from `Badge`, which carries a state or a count. A tag names what something is ABOUT, so several sit together in a row and the reader scans them; a badge is one fact about one record. This is where a `Token` component would have gone. It was not built: a token is a tag with a remove button, and the difference between the two is one prop, not one component. The system already ships three things that look alike — `Badge`, `Tag`, `StatusPill` — and a fourth whose whole distinction is an X on the end would be the one a call site picks by coin toss. Presentational until it is given a handler, and the component owns both interactive cases rather than leaving one to a wrapper at the call site. That is not a convenience: a wrapping `<button>` around a chip that already holds the remove `<button>` is a button inside a button, which no parser keeps and no accessibility tree reports the way it was written. Given both, the chip renders the label and the X as SIBLING buttons — the label takes the leading padding with it, so it is the whole of the chip up to the X rather than the words with dead padding around them.
22
47
 
23
48
  ### Props
24
49
 
25
50
  - `children` (required) — `ReactNode`.
26
- - `active` — `boolean` default `false`. Renders the pressed/selected look. Pair with `aria-pressed` on a wrapper button.
51
+ - `active` — `boolean`. Renders the pressed/selected look, and declares the chip a toggle. An interactive chip reads `aria-pressed` off this same value, so the accent fill and the state a screen reader hears cannot drift apart. Leave it off for a chip whose `onClick` navigates or opens something: a control that is neither pressed nor unpressed is better announced as neither than as "not pressed".
52
+ - `onClick` — `() => void`. Makes the chip ITSELF the filter control. This prop exists because the alternative did not survive contact with `onRemove`. The advice used to be to wrap the tag in a button at the call site, which is fine on its own and invalid the moment the chip is also removable: the remove control is a real `<button>`, so the wrapper puts a button inside a button — markup the parser splits into siblings, leaving a DOM neither the author nor the accessibility tree expects. With this the wrapper is never written. The chip carries the click, the focus ring and the pressed state on the element that draws them, and a removable filter chip renders its two controls side by side instead of one inside the other.
53
+ - `onRemove` — `() => void`. Called when the reader dismisses the chip.
54
+ - `removeLabel` — `string`. The remove button's accessible name. Name the subject, not the action.
27
55
 
28
- Also accepts: `HTMLAttributes<HTMLSpanElement>`.
56
+ Also accepts: `Omit<HTMLAttributes<HTMLElement>, 'onClick'>`.
29
57
 
30
58
  ## Examples
31
59
 
32
60
  ```tsx
33
61
  <Tag>TypeScript</Tag>
34
- <button type="button" aria-pressed={on} onClick={toggle}><Tag active={on}>Rust</Tag></button>
62
+ <Tag active={on} onClick={toggle}>Rust</Tag>
63
+ <Tag onRemove={() => drop('rust')} removeLabel="Remove Rust filter">Rust</Tag>
64
+ // Both: a filter the reader can toggle and also take out of the row.
65
+ <Tag active={on} onClick={toggle} onRemove={drop} removeLabel="Remove Rust filter">Rust</Tag>
35
66
  ```
@@ -0,0 +1,65 @@
1
+ # Text
2
+
3
+ The system’s paragraph, on the second rung of the ink ladder.
4
+
5
+ - Group: Display
6
+ - Import: `import { Text } from '@misoto22/design'`
7
+ - Version: 0.9.0
8
+ - Docs: https://ui.misoto22.com/components/text/
9
+ - Related: heading, article, markdown
10
+
11
+ ## When to reach for it
12
+
13
+ One paragraph, or one run of text, outside a reading column. A whole column of prose is an Article.
14
+
15
+ ## Anatomy
16
+
17
+ - **Box** (required) — The element `as` names — a <p> unless told otherwise. It carries the size, the tone and margin: 0, so the spacing between blocks belongs to the surface rather than to the paragraph.
18
+ - **Type step** (required) — size, one of four: xs, sm, base and lead. lead is --fs-item, the bottom rung of the heading ladder, and is the standfirst that carries a piece.
19
+ - **Ink step** (required) — tone, one of three, because the ink ladder has three rungs: body is --ink-2, strong is --ink, muted is --ink-3-aa.
20
+
21
+ ## Best practices
22
+
23
+ ### Do
24
+
25
+ - Leave tone alone for body copy. The default is --ink-2 on purpose: a page whose paragraphs are all full-strength ink has spent the top of the ladder on its body text and has nothing left for the headings.
26
+ - Use as="span" for a run inside a sentence. A <p> nested inside a <p> is not nesting — the HTML parser closes the outer one and you get two paragraphs and a broken layout.
27
+ - Reach for size="lead" for the standfirst under a title, and stop there. It is --fs-item, the same step an in-card title uses; anything larger is a heading that has not admitted it.
28
+
29
+ ### Don’t
30
+
31
+ - Do not set spacing on it. Every Text is margin: 0, so a stack of them inside a plain <div> has no rhythm by design — put them in an Article or give the container the gap, or every surface ends up with its own idea of what a paragraph gap is.
32
+ - tone="muted" is --ink-3-aa, never --ink-3. The two look identical on paper and are not the same token: --ink-3 is a translucent tint that takes on whatever is under it, so it clears AA on the page ground and quietly fails on a card or a code plate.
33
+ - Do not use it as a heading with a bigger size. The element is what a screen reader navigates by, and a <p> at --fs-item is invisible to a heading list.
34
+
35
+ ## Accessibility
36
+
37
+ - as changes the element and nothing else, so the markup can say what the content is without the look changing under it.
38
+ - Every tone is an AA-safe rung; the muted step is --ink-3-aa rather than the translucent --ink-3.
39
+
40
+ ## Text
41
+
42
+ A paragraph, or a run of text that wants the system's voice. The step between `Article` and raw JSX. `Article` styles a whole reading column from element selectors and is the right answer for a post; this is for the single paragraph that is NOT in a column — a card's description, a dialog's explanation, the line under an empty state. The default tone is `body` (`--ink-2`), not `--ink`. A page whose paragraphs are all full-strength ink has spent the top of the ladder on its body copy and has nothing left for the headings, which is the single most common way a monochrome page loses its hierarchy.
43
+
44
+ ### Props
45
+
46
+ - `children` — `ReactNode`.
47
+ - `size` — `TextSize` default `'base'`. Which rung of the type scale. See TextSize.
48
+ - `tone` — `TextTone` default `'body'`. Which rung of the ink ladder. See TextTone.
49
+ - `as` — `TextElement` default `'p'`. The element, and ONLY the element. Changing it changes what the markup means — a `span` inside a sentence, an `li` inside a list someone else opened — and changes nothing about the look. That separation is the whole point: the alternative is a `<p>` nested inside a `<p>`, which the HTML parser silently splits into two, or a paragraph faked out of a `<div>` because the real element brought a size with it.
50
+
51
+ Also accepts: `HTMLAttributes<HTMLElement>`.
52
+
53
+ ## Types
54
+
55
+ - `TextSize` = `'xs' | 'sm' | 'base' | 'lead'`
56
+ - `TextTone` = `'body' | 'strong' | 'muted'`
57
+ - `TextElement` = `'p' | 'span' | 'div' | 'li' | 'figcaption'`
58
+
59
+ ## Examples
60
+
61
+ ```tsx
62
+ <Text>Twelve releases this quarter, none rolled back.</Text>
63
+ <Text size="lead" tone="strong">A monochrome system for software and writing.</Text>
64
+ <Text as="span" size="sm" tone="muted">Updated just now</Text>
65
+ ```
@@ -4,10 +4,29 @@ Multi-line text entry, resizable vertically only.
4
4
 
5
5
  - Group: Forms
6
6
  - Import: `import { Textarea } from '@misoto22/design'`
7
- - Version: 0.7.0
7
+ - Version: 0.9.0
8
8
  - Docs: https://ui.misoto22.com/components/textarea/
9
9
  - Related: input, field
10
10
 
11
+ ## Anatomy
12
+
13
+ - **Control box** (required) — The <textarea>, on the same CONTROL_BASE as Input plus a min-h-24 floor. That floor is under rows, not over it: rows={2} still renders six rems tall.
14
+ - **Resize grip** — The browser’s own corner handle, constrained to resize-y — a reader can lengthen the box but cannot drag it past the measure or out of the page’s gutter.
15
+ - **Danger border** — The same pair isInvalid reads on Input: the invalid prop or an aria-invalid, including the one a Field sets when it has an error.
16
+
17
+ ## Best practices
18
+
19
+ ### Do
20
+
21
+ - Set rows to the answer you expect. It is the only thing that raises the resting height above the six-rem floor, and the size of the box is the clearest thing on the page about how long an answer should be.
22
+ - If there is a length limit, set maxLength AND say so in the hint: maxLength swallows the keystroke without explaining, and a paste one character too long is silently truncated.
23
+ - Keep Enter meaning newline. A textarea that submits on Enter has taken the one key the control exists to accept, and the reader loses the paragraph they were halfway through.
24
+
25
+ ### Don’t
26
+
27
+ - There is no auto-grow. The height is whatever rows and min-h-24 settled on and it never follows the content, so a long answer is reviewed through a six-rem window unless the call site says otherwise.
28
+ - Do not put a required format in the Field’s hint and nothing else: hint and error share one slot, so the format vanishes the instant the field is wrong — which is the only moment anyone needed it.
29
+
11
30
  ## Textarea
12
31
 
13
32
  Multi-line text entry. Resizes vertically only: horizontal resize lets a reader drag the control past the measure and past the page's own gutter.
@@ -0,0 +1,64 @@
1
+ # Timestamp
2
+
3
+ A date or a time, rendered the one way the system renders them.
4
+
5
+ - Group: Display
6
+ - Import: `import { Timestamp } from '@misoto22/design'`
7
+ - Version: 0.9.0
8
+ - Docs: https://ui.misoto22.com/components/timestamp/
9
+ - Related: text, badge, description-list
10
+
11
+ ## When to reach for it
12
+
13
+ Any instant on screen. The alternative is toLocaleString() at the call site, which is how a product ends up with four date formats on one screen.
14
+
15
+ ## Anatomy
16
+
17
+ - **Element** (required) — A <time> whose datetime is the full ISO instant from the very first render and never changes, so anything parsing the markup gets the exact moment whether or not the effect has run.
18
+ - **First paint** (required) — The UTC calendar date, sliced straight out of the ISO string with no Intl anywhere near it. It is what the server renders and what the client renders while hydrating — both sides compute it from the same characters, so they cannot disagree.
19
+ - **Local reading** (required) — Applied after mount, in an effect, where there is a reader to be local to: Intl.RelativeTimeFormat with numeric "auto" for the relative form, Intl.DateTimeFormat at dateStyle medium for the absolute one.
20
+ - **Missing value** — A value nothing can parse renders an em dash at --ink-3-aa and no <time> at all, because an element whose datetime cannot be written is not a time.
21
+
22
+ ## Best practices
23
+
24
+ ### Do
25
+
26
+ - Leave format on auto for a record list. It reads relative while the gap is under relativeWithin — a week by default — and switches to the calendar date past it, which is both the more useful fact and the one that stops changing.
27
+ - Pass the instant, not a formatted string. A Date, an ISO string or epoch milliseconds all work, and all three end up as the same ISO datetime attribute.
28
+ - Re-render from above when a list has to tick. It formats once per mount on purpose: a hundred rows each holding an interval to keep "3 minutes ago" honest is a cost nobody asked for.
29
+
30
+ ### Don’t
31
+
32
+ - Do not expect the relative text in the server-rendered HTML. The first paint is deliberately the UTC date — a crawler, a static export and a test reading markup all see 2026-01-14, and only a mounted browser sees "3 hours ago".
33
+ - Do not format a date beside it with toLocaleString. The two would disagree the moment one page renders on a build server, which is exactly the hydration mismatch this component is built around.
34
+ - Do not use it for a duration. It renders an instant relative to now; "2m 14s of build time" is a length, not a moment, and belongs in a plain string.
35
+
36
+ ## Accessibility
37
+
38
+ - The datetime attribute carries the exact ISO instant from the first render, so assistive technology reading the machine value never depends on an effect having run.
39
+ - The visible text changes once after mount and the machine value never does, which keeps the announced value and the parsed value in agreement.
40
+ - An unparseable value renders an em dash rather than the browser’s literal "Invalid Date" string, which is an engineering artefact and not something to put in front of a reader.
41
+
42
+ ## Timestamp
43
+
44
+ A date or a time, rendered the one way the system renders them. Every list of records needs this, and `new Date().toLocaleString()` at the call site is precisely how a product ends up with four date formats on one screen. **On hydration.** Both halves of a formatted date are environment-dependent: a relative time depends on when it is read, and even an absolute one depends on the reader's locale and time zone, none of which a static build knows. So the first paint — the one the server produces and the one the client must reproduce exactly — is the ISO calendar date in UTC, sliced straight out of the ISO string with no `Intl` anywhere near it. Both sides compute it from the same characters, so they cannot disagree. The locale-aware and relative forms are applied after mount, in an effect, where there is a reader to be local to. This package statically exports every page, so the alternative is a hydration mismatch on any page with a date on it. The `datetime` attribute is the full ISO instant from the first render onwards and never changes, so a screen reader, a crawler, or anything else parsing the markup gets the exact moment whether or not the effect has run. It formats once per mount. A hundred rows each holding a ticking interval to keep "3 minutes ago" honest is a cost nobody asked for; a list that must tick should re-key or re-render from above.
45
+
46
+ ### Props
47
+
48
+ - `value` (required) — `Date | string | number`. The instant. A `Date`, an ISO string, or epoch milliseconds.
49
+ - `format` — `TimestampFormat` default `'auto'`. How the instant reads. See TimestampFormat.
50
+ - `relativeWithin` — `number` default `604_800_000`. How far from now `auto` still prints a relative time, in milliseconds. Seven days by default — past a week the calendar date is the more useful fact, and it is also the one that stops changing.
51
+ - `showTime` — `boolean` default `false`. Adds the clock time to the absolute form.
52
+
53
+ Also accepts: `Omit<TimeHTMLAttributes<HTMLTimeElement>, 'dateTime' | 'children'>`.
54
+
55
+ ## Types
56
+
57
+ - `TimestampFormat` = `'auto' | 'relative' | 'absolute'`
58
+
59
+ ## Examples
60
+
61
+ ```tsx
62
+ <Timestamp value={deploy.finishedAt} />
63
+ <Timestamp value="2026-01-14T09:30:00Z" format="absolute" showTime />
64
+ ```
@@ -4,7 +4,7 @@ A transient confirmation, mounted once near the app root.
4
4
 
5
5
  - Group: Feedback
6
6
  - Import: `import { Toast } from '@misoto22/design'`
7
- - Version: 0.7.0
7
+ - Version: 0.9.0
8
8
  - Docs: https://ui.misoto22.com/components/toast/
9
9
  - Related: alert
10
10
 
@@ -12,9 +12,33 @@ A transient confirmation, mounted once near the app root.
12
12
 
13
13
  Something succeeded and needs no response. A toast is dismissed by time, and time is not an acknowledgement.
14
14
 
15
+ ## Anatomy
16
+
17
+ - **Toaster** (required) — The single mount, bottom-right by default. It renders sonner’s list into a portal at the end of body, which is why the theming is an inline style — a stylesheet scoped to the app never reaches there.
18
+ - **Token style** (required) — sonner’s --normal-bg, --normal-text, --normal-border and --border-radius pointed at --paper, --ink, --rule-2 and --radius, plus the sans face. The --success-* and --error-* pairs join them only when richColors is on, which is the only state sonner reads them in.
19
+ - **Notification region** (required) — sonner’s own section, aria-live="polite" and labelled “Notifications altKey+KeyT”. Taken out of the tab order and reachable by that shortcut, and polite for every toast type — there is no assertive path.
20
+ - **Toast** — One entry, pushed by toast() or one of its typed variants and removed from the DOM after sonner’s default four seconds, which this wrapper does not change. Three are visible at once; the rest queue.
21
+ - **Close button** — On by default here, where sonner ships it off. Without it the only ways out are the timer and a swipe, and a keyboard has no swipe.
22
+
23
+ ## Best practices
24
+
25
+ ### Do
26
+
27
+ - Mount exactly one Toaster. Every toast() call reaches every Toaster listening, so one in a root layout and one in a nested layout render the same message twice, in two corners.
28
+ - Set duration per toast for anything longer than a short sentence. The wrapper leaves sonner’s default at four seconds — roughly ten words read aloud — and the rest of the message is removed from the page before it has been read.
29
+ - Keep the message to what happened. Three toasts are visible at a time and the rest wait their turn, so a loop that toasts per item shows the last three and delivers the others after the reader has moved on.
30
+ - Set data-mode on <html> and leave theme alone. sonner hard-codes the description’s colour per theme — #3f3f3f, overridden only under its dark theme — so a page painted dark by an attribute the Toaster was not following put that grey on --paper at roughly 1.85:1, and every toast with a description lost its second half.
31
+
32
+ ### Don’t
33
+
34
+ - Nothing a reader must act on belongs here. Four seconds is a deadline they were never told about, and the button is in a portal at the end of body that a keyboard reaches last — an Undo in a toast is an offer most people cannot take.
35
+ - Nothing a reader must read twice belongs here either — an error code, a reference, a name to type elsewhere. There is no history: once the timer expires the text is out of the DOM and unrecoverable.
36
+ - Do not report a failure with toast.error and consider it reported. The region is polite for every type, so the failure queues behind whatever the screen reader was already saying and can be removed before its turn comes.
37
+ - Do not pass theme="system". It reads prefers-color-scheme, not data-mode, so a reader who overrode a dark operating system with a light page gets a dark toast over it — the same defect the old default had, pointing the other way.
38
+
15
39
  ## Toaster
16
40
 
17
- Transient confirmations, mounted once near the app root. A toast is for something that succeeded and needs no response. Anything the reader must act on belongs in the page — a toast is dismissed by time, and time is not an acknowledgement. `richColors` stays off by default: sonner's rich palette is not this system's status scale, and turning it on reintroduces chroma the White Reset spends only on state.
41
+ Transient confirmations, mounted once near the app root. A toast is for something that succeeded and needs no response. Anything the reader must act on belongs in the page — a toast is dismissed by time, and time is not an acknowledgement. `theme` follows `data-mode`. sonner defaults to `light` and hard-codes the description's colour per theme — `#3f3f3f`, overridden only under `[data-sonner-theme=dark]` — so a Toaster that never passed `theme` put dark grey text on this system's `--paper: #0d0d0d` and every `toast(title, { description })` lost its second half. Pass `theme` yourself and that wins; sonner's own `system` is the one value not to reach for, since it reads the OS rather than the attribute the page is actually painted from. `richColors` stays off by default: sonner's rich palette is not this system's status scale, and turning it on reintroduces chroma the White Reset spends only on state.
18
42
 
19
43
  ## Examples
20
44
 
@@ -4,7 +4,7 @@ A segmented control: several options, one strip.
4
4
 
5
5
  - Group: Forms
6
6
  - Import: `import { ToggleGroup } from '@misoto22/design'`
7
- - Version: 0.7.0
7
+ - Version: 0.9.0
8
8
  - Docs: https://ui.misoto22.com/components/toggle-group/
9
9
  - Related: tabs, radio-group
10
10
 
@@ -12,6 +12,28 @@ A segmented control: several options, one strip.
12
12
 
13
13
  It changes a VALUE. Something that switches panels is Tabs.
14
14
 
15
+ ## Anatomy
16
+
17
+ - **Strip** (required) — The bordered pill holding the segments, w-fit as well as inline-flex — without it a flex or grid parent stretches the strip to the widest sibling and leaves dead space after the last segment.
18
+ - **Travelling pill** — The --accent block behind the selection, on single-value groups only and only once it has measured a selected segment. It moves rather than cross-fading, so the eye follows one thing.
19
+ - **Segment** (required) — A button at --control-h-sm. In a single group it changes ink only and lets the pill behind it do the filling; in a multiple group it fills itself, because there is nothing travelling.
20
+ - **Segment content** — children, in a gap-2 row. There is no iconOnly path here the way Button has one, so an icon with no words is a segment with no name.
21
+
22
+ ## Best practices
23
+
24
+ ### Do
25
+
26
+ - Give a single-value group a defaultValue or a value. The pill appears only after it has measured a selected segment, so a group that starts empty is a bare strip with nothing marked in it.
27
+ - Name the strip. Inside a Field its label does it, through aria-labelledby — the root is a div, so there is nothing for htmlFor to bind to — and standing alone it needs its own aria-label, which with type="single" is what a radiogroup is announced by.
28
+ - Give an icon-only segment its own aria-label: nothing strips the text or supplies a name for you here, so a strip of three glyphs announces three unnamed buttons.
29
+
30
+ ### Don’t
31
+
32
+ - type="single" has radio semantics but not radio behaviour: pressing the selected segment deselects it and commits an empty string, so a view switcher built on it can be switched off into no view at all.
33
+ - Segments are --control-h-sm — 36px comfortable, 30px under data-density="compact" — which is below the 44px pointer floor (WCAG 2.5.5). A strip meant for a thumb needs its own height.
34
+ - Do not put six options in it. The strip neither wraps nor scrolls, so past about five segments it simply runs out past its container, and that is a Select or a Combobox anyway.
35
+ - A Field’s required marks a single-value strip and leaves a multiple-value one unmarked: that one is a role="toolbar", which takes no aria-required at all, so on type="multiple" the asterisk is the whole of the marking.
36
+
15
37
  ## Accessibility
16
38
 
17
39
  - type="single" gets radio semantics; type="multiple" gets independent toggles. Choosing wrong tells a screen reader that picking one option unpicks the others.
@@ -24,7 +46,7 @@ It changes a VALUE. Something that switches panels is Tabs.
24
46
 
25
47
  ## ToggleGroup
26
48
 
27
- A segmented control: several options, one strip. `type="single"` is a choice — Radix gives it radio semantics, and it is the right shape for a view switcher or a density setting. `type="multiple"` is a set of independent toggles, which is a different thing announced differently; choosing the wrong one is how a "filter by tag" control ends up telling a screen reader that picking one tag unpicks the others. The two look different on purpose. A single-value strip moves ONE filled pill between its options, so the eye follows a thing travelling; a multiple-value strip fills each pressed option separately, because there is no single selection to travel. Two people looking at a screenshot should be able to tell which kind they are looking at, and before this they could not. Distinct from `Tabs`, which switches PANELS and owns a tabpanel relationship. A toggle group changes a value.
49
+ A segmented control: several options, one strip. `type="single"` is a choice — Radix gives it radio semantics, and it is the right shape for a view switcher or a density setting. `type="multiple"` is a set of independent toggles, which is a different thing announced differently; choosing the wrong one is how a "filter by tag" control ends up telling a screen reader that picking one tag unpicks the others. The two look different on purpose. A single-value strip moves ONE filled pill between its options, so the eye follows a thing travelling; a multiple-value strip fills each pressed option separately, because there is no single selection to travel. Two people looking at a screenshot should be able to tell which kind they are looking at, and before this they could not. Distinct from `Tabs`, which switches PANELS and owns a tabpanel relationship. A toggle group changes a value. Inside a `Field` the strip takes its name from that label, by pointing back at it — the root is a div, and `<label for>` does not bind to one, so the words above it do not click through. Standing alone it still needs its own `aria-label`.
28
50
 
29
51
  Also accepts: `ComponentProps<typeof ToggleGroupPrimitive.Root>`.
30
52
 
@@ -0,0 +1,71 @@
1
+ # Toolbar
2
+
3
+ The bar of actions at the edge of a working surface.
4
+
5
+ - Group: Surfaces
6
+ - Import: `import { Toolbar } from '@misoto22/design'`
7
+ - Version: 0.9.0
8
+ - Docs: https://ui.misoto22.com/components/toolbar/
9
+ - Related: button, app-shell, card
10
+
11
+ ## When to reach for it
12
+
13
+ A form’s actions that must stay in reach while the form scrolls, or a filter bar over a list. Not a page header — that is AppShell.
14
+
15
+ ## Anatomy
16
+
17
+ - **Bar** (required) — A <div role="group"> named by label, wrapping its children on a flex row at --z-sticky. It is not role="toolbar": that role promises a single tab stop with arrow keys between the controls, and this implements no such thing.
18
+ - **Ground** (required) — Opaque --paper, and deliberately not a blur. Content scrolls UNDER this bar, so anything translucent puts the last row of a table behind the submit button and makes both unreadable.
19
+ - **Edge** (required) — A --rule-2 hairline on the side the bar sticks to: border-t for bottom, border-b for top. position="static" keeps the rule and drops the stickiness.
20
+ - **Actions** (required) — children, on a flex-wrap row with a --gap of 3. align places them along the inline axis and defaults to end, which is where a form’s primary action goes.
21
+
22
+ ## Best practices
23
+
24
+ ### Do
25
+
26
+ - Write label as what the bar IS — "Form actions", "List filters". A group with no name is announced as "group", and a page with two of them announces the same nothing twice.
27
+ - Give the scrolling ancestor a height for position="bottom". A sticky element sticks within its scroll container, so a bar inside a container that is as tall as its content has nothing to stick to and simply sits at the end.
28
+ - Keep it to the actions. A bar that has grown a title, a status and a breadcrumb is a page header, and a page header that follows the reader down the screen is a page with less of itself visible.
29
+
30
+ ### Don’t
31
+
32
+ - Do not add role="toolbar" through props. The role tells a screen-reader user that arrow keys move between the controls; nothing here implements roving tabindex, so those keys would do nothing and the promise would be false.
33
+ - Do not make the ground translucent to "let the content show through". The content it would show through is the row the reader is trying to read, and the button they are trying to press.
34
+
35
+ ## Accessibility
36
+
37
+ - label is required and becomes the group’s accessible name, so a page with a filter bar and an action bar announces two distinct things.
38
+ - Every control keeps its own place in the tab order, because the bar deliberately does not claim role="toolbar" and its single-tab-stop contract.
39
+ - The ground is opaque, so a control on the bar always meets its contrast ratio against --paper rather than against whatever happens to be scrolling behind it.
40
+
41
+ ## Keyboard
42
+
43
+ - Tab — Reaches each control in turn — the bar itself is not a stop.
44
+
45
+ ## Toolbar
46
+
47
+ The bar of actions at the edge of a working surface. Two page templates built the same thing independently — a sticky strip on `--paper` with a rule along the edge it sticks to — which is the signal that it belongs here rather than in each of them. The ground is opaque `--paper` and not a blur. Content scrolls UNDER this bar, so anything translucent puts the last row of a table behind the submit button and makes both unreadable; `FloatingIconButton` blurs because it floats over a gap, which is a different problem. It is not `role="toolbar"`. That role's contract is a single tab stop with arrow keys moving between the controls inside it, and this implements no such thing — declaring the role without the behaviour tells a screen-reader user to press arrow keys that do nothing. It is a named `group`, so the controls keep their own places in the tab order and the bar is still announced.
48
+
49
+ ### Props
50
+
51
+ - `label` (required) — `string`. Names the bar for a screen reader — "Form actions", "List filters". Required, because a group with no name is announced as "group" and a page with two of them is a page with two identical announcements.
52
+ - `position` — `ToolbarPosition` default `'bottom'`. Which edge the bar sticks to. See ToolbarPosition.
53
+ - `align` — `ToolbarAlign` default `'end'`. Where the contents sit along the inline axis.
54
+ - `children` (required) — `ReactNode`.
55
+
56
+ Also accepts: `HTMLAttributes<HTMLDivElement>`.
57
+
58
+ ## Types
59
+
60
+ - `ToolbarPosition` = `'bottom' | 'top' | 'static'`
61
+ - `ToolbarAlign` = `'start' | 'center' | 'end' | 'between'`
62
+
63
+ ## Examples
64
+
65
+ ```tsx
66
+ <Toolbar label="Form actions">
67
+ <Button variant="secondary">Cancel</Button>
68
+ <Button type="submit">Save changes</Button>
69
+ </Toolbar>
70
+ <Toolbar label="List filters" position="top" align="between">…</Toolbar>
71
+ ```
@@ -4,7 +4,7 @@ A short label on hover and on focus.
4
4
 
5
5
  - Group: Overlays
6
6
  - Import: `import { Tooltip } from '@misoto22/design'`
7
- - Version: 0.7.0
7
+ - Version: 0.9.0
8
8
  - Docs: https://ui.misoto22.com/components/tooltip/
9
9
  - Related: dialog
10
10
 
@@ -12,6 +12,28 @@ A short label on hover and on focus.
12
12
 
13
13
  Never for anything the reader NEEDS: a tooltip is unreachable on touch and invisible while scanning.
14
14
 
15
+ ## Anatomy
16
+
17
+ - **Provider** (required) — TooltipProvider, wrapped once around the app or the smallest subtree that has tooltips. It holds the shared 700ms open delay and the 300ms skip window; Radix throws without it rather than rendering an untimed tip.
18
+ - **Trigger** (required) — children, handed to Radix with asChild — so the child IS the trigger and no wrapper is inserted around it.
19
+ - **Tip** (required) — content, in the portalled panel: 11px mono on --feature-surface, capped at 16rem, 6px off the chosen side, at --z-toast (300) so it stays above a modal it was opened inside.
20
+ - **Portal** — Where the tip lands — document.body, or the element an enclosing OverlayContainer names, which is also the box it collides against with 8px of padding.
21
+
22
+ ## Best practices
23
+
24
+ ### Do
25
+
26
+ - Put the Provider high and put one there. Radix throws without it, and a provider per tooltip defeats the shared timing that stops a row of icon buttons flashing a separate tip on every hover.
27
+ - Match the tip to the control’s aria-label word for word: two different names for one control is the “label in name” failure (WCAG 2.5.3), and a voice-control user says the words they can see.
28
+ - Keep the tip to a phrase. It is capped at 16rem and set in 11px mono, so a sentence wraps into a five-line block that covers the thing it was describing.
29
+ - Put it on a control that already works without it: Radix returns early when the pointer type is touch, so the tip never opens on a phone at all and anything it is the sole carrier of is simply missing there.
30
+
31
+ ### Don’t
32
+
33
+ - delayDuration={0} does not just make it faster — the state becomes instant-open rather than delayed-open, and the fade is keyed to delayed-open, so the tip appears with no transition at all.
34
+ - Setting delayDuration on one Tooltip overrides the provider for that trigger alone, which is how a toolbar ends up with one tip that appears instantly beside neighbours at 700ms — read as lag, not as emphasis.
35
+ - Nothing focusable belongs in content: the tip is not in the tab order and closes when the trigger loses focus, so a link or a button in there is reachable by pointer and by nothing else. That is a Popover.
36
+
15
37
  ## Accessibility
16
38
 
17
39
  - Inside a bounded frame — a device preview, an embedded console — wrap the subtree in `<OverlayContainer container={el}>`. The panel then renders into that element and collides with its edges instead of the viewport’s, and inherits the `dir` and `data-density` set there.
@@ -4,7 +4,7 @@ Part of a whole, when the whole has too many parts for a pie — and the parts n
4
4
 
5
5
  - Group: Charts
6
6
  - Import: `import { TreemapChart } from '@misoto22/design/charts'`
7
- - Version: 0.7.0
7
+ - Version: 0.9.0
8
8
  - Docs: https://ui.misoto22.com/components/treemap-chart/
9
9
  - Related: pie-chart, bar-chart
10
10
 
@@ -12,6 +12,28 @@ Part of a whole, when the whole has too many parts for a pie — and the parts n
12
12
 
13
13
  Fifty items where a pie fails at six. Under a dozen items with a ranking to read, a BarChart’s length is the more precise encoding.
14
14
 
15
+ ## Anatomy
16
+
17
+ - **Figure frame** (required) — ChartFigure’s <figure>, named by title, wrapping one ChartContainer.
18
+ - **Tiles** (required) — The root’s own tile renderer. The gap between tiles is a 2px --chart-surface STROKE rather than a smaller rect, so the tiles still tile — a treemap whose parts do not touch stops reading as a partition of one whole.
19
+ - **Tile labels** — showLabels, on by default, but a tile is only labelled when it is wider than 56px and taller than 26px. Below that the name is dropped rather than clipped, so the long tail is unlabelled by design.
20
+ - **Tooltip** — <TreemapChart.Tooltip>, keyed on the tile name. It is doing more work here than elsewhere: it is the only way to name a tile too small to carry its own label.
21
+ - **Hidden data table** (required) — The sr-only table lists the LEAVES, each with the path that names it. A nested tree read row by row is not something anyone can follow, so the hierarchy is flattened into the row header instead.
22
+ - **Paint** — variant="ramp" walks --series-1 to --series-8 by tile INDEX; variant="nested" steps by DEPTH instead, which is the right encoding once the question is what is inside what.
23
+
24
+ ## Best practices
25
+
26
+ ### Do
27
+
28
+ - Feed it non-negative values that sum to something the reader recognises as the whole. Area is the encoding, an area cannot be negative, and a leaf at zero or below is laid out at zero width and dropped from the picture — the hidden table prints it as “not drawn” rather than letting the two views disagree about how many leaves there are.
29
+ - Compose <TreemapChart.Tooltip> whenever there is a tail. Anything under 56 by 26 pixels carries no label at all, and on a fifty-item treemap that is most of it.
30
+ - Switch to variant="nested" once the tree has a second level. ramp keys the fill off the tile index, so it separates siblings and says nothing at all about depth.
31
+
32
+ ### Don’t
33
+
34
+ - Do not read the ramp as a key. The slot is index modulo eight, so tile one and tile nine are painted identically — the fill here is separation, not identity, and the picture will not correct a reader who assumes otherwise.
35
+ - Do not reach for it to rank a dozen items. A bar’s length is read far more precisely than a rectangle’s area, and the squarify layout deliberately does not order tiles by value alone, so a reader cannot even scan them in order.
36
+
15
37
  ## Accessibility
16
38
 
17
39
  - title is required. The table view lists the LEAVES with the path that names them: a nested tree read row by row is not something anyone can follow.
@@ -37,6 +59,7 @@ Part of a whole, when the whole has too many parts for a pie — and the parts n
37
59
  - `children` — `ReactNode`. The hover panel.
38
60
  - `chartProps` — `TreemapExtras`.
39
61
  - `hideDataTable` — `boolean` default `false`. Drops the hidden table view. Only correct when the page prints the data itself.
62
+ - `empty` — `ChartEmptyProps | false`. What the chart shows when it has nothing to draw. `false` keeps the empty plot, for a chart whose emptiness is itself the reading.
40
63
 
41
64
  ## Types
42
65