@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
@@ -3,12 +3,16 @@ import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { Label } from "@radix-ui/react-label";
4
4
  import { cloneElement, isValidElement, useId } from "react";
5
5
  import { cn } from "../../lib/cn.js";
6
+ import { DEV, warn } from "../../lib/warn.js";
7
+ import { FieldControlProvider } from "./field-control.js";
6
8
  function Field({
7
9
  label,
8
10
  htmlFor,
11
+ description,
9
12
  hint,
10
13
  error,
11
14
  required,
15
+ layout = "stacked",
12
16
  children,
13
17
  className,
14
18
  ...rest
@@ -17,33 +21,70 @@ function Field({
17
21
  const controlId = htmlFor ?? generatedId;
18
22
  const message = error ?? hint;
19
23
  const messageId = message != null ? `${controlId}-${error != null ? "error" : "hint"}` : void 0;
24
+ const descriptionId = description != null ? `${controlId}-description` : void 0;
25
+ const labelId = label != null ? `${controlId}-label` : void 0;
20
26
  let control = children;
21
27
  if (isValidElement(children)) {
22
28
  const child = children;
23
29
  control = cloneElement(child, {
24
30
  id: child.props.id ?? controlId,
25
- "aria-describedby": [child.props["aria-describedby"], messageId].filter(Boolean).join(" ") || void 0,
31
+ "aria-describedby": [child.props["aria-describedby"], descriptionId, messageId].filter(Boolean).join(" ") || void 0,
26
32
  "aria-required": required || child.props["aria-required"] || void 0,
27
33
  "aria-invalid": error != null ? child.props["aria-invalid"] ?? true : child.props["aria-invalid"]
28
34
  });
35
+ } else if (DEV) {
36
+ warn({
37
+ code: "FIELD_CONTROL_NOT_WIRED",
38
+ problem: "Field's child is not a single React element, so the label, aria-describedby, aria-required and aria-invalid were not applied to any control.",
39
+ field: "children",
40
+ fix: "Put exactly one control element directly inside Field. For a row of controls, give each its own Field and lay them out around it.",
41
+ component: "Field"
42
+ });
29
43
  }
30
- return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-1.5", className), ...rest, children: [
31
- label != null && /* @__PURE__ */ jsxs(Label, { htmlFor: controlId, className: "text-sm text-(--ink)", children: [
44
+ if (DEV && isValidElement(children) && typeof children.type === "string") {
45
+ const LABELLABLE = ["input", "select", "textarea", "button", "meter", "output", "progress"];
46
+ if (!LABELLABLE.includes(children.type)) {
47
+ warn({
48
+ code: "FIELD_CONTROL_NOT_LABELLABLE",
49
+ problem: `Field's child is a <${children.type}>, which cannot take a label \u2014 so the id, aria-describedby, aria-required and aria-invalid were applied to it rather than to a control.`,
50
+ field: "children",
51
+ fix: "Put the control itself directly inside Field, with no wrapper. For a row of controls, give each its own Field and lay them out around it.",
52
+ component: "Field"
53
+ });
54
+ }
55
+ }
56
+ const wired = /* @__PURE__ */ jsx(FieldControlProvider, { value: { labelId }, children: control });
57
+ const heading = (label != null || description != null) && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
58
+ label != null && /* @__PURE__ */ jsxs(Label, { id: labelId, htmlFor: controlId, className: "text-sm text-(--ink)", children: [
32
59
  label,
33
60
  required && /* @__PURE__ */ jsxs("span", { className: "text-(--danger)", "aria-hidden": "true", children: [
34
61
  " ",
35
62
  "*"
36
63
  ] })
37
64
  ] }),
38
- control,
39
- message != null && /* @__PURE__ */ jsx(
40
- "p",
41
- {
42
- id: messageId,
43
- className: cn("m-0 text-xs", error != null ? "text-(--danger)" : "text-(--ink-3-aa)"),
44
- children: message
45
- }
46
- )
65
+ description != null && /* @__PURE__ */ jsx("p", { id: descriptionId, className: "m-0 text-xs text-(--ink-3-aa)", children: description })
66
+ ] });
67
+ const note = message != null && /* @__PURE__ */ jsx(
68
+ "p",
69
+ {
70
+ id: messageId,
71
+ className: cn("m-0 text-xs", error != null ? "text-(--danger)" : "text-(--ink-3-aa)"),
72
+ children: message
73
+ }
74
+ );
75
+ if (layout === "row") {
76
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-1.5", className), ...rest, children: [
77
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-6", children: [
78
+ /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children: heading }),
79
+ /* @__PURE__ */ jsx("div", { className: "shrink-0", children: wired })
80
+ ] }),
81
+ note
82
+ ] });
83
+ }
84
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-1.5", className), ...rest, children: [
85
+ heading,
86
+ wired,
87
+ note
47
88
  ] });
48
89
  }
49
90
  var Field_default = Field;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/Field/Field.tsx"],"sourcesContent":["'use client'\n\nimport { Label } from '@radix-ui/react-label'\nimport { cloneElement, isValidElement, useId } from 'react'\nimport type { HTMLAttributes, ReactElement, ReactNode } from 'react'\nimport { cn } from '../../lib/cn'\n\nexport interface FieldProps extends HTMLAttributes<HTMLDivElement> {\n /** Visible label text; renders a `--danger` asterisk when `required`. */\n label?: ReactNode\n /**\n * The control's `id`. Optional: when omitted, the field generates one and\n * puts it on the control child itself, so the label still points at\n * something. Pass it explicitly when the id has to be stable across renders\n * — a form library referencing it by name, say.\n */\n htmlFor?: string\n /** Helper copy shown below the control when there is no `error`. */\n hint?: ReactNode\n /** Validation message; takes precedence over `hint` when present. */\n error?: ReactNode\n required?: boolean\n children: ReactNode\n}\n\ntype WirableControl = ReactElement<{\n id?: string\n 'aria-describedby'?: string\n 'aria-required'?: boolean\n 'aria-invalid'?: boolean | 'true' | 'false'\n}>\n\n/**\n * A labelled form row: label, control, and the one message below it.\n *\n * The visible message is only half of accessible validation — it must also\n * reach the control. This wires `aria-describedby`, `aria-required` and\n * `aria-invalid` onto the single control child so the requirement and the error\n * are announced, not merely drawn (WCAG 1.3.1 / 3.3.1 / 4.1.2).\n *\n * An earlier version derived the message id from `htmlFor`, which meant a\n * caller who left `htmlFor` off got a hint that was rendered and never\n * announced — the failure was invisible in the browser and total for a screen\n * reader. The id is now generated when it is not supplied.\n *\n * `hint` and `error` are one slot, not two stacked messages: when a field is\n * wrong, the thing to read is what is wrong with it.\n *\n * @example\n * <Field label=\"Email\" required hint=\"We never share it.\"><Input type=\"email\" /></Field>\n * @example\n * <Field label=\"Name\" error=\"Name is required.\"><Input /></Field>\n */\nexport function Field({\n label,\n htmlFor,\n hint,\n error,\n required,\n children,\n className,\n ...rest\n}: FieldProps) {\n const generatedId = useId()\n const controlId = htmlFor ?? generatedId\n const message = error ?? hint\n const messageId = message != null ? `${controlId}-${error != null ? 'error' : 'hint'}` : undefined\n\n let control = children\n if (isValidElement(children)) {\n const child = children as WirableControl\n control = cloneElement(child, {\n id: child.props.id ?? controlId,\n 'aria-describedby':\n [child.props['aria-describedby'], messageId].filter(Boolean).join(' ') || undefined,\n 'aria-required': required || child.props['aria-required'] || undefined,\n 'aria-invalid':\n error != null ? (child.props['aria-invalid'] ?? true) : child.props['aria-invalid'],\n })\n }\n\n return (\n <div className={cn('flex flex-col gap-1.5', className)} {...rest}>\n {label != null && (\n <Label htmlFor={controlId} className=\"text-sm text-(--ink)\">\n {label}\n {required && (\n <span className=\"text-(--danger)\" aria-hidden=\"true\">\n {' '}\n *\n </span>\n )}\n </Label>\n )}\n {control}\n {message != null && (\n <p\n id={messageId}\n className={cn('m-0 text-xs', error != null ? 'text-(--danger)' : 'text-(--ink-3-aa)')}\n >\n {message}\n </p>\n )}\n </div>\n )\n}\n\nexport default Field\n"],"mappings":";AAuFY,SASJ,KATI;AArFZ,SAAS,aAAa;AACtB,SAAS,cAAc,gBAAgB,aAAa;AAEpD,SAAS,UAAU;AAgDZ,SAAS,MAAM;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAe;AACb,QAAM,cAAc,MAAM;AAC1B,QAAM,YAAY,WAAW;AAC7B,QAAM,UAAU,SAAS;AACzB,QAAM,YAAY,WAAW,OAAO,GAAG,SAAS,IAAI,SAAS,OAAO,UAAU,MAAM,KAAK;AAEzF,MAAI,UAAU;AACd,MAAI,eAAe,QAAQ,GAAG;AAC5B,UAAM,QAAQ;AACd,cAAU,aAAa,OAAO;AAAA,MAC5B,IAAI,MAAM,MAAM,MAAM;AAAA,MACtB,oBACE,CAAC,MAAM,MAAM,kBAAkB,GAAG,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,KAAK;AAAA,MAC5E,iBAAiB,YAAY,MAAM,MAAM,eAAe,KAAK;AAAA,MAC7D,gBACE,SAAS,OAAQ,MAAM,MAAM,cAAc,KAAK,OAAQ,MAAM,MAAM,cAAc;AAAA,IACtF,CAAC;AAAA,EACH;AAEA,SACE,qBAAC,SAAI,WAAW,GAAG,yBAAyB,SAAS,GAAI,GAAG,MACzD;AAAA,aAAS,QACR,qBAAC,SAAM,SAAS,WAAW,WAAU,wBAClC;AAAA;AAAA,MACA,YACC,qBAAC,UAAK,WAAU,mBAAkB,eAAY,QAC3C;AAAA;AAAA,QAAI;AAAA,SAEP;AAAA,OAEJ;AAAA,IAED;AAAA,IACA,WAAW,QACV;AAAA,MAAC;AAAA;AAAA,QACC,IAAI;AAAA,QACJ,WAAW,GAAG,eAAe,SAAS,OAAO,oBAAoB,mBAAmB;AAAA,QAEnF;AAAA;AAAA,IACH;AAAA,KAEJ;AAEJ;AAEA,IAAO,gBAAQ;","names":[]}
1
+ {"version":3,"sources":["../../../src/components/Field/Field.tsx"],"sourcesContent":["'use client'\n\nimport { Label } from '@radix-ui/react-label'\nimport { cloneElement, isValidElement, useId } from 'react'\nimport type { HTMLAttributes, ReactElement, ReactNode } from 'react'\nimport { cn } from '../../lib/cn'\nimport { DEV, warn } from '../../lib/warn'\nimport { FieldControlProvider } from './field-control'\n\n/**\n * Where the control sits relative to its label.\n *\n * `stacked` is the form row: label, control, message, down the page.\n *\n * `row` is the settings row: the label and its `description` in a column at the\n * inline start, the control at the inline end, one rhythm down a settings\n * screen. It is a layout, not a second component — the label wiring, the\n * required marker and the message slot are the same three things either way,\n * and a `SettingRow` beside this would be all three of them written twice.\n */\nexport type FieldLayout = 'stacked' | 'row'\n\nexport interface FieldProps extends HTMLAttributes<HTMLDivElement> {\n /** Visible label text; renders a `--danger` asterisk when `required`. */\n label?: ReactNode\n /**\n * The control's `id`. Optional: when omitted, the field generates one and\n * puts it on the control child itself, so the label still points at\n * something. Pass it explicitly when the id has to be stable across renders\n * — a form library referencing it by name, say.\n */\n htmlFor?: string\n /**\n * A second line under the LABEL, explaining what the setting does.\n *\n * Distinct from `hint`, which sits under the control and belongs to the input\n * — \"We never share it\". This belongs to the thing being switched on, and it\n * is what makes a settings row a settings row. Both reach the control through\n * `aria-describedby`, so a row that has a description and an error announces\n * both.\n */\n description?: ReactNode\n /** Helper copy shown below the control when there is no `error`. */\n hint?: ReactNode\n /** Validation message; takes precedence over `hint` when present. */\n error?: ReactNode\n required?: boolean\n /** Where the control sits relative to its label. See {@link FieldLayout}. */\n layout?: FieldLayout\n children: ReactNode\n}\n\ntype WirableControl = ReactElement<{\n id?: string\n 'aria-describedby'?: string\n 'aria-required'?: boolean\n 'aria-invalid'?: boolean | 'true' | 'false'\n}>\n\n/**\n * A labelled form row: label, control, and the one message below it.\n *\n * The visible message is only half of accessible validation — it must also\n * reach the control. This wires `aria-describedby`, `aria-required` and\n * `aria-invalid` onto the single control child so the requirement and the error\n * are announced, not merely drawn (WCAG 1.3.1 / 3.3.1 / 4.1.2).\n *\n * An earlier version derived the message id from `htmlFor`, which meant a\n * caller who left `htmlFor` off got a hint that was rendered and never\n * announced — the failure was invisible in the browser and total for a screen\n * reader. The id is now generated when it is not supplied.\n *\n * `hint` and `error` are one slot, not two stacked messages: when a field is\n * wrong, the thing to read is what is wrong with it. `description` is a\n * different slot again — it explains the SETTING, not the input, and it is what\n * `layout=\"row\"` puts under the label to make a settings row.\n *\n * **How the wiring reaches the control.** `cloneElement` puts the four\n * attributes on the single child, and each control forwards them to whatever\n * element carries the role — which is the child itself for `Input`, `Textarea`,\n * `NativeSelect`, `Checkbox`, `Switch` and any host element written by hand, and\n * a trigger, a group or a thumb further down for `Select`, `Combobox`,\n * `DatePicker`, `Slider`, `RadioGroup` and `ToggleGroup`. The composites used to\n * drop them on the floor, which drew a hint under a control that never announced\n * it; a wrapper that appears to wire things up and does not is worse than one\n * that never claimed to.\n *\n * The label's own id travels separately, through context, because a name is the\n * one thing a prop cannot carry: a trigger whose text is its VALUE is named by\n * the label AND by itself, so `<Field label=\"Region\"><Select/></Field>`\n * announces \"Region, Australia\" rather than either half.\n *\n * Three things stay out of reach, and each of them is the control's own markup\n * rather than a gap in this wiring. A `<label for>` binds only to a labellable\n * element, so the words do not click through to a `RadioGroup`, a `ToggleGroup`\n * or a `Slider`: the first two are a `role=\"radiogroup\"` named by pointing back\n * at the label instead, exactly as a `<legend>` is, and the third carries\n * `role=\"slider\"` on a thumb below a roleless root. `required` reaches a control\n * as `aria-required`, which `DatePicker`'s plain `<button>` trigger and a\n * multiple-value `ToggleGroup`'s `role=\"toolbar\"` have nowhere to put; there the\n * asterisk is the only marker. And `aria-invalid` reaches `Slider`'s root rather\n * than its thumb, so an errored slider is drawn wrong without being announced\n * wrong.\n *\n * Each composite still takes its own `label` prop — that is what names it\n * standing outside a field, and `Select`, `Combobox` and `DatePicker` warn when\n * it is blank. It is no longer used INSTEAD of this one's.\n *\n * What no wiring can reach, the field says out loud in development rather than\n * failing silently: `FIELD_CONTROL_NOT_LABELLABLE` when the child is a host\n * element a label cannot bind to — the `<div>` wrapper that takes the id and\n * leaves the control inside it with nothing — and `FIELD_CONTROL_NOT_WIRED`\n * when there is no single element to wire at all.\n *\n * @example\n * <Field label=\"Email\" required hint=\"We never share it.\"><Input type=\"email\" /></Field>\n * @example\n * <Field label=\"Name\" error=\"Name is required.\"><Input /></Field>\n * @example\n * <Field layout=\"row\" label=\"Email notifications\" description=\"A digest every Monday.\">\n * <Switch defaultChecked />\n * </Field>\n */\nexport function Field({\n label,\n htmlFor,\n description,\n hint,\n error,\n required,\n layout = 'stacked',\n children,\n className,\n ...rest\n}: FieldProps) {\n const generatedId = useId()\n const controlId = htmlFor ?? generatedId\n const message = error ?? hint\n const messageId = message != null ? `${controlId}-${error != null ? 'error' : 'hint'}` : undefined\n const descriptionId = description != null ? `${controlId}-description` : undefined\n const labelId = label != null ? `${controlId}-label` : undefined\n\n let control = children\n if (isValidElement(children)) {\n const child = children as WirableControl\n control = cloneElement(child, {\n id: child.props.id ?? controlId,\n 'aria-describedby':\n [child.props['aria-describedby'], descriptionId, messageId].filter(Boolean).join(' ') ||\n undefined,\n 'aria-required': required || child.props['aria-required'] || undefined,\n 'aria-invalid':\n error != null ? (child.props['aria-invalid'] ?? true) : child.props['aria-invalid'],\n })\n } else if (DEV) {\n warn({\n code: 'FIELD_CONTROL_NOT_WIRED',\n problem:\n \"Field's child is not a single React element, so the label, aria-describedby, aria-required and aria-invalid were not applied to any control.\",\n field: 'children',\n fix: 'Put exactly one control element directly inside Field. For a row of controls, give each its own Field and lay them out around it.',\n component: 'Field',\n })\n }\n\n if (DEV && isValidElement(children) && typeof children.type === 'string') {\n // A wrapper is the failure this exists for, and it is the one that looks\n // most correct: `<Field><div><Input /></div></Field>` renders, and the\n // label points at the DIV. The id, the describedby and the invalid state\n // all land on a box, the control inside gets none of them, and a browser\n // shows nothing wrong.\n //\n // Narrowed to HOST elements because that is the half that can be decided:\n // a lowercase tag either takes a label or it does not. A function component\n // might forward its props to a real control, and warning on those would\n // fire on every correct use of Input, Select and the rest.\n const LABELLABLE = ['input', 'select', 'textarea', 'button', 'meter', 'output', 'progress']\n if (!LABELLABLE.includes(children.type)) {\n warn({\n code: 'FIELD_CONTROL_NOT_LABELLABLE',\n problem: `Field's child is a <${children.type}>, which cannot take a label — so the id, aria-describedby, aria-required and aria-invalid were applied to it rather than to a control.`,\n field: 'children',\n fix: 'Put the control itself directly inside Field, with no wrapper. For a row of controls, give each its own Field and lay them out around it.',\n component: 'Field',\n })\n }\n }\n\n // The label's id, for the controls that have to name themselves from it —\n // everything else the field decided is already on the cloned child.\n const wired = <FieldControlProvider value={{ labelId }}>{control}</FieldControlProvider>\n\n const heading = (label != null || description != null) && (\n <div className=\"flex flex-col gap-1\">\n {label != null && (\n <Label id={labelId} htmlFor={controlId} className=\"text-sm text-(--ink)\">\n {label}\n {required && (\n <span className=\"text-(--danger)\" aria-hidden=\"true\">\n {' '}\n *\n </span>\n )}\n </Label>\n )}\n {description != null && (\n <p id={descriptionId} className=\"m-0 text-xs text-(--ink-3-aa)\">\n {description}\n </p>\n )}\n </div>\n )\n\n const note = message != null && (\n <p\n id={messageId}\n className={cn('m-0 text-xs', error != null ? 'text-(--danger)' : 'text-(--ink-3-aa)')}\n >\n {message}\n </p>\n )\n\n if (layout === 'row') {\n return (\n <div className={cn('flex flex-col gap-1.5', className)} {...rest}>\n {/* `items-start` and not `items-center`: a description of two lines\n would otherwise drag the switch down to the middle of the paragraph,\n and a column of settings rows would have its controls on five\n different lines. */}\n <div className=\"flex items-start justify-between gap-6\">\n <div className=\"min-w-0 flex-1\">{heading}</div>\n <div className=\"shrink-0\">{wired}</div>\n </div>\n {note}\n </div>\n )\n }\n\n return (\n <div className={cn('flex flex-col gap-1.5', className)} {...rest}>\n {heading}\n {wired}\n {note}\n </div>\n )\n}\n\nexport default Field\n"],"mappings":";AA8LgB,cAQJ,YARI;AA5LhB,SAAS,aAAa;AACtB,SAAS,cAAc,gBAAgB,aAAa;AAEpD,SAAS,UAAU;AACnB,SAAS,KAAK,YAAY;AAC1B,SAAS,4BAA4B;AAoH9B,SAAS,MAAM;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAS;AAAA,EACT;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAe;AACb,QAAM,cAAc,MAAM;AAC1B,QAAM,YAAY,WAAW;AAC7B,QAAM,UAAU,SAAS;AACzB,QAAM,YAAY,WAAW,OAAO,GAAG,SAAS,IAAI,SAAS,OAAO,UAAU,MAAM,KAAK;AACzF,QAAM,gBAAgB,eAAe,OAAO,GAAG,SAAS,iBAAiB;AACzE,QAAM,UAAU,SAAS,OAAO,GAAG,SAAS,WAAW;AAEvD,MAAI,UAAU;AACd,MAAI,eAAe,QAAQ,GAAG;AAC5B,UAAM,QAAQ;AACd,cAAU,aAAa,OAAO;AAAA,MAC5B,IAAI,MAAM,MAAM,MAAM;AAAA,MACtB,oBACE,CAAC,MAAM,MAAM,kBAAkB,GAAG,eAAe,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,KACpF;AAAA,MACF,iBAAiB,YAAY,MAAM,MAAM,eAAe,KAAK;AAAA,MAC7D,gBACE,SAAS,OAAQ,MAAM,MAAM,cAAc,KAAK,OAAQ,MAAM,MAAM,cAAc;AAAA,IACtF,CAAC;AAAA,EACH,WAAW,KAAK;AACd,SAAK;AAAA,MACH,MAAM;AAAA,MACN,SACE;AAAA,MACF,OAAO;AAAA,MACP,KAAK;AAAA,MACL,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,MAAI,OAAO,eAAe,QAAQ,KAAK,OAAO,SAAS,SAAS,UAAU;AAWxE,UAAM,aAAa,CAAC,SAAS,UAAU,YAAY,UAAU,SAAS,UAAU,UAAU;AAC1F,QAAI,CAAC,WAAW,SAAS,SAAS,IAAI,GAAG;AACvC,WAAK;AAAA,QACH,MAAM;AAAA,QACN,SAAS,uBAAuB,SAAS,IAAI;AAAA,QAC7C,OAAO;AAAA,QACP,KAAK;AAAA,QACL,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAAA,EACF;AAIA,QAAM,QAAQ,oBAAC,wBAAqB,OAAO,EAAE,QAAQ,GAAI,mBAAQ;AAEjE,QAAM,WAAW,SAAS,QAAQ,eAAe,SAC/C,qBAAC,SAAI,WAAU,uBACZ;AAAA,aAAS,QACR,qBAAC,SAAM,IAAI,SAAS,SAAS,WAAW,WAAU,wBAC/C;AAAA;AAAA,MACA,YACC,qBAAC,UAAK,WAAU,mBAAkB,eAAY,QAC3C;AAAA;AAAA,QAAI;AAAA,SAEP;AAAA,OAEJ;AAAA,IAED,eAAe,QACd,oBAAC,OAAE,IAAI,eAAe,WAAU,iCAC7B,uBACH;AAAA,KAEJ;AAGF,QAAM,OAAO,WAAW,QACtB;AAAA,IAAC;AAAA;AAAA,MACC,IAAI;AAAA,MACJ,WAAW,GAAG,eAAe,SAAS,OAAO,oBAAoB,mBAAmB;AAAA,MAEnF;AAAA;AAAA,EACH;AAGF,MAAI,WAAW,OAAO;AACpB,WACE,qBAAC,SAAI,WAAW,GAAG,yBAAyB,SAAS,GAAI,GAAG,MAK1D;AAAA,2BAAC,SAAI,WAAU,0CACb;AAAA,4BAAC,SAAI,WAAU,kBAAkB,mBAAQ;AAAA,QACzC,oBAAC,SAAI,WAAU,YAAY,iBAAM;AAAA,SACnC;AAAA,MACC;AAAA,OACH;AAAA,EAEJ;AAEA,SACE,qBAAC,SAAI,WAAW,GAAG,yBAAyB,SAAS,GAAI,GAAG,MACzD;AAAA;AAAA,IACA;AAAA,IACA;AAAA,KACH;AAEJ;AAEA,IAAO,gBAAQ;","names":[]}
@@ -0,0 +1,31 @@
1
+ import * as react from 'react';
2
+
3
+ /**
4
+ * The one thing a `Field` cannot hand its control as a prop: where its label is.
5
+ *
6
+ * Everything else the field decides — the id, `aria-describedby`,
7
+ * `aria-required`, `aria-invalid` — travels as props on the cloned child, and a
8
+ * control that swallowed them was simply not forwarding them to the element
9
+ * that carries the role. That is a bug in the control, not a missing channel.
10
+ *
11
+ * A NAME is different. A trigger whose text is its value has to be named by the
12
+ * label AND by itself, which is two ids in one `aria-labelledby`; a group has to
13
+ * point BACK at the label, because `<label for>` does not bind to a
14
+ * `role="radiogroup"`. Neither can be expressed by a value the field computes on
15
+ * its own, so the label's id is published here and the control assembles the
16
+ * rest.
17
+ */
18
+ interface FieldControl {
19
+ /** The label element's id, or undefined when the field has no label. */
20
+ labelId?: string;
21
+ }
22
+ declare const FieldControlProvider: react.Provider<FieldControl | null>;
23
+ /**
24
+ * The enclosing `Field`'s label, if there is one.
25
+ *
26
+ * Null is a supported state, not a failure: every control here works outside a
27
+ * field, and each names itself from its own `label` prop when it must.
28
+ */
29
+ declare function useFieldControl(): FieldControl | null;
30
+
31
+ export { type FieldControl, FieldControlProvider, useFieldControl };
@@ -0,0 +1,12 @@
1
+ "use client";
2
+ import { createContext, useContext } from "react";
3
+ const FieldControlContext = createContext(null);
4
+ const FieldControlProvider = FieldControlContext.Provider;
5
+ function useFieldControl() {
6
+ return useContext(FieldControlContext);
7
+ }
8
+ export {
9
+ FieldControlProvider,
10
+ useFieldControl
11
+ };
12
+ //# sourceMappingURL=field-control.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/Field/field-control.ts"],"sourcesContent":["'use client'\n\nimport { createContext, useContext } from 'react'\n\n/**\n * The one thing a `Field` cannot hand its control as a prop: where its label is.\n *\n * Everything else the field decides — the id, `aria-describedby`,\n * `aria-required`, `aria-invalid` — travels as props on the cloned child, and a\n * control that swallowed them was simply not forwarding them to the element\n * that carries the role. That is a bug in the control, not a missing channel.\n *\n * A NAME is different. A trigger whose text is its value has to be named by the\n * label AND by itself, which is two ids in one `aria-labelledby`; a group has to\n * point BACK at the label, because `<label for>` does not bind to a\n * `role=\"radiogroup\"`. Neither can be expressed by a value the field computes on\n * its own, so the label's id is published here and the control assembles the\n * rest.\n */\nexport interface FieldControl {\n /** The label element's id, or undefined when the field has no label. */\n labelId?: string\n}\n\nconst FieldControlContext = createContext<FieldControl | null>(null)\n\nexport const FieldControlProvider = FieldControlContext.Provider\n\n/**\n * The enclosing `Field`'s label, if there is one.\n *\n * Null is a supported state, not a failure: every control here works outside a\n * field, and each names itself from its own `label` prop when it must.\n */\nexport function useFieldControl(): FieldControl | null {\n return useContext(FieldControlContext)\n}\n"],"mappings":";AAEA,SAAS,eAAe,kBAAkB;AAsB1C,MAAM,sBAAsB,cAAmC,IAAI;AAE5D,MAAM,uBAAuB,oBAAoB;AAQjD,SAAS,kBAAuC;AACrD,SAAO,WAAW,mBAAmB;AACvC;","names":[]}
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { jsx } from "react/jsx-runtime";
3
3
  import { cn } from "../../lib/cn.js";
4
+ import { warnBlankName } from "../../lib/warn.js";
4
5
  const POSITION_CLASS = { start: "bottom-20 start-6", end: "bottom-6 end-6" };
5
6
  function FloatingIconButton({
6
7
  position,
@@ -9,6 +10,7 @@ function FloatingIconButton({
9
10
  className,
10
11
  ...rest
11
12
  }) {
13
+ warnBlankName("FloatingIconButton", "label", label, 'the button is announced as "button" and nothing else');
12
14
  return /* @__PURE__ */ jsx(
13
15
  "button",
14
16
  {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/FloatingIconButton/FloatingIconButton.tsx"],"sourcesContent":["'use client'\n\nimport type { ButtonHTMLAttributes, ReactNode } from 'react'\nimport { cn } from '../../lib/cn'\n\nexport interface FloatingIconButtonProps\n extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'children'> {\n /**\n * Which bottom corner the control is pinned to, in READING order —\n * `end` is the right in English and the left in Arabic. Naming the sides\n * `left`/`right` would have hard-coded one script's layout into the API.\n */\n position: 'start' | 'end'\n /** Accessible name — the button has no visible text, so this is its only name. */\n label: string\n children: ReactNode\n}\n\n/**\n * Full literal class strings per corner. Tailwind only generates classes it can\n * see verbatim in the source, so the side is never interpolated into a string.\n *\n * The start corner sits higher: browser and OS chrome (a download shelf, a\n * status toast) commonly occupies the corner where reading begins, and the\n * global scroll action keeps the far one.\n */\nconst POSITION_CLASS = { start: 'bottom-20 start-6', end: 'bottom-6 end-6' } as const\n\n/**\n * A round action pinned to a screen corner.\n *\n * A translucent paper ground with a backdrop blur rather than a drop shadow —\n * the White Reset has no elevation ramp, so what separates the control from\n * the page under it is the blur and the hairline, not a glow.\n *\n * @example\n * <FloatingIconButton position=\"right\" label=\"Back to top\" onClick={scrollUp}>\n * <ArrowUp size={16} />\n * </FloatingIconButton>\n */\nexport function FloatingIconButton({\n position,\n label,\n children,\n className,\n ...rest\n}: FloatingIconButtonProps) {\n return (\n <button\n type=\"button\"\n aria-label={label}\n className={cn(\n 'fixed z-(--z-drawer) flex size-(--control-h-md) items-center justify-center rounded-(--radius-pill) border border-(--rule-2) bg-(--paper)/90 text-(--ink-2) backdrop-blur-sm transition-colors duration-(--duration-fast) hover:border-(--ink) hover:text-(--ink)',\n POSITION_CLASS[position],\n className,\n )}\n {...rest}\n >\n {children}\n </button>\n )\n}\n\nexport default FloatingIconButton\n"],"mappings":";AAgDI;AA7CJ,SAAS,UAAU;AAuBnB,MAAM,iBAAiB,EAAE,OAAO,qBAAqB,KAAK,iBAAiB;AAcpE,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAA4B;AAC1B,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,cAAY;AAAA,MACZ,WAAW;AAAA,QACT;AAAA,QACA,eAAe,QAAQ;AAAA,QACvB;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEH;AAAA;AAAA,EACH;AAEJ;AAEA,IAAO,6BAAQ;","names":[]}
1
+ {"version":3,"sources":["../../../src/components/FloatingIconButton/FloatingIconButton.tsx"],"sourcesContent":["'use client'\n\nimport type { ButtonHTMLAttributes, ReactNode } from 'react'\nimport { cn } from '../../lib/cn'\nimport { warnBlankName } from '../../lib/warn'\n\nexport interface FloatingIconButtonProps\n extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'children'> {\n /**\n * Which bottom corner the control is pinned to, in READING order —\n * `end` is the right in English and the left in Arabic. Naming the sides\n * `left`/`right` would have hard-coded one script's layout into the API.\n */\n position: 'start' | 'end'\n /** Accessible name — the button has no visible text, so this is its only name. */\n label: string\n children: ReactNode\n}\n\n/**\n * Full literal class strings per corner. Tailwind only generates classes it can\n * see verbatim in the source, so the side is never interpolated into a string.\n *\n * The start corner sits higher: browser and OS chrome (a download shelf, a\n * status toast) commonly occupies the corner where reading begins, and the\n * global scroll action keeps the far one.\n */\nconst POSITION_CLASS = { start: 'bottom-20 start-6', end: 'bottom-6 end-6' } as const\n\n/**\n * A round action pinned to a screen corner.\n *\n * A translucent paper ground with a backdrop blur rather than a drop shadow —\n * the White Reset has no elevation ramp, so what separates the control from\n * the page under it is the blur and the hairline, not a glow.\n *\n * @example\n * <FloatingIconButton position=\"right\" label=\"Back to top\" onClick={scrollUp}>\n * <ArrowUp size={16} />\n * </FloatingIconButton>\n */\nexport function FloatingIconButton({\n position,\n label,\n children,\n className,\n ...rest\n}: FloatingIconButtonProps) {\n warnBlankName('FloatingIconButton', 'label', label, 'the button is announced as \"button\" and nothing else')\n return (\n <button\n type=\"button\"\n aria-label={label}\n className={cn(\n 'fixed z-(--z-drawer) flex size-(--control-h-md) items-center justify-center rounded-(--radius-pill) border border-(--rule-2) bg-(--paper)/90 text-(--ink-2) backdrop-blur-sm transition-colors duration-(--duration-fast) hover:border-(--ink) hover:text-(--ink)',\n POSITION_CLASS[position],\n className,\n )}\n {...rest}\n >\n {children}\n </button>\n )\n}\n\nexport default FloatingIconButton\n"],"mappings":";AAkDI;AA/CJ,SAAS,UAAU;AACnB,SAAS,qBAAqB;AAuB9B,MAAM,iBAAiB,EAAE,OAAO,qBAAqB,KAAK,iBAAiB;AAcpE,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAA4B;AAC1B,gBAAc,sBAAsB,SAAS,OAAO,sDAAsD;AAC1G,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,cAAY;AAAA,MACZ,WAAW;AAAA,QACT;AAAA,QACA,eAAe,QAAQ;AAAA,QACvB;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEH;AAAA;AAAA,EACH;AAEJ;AAEA,IAAO,6BAAQ;","names":[]}
@@ -0,0 +1,62 @@
1
+ import * as react from 'react';
2
+ import { HTMLAttributes, ReactNode } from 'react';
3
+
4
+ type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
5
+ /**
6
+ * A step on the type ladder, named for the thing it heads.
7
+ *
8
+ * `title` is the top and there is nothing above it — a page has exactly one
9
+ * thing larger than its own records. `label` is not on the size ladder at all:
10
+ * it is the mono kicker, which is what a fifth-level heading should look like,
11
+ * because a serif heading three steps down is indistinguishable from bold body
12
+ * copy.
13
+ */
14
+ type HeadingSize = 'title' | 'lead' | 'heading' | 'sub' | 'item' | 'label';
15
+ interface HeadingProps extends HTMLAttributes<HTMLHeadingElement> {
16
+ children?: ReactNode;
17
+ /**
18
+ * The element: `1` renders `<h1>`, `6` renders `<h6>`.
19
+ *
20
+ * This is the document outline and nothing else — it is what a screen reader
21
+ * navigates by, so it follows the section the heading opens, never the size
22
+ * it wants to be. A heading two levels down inside an `<h2>` section is an
23
+ * `<h3>` even when the design calls for something enormous.
24
+ */
25
+ level: HeadingLevel;
26
+ /**
27
+ * The size, when the outline and the design genuinely disagree.
28
+ *
29
+ * Defaults from `level` through the ladder above, which is the answer nearly
30
+ * always. Reach for this when a semantically-correct `h3` opens a page and
31
+ * has to look like one — not to squeeze a fourth step between two that are
32
+ * already only 14% apart.
33
+ */
34
+ size?: HeadingSize;
35
+ }
36
+ /**
37
+ * A heading, with its element and its size decided separately.
38
+ *
39
+ * Every heading component that takes one number gets this wrong in one of two
40
+ * directions: either the outline is bent to reach a size (an `<h1>` in the
41
+ * middle of a page because the design wanted big type), or the size is bent to
42
+ * keep the outline (a section title set at 20px because it is the fourth level
43
+ * down). Both are one prop away from being right, so there are two.
44
+ *
45
+ * `level` is the document. `size` is the page. The default binds them through
46
+ * the system's ladder, so writing only `level` is correct — and the moment they
47
+ * come apart, the call site says so.
48
+ *
49
+ * Set in the editorial serif at weight 400, like every heading in the system.
50
+ * It also carries `scroll-margin-top`, so a heading given an `id` and linked
51
+ * from a table of contents comes to rest below the masthead rather than under
52
+ * it.
53
+ *
54
+ * @example
55
+ * <Heading level={1}>The White Reset</Heading>
56
+ * @example
57
+ * // Third level in the outline, page-title sized.
58
+ * <Heading level={3} size="title">Colour</Heading>
59
+ */
60
+ declare function Heading({ children, level, size, className, ...rest }: HeadingProps): react.JSX.Element;
61
+
62
+ export { Heading, type HeadingLevel, type HeadingProps, type HeadingSize, Heading as default };
@@ -0,0 +1,44 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { cn } from "../../lib/cn.js";
3
+ const SIZE = {
4
+ title: "text-[length:var(--fs-title)] leading-[1.1] tracking-[-0.02em]",
5
+ lead: "text-[length:var(--fs-lead)] leading-[1.15] tracking-[-0.015em]",
6
+ heading: "text-[length:var(--fs-heading)] leading-[1.2]",
7
+ sub: "text-[length:var(--fs-sub)] leading-[1.25]",
8
+ item: "text-[length:var(--fs-item)] leading-[1.3]",
9
+ // Spelled out rather than reaching for the `eyebrow` utility: it and
10
+ // `font-heading` both set font-family, and a custom utility is invisible to
11
+ // tailwind-merge — so the two would land in the same cascade layer at the
12
+ // same specificity and source order would pick the winner.
13
+ label: "font-mono text-[11px] uppercase leading-[1.6] tracking-[0.2em] text-(--ink-3-aa)"
14
+ };
15
+ const LADDER = {
16
+ 1: "title",
17
+ 2: "heading",
18
+ 3: "sub",
19
+ 4: "item",
20
+ 5: "label",
21
+ 6: "label"
22
+ };
23
+ function Heading({ children, level, size, className, ...rest }) {
24
+ const Comp = `h${level}`;
25
+ const step = size ?? LADDER[level];
26
+ return /* @__PURE__ */ jsx(
27
+ Comp,
28
+ {
29
+ className: cn(
30
+ "m-0 scroll-mt-[var(--scroll-offset)] font-heading font-normal text-(--ink)",
31
+ SIZE[step],
32
+ className
33
+ ),
34
+ ...rest,
35
+ children
36
+ }
37
+ );
38
+ }
39
+ var Heading_default = Heading;
40
+ export {
41
+ Heading,
42
+ Heading_default as default
43
+ };
44
+ //# sourceMappingURL=Heading.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/Heading/Heading.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from 'react'\nimport { cn } from '../../lib/cn'\n\nexport type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6\n\n/**\n * A step on the type ladder, named for the thing it heads.\n *\n * `title` is the top and there is nothing above it — a page has exactly one\n * thing larger than its own records. `label` is not on the size ladder at all:\n * it is the mono kicker, which is what a fifth-level heading should look like,\n * because a serif heading three steps down is indistinguishable from bold body\n * copy.\n */\nexport type HeadingSize = 'title' | 'lead' | 'heading' | 'sub' | 'item' | 'label'\n\nconst SIZE: Record<HeadingSize, string> = {\n title: 'text-[length:var(--fs-title)] leading-[1.1] tracking-[-0.02em]',\n lead: 'text-[length:var(--fs-lead)] leading-[1.15] tracking-[-0.015em]',\n heading: 'text-[length:var(--fs-heading)] leading-[1.2]',\n sub: 'text-[length:var(--fs-sub)] leading-[1.25]',\n item: 'text-[length:var(--fs-item)] leading-[1.3]',\n // Spelled out rather than reaching for the `eyebrow` utility: it and\n // `font-heading` both set font-family, and a custom utility is invisible to\n // tailwind-merge — so the two would land in the same cascade layer at the\n // same specificity and source order would pick the winner.\n label: 'font-mono text-[11px] uppercase leading-[1.6] tracking-[0.2em] text-(--ink-3-aa)',\n}\n\n/**\n * What each level looks like when nobody says otherwise — and the reason this\n * component exists rather than six styled tags.\n *\n * Read the gaps. `1 → title` then `2 → heading` SKIPS `lead`, because the\n * ladder's steps sit close together on purpose: it separates records of the\n * same kind, not a heading from its own sub-heading. `--fs-lead` over\n * `--fs-heading` is a ratio of 1.14 and reads as a rendering accident;\n * `--fs-title` over `--fs-heading` is 1.86 and reads as a hierarchy.\n *\n * So the correct pairing is what a caller gets for free, and stepping off the\n * ladder costs a prop and is visible in review. This is the same map\n * `article.css` applies to rendered Markdown, which is what makes a component\n * page and a post read as one publication.\n */\nconst LADDER: Record<HeadingLevel, HeadingSize> = {\n 1: 'title',\n 2: 'heading',\n 3: 'sub',\n 4: 'item',\n 5: 'label',\n 6: 'label',\n}\n\nexport interface HeadingProps extends HTMLAttributes<HTMLHeadingElement> {\n children?: ReactNode\n /**\n * The element: `1` renders `<h1>`, `6` renders `<h6>`.\n *\n * This is the document outline and nothing else — it is what a screen reader\n * navigates by, so it follows the section the heading opens, never the size\n * it wants to be. A heading two levels down inside an `<h2>` section is an\n * `<h3>` even when the design calls for something enormous.\n */\n level: HeadingLevel\n /**\n * The size, when the outline and the design genuinely disagree.\n *\n * Defaults from `level` through the ladder above, which is the answer nearly\n * always. Reach for this when a semantically-correct `h3` opens a page and\n * has to look like one — not to squeeze a fourth step between two that are\n * already only 14% apart.\n */\n size?: HeadingSize\n}\n\n/**\n * A heading, with its element and its size decided separately.\n *\n * Every heading component that takes one number gets this wrong in one of two\n * directions: either the outline is bent to reach a size (an `<h1>` in the\n * middle of a page because the design wanted big type), or the size is bent to\n * keep the outline (a section title set at 20px because it is the fourth level\n * down). Both are one prop away from being right, so there are two.\n *\n * `level` is the document. `size` is the page. The default binds them through\n * the system's ladder, so writing only `level` is correct — and the moment they\n * come apart, the call site says so.\n *\n * Set in the editorial serif at weight 400, like every heading in the system.\n * It also carries `scroll-margin-top`, so a heading given an `id` and linked\n * from a table of contents comes to rest below the masthead rather than under\n * it.\n *\n * @example\n * <Heading level={1}>The White Reset</Heading>\n * @example\n * // Third level in the outline, page-title sized.\n * <Heading level={3} size=\"title\">Colour</Heading>\n */\nexport function Heading({ children, level, size, className, ...rest }: HeadingProps) {\n const Comp = `h${level}` as const\n const step = size ?? LADDER[level]\n\n return (\n <Comp\n className={cn(\n 'm-0 scroll-mt-[var(--scroll-offset)] font-heading font-normal text-(--ink)',\n SIZE[step],\n className,\n )}\n {...rest}\n >\n {children}\n </Comp>\n )\n}\n\nexport default Heading\n"],"mappings":"AAwGI;AAvGJ,SAAS,UAAU;AAenB,MAAM,OAAoC;AAAA,EACxC,OAAO;AAAA,EACP,MAAM;AAAA,EACN,SAAS;AAAA,EACT,KAAK;AAAA,EACL,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA,EAKN,OAAO;AACT;AAiBA,MAAM,SAA4C;AAAA,EAChD,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AACL;AAgDO,SAAS,QAAQ,EAAE,UAAU,OAAO,MAAM,WAAW,GAAG,KAAK,GAAiB;AACnF,QAAM,OAAO,IAAI,KAAK;AACtB,QAAM,OAAO,QAAQ,OAAO,KAAK;AAEjC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA,KAAK,IAAI;AAAA,QACT;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEH;AAAA;AAAA,EACH;AAEJ;AAEA,IAAO,kBAAQ;","names":[]}
@@ -0,0 +1,139 @@
1
+ import * as react from 'react';
2
+ import { MarkdownHeadingLevel, MarkdownNode } from './nodes.js';
3
+ export { MarkdownInline } from './nodes.js';
4
+ export { parseMarkdown } from './parse.js';
5
+ export { slugify } from './slug.js';
6
+
7
+ interface MarkdownProps {
8
+ /** The Markdown source. A string — not nodes, not HTML. */
9
+ children: string;
10
+ /**
11
+ * The level the document's top heading renders at.
12
+ *
13
+ * Markdown is written as a document, so its `#` is an `<h1>`. Dropped into a
14
+ * page that already has one — inside an `<h2>` section, in a card, under a
15
+ * dialog's title — that produces two first-level headings and an outline a
16
+ * screen reader cannot navigate. Set this to the level BELOW the heading the
17
+ * content sits under, and every level in the document shifts with it.
18
+ */
19
+ headingLevelStart?: MarkdownHeadingLevel;
20
+ /**
21
+ * Namespaces the generated heading ids.
22
+ *
23
+ * Two documents on one page both containing "Installation" would otherwise
24
+ * both claim `#installation`, and a fragment link would land on whichever the
25
+ * browser found first.
26
+ */
27
+ idPrefix?: string;
28
+ /**
29
+ * Adds the system's outbound arrow to links that leave for another site.
30
+ *
31
+ * Off by default, and opt-in rather than automatic for two reasons. The mark
32
+ * is an addition to a sentence the component did not write, which is a
33
+ * different kind of act from styling one. And `Markdown` has no idea what
34
+ * origin it is being rendered on, so "leaves for another site" can only mean
35
+ * "carries an `http`/`https` scheme" — an absolute link back to your own
36
+ * domain gets the arrow too. A caller who knows the shape of their content
37
+ * turns it on; one who does not should not have it turned on for them.
38
+ *
39
+ * The `rel` on an outbound link is NOT opt-in and cannot be turned off: it
40
+ * is the security half of the same boundary as the scheme check.
41
+ */
42
+ markExternalLinks?: boolean;
43
+ /**
44
+ * Bring your own parser.
45
+ *
46
+ * Anything that turns the source into `MarkdownNode`s: markdown-it, remark,
47
+ * or a pipeline that already has an AST and only needs mapping. The node
48
+ * shapes are exported alongside the component as `MarkdownNode`,
49
+ * `MarkdownInline` and `MarkdownHeadingLevel`. The built-in parser covers the
50
+ * subset this system styles; this is the seam for tables, footnotes, task
51
+ * lists and everything else.
52
+ */
53
+ parse?: (source: string) => MarkdownNode[];
54
+ }
55
+ /**
56
+ * A Markdown string, rendered as this system's components.
57
+ *
58
+ * The gap it fills is content nobody on this side wrote: a comment, a README, a
59
+ * model's answer, a description out of a database. `Article` cannot take those
60
+ * — it renders HTML through `dangerouslySetInnerHTML` and is documented as
61
+ * trusted-input-only — and until now the alternative was a `<pre>` or a
62
+ * sanitiser bolted onto a styling primitive.
63
+ *
64
+ * IT IS NOT AN `Article`, and the two do not merge. `Markdown` turns a string
65
+ * into nodes; `Article` is the reading column those nodes can sit in. It
66
+ * renders a FRAGMENT rather than a wrapper, which is what makes that nesting
67
+ * work — `Article`'s rhythm is a direct-child combinator, so any element
68
+ * between the two, `display: contents` included, would cost every paragraph
69
+ * its spacing.
70
+ *
71
+ * ── It brings type and colour, and no vertical rhythm ──
72
+ *
73
+ * The nodes carry the system's faces and inks on their own, so one of these
74
+ * looks right in isolation. It is not SPACED in isolation: every node renders
75
+ * `m-0`, and a fragment has no box of its own to put a gap in. Nor does a
76
+ * uniform `gap` on a container reproduce it, because prose spacing is not
77
+ * uniform — `article.css` gives a heading 2.25em above and 0.75em below, which
78
+ * is what sits a heading with the paragraph it introduces rather than midway
79
+ * between two. For anything longer than a sentence — a comment, an answer, a
80
+ * README — put it in `<Article as="div">` and get the real rhythm for the cost
81
+ * of one element.
82
+ *
83
+ * ── A fenced code block brings a client component with it ──
84
+ *
85
+ * The renderer is plain functions and has no state, but a fenced block renders
86
+ * `CodeBlock`, which is `'use client'` and arrives with `useState`,
87
+ * `useEffect` and two icons. That is correct — the copy button is the reason
88
+ * the block exists — but "server-rendered" only holds for content with no code
89
+ * in it, which is worth knowing before this goes into a route that has no
90
+ * client bundle yet.
91
+ *
92
+ * ── Why there is no parser in `dependencies` ──
93
+ *
94
+ * Three options, and the decision is written here because it is the one a
95
+ * reader will want to argue with.
96
+ *
97
+ * 1. BUNDLE A PARSER. markdown-it is the obvious pick, and the documentation
98
+ * site already depends on it — but the site is an app and this is a
99
+ * library, where the dependency list is part of the contract every consumer
100
+ * signs. Measured with the same esbuild pass `check:size` uses, markdown-it
101
+ * is 110.7 kB minified against the 38.9 kB this package had left under its
102
+ * bundle budget. It is not close, and "we will raise the budget" is how a
103
+ * design system becomes the largest thing on a page.
104
+ * 2. TAKE PRE-PARSED HTML, the way `Article` does. Cheapest, and wrong for the
105
+ * case this exists for: HTML from an untrusted author is the input this is
106
+ * supposed to make safe, and it cannot carry `headingLevelStart` or stable
107
+ * heading ids without the component parsing markup back apart to find them.
108
+ * 3. PARSE THE SUBSET WE STYLE, and take a `parse` function for the rest.
109
+ * Chosen. The block grammar is line-based and small (see `parse.ts`), it
110
+ * emits React elements rather than markup — so there is no
111
+ * `dangerouslySetInnerHTML` in this path at all, no sanitiser to configure
112
+ * and no sanitiser to get wrong — and a consumer who needs tables,
113
+ * footnotes or task lists passes `parse` and keeps every other promise the
114
+ * component makes.
115
+ *
116
+ * Headings carry an `id` slugged from their own text and deduplicated within
117
+ * the document, so a table of contents can link to them without the caller
118
+ * post-processing the DOM to find out where they went.
119
+ *
120
+ * A link in the source is validated here, at the boundary: a scheme that is not
121
+ * `http`, `https`, `mailto` or `tel` never becomes a link, and one that leaves
122
+ * for another site carries `rel="noreferrer nofollow"` — so an author the page
123
+ * does not trust cannot spend its ranking or read its URL out of the `Referer`.
124
+ *
125
+ * @example
126
+ * // A comment body or an answer: the reading column is what spaces it.
127
+ * <Article as="div">
128
+ * <Markdown headingLevelStart={3} idPrefix="answer">{answer}</Markdown>
129
+ * </Article>
130
+ * @example
131
+ * // A whole document, in the column it was written for.
132
+ * <Article><Markdown>{readme}</Markdown></Article>
133
+ * @example
134
+ * // Tables and footnotes, via the consumer's own pipeline.
135
+ * <Markdown parse={(source) => toMarkdownNodes(md.parse(source, {}))}>{post}</Markdown>
136
+ */
137
+ declare function Markdown({ children, headingLevelStart, idPrefix, markExternalLinks, parse, }: MarkdownProps): react.JSX.Element;
138
+
139
+ export { Markdown, MarkdownHeadingLevel, MarkdownNode, type MarkdownProps, Markdown as default };
@@ -0,0 +1,135 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { Fragment } from "react";
3
+ import { Code } from "../Code/Code.js";
4
+ import { CodeBlock } from "../CodeBlock/CodeBlock.js";
5
+ import { Heading } from "../Heading/Heading.js";
6
+ import { LinkArrow } from "../LinkArrow/LinkArrow.js";
7
+ import { Separator } from "../Separator/Separator.js";
8
+ import { Text } from "../Text/Text.js";
9
+ import { isOutbound } from "./inline.js";
10
+ import { parseMarkdown } from "./parse.js";
11
+ import { slugify } from "./slug.js";
12
+ import { parseMarkdown as parseMarkdown2 } from "./parse.js";
13
+ import { slugify as slugify2 } from "./slug.js";
14
+ function textOf(nodes) {
15
+ return nodes.map((node) => {
16
+ if (node.type === "text" || node.type === "code") return node.value;
17
+ if (node.type === "image") return node.alt;
18
+ return textOf(node.children);
19
+ }).join("");
20
+ }
21
+ function headingId(text, context) {
22
+ const base = slugify(text) || "section";
23
+ const seen = (context.taken.get(base) ?? 0) + 1;
24
+ context.taken.set(base, seen);
25
+ const id = seen === 1 ? base : `${base}-${seen}`;
26
+ return context.idPrefix ? `${context.idPrefix}-${id}` : id;
27
+ }
28
+ function renderInline(node, key, context) {
29
+ switch (node.type) {
30
+ case "text":
31
+ return node.value;
32
+ case "code":
33
+ return /* @__PURE__ */ jsx(Code, { children: node.value }, key);
34
+ case "strong":
35
+ return /* @__PURE__ */ jsx("strong", { className: "font-medium text-(--ink)", children: node.children.map((child, index) => renderInline(child, index, context)) }, key);
36
+ case "emphasis":
37
+ return /* @__PURE__ */ jsx("em", { className: "italic", children: node.children.map((child, index) => renderInline(child, index, context)) }, key);
38
+ case "image":
39
+ return /* @__PURE__ */ jsx(
40
+ "img",
41
+ {
42
+ src: node.src,
43
+ alt: node.alt,
44
+ loading: "lazy",
45
+ className: "h-auto max-w-full rounded-(--radius)"
46
+ },
47
+ key
48
+ );
49
+ case "link": {
50
+ const outbound = isOutbound(node.href);
51
+ return /* @__PURE__ */ jsxs(
52
+ "a",
53
+ {
54
+ href: node.href,
55
+ rel: outbound ? "noreferrer nofollow" : void 0,
56
+ className: "text-(--ink) underline decoration-[var(--rule-2)] underline-offset-4 transition-[text-decoration-color] duration-(--duration-fast) hover:decoration-[var(--ink)]",
57
+ children: [
58
+ node.children.map((child, index) => renderInline(child, index, context)),
59
+ outbound && context.markExternalLinks ? /* @__PURE__ */ jsx(LinkArrow, {}) : null
60
+ ]
61
+ },
62
+ key
63
+ );
64
+ }
65
+ }
66
+ }
67
+ function renderItem(blocks, key, context) {
68
+ const first = blocks[0];
69
+ const only = blocks.length === 1 && first?.type === "paragraph" ? first : void 0;
70
+ return /* @__PURE__ */ jsx("li", { className: "relative", children: only ? only.children.map((child, i) => renderInline(child, i, context)) : blocks.map((block, i) => renderBlock(block, i, context)) }, key);
71
+ }
72
+ function renderBlock(node, key, context) {
73
+ switch (node.type) {
74
+ case "heading": {
75
+ const level = Math.min(6, node.level + context.headingLevelStart - 1);
76
+ return /* @__PURE__ */ jsx(Heading, { level, id: headingId(textOf(node.children), context), children: node.children.map((child, index) => renderInline(child, index, context)) }, key);
77
+ }
78
+ case "paragraph":
79
+ return /* @__PURE__ */ jsx(Text, { children: node.children.map((child, index) => renderInline(child, index, context)) }, key);
80
+ case "code":
81
+ return /* @__PURE__ */ jsx(CodeBlock, { code: node.value, lang: node.lang }, key);
82
+ case "rule":
83
+ return /* @__PURE__ */ jsx(Separator, { weight: "edge", decorative: false }, key);
84
+ case "quote":
85
+ return /* @__PURE__ */ jsx(
86
+ "blockquote",
87
+ {
88
+ className: "m-0 border-s-2 border-(--rule-hard) ps-[1.25em] font-serif text-[length:var(--fs-item)] leading-[1.55] text-(--ink) [&>*+*]:mt-[0.6em]",
89
+ children: node.children.map((child, i) => renderBlock(child, i, context))
90
+ },
91
+ key
92
+ );
93
+ case "list":
94
+ return node.ordered ? /* @__PURE__ */ jsx(
95
+ "ol",
96
+ {
97
+ className: "m-0 list-decimal ps-[1.4em] text-(--ink-2) marker:text-(--ink-3-aa) [&>li+li]:mt-[0.4em]",
98
+ children: node.items.map((item, i) => renderItem(item, i, context))
99
+ },
100
+ key
101
+ ) : (
102
+ // The marker is a hairline dash drawn on `::before`, not a disc: the
103
+ // system's only filled circle is a status dot. `article.css` draws the
104
+ // same dash on the same pseudo-element, so markdown dropped into an
105
+ // Article coincides with the stylesheet rather than doubling it.
106
+ /* @__PURE__ */ jsx(
107
+ "ul",
108
+ {
109
+ className: "m-0 list-none ps-[1.15em] text-(--ink-2) [&>li+li]:mt-[0.4em] [&>li]:before:absolute [&>li]:before:start-[-1.15em] [&>li]:before:top-[0.85em] [&>li]:before:h-px [&>li]:before:w-[0.55em] [&>li]:before:bg-(--rule-2) [&>li]:before:content-['']",
110
+ children: node.items.map((item, i) => renderItem(item, i, context))
111
+ },
112
+ key
113
+ )
114
+ );
115
+ }
116
+ }
117
+ function Markdown({
118
+ children,
119
+ headingLevelStart = 1,
120
+ idPrefix,
121
+ markExternalLinks = false,
122
+ parse = parseMarkdown
123
+ }) {
124
+ const context = { headingLevelStart, idPrefix, markExternalLinks, taken: /* @__PURE__ */ new Map() };
125
+ const nodes = typeof children === "string" ? parse(children) : [];
126
+ return /* @__PURE__ */ jsx(Fragment, { children: nodes.map((node, index) => renderBlock(node, index, context)) });
127
+ }
128
+ var Markdown_default = Markdown;
129
+ export {
130
+ Markdown,
131
+ Markdown_default as default,
132
+ parseMarkdown2 as parseMarkdown,
133
+ slugify2 as slugify
134
+ };
135
+ //# sourceMappingURL=Markdown.js.map