basalt-ui 1.26.0 → 1.28.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 (1069) hide show
  1. package/AGENTS.md +23 -23
  2. package/CHANGELOG.md +67 -0
  3. package/MIGRATING.md +896 -37
  4. package/README.md +33 -3
  5. package/agent/rules/basalt-batteries.md +25 -10
  6. package/agent/rules/basalt-controls.md +73 -43
  7. package/agent/rules/basalt-mantine.md +17 -6
  8. package/agent/rules/basalt-state.md +5 -0
  9. package/agent/rules/basalt-tokens.md +1 -1
  10. package/configs/oxlint-plugin.js +1286 -73
  11. package/configs/oxlint-plugin.test.ts +1338 -29
  12. package/configs/oxlint.json +12 -5
  13. package/dist/agent/coalesce.d.ts.map +1 -1
  14. package/dist/agent/coalesce.js +2 -1
  15. package/dist/agent/merge.d.ts.map +1 -1
  16. package/dist/agent/merge.js +2 -1
  17. package/dist/agent/part-list.d.ts.map +1 -1
  18. package/dist/agent/part-list.js +2 -0
  19. package/dist/agent/stick-to-bottom.d.ts +3 -6
  20. package/dist/agent/stick-to-bottom.d.ts.map +1 -1
  21. package/dist/agent/stick-to-bottom.js +6 -3
  22. package/dist/agent-chat/composer.d.ts +6 -2
  23. package/dist/agent-chat/composer.d.ts.map +1 -1
  24. package/dist/agent-chat/composer.js +49 -33
  25. package/dist/agent-chat/relative-time.d.ts +0 -9
  26. package/dist/agent-chat/relative-time.d.ts.map +1 -1
  27. package/dist/agent-chat/relative-time.js +2 -1
  28. package/dist/agent-chat/thread-detail-panel.d.ts +3 -2
  29. package/dist/agent-chat/thread-detail-panel.d.ts.map +1 -1
  30. package/dist/agent-chat/thread-detail-panel.js +8 -5
  31. package/dist/agent-chat/thread-feed-row.d.ts +2 -1
  32. package/dist/agent-chat/thread-feed-row.d.ts.map +1 -1
  33. package/dist/agent-chat/thread-feed-row.js +92 -92
  34. package/dist/agent-chat/thread-feed.d.ts +3 -2
  35. package/dist/agent-chat/thread-feed.d.ts.map +1 -1
  36. package/dist/agent-chat/thread-feed.js +8 -3
  37. package/dist/agent-chat/thread-message.d.ts +4 -3
  38. package/dist/agent-chat/thread-message.d.ts.map +1 -1
  39. package/dist/agent-chat/thread-message.js +70 -31
  40. package/dist/agent-chat/thread-outcome-card.d.ts +3 -2
  41. package/dist/agent-chat/thread-outcome-card.d.ts.map +1 -1
  42. package/dist/agent-chat/thread-outcome-card.js +9 -2
  43. package/dist/agent-chat/thread-workspace.d.ts +7 -2
  44. package/dist/agent-chat/thread-workspace.d.ts.map +1 -1
  45. package/dist/agent-chat/thread-workspace.js +62 -29
  46. package/dist/agent-chat/tool-chip.d.ts +3 -2
  47. package/dist/agent-chat/tool-chip.d.ts.map +1 -1
  48. package/dist/agent-chat/tool-chip.js +7 -2
  49. package/dist/charts/hooks/useBandPlot.d.ts.map +1 -1
  50. package/dist/charts/hooks/useBandPlot.js +15 -8
  51. package/dist/charts/index.d.ts +8 -7
  52. package/dist/charts/index.d.ts.map +1 -1
  53. package/dist/charts/index.js +45 -5
  54. package/dist/charts/kinds/BandStrip.d.ts +10 -7
  55. package/dist/charts/kinds/BandStrip.d.ts.map +1 -1
  56. package/dist/charts/kinds/BandStrip.js +12 -7
  57. package/dist/charts/kinds/Bars.d.ts +12 -6
  58. package/dist/charts/kinds/Bars.d.ts.map +1 -1
  59. package/dist/charts/kinds/Bars.js +37 -11
  60. package/dist/charts/kinds/Donut.d.ts +6 -5
  61. package/dist/charts/kinds/Donut.d.ts.map +1 -1
  62. package/dist/charts/kinds/Donut.js +19 -2
  63. package/dist/charts/kinds/DualPanel.d.ts +6 -5
  64. package/dist/charts/kinds/DualPanel.d.ts.map +1 -1
  65. package/dist/charts/kinds/DualPanel.js +36 -8
  66. package/dist/charts/kinds/Heatmap.d.ts +10 -6
  67. package/dist/charts/kinds/Heatmap.d.ts.map +1 -1
  68. package/dist/charts/kinds/Heatmap.js +58 -31
  69. package/dist/charts/kinds/MirroredBars.d.ts +6 -5
  70. package/dist/charts/kinds/MirroredBars.d.ts.map +1 -1
  71. package/dist/charts/kinds/MirroredBars.js +9 -2
  72. package/dist/charts/kinds/MultiLine.d.ts +11 -6
  73. package/dist/charts/kinds/MultiLine.d.ts.map +1 -1
  74. package/dist/charts/kinds/MultiLine.js +24 -15
  75. package/dist/charts/kinds/StackedArea.d.ts +18 -8
  76. package/dist/charts/kinds/StackedArea.d.ts.map +1 -1
  77. package/dist/charts/kinds/StackedArea.js +29 -4
  78. package/dist/charts/kinds/ZonedLine.d.ts +12 -8
  79. package/dist/charts/kinds/ZonedLine.d.ts.map +1 -1
  80. package/dist/charts/kinds/ZonedLine.js +33 -23
  81. package/dist/charts/layout/auto-margin.d.ts +65 -8
  82. package/dist/charts/layout/auto-margin.d.ts.map +1 -1
  83. package/dist/charts/layout/auto-margin.js +45 -10
  84. package/dist/charts/layout/log-ticks.d.ts +27 -0
  85. package/dist/charts/layout/log-ticks.d.ts.map +1 -0
  86. package/dist/charts/layout/log-ticks.js +42 -0
  87. package/dist/charts/primitives/Axes.d.ts +11 -2
  88. package/dist/charts/primitives/Axes.d.ts.map +1 -1
  89. package/dist/charts/primitives/Axes.js +15 -5
  90. package/dist/charts/primitives/CartesianChart.d.ts +45 -7
  91. package/dist/charts/primitives/CartesianChart.d.ts.map +1 -1
  92. package/dist/charts/primitives/CartesianChart.js +86 -28
  93. package/dist/charts/primitives/ChartCard.d.ts +27 -2
  94. package/dist/charts/primitives/ChartCard.d.ts.map +1 -1
  95. package/dist/charts/primitives/ChartCard.js +37 -17
  96. package/dist/charts/primitives/ChartFrame.d.ts +30 -4
  97. package/dist/charts/primitives/ChartFrame.d.ts.map +1 -1
  98. package/dist/charts/primitives/ChartFrame.js +45 -15
  99. package/dist/charts/primitives/ChartLegend.d.ts +13 -2
  100. package/dist/charts/primitives/ChartLegend.d.ts.map +1 -1
  101. package/dist/charts/primitives/ChartLegend.js +33 -13
  102. package/dist/charts/primitives/ChartPending.d.ts +77 -4
  103. package/dist/charts/primitives/ChartPending.d.ts.map +1 -1
  104. package/dist/charts/primitives/ChartPending.js +100 -6
  105. package/dist/charts/primitives/ChartTooltip.d.ts +7 -0
  106. package/dist/charts/primitives/ChartTooltip.d.ts.map +1 -1
  107. package/dist/charts/primitives/ChartTooltip.js +18 -5
  108. package/dist/charts/primitives/Crosshair.d.ts +3 -0
  109. package/dist/charts/primitives/Crosshair.d.ts.map +1 -1
  110. package/dist/charts/primitives/Crosshair.js +3 -1
  111. package/dist/charts/primitives/chart-frame-layout.d.ts +95 -0
  112. package/dist/charts/primitives/chart-frame-layout.d.ts.map +1 -0
  113. package/dist/charts/primitives/chart-frame-layout.js +89 -0
  114. package/dist/charts/primitives/chart-tier.d.ts +16 -0
  115. package/dist/charts/primitives/chart-tier.d.ts.map +1 -0
  116. package/dist/charts/primitives/chart-tier.js +20 -0
  117. package/dist/charts/series.d.ts +55 -1
  118. package/dist/charts/series.d.ts.map +1 -1
  119. package/dist/charts/series.js +27 -1
  120. package/dist/charts/sparklines/BarSparkline.d.ts +3 -3
  121. package/dist/charts/sparklines/BarSparkline.d.ts.map +1 -1
  122. package/dist/charts/sparklines/BarSparkline.js +9 -3
  123. package/dist/charts/sparklines/LineSparkline.d.ts +3 -3
  124. package/dist/charts/sparklines/LineSparkline.d.ts.map +1 -1
  125. package/dist/charts/sparklines/LineSparkline.js +15 -3
  126. package/dist/charts/sparklines/index.d.ts +2 -2
  127. package/dist/charts/sparklines/index.d.ts.map +1 -1
  128. package/dist/charts/utils/format.d.ts +92 -2
  129. package/dist/charts/utils/format.d.ts.map +1 -1
  130. package/dist/charts/utils/format.js +64 -1
  131. package/dist/charts/utils/ticks.d.ts +81 -2
  132. package/dist/charts/utils/ticks.d.ts.map +1 -1
  133. package/dist/charts/utils/ticks.js +54 -4
  134. package/dist/cli/index.d.ts.map +1 -1
  135. package/dist/cli/index.js +2 -2
  136. package/dist/commands/ShortcutsHelp.d.ts +3 -2
  137. package/dist/commands/ShortcutsHelp.d.ts.map +1 -1
  138. package/dist/commands/ShortcutsHelp.js +8 -2
  139. package/dist/commands/define-commands.d.ts.map +1 -1
  140. package/dist/commands/define-commands.js +2 -2
  141. package/dist/commands/define-overlays.d.ts +102 -0
  142. package/dist/commands/define-overlays.d.ts.map +1 -1
  143. package/dist/commands/define-overlays.js +102 -2
  144. package/dist/commands/index.d.ts +10 -1
  145. package/dist/commands/index.d.ts.map +1 -1
  146. package/dist/commands/index.js +3 -1
  147. package/dist/commands/overlays-mount.d.ts +13 -6
  148. package/dist/commands/overlays-mount.d.ts.map +1 -1
  149. package/dist/commands/overlays-mount.js +23 -14
  150. package/dist/common/errors.d.ts +34 -0
  151. package/dist/common/errors.d.ts.map +1 -0
  152. package/dist/common/errors.js +36 -0
  153. package/dist/common/index.d.ts +15 -0
  154. package/dist/common/index.d.ts.map +1 -0
  155. package/dist/common/index.js +29 -0
  156. package/dist/common/props.d.ts +63 -0
  157. package/dist/common/props.d.ts.map +1 -0
  158. package/dist/common/props.js +6 -0
  159. package/dist/common/query-state-like.d.ts +43 -0
  160. package/dist/common/query-state-like.d.ts.map +1 -0
  161. package/dist/common/query-state-like.js +20 -0
  162. package/dist/common/refs.d.ts +29 -0
  163. package/dist/common/refs.d.ts.map +1 -0
  164. package/dist/common/refs.js +29 -0
  165. package/dist/common/scroll-parent.d.ts +23 -0
  166. package/dist/common/scroll-parent.d.ts.map +1 -0
  167. package/dist/common/scroll-parent.js +21 -0
  168. package/dist/common/validate.d.ts +38 -0
  169. package/dist/common/validate.d.ts.map +1 -0
  170. package/dist/common/validate.js +36 -0
  171. package/dist/connectivity/connectivity-indicator.d.ts +3 -1
  172. package/dist/connectivity/connectivity-indicator.d.ts.map +1 -1
  173. package/dist/connectivity/connectivity-indicator.js +3 -1
  174. package/dist/connectivity/connectivity-provider.d.ts.map +1 -1
  175. package/dist/connectivity/connectivity-provider.js +4 -1
  176. package/dist/connectivity/index.d.ts +1 -0
  177. package/dist/connectivity/index.d.ts.map +1 -1
  178. package/dist/connectivity/types.d.ts +2 -2
  179. package/dist/connectivity/types.d.ts.map +1 -1
  180. package/dist/connectivity/use-connectivity.d.ts.map +1 -1
  181. package/dist/content/article-layout.module.css +11 -4
  182. package/dist/content/callout.d.ts +8 -4
  183. package/dist/content/callout.d.ts.map +1 -1
  184. package/dist/content/callout.js +15 -8
  185. package/dist/content/guide.d.ts +5 -4
  186. package/dist/content/guide.d.ts.map +1 -1
  187. package/dist/content/guide.js +13 -4
  188. package/dist/content/heading-anchor.d.ts +24 -2
  189. package/dist/content/heading-anchor.d.ts.map +1 -1
  190. package/dist/content/heading-anchor.js +23 -9
  191. package/dist/content/index.d.ts.map +1 -1
  192. package/dist/content/markdown.d.ts.map +1 -1
  193. package/dist/content/markdown.js +2 -0
  194. package/dist/content/prose.module.css +9 -7
  195. package/dist/content/reading-progress.d.ts +10 -4
  196. package/dist/content/reading-progress.d.ts.map +1 -1
  197. package/dist/content/reading-progress.js +26 -10
  198. package/dist/content/slug.d.ts +4 -0
  199. package/dist/content/slug.d.ts.map +1 -1
  200. package/dist/content/toc.d.ts +11 -0
  201. package/dist/content/toc.d.ts.map +1 -1
  202. package/dist/content/toc.js +23 -10
  203. package/dist/controls/actions.d.ts +49 -6
  204. package/dist/controls/actions.d.ts.map +1 -1
  205. package/dist/controls/actions.js +39 -8
  206. package/dist/controls/compare-filter.d.ts +3 -2
  207. package/dist/controls/compare-filter.d.ts.map +1 -1
  208. package/dist/controls/compare-filter.js +17 -2
  209. package/dist/controls/control-group.d.ts +3 -3
  210. package/dist/controls/control-group.d.ts.map +1 -1
  211. package/dist/controls/control-group.js +9 -2
  212. package/dist/controls/controls.module.css +169 -186
  213. package/dist/controls/controls.module.css.d.ts +9 -11
  214. package/dist/controls/enum-filter.d.ts +13 -3
  215. package/dist/controls/enum-filter.d.ts.map +1 -1
  216. package/dist/controls/enum-filter.js +32 -15
  217. package/dist/controls/filter-context.d.ts +15 -6
  218. package/dist/controls/filter-context.d.ts.map +1 -1
  219. package/dist/controls/filter-pill.d.ts +3 -3
  220. package/dist/controls/filter-pill.d.ts.map +1 -1
  221. package/dist/controls/filter-pill.js +4 -1
  222. package/dist/controls/filter-set.d.ts +3 -2
  223. package/dist/controls/filter-set.d.ts.map +1 -1
  224. package/dist/controls/filter-set.js +66 -41
  225. package/dist/controls/filter-sheet.d.ts +20 -80
  226. package/dist/controls/filter-sheet.d.ts.map +1 -1
  227. package/dist/controls/filter-sheet.js +9 -95
  228. package/dist/controls/index.d.ts +3 -0
  229. package/dist/controls/index.d.ts.map +1 -1
  230. package/dist/controls/index.js +6 -0
  231. package/dist/controls/multi-select-filter.d.ts +18 -2
  232. package/dist/controls/multi-select-filter.d.ts.map +1 -1
  233. package/dist/controls/multi-select-filter.js +124 -22
  234. package/dist/controls/number-filter.d.ts +28 -0
  235. package/dist/controls/number-filter.d.ts.map +1 -0
  236. package/dist/controls/number-filter.js +172 -0
  237. package/dist/controls/panel-row.d.ts +132 -0
  238. package/dist/controls/panel-row.d.ts.map +1 -0
  239. package/dist/controls/panel-row.js +173 -0
  240. package/dist/controls/panel-row.module.css +86 -0
  241. package/dist/controls/panel-row.module.css.d.ts +13 -0
  242. package/dist/controls/range-filter.d.ts +20 -5
  243. package/dist/controls/range-filter.d.ts.map +1 -1
  244. package/dist/controls/range-filter.js +75 -38
  245. package/dist/controls/search-filter.d.ts +3 -2
  246. package/dist/controls/search-filter.d.ts.map +1 -1
  247. package/dist/controls/search-filter.js +26 -11
  248. package/dist/controls/select-filter.d.ts +2 -1
  249. package/dist/controls/select-filter.d.ts.map +1 -1
  250. package/dist/controls/select-filter.js +4 -0
  251. package/dist/controls/slider-control.d.ts +36 -0
  252. package/dist/controls/slider-control.d.ts.map +1 -0
  253. package/dist/controls/slider-control.js +64 -0
  254. package/dist/controls/sync-button.d.ts +3 -2
  255. package/dist/controls/sync-button.d.ts.map +1 -1
  256. package/dist/controls/sync-button.js +16 -3
  257. package/dist/controls/toggle-filter.d.ts +3 -2
  258. package/dist/controls/toggle-filter.d.ts.map +1 -1
  259. package/dist/controls/toggle-filter.js +29 -12
  260. package/dist/controls/view-tabs.d.ts +3 -2
  261. package/dist/controls/view-tabs.d.ts.map +1 -1
  262. package/dist/controls/view-tabs.js +43 -11
  263. package/dist/controls-dates/date-range-picker.d.ts +1 -1
  264. package/dist/controls-dates/date-range-picker.d.ts.map +1 -1
  265. package/dist/controls-dates/date-range-picker.js +6 -1
  266. package/dist/dashboard/delta-badge.d.ts +5 -1
  267. package/dist/dashboard/delta-badge.d.ts.map +1 -1
  268. package/dist/dashboard/empty-state.d.ts +10 -3
  269. package/dist/dashboard/empty-state.d.ts.map +1 -1
  270. package/dist/dashboard/empty-state.js +37 -6
  271. package/dist/dashboard/index.d.ts +6 -4
  272. package/dist/dashboard/index.d.ts.map +1 -1
  273. package/dist/dashboard/index.js +10 -2
  274. package/dist/dashboard/query-state.d.ts +48 -27
  275. package/dist/dashboard/query-state.d.ts.map +1 -1
  276. package/dist/dashboard/query-state.js +111 -57
  277. package/dist/dashboard/settings-section.d.ts +19 -9
  278. package/dist/dashboard/settings-section.d.ts.map +1 -1
  279. package/dist/dashboard/settings-section.js +74 -25
  280. package/dist/dashboard/stat-card.d.ts +76 -19
  281. package/dist/dashboard/stat-card.d.ts.map +1 -1
  282. package/dist/dashboard/stat-card.js +78 -38
  283. package/dist/dashboard/stat-card.module.css +112 -26
  284. package/dist/dashboard/stat-card.module.css.d.ts +5 -0
  285. package/dist/dashboard/stat-group.d.ts +41 -0
  286. package/dist/dashboard/stat-group.d.ts.map +1 -0
  287. package/dist/dashboard/stat-group.js +30 -0
  288. package/dist/dashboard/stat-group.module.css +66 -0
  289. package/dist/dashboard/stat-group.module.css.d.ts +8 -0
  290. package/dist/dashboard/widget-grid.d.ts +27 -0
  291. package/dist/dashboard/widget-grid.d.ts.map +1 -0
  292. package/dist/dashboard/widget-grid.js +41 -0
  293. package/dist/dashboard/widget-grid.module.css +53 -0
  294. package/dist/dashboard/widget-grid.module.css.d.ts +9 -0
  295. package/dist/data/data-table.d.ts +151 -12
  296. package/dist/data/data-table.d.ts.map +1 -1
  297. package/dist/data/data-table.js +392 -138
  298. package/dist/data/data-table.module.css +64 -0
  299. package/dist/data/data-table.module.css.d.ts +11 -0
  300. package/dist/data/index.d.ts +2 -2
  301. package/dist/data/index.d.ts.map +1 -1
  302. package/dist/data/index.js +24 -2
  303. package/dist/data/query-branch.d.ts +28 -0
  304. package/dist/data/query-branch.d.ts.map +1 -0
  305. package/dist/data/query-branch.js +10 -0
  306. package/dist/data/table.d.ts +2 -2
  307. package/dist/data/table.d.ts.map +1 -1
  308. package/dist/data/virtual-list.d.ts +65 -6
  309. package/dist/data/virtual-list.d.ts.map +1 -1
  310. package/dist/data/virtual-list.js +89 -38
  311. package/dist/data/virtual.d.ts +1 -1
  312. package/dist/data/virtual.d.ts.map +1 -1
  313. package/dist/forms/FormErrorSummary.d.ts +4 -3
  314. package/dist/forms/FormErrorSummary.d.ts.map +1 -1
  315. package/dist/forms/FormErrorSummary.js +6 -4
  316. package/dist/forms/create-form.d.ts +2 -2
  317. package/dist/forms/field.d.ts +46 -6
  318. package/dist/forms/field.d.ts.map +1 -1
  319. package/dist/forms/field.js +10 -5
  320. package/dist/forms/form-layout.d.ts +142 -0
  321. package/dist/forms/form-layout.d.ts.map +1 -0
  322. package/dist/forms/form-layout.js +110 -0
  323. package/dist/forms/form-layout.module.css +145 -0
  324. package/dist/forms/form-layout.module.css.d.ts +20 -0
  325. package/dist/forms/form-state.d.ts +42 -0
  326. package/dist/forms/form-state.d.ts.map +1 -0
  327. package/dist/forms/form-state.js +26 -0
  328. package/dist/forms/index.d.ts +22 -6
  329. package/dist/forms/index.d.ts.map +1 -1
  330. package/dist/forms/index.js +19 -3
  331. package/dist/forms/use-field-array.d.ts +60 -0
  332. package/dist/forms/use-field-array.d.ts.map +1 -0
  333. package/dist/forms/use-field-array.js +20 -0
  334. package/dist/forms/use-form-draft.d.ts +25 -10
  335. package/dist/forms/use-form-draft.d.ts.map +1 -1
  336. package/dist/forms/use-form-draft.js +55 -18
  337. package/dist/forms/use-form-submit.d.ts +88 -0
  338. package/dist/forms/use-form-submit.d.ts.map +1 -0
  339. package/dist/forms/use-form-submit.js +63 -0
  340. package/dist/guard/index.d.ts +1 -1
  341. package/dist/guard/index.d.ts.map +1 -1
  342. package/dist/guard/index.js +27 -11
  343. package/dist/index.d.ts +10 -8
  344. package/dist/index.d.ts.map +1 -1
  345. package/dist/index.js +44 -4
  346. package/dist/nav/types.d.ts +15 -6
  347. package/dist/nav/types.d.ts.map +1 -1
  348. package/dist/notifications/bell.d.ts +3 -2
  349. package/dist/notifications/bell.d.ts.map +1 -1
  350. package/dist/notifications/bell.js +73 -56
  351. package/dist/notifications/center.d.ts +15 -4
  352. package/dist/notifications/center.d.ts.map +1 -1
  353. package/dist/notifications/center.js +5 -2
  354. package/dist/notifications/define-notifications.d.ts +56 -14
  355. package/dist/notifications/define-notifications.d.ts.map +1 -1
  356. package/dist/notifications/define-notifications.js +2 -1
  357. package/dist/notifications/index.d.ts +6 -2
  358. package/dist/notifications/index.d.ts.map +1 -1
  359. package/dist/notifications/index.js +5 -1
  360. package/dist/notifications/mount-guard.d.ts +8 -0
  361. package/dist/notifications/mount-guard.d.ts.map +1 -0
  362. package/dist/notifications/mount-guard.js +19 -0
  363. package/dist/notifications/notify.d.ts +58 -1
  364. package/dist/notifications/notify.d.ts.map +1 -1
  365. package/dist/notifications/notify.js +46 -2
  366. package/dist/notifications/overlay.d.ts.map +1 -1
  367. package/dist/notifications/overlay.js +2 -0
  368. package/dist/notifications/store.d.ts +7 -0
  369. package/dist/notifications/store.d.ts.map +1 -1
  370. package/dist/provider/index.d.ts +37 -5
  371. package/dist/provider/index.d.ts.map +1 -1
  372. package/dist/provider/index.js +66 -28
  373. package/dist/provider/lab-theme.d.ts.map +1 -1
  374. package/dist/provider/lab-theme.js +2 -1
  375. package/dist/query/devtools.d.ts.map +1 -1
  376. package/dist/query/devtools.js +1 -0
  377. package/dist/router-tanstack/field.d.ts +1 -1
  378. package/dist/router-tanstack/field.d.ts.map +1 -1
  379. package/dist/router-tanstack/index.d.ts +1 -1
  380. package/dist/router-tanstack/index.d.ts.map +1 -1
  381. package/dist/router-tanstack/search-store.d.ts +4 -1
  382. package/dist/router-tanstack/search-store.d.ts.map +1 -1
  383. package/dist/router-tanstack/search-store.js +92 -8
  384. package/dist/router-tanstack/use-nav.d.ts.map +1 -1
  385. package/dist/router-tanstack/use-nav.js +1 -1
  386. package/dist/section/index.d.ts +1 -1
  387. package/dist/section/index.d.ts.map +1 -1
  388. package/dist/section/section.d.ts +36 -2
  389. package/dist/section/section.d.ts.map +1 -1
  390. package/dist/section/section.js +49 -57
  391. package/dist/section/section.module.css +11 -0
  392. package/dist/shell/account-types.d.ts +5 -2
  393. package/dist/shell/account-types.d.ts.map +1 -1
  394. package/dist/shell/app-brand.d.ts +13 -0
  395. package/dist/shell/app-brand.d.ts.map +1 -0
  396. package/dist/shell/app-brand.js +94 -0
  397. package/dist/shell/app-brand.module.css +109 -0
  398. package/dist/shell/app-brand.module.css.d.ts +14 -0
  399. package/dist/shell/app-breadcrumbs.d.ts +4 -2
  400. package/dist/shell/app-breadcrumbs.d.ts.map +1 -1
  401. package/dist/shell/app-breadcrumbs.js +33 -22
  402. package/dist/shell/app-header.module.css +10 -5
  403. package/dist/shell/app-main.module.css +107 -0
  404. package/dist/shell/app-main.module.css.d.ts +11 -0
  405. package/dist/shell/app-mobile-nav.d.ts +3 -2
  406. package/dist/shell/app-mobile-nav.d.ts.map +1 -1
  407. package/dist/shell/app-mobile-nav.js +29 -15
  408. package/dist/shell/app-mobile-nav.module.css +48 -27
  409. package/dist/shell/app-mobile-nav.module.css.d.ts +0 -1
  410. package/dist/shell/app-sidebar-account.d.ts +2 -1
  411. package/dist/shell/app-sidebar-account.d.ts.map +1 -1
  412. package/dist/shell/app-sidebar-account.js +57 -22
  413. package/dist/shell/app-sidebar.d.ts +9 -3
  414. package/dist/shell/app-sidebar.d.ts.map +1 -1
  415. package/dist/shell/app-sidebar.js +55 -109
  416. package/dist/shell/app-sidebar.module.css +53 -96
  417. package/dist/shell/app-sidebar.module.css.d.ts +0 -5
  418. package/dist/shell/index.d.ts +14 -6
  419. package/dist/shell/index.d.ts.map +1 -1
  420. package/dist/shell/index.js +47 -12
  421. package/dist/shell/isomorphic-layout-effect.d.ts +14 -0
  422. package/dist/shell/isomorphic-layout-effect.d.ts.map +1 -0
  423. package/dist/shell/isomorphic-layout-effect.js +5 -0
  424. package/dist/shell/mobile-nav-model.d.ts.map +1 -1
  425. package/dist/shell/mobile-nav-model.js +27 -6
  426. package/dist/shell/nav-count-badge.d.ts +5 -3
  427. package/dist/shell/nav-count-badge.d.ts.map +1 -1
  428. package/dist/shell/nav-count-badge.js +3 -1
  429. package/dist/shell/page-aside.d.ts +43 -0
  430. package/dist/shell/page-aside.d.ts.map +1 -0
  431. package/dist/shell/page-aside.js +202 -0
  432. package/dist/shell/page-aside.module.css +174 -0
  433. package/dist/shell/page-aside.module.css.d.ts +14 -0
  434. package/dist/shell/page-bar.d.ts +55 -15
  435. package/dist/shell/page-bar.d.ts.map +1 -1
  436. package/dist/shell/page-bar.js +130 -41
  437. package/dist/shell/page-bar.module.css +107 -13
  438. package/dist/shell/page-bar.module.css.d.ts +4 -1
  439. package/dist/shell/sidebar-search.d.ts +4 -2
  440. package/dist/shell/sidebar-search.d.ts.map +1 -1
  441. package/dist/shell/sidebar-search.js +9 -4
  442. package/dist/shell/sidebar-search.module.css +1 -1
  443. package/dist/state/fields.d.ts +227 -34
  444. package/dist/state/fields.d.ts.map +1 -1
  445. package/dist/state/fields.js +77 -30
  446. package/dist/state/persisted-or-local.d.ts +9 -0
  447. package/dist/state/persisted-or-local.d.ts.map +1 -0
  448. package/dist/state/persisted-or-local.js +24 -0
  449. package/dist/state/persisted.d.ts +12 -0
  450. package/dist/state/persisted.d.ts.map +1 -1
  451. package/dist/state/persisted.js +36 -18
  452. package/dist/state.d.ts +1 -1
  453. package/dist/state.d.ts.map +1 -1
  454. package/dist/state.js +2 -6
  455. package/dist/surfaces.d.ts +12 -11
  456. package/dist/surfaces.d.ts.map +1 -1
  457. package/dist/surfaces.js +43 -12
  458. package/dist/theme/ctl-theme.d.ts.map +1 -1
  459. package/dist/theme/index.d.ts.map +1 -1
  460. package/dist/theme/index.js +102 -17
  461. package/dist/theme/nav-link.module.css +37 -26
  462. package/dist/theme/segmented-control.module.css +22 -0
  463. package/dist/theme/segmented-control.module.css.d.ts +1 -0
  464. package/dist/theme-lab/boot.d.ts +66 -0
  465. package/dist/theme-lab/boot.d.ts.map +1 -0
  466. package/dist/theme-lab/boot.js +82 -0
  467. package/dist/theme-lab/index.d.ts +4 -43
  468. package/dist/theme-lab/index.d.ts.map +1 -1
  469. package/dist/theme-lab/index.js +9 -69
  470. package/dist/theme-toggle/index.d.ts +3 -2
  471. package/dist/theme-toggle/index.d.ts.map +1 -1
  472. package/dist/theme-toggle/index.js +8 -2
  473. package/dist/tokens/index.d.ts +42 -0
  474. package/dist/tokens/index.d.ts.map +1 -1
  475. package/dist/tokens/index.js +35 -6
  476. package/dist/tokens/palette.d.ts +45 -25
  477. package/dist/tokens/palette.d.ts.map +1 -1
  478. package/dist/tokens/palette.js +31 -14
  479. package/dist/tokens.css +4 -5
  480. package/dist/utils/is-dev.d.ts +3 -0
  481. package/dist/utils/is-dev.d.ts.map +1 -0
  482. package/dist/utils/is-dev.js +6 -0
  483. package/dist/widget-header/delta-badge.d.ts +7 -1
  484. package/dist/widget-header/delta-badge.d.ts.map +1 -1
  485. package/dist/widget-header/delta-badge.js +8 -1
  486. package/dist/widget-header/index.d.ts +2 -2
  487. package/dist/widget-header/index.d.ts.map +1 -1
  488. package/dist/widget-header/index.js +3 -1
  489. package/dist/widget-header/widget-header.d.ts +99 -4
  490. package/dist/widget-header/widget-header.d.ts.map +1 -1
  491. package/dist/widget-header/widget-header.js +45 -18
  492. package/dist/widget-header/widget-header.module.css +87 -7
  493. package/dist/widget-header/widget-header.module.css.d.ts +1 -0
  494. package/llms.txt +6 -6
  495. package/package.json +49 -25
  496. package/src/agent/coalesce.ts +2 -1
  497. package/src/agent/merge.ts +2 -1
  498. package/src/agent/part-list.tsx +2 -0
  499. package/src/agent/stick-to-bottom.tsx +9 -11
  500. package/src/agent-chat/composer.tsx +124 -103
  501. package/src/agent-chat/relative-time.ts +2 -1
  502. package/src/agent-chat/thread-detail-panel.tsx +9 -5
  503. package/src/agent-chat/thread-feed-row.tsx +17 -9
  504. package/src/agent-chat/thread-feed.tsx +9 -3
  505. package/src/agent-chat/thread-message.tsx +48 -13
  506. package/src/agent-chat/thread-outcome-card.tsx +9 -1
  507. package/src/agent-chat/thread-workspace.tsx +72 -33
  508. package/src/agent-chat/tool-chip.tsx +8 -2
  509. package/src/charts/hooks/useBandPlot.ts +26 -8
  510. package/src/charts/index.ts +39 -4
  511. package/src/charts/kinds/BandStrip.tsx +36 -14
  512. package/src/charts/kinds/Bars.tsx +67 -16
  513. package/src/charts/kinds/Donut.tsx +30 -3
  514. package/src/charts/kinds/DualPanel.tsx +56 -10
  515. package/src/charts/kinds/Heatmap.tsx +90 -33
  516. package/src/charts/kinds/MirroredBars.tsx +21 -3
  517. package/src/charts/kinds/MultiLine.tsx +61 -18
  518. package/src/charts/kinds/StackedArea.tsx +77 -6
  519. package/src/charts/kinds/ZonedLine.tsx +71 -31
  520. package/src/charts/layout/auto-margin.ts +134 -21
  521. package/src/charts/layout/log-ticks.ts +90 -0
  522. package/src/charts/primitives/Axes.tsx +33 -5
  523. package/src/charts/primitives/CartesianChart.tsx +194 -41
  524. package/src/charts/primitives/ChartCard.tsx +66 -25
  525. package/src/charts/primitives/ChartFrame.tsx +107 -26
  526. package/src/charts/primitives/ChartLegend.tsx +43 -13
  527. package/src/charts/primitives/ChartPending.tsx +185 -7
  528. package/src/charts/primitives/ChartTooltip.tsx +37 -5
  529. package/src/charts/primitives/Crosshair.tsx +6 -3
  530. package/src/charts/primitives/chart-frame-layout.ts +212 -0
  531. package/src/charts/primitives/chart-tier.tsx +37 -0
  532. package/src/charts/series.ts +77 -1
  533. package/src/charts/sparklines/BarSparkline.tsx +11 -3
  534. package/src/charts/sparklines/LineSparkline.tsx +18 -4
  535. package/src/charts/sparklines/index.ts +2 -2
  536. package/src/charts/utils/format.ts +163 -2
  537. package/src/charts/utils/ticks.ts +149 -4
  538. package/src/cli/index.ts +8 -3
  539. package/src/commands/ShortcutsHelp.tsx +10 -3
  540. package/src/commands/define-commands.ts +2 -2
  541. package/src/commands/define-overlays.ts +216 -1
  542. package/src/commands/index.ts +12 -0
  543. package/src/commands/overlays-mount.tsx +60 -26
  544. package/src/common/errors.ts +73 -0
  545. package/src/common/index.ts +21 -0
  546. package/src/common/props.ts +71 -0
  547. package/src/common/query-state-like.ts +64 -0
  548. package/src/common/refs.ts +58 -0
  549. package/src/common/scroll-parent.ts +42 -0
  550. package/src/common/validate.ts +94 -0
  551. package/src/connectivity/connectivity-indicator.tsx +6 -1
  552. package/src/connectivity/connectivity-provider.tsx +4 -1
  553. package/src/connectivity/index.ts +1 -0
  554. package/src/connectivity/types.ts +5 -2
  555. package/src/connectivity/use-connectivity.ts +3 -2
  556. package/src/content/article-layout.module.css +11 -4
  557. package/src/content/callout.tsx +13 -7
  558. package/src/content/guide.tsx +14 -4
  559. package/src/content/heading-anchor.tsx +14 -3
  560. package/src/content/index.ts +2 -0
  561. package/src/content/markdown.tsx +2 -0
  562. package/src/content/prose.module.css +9 -7
  563. package/src/content/reading-progress.tsx +40 -15
  564. package/src/content/slug.ts +4 -0
  565. package/src/content/toc.tsx +47 -10
  566. package/src/controls/actions.tsx +89 -9
  567. package/src/controls/compare-filter.tsx +20 -3
  568. package/src/controls/control-group.tsx +11 -4
  569. package/src/controls/controls.module.css +169 -186
  570. package/src/controls/controls.module.css.d.ts +9 -11
  571. package/src/controls/enum-filter.tsx +46 -19
  572. package/src/controls/filter-context.tsx +21 -8
  573. package/src/controls/filter-pill.tsx +6 -3
  574. package/src/controls/filter-set.tsx +32 -13
  575. package/src/controls/filter-sheet.tsx +44 -194
  576. package/src/controls/index.ts +8 -0
  577. package/src/controls/multi-select-filter.tsx +179 -29
  578. package/src/controls/number-filter.tsx +329 -0
  579. package/src/controls/panel-row.module.css +86 -0
  580. package/src/controls/panel-row.module.css.d.ts +13 -0
  581. package/src/controls/panel-row.tsx +392 -0
  582. package/src/controls/range-filter.tsx +133 -43
  583. package/src/controls/search-filter.tsx +31 -13
  584. package/src/controls/select-filter.tsx +11 -1
  585. package/src/controls/slider-control.tsx +159 -0
  586. package/src/controls/sync-button.tsx +13 -3
  587. package/src/controls/toggle-filter.tsx +37 -17
  588. package/src/controls/view-tabs.tsx +63 -11
  589. package/src/controls-dates/date-range-picker.tsx +8 -1
  590. package/src/dashboard/delta-badge.tsx +5 -1
  591. package/src/dashboard/empty-state.tsx +72 -25
  592. package/src/dashboard/index.ts +19 -2
  593. package/src/dashboard/query-state.tsx +154 -84
  594. package/src/dashboard/settings-section.tsx +87 -31
  595. package/src/dashboard/stat-card.module.css +112 -26
  596. package/src/dashboard/stat-card.module.css.d.ts +5 -0
  597. package/src/dashboard/stat-card.tsx +207 -68
  598. package/src/dashboard/stat-group.module.css +66 -0
  599. package/src/dashboard/stat-group.module.css.d.ts +8 -0
  600. package/src/dashboard/stat-group.tsx +74 -0
  601. package/src/dashboard/widget-grid.module.css +53 -0
  602. package/src/dashboard/widget-grid.module.css.d.ts +9 -0
  603. package/src/dashboard/widget-grid.tsx +127 -0
  604. package/src/data/data-table.module.css +64 -0
  605. package/src/data/data-table.module.css.d.ts +11 -0
  606. package/src/data/data-table.tsx +927 -346
  607. package/src/data/index.ts +30 -2
  608. package/src/data/query-branch.ts +53 -0
  609. package/src/data/table.ts +5 -0
  610. package/src/data/virtual-list.tsx +189 -55
  611. package/src/data/virtual.ts +5 -1
  612. package/src/forms/FormErrorSummary.tsx +13 -6
  613. package/src/forms/create-form.ts +2 -2
  614. package/src/forms/field.ts +60 -11
  615. package/src/forms/form-layout.module.css +145 -0
  616. package/src/forms/form-layout.module.css.d.ts +20 -0
  617. package/src/forms/form-layout.tsx +305 -0
  618. package/src/forms/form-state.tsx +94 -0
  619. package/src/forms/index.ts +38 -7
  620. package/src/forms/use-field-array.ts +94 -0
  621. package/src/forms/use-form-draft.ts +145 -53
  622. package/src/forms/use-form-submit.ts +199 -0
  623. package/src/guard/index.ts +91 -23
  624. package/src/index.ts +79 -10
  625. package/src/nav/types.ts +15 -6
  626. package/src/notifications/bell.tsx +18 -4
  627. package/src/notifications/center.tsx +18 -5
  628. package/src/notifications/define-notifications.ts +64 -18
  629. package/src/notifications/index.ts +12 -1
  630. package/src/notifications/mount-guard.ts +41 -0
  631. package/src/notifications/notify.tsx +122 -3
  632. package/src/notifications/overlay.tsx +2 -0
  633. package/src/notifications/store.ts +7 -0
  634. package/src/provider/index.tsx +101 -13
  635. package/src/provider/lab-theme.ts +2 -1
  636. package/src/query/devtools.tsx +1 -0
  637. package/src/router-tanstack/field.ts +5 -0
  638. package/src/router-tanstack/index.ts +4 -0
  639. package/src/router-tanstack/search-store.ts +171 -12
  640. package/src/router-tanstack/use-nav.ts +18 -13
  641. package/src/section/index.ts +1 -1
  642. package/src/section/section.module.css +11 -0
  643. package/src/section/section.tsx +163 -96
  644. package/src/shell/account-types.ts +5 -2
  645. package/src/shell/app-brand.module.css +109 -0
  646. package/src/shell/app-brand.module.css.d.ts +14 -0
  647. package/src/shell/app-brand.tsx +140 -0
  648. package/src/shell/app-breadcrumbs.tsx +19 -9
  649. package/src/shell/app-header.module.css +10 -5
  650. package/src/shell/app-main.module.css +107 -0
  651. package/src/shell/app-main.module.css.d.ts +11 -0
  652. package/src/shell/app-mobile-nav.module.css +48 -27
  653. package/src/shell/app-mobile-nav.module.css.d.ts +0 -1
  654. package/src/shell/app-mobile-nav.tsx +43 -11
  655. package/src/shell/app-sidebar-account.tsx +29 -6
  656. package/src/shell/app-sidebar.module.css +53 -96
  657. package/src/shell/app-sidebar.module.css.d.ts +0 -5
  658. package/src/shell/app-sidebar.tsx +40 -113
  659. package/src/shell/index.tsx +156 -65
  660. package/src/shell/isomorphic-layout-effect.ts +14 -0
  661. package/src/shell/mobile-nav-model.ts +66 -10
  662. package/src/shell/nav-count-badge.tsx +6 -1
  663. package/src/shell/page-aside.module.css +174 -0
  664. package/src/shell/page-aside.module.css.d.ts +14 -0
  665. package/src/shell/page-aside.tsx +377 -0
  666. package/src/shell/page-bar.module.css +107 -13
  667. package/src/shell/page-bar.module.css.d.ts +4 -1
  668. package/src/shell/page-bar.tsx +294 -94
  669. package/src/shell/sidebar-search.module.css +1 -1
  670. package/src/shell/sidebar-search.tsx +13 -4
  671. package/src/state/fields.ts +360 -69
  672. package/src/state/persisted-or-local.ts +50 -0
  673. package/src/state/persisted.ts +76 -26
  674. package/src/state.ts +4 -7
  675. package/src/surfaces.ts +43 -12
  676. package/src/theme/ctl-theme.tsx +10 -0
  677. package/src/theme/index.ts +129 -16
  678. package/src/theme/nav-link.module.css +37 -26
  679. package/src/theme/segmented-control.module.css +22 -0
  680. package/src/theme/segmented-control.module.css.d.ts +1 -0
  681. package/src/theme-lab/boot.ts +140 -0
  682. package/src/theme-lab/index.tsx +21 -112
  683. package/src/theme-toggle/index.tsx +10 -3
  684. package/src/tokens/index.ts +50 -6
  685. package/src/tokens/palette.ts +58 -30
  686. package/src/utils/is-dev.ts +4 -0
  687. package/src/widget-header/delta-badge.tsx +25 -5
  688. package/src/widget-header/index.ts +10 -2
  689. package/src/widget-header/widget-header.module.css +87 -7
  690. package/src/widget-header/widget-header.module.css.d.ts +1 -0
  691. package/src/widget-header/widget-header.tsx +166 -42
  692. package/dist/agent/adapter.test.d.ts +0 -2
  693. package/dist/agent/adapter.test.d.ts.map +0 -1
  694. package/dist/agent/ai-sdk-transport.test.d.ts +0 -2
  695. package/dist/agent/ai-sdk-transport.test.d.ts.map +0 -1
  696. package/dist/agent/coalesce.test.d.ts +0 -2
  697. package/dist/agent/coalesce.test.d.ts.map +0 -1
  698. package/dist/agent/foreign.test.d.ts +0 -2
  699. package/dist/agent/foreign.test.d.ts.map +0 -1
  700. package/dist/agent/id.test.d.ts +0 -2
  701. package/dist/agent/id.test.d.ts.map +0 -1
  702. package/dist/agent/merge.test.d.ts +0 -2
  703. package/dist/agent/merge.test.d.ts.map +0 -1
  704. package/dist/agent/part-list.test.d.ts +0 -2
  705. package/dist/agent/part-list.test.d.ts.map +0 -1
  706. package/dist/agent/parts.test.d.ts +0 -2
  707. package/dist/agent/parts.test.d.ts.map +0 -1
  708. package/dist/agent/thread.test.d.ts +0 -2
  709. package/dist/agent/thread.test.d.ts.map +0 -1
  710. package/dist/agent/transport.test.d.ts +0 -2
  711. package/dist/agent/transport.test.d.ts.map +0 -1
  712. package/dist/agent/use-agent-stream.test.d.ts +0 -2
  713. package/dist/agent/use-agent-stream.test.d.ts.map +0 -1
  714. package/dist/agent/use-agent-thread-runs.foreign.test.d.ts +0 -2
  715. package/dist/agent/use-agent-thread-runs.foreign.test.d.ts.map +0 -1
  716. package/dist/agent/use-agent-thread-runs.resume.test.d.ts +0 -2
  717. package/dist/agent/use-agent-thread-runs.resume.test.d.ts.map +0 -1
  718. package/dist/agent/use-agent-thread-runs.test.d.ts +0 -2
  719. package/dist/agent/use-agent-thread-runs.test.d.ts.map +0 -1
  720. package/dist/agent/use-agent-thread-runs.wedge.test.d.ts +0 -2
  721. package/dist/agent/use-agent-thread-runs.wedge.test.d.ts.map +0 -1
  722. package/dist/agent-chat/composer.test.d.ts +0 -2
  723. package/dist/agent-chat/composer.test.d.ts.map +0 -1
  724. package/dist/agent-chat/relative-time.test.d.ts +0 -2
  725. package/dist/agent-chat/relative-time.test.d.ts.map +0 -1
  726. package/dist/agent-chat/thread-feed-row.test.d.ts +0 -2
  727. package/dist/agent-chat/thread-feed-row.test.d.ts.map +0 -1
  728. package/dist/agent-chat/thread-feed.test.d.ts +0 -2
  729. package/dist/agent-chat/thread-feed.test.d.ts.map +0 -1
  730. package/dist/agent-chat/thread-message.test.d.ts +0 -2
  731. package/dist/agent-chat/thread-message.test.d.ts.map +0 -1
  732. package/dist/agent-chat/thread-workspace.test.d.ts +0 -2
  733. package/dist/agent-chat/thread-workspace.test.d.ts.map +0 -1
  734. package/dist/agent-chat/tool-chip.test.d.ts +0 -2
  735. package/dist/agent-chat/tool-chip.test.d.ts.map +0 -1
  736. package/dist/agent-chat/virtualize.type-guard.test.d.ts +0 -2
  737. package/dist/agent-chat/virtualize.type-guard.test.d.ts.map +0 -1
  738. package/dist/charts/cursor/resolve.test.d.ts +0 -2
  739. package/dist/charts/cursor/resolve.test.d.ts.map +0 -1
  740. package/dist/charts/cursor/store.test.d.ts +0 -2
  741. package/dist/charts/cursor/store.test.d.ts.map +0 -1
  742. package/dist/charts/kinds/BandStrip.test.d.ts +0 -2
  743. package/dist/charts/kinds/BandStrip.test.d.ts.map +0 -1
  744. package/dist/charts/kinds/Bars.test.d.ts +0 -2
  745. package/dist/charts/kinds/Bars.test.d.ts.map +0 -1
  746. package/dist/charts/kinds/DualPanel.test.d.ts +0 -2
  747. package/dist/charts/kinds/DualPanel.test.d.ts.map +0 -1
  748. package/dist/charts/kinds/MirroredBars.test.d.ts +0 -2
  749. package/dist/charts/kinds/MirroredBars.test.d.ts.map +0 -1
  750. package/dist/charts/kinds/MultiLine.test.d.ts +0 -2
  751. package/dist/charts/kinds/MultiLine.test.d.ts.map +0 -1
  752. package/dist/charts/kinds/StackedArea.test.d.ts +0 -2
  753. package/dist/charts/kinds/StackedArea.test.d.ts.map +0 -1
  754. package/dist/charts/kinds/ZonedLine.test.d.ts +0 -2
  755. package/dist/charts/kinds/ZonedLine.test.d.ts.map +0 -1
  756. package/dist/charts/layout/auto-margin.test.d.ts +0 -2
  757. package/dist/charts/layout/auto-margin.test.d.ts.map +0 -1
  758. package/dist/charts/primitives/CartesianChart.test.d.ts +0 -2
  759. package/dist/charts/primitives/CartesianChart.test.d.ts.map +0 -1
  760. package/dist/charts/primitives/ChartCard.test.d.ts +0 -2
  761. package/dist/charts/primitives/ChartCard.test.d.ts.map +0 -1
  762. package/dist/charts/primitives/ChartFrame.test.d.ts +0 -2
  763. package/dist/charts/primitives/ChartFrame.test.d.ts.map +0 -1
  764. package/dist/charts/primitives/ChartLegend.test.d.ts +0 -2
  765. package/dist/charts/primitives/ChartLegend.test.d.ts.map +0 -1
  766. package/dist/charts/primitives/ChartTooltip.test.d.ts +0 -2
  767. package/dist/charts/primitives/ChartTooltip.test.d.ts.map +0 -1
  768. package/dist/charts/primitives/XZoneRects.test.d.ts +0 -2
  769. package/dist/charts/primitives/XZoneRects.test.d.ts.map +0 -1
  770. package/dist/charts/series.test.d.ts +0 -2
  771. package/dist/charts/series.test.d.ts.map +0 -1
  772. package/dist/charts/utils/domain.test.d.ts +0 -2
  773. package/dist/charts/utils/domain.test.d.ts.map +0 -1
  774. package/dist/charts/utils/measure-text.test.d.ts +0 -2
  775. package/dist/charts/utils/measure-text.test.d.ts.map +0 -1
  776. package/dist/cli/check-coverage.test.d.ts +0 -2
  777. package/dist/cli/check-coverage.test.d.ts.map +0 -1
  778. package/dist/cli/check-theme.test.d.ts +0 -2
  779. package/dist/cli/check-theme.test.d.ts.map +0 -1
  780. package/dist/cli/help.test.d.ts +0 -2
  781. package/dist/cli/help.test.d.ts.map +0 -1
  782. package/dist/cli/init-sync.test.d.ts +0 -2
  783. package/dist/cli/init-sync.test.d.ts.map +0 -1
  784. package/dist/cli/placement-engine.test.d.ts +0 -2
  785. package/dist/cli/placement-engine.test.d.ts.map +0 -1
  786. package/dist/cli/shipped-versions.test.d.ts +0 -2
  787. package/dist/cli/shipped-versions.test.d.ts.map +0 -1
  788. package/dist/cli/tarball-parity.test.d.ts +0 -2
  789. package/dist/cli/tarball-parity.test.d.ts.map +0 -1
  790. package/dist/cli/template-format.test.d.ts +0 -2
  791. package/dist/cli/template-format.test.d.ts.map +0 -1
  792. package/dist/cli/template-ledger.test.d.ts +0 -2
  793. package/dist/cli/template-ledger.test.d.ts.map +0 -1
  794. package/dist/cli/tokens-css.test.d.ts +0 -2
  795. package/dist/cli/tokens-css.test.d.ts.map +0 -1
  796. package/dist/cli/toolchain-wiring.test.d.ts +0 -2
  797. package/dist/cli/toolchain-wiring.test.d.ts.map +0 -1
  798. package/dist/cli/waiver-audit.test.d.ts +0 -2
  799. package/dist/cli/waiver-audit.test.d.ts.map +0 -1
  800. package/dist/content/article-actions.test.d.ts +0 -2
  801. package/dist/content/article-actions.test.d.ts.map +0 -1
  802. package/dist/content/article-model.test.d.ts +0 -2
  803. package/dist/content/article-model.test.d.ts.map +0 -1
  804. package/dist/content/block-split.test.d.ts +0 -2
  805. package/dist/content/block-split.test.d.ts.map +0 -1
  806. package/dist/content/heading-components.test.d.ts +0 -2
  807. package/dist/content/heading-components.test.d.ts.map +0 -1
  808. package/dist/content/markdown.test.d.ts +0 -2
  809. package/dist/content/markdown.test.d.ts.map +0 -1
  810. package/dist/content/prose.module.css.test.d.ts +0 -2
  811. package/dist/content/prose.module.css.test.d.ts.map +0 -1
  812. package/dist/content/sanitize.test.d.ts +0 -2
  813. package/dist/content/sanitize.test.d.ts.map +0 -1
  814. package/dist/content/slug.test.d.ts +0 -2
  815. package/dist/content/slug.test.d.ts.map +0 -1
  816. package/dist/controls/actions.test.d.ts +0 -2
  817. package/dist/controls/actions.test.d.ts.map +0 -1
  818. package/dist/controls/actions.type-guard.test.d.ts +0 -2
  819. package/dist/controls/actions.type-guard.test.d.ts.map +0 -1
  820. package/dist/controls/control-group.test.d.ts +0 -2
  821. package/dist/controls/control-group.test.d.ts.map +0 -1
  822. package/dist/controls/controls.router.test.d.ts +0 -2
  823. package/dist/controls/controls.router.test.d.ts.map +0 -1
  824. package/dist/controls/filter-set.test.d.ts +0 -2
  825. package/dist/controls/filter-set.test.d.ts.map +0 -1
  826. package/dist/controls/peer-boundary.test.d.ts +0 -2
  827. package/dist/controls/peer-boundary.test.d.ts.map +0 -1
  828. package/dist/controls/props-contract.test.d.ts +0 -2
  829. package/dist/controls/props-contract.test.d.ts.map +0 -1
  830. package/dist/controls/sync-button.test.d.ts +0 -2
  831. package/dist/controls/sync-button.test.d.ts.map +0 -1
  832. package/dist/dashboard/query-state.test.d.ts +0 -2
  833. package/dist/dashboard/query-state.test.d.ts.map +0 -1
  834. package/dist/dashboard/settings-section.test.d.ts +0 -2
  835. package/dist/dashboard/settings-section.test.d.ts.map +0 -1
  836. package/dist/dashboard/stat-card.test.d.ts +0 -2
  837. package/dist/dashboard/stat-card.test.d.ts.map +0 -1
  838. package/dist/data/data-table.test.d.ts +0 -2
  839. package/dist/data/data-table.test.d.ts.map +0 -1
  840. package/dist/guard/check-source.test.d.ts +0 -2
  841. package/dist/guard/check-source.test.d.ts.map +0 -1
  842. package/dist/guard/grace.test.d.ts +0 -20
  843. package/dist/guard/grace.test.d.ts.map +0 -1
  844. package/dist/guard/guard-hook.test.d.ts +0 -2
  845. package/dist/guard/guard-hook.test.d.ts.map +0 -1
  846. package/dist/provider/index.test.d.ts +0 -2
  847. package/dist/provider/index.test.d.ts.map +0 -1
  848. package/dist/provider/lab-theme.test.d.ts +0 -2
  849. package/dist/provider/lab-theme.test.d.ts.map +0 -1
  850. package/dist/query/error-message.test.d.ts +0 -2
  851. package/dist/query/error-message.test.d.ts.map +0 -1
  852. package/dist/router-tanstack/multi-search-param-store.test.d.ts +0 -2
  853. package/dist/router-tanstack/multi-search-param-store.test.d.ts.map +0 -1
  854. package/dist/router-tanstack/nav.test.d.ts +0 -2
  855. package/dist/router-tanstack/nav.test.d.ts.map +0 -1
  856. package/dist/router-tanstack/search-param-store.test.d.ts +0 -2
  857. package/dist/router-tanstack/search-param-store.test.d.ts.map +0 -1
  858. package/dist/router-tanstack/search-store.router.test.d.ts +0 -2
  859. package/dist/router-tanstack/search-store.router.test.d.ts.map +0 -1
  860. package/dist/router-tanstack/search-store.test.d.ts +0 -2
  861. package/dist/router-tanstack/search-store.test.d.ts.map +0 -1
  862. package/dist/router-tanstack/use-nav.test.d.ts +0 -2
  863. package/dist/router-tanstack/use-nav.test.d.ts.map +0 -1
  864. package/dist/section/section.test.d.ts +0 -2
  865. package/dist/section/section.test.d.ts.map +0 -1
  866. package/dist/shell/app-mobile-nav.test.d.ts +0 -2
  867. package/dist/shell/app-mobile-nav.test.d.ts.map +0 -1
  868. package/dist/shell/app-sidebar.test.d.ts +0 -2
  869. package/dist/shell/app-sidebar.test.d.ts.map +0 -1
  870. package/dist/shell/index.test.d.ts +0 -2
  871. package/dist/shell/index.test.d.ts.map +0 -1
  872. package/dist/shell/mobile-nav-model.test.d.ts +0 -2
  873. package/dist/shell/mobile-nav-model.test.d.ts.map +0 -1
  874. package/dist/shell/page-bar.test.d.ts +0 -2
  875. package/dist/shell/page-bar.test.d.ts.map +0 -1
  876. package/dist/state/fields.test.d.ts +0 -2
  877. package/dist/state/fields.test.d.ts.map +0 -1
  878. package/dist/styles.floor.test.d.ts +0 -2
  879. package/dist/styles.floor.test.d.ts.map +0 -1
  880. package/dist/theme/border-coverage.test.d.ts +0 -18
  881. package/dist/theme/border-coverage.test.d.ts.map +0 -1
  882. package/dist/theme/contrast.test.d.ts +0 -2
  883. package/dist/theme/contrast.test.d.ts.map +0 -1
  884. package/dist/theme/ctl-theme.test.d.ts +0 -2
  885. package/dist/theme/ctl-theme.test.d.ts.map +0 -1
  886. package/dist/theme/ctl-tier-coverage.test.d.ts +0 -2
  887. package/dist/theme/ctl-tier-coverage.test.d.ts.map +0 -1
  888. package/dist/theme/density-option.test.d.ts +0 -2
  889. package/dist/theme/density-option.test.d.ts.map +0 -1
  890. package/dist/theme/density-relations.test.d.ts +0 -2
  891. package/dist/theme/density-relations.test.d.ts.map +0 -1
  892. package/dist/theme/derive-theme.test.d.ts +0 -2
  893. package/dist/theme/derive-theme.test.d.ts.map +0 -1
  894. package/dist/theme/divider-law.test.d.ts +0 -2
  895. package/dist/theme/divider-law.test.d.ts.map +0 -1
  896. package/dist/theme/fonts-option.test.d.ts +0 -2
  897. package/dist/theme/fonts-option.test.d.ts.map +0 -1
  898. package/dist/theme/icon-slot.test.d.ts +0 -2
  899. package/dist/theme/icon-slot.test.d.ts.map +0 -1
  900. package/dist/theme/layout-rhythm-css.test.d.ts +0 -2
  901. package/dist/theme/layout-rhythm-css.test.d.ts.map +0 -1
  902. package/dist/theme/radius-option.test.d.ts +0 -2
  903. package/dist/theme/radius-option.test.d.ts.map +0 -1
  904. package/dist/theme/radius.test.d.ts +0 -2
  905. package/dist/theme/radius.test.d.ts.map +0 -1
  906. package/dist/theme/shadow-surfaces.test.d.ts +0 -26
  907. package/dist/theme/shadow-surfaces.test.d.ts.map +0 -1
  908. package/dist/theme/spacing.test.d.ts +0 -2
  909. package/dist/theme/spacing.test.d.ts.map +0 -1
  910. package/dist/theme/use-basalt-spacing.test.d.ts +0 -2
  911. package/dist/theme/use-basalt-spacing.test.d.ts.map +0 -1
  912. package/dist/theme-lab/derive-controls.test.d.ts +0 -2
  913. package/dist/theme-lab/derive-controls.test.d.ts.map +0 -1
  914. package/dist/theme-lab/derive-state.test.d.ts +0 -2
  915. package/dist/theme-lab/derive-state.test.d.ts.map +0 -1
  916. package/dist/theme-lab/theme-lab.test.d.ts +0 -2
  917. package/dist/theme-lab/theme-lab.test.d.ts.map +0 -1
  918. package/dist/tokens/build-fonts-css.test.d.ts +0 -2
  919. package/dist/tokens/build-fonts-css.test.d.ts.map +0 -1
  920. package/dist/tokens/build-radius-css.test.d.ts +0 -2
  921. package/dist/tokens/build-radius-css.test.d.ts.map +0 -1
  922. package/dist/tokens/chart-margin.test.d.ts +0 -2
  923. package/dist/tokens/chart-margin.test.d.ts.map +0 -1
  924. package/dist/tokens/density.test.d.ts +0 -2
  925. package/dist/tokens/density.test.d.ts.map +0 -1
  926. package/dist/tokens/derive-radius.test.d.ts +0 -2
  927. package/dist/tokens/derive-radius.test.d.ts.map +0 -1
  928. package/dist/tokens/derive.test.d.ts +0 -2
  929. package/dist/tokens/derive.test.d.ts.map +0 -1
  930. package/dist/tokens/palette.test.d.ts +0 -2
  931. package/dist/tokens/palette.test.d.ts.map +0 -1
  932. package/dist/tokens/text-scale.test.d.ts +0 -2
  933. package/dist/tokens/text-scale.test.d.ts.map +0 -1
  934. package/dist/vite-color-mix.test.d.ts +0 -2
  935. package/dist/vite-color-mix.test.d.ts.map +0 -1
  936. package/dist/vite.test.d.ts +0 -2
  937. package/dist/vite.test.d.ts.map +0 -1
  938. package/dist/widget-header/delta-badge.test.d.ts +0 -2
  939. package/dist/widget-header/delta-badge.test.d.ts.map +0 -1
  940. package/dist/widget-header/no-mantine.test.d.ts +0 -2
  941. package/dist/widget-header/no-mantine.test.d.ts.map +0 -1
  942. package/dist/widget-header/widget-header.test.d.ts +0 -2
  943. package/dist/widget-header/widget-header.test.d.ts.map +0 -1
  944. package/src/agent/adapter.test.ts +0 -1640
  945. package/src/agent/ai-sdk-transport.test.ts +0 -658
  946. package/src/agent/coalesce.test.ts +0 -387
  947. package/src/agent/foreign.test.ts +0 -51
  948. package/src/agent/id.test.ts +0 -169
  949. package/src/agent/merge.test.ts +0 -206
  950. package/src/agent/part-list.test.tsx +0 -112
  951. package/src/agent/parts.test.ts +0 -720
  952. package/src/agent/thread.test.ts +0 -220
  953. package/src/agent/transport.test.ts +0 -70
  954. package/src/agent/use-agent-stream.test.tsx +0 -287
  955. package/src/agent/use-agent-thread-runs.foreign.test.tsx +0 -138
  956. package/src/agent/use-agent-thread-runs.resume.test.tsx +0 -294
  957. package/src/agent/use-agent-thread-runs.test.tsx +0 -1120
  958. package/src/agent/use-agent-thread-runs.wedge.test.tsx +0 -387
  959. package/src/agent-chat/composer.test.tsx +0 -924
  960. package/src/agent-chat/relative-time.test.ts +0 -95
  961. package/src/agent-chat/thread-feed-row.test.tsx +0 -510
  962. package/src/agent-chat/thread-feed.test.tsx +0 -241
  963. package/src/agent-chat/thread-message.test.tsx +0 -1285
  964. package/src/agent-chat/thread-workspace.test.tsx +0 -169
  965. package/src/agent-chat/tool-chip.test.tsx +0 -139
  966. package/src/agent-chat/virtualize.type-guard.test.ts +0 -49
  967. package/src/charts/cursor/resolve.test.ts +0 -151
  968. package/src/charts/cursor/store.test.ts +0 -64
  969. package/src/charts/kinds/BandStrip.test.tsx +0 -282
  970. package/src/charts/kinds/Bars.test.tsx +0 -183
  971. package/src/charts/kinds/DualPanel.test.tsx +0 -527
  972. package/src/charts/kinds/MirroredBars.test.tsx +0 -232
  973. package/src/charts/kinds/MultiLine.test.tsx +0 -218
  974. package/src/charts/kinds/StackedArea.test.tsx +0 -114
  975. package/src/charts/kinds/ZonedLine.test.tsx +0 -147
  976. package/src/charts/layout/auto-margin.test.ts +0 -42
  977. package/src/charts/primitives/CartesianChart.test.tsx +0 -647
  978. package/src/charts/primitives/ChartCard.test.tsx +0 -66
  979. package/src/charts/primitives/ChartFrame.test.tsx +0 -142
  980. package/src/charts/primitives/ChartLegend.test.tsx +0 -78
  981. package/src/charts/primitives/ChartTooltip.test.tsx +0 -44
  982. package/src/charts/primitives/XZoneRects.test.tsx +0 -123
  983. package/src/charts/series.test.ts +0 -112
  984. package/src/charts/utils/domain.test.ts +0 -54
  985. package/src/charts/utils/measure-text.test.ts +0 -36
  986. package/src/cli/check-coverage.test.ts +0 -297
  987. package/src/cli/check-theme.test.ts +0 -837
  988. package/src/cli/help.test.ts +0 -170
  989. package/src/cli/init-sync.test.ts +0 -343
  990. package/src/cli/placement-engine.test.ts +0 -298
  991. package/src/cli/shipped-versions.test.ts +0 -83
  992. package/src/cli/tarball-parity.test.ts +0 -44
  993. package/src/cli/template-format.test.ts +0 -64
  994. package/src/cli/template-ledger.test.ts +0 -219
  995. package/src/cli/tokens-css.test.ts +0 -249
  996. package/src/cli/toolchain-wiring.test.ts +0 -1358
  997. package/src/cli/waiver-audit.test.ts +0 -215
  998. package/src/content/article-actions.test.ts +0 -78
  999. package/src/content/article-model.test.ts +0 -119
  1000. package/src/content/block-split.test.ts +0 -75
  1001. package/src/content/heading-components.test.tsx +0 -65
  1002. package/src/content/markdown.test.tsx +0 -603
  1003. package/src/content/prose.module.css.test.ts +0 -39
  1004. package/src/content/sanitize.test.ts +0 -659
  1005. package/src/content/slug.test.ts +0 -62
  1006. package/src/controls/actions.test.tsx +0 -252
  1007. package/src/controls/actions.type-guard.test.ts +0 -63
  1008. package/src/controls/control-group.test.tsx +0 -229
  1009. package/src/controls/controls.router.test.tsx +0 -637
  1010. package/src/controls/filter-set.test.tsx +0 -472
  1011. package/src/controls/peer-boundary.test.ts +0 -85
  1012. package/src/controls/props-contract.test.tsx +0 -106
  1013. package/src/controls/sync-button.test.tsx +0 -183
  1014. package/src/dashboard/query-state.test.tsx +0 -152
  1015. package/src/dashboard/settings-section.test.tsx +0 -56
  1016. package/src/dashboard/stat-card.test.tsx +0 -154
  1017. package/src/data/data-table.test.tsx +0 -434
  1018. package/src/guard/check-source.test.ts +0 -3355
  1019. package/src/guard/grace.test.ts +0 -149
  1020. package/src/guard/guard-hook.test.ts +0 -203
  1021. package/src/provider/index.test.tsx +0 -101
  1022. package/src/provider/lab-theme.test.ts +0 -147
  1023. package/src/query/error-message.test.ts +0 -67
  1024. package/src/router-tanstack/multi-search-param-store.test.ts +0 -124
  1025. package/src/router-tanstack/nav.test.ts +0 -111
  1026. package/src/router-tanstack/search-param-store.test.ts +0 -135
  1027. package/src/router-tanstack/search-store.router.test.tsx +0 -661
  1028. package/src/router-tanstack/search-store.test.ts +0 -418
  1029. package/src/router-tanstack/use-nav.test.tsx +0 -187
  1030. package/src/section/section.test.tsx +0 -204
  1031. package/src/shell/app-mobile-nav.test.tsx +0 -403
  1032. package/src/shell/app-sidebar.test.tsx +0 -509
  1033. package/src/shell/index.test.tsx +0 -428
  1034. package/src/shell/mobile-nav-model.test.ts +0 -517
  1035. package/src/shell/page-bar.test.tsx +0 -316
  1036. package/src/state/fields.test.tsx +0 -258
  1037. package/src/styles.floor.test.ts +0 -36
  1038. package/src/theme/border-coverage.test.ts +0 -272
  1039. package/src/theme/contrast.test.ts +0 -354
  1040. package/src/theme/ctl-theme.test.tsx +0 -275
  1041. package/src/theme/ctl-tier-coverage.test.ts +0 -170
  1042. package/src/theme/density-option.test.ts +0 -96
  1043. package/src/theme/density-relations.test.ts +0 -506
  1044. package/src/theme/derive-theme.test.ts +0 -101
  1045. package/src/theme/divider-law.test.ts +0 -259
  1046. package/src/theme/fonts-option.test.ts +0 -75
  1047. package/src/theme/icon-slot.test.tsx +0 -275
  1048. package/src/theme/layout-rhythm-css.test.ts +0 -72
  1049. package/src/theme/radius-option.test.ts +0 -86
  1050. package/src/theme/radius.test.ts +0 -142
  1051. package/src/theme/shadow-surfaces.test.ts +0 -488
  1052. package/src/theme/spacing.test.ts +0 -495
  1053. package/src/theme/use-basalt-spacing.test.tsx +0 -55
  1054. package/src/theme-lab/derive-controls.test.ts +0 -94
  1055. package/src/theme-lab/derive-state.test.ts +0 -71
  1056. package/src/theme-lab/theme-lab.test.ts +0 -46
  1057. package/src/tokens/build-fonts-css.test.ts +0 -52
  1058. package/src/tokens/build-radius-css.test.ts +0 -25
  1059. package/src/tokens/chart-margin.test.ts +0 -39
  1060. package/src/tokens/density.test.ts +0 -259
  1061. package/src/tokens/derive-radius.test.ts +0 -62
  1062. package/src/tokens/derive.test.ts +0 -30
  1063. package/src/tokens/palette.test.ts +0 -114
  1064. package/src/tokens/text-scale.test.ts +0 -51
  1065. package/src/vite-color-mix.test.ts +0 -46
  1066. package/src/vite.test.ts +0 -423
  1067. package/src/widget-header/delta-badge.test.tsx +0 -60
  1068. package/src/widget-header/no-mantine.test.ts +0 -33
  1069. package/src/widget-header/widget-header.test.tsx +0 -187
@@ -0,0 +1,212 @@
1
+ /**
2
+ * Pure, DOM-free layout math behind `ChartFrame`'s plot/legend split — extracted so the arithmetic
3
+ * is testable without a `ResizeObserver` and `ChartFrame.tsx` stays the measuring/rendering shell.
4
+ */
5
+
6
+ import { VX } from '../../tokens'
7
+ import type { ChartMargin } from '../../tokens'
8
+ import type { LegendEntry } from './ChartLegend'
9
+ import { measureText } from '../utils/measure-text'
10
+
11
+ /** Line box of one legend row at `VX.legendFontSize`. */
12
+ const LEGEND_LINE_H = Math.ceil(VX.legendFontSize * 1.35)
13
+ /** `ChartLegend`'s own vertical wrapper padding (`8px 0 2px`). */
14
+ const LEGEND_PAD_Y = 10
15
+ /** Swatch plus the gap to its label — the fixed part of a legend entry's width. */
16
+ const LEGEND_SWATCH_W = 24
17
+
18
+ /**
19
+ * The two size tiers a chart resolves to. There are exactly two, and there is no `tablet`: the
20
+ * tier exists to answer "is there room for full-size chrome around the plot", which is a yes/no
21
+ * question, and a third rung would need a third calibrated metric set nothing has asked for.
22
+ */
23
+ export type ChartTier = 'phone' | 'desktop'
24
+
25
+ /**
26
+ * The tier a chart's chrome resolves to, from the width of the box it was MEASURED in — never
27
+ * from a media query.
28
+ *
29
+ * A viewport breakpoint answers the wrong question. A chart in a 2-column grid cell on a 1440px
30
+ * desktop is exactly as narrow as one filling a phone, and `@media` cannot see that; the
31
+ * `ResizeObserver` `ChartFrame` already runs can. It also keeps this file (and the whole chart
32
+ * layer) Mantine-free — `theme.breakpoints` is on the coupled side of the boundary.
33
+ *
34
+ * An UNMEASURED box (`containerW <= 0` — SSR, or before the observer's first callback) resolves
35
+ * to `'desktop'`: the first frame must not paint phone chrome that then re-lays-out one frame
36
+ * later, and `resolvePlotRect` already treats an unmeasured width as the first-frame case.
37
+ */
38
+ export function resolveChartTier(containerW: number): ChartTier {
39
+ return containerW > 0 && containerW < VX.phoneChartWidth ? 'phone' : 'desktop'
40
+ }
41
+
42
+ /**
43
+ * How much of `VX.margin` a phone-tier chart keeps as its FLOOR. The measured law is unchanged —
44
+ * a side may still only grow past its floor (`autoMargin`) — this only stops a static token from
45
+ * spending 44px of a 360px chart on a gutter three characters wide.
46
+ */
47
+ const PHONE_MARGIN_SCALE = 0.75
48
+
49
+ /** Phone-tier crosshair dot radius. One step in, so the marker still reads as a punched hole at
50
+ * the smaller stroke widths a narrow chart draws. */
51
+ const PHONE_DOT_R = Math.max(VX.dotR - 1, 2)
52
+
53
+ /** Legend entries a phone-tier legend renders before rolling the rest into `+N more`. Two is the
54
+ * cap because a third entry wraps at every realistic phone width, and a wrapped legend is what
55
+ * eats the plot (`legendEntryCap`). */
56
+ const PHONE_LEGEND_MAX_ROWS = 2
57
+
58
+ /** Tooltip `minWidth`, per tier — 140px is 39% of a 360px screen. */
59
+ const TOOLTIP_MIN_WIDTH = { desktop: 140, phone: 110 } as const
60
+
61
+ /** Every size a chart's chrome resolves per tier. One object so a new tier-sensitive size is added
62
+ * in one place and read by name, rather than each primitive branching on the tier itself. */
63
+ export type ChartTierMetrics = {
64
+ /** Which tier these are, so a consumer of the metrics never needs both values threaded. */
65
+ tier: ChartTier
66
+ /** Axis tick label font size, px. Threaded into BOTH `autoMargin`'s measurement and the painted
67
+ * axis — measured labels must be the painted labels (`docs/CHARTS-SPEC.md` §1). */
68
+ axisFont: number
69
+ /** Legend label font size, px. */
70
+ legendFontSize: number
71
+ /** Crosshair dot radius, px. */
72
+ dotR: number
73
+ /** Floating tooltip `minWidth`, px. */
74
+ tooltipMinWidth: number
75
+ /** Default entry cap on the legend, or `undefined` for no default cap. An explicit
76
+ * `legend.maxRows` still wins as the upper bound. */
77
+ legendMaxRows: number | undefined
78
+ /** Per-side margin FLOORS (`VX.margin` is a floor, never a ceiling — §1). */
79
+ margin: ChartMargin
80
+ }
81
+
82
+ const DESKTOP_METRICS: ChartTierMetrics = {
83
+ tier: 'desktop',
84
+ axisFont: VX.axisFont,
85
+ legendFontSize: VX.legendFontSize,
86
+ dotR: VX.dotR,
87
+ tooltipMinWidth: TOOLTIP_MIN_WIDTH.desktop,
88
+ legendMaxRows: undefined,
89
+ margin: VX.margin,
90
+ }
91
+
92
+ const PHONE_METRICS: ChartTierMetrics = {
93
+ tier: 'phone',
94
+ // One step DOWN the shared type ladder, never an arbitrary px value: micro → nano for ticks,
95
+ // sm → xs for the legend (`TEXT` in tokens/index.ts).
96
+ axisFont: VX.text.nano,
97
+ legendFontSize: VX.text.xs,
98
+ dotR: PHONE_DOT_R,
99
+ tooltipMinWidth: TOOLTIP_MIN_WIDTH.phone,
100
+ legendMaxRows: PHONE_LEGEND_MAX_ROWS,
101
+ margin: {
102
+ top: Math.round(VX.margin.top * PHONE_MARGIN_SCALE),
103
+ right: Math.round(VX.margin.right * PHONE_MARGIN_SCALE),
104
+ bottom: Math.round(VX.margin.bottom * PHONE_MARGIN_SCALE),
105
+ left: Math.round(VX.margin.left * PHONE_MARGIN_SCALE),
106
+ },
107
+ }
108
+
109
+ /** The resolved sizes for one tier. Frozen module constants — never a new object per render. */
110
+ export function chartTierMetrics(tier: ChartTier): ChartTierMetrics {
111
+ return tier === 'phone' ? PHONE_METRICS : DESKTOP_METRICS
112
+ }
113
+
114
+ /**
115
+ * Resolve the plot rect from the measured box and the measured legend band. Pure and exported so
116
+ * the two floors below are testable without a `ResizeObserver`.
117
+ *
118
+ * Two floors, and each is only a floor while it is honest:
119
+ * - **width** — `minWidth` is a FIRST-FRAME guard, applied only while `containerW` is still 0
120
+ * (unmeasured, or SSR, where the observer never fires). Once measured the plot tracks the box
121
+ * exactly, floored at 1 so no scale divides by zero: applying a 200px floor forever drew an SVG
122
+ * wider than its own container inside any narrower grid cell.
123
+ * - **height** — the legend band is subtracted first (it always was), but the remainder can no
124
+ * longer collapse: eight entries wrapping to five rows at phone width ate a fixed
125
+ * `height={240}` toward zero and the body stopped rendering entirely. The plot stops at
126
+ * `VX.minPlotHeight` and the frame's own box grows by the difference instead — it is a flex
127
+ * column with `height: auto`, so that growth is automatic. Under `fill` the box CANNOT grow, so
128
+ * the legend is capped instead ({@link legendEntryCap}). An unmeasured box (`resolvedHeight <=
129
+ * 0`, i.e. a `fill` frame before its first measurement) stays at 0 and renders nothing, exactly
130
+ * as before — the floor must never invent a height for a box nobody has measured.
131
+ */
132
+ export function resolvePlotRect(input: {
133
+ containerW: number
134
+ resolvedHeight: number
135
+ minWidth: number
136
+ sideLegendWidth: number
137
+ topBottomLegendHeight: number
138
+ }): { width: number; height: number } {
139
+ const { containerW, resolvedHeight, minWidth, sideLegendWidth, topBottomLegendHeight } = input
140
+ return {
141
+ width: containerW === 0 ? minWidth : Math.max(containerW - sideLegendWidth, 1),
142
+ height:
143
+ resolvedHeight <= 0 ? 0 : Math.max(resolvedHeight - topBottomLegendHeight, VX.minPlotHeight),
144
+ }
145
+ }
146
+
147
+ /** Height of a legend band `rows` rows tall, wrapper padding included. */
148
+ const legendBandHeight = (rows: number): number =>
149
+ LEGEND_PAD_Y + rows * LEGEND_LINE_H + Math.max(rows - 1, 0) * VX.legendGap
150
+
151
+ /** Width one legend entry occupies — swatch, gap, label, and the note that rides after it. */
152
+ const legendEntryWidth = (item: LegendEntry): number =>
153
+ LEGEND_SWATCH_W +
154
+ measureText(
155
+ item.note === undefined ? item.label : `${item.label} ${item.note}`,
156
+ VX.legendFontSize,
157
+ )
158
+
159
+ /** How many of `items` fit in `rows` wrapped rows of `width` — the same greedy wrap the flex
160
+ * container performs, measured rather than assumed (`docs/CHARTS-SPEC.md` §1). */
161
+ function entriesWithinRows(items: readonly LegendEntry[], width: number, rows: number): number {
162
+ let row = 1
163
+ let x = 0
164
+ let fitted = 0
165
+ for (const item of items) {
166
+ const w = legendEntryWidth(item)
167
+ const next = x === 0 ? w : x + VX.legendGap + w
168
+ if (next > width && x > 0) {
169
+ row += 1
170
+ if (row > rows) return fitted
171
+ x = w
172
+ } else {
173
+ x = next
174
+ }
175
+ fitted += 1
176
+ }
177
+ return fitted
178
+ }
179
+
180
+ /**
181
+ * The entry cap a `fill` frame's legend must respect so the plot keeps `VX.minPlotHeight`.
182
+ *
183
+ * A fixed-height frame grows to fit its legend; a `fill` frame is pinned to its cell, so the only
184
+ * remaining lever is `ChartLegend`'s `maxRows` rollup (an ENTRY cap — see its JSDoc). The rows the
185
+ * legend may take follow from the height left over; how many entries that is follows from
186
+ * MEASURING the labels, not from assuming one entry per row — otherwise a five-entry legend that
187
+ * fits on one line would roll up to `+2 more` in every 240px cell, moving rendering for charts
188
+ * that never had the bug. Returns `undefined` when the whole legend already fits.
189
+ */
190
+ export function legendEntryCap(input: {
191
+ items: readonly LegendEntry[]
192
+ containerW: number
193
+ /** Frame height the legend may consume — `resolvedHeight - VX.minPlotHeight`. */
194
+ available: number
195
+ /** An explicit caller cap always wins as the upper bound. */
196
+ callerMaxRows?: number
197
+ }): number | undefined {
198
+ const { items, containerW, available, callerMaxRows } = input
199
+ if (containerW <= 0 || items.length === 0) return callerMaxRows
200
+ const rows = Math.max(
201
+ 1,
202
+ Math.floor((available - LEGEND_PAD_Y + VX.legendGap) / (LEGEND_LINE_H + VX.legendGap)),
203
+ )
204
+ if (
205
+ legendBandHeight(rows) <= available &&
206
+ entriesWithinRows(items, containerW, rows) >= items.length
207
+ ) {
208
+ return callerMaxRows
209
+ }
210
+ const fitted = Math.max(1, entriesWithinRows(items, containerW, rows))
211
+ return callerMaxRows === undefined ? fitted : Math.min(fitted, callerMaxRows)
212
+ }
@@ -0,0 +1,37 @@
1
+ import { createContext, useContext } from 'react'
2
+ import type { ReactNode } from 'react'
3
+ import { chartTierMetrics, resolveChartTier } from './chart-frame-layout'
4
+ import type { ChartTier, ChartTierMetrics } from './chart-frame-layout'
5
+
6
+ /**
7
+ * Ambient chart tier. `ChartFrame` publishes the tier it resolved from its own MEASURED width;
8
+ * the axes, the legend, the crosshair dots and the tooltip read it back without every kind having
9
+ * to thread a prop it does not otherwise care about.
10
+ *
11
+ * Default `'desktop'`, so a primitive rendered outside a `ChartFrame` (a hand-composed plot, a
12
+ * `TooltipRow` in a consumer's own tooltip) keeps exactly today's sizes.
13
+ */
14
+ const ChartTierContext = createContext<ChartTier>('desktop')
15
+
16
+ export type ChartTierProviderProps = {
17
+ tier: ChartTier
18
+ children: ReactNode
19
+ }
20
+
21
+ /** Publishes a resolved tier to the subtree. Mounted once, by `ChartFrame`. */
22
+ export function ChartTierProvider({ tier, children }: ChartTierProviderProps): ReactNode {
23
+ return <ChartTierContext.Provider value={tier}>{children}</ChartTierContext.Provider>
24
+ }
25
+
26
+ /** The tier of the nearest measured `ChartFrame`, or `'desktop'` outside one. */
27
+ export function useChartTier(): ChartTier {
28
+ return useContext(ChartTierContext)
29
+ }
30
+
31
+ /** The resolved sizes for the ambient tier — the form every primitive actually wants. */
32
+ export function useChartTierMetrics(): ChartTierMetrics {
33
+ return chartTierMetrics(useContext(ChartTierContext))
34
+ }
35
+
36
+ export { chartTierMetrics, resolveChartTier }
37
+ export type { ChartTier, ChartTierMetrics }
@@ -7,6 +7,13 @@
7
7
  * share one definition.
8
8
  */
9
9
 
10
+ import {
11
+ curveLinear,
12
+ curveMonotoneX,
13
+ curveStep,
14
+ curveStepAfter,
15
+ curveStepBefore,
16
+ } from '@visx/curve'
10
17
  import type { LegendEntry } from './primitives/ChartLegend'
11
18
 
12
19
  /**
@@ -24,6 +31,43 @@ export type SeriesMark = 'line' | 'bar' | 'area'
24
31
  /** Only meaningful for `mark: 'line'`. */
25
32
  export type SeriesDash = 'solid' | 'dashed'
26
33
 
34
+ /**
35
+ * The interpolation between two plotted points. Named rather than a raw d3 `CurveFactory` so the
36
+ * set is closed, serializable, and identical across every kind — a chart cannot pick a curve the
37
+ * legend swatch and the sibling chart next to it do not also understand.
38
+ *
39
+ * - `monotone` (default, today's behaviour everywhere) — smoothed, overshoot-free.
40
+ * - `linear` — straight segments. The honest choice when the points are samples, not a signal.
41
+ * - `step` / `stepAfter` / `stepBefore` — the value HOLDS between samples and changes at one x.
42
+ * Reach for these when the quantity is piecewise-constant (a price tier, a config value, a
43
+ * discrete state): a smoothed curve through them draws intermediate values that never existed.
44
+ * `stepAfter` holds the value forward from its own x, `stepBefore` holds it back from the next,
45
+ * `step` changes at the midpoint.
46
+ */
47
+ export type SeriesCurve = 'monotone' | 'linear' | 'step' | 'stepAfter' | 'stepBefore'
48
+
49
+ /** d3's curve-factory shape, taken from a curve we already import rather than from
50
+ * `@visx/vendor/d3-shape` — that package is a transitive of `@visx/curve`, not one of the nine
51
+ * exact-pinned peers, so naming it in an import would add an undeclared dependency. */
52
+ type CurveFactory = typeof curveMonotoneX
53
+
54
+ const CURVES: Record<SeriesCurve, CurveFactory> = {
55
+ monotone: curveMonotoneX,
56
+ linear: curveLinear,
57
+ step: curveStep,
58
+ stepAfter: curveStepAfter,
59
+ stepBefore: curveStepBefore,
60
+ }
61
+
62
+ /**
63
+ * The d3 curve factory for a {@link SeriesCurve}. `undefined` resolves to `curveMonotoneX` — the
64
+ * value every kind hard-coded before this seam existed, so an omitted `curve` moves nothing.
65
+ * Exported for a hand-composed plot that draws its own `LinePath` from the same `series` array.
66
+ */
67
+ export function curveFor(curve?: SeriesCurve): CurveFactory {
68
+ return curve === undefined ? curveMonotoneX : CURVES[curve]
69
+ }
70
+
27
71
  /** Drives legend grouping/dividers. */
28
72
  export type SeriesRole = 'series' | 'overlay' | 'reference'
29
73
 
@@ -56,6 +100,12 @@ export type SeriesStyle = {
56
100
  mark: SeriesMark
57
101
  /** Default 'solid'. */
58
102
  dash?: SeriesDash
103
+ /**
104
+ * Interpolation between points for the line/area shapes this series draws. Default `'monotone'`
105
+ * — today's behaviour, unchanged, everywhere. See {@link SeriesCurve} for when a step curve is
106
+ * the honest one. Silently no-ops on `mark: 'bar'`, which has nothing to interpolate.
107
+ */
108
+ curve?: SeriesCurve
59
109
  /** Default VX.lineWidth (one width, everywhere). */
60
110
  strokeWidth?: number
61
111
  /** bar/area: the swatch honors this so it cannot lie. */
@@ -95,7 +145,12 @@ export type SeriesStyle = {
95
145
 
96
146
  /** Full descriptor = visual identity + data accessors. Generic over the point type. */
97
147
  export type ChartSeries<T> = SeriesStyle & {
98
- /** null = line gap + skipped tooltip row. */
148
+ /**
149
+ * null = an ABSENCE, never a zero: a real gap in the line/area (`defined`, not a straight
150
+ * interpolation across the hole) plus a skipped tooltip row and no crosshair dot. In a STACKED
151
+ * kind the absence is contagious — a band with no value leaves no cumulative total, so the whole
152
+ * stack gaps at that x (`StackedArea`'s JSDoc has the accounting).
153
+ */
99
154
  getValue: (d: T) => number | null
100
155
  /** Per-series override of the shared tooltip/value formatter. Receives the hovered datum
101
156
  * alongside the value so a row can read fields beyond the plotted number (e.g. `97.5 kg (92.5 ×
@@ -195,3 +250,24 @@ export function deriveTooltipRows<T>(
195
250
  }
196
251
  return rows
197
252
  }
253
+
254
+ /**
255
+ * Coerces a `ChartSeries.getValue` result into what a plotted point stores as its y: `null`,
256
+ * `undefined` and `NaN` all collapse to `null`, which downstream `definedOn` reads as a
257
+ * documented gap rather than a value to plot. Shared by `MultiLine`'s `seriesPoints` and
258
+ * `ZonedLine`'s `linePoints` — both used to reimplement this coercion independently.
259
+ */
260
+ export function toPlotPoint(v: number | null | undefined): number | null {
261
+ return v === null || v === undefined || Number.isNaN(v) ? null : v
262
+ }
263
+
264
+ /**
265
+ * A `defined` predicate for `LinePath`/`AreaClosed`/`Threshold`, bound to one y-scale. A null
266
+ * `__y` is a documented gap (`ChartSeries.getValue`), and a non-positive value on a log scale maps
267
+ * to `NaN` via the scale itself — without excluding both, d3's generators either draw an
268
+ * interpolated straight line across the hole or blank the entire path from that point on (SVG's
269
+ * `NaN` path-command handling). Shared by `MultiLine` and `ZonedLine`.
270
+ */
271
+ export function definedOn(scale: (y: number) => number): (d: { __y: number | null }) => boolean {
272
+ return (d) => d.__y !== null && Number.isFinite(scale(d.__y))
273
+ }
@@ -1,8 +1,9 @@
1
1
  import { scaleLinear } from '@visx/scale'
2
2
  import { useMemo } from 'react'
3
+ import type { BasaltProps } from '../../common/props'
3
4
  import { VX } from '../../tokens'
4
5
 
5
- type BarSparklineProps = {
6
+ export type BarSparklineProps = BasaltProps & {
6
7
  data: number[]
7
8
  width: number
8
9
  height: number
@@ -47,6 +48,8 @@ export function BarSparkline({
47
48
  emphasizeLast = false,
48
49
  emphasisColor,
49
50
  ariaLabel,
51
+ className,
52
+ style,
50
53
  }: BarSparklineProps) {
51
54
  const fillColor = color ?? VX.faint
52
55
  const lastColor = emphasisColor ?? VX.accent
@@ -57,14 +60,19 @@ export function BarSparkline({
57
60
  return scaleLinear<number>({ domain: [0, max], range: [0, height] })
58
61
  }, [data, height])
59
62
 
60
- if (!data.length) return <svg width={width} height={height} {...a11yProps} />
63
+ const rootProps = {
64
+ ...(className !== undefined && { className }),
65
+ ...(style !== undefined && { style }),
66
+ }
67
+
68
+ if (!data.length) return <svg width={width} height={height} {...rootProps} {...a11yProps} />
61
69
 
62
70
  const step = width / data.length
63
71
  const barWidth = Math.max(step - barGap, 1)
64
72
  const lastIndex = data.length - 1
65
73
 
66
74
  return (
67
- <svg width={width} height={height} {...a11yProps}>
75
+ <svg width={width} height={height} {...rootProps} {...a11yProps}>
68
76
  {data.map((v, i) => {
69
77
  const bh = Math.max(yScale(Math.max(v, 0)), 0)
70
78
  const isLast = emphasizeLast && i === lastIndex
@@ -3,9 +3,10 @@ import { Group } from '@visx/group'
3
3
  import { scaleLinear } from '@visx/scale'
4
4
  import { LinePath } from '@visx/shape'
5
5
  import { useMemo } from 'react'
6
+ import type { BasaltProps } from '../../common/props'
6
7
  import { VX } from '../../tokens'
7
8
 
8
- type LineSparklineProps = {
9
+ export type LineSparklineProps = BasaltProps & {
9
10
  data: number[]
10
11
  width: number
11
12
  height: number
@@ -18,7 +19,15 @@ type LineSparklineProps = {
18
19
  * Quiet single-hue trend line (docs/DESIGN-SPEC.md §5: "single 1.6px faint line, no fill, no
19
20
  * axes, no dots"). Sparklines default to `VX.faint`, not the bolder `VX.line` used by full charts.
20
21
  */
21
- export function LineSparkline({ data, width, height, color, ariaLabel }: LineSparklineProps) {
22
+ export function LineSparkline({
23
+ data,
24
+ width,
25
+ height,
26
+ color,
27
+ ariaLabel,
28
+ className,
29
+ style,
30
+ }: LineSparklineProps) {
22
31
  const strokeColor = color ?? VX.faint
23
32
  const a11yProps = ariaLabel !== undefined ? { role: 'img' as const, 'aria-label': ariaLabel } : {}
24
33
 
@@ -36,12 +45,17 @@ export function LineSparkline({ data, width, height, color, ariaLabel }: LineSpa
36
45
  return scaleLinear<number>({ domain: [min - pad, max + pad], range: [height, 0] })
37
46
  }, [data, height])
38
47
 
39
- if (data.length < 2) return <svg width={width} height={height} {...a11yProps} />
48
+ const rootProps = {
49
+ ...(className !== undefined && { className }),
50
+ ...(style !== undefined && { style }),
51
+ }
52
+
53
+ if (data.length < 2) return <svg width={width} height={height} {...rootProps} {...a11yProps} />
40
54
 
41
55
  const indexed = data.map((v, i) => ({ v, i }))
42
56
 
43
57
  return (
44
- <svg width={width} height={height} {...a11yProps}>
58
+ <svg width={width} height={height} {...rootProps} {...a11yProps}>
45
59
  <Group>
46
60
  <LinePath<{ v: number; i: number }>
47
61
  data={indexed}
@@ -1,2 +1,2 @@
1
- export { LineSparkline } from './LineSparkline'
2
- export { BarSparkline } from './BarSparkline'
1
+ export { LineSparkline, type LineSparklineProps } from './LineSparkline'
2
+ export { BarSparkline, type BarSparklineProps } from './BarSparkline'
@@ -1,9 +1,22 @@
1
1
  const MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
2
2
  const SHORT_DAYS = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
3
3
 
4
- /** Axis-friendly short date: DD.MM */
4
+ /**
5
+ * What EVERY formatter here prints for input it cannot represent — `NaN`, `±Infinity`, an
6
+ * `Invalid Date`. An em dash (U+2014), the same glyph the tooltip already uses for a missing value.
7
+ *
8
+ * The rule is one rule on purpose. `Intl.NumberFormat` renders `NaN` as the literal string `"NaN"`
9
+ * and `Infinity` as `"∞"`, so a y axis whose domain collapsed (an empty series, a 0/0 rate, a log
10
+ * scale reaching zero) painted its own arithmetic accident as a tick label and a tooltip read
11
+ * `NaN%`. A chart may say it does not know; it may not print a number that is not one.
12
+ */
13
+ export const NON_FINITE = '\u2014'
14
+
15
+ /** Axis-friendly short date: DD.MM. A non-finite or invalid date prints {@link NON_FINITE}. */
5
16
  export function fmtAxisDate(value: unknown): string {
17
+ if (typeof value === 'number' && !Number.isFinite(value)) return NON_FINITE
6
18
  if (value instanceof Date) {
19
+ if (Number.isNaN(value.getTime())) return NON_FINITE
7
20
  const dd = String(value.getDate()).padStart(2, '0')
8
21
  const mm = String(value.getMonth() + 1).padStart(2, '0')
9
22
  return `${dd}.${mm}`
@@ -14,9 +27,12 @@ export function fmtAxisDate(value: unknown): string {
14
27
  return s
15
28
  }
16
29
 
17
- /** Tooltip-friendly long date: "Mon Apr 21 2026" */
30
+ /** Tooltip-friendly long date: "Mon Apr 21 2026". A non-finite or invalid date prints
31
+ * {@link NON_FINITE}. */
18
32
  export function fmtTooltipDate(date: unknown): string {
33
+ if (typeof date === 'number' && !Number.isFinite(date)) return NON_FINITE
19
34
  if (date instanceof Date) {
35
+ if (Number.isNaN(date.getTime())) return NON_FINITE
20
36
  return `${SHORT_DAYS[date.getDay()]} ${MONTHS[date.getMonth()]} ${date.getDate()} ${date.getFullYear()}`
21
37
  }
22
38
  const s = String(date ?? '')
@@ -25,3 +41,148 @@ export function fmtTooltipDate(date: unknown): string {
25
41
  const d = new Date(Number(match[1]), Number(match[2]) - 1, Number(match[3]))
26
42
  return `${SHORT_DAYS[d.getDay()]} ${MONTHS[d.getMonth()]} ${d.getDate()} ${d.getFullYear()}`
27
43
  }
44
+
45
+ /**
46
+ * The number-format law.
47
+ *
48
+ * `format.ts` shipped two date formatters and nothing else, so every axis and every tooltip in
49
+ * every demo and consumer hand-rolled its own `` `$${v}k` `` — a template literal that is not
50
+ * locale-aware, not compact-aware, and different in each of the places it was written. These four
51
+ * are `Intl.NumberFormat` with the arguments already decided, so a chart states WHAT a number is
52
+ * rather than how to punctuate it.
53
+ *
54
+ * `locale` defaults to `undefined`, which is `Intl`'s own "use the runtime's locale" — the correct
55
+ * default for an app whose reader is the person looking at it. Pass it explicitly (`'en-US'`) when
56
+ * the output must be stable regardless of where it runs, which is what the tests here do.
57
+ *
58
+ * Every one of them returns {@link NON_FINITE} for input that is not a finite number — see its
59
+ * JSDoc for why that is a law of this module rather than a per-call-site guard.
60
+ */
61
+
62
+ /** Options every formatter here accepts. */
63
+ type LocaleOption = {
64
+ /** BCP-47 tag. Default `undefined` — the runtime's own locale. */
65
+ locale?: string
66
+ }
67
+
68
+ /**
69
+ * `Intl.NumberFormat` construction is the expensive half of formatting and a chart formats one
70
+ * label per tick per frame, so instances are memoized on their own arguments. The key is the
71
+ * serialized options because that is exactly what identifies an instance.
72
+ */
73
+ const formatterCache = new Map<string, Intl.NumberFormat>()
74
+
75
+ /** The compact `K` suffix, matched only where it follows the digits it qualifies — so a currency
76
+ * prefix that happens to contain one (`HK$`) survives the lowercasing. */
77
+ const COMPACT_K = /(\d\s?)K/
78
+
79
+ function numberFormat(
80
+ locale: string | undefined,
81
+ options: Intl.NumberFormatOptions,
82
+ ): Intl.NumberFormat {
83
+ const key = `${locale ?? ''}|${JSON.stringify(options)}`
84
+ const cached = formatterCache.get(key)
85
+ if (cached !== undefined) return cached
86
+ const created = new Intl.NumberFormat(locale, options)
87
+ formatterCache.set(key, created)
88
+ return created
89
+ }
90
+
91
+ export type FmtCompactOptions = LocaleOption & {
92
+ /** Significant-ish fraction digits on the compacted number. Default 1 (`1.2k`, `3.4M`). */
93
+ digits?: number
94
+ }
95
+
96
+ /**
97
+ * Compact notation: `1.2k`, `3.4M`, `-820`. The axis formatter for any count whose range spans
98
+ * more than three digits — a y axis reading `1,200,000` spends a third of the plot width on a
99
+ * gutter. A non-finite value prints {@link NON_FINITE}.
100
+ *
101
+ * Note `Intl`'s compact notation is LOCALE text, not a suffix table: `en` gives `1.2K`, and this
102
+ * lowercases the `K` to match the package's own numeral style while leaving every other locale's
103
+ * word (`1,2 Mio.`) untouched. Only a `K` attached to the DIGITS is touched — `HK$1.2K` must keep
104
+ * its currency prefix, which a bare `replace('K', 'k')` ate.
105
+ */
106
+ export function fmtCompact(value: number, options: FmtCompactOptions = {}): string {
107
+ if (!Number.isFinite(value)) return NON_FINITE
108
+ const { digits = 1, locale } = options
109
+ return numberFormat(locale, {
110
+ notation: 'compact',
111
+ compactDisplay: 'short',
112
+ maximumFractionDigits: digits,
113
+ })
114
+ .format(value)
115
+ .replace(COMPACT_K, '$1k')
116
+ }
117
+
118
+ export type FmtPercentOptions = LocaleOption & {
119
+ /** Fraction digits. Default 0 (`42%`). */
120
+ digits?: number
121
+ /**
122
+ * What the incoming number MEANS. `'ratio'` (default) is `0.42 → 42%`; `'percent'` is
123
+ * `42 → 42%`. Required as an explicit option rather than guessed from magnitude: a ratio of 1.2
124
+ * and a percentage of 1.2 are both perfectly ordinary numbers, and a heuristic would silently
125
+ * render one of them 100× wrong.
126
+ */
127
+ input?: 'ratio' | 'percent'
128
+ }
129
+
130
+ /** Percentages, from either a ratio or an already-scaled percentage. A non-finite value prints
131
+ * {@link NON_FINITE} — a rate is the commonest source of a 0/0. */
132
+ export function fmtPercent(value: number, options: FmtPercentOptions = {}): string {
133
+ if (!Number.isFinite(value)) return NON_FINITE
134
+ const { digits = 0, input = 'ratio', locale } = options
135
+ return numberFormat(locale, {
136
+ style: 'percent',
137
+ minimumFractionDigits: digits,
138
+ maximumFractionDigits: digits,
139
+ }).format(input === 'percent' ? value / 100 : value)
140
+ }
141
+
142
+ export type FmtCurrencyOptions = LocaleOption & {
143
+ /** ISO 4217 code — required. There is no default currency; a wrong symbol is worse than a
144
+ * verbose call site. */
145
+ currency: string
146
+ /** Compact notation for the amount (`$1.2k`). Default false. */
147
+ compact?: boolean
148
+ /** Fraction digits. Default 0 compacted, else the currency's own default (`undefined`). */
149
+ digits?: number
150
+ }
151
+
152
+ /** Money. `fmtCurrency(1234, { currency: 'USD' })` → `$1,234`. A non-finite amount prints
153
+ * {@link NON_FINITE}. */
154
+ export function fmtCurrency(value: number, options: FmtCurrencyOptions): string {
155
+ if (!Number.isFinite(value)) return NON_FINITE
156
+ const { currency, compact = false, digits, locale } = options
157
+ const fractionDigits = digits ?? (compact ? 1 : 0)
158
+ return numberFormat(locale, {
159
+ style: 'currency',
160
+ currency,
161
+ ...(compact && { notation: 'compact', compactDisplay: 'short' }),
162
+ minimumFractionDigits: compact ? 0 : fractionDigits,
163
+ maximumFractionDigits: fractionDigits,
164
+ })
165
+ .format(value)
166
+ .replace(COMPACT_K, '$1k')
167
+ }
168
+
169
+ /** Grouped integer: `12,480`. Rounds — an integer formatter that printed `12,480.4` would be
170
+ * lying about its own name. A non-finite value prints {@link NON_FINITE}. */
171
+ export function fmtInt(value: number, options: LocaleOption = {}): string {
172
+ if (!Number.isFinite(value)) return NON_FINITE
173
+ return numberFormat(options.locale, { maximumFractionDigits: 0 }).format(value)
174
+ }
175
+
176
+ /**
177
+ * Every shipped formatter under one name, so a chart can be handed the whole set
178
+ * (`format={formatters.compact}`) and a consumer has one import to reach for instead of four.
179
+ * Same members as the named exports — this is a convenience, never a second implementation.
180
+ */
181
+ export const formatters = {
182
+ compact: fmtCompact,
183
+ percent: fmtPercent,
184
+ currency: fmtCurrency,
185
+ int: fmtInt,
186
+ axisDate: fmtAxisDate,
187
+ tooltipDate: fmtTooltipDate,
188
+ } as const