basalt-ui 1.24.0 → 1.26.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 (467) hide show
  1. package/AGENTS.md +8 -6
  2. package/CHANGELOG.md +25 -0
  3. package/MIGRATING.md +547 -21
  4. package/README.md +46 -33
  5. package/agent/rules/basalt-batteries.md +205 -0
  6. package/agent/rules/basalt-charts.md +125 -555
  7. package/agent/rules/basalt-controls.md +155 -0
  8. package/agent/rules/basalt-mantine.md +146 -439
  9. package/agent/rules/basalt-state.md +113 -96
  10. package/agent/rules/basalt-tokens.md +126 -288
  11. package/agent/skills/basalt-app/SKILL.md +70 -195
  12. package/agent/skills/basalt-charts/SKILL.md +54 -234
  13. package/agent/skills/basalt-design/SKILL.md +56 -248
  14. package/agent/templates/CLAUDE-block.md.tpl +31 -40
  15. package/agent/templates/DESIGN.md.tpl +22 -51
  16. package/configs/oxlint-plugin.js +1275 -31
  17. package/configs/oxlint-plugin.test.ts +947 -11
  18. package/configs/oxlint.json +11 -3
  19. package/dist/charts/cursor/resolve.d.ts +18 -0
  20. package/dist/charts/cursor/resolve.d.ts.map +1 -1
  21. package/dist/charts/cursor/resolve.js +15 -6
  22. package/dist/charts/cursor/scope.d.ts +6 -3
  23. package/dist/charts/cursor/scope.d.ts.map +1 -1
  24. package/dist/charts/cursor/store.d.ts +5 -1
  25. package/dist/charts/cursor/store.d.ts.map +1 -1
  26. package/dist/charts/cursor/store.js +4 -4
  27. package/dist/charts/hooks/useChartCursor.d.ts.map +1 -1
  28. package/dist/charts/hooks/useChartCursor.js +9 -8
  29. package/dist/charts/index.d.ts +2 -2
  30. package/dist/charts/index.d.ts.map +1 -1
  31. package/dist/charts/primitives/ChartCard.d.ts +34 -9
  32. package/dist/charts/primitives/ChartCard.d.ts.map +1 -1
  33. package/dist/charts/primitives/ChartCard.js +29 -114
  34. package/dist/charts/primitives/ChartCard.test.d.ts +2 -0
  35. package/dist/charts/primitives/ChartCard.test.d.ts.map +1 -0
  36. package/dist/charts/sparklines/BarSparkline.d.ts +26 -2
  37. package/dist/charts/sparklines/BarSparkline.d.ts.map +1 -1
  38. package/dist/charts/sparklines/BarSparkline.js +18 -4
  39. package/dist/cli/check-coverage.test.d.ts +2 -0
  40. package/dist/cli/check-coverage.test.d.ts.map +1 -0
  41. package/dist/cli/index.d.ts +67 -4
  42. package/dist/cli/index.d.ts.map +1 -1
  43. package/dist/cli/index.js +225 -7
  44. package/dist/connectivity/connectivity-indicator.d.ts +4 -1
  45. package/dist/connectivity/connectivity-indicator.d.ts.map +1 -1
  46. package/dist/connectivity/connectivity-indicator.js +1 -1
  47. package/dist/content/index.d.ts +5 -3
  48. package/dist/content/index.d.ts.map +1 -1
  49. package/dist/content/index.js +4 -2
  50. package/dist/content/prose.module.css +7 -28
  51. package/dist/controls/actions.d.ts +169 -0
  52. package/dist/controls/actions.d.ts.map +1 -0
  53. package/dist/controls/actions.js +287 -0
  54. package/dist/controls/actions.module.css +62 -0
  55. package/dist/controls/actions.module.css.d.ts +13 -0
  56. package/dist/controls/actions.test.d.ts +2 -0
  57. package/dist/controls/actions.test.d.ts.map +1 -0
  58. package/dist/controls/actions.type-guard.test.d.ts +2 -0
  59. package/dist/controls/actions.type-guard.test.d.ts.map +1 -0
  60. package/dist/controls/compare-filter.d.ts +41 -0
  61. package/dist/controls/compare-filter.d.ts.map +1 -0
  62. package/dist/controls/compare-filter.js +23 -0
  63. package/dist/controls/control-group.d.ts +19 -0
  64. package/dist/controls/control-group.d.ts.map +1 -0
  65. package/dist/controls/control-group.js +20 -0
  66. package/dist/controls/control-group.test.d.ts +2 -0
  67. package/dist/controls/control-group.test.d.ts.map +1 -0
  68. package/dist/controls/controls.module.css +542 -0
  69. package/dist/controls/controls.module.css.d.ts +35 -0
  70. package/dist/controls/controls.router.test.d.ts +2 -0
  71. package/dist/controls/controls.router.test.d.ts.map +1 -0
  72. package/dist/controls/enum-filter.d.ts +30 -0
  73. package/dist/controls/enum-filter.d.ts.map +1 -0
  74. package/dist/controls/enum-filter.js +91 -0
  75. package/dist/controls/filter-context.d.ts +55 -0
  76. package/dist/controls/filter-context.d.ts.map +1 -0
  77. package/dist/controls/filter-context.js +69 -0
  78. package/dist/controls/filter-pill.d.ts +28 -0
  79. package/dist/controls/filter-pill.d.ts.map +1 -0
  80. package/dist/controls/filter-pill.js +70 -0
  81. package/dist/controls/filter-set.d.ts +13 -0
  82. package/dist/controls/filter-set.d.ts.map +1 -0
  83. package/dist/controls/filter-set.js +125 -0
  84. package/dist/controls/filter-set.test.d.ts +2 -0
  85. package/dist/controls/filter-set.test.d.ts.map +1 -0
  86. package/dist/controls/filter-sheet.d.ts +117 -0
  87. package/dist/controls/filter-sheet.d.ts.map +1 -0
  88. package/dist/controls/filter-sheet.js +146 -0
  89. package/dist/controls/glyphs.d.ts +27 -0
  90. package/dist/controls/glyphs.d.ts.map +1 -0
  91. package/dist/controls/glyphs.js +49 -0
  92. package/dist/controls/index.d.ts +19 -0
  93. package/dist/controls/index.d.ts.map +1 -0
  94. package/dist/controls/index.js +44 -0
  95. package/dist/controls/multi-select-filter.d.ts +23 -0
  96. package/dist/controls/multi-select-filter.d.ts.map +1 -0
  97. package/dist/controls/multi-select-filter.js +89 -0
  98. package/dist/controls/peer-boundary.test.d.ts +2 -0
  99. package/dist/controls/peer-boundary.test.d.ts.map +1 -0
  100. package/dist/controls/props-contract.test.d.ts +2 -0
  101. package/dist/controls/props-contract.test.d.ts.map +1 -0
  102. package/dist/controls/range-filter.d.ts +29 -0
  103. package/dist/controls/range-filter.d.ts.map +1 -0
  104. package/dist/controls/range-filter.js +120 -0
  105. package/dist/controls/search-filter.d.ts +10 -0
  106. package/dist/controls/search-filter.d.ts.map +1 -0
  107. package/dist/controls/search-filter.js +81 -0
  108. package/dist/controls/select-filter.d.ts +74 -0
  109. package/dist/controls/select-filter.d.ts.map +1 -0
  110. package/dist/controls/select-filter.js +10 -0
  111. package/dist/controls/sync-button.d.ts +38 -0
  112. package/dist/controls/sync-button.d.ts.map +1 -0
  113. package/dist/controls/sync-button.js +119 -0
  114. package/dist/controls/sync-button.module.css +63 -0
  115. package/dist/controls/sync-button.module.css.d.ts +11 -0
  116. package/dist/controls/sync-button.test.d.ts +2 -0
  117. package/dist/controls/sync-button.test.d.ts.map +1 -0
  118. package/dist/controls/toggle-filter.d.ts +9 -0
  119. package/dist/controls/toggle-filter.d.ts.map +1 -0
  120. package/dist/controls/toggle-filter.js +42 -0
  121. package/dist/controls/view-tabs.d.ts +23 -0
  122. package/dist/controls/view-tabs.d.ts.map +1 -0
  123. package/dist/controls/view-tabs.js +59 -0
  124. package/dist/controls-dates/date-range-picker.d.ts +4 -0
  125. package/dist/controls-dates/date-range-picker.d.ts.map +1 -0
  126. package/dist/controls-dates/date-range-picker.js +18 -0
  127. package/dist/controls-dates/index.d.ts +9 -0
  128. package/dist/controls-dates/index.d.ts.map +1 -0
  129. package/dist/controls-dates/index.js +4 -0
  130. package/dist/dashboard/delta-badge.d.ts +6 -12
  131. package/dist/dashboard/delta-badge.d.ts.map +1 -1
  132. package/dist/dashboard/delta-badge.js +1 -50
  133. package/dist/dashboard/query-state.d.ts +1 -1
  134. package/dist/dashboard/settings-section.d.ts +6 -4
  135. package/dist/dashboard/settings-section.d.ts.map +1 -1
  136. package/dist/dashboard/settings-section.js +23 -16
  137. package/dist/dashboard/settings-section.module.css +10 -0
  138. package/dist/dashboard/settings-section.module.css.d.ts +1 -0
  139. package/dist/dashboard/settings-section.test.d.ts +2 -0
  140. package/dist/dashboard/settings-section.test.d.ts.map +1 -0
  141. package/dist/dashboard/stat-card.d.ts +44 -9
  142. package/dist/dashboard/stat-card.d.ts.map +1 -1
  143. package/dist/dashboard/stat-card.js +80 -48
  144. package/dist/dashboard/stat-card.module.css +82 -0
  145. package/dist/dashboard/stat-card.module.css.d.ts +11 -0
  146. package/dist/data/data-table.d.ts +102 -20
  147. package/dist/data/data-table.d.ts.map +1 -1
  148. package/dist/data/data-table.js +166 -65
  149. package/dist/data/table.d.ts +1 -1
  150. package/dist/data/table.d.ts.map +1 -1
  151. package/dist/guard/grace.test.d.ts +20 -0
  152. package/dist/guard/grace.test.d.ts.map +1 -0
  153. package/dist/guard/index.d.ts +66 -3
  154. package/dist/guard/index.d.ts.map +1 -1
  155. package/dist/guard/index.js +82 -7
  156. package/dist/guard/types.d.ts +3 -3
  157. package/dist/guard/types.d.ts.map +1 -1
  158. package/dist/index.d.ts +12 -2
  159. package/dist/index.d.ts.map +1 -1
  160. package/dist/index.js +13 -10
  161. package/dist/nav/types.d.ts +78 -2
  162. package/dist/nav/types.d.ts.map +1 -1
  163. package/dist/notifications/bell.d.ts +4 -1
  164. package/dist/notifications/bell.d.ts.map +1 -1
  165. package/dist/notifications/index.d.ts +1 -1
  166. package/dist/router-tanstack/field.d.ts +14 -0
  167. package/dist/router-tanstack/field.d.ts.map +1 -0
  168. package/dist/router-tanstack/field.js +4 -0
  169. package/dist/router-tanstack/index.d.ts +6 -2
  170. package/dist/router-tanstack/index.d.ts.map +1 -1
  171. package/dist/router-tanstack/index.js +4 -0
  172. package/dist/router-tanstack/multi-search-param-store.d.ts +4 -52
  173. package/dist/router-tanstack/multi-search-param-store.d.ts.map +1 -1
  174. package/dist/router-tanstack/multi-search-param-store.js +19 -27
  175. package/dist/router-tanstack/search-param-store.d.ts +3 -87
  176. package/dist/router-tanstack/search-param-store.d.ts.map +1 -1
  177. package/dist/router-tanstack/search-param-store.js +16 -45
  178. package/dist/router-tanstack/search-store.d.ts +81 -0
  179. package/dist/router-tanstack/search-store.d.ts.map +1 -0
  180. package/dist/router-tanstack/search-store.js +187 -0
  181. package/dist/router-tanstack/search-store.router.test.d.ts +2 -0
  182. package/dist/router-tanstack/search-store.router.test.d.ts.map +1 -0
  183. package/dist/router-tanstack/search-store.test.d.ts +2 -0
  184. package/dist/router-tanstack/search-store.test.d.ts.map +1 -0
  185. package/dist/router-tanstack/use-nav.d.ts +0 -2
  186. package/dist/router-tanstack/use-nav.d.ts.map +1 -1
  187. package/dist/router-tanstack/use-nav.js +34 -12
  188. package/dist/router-tanstack/use-nav.test.d.ts +2 -0
  189. package/dist/router-tanstack/use-nav.test.d.ts.map +1 -0
  190. package/dist/section/index.d.ts +2 -0
  191. package/dist/section/index.d.ts.map +1 -0
  192. package/dist/section/index.js +4 -0
  193. package/dist/section/section.d.ts +24 -0
  194. package/dist/section/section.d.ts.map +1 -0
  195. package/dist/section/section.js +126 -0
  196. package/dist/section/section.module.css +104 -0
  197. package/dist/section/section.module.css.d.ts +11 -0
  198. package/dist/section/section.test.d.ts +2 -0
  199. package/dist/section/section.test.d.ts.map +1 -0
  200. package/dist/shell/app-breadcrumbs.d.ts.map +1 -1
  201. package/dist/shell/app-breadcrumbs.js +18 -15
  202. package/dist/shell/app-header.module.css +77 -37
  203. package/dist/shell/app-header.module.css.d.ts +2 -1
  204. package/dist/shell/app-mobile-nav.d.ts +9 -2
  205. package/dist/shell/app-mobile-nav.d.ts.map +1 -1
  206. package/dist/shell/app-mobile-nav.js +98 -11
  207. package/dist/shell/app-mobile-nav.module.css +8 -0
  208. package/dist/shell/app-mobile-nav.module.css.d.ts +1 -0
  209. package/dist/shell/app-sidebar.d.ts +55 -28
  210. package/dist/shell/app-sidebar.d.ts.map +1 -1
  211. package/dist/shell/app-sidebar.js +116 -67
  212. package/dist/shell/app-sidebar.module.css +303 -20
  213. package/dist/shell/app-sidebar.module.css.d.ts +19 -1
  214. package/dist/shell/index.d.ts +55 -21
  215. package/dist/shell/index.d.ts.map +1 -1
  216. package/dist/shell/index.js +40 -18
  217. package/dist/shell/mobile-nav-model.d.ts +13 -2
  218. package/dist/shell/mobile-nav-model.d.ts.map +1 -1
  219. package/dist/shell/mobile-nav-model.js +15 -1
  220. package/dist/shell/nav-count-badge.d.ts +1 -1
  221. package/dist/shell/page-bar.d.ts +51 -0
  222. package/dist/shell/page-bar.d.ts.map +1 -0
  223. package/dist/shell/page-bar.js +154 -0
  224. package/dist/shell/page-bar.module.css +178 -0
  225. package/dist/shell/page-bar.module.css.d.ts +17 -0
  226. package/dist/shell/page-bar.test.d.ts +2 -0
  227. package/dist/shell/page-bar.test.d.ts.map +1 -0
  228. package/dist/shell/sidebar-block-model.d.ts +48 -0
  229. package/dist/shell/sidebar-block-model.d.ts.map +1 -0
  230. package/dist/shell/sidebar-block-model.js +39 -0
  231. package/dist/shell/sidebar-blocks.d.ts +32 -0
  232. package/dist/shell/sidebar-blocks.d.ts.map +1 -0
  233. package/dist/shell/sidebar-blocks.js +169 -0
  234. package/dist/shell/sidebar-search.d.ts +13 -1
  235. package/dist/shell/sidebar-search.d.ts.map +1 -1
  236. package/dist/shell/sidebar-search.js +34 -1
  237. package/dist/shell/sidebar-search.module.css +26 -0
  238. package/dist/shell/sidebar-search.module.css.d.ts +2 -0
  239. package/dist/state/fields.d.ts +392 -0
  240. package/dist/state/fields.d.ts.map +1 -0
  241. package/dist/state/fields.js +369 -0
  242. package/dist/state/fields.test.d.ts +2 -0
  243. package/dist/state/fields.test.d.ts.map +1 -0
  244. package/dist/state/persisted.d.ts +48 -0
  245. package/dist/state/persisted.d.ts.map +1 -0
  246. package/dist/state/persisted.js +105 -0
  247. package/dist/state.d.ts +11 -56
  248. package/dist/state.d.ts.map +1 -1
  249. package/dist/state.js +14 -120
  250. package/dist/styles.css +13 -0
  251. package/dist/surfaces.d.ts +106 -24
  252. package/dist/surfaces.d.ts.map +1 -1
  253. package/dist/surfaces.js +155 -19
  254. package/dist/theme/controls.module.css +16 -1
  255. package/dist/theme/ctl-theme.d.ts +32 -0
  256. package/dist/theme/ctl-theme.d.ts.map +1 -0
  257. package/dist/theme/ctl-theme.js +54 -0
  258. package/dist/theme/ctl-theme.test.d.ts +2 -0
  259. package/dist/theme/ctl-theme.test.d.ts.map +1 -0
  260. package/dist/theme/ctl-tier-coverage.test.d.ts +2 -0
  261. package/dist/theme/ctl-tier-coverage.test.d.ts.map +1 -0
  262. package/dist/theme/divider-law.test.d.ts +2 -0
  263. package/dist/theme/divider-law.test.d.ts.map +1 -0
  264. package/dist/theme/icon-slot.d.ts +44 -0
  265. package/dist/theme/icon-slot.d.ts.map +1 -0
  266. package/dist/theme/icon-slot.js +21 -0
  267. package/dist/theme/icon-slot.module.css +47 -0
  268. package/dist/theme/icon-slot.module.css.d.ts +8 -0
  269. package/dist/theme/icon-slot.test.d.ts +2 -0
  270. package/dist/theme/icon-slot.test.d.ts.map +1 -0
  271. package/dist/theme/index.d.ts +1 -0
  272. package/dist/theme/index.d.ts.map +1 -1
  273. package/dist/theme/index.js +82 -5
  274. package/dist/theme/layout-rhythm-css.test.d.ts +2 -0
  275. package/dist/theme/layout-rhythm-css.test.d.ts.map +1 -0
  276. package/dist/theme/segmented-control.module.css +20 -0
  277. package/dist/theme/shadow-surfaces.test.d.ts.map +1 -1
  278. package/dist/tokens/index.d.ts +12 -0
  279. package/dist/tokens/index.d.ts.map +1 -1
  280. package/dist/tokens/index.js +38 -8
  281. package/dist/tokens/palette.d.ts +97 -61
  282. package/dist/tokens/palette.d.ts.map +1 -1
  283. package/dist/tokens/palette.js +76 -38
  284. package/dist/tokens.css +10 -2
  285. package/dist/widget-header/delta-badge.d.ts +13 -0
  286. package/dist/widget-header/delta-badge.d.ts.map +1 -0
  287. package/dist/widget-header/delta-badge.js +29 -0
  288. package/dist/widget-header/delta-badge.test.d.ts +2 -0
  289. package/dist/widget-header/delta-badge.test.d.ts.map +1 -0
  290. package/dist/widget-header/index.d.ts +3 -0
  291. package/dist/widget-header/index.d.ts.map +1 -0
  292. package/dist/widget-header/index.js +6 -0
  293. package/dist/widget-header/no-mantine.test.d.ts +2 -0
  294. package/dist/widget-header/no-mantine.test.d.ts.map +1 -0
  295. package/dist/widget-header/widget-header.d.ts +37 -0
  296. package/dist/widget-header/widget-header.d.ts.map +1 -0
  297. package/dist/widget-header/widget-header.js +77 -0
  298. package/dist/widget-header/widget-header.module.css +335 -0
  299. package/dist/widget-header/widget-header.module.css.d.ts +24 -0
  300. package/dist/widget-header/widget-header.test.d.ts +2 -0
  301. package/dist/widget-header/widget-header.test.d.ts.map +1 -0
  302. package/llms.txt +30 -17
  303. package/package.json +14 -1
  304. package/src/charts/cursor/resolve.test.ts +29 -1
  305. package/src/charts/cursor/resolve.ts +38 -6
  306. package/src/charts/cursor/scope.tsx +6 -3
  307. package/src/charts/cursor/store.test.ts +19 -1
  308. package/src/charts/cursor/store.ts +10 -5
  309. package/src/charts/hooks/useChartCursor.ts +16 -8
  310. package/src/charts/index.ts +2 -2
  311. package/src/charts/primitives/CartesianChart.test.tsx +124 -0
  312. package/src/charts/primitives/ChartCard.test.tsx +66 -0
  313. package/src/charts/primitives/ChartCard.tsx +86 -146
  314. package/src/charts/sparklines/BarSparkline.tsx +43 -5
  315. package/src/cli/check-coverage.test.ts +297 -0
  316. package/src/cli/check-theme.test.ts +38 -14
  317. package/src/cli/index.ts +392 -16
  318. package/src/cli/init-sync.test.ts +97 -0
  319. package/src/connectivity/connectivity-indicator.tsx +16 -9
  320. package/src/content/index.ts +16 -3
  321. package/src/content/prose.module.css +7 -28
  322. package/src/content/prose.module.css.test.ts +8 -24
  323. package/src/controls/actions.module.css +62 -0
  324. package/src/controls/actions.module.css.d.ts +13 -0
  325. package/src/controls/actions.test.tsx +252 -0
  326. package/src/controls/actions.tsx +655 -0
  327. package/src/controls/actions.type-guard.test.ts +63 -0
  328. package/src/controls/compare-filter.tsx +64 -0
  329. package/src/controls/control-group.test.tsx +229 -0
  330. package/src/controls/control-group.tsx +63 -0
  331. package/src/controls/controls.module.css +542 -0
  332. package/src/controls/controls.module.css.d.ts +35 -0
  333. package/src/controls/controls.router.test.tsx +637 -0
  334. package/src/controls/enum-filter.tsx +159 -0
  335. package/src/controls/filter-context.tsx +153 -0
  336. package/src/controls/filter-pill.tsx +120 -0
  337. package/src/controls/filter-set.test.tsx +472 -0
  338. package/src/controls/filter-set.tsx +225 -0
  339. package/src/controls/filter-sheet.tsx +285 -0
  340. package/src/controls/glyphs.tsx +81 -0
  341. package/src/controls/index.ts +48 -0
  342. package/src/controls/multi-select-filter.tsx +140 -0
  343. package/src/controls/peer-boundary.test.ts +85 -0
  344. package/src/controls/props-contract.test.tsx +106 -0
  345. package/src/controls/range-filter.tsx +184 -0
  346. package/src/controls/search-filter.tsx +123 -0
  347. package/src/controls/select-filter.tsx +89 -0
  348. package/src/controls/sync-button.module.css +63 -0
  349. package/src/controls/sync-button.module.css.d.ts +11 -0
  350. package/src/controls/sync-button.test.tsx +183 -0
  351. package/src/controls/sync-button.tsx +197 -0
  352. package/src/controls/toggle-filter.tsx +60 -0
  353. package/src/controls/view-tabs.tsx +110 -0
  354. package/src/controls-dates/date-range-picker.tsx +42 -0
  355. package/src/controls-dates/index.ts +8 -0
  356. package/src/dashboard/delta-badge.tsx +4 -74
  357. package/src/dashboard/query-state.tsx +1 -1
  358. package/src/dashboard/settings-section.module.css +10 -0
  359. package/src/dashboard/settings-section.module.css.d.ts +1 -0
  360. package/src/dashboard/settings-section.test.tsx +56 -0
  361. package/src/dashboard/settings-section.tsx +33 -30
  362. package/src/dashboard/stat-card.module.css +82 -0
  363. package/src/dashboard/stat-card.module.css.d.ts +11 -0
  364. package/src/dashboard/stat-card.test.tsx +67 -1
  365. package/src/dashboard/stat-card.tsx +209 -68
  366. package/src/data/data-table.test.tsx +282 -6
  367. package/src/data/data-table.tsx +429 -94
  368. package/src/data/table.ts +2 -0
  369. package/src/guard/check-source.test.ts +126 -13
  370. package/src/guard/grace.test.ts +149 -0
  371. package/src/guard/index.ts +172 -29
  372. package/src/guard/types.ts +4 -2
  373. package/src/index.ts +46 -5
  374. package/src/nav/types.ts +84 -2
  375. package/src/notifications/bell.tsx +6 -3
  376. package/src/notifications/index.ts +1 -1
  377. package/src/router-tanstack/field.ts +31 -0
  378. package/src/router-tanstack/index.ts +24 -2
  379. package/src/router-tanstack/multi-search-param-store.test.ts +71 -3
  380. package/src/router-tanstack/multi-search-param-store.ts +46 -77
  381. package/src/router-tanstack/search-param-store.ts +42 -159
  382. package/src/router-tanstack/search-store.router.test.tsx +661 -0
  383. package/src/router-tanstack/search-store.test.ts +418 -0
  384. package/src/router-tanstack/search-store.ts +380 -0
  385. package/src/router-tanstack/use-nav.test.tsx +187 -0
  386. package/src/router-tanstack/use-nav.ts +72 -14
  387. package/src/section/index.ts +1 -0
  388. package/src/section/section.module.css +104 -0
  389. package/src/section/section.module.css.d.ts +11 -0
  390. package/src/section/section.test.tsx +204 -0
  391. package/src/section/section.tsx +220 -0
  392. package/src/shell/app-breadcrumbs.tsx +44 -31
  393. package/src/shell/app-header.module.css +77 -37
  394. package/src/shell/app-header.module.css.d.ts +2 -1
  395. package/src/shell/app-mobile-nav.module.css +8 -0
  396. package/src/shell/app-mobile-nav.module.css.d.ts +1 -0
  397. package/src/shell/app-mobile-nav.tsx +147 -8
  398. package/src/shell/app-sidebar-account.tsx +2 -2
  399. package/src/shell/app-sidebar.module.css +303 -20
  400. package/src/shell/app-sidebar.module.css.d.ts +19 -1
  401. package/src/shell/app-sidebar.test.tsx +456 -41
  402. package/src/shell/app-sidebar.tsx +276 -140
  403. package/src/shell/index.test.tsx +291 -5
  404. package/src/shell/index.tsx +137 -38
  405. package/src/shell/mobile-nav-model.test.ts +228 -7
  406. package/src/shell/mobile-nav-model.ts +53 -3
  407. package/src/shell/nav-count-badge.tsx +1 -1
  408. package/src/shell/page-bar.module.css +178 -0
  409. package/src/shell/page-bar.module.css.d.ts +17 -0
  410. package/src/shell/page-bar.test.tsx +316 -0
  411. package/src/shell/page-bar.tsx +315 -0
  412. package/src/shell/sidebar-block-model.ts +83 -0
  413. package/src/shell/sidebar-blocks.tsx +301 -0
  414. package/src/shell/sidebar-search.module.css +26 -0
  415. package/src/shell/sidebar-search.module.css.d.ts +2 -0
  416. package/src/shell/sidebar-search.tsx +71 -2
  417. package/src/state/fields.test.tsx +258 -0
  418. package/src/state/fields.ts +892 -0
  419. package/src/state/persisted.ts +211 -0
  420. package/src/state.ts +46 -240
  421. package/src/styles.css +13 -0
  422. package/src/surfaces.ts +203 -36
  423. package/src/theme/controls.module.css +16 -1
  424. package/src/theme/ctl-theme.test.tsx +275 -0
  425. package/src/theme/ctl-theme.tsx +138 -0
  426. package/src/theme/ctl-tier-coverage.test.ts +170 -0
  427. package/src/theme/density-relations.test.ts +106 -51
  428. package/src/theme/divider-law.test.ts +259 -0
  429. package/src/theme/icon-slot.module.css +47 -0
  430. package/src/theme/icon-slot.module.css.d.ts +8 -0
  431. package/src/theme/icon-slot.test.tsx +275 -0
  432. package/src/theme/icon-slot.tsx +59 -0
  433. package/src/theme/index.ts +165 -3
  434. package/src/theme/layout-rhythm-css.test.ts +72 -0
  435. package/src/theme/radius.test.ts +11 -1
  436. package/src/theme/segmented-control.module.css +20 -0
  437. package/src/theme/shadow-surfaces.test.ts +20 -7
  438. package/src/theme/spacing.test.ts +75 -27
  439. package/src/theme/use-basalt-spacing.ts +2 -2
  440. package/src/tokens/density.test.ts +7 -25
  441. package/src/tokens/index.ts +48 -8
  442. package/src/tokens/palette.ts +107 -73
  443. package/src/widget-header/delta-badge.test.tsx +60 -0
  444. package/src/widget-header/delta-badge.tsx +57 -0
  445. package/src/widget-header/index.ts +2 -0
  446. package/src/widget-header/no-mantine.test.ts +33 -0
  447. package/src/widget-header/widget-header.module.css +335 -0
  448. package/src/widget-header/widget-header.module.css.d.ts +24 -0
  449. package/src/widget-header/widget-header.test.tsx +187 -0
  450. package/src/widget-header/widget-header.tsx +168 -0
  451. package/agent/rules/basalt-agent.md +0 -452
  452. package/agent/rules/basalt-app.md +0 -246
  453. package/agent/rules/basalt-commands.md +0 -320
  454. package/agent/rules/basalt-content.md +0 -409
  455. package/agent/rules/basalt-data.md +0 -269
  456. package/agent/rules/basalt-forms.md +0 -186
  457. package/agent/rules/basalt-notifications.md +0 -264
  458. package/agent/rules/basalt-query.md +0 -187
  459. package/agent/rules/basalt-router.md +0 -336
  460. package/dist/content/article-filter-bar.d.ts +0 -40
  461. package/dist/content/article-filter-bar.d.ts.map +0 -1
  462. package/dist/content/article-filter-bar.js +0 -56
  463. package/dist/shell/page-header.d.ts +0 -13
  464. package/dist/shell/page-header.d.ts.map +0 -1
  465. package/dist/shell/page-header.js +0 -23
  466. package/src/content/article-filter-bar.tsx +0 -88
  467. package/src/shell/page-header.tsx +0 -35
@@ -27,11 +27,19 @@
27
27
  "basalt/raw-size-literal": "error",
28
28
  "basalt/card-inset": "error",
29
29
  "basalt/chart-in-raw-surface": "error",
30
- "basalt/hand-rolled-plot": "warn",
31
- "basalt/chart-legend-literal": "warn",
30
+ "basalt/hand-rolled-plot": "error",
31
+ "basalt/chart-legend-literal": "error",
32
32
  "basalt/shadow-basalt-export": "warn",
33
- "basalt/hand-rolled-shell": "warn",
33
+ "basalt/hand-rolled-shell": "error",
34
34
  "basalt/raw-scroll-container": "error",
35
+ "basalt/hand-rolled-filter": "error",
36
+ "basalt/control-outside-home": "warn",
37
+ "basalt/control-size-literal": "warn",
38
+ "basalt/page-bar-budget": "error",
39
+ "basalt/in-body-page-title": "warn",
40
+ "basalt/responsive-twin": "warn",
41
+ "basalt/search-literal-link": "warn",
42
+ "basalt/use-search-from-literal": "warn",
35
43
  "basalt/visx-boundary": "error",
36
44
  "basalt/visx-tooltip": "error",
37
45
  "basalt/agent-resume-guard": "error",
@@ -13,6 +13,24 @@
13
13
  * since "nearest category" is meaningless.
14
14
  */
15
15
  export declare function parseKey(key: string): number | null;
16
+ /** The x-domain families the shared cursor partitions on, derived from a chart's own keys — never
17
+ * a prop, never `ChartCursorScope`. A chart's kind is stamped on every broadcast it makes, and a
18
+ * receiving chart ignores any broadcast whose kind differs from its own — so a category chart can
19
+ * never be mistaken for a time chart just because both domains happen to parse. */
20
+ export type DomainKind = 'time' | 'linear' | 'band';
21
+ /**
22
+ * Classify a domain by the SAME parse precedence `parseKey` applies to each key, so a domain can
23
+ * never be classified one way and resolved another:
24
+ *
25
+ * - empty domain → `'band'` (nothing to share).
26
+ * - every key numeric (same test `parseKey` tries first) → `'linear'`.
27
+ * - otherwise every key `Date.parse`-able (same test `parseKey` falls back to) → `'time'`.
28
+ * - otherwise → `'band'` (categories, or a mixed domain).
29
+ *
30
+ * Ordering matters and mirrors `parseKey` exactly: a domain of bare years like `"2026"` is numeric
31
+ * FIRST, so it classifies `'linear'`, not `'time'`, even though every value is also a valid date.
32
+ */
33
+ export declare function classifyDomain(keys: readonly string[]): DomainKind;
16
34
  /**
17
35
  * How a foreign key maps onto a chart's own points.
18
36
  *
@@ -1 +1 @@
1
- {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../../src/charts/cursor/resolve.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOnD;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,SAAS,CAAA;AAEpD,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI;IAC3B,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;IACrB,0EAA0E;IAC1E,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,mCAAmC;IACnC,MAAM,EAAE,CAAC,EAAE,CAAA;IACX,gFAAgF;IAChF,IAAI,EAAE,MAAM,CAAA;IACZ,wDAAwD;IACxD,UAAU,EAAE,gBAAgB,CAAA;CAC7B,CAAA;AAED,2DAA2D;AAC3D,wBAAgB,gBAAgB,CAAC,CAAC,EAChC,IAAI,EAAE,SAAS,CAAC,EAAE,EAClB,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,EACxB,UAAU,GAAE,gBAA4B,GACvC,WAAW,CAAC,CAAC,CAAC,CA8BhB;AAoBD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAClC,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,EACrB,GAAG,EAAE,MAAM,EACX,UAAU,GAAE,gBAAmC,GAC9C,CAAC,GAAG,IAAI,CA0CV"}
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../../src/charts/cursor/resolve.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAaH;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGnD;AAED;;;mFAGmF;AACnF,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAA;AAEnD;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,UAAU,CAKlE;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,SAAS,CAAA;AAEpD,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI;IAC3B,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;IACrB,0EAA0E;IAC1E,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,mCAAmC;IACnC,MAAM,EAAE,CAAC,EAAE,CAAA;IACX,gFAAgF;IAChF,IAAI,EAAE,MAAM,CAAA;IACZ,wDAAwD;IACxD,UAAU,EAAE,gBAAgB,CAAA;CAC7B,CAAA;AAED,2DAA2D;AAC3D,wBAAgB,gBAAgB,CAAC,CAAC,EAChC,IAAI,EAAE,SAAS,CAAC,EAAE,EAClB,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,EACxB,UAAU,GAAE,gBAA4B,GACvC,WAAW,CAAC,CAAC,CAAC,CA8BhB;AAoBD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAClC,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,EACrB,GAAG,EAAE,MAAM,EACX,UAAU,GAAE,gBAAmC,GAC9C,CAAC,GAAG,IAAI,CA0CV"}
@@ -1,10 +1,18 @@
1
+ function isNumericString(key) {
2
+ return /^[-+]?\d*\.?\d+$/.test(key) && Number.isFinite(Number(key));
3
+ }
4
+ function isDateParseableString(key) {
5
+ return !Number.isNaN(Date.parse(key));
6
+ }
1
7
  function parseKey(key) {
2
- if (/^[-+]?\d*\.?\d+$/.test(key)) {
3
- const n = Number(key);
4
- return Number.isFinite(n) ? n : null;
5
- }
6
- const t = Date.parse(key);
7
- return Number.isNaN(t) ? null : t;
8
+ if (isNumericString(key)) return Number(key);
9
+ return isDateParseableString(key) ? Date.parse(key) : null;
10
+ }
11
+ function classifyDomain(keys) {
12
+ if (keys.length === 0) return "band";
13
+ if (keys.every(isNumericString)) return "linear";
14
+ if (keys.every(isDateParseableString)) return "time";
15
+ return "band";
8
16
  }
9
17
  function buildDomainIndex(data, getKey, resolution = "nearest") {
10
18
  const byKey = /* @__PURE__ */ new Map();
@@ -77,6 +85,7 @@ function resolveCursorPoint(index, key, resolution = index.resolution) {
77
85
  }
78
86
  export {
79
87
  buildDomainIndex,
88
+ classifyDomain,
80
89
  parseKey,
81
90
  resolveCursorPoint
82
91
  };
@@ -5,9 +5,12 @@ export type ChartCursorScopeProps = {
5
5
  };
6
6
  /**
7
7
  * ISOLATES its subtree onto a private cursor store — the inverse of the removed `ChartHoverSync`, which
8
- * had to be mounted to enable sharing at all. Charts share a cursor by default now; wrap a group
9
- * in this only when it must NOT follow the rest of the page (e.g. two independent dashboards
10
- * rendered side by side over the same calendar).
8
+ * had to be mounted to enable sharing at all. Charts share a cursor by default now, AND the shared
9
+ * cursor partitions automatically by x-domain kind (`DomainKind`, derived from each chart's own
10
+ * data in `useChartCursor`) — a categorical chart never follows a date chart just because both
11
+ * happen to be on the page, with nothing to configure. `ChartCursorScope` is no longer the tool for
12
+ * that case. What it is still for: isolating two charts that share the same domain KIND but are
13
+ * semantically unrelated — two different tenants' date ranges rendered side by side on one page.
11
14
  */
12
15
  export declare function ChartCursorScope({ children }: ChartCursorScopeProps): import("react").JSX.Element;
13
16
  /** The cursor store this chart belongs to — the nearest `ChartCursorScope`, else the global one. */
@@ -1 +1 @@
1
- {"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../../../src/charts/cursor/scope.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACtC,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAKvD,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,EAAE,SAAS,CAAA;CACpB,CAAA;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,QAAQ,EAAE,EAAE,qBAAqB,+BAGnE;AAED,oGAAoG;AACpG,wBAAgB,cAAc,IAAI,WAAW,CAE5C;AAED,mFAAmF;AACnF,wBAAgB,cAAc,IAAI,WAAW,CAG5C"}
1
+ {"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../../../src/charts/cursor/scope.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACtC,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAKvD,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,EAAE,SAAS,CAAA;CACpB,CAAA;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,QAAQ,EAAE,EAAE,qBAAqB,+BAGnE;AAED,oGAAoG;AACpG,wBAAgB,cAAc,IAAI,WAAW,CAE5C;AAED,mFAAmF;AACnF,wBAAgB,cAAc,IAAI,WAAW,CAG5C"}
@@ -11,16 +11,20 @@
11
11
  * charts subscribed to it, instead of every descendant of a provider whose value object is new
12
12
  * on each pointer frame.
13
13
  */
14
+ import type { DomainKind } from './resolve.js';
14
15
  /** Broadcast cursor position: an opaque domain key plus the chart that owns it. */
15
16
  export type CursorState = {
16
17
  /** The hovered x-domain key (a date/category string), or null when nothing is hovered. */
17
18
  key: string | null;
18
19
  /** `chartId` of the chart the pointer is actually over — the one that owns the tooltip. */
19
20
  source: string | null;
21
+ /** The broadcaster's own x-domain kind. `null` only in the empty state — the store itself does
22
+ * not police this, it just carries it; the partition is enforced by the reading hook. */
23
+ kind: DomainKind | null;
20
24
  };
21
25
  export type CursorStore = {
22
26
  get: () => CursorState;
23
- set: (key: string | null, source: string | null) => void;
27
+ set: (key: string | null, source: string | null, kind?: DomainKind | null) => void;
24
28
  subscribe: (onChange: () => void) => () => void;
25
29
  };
26
30
  /** Stable identity for "nothing hovered" — also the SSR snapshot, so it must never be recreated. */
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../src/charts/cursor/store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,mFAAmF;AACnF,MAAM,MAAM,WAAW,GAAG;IACxB,0FAA0F;IAC1F,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IAClB,2FAA2F;IAC3F,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CACtB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,GAAG,EAAE,MAAM,WAAW,CAAA;IACtB,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAA;IACxD,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,CAAA;CAChD,CAAA;AAED,oGAAoG;AACpG,eAAO,MAAM,YAAY,EAAE,WAAyC,CAAA;AAEpE,wBAAgB,iBAAiB,IAAI,WAAW,CAkB/C;AAED,qFAAqF;AACrF,eAAO,MAAM,iBAAiB,EAAE,WAAiC,CAAA"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../src/charts/cursor/store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAE3C,mFAAmF;AACnF,MAAM,MAAM,WAAW,GAAG;IACxB,0FAA0F;IAC1F,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IAClB,2FAA2F;IAC3F,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB;6FACyF;IACzF,IAAI,EAAE,UAAU,GAAG,IAAI,CAAA;CACxB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,GAAG,EAAE,MAAM,WAAW,CAAA;IACtB,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,IAAI,CAAC,EAAE,UAAU,GAAG,IAAI,KAAK,IAAI,CAAA;IAClF,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,CAAA;CAChD,CAAA;AAED,oGAAoG;AACpG,eAAO,MAAM,YAAY,EAAE,WAAqD,CAAA;AAEhF,wBAAgB,iBAAiB,IAAI,WAAW,CAkB/C;AAED,qFAAqF;AACrF,eAAO,MAAM,iBAAiB,EAAE,WAAiC,CAAA"}
@@ -1,12 +1,12 @@
1
- const EMPTY_CURSOR = { key: null, source: null };
1
+ const EMPTY_CURSOR = { key: null, source: null, kind: null };
2
2
  function createCursorStore() {
3
3
  let state = EMPTY_CURSOR;
4
4
  const listeners = /* @__PURE__ */ new Set();
5
5
  return {
6
6
  get: () => state,
7
- set: (key, source) => {
8
- if (state.key === key && state.source === source) return;
9
- state = key === null && source === null ? EMPTY_CURSOR : { key, source };
7
+ set: (key, source, kind = null) => {
8
+ if (state.key === key && state.source === source && state.kind === kind) return;
9
+ state = key === null && source === null ? EMPTY_CURSOR : { key, source, kind };
10
10
  for (const listener of listeners) listener();
11
11
  },
12
12
  subscribe: (onChange) => {
@@ -1 +1 @@
1
- {"version":3,"file":"useChartCursor.d.ts","sourceRoot":"","sources":["../../../src/charts/hooks/useChartCursor.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,OAAO,CAAA;AACxD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAIzD,mEAAmE;AACnE,MAAM,MAAM,YAAY,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAEnD,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI;IAC3B,kGAAkG;IAClG,KAAK,EAAE,CAAC,GAAG,IAAI,CAAA;IACf,kGAAkG;IAClG,QAAQ,EAAE,OAAO,CAAA;IACjB,4EAA4E;IAC5E,MAAM,EAAE,YAAY,GAAG,IAAI,CAAA;IAC3B,aAAa,EAAE,CAAC,KAAK,EAAE,YAAY,CAAC,cAAc,CAAC,KAAK,IAAI,CAAA;IAC5D,cAAc,EAAE,MAAM,IAAI,CAAA;IAC1B,SAAS,EAAE,CAAC,KAAK,EAAE,aAAa,CAAC,cAAc,CAAC,KAAK,IAAI,CAAA;IACzD,MAAM,EAAE,MAAM,IAAI,CAAA;CACnB,CAAA;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,EAChC,IAAI,EACJ,OAAO,EACP,MAAM,EACN,MAAM,EACN,UAAU,EACV,UAAsB,GACvB,EAAE;IACD,IAAI,EAAE,SAAS,CAAC,EAAE,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAA;IACxB,gEAAgE;IAChE,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAA;IAC3C,UAAU,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,UAAU,CAAC,EAAE,gBAAgB,CAAA;CAC9B,GAAG,WAAW,CAAC,CAAC,CAAC,CAsHjB"}
1
+ {"version":3,"file":"useChartCursor.d.ts","sourceRoot":"","sources":["../../../src/charts/hooks/useChartCursor.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,OAAO,CAAA;AACxD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAIzD,mEAAmE;AACnE,MAAM,MAAM,YAAY,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAEnD,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI;IAC3B,kGAAkG;IAClG,KAAK,EAAE,CAAC,GAAG,IAAI,CAAA;IACf,kGAAkG;IAClG,QAAQ,EAAE,OAAO,CAAA;IACjB,4EAA4E;IAC5E,MAAM,EAAE,YAAY,GAAG,IAAI,CAAA;IAC3B,aAAa,EAAE,CAAC,KAAK,EAAE,YAAY,CAAC,cAAc,CAAC,KAAK,IAAI,CAAA;IAC5D,cAAc,EAAE,MAAM,IAAI,CAAA;IAC1B,SAAS,EAAE,CAAC,KAAK,EAAE,aAAa,CAAC,cAAc,CAAC,KAAK,IAAI,CAAA;IACzD,MAAM,EAAE,MAAM,IAAI,CAAA;CACnB,CAAA;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,EAChC,IAAI,EACJ,OAAO,EACP,MAAM,EACN,MAAM,EACN,UAAU,EACV,UAAsB,GACvB,EAAE;IACD,IAAI,EAAE,SAAS,CAAC,EAAE,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAA;IACxB,gEAAgE;IAChE,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAA;IAC3C,UAAU,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,UAAU,CAAC,EAAE,gBAAgB,CAAA;CAC9B,GAAG,WAAW,CAAC,CAAC,CAAC,CA8HjB"}
@@ -1,6 +1,6 @@
1
1
  import { localPoint } from "@visx/event";
2
2
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
3
- import { buildDomainIndex, resolveCursorPoint } from "../cursor/resolve.js";
3
+ import { buildDomainIndex, classifyDomain, resolveCursorPoint } from "../cursor/resolve.js";
4
4
  import { useCursorState, useCursorStore } from "../cursor/scope.js";
5
5
  function useChartCursor({
6
6
  data,
@@ -21,12 +21,13 @@ function useChartCursor({
21
21
  () => buildDomainIndex(data, getKeyRef.current, resolution),
22
22
  [data, resolution]
23
23
  );
24
+ const kind = useMemo(() => classifyDomain(data.map((d) => getKeyRef.current(d))), [data]);
24
25
  const frameRef = useRef(null);
25
26
  const pendingRef = useRef(null);
26
27
  useEffect(
27
28
  () => () => {
28
29
  if (frameRef.current !== null) cancelAnimationFrame(frameRef.current);
29
- if (store.get().source === chartId) store.set(null, null);
30
+ if (store.get().source === chartId) store.set(null, null, null);
30
31
  },
31
32
  [store, chartId]
32
33
  );
@@ -55,9 +56,9 @@ function useChartCursor({
55
56
  }
56
57
  }
57
58
  scheduleAnchor({ x: event.clientX, y: event.clientY });
58
- store.set(getKeyRef.current(closest), chartId);
59
+ store.set(getKeyRef.current(closest), chartId, kind);
59
60
  },
60
- [data, marginLeft, chartId, store, scheduleAnchor]
61
+ [data, marginLeft, chartId, store, scheduleAnchor, kind]
61
62
  );
62
63
  const clear = useCallback(() => {
63
64
  if (frameRef.current !== null) {
@@ -66,7 +67,7 @@ function useChartCursor({
66
67
  }
67
68
  pendingRef.current = null;
68
69
  setAnchor(null);
69
- if (store.get().source === chartId) store.set(null, null);
70
+ if (store.get().source === chartId) store.set(null, null, null);
70
71
  }, [store, chartId]);
71
72
  const onKeyDown = useCallback(
72
73
  (event) => {
@@ -88,11 +89,11 @@ function useChartCursor({
88
89
  const rect = event.currentTarget.getBoundingClientRect();
89
90
  const x = xScaleRef.current(getKeyRef.current(next)) ?? 0;
90
91
  scheduleAnchor({ x: rect.left + x, y: rect.top });
91
- store.set(getKeyRef.current(next), chartId);
92
+ store.set(getKeyRef.current(next), chartId, kind);
92
93
  },
93
- [data, store, chartId, clear, scheduleAnchor]
94
+ [data, store, chartId, clear, scheduleAnchor, kind]
94
95
  );
95
- const point = cursor.key === null ? null : resolveCursorPoint(index, cursor.key);
96
+ const point = cursor.key === null || cursor.kind !== kind ? null : resolveCursorPoint(index, cursor.key);
96
97
  return {
97
98
  point,
98
99
  isSource: cursor.source === chartId,
@@ -21,7 +21,7 @@ export { ChartFrame, type ChartFrameProps, type ChartFrameLegend, type PlotRect,
21
21
  export { ChartCenter, type ChartCenterProps, ChartPending, type ChartPendingProps, } from './primitives/ChartPending.js';
22
22
  export { Crosshair, SeriesDot } from './primitives/Crosshair.js';
23
23
  export { HatchPattern, hatchFill, hatchSizeFor } from './primitives/HatchPattern.js';
24
- export { ChartCard } from './primitives/ChartCard.js';
24
+ export { ChartCard, type ChartCardProps } from './primitives/ChartCard.js';
25
25
  export { ChartLegend, type LegendEntry } from './primitives/ChartLegend.js';
26
26
  export { ChartTooltipFloat, TooltipHeader, TooltipRow, TooltipBody, } from './primitives/ChartTooltip.js';
27
27
  export { AxisBottomDate, AxisLeftNumeric, AxisRightNumeric } from './primitives/Axes.js';
@@ -31,7 +31,7 @@ export { XZoneRects, type XZoneSpec } from './primitives/XZoneRects.js';
31
31
  export { AreaGradient, areaFillUrl } from './primitives/AreaGradient.js';
32
32
  export { useChartCursor, type ChartCursor, type CursorAnchor } from './hooks/useChartCursor.js';
33
33
  export { foldBands, type BandFold, type BandTooltipConfig, type BandTooltipRowContext, } from './hooks/useBandPlot.js';
34
- export type { CursorResolution } from './cursor/resolve.js';
34
+ export type { CursorResolution, DomainKind } from './cursor/resolve.js';
35
35
  export { useChartSize, type UseChartSizeResult, type ChartSize } from './hooks/useChartSize.js';
36
36
  export { fmtAxisDate, fmtTooltipDate } from './utils/format.js';
37
37
  export { smartTicks, smartTicksEvery } from './utils/ticks.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/charts/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/charts/index.ts"],"names":[],"mappings":"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"}
@@ -1,14 +1,39 @@
1
- import type { ReactNode } from 'react';
2
1
  /**
3
- * Standard wrapper for every visx chart — card with info-tooltip title + optional
4
- * subtitle (the question the chart answers) + optional extra slot (current value
5
- * badge etc.). Do not wrap visx charts in bare divs.
2
+ * Standard wrapper for every visx chart (docs/CONTROLS-SPEC.md §2.2) — card with a `WidgetHeader
3
+ * tier="widget"` title row (icon/info/value/delta/count/actions) plus an optional subtitle, over a
4
+ * clipped chart body. Do not wrap visx charts in bare divs.
5
+ *
6
+ * `WidgetHeader` lives in `src/widget-header/` and is itself Mantine-free, so composing it here
7
+ * keeps `./charts` resolving with no `@mantine/*` installed (`check-dist-layering.mjs`,
8
+ * `basalt/token-layer-boundary`). The `actions` slot cannot mount `CtlSlot` (Mantine-coupled) for
9
+ * the same reason — it carries only `data-basalt-tier="widget"`; a basalt control placed there
10
+ * sizes itself (`size="ctl"` internally), and a raw Mantine element is not auto-tiered.
11
+ *
12
+ * The header renders only when at least one of title/info/value/actions/icon/count is set — ending
13
+ * the `''`-as-hidden-header sentinel a consumer used to reach for otherwise.
6
14
  */
7
- export declare function ChartCard({ title, subtitle, tooltip, extra, children, }: {
8
- title: string;
15
+ import type { ReactNode } from 'react';
16
+ export type ChartCardProps = {
17
+ /** Optional — the header renders only when this or one of info/value/actions/icon/count is set. */
18
+ title?: string;
19
+ /** Optional leading icon, forwarded to `WidgetHeader`. */
20
+ icon?: ReactNode;
21
+ /** Optional muted line rendered below the title row — does NOT by itself trigger the header. */
9
22
  subtitle?: string;
10
- tooltip: string;
11
- extra?: ReactNode;
23
+ /** Renders `WidgetHeader`'s info glyph beside the title — a `More information` button whose
24
+ * bubble opens on hover, focus and click. Never part of the heading's accessible name. */
25
+ info?: string;
26
+ /** Pre-formatted metric value, on the hero-metric row with `delta`. */
27
+ value?: string;
28
+ /** Signed delta rendered via `DeltaBadge`, alongside `value`. */
29
+ delta?: number;
30
+ /** Comparison timeframe forwarded to `DeltaBadge` (e.g. `MoM`). */
31
+ deltaPeriod?: string;
32
+ /** Mono count tag after the title. */
33
+ count?: number;
34
+ /** Right-aligned slot — carries `data-basalt-tier="widget"` (no `CtlSlot`; see module doc). */
35
+ actions?: ReactNode;
12
36
  children: ReactNode;
13
- }): import("react").JSX.Element;
37
+ };
38
+ export declare function ChartCard({ title, icon, subtitle, info, value, delta, deltaPeriod, count, actions, children, }: ChartCardProps): import("react").JSX.Element;
14
39
  //# sourceMappingURL=ChartCard.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ChartCard.d.ts","sourceRoot":"","sources":["../../../src/charts/primitives/ChartCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,SAAS,EAAE,MAAM,OAAO,CAAA;AAkJrD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,QAAQ,EACR,OAAO,EACP,KAAK,EACL,QAAQ,GACT,EAAE;IACD,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,SAAS,CAAA;IACjB,QAAQ,EAAE,SAAS,CAAA;CACpB,+BAgBA"}
1
+ {"version":3,"file":"ChartCard.d.ts","sourceRoot":"","sources":["../../../src/charts/primitives/ChartCard.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAiB,SAAS,EAAE,MAAM,OAAO,CAAA;AAuCrD,MAAM,MAAM,cAAc,GAAG;IAC3B,mGAAmG;IACnG,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,0DAA0D;IAC1D,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,gGAAgG;IAChG,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;8FAC0F;IAC1F,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,iEAAiE;IACjE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,+FAA+F;IAC/F,OAAO,CAAC,EAAE,SAAS,CAAA;IACnB,QAAQ,EAAE,SAAS,CAAA;CACpB,CAAA;AAED,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,IAAI,EACJ,QAAQ,EACR,IAAI,EACJ,KAAK,EACL,KAAK,EACL,WAAW,EACX,KAAK,EACL,OAAO,EACP,QAAQ,GACT,EAAE,cAAc,+BAgChB"}
@@ -1,76 +1,6 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
- import { useEffect, useId, useRef, useState } from "react";
3
2
  import { VX } from "../../tokens/index.js";
4
- const infoWrapStyle = {
5
- position: "relative",
6
- display: "inline-flex",
7
- alignItems: "center",
8
- marginLeft: 5
9
- };
10
- const infoTriggerStyle = {
11
- appearance: "none",
12
- background: "none",
13
- border: "none",
14
- padding: 0,
15
- margin: 0,
16
- cursor: "help",
17
- display: "inline-flex",
18
- alignItems: "center"
19
- };
20
- const bubbleStyle = {
21
- position: "absolute",
22
- top: "calc(100% + 7px)",
23
- left: 0,
24
- zIndex: 10,
25
- maxWidth: 260,
26
- width: "max-content",
27
- padding: "7px 10px",
28
- borderRadius: VX.radiusCard,
29
- backgroundColor: VX.surface.panel,
30
- boxShadow: VX.shadowCard,
31
- color: VX.muted,
32
- fontSize: VX.text.sm,
33
- fontWeight: 400,
34
- lineHeight: 1.4,
35
- whiteSpace: "normal",
36
- pointerEvents: "none"
37
- };
38
- function InfoIcon({ title }) {
39
- const [open, setOpen] = useState(false);
40
- const tipId = useId();
41
- const triggerRef = useRef(null);
42
- useEffect(() => {
43
- if (!open) return;
44
- const handlePointerDown = (event) => {
45
- if (triggerRef.current?.contains(event.target)) return;
46
- setOpen(false);
47
- };
48
- document.addEventListener("pointerdown", handlePointerDown);
49
- return () => document.removeEventListener("pointerdown", handlePointerDown);
50
- }, [open]);
51
- return /* @__PURE__ */ jsxs("span", { style: infoWrapStyle, children: [
52
- /* @__PURE__ */ jsx(
53
- "button",
54
- {
55
- ref: triggerRef,
56
- type: "button",
57
- "aria-label": "More information",
58
- "aria-describedby": open ? tipId : void 0,
59
- onMouseEnter: () => setOpen(true),
60
- onMouseLeave: () => setOpen(false),
61
- onFocus: () => setOpen(true),
62
- onBlur: () => setOpen(false),
63
- onClick: () => setOpen(true),
64
- onKeyDown: (event) => {
65
- if (event.key === "Escape") setOpen(false);
66
- },
67
- style: { ...infoTriggerStyle, color: open ? VX.muted : VX.faint },
68
- children: /* @__PURE__ */ jsx("svg", { width: 11, height: 11, viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M12 0C5.373 0 0 5.373 0 12s5.373 12 12 12 12-5.373 12-12S18.627 0 12 0zm0 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3zm0 5a1 1 0 0 1 1 1v7a1 1 0 1 1-2 0v-7a1 1 0 0 1 1-1z" }) })
69
- }
70
- ),
71
- open && /* @__PURE__ */ jsx("span", { id: tipId, role: "tooltip", style: bubbleStyle, children: title })
72
- ] });
73
- }
3
+ import { WidgetHeader } from "../../widget-header/index.js";
74
4
  const cardStyle = {
75
5
  borderRadius: VX.radiusCard,
76
6
  boxShadow: VX.shadowCard,
@@ -85,57 +15,42 @@ const bodyClipStyle = {
85
15
  borderBottomLeftRadius: VX.radiusCard,
86
16
  borderBottomRightRadius: VX.radiusCard,
87
17
  overflow: "hidden",
88
- padding: "2px var(--mantine-spacing-sm, 0.75rem) var(--mantine-spacing-xs, 0.625rem)"
89
- };
90
- const headerStyle = {
91
- display: "flex",
92
- justifyContent: "space-between",
93
- alignItems: "center",
94
- // Card inset = spacing xs (vertical) / sm (horizontal). The `--mantine-spacing-*` vars carry
95
- // basalt's OWNED scale (theme.spacing.xs 0.625rem / sm 0.75rem); the rem fallbacks keep a
96
- // Mantine-free `./charts`-only consumer (no MantineProvider vars) padded identically. No
97
- // header/body divider — the title block and the plot read as one continuous surface; a rule here
98
- // only doubled the card's shadow-embedded ring and made the header feel heavier.
99
- padding: "var(--mantine-spacing-xs, 0.625rem) var(--mantine-spacing-sm, 0.75rem) 4px"
100
- };
101
- const titleColumnStyle = {
102
- display: "inline-flex",
103
- flexDirection: "column",
104
- lineHeight: 1.15
18
+ padding: "2px var(--mantine-spacing-sm, 0.8125rem) var(--mantine-spacing-xs, 0.6875rem)"
105
19
  };
106
- const titleStyle = {
107
- display: "inline-flex",
108
- alignItems: "center",
109
- fontFamily: "var(--basalt-font-head)",
110
- fontStretch: "88%",
111
- fontWeight: 550,
112
- fontSize: VX.text.md,
113
- color: VX.ink
114
- };
115
- const subtitleStyle = {
116
- fontSize: VX.text.sm,
117
- fontWeight: 400,
118
- color: VX.muted,
119
- marginTop: 1
20
+ const headerWrapStyle = {
21
+ padding: "var(--mantine-spacing-xs, 0.6875rem) var(--mantine-spacing-sm, 0.8125rem) 4px"
120
22
  };
121
23
  function ChartCard({
122
24
  title,
25
+ icon,
123
26
  subtitle,
124
- tooltip,
125
- extra,
27
+ info,
28
+ value,
29
+ delta,
30
+ deltaPeriod,
31
+ count,
32
+ actions,
126
33
  children
127
34
  }) {
35
+ const hasHeader = title !== void 0 || info !== void 0 || value !== void 0 || actions !== void 0 || icon !== void 0 || count !== void 0;
128
36
  return /* @__PURE__ */ jsxs("div", { style: cardStyle, children: [
129
- /* @__PURE__ */ jsxs("div", { style: headerStyle, children: [
130
- /* @__PURE__ */ jsxs("span", { style: titleColumnStyle, children: [
131
- /* @__PURE__ */ jsxs("span", { style: titleStyle, children: [
132
- title,
133
- /* @__PURE__ */ jsx(InfoIcon, { title: tooltip })
134
- ] }),
135
- subtitle !== void 0 && /* @__PURE__ */ jsx("span", { style: subtitleStyle, children: subtitle })
136
- ] }),
137
- extra !== void 0 && /* @__PURE__ */ jsx("span", { children: extra })
138
- ] }),
37
+ hasHeader && /* @__PURE__ */ jsx("div", { style: headerWrapStyle, children: /* @__PURE__ */ jsx(
38
+ WidgetHeader,
39
+ {
40
+ tier: "widget",
41
+ title: title ?? "",
42
+ ...icon !== void 0 && { icon },
43
+ ...subtitle !== void 0 && { subtitle },
44
+ ...info !== void 0 && { info },
45
+ ...value !== void 0 && { value },
46
+ ...delta !== void 0 && { delta },
47
+ ...deltaPeriod !== void 0 && { deltaPeriod },
48
+ ...count !== void 0 && { count },
49
+ ...actions !== void 0 && {
50
+ actions: /* @__PURE__ */ jsx("span", { "data-basalt-tier": "widget", children: actions })
51
+ }
52
+ }
53
+ ) }),
139
54
  /* @__PURE__ */ jsx("div", { style: bodyClipStyle, children })
140
55
  ] });
141
56
  }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ChartCard.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChartCard.test.d.ts","sourceRoot":"","sources":["../../../src/charts/primitives/ChartCard.test.tsx"],"names":[],"mappings":""}
@@ -3,11 +3,35 @@ type BarSparklineProps = {
3
3
  width: number;
4
4
  height: number;
5
5
  color?: string;
6
+ /**
7
+ * Gap between two bars, in px. `1` is the shipped look; `2` at ~10 bars reads as a discrete series
8
+ * rather than a histogram, which is the KPI-card treatment.
9
+ *
10
+ * @default 1
11
+ */
12
+ barGap?: number;
13
+ /**
14
+ * Bar corner radius, in px. `0` is the shipped look.
15
+ *
16
+ * @default 0
17
+ */
18
+ barRadius?: number;
19
+ /**
20
+ * Paints the LAST bar in `emphasisColor` at full opacity — "this is where the series ends", the
21
+ * one reading a trend beside a KPI value is actually for. Off by default: a chart that means
22
+ * something by its final point must say so.
23
+ *
24
+ * @default false
25
+ */
26
+ emphasizeLast?: boolean;
27
+ /** The emphasised bar's fill. @default `VX.accent` */
28
+ emphasisColor?: string;
6
29
  /** Accessible text alternative, applied as `aria-label` (+ `role="img"`) on the `<svg>`. */
7
30
  ariaLabel?: string;
8
31
  };
9
32
  /** Quiet inline bar trend — defaults to `VX.faint`, matching the sparkline family's restrained
10
- * identity (docs/DESIGN-SPEC.md §5). */
11
- export declare function BarSparkline({ data, width, height, color, ariaLabel }: BarSparklineProps): import("react").JSX.Element;
33
+ * identity (docs/DESIGN-SPEC.md §5). Every geometry option below defaults to the shipped look, so
34
+ * an existing call site renders byte-identically. */
35
+ export declare function BarSparkline({ data, width, height, color, barGap, barRadius, emphasizeLast, emphasisColor, ariaLabel, }: BarSparklineProps): import("react").JSX.Element;
12
36
  export {};
13
37
  //# sourceMappingURL=BarSparkline.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"BarSparkline.d.ts","sourceRoot":"","sources":["../../../src/charts/sparklines/BarSparkline.tsx"],"names":[],"mappings":"AAIA,KAAK,iBAAiB,GAAG;IACvB,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,4FAA4F;IAC5F,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;wCACwC;AACxC,wBAAgB,YAAY,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,iBAAiB,+BAgCxF"}
1
+ {"version":3,"file":"BarSparkline.d.ts","sourceRoot":"","sources":["../../../src/charts/sparklines/BarSparkline.tsx"],"names":[],"mappings":"AAIA,KAAK,iBAAiB,GAAG;IACvB,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,sDAAsD;IACtD,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,4FAA4F;IAC5F,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;qDAEqD;AACrD,wBAAgB,YAAY,CAAC,EAC3B,IAAI,EACJ,KAAK,EACL,MAAM,EACN,KAAK,EACL,MAAU,EACV,SAAa,EACb,aAAqB,EACrB,aAAa,EACb,SAAS,GACV,EAAE,iBAAiB,+BAoCnB"}
@@ -2,8 +2,19 @@ import { jsx } from "react/jsx-runtime";
2
2
  import { scaleLinear } from "@visx/scale";
3
3
  import { useMemo } from "react";
4
4
  import { VX } from "../../tokens/index.js";
5
- function BarSparkline({ data, width, height, color, ariaLabel }) {
5
+ function BarSparkline({
6
+ data,
7
+ width,
8
+ height,
9
+ color,
10
+ barGap = 1,
11
+ barRadius = 0,
12
+ emphasizeLast = false,
13
+ emphasisColor,
14
+ ariaLabel
15
+ }) {
6
16
  const fillColor = color ?? VX.faint;
17
+ const lastColor = emphasisColor ?? VX.accent;
7
18
  const a11yProps = ariaLabel !== void 0 ? { role: "img", "aria-label": ariaLabel } : {};
8
19
  const yScale = useMemo(() => {
9
20
  const max = Math.max(...data.filter((v) => isFinite(v)), 1);
@@ -11,9 +22,11 @@ function BarSparkline({ data, width, height, color, ariaLabel }) {
11
22
  }, [data, height]);
12
23
  if (!data.length) return /* @__PURE__ */ jsx("svg", { width, height, ...a11yProps });
13
24
  const step = width / data.length;
14
- const barWidth = Math.max(step - 1, 1);
25
+ const barWidth = Math.max(step - barGap, 1);
26
+ const lastIndex = data.length - 1;
15
27
  return /* @__PURE__ */ jsx("svg", { width, height, ...a11yProps, children: data.map((v, i) => {
16
28
  const bh = Math.max(yScale(Math.max(v, 0)), 0);
29
+ const isLast = emphasizeLast && i === lastIndex;
17
30
  return /* @__PURE__ */ jsx(
18
31
  "rect",
19
32
  {
@@ -21,8 +34,9 @@ function BarSparkline({ data, width, height, color, ariaLabel }) {
21
34
  y: height - bh,
22
35
  width: barWidth,
23
36
  height: bh,
24
- fill: fillColor,
25
- fillOpacity: 0.75
37
+ ...barRadius > 0 && { rx: barRadius },
38
+ fill: isLast ? lastColor : fillColor,
39
+ fillOpacity: isLast ? 1 : 0.75
26
40
  },
27
41
  i
28
42
  );
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=check-coverage.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-coverage.test.d.ts","sourceRoot":"","sources":["../../src/cli/check-coverage.test.ts"],"names":[],"mappings":""}