@misoto22/folio 0.0.0 → 0.16.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 (686) hide show
  1. package/AGENTS.md +88 -0
  2. package/CLAUDE.md +1 -0
  3. package/LICENSE +21 -0
  4. package/README.md +208 -2
  5. package/bin/folio-design.mjs +277 -0
  6. package/bin/migrate-legacy.mjs +81 -0
  7. package/dist/agent/Accordion.md +65 -0
  8. package/dist/agent/Actions.md +49 -0
  9. package/dist/agent/Alert.md +65 -0
  10. package/dist/agent/AppShell.md +69 -0
  11. package/dist/agent/ArchitectureFigure.md +72 -0
  12. package/dist/agent/AreaChart.md +94 -0
  13. package/dist/agent/Article.md +65 -0
  14. package/dist/agent/AspectRatio.md +58 -0
  15. package/dist/agent/Avatar.md +53 -0
  16. package/dist/agent/Badge.md +62 -0
  17. package/dist/agent/BarChart.md +93 -0
  18. package/dist/agent/BarList.md +67 -0
  19. package/dist/agent/BigNumber.md +70 -0
  20. package/dist/agent/BoxPlot.md +82 -0
  21. package/dist/agent/Breadcrumb.md +55 -0
  22. package/dist/agent/BulletChart.md +71 -0
  23. package/dist/agent/Button.md +81 -0
  24. package/dist/agent/Calendar.md +77 -0
  25. package/dist/agent/CalendarHeatmap.md +75 -0
  26. package/dist/agent/Card.md +72 -0
  27. package/dist/agent/Checkbox.md +57 -0
  28. package/dist/agent/Code.md +51 -0
  29. package/dist/agent/CodeBlock.md +77 -0
  30. package/dist/agent/Collapsible.md +68 -0
  31. package/dist/agent/Collection.md +169 -0
  32. package/dist/agent/ColorPicker.md +76 -0
  33. package/dist/agent/Combobox.md +77 -0
  34. package/dist/agent/Command.md +122 -0
  35. package/dist/agent/ComposedChart.md +82 -0
  36. package/dist/agent/Contact.md +90 -0
  37. package/dist/agent/Content.md +70 -0
  38. package/dist/agent/ContextMenu.md +93 -0
  39. package/dist/agent/Conversation.md +247 -0
  40. package/dist/agent/DataflowFigure.md +49 -0
  41. package/dist/agent/DatePicker.md +104 -0
  42. package/dist/agent/DescriptionList.md +69 -0
  43. package/dist/agent/Diagram.md +71 -0
  44. package/dist/agent/DiagramCanvas.md +71 -0
  45. package/dist/agent/DiagramExportMenu.md +65 -0
  46. package/dist/agent/DiagramInspector.md +73 -0
  47. package/dist/agent/DiagramLegend.md +56 -0
  48. package/dist/agent/DiagramMinimap.md +69 -0
  49. package/dist/agent/DiagramToolbar.md +70 -0
  50. package/dist/agent/Dialog.md +76 -0
  51. package/dist/agent/DropdownMenu.md +110 -0
  52. package/dist/agent/EmptyState.md +63 -0
  53. package/dist/agent/ErrorState.md +67 -0
  54. package/dist/agent/Evidence.md +165 -0
  55. package/dist/agent/Facet.md +107 -0
  56. package/dist/agent/Field.md +79 -0
  57. package/dist/agent/FigureBand.md +49 -0
  58. package/dist/agent/FloatingIconButton.md +61 -0
  59. package/dist/agent/FunnelChart.md +75 -0
  60. package/dist/agent/Heading.md +65 -0
  61. package/dist/agent/Heatmap.md +78 -0
  62. package/dist/agent/Histogram.md +88 -0
  63. package/dist/agent/Input.md +52 -0
  64. package/dist/agent/Kbd.md +48 -0
  65. package/dist/agent/LifecycleFigure.md +50 -0
  66. package/dist/agent/LineChart.md +85 -0
  67. package/dist/agent/LinkArrow.md +49 -0
  68. package/dist/agent/Markdown.md +69 -0
  69. package/dist/agent/Media.md +261 -0
  70. package/dist/agent/Metric.md +70 -0
  71. package/dist/agent/Metrics.md +114 -0
  72. package/dist/agent/Music.md +86 -0
  73. package/dist/agent/NativeSelect.md +62 -0
  74. package/dist/agent/NavItem.md +56 -0
  75. package/dist/agent/NumberField.md +73 -0
  76. package/dist/agent/PageHeader.md +69 -0
  77. package/dist/agent/Pagination.md +70 -0
  78. package/dist/agent/PieChart.md +80 -0
  79. package/dist/agent/Popover.md +80 -0
  80. package/dist/agent/Portfolio.md +93 -0
  81. package/dist/agent/PortfolioIndex.md +34 -0
  82. package/dist/agent/Progress.md +58 -0
  83. package/dist/agent/RadarChart.md +79 -0
  84. package/dist/agent/RadialChart.md +81 -0
  85. package/dist/agent/RadioGroup.md +66 -0
  86. package/dist/agent/Reading.md +233 -0
  87. package/dist/agent/Recovery.md +72 -0
  88. package/dist/agent/SankeyChart.md +85 -0
  89. package/dist/agent/ScatterChart.md +80 -0
  90. package/dist/agent/ScrollArea.md +62 -0
  91. package/dist/agent/SearchPalette.md +51 -0
  92. package/dist/agent/SearchableMenu.md +69 -0
  93. package/dist/agent/Select.md +102 -0
  94. package/dist/agent/Separator.md +60 -0
  95. package/dist/agent/SequenceFigure.md +51 -0
  96. package/dist/agent/Sheet.md +82 -0
  97. package/dist/agent/Sidebar.md +194 -0
  98. package/dist/agent/SiteNavigation.md +62 -0
  99. package/dist/agent/SiteShell.md +67 -0
  100. package/dist/agent/Skeleton.md +96 -0
  101. package/dist/agent/Slider.md +67 -0
  102. package/dist/agent/Sparkline.md +68 -0
  103. package/dist/agent/Spinner.md +62 -0
  104. package/dist/agent/StatusDot.md +56 -0
  105. package/dist/agent/StatusPill.md +55 -0
  106. package/dist/agent/Steps.md +68 -0
  107. package/dist/agent/Switch.md +50 -0
  108. package/dist/agent/Table.md +111 -0
  109. package/dist/agent/Tabs.md +71 -0
  110. package/dist/agent/Tag.md +67 -0
  111. package/dist/agent/Text.md +66 -0
  112. package/dist/agent/Textarea.md +46 -0
  113. package/dist/agent/Timeline.md +114 -0
  114. package/dist/agent/Timestamp.md +65 -0
  115. package/dist/agent/Toast.md +51 -0
  116. package/dist/agent/ToggleGroup.md +67 -0
  117. package/dist/agent/Toolbar.md +72 -0
  118. package/dist/agent/Tooltip.md +74 -0
  119. package/dist/agent/TreemapChart.md +76 -0
  120. package/dist/agent/WaterfallChart.md +86 -0
  121. package/dist/agent/WorkflowFigure.md +51 -0
  122. package/dist/agent/catalog.json +8006 -0
  123. package/dist/agent/index.md +182 -0
  124. package/dist/article.css +407 -0
  125. package/dist/charts/AreaChart/AreaChart.d.ts +198 -0
  126. package/dist/charts/AreaChart/AreaChart.js +479 -0
  127. package/dist/charts/AreaChart/AreaChart.js.map +1 -0
  128. package/dist/charts/BarChart/BarChart.d.ts +190 -0
  129. package/dist/charts/BarChart/BarChart.js +599 -0
  130. package/dist/charts/BarChart/BarChart.js.map +1 -0
  131. package/dist/charts/BarList/BarList.d.ts +65 -0
  132. package/dist/charts/BarList/BarList.js +79 -0
  133. package/dist/charts/BarList/BarList.js.map +1 -0
  134. package/dist/charts/BigNumber/BigNumber.d.ts +72 -0
  135. package/dist/charts/BigNumber/BigNumber.js +51 -0
  136. package/dist/charts/BigNumber/BigNumber.js.map +1 -0
  137. package/dist/charts/BoxPlot/BoxPlot.d.ts +177 -0
  138. package/dist/charts/BoxPlot/BoxPlot.js +497 -0
  139. package/dist/charts/BoxPlot/BoxPlot.js.map +1 -0
  140. package/dist/charts/BulletChart/BulletChart.d.ts +100 -0
  141. package/dist/charts/BulletChart/BulletChart.js +197 -0
  142. package/dist/charts/BulletChart/BulletChart.js.map +1 -0
  143. package/dist/charts/CalendarHeatmap/CalendarHeatmap.d.ts +106 -0
  144. package/dist/charts/CalendarHeatmap/CalendarHeatmap.js +103 -0
  145. package/dist/charts/CalendarHeatmap/CalendarHeatmap.js.map +1 -0
  146. package/dist/charts/ComposedChart/ComposedChart.d.ts +178 -0
  147. package/dist/charts/ComposedChart/ComposedChart.js +667 -0
  148. package/dist/charts/ComposedChart/ComposedChart.js.map +1 -0
  149. package/dist/charts/Facet/Facet.d.ts +240 -0
  150. package/dist/charts/Facet/Facet.js +133 -0
  151. package/dist/charts/Facet/Facet.js.map +1 -0
  152. package/dist/charts/Facet/panels.d.ts +187 -0
  153. package/dist/charts/Facet/panels.js +203 -0
  154. package/dist/charts/Facet/panels.js.map +1 -0
  155. package/dist/charts/FunnelChart/FunnelChart.d.ts +106 -0
  156. package/dist/charts/FunnelChart/FunnelChart.js +137 -0
  157. package/dist/charts/FunnelChart/FunnelChart.js.map +1 -0
  158. package/dist/charts/Heatmap/Heatmap.d.ts +101 -0
  159. package/dist/charts/Heatmap/Heatmap.js +125 -0
  160. package/dist/charts/Heatmap/Heatmap.js.map +1 -0
  161. package/dist/charts/Histogram/Histogram.d.ts +188 -0
  162. package/dist/charts/Histogram/Histogram.js +382 -0
  163. package/dist/charts/Histogram/Histogram.js.map +1 -0
  164. package/dist/charts/LineChart/LineChart.d.ts +174 -0
  165. package/dist/charts/LineChart/LineChart.js +485 -0
  166. package/dist/charts/LineChart/LineChart.js.map +1 -0
  167. package/dist/charts/PieChart/PieChart.d.ts +140 -0
  168. package/dist/charts/PieChart/PieChart.js +317 -0
  169. package/dist/charts/PieChart/PieChart.js.map +1 -0
  170. package/dist/charts/RadarChart/RadarChart.d.ts +135 -0
  171. package/dist/charts/RadarChart/RadarChart.js +303 -0
  172. package/dist/charts/RadarChart/RadarChart.js.map +1 -0
  173. package/dist/charts/RadialChart/RadialChart.d.ts +142 -0
  174. package/dist/charts/RadialChart/RadialChart.js +279 -0
  175. package/dist/charts/RadialChart/RadialChart.js.map +1 -0
  176. package/dist/charts/SankeyChart/SankeyChart.d.ts +149 -0
  177. package/dist/charts/SankeyChart/SankeyChart.js +509 -0
  178. package/dist/charts/SankeyChart/SankeyChart.js.map +1 -0
  179. package/dist/charts/ScatterChart/ScatterChart.d.ts +149 -0
  180. package/dist/charts/ScatterChart/ScatterChart.js +275 -0
  181. package/dist/charts/ScatterChart/ScatterChart.js.map +1 -0
  182. package/dist/charts/Sparkline/Sparkline.d.ts +53 -0
  183. package/dist/charts/Sparkline/Sparkline.js +95 -0
  184. package/dist/charts/Sparkline/Sparkline.js.map +1 -0
  185. package/dist/charts/TreemapChart/TreemapChart.d.ts +98 -0
  186. package/dist/charts/TreemapChart/TreemapChart.js +127 -0
  187. package/dist/charts/TreemapChart/TreemapChart.js.map +1 -0
  188. package/dist/charts/WaterfallChart/WaterfallChart.d.ts +164 -0
  189. package/dist/charts/WaterfallChart/WaterfallChart.js +321 -0
  190. package/dist/charts/WaterfallChart/WaterfallChart.js.map +1 -0
  191. package/dist/charts/index.d.ts +43 -0
  192. package/dist/charts/index.js +130 -0
  193. package/dist/charts/index.js.map +1 -0
  194. package/dist/charts/lib/annotations.d.ts +103 -0
  195. package/dist/charts/lib/annotations.js +99 -0
  196. package/dist/charts/lib/annotations.js.map +1 -0
  197. package/dist/charts/lib/axis.d.ts +18 -0
  198. package/dist/charts/lib/axis.js +21 -0
  199. package/dist/charts/lib/axis.js.map +1 -0
  200. package/dist/charts/lib/background.d.ts +33 -0
  201. package/dist/charts/lib/background.js +173 -0
  202. package/dist/charts/lib/background.js.map +1 -0
  203. package/dist/charts/lib/brush.d.ts +94 -0
  204. package/dist/charts/lib/brush.js +535 -0
  205. package/dist/charts/lib/brush.js.map +1 -0
  206. package/dist/charts/lib/chart.d.ts +94 -0
  207. package/dist/charts/lib/chart.js +149 -0
  208. package/dist/charts/lib/chart.js.map +1 -0
  209. package/dist/charts/lib/dot.d.ts +29 -0
  210. package/dist/charts/lib/dot.js +78 -0
  211. package/dist/charts/lib/dot.js.map +1 -0
  212. package/dist/charts/lib/empty.d.ts +31 -0
  213. package/dist/charts/lib/empty.js +24 -0
  214. package/dist/charts/lib/empty.js.map +1 -0
  215. package/dist/charts/lib/export.d.ts +94 -0
  216. package/dist/charts/lib/export.js +62 -0
  217. package/dist/charts/lib/export.js.map +1 -0
  218. package/dist/charts/lib/figure.d.ts +81 -0
  219. package/dist/charts/lib/figure.js +62 -0
  220. package/dist/charts/lib/figure.js.map +1 -0
  221. package/dist/charts/lib/format.d.ts +46 -0
  222. package/dist/charts/lib/format.js +56 -0
  223. package/dist/charts/lib/format.js.map +1 -0
  224. package/dist/charts/lib/legend.d.ts +45 -0
  225. package/dist/charts/lib/legend.js +117 -0
  226. package/dist/charts/lib/legend.js.map +1 -0
  227. package/dist/charts/lib/loading.d.ts +48 -0
  228. package/dist/charts/lib/loading.js +105 -0
  229. package/dist/charts/lib/loading.js.map +1 -0
  230. package/dist/charts/lib/paint.d.ts +154 -0
  231. package/dist/charts/lib/paint.js +551 -0
  232. package/dist/charts/lib/paint.js.map +1 -0
  233. package/dist/charts/lib/scale.d.ts +23 -0
  234. package/dist/charts/lib/scale.js +13 -0
  235. package/dist/charts/lib/scale.js.map +1 -0
  236. package/dist/charts/lib/selection.d.ts +20 -0
  237. package/dist/charts/lib/selection.js +18 -0
  238. package/dist/charts/lib/selection.js.map +1 -0
  239. package/dist/charts/lib/sonify-control.d.ts +163 -0
  240. package/dist/charts/lib/sonify-control.js +172 -0
  241. package/dist/charts/lib/sonify-control.js.map +1 -0
  242. package/dist/charts/lib/sonify.d.ts +248 -0
  243. package/dist/charts/lib/sonify.js +262 -0
  244. package/dist/charts/lib/sonify.js.map +1 -0
  245. package/dist/charts/lib/toolbar.d.ts +144 -0
  246. package/dist/charts/lib/toolbar.js +156 -0
  247. package/dist/charts/lib/toolbar.js.map +1 -0
  248. package/dist/charts/lib/tooltip.d.ts +59 -0
  249. package/dist/charts/lib/tooltip.js +135 -0
  250. package/dist/charts/lib/tooltip.js.map +1 -0
  251. package/dist/charts/lib/values.d.ts +56 -0
  252. package/dist/charts/lib/values.js +71 -0
  253. package/dist/charts/lib/values.js.map +1 -0
  254. package/dist/charts/lib/zoom.d.ts +139 -0
  255. package/dist/charts/lib/zoom.js +314 -0
  256. package/dist/charts/lib/zoom.js.map +1 -0
  257. package/dist/components/Accordion/Accordion.d.ts +34 -0
  258. package/dist/components/Accordion/Accordion.js +43 -0
  259. package/dist/components/Accordion/Accordion.js.map +1 -0
  260. package/dist/components/Alert/Alert.d.ts +32 -0
  261. package/dist/components/Alert/Alert.js +49 -0
  262. package/dist/components/Alert/Alert.js.map +1 -0
  263. package/dist/components/AppShell/AppShell.d.ts +58 -0
  264. package/dist/components/AppShell/AppShell.js +126 -0
  265. package/dist/components/AppShell/AppShell.js.map +1 -0
  266. package/dist/components/Article/Article.d.ts +58 -0
  267. package/dist/components/Article/Article.js +34 -0
  268. package/dist/components/Article/Article.js.map +1 -0
  269. package/dist/components/AspectRatio/AspectRatio.d.ts +46 -0
  270. package/dist/components/AspectRatio/AspectRatio.js +33 -0
  271. package/dist/components/AspectRatio/AspectRatio.js.map +1 -0
  272. package/dist/components/Avatar/Avatar.d.ts +38 -0
  273. package/dist/components/Avatar/Avatar.js +44 -0
  274. package/dist/components/Avatar/Avatar.js.map +1 -0
  275. package/dist/components/Badge/Badge.d.ts +30 -0
  276. package/dist/components/Badge/Badge.js +29 -0
  277. package/dist/components/Badge/Badge.js.map +1 -0
  278. package/dist/components/Breadcrumb/Breadcrumb.d.ts +37 -0
  279. package/dist/components/Breadcrumb/Breadcrumb.js +46 -0
  280. package/dist/components/Breadcrumb/Breadcrumb.js.map +1 -0
  281. package/dist/components/Button/Button.d.ts +70 -0
  282. package/dist/components/Button/Button.js +95 -0
  283. package/dist/components/Button/Button.js.map +1 -0
  284. package/dist/components/Calendar/Calendar.d.ts +54 -0
  285. package/dist/components/Calendar/Calendar.js +369 -0
  286. package/dist/components/Calendar/Calendar.js.map +1 -0
  287. package/dist/components/Card/Card.d.ts +55 -0
  288. package/dist/components/Card/Card.js +64 -0
  289. package/dist/components/Card/Card.js.map +1 -0
  290. package/dist/components/Checkbox/Checkbox.d.ts +26 -0
  291. package/dist/components/Checkbox/Checkbox.js +34 -0
  292. package/dist/components/Checkbox/Checkbox.js.map +1 -0
  293. package/dist/components/Code/Code.d.ts +30 -0
  294. package/dist/components/Code/Code.js +21 -0
  295. package/dist/components/Code/Code.js.map +1 -0
  296. package/dist/components/CodeBlock/CodeBlock.d.ts +145 -0
  297. package/dist/components/CodeBlock/CodeBlock.js +114 -0
  298. package/dist/components/CodeBlock/CodeBlock.js.map +1 -0
  299. package/dist/components/Collapsible/Collapsible.d.ts +45 -0
  300. package/dist/components/Collapsible/Collapsible.js +60 -0
  301. package/dist/components/Collapsible/Collapsible.js.map +1 -0
  302. package/dist/components/ColorPicker/ColorPicker.d.ts +67 -0
  303. package/dist/components/ColorPicker/ColorPicker.js +334 -0
  304. package/dist/components/ColorPicker/ColorPicker.js.map +1 -0
  305. package/dist/components/Combobox/Combobox.d.ts +77 -0
  306. package/dist/components/Combobox/Combobox.js +170 -0
  307. package/dist/components/Combobox/Combobox.js.map +1 -0
  308. package/dist/components/Command/Command.d.ts +125 -0
  309. package/dist/components/Command/Command.js +204 -0
  310. package/dist/components/Command/Command.js.map +1 -0
  311. package/dist/components/ContextMenu/ContextMenu.d.ts +63 -0
  312. package/dist/components/ContextMenu/ContextMenu.js +109 -0
  313. package/dist/components/ContextMenu/ContextMenu.js.map +1 -0
  314. package/dist/components/DatePicker/DatePicker.d.ts +130 -0
  315. package/dist/components/DatePicker/DatePicker.js +257 -0
  316. package/dist/components/DatePicker/DatePicker.js.map +1 -0
  317. package/dist/components/DescriptionList/DescriptionList.d.ts +73 -0
  318. package/dist/components/DescriptionList/DescriptionList.js +35 -0
  319. package/dist/components/DescriptionList/DescriptionList.js.map +1 -0
  320. package/dist/components/Diagram/Diagram.d.ts +86 -0
  321. package/dist/components/Diagram/Diagram.js +211 -0
  322. package/dist/components/Diagram/Diagram.js.map +1 -0
  323. package/dist/components/Dialog/Dialog.d.ts +63 -0
  324. package/dist/components/Dialog/Dialog.js +90 -0
  325. package/dist/components/Dialog/Dialog.js.map +1 -0
  326. package/dist/components/DropdownMenu/DropdownMenu.d.ts +87 -0
  327. package/dist/components/DropdownMenu/DropdownMenu.js +120 -0
  328. package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -0
  329. package/dist/components/EmptyState/EmptyState.d.ts +55 -0
  330. package/dist/components/EmptyState/EmptyState.js +32 -0
  331. package/dist/components/EmptyState/EmptyState.js.map +1 -0
  332. package/dist/components/ErrorState/ErrorState.d.ts +55 -0
  333. package/dist/components/ErrorState/ErrorState.js +41 -0
  334. package/dist/components/ErrorState/ErrorState.js.map +1 -0
  335. package/dist/components/Field/Field.d.ts +111 -0
  336. package/dist/components/Field/Field.js +95 -0
  337. package/dist/components/Field/Field.js.map +1 -0
  338. package/dist/components/Field/field-control.d.ts +31 -0
  339. package/dist/components/Field/field-control.js +12 -0
  340. package/dist/components/Field/field-control.js.map +1 -0
  341. package/dist/components/FigureBand/FigureBand.d.ts +31 -0
  342. package/dist/components/FigureBand/FigureBand.js +51 -0
  343. package/dist/components/FigureBand/FigureBand.js.map +1 -0
  344. package/dist/components/FloatingIconButton/FloatingIconButton.d.ts +29 -0
  345. package/dist/components/FloatingIconButton/FloatingIconButton.js +34 -0
  346. package/dist/components/FloatingIconButton/FloatingIconButton.js.map +1 -0
  347. package/dist/components/Heading/Heading.d.ts +62 -0
  348. package/dist/components/Heading/Heading.js +44 -0
  349. package/dist/components/Heading/Heading.js.map +1 -0
  350. package/dist/components/Input/Input.d.ts +22 -0
  351. package/dist/components/Input/Input.js +21 -0
  352. package/dist/components/Input/Input.js.map +1 -0
  353. package/dist/components/Kbd/Kbd.d.ts +27 -0
  354. package/dist/components/Kbd/Kbd.js +21 -0
  355. package/dist/components/Kbd/Kbd.js.map +1 -0
  356. package/dist/components/LinkArrow/LinkArrow.d.ts +24 -0
  357. package/dist/components/LinkArrow/LinkArrow.js +24 -0
  358. package/dist/components/LinkArrow/LinkArrow.js.map +1 -0
  359. package/dist/components/Markdown/Markdown.d.ts +139 -0
  360. package/dist/components/Markdown/Markdown.js +135 -0
  361. package/dist/components/Markdown/Markdown.js.map +1 -0
  362. package/dist/components/Markdown/inline.d.ts +29 -0
  363. package/dist/components/Markdown/inline.js +74 -0
  364. package/dist/components/Markdown/inline.js.map +1 -0
  365. package/dist/components/Markdown/nodes.d.ts +65 -0
  366. package/dist/components/Markdown/nodes.js +1 -0
  367. package/dist/components/Markdown/nodes.js.map +1 -0
  368. package/dist/components/Markdown/parse.d.ts +24 -0
  369. package/dist/components/Markdown/parse.js +110 -0
  370. package/dist/components/Markdown/parse.js.map +1 -0
  371. package/dist/components/Markdown/slug.d.ts +15 -0
  372. package/dist/components/Markdown/slug.js +7 -0
  373. package/dist/components/Markdown/slug.js.map +1 -0
  374. package/dist/components/Metric/Metric.d.ts +61 -0
  375. package/dist/components/Metric/Metric.js +51 -0
  376. package/dist/components/Metric/Metric.js.map +1 -0
  377. package/dist/components/NativeSelect/NativeSelect.d.ts +33 -0
  378. package/dist/components/NativeSelect/NativeSelect.js +44 -0
  379. package/dist/components/NativeSelect/NativeSelect.js.map +1 -0
  380. package/dist/components/NavItem/NavItem.d.ts +39 -0
  381. package/dist/components/NavItem/NavItem.js +31 -0
  382. package/dist/components/NavItem/NavItem.js.map +1 -0
  383. package/dist/components/NumberField/NumberField.d.ts +69 -0
  384. package/dist/components/NumberField/NumberField.js +162 -0
  385. package/dist/components/NumberField/NumberField.js.map +1 -0
  386. package/dist/components/PageHeader/PageHeader.d.ts +92 -0
  387. package/dist/components/PageHeader/PageHeader.js +37 -0
  388. package/dist/components/PageHeader/PageHeader.js.map +1 -0
  389. package/dist/components/Pagination/Pagination.d.ts +67 -0
  390. package/dist/components/Pagination/Pagination.js +112 -0
  391. package/dist/components/Pagination/Pagination.js.map +1 -0
  392. package/dist/components/Popover/Popover.d.ts +39 -0
  393. package/dist/components/Popover/Popover.js +57 -0
  394. package/dist/components/Popover/Popover.js.map +1 -0
  395. package/dist/components/Progress/Progress.d.ts +43 -0
  396. package/dist/components/Progress/Progress.js +57 -0
  397. package/dist/components/Progress/Progress.js.map +1 -0
  398. package/dist/components/RadioGroup/RadioGroup.d.ts +49 -0
  399. package/dist/components/RadioGroup/RadioGroup.js +53 -0
  400. package/dist/components/RadioGroup/RadioGroup.js.map +1 -0
  401. package/dist/components/ScrollArea/ScrollArea.d.ts +46 -0
  402. package/dist/components/ScrollArea/ScrollArea.js +54 -0
  403. package/dist/components/ScrollArea/ScrollArea.js.map +1 -0
  404. package/dist/components/SearchableMenu/SearchableMenu.d.ts +68 -0
  405. package/dist/components/SearchableMenu/SearchableMenu.js +101 -0
  406. package/dist/components/SearchableMenu/SearchableMenu.js.map +1 -0
  407. package/dist/components/Select/Select.d.ts +87 -0
  408. package/dist/components/Select/Select.js +130 -0
  409. package/dist/components/Select/Select.js.map +1 -0
  410. package/dist/components/Separator/Separator.d.ts +48 -0
  411. package/dist/components/Separator/Separator.js +43 -0
  412. package/dist/components/Separator/Separator.js.map +1 -0
  413. package/dist/components/Sheet/Sheet.d.ts +43 -0
  414. package/dist/components/Sheet/Sheet.js +79 -0
  415. package/dist/components/Sheet/Sheet.js.map +1 -0
  416. package/dist/components/Sidebar/Sidebar.d.ts +357 -0
  417. package/dist/components/Sidebar/Sidebar.js +447 -0
  418. package/dist/components/Sidebar/Sidebar.js.map +1 -0
  419. package/dist/components/Skeleton/Skeleton.d.ts +70 -0
  420. package/dist/components/Skeleton/Skeleton.js +44 -0
  421. package/dist/components/Skeleton/Skeleton.js.map +1 -0
  422. package/dist/components/Slider/Slider.d.ts +74 -0
  423. package/dist/components/Slider/Slider.js +143 -0
  424. package/dist/components/Slider/Slider.js.map +1 -0
  425. package/dist/components/Spinner/Spinner.d.ts +58 -0
  426. package/dist/components/Spinner/Spinner.js +49 -0
  427. package/dist/components/Spinner/Spinner.js.map +1 -0
  428. package/dist/components/StatusDot/StatusDot.d.ts +29 -0
  429. package/dist/components/StatusDot/StatusDot.js +44 -0
  430. package/dist/components/StatusDot/StatusDot.js.map +1 -0
  431. package/dist/components/StatusPill/StatusPill.d.ts +30 -0
  432. package/dist/components/StatusPill/StatusPill.js +37 -0
  433. package/dist/components/StatusPill/StatusPill.js.map +1 -0
  434. package/dist/components/Steps/Steps.d.ts +65 -0
  435. package/dist/components/Steps/Steps.js +25 -0
  436. package/dist/components/Steps/Steps.js.map +1 -0
  437. package/dist/components/Switch/Switch.d.ts +23 -0
  438. package/dist/components/Switch/Switch.js +23 -0
  439. package/dist/components/Switch/Switch.js.map +1 -0
  440. package/dist/components/Table/Table.d.ts +116 -0
  441. package/dist/components/Table/Table.js +137 -0
  442. package/dist/components/Table/Table.js.map +1 -0
  443. package/dist/components/Tabs/Tabs.d.ts +37 -0
  444. package/dist/components/Tabs/Tabs.js +205 -0
  445. package/dist/components/Tabs/Tabs.js.map +1 -0
  446. package/dist/components/Tag/Tag.d.ts +87 -0
  447. package/dist/components/Tag/Tag.js +62 -0
  448. package/dist/components/Tag/Tag.js.map +1 -0
  449. package/dist/components/Text/Text.d.ts +62 -0
  450. package/dist/components/Text/Text.js +30 -0
  451. package/dist/components/Text/Text.js.map +1 -0
  452. package/dist/components/Textarea/Textarea.d.ts +20 -0
  453. package/dist/components/Textarea/Textarea.js +32 -0
  454. package/dist/components/Textarea/Textarea.js.map +1 -0
  455. package/dist/components/Timestamp/Timestamp.d.ts +59 -0
  456. package/dist/components/Timestamp/Timestamp.js +56 -0
  457. package/dist/components/Timestamp/Timestamp.js.map +1 -0
  458. package/dist/components/Toast/Toast.d.ts +32 -0
  459. package/dist/components/Toast/Toast.js +64 -0
  460. package/dist/components/Toast/Toast.js.map +1 -0
  461. package/dist/components/ToggleGroup/ToggleGroup.d.ts +46 -0
  462. package/dist/components/ToggleGroup/ToggleGroup.js +88 -0
  463. package/dist/components/ToggleGroup/ToggleGroup.js.map +1 -0
  464. package/dist/components/Toolbar/Toolbar.d.ts +55 -0
  465. package/dist/components/Toolbar/Toolbar.js +43 -0
  466. package/dist/components/Toolbar/Toolbar.js.map +1 -0
  467. package/dist/components/Tooltip/Tooltip.d.ts +43 -0
  468. package/dist/components/Tooltip/Tooltip.js +40 -0
  469. package/dist/components/Tooltip/Tooltip.js.map +1 -0
  470. package/dist/diagrams/ArchitectureFigure/ArchitectureFigure.d.ts +55 -0
  471. package/dist/diagrams/ArchitectureFigure/ArchitectureFigure.js +175 -0
  472. package/dist/diagrams/ArchitectureFigure/ArchitectureFigure.js.map +1 -0
  473. package/dist/diagrams/DataflowFigure/DataflowFigure.d.ts +28 -0
  474. package/dist/diagrams/DataflowFigure/DataflowFigure.js +148 -0
  475. package/dist/diagrams/DataflowFigure/DataflowFigure.js.map +1 -0
  476. package/dist/diagrams/DiagramCanvas/DiagramCanvas.d.ts +78 -0
  477. package/dist/diagrams/DiagramCanvas/DiagramCanvas.js +229 -0
  478. package/dist/diagrams/DiagramCanvas/DiagramCanvas.js.map +1 -0
  479. package/dist/diagrams/DiagramExportMenu/DiagramExportMenu.d.ts +106 -0
  480. package/dist/diagrams/DiagramExportMenu/DiagramExportMenu.js +123 -0
  481. package/dist/diagrams/DiagramExportMenu/DiagramExportMenu.js.map +1 -0
  482. package/dist/diagrams/DiagramInspector/DiagramInspector.d.ts +70 -0
  483. package/dist/diagrams/DiagramInspector/DiagramInspector.js +94 -0
  484. package/dist/diagrams/DiagramInspector/DiagramInspector.js.map +1 -0
  485. package/dist/diagrams/DiagramLegend/DiagramLegend.d.ts +42 -0
  486. package/dist/diagrams/DiagramLegend/DiagramLegend.js +35 -0
  487. package/dist/diagrams/DiagramLegend/DiagramLegend.js.map +1 -0
  488. package/dist/diagrams/DiagramMinimap/DiagramMinimap.d.ts +77 -0
  489. package/dist/diagrams/DiagramMinimap/DiagramMinimap.js +106 -0
  490. package/dist/diagrams/DiagramMinimap/DiagramMinimap.js.map +1 -0
  491. package/dist/diagrams/DiagramToolbar/DiagramToolbar.d.ts +48 -0
  492. package/dist/diagrams/DiagramToolbar/DiagramToolbar.js +53 -0
  493. package/dist/diagrams/DiagramToolbar/DiagramToolbar.js.map +1 -0
  494. package/dist/diagrams/LifecycleFigure/LifecycleFigure.d.ts +31 -0
  495. package/dist/diagrams/LifecycleFigure/LifecycleFigure.js +234 -0
  496. package/dist/diagrams/LifecycleFigure/LifecycleFigure.js.map +1 -0
  497. package/dist/diagrams/SequenceFigure/SequenceFigure.d.ts +38 -0
  498. package/dist/diagrams/SequenceFigure/SequenceFigure.js +261 -0
  499. package/dist/diagrams/SequenceFigure/SequenceFigure.js.map +1 -0
  500. package/dist/diagrams/WorkflowFigure/WorkflowFigure.d.ts +36 -0
  501. package/dist/diagrams/WorkflowFigure/WorkflowFigure.js +259 -0
  502. package/dist/diagrams/WorkflowFigure/WorkflowFigure.js.map +1 -0
  503. package/dist/diagrams/index.d.ts +17 -0
  504. package/dist/diagrams/index.js +29 -0
  505. package/dist/diagrams/index.js.map +1 -0
  506. package/dist/diagrams/lib/dev.d.ts +61 -0
  507. package/dist/diagrams/lib/dev.js +96 -0
  508. package/dist/diagrams/lib/dev.js.map +1 -0
  509. package/dist/diagrams/lib/frame.d.ts +138 -0
  510. package/dist/diagrams/lib/frame.js +131 -0
  511. package/dist/diagrams/lib/frame.js.map +1 -0
  512. package/dist/diagrams/lib/geometry.d.ts +114 -0
  513. package/dist/diagrams/lib/geometry.js +113 -0
  514. package/dist/diagrams/lib/geometry.js.map +1 -0
  515. package/dist/diagrams/lib/legend.d.ts +32 -0
  516. package/dist/diagrams/lib/legend.js +84 -0
  517. package/dist/diagrams/lib/legend.js.map +1 -0
  518. package/dist/diagrams/lib/marks.d.ts +207 -0
  519. package/dist/diagrams/lib/marks.js +480 -0
  520. package/dist/diagrams/lib/marks.js.map +1 -0
  521. package/dist/diagrams/lib/route.d.ts +106 -0
  522. package/dist/diagrams/lib/route.js +201 -0
  523. package/dist/diagrams/lib/route.js.map +1 -0
  524. package/dist/diagrams/lib/wires.d.ts +59 -0
  525. package/dist/diagrams/lib/wires.js +94 -0
  526. package/dist/diagrams/lib/wires.js.map +1 -0
  527. package/dist/diagrams/spec.d.ts +405 -0
  528. package/dist/diagrams/spec.js +1 -0
  529. package/dist/diagrams/spec.js.map +1 -0
  530. package/dist/fonts/hanken-grotesk-300.woff2 +0 -0
  531. package/dist/fonts/hanken-grotesk-400.woff2 +0 -0
  532. package/dist/fonts/hanken-grotesk-500.woff2 +0 -0
  533. package/dist/fonts/hanken-grotesk-600.woff2 +0 -0
  534. package/dist/fonts/hanken-grotesk-700.woff2 +0 -0
  535. package/dist/fonts/ibm-plex-mono-400.woff2 +0 -0
  536. package/dist/fonts/ibm-plex-mono-500.woff2 +0 -0
  537. package/dist/fonts/ibm-plex-mono-600.woff2 +0 -0
  538. package/dist/fonts/newsreader-300.woff2 +0 -0
  539. package/dist/fonts/newsreader-400.woff2 +0 -0
  540. package/dist/fonts/newsreader-500.woff2 +0 -0
  541. package/dist/fonts/newsreader-600.woff2 +0 -0
  542. package/dist/fonts.css +96 -0
  543. package/dist/index.d.ts +97 -0
  544. package/dist/index.js +80 -0
  545. package/dist/index.js.map +1 -0
  546. package/dist/keyframes.css +300 -0
  547. package/dist/lib/cn.d.ts +21 -0
  548. package/dist/lib/cn.js +9 -0
  549. package/dist/lib/cn.js.map +1 -0
  550. package/dist/lib/color.d.ts +80 -0
  551. package/dist/lib/color.js +189 -0
  552. package/dist/lib/color.js.map +1 -0
  553. package/dist/lib/control.d.ts +32 -0
  554. package/dist/lib/control.js +14 -0
  555. package/dist/lib/control.js.map +1 -0
  556. package/dist/lib/index.d.ts +4 -0
  557. package/dist/lib/index.js +11 -0
  558. package/dist/lib/index.js.map +1 -0
  559. package/dist/lib/numeric.d.ts +35 -0
  560. package/dist/lib/numeric.js +29 -0
  561. package/dist/lib/numeric.js.map +1 -0
  562. package/dist/lib/overlay-container.d.ts +48 -0
  563. package/dist/lib/overlay-container.js +15 -0
  564. package/dist/lib/overlay-container.js.map +1 -0
  565. package/dist/lib/slot-content.d.ts +8 -0
  566. package/dist/lib/slot-content.js +17 -0
  567. package/dist/lib/slot-content.js.map +1 -0
  568. package/dist/lib/step-rail.d.ts +45 -0
  569. package/dist/lib/step-rail.js +47 -0
  570. package/dist/lib/step-rail.js.map +1 -0
  571. package/dist/lib/svg-export.d.ts +138 -0
  572. package/dist/lib/svg-export.js +198 -0
  573. package/dist/lib/svg-export.js.map +1 -0
  574. package/dist/lib/useClipboardCopy.d.ts +30 -0
  575. package/dist/lib/useClipboardCopy.js +37 -0
  576. package/dist/lib/useClipboardCopy.js.map +1 -0
  577. package/dist/lib/useSelectionIndicator.d.ts +29 -0
  578. package/dist/lib/useSelectionIndicator.js +49 -0
  579. package/dist/lib/useSelectionIndicator.js.map +1 -0
  580. package/dist/lib/warn.d.ts +73 -0
  581. package/dist/lib/warn.js +38 -0
  582. package/dist/lib/warn.js.map +1 -0
  583. package/dist/semantic.css +193 -0
  584. package/dist/styles.css +98 -0
  585. package/dist/themes.css +514 -0
  586. package/dist/tokens/brand.d.ts +47 -0
  587. package/dist/tokens/brand.js +38 -0
  588. package/dist/tokens/brand.js.map +1 -0
  589. package/dist/tokens.css +652 -0
  590. package/dist/tokens.d.ts +198 -0
  591. package/dist/tokens.js +1020 -0
  592. package/dist/tokens.json +1019 -0
  593. package/dist/website/Actions/Actions.d.ts +34 -0
  594. package/dist/website/Actions/Actions.js +29 -0
  595. package/dist/website/Actions/Actions.js.map +1 -0
  596. package/dist/website/Collection/Collection.d.ts +128 -0
  597. package/dist/website/Collection/Collection.js +162 -0
  598. package/dist/website/Collection/Collection.js.map +1 -0
  599. package/dist/website/Contact/Contact.d.ts +87 -0
  600. package/dist/website/Contact/Contact.js +94 -0
  601. package/dist/website/Contact/Contact.js.map +1 -0
  602. package/dist/website/Content/CodePanel.d.ts +27 -0
  603. package/dist/website/Content/CodePanel.js +30 -0
  604. package/dist/website/Content/CodePanel.js.map +1 -0
  605. package/dist/website/Content/Content.d.ts +29 -0
  606. package/dist/website/Content/Content.js +38 -0
  607. package/dist/website/Content/Content.js.map +1 -0
  608. package/dist/website/Conversation/Conversation.d.ts +193 -0
  609. package/dist/website/Conversation/Conversation.js +252 -0
  610. package/dist/website/Conversation/Conversation.js.map +1 -0
  611. package/dist/website/Evidence/Evidence.d.ts +116 -0
  612. package/dist/website/Evidence/Evidence.js +142 -0
  613. package/dist/website/Evidence/Evidence.js.map +1 -0
  614. package/dist/website/Media/Media.d.ts +173 -0
  615. package/dist/website/Media/Media.js +225 -0
  616. package/dist/website/Media/Media.js.map +1 -0
  617. package/dist/website/Media/MediaLightbox.d.ts +18 -0
  618. package/dist/website/Media/MediaLightbox.js +38 -0
  619. package/dist/website/Media/MediaLightbox.js.map +1 -0
  620. package/dist/website/Metrics/Metrics.d.ts +74 -0
  621. package/dist/website/Metrics/Metrics.js +96 -0
  622. package/dist/website/Metrics/Metrics.js.map +1 -0
  623. package/dist/website/Music/Music.d.ts +60 -0
  624. package/dist/website/Music/Music.js +80 -0
  625. package/dist/website/Music/Music.js.map +1 -0
  626. package/dist/website/Portfolio/FrameLayout.d.ts +9 -0
  627. package/dist/website/Portfolio/FrameLayout.js +42 -0
  628. package/dist/website/Portfolio/FrameLayout.js.map +1 -0
  629. package/dist/website/Portfolio/Portfolio.d.ts +49 -0
  630. package/dist/website/Portfolio/Portfolio.js +66 -0
  631. package/dist/website/Portfolio/Portfolio.js.map +1 -0
  632. package/dist/website/Portfolio/QuestionCard.d.ts +22 -0
  633. package/dist/website/Portfolio/QuestionCard.js +33 -0
  634. package/dist/website/Portfolio/QuestionCard.js.map +1 -0
  635. package/dist/website/PortfolioIndex/PortfolioIndex.d.ts +21 -0
  636. package/dist/website/PortfolioIndex/PortfolioIndex.js +31 -0
  637. package/dist/website/PortfolioIndex/PortfolioIndex.js.map +1 -0
  638. package/dist/website/Reading/Reading.d.ts +203 -0
  639. package/dist/website/Reading/Reading.js +357 -0
  640. package/dist/website/Reading/Reading.js.map +1 -0
  641. package/dist/website/Recovery/Recovery.d.ts +39 -0
  642. package/dist/website/Recovery/Recovery.js +96 -0
  643. package/dist/website/Recovery/Recovery.js.map +1 -0
  644. package/dist/website/SearchPalette/SearchPalette.d.ts +59 -0
  645. package/dist/website/SearchPalette/SearchPalette.js +120 -0
  646. package/dist/website/SearchPalette/SearchPalette.js.map +1 -0
  647. package/dist/website/SiteNavigation/SiteNavigation.d.ts +46 -0
  648. package/dist/website/SiteNavigation/SiteNavigation.js +101 -0
  649. package/dist/website/SiteNavigation/SiteNavigation.js.map +1 -0
  650. package/dist/website/SiteShell/SiteShell.d.ts +45 -0
  651. package/dist/website/SiteShell/SiteShell.js +46 -0
  652. package/dist/website/SiteShell/SiteShell.js.map +1 -0
  653. package/dist/website/Timeline/Timeline.d.ts +80 -0
  654. package/dist/website/Timeline/Timeline.js +99 -0
  655. package/dist/website/Timeline/Timeline.js.map +1 -0
  656. package/dist/website/index.d.ts +27 -0
  657. package/dist/website/index.js +21 -0
  658. package/dist/website/index.js.map +1 -0
  659. package/dist/website-actions.css +6 -0
  660. package/dist/website-base.css +46 -0
  661. package/dist/website-collection.css +89 -0
  662. package/dist/website-contact.css +29 -0
  663. package/dist/website-content.css +17 -0
  664. package/dist/website-controls.css +91 -0
  665. package/dist/website-conversation.css +115 -0
  666. package/dist/website-evidence.css +56 -0
  667. package/dist/website-media.css +227 -0
  668. package/dist/website-metrics.css +15 -0
  669. package/dist/website-music.css +27 -0
  670. package/dist/website-portfolio.css +94 -0
  671. package/dist/website-reading.css +159 -0
  672. package/dist/website-recovery.css +28 -0
  673. package/dist/website-search.css +26 -0
  674. package/dist/website-shell.css +89 -0
  675. package/dist/website-timeline.css +43 -0
  676. package/dist/website.css +25 -0
  677. package/llms.txt +35 -0
  678. package/package.json +163 -5
  679. package/skills/folio-design/SKILL.md +228 -0
  680. package/skills/folio-design/evals/claims.json +95 -0
  681. package/skills/folio-design/evals/evals.json +84 -0
  682. package/skills/folio-design/rules/a11y.md +167 -0
  683. package/skills/folio-design/rules/composition.md +108 -0
  684. package/skills/folio-design/rules/forms.md +135 -0
  685. package/skills/folio-design/rules/naming.md +155 -0
  686. package/skills/folio-design/rules/tokens.md +133 -0
@@ -0,0 +1,94 @@
1
+ import * as react from 'react';
2
+ import { ReactNode, ComponentType, ComponentProps } from 'react';
3
+ import { ResponsiveContainer } from 'recharts';
4
+
5
+ /**
6
+ * How many series the system will paint before it refuses.
7
+ *
8
+ * Eight is not a rendering limit — it is the width of the validated ramp in
9
+ * `tokens.css`. A ninth series has no slot, and generating one would mean
10
+ * inventing a colour nobody checked against the eighth. The catalogued answer
11
+ * to "I have twelve categories" is to fold the tail into an "Other" series or
12
+ * to facet, and this constant is where that decision is enforced rather than
13
+ * left to whoever is looking at the chart.
14
+ */
15
+ declare const SERIES_SLOTS = 8;
16
+ /** Theme name → the selector its block is written under. */
17
+ declare const THEMES: {
18
+ readonly light: "";
19
+ readonly dark: "[data-mode='dark']";
20
+ };
21
+ type ThemeKey = keyof typeof THEMES;
22
+ /** Colours for one series, per theme. At least one theme must be given. */
23
+ type ThemeColors = {
24
+ [K in ThemeKey]: Required<Pick<Record<ThemeKey, string[]>, K>> & Partial<Omit<Record<ThemeKey, string[]>, K>>;
25
+ }[ThemeKey];
26
+ interface ChartSeries {
27
+ /**
28
+ * What the legend, the tooltip and the hidden data table call this series.
29
+ *
30
+ * Required, unlike the shape this was ported from. Colour is never the only
31
+ * carrier of identity in this system, and a legend entry with no label is a
32
+ * swatch that means nothing — least of all in the monochrome default, where
33
+ * two series differ by a step of grey and a texture.
34
+ */
35
+ label: ReactNode;
36
+ /** Drawn in place of the legend/tooltip swatch. Decorative; label still wins. */
37
+ icon?: ComponentType;
38
+ /**
39
+ * Explicit colours for this series, overriding its slot on the series ramp.
40
+ *
41
+ * Reach for this only when the data itself carries a colour the reader
42
+ * already knows — a brand, a traffic light, a map key. For "I want my chart
43
+ * to have colours", set `data-chart-palette="chroma"` on any ancestor: that
44
+ * swaps the whole ramp for a palette validated against both grounds, which a
45
+ * hand-picked array is not.
46
+ *
47
+ * More than one colour paints the series as a horizontal gradient across
48
+ * those stops. Values are plain CSS colours; anything that could break out of
49
+ * a declaration is rejected at the boundary rather than injected.
50
+ */
51
+ colors?: ThemeColors;
52
+ }
53
+ /** Series keys → how each is labelled and painted. Declaration order is slot order. */
54
+ type ChartConfig = Record<string, ChartSeries>;
55
+ interface ChartContextValue {
56
+ config: ChartConfig;
57
+ }
58
+ /** The chart config of the nearest chart root. Throws outside one. */
59
+ declare function useChart(): ChartContextValue;
60
+ /** How many gradient stops a series paints with — one means a flat fill. */
61
+ declare function colorStops(series: ChartSeries | undefined): number;
62
+ /**
63
+ * A series key, reduced to what may appear in a custom property name. Keys come
64
+ * from consumer data, so the same boundary argument as `isSafeColor` applies —
65
+ * here it is the property NAME rather than its value.
66
+ */
67
+ declare function cssName(key: string): string;
68
+ interface ChartContainerProps extends Omit<ComponentProps<'div'>, 'children'>, Pick<ComponentProps<typeof ResponsiveContainer>, 'initialDimension' | 'minHeight' | 'minWidth' | 'maxHeight' | 'height' | 'width' | 'children'> {
69
+ config: ChartConfig;
70
+ /** Rendered under the plot, inside the same measured box — the brush lives here. */
71
+ footer?: ReactNode;
72
+ }
73
+ /**
74
+ * The measured box every chart is drawn into, and the only place Recharts'
75
+ * hard-coded greys are re-pointed at system tokens.
76
+ *
77
+ * Recharts paints its axes, grid, cursor and radial track with literal `#ccc`
78
+ * and `#fff`. The selectors below catch each of those and hand it a token, so a
79
+ * chart follows light/dark and a surface theme without a consumer configuring
80
+ * anything — and so nothing in the package has to pass a colour down by prop.
81
+ */
82
+ declare function ChartContainer({ id, config, initialDimension, className, children, footer, ...rest }: ChartContainerProps): react.JSX.Element;
83
+ /**
84
+ * Reads the config entry behind a Recharts payload item.
85
+ *
86
+ * Recharts hands the same series different names in different chart types — a
87
+ * pie sector's key is on `payload.payload[nameKey]`, a bar's is `dataKey` — so
88
+ * this is the one place that disagreement is resolved.
89
+ */
90
+ declare function seriesFromPayload(config: ChartConfig, payload: unknown, key: string): ChartSeries | undefined;
91
+ /** Formats an expanded stack's axis, where 0–1 means 0–100%. */
92
+ declare function percentTick(value: number): string;
93
+
94
+ export { type ChartConfig, ChartContainer, type ChartContainerProps, type ChartSeries, SERIES_SLOTS, colorStops, cssName, percentTick, seriesFromPayload, useChart };
@@ -0,0 +1,149 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import {
4
+ createContext,
5
+ useContext,
6
+ useId,
7
+ useMemo
8
+ } from "react";
9
+ import { ResponsiveContainer } from "recharts";
10
+ import { cn } from "../../lib/cn.js";
11
+ const SERIES_SLOTS = 8;
12
+ const THEMES = { light: "", dark: "[data-mode='dark']" };
13
+ const THEME_KEYS = Object.keys(THEMES);
14
+ const ChartContext = createContext(null);
15
+ function useChart() {
16
+ const context = useContext(ChartContext);
17
+ if (!context) throw new Error("A chart part must be rendered inside a chart root");
18
+ return context;
19
+ }
20
+ const CSS_COLOR = /^[A-Za-z0-9#(),.%\-\s_]{1,120}$/;
21
+ function isSafeColor(value) {
22
+ return typeof value === "string" && CSS_COLOR.test(value) && !value.includes("/*");
23
+ }
24
+ function distribute(colors, slots) {
25
+ if (colors.length >= slots) return colors.slice(0, slots);
26
+ const base = Math.floor(slots / colors.length);
27
+ const extra = slots % colors.length;
28
+ const out = [];
29
+ colors.forEach((color, index) => {
30
+ const count = base + (index >= colors.length - extra ? 1 : 0);
31
+ for (let n = 0; n < count; n += 1) out.push(color);
32
+ });
33
+ return out;
34
+ }
35
+ function colorStops(series) {
36
+ if (!series?.colors) return 1;
37
+ return Math.max(1, ...THEME_KEYS.map((theme) => series.colors?.[theme]?.length ?? 0));
38
+ }
39
+ function ChartStyle({ id, config }) {
40
+ const css = useMemo(() => {
41
+ const entries = Object.entries(config);
42
+ const rules = (theme) => entries.flatMap(([key, series], slot) => {
43
+ const stops = colorStops(series);
44
+ const slotColor = `var(--series-${slot % SERIES_SLOTS + 1})`;
45
+ const given = series.colors?.[theme] ?? series.colors?.light ?? series.colors?.dark;
46
+ const safe = given?.filter(isSafeColor) ?? [];
47
+ const colors = safe.length > 0 ? safe : [slotColor];
48
+ return distribute(colors, stops).map(
49
+ (color, index) => ` --color-${cssName(key)}-${index}: ${color};`
50
+ );
51
+ }).join("\n");
52
+ return THEME_KEYS.map((theme) => {
53
+ const body = rules(theme);
54
+ if (!body) return "";
55
+ return `${THEMES[theme]} [data-chart='${id}'] {
56
+ ${body}
57
+ }`;
58
+ }).filter(Boolean).join("\n");
59
+ }, [id, config]);
60
+ if (!css) return null;
61
+ return /* @__PURE__ */ jsx("style", { children: css });
62
+ }
63
+ function cssName(key) {
64
+ return key.replace(/[^A-Za-z0-9_-]/g, "-");
65
+ }
66
+ function ChartContainer({
67
+ id,
68
+ config,
69
+ initialDimension = { width: 320, height: 200 },
70
+ className,
71
+ children,
72
+ footer,
73
+ ...rest
74
+ }) {
75
+ const generated = useId().replace(/:/g, "");
76
+ const chartId = `chart-${id ?? generated}`;
77
+ return /* @__PURE__ */ jsx(ChartContext.Provider, { value: { config }, children: /* @__PURE__ */ jsxs(
78
+ "div",
79
+ {
80
+ "data-slot": "chart",
81
+ "data-chart": chartId,
82
+ className: cn(
83
+ "relative flex min-h-0 w-full flex-1 flex-col justify-center text-xs",
84
+ // 16:9 is right for a card and wrong for a full-width panel: at
85
+ // 1200px it is a 675px-tall plot with six points in it. The cap is
86
+ // what stops the aspect ratio running away with a wide container,
87
+ // and `min-h` keeps it from collapsing in a narrow one.
88
+ //
89
+ // With a footer the shape moves DOWN one element rather than being
90
+ // dropped — see the container below. Sizing this box 16:9 would hand
91
+ // the footer's height to the footer out of the plot's share, which is
92
+ // a plot that shrinks as its brush grows.
93
+ !footer && "aspect-video max-h-[26rem] min-h-[13rem]",
94
+ // Recharts' own defaults, re-pointed at the token layer.
95
+ "[&_.recharts-cartesian-axis-tick_text]:fill-(--chart-axis)",
96
+ "[&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-(--chart-grid)",
97
+ "[&_.recharts-curve.recharts-tooltip-cursor]:stroke-(--chart-cursor)",
98
+ "[&_.recharts-polar-grid_[stroke='#ccc']]:stroke-(--chart-grid)",
99
+ "[&_.recharts-radial-bar-background-sector]:fill-(--chart-track)",
100
+ "[&_.recharts-rectangle.recharts-tooltip-cursor]:fill-(--chart-track)",
101
+ "[&_.recharts-reference-line_[stroke='#ccc']]:stroke-(--chart-grid)",
102
+ "[&_.recharts-dot[stroke='#fff']]:stroke-transparent",
103
+ "[&_.recharts-sector[stroke='#fff']]:stroke-transparent",
104
+ // Keyboard-focusable SVGs use the same global :focus-visible rule as
105
+ // every other control. A utility-level outline reset here overrides
106
+ // that base rule and leaves a working chart with no visible focus.
107
+ className
108
+ ),
109
+ ...rest,
110
+ children: [
111
+ /* @__PURE__ */ jsx(ChartStyle, { id: chartId, config }),
112
+ /* @__PURE__ */ jsx(
113
+ ResponsiveContainer,
114
+ {
115
+ className: cn(
116
+ "w-full flex-1",
117
+ footer ? "aspect-video max-h-[26rem] min-h-[13rem]" : "min-h-0"
118
+ ),
119
+ initialDimension,
120
+ children
121
+ }
122
+ ),
123
+ footer
124
+ ]
125
+ }
126
+ ) });
127
+ }
128
+ function seriesFromPayload(config, payload, key) {
129
+ if (typeof payload !== "object" || payload === null) return void 0;
130
+ const nested = "payload" in payload && typeof payload.payload === "object" && payload.payload !== null ? payload.payload : void 0;
131
+ let name = key;
132
+ const direct = payload[key];
133
+ if (typeof direct === "string") name = direct;
134
+ else if (nested && typeof nested[key] === "string") name = nested[key];
135
+ return name in config ? config[name] : config[key];
136
+ }
137
+ function percentTick(value) {
138
+ return `${Math.round(value * 100)}%`;
139
+ }
140
+ export {
141
+ ChartContainer,
142
+ SERIES_SLOTS,
143
+ colorStops,
144
+ cssName,
145
+ percentTick,
146
+ seriesFromPayload,
147
+ useChart
148
+ };
149
+ //# sourceMappingURL=chart.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/charts/lib/chart.tsx"],"sourcesContent":["'use client'\n\nimport {\n createContext,\n useContext,\n useId,\n useMemo,\n type ComponentProps,\n type ComponentType,\n type ReactNode,\n} from 'react'\nimport { ResponsiveContainer } from 'recharts'\nimport { cn } from '../../lib/cn'\n\n/**\n * How many series the system will paint before it refuses.\n *\n * Eight is not a rendering limit — it is the width of the validated ramp in\n * `tokens.css`. A ninth series has no slot, and generating one would mean\n * inventing a colour nobody checked against the eighth. The catalogued answer\n * to \"I have twelve categories\" is to fold the tail into an \"Other\" series or\n * to facet, and this constant is where that decision is enforced rather than\n * left to whoever is looking at the chart.\n */\nexport const SERIES_SLOTS = 8\n\n/** Theme name → the selector its block is written under. */\nconst THEMES = { light: '', dark: \"[data-mode='dark']\" } as const\n\ntype ThemeKey = keyof typeof THEMES\n\nconst THEME_KEYS = Object.keys(THEMES) as ThemeKey[]\n\n/** Colours for one series, per theme. At least one theme must be given. */\ntype ThemeColors = {\n [K in ThemeKey]: Required<Pick<Record<ThemeKey, string[]>, K>> &\n Partial<Omit<Record<ThemeKey, string[]>, K>>\n}[ThemeKey]\n\nexport interface ChartSeries {\n /**\n * What the legend, the tooltip and the hidden data table call this series.\n *\n * Required, unlike the shape this was ported from. Colour is never the only\n * carrier of identity in this system, and a legend entry with no label is a\n * swatch that means nothing — least of all in the monochrome default, where\n * two series differ by a step of grey and a texture.\n */\n label: ReactNode\n /** Drawn in place of the legend/tooltip swatch. Decorative; label still wins. */\n icon?: ComponentType\n /**\n * Explicit colours for this series, overriding its slot on the series ramp.\n *\n * Reach for this only when the data itself carries a colour the reader\n * already knows — a brand, a traffic light, a map key. For \"I want my chart\n * to have colours\", set `data-chart-palette=\"chroma\"` on any ancestor: that\n * swaps the whole ramp for a palette validated against both grounds, which a\n * hand-picked array is not.\n *\n * More than one colour paints the series as a horizontal gradient across\n * those stops. Values are plain CSS colours; anything that could break out of\n * a declaration is rejected at the boundary rather than injected.\n */\n colors?: ThemeColors\n}\n\n/** Series keys → how each is labelled and painted. Declaration order is slot order. */\nexport type ChartConfig = Record<string, ChartSeries>\n\ninterface ChartContextValue {\n config: ChartConfig\n}\n\nconst ChartContext = createContext<ChartContextValue | null>(null)\n\n/** The chart config of the nearest chart root. Throws outside one. */\nexport function useChart(): ChartContextValue {\n const context = useContext(ChartContext)\n if (!context) throw new Error('A chart part must be rendered inside a chart root')\n return context\n}\n\n/**\n * A CSS colour, or something that would escape the declaration it is written\n * into.\n *\n * `ChartStyle` writes consumer-supplied values into a `<style>` element, which\n * makes this a system boundary in the security sense: without the check, a\n * `colors` array carrying `red; } html { display: none } .x {` is not a colour,\n * it is a stylesheet. The allowed set is deliberately shaped around what a\n * colour is made of — identifiers, digits, `#`, brackets, commas, percent — so\n * `var(--x)`, `oklch(…)` and `color-mix(in srgb, …)` all pass and no `;`, `{`,\n * `}`, `<`, `\\` or comment sequence does.\n */\nconst CSS_COLOR = /^[A-Za-z0-9#(),.%\\-\\s_]{1,120}$/\n\nfunction isSafeColor(value: unknown): value is string {\n return typeof value === 'string' && CSS_COLOR.test(value) && !value.includes('/*')\n}\n\n/**\n * Distributes fewer colours than slots, giving the surplus to the last stops.\n * Two colours over four slots read as `[a, a, b, b]`; three over four as\n * `[a, b, c, c]`.\n */\nfunction distribute(colors: string[], slots: number): string[] {\n if (colors.length >= slots) return colors.slice(0, slots)\n\n const base = Math.floor(slots / colors.length)\n const extra = slots % colors.length\n const out: string[] = []\n colors.forEach((color, index) => {\n const count = base + (index >= colors.length - extra ? 1 : 0)\n for (let n = 0; n < count; n += 1) out.push(color)\n })\n return out\n}\n\n/** How many gradient stops a series paints with — one means a flat fill. */\nexport function colorStops(series: ChartSeries | undefined): number {\n if (!series?.colors) return 1\n return Math.max(1, ...THEME_KEYS.map((theme) => series.colors?.[theme]?.length ?? 0))\n}\n\n/**\n * The custom properties one chart instance paints from.\n *\n * Every series resolves to `--color-<key>-<n>`, and every mark, swatch and\n * gradient stop in the package reads only those names. That indirection is what\n * lets the same chart be repainted by an ancestor attribute — a theme, a\n * palette, dark mode — without a component knowing anything about colour.\n *\n * A series with no `colors` takes its slot on the ramp, in declaration order.\n * That is the \"assign in fixed order, never cycle\" rule expressed as code: the\n * fourth series is `--series-4` whether or not the first three are on screen,\n * so hiding a series never repaints the survivors.\n */\nfunction ChartStyle({ id, config }: { id: string; config: ChartConfig }) {\n const css = useMemo(() => {\n const entries = Object.entries(config)\n\n const rules = (theme: ThemeKey) =>\n entries\n .flatMap(([key, series], slot) => {\n const stops = colorStops(series)\n const slotColor = `var(--series-${(slot % SERIES_SLOTS) + 1})`\n const given = series.colors?.[theme] ?? series.colors?.light ?? series.colors?.dark\n const safe = given?.filter(isSafeColor) ?? []\n // A rejected colour falls back to the ramp rather than to nothing: an\n // unpainted series is invisible, which is a worse failure than an\n // ignored value and a harder one to notice.\n const colors = safe.length > 0 ? safe : [slotColor]\n return distribute(colors, stops).map(\n (color, index) => ` --color-${cssName(key)}-${index}: ${color};`,\n )\n })\n .join('\\n')\n\n return THEME_KEYS.map((theme) => {\n const body = rules(theme)\n if (!body) return ''\n return `${THEMES[theme]} [data-chart='${id}'] {\\n${body}\\n}`\n })\n .filter(Boolean)\n .join('\\n')\n }, [id, config])\n\n if (!css) return null\n\n return <style>{css}</style>\n}\n\n/**\n * A series key, reduced to what may appear in a custom property name. Keys come\n * from consumer data, so the same boundary argument as `isSafeColor` applies —\n * here it is the property NAME rather than its value.\n */\nexport function cssName(key: string): string {\n return key.replace(/[^A-Za-z0-9_-]/g, '-')\n}\n\nexport interface ChartContainerProps\n extends Omit<ComponentProps<'div'>, 'children'>,\n Pick<\n ComponentProps<typeof ResponsiveContainer>,\n 'initialDimension' | 'minHeight' | 'minWidth' | 'maxHeight' | 'height' | 'width' | 'children'\n > {\n config: ChartConfig\n /** Rendered under the plot, inside the same measured box — the brush lives here. */\n footer?: ReactNode\n}\n\n/**\n * The measured box every chart is drawn into, and the only place Recharts'\n * hard-coded greys are re-pointed at system tokens.\n *\n * Recharts paints its axes, grid, cursor and radial track with literal `#ccc`\n * and `#fff`. The selectors below catch each of those and hand it a token, so a\n * chart follows light/dark and a surface theme without a consumer configuring\n * anything — and so nothing in the package has to pass a colour down by prop.\n */\nexport function ChartContainer({\n id,\n config,\n initialDimension = { width: 320, height: 200 },\n className,\n children,\n footer,\n ...rest\n}: ChartContainerProps) {\n const generated = useId().replace(/:/g, '')\n const chartId = `chart-${id ?? generated}`\n\n return (\n <ChartContext.Provider value={{ config }}>\n <div\n data-slot=\"chart\"\n data-chart={chartId}\n className={cn(\n 'relative flex min-h-0 w-full flex-1 flex-col justify-center text-xs',\n // 16:9 is right for a card and wrong for a full-width panel: at\n // 1200px it is a 675px-tall plot with six points in it. The cap is\n // what stops the aspect ratio running away with a wide container,\n // and `min-h` keeps it from collapsing in a narrow one.\n //\n // With a footer the shape moves DOWN one element rather than being\n // dropped — see the container below. Sizing this box 16:9 would hand\n // the footer's height to the footer out of the plot's share, which is\n // a plot that shrinks as its brush grows.\n !footer && 'aspect-video max-h-[26rem] min-h-[13rem]',\n // Recharts' own defaults, re-pointed at the token layer.\n \"[&_.recharts-cartesian-axis-tick_text]:fill-(--chart-axis)\",\n \"[&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-(--chart-grid)\",\n '[&_.recharts-curve.recharts-tooltip-cursor]:stroke-(--chart-cursor)',\n \"[&_.recharts-polar-grid_[stroke='#ccc']]:stroke-(--chart-grid)\",\n '[&_.recharts-radial-bar-background-sector]:fill-(--chart-track)',\n '[&_.recharts-rectangle.recharts-tooltip-cursor]:fill-(--chart-track)',\n \"[&_.recharts-reference-line_[stroke='#ccc']]:stroke-(--chart-grid)\",\n \"[&_.recharts-dot[stroke='#fff']]:stroke-transparent\",\n \"[&_.recharts-sector[stroke='#fff']]:stroke-transparent\",\n // Keyboard-focusable SVGs use the same global :focus-visible rule as\n // every other control. A utility-level outline reset here overrides\n // that base rule and leaves a working chart with no visible focus.\n className,\n )}\n {...rest}\n >\n <ChartStyle id={chartId} config={config} />\n {/* The plot carries the shape when there is a footer under it.\n It used to carry nothing: the outer box dropped `aspect-video` AND\n `min-h` the moment a footer existed, on the reasoning that a fixed\n aspect plus a footer overflows — which is true of the aspect and\n not of the floor. So a chart with a brush had a plot with no\n intrinsic height at all, and in any container that sizes to its\n content the plot measured zero and only the brush's own 56px\n survived. Recharts says so out loud — \"width(-1) and height(-1) of\n chart should be greater than 0\" — into a console nobody reads. */}\n <ResponsiveContainer\n className={cn(\n 'w-full flex-1',\n footer ? 'aspect-video max-h-[26rem] min-h-[13rem]' : 'min-h-0',\n )}\n initialDimension={initialDimension}\n >\n {children}\n </ResponsiveContainer>\n {footer}\n </div>\n </ChartContext.Provider>\n )\n}\n\n/**\n * Reads the config entry behind a Recharts payload item.\n *\n * Recharts hands the same series different names in different chart types — a\n * pie sector's key is on `payload.payload[nameKey]`, a bar's is `dataKey` — so\n * this is the one place that disagreement is resolved.\n */\nexport function seriesFromPayload(\n config: ChartConfig,\n payload: unknown,\n key: string,\n): ChartSeries | undefined {\n if (typeof payload !== 'object' || payload === null) return undefined\n\n const nested =\n 'payload' in payload && typeof payload.payload === 'object' && payload.payload !== null\n ? (payload.payload as Record<string, unknown>)\n : undefined\n\n let name = key\n const direct = (payload as Record<string, unknown>)[key]\n if (typeof direct === 'string') name = direct\n else if (nested && typeof nested[key] === 'string') name = nested[key] as string\n\n return name in config ? config[name] : config[key]\n}\n\n/** Formats an expanded stack's axis, where 0–1 means 0–100%. */\nexport function percentTick(value: number): string {\n return `${Math.round(value * 100)}%`\n}\n"],"mappings":";AA0KS,cA8CH,YA9CG;AAxKT;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AACP,SAAS,2BAA2B;AACpC,SAAS,UAAU;AAYZ,MAAM,eAAe;AAG5B,MAAM,SAAS,EAAE,OAAO,IAAI,MAAM,qBAAqB;AAIvD,MAAM,aAAa,OAAO,KAAK,MAAM;AA2CrC,MAAM,eAAe,cAAwC,IAAI;AAG1D,SAAS,WAA8B;AAC5C,QAAM,UAAU,WAAW,YAAY;AACvC,MAAI,CAAC,QAAS,OAAM,IAAI,MAAM,mDAAmD;AACjF,SAAO;AACT;AAcA,MAAM,YAAY;AAElB,SAAS,YAAY,OAAiC;AACpD,SAAO,OAAO,UAAU,YAAY,UAAU,KAAK,KAAK,KAAK,CAAC,MAAM,SAAS,IAAI;AACnF;AAOA,SAAS,WAAW,QAAkB,OAAyB;AAC7D,MAAI,OAAO,UAAU,MAAO,QAAO,OAAO,MAAM,GAAG,KAAK;AAExD,QAAM,OAAO,KAAK,MAAM,QAAQ,OAAO,MAAM;AAC7C,QAAM,QAAQ,QAAQ,OAAO;AAC7B,QAAM,MAAgB,CAAC;AACvB,SAAO,QAAQ,CAAC,OAAO,UAAU;AAC/B,UAAM,QAAQ,QAAQ,SAAS,OAAO,SAAS,QAAQ,IAAI;AAC3D,aAAS,IAAI,GAAG,IAAI,OAAO,KAAK,EAAG,KAAI,KAAK,KAAK;AAAA,EACnD,CAAC;AACD,SAAO;AACT;AAGO,SAAS,WAAW,QAAyC;AAClE,MAAI,CAAC,QAAQ,OAAQ,QAAO;AAC5B,SAAO,KAAK,IAAI,GAAG,GAAG,WAAW,IAAI,CAAC,UAAU,OAAO,SAAS,KAAK,GAAG,UAAU,CAAC,CAAC;AACtF;AAeA,SAAS,WAAW,EAAE,IAAI,OAAO,GAAwC;AACvE,QAAM,MAAM,QAAQ,MAAM;AACxB,UAAM,UAAU,OAAO,QAAQ,MAAM;AAErC,UAAM,QAAQ,CAAC,UACb,QACG,QAAQ,CAAC,CAAC,KAAK,MAAM,GAAG,SAAS;AAChC,YAAM,QAAQ,WAAW,MAAM;AAC/B,YAAM,YAAY,gBAAiB,OAAO,eAAgB,CAAC;AAC3D,YAAM,QAAQ,OAAO,SAAS,KAAK,KAAK,OAAO,QAAQ,SAAS,OAAO,QAAQ;AAC/E,YAAM,OAAO,OAAO,OAAO,WAAW,KAAK,CAAC;AAI5C,YAAM,SAAS,KAAK,SAAS,IAAI,OAAO,CAAC,SAAS;AAClD,aAAO,WAAW,QAAQ,KAAK,EAAE;AAAA,QAC/B,CAAC,OAAO,UAAU,aAAa,QAAQ,GAAG,CAAC,IAAI,KAAK,KAAK,KAAK;AAAA,MAChE;AAAA,IACF,CAAC,EACA,KAAK,IAAI;AAEd,WAAO,WAAW,IAAI,CAAC,UAAU;AAC/B,YAAM,OAAO,MAAM,KAAK;AACxB,UAAI,CAAC,KAAM,QAAO;AAClB,aAAO,GAAG,OAAO,KAAK,CAAC,iBAAiB,EAAE;AAAA,EAAS,IAAI;AAAA;AAAA,IACzD,CAAC,EACE,OAAO,OAAO,EACd,KAAK,IAAI;AAAA,EACd,GAAG,CAAC,IAAI,MAAM,CAAC;AAEf,MAAI,CAAC,IAAK,QAAO;AAEjB,SAAO,oBAAC,WAAO,eAAI;AACrB;AAOO,SAAS,QAAQ,KAAqB;AAC3C,SAAO,IAAI,QAAQ,mBAAmB,GAAG;AAC3C;AAsBO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA,mBAAmB,EAAE,OAAO,KAAK,QAAQ,IAAI;AAAA,EAC7C;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAwB;AACtB,QAAM,YAAY,MAAM,EAAE,QAAQ,MAAM,EAAE;AAC1C,QAAM,UAAU,SAAS,MAAM,SAAS;AAExC,SACE,oBAAC,aAAa,UAAb,EAAsB,OAAO,EAAE,OAAO,GACrC;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,cAAY;AAAA,MACZ,WAAW;AAAA,QACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAUA,CAAC,UAAU;AAAA;AAAA,QAEX;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA;AAAA;AAAA;AAAA,QAIA;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEJ;AAAA,4BAAC,cAAW,IAAI,SAAS,QAAgB;AAAA,QAUzC;AAAA,UAAC;AAAA;AAAA,YACC,WAAW;AAAA,cACT;AAAA,cACA,SAAS,6CAA6C;AAAA,YACxD;AAAA,YACA;AAAA,YAEC;AAAA;AAAA,QACH;AAAA,QACC;AAAA;AAAA;AAAA,EACH,GACF;AAEJ;AASO,SAAS,kBACd,QACA,SACA,KACyB;AACzB,MAAI,OAAO,YAAY,YAAY,YAAY,KAAM,QAAO;AAE5D,QAAM,SACJ,aAAa,WAAW,OAAO,QAAQ,YAAY,YAAY,QAAQ,YAAY,OAC9E,QAAQ,UACT;AAEN,MAAI,OAAO;AACX,QAAM,SAAU,QAAoC,GAAG;AACvD,MAAI,OAAO,WAAW,SAAU,QAAO;AAAA,WAC9B,UAAU,OAAO,OAAO,GAAG,MAAM,SAAU,QAAO,OAAO,GAAG;AAErE,SAAO,QAAQ,SAAS,OAAO,IAAI,IAAI,OAAO,GAAG;AACnD;AAGO,SAAS,YAAY,OAAuB;AACjD,SAAO,GAAG,KAAK,MAAM,QAAQ,GAAG,CAAC;AACnC;","names":[]}
@@ -0,0 +1,29 @@
1
+ import * as react from 'react';
2
+
3
+ /** How a point marker is drawn on a line or an area. */
4
+ type ChartDotVariant = 'default' | 'border' | 'colored-border';
5
+ interface ChartDotProps {
6
+ cx?: number;
7
+ cy?: number;
8
+ /** The series this dot belongs to — it picks up that series' gradient. */
9
+ dataKey: string;
10
+ /** The owning mark's id, which scopes its gradient. */
11
+ chartId: string;
12
+ className?: string;
13
+ fillOpacity?: number;
14
+ variant?: ChartDotVariant;
15
+ /** The intro wipe's mask, so a resting dot reveals with its own line. */
16
+ maskId?: string;
17
+ }
18
+ /**
19
+ * A point marker painted from its series' gradient rather than from a flat
20
+ * colour.
21
+ *
22
+ * The trick each variant shares: a full-width rect filled with the series
23
+ * gradient, clipped to a circle. Filling the circle directly would restart the
24
+ * gradient inside the dot's own bounding box, so every dot on a line would be
25
+ * the same colour instead of sampling the gradient at the x it sits on.
26
+ */
27
+ declare const ChartDot: react.MemoExoticComponent<({ cx, cy, dataKey, chartId, className, fillOpacity, variant, maskId, }: ChartDotProps) => react.JSX.Element | null>;
28
+
29
+ export { ChartDot, type ChartDotProps, type ChartDotVariant };
@@ -0,0 +1,78 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { memo, useId } from "react";
3
+ import { cn } from "../../lib/cn.js";
4
+ const ChartDot = memo(function ChartDot2({
5
+ cx,
6
+ cy,
7
+ dataKey,
8
+ chartId,
9
+ className,
10
+ fillOpacity = 1,
11
+ variant = "default",
12
+ maskId
13
+ }) {
14
+ const dotId = useId().replace(/:/g, "");
15
+ if (cx === void 0 || cy === void 0) return null;
16
+ const paint = `url(#${chartId}-colors-${dataKey})`;
17
+ const mask = maskId ? `url(#${maskId})` : void 0;
18
+ if (variant === "border") {
19
+ const r2 = 6;
20
+ const inner = r2 - 2.5;
21
+ return /* @__PURE__ */ jsxs("g", { className: cn("text-(--chart-surface)", className), mask, children: [
22
+ /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx("clipPath", { id: `dot-${dotId}`, children: /* @__PURE__ */ jsx("circle", { cx, cy, r: inner }) }) }),
23
+ /* @__PURE__ */ jsx("circle", { cx, cy, r: r2, fill: "currentColor" }),
24
+ /* @__PURE__ */ jsx(
25
+ "rect",
26
+ {
27
+ x: "0",
28
+ y: cy - inner,
29
+ width: "100%",
30
+ height: inner * 2,
31
+ fill: paint,
32
+ fillOpacity,
33
+ clipPath: `url(#dot-${dotId})`
34
+ }
35
+ )
36
+ ] });
37
+ }
38
+ if (variant === "colored-border") {
39
+ const r2 = 3;
40
+ const stroke = 1;
41
+ return /* @__PURE__ */ jsxs("g", { className: cn("text-(--chart-surface)", className), mask, children: [
42
+ /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx("clipPath", { id: `dot-${dotId}`, children: /* @__PURE__ */ jsx("circle", { cx, cy, r: r2 + stroke / 2 }) }) }),
43
+ /* @__PURE__ */ jsx(
44
+ "rect",
45
+ {
46
+ x: "0",
47
+ y: cy - r2 - stroke / 2,
48
+ width: "100%",
49
+ height: (r2 + stroke / 2) * 2,
50
+ fill: paint,
51
+ fillOpacity,
52
+ clipPath: `url(#dot-${dotId})`
53
+ }
54
+ ),
55
+ /* @__PURE__ */ jsx("circle", { cx, cy, r: r2 - stroke / 2, fill: "currentColor" })
56
+ ] });
57
+ }
58
+ const r = 3;
59
+ return /* @__PURE__ */ jsxs("g", { className, mask, children: [
60
+ /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx("clipPath", { id: `dot-${dotId}`, children: /* @__PURE__ */ jsx("circle", { cx, cy, r }) }) }),
61
+ /* @__PURE__ */ jsx(
62
+ "rect",
63
+ {
64
+ x: "0",
65
+ y: cy - r,
66
+ width: "100%",
67
+ height: r * 2,
68
+ fill: paint,
69
+ fillOpacity,
70
+ clipPath: `url(#dot-${dotId})`
71
+ }
72
+ )
73
+ ] });
74
+ });
75
+ export {
76
+ ChartDot
77
+ };
78
+ //# sourceMappingURL=dot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/charts/lib/dot.tsx"],"sourcesContent":["import { memo, useId } from 'react'\nimport { cn } from '../../lib/cn'\n\n/** How a point marker is drawn on a line or an area. */\nexport type ChartDotVariant = 'default' | 'border' | 'colored-border'\n\nexport interface ChartDotProps {\n cx?: number\n cy?: number\n /** The series this dot belongs to — it picks up that series' gradient. */\n dataKey: string\n /** The owning mark's id, which scopes its gradient. */\n chartId: string\n className?: string\n fillOpacity?: number\n variant?: ChartDotVariant\n /** The intro wipe's mask, so a resting dot reveals with its own line. */\n maskId?: string\n}\n\n/**\n * A point marker painted from its series' gradient rather than from a flat\n * colour.\n *\n * The trick each variant shares: a full-width rect filled with the series\n * gradient, clipped to a circle. Filling the circle directly would restart the\n * gradient inside the dot's own bounding box, so every dot on a line would be\n * the same colour instead of sampling the gradient at the x it sits on.\n */\nexport const ChartDot = memo(function ChartDot({\n cx,\n cy,\n dataKey,\n chartId,\n className,\n fillOpacity = 1,\n variant = 'default',\n maskId,\n}: ChartDotProps) {\n const dotId = useId().replace(/:/g, '')\n\n if (cx === undefined || cy === undefined) return null\n\n const paint = `url(#${chartId}-colors-${dataKey})`\n const mask = maskId ? `url(#${maskId})` : undefined\n\n if (variant === 'border') {\n // A wide ground ring in the page colour, so the dot reads as sitting on top\n // of the line rather than being a bulge in it.\n const r = 6\n const inner = r - 2.5\n return (\n <g className={cn('text-(--chart-surface)', className)} mask={mask}>\n <defs>\n <clipPath id={`dot-${dotId}`}>\n <circle cx={cx} cy={cy} r={inner} />\n </clipPath>\n </defs>\n <circle cx={cx} cy={cy} r={r} fill=\"currentColor\" />\n <rect\n x=\"0\"\n y={cy - inner}\n width=\"100%\"\n height={inner * 2}\n fill={paint}\n fillOpacity={fillOpacity}\n clipPath={`url(#dot-${dotId})`}\n />\n </g>\n )\n }\n\n if (variant === 'colored-border') {\n const r = 3\n const stroke = 1\n return (\n <g className={cn('text-(--chart-surface)', className)} mask={mask}>\n <defs>\n <clipPath id={`dot-${dotId}`}>\n <circle cx={cx} cy={cy} r={r + stroke / 2} />\n </clipPath>\n </defs>\n <rect\n x=\"0\"\n y={cy - r - stroke / 2}\n width=\"100%\"\n height={(r + stroke / 2) * 2}\n fill={paint}\n fillOpacity={fillOpacity}\n clipPath={`url(#dot-${dotId})`}\n />\n <circle cx={cx} cy={cy} r={r - stroke / 2} fill=\"currentColor\" />\n </g>\n )\n }\n\n const r = 3\n return (\n <g className={className} mask={mask}>\n <defs>\n <clipPath id={`dot-${dotId}`}>\n <circle cx={cx} cy={cy} r={r} />\n </clipPath>\n </defs>\n <rect\n x=\"0\"\n y={cy - r}\n width=\"100%\"\n height={r * 2}\n fill={paint}\n fillOpacity={fillOpacity}\n clipPath={`url(#dot-${dotId})`}\n />\n </g>\n )\n})\n"],"mappings":"AAoDM,SAGM,KAHN;AApDN,SAAS,MAAM,aAAa;AAC5B,SAAS,UAAU;AA4BZ,MAAM,WAAW,KAAK,SAASA,UAAS;AAAA,EAC7C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd,UAAU;AAAA,EACV;AACF,GAAkB;AAChB,QAAM,QAAQ,MAAM,EAAE,QAAQ,MAAM,EAAE;AAEtC,MAAI,OAAO,UAAa,OAAO,OAAW,QAAO;AAEjD,QAAM,QAAQ,QAAQ,OAAO,WAAW,OAAO;AAC/C,QAAM,OAAO,SAAS,QAAQ,MAAM,MAAM;AAE1C,MAAI,YAAY,UAAU;AAGxB,UAAMC,KAAI;AACV,UAAM,QAAQA,KAAI;AAClB,WACE,qBAAC,OAAE,WAAW,GAAG,0BAA0B,SAAS,GAAG,MACrD;AAAA,0BAAC,UACC,8BAAC,cAAS,IAAI,OAAO,KAAK,IACxB,8BAAC,YAAO,IAAQ,IAAQ,GAAG,OAAO,GACpC,GACF;AAAA,MACA,oBAAC,YAAO,IAAQ,IAAQ,GAAGA,IAAG,MAAK,gBAAe;AAAA,MAClD;AAAA,QAAC;AAAA;AAAA,UACC,GAAE;AAAA,UACF,GAAG,KAAK;AAAA,UACR,OAAM;AAAA,UACN,QAAQ,QAAQ;AAAA,UAChB,MAAM;AAAA,UACN;AAAA,UACA,UAAU,YAAY,KAAK;AAAA;AAAA,MAC7B;AAAA,OACF;AAAA,EAEJ;AAEA,MAAI,YAAY,kBAAkB;AAChC,UAAMA,KAAI;AACV,UAAM,SAAS;AACf,WACE,qBAAC,OAAE,WAAW,GAAG,0BAA0B,SAAS,GAAG,MACrD;AAAA,0BAAC,UACC,8BAAC,cAAS,IAAI,OAAO,KAAK,IACxB,8BAAC,YAAO,IAAQ,IAAQ,GAAGA,KAAI,SAAS,GAAG,GAC7C,GACF;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,GAAE;AAAA,UACF,GAAG,KAAKA,KAAI,SAAS;AAAA,UACrB,OAAM;AAAA,UACN,SAASA,KAAI,SAAS,KAAK;AAAA,UAC3B,MAAM;AAAA,UACN;AAAA,UACA,UAAU,YAAY,KAAK;AAAA;AAAA,MAC7B;AAAA,MACA,oBAAC,YAAO,IAAQ,IAAQ,GAAGA,KAAI,SAAS,GAAG,MAAK,gBAAe;AAAA,OACjE;AAAA,EAEJ;AAEA,QAAM,IAAI;AACV,SACE,qBAAC,OAAE,WAAsB,MACvB;AAAA,wBAAC,UACC,8BAAC,cAAS,IAAI,OAAO,KAAK,IACxB,8BAAC,YAAO,IAAQ,IAAQ,GAAM,GAChC,GACF;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,GAAE;AAAA,QACF,GAAG,KAAK;AAAA,QACR,OAAM;AAAA,QACN,QAAQ,IAAI;AAAA,QACZ,MAAM;AAAA,QACN;AAAA,QACA,UAAU,YAAY,KAAK;AAAA;AAAA,IAC7B;AAAA,KACF;AAEJ,CAAC;","names":["ChartDot","r"]}
@@ -0,0 +1,31 @@
1
+ import * as react from 'react';
2
+ import { ReactNode } from 'react';
3
+
4
+ interface ChartEmptyProps {
5
+ /** What is missing. Says what happened, not "no data". */
6
+ title?: ReactNode;
7
+ /** Why, or what to change — a filter to widen, a range to move. */
8
+ description?: ReactNode;
9
+ /** The one thing to do next. */
10
+ action?: ReactNode;
11
+ }
12
+ /**
13
+ * What a chart shows when it has nothing to draw.
14
+ *
15
+ * The state almost every chart library forgets, and the one a real dashboard
16
+ * hits within a week: a filter that matches nothing, a new account, a range
17
+ * before the data starts. Without it a chart hands the reader an empty pair of
18
+ * axes, which is indistinguishable from a chart that failed to load — so the
19
+ * reader reloads the page, and it is still empty.
20
+ *
21
+ * Distinct from the loading skeleton, which says "not yet". This says "there
22
+ * is nothing here", which is a different sentence and usually has an action
23
+ * attached to it.
24
+ *
25
+ * Reuses the system's own `EmptyState` rather than inventing a chart-shaped
26
+ * one: an empty chart and an empty table are the same event, and a reader
27
+ * should not have to learn two vocabularies for it.
28
+ */
29
+ declare function ChartEmpty({ title, description, action, }: ChartEmptyProps): react.JSX.Element;
30
+
31
+ export { ChartEmpty, type ChartEmptyProps };
@@ -0,0 +1,24 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { EmptyState } from "../../components/EmptyState/EmptyState.js";
3
+ function ChartEmpty({
4
+ title = "No data in this range",
5
+ description = "Nothing matched the current filters. Widen the range, or clear a filter.",
6
+ action
7
+ }) {
8
+ return (
9
+ // `my-auto` is what keeps this where the plot was. The box sizes itself
10
+ // 16:9 up to 26rem, which is right for a card that grows to its content and
11
+ // short of a figure given a fixed height by the page around it — a
12
+ // dashboard tile, a panel in a grid. Without the auto margin the state pins
13
+ // to the top of that figure while the plot it stands in for filled the
14
+ // whole cell, so the same chart reads at two different heights depending on
15
+ // whether it has data. The margin absorbs the free space when there is any
16
+ // and does nothing when there is none, so the content-sized case is
17
+ // untouched.
18
+ /* @__PURE__ */ jsx("div", { className: "my-auto flex aspect-video max-h-[26rem] min-h-[13rem] w-full items-center justify-center", children: /* @__PURE__ */ jsx(EmptyState, { title, description, action, className: "py-0" }) })
19
+ );
20
+ }
21
+ export {
22
+ ChartEmpty
23
+ };
24
+ //# sourceMappingURL=empty.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/charts/lib/empty.tsx"],"sourcesContent":["import type { ReactNode } from 'react'\nimport { EmptyState } from '../../components/EmptyState/EmptyState'\n\nexport interface ChartEmptyProps {\n /** What is missing. Says what happened, not \"no data\". */\n title?: ReactNode\n /** Why, or what to change — a filter to widen, a range to move. */\n description?: ReactNode\n /** The one thing to do next. */\n action?: ReactNode\n}\n\n/**\n * What a chart shows when it has nothing to draw.\n *\n * The state almost every chart library forgets, and the one a real dashboard\n * hits within a week: a filter that matches nothing, a new account, a range\n * before the data starts. Without it a chart hands the reader an empty pair of\n * axes, which is indistinguishable from a chart that failed to load — so the\n * reader reloads the page, and it is still empty.\n *\n * Distinct from the loading skeleton, which says \"not yet\". This says \"there\n * is nothing here\", which is a different sentence and usually has an action\n * attached to it.\n *\n * Reuses the system's own `EmptyState` rather than inventing a chart-shaped\n * one: an empty chart and an empty table are the same event, and a reader\n * should not have to learn two vocabularies for it.\n */\nexport function ChartEmpty({\n title = 'No data in this range',\n description = 'Nothing matched the current filters. Widen the range, or clear a filter.',\n action,\n}: ChartEmptyProps) {\n return (\n // `my-auto` is what keeps this where the plot was. The box sizes itself\n // 16:9 up to 26rem, which is right for a card that grows to its content and\n // short of a figure given a fixed height by the page around it — a\n // dashboard tile, a panel in a grid. Without the auto margin the state pins\n // to the top of that figure while the plot it stands in for filled the\n // whole cell, so the same chart reads at two different heights depending on\n // whether it has data. The margin absorbs the free space when there is any\n // and does nothing when there is none, so the content-sized case is\n // untouched.\n <div className=\"my-auto flex aspect-video max-h-[26rem] min-h-[13rem] w-full items-center justify-center\">\n <EmptyState title={title} description={description} action={action} className=\"py-0\" />\n </div>\n )\n}\n"],"mappings":"AA6CM;AA5CN,SAAS,kBAAkB;AA4BpB,SAAS,WAAW;AAAA,EACzB,QAAQ;AAAA,EACR,cAAc;AAAA,EACd;AACF,GAAoB;AAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAUE,oBAAC,SAAI,WAAU,4FACb,8BAAC,cAAW,OAAc,aAA0B,QAAgB,WAAU,QAAO,GACvF;AAAA;AAEJ;","names":[]}
@@ -0,0 +1,94 @@
1
+ import { ChartColumn } from './figure.js';
2
+ export { downloadBlob } from '../../lib/svg-export.js';
3
+ import 'react';
4
+ import './empty.js';
5
+
6
+ /**
7
+ * Taking a chart off the page: a PNG of the plot, or a CSV of its rows.
8
+ *
9
+ * The general half — walking a live tree to inline its resolved paint,
10
+ * serialising a standalone SVG document, rasterising one through a canvas — is
11
+ * not chart-shaped at all, and lives in `src/lib/svg-export.ts` shared with the
12
+ * diagrams entry. What is left here is what only a Recharts chart knows: which
13
+ * `<svg>` in the subtree is the plot, what a row of chart data looks like as a
14
+ * CSV record, and that the ground behind an exported plot is `--chart-surface`.
15
+ *
16
+ * Nothing here touches the DOM at module scope. Every browser API is reached
17
+ * for inside a function body, so this module is safe to import from a server
18
+ * component and only fails when a consumer actually asks for a file on a
19
+ * server, which is a call that cannot succeed anywhere.
20
+ */
21
+ interface ChartPngOptions {
22
+ /**
23
+ * Printed above the plot in the exported image. Pass the figure's title: a
24
+ * PNG travels into a slide deck with none of the page's context around it,
25
+ * and an unnamed plot in a deck is a plot nobody can cite.
26
+ */
27
+ title?: string;
28
+ /** Multiplier on the on-screen size. 2 is a retina-sharp export. */
29
+ scale?: number;
30
+ /**
31
+ * Painted behind the plot. Defaults to the resolved `--chart-surface`, which
32
+ * is what makes a dark-mode export come out dark rather than transparent.
33
+ */
34
+ background?: string;
35
+ /** Space around the plot, in CSS pixels. */
36
+ padding?: number;
37
+ }
38
+ /**
39
+ * The chart's `<svg>`, rasterised to a PNG blob.
40
+ *
41
+ * Three chart-specific decisions and nothing else. `serializeSvg` does the
42
+ * work, and its comment carries the reason a naive `XMLSerializer` export of a
43
+ * themed chart comes out as an empty rectangle with axes on it.
44
+ *
45
+ * 1. WHICH `<svg>` — the plot, not the first one in the subtree. See
46
+ * `findPlotSvg`.
47
+ * 2. WHAT GROUND — `--chart-surface`, resolved against the live element, which
48
+ * is what makes a dark-mode export come out dark rather than transparent.
49
+ * 3. WHAT INK AND FACE for the caption — `--ink` and the element's own
50
+ * resolved family, so the exported title matches the page it came from.
51
+ *
52
+ * ## What this cannot capture, honestly
53
+ *
54
+ * - **Anything drawn in HTML.** The legend, the tooltip, the brush strip and
55
+ * the hidden data table are DOM, not SVG. The PNG is the plot.
56
+ * - **Web fonts, cross-origin images, and the exact rendering.** See
57
+ * `serializeSvg` and `rasterize`.
58
+ *
59
+ * @example
60
+ * const blob = await chartToPng(plotRef.current, { title: 'Visitors per month' })
61
+ * downloadBlob(blob, exportFilename('Visitors per month', 'png'))
62
+ */
63
+ declare function chartToPng(element: HTMLElement | SVGSVGElement, options?: ChartPngOptions): Promise<Blob>;
64
+ /**
65
+ * The chart's rows as RFC 4180 CSV.
66
+ *
67
+ * Quotes a field only when it needs quoting — a comma, a double quote, or a
68
+ * line break in it — doubles any quote inside, and separates records with CRLF
69
+ * as the RFC requires rather than with the `\n` a Unix habit would reach for.
70
+ *
71
+ * Numbers are written unformatted on purpose. `1,234` would need quoting and
72
+ * would then land in the spreadsheet as text, which is the one thing a numeric
73
+ * export must not do; formatting belongs to the chart, not to the file.
74
+ *
75
+ * A column's `label` is a `ReactNode`, so only a string or a number can be a
76
+ * header. Anything else falls back to the column's key, which is a worse
77
+ * header than the label but a better one than an empty cell.
78
+ *
79
+ * @example
80
+ * const csv = chartToCsv(data, [{ key: 'desktop', label: 'Desktop' }])
81
+ * downloadBlob(new Blob([csv], { type: 'text/csv;charset=utf-8' }), 'visitors.csv')
82
+ */
83
+ declare function chartToCsv(rows: Record<string, unknown>[], columns: ChartColumn[]): string;
84
+
85
+ /**
86
+ * A figure's title as a filename.
87
+ *
88
+ * The shared slugger, with `chart` rather than `figure` as the fallback for a
89
+ * title that slugs to nothing — an export from this entry is a chart, and the
90
+ * name a reader finds in their downloads folder should say so.
91
+ */
92
+ declare function exportFilename(title: string, extension: string): string;
93
+
94
+ export { type ChartPngOptions, chartToCsv, chartToPng, exportFilename };
@@ -0,0 +1,62 @@
1
+ import {
2
+ downloadBlob,
3
+ exportFilename as figureFilename,
4
+ rasterize,
5
+ readToken,
6
+ serializeSvg
7
+ } from "../../lib/svg-export.js";
8
+ async function chartToPng(element, options = {}) {
9
+ const { title, scale = 2, background, padding = 16 } = options;
10
+ const svg = findPlotSvg(element);
11
+ if (!svg) throw new Error("chartToPng: found no <svg> to export inside the element it was given");
12
+ const markup = serializeSvg(svg, {
13
+ padding,
14
+ background: background ?? readToken(element, "--chart-surface", "#ffffff"),
15
+ title,
16
+ titleColor: readToken(element, "--ink", "#101010"),
17
+ titleFont: getComputedStyle(element).fontFamily || "sans-serif"
18
+ });
19
+ return rasterize(markup, "png", { scale });
20
+ }
21
+ function findPlotSvg(element) {
22
+ if (element.tagName.toLowerCase() === "svg") return element;
23
+ const scope = element.querySelector('[data-slot="chart"]') ?? element;
24
+ return scope.querySelector("svg.recharts-surface") ?? scope.querySelector("svg");
25
+ }
26
+ const UTF8_BOM = "\uFEFF";
27
+ function chartToCsv(rows, columns) {
28
+ if (columns.length === 0) return UTF8_BOM;
29
+ const lines = [columns.map((column) => csvField(headerText(column))).join(",")];
30
+ for (const row of rows) {
31
+ lines.push(columns.map((column) => csvField(cellText(row[column.key]))).join(","));
32
+ }
33
+ return `${UTF8_BOM}${lines.join("\r\n")}\r
34
+ `;
35
+ }
36
+ function csvField(value) {
37
+ if (!/[",\r\n]/.test(value)) return value;
38
+ return `"${value.replace(/"/g, '""')}"`;
39
+ }
40
+ function headerText(column) {
41
+ const { label } = column;
42
+ if (typeof label === "string") return label;
43
+ if (typeof label === "number") return String(label);
44
+ return column.key;
45
+ }
46
+ function cellText(value) {
47
+ if (value === null || value === void 0) return "";
48
+ if (typeof value === "number") return Number.isFinite(value) ? String(value) : "";
49
+ if (typeof value === "string" || typeof value === "boolean") return String(value);
50
+ if (value instanceof Date) return value.toISOString();
51
+ return "";
52
+ }
53
+ function exportFilename(title, extension) {
54
+ return figureFilename(title, extension, "chart");
55
+ }
56
+ export {
57
+ chartToCsv,
58
+ chartToPng,
59
+ downloadBlob,
60
+ exportFilename
61
+ };
62
+ //# sourceMappingURL=export.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/charts/lib/export.ts"],"sourcesContent":["import type { ChartColumn } from './figure'\nimport {\n downloadBlob,\n exportFilename as figureFilename,\n rasterize,\n readToken,\n serializeSvg,\n} from '../../lib/svg-export'\n\n/**\n * Taking a chart off the page: a PNG of the plot, or a CSV of its rows.\n *\n * The general half — walking a live tree to inline its resolved paint,\n * serialising a standalone SVG document, rasterising one through a canvas — is\n * not chart-shaped at all, and lives in `src/lib/svg-export.ts` shared with the\n * diagrams entry. What is left here is what only a Recharts chart knows: which\n * `<svg>` in the subtree is the plot, what a row of chart data looks like as a\n * CSV record, and that the ground behind an exported plot is `--chart-surface`.\n *\n * Nothing here touches the DOM at module scope. Every browser API is reached\n * for inside a function body, so this module is safe to import from a server\n * component and only fails when a consumer actually asks for a file on a\n * server, which is a call that cannot succeed anywhere.\n */\n\nexport interface ChartPngOptions {\n /**\n * Printed above the plot in the exported image. Pass the figure's title: a\n * PNG travels into a slide deck with none of the page's context around it,\n * and an unnamed plot in a deck is a plot nobody can cite.\n */\n title?: string\n /** Multiplier on the on-screen size. 2 is a retina-sharp export. */\n scale?: number\n /**\n * Painted behind the plot. Defaults to the resolved `--chart-surface`, which\n * is what makes a dark-mode export come out dark rather than transparent.\n */\n background?: string\n /** Space around the plot, in CSS pixels. */\n padding?: number\n}\n\n/**\n * The chart's `<svg>`, rasterised to a PNG blob.\n *\n * Three chart-specific decisions and nothing else. `serializeSvg` does the\n * work, and its comment carries the reason a naive `XMLSerializer` export of a\n * themed chart comes out as an empty rectangle with axes on it.\n *\n * 1. WHICH `<svg>` — the plot, not the first one in the subtree. See\n * `findPlotSvg`.\n * 2. WHAT GROUND — `--chart-surface`, resolved against the live element, which\n * is what makes a dark-mode export come out dark rather than transparent.\n * 3. WHAT INK AND FACE for the caption — `--ink` and the element's own\n * resolved family, so the exported title matches the page it came from.\n *\n * ## What this cannot capture, honestly\n *\n * - **Anything drawn in HTML.** The legend, the tooltip, the brush strip and\n * the hidden data table are DOM, not SVG. The PNG is the plot.\n * - **Web fonts, cross-origin images, and the exact rendering.** See\n * `serializeSvg` and `rasterize`.\n *\n * @example\n * const blob = await chartToPng(plotRef.current, { title: 'Visitors per month' })\n * downloadBlob(blob, exportFilename('Visitors per month', 'png'))\n */\nexport async function chartToPng(\n element: HTMLElement | SVGSVGElement,\n options: ChartPngOptions = {},\n): Promise<Blob> {\n const { title, scale = 2, background, padding = 16 } = options\n\n const svg = findPlotSvg(element)\n if (!svg) throw new Error('chartToPng: found no <svg> to export inside the element it was given')\n\n const markup = serializeSvg(svg, {\n padding,\n background: background ?? readToken(element, '--chart-surface', '#ffffff'),\n title,\n titleColor: readToken(element, '--ink', '#101010'),\n titleFont: getComputedStyle(element).fontFamily || 'sans-serif',\n })\n\n return rasterize(markup, 'png', { scale })\n}\n\n/**\n * The plot's `<svg>`, not the first `<svg>` in the subtree.\n *\n * Two narrowings, and both are load-bearing. The toolbar sits outside the plot\n * wrapper and every control in it is an `<svg>`, so the scope comes first;\n * INSIDE the wrapper the legend draws its own swatches, so `.recharts-surface`\n * comes second. Either one missing exports a picture of an icon, which looks\n * like a working download until somebody opens the file.\n */\nfunction findPlotSvg(element: HTMLElement | SVGSVGElement): SVGSVGElement | null {\n if (element.tagName.toLowerCase() === 'svg') return element as SVGSVGElement\n const scope = element.querySelector('[data-slot=\"chart\"]') ?? element\n return scope.querySelector<SVGSVGElement>('svg.recharts-surface') ?? scope.querySelector('svg')\n}\n\n/**\n * A UTF-8 byte order mark.\n *\n * Excel does not sniff encodings. Handed a CSV with no BOM it decodes the file\n * with the machine's legacy code page, so \"Müller\", \"東京\" and \"€\" arrive as\n * mojibake on most Windows installs — and the reader's conclusion is that the\n * export is broken, not that the encoding was guessed. The BOM is the only\n * in-band signal Excel honours, and every other tool skips it silently.\n */\nconst UTF8_BOM = '\\uFEFF'\n\n/**\n * The chart's rows as RFC 4180 CSV.\n *\n * Quotes a field only when it needs quoting — a comma, a double quote, or a\n * line break in it — doubles any quote inside, and separates records with CRLF\n * as the RFC requires rather than with the `\\n` a Unix habit would reach for.\n *\n * Numbers are written unformatted on purpose. `1,234` would need quoting and\n * would then land in the spreadsheet as text, which is the one thing a numeric\n * export must not do; formatting belongs to the chart, not to the file.\n *\n * A column's `label` is a `ReactNode`, so only a string or a number can be a\n * header. Anything else falls back to the column's key, which is a worse\n * header than the label but a better one than an empty cell.\n *\n * @example\n * const csv = chartToCsv(data, [{ key: 'desktop', label: 'Desktop' }])\n * downloadBlob(new Blob([csv], { type: 'text/csv;charset=utf-8' }), 'visitors.csv')\n */\nexport function chartToCsv(rows: Record<string, unknown>[], columns: ChartColumn[]): string {\n if (columns.length === 0) return UTF8_BOM\n\n const lines = [columns.map((column) => csvField(headerText(column))).join(',')]\n\n for (const row of rows) {\n lines.push(columns.map((column) => csvField(cellText(row[column.key]))).join(','))\n }\n\n // The RFC makes the last CRLF optional; writing it matches what a\n // spreadsheet emits and keeps the file from ending mid-record in a terminal.\n return `${UTF8_BOM}${lines.join('\\r\\n')}\\r\\n`\n}\n\n/** One field, quoted only when the RFC says it has to be. */\nfunction csvField(value: string): string {\n if (!/[\",\\r\\n]/.test(value)) return value\n return `\"${value.replace(/\"/g, '\"\"')}\"`\n}\n\n/** A column's header text, falling back to its key when the label is markup. */\nfunction headerText(column: ChartColumn): string {\n const { label } = column\n if (typeof label === 'string') return label\n if (typeof label === 'number') return String(label)\n return column.key\n}\n\n/** A cell value as text. Anything that is not a primitive reads as empty. */\nfunction cellText(value: unknown): string {\n if (value === null || value === undefined) return ''\n if (typeof value === 'number') return Number.isFinite(value) ? String(value) : ''\n if (typeof value === 'string' || typeof value === 'boolean') return String(value)\n if (value instanceof Date) return value.toISOString()\n return ''\n}\n\nexport { downloadBlob }\n\n/**\n * A figure's title as a filename.\n *\n * The shared slugger, with `chart` rather than `figure` as the fallback for a\n * title that slugs to nothing — an export from this entry is a chart, and the\n * name a reader finds in their downloads folder should say so.\n */\nexport function exportFilename(title: string, extension: string): string {\n return figureFilename(title, extension, 'chart')\n}\n"],"mappings":"AACA;AAAA,EACE;AAAA,EACA,kBAAkB;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,OACK;AA6DP,eAAsB,WACpB,SACA,UAA2B,CAAC,GACb;AACf,QAAM,EAAE,OAAO,QAAQ,GAAG,YAAY,UAAU,GAAG,IAAI;AAEvD,QAAM,MAAM,YAAY,OAAO;AAC/B,MAAI,CAAC,IAAK,OAAM,IAAI,MAAM,sEAAsE;AAEhG,QAAM,SAAS,aAAa,KAAK;AAAA,IAC/B;AAAA,IACA,YAAY,cAAc,UAAU,SAAS,mBAAmB,SAAS;AAAA,IACzE;AAAA,IACA,YAAY,UAAU,SAAS,SAAS,SAAS;AAAA,IACjD,WAAW,iBAAiB,OAAO,EAAE,cAAc;AAAA,EACrD,CAAC;AAED,SAAO,UAAU,QAAQ,OAAO,EAAE,MAAM,CAAC;AAC3C;AAWA,SAAS,YAAY,SAA4D;AAC/E,MAAI,QAAQ,QAAQ,YAAY,MAAM,MAAO,QAAO;AACpD,QAAM,QAAQ,QAAQ,cAAc,qBAAqB,KAAK;AAC9D,SAAO,MAAM,cAA6B,sBAAsB,KAAK,MAAM,cAAc,KAAK;AAChG;AAWA,MAAM,WAAW;AAqBV,SAAS,WAAW,MAAiC,SAAgC;AAC1F,MAAI,QAAQ,WAAW,EAAG,QAAO;AAEjC,QAAM,QAAQ,CAAC,QAAQ,IAAI,CAAC,WAAW,SAAS,WAAW,MAAM,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC;AAE9E,aAAW,OAAO,MAAM;AACtB,UAAM,KAAK,QAAQ,IAAI,CAAC,WAAW,SAAS,SAAS,IAAI,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC;AAAA,EACnF;AAIA,SAAO,GAAG,QAAQ,GAAG,MAAM,KAAK,MAAM,CAAC;AAAA;AACzC;AAGA,SAAS,SAAS,OAAuB;AACvC,MAAI,CAAC,WAAW,KAAK,KAAK,EAAG,QAAO;AACpC,SAAO,IAAI,MAAM,QAAQ,MAAM,IAAI,CAAC;AACtC;AAGA,SAAS,WAAW,QAA6B;AAC/C,QAAM,EAAE,MAAM,IAAI;AAClB,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,OAAO,UAAU,SAAU,QAAO,OAAO,KAAK;AAClD,SAAO,OAAO;AAChB;AAGA,SAAS,SAAS,OAAwB;AACxC,MAAI,UAAU,QAAQ,UAAU,OAAW,QAAO;AAClD,MAAI,OAAO,UAAU,SAAU,QAAO,OAAO,SAAS,KAAK,IAAI,OAAO,KAAK,IAAI;AAC/E,MAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAAW,QAAO,OAAO,KAAK;AAChF,MAAI,iBAAiB,KAAM,QAAO,MAAM,YAAY;AACpD,SAAO;AACT;AAWO,SAAS,eAAe,OAAe,WAA2B;AACvE,SAAO,eAAe,OAAO,WAAW,OAAO;AACjD;","names":[]}