@misoto22/folio 0.0.0 → 0.17.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 (721) 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/Workbench.md +142 -0
  122. package/dist/agent/WorkflowFigure.md +51 -0
  123. package/dist/agent/catalog.json +8055 -0
  124. package/dist/agent/index.md +185 -0
  125. package/dist/article.css +407 -0
  126. package/dist/charts/AreaChart/AreaChart.d.ts +198 -0
  127. package/dist/charts/AreaChart/AreaChart.js +479 -0
  128. package/dist/charts/AreaChart/AreaChart.js.map +1 -0
  129. package/dist/charts/BarChart/BarChart.d.ts +190 -0
  130. package/dist/charts/BarChart/BarChart.js +599 -0
  131. package/dist/charts/BarChart/BarChart.js.map +1 -0
  132. package/dist/charts/BarList/BarList.d.ts +65 -0
  133. package/dist/charts/BarList/BarList.js +79 -0
  134. package/dist/charts/BarList/BarList.js.map +1 -0
  135. package/dist/charts/BigNumber/BigNumber.d.ts +72 -0
  136. package/dist/charts/BigNumber/BigNumber.js +51 -0
  137. package/dist/charts/BigNumber/BigNumber.js.map +1 -0
  138. package/dist/charts/BoxPlot/BoxPlot.d.ts +177 -0
  139. package/dist/charts/BoxPlot/BoxPlot.js +497 -0
  140. package/dist/charts/BoxPlot/BoxPlot.js.map +1 -0
  141. package/dist/charts/BulletChart/BulletChart.d.ts +100 -0
  142. package/dist/charts/BulletChart/BulletChart.js +197 -0
  143. package/dist/charts/BulletChart/BulletChart.js.map +1 -0
  144. package/dist/charts/CalendarHeatmap/CalendarHeatmap.d.ts +106 -0
  145. package/dist/charts/CalendarHeatmap/CalendarHeatmap.js +103 -0
  146. package/dist/charts/CalendarHeatmap/CalendarHeatmap.js.map +1 -0
  147. package/dist/charts/ComposedChart/ComposedChart.d.ts +178 -0
  148. package/dist/charts/ComposedChart/ComposedChart.js +667 -0
  149. package/dist/charts/ComposedChart/ComposedChart.js.map +1 -0
  150. package/dist/charts/Facet/Facet.d.ts +240 -0
  151. package/dist/charts/Facet/Facet.js +133 -0
  152. package/dist/charts/Facet/Facet.js.map +1 -0
  153. package/dist/charts/Facet/panels.d.ts +187 -0
  154. package/dist/charts/Facet/panels.js +203 -0
  155. package/dist/charts/Facet/panels.js.map +1 -0
  156. package/dist/charts/FunnelChart/FunnelChart.d.ts +106 -0
  157. package/dist/charts/FunnelChart/FunnelChart.js +137 -0
  158. package/dist/charts/FunnelChart/FunnelChart.js.map +1 -0
  159. package/dist/charts/Heatmap/Heatmap.d.ts +101 -0
  160. package/dist/charts/Heatmap/Heatmap.js +125 -0
  161. package/dist/charts/Heatmap/Heatmap.js.map +1 -0
  162. package/dist/charts/Histogram/Histogram.d.ts +188 -0
  163. package/dist/charts/Histogram/Histogram.js +382 -0
  164. package/dist/charts/Histogram/Histogram.js.map +1 -0
  165. package/dist/charts/LineChart/LineChart.d.ts +174 -0
  166. package/dist/charts/LineChart/LineChart.js +485 -0
  167. package/dist/charts/LineChart/LineChart.js.map +1 -0
  168. package/dist/charts/PieChart/PieChart.d.ts +140 -0
  169. package/dist/charts/PieChart/PieChart.js +317 -0
  170. package/dist/charts/PieChart/PieChart.js.map +1 -0
  171. package/dist/charts/RadarChart/RadarChart.d.ts +135 -0
  172. package/dist/charts/RadarChart/RadarChart.js +303 -0
  173. package/dist/charts/RadarChart/RadarChart.js.map +1 -0
  174. package/dist/charts/RadialChart/RadialChart.d.ts +142 -0
  175. package/dist/charts/RadialChart/RadialChart.js +279 -0
  176. package/dist/charts/RadialChart/RadialChart.js.map +1 -0
  177. package/dist/charts/SankeyChart/SankeyChart.d.ts +149 -0
  178. package/dist/charts/SankeyChart/SankeyChart.js +509 -0
  179. package/dist/charts/SankeyChart/SankeyChart.js.map +1 -0
  180. package/dist/charts/ScatterChart/ScatterChart.d.ts +149 -0
  181. package/dist/charts/ScatterChart/ScatterChart.js +275 -0
  182. package/dist/charts/ScatterChart/ScatterChart.js.map +1 -0
  183. package/dist/charts/Sparkline/Sparkline.d.ts +53 -0
  184. package/dist/charts/Sparkline/Sparkline.js +95 -0
  185. package/dist/charts/Sparkline/Sparkline.js.map +1 -0
  186. package/dist/charts/TreemapChart/TreemapChart.d.ts +98 -0
  187. package/dist/charts/TreemapChart/TreemapChart.js +127 -0
  188. package/dist/charts/TreemapChart/TreemapChart.js.map +1 -0
  189. package/dist/charts/WaterfallChart/WaterfallChart.d.ts +164 -0
  190. package/dist/charts/WaterfallChart/WaterfallChart.js +321 -0
  191. package/dist/charts/WaterfallChart/WaterfallChart.js.map +1 -0
  192. package/dist/charts/index.d.ts +43 -0
  193. package/dist/charts/index.js +130 -0
  194. package/dist/charts/index.js.map +1 -0
  195. package/dist/charts/lib/annotations.d.ts +103 -0
  196. package/dist/charts/lib/annotations.js +99 -0
  197. package/dist/charts/lib/annotations.js.map +1 -0
  198. package/dist/charts/lib/axis.d.ts +18 -0
  199. package/dist/charts/lib/axis.js +21 -0
  200. package/dist/charts/lib/axis.js.map +1 -0
  201. package/dist/charts/lib/background.d.ts +33 -0
  202. package/dist/charts/lib/background.js +173 -0
  203. package/dist/charts/lib/background.js.map +1 -0
  204. package/dist/charts/lib/brush.d.ts +94 -0
  205. package/dist/charts/lib/brush.js +535 -0
  206. package/dist/charts/lib/brush.js.map +1 -0
  207. package/dist/charts/lib/chart.d.ts +94 -0
  208. package/dist/charts/lib/chart.js +149 -0
  209. package/dist/charts/lib/chart.js.map +1 -0
  210. package/dist/charts/lib/dot.d.ts +29 -0
  211. package/dist/charts/lib/dot.js +78 -0
  212. package/dist/charts/lib/dot.js.map +1 -0
  213. package/dist/charts/lib/empty.d.ts +31 -0
  214. package/dist/charts/lib/empty.js +24 -0
  215. package/dist/charts/lib/empty.js.map +1 -0
  216. package/dist/charts/lib/export.d.ts +94 -0
  217. package/dist/charts/lib/export.js +62 -0
  218. package/dist/charts/lib/export.js.map +1 -0
  219. package/dist/charts/lib/figure.d.ts +81 -0
  220. package/dist/charts/lib/figure.js +62 -0
  221. package/dist/charts/lib/figure.js.map +1 -0
  222. package/dist/charts/lib/format.d.ts +46 -0
  223. package/dist/charts/lib/format.js +56 -0
  224. package/dist/charts/lib/format.js.map +1 -0
  225. package/dist/charts/lib/legend.d.ts +45 -0
  226. package/dist/charts/lib/legend.js +117 -0
  227. package/dist/charts/lib/legend.js.map +1 -0
  228. package/dist/charts/lib/loading.d.ts +48 -0
  229. package/dist/charts/lib/loading.js +105 -0
  230. package/dist/charts/lib/loading.js.map +1 -0
  231. package/dist/charts/lib/paint.d.ts +154 -0
  232. package/dist/charts/lib/paint.js +551 -0
  233. package/dist/charts/lib/paint.js.map +1 -0
  234. package/dist/charts/lib/scale.d.ts +23 -0
  235. package/dist/charts/lib/scale.js +13 -0
  236. package/dist/charts/lib/scale.js.map +1 -0
  237. package/dist/charts/lib/selection.d.ts +20 -0
  238. package/dist/charts/lib/selection.js +18 -0
  239. package/dist/charts/lib/selection.js.map +1 -0
  240. package/dist/charts/lib/sonify-control.d.ts +163 -0
  241. package/dist/charts/lib/sonify-control.js +172 -0
  242. package/dist/charts/lib/sonify-control.js.map +1 -0
  243. package/dist/charts/lib/sonify.d.ts +248 -0
  244. package/dist/charts/lib/sonify.js +262 -0
  245. package/dist/charts/lib/sonify.js.map +1 -0
  246. package/dist/charts/lib/toolbar.d.ts +144 -0
  247. package/dist/charts/lib/toolbar.js +156 -0
  248. package/dist/charts/lib/toolbar.js.map +1 -0
  249. package/dist/charts/lib/tooltip.d.ts +59 -0
  250. package/dist/charts/lib/tooltip.js +135 -0
  251. package/dist/charts/lib/tooltip.js.map +1 -0
  252. package/dist/charts/lib/values.d.ts +56 -0
  253. package/dist/charts/lib/values.js +71 -0
  254. package/dist/charts/lib/values.js.map +1 -0
  255. package/dist/charts/lib/zoom.d.ts +139 -0
  256. package/dist/charts/lib/zoom.js +314 -0
  257. package/dist/charts/lib/zoom.js.map +1 -0
  258. package/dist/components/Accordion/Accordion.d.ts +34 -0
  259. package/dist/components/Accordion/Accordion.js +43 -0
  260. package/dist/components/Accordion/Accordion.js.map +1 -0
  261. package/dist/components/Alert/Alert.d.ts +32 -0
  262. package/dist/components/Alert/Alert.js +49 -0
  263. package/dist/components/Alert/Alert.js.map +1 -0
  264. package/dist/components/AppShell/AppShell.d.ts +58 -0
  265. package/dist/components/AppShell/AppShell.js +126 -0
  266. package/dist/components/AppShell/AppShell.js.map +1 -0
  267. package/dist/components/Article/Article.d.ts +58 -0
  268. package/dist/components/Article/Article.js +34 -0
  269. package/dist/components/Article/Article.js.map +1 -0
  270. package/dist/components/AspectRatio/AspectRatio.d.ts +46 -0
  271. package/dist/components/AspectRatio/AspectRatio.js +33 -0
  272. package/dist/components/AspectRatio/AspectRatio.js.map +1 -0
  273. package/dist/components/Avatar/Avatar.d.ts +38 -0
  274. package/dist/components/Avatar/Avatar.js +44 -0
  275. package/dist/components/Avatar/Avatar.js.map +1 -0
  276. package/dist/components/Badge/Badge.d.ts +30 -0
  277. package/dist/components/Badge/Badge.js +29 -0
  278. package/dist/components/Badge/Badge.js.map +1 -0
  279. package/dist/components/Breadcrumb/Breadcrumb.d.ts +37 -0
  280. package/dist/components/Breadcrumb/Breadcrumb.js +46 -0
  281. package/dist/components/Breadcrumb/Breadcrumb.js.map +1 -0
  282. package/dist/components/Button/Button.d.ts +70 -0
  283. package/dist/components/Button/Button.js +95 -0
  284. package/dist/components/Button/Button.js.map +1 -0
  285. package/dist/components/Calendar/Calendar.d.ts +54 -0
  286. package/dist/components/Calendar/Calendar.js +369 -0
  287. package/dist/components/Calendar/Calendar.js.map +1 -0
  288. package/dist/components/Card/Card.d.ts +55 -0
  289. package/dist/components/Card/Card.js +64 -0
  290. package/dist/components/Card/Card.js.map +1 -0
  291. package/dist/components/Checkbox/Checkbox.d.ts +26 -0
  292. package/dist/components/Checkbox/Checkbox.js +34 -0
  293. package/dist/components/Checkbox/Checkbox.js.map +1 -0
  294. package/dist/components/Code/Code.d.ts +30 -0
  295. package/dist/components/Code/Code.js +21 -0
  296. package/dist/components/Code/Code.js.map +1 -0
  297. package/dist/components/CodeBlock/CodeBlock.d.ts +145 -0
  298. package/dist/components/CodeBlock/CodeBlock.js +114 -0
  299. package/dist/components/CodeBlock/CodeBlock.js.map +1 -0
  300. package/dist/components/Collapsible/Collapsible.d.ts +45 -0
  301. package/dist/components/Collapsible/Collapsible.js +60 -0
  302. package/dist/components/Collapsible/Collapsible.js.map +1 -0
  303. package/dist/components/ColorPicker/ColorPicker.d.ts +67 -0
  304. package/dist/components/ColorPicker/ColorPicker.js +334 -0
  305. package/dist/components/ColorPicker/ColorPicker.js.map +1 -0
  306. package/dist/components/Combobox/Combobox.d.ts +77 -0
  307. package/dist/components/Combobox/Combobox.js +170 -0
  308. package/dist/components/Combobox/Combobox.js.map +1 -0
  309. package/dist/components/Command/Command.d.ts +125 -0
  310. package/dist/components/Command/Command.js +204 -0
  311. package/dist/components/Command/Command.js.map +1 -0
  312. package/dist/components/ContextMenu/ContextMenu.d.ts +63 -0
  313. package/dist/components/ContextMenu/ContextMenu.js +109 -0
  314. package/dist/components/ContextMenu/ContextMenu.js.map +1 -0
  315. package/dist/components/DatePicker/DatePicker.d.ts +130 -0
  316. package/dist/components/DatePicker/DatePicker.js +257 -0
  317. package/dist/components/DatePicker/DatePicker.js.map +1 -0
  318. package/dist/components/DescriptionList/DescriptionList.d.ts +73 -0
  319. package/dist/components/DescriptionList/DescriptionList.js +35 -0
  320. package/dist/components/DescriptionList/DescriptionList.js.map +1 -0
  321. package/dist/components/Diagram/Diagram.d.ts +86 -0
  322. package/dist/components/Diagram/Diagram.js +211 -0
  323. package/dist/components/Diagram/Diagram.js.map +1 -0
  324. package/dist/components/Dialog/Dialog.d.ts +63 -0
  325. package/dist/components/Dialog/Dialog.js +90 -0
  326. package/dist/components/Dialog/Dialog.js.map +1 -0
  327. package/dist/components/DropdownMenu/DropdownMenu.d.ts +87 -0
  328. package/dist/components/DropdownMenu/DropdownMenu.js +120 -0
  329. package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -0
  330. package/dist/components/EmptyState/EmptyState.d.ts +55 -0
  331. package/dist/components/EmptyState/EmptyState.js +32 -0
  332. package/dist/components/EmptyState/EmptyState.js.map +1 -0
  333. package/dist/components/ErrorState/ErrorState.d.ts +55 -0
  334. package/dist/components/ErrorState/ErrorState.js +41 -0
  335. package/dist/components/ErrorState/ErrorState.js.map +1 -0
  336. package/dist/components/Field/Field.d.ts +111 -0
  337. package/dist/components/Field/Field.js +95 -0
  338. package/dist/components/Field/Field.js.map +1 -0
  339. package/dist/components/Field/field-control.d.ts +31 -0
  340. package/dist/components/Field/field-control.js +12 -0
  341. package/dist/components/Field/field-control.js.map +1 -0
  342. package/dist/components/FigureBand/FigureBand.d.ts +31 -0
  343. package/dist/components/FigureBand/FigureBand.js +51 -0
  344. package/dist/components/FigureBand/FigureBand.js.map +1 -0
  345. package/dist/components/FloatingIconButton/FloatingIconButton.d.ts +29 -0
  346. package/dist/components/FloatingIconButton/FloatingIconButton.js +34 -0
  347. package/dist/components/FloatingIconButton/FloatingIconButton.js.map +1 -0
  348. package/dist/components/Heading/Heading.d.ts +62 -0
  349. package/dist/components/Heading/Heading.js +44 -0
  350. package/dist/components/Heading/Heading.js.map +1 -0
  351. package/dist/components/Input/Input.d.ts +22 -0
  352. package/dist/components/Input/Input.js +21 -0
  353. package/dist/components/Input/Input.js.map +1 -0
  354. package/dist/components/Kbd/Kbd.d.ts +27 -0
  355. package/dist/components/Kbd/Kbd.js +21 -0
  356. package/dist/components/Kbd/Kbd.js.map +1 -0
  357. package/dist/components/LinkArrow/LinkArrow.d.ts +24 -0
  358. package/dist/components/LinkArrow/LinkArrow.js +24 -0
  359. package/dist/components/LinkArrow/LinkArrow.js.map +1 -0
  360. package/dist/components/Markdown/Markdown.d.ts +139 -0
  361. package/dist/components/Markdown/Markdown.js +135 -0
  362. package/dist/components/Markdown/Markdown.js.map +1 -0
  363. package/dist/components/Markdown/inline.d.ts +29 -0
  364. package/dist/components/Markdown/inline.js +74 -0
  365. package/dist/components/Markdown/inline.js.map +1 -0
  366. package/dist/components/Markdown/nodes.d.ts +65 -0
  367. package/dist/components/Markdown/nodes.js +1 -0
  368. package/dist/components/Markdown/nodes.js.map +1 -0
  369. package/dist/components/Markdown/parse.d.ts +24 -0
  370. package/dist/components/Markdown/parse.js +110 -0
  371. package/dist/components/Markdown/parse.js.map +1 -0
  372. package/dist/components/Markdown/slug.d.ts +15 -0
  373. package/dist/components/Markdown/slug.js +7 -0
  374. package/dist/components/Markdown/slug.js.map +1 -0
  375. package/dist/components/Metric/Metric.d.ts +61 -0
  376. package/dist/components/Metric/Metric.js +51 -0
  377. package/dist/components/Metric/Metric.js.map +1 -0
  378. package/dist/components/NativeSelect/NativeSelect.d.ts +33 -0
  379. package/dist/components/NativeSelect/NativeSelect.js +44 -0
  380. package/dist/components/NativeSelect/NativeSelect.js.map +1 -0
  381. package/dist/components/NavItem/NavItem.d.ts +39 -0
  382. package/dist/components/NavItem/NavItem.js +31 -0
  383. package/dist/components/NavItem/NavItem.js.map +1 -0
  384. package/dist/components/NumberField/NumberField.d.ts +69 -0
  385. package/dist/components/NumberField/NumberField.js +162 -0
  386. package/dist/components/NumberField/NumberField.js.map +1 -0
  387. package/dist/components/PageHeader/PageHeader.d.ts +92 -0
  388. package/dist/components/PageHeader/PageHeader.js +37 -0
  389. package/dist/components/PageHeader/PageHeader.js.map +1 -0
  390. package/dist/components/Pagination/Pagination.d.ts +67 -0
  391. package/dist/components/Pagination/Pagination.js +112 -0
  392. package/dist/components/Pagination/Pagination.js.map +1 -0
  393. package/dist/components/Popover/Popover.d.ts +39 -0
  394. package/dist/components/Popover/Popover.js +57 -0
  395. package/dist/components/Popover/Popover.js.map +1 -0
  396. package/dist/components/Progress/Progress.d.ts +43 -0
  397. package/dist/components/Progress/Progress.js +57 -0
  398. package/dist/components/Progress/Progress.js.map +1 -0
  399. package/dist/components/RadioGroup/RadioGroup.d.ts +49 -0
  400. package/dist/components/RadioGroup/RadioGroup.js +53 -0
  401. package/dist/components/RadioGroup/RadioGroup.js.map +1 -0
  402. package/dist/components/ScrollArea/ScrollArea.d.ts +46 -0
  403. package/dist/components/ScrollArea/ScrollArea.js +54 -0
  404. package/dist/components/ScrollArea/ScrollArea.js.map +1 -0
  405. package/dist/components/SearchableMenu/SearchableMenu.d.ts +68 -0
  406. package/dist/components/SearchableMenu/SearchableMenu.js +101 -0
  407. package/dist/components/SearchableMenu/SearchableMenu.js.map +1 -0
  408. package/dist/components/Select/Select.d.ts +87 -0
  409. package/dist/components/Select/Select.js +130 -0
  410. package/dist/components/Select/Select.js.map +1 -0
  411. package/dist/components/Separator/Separator.d.ts +48 -0
  412. package/dist/components/Separator/Separator.js +43 -0
  413. package/dist/components/Separator/Separator.js.map +1 -0
  414. package/dist/components/Sheet/Sheet.d.ts +43 -0
  415. package/dist/components/Sheet/Sheet.js +79 -0
  416. package/dist/components/Sheet/Sheet.js.map +1 -0
  417. package/dist/components/Sidebar/Sidebar.d.ts +357 -0
  418. package/dist/components/Sidebar/Sidebar.js +447 -0
  419. package/dist/components/Sidebar/Sidebar.js.map +1 -0
  420. package/dist/components/Skeleton/Skeleton.d.ts +70 -0
  421. package/dist/components/Skeleton/Skeleton.js +44 -0
  422. package/dist/components/Skeleton/Skeleton.js.map +1 -0
  423. package/dist/components/Slider/Slider.d.ts +74 -0
  424. package/dist/components/Slider/Slider.js +143 -0
  425. package/dist/components/Slider/Slider.js.map +1 -0
  426. package/dist/components/Spinner/Spinner.d.ts +58 -0
  427. package/dist/components/Spinner/Spinner.js +49 -0
  428. package/dist/components/Spinner/Spinner.js.map +1 -0
  429. package/dist/components/StatusDot/StatusDot.d.ts +29 -0
  430. package/dist/components/StatusDot/StatusDot.js +44 -0
  431. package/dist/components/StatusDot/StatusDot.js.map +1 -0
  432. package/dist/components/StatusPill/StatusPill.d.ts +30 -0
  433. package/dist/components/StatusPill/StatusPill.js +37 -0
  434. package/dist/components/StatusPill/StatusPill.js.map +1 -0
  435. package/dist/components/Steps/Steps.d.ts +65 -0
  436. package/dist/components/Steps/Steps.js +25 -0
  437. package/dist/components/Steps/Steps.js.map +1 -0
  438. package/dist/components/Switch/Switch.d.ts +23 -0
  439. package/dist/components/Switch/Switch.js +23 -0
  440. package/dist/components/Switch/Switch.js.map +1 -0
  441. package/dist/components/Table/Table.d.ts +116 -0
  442. package/dist/components/Table/Table.js +137 -0
  443. package/dist/components/Table/Table.js.map +1 -0
  444. package/dist/components/Tabs/Tabs.d.ts +37 -0
  445. package/dist/components/Tabs/Tabs.js +205 -0
  446. package/dist/components/Tabs/Tabs.js.map +1 -0
  447. package/dist/components/Tag/Tag.d.ts +87 -0
  448. package/dist/components/Tag/Tag.js +62 -0
  449. package/dist/components/Tag/Tag.js.map +1 -0
  450. package/dist/components/Text/Text.d.ts +62 -0
  451. package/dist/components/Text/Text.js +30 -0
  452. package/dist/components/Text/Text.js.map +1 -0
  453. package/dist/components/Textarea/Textarea.d.ts +20 -0
  454. package/dist/components/Textarea/Textarea.js +32 -0
  455. package/dist/components/Textarea/Textarea.js.map +1 -0
  456. package/dist/components/Timestamp/Timestamp.d.ts +59 -0
  457. package/dist/components/Timestamp/Timestamp.js +56 -0
  458. package/dist/components/Timestamp/Timestamp.js.map +1 -0
  459. package/dist/components/Toast/Toast.d.ts +32 -0
  460. package/dist/components/Toast/Toast.js +64 -0
  461. package/dist/components/Toast/Toast.js.map +1 -0
  462. package/dist/components/ToggleGroup/ToggleGroup.d.ts +46 -0
  463. package/dist/components/ToggleGroup/ToggleGroup.js +88 -0
  464. package/dist/components/ToggleGroup/ToggleGroup.js.map +1 -0
  465. package/dist/components/Toolbar/Toolbar.d.ts +55 -0
  466. package/dist/components/Toolbar/Toolbar.js +43 -0
  467. package/dist/components/Toolbar/Toolbar.js.map +1 -0
  468. package/dist/components/Tooltip/Tooltip.d.ts +43 -0
  469. package/dist/components/Tooltip/Tooltip.js +40 -0
  470. package/dist/components/Tooltip/Tooltip.js.map +1 -0
  471. package/dist/diagrams/ArchitectureFigure/ArchitectureFigure.d.ts +55 -0
  472. package/dist/diagrams/ArchitectureFigure/ArchitectureFigure.js +175 -0
  473. package/dist/diagrams/ArchitectureFigure/ArchitectureFigure.js.map +1 -0
  474. package/dist/diagrams/DataflowFigure/DataflowFigure.d.ts +28 -0
  475. package/dist/diagrams/DataflowFigure/DataflowFigure.js +148 -0
  476. package/dist/diagrams/DataflowFigure/DataflowFigure.js.map +1 -0
  477. package/dist/diagrams/DiagramCanvas/DiagramCanvas.d.ts +78 -0
  478. package/dist/diagrams/DiagramCanvas/DiagramCanvas.js +229 -0
  479. package/dist/diagrams/DiagramCanvas/DiagramCanvas.js.map +1 -0
  480. package/dist/diagrams/DiagramExportMenu/DiagramExportMenu.d.ts +106 -0
  481. package/dist/diagrams/DiagramExportMenu/DiagramExportMenu.js +123 -0
  482. package/dist/diagrams/DiagramExportMenu/DiagramExportMenu.js.map +1 -0
  483. package/dist/diagrams/DiagramInspector/DiagramInspector.d.ts +70 -0
  484. package/dist/diagrams/DiagramInspector/DiagramInspector.js +94 -0
  485. package/dist/diagrams/DiagramInspector/DiagramInspector.js.map +1 -0
  486. package/dist/diagrams/DiagramLegend/DiagramLegend.d.ts +42 -0
  487. package/dist/diagrams/DiagramLegend/DiagramLegend.js +35 -0
  488. package/dist/diagrams/DiagramLegend/DiagramLegend.js.map +1 -0
  489. package/dist/diagrams/DiagramMinimap/DiagramMinimap.d.ts +77 -0
  490. package/dist/diagrams/DiagramMinimap/DiagramMinimap.js +106 -0
  491. package/dist/diagrams/DiagramMinimap/DiagramMinimap.js.map +1 -0
  492. package/dist/diagrams/DiagramToolbar/DiagramToolbar.d.ts +48 -0
  493. package/dist/diagrams/DiagramToolbar/DiagramToolbar.js +53 -0
  494. package/dist/diagrams/DiagramToolbar/DiagramToolbar.js.map +1 -0
  495. package/dist/diagrams/LifecycleFigure/LifecycleFigure.d.ts +31 -0
  496. package/dist/diagrams/LifecycleFigure/LifecycleFigure.js +234 -0
  497. package/dist/diagrams/LifecycleFigure/LifecycleFigure.js.map +1 -0
  498. package/dist/diagrams/SequenceFigure/SequenceFigure.d.ts +38 -0
  499. package/dist/diagrams/SequenceFigure/SequenceFigure.js +261 -0
  500. package/dist/diagrams/SequenceFigure/SequenceFigure.js.map +1 -0
  501. package/dist/diagrams/WorkflowFigure/WorkflowFigure.d.ts +36 -0
  502. package/dist/diagrams/WorkflowFigure/WorkflowFigure.js +259 -0
  503. package/dist/diagrams/WorkflowFigure/WorkflowFigure.js.map +1 -0
  504. package/dist/diagrams/index.d.ts +17 -0
  505. package/dist/diagrams/index.js +29 -0
  506. package/dist/diagrams/index.js.map +1 -0
  507. package/dist/diagrams/lib/dev.d.ts +61 -0
  508. package/dist/diagrams/lib/dev.js +96 -0
  509. package/dist/diagrams/lib/dev.js.map +1 -0
  510. package/dist/diagrams/lib/frame.d.ts +138 -0
  511. package/dist/diagrams/lib/frame.js +131 -0
  512. package/dist/diagrams/lib/frame.js.map +1 -0
  513. package/dist/diagrams/lib/geometry.d.ts +114 -0
  514. package/dist/diagrams/lib/geometry.js +113 -0
  515. package/dist/diagrams/lib/geometry.js.map +1 -0
  516. package/dist/diagrams/lib/legend.d.ts +32 -0
  517. package/dist/diagrams/lib/legend.js +84 -0
  518. package/dist/diagrams/lib/legend.js.map +1 -0
  519. package/dist/diagrams/lib/marks.d.ts +207 -0
  520. package/dist/diagrams/lib/marks.js +480 -0
  521. package/dist/diagrams/lib/marks.js.map +1 -0
  522. package/dist/diagrams/lib/route.d.ts +106 -0
  523. package/dist/diagrams/lib/route.js +201 -0
  524. package/dist/diagrams/lib/route.js.map +1 -0
  525. package/dist/diagrams/lib/wires.d.ts +59 -0
  526. package/dist/diagrams/lib/wires.js +94 -0
  527. package/dist/diagrams/lib/wires.js.map +1 -0
  528. package/dist/diagrams/spec.d.ts +405 -0
  529. package/dist/diagrams/spec.js +1 -0
  530. package/dist/diagrams/spec.js.map +1 -0
  531. package/dist/fonts/hanken-grotesk-300.woff2 +0 -0
  532. package/dist/fonts/hanken-grotesk-400.woff2 +0 -0
  533. package/dist/fonts/hanken-grotesk-500.woff2 +0 -0
  534. package/dist/fonts/hanken-grotesk-600.woff2 +0 -0
  535. package/dist/fonts/hanken-grotesk-700.woff2 +0 -0
  536. package/dist/fonts/ibm-plex-mono-400.woff2 +0 -0
  537. package/dist/fonts/ibm-plex-mono-500.woff2 +0 -0
  538. package/dist/fonts/ibm-plex-mono-600.woff2 +0 -0
  539. package/dist/fonts/newsreader-300.woff2 +0 -0
  540. package/dist/fonts/newsreader-400.woff2 +0 -0
  541. package/dist/fonts/newsreader-500.woff2 +0 -0
  542. package/dist/fonts/newsreader-600.woff2 +0 -0
  543. package/dist/fonts.css +96 -0
  544. package/dist/index.d.ts +97 -0
  545. package/dist/index.js +80 -0
  546. package/dist/index.js.map +1 -0
  547. package/dist/keyframes.css +300 -0
  548. package/dist/lib/cn.d.ts +21 -0
  549. package/dist/lib/cn.js +9 -0
  550. package/dist/lib/cn.js.map +1 -0
  551. package/dist/lib/color.d.ts +80 -0
  552. package/dist/lib/color.js +189 -0
  553. package/dist/lib/color.js.map +1 -0
  554. package/dist/lib/control.d.ts +32 -0
  555. package/dist/lib/control.js +14 -0
  556. package/dist/lib/control.js.map +1 -0
  557. package/dist/lib/index.d.ts +4 -0
  558. package/dist/lib/index.js +11 -0
  559. package/dist/lib/index.js.map +1 -0
  560. package/dist/lib/numeric.d.ts +35 -0
  561. package/dist/lib/numeric.js +29 -0
  562. package/dist/lib/numeric.js.map +1 -0
  563. package/dist/lib/overlay-container.d.ts +48 -0
  564. package/dist/lib/overlay-container.js +15 -0
  565. package/dist/lib/overlay-container.js.map +1 -0
  566. package/dist/lib/slot-content.d.ts +8 -0
  567. package/dist/lib/slot-content.js +17 -0
  568. package/dist/lib/slot-content.js.map +1 -0
  569. package/dist/lib/step-rail.d.ts +45 -0
  570. package/dist/lib/step-rail.js +47 -0
  571. package/dist/lib/step-rail.js.map +1 -0
  572. package/dist/lib/svg-export.d.ts +138 -0
  573. package/dist/lib/svg-export.js +198 -0
  574. package/dist/lib/svg-export.js.map +1 -0
  575. package/dist/lib/useClipboardCopy.d.ts +30 -0
  576. package/dist/lib/useClipboardCopy.js +37 -0
  577. package/dist/lib/useClipboardCopy.js.map +1 -0
  578. package/dist/lib/useSelectionIndicator.d.ts +29 -0
  579. package/dist/lib/useSelectionIndicator.js +49 -0
  580. package/dist/lib/useSelectionIndicator.js.map +1 -0
  581. package/dist/lib/warn.d.ts +73 -0
  582. package/dist/lib/warn.js +38 -0
  583. package/dist/lib/warn.js.map +1 -0
  584. package/dist/semantic.css +200 -0
  585. package/dist/styles.css +98 -0
  586. package/dist/themes.css +607 -0
  587. package/dist/tokens/brand.d.ts +47 -0
  588. package/dist/tokens/brand.js +38 -0
  589. package/dist/tokens/brand.js.map +1 -0
  590. package/dist/tokens.css +666 -0
  591. package/dist/tokens.d.ts +205 -0
  592. package/dist/tokens.js +1056 -0
  593. package/dist/tokens.json +1055 -0
  594. package/dist/website/Actions/Actions.d.ts +34 -0
  595. package/dist/website/Actions/Actions.js +29 -0
  596. package/dist/website/Actions/Actions.js.map +1 -0
  597. package/dist/website/Collection/Collection.d.ts +128 -0
  598. package/dist/website/Collection/Collection.js +162 -0
  599. package/dist/website/Collection/Collection.js.map +1 -0
  600. package/dist/website/Contact/Contact.d.ts +87 -0
  601. package/dist/website/Contact/Contact.js +94 -0
  602. package/dist/website/Contact/Contact.js.map +1 -0
  603. package/dist/website/Content/CodePanel.d.ts +27 -0
  604. package/dist/website/Content/CodePanel.js +30 -0
  605. package/dist/website/Content/CodePanel.js.map +1 -0
  606. package/dist/website/Content/Content.d.ts +29 -0
  607. package/dist/website/Content/Content.js +38 -0
  608. package/dist/website/Content/Content.js.map +1 -0
  609. package/dist/website/Conversation/Conversation.d.ts +193 -0
  610. package/dist/website/Conversation/Conversation.js +252 -0
  611. package/dist/website/Conversation/Conversation.js.map +1 -0
  612. package/dist/website/Evidence/Evidence.d.ts +116 -0
  613. package/dist/website/Evidence/Evidence.js +142 -0
  614. package/dist/website/Evidence/Evidence.js.map +1 -0
  615. package/dist/website/Media/Media.d.ts +173 -0
  616. package/dist/website/Media/Media.js +225 -0
  617. package/dist/website/Media/Media.js.map +1 -0
  618. package/dist/website/Media/MediaLightbox.d.ts +18 -0
  619. package/dist/website/Media/MediaLightbox.js +38 -0
  620. package/dist/website/Media/MediaLightbox.js.map +1 -0
  621. package/dist/website/Metrics/Metrics.d.ts +74 -0
  622. package/dist/website/Metrics/Metrics.js +96 -0
  623. package/dist/website/Metrics/Metrics.js.map +1 -0
  624. package/dist/website/Music/Music.d.ts +60 -0
  625. package/dist/website/Music/Music.js +80 -0
  626. package/dist/website/Music/Music.js.map +1 -0
  627. package/dist/website/Portfolio/FrameLayout.d.ts +9 -0
  628. package/dist/website/Portfolio/FrameLayout.js +42 -0
  629. package/dist/website/Portfolio/FrameLayout.js.map +1 -0
  630. package/dist/website/Portfolio/Portfolio.d.ts +49 -0
  631. package/dist/website/Portfolio/Portfolio.js +66 -0
  632. package/dist/website/Portfolio/Portfolio.js.map +1 -0
  633. package/dist/website/Portfolio/QuestionCard.d.ts +22 -0
  634. package/dist/website/Portfolio/QuestionCard.js +33 -0
  635. package/dist/website/Portfolio/QuestionCard.js.map +1 -0
  636. package/dist/website/PortfolioIndex/PortfolioIndex.d.ts +21 -0
  637. package/dist/website/PortfolioIndex/PortfolioIndex.js +31 -0
  638. package/dist/website/PortfolioIndex/PortfolioIndex.js.map +1 -0
  639. package/dist/website/Reading/Reading.d.ts +203 -0
  640. package/dist/website/Reading/Reading.js +357 -0
  641. package/dist/website/Reading/Reading.js.map +1 -0
  642. package/dist/website/Recovery/Recovery.d.ts +39 -0
  643. package/dist/website/Recovery/Recovery.js +96 -0
  644. package/dist/website/Recovery/Recovery.js.map +1 -0
  645. package/dist/website/SearchPalette/SearchPalette.d.ts +59 -0
  646. package/dist/website/SearchPalette/SearchPalette.js +120 -0
  647. package/dist/website/SearchPalette/SearchPalette.js.map +1 -0
  648. package/dist/website/SiteNavigation/SiteNavigation.d.ts +46 -0
  649. package/dist/website/SiteNavigation/SiteNavigation.js +101 -0
  650. package/dist/website/SiteNavigation/SiteNavigation.js.map +1 -0
  651. package/dist/website/SiteShell/SiteShell.d.ts +45 -0
  652. package/dist/website/SiteShell/SiteShell.js +46 -0
  653. package/dist/website/SiteShell/SiteShell.js.map +1 -0
  654. package/dist/website/Timeline/Timeline.d.ts +80 -0
  655. package/dist/website/Timeline/Timeline.js +99 -0
  656. package/dist/website/Timeline/Timeline.js.map +1 -0
  657. package/dist/website/Workbench/Chronology.d.ts +32 -0
  658. package/dist/website/Workbench/Chronology.js +32 -0
  659. package/dist/website/Workbench/Chronology.js.map +1 -0
  660. package/dist/website/Workbench/ContactRow.d.ts +13 -0
  661. package/dist/website/Workbench/ContactRow.js +11 -0
  662. package/dist/website/Workbench/ContactRow.js.map +1 -0
  663. package/dist/website/Workbench/PhotoMosaic.d.ts +13 -0
  664. package/dist/website/Workbench/PhotoMosaic.js +15 -0
  665. package/dist/website/Workbench/PhotoMosaic.js.map +1 -0
  666. package/dist/website/Workbench/Reveal.d.ts +19 -0
  667. package/dist/website/Workbench/Reveal.js +29 -0
  668. package/dist/website/Workbench/Reveal.js.map +1 -0
  669. package/dist/website/Workbench/ToolStrip.d.ts +18 -0
  670. package/dist/website/Workbench/ToolStrip.js +15 -0
  671. package/dist/website/Workbench/ToolStrip.js.map +1 -0
  672. package/dist/website/Workbench/Workbench.d.ts +23 -0
  673. package/dist/website/Workbench/Workbench.js +22 -0
  674. package/dist/website/Workbench/Workbench.js.map +1 -0
  675. package/dist/website/Workbench/WorkbenchCard.d.ts +29 -0
  676. package/dist/website/Workbench/WorkbenchCard.js +21 -0
  677. package/dist/website/Workbench/WorkbenchCard.js.map +1 -0
  678. package/dist/website/Workbench/WorkbenchEntries.d.ts +22 -0
  679. package/dist/website/Workbench/WorkbenchEntries.js +24 -0
  680. package/dist/website/Workbench/WorkbenchEntries.js.map +1 -0
  681. package/dist/website/Workbench/WorkbenchFigure.d.ts +20 -0
  682. package/dist/website/Workbench/WorkbenchFigure.js +15 -0
  683. package/dist/website/Workbench/WorkbenchFigure.js.map +1 -0
  684. package/dist/website/Workbench/WorkbenchHero.d.ts +24 -0
  685. package/dist/website/Workbench/WorkbenchHero.js +24 -0
  686. package/dist/website/Workbench/WorkbenchHero.js.map +1 -0
  687. package/dist/website/Workbench/theme.d.ts +22 -0
  688. package/dist/website/Workbench/theme.js +12 -0
  689. package/dist/website/Workbench/theme.js.map +1 -0
  690. package/dist/website/index.d.ts +38 -0
  691. package/dist/website/index.js +32 -0
  692. package/dist/website/index.js.map +1 -0
  693. package/dist/website-actions.css +6 -0
  694. package/dist/website-base.css +46 -0
  695. package/dist/website-collection.css +89 -0
  696. package/dist/website-contact.css +29 -0
  697. package/dist/website-content.css +20 -0
  698. package/dist/website-controls.css +91 -0
  699. package/dist/website-conversation.css +115 -0
  700. package/dist/website-evidence.css +56 -0
  701. package/dist/website-media.css +227 -0
  702. package/dist/website-metrics.css +15 -0
  703. package/dist/website-music.css +27 -0
  704. package/dist/website-portfolio.css +94 -0
  705. package/dist/website-reading.css +159 -0
  706. package/dist/website-recovery.css +28 -0
  707. package/dist/website-search.css +26 -0
  708. package/dist/website-shell.css +89 -0
  709. package/dist/website-timeline.css +43 -0
  710. package/dist/website-workbench.css +162 -0
  711. package/dist/website.css +26 -0
  712. package/llms.txt +35 -0
  713. package/package.json +163 -5
  714. package/skills/folio-design/SKILL.md +228 -0
  715. package/skills/folio-design/evals/claims.json +95 -0
  716. package/skills/folio-design/evals/evals.json +84 -0
  717. package/skills/folio-design/rules/a11y.md +167 -0
  718. package/skills/folio-design/rules/composition.md +108 -0
  719. package/skills/folio-design/rules/forms.md +135 -0
  720. package/skills/folio-design/rules/naming.md +155 -0
  721. package/skills/folio-design/rules/tokens.md +135 -0
@@ -0,0 +1,248 @@
1
+ /**
2
+ * A chart's values as pitch over time — the reading a listener gets instead of
3
+ * the picture.
4
+ *
5
+ * The hidden data table (see `figure.tsx`) hands a screen-reader user every
6
+ * number, which is access but not a SHAPE: fourteen figures read one at a time
7
+ * do not tell anyone that the line dips in March and never recovers. A run of
8
+ * tones does, in three seconds, and it is the one thing a chart can offer that
9
+ * a table cannot. Highcharts is the only mainstream library that ships it; this
10
+ * is that idea, without the dependency.
11
+ *
12
+ * Nothing here touches `window` or constructs an `AudioContext` at module load.
13
+ * The context is created on the first `play()`, which is the only moment a
14
+ * browser will allow it — every engine blocks audio until a user gesture, and a
15
+ * context built at import time arrives permanently `suspended`.
16
+ *
17
+ * **This never starts on its own.** `prefers-reduced-motion` is not the setting
18
+ * that governs it — sound is not motion, and gating audio behind a motion
19
+ * preference would both silence readers who want it and imply that readers who
20
+ * do not want motion also do not want sound. The correct rule is simpler and
21
+ * absolute: audio begins from an explicit user action, and from nothing else.
22
+ * There is deliberately no `autoPlay` option to pass.
23
+ */
24
+ /** Whether the run is sounding, held, or not started. */
25
+ type SonifyState = 'idle' | 'playing' | 'paused';
26
+ /**
27
+ * The oscillator behind every note.
28
+ *
29
+ * `triangle` is the default because the two obvious choices are both worse: a
30
+ * `sine` has no harmonics above its fundamental, so on a laptop speaker — which
31
+ * reproduces almost nothing under 200 Hz — the bottom of the range simply
32
+ * vanishes, and a listener hears silence where the data is lowest. A `square`
33
+ * is the opposite problem: all odd harmonics at full strength is fatiguing
34
+ * inside ten notes and genuinely unpleasant across sixty. A triangle carries
35
+ * enough harmonic content to survive a small speaker and stay comfortable.
36
+ */
37
+ type SonifyWave = 'sine' | 'triangle' | 'square' | 'sawtooth';
38
+ /** The value range the pitch scale is stretched across. */
39
+ interface SonifyDomain {
40
+ min: number;
41
+ max: number;
42
+ }
43
+ /** One series, flattened to what sound needs: its values, in order. */
44
+ interface SonifySeries {
45
+ /** The series key, so a caller can tie a point back to its own data. */
46
+ key: string;
47
+ /** What the series is called, spoken before its run of tones. */
48
+ label: string;
49
+ /** One entry per point. `null` is a gap — it holds its slot in silence. */
50
+ values: (number | null)[];
51
+ /** The category axis, if there is one. Used to say where the run starts and ends. */
52
+ categories?: string[];
53
+ }
54
+ /** The point sounding right now, for a caller that wants to highlight it. */
55
+ interface SonifyPoint {
56
+ seriesKey: string;
57
+ seriesLabel: string;
58
+ /** Position within its own series. */
59
+ index: number;
60
+ /** The category this point sits at, when the chart has a category axis. */
61
+ category?: string;
62
+ /** `null` for a gap in the data, which sounds as a rest. */
63
+ value: number | null;
64
+ }
65
+ interface SonifyOptions {
66
+ /** How long each point holds the floor. Below ~90ms the run stops being readable. */
67
+ noteMs?: number;
68
+ /** Silence after a series, before the next one is announced. */
69
+ gapMs?: number;
70
+ /**
71
+ * The pause between an announcement and the first note it describes.
72
+ *
73
+ * Not decoration: a screen reader needs the floor to itself to read the range
74
+ * out, and a tone starting on top of it means the listener gets neither.
75
+ */
76
+ leadInMs?: number;
77
+ /** The pitch the lowest value sounds at, in Hz. */
78
+ rootFrequency?: number;
79
+ /** How far above the root the highest value sits, in semitones. */
80
+ semitones?: number;
81
+ wave?: SonifyWave;
82
+ /** Peak gain per note, 0–1. Deliberately quiet; a chart is not a media player. */
83
+ volume?: number;
84
+ /**
85
+ * How a number is spoken in an announcement. Defaults to the axis's own
86
+ * formatting.
87
+ *
88
+ * Define it outside the render or memoise it. It is part of what the run
89
+ * says, so a new function identity rebuilds the run — and a rebuilt run is a
90
+ * stopped one.
91
+ */
92
+ formatValue?: (value: number) => string;
93
+ }
94
+ /**
95
+ * The defaults, and why each is the number it is.
96
+ *
97
+ * `rootFrequency` 220 Hz (A3) with a `semitones` span of 24 puts the whole
98
+ * range between A3 and A5. Below roughly 200 Hz a laptop or phone speaker
99
+ * reproduces very little, and above about 1 kHz sustained tones start to read
100
+ * as an alarm; two octaves inside that window is the widest span that stays
101
+ * comfortable at both ends. Two octaves is also about where pitch DISCRIMINATION
102
+ * stops improving — stretching to four does not let anyone read the numbers off
103
+ * more precisely, it just makes the top shrill.
104
+ */
105
+ declare const SONIFY_DEFAULTS: {
106
+ readonly noteMs: 220;
107
+ readonly gapMs: 700;
108
+ readonly leadInMs: 1200;
109
+ readonly rootFrequency: 220;
110
+ readonly semitones: 24;
111
+ readonly wave: "triangle";
112
+ readonly volume: 0.18;
113
+ };
114
+ /**
115
+ * A value's pitch, on a semitone scale rather than a linear sweep of hertz.
116
+ *
117
+ * This is the single most important decision in the file. Pitch perception is
118
+ * logarithmic: the ear hears a RATIO, not a difference. 220 Hz to 440 Hz is one
119
+ * octave and so is 440 Hz to 880 Hz, even though the second gap is twice as
120
+ * many hertz. Map values linearly onto hertz and the consequence is immediate —
121
+ * the bottom half of the data spreads across most of the perceived range while
122
+ * the top half compresses into a few near-identical tones, so a rise from 900
123
+ * to 1000 sounds like nothing and a rise from 10 to 110 sounds enormous. The
124
+ * chart lied.
125
+ *
126
+ * Mapping the value range onto a fixed span of SEMITONES fixes it: equal steps
127
+ * in the data become equal musical intervals, which is what a listener actually
128
+ * compares. The map is linear-in-value and exponential-in-frequency, so it is
129
+ * the audio equivalent of a linear axis — not a log axis, which would be a
130
+ * different claim about the data.
131
+ *
132
+ * A flat series (`min === max`) sounds at the middle of the range rather than at
133
+ * the floor: flat data is not low data, and a run of bottom notes reads as one.
134
+ *
135
+ * @example
136
+ * valueToFrequency(50, { min: 0, max: 100 }) // 220 * 2 ** 1 = 440 Hz, one octave up
137
+ */
138
+ declare function valueToFrequency(value: number, domain: SonifyDomain, pitch?: Pick<SonifyOptions, 'rootFrequency' | 'semitones'>): number;
139
+ /**
140
+ * The value range every series is measured against, or `null` when nothing is
141
+ * finite.
142
+ *
143
+ * Shared across all series on purpose. These charts draw their series against
144
+ * ONE value axis, so they have to sound against one pitch axis too — normalising
145
+ * each series to its own extremes would make a flat series that never leaves 2%
146
+ * sound exactly like the one that swings across the whole plot, which is the
147
+ * opposite of what the picture says.
148
+ */
149
+ declare function sonifyDomain(series: SonifySeries[]): SonifyDomain | null;
150
+ /**
151
+ * What is said before a series plays.
152
+ *
153
+ * A run of tones with no frame of reference is unreadable — the listener hears
154
+ * a contour and has no idea whether it spans four units or four million, or how
155
+ * many points went by. Naming the count, the span of the category axis and the
156
+ * two extremes costs one sentence and turns the melody into a measurement. The
157
+ * direction of the mapping is stated too, because "higher is more" is a
158
+ * convention, not a fact the sound carries.
159
+ */
160
+ declare function describeSeries(series: SonifySeries, formatValue?: (value: number) => string): string;
161
+ /** One thing that happens at one moment: something said, or a note sounded. */
162
+ type SonifyStep = {
163
+ kind: 'announce';
164
+ atMs: number;
165
+ text: string;
166
+ } | {
167
+ kind: 'note';
168
+ atMs: number;
169
+ point: SonifyPoint;
170
+ frequency: number | null;
171
+ };
172
+ /**
173
+ * The whole run, laid out on a timeline before a single sound is made.
174
+ *
175
+ * Built as data rather than driven by a loop with a timer inside it, because
176
+ * this is the part worth testing: the maths that decides when each note lands
177
+ * is checkable without a speaker, and pause/resume becomes "walk the same array
178
+ * from a different index" rather than a second, subtly different code path.
179
+ *
180
+ * Several series play **in sequence, each introduced by name**, rather than
181
+ * simultaneously with one panned to each ear. Hard panning is the more
182
+ * impressive demo and the wrong choice: it assumes a stereo output and two
183
+ * usable ears, so a mono speaker, a single hearing aid, or unilateral hearing
184
+ * loss collapses both series into one interleaved melody the listener cannot
185
+ * unpick — and it caps the feature at two series, when four is ordinary. Played
186
+ * in sequence, the worst case is that the run takes longer, which is a cost the
187
+ * listener can see coming and a caller can shorten with `noteMs`.
188
+ */
189
+ declare function sonifyTimeline(series: SonifySeries[], options?: SonifyOptions): SonifyStep[];
190
+ /** How long the whole run takes, in milliseconds. */
191
+ declare function sonifyDuration(series: SonifySeries[], options?: SonifyOptions): number;
192
+ /**
193
+ * Whether this environment can make a sound at all.
194
+ *
195
+ * Safe on a server: it reads `window` from inside a function, so importing this
196
+ * module during a server render touches nothing.
197
+ */
198
+ declare function hasAudioSupport(): boolean;
199
+ interface SonifyHandlers {
200
+ /** The point currently sounding, so a chart can mark it. `null` between series. */
201
+ onPoint?: (point: SonifyPoint | null) => void;
202
+ /** Text meant for a live region — the range announcement before each series. */
203
+ onAnnounce?: (text: string) => void;
204
+ onStateChange?: (state: SonifyState) => void;
205
+ /** Fires once the last note has sounded, not when it was scheduled. */
206
+ onEnd?: () => void;
207
+ }
208
+ interface SonifyInput extends SonifyHandlers {
209
+ series: SonifySeries[];
210
+ options?: SonifyOptions;
211
+ }
212
+ interface SonifyController {
213
+ /**
214
+ * Starts, or resumes from where a pause left off.
215
+ *
216
+ * MUST be called from a user gesture. That is a browser rule, not a
217
+ * preference — and it is also the accessibility rule this feature is built
218
+ * on, so there is no way to reach this except from something the reader did.
219
+ */
220
+ play: () => void;
221
+ /** Holds position. The current note is faded out rather than cut. */
222
+ pause: () => void;
223
+ /** Stops and rewinds to the beginning. */
224
+ stop: () => void;
225
+ /** Stops and releases the audio hardware. Call on unmount. */
226
+ destroy: () => void;
227
+ readonly state: SonifyState;
228
+ /** The whole run, in milliseconds. */
229
+ readonly durationMs: number;
230
+ }
231
+ /**
232
+ * A run of one chart's series, ready to play.
233
+ *
234
+ * Constructing one allocates nothing but an array — no `AudioContext`, no
235
+ * timer, no node. That matters because a chart builds its controller during
236
+ * render, where creating a context would both break a server render and burn
237
+ * one of the browser's limited context slots on a chart nobody listens to.
238
+ *
239
+ * @example
240
+ * const run = createSonification({
241
+ * series: [{ key: 'desktop', label: 'Desktop', values: [186, 305, 237], categories: ['Jan', 'Feb', 'Mar'] }],
242
+ * onPoint: (point) => setActive(point),
243
+ * })
244
+ * button.addEventListener('click', () => run.play())
245
+ */
246
+ declare function createSonification({ series, options, onPoint, onAnnounce, onStateChange, onEnd, }: SonifyInput): SonifyController;
247
+
248
+ export { SONIFY_DEFAULTS, type SonifyController, type SonifyDomain, type SonifyHandlers, type SonifyInput, type SonifyOptions, type SonifyPoint, type SonifySeries, type SonifyState, type SonifyStep, type SonifyWave, createSonification, describeSeries, hasAudioSupport, sonifyDomain, sonifyDuration, sonifyTimeline, valueToFrequency };
@@ -0,0 +1,262 @@
1
+ import { defaultTick } from "./format.js";
2
+ const SONIFY_DEFAULTS = {
3
+ noteMs: 220,
4
+ gapMs: 700,
5
+ leadInMs: 1200,
6
+ rootFrequency: 220,
7
+ semitones: 24,
8
+ wave: "triangle",
9
+ volume: 0.18
10
+ };
11
+ const ATTACK_SECONDS = 8e-3;
12
+ const RELEASE_SECONDS = 0.06;
13
+ const NOTE_DUTY = 0.85;
14
+ const LOOKAHEAD_SECONDS = 0.02;
15
+ const CUT_SECONDS = 0.015;
16
+ function valueToFrequency(value, domain, pitch = {}) {
17
+ const root = pitch.rootFrequency ?? SONIFY_DEFAULTS.rootFrequency;
18
+ const semitones = pitch.semitones ?? SONIFY_DEFAULTS.semitones;
19
+ const span = domain.max - domain.min;
20
+ const position = span === 0 ? 0.5 : (value - domain.min) / span;
21
+ const clamped = Math.min(1, Math.max(0, position));
22
+ return root * 2 ** (clamped * semitones / 12);
23
+ }
24
+ function sonifyDomain(series) {
25
+ let min = Number.POSITIVE_INFINITY;
26
+ let max = Number.NEGATIVE_INFINITY;
27
+ for (const entry of series) {
28
+ for (const value of entry.values) {
29
+ if (value === null || !Number.isFinite(value)) continue;
30
+ if (value < min) min = value;
31
+ if (value > max) max = value;
32
+ }
33
+ }
34
+ return min === Number.POSITIVE_INFINITY ? null : { min, max };
35
+ }
36
+ function describeSeries(series, formatValue = defaultTick) {
37
+ const finite = series.values.filter((value) => value !== null && Number.isFinite(value));
38
+ if (finite.length === 0) return `${series.label}, no data.`;
39
+ const categories = series.categories ?? [];
40
+ const first = categories[0];
41
+ const last = categories[categories.length - 1];
42
+ const span = first !== void 0 && last !== void 0 && first !== last ? `, ${first} to ${last}` : "";
43
+ const low = formatValue(Math.min(...finite));
44
+ const high = formatValue(Math.max(...finite));
45
+ const gaps = series.values.length - finite.length;
46
+ const missing = gaps > 0 ? ` ${gaps} missing.` : "";
47
+ return `${series.label}, ${series.values.length} points${span}. Values from ${low} to ${high}, low pitch to high pitch.${missing}`;
48
+ }
49
+ function sonifyTimeline(series, options = {}) {
50
+ const noteMs = options.noteMs ?? SONIFY_DEFAULTS.noteMs;
51
+ const gapMs = options.gapMs ?? SONIFY_DEFAULTS.gapMs;
52
+ const leadInMs = options.leadInMs ?? SONIFY_DEFAULTS.leadInMs;
53
+ const formatValue = options.formatValue ?? defaultTick;
54
+ const domain = sonifyDomain(series);
55
+ const steps = [];
56
+ let at = 0;
57
+ series.forEach((entry, entryIndex) => {
58
+ if (entryIndex > 0) at += gapMs;
59
+ steps.push({ kind: "announce", atMs: at, text: describeSeries(entry, formatValue) });
60
+ at += leadInMs;
61
+ entry.values.forEach((raw, index) => {
62
+ const value = raw !== null && Number.isFinite(raw) ? raw : null;
63
+ steps.push({
64
+ kind: "note",
65
+ atMs: at,
66
+ point: {
67
+ seriesKey: entry.key,
68
+ seriesLabel: entry.label,
69
+ index,
70
+ category: entry.categories?.[index],
71
+ value
72
+ },
73
+ // A gap keeps its slot and sounds as a rest. Closing it up would move
74
+ // every later point earlier and quietly redraw the shape.
75
+ frequency: value === null || domain === null ? null : valueToFrequency(value, domain, options)
76
+ });
77
+ at += noteMs;
78
+ });
79
+ });
80
+ return steps;
81
+ }
82
+ function sonifyDuration(series, options = {}) {
83
+ const steps = sonifyTimeline(series, options);
84
+ const last = steps[steps.length - 1];
85
+ if (!last) return 0;
86
+ return last.kind === "note" ? last.atMs + (options.noteMs ?? SONIFY_DEFAULTS.noteMs) : last.atMs;
87
+ }
88
+ function hasAudioSupport() {
89
+ if (typeof window === "undefined") return false;
90
+ return audioContextConstructor() !== void 0;
91
+ }
92
+ function audioContextConstructor() {
93
+ if (typeof window === "undefined") return void 0;
94
+ const scope = window;
95
+ return scope.AudioContext ?? scope.webkitAudioContext;
96
+ }
97
+ function createSonification({
98
+ series,
99
+ options = {},
100
+ onPoint,
101
+ onAnnounce,
102
+ onStateChange,
103
+ onEnd
104
+ }) {
105
+ const steps = sonifyTimeline(series, options);
106
+ const durationMs = sonifyDuration(series, options);
107
+ const wave = options.wave ?? SONIFY_DEFAULTS.wave;
108
+ const volume = options.volume ?? SONIFY_DEFAULTS.volume;
109
+ const noteMs = options.noteMs ?? SONIFY_DEFAULTS.noteMs;
110
+ let state = "idle";
111
+ let cursor = 0;
112
+ let elapsedMs = 0;
113
+ let anchorMs = 0;
114
+ let timer = null;
115
+ let context = null;
116
+ let master = null;
117
+ const live = /* @__PURE__ */ new Set();
118
+ function setState(next) {
119
+ if (state === next) return;
120
+ state = next;
121
+ onStateChange?.(next);
122
+ }
123
+ function audio() {
124
+ if (context && master) return { context, master };
125
+ const Constructor = audioContextConstructor();
126
+ if (!Constructor) return null;
127
+ context = new Constructor();
128
+ master = context.createGain();
129
+ master.gain.value = volume;
130
+ master.connect(context.destination);
131
+ return { context, master };
132
+ }
133
+ function sound(frequency, at) {
134
+ const engine = audio();
135
+ if (!engine) return;
136
+ const body = Math.max(ATTACK_SECONDS + RELEASE_SECONDS, noteMs / 1e3 * NOTE_DUTY);
137
+ const oscillator = engine.context.createOscillator();
138
+ const gain = engine.context.createGain();
139
+ oscillator.type = wave;
140
+ oscillator.frequency.setValueAtTime(frequency, at);
141
+ gain.gain.setValueAtTime(0, at);
142
+ gain.gain.linearRampToValueAtTime(1, at + ATTACK_SECONDS);
143
+ gain.gain.setValueAtTime(1, at + body - RELEASE_SECONDS);
144
+ gain.gain.linearRampToValueAtTime(0, at + body);
145
+ oscillator.connect(gain);
146
+ gain.connect(engine.master);
147
+ oscillator.start(at);
148
+ oscillator.stop(at + body);
149
+ const node = { oscillator, gain };
150
+ live.add(node);
151
+ oscillator.onended = () => {
152
+ live.delete(node);
153
+ gain.disconnect();
154
+ oscillator.disconnect();
155
+ };
156
+ }
157
+ function silence() {
158
+ if (!context) return;
159
+ const now = context.currentTime;
160
+ for (const node of live) {
161
+ node.gain.gain.cancelScheduledValues(now);
162
+ node.gain.gain.setValueAtTime(node.gain.gain.value, now);
163
+ node.gain.gain.linearRampToValueAtTime(0, now + CUT_SECONDS);
164
+ node.oscillator.stop(now + CUT_SECONDS);
165
+ }
166
+ }
167
+ function clearTimer() {
168
+ if (timer === null) return;
169
+ clearTimeout(timer);
170
+ timer = null;
171
+ }
172
+ function finish() {
173
+ clearTimer();
174
+ cursor = 0;
175
+ elapsedMs = 0;
176
+ setState("idle");
177
+ onPoint?.(null);
178
+ onEnd?.();
179
+ }
180
+ function tick() {
181
+ timer = null;
182
+ const step = steps[cursor];
183
+ if (!step) {
184
+ finish();
185
+ return;
186
+ }
187
+ cursor += 1;
188
+ if (step.kind === "announce") {
189
+ onPoint?.(null);
190
+ onAnnounce?.(step.text);
191
+ } else {
192
+ onPoint?.(step.point);
193
+ if (step.frequency !== null && context) {
194
+ sound(step.frequency, context.currentTime + LOOKAHEAD_SECONDS);
195
+ }
196
+ }
197
+ schedule();
198
+ }
199
+ function schedule() {
200
+ const next = steps[cursor];
201
+ const target = next ? next.atMs : durationMs;
202
+ const wait = Math.max(0, target - (Date.now() - anchorMs));
203
+ timer = setTimeout(tick, wait);
204
+ }
205
+ function play() {
206
+ if (state === "playing") return;
207
+ const engine = audio();
208
+ if (engine && engine.context.state === "suspended") void engine.context.resume();
209
+ anchorMs = Date.now() - elapsedMs;
210
+ setState("playing");
211
+ schedule();
212
+ }
213
+ function pause() {
214
+ if (state !== "playing") return;
215
+ elapsedMs = Date.now() - anchorMs;
216
+ clearTimer();
217
+ silence();
218
+ setState("paused");
219
+ }
220
+ function stop() {
221
+ clearTimer();
222
+ silence();
223
+ cursor = 0;
224
+ elapsedMs = 0;
225
+ setState("idle");
226
+ onPoint?.(null);
227
+ }
228
+ function destroy() {
229
+ clearTimer();
230
+ silence();
231
+ cursor = 0;
232
+ elapsedMs = 0;
233
+ state = "idle";
234
+ void context?.close();
235
+ context = null;
236
+ master = null;
237
+ live.clear();
238
+ }
239
+ return {
240
+ play,
241
+ pause,
242
+ stop,
243
+ destroy,
244
+ get state() {
245
+ return state;
246
+ },
247
+ get durationMs() {
248
+ return durationMs;
249
+ }
250
+ };
251
+ }
252
+ export {
253
+ SONIFY_DEFAULTS,
254
+ createSonification,
255
+ describeSeries,
256
+ hasAudioSupport,
257
+ sonifyDomain,
258
+ sonifyDuration,
259
+ sonifyTimeline,
260
+ valueToFrequency
261
+ };
262
+ //# sourceMappingURL=sonify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/charts/lib/sonify.ts"],"sourcesContent":["import { defaultTick } from './format'\n\n/**\n * A chart's values as pitch over time — the reading a listener gets instead of\n * the picture.\n *\n * The hidden data table (see `figure.tsx`) hands a screen-reader user every\n * number, which is access but not a SHAPE: fourteen figures read one at a time\n * do not tell anyone that the line dips in March and never recovers. A run of\n * tones does, in three seconds, and it is the one thing a chart can offer that\n * a table cannot. Highcharts is the only mainstream library that ships it; this\n * is that idea, without the dependency.\n *\n * Nothing here touches `window` or constructs an `AudioContext` at module load.\n * The context is created on the first `play()`, which is the only moment a\n * browser will allow it — every engine blocks audio until a user gesture, and a\n * context built at import time arrives permanently `suspended`.\n *\n * **This never starts on its own.** `prefers-reduced-motion` is not the setting\n * that governs it — sound is not motion, and gating audio behind a motion\n * preference would both silence readers who want it and imply that readers who\n * do not want motion also do not want sound. The correct rule is simpler and\n * absolute: audio begins from an explicit user action, and from nothing else.\n * There is deliberately no `autoPlay` option to pass.\n */\n\n/** Whether the run is sounding, held, or not started. */\nexport type SonifyState = 'idle' | 'playing' | 'paused'\n\n/**\n * The oscillator behind every note.\n *\n * `triangle` is the default because the two obvious choices are both worse: a\n * `sine` has no harmonics above its fundamental, so on a laptop speaker — which\n * reproduces almost nothing under 200 Hz — the bottom of the range simply\n * vanishes, and a listener hears silence where the data is lowest. A `square`\n * is the opposite problem: all odd harmonics at full strength is fatiguing\n * inside ten notes and genuinely unpleasant across sixty. A triangle carries\n * enough harmonic content to survive a small speaker and stay comfortable.\n */\nexport type SonifyWave = 'sine' | 'triangle' | 'square' | 'sawtooth'\n\n/** The value range the pitch scale is stretched across. */\nexport interface SonifyDomain {\n min: number\n max: number\n}\n\n/** One series, flattened to what sound needs: its values, in order. */\nexport interface SonifySeries {\n /** The series key, so a caller can tie a point back to its own data. */\n key: string\n /** What the series is called, spoken before its run of tones. */\n label: string\n /** One entry per point. `null` is a gap — it holds its slot in silence. */\n values: (number | null)[]\n /** The category axis, if there is one. Used to say where the run starts and ends. */\n categories?: string[]\n}\n\n/** The point sounding right now, for a caller that wants to highlight it. */\nexport interface SonifyPoint {\n seriesKey: string\n seriesLabel: string\n /** Position within its own series. */\n index: number\n /** The category this point sits at, when the chart has a category axis. */\n category?: string\n /** `null` for a gap in the data, which sounds as a rest. */\n value: number | null\n}\n\nexport interface SonifyOptions {\n /** How long each point holds the floor. Below ~90ms the run stops being readable. */\n noteMs?: number\n /** Silence after a series, before the next one is announced. */\n gapMs?: number\n /**\n * The pause between an announcement and the first note it describes.\n *\n * Not decoration: a screen reader needs the floor to itself to read the range\n * out, and a tone starting on top of it means the listener gets neither.\n */\n leadInMs?: number\n /** The pitch the lowest value sounds at, in Hz. */\n rootFrequency?: number\n /** How far above the root the highest value sits, in semitones. */\n semitones?: number\n wave?: SonifyWave\n /** Peak gain per note, 0–1. Deliberately quiet; a chart is not a media player. */\n volume?: number\n /**\n * How a number is spoken in an announcement. Defaults to the axis's own\n * formatting.\n *\n * Define it outside the render or memoise it. It is part of what the run\n * says, so a new function identity rebuilds the run — and a rebuilt run is a\n * stopped one.\n */\n formatValue?: (value: number) => string\n}\n\n/**\n * The defaults, and why each is the number it is.\n *\n * `rootFrequency` 220 Hz (A3) with a `semitones` span of 24 puts the whole\n * range between A3 and A5. Below roughly 200 Hz a laptop or phone speaker\n * reproduces very little, and above about 1 kHz sustained tones start to read\n * as an alarm; two octaves inside that window is the widest span that stays\n * comfortable at both ends. Two octaves is also about where pitch DISCRIMINATION\n * stops improving — stretching to four does not let anyone read the numbers off\n * more precisely, it just makes the top shrill.\n */\nexport const SONIFY_DEFAULTS = {\n noteMs: 220,\n gapMs: 700,\n leadInMs: 1200,\n rootFrequency: 220,\n semitones: 24,\n wave: 'triangle',\n volume: 0.18,\n} as const satisfies Required<Omit<SonifyOptions, 'formatValue'>>\n\n/** Ramp up, in seconds. Short enough to read as an attack, long enough not to click. */\nconst ATTACK_SECONDS = 0.008\n\n/** Ramp down, in seconds. Longer than the attack, as a plucked note is. */\nconst RELEASE_SECONDS = 0.06\n\n/** How much of its slot a note actually sounds for; the rest is the gap between notes. */\nconst NOTE_DUTY = 0.85\n\n/**\n * How far ahead of the clock a note is scheduled.\n *\n * Scheduling at `currentTime` exactly means scheduling in the past by the time\n * the call returns on a busy main thread, and Web Audio silently drops those.\n * Twenty milliseconds is inaudible as latency and is more than the jitter a\n * timer introduces.\n */\nconst LOOKAHEAD_SECONDS = 0.02\n\n/** The fade applied when a note is cut short by a pause or a stop. */\nconst CUT_SECONDS = 0.015\n\n/**\n * A value's pitch, on a semitone scale rather than a linear sweep of hertz.\n *\n * This is the single most important decision in the file. Pitch perception is\n * logarithmic: the ear hears a RATIO, not a difference. 220 Hz to 440 Hz is one\n * octave and so is 440 Hz to 880 Hz, even though the second gap is twice as\n * many hertz. Map values linearly onto hertz and the consequence is immediate —\n * the bottom half of the data spreads across most of the perceived range while\n * the top half compresses into a few near-identical tones, so a rise from 900\n * to 1000 sounds like nothing and a rise from 10 to 110 sounds enormous. The\n * chart lied.\n *\n * Mapping the value range onto a fixed span of SEMITONES fixes it: equal steps\n * in the data become equal musical intervals, which is what a listener actually\n * compares. The map is linear-in-value and exponential-in-frequency, so it is\n * the audio equivalent of a linear axis — not a log axis, which would be a\n * different claim about the data.\n *\n * A flat series (`min === max`) sounds at the middle of the range rather than at\n * the floor: flat data is not low data, and a run of bottom notes reads as one.\n *\n * @example\n * valueToFrequency(50, { min: 0, max: 100 }) // 220 * 2 ** 1 = 440 Hz, one octave up\n */\nexport function valueToFrequency(\n value: number,\n domain: SonifyDomain,\n pitch: Pick<SonifyOptions, 'rootFrequency' | 'semitones'> = {},\n): number {\n const root = pitch.rootFrequency ?? SONIFY_DEFAULTS.rootFrequency\n const semitones = pitch.semitones ?? SONIFY_DEFAULTS.semitones\n const span = domain.max - domain.min\n\n const position = span === 0 ? 0.5 : (value - domain.min) / span\n const clamped = Math.min(1, Math.max(0, position))\n\n return root * 2 ** ((clamped * semitones) / 12)\n}\n\n/**\n * The value range every series is measured against, or `null` when nothing is\n * finite.\n *\n * Shared across all series on purpose. These charts draw their series against\n * ONE value axis, so they have to sound against one pitch axis too — normalising\n * each series to its own extremes would make a flat series that never leaves 2%\n * sound exactly like the one that swings across the whole plot, which is the\n * opposite of what the picture says.\n */\nexport function sonifyDomain(series: SonifySeries[]): SonifyDomain | null {\n let min = Number.POSITIVE_INFINITY\n let max = Number.NEGATIVE_INFINITY\n\n for (const entry of series) {\n for (const value of entry.values) {\n if (value === null || !Number.isFinite(value)) continue\n if (value < min) min = value\n if (value > max) max = value\n }\n }\n\n return min === Number.POSITIVE_INFINITY ? null : { min, max }\n}\n\n/**\n * What is said before a series plays.\n *\n * A run of tones with no frame of reference is unreadable — the listener hears\n * a contour and has no idea whether it spans four units or four million, or how\n * many points went by. Naming the count, the span of the category axis and the\n * two extremes costs one sentence and turns the melody into a measurement. The\n * direction of the mapping is stated too, because \"higher is more\" is a\n * convention, not a fact the sound carries.\n */\nexport function describeSeries(\n series: SonifySeries,\n formatValue: (value: number) => string = defaultTick,\n): string {\n const finite = series.values.filter((value): value is number => value !== null && Number.isFinite(value))\n\n if (finite.length === 0) return `${series.label}, no data.`\n\n const categories = series.categories ?? []\n const first = categories[0]\n const last = categories[categories.length - 1]\n const span = first !== undefined && last !== undefined && first !== last ? `, ${first} to ${last}` : ''\n\n const low = formatValue(Math.min(...finite))\n const high = formatValue(Math.max(...finite))\n const gaps = series.values.length - finite.length\n const missing = gaps > 0 ? ` ${gaps} missing.` : ''\n\n return `${series.label}, ${series.values.length} points${span}. Values from ${low} to ${high}, low pitch to high pitch.${missing}`\n}\n\n/** One thing that happens at one moment: something said, or a note sounded. */\nexport type SonifyStep =\n | { kind: 'announce'; atMs: number; text: string }\n | { kind: 'note'; atMs: number; point: SonifyPoint; frequency: number | null }\n\n/**\n * The whole run, laid out on a timeline before a single sound is made.\n *\n * Built as data rather than driven by a loop with a timer inside it, because\n * this is the part worth testing: the maths that decides when each note lands\n * is checkable without a speaker, and pause/resume becomes \"walk the same array\n * from a different index\" rather than a second, subtly different code path.\n *\n * Several series play **in sequence, each introduced by name**, rather than\n * simultaneously with one panned to each ear. Hard panning is the more\n * impressive demo and the wrong choice: it assumes a stereo output and two\n * usable ears, so a mono speaker, a single hearing aid, or unilateral hearing\n * loss collapses both series into one interleaved melody the listener cannot\n * unpick — and it caps the feature at two series, when four is ordinary. Played\n * in sequence, the worst case is that the run takes longer, which is a cost the\n * listener can see coming and a caller can shorten with `noteMs`.\n */\nexport function sonifyTimeline(series: SonifySeries[], options: SonifyOptions = {}): SonifyStep[] {\n const noteMs = options.noteMs ?? SONIFY_DEFAULTS.noteMs\n const gapMs = options.gapMs ?? SONIFY_DEFAULTS.gapMs\n const leadInMs = options.leadInMs ?? SONIFY_DEFAULTS.leadInMs\n const formatValue = options.formatValue ?? defaultTick\n\n const domain = sonifyDomain(series)\n const steps: SonifyStep[] = []\n let at = 0\n\n series.forEach((entry, entryIndex) => {\n if (entryIndex > 0) at += gapMs\n steps.push({ kind: 'announce', atMs: at, text: describeSeries(entry, formatValue) })\n at += leadInMs\n\n entry.values.forEach((raw, index) => {\n const value = raw !== null && Number.isFinite(raw) ? raw : null\n steps.push({\n kind: 'note',\n atMs: at,\n point: {\n seriesKey: entry.key,\n seriesLabel: entry.label,\n index,\n category: entry.categories?.[index],\n value,\n },\n // A gap keeps its slot and sounds as a rest. Closing it up would move\n // every later point earlier and quietly redraw the shape.\n frequency: value === null || domain === null ? null : valueToFrequency(value, domain, options),\n })\n at += noteMs\n })\n })\n\n return steps\n}\n\n/** How long the whole run takes, in milliseconds. */\nexport function sonifyDuration(series: SonifySeries[], options: SonifyOptions = {}): number {\n const steps = sonifyTimeline(series, options)\n const last = steps[steps.length - 1]\n if (!last) return 0\n return last.kind === 'note' ? last.atMs + (options.noteMs ?? SONIFY_DEFAULTS.noteMs) : last.atMs\n}\n\n/**\n * Whether this environment can make a sound at all.\n *\n * Safe on a server: it reads `window` from inside a function, so importing this\n * module during a server render touches nothing.\n */\nexport function hasAudioSupport(): boolean {\n if (typeof window === 'undefined') return false\n return audioContextConstructor() !== undefined\n}\n\ntype AudioContextConstructor = new () => AudioContext\n\nfunction audioContextConstructor(): AudioContextConstructor | undefined {\n if (typeof window === 'undefined') return undefined\n const scope = window as typeof window & { webkitAudioContext?: AudioContextConstructor }\n return scope.AudioContext ?? scope.webkitAudioContext\n}\n\nexport interface SonifyHandlers {\n /** The point currently sounding, so a chart can mark it. `null` between series. */\n onPoint?: (point: SonifyPoint | null) => void\n /** Text meant for a live region — the range announcement before each series. */\n onAnnounce?: (text: string) => void\n onStateChange?: (state: SonifyState) => void\n /** Fires once the last note has sounded, not when it was scheduled. */\n onEnd?: () => void\n}\n\nexport interface SonifyInput extends SonifyHandlers {\n series: SonifySeries[]\n options?: SonifyOptions\n}\n\nexport interface SonifyController {\n /**\n * Starts, or resumes from where a pause left off.\n *\n * MUST be called from a user gesture. That is a browser rule, not a\n * preference — and it is also the accessibility rule this feature is built\n * on, so there is no way to reach this except from something the reader did.\n */\n play: () => void\n /** Holds position. The current note is faded out rather than cut. */\n pause: () => void\n /** Stops and rewinds to the beginning. */\n stop: () => void\n /** Stops and releases the audio hardware. Call on unmount. */\n destroy: () => void\n readonly state: SonifyState\n /** The whole run, in milliseconds. */\n readonly durationMs: number\n}\n\n/**\n * A run of one chart's series, ready to play.\n *\n * Constructing one allocates nothing but an array — no `AudioContext`, no\n * timer, no node. That matters because a chart builds its controller during\n * render, where creating a context would both break a server render and burn\n * one of the browser's limited context slots on a chart nobody listens to.\n *\n * @example\n * const run = createSonification({\n * series: [{ key: 'desktop', label: 'Desktop', values: [186, 305, 237], categories: ['Jan', 'Feb', 'Mar'] }],\n * onPoint: (point) => setActive(point),\n * })\n * button.addEventListener('click', () => run.play())\n */\nexport function createSonification({\n series,\n options = {},\n onPoint,\n onAnnounce,\n onStateChange,\n onEnd,\n}: SonifyInput): SonifyController {\n const steps = sonifyTimeline(series, options)\n const durationMs = sonifyDuration(series, options)\n const wave = options.wave ?? SONIFY_DEFAULTS.wave\n const volume = options.volume ?? SONIFY_DEFAULTS.volume\n const noteMs = options.noteMs ?? SONIFY_DEFAULTS.noteMs\n\n let state: SonifyState = 'idle'\n let cursor = 0\n let elapsedMs = 0\n let anchorMs = 0\n let timer: ReturnType<typeof setTimeout> | null = null\n let context: AudioContext | null = null\n let master: GainNode | null = null\n const live = new Set<{ oscillator: OscillatorNode; gain: GainNode }>()\n\n function setState(next: SonifyState) {\n if (state === next) return\n state = next\n onStateChange?.(next)\n }\n\n /**\n * The context, built on demand.\n *\n * Returns `null` where audio is unavailable rather than throwing, so a\n * browser without Web Audio degrades to a control that does nothing visible\n * instead of an unhandled error inside a click handler.\n */\n function audio(): { context: AudioContext; master: GainNode } | null {\n if (context && master) return { context, master }\n\n const Constructor = audioContextConstructor()\n if (!Constructor) return null\n\n context = new Constructor()\n master = context.createGain()\n master.gain.value = volume\n master.connect(context.destination)\n return { context, master }\n }\n\n /**\n * One note, with an envelope.\n *\n * The envelope is not polish. An oscillator switched on at full amplitude\n * starts mid-waveform, and that step discontinuity is broadband — it is heard\n * as a click on every single note, which across sixty points is louder and\n * more tiring than the data itself. A few milliseconds of ramp at each end\n * removes it completely.\n */\n function sound(frequency: number, at: number) {\n const engine = audio()\n if (!engine) return\n\n const body = Math.max(ATTACK_SECONDS + RELEASE_SECONDS, (noteMs / 1000) * NOTE_DUTY)\n const oscillator = engine.context.createOscillator()\n const gain = engine.context.createGain()\n\n oscillator.type = wave\n oscillator.frequency.setValueAtTime(frequency, at)\n\n gain.gain.setValueAtTime(0, at)\n gain.gain.linearRampToValueAtTime(1, at + ATTACK_SECONDS)\n gain.gain.setValueAtTime(1, at + body - RELEASE_SECONDS)\n gain.gain.linearRampToValueAtTime(0, at + body)\n\n oscillator.connect(gain)\n gain.connect(engine.master)\n oscillator.start(at)\n oscillator.stop(at + body)\n\n const node = { oscillator, gain }\n live.add(node)\n oscillator.onended = () => {\n live.delete(node)\n gain.disconnect()\n oscillator.disconnect()\n }\n }\n\n /** Fades whatever is sounding, rather than cutting it — a cut clicks too. */\n function silence() {\n if (!context) return\n const now = context.currentTime\n for (const node of live) {\n node.gain.gain.cancelScheduledValues(now)\n node.gain.gain.setValueAtTime(node.gain.gain.value, now)\n node.gain.gain.linearRampToValueAtTime(0, now + CUT_SECONDS)\n node.oscillator.stop(now + CUT_SECONDS)\n }\n }\n\n function clearTimer() {\n if (timer === null) return\n clearTimeout(timer)\n timer = null\n }\n\n function finish() {\n clearTimer()\n cursor = 0\n elapsedMs = 0\n setState('idle')\n onPoint?.(null)\n onEnd?.()\n }\n\n function tick() {\n timer = null\n const step = steps[cursor]\n if (!step) {\n finish()\n return\n }\n\n cursor += 1\n\n if (step.kind === 'announce') {\n onPoint?.(null)\n onAnnounce?.(step.text)\n } else {\n onPoint?.(step.point)\n if (step.frequency !== null && context) {\n sound(step.frequency, context.currentTime + LOOKAHEAD_SECONDS)\n }\n }\n\n schedule()\n }\n\n /** Queues the next step against the run's own clock, so jitter never accumulates. */\n function schedule() {\n const next = steps[cursor]\n const target = next ? next.atMs : durationMs\n const wait = Math.max(0, target - (Date.now() - anchorMs))\n timer = setTimeout(tick, wait)\n }\n\n function play() {\n if (state === 'playing') return\n\n const engine = audio()\n // A context created inside a gesture handler can still arrive suspended —\n // Safari does this — so it is resumed rather than assumed live.\n if (engine && engine.context.state === 'suspended') void engine.context.resume()\n\n anchorMs = Date.now() - elapsedMs\n setState('playing')\n schedule()\n }\n\n function pause() {\n if (state !== 'playing') return\n elapsedMs = Date.now() - anchorMs\n clearTimer()\n silence()\n setState('paused')\n }\n\n function stop() {\n clearTimer()\n silence()\n cursor = 0\n elapsedMs = 0\n setState('idle')\n onPoint?.(null)\n }\n\n function destroy() {\n clearTimer()\n silence()\n cursor = 0\n elapsedMs = 0\n state = 'idle'\n void context?.close()\n context = null\n master = null\n live.clear()\n }\n\n return {\n play,\n pause,\n stop,\n destroy,\n get state() {\n return state\n },\n get durationMs() {\n return durationMs\n },\n }\n}\n"],"mappings":"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","names":[]}