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
@@ -158,7 +158,24 @@ const SPACE_ANCHORS_BASE = {
158
158
  * (both read {@link CONTROL_HEIGHT_BASE}), so a Button/ActionIcon placed beside a `size="md"`
159
159
  * Input tracks it at every density level instead of only coinciding at level 0 (the defect this
160
160
  * anchor fixes — Mantine's own `--button-height-md`/`--ai-size` are static, density-blind). */
161
- controlHeight: CONTROL_HEIGHT_BASE
161
+ controlHeight: CONTROL_HEIGHT_BASE,
162
+ /** The `size="icon"` count-tag height (`docs/CONTROLS-SPEC.md` §5) — inline chip / table-cell
163
+ * count badge. Floored at 18px in {@link deriveSpacing} (same "negative level can't collapse a
164
+ * real control below a legible/tappable minimum" reasoning as `sidebarSearchTriggerHeight`'s WCAG
165
+ * floor, one notch tighter since a count tag is a badge, not a primary interactive target). */
166
+ controlHeightTag: 20,
167
+ /** The `size="icon"` ActionIcon height (`docs/CONTROLS-SPEC.md` §5) — `WidgetHeader
168
+ * tier="widget"` actions. Floored at 22px in {@link deriveSpacing}. */
169
+ controlHeightWidget: 24,
170
+ /** The `size="ctl"` Mantine tier's resolved height (`docs/CONTROLS-SPEC.md` §5, C5) —
171
+ * `PageBar`/`Section`/table toolbar/sidebar-block controls. Floored at 28px in
172
+ * {@link deriveSpacing}. */
173
+ controlHeightCtl: 30,
174
+ /** The touch hit-area size (`::before`) every home control expands to below `sm` (C15,
175
+ * `docs/CONTROLS-SPEC.md` §5) — independent of the visible `controlHeightCtl` box, same shape as
176
+ * `mobileNavBarHeight`/`mobileNavRowHeight`'s Apple HIG 44pt / WCAG 2.5.5 floors elsewhere in this
177
+ * table. Floored at 30px in {@link deriveSpacing} (C15's "floor 30 at density −3"). */
178
+ touchControlHeight: 36
162
179
  };
163
180
  const SPACE_SCALE_BASE = {
164
181
  xs: 11,
@@ -171,14 +188,13 @@ const SPACE_STEP_BASE = {
171
188
  /** Timeline `defaultProps.bulletSize`. */
172
189
  timelineBullet: 22,
173
190
  // ── Shared across ≥2 sites (structural — must render at the same value) ──────────────────────
174
- // `stickyHeaderClearance`/`stickyHeaderClearanceMobile` USED to live here as ONE independent base
175
- // literal (84) — they don't any more. Both are DERIVED, post-`step`, from their OWN AppShell
176
- // header (`appShellHeaderHeight` / `appShellHeaderMobileHeight` below) instead (see
177
- // {@link deriveSpacing}'s doc for why): an independent literal could drift from the header it's
178
- // supposed to clear, which is exactly what happened (84 < 96, under-clearing the mobile header at
179
- // every level before this fix) — and a SINGLE derived value still over-cleared the desktop header
180
- // by 60px, since the desktop header is less than half the mobile one's height. `SpaceValues.step`
181
- // still carries both keys — see that type's own doc — they're just not part of this BASE table.
191
+ // `stickyHeaderClearance` USED to live here as an independent base literal (84) — it doesn't any
192
+ // more. It is DERIVED, post-`step`, from the AppShell header it exists to clear
193
+ // (`appShellHeaderHeight` below) instead (see {@link deriveSpacing}'s doc for why): an independent
194
+ // literal could drift from that header, which is exactly what happened. `SpaceValues.step` still
195
+ // carries the key — see that type's own doc — it is just not part of this BASE table. The
196
+ // `stickyHeaderClearanceMobile` sibling went with the two-row mobile header in 1.26.0: the header
197
+ // is one 48px row at every viewport now, so one clearance covers both.
182
198
  /** NavLink leftSection icon-to-label gap — shared by `theme/nav-link.module.css` (every render
183
199
  * path) and `shell/app-sidebar.module.css`'s own `.link` rule (belt-and-suspenders on the same
184
200
  * DOM), and reused verbatim for `.footerBtn`/`.accountRow`'s icon gap (their own doc comments call
@@ -375,35 +391,28 @@ const SPACE_STEP_BASE = {
375
391
  sidebarAccountMenuWidth: 220,
376
392
  /** Settings-menu `<Menu width={…}>` (`app-sidebar.tsx`). */
377
393
  sidebarSettingsMenuWidth: 200,
378
- // ── shell/app-header.module.css ───────────────────────────────────────────────────────────────
379
- /** Mobile two-row header's page-actions row height. */
380
- appHeaderMobileActionsHeight: 52,
381
394
  // ── shell/index.tsx (AppShell dimensions) ──────────────────────────────────────────────
382
395
  /** AppShell desktop header bar height — sized to hold one row of `size="md"` controls, so it
383
396
  * tracks `controlHeight`. Its level-0 coincidence with `appShellNavbarRailWidth` below is a
384
397
  * coincidence, not a law: this is a horizontal bar's HEIGHT (governed by control height), that
385
398
  * is a vertical rail's WIDTH (governed by icon footprint). They stay separate entries. */
399
+ /** AppShell header bar height — ONE value at every viewport since 1.26.0 (law C14,
400
+ * `docs/CONTROLS-SPEC.md` §2.1). The pre-1.26.0 `appShellHeaderMobileHeight` (97) existed only
401
+ * because the mobile header wrapped to a second, always-reserved page-actions row; `PageBar`
402
+ * folds that row's overflow into a kebab and moves its filters/tabs into the page flow, so the
403
+ * bar is 48px on a phone too and there is no sum to keep in step any more. */
386
404
  appShellHeaderHeight: 48,
387
- /** AppShell mobile (two-row) header height. Not one concept but a sum: row 1 + `app-header.
388
- * module.css`'s wrap row-gap (`--mantine-spacing-sm`) + `appHeaderMobileActionsHeight`. Two of
389
- * those three addends already track density, so the container must too — held fixed, row 1's
390
- * budget collapses 52px -> 12px across the level range.
405
+ /** AppShell navbar width, expanded — ONE entry for both the `base` (mobile, where the navbar is
406
+ * permanently collapsed and unused — see `MobileNav`) and the expanded `sm` value: the same
407
+ * `.root` at full width, genuinely one concept.
391
408
  *
392
- * KEEP THIS EQUAL TO THE SUM. At level 0: 32 (row 1) + 13 (`SPACE_SCALE.sm`) + 52
393
- * (`appHeaderMobileActionsHeight`) = 97. It was 96 while `SPACE_SCALE.sm` was 12; the
394
- * component-roominess retune raised that addend, and leaving the total at 96 silently took the
395
- * pixel out of row 1 instead — which is what ate the last of its WCAG 2.5.8 target-size margin at
396
- * density -3 (`theme/density-relations.test.ts` measures row 1 as the REMAINDER of this sum, so
397
- * the total is the only place the budget can come from). Raise this whenever `SPACE_SCALE.sm` or
398
- * `appHeaderMobileActionsHeight` moves. Better still, make it unnecessary: computing this the way
399
- * `stickyHeaderClearance*` already is — post-`step`, from its own addends rather than as an
400
- * independent literal — would make the drift impossible instead of merely re-tuned. That is the
401
- * same refactor, and the same reasoning, this PR applied to the clearances; it is worth doing to
402
- * this one too, and it stays a follow-up only because it moves every non-zero level's value. */
403
- appShellHeaderMobileHeight: 97,
404
- /** AppShell navbar width, expanded — ONE entry for both the `base` (mobile drawer) and the
405
- * expanded `sm` value: the same `.root` at full width, genuinely one concept. */
406
- appShellNavbarWidth: 216,
409
+ * 256, up from 216. At 216 the column was 196px of usable text after `.root`'s 10px inset a side,
410
+ * and the sidebar carries more than nav rows: a block row is `label · meta`, an account row is
411
+ * `avatar · name · plan`, and a `Recents` entry is a sentence. Every one of them was ellipsizing
412
+ * in the second word. 256 is also the width the shell's own dropdowns already assume
413
+ * (`sidebarAccountMenuWidth` 220 + the row inset), so the menu no longer overhangs the column it
414
+ * belongs to. */
415
+ appShellNavbarWidth: 256,
407
416
  /** AppShell navbar width, collapsed icon rail. Separate from `appShellHeaderHeight` above
408
417
  * despite sharing 48 at level 0 (see that entry's note). */
409
418
  appShellNavbarRailWidth: 48,
@@ -482,7 +491,33 @@ const SPACE_STEP_BASE = {
482
491
  /** `data/virtual-list.tsx`'s skeleton row vertical inset. */
483
492
  virtualRowInsetY: 8,
484
493
  /** `data/virtual-list.tsx`'s skeleton row horizontal inset. */
485
- virtualRowInsetX: 12
494
+ virtualRowInsetX: 12,
495
+ // ── Controls — homes/tiers (`docs/CONTROLS-SPEC.md` §5) ──────────────────────────────────────
496
+ /** `PageBar` row height (row 1 or row 2, each measured independently — the bar's own overall
497
+ * height is the sum published as `--basalt-page-bar-h`, computed by `PageBar` itself, not a
498
+ * static token). */
499
+ pageBarRowHeight: 40,
500
+ /** `WidgetHeader tier="section"` row height. */
501
+ sectionHeaderHeight: 36,
502
+ /** `WidgetHeader tier="widget"` row height. */
503
+ widgetHeaderHeight: 28,
504
+ /** Sidebar block list-item row height. */
505
+ sidebarBlockRowHeight: 32,
506
+ /** Gap between adjacent controls inside a home (filter pills, action buttons). */
507
+ controlGap: 6,
508
+ /** Mobile bottom-sheet row height (the `Filters (n)` drawer, a block's More-sheet row) — Apple
509
+ * HIG 44pt / WCAG 2.5.5 AAA, same floor family as `mobileNavRowHeight`. */
510
+ sheetRowHeight: 44,
511
+ /** `BasaltDataTable`'s header row. Its own entry rather than a reuse of `sectionHeaderHeight`
512
+ * (which is 36 too at level 0): one is a heading's box, this is a table's `th`, and a density
513
+ * pass that wants denser table rows must not be forced to shrink every section header with them.
514
+ * Mantine sizes both `th` and `td` from ONE `verticalSpacing` prop, so a 36/40 pair is
515
+ * unreachable through it — both are applied in `theme/index.ts`'s `Table.extend` as JS numbers,
516
+ * which is why (like `progressBarSize`) neither is emitted as a `--vx-*` var. */
517
+ tableHeaderHeight: 36,
518
+ /** `BasaltDataTable`'s body row — one step taller than the header, so the mono uppercase `th`
519
+ * reads as a label band over roomier data rows rather than as the first row of the data. */
520
+ tableRowHeight: 40
486
521
  };
487
522
  const SPACE_FIXED = {
488
523
  /** Timeline `defaultProps.lineWidth`; also used for 1px borders. */
@@ -530,18 +565,21 @@ function deriveSpacing(level) {
530
565
  anchors.stackMd = stackUnit * 3;
531
566
  anchors.stackLg = stackUnit * 4;
532
567
  anchors.stackXl = stackUnit * 6;
568
+ anchors.controlHeightTag = Math.max(18, anchors.controlHeightTag);
569
+ anchors.controlHeightWidget = Math.max(22, anchors.controlHeightWidget);
570
+ anchors.controlHeightCtl = Math.max(28, anchors.controlHeightCtl);
571
+ anchors.touchControlHeight = Math.max(30, anchors.touchControlHeight);
533
572
  const mappedStep = mapSpaceGroup(SPACE_STEP_BASE, level, multiplier);
534
573
  mappedStep.sidebarSearchTriggerHeight = Math.max(24, mappedStep.sidebarSearchTriggerHeight);
535
574
  mappedStep.mobileNavBarHeight = Math.max(48, mappedStep.mobileNavBarHeight);
536
575
  mappedStep.mobileNavRowHeight = Math.max(44, mappedStep.mobileNavRowHeight);
576
+ mappedStep.sheetRowHeight = Math.max(44, mappedStep.sheetRowHeight);
537
577
  const step = {
538
578
  ...mappedStep,
539
- // RESPONSIVE, one per AppShell breakpoint — each DERIVED from its own header, plus
540
- // density-tracking breathing room — see this function's doc (third bullet, Decision 3) for the
541
- // full rationale, and `theme/spacing.test.ts` for why `stickyHeaderClearance` alone is exempt
542
- // from the level-0 byte-identity gate.
543
- stickyHeaderClearance: mappedStep.appShellHeaderHeight + anchors.stackMd,
544
- stickyHeaderClearanceMobile: mappedStep.appShellHeaderMobileHeight + anchors.stackMd
579
+ // DERIVED from the header it clears, plus density-tracking breathing room — see this function's
580
+ // doc (third bullet) for the full rationale, and `theme/spacing.test.ts` for why
581
+ // `stickyHeaderClearance` alone is exempt from the level-0 byte-identity gate.
582
+ stickyHeaderClearance: mappedStep.appShellHeaderHeight + anchors.stackMd
545
583
  };
546
584
  return {
547
585
  anchors,
package/dist/tokens.css CHANGED
@@ -10,13 +10,16 @@
10
10
  --vx-space-row-line-height: 1.35;
11
11
  --vx-space-input-height: 2.625rem;
12
12
  --vx-space-control-height: 2.625rem;
13
+ --vx-space-control-height-tag: 1.25rem;
14
+ --vx-space-control-height-widget: 1.5rem;
15
+ --vx-space-control-height-ctl: 1.875rem;
16
+ --vx-space-touch-control-height: 2.25rem;
13
17
  --vx-space-stack-xs: 4px;
14
18
  --vx-space-stack-sm: 8px;
15
19
  --vx-space-stack-md: 12px;
16
20
  --vx-space-stack-lg: 16px;
17
21
  --vx-space-stack-xl: 24px;
18
22
  --vx-space-sticky-header-clearance: 60px;
19
- --vx-space-sticky-header-clearance-mobile: 109px;
20
23
  --vx-space-nav-icon-gap: 10px;
21
24
  --vx-space-sidebar-region-gap: 10px;
22
25
  --vx-space-prose-quote-inset-y: 2px;
@@ -93,7 +96,6 @@
93
96
  --vx-space-sidebar-child-list-indent: 15px;
94
97
  --vx-space-sidebar-child-row-inset-y: 4px;
95
98
  --vx-space-sidebar-child-row-indent: 12px;
96
- --vx-space-app-header-mobile-actions-height: 52px;
97
99
  --vx-space-mobile-nav-tab-gap: 3px;
98
100
  --vx-space-mobile-nav-icon-size: 24px;
99
101
  --vx-space-mobile-nav-tab-inset-y: 2px;
@@ -113,6 +115,12 @@
113
115
  --vx-space-stat-card-gap: 8px;
114
116
  --vx-space-virtual-row-inset-y: 8px;
115
117
  --vx-space-virtual-row-inset-x: 12px;
118
+ --vx-space-page-bar-row-height: 2.5rem;
119
+ --vx-space-section-header-height: 2.25rem;
120
+ --vx-space-widget-header-height: 1.75rem;
121
+ --vx-space-sidebar-block-row-height: 2rem;
122
+ --vx-space-control-gap: 6px;
123
+ --vx-space-sheet-row-height: 2.75rem;
116
124
  --vx-prose-measure: 72ch;
117
125
  --vx-fill-gray: #717176;
118
126
  --vx-fill-red: #b7514e;
@@ -0,0 +1,13 @@
1
+ export type DeltaBadgeProps = {
2
+ /** Signed delta driving tone (positive/negative/zero) and, by default, the label magnitude. */
3
+ value: number;
4
+ /** Formats the value into the label text. Defaults to `${Math.abs(value).toFixed(1)}%`. */
5
+ format?: (value: number) => string;
6
+ /** Render the ▲/▼ direction glyph. Defaults to `true`; a zero value never shows a glyph. */
7
+ withGlyph?: boolean;
8
+ /** Optional comparison timeframe rendered directly after the value in a dimmer shade of the same
9
+ * tone (e.g. `MoM`, `WoW`, `YTD`) — states what the delta is measured against without a hover. */
10
+ period?: string | undefined;
11
+ };
12
+ export declare function DeltaBadge({ value, format, withGlyph, period, }: DeltaBadgeProps): import("react").JSX.Element;
13
+ //# sourceMappingURL=delta-badge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delta-badge.d.ts","sourceRoot":"","sources":["../../src/widget-header/delta-badge.tsx"],"names":[],"mappings":"AAsBA,MAAM,MAAM,eAAe,GAAG;IAC5B,+FAA+F;IAC/F,KAAK,EAAE,MAAM,CAAA;IACb,2FAA2F;IAC3F,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;IAClC,4FAA4F;IAC5F,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;sGACkG;IAClG,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAC5B,CAAA;AAID,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,MAAsB,EACtB,SAAgB,EAChB,MAAM,GACP,EAAE,eAAe,+BAejB"}
@@ -0,0 +1,29 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { alpha, VX } from "../tokens/index.js";
3
+ import classes from "./widget-header.module.css";
4
+ const defaultFormat = (value) => `${Math.abs(value).toFixed(1)}%`;
5
+ function DeltaBadge({
6
+ value,
7
+ format = defaultFormat,
8
+ withGlyph = true,
9
+ period
10
+ }) {
11
+ const tone = value > 0 ? VX.status.good : value < 0 ? VX.status.bad : VX.faint;
12
+ const glyph = value > 0 ? "\u25B2" : value < 0 ? "\u25BC" : void 0;
13
+ const showGlyph = withGlyph && glyph !== void 0;
14
+ return /* @__PURE__ */ jsxs(
15
+ "span",
16
+ {
17
+ className: classes.deltaBadge,
18
+ style: { backgroundColor: alpha(tone, 0.13), color: tone },
19
+ children: [
20
+ showGlyph && /* @__PURE__ */ jsx("span", { className: classes.deltaGlyph, children: glyph }),
21
+ format(value),
22
+ period !== void 0 && /* @__PURE__ */ jsx("span", { className: classes.deltaPeriod, children: period })
23
+ ]
24
+ }
25
+ );
26
+ }
27
+ export {
28
+ DeltaBadge
29
+ };
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=delta-badge.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delta-badge.test.d.ts","sourceRoot":"","sources":["../../src/widget-header/delta-badge.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ export { WidgetHeader, type WidgetHeaderProps } from './widget-header.js';
2
+ export { DeltaBadge, type DeltaBadgeProps } from './delta-badge.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/widget-header/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AACtE,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,eAAe,CAAA"}
@@ -0,0 +1,6 @@
1
+ import { WidgetHeader } from "./widget-header.js";
2
+ import { DeltaBadge } from "./delta-badge.js";
3
+ export {
4
+ DeltaBadge,
5
+ WidgetHeader
6
+ };
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=no-mantine.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-mantine.test.d.ts","sourceRoot":"","sources":["../../src/widget-header/no-mantine.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,37 @@
1
+ import type { ReactNode } from 'react';
2
+ export type WidgetHeaderProps = {
3
+ /** `section` renders an `<h2>` at the section-header height; `widget` renders an `<h3>` at the
4
+ * tighter icon-tier height, display-only. */
5
+ tier: 'section' | 'widget';
6
+ /** Head-font title (88% stretch, weight 550). */
7
+ title: string;
8
+ /** Optional leading icon, rendered before the title. Decorative — hidden from assistive tech. */
9
+ icon?: ReactNode;
10
+ /** Optional muted line rendered below the title row. */
11
+ subtitle?: string;
12
+ /**
13
+ * Renders an info glyph BESIDE the heading (never inside it — this text would otherwise become
14
+ * part of the heading's accessible name, and an `info` paragraph read out in every headings list
15
+ * is what that cost). The glyph is named `More information`; the text itself reaches assistive
16
+ * tech through `aria-describedby` on a `role="tooltip"` bubble that opens on hover, focus and
17
+ * click — so a keyboard user gets it too. Mantine-free: a plain state bubble, not a Tooltip.
18
+ */
19
+ info?: string;
20
+ /** Pre-formatted metric value (mono, hero size). Renders on its own row with `delta`, directly
21
+ * under the title row — never inline with the title. */
22
+ value?: string;
23
+ /** Signed delta rendered via `DeltaBadge`, on the same hero-metric row as `value`. */
24
+ delta?: number;
25
+ /** Comparison timeframe forwarded to `DeltaBadge` (e.g. `MoM`). */
26
+ deltaPeriod?: string;
27
+ /** Trend visual slot, rendered below the metric row. Carries `data-placement="right"` so a
28
+ * wave-3 composer's `bleed` layout can select it. */
29
+ sparkline?: ReactNode;
30
+ /** Mono count tag rendered after the title (C11 — every table/list states its count). `0` is a
31
+ * real count and renders, distinct from omitting the prop entirely. */
32
+ count?: number;
33
+ /** Right-aligned slot (`margin-inline-start: auto`) — the C1/C5 home for header actions. */
34
+ actions?: ReactNode;
35
+ };
36
+ export declare function WidgetHeader({ tier, title, icon, subtitle, info, value, delta, deltaPeriod, sparkline, count, actions, }: WidgetHeaderProps): import("react").JSX.Element;
37
+ //# sourceMappingURL=widget-header.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"widget-header.d.ts","sourceRoot":"","sources":["../../src/widget-header/widget-header.tsx"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAKtC,MAAM,MAAM,iBAAiB,GAAG;IAC9B;iDAC6C;IAC7C,IAAI,EAAE,SAAS,GAAG,QAAQ,CAAA;IAC1B,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAA;IACb,iGAAiG;IACjG,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,wDAAwD;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;4DACwD;IACxD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,sFAAsF;IACtF,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;yDACqD;IACrD,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB;2EACuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,4FAA4F;IAC5F,OAAO,CAAC,EAAE,SAAS,CAAA;CACpB,CAAA;AAyDD,wBAAgB,YAAY,CAAC,EAC3B,IAAI,EACJ,KAAK,EACL,IAAI,EACJ,QAAQ,EACR,IAAI,EACJ,KAAK,EACL,KAAK,EACL,WAAW,EACX,SAAS,EACT,KAAK,EACL,OAAO,GACR,EAAE,iBAAiB,+BAiCnB"}
@@ -0,0 +1,77 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useId, useRef, useState } from "react";
3
+ import { IconSlot } from "../theme/icon-slot.js";
4
+ import { DeltaBadge } from "./delta-badge.js";
5
+ import classes from "./widget-header.module.css";
6
+ function InfoGlyph({ text }) {
7
+ const [open, setOpen] = useState(false);
8
+ const tipId = useId();
9
+ const triggerRef = useRef(null);
10
+ useEffect(() => {
11
+ if (!open) return;
12
+ const handlePointerDown = (event) => {
13
+ if (triggerRef.current?.contains(event.target)) return;
14
+ setOpen(false);
15
+ };
16
+ document.addEventListener("pointerdown", handlePointerDown);
17
+ return () => document.removeEventListener("pointerdown", handlePointerDown);
18
+ }, [open]);
19
+ return /* @__PURE__ */ jsxs("span", { className: classes.info, children: [
20
+ /* @__PURE__ */ jsx(
21
+ "button",
22
+ {
23
+ ref: triggerRef,
24
+ type: "button",
25
+ className: classes.infoTrigger,
26
+ "aria-label": "More information",
27
+ "aria-describedby": open ? tipId : void 0,
28
+ "data-open": open,
29
+ onMouseEnter: () => setOpen(true),
30
+ onMouseLeave: () => setOpen(false),
31
+ onFocus: () => setOpen(true),
32
+ onBlur: () => setOpen(false),
33
+ onClick: () => setOpen(true),
34
+ onKeyDown: (event) => {
35
+ if (event.key === "Escape") setOpen(false);
36
+ },
37
+ 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" }) })
38
+ }
39
+ ),
40
+ open && /* @__PURE__ */ jsx("span", { id: tipId, role: "tooltip", className: classes.infoBubble, children: text })
41
+ ] });
42
+ }
43
+ function WidgetHeader({
44
+ tier,
45
+ title,
46
+ icon,
47
+ subtitle,
48
+ info,
49
+ value,
50
+ delta,
51
+ deltaPeriod,
52
+ sparkline,
53
+ count,
54
+ actions
55
+ }) {
56
+ const Heading = tier === "section" ? "h2" : "h3";
57
+ return /* @__PURE__ */ jsxs("div", { className: classes.root, "data-tier": tier, children: [
58
+ /* @__PURE__ */ jsxs("div", { className: classes.titleRow, children: [
59
+ /* @__PURE__ */ jsxs(Heading, { className: classes.heading, children: [
60
+ icon !== void 0 && /* @__PURE__ */ jsx(IconSlot, { className: classes.icon, children: icon }),
61
+ /* @__PURE__ */ jsx("span", { className: classes.titleText, children: title })
62
+ ] }),
63
+ info !== void 0 && /* @__PURE__ */ jsx(InfoGlyph, { text: info }),
64
+ count !== void 0 && /* @__PURE__ */ jsx("span", { className: classes.count, children: count }),
65
+ actions !== void 0 && /* @__PURE__ */ jsx("span", { className: classes.actions, children: actions })
66
+ ] }),
67
+ (value !== void 0 || delta !== void 0) && /* @__PURE__ */ jsxs("div", { className: classes.metrics, children: [
68
+ value !== void 0 && /* @__PURE__ */ jsx("span", { className: classes.value, children: value }),
69
+ delta !== void 0 && /* @__PURE__ */ jsx(DeltaBadge, { value: delta, period: deltaPeriod })
70
+ ] }),
71
+ subtitle !== void 0 && /* @__PURE__ */ jsx("span", { className: classes.subtitle, children: subtitle }),
72
+ sparkline !== void 0 && /* @__PURE__ */ jsx("div", { className: classes.sparkline, "data-placement": "right", children: sparkline })
73
+ ] });
74
+ }
75
+ export {
76
+ WidgetHeader
77
+ };