@misoto22/design 0.6.1 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (402) hide show
  1. package/AGENTS.md +87 -0
  2. package/CLAUDE.md +1 -0
  3. package/README.md +62 -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 +71 -0
  9. package/dist/agent/AreaChart.md +27 -2
  10. package/dist/agent/Article.md +26 -3
  11. package/dist/agent/AspectRatio.md +57 -0
  12. package/dist/agent/Avatar.md +25 -5
  13. package/dist/agent/Badge.md +22 -1
  14. package/dist/agent/BarChart.md +29 -2
  15. package/dist/agent/BarList.md +27 -1
  16. package/dist/agent/BigNumber.md +26 -2
  17. package/dist/agent/BoxPlot.md +24 -1
  18. package/dist/agent/Breadcrumb.md +24 -2
  19. package/dist/agent/BulletChart.md +23 -1
  20. package/dist/agent/Button.md +25 -1
  21. package/dist/agent/Calendar.md +37 -3
  22. package/dist/agent/Card.md +24 -2
  23. package/dist/agent/Checkbox.md +23 -2
  24. package/dist/agent/Code.md +50 -0
  25. package/dist/agent/CodeBlock.md +74 -0
  26. package/dist/agent/Collapsible.md +22 -1
  27. package/dist/agent/Combobox.md +29 -3
  28. package/dist/agent/Command.md +25 -2
  29. package/dist/agent/ComposedChart.md +26 -2
  30. package/dist/agent/ContextMenu.md +37 -4
  31. package/dist/agent/DataflowFigure.md +48 -0
  32. package/dist/agent/DatePicker.md +34 -6
  33. package/dist/agent/DescriptionList.md +68 -0
  34. package/dist/agent/Diagram.md +27 -3
  35. package/dist/agent/DiagramCanvas.md +70 -0
  36. package/dist/agent/DiagramExportMenu.md +64 -0
  37. package/dist/agent/DiagramInspector.md +72 -0
  38. package/dist/agent/DiagramLegend.md +55 -0
  39. package/dist/agent/DiagramMinimap.md +68 -0
  40. package/dist/agent/DiagramToolbar.md +69 -0
  41. package/dist/agent/Dialog.md +26 -3
  42. package/dist/agent/DropdownMenu.md +45 -6
  43. package/dist/agent/EmptyState.md +26 -1
  44. package/dist/agent/ErrorState.md +27 -2
  45. package/dist/agent/Facet.md +25 -1
  46. package/dist/agent/Field.md +45 -4
  47. package/dist/agent/FigureBand.md +24 -1
  48. package/dist/agent/FloatingIconButton.md +23 -1
  49. package/dist/agent/FunnelChart.md +23 -1
  50. package/dist/agent/Heading.md +64 -0
  51. package/dist/agent/Heatmap.md +25 -1
  52. package/dist/agent/Histogram.md +26 -2
  53. package/dist/agent/Input.md +22 -1
  54. package/dist/agent/Kbd.md +19 -1
  55. package/dist/agent/LifecycleFigure.md +49 -0
  56. package/dist/agent/LineChart.md +26 -2
  57. package/dist/agent/LinkArrow.md +20 -1
  58. package/dist/agent/Markdown.md +68 -0
  59. package/dist/agent/NativeSelect.md +23 -2
  60. package/dist/agent/NavItem.md +21 -1
  61. package/dist/agent/Pagination.md +28 -2
  62. package/dist/agent/PieChart.md +26 -2
  63. package/dist/agent/Popover.md +23 -1
  64. package/dist/agent/Progress.md +27 -3
  65. package/dist/agent/RadarChart.md +26 -2
  66. package/dist/agent/RadialChart.md +26 -3
  67. package/dist/agent/RadioGroup.md +23 -2
  68. package/dist/agent/SankeyChart.md +25 -2
  69. package/dist/agent/ScatterChart.md +27 -2
  70. package/dist/agent/ScrollArea.md +24 -3
  71. package/dist/agent/SearchableMenu.md +23 -1
  72. package/dist/agent/Select.md +29 -3
  73. package/dist/agent/Separator.md +28 -4
  74. package/dist/agent/SequenceFigure.md +50 -0
  75. package/dist/agent/Sheet.md +25 -2
  76. package/dist/agent/Skeleton.md +24 -2
  77. package/dist/agent/Slider.md +27 -4
  78. package/dist/agent/Sparkline.md +23 -1
  79. package/dist/agent/Spinner.md +24 -2
  80. package/dist/agent/StatusDot.md +20 -1
  81. package/dist/agent/StatusPill.md +28 -2
  82. package/dist/agent/Steps.md +24 -1
  83. package/dist/agent/Switch.md +21 -1
  84. package/dist/agent/Table.md +26 -3
  85. package/dist/agent/Tabs.md +24 -2
  86. package/dist/agent/Tag.md +40 -9
  87. package/dist/agent/Text.md +65 -0
  88. package/dist/agent/Textarea.md +20 -1
  89. package/dist/agent/Timestamp.md +64 -0
  90. package/dist/agent/Toast.md +26 -2
  91. package/dist/agent/ToggleGroup.md +24 -2
  92. package/dist/agent/Toolbar.md +71 -0
  93. package/dist/agent/Tooltip.md +23 -1
  94. package/dist/agent/TreemapChart.md +24 -1
  95. package/dist/agent/WaterfallChart.md +24 -1
  96. package/dist/agent/WorkflowFigure.md +50 -0
  97. package/dist/agent/catalog.json +6086 -1009
  98. package/dist/agent/index.md +27 -4
  99. package/dist/article.css +16 -4
  100. package/dist/charts/AreaChart/AreaChart.d.ts +9 -2
  101. package/dist/charts/AreaChart/AreaChart.js +12 -13
  102. package/dist/charts/AreaChart/AreaChart.js.map +1 -1
  103. package/dist/charts/BarChart/BarChart.d.ts +14 -3
  104. package/dist/charts/BarChart/BarChart.js +20 -12
  105. package/dist/charts/BarChart/BarChart.js.map +1 -1
  106. package/dist/charts/BarList/BarList.d.ts +9 -1
  107. package/dist/charts/BarList/BarList.js +9 -1
  108. package/dist/charts/BarList/BarList.js.map +1 -1
  109. package/dist/charts/BigNumber/BigNumber.d.ts +19 -3
  110. package/dist/charts/BigNumber/BigNumber.js +25 -5
  111. package/dist/charts/BigNumber/BigNumber.js.map +1 -1
  112. package/dist/charts/BoxPlot/BoxPlot.js +4 -2
  113. package/dist/charts/BoxPlot/BoxPlot.js.map +1 -1
  114. package/dist/charts/BulletChart/BulletChart.js +28 -7
  115. package/dist/charts/BulletChart/BulletChart.js.map +1 -1
  116. package/dist/charts/ComposedChart/ComposedChart.d.ts +9 -2
  117. package/dist/charts/ComposedChart/ComposedChart.js +10 -10
  118. package/dist/charts/ComposedChart/ComposedChart.js.map +1 -1
  119. package/dist/charts/FunnelChart/FunnelChart.d.ts +7 -2
  120. package/dist/charts/FunnelChart/FunnelChart.js +6 -16
  121. package/dist/charts/FunnelChart/FunnelChart.js.map +1 -1
  122. package/dist/charts/Heatmap/Heatmap.d.ts +17 -3
  123. package/dist/charts/Heatmap/Heatmap.js +20 -11
  124. package/dist/charts/Heatmap/Heatmap.js.map +1 -1
  125. package/dist/charts/Histogram/Histogram.d.ts +24 -1
  126. package/dist/charts/Histogram/Histogram.js +43 -11
  127. package/dist/charts/Histogram/Histogram.js.map +1 -1
  128. package/dist/charts/LineChart/LineChart.d.ts +9 -2
  129. package/dist/charts/LineChart/LineChart.js +11 -12
  130. package/dist/charts/LineChart/LineChart.js.map +1 -1
  131. package/dist/charts/PieChart/PieChart.d.ts +15 -3
  132. package/dist/charts/PieChart/PieChart.js +14 -6
  133. package/dist/charts/PieChart/PieChart.js.map +1 -1
  134. package/dist/charts/RadarChart/RadarChart.d.ts +15 -3
  135. package/dist/charts/RadarChart/RadarChart.js +11 -9
  136. package/dist/charts/RadarChart/RadarChart.js.map +1 -1
  137. package/dist/charts/RadialChart/RadialChart.d.ts +22 -4
  138. package/dist/charts/RadialChart/RadialChart.js +28 -6
  139. package/dist/charts/RadialChart/RadialChart.js.map +1 -1
  140. package/dist/charts/SankeyChart/SankeyChart.d.ts +16 -4
  141. package/dist/charts/SankeyChart/SankeyChart.js +14 -6
  142. package/dist/charts/SankeyChart/SankeyChart.js.map +1 -1
  143. package/dist/charts/ScatterChart/ScatterChart.d.ts +24 -3
  144. package/dist/charts/ScatterChart/ScatterChart.js +21 -15
  145. package/dist/charts/ScatterChart/ScatterChart.js.map +1 -1
  146. package/dist/charts/Sparkline/Sparkline.js +5 -3
  147. package/dist/charts/Sparkline/Sparkline.js.map +1 -1
  148. package/dist/charts/TreemapChart/TreemapChart.d.ts +7 -2
  149. package/dist/charts/TreemapChart/TreemapChart.js +20 -11
  150. package/dist/charts/TreemapChart/TreemapChart.js.map +1 -1
  151. package/dist/charts/WaterfallChart/WaterfallChart.js +4 -2
  152. package/dist/charts/WaterfallChart/WaterfallChart.js.map +1 -1
  153. package/dist/charts/index.d.ts +2 -1
  154. package/dist/charts/lib/export.d.ts +34 -43
  155. package/dist/charts/lib/export.js +16 -158
  156. package/dist/charts/lib/export.js.map +1 -1
  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/Combobox/Combobox.d.ts +15 -1
  204. package/dist/components/Combobox/Combobox.js +25 -5
  205. package/dist/components/Combobox/Combobox.js.map +1 -1
  206. package/dist/components/Command/Command.d.ts +4 -2
  207. package/dist/components/Command/Command.js +13 -1
  208. package/dist/components/Command/Command.js.map +1 -1
  209. package/dist/components/ContextMenu/ContextMenu.d.ts +30 -5
  210. package/dist/components/ContextMenu/ContextMenu.js +32 -2
  211. package/dist/components/ContextMenu/ContextMenu.js.map +1 -1
  212. package/dist/components/DatePicker/DatePicker.d.ts +36 -4
  213. package/dist/components/DatePicker/DatePicker.js +55 -12
  214. package/dist/components/DatePicker/DatePicker.js.map +1 -1
  215. package/dist/components/DescriptionList/DescriptionList.d.ts +73 -0
  216. package/dist/components/DescriptionList/DescriptionList.js +35 -0
  217. package/dist/components/DescriptionList/DescriptionList.js.map +1 -0
  218. package/dist/components/Diagram/Diagram.d.ts +8 -3
  219. package/dist/components/Diagram/Diagram.js +82 -10
  220. package/dist/components/Diagram/Diagram.js.map +1 -1
  221. package/dist/components/Dialog/Dialog.d.ts +18 -3
  222. package/dist/components/Dialog/Dialog.js +20 -2
  223. package/dist/components/Dialog/Dialog.js.map +1 -1
  224. package/dist/components/DropdownMenu/DropdownMenu.d.ts +49 -11
  225. package/dist/components/DropdownMenu/DropdownMenu.js +32 -2
  226. package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -1
  227. package/dist/components/EmptyState/EmptyState.d.ts +25 -1
  228. package/dist/components/EmptyState/EmptyState.js +3 -1
  229. package/dist/components/EmptyState/EmptyState.js.map +1 -1
  230. package/dist/components/ErrorState/ErrorState.d.ts +22 -1
  231. package/dist/components/ErrorState/ErrorState.js +11 -2
  232. package/dist/components/ErrorState/ErrorState.js.map +1 -1
  233. package/dist/components/Field/Field.d.ts +70 -3
  234. package/dist/components/Field/Field.js +53 -12
  235. package/dist/components/Field/Field.js.map +1 -1
  236. package/dist/components/Field/field-control.d.ts +31 -0
  237. package/dist/components/Field/field-control.js +12 -0
  238. package/dist/components/Field/field-control.js.map +1 -0
  239. package/dist/components/FloatingIconButton/FloatingIconButton.js +2 -0
  240. package/dist/components/FloatingIconButton/FloatingIconButton.js.map +1 -1
  241. package/dist/components/Heading/Heading.d.ts +62 -0
  242. package/dist/components/Heading/Heading.js +44 -0
  243. package/dist/components/Heading/Heading.js.map +1 -0
  244. package/dist/components/Markdown/Markdown.d.ts +139 -0
  245. package/dist/components/Markdown/Markdown.js +135 -0
  246. package/dist/components/Markdown/Markdown.js.map +1 -0
  247. package/dist/components/Markdown/inline.d.ts +29 -0
  248. package/dist/components/Markdown/inline.js +74 -0
  249. package/dist/components/Markdown/inline.js.map +1 -0
  250. package/dist/components/Markdown/nodes.d.ts +65 -0
  251. package/dist/components/Markdown/nodes.js +1 -0
  252. package/dist/components/Markdown/nodes.js.map +1 -0
  253. package/dist/components/Markdown/parse.d.ts +24 -0
  254. package/dist/components/Markdown/parse.js +110 -0
  255. package/dist/components/Markdown/parse.js.map +1 -0
  256. package/dist/components/Markdown/slug.d.ts +15 -0
  257. package/dist/components/Markdown/slug.js +7 -0
  258. package/dist/components/Markdown/slug.js.map +1 -0
  259. package/dist/components/NativeSelect/NativeSelect.d.ts +6 -0
  260. package/dist/components/NativeSelect/NativeSelect.js +2 -3
  261. package/dist/components/NativeSelect/NativeSelect.js.map +1 -1
  262. package/dist/components/Pagination/Pagination.d.ts +24 -1
  263. package/dist/components/Pagination/Pagination.js +6 -3
  264. package/dist/components/Pagination/Pagination.js.map +1 -1
  265. package/dist/components/Progress/Progress.d.ts +17 -5
  266. package/dist/components/Progress/Progress.js +18 -6
  267. package/dist/components/Progress/Progress.js.map +1 -1
  268. package/dist/components/RadioGroup/RadioGroup.d.ts +6 -0
  269. package/dist/components/RadioGroup/RadioGroup.js +11 -1
  270. package/dist/components/RadioGroup/RadioGroup.js.map +1 -1
  271. package/dist/components/ScrollArea/ScrollArea.d.ts +15 -0
  272. package/dist/components/ScrollArea/ScrollArea.js +2 -2
  273. package/dist/components/ScrollArea/ScrollArea.js.map +1 -1
  274. package/dist/components/SearchableMenu/SearchableMenu.d.ts +11 -2
  275. package/dist/components/SearchableMenu/SearchableMenu.js +24 -2
  276. package/dist/components/SearchableMenu/SearchableMenu.js.map +1 -1
  277. package/dist/components/Select/Select.d.ts +18 -2
  278. package/dist/components/Select/Select.js +20 -3
  279. package/dist/components/Select/Select.js.map +1 -1
  280. package/dist/components/Separator/Separator.d.ts +21 -3
  281. package/dist/components/Separator/Separator.js +9 -1
  282. package/dist/components/Separator/Separator.js.map +1 -1
  283. package/dist/components/Sheet/Sheet.d.ts +3 -0
  284. package/dist/components/Sheet/Sheet.js +11 -2
  285. package/dist/components/Sheet/Sheet.js.map +1 -1
  286. package/dist/components/Skeleton/Skeleton.d.ts +8 -1
  287. package/dist/components/Skeleton/Skeleton.js +1 -1
  288. package/dist/components/Skeleton/Skeleton.js.map +1 -1
  289. package/dist/components/Slider/Slider.d.ts +21 -3
  290. package/dist/components/Slider/Slider.js +54 -27
  291. package/dist/components/Slider/Slider.js.map +1 -1
  292. package/dist/components/Spinner/Spinner.d.ts +8 -0
  293. package/dist/components/Spinner/Spinner.js +3 -2
  294. package/dist/components/Spinner/Spinner.js.map +1 -1
  295. package/dist/components/StatusPill/StatusPill.d.ts +5 -0
  296. package/dist/components/StatusPill/StatusPill.js +6 -0
  297. package/dist/components/StatusPill/StatusPill.js.map +1 -1
  298. package/dist/components/Table/Table.d.ts +6 -0
  299. package/dist/components/Table/Table.js +3 -1
  300. package/dist/components/Table/Table.js.map +1 -1
  301. package/dist/components/Tag/Tag.d.ts +68 -9
  302. package/dist/components/Tag/Tag.js +50 -10
  303. package/dist/components/Tag/Tag.js.map +1 -1
  304. package/dist/components/Text/Text.d.ts +62 -0
  305. package/dist/components/Text/Text.js +30 -0
  306. package/dist/components/Text/Text.js.map +1 -0
  307. package/dist/components/Timestamp/Timestamp.d.ts +59 -0
  308. package/dist/components/Timestamp/Timestamp.js +56 -0
  309. package/dist/components/Timestamp/Timestamp.js.map +1 -0
  310. package/dist/components/Toast/Toast.d.ts +9 -1
  311. package/dist/components/Toast/Toast.js +27 -4
  312. package/dist/components/Toast/Toast.js.map +1 -1
  313. package/dist/components/ToggleGroup/ToggleGroup.d.ts +6 -1
  314. package/dist/components/ToggleGroup/ToggleGroup.js +11 -1
  315. package/dist/components/ToggleGroup/ToggleGroup.js.map +1 -1
  316. package/dist/components/Toolbar/Toolbar.d.ts +55 -0
  317. package/dist/components/Toolbar/Toolbar.js +43 -0
  318. package/dist/components/Toolbar/Toolbar.js.map +1 -0
  319. package/dist/diagrams/ArchitectureFigure/ArchitectureFigure.d.ts +55 -0
  320. package/dist/diagrams/ArchitectureFigure/ArchitectureFigure.js +175 -0
  321. package/dist/diagrams/ArchitectureFigure/ArchitectureFigure.js.map +1 -0
  322. package/dist/diagrams/DataflowFigure/DataflowFigure.d.ts +28 -0
  323. package/dist/diagrams/DataflowFigure/DataflowFigure.js +148 -0
  324. package/dist/diagrams/DataflowFigure/DataflowFigure.js.map +1 -0
  325. package/dist/diagrams/DiagramCanvas/DiagramCanvas.d.ts +78 -0
  326. package/dist/diagrams/DiagramCanvas/DiagramCanvas.js +229 -0
  327. package/dist/diagrams/DiagramCanvas/DiagramCanvas.js.map +1 -0
  328. package/dist/diagrams/DiagramExportMenu/DiagramExportMenu.d.ts +106 -0
  329. package/dist/diagrams/DiagramExportMenu/DiagramExportMenu.js +123 -0
  330. package/dist/diagrams/DiagramExportMenu/DiagramExportMenu.js.map +1 -0
  331. package/dist/diagrams/DiagramInspector/DiagramInspector.d.ts +70 -0
  332. package/dist/diagrams/DiagramInspector/DiagramInspector.js +94 -0
  333. package/dist/diagrams/DiagramInspector/DiagramInspector.js.map +1 -0
  334. package/dist/diagrams/DiagramLegend/DiagramLegend.d.ts +42 -0
  335. package/dist/diagrams/DiagramLegend/DiagramLegend.js +35 -0
  336. package/dist/diagrams/DiagramLegend/DiagramLegend.js.map +1 -0
  337. package/dist/diagrams/DiagramMinimap/DiagramMinimap.d.ts +77 -0
  338. package/dist/diagrams/DiagramMinimap/DiagramMinimap.js +106 -0
  339. package/dist/diagrams/DiagramMinimap/DiagramMinimap.js.map +1 -0
  340. package/dist/diagrams/DiagramToolbar/DiagramToolbar.d.ts +48 -0
  341. package/dist/diagrams/DiagramToolbar/DiagramToolbar.js +53 -0
  342. package/dist/diagrams/DiagramToolbar/DiagramToolbar.js.map +1 -0
  343. package/dist/diagrams/LifecycleFigure/LifecycleFigure.d.ts +31 -0
  344. package/dist/diagrams/LifecycleFigure/LifecycleFigure.js +234 -0
  345. package/dist/diagrams/LifecycleFigure/LifecycleFigure.js.map +1 -0
  346. package/dist/diagrams/SequenceFigure/SequenceFigure.d.ts +38 -0
  347. package/dist/diagrams/SequenceFigure/SequenceFigure.js +261 -0
  348. package/dist/diagrams/SequenceFigure/SequenceFigure.js.map +1 -0
  349. package/dist/diagrams/WorkflowFigure/WorkflowFigure.d.ts +36 -0
  350. package/dist/diagrams/WorkflowFigure/WorkflowFigure.js +259 -0
  351. package/dist/diagrams/WorkflowFigure/WorkflowFigure.js.map +1 -0
  352. package/dist/diagrams/index.d.ts +17 -0
  353. package/dist/diagrams/index.js +29 -0
  354. package/dist/diagrams/index.js.map +1 -0
  355. package/dist/diagrams/lib/dev.d.ts +61 -0
  356. package/dist/diagrams/lib/dev.js +96 -0
  357. package/dist/diagrams/lib/dev.js.map +1 -0
  358. package/dist/diagrams/lib/frame.d.ts +138 -0
  359. package/dist/diagrams/lib/frame.js +131 -0
  360. package/dist/diagrams/lib/frame.js.map +1 -0
  361. package/dist/diagrams/lib/geometry.d.ts +114 -0
  362. package/dist/diagrams/lib/geometry.js +113 -0
  363. package/dist/diagrams/lib/geometry.js.map +1 -0
  364. package/dist/diagrams/lib/legend.d.ts +32 -0
  365. package/dist/diagrams/lib/legend.js +84 -0
  366. package/dist/diagrams/lib/legend.js.map +1 -0
  367. package/dist/diagrams/lib/marks.d.ts +207 -0
  368. package/dist/diagrams/lib/marks.js +480 -0
  369. package/dist/diagrams/lib/marks.js.map +1 -0
  370. package/dist/diagrams/lib/route.d.ts +85 -0
  371. package/dist/diagrams/lib/route.js +178 -0
  372. package/dist/diagrams/lib/route.js.map +1 -0
  373. package/dist/diagrams/lib/wires.d.ts +59 -0
  374. package/dist/diagrams/lib/wires.js +90 -0
  375. package/dist/diagrams/lib/wires.js.map +1 -0
  376. package/dist/diagrams/spec.d.ts +405 -0
  377. package/dist/diagrams/spec.js +1 -0
  378. package/dist/diagrams/spec.js.map +1 -0
  379. package/dist/index.d.ts +16 -4
  380. package/dist/index.js +9 -0
  381. package/dist/index.js.map +1 -1
  382. package/dist/keyframes.css +57 -3
  383. package/dist/lib/overlay-container.d.ts +14 -4
  384. package/dist/lib/overlay-container.js.map +1 -1
  385. package/dist/lib/svg-export.d.ts +138 -0
  386. package/dist/lib/svg-export.js +198 -0
  387. package/dist/lib/svg-export.js.map +1 -0
  388. package/dist/lib/warn.d.ts +73 -0
  389. package/dist/lib/warn.js +38 -0
  390. package/dist/lib/warn.js.map +1 -0
  391. package/dist/semantic.css +51 -6
  392. package/dist/styles.css +1 -1
  393. package/dist/tokens.css +20 -2
  394. package/dist/tokens.d.ts +17 -1
  395. package/dist/tokens.js +121 -36
  396. package/dist/tokens.json +121 -36
  397. package/llms.txt +35 -0
  398. package/package.json +9 -2
  399. package/skills/misoto22-design/SKILL.md +21 -7
  400. package/skills/misoto22-design/evals/evals.json +84 -0
  401. package/skills/misoto22-design/rules/a11y.md +55 -3
  402. package/skills/misoto22-design/rules/forms.md +5 -0
@@ -0,0 +1,65 @@
1
+ /**
2
+ * The node shapes `Markdown` renders, and the contract a custom `parse`
3
+ * function has to meet.
4
+ *
5
+ * Deliberately small. It is not an attempt at mdast: it is the set of blocks
6
+ * this design system has an opinion about, which is the set `article.css`
7
+ * already styles. Anything outside it — footnotes, tables, task lists,
8
+ * definition lists, embedded HTML — is a `parse` away, and the point of naming
9
+ * the shapes here rather than accepting a foreign AST is that a consumer
10
+ * bringing markdown-it or remark maps into a surface the package can promise
11
+ * to keep rendering.
12
+ */
13
+ type MarkdownHeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
14
+ /** A run of text, and the four things that can happen inside one. */
15
+ type MarkdownInline = {
16
+ type: 'text';
17
+ value: string;
18
+ } | {
19
+ type: 'code';
20
+ value: string;
21
+ } | {
22
+ type: 'strong';
23
+ children: MarkdownInline[];
24
+ } | {
25
+ type: 'emphasis';
26
+ children: MarkdownInline[];
27
+ } | {
28
+ type: 'link';
29
+ href: string;
30
+ children: MarkdownInline[];
31
+ } | {
32
+ type: 'image';
33
+ src: string;
34
+ alt: string;
35
+ };
36
+ /**
37
+ * A block.
38
+ *
39
+ * `list` items and `quote` children are blocks in turn, which is what makes a
40
+ * nested list, or a fence inside a bullet, fall out of the same recursion
41
+ * rather than needing a case of its own.
42
+ */
43
+ type MarkdownNode = {
44
+ type: 'heading';
45
+ level: MarkdownHeadingLevel;
46
+ children: MarkdownInline[];
47
+ } | {
48
+ type: 'paragraph';
49
+ children: MarkdownInline[];
50
+ } | {
51
+ type: 'code';
52
+ value: string;
53
+ lang?: string;
54
+ } | {
55
+ type: 'list';
56
+ ordered: boolean;
57
+ items: MarkdownNode[][];
58
+ } | {
59
+ type: 'quote';
60
+ children: MarkdownNode[];
61
+ } | {
62
+ type: 'rule';
63
+ };
64
+
65
+ export type { MarkdownHeadingLevel, MarkdownInline, MarkdownNode };
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=nodes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,24 @@
1
+ import { MarkdownNode } from './nodes.js';
2
+
3
+ /**
4
+ * A Markdown string, as nodes.
5
+ *
6
+ * The supported subset, stated so nobody has to find its edges by experiment:
7
+ * ATX headings, paragraphs, fenced code with an info string, blockquotes,
8
+ * ordered and unordered lists including nesting, thematic breaks — and inline
9
+ * emphasis, strong, code spans, links, images and backslash escapes.
10
+ *
11
+ * What is NOT here, and is deliberate: tables, footnotes, task lists, setext
12
+ * headings, reference links, hard line breaks, and raw HTML. Raw HTML is the
13
+ * one that matters — it is left as text rather than rendered, so this path has
14
+ * no `dangerouslySetInnerHTML` anywhere in it and cannot be talked into one. A
15
+ * document that needs the rest brings its own parser through `Markdown`'s
16
+ * `parse` prop.
17
+ *
18
+ * Never throws. Malformed input is not an error condition here — it is Tuesday
19
+ * — so an unterminated fence, a stray bracket or an empty string each produce
20
+ * the nodes they can and no more.
21
+ */
22
+ declare function parseMarkdown(source: string): MarkdownNode[];
23
+
24
+ export { parseMarkdown };
@@ -0,0 +1,110 @@
1
+ import { parseInline } from "./inline.js";
2
+ const FENCE = /^ {0,3}(`{3,}|~{3,})\s*([^\s`]*)\s*$/;
3
+ const HEADING = /^ {0,3}(#{1,6})\s+(.*?)\s*#*\s*$/;
4
+ const RULE = /^ {0,3}(?:-{3,}|\*{3,}|_{3,})\s*$/;
5
+ const QUOTE = /^ {0,3}>\s?(.*)$/;
6
+ const ITEM = /^(\s*)([-*+]|\d{1,9}[.)])\s+(.*)$/;
7
+ const lineAt = (lines, index) => lines[index] ?? "";
8
+ const opensBlock = (line) => HEADING.test(line) || RULE.test(line) || FENCE.test(line) || QUOTE.test(line) || ITEM.test(line);
9
+ const closesFence = (line, marker) => new RegExp(`^ {0,3}${marker.charAt(0)}{${marker.length},}\\s*$`).test(line);
10
+ function takeFence(lines, start, out) {
11
+ const fence = FENCE.exec(lineAt(lines, start));
12
+ if (!fence) return start + 1;
13
+ const [, marker = "", info = ""] = fence;
14
+ const body = [];
15
+ let i = start + 1;
16
+ while (i < lines.length && !closesFence(lineAt(lines, i), marker)) {
17
+ body.push(lineAt(lines, i));
18
+ i += 1;
19
+ }
20
+ out.push({ type: "code", value: body.join("\n"), lang: info || void 0 });
21
+ return i < lines.length ? i + 1 : i;
22
+ }
23
+ function takeQuote(lines, start, out) {
24
+ const body = [];
25
+ let i = start;
26
+ while (i < lines.length) {
27
+ const quoted = QUOTE.exec(lineAt(lines, i));
28
+ if (!quoted) break;
29
+ body.push(quoted[1] ?? "");
30
+ i += 1;
31
+ }
32
+ out.push({ type: "quote", children: parseBlocks(body) });
33
+ return i;
34
+ }
35
+ function takeList(lines, start, out) {
36
+ const first = ITEM.exec(lineAt(lines, start));
37
+ if (!first) return start + 1;
38
+ const baseIndent = (first[1] ?? "").length;
39
+ const ordered = /\d/.test(first[2] ?? "");
40
+ const items = [];
41
+ let current;
42
+ let indent = 0;
43
+ let i = start;
44
+ while (i < lines.length) {
45
+ const line = lineAt(lines, i);
46
+ const item = ITEM.exec(line);
47
+ const [, gap = "", bullet = "", rest = ""] = item ?? [];
48
+ if (item && gap.length <= baseIndent) {
49
+ if (ordered !== /\d/.test(bullet)) break;
50
+ if (current) items.push(parseBlocks(current));
51
+ indent = gap.length + bullet.length + 1;
52
+ current = [rest];
53
+ i += 1;
54
+ continue;
55
+ }
56
+ if (current !== void 0 && (line.trim() === "" || line.startsWith(" ".repeat(indent)))) {
57
+ current.push(line.slice(indent));
58
+ i += 1;
59
+ continue;
60
+ }
61
+ break;
62
+ }
63
+ if (current) items.push(parseBlocks(current));
64
+ out.push({ type: "list", ordered, items });
65
+ return i;
66
+ }
67
+ function takeParagraph(lines, start, out) {
68
+ const body = [];
69
+ let i = start;
70
+ for (let line = lineAt(lines, i); i < lines.length; line = lineAt(lines, i)) {
71
+ if (line.trim() === "" || opensBlock(line)) break;
72
+ body.push(line.trim());
73
+ i += 1;
74
+ }
75
+ if (body.length === 0) return start + 1;
76
+ out.push({ type: "paragraph", children: parseInline(body.join(" ")) });
77
+ return i;
78
+ }
79
+ function parseBlocks(lines) {
80
+ const out = [];
81
+ let i = 0;
82
+ while (i < lines.length) {
83
+ const line = lineAt(lines, i);
84
+ const heading = HEADING.exec(line);
85
+ if (line.trim() === "") i += 1;
86
+ else if (FENCE.test(line)) i = takeFence(lines, i, out);
87
+ else if (heading) {
88
+ out.push({
89
+ type: "heading",
90
+ level: (heading[1] ?? "#").length,
91
+ children: parseInline(heading[2] ?? "")
92
+ });
93
+ i += 1;
94
+ } else if (RULE.test(line)) {
95
+ out.push({ type: "rule" });
96
+ i += 1;
97
+ } else if (QUOTE.test(line)) i = takeQuote(lines, i, out);
98
+ else if (ITEM.test(line)) i = takeList(lines, i, out);
99
+ else i = takeParagraph(lines, i, out);
100
+ }
101
+ return out;
102
+ }
103
+ function parseMarkdown(source) {
104
+ if (typeof source !== "string" || source.trim() === "") return [];
105
+ return parseBlocks(source.replace(/\r\n?/g, "\n").split("\n"));
106
+ }
107
+ export {
108
+ parseMarkdown
109
+ };
110
+ //# sourceMappingURL=parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/Markdown/parse.ts"],"sourcesContent":["import { parseInline } from './inline'\nimport type { MarkdownHeadingLevel, MarkdownNode } from './nodes'\n\n/**\n * The block grammar, as the six line shapes it recognises.\n *\n * Line-based rather than character-based, which is what keeps this small enough\n * to live in a design system: Markdown's blocks are decided by how a line\n * STARTS, and the interesting half — emphasis, links, code spans — is the\n * inline pass, which runs once per block.\n */\nconst FENCE = /^ {0,3}(`{3,}|~{3,})\\s*([^\\s`]*)\\s*$/\nconst HEADING = /^ {0,3}(#{1,6})\\s+(.*?)\\s*#*\\s*$/\nconst RULE = /^ {0,3}(?:-{3,}|\\*{3,}|_{3,})\\s*$/\nconst QUOTE = /^ {0,3}>\\s?(.*)$/\nconst ITEM = /^(\\s*)([-*+]|\\d{1,9}[.)])\\s+(.*)$/\n\n/**\n * A line, or the empty string past the end.\n *\n * `noUncheckedIndexedAccess` is on, and every scanner below walks off the end\n * of the array by construction — reading one line ahead is how a list decides\n * whether a blank line ended it. An empty string matches none of the patterns,\n * which is exactly the answer wanted there.\n */\nconst lineAt = (lines: string[], index: number): string => lines[index] ?? ''\n\nconst opensBlock = (line: string): boolean =>\n HEADING.test(line) || RULE.test(line) || FENCE.test(line) || QUOTE.test(line) || ITEM.test(line)\n\n/** A fence closes on the same character, at the same length or longer. */\nconst closesFence = (line: string, marker: string): boolean =>\n new RegExp(`^ {0,3}${marker.charAt(0)}{${marker.length},}\\\\s*$`).test(line)\n\nfunction takeFence(lines: string[], start: number, out: MarkdownNode[]): number {\n const fence = FENCE.exec(lineAt(lines, start))\n if (!fence) return start + 1\n const [, marker = '', info = ''] = fence\n\n const body: string[] = []\n let i = start + 1\n while (i < lines.length && !closesFence(lineAt(lines, i), marker)) {\n body.push(lineAt(lines, i))\n i += 1\n }\n out.push({ type: 'code', value: body.join('\\n'), lang: info || undefined })\n\n // An unclosed fence runs to the end of the document rather than throwing.\n // That is what CommonMark specifies, and it is also the exact shape of a\n // model's answer that hit its token limit mid-snippet.\n return i < lines.length ? i + 1 : i\n}\n\nfunction takeQuote(lines: string[], start: number, out: MarkdownNode[]): number {\n const body: string[] = []\n let i = start\n while (i < lines.length) {\n const quoted = QUOTE.exec(lineAt(lines, i))\n if (!quoted) break\n body.push(quoted[1] ?? '')\n i += 1\n }\n // Recursive, so a list, a fence or a nested quote inside a blockquote is the\n // same code path rather than five more cases.\n out.push({ type: 'quote', children: parseBlocks(body) })\n return i\n}\n\nfunction takeList(lines: string[], start: number, out: MarkdownNode[]): number {\n const first = ITEM.exec(lineAt(lines, start))\n if (!first) return start + 1\n\n const baseIndent = (first[1] ?? '').length\n const ordered = /\\d/.test(first[2] ?? '')\n const items: MarkdownNode[][] = []\n let current: string[] | undefined\n let indent = 0\n let i = start\n\n while (i < lines.length) {\n const line = lineAt(lines, i)\n const item = ITEM.exec(line)\n const [, gap = '', bullet = '', rest = ''] = item ?? []\n\n if (item && gap.length <= baseIndent) {\n // A bullet directly under a number is a second list, not a stray item.\n if (ordered !== /\\d/.test(bullet)) break\n if (current) items.push(parseBlocks(current))\n indent = gap.length + bullet.length + 1\n current = [rest]\n i += 1\n continue\n }\n if (current !== undefined && (line.trim() === '' || line.startsWith(' '.repeat(indent)))) {\n current.push(line.slice(indent))\n i += 1\n continue\n }\n break\n }\n\n if (current) items.push(parseBlocks(current))\n out.push({ type: 'list', ordered, items })\n return i\n}\n\nfunction takeParagraph(lines: string[], start: number, out: MarkdownNode[]): number {\n const body: string[] = []\n let i = start\n for (let line = lineAt(lines, i); i < lines.length; line = lineAt(lines, i)) {\n if (line.trim() === '' || opensBlock(line)) break\n body.push(line.trim())\n i += 1\n }\n if (body.length === 0) return start + 1\n\n // Soft line breaks join with a space, which is what Markdown means by them:\n // a paragraph hard-wrapped at 80 columns is one paragraph.\n out.push({ type: 'paragraph', children: parseInline(body.join(' ')) })\n return i\n}\n\nfunction parseBlocks(lines: string[]): MarkdownNode[] {\n const out: MarkdownNode[] = []\n let i = 0\n while (i < lines.length) {\n const line = lineAt(lines, i)\n const heading = HEADING.exec(line)\n\n if (line.trim() === '') i += 1\n else if (FENCE.test(line)) i = takeFence(lines, i, out)\n else if (heading) {\n out.push({\n type: 'heading',\n level: (heading[1] ?? '#').length as MarkdownHeadingLevel,\n children: parseInline(heading[2] ?? ''),\n })\n i += 1\n } else if (RULE.test(line)) {\n out.push({ type: 'rule' })\n i += 1\n } else if (QUOTE.test(line)) i = takeQuote(lines, i, out)\n else if (ITEM.test(line)) i = takeList(lines, i, out)\n else i = takeParagraph(lines, i, out)\n }\n return out\n}\n\n/**\n * A Markdown string, as nodes.\n *\n * The supported subset, stated so nobody has to find its edges by experiment:\n * ATX headings, paragraphs, fenced code with an info string, blockquotes,\n * ordered and unordered lists including nesting, thematic breaks — and inline\n * emphasis, strong, code spans, links, images and backslash escapes.\n *\n * What is NOT here, and is deliberate: tables, footnotes, task lists, setext\n * headings, reference links, hard line breaks, and raw HTML. Raw HTML is the\n * one that matters — it is left as text rather than rendered, so this path has\n * no `dangerouslySetInnerHTML` anywhere in it and cannot be talked into one. A\n * document that needs the rest brings its own parser through `Markdown`'s\n * `parse` prop.\n *\n * Never throws. Malformed input is not an error condition here — it is Tuesday\n * — so an unterminated fence, a stray bracket or an empty string each produce\n * the nodes they can and no more.\n */\nexport function parseMarkdown(source: string): MarkdownNode[] {\n if (typeof source !== 'string' || source.trim() === '') return []\n return parseBlocks(source.replace(/\\r\\n?/g, '\\n').split('\\n'))\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * A heading's text, as an anchor id.
3
+ *
4
+ * Exported because a table of contents has to arrive at the SAME id the
5
+ * rendered heading got, and the alternative is building the list by reading it
6
+ * back off the DOM — which a server render does not have.
7
+ *
8
+ * Letters and numbers survive in any script (`\p{L}`, not `a-z`), so a Chinese
9
+ * or Greek heading keeps its characters instead of slugging away to nothing and
10
+ * colliding with every other one on the page. `Markdown` deduplicates what does
11
+ * collide by appending `-2`, `-3`, and so on in document order.
12
+ */
13
+ declare function slugify(text: string): string;
14
+
15
+ export { slugify };
@@ -0,0 +1,7 @@
1
+ function slugify(text) {
2
+ return text.trim().toLowerCase().replace(/[^\p{L}\p{N}]+/gu, "-").replace(/^-+|-+$/g, "");
3
+ }
4
+ export {
5
+ slugify
6
+ };
7
+ //# sourceMappingURL=slug.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/Markdown/slug.ts"],"sourcesContent":["/**\n * A heading's text, as an anchor id.\n *\n * Exported because a table of contents has to arrive at the SAME id the\n * rendered heading got, and the alternative is building the list by reading it\n * back off the DOM — which a server render does not have.\n *\n * Letters and numbers survive in any script (`\\p{L}`, not `a-z`), so a Chinese\n * or Greek heading keeps its characters instead of slugging away to nothing and\n * colliding with every other one on the page. `Markdown` deduplicates what does\n * collide by appending `-2`, `-3`, and so on in document order.\n */\nexport function slugify(text: string): string {\n return text\n .trim()\n .toLowerCase()\n .replace(/[^\\p{L}\\p{N}]+/gu, '-')\n .replace(/^-+|-+$/g, '')\n}\n"],"mappings":"AAYO,SAAS,QAAQ,MAAsB;AAC5C,SAAO,KACJ,KAAK,EACL,YAAY,EACZ,QAAQ,oBAAoB,GAAG,EAC/B,QAAQ,YAAY,EAAE;AAC3B;","names":[]}
@@ -19,6 +19,12 @@ interface NativeSelectProps extends SelectHTMLAttributes<HTMLSelectElement> {
19
19
  * list is drawn by the operating system, so it carries none of these tokens —
20
20
  * which is exactly why it stopped being the default.
21
21
  *
22
+ * `className` sizes the WRAPPER, not the `<select>` inside it. This is the one
23
+ * control here that renders two elements, and the chevron is pinned to the
24
+ * wrapper's end edge: a width on the select alone narrowed the box and left the
25
+ * arrow floating at the far side of the row. The select fills whatever the
26
+ * wrapper is.
27
+ *
22
28
  * @example
23
29
  * <NativeSelect defaultValue="au"><option value="au">Australia</option></NativeSelect>
24
30
  */
@@ -11,7 +11,7 @@ function NativeSelect({
11
11
  ...rest
12
12
  }) {
13
13
  const bad = isInvalid(invalid, ariaInvalid);
14
- return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
14
+ return /* @__PURE__ */ jsxs("div", { className: cn("relative", className), children: [
15
15
  /* @__PURE__ */ jsx(
16
16
  "select",
17
17
  {
@@ -20,8 +20,7 @@ function NativeSelect({
20
20
  className: cn(
21
21
  CONTROL_BASE,
22
22
  "cursor-pointer appearance-none pe-9",
23
- bad ? CONTROL_BORDER.invalid : CONTROL_BORDER.resting,
24
- className
23
+ bad ? CONTROL_BORDER.invalid : CONTROL_BORDER.resting
25
24
  ),
26
25
  ...rest,
27
26
  children
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/NativeSelect/NativeSelect.tsx"],"sourcesContent":["import { ChevronDown } from 'lucide-react'\nimport type { Ref, SelectHTMLAttributes } from 'react'\nimport { cn } from '../../lib/cn'\nimport { CONTROL_BASE, CONTROL_BORDER, isInvalid } from '../../lib/control'\n\nexport interface NativeSelectProps extends SelectHTMLAttributes<HTMLSelectElement> {\n /** Paints the resting border with `--danger` and reflects `aria-invalid`. */\n invalid?: boolean\n ref?: Ref<HTMLSelectElement>\n}\n\n/**\n * A native `<select>`, restyled.\n *\n * The escape hatch, not the default — `Select` is the styled one. Reach for\n * this where the platform's own picker is genuinely better: a very long list on\n * a phone, a form that must work without JavaScript, a page where the last\n * kilobyte matters. The browser gives typeahead and the mobile wheel for free,\n * and those are real.\n *\n * What it cannot do is look like the rest of the system once open. The option\n * list is drawn by the operating system, so it carries none of these tokens —\n * which is exactly why it stopped being the default.\n *\n * @example\n * <NativeSelect defaultValue=\"au\"><option value=\"au\">Australia</option></NativeSelect>\n */\nexport function NativeSelect({\n invalid,\n className,\n ref,\n children,\n 'aria-invalid': ariaInvalid,\n ...rest\n}: NativeSelectProps) {\n const bad = isInvalid(invalid, ariaInvalid)\n return (\n <div className=\"relative\">\n <select\n ref={ref}\n aria-invalid={ariaInvalid ?? (invalid ? true : undefined)}\n className={cn(\n CONTROL_BASE,\n 'cursor-pointer appearance-none pe-9',\n bad ? CONTROL_BORDER.invalid : CONTROL_BORDER.resting,\n className,\n )}\n {...rest}\n >\n {children}\n </select>\n <ChevronDown\n size={16}\n strokeWidth={1.5}\n className=\"pointer-events-none absolute end-3 top-1/2 -translate-y-1/2 text-(--ink-3-aa)\"\n aria-hidden\n />\n </div>\n )\n}\n\nexport default NativeSelect\n"],"mappings":"AAqCI,SACE,KADF;AArCJ,SAAS,mBAAmB;AAE5B,SAAS,UAAU;AACnB,SAAS,cAAc,gBAAgB,iBAAiB;AAwBjD,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,gBAAgB;AAAA,EAChB,GAAG;AACL,GAAsB;AACpB,QAAM,MAAM,UAAU,SAAS,WAAW;AAC1C,SACE,qBAAC,SAAI,WAAU,YACb;AAAA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,gBAAc,gBAAgB,UAAU,OAAO;AAAA,QAC/C,WAAW;AAAA,UACT;AAAA,UACA;AAAA,UACA,MAAM,eAAe,UAAU,eAAe;AAAA,UAC9C;AAAA,QACF;AAAA,QACC,GAAG;AAAA,QAEH;AAAA;AAAA,IACH;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM;AAAA,QACN,aAAa;AAAA,QACb,WAAU;AAAA,QACV,eAAW;AAAA;AAAA,IACb;AAAA,KACF;AAEJ;AAEA,IAAO,uBAAQ;","names":[]}
1
+ {"version":3,"sources":["../../../src/components/NativeSelect/NativeSelect.tsx"],"sourcesContent":["import { ChevronDown } from 'lucide-react'\nimport type { Ref, SelectHTMLAttributes } from 'react'\nimport { cn } from '../../lib/cn'\nimport { CONTROL_BASE, CONTROL_BORDER, isInvalid } from '../../lib/control'\n\nexport interface NativeSelectProps extends SelectHTMLAttributes<HTMLSelectElement> {\n /** Paints the resting border with `--danger` and reflects `aria-invalid`. */\n invalid?: boolean\n ref?: Ref<HTMLSelectElement>\n}\n\n/**\n * A native `<select>`, restyled.\n *\n * The escape hatch, not the default — `Select` is the styled one. Reach for\n * this where the platform's own picker is genuinely better: a very long list on\n * a phone, a form that must work without JavaScript, a page where the last\n * kilobyte matters. The browser gives typeahead and the mobile wheel for free,\n * and those are real.\n *\n * What it cannot do is look like the rest of the system once open. The option\n * list is drawn by the operating system, so it carries none of these tokens —\n * which is exactly why it stopped being the default.\n *\n * `className` sizes the WRAPPER, not the `<select>` inside it. This is the one\n * control here that renders two elements, and the chevron is pinned to the\n * wrapper's end edge: a width on the select alone narrowed the box and left the\n * arrow floating at the far side of the row. The select fills whatever the\n * wrapper is.\n *\n * @example\n * <NativeSelect defaultValue=\"au\"><option value=\"au\">Australia</option></NativeSelect>\n */\nexport function NativeSelect({\n invalid,\n className,\n ref,\n children,\n 'aria-invalid': ariaInvalid,\n ...rest\n}: NativeSelectProps) {\n const bad = isInvalid(invalid, ariaInvalid)\n return (\n <div className={cn('relative', className)}>\n <select\n ref={ref}\n aria-invalid={ariaInvalid ?? (invalid ? true : undefined)}\n className={cn(\n CONTROL_BASE,\n 'cursor-pointer appearance-none pe-9',\n bad ? CONTROL_BORDER.invalid : CONTROL_BORDER.resting,\n )}\n {...rest}\n >\n {children}\n </select>\n <ChevronDown\n size={16}\n strokeWidth={1.5}\n className=\"pointer-events-none absolute end-3 top-1/2 -translate-y-1/2 text-(--ink-3-aa)\"\n aria-hidden\n />\n </div>\n )\n}\n\nexport default NativeSelect\n"],"mappings":"AA2CI,SACE,KADF;AA3CJ,SAAS,mBAAmB;AAE5B,SAAS,UAAU;AACnB,SAAS,cAAc,gBAAgB,iBAAiB;AA8BjD,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,gBAAgB;AAAA,EAChB,GAAG;AACL,GAAsB;AACpB,QAAM,MAAM,UAAU,SAAS,WAAW;AAC1C,SACE,qBAAC,SAAI,WAAW,GAAG,YAAY,SAAS,GACtC;AAAA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,gBAAc,gBAAgB,UAAU,OAAO;AAAA,QAC/C,WAAW;AAAA,UACT;AAAA,UACA;AAAA,UACA,MAAM,eAAe,UAAU,eAAe;AAAA,QAChD;AAAA,QACC,GAAG;AAAA,QAEH;AAAA;AAAA,IACH;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM;AAAA,QACN,aAAa;AAAA,QACb,WAAU;AAAA,QACV,eAAW;AAAA;AAAA,IACb;AAAA,KACF;AAEJ;AAEA,IAAO,uBAAQ;","names":[]}
@@ -10,6 +10,24 @@ interface PaginationProps extends Omit<HTMLAttributes<HTMLElement>, 'onChange'>
10
10
  /** How many numbered pages sit either side of the current one. */
11
11
  siblings?: number;
12
12
  label?: string;
13
+ /**
14
+ * Names the two step controls.
15
+ *
16
+ * Each is a chevron and nothing else, so these strings are its entire
17
+ * accessible name — the same reason `AppShell` exposes `openLabel` and
18
+ * `closeLabel` rather than baking them in.
19
+ */
20
+ previousLabel?: string;
21
+ nextLabel?: string;
22
+ /**
23
+ * Names one numbered page.
24
+ *
25
+ * A function rather than a template, because the number does not sit in the
26
+ * same place in every language and neither does the noun around it —
27
+ * `"Page 3"`, `"第 3 页"`, `"Seite 3"`. The visible digit is the same either
28
+ * way; this is what a screen reader hears instead of a bare number.
29
+ */
30
+ pageLabel?: (page: number) => string;
13
31
  }
14
32
  declare const GAP: "\u2026";
15
33
  /**
@@ -36,9 +54,14 @@ declare function paginationRange(page: number, pageCount: number, siblings?: num
36
54
  *
37
55
  * Renders nothing at one page or fewer. A pager for a single page is furniture.
38
56
  *
57
+ * Every string a reader hears is a prop. The chevrons carry no text, so
58
+ * `previousLabel` and `nextLabel` are the whole of those two controls' names,
59
+ * and `pageLabel` is a function because "Page 3" is a phrase whose parts move
60
+ * around between languages.
61
+ *
39
62
  * @example
40
63
  * <Pagination page={page} pageCount={12} onPageChange={setPage} />
41
64
  */
42
- declare function Pagination({ page, pageCount, onPageChange, siblings, label, className, ...rest }: PaginationProps): react.JSX.Element | null;
65
+ declare function Pagination({ page, pageCount, onPageChange, siblings, label, previousLabel, nextLabel, pageLabel, className, ...rest }: PaginationProps): react.JSX.Element | null;
43
66
 
44
67
  export { Pagination, type PaginationProps, Pagination as default, paginationRange };
@@ -34,6 +34,9 @@ function Pagination({
34
34
  onPageChange,
35
35
  siblings = 1,
36
36
  label = "Pagination",
37
+ previousLabel = "Previous page",
38
+ nextLabel = "Next page",
39
+ pageLabel = (page2) => `Page ${page2}`,
37
40
  className,
38
41
  ...rest
39
42
  }) {
@@ -45,7 +48,7 @@ function Pagination({
45
48
  "button",
46
49
  {
47
50
  type: "button",
48
- "aria-label": "Previous page",
51
+ "aria-label": previousLabel,
49
52
  disabled: page <= 1,
50
53
  onClick: () => onPageChange(page - 1),
51
54
  className: cn(STEP, "border-(--rule-2) text-(--ink-2) hover:border-(--ink) hover:text-(--ink)"),
@@ -74,7 +77,7 @@ function Pagination({
74
77
  {
75
78
  type: "button",
76
79
  "aria-current": entry === page ? "page" : void 0,
77
- "aria-label": `Page ${entry}`,
80
+ "aria-label": pageLabel(entry),
78
81
  "data-indicator-active": entry === page ? "true" : void 0,
79
82
  onClick: () => onPageChange(entry),
80
83
  className: cn(
@@ -91,7 +94,7 @@ function Pagination({
91
94
  "button",
92
95
  {
93
96
  type: "button",
94
- "aria-label": "Next page",
97
+ "aria-label": nextLabel,
95
98
  disabled: page >= pageCount,
96
99
  onClick: () => onPageChange(page + 1),
97
100
  className: cn(STEP, "border-(--rule-2) text-(--ink-2) hover:border-(--ink) hover:text-(--ink)"),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/Pagination/Pagination.tsx"],"sourcesContent":["'use client'\n\nimport { ChevronLeft, ChevronRight } from 'lucide-react'\nimport type { HTMLAttributes } from 'react'\nimport { cn } from '../../lib/cn'\nimport { useSelectionIndicator } from '../../lib/useSelectionIndicator'\n\nexport interface PaginationProps extends Omit<HTMLAttributes<HTMLElement>, 'onChange'> {\n /** 1-based. */\n page: number\n /** Total pages. A value of 1 or less renders nothing. */\n pageCount: number\n onPageChange: (page: number) => void\n /** How many numbered pages sit either side of the current one. */\n siblings?: number\n label?: string\n}\n\nconst GAP = '…' as const\n\n/**\n * Builds the visible page list: always the first and last page, a window around\n * the current one, and an ellipsis wherever the sequence skips.\n *\n * Returned as numbers and a literal ellipsis rather than as pre-rendered nodes,\n * so the shape is testable without a DOM — the off-by-one at the window edges\n * is the whole difficulty of this component.\n */\nexport function paginationRange(page: number, pageCount: number, siblings = 1): (number | typeof GAP)[] {\n const first = 1\n const last = pageCount\n\n // Below the width the elided form would occupy — first, last, the window and\n // two ellipses — printing every page is both shorter and more useful. Without\n // this, a five-page list renders \"1 2 … 5\", which hides a page to save\n // nothing.\n const widest = 2 * siblings + 5\n if (pageCount <= widest) {\n return Array.from({ length: pageCount }, (_, index) => index + 1)\n }\n\n const start = Math.max(first, page - siblings)\n const end = Math.min(last, page + siblings)\n\n const pages: (number | typeof GAP)[] = []\n if (start > first) {\n pages.push(first)\n // A single skipped page is printed, not elided: \"1 … 3\" is longer than\n // \"1 2 3\" and tells the reader less.\n if (start > first + 2) pages.push(GAP)\n else if (start === first + 2) pages.push(first + 1)\n }\n for (let n = start; n <= end; n += 1) pages.push(n)\n if (end < last) {\n if (end < last - 2) pages.push(GAP)\n else if (end === last - 2) pages.push(last - 1)\n pages.push(last)\n }\n return pages\n}\n\nconst STEP =\n 'inline-flex size-(--control-h-sm) items-center justify-center rounded-(--radius-pill) border transition-colors duration-(--duration-fast) disabled:opacity-(--disabled-opacity) disabled:pointer-events-none'\n\n/**\n * Numbered pagination.\n *\n * The current page is marked by one filled pill that TRAVELS between the\n * numbers rather than by a background switching off on one and on on another.\n * Two backgrounds cross-fading reads as two things changing; a shape moving\n * reads as the one thing that actually did.\n *\n * A `<nav>` wrapping a list, and the current page is a `<button aria-current>`\n * rather than a styled `<span>` — a reader jumping by landmark needs to find\n * the control, and a reader on the current page needs to be told they are\n * already there.\n *\n * Renders nothing at one page or fewer. A pager for a single page is furniture.\n *\n * @example\n * <Pagination page={page} pageCount={12} onPageChange={setPage} />\n */\nexport function Pagination({\n page,\n pageCount,\n onPageChange,\n siblings = 1,\n label = 'Pagination',\n className,\n ...rest\n}: PaginationProps) {\n // Called before the early return, because a hook cannot be conditional — and\n // keyed on the page so the pill re-measures when the elided window shifts and\n // the numbers under it change.\n const [listRef, indicator] = useSelectionIndicator<HTMLOListElement>(String(page))\n\n if (pageCount <= 1) return null\n const pages = paginationRange(page, pageCount, siblings)\n\n return (\n <nav aria-label={label} className={cn('flex items-center gap-1.5', className)} {...rest}>\n <button\n type=\"button\"\n aria-label=\"Previous page\"\n disabled={page <= 1}\n onClick={() => onPageChange(page - 1)}\n className={cn(STEP, 'border-(--rule-2) text-(--ink-2) hover:border-(--ink) hover:text-(--ink)')}\n >\n <ChevronLeft size={16} strokeWidth={1.5} aria-hidden />\n </button>\n\n <ol ref={listRef} className=\"relative m-0 flex list-none items-center gap-1 p-0\">\n {indicator.ready && (\n <span\n aria-hidden\n data-m22-animated\n className=\"absolute rounded-(--radius-pill) bg-(--accent) transition-[transform,width] duration-(--duration-base) ease-(--ease-out-expo) motion-reduce:transition-none\"\n style={{\n transform: `translate(${indicator.offset}px, ${indicator.top}px)`,\n width: indicator.width,\n height: indicator.height,\n insetInlineStart: 0,\n top: 0,\n }}\n />\n )}\n {pages.map((entry, index) =>\n entry === GAP ? (\n <li key={`gap-${index}`} aria-hidden=\"true\" className=\"px-1 mono-meta text-(--ink-3-aa)\">\n {GAP}\n </li>\n ) : (\n <li key={entry} className=\"relative z-1\">\n <button\n type=\"button\"\n aria-current={entry === page ? 'page' : undefined}\n aria-label={`Page ${entry}`}\n data-indicator-active={entry === page ? 'true' : undefined}\n onClick={() => onPageChange(entry)}\n className={cn(\n STEP,\n 'mono-meta tabular-nums',\n entry === page\n ? 'border-transparent text-(--accent-foreground)'\n : 'border-transparent text-(--ink-2) hover:border-(--rule-2) hover:text-(--ink)',\n )}\n >\n {entry}\n </button>\n </li>\n ),\n )}\n </ol>\n\n <button\n type=\"button\"\n aria-label=\"Next page\"\n disabled={page >= pageCount}\n onClick={() => onPageChange(page + 1)}\n className={cn(STEP, 'border-(--rule-2) text-(--ink-2) hover:border-(--ink) hover:text-(--ink)')}\n >\n <ChevronRight size={16} strokeWidth={1.5} aria-hidden />\n </button>\n </nav>\n )\n}\n\nexport default Pagination\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/components/Pagination/Pagination.tsx"],"sourcesContent":["'use client'\n\nimport { ChevronLeft, ChevronRight } from 'lucide-react'\nimport type { HTMLAttributes } from 'react'\nimport { cn } from '../../lib/cn'\nimport { useSelectionIndicator } from '../../lib/useSelectionIndicator'\n\nexport interface PaginationProps extends Omit<HTMLAttributes<HTMLElement>, 'onChange'> {\n /** 1-based. */\n page: number\n /** Total pages. A value of 1 or less renders nothing. */\n pageCount: number\n onPageChange: (page: number) => void\n /** How many numbered pages sit either side of the current one. */\n siblings?: number\n label?: string\n /**\n * Names the two step controls.\n *\n * Each is a chevron and nothing else, so these strings are its entire\n * accessible name — the same reason `AppShell` exposes `openLabel` and\n * `closeLabel` rather than baking them in.\n */\n previousLabel?: string\n nextLabel?: string\n /**\n * Names one numbered page.\n *\n * A function rather than a template, because the number does not sit in the\n * same place in every language and neither does the noun around it —\n * `\"Page 3\"`, `\"第 3 页\"`, `\"Seite 3\"`. The visible digit is the same either\n * way; this is what a screen reader hears instead of a bare number.\n */\n pageLabel?: (page: number) => string\n}\n\nconst GAP = '…' as const\n\n/**\n * Builds the visible page list: always the first and last page, a window around\n * the current one, and an ellipsis wherever the sequence skips.\n *\n * Returned as numbers and a literal ellipsis rather than as pre-rendered nodes,\n * so the shape is testable without a DOM — the off-by-one at the window edges\n * is the whole difficulty of this component.\n */\nexport function paginationRange(page: number, pageCount: number, siblings = 1): (number | typeof GAP)[] {\n const first = 1\n const last = pageCount\n\n // Below the width the elided form would occupy — first, last, the window and\n // two ellipses — printing every page is both shorter and more useful. Without\n // this, a five-page list renders \"1 2 … 5\", which hides a page to save\n // nothing.\n const widest = 2 * siblings + 5\n if (pageCount <= widest) {\n return Array.from({ length: pageCount }, (_, index) => index + 1)\n }\n\n const start = Math.max(first, page - siblings)\n const end = Math.min(last, page + siblings)\n\n const pages: (number | typeof GAP)[] = []\n if (start > first) {\n pages.push(first)\n // A single skipped page is printed, not elided: \"1 … 3\" is longer than\n // \"1 2 3\" and tells the reader less.\n if (start > first + 2) pages.push(GAP)\n else if (start === first + 2) pages.push(first + 1)\n }\n for (let n = start; n <= end; n += 1) pages.push(n)\n if (end < last) {\n if (end < last - 2) pages.push(GAP)\n else if (end === last - 2) pages.push(last - 1)\n pages.push(last)\n }\n return pages\n}\n\nconst STEP =\n 'inline-flex size-(--control-h-sm) items-center justify-center rounded-(--radius-pill) border transition-colors duration-(--duration-fast) disabled:opacity-(--disabled-opacity) disabled:pointer-events-none'\n\n/**\n * Numbered pagination.\n *\n * The current page is marked by one filled pill that TRAVELS between the\n * numbers rather than by a background switching off on one and on on another.\n * Two backgrounds cross-fading reads as two things changing; a shape moving\n * reads as the one thing that actually did.\n *\n * A `<nav>` wrapping a list, and the current page is a `<button aria-current>`\n * rather than a styled `<span>` — a reader jumping by landmark needs to find\n * the control, and a reader on the current page needs to be told they are\n * already there.\n *\n * Renders nothing at one page or fewer. A pager for a single page is furniture.\n *\n * Every string a reader hears is a prop. The chevrons carry no text, so\n * `previousLabel` and `nextLabel` are the whole of those two controls' names,\n * and `pageLabel` is a function because \"Page 3\" is a phrase whose parts move\n * around between languages.\n *\n * @example\n * <Pagination page={page} pageCount={12} onPageChange={setPage} />\n */\nexport function Pagination({\n page,\n pageCount,\n onPageChange,\n siblings = 1,\n label = 'Pagination',\n previousLabel = 'Previous page',\n nextLabel = 'Next page',\n pageLabel = (page) => `Page ${page}`,\n className,\n ...rest\n}: PaginationProps) {\n // Called before the early return, because a hook cannot be conditional — and\n // keyed on the page so the pill re-measures when the elided window shifts and\n // the numbers under it change.\n const [listRef, indicator] = useSelectionIndicator<HTMLOListElement>(String(page))\n\n if (pageCount <= 1) return null\n const pages = paginationRange(page, pageCount, siblings)\n\n return (\n <nav aria-label={label} className={cn('flex items-center gap-1.5', className)} {...rest}>\n <button\n type=\"button\"\n aria-label={previousLabel}\n disabled={page <= 1}\n onClick={() => onPageChange(page - 1)}\n className={cn(STEP, 'border-(--rule-2) text-(--ink-2) hover:border-(--ink) hover:text-(--ink)')}\n >\n <ChevronLeft size={16} strokeWidth={1.5} aria-hidden />\n </button>\n\n <ol ref={listRef} className=\"relative m-0 flex list-none items-center gap-1 p-0\">\n {indicator.ready && (\n <span\n aria-hidden\n data-m22-animated\n className=\"absolute rounded-(--radius-pill) bg-(--accent) transition-[transform,width] duration-(--duration-base) ease-(--ease-out-expo) motion-reduce:transition-none\"\n style={{\n transform: `translate(${indicator.offset}px, ${indicator.top}px)`,\n width: indicator.width,\n height: indicator.height,\n insetInlineStart: 0,\n top: 0,\n }}\n />\n )}\n {pages.map((entry, index) =>\n entry === GAP ? (\n <li key={`gap-${index}`} aria-hidden=\"true\" className=\"px-1 mono-meta text-(--ink-3-aa)\">\n {GAP}\n </li>\n ) : (\n <li key={entry} className=\"relative z-1\">\n <button\n type=\"button\"\n aria-current={entry === page ? 'page' : undefined}\n aria-label={pageLabel(entry)}\n data-indicator-active={entry === page ? 'true' : undefined}\n onClick={() => onPageChange(entry)}\n className={cn(\n STEP,\n 'mono-meta tabular-nums',\n entry === page\n ? 'border-transparent text-(--accent-foreground)'\n : 'border-transparent text-(--ink-2) hover:border-(--rule-2) hover:text-(--ink)',\n )}\n >\n {entry}\n </button>\n </li>\n ),\n )}\n </ol>\n\n <button\n type=\"button\"\n aria-label={nextLabel}\n disabled={page >= pageCount}\n onClick={() => onPageChange(page + 1)}\n className={cn(STEP, 'border-(--rule-2) text-(--ink-2) hover:border-(--ink) hover:text-(--ink)')}\n >\n <ChevronRight size={16} strokeWidth={1.5} aria-hidden />\n </button>\n </nav>\n )\n}\n\nexport default Pagination\n"],"mappings":"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","names":["page"]}
@@ -2,13 +2,25 @@ import * as react from 'react';
2
2
  import { ComponentProps } from 'react';
3
3
  import * as ProgressPrimitive from '@radix-ui/react-progress';
4
4
 
5
- interface ProgressProps extends Omit<ComponentProps<typeof ProgressPrimitive.Root>, 'value'> {
5
+ interface ProgressProps extends Omit<ComponentProps<typeof ProgressPrimitive.Root>, 'value' | 'max'> {
6
6
  /**
7
- * 0100. Omit (or pass `null`) when the duration is genuinely unknown — the
8
- * bar then sweeps instead of filling, and Radix drops `aria-valuenow` so a
9
- * screen reader is told "indeterminate" rather than a number that is a guess.
7
+ * 0 to `max`, which is 100 unless you say otherwise. Omit (or pass `null`)
8
+ * when the duration is genuinely unknown the bar then sweeps instead of
9
+ * filling, and Radix drops `aria-valuenow` so a screen reader is told
10
+ * "indeterminate" rather than a number that is a guess.
10
11
  */
11
12
  value?: number | null;
13
+ /**
14
+ * What `value` is measured against. 100 by default.
15
+ *
16
+ * The width is computed from it as well as announced from it. It used to be
17
+ * only announced: `max` reached Radix through `...rest` while the width was
18
+ * `value` clamped to 100, so `max={500}` with `value={100}` painted a full
19
+ * bar and told a screen reader "100 of 500". A max that is not a positive
20
+ * number is refused the way Radix refuses it — Radix warns, and both fall
21
+ * back to 100 rather than drawing one picture and announcing another.
22
+ */
23
+ max?: number;
12
24
  /** Names what is progressing. Required: a bare bar announces nothing. */
13
25
  label: string;
14
26
  /** Prints the percentage above the bar. Only meaningful when `value` is set. */
@@ -26,6 +38,6 @@ interface ProgressProps extends Omit<ComponentProps<typeof ProgressPrimitive.Roo
26
38
  * @example
27
39
  * <Progress label="Indexing" />
28
40
  */
29
- declare function Progress({ value, label, showValue, className, ...rest }: ProgressProps): react.JSX.Element;
41
+ declare function Progress({ value, max, label, showValue, className, ...rest }: ProgressProps): react.JSX.Element;
30
42
 
31
43
  export { Progress, type ProgressProps, Progress as default };
@@ -2,21 +2,33 @@
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as ProgressPrimitive from "@radix-ui/react-progress";
4
4
  import { cn } from "../../lib/cn.js";
5
- function Progress({ value = null, label, showValue = false, className, ...rest }) {
5
+ import { warnBlankName } from "../../lib/warn.js";
6
+ function Progress({
7
+ value = null,
8
+ max,
9
+ label,
10
+ showValue = false,
11
+ className,
12
+ ...rest
13
+ }) {
14
+ warnBlankName("Progress", "label", label, "the progressbar is announced with no name and its percentage describes nothing");
6
15
  const indeterminate = value === null || value === void 0;
7
- const clamped = indeterminate ? 0 : Math.min(100, Math.max(0, value));
16
+ const ceiling = typeof max === "number" && !Number.isNaN(max) && max > 0 ? max : 100;
17
+ const bounded = indeterminate ? 0 : Math.min(ceiling, Math.max(0, value));
18
+ const percent = bounded / ceiling * 100;
8
19
  return /* @__PURE__ */ jsxs("div", { className: cn("flex w-full flex-col gap-2", className), children: [
9
20
  showValue && !indeterminate && /* @__PURE__ */ jsxs("div", { className: "flex items-baseline justify-between mono-meta text-(--ink-3-aa)", children: [
10
21
  /* @__PURE__ */ jsx("span", { children: label }),
11
22
  /* @__PURE__ */ jsxs("span", { className: "tabular-nums", children: [
12
- Math.round(clamped),
23
+ Math.round(percent),
13
24
  "%"
14
25
  ] })
15
26
  ] }),
16
27
  /* @__PURE__ */ jsx(
17
28
  ProgressPrimitive.Root,
18
29
  {
19
- value: indeterminate ? null : clamped,
30
+ value: indeterminate ? null : bounded,
31
+ max,
20
32
  "aria-label": label,
21
33
  className: "relative h-1 w-full overflow-hidden rounded-(--radius-pill) bg-(--stone)",
22
34
  ...rest,
@@ -24,13 +36,13 @@ function Progress({ value = null, label, showValue = false, className, ...rest }
24
36
  "span",
25
37
  {
26
38
  "data-m22-animated": true,
27
- className: "absolute inset-y-0 start-0 w-1/4 rounded-(--radius-pill) bg-(--accent) rtl:-scale-x-100 motion-safe:animate-[m22-sweep_1.4s_var(--ease)_infinite] motion-reduce:w-full motion-reduce:opacity-40"
39
+ className: "absolute inset-y-0 start-0 w-1/4 rounded-(--radius-pill) bg-(--accent) rtl:-scale-x-100 motion-safe:animate-[m22-sweep_1.4s_var(--ease)_infinite]"
28
40
  }
29
41
  ) : /* @__PURE__ */ jsx(
30
42
  ProgressPrimitive.Indicator,
31
43
  {
32
44
  className: "h-full rounded-(--radius-pill) bg-(--accent) transition-[width] duration-(--duration-slow) ease-(--ease-out-expo)",
33
- style: { width: `${clamped}%` }
45
+ style: { width: `${percent}%` }
34
46
  }
35
47
  )
36
48
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/Progress/Progress.tsx"],"sourcesContent":["'use client'\n\nimport * as ProgressPrimitive from '@radix-ui/react-progress'\nimport type { ComponentProps } from 'react'\nimport { cn } from '../../lib/cn'\n\nexport interface ProgressProps\n extends Omit<ComponentProps<typeof ProgressPrimitive.Root>, 'value'> {\n /**\n * 0100. Omit (or pass `null`) when the duration is genuinely unknown — the\n * bar then sweeps instead of filling, and Radix drops `aria-valuenow` so a\n * screen reader is told \"indeterminate\" rather than a number that is a guess.\n */\n value?: number | null\n /** Names what is progressing. Required: a bare bar announces nothing. */\n label: string\n /** Prints the percentage above the bar. Only meaningful when `value` is set. */\n showValue?: boolean\n}\n\n/**\n * A bar that fills, or sweeps when the end is unknown.\n *\n * Flat: a track in `--stone`, a fill in `--ink`. The White Reset has no\n * gradient and no glow, so the only thing carrying the reading is the boundary\n * between the two.\n *\n * @example\n * <Progress value={62} label=\"Uploading photos\" showValue />\n * @example\n * <Progress label=\"Indexing\" />\n */\nexport function Progress({ value = null, label, showValue = false, className, ...rest }: ProgressProps) {\n const indeterminate = value === null || value === undefined\n const clamped = indeterminate ? 0 : Math.min(100, Math.max(0, value))\n\n return (\n <div className={cn('flex w-full flex-col gap-2', className)}>\n {showValue && !indeterminate && (\n <div className=\"flex items-baseline justify-between mono-meta text-(--ink-3-aa)\">\n <span>{label}</span>\n <span className=\"tabular-nums\">{Math.round(clamped)}%</span>\n </div>\n )}\n <ProgressPrimitive.Root\n value={indeterminate ? null : clamped}\n aria-label={label}\n className=\"relative h-1 w-full overflow-hidden rounded-(--radius-pill) bg-(--stone)\"\n {...rest}\n >\n {indeterminate ? (\n <span\n data-m22-animated\n // A quarter-width bar travelling the track. `transform` only, so it\n // runs on the compositor and never triggers layout. `rtl:-scale-x-100`\n // mirrors the whole motion rather than needing a second keyframe:\n // in a right-to-left document the sweep has to run the other way, or\n // it reads as progress running backwards.\n className=\"absolute inset-y-0 start-0 w-1/4 rounded-(--radius-pill) bg-(--accent) rtl:-scale-x-100 motion-safe:animate-[m22-sweep_1.4s_var(--ease)_infinite] motion-reduce:w-full motion-reduce:opacity-40\"\n />\n ) : (\n <ProgressPrimitive.Indicator\n // Width, not a translate. A `translateX(-N%)` fill has to be negated\n // in a right-to-left document, and an inline style cannot carry a\n // direction variant — so the bar grew from the wrong edge. Width\n // grows from the inline start on its own, in either direction.\n className=\"h-full rounded-(--radius-pill) bg-(--accent) transition-[width] duration-(--duration-slow) ease-(--ease-out-expo)\"\n style={{ width: `${clamped}%` }}\n />\n )}\n </ProgressPrimitive.Root>\n </div>\n )\n}\n\nexport default Progress\n"],"mappings":";AAwCU,cACA,YADA;AAtCV,YAAY,uBAAuB;AAEnC,SAAS,UAAU;AA4BZ,SAAS,SAAS,EAAE,QAAQ,MAAM,OAAO,YAAY,OAAO,WAAW,GAAG,KAAK,GAAkB;AACtG,QAAM,gBAAgB,UAAU,QAAQ,UAAU;AAClD,QAAM,UAAU,gBAAgB,IAAI,KAAK,IAAI,KAAK,KAAK,IAAI,GAAG,KAAK,CAAC;AAEpE,SACE,qBAAC,SAAI,WAAW,GAAG,8BAA8B,SAAS,GACvD;AAAA,iBAAa,CAAC,iBACb,qBAAC,SAAI,WAAU,mEACb;AAAA,0BAAC,UAAM,iBAAM;AAAA,MACb,qBAAC,UAAK,WAAU,gBAAgB;AAAA,aAAK,MAAM,OAAO;AAAA,QAAE;AAAA,SAAC;AAAA,OACvD;AAAA,IAEF;AAAA,MAAC,kBAAkB;AAAA,MAAlB;AAAA,QACC,OAAO,gBAAgB,OAAO;AAAA,QAC9B,cAAY;AAAA,QACZ,WAAU;AAAA,QACT,GAAG;AAAA,QAEH,0BACC;AAAA,UAAC;AAAA;AAAA,YACC,qBAAiB;AAAA,YAMjB,WAAU;AAAA;AAAA,QACZ,IAEA;AAAA,UAAC,kBAAkB;AAAA,UAAlB;AAAA,YAKC,WAAU;AAAA,YACV,OAAO,EAAE,OAAO,GAAG,OAAO,IAAI;AAAA;AAAA,QAChC;AAAA;AAAA,IAEJ;AAAA,KACF;AAEJ;AAEA,IAAO,mBAAQ;","names":[]}
1
+ {"version":3,"sources":["../../../src/components/Progress/Progress.tsx"],"sourcesContent":["'use client'\n\nimport * as ProgressPrimitive from '@radix-ui/react-progress'\nimport type { ComponentProps } from 'react'\nimport { cn } from '../../lib/cn'\nimport { warnBlankName } from '../../lib/warn'\n\nexport interface ProgressProps\n extends Omit<ComponentProps<typeof ProgressPrimitive.Root>, 'value' | 'max'> {\n /**\n * 0 to `max`, which is 100 unless you say otherwise. Omit (or pass `null`)\n * when the duration is genuinely unknown — the bar then sweeps instead of\n * filling, and Radix drops `aria-valuenow` so a screen reader is told\n * \"indeterminate\" rather than a number that is a guess.\n */\n value?: number | null\n /**\n * What `value` is measured against. 100 by default.\n *\n * The width is computed from it as well as announced from it. It used to be\n * only announced: `max` reached Radix through `...rest` while the width was\n * `value` clamped to 100, so `max={500}` with `value={100}` painted a full\n * bar and told a screen reader \"100 of 500\". A max that is not a positive\n * number is refused the way Radix refuses it — Radix warns, and both fall\n * back to 100 rather than drawing one picture and announcing another.\n */\n max?: number\n /** Names what is progressing. Required: a bare bar announces nothing. */\n label: string\n /** Prints the percentage above the bar. Only meaningful when `value` is set. */\n showValue?: boolean\n}\n\n/**\n * A bar that fills, or sweeps when the end is unknown.\n *\n * Flat: a track in `--stone`, a fill in `--ink`. The White Reset has no\n * gradient and no glow, so the only thing carrying the reading is the boundary\n * between the two.\n *\n * @example\n * <Progress value={62} label=\"Uploading photos\" showValue />\n * @example\n * <Progress label=\"Indexing\" />\n */\nexport function Progress({\n value = null,\n max,\n label,\n showValue = false,\n className,\n ...rest\n}: ProgressProps) {\n warnBlankName('Progress', 'label', label, 'the progressbar is announced with no name and its percentage describes nothing')\n const indeterminate = value === null || value === undefined\n // Radix's own test for a usable max, so the fallback below is the same\n // fallback it applies — and `max` is forwarded raw, so Radix still prints the\n // warning rather than this component swallowing a bad prop quietly.\n const ceiling = typeof max === 'number' && !Number.isNaN(max) && max > 0 ? max : 100\n const bounded = indeterminate ? 0 : Math.min(ceiling, Math.max(0, value))\n const percent = (bounded / ceiling) * 100\n\n return (\n <div className={cn('flex w-full flex-col gap-2', className)}>\n {showValue && !indeterminate && (\n <div className=\"flex items-baseline justify-between mono-meta text-(--ink-3-aa)\">\n <span>{label}</span>\n <span className=\"tabular-nums\">{Math.round(percent)}%</span>\n </div>\n )}\n <ProgressPrimitive.Root\n value={indeterminate ? null : bounded}\n max={max}\n aria-label={label}\n className=\"relative h-1 w-full overflow-hidden rounded-(--radius-pill) bg-(--stone)\"\n {...rest}\n >\n {indeterminate ? (\n <span\n data-m22-animated\n // A quarter-width bar travelling the track. `transform` only, so it\n // runs on the compositor and never triggers layout. `rtl:-scale-x-100`\n // mirrors the whole motion rather than needing a second keyframe:\n // in a right-to-left document the sweep has to run the other way, or\n // it reads as progress running backwards.\n //\n // Nothing overrides it under `motion-reduce`, and that is the fix\n // rather than an omission: it used to become `w-full` at 40%\n // opacity, which is the shape of a FINISHED bar at rest, so a\n // reader who asked for less motion was told the operation was done.\n // Still, it is a quarter of the track at the inline start — the\n // same answer Spinner gives, where a ring that has stopped turning\n // still reads as unfinished because it is not a whole circle.\n className=\"absolute inset-y-0 start-0 w-1/4 rounded-(--radius-pill) bg-(--accent) rtl:-scale-x-100 motion-safe:animate-[m22-sweep_1.4s_var(--ease)_infinite]\"\n />\n ) : (\n <ProgressPrimitive.Indicator\n // Width, not a translate. A `translateX(-N%)` fill has to be negated\n // in a right-to-left document, and an inline style cannot carry a\n // direction variant — so the bar grew from the wrong edge. Width\n // grows from the inline start on its own, in either direction.\n className=\"h-full rounded-(--radius-pill) bg-(--accent) transition-[width] duration-(--duration-slow) ease-(--ease-out-expo)\"\n style={{ width: `${percent}%` }}\n />\n )}\n </ProgressPrimitive.Root>\n </div>\n )\n}\n\nexport default Progress\n"],"mappings":";AAkEU,cACA,YADA;AAhEV,YAAY,uBAAuB;AAEnC,SAAS,UAAU;AACnB,SAAS,qBAAqB;AAwCvB,SAAS,SAAS;AAAA,EACvB,QAAQ;AAAA,EACR;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA,GAAG;AACL,GAAkB;AAChB,gBAAc,YAAY,SAAS,OAAO,gFAAgF;AAC1H,QAAM,gBAAgB,UAAU,QAAQ,UAAU;AAIlD,QAAM,UAAU,OAAO,QAAQ,YAAY,CAAC,OAAO,MAAM,GAAG,KAAK,MAAM,IAAI,MAAM;AACjF,QAAM,UAAU,gBAAgB,IAAI,KAAK,IAAI,SAAS,KAAK,IAAI,GAAG,KAAK,CAAC;AACxE,QAAM,UAAW,UAAU,UAAW;AAEtC,SACE,qBAAC,SAAI,WAAW,GAAG,8BAA8B,SAAS,GACvD;AAAA,iBAAa,CAAC,iBACb,qBAAC,SAAI,WAAU,mEACb;AAAA,0BAAC,UAAM,iBAAM;AAAA,MACb,qBAAC,UAAK,WAAU,gBAAgB;AAAA,aAAK,MAAM,OAAO;AAAA,QAAE;AAAA,SAAC;AAAA,OACvD;AAAA,IAEF;AAAA,MAAC,kBAAkB;AAAA,MAAlB;AAAA,QACC,OAAO,gBAAgB,OAAO;AAAA,QAC9B;AAAA,QACA,cAAY;AAAA,QACZ,WAAU;AAAA,QACT,GAAG;AAAA,QAEH,0BACC;AAAA,UAAC;AAAA;AAAA,YACC,qBAAiB;AAAA,YAcjB,WAAU;AAAA;AAAA,QACZ,IAEA;AAAA,UAAC,kBAAkB;AAAA,UAAlB;AAAA,YAKC,WAAU;AAAA,YACV,OAAO,EAAE,OAAO,GAAG,OAAO,IAAI;AAAA;AAAA,QAChC;AAAA;AAAA,IAEJ;AAAA,KACF;AAEJ;AAEA,IAAO,mBAAQ;","names":[]}
@@ -11,6 +11,12 @@ type RadioGroupProps = ComponentProps<typeof RadioGroupPrimitive.Root>;
11
11
  * requires and what a stack of hand-rolled `<input type="radio">` wrappers
12
12
  * usually gets wrong.
13
13
  *
14
+ * Inside a `Field` the group takes its name from that label, by pointing back
15
+ * at it: the root is a `<div role="radiogroup">` and `<label for>` does not bind
16
+ * to one, so the words above it click through no more than a `<legend>` does.
17
+ * Standing alone, it still needs an `aria-label` of its own — an unnamed group
18
+ * is three unlabelled radios.
19
+ *
14
20
  * @example
15
21
  * <RadioGroup defaultValue="light" aria-label="Theme">
16
22
  * <RadioGroupItem value="light">Light</RadioGroupItem>
@@ -3,9 +3,19 @@ import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
4
4
  import { useEffect, useRef } from "react";
5
5
  import { cn } from "../../lib/cn.js";
6
+ import { useFieldControl } from "../Field/field-control.js";
6
7
  const ARROW_GRACE_MS = 300;
7
8
  function RadioGroup({ className, ...props }) {
8
- return /* @__PURE__ */ jsx(RadioGroupPrimitive.Root, { className: cn("flex flex-col gap-2.5", className), ...props });
9
+ const field = useFieldControl();
10
+ const named = props["aria-label"] != null || props["aria-labelledby"] != null;
11
+ return /* @__PURE__ */ jsx(
12
+ RadioGroupPrimitive.Root,
13
+ {
14
+ "aria-labelledby": named ? void 0 : field?.labelId,
15
+ className: cn("flex flex-col gap-2.5", className),
16
+ ...props
17
+ }
18
+ );
9
19
  }
10
20
  function RadioGroupItem({ children, className, id, onFocus, ...props }) {
11
21
  const arrowPressedAt = useRef(0);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/RadioGroup/RadioGroup.tsx"],"sourcesContent":["'use client'\n\nimport * as RadioGroupPrimitive from '@radix-ui/react-radio-group'\nimport { useEffect, useRef, type ComponentProps, type FocusEvent, type ReactNode } from 'react'\nimport { cn } from '../../lib/cn'\n\n/**\n * How recently an arrow key was pressed, in milliseconds, for selection to\n * still count as \"caused by\" it.\n *\n * A boolean cleared on `keyup` — which is how the upstream primitive tracks\n * this — loses the race: the roving focus moves through a React state update,\n * and by the time the commit lands and the element takes focus, a normal\n * keypress has already released. The result is a group whose arrow keys move\n * the outline and select nothing, which is half the ARIA radiogroup pattern\n * missing. A timestamp cannot be cleared out from under the focus handler.\n */\nconst ARROW_GRACE_MS = 300\n\nexport type RadioGroupProps = ComponentProps<typeof RadioGroupPrimitive.Root>\n\n/**\n * A set of mutually exclusive choices.\n *\n * Radix owns the roving tabindex, so the whole group is ONE tab stop and the\n * arrow keys move between options — which is what the ARIA radiogroup pattern\n * requires and what a stack of hand-rolled `<input type=\"radio\">` wrappers\n * usually gets wrong.\n *\n * @example\n * <RadioGroup defaultValue=\"light\" aria-label=\"Theme\">\n * <RadioGroupItem value=\"light\">Light</RadioGroupItem>\n * <RadioGroupItem value=\"dark\">Dark</RadioGroupItem>\n * </RadioGroup>\n */\nexport function RadioGroup({ className, ...props }: RadioGroupProps) {\n return <RadioGroupPrimitive.Root className={cn('flex flex-col gap-2.5', className)} {...props} />\n}\n\nexport interface RadioGroupItemProps\n extends Omit<ComponentProps<typeof RadioGroupPrimitive.Item>, 'children'> {\n /** The visible label. Rendered inside the `<label>` that wraps the control. */\n children: ReactNode\n}\n\n/**\n * One option, and its label, as a single click target.\n *\n * The `<label>` wraps both, so the whole row is clickable — a bare 18px circle\n * is below every pointer-target guideline and is miserable on a phone. It is\n * also what gives the control its accessible name: remove the wrapper and the\n * radio has no name at all.\n *\n * Selection follows focus, which is the half of the pattern that makes a\n * radiogroup usable from the keyboard: moving to an option chooses it, so\n * nobody has to press an extra key to commit. That is implemented here rather\n * than inherited, because the upstream primitive gates it on a flag cleared by\n * `keyup` and loses the race against its own focus move — see ARROW_GRACE_MS.\n * Re-selecting an already-selected option is a no-op, so this stays correct\n * even where the upstream path does fire.\n */\nexport function RadioGroupItem({ children, className, id, onFocus, ...props }: RadioGroupItemProps) {\n const arrowPressedAt = useRef(0)\n\n useEffect(() => {\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key.startsWith('Arrow')) arrowPressedAt.current = Date.now()\n }\n document.addEventListener('keydown', onKeyDown)\n return () => document.removeEventListener('keydown', onKeyDown)\n }, [])\n\n const selectOnArrowFocus = (event: FocusEvent<HTMLButtonElement>) => {\n onFocus?.(event)\n if (Date.now() - arrowPressedAt.current < ARROW_GRACE_MS) event.currentTarget.click()\n }\n\n return (\n <label className={cn('flex cursor-pointer items-center gap-2.5 text-sm text-(--ink-2)', className)}>\n <RadioGroupPrimitive.Item\n id={id}\n onFocus={selectOnArrowFocus}\n className=\"grid size-[18px] shrink-0 place-items-center rounded-full border border-(--rule-2) bg-(--paper) transition-colors duration-(--duration-fast) data-[state=checked]:border-(--accent) disabled:opacity-(--disabled-opacity) disabled:pointer-events-none\"\n {...props}\n >\n <RadioGroupPrimitive.Indicator className=\"size-2.5 rounded-full bg-(--accent)\" />\n </RadioGroupPrimitive.Item>\n {children}\n </label>\n )\n}\n\nexport default RadioGroup\n"],"mappings":";AAoCS,cA0CL,YA1CK;AAlCT,YAAY,yBAAyB;AACrC,SAAS,WAAW,cAAoE;AACxF,SAAS,UAAU;AAanB,MAAM,iBAAiB;AAkBhB,SAAS,WAAW,EAAE,WAAW,GAAG,MAAM,GAAoB;AACnE,SAAO,oBAAC,oBAAoB,MAApB,EAAyB,WAAW,GAAG,yBAAyB,SAAS,GAAI,GAAG,OAAO;AACjG;AAwBO,SAAS,eAAe,EAAE,UAAU,WAAW,IAAI,SAAS,GAAG,MAAM,GAAwB;AAClG,QAAM,iBAAiB,OAAO,CAAC;AAE/B,YAAU,MAAM;AACd,UAAM,YAAY,CAAC,UAAyB;AAC1C,UAAI,MAAM,IAAI,WAAW,OAAO,EAAG,gBAAe,UAAU,KAAK,IAAI;AAAA,IACvE;AACA,aAAS,iBAAiB,WAAW,SAAS;AAC9C,WAAO,MAAM,SAAS,oBAAoB,WAAW,SAAS;AAAA,EAChE,GAAG,CAAC,CAAC;AAEL,QAAM,qBAAqB,CAAC,UAAyC;AACnE,cAAU,KAAK;AACf,QAAI,KAAK,IAAI,IAAI,eAAe,UAAU,eAAgB,OAAM,cAAc,MAAM;AAAA,EACtF;AAEA,SACE,qBAAC,WAAM,WAAW,GAAG,mEAAmE,SAAS,GAC/F;AAAA;AAAA,MAAC,oBAAoB;AAAA,MAApB;AAAA,QACC;AAAA,QACA,SAAS;AAAA,QACT,WAAU;AAAA,QACT,GAAG;AAAA,QAEJ,8BAAC,oBAAoB,WAApB,EAA8B,WAAU,uCAAsC;AAAA;AAAA,IACjF;AAAA,IACC;AAAA,KACH;AAEJ;AAEA,IAAO,qBAAQ;","names":[]}
1
+ {"version":3,"sources":["../../../src/components/RadioGroup/RadioGroup.tsx"],"sourcesContent":["'use client'\n\nimport * as RadioGroupPrimitive from '@radix-ui/react-radio-group'\nimport { useEffect, useRef, type ComponentProps, type FocusEvent, type ReactNode } from 'react'\nimport { cn } from '../../lib/cn'\nimport { useFieldControl } from '../Field/field-control'\n\n/**\n * How recently an arrow key was pressed, in milliseconds, for selection to\n * still count as \"caused by\" it.\n *\n * A boolean cleared on `keyup` — which is how the upstream primitive tracks\n * this — loses the race: the roving focus moves through a React state update,\n * and by the time the commit lands and the element takes focus, a normal\n * keypress has already released. The result is a group whose arrow keys move\n * the outline and select nothing, which is half the ARIA radiogroup pattern\n * missing. A timestamp cannot be cleared out from under the focus handler.\n */\nconst ARROW_GRACE_MS = 300\n\nexport type RadioGroupProps = ComponentProps<typeof RadioGroupPrimitive.Root>\n\n/**\n * A set of mutually exclusive choices.\n *\n * Radix owns the roving tabindex, so the whole group is ONE tab stop and the\n * arrow keys move between options — which is what the ARIA radiogroup pattern\n * requires and what a stack of hand-rolled `<input type=\"radio\">` wrappers\n * usually gets wrong.\n *\n * Inside a `Field` the group takes its name from that label, by pointing back\n * at it: the root is a `<div role=\"radiogroup\">` and `<label for>` does not bind\n * to one, so the words above it click through no more than a `<legend>` does.\n * Standing alone, it still needs an `aria-label` of its own — an unnamed group\n * is three unlabelled radios.\n *\n * @example\n * <RadioGroup defaultValue=\"light\" aria-label=\"Theme\">\n * <RadioGroupItem value=\"light\">Light</RadioGroupItem>\n * <RadioGroupItem value=\"dark\">Dark</RadioGroupItem>\n * </RadioGroup>\n */\nexport function RadioGroup({ className, ...props }: RadioGroupProps) {\n const field = useFieldControl()\n const named = props['aria-label'] != null || props['aria-labelledby'] != null\n\n return (\n <RadioGroupPrimitive.Root\n aria-labelledby={named ? undefined : field?.labelId}\n className={cn('flex flex-col gap-2.5', className)}\n {...props}\n />\n )\n}\n\nexport interface RadioGroupItemProps\n extends Omit<ComponentProps<typeof RadioGroupPrimitive.Item>, 'children'> {\n /** The visible label. Rendered inside the `<label>` that wraps the control. */\n children: ReactNode\n}\n\n/**\n * One option, and its label, as a single click target.\n *\n * The `<label>` wraps both, so the whole row is clickable — a bare 18px circle\n * is below every pointer-target guideline and is miserable on a phone. It is\n * also what gives the control its accessible name: remove the wrapper and the\n * radio has no name at all.\n *\n * Selection follows focus, which is the half of the pattern that makes a\n * radiogroup usable from the keyboard: moving to an option chooses it, so\n * nobody has to press an extra key to commit. That is implemented here rather\n * than inherited, because the upstream primitive gates it on a flag cleared by\n * `keyup` and loses the race against its own focus move — see ARROW_GRACE_MS.\n * Re-selecting an already-selected option is a no-op, so this stays correct\n * even where the upstream path does fire.\n */\nexport function RadioGroupItem({ children, className, id, onFocus, ...props }: RadioGroupItemProps) {\n const arrowPressedAt = useRef(0)\n\n useEffect(() => {\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key.startsWith('Arrow')) arrowPressedAt.current = Date.now()\n }\n document.addEventListener('keydown', onKeyDown)\n return () => document.removeEventListener('keydown', onKeyDown)\n }, [])\n\n const selectOnArrowFocus = (event: FocusEvent<HTMLButtonElement>) => {\n onFocus?.(event)\n if (Date.now() - arrowPressedAt.current < ARROW_GRACE_MS) event.currentTarget.click()\n }\n\n return (\n <label className={cn('flex cursor-pointer items-center gap-2.5 text-sm text-(--ink-2)', className)}>\n <RadioGroupPrimitive.Item\n id={id}\n onFocus={selectOnArrowFocus}\n className=\"grid size-[18px] shrink-0 place-items-center rounded-full border border-(--rule-2) bg-(--paper) transition-colors duration-(--duration-fast) data-[state=checked]:border-(--accent) disabled:opacity-(--disabled-opacity) disabled:pointer-events-none\"\n {...props}\n >\n <RadioGroupPrimitive.Indicator className=\"size-2.5 rounded-full bg-(--accent)\" />\n </RadioGroupPrimitive.Item>\n {children}\n </label>\n )\n}\n\nexport default RadioGroup\n"],"mappings":";AA+CI,cA+CA,YA/CA;AA7CJ,YAAY,yBAAyB;AACrC,SAAS,WAAW,cAAoE;AACxF,SAAS,UAAU;AACnB,SAAS,uBAAuB;AAahC,MAAM,iBAAiB;AAwBhB,SAAS,WAAW,EAAE,WAAW,GAAG,MAAM,GAAoB;AACnE,QAAM,QAAQ,gBAAgB;AAC9B,QAAM,QAAQ,MAAM,YAAY,KAAK,QAAQ,MAAM,iBAAiB,KAAK;AAEzE,SACE;AAAA,IAAC,oBAAoB;AAAA,IAApB;AAAA,MACC,mBAAiB,QAAQ,SAAY,OAAO;AAAA,MAC5C,WAAW,GAAG,yBAAyB,SAAS;AAAA,MAC/C,GAAG;AAAA;AAAA,EACN;AAEJ;AAwBO,SAAS,eAAe,EAAE,UAAU,WAAW,IAAI,SAAS,GAAG,MAAM,GAAwB;AAClG,QAAM,iBAAiB,OAAO,CAAC;AAE/B,YAAU,MAAM;AACd,UAAM,YAAY,CAAC,UAAyB;AAC1C,UAAI,MAAM,IAAI,WAAW,OAAO,EAAG,gBAAe,UAAU,KAAK,IAAI;AAAA,IACvE;AACA,aAAS,iBAAiB,WAAW,SAAS;AAC9C,WAAO,MAAM,SAAS,oBAAoB,WAAW,SAAS;AAAA,EAChE,GAAG,CAAC,CAAC;AAEL,QAAM,qBAAqB,CAAC,UAAyC;AACnE,cAAU,KAAK;AACf,QAAI,KAAK,IAAI,IAAI,eAAe,UAAU,eAAgB,OAAM,cAAc,MAAM;AAAA,EACtF;AAEA,SACE,qBAAC,WAAM,WAAW,GAAG,mEAAmE,SAAS,GAC/F;AAAA;AAAA,MAAC,oBAAoB;AAAA,MAApB;AAAA,QACC;AAAA,QACA,SAAS;AAAA,QACT,WAAU;AAAA,QACT,GAAG;AAAA,QAEJ,8BAAC,oBAAoB,WAApB,EAA8B,WAAU,uCAAsC;AAAA;AAAA,IACjF;AAAA,IACC;AAAA,KACH;AAEJ;AAEA,IAAO,qBAAQ;","names":[]}