basalt-ui 1.27.0 → 1.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1063) hide show
  1. package/AGENTS.md +23 -23
  2. package/CHANGELOG.md +59 -0
  3. package/MIGRATING.md +613 -20
  4. package/README.md +33 -3
  5. package/agent/rules/basalt-batteries.md +25 -10
  6. package/agent/rules/basalt-controls.md +56 -31
  7. package/agent/rules/basalt-mantine.md +17 -6
  8. package/agent/rules/basalt-tokens.md +1 -1
  9. package/configs/oxlint-plugin.js +1056 -28
  10. package/configs/oxlint-plugin.test.ts +1066 -0
  11. package/configs/oxlint.json +7 -0
  12. package/dist/agent/coalesce.d.ts.map +1 -1
  13. package/dist/agent/coalesce.js +2 -1
  14. package/dist/agent/merge.d.ts.map +1 -1
  15. package/dist/agent/merge.js +2 -1
  16. package/dist/agent/part-list.d.ts.map +1 -1
  17. package/dist/agent/part-list.js +2 -0
  18. package/dist/agent/stick-to-bottom.d.ts +3 -6
  19. package/dist/agent/stick-to-bottom.d.ts.map +1 -1
  20. package/dist/agent/stick-to-bottom.js +6 -3
  21. package/dist/agent-chat/composer.d.ts +6 -2
  22. package/dist/agent-chat/composer.d.ts.map +1 -1
  23. package/dist/agent-chat/composer.js +49 -33
  24. package/dist/agent-chat/relative-time.d.ts +0 -9
  25. package/dist/agent-chat/relative-time.d.ts.map +1 -1
  26. package/dist/agent-chat/relative-time.js +2 -1
  27. package/dist/agent-chat/thread-detail-panel.d.ts +3 -2
  28. package/dist/agent-chat/thread-detail-panel.d.ts.map +1 -1
  29. package/dist/agent-chat/thread-detail-panel.js +8 -5
  30. package/dist/agent-chat/thread-feed-row.d.ts +2 -1
  31. package/dist/agent-chat/thread-feed-row.d.ts.map +1 -1
  32. package/dist/agent-chat/thread-feed-row.js +92 -92
  33. package/dist/agent-chat/thread-feed.d.ts +3 -2
  34. package/dist/agent-chat/thread-feed.d.ts.map +1 -1
  35. package/dist/agent-chat/thread-feed.js +8 -3
  36. package/dist/agent-chat/thread-message.d.ts +4 -3
  37. package/dist/agent-chat/thread-message.d.ts.map +1 -1
  38. package/dist/agent-chat/thread-message.js +70 -31
  39. package/dist/agent-chat/thread-outcome-card.d.ts +3 -2
  40. package/dist/agent-chat/thread-outcome-card.d.ts.map +1 -1
  41. package/dist/agent-chat/thread-outcome-card.js +9 -2
  42. package/dist/agent-chat/thread-workspace.d.ts +7 -2
  43. package/dist/agent-chat/thread-workspace.d.ts.map +1 -1
  44. package/dist/agent-chat/thread-workspace.js +62 -29
  45. package/dist/agent-chat/tool-chip.d.ts +3 -2
  46. package/dist/agent-chat/tool-chip.d.ts.map +1 -1
  47. package/dist/agent-chat/tool-chip.js +7 -2
  48. package/dist/charts/hooks/useBandPlot.d.ts.map +1 -1
  49. package/dist/charts/hooks/useBandPlot.js +15 -8
  50. package/dist/charts/index.d.ts +8 -7
  51. package/dist/charts/index.d.ts.map +1 -1
  52. package/dist/charts/index.js +45 -5
  53. package/dist/charts/kinds/BandStrip.d.ts +10 -7
  54. package/dist/charts/kinds/BandStrip.d.ts.map +1 -1
  55. package/dist/charts/kinds/BandStrip.js +12 -7
  56. package/dist/charts/kinds/Bars.d.ts +12 -6
  57. package/dist/charts/kinds/Bars.d.ts.map +1 -1
  58. package/dist/charts/kinds/Bars.js +37 -11
  59. package/dist/charts/kinds/Donut.d.ts +6 -5
  60. package/dist/charts/kinds/Donut.d.ts.map +1 -1
  61. package/dist/charts/kinds/Donut.js +19 -2
  62. package/dist/charts/kinds/DualPanel.d.ts +6 -5
  63. package/dist/charts/kinds/DualPanel.d.ts.map +1 -1
  64. package/dist/charts/kinds/DualPanel.js +36 -8
  65. package/dist/charts/kinds/Heatmap.d.ts +10 -6
  66. package/dist/charts/kinds/Heatmap.d.ts.map +1 -1
  67. package/dist/charts/kinds/Heatmap.js +58 -31
  68. package/dist/charts/kinds/MirroredBars.d.ts +6 -5
  69. package/dist/charts/kinds/MirroredBars.d.ts.map +1 -1
  70. package/dist/charts/kinds/MirroredBars.js +9 -2
  71. package/dist/charts/kinds/MultiLine.d.ts +11 -6
  72. package/dist/charts/kinds/MultiLine.d.ts.map +1 -1
  73. package/dist/charts/kinds/MultiLine.js +24 -15
  74. package/dist/charts/kinds/StackedArea.d.ts +18 -8
  75. package/dist/charts/kinds/StackedArea.d.ts.map +1 -1
  76. package/dist/charts/kinds/StackedArea.js +29 -4
  77. package/dist/charts/kinds/ZonedLine.d.ts +12 -8
  78. package/dist/charts/kinds/ZonedLine.d.ts.map +1 -1
  79. package/dist/charts/kinds/ZonedLine.js +33 -23
  80. package/dist/charts/layout/auto-margin.d.ts +65 -8
  81. package/dist/charts/layout/auto-margin.d.ts.map +1 -1
  82. package/dist/charts/layout/auto-margin.js +45 -10
  83. package/dist/charts/layout/log-ticks.d.ts +27 -0
  84. package/dist/charts/layout/log-ticks.d.ts.map +1 -0
  85. package/dist/charts/layout/log-ticks.js +42 -0
  86. package/dist/charts/primitives/Axes.d.ts +11 -2
  87. package/dist/charts/primitives/Axes.d.ts.map +1 -1
  88. package/dist/charts/primitives/Axes.js +15 -5
  89. package/dist/charts/primitives/CartesianChart.d.ts +45 -7
  90. package/dist/charts/primitives/CartesianChart.d.ts.map +1 -1
  91. package/dist/charts/primitives/CartesianChart.js +86 -28
  92. package/dist/charts/primitives/ChartCard.d.ts +27 -2
  93. package/dist/charts/primitives/ChartCard.d.ts.map +1 -1
  94. package/dist/charts/primitives/ChartCard.js +37 -17
  95. package/dist/charts/primitives/ChartFrame.d.ts +30 -4
  96. package/dist/charts/primitives/ChartFrame.d.ts.map +1 -1
  97. package/dist/charts/primitives/ChartFrame.js +45 -15
  98. package/dist/charts/primitives/ChartLegend.d.ts +13 -2
  99. package/dist/charts/primitives/ChartLegend.d.ts.map +1 -1
  100. package/dist/charts/primitives/ChartLegend.js +33 -13
  101. package/dist/charts/primitives/ChartPending.d.ts +77 -4
  102. package/dist/charts/primitives/ChartPending.d.ts.map +1 -1
  103. package/dist/charts/primitives/ChartPending.js +100 -6
  104. package/dist/charts/primitives/ChartTooltip.d.ts +7 -0
  105. package/dist/charts/primitives/ChartTooltip.d.ts.map +1 -1
  106. package/dist/charts/primitives/ChartTooltip.js +18 -5
  107. package/dist/charts/primitives/Crosshair.d.ts +3 -0
  108. package/dist/charts/primitives/Crosshair.d.ts.map +1 -1
  109. package/dist/charts/primitives/Crosshair.js +3 -1
  110. package/dist/charts/primitives/chart-frame-layout.d.ts +95 -0
  111. package/dist/charts/primitives/chart-frame-layout.d.ts.map +1 -0
  112. package/dist/charts/primitives/chart-frame-layout.js +89 -0
  113. package/dist/charts/primitives/chart-tier.d.ts +16 -0
  114. package/dist/charts/primitives/chart-tier.d.ts.map +1 -0
  115. package/dist/charts/primitives/chart-tier.js +20 -0
  116. package/dist/charts/series.d.ts +55 -1
  117. package/dist/charts/series.d.ts.map +1 -1
  118. package/dist/charts/series.js +27 -1
  119. package/dist/charts/sparklines/BarSparkline.d.ts +3 -3
  120. package/dist/charts/sparklines/BarSparkline.d.ts.map +1 -1
  121. package/dist/charts/sparklines/BarSparkline.js +9 -3
  122. package/dist/charts/sparklines/LineSparkline.d.ts +3 -3
  123. package/dist/charts/sparklines/LineSparkline.d.ts.map +1 -1
  124. package/dist/charts/sparklines/LineSparkline.js +15 -3
  125. package/dist/charts/sparklines/index.d.ts +2 -2
  126. package/dist/charts/sparklines/index.d.ts.map +1 -1
  127. package/dist/charts/utils/format.d.ts +92 -2
  128. package/dist/charts/utils/format.d.ts.map +1 -1
  129. package/dist/charts/utils/format.js +64 -1
  130. package/dist/charts/utils/ticks.d.ts +81 -2
  131. package/dist/charts/utils/ticks.d.ts.map +1 -1
  132. package/dist/charts/utils/ticks.js +54 -4
  133. package/dist/cli/index.d.ts.map +1 -1
  134. package/dist/cli/index.js +2 -2
  135. package/dist/commands/ShortcutsHelp.d.ts +3 -2
  136. package/dist/commands/ShortcutsHelp.d.ts.map +1 -1
  137. package/dist/commands/ShortcutsHelp.js +8 -2
  138. package/dist/commands/define-commands.d.ts.map +1 -1
  139. package/dist/commands/define-commands.js +2 -2
  140. package/dist/commands/define-overlays.d.ts +102 -0
  141. package/dist/commands/define-overlays.d.ts.map +1 -1
  142. package/dist/commands/define-overlays.js +102 -2
  143. package/dist/commands/index.d.ts +10 -1
  144. package/dist/commands/index.d.ts.map +1 -1
  145. package/dist/commands/index.js +3 -1
  146. package/dist/commands/overlays-mount.d.ts +13 -6
  147. package/dist/commands/overlays-mount.d.ts.map +1 -1
  148. package/dist/commands/overlays-mount.js +23 -14
  149. package/dist/common/errors.d.ts +34 -0
  150. package/dist/common/errors.d.ts.map +1 -0
  151. package/dist/common/errors.js +36 -0
  152. package/dist/common/index.d.ts +15 -0
  153. package/dist/common/index.d.ts.map +1 -0
  154. package/dist/common/index.js +29 -0
  155. package/dist/common/props.d.ts +63 -0
  156. package/dist/common/props.d.ts.map +1 -0
  157. package/dist/common/props.js +6 -0
  158. package/dist/common/query-state-like.d.ts +43 -0
  159. package/dist/common/query-state-like.d.ts.map +1 -0
  160. package/dist/common/query-state-like.js +20 -0
  161. package/dist/common/refs.d.ts +29 -0
  162. package/dist/common/refs.d.ts.map +1 -0
  163. package/dist/common/refs.js +29 -0
  164. package/dist/common/scroll-parent.d.ts +23 -0
  165. package/dist/common/scroll-parent.d.ts.map +1 -0
  166. package/dist/common/scroll-parent.js +21 -0
  167. package/dist/common/validate.d.ts +38 -0
  168. package/dist/common/validate.d.ts.map +1 -0
  169. package/dist/common/validate.js +36 -0
  170. package/dist/connectivity/connectivity-indicator.d.ts +3 -1
  171. package/dist/connectivity/connectivity-indicator.d.ts.map +1 -1
  172. package/dist/connectivity/connectivity-indicator.js +3 -1
  173. package/dist/connectivity/connectivity-provider.d.ts.map +1 -1
  174. package/dist/connectivity/connectivity-provider.js +4 -1
  175. package/dist/connectivity/index.d.ts +1 -0
  176. package/dist/connectivity/index.d.ts.map +1 -1
  177. package/dist/connectivity/types.d.ts +2 -2
  178. package/dist/connectivity/types.d.ts.map +1 -1
  179. package/dist/connectivity/use-connectivity.d.ts.map +1 -1
  180. package/dist/content/article-layout.module.css +11 -4
  181. package/dist/content/callout.d.ts +8 -4
  182. package/dist/content/callout.d.ts.map +1 -1
  183. package/dist/content/callout.js +15 -8
  184. package/dist/content/guide.d.ts +5 -4
  185. package/dist/content/guide.d.ts.map +1 -1
  186. package/dist/content/guide.js +13 -4
  187. package/dist/content/heading-anchor.d.ts +24 -2
  188. package/dist/content/heading-anchor.d.ts.map +1 -1
  189. package/dist/content/heading-anchor.js +23 -9
  190. package/dist/content/index.d.ts.map +1 -1
  191. package/dist/content/markdown.d.ts.map +1 -1
  192. package/dist/content/markdown.js +2 -0
  193. package/dist/content/prose.module.css +9 -7
  194. package/dist/content/reading-progress.d.ts +10 -4
  195. package/dist/content/reading-progress.d.ts.map +1 -1
  196. package/dist/content/reading-progress.js +26 -10
  197. package/dist/content/slug.d.ts +4 -0
  198. package/dist/content/slug.d.ts.map +1 -1
  199. package/dist/content/toc.d.ts +11 -0
  200. package/dist/content/toc.d.ts.map +1 -1
  201. package/dist/content/toc.js +23 -10
  202. package/dist/controls/actions.d.ts +49 -6
  203. package/dist/controls/actions.d.ts.map +1 -1
  204. package/dist/controls/actions.js +39 -8
  205. package/dist/controls/compare-filter.d.ts +3 -2
  206. package/dist/controls/compare-filter.d.ts.map +1 -1
  207. package/dist/controls/compare-filter.js +17 -2
  208. package/dist/controls/control-group.d.ts +3 -3
  209. package/dist/controls/control-group.d.ts.map +1 -1
  210. package/dist/controls/control-group.js +9 -2
  211. package/dist/controls/controls.module.css +169 -186
  212. package/dist/controls/controls.module.css.d.ts +9 -11
  213. package/dist/controls/enum-filter.d.ts +3 -2
  214. package/dist/controls/enum-filter.d.ts.map +1 -1
  215. package/dist/controls/enum-filter.js +28 -13
  216. package/dist/controls/filter-context.d.ts +8 -4
  217. package/dist/controls/filter-context.d.ts.map +1 -1
  218. package/dist/controls/filter-pill.d.ts +3 -3
  219. package/dist/controls/filter-pill.d.ts.map +1 -1
  220. package/dist/controls/filter-pill.js +4 -1
  221. package/dist/controls/filter-set.d.ts +3 -2
  222. package/dist/controls/filter-set.d.ts.map +1 -1
  223. package/dist/controls/filter-set.js +66 -41
  224. package/dist/controls/filter-sheet.d.ts +20 -80
  225. package/dist/controls/filter-sheet.d.ts.map +1 -1
  226. package/dist/controls/filter-sheet.js +9 -95
  227. package/dist/controls/index.d.ts +2 -0
  228. package/dist/controls/index.d.ts.map +1 -1
  229. package/dist/controls/index.js +4 -0
  230. package/dist/controls/multi-select-filter.d.ts +18 -2
  231. package/dist/controls/multi-select-filter.d.ts.map +1 -1
  232. package/dist/controls/multi-select-filter.js +122 -20
  233. package/dist/controls/number-filter.d.ts +7 -5
  234. package/dist/controls/number-filter.d.ts.map +1 -1
  235. package/dist/controls/number-filter.js +40 -11
  236. package/dist/controls/panel-row.d.ts +132 -0
  237. package/dist/controls/panel-row.d.ts.map +1 -0
  238. package/dist/controls/panel-row.js +173 -0
  239. package/dist/controls/panel-row.module.css +86 -0
  240. package/dist/controls/panel-row.module.css.d.ts +13 -0
  241. package/dist/controls/range-filter.d.ts +2 -1
  242. package/dist/controls/range-filter.d.ts.map +1 -1
  243. package/dist/controls/range-filter.js +57 -35
  244. package/dist/controls/search-filter.d.ts +3 -2
  245. package/dist/controls/search-filter.d.ts.map +1 -1
  246. package/dist/controls/search-filter.js +25 -10
  247. package/dist/controls/select-filter.d.ts +2 -1
  248. package/dist/controls/select-filter.d.ts.map +1 -1
  249. package/dist/controls/select-filter.js +4 -0
  250. package/dist/controls/slider-control.d.ts +36 -0
  251. package/dist/controls/slider-control.d.ts.map +1 -0
  252. package/dist/controls/slider-control.js +64 -0
  253. package/dist/controls/sync-button.d.ts +3 -2
  254. package/dist/controls/sync-button.d.ts.map +1 -1
  255. package/dist/controls/sync-button.js +16 -3
  256. package/dist/controls/toggle-filter.d.ts +3 -2
  257. package/dist/controls/toggle-filter.d.ts.map +1 -1
  258. package/dist/controls/toggle-filter.js +28 -11
  259. package/dist/controls/view-tabs.d.ts +3 -2
  260. package/dist/controls/view-tabs.d.ts.map +1 -1
  261. package/dist/controls/view-tabs.js +43 -11
  262. package/dist/controls-dates/date-range-picker.d.ts +1 -1
  263. package/dist/controls-dates/date-range-picker.d.ts.map +1 -1
  264. package/dist/controls-dates/date-range-picker.js +6 -1
  265. package/dist/dashboard/delta-badge.d.ts +5 -1
  266. package/dist/dashboard/delta-badge.d.ts.map +1 -1
  267. package/dist/dashboard/empty-state.d.ts +10 -3
  268. package/dist/dashboard/empty-state.d.ts.map +1 -1
  269. package/dist/dashboard/empty-state.js +37 -6
  270. package/dist/dashboard/index.d.ts +6 -4
  271. package/dist/dashboard/index.d.ts.map +1 -1
  272. package/dist/dashboard/index.js +7 -1
  273. package/dist/dashboard/query-state.d.ts +48 -27
  274. package/dist/dashboard/query-state.d.ts.map +1 -1
  275. package/dist/dashboard/query-state.js +111 -57
  276. package/dist/dashboard/settings-section.d.ts +19 -9
  277. package/dist/dashboard/settings-section.d.ts.map +1 -1
  278. package/dist/dashboard/settings-section.js +74 -25
  279. package/dist/dashboard/stat-card.d.ts +44 -38
  280. package/dist/dashboard/stat-card.d.ts.map +1 -1
  281. package/dist/dashboard/stat-card.js +55 -42
  282. package/dist/dashboard/stat-card.module.css +46 -31
  283. package/dist/dashboard/stat-card.module.css.d.ts +1 -0
  284. package/dist/dashboard/stat-group.d.ts +41 -0
  285. package/dist/dashboard/stat-group.d.ts.map +1 -0
  286. package/dist/dashboard/stat-group.js +30 -0
  287. package/dist/dashboard/stat-group.module.css +66 -0
  288. package/dist/dashboard/stat-group.module.css.d.ts +8 -0
  289. package/dist/dashboard/widget-grid.d.ts +27 -0
  290. package/dist/dashboard/widget-grid.d.ts.map +1 -0
  291. package/dist/dashboard/widget-grid.js +41 -0
  292. package/dist/dashboard/widget-grid.module.css +53 -0
  293. package/dist/dashboard/widget-grid.module.css.d.ts +9 -0
  294. package/dist/data/data-table.d.ts +151 -12
  295. package/dist/data/data-table.d.ts.map +1 -1
  296. package/dist/data/data-table.js +384 -138
  297. package/dist/data/data-table.module.css +64 -0
  298. package/dist/data/data-table.module.css.d.ts +11 -0
  299. package/dist/data/index.d.ts +2 -2
  300. package/dist/data/index.d.ts.map +1 -1
  301. package/dist/data/index.js +24 -2
  302. package/dist/data/query-branch.d.ts +28 -0
  303. package/dist/data/query-branch.d.ts.map +1 -0
  304. package/dist/data/query-branch.js +10 -0
  305. package/dist/data/table.d.ts +2 -2
  306. package/dist/data/table.d.ts.map +1 -1
  307. package/dist/data/virtual-list.d.ts +65 -6
  308. package/dist/data/virtual-list.d.ts.map +1 -1
  309. package/dist/data/virtual-list.js +89 -38
  310. package/dist/data/virtual.d.ts +1 -1
  311. package/dist/data/virtual.d.ts.map +1 -1
  312. package/dist/forms/FormErrorSummary.d.ts +4 -3
  313. package/dist/forms/FormErrorSummary.d.ts.map +1 -1
  314. package/dist/forms/FormErrorSummary.js +6 -4
  315. package/dist/forms/create-form.d.ts +2 -2
  316. package/dist/forms/field.d.ts +46 -6
  317. package/dist/forms/field.d.ts.map +1 -1
  318. package/dist/forms/field.js +10 -5
  319. package/dist/forms/form-layout.d.ts +142 -0
  320. package/dist/forms/form-layout.d.ts.map +1 -0
  321. package/dist/forms/form-layout.js +110 -0
  322. package/dist/forms/form-layout.module.css +145 -0
  323. package/dist/forms/form-layout.module.css.d.ts +20 -0
  324. package/dist/forms/form-state.d.ts +42 -0
  325. package/dist/forms/form-state.d.ts.map +1 -0
  326. package/dist/forms/form-state.js +26 -0
  327. package/dist/forms/index.d.ts +22 -6
  328. package/dist/forms/index.d.ts.map +1 -1
  329. package/dist/forms/index.js +19 -3
  330. package/dist/forms/use-field-array.d.ts +60 -0
  331. package/dist/forms/use-field-array.d.ts.map +1 -0
  332. package/dist/forms/use-field-array.js +20 -0
  333. package/dist/forms/use-form-draft.d.ts +25 -10
  334. package/dist/forms/use-form-draft.d.ts.map +1 -1
  335. package/dist/forms/use-form-draft.js +55 -18
  336. package/dist/forms/use-form-submit.d.ts +88 -0
  337. package/dist/forms/use-form-submit.d.ts.map +1 -0
  338. package/dist/forms/use-form-submit.js +63 -0
  339. package/dist/guard/index.d.ts.map +1 -1
  340. package/dist/guard/index.js +26 -6
  341. package/dist/index.d.ts +10 -8
  342. package/dist/index.d.ts.map +1 -1
  343. package/dist/index.js +44 -4
  344. package/dist/nav/types.d.ts +15 -6
  345. package/dist/nav/types.d.ts.map +1 -1
  346. package/dist/notifications/bell.d.ts +3 -2
  347. package/dist/notifications/bell.d.ts.map +1 -1
  348. package/dist/notifications/bell.js +73 -56
  349. package/dist/notifications/center.d.ts +15 -4
  350. package/dist/notifications/center.d.ts.map +1 -1
  351. package/dist/notifications/center.js +5 -2
  352. package/dist/notifications/define-notifications.d.ts +56 -14
  353. package/dist/notifications/define-notifications.d.ts.map +1 -1
  354. package/dist/notifications/define-notifications.js +2 -1
  355. package/dist/notifications/index.d.ts +6 -2
  356. package/dist/notifications/index.d.ts.map +1 -1
  357. package/dist/notifications/index.js +5 -1
  358. package/dist/notifications/mount-guard.d.ts +8 -0
  359. package/dist/notifications/mount-guard.d.ts.map +1 -0
  360. package/dist/notifications/mount-guard.js +19 -0
  361. package/dist/notifications/notify.d.ts +58 -1
  362. package/dist/notifications/notify.d.ts.map +1 -1
  363. package/dist/notifications/notify.js +46 -2
  364. package/dist/notifications/overlay.d.ts.map +1 -1
  365. package/dist/notifications/overlay.js +2 -0
  366. package/dist/notifications/store.d.ts +7 -0
  367. package/dist/notifications/store.d.ts.map +1 -1
  368. package/dist/provider/index.d.ts +37 -5
  369. package/dist/provider/index.d.ts.map +1 -1
  370. package/dist/provider/index.js +66 -28
  371. package/dist/provider/lab-theme.d.ts.map +1 -1
  372. package/dist/provider/lab-theme.js +2 -1
  373. package/dist/query/devtools.d.ts.map +1 -1
  374. package/dist/query/devtools.js +1 -0
  375. package/dist/router-tanstack/field.d.ts +1 -1
  376. package/dist/router-tanstack/field.d.ts.map +1 -1
  377. package/dist/router-tanstack/search-store.d.ts.map +1 -1
  378. package/dist/router-tanstack/search-store.js +1 -1
  379. package/dist/router-tanstack/use-nav.d.ts.map +1 -1
  380. package/dist/router-tanstack/use-nav.js +1 -1
  381. package/dist/section/index.d.ts +1 -1
  382. package/dist/section/index.d.ts.map +1 -1
  383. package/dist/section/section.d.ts +36 -2
  384. package/dist/section/section.d.ts.map +1 -1
  385. package/dist/section/section.js +49 -57
  386. package/dist/section/section.module.css +11 -0
  387. package/dist/shell/account-types.d.ts +5 -2
  388. package/dist/shell/account-types.d.ts.map +1 -1
  389. package/dist/shell/app-brand.d.ts +13 -0
  390. package/dist/shell/app-brand.d.ts.map +1 -0
  391. package/dist/shell/app-brand.js +94 -0
  392. package/dist/shell/app-brand.module.css +109 -0
  393. package/dist/shell/app-brand.module.css.d.ts +14 -0
  394. package/dist/shell/app-breadcrumbs.d.ts +4 -2
  395. package/dist/shell/app-breadcrumbs.d.ts.map +1 -1
  396. package/dist/shell/app-breadcrumbs.js +33 -22
  397. package/dist/shell/app-header.module.css +10 -5
  398. package/dist/shell/app-main.module.css +107 -0
  399. package/dist/shell/app-main.module.css.d.ts +11 -0
  400. package/dist/shell/app-mobile-nav.d.ts +3 -2
  401. package/dist/shell/app-mobile-nav.d.ts.map +1 -1
  402. package/dist/shell/app-mobile-nav.js +29 -15
  403. package/dist/shell/app-mobile-nav.module.css +48 -27
  404. package/dist/shell/app-mobile-nav.module.css.d.ts +0 -1
  405. package/dist/shell/app-sidebar-account.d.ts +2 -1
  406. package/dist/shell/app-sidebar-account.d.ts.map +1 -1
  407. package/dist/shell/app-sidebar-account.js +57 -22
  408. package/dist/shell/app-sidebar.d.ts +9 -3
  409. package/dist/shell/app-sidebar.d.ts.map +1 -1
  410. package/dist/shell/app-sidebar.js +55 -109
  411. package/dist/shell/app-sidebar.module.css +53 -96
  412. package/dist/shell/app-sidebar.module.css.d.ts +0 -5
  413. package/dist/shell/index.d.ts +14 -6
  414. package/dist/shell/index.d.ts.map +1 -1
  415. package/dist/shell/index.js +47 -12
  416. package/dist/shell/isomorphic-layout-effect.d.ts +14 -0
  417. package/dist/shell/isomorphic-layout-effect.d.ts.map +1 -0
  418. package/dist/shell/isomorphic-layout-effect.js +5 -0
  419. package/dist/shell/mobile-nav-model.d.ts.map +1 -1
  420. package/dist/shell/mobile-nav-model.js +27 -6
  421. package/dist/shell/nav-count-badge.d.ts +5 -3
  422. package/dist/shell/nav-count-badge.d.ts.map +1 -1
  423. package/dist/shell/nav-count-badge.js +3 -1
  424. package/dist/shell/page-aside.d.ts +43 -0
  425. package/dist/shell/page-aside.d.ts.map +1 -0
  426. package/dist/shell/page-aside.js +202 -0
  427. package/dist/shell/page-aside.module.css +174 -0
  428. package/dist/shell/page-aside.module.css.d.ts +14 -0
  429. package/dist/shell/page-bar.d.ts +55 -15
  430. package/dist/shell/page-bar.d.ts.map +1 -1
  431. package/dist/shell/page-bar.js +130 -41
  432. package/dist/shell/page-bar.module.css +107 -13
  433. package/dist/shell/page-bar.module.css.d.ts +4 -1
  434. package/dist/shell/sidebar-search.d.ts +4 -2
  435. package/dist/shell/sidebar-search.d.ts.map +1 -1
  436. package/dist/shell/sidebar-search.js +9 -4
  437. package/dist/shell/sidebar-search.module.css +1 -1
  438. package/dist/state/fields.d.ts +23 -3
  439. package/dist/state/fields.d.ts.map +1 -1
  440. package/dist/state/fields.js +13 -2
  441. package/dist/state/persisted-or-local.d.ts +9 -0
  442. package/dist/state/persisted-or-local.d.ts.map +1 -0
  443. package/dist/state/persisted-or-local.js +24 -0
  444. package/dist/state.d.ts +1 -1
  445. package/dist/state.d.ts.map +1 -1
  446. package/dist/state.js +2 -6
  447. package/dist/surfaces.d.ts +12 -11
  448. package/dist/surfaces.d.ts.map +1 -1
  449. package/dist/surfaces.js +42 -12
  450. package/dist/theme/ctl-theme.d.ts.map +1 -1
  451. package/dist/theme/index.d.ts.map +1 -1
  452. package/dist/theme/index.js +102 -17
  453. package/dist/theme/nav-link.module.css +37 -26
  454. package/dist/theme/segmented-control.module.css +22 -0
  455. package/dist/theme/segmented-control.module.css.d.ts +1 -0
  456. package/dist/theme-lab/boot.d.ts +66 -0
  457. package/dist/theme-lab/boot.d.ts.map +1 -0
  458. package/dist/theme-lab/boot.js +82 -0
  459. package/dist/theme-lab/index.d.ts +4 -43
  460. package/dist/theme-lab/index.d.ts.map +1 -1
  461. package/dist/theme-lab/index.js +9 -69
  462. package/dist/theme-toggle/index.d.ts +3 -2
  463. package/dist/theme-toggle/index.d.ts.map +1 -1
  464. package/dist/theme-toggle/index.js +8 -2
  465. package/dist/tokens/index.d.ts +42 -0
  466. package/dist/tokens/index.d.ts.map +1 -1
  467. package/dist/tokens/index.js +35 -6
  468. package/dist/tokens/palette.d.ts +45 -25
  469. package/dist/tokens/palette.d.ts.map +1 -1
  470. package/dist/tokens/palette.js +31 -14
  471. package/dist/tokens.css +4 -5
  472. package/dist/utils/is-dev.d.ts +3 -0
  473. package/dist/utils/is-dev.d.ts.map +1 -0
  474. package/dist/utils/is-dev.js +6 -0
  475. package/dist/widget-header/delta-badge.d.ts +7 -1
  476. package/dist/widget-header/delta-badge.d.ts.map +1 -1
  477. package/dist/widget-header/delta-badge.js +8 -1
  478. package/dist/widget-header/index.d.ts +2 -2
  479. package/dist/widget-header/index.d.ts.map +1 -1
  480. package/dist/widget-header/index.js +3 -1
  481. package/dist/widget-header/widget-header.d.ts +69 -4
  482. package/dist/widget-header/widget-header.d.ts.map +1 -1
  483. package/dist/widget-header/widget-header.js +42 -27
  484. package/dist/widget-header/widget-header.module.css +72 -7
  485. package/llms.txt +6 -6
  486. package/package.json +49 -25
  487. package/src/agent/coalesce.ts +2 -1
  488. package/src/agent/merge.ts +2 -1
  489. package/src/agent/part-list.tsx +2 -0
  490. package/src/agent/stick-to-bottom.tsx +9 -11
  491. package/src/agent-chat/composer.tsx +124 -103
  492. package/src/agent-chat/relative-time.ts +2 -1
  493. package/src/agent-chat/thread-detail-panel.tsx +9 -5
  494. package/src/agent-chat/thread-feed-row.tsx +17 -9
  495. package/src/agent-chat/thread-feed.tsx +9 -3
  496. package/src/agent-chat/thread-message.tsx +48 -13
  497. package/src/agent-chat/thread-outcome-card.tsx +9 -1
  498. package/src/agent-chat/thread-workspace.tsx +72 -33
  499. package/src/agent-chat/tool-chip.tsx +8 -2
  500. package/src/charts/hooks/useBandPlot.ts +26 -8
  501. package/src/charts/index.ts +39 -4
  502. package/src/charts/kinds/BandStrip.tsx +36 -14
  503. package/src/charts/kinds/Bars.tsx +67 -16
  504. package/src/charts/kinds/Donut.tsx +30 -3
  505. package/src/charts/kinds/DualPanel.tsx +56 -10
  506. package/src/charts/kinds/Heatmap.tsx +90 -33
  507. package/src/charts/kinds/MirroredBars.tsx +21 -3
  508. package/src/charts/kinds/MultiLine.tsx +61 -18
  509. package/src/charts/kinds/StackedArea.tsx +77 -6
  510. package/src/charts/kinds/ZonedLine.tsx +71 -31
  511. package/src/charts/layout/auto-margin.ts +134 -21
  512. package/src/charts/layout/log-ticks.ts +90 -0
  513. package/src/charts/primitives/Axes.tsx +33 -5
  514. package/src/charts/primitives/CartesianChart.tsx +194 -41
  515. package/src/charts/primitives/ChartCard.tsx +66 -25
  516. package/src/charts/primitives/ChartFrame.tsx +107 -26
  517. package/src/charts/primitives/ChartLegend.tsx +43 -13
  518. package/src/charts/primitives/ChartPending.tsx +185 -7
  519. package/src/charts/primitives/ChartTooltip.tsx +37 -5
  520. package/src/charts/primitives/Crosshair.tsx +6 -3
  521. package/src/charts/primitives/chart-frame-layout.ts +212 -0
  522. package/src/charts/primitives/chart-tier.tsx +37 -0
  523. package/src/charts/series.ts +77 -1
  524. package/src/charts/sparklines/BarSparkline.tsx +11 -3
  525. package/src/charts/sparklines/LineSparkline.tsx +18 -4
  526. package/src/charts/sparklines/index.ts +2 -2
  527. package/src/charts/utils/format.ts +163 -2
  528. package/src/charts/utils/ticks.ts +149 -4
  529. package/src/cli/index.ts +8 -3
  530. package/src/commands/ShortcutsHelp.tsx +10 -3
  531. package/src/commands/define-commands.ts +2 -2
  532. package/src/commands/define-overlays.ts +216 -1
  533. package/src/commands/index.ts +12 -0
  534. package/src/commands/overlays-mount.tsx +60 -26
  535. package/src/common/errors.ts +73 -0
  536. package/src/common/index.ts +21 -0
  537. package/src/common/props.ts +71 -0
  538. package/src/common/query-state-like.ts +64 -0
  539. package/src/common/refs.ts +58 -0
  540. package/src/common/scroll-parent.ts +42 -0
  541. package/src/common/validate.ts +94 -0
  542. package/src/connectivity/connectivity-indicator.tsx +6 -1
  543. package/src/connectivity/connectivity-provider.tsx +4 -1
  544. package/src/connectivity/index.ts +1 -0
  545. package/src/connectivity/types.ts +5 -2
  546. package/src/connectivity/use-connectivity.ts +3 -2
  547. package/src/content/article-layout.module.css +11 -4
  548. package/src/content/callout.tsx +13 -7
  549. package/src/content/guide.tsx +14 -4
  550. package/src/content/heading-anchor.tsx +14 -3
  551. package/src/content/index.ts +2 -0
  552. package/src/content/markdown.tsx +2 -0
  553. package/src/content/prose.module.css +9 -7
  554. package/src/content/reading-progress.tsx +40 -15
  555. package/src/content/slug.ts +4 -0
  556. package/src/content/toc.tsx +47 -10
  557. package/src/controls/actions.tsx +89 -9
  558. package/src/controls/compare-filter.tsx +20 -3
  559. package/src/controls/control-group.tsx +11 -4
  560. package/src/controls/controls.module.css +169 -186
  561. package/src/controls/controls.module.css.d.ts +9 -11
  562. package/src/controls/enum-filter.tsx +32 -16
  563. package/src/controls/filter-context.tsx +14 -6
  564. package/src/controls/filter-pill.tsx +6 -3
  565. package/src/controls/filter-set.tsx +32 -13
  566. package/src/controls/filter-sheet.tsx +44 -194
  567. package/src/controls/index.ts +7 -0
  568. package/src/controls/multi-select-filter.tsx +177 -27
  569. package/src/controls/number-filter.tsx +61 -23
  570. package/src/controls/panel-row.module.css +86 -0
  571. package/src/controls/panel-row.module.css.d.ts +13 -0
  572. package/src/controls/panel-row.tsx +392 -0
  573. package/src/controls/range-filter.tsx +76 -39
  574. package/src/controls/search-filter.tsx +30 -12
  575. package/src/controls/select-filter.tsx +11 -1
  576. package/src/controls/slider-control.tsx +159 -0
  577. package/src/controls/sync-button.tsx +13 -3
  578. package/src/controls/toggle-filter.tsx +36 -16
  579. package/src/controls/view-tabs.tsx +63 -11
  580. package/src/controls-dates/date-range-picker.tsx +8 -1
  581. package/src/dashboard/delta-badge.tsx +5 -1
  582. package/src/dashboard/empty-state.tsx +72 -25
  583. package/src/dashboard/index.ts +13 -1
  584. package/src/dashboard/query-state.tsx +154 -84
  585. package/src/dashboard/settings-section.tsx +87 -31
  586. package/src/dashboard/stat-card.module.css +46 -31
  587. package/src/dashboard/stat-card.module.css.d.ts +1 -0
  588. package/src/dashboard/stat-card.tsx +185 -127
  589. package/src/dashboard/stat-group.module.css +66 -0
  590. package/src/dashboard/stat-group.module.css.d.ts +8 -0
  591. package/src/dashboard/stat-group.tsx +74 -0
  592. package/src/dashboard/widget-grid.module.css +53 -0
  593. package/src/dashboard/widget-grid.module.css.d.ts +9 -0
  594. package/src/dashboard/widget-grid.tsx +127 -0
  595. package/src/data/data-table.module.css +64 -0
  596. package/src/data/data-table.module.css.d.ts +11 -0
  597. package/src/data/data-table.tsx +919 -346
  598. package/src/data/index.ts +30 -2
  599. package/src/data/query-branch.ts +53 -0
  600. package/src/data/table.ts +5 -0
  601. package/src/data/virtual-list.tsx +189 -55
  602. package/src/data/virtual.ts +5 -1
  603. package/src/forms/FormErrorSummary.tsx +13 -6
  604. package/src/forms/create-form.ts +2 -2
  605. package/src/forms/field.ts +60 -11
  606. package/src/forms/form-layout.module.css +145 -0
  607. package/src/forms/form-layout.module.css.d.ts +20 -0
  608. package/src/forms/form-layout.tsx +305 -0
  609. package/src/forms/form-state.tsx +94 -0
  610. package/src/forms/index.ts +38 -7
  611. package/src/forms/use-field-array.ts +94 -0
  612. package/src/forms/use-form-draft.ts +145 -53
  613. package/src/forms/use-form-submit.ts +199 -0
  614. package/src/guard/index.ts +73 -18
  615. package/src/index.ts +74 -10
  616. package/src/nav/types.ts +15 -6
  617. package/src/notifications/bell.tsx +18 -4
  618. package/src/notifications/center.tsx +18 -5
  619. package/src/notifications/define-notifications.ts +64 -18
  620. package/src/notifications/index.ts +12 -1
  621. package/src/notifications/mount-guard.ts +41 -0
  622. package/src/notifications/notify.tsx +122 -3
  623. package/src/notifications/overlay.tsx +2 -0
  624. package/src/notifications/store.ts +7 -0
  625. package/src/provider/index.tsx +101 -13
  626. package/src/provider/lab-theme.ts +2 -1
  627. package/src/query/devtools.tsx +1 -0
  628. package/src/router-tanstack/field.ts +1 -0
  629. package/src/router-tanstack/search-store.ts +3 -10
  630. package/src/router-tanstack/use-nav.ts +18 -13
  631. package/src/section/index.ts +1 -1
  632. package/src/section/section.module.css +11 -0
  633. package/src/section/section.tsx +163 -96
  634. package/src/shell/account-types.ts +5 -2
  635. package/src/shell/app-brand.module.css +109 -0
  636. package/src/shell/app-brand.module.css.d.ts +14 -0
  637. package/src/shell/app-brand.tsx +140 -0
  638. package/src/shell/app-breadcrumbs.tsx +19 -9
  639. package/src/shell/app-header.module.css +10 -5
  640. package/src/shell/app-main.module.css +107 -0
  641. package/src/shell/app-main.module.css.d.ts +11 -0
  642. package/src/shell/app-mobile-nav.module.css +48 -27
  643. package/src/shell/app-mobile-nav.module.css.d.ts +0 -1
  644. package/src/shell/app-mobile-nav.tsx +43 -11
  645. package/src/shell/app-sidebar-account.tsx +29 -6
  646. package/src/shell/app-sidebar.module.css +53 -96
  647. package/src/shell/app-sidebar.module.css.d.ts +0 -5
  648. package/src/shell/app-sidebar.tsx +40 -113
  649. package/src/shell/index.tsx +156 -65
  650. package/src/shell/isomorphic-layout-effect.ts +14 -0
  651. package/src/shell/mobile-nav-model.ts +66 -10
  652. package/src/shell/nav-count-badge.tsx +6 -1
  653. package/src/shell/page-aside.module.css +174 -0
  654. package/src/shell/page-aside.module.css.d.ts +14 -0
  655. package/src/shell/page-aside.tsx +377 -0
  656. package/src/shell/page-bar.module.css +107 -13
  657. package/src/shell/page-bar.module.css.d.ts +4 -1
  658. package/src/shell/page-bar.tsx +294 -94
  659. package/src/shell/sidebar-search.module.css +1 -1
  660. package/src/shell/sidebar-search.tsx +13 -4
  661. package/src/state/fields.ts +43 -10
  662. package/src/state/persisted-or-local.ts +50 -0
  663. package/src/state.ts +0 -9
  664. package/src/surfaces.ts +42 -12
  665. package/src/theme/ctl-theme.tsx +10 -0
  666. package/src/theme/index.ts +129 -16
  667. package/src/theme/nav-link.module.css +37 -26
  668. package/src/theme/segmented-control.module.css +22 -0
  669. package/src/theme/segmented-control.module.css.d.ts +1 -0
  670. package/src/theme-lab/boot.ts +140 -0
  671. package/src/theme-lab/index.tsx +21 -112
  672. package/src/theme-toggle/index.tsx +10 -3
  673. package/src/tokens/index.ts +50 -6
  674. package/src/tokens/palette.ts +58 -30
  675. package/src/utils/is-dev.ts +4 -0
  676. package/src/widget-header/delta-badge.tsx +25 -5
  677. package/src/widget-header/index.ts +10 -2
  678. package/src/widget-header/widget-header.module.css +72 -7
  679. package/src/widget-header/widget-header.tsx +150 -71
  680. package/dist/agent/adapter.test.d.ts +0 -2
  681. package/dist/agent/adapter.test.d.ts.map +0 -1
  682. package/dist/agent/ai-sdk-transport.test.d.ts +0 -2
  683. package/dist/agent/ai-sdk-transport.test.d.ts.map +0 -1
  684. package/dist/agent/coalesce.test.d.ts +0 -2
  685. package/dist/agent/coalesce.test.d.ts.map +0 -1
  686. package/dist/agent/foreign.test.d.ts +0 -2
  687. package/dist/agent/foreign.test.d.ts.map +0 -1
  688. package/dist/agent/id.test.d.ts +0 -2
  689. package/dist/agent/id.test.d.ts.map +0 -1
  690. package/dist/agent/merge.test.d.ts +0 -2
  691. package/dist/agent/merge.test.d.ts.map +0 -1
  692. package/dist/agent/part-list.test.d.ts +0 -2
  693. package/dist/agent/part-list.test.d.ts.map +0 -1
  694. package/dist/agent/parts.test.d.ts +0 -2
  695. package/dist/agent/parts.test.d.ts.map +0 -1
  696. package/dist/agent/thread.test.d.ts +0 -2
  697. package/dist/agent/thread.test.d.ts.map +0 -1
  698. package/dist/agent/transport.test.d.ts +0 -2
  699. package/dist/agent/transport.test.d.ts.map +0 -1
  700. package/dist/agent/use-agent-stream.test.d.ts +0 -2
  701. package/dist/agent/use-agent-stream.test.d.ts.map +0 -1
  702. package/dist/agent/use-agent-thread-runs.foreign.test.d.ts +0 -2
  703. package/dist/agent/use-agent-thread-runs.foreign.test.d.ts.map +0 -1
  704. package/dist/agent/use-agent-thread-runs.resume.test.d.ts +0 -2
  705. package/dist/agent/use-agent-thread-runs.resume.test.d.ts.map +0 -1
  706. package/dist/agent/use-agent-thread-runs.test.d.ts +0 -2
  707. package/dist/agent/use-agent-thread-runs.test.d.ts.map +0 -1
  708. package/dist/agent/use-agent-thread-runs.wedge.test.d.ts +0 -2
  709. package/dist/agent/use-agent-thread-runs.wedge.test.d.ts.map +0 -1
  710. package/dist/agent-chat/composer.test.d.ts +0 -2
  711. package/dist/agent-chat/composer.test.d.ts.map +0 -1
  712. package/dist/agent-chat/relative-time.test.d.ts +0 -2
  713. package/dist/agent-chat/relative-time.test.d.ts.map +0 -1
  714. package/dist/agent-chat/thread-feed-row.test.d.ts +0 -2
  715. package/dist/agent-chat/thread-feed-row.test.d.ts.map +0 -1
  716. package/dist/agent-chat/thread-feed.test.d.ts +0 -2
  717. package/dist/agent-chat/thread-feed.test.d.ts.map +0 -1
  718. package/dist/agent-chat/thread-message.test.d.ts +0 -2
  719. package/dist/agent-chat/thread-message.test.d.ts.map +0 -1
  720. package/dist/agent-chat/thread-workspace.test.d.ts +0 -2
  721. package/dist/agent-chat/thread-workspace.test.d.ts.map +0 -1
  722. package/dist/agent-chat/tool-chip.test.d.ts +0 -2
  723. package/dist/agent-chat/tool-chip.test.d.ts.map +0 -1
  724. package/dist/agent-chat/virtualize.type-guard.test.d.ts +0 -2
  725. package/dist/agent-chat/virtualize.type-guard.test.d.ts.map +0 -1
  726. package/dist/charts/cursor/resolve.test.d.ts +0 -2
  727. package/dist/charts/cursor/resolve.test.d.ts.map +0 -1
  728. package/dist/charts/cursor/store.test.d.ts +0 -2
  729. package/dist/charts/cursor/store.test.d.ts.map +0 -1
  730. package/dist/charts/kinds/BandStrip.test.d.ts +0 -2
  731. package/dist/charts/kinds/BandStrip.test.d.ts.map +0 -1
  732. package/dist/charts/kinds/Bars.test.d.ts +0 -2
  733. package/dist/charts/kinds/Bars.test.d.ts.map +0 -1
  734. package/dist/charts/kinds/DualPanel.test.d.ts +0 -2
  735. package/dist/charts/kinds/DualPanel.test.d.ts.map +0 -1
  736. package/dist/charts/kinds/MirroredBars.test.d.ts +0 -2
  737. package/dist/charts/kinds/MirroredBars.test.d.ts.map +0 -1
  738. package/dist/charts/kinds/MultiLine.test.d.ts +0 -2
  739. package/dist/charts/kinds/MultiLine.test.d.ts.map +0 -1
  740. package/dist/charts/kinds/StackedArea.test.d.ts +0 -2
  741. package/dist/charts/kinds/StackedArea.test.d.ts.map +0 -1
  742. package/dist/charts/kinds/ZonedLine.test.d.ts +0 -2
  743. package/dist/charts/kinds/ZonedLine.test.d.ts.map +0 -1
  744. package/dist/charts/layout/auto-margin.test.d.ts +0 -2
  745. package/dist/charts/layout/auto-margin.test.d.ts.map +0 -1
  746. package/dist/charts/primitives/CartesianChart.test.d.ts +0 -2
  747. package/dist/charts/primitives/CartesianChart.test.d.ts.map +0 -1
  748. package/dist/charts/primitives/ChartCard.test.d.ts +0 -2
  749. package/dist/charts/primitives/ChartCard.test.d.ts.map +0 -1
  750. package/dist/charts/primitives/ChartFrame.test.d.ts +0 -2
  751. package/dist/charts/primitives/ChartFrame.test.d.ts.map +0 -1
  752. package/dist/charts/primitives/ChartLegend.test.d.ts +0 -2
  753. package/dist/charts/primitives/ChartLegend.test.d.ts.map +0 -1
  754. package/dist/charts/primitives/ChartTooltip.test.d.ts +0 -2
  755. package/dist/charts/primitives/ChartTooltip.test.d.ts.map +0 -1
  756. package/dist/charts/primitives/XZoneRects.test.d.ts +0 -2
  757. package/dist/charts/primitives/XZoneRects.test.d.ts.map +0 -1
  758. package/dist/charts/series.test.d.ts +0 -2
  759. package/dist/charts/series.test.d.ts.map +0 -1
  760. package/dist/charts/utils/domain.test.d.ts +0 -2
  761. package/dist/charts/utils/domain.test.d.ts.map +0 -1
  762. package/dist/charts/utils/measure-text.test.d.ts +0 -2
  763. package/dist/charts/utils/measure-text.test.d.ts.map +0 -1
  764. package/dist/cli/check-coverage.test.d.ts +0 -2
  765. package/dist/cli/check-coverage.test.d.ts.map +0 -1
  766. package/dist/cli/check-theme.test.d.ts +0 -2
  767. package/dist/cli/check-theme.test.d.ts.map +0 -1
  768. package/dist/cli/help.test.d.ts +0 -2
  769. package/dist/cli/help.test.d.ts.map +0 -1
  770. package/dist/cli/init-sync.test.d.ts +0 -2
  771. package/dist/cli/init-sync.test.d.ts.map +0 -1
  772. package/dist/cli/placement-engine.test.d.ts +0 -2
  773. package/dist/cli/placement-engine.test.d.ts.map +0 -1
  774. package/dist/cli/shipped-versions.test.d.ts +0 -2
  775. package/dist/cli/shipped-versions.test.d.ts.map +0 -1
  776. package/dist/cli/tarball-parity.test.d.ts +0 -2
  777. package/dist/cli/tarball-parity.test.d.ts.map +0 -1
  778. package/dist/cli/template-format.test.d.ts +0 -2
  779. package/dist/cli/template-format.test.d.ts.map +0 -1
  780. package/dist/cli/template-ledger.test.d.ts +0 -2
  781. package/dist/cli/template-ledger.test.d.ts.map +0 -1
  782. package/dist/cli/tokens-css.test.d.ts +0 -2
  783. package/dist/cli/tokens-css.test.d.ts.map +0 -1
  784. package/dist/cli/toolchain-wiring.test.d.ts +0 -2
  785. package/dist/cli/toolchain-wiring.test.d.ts.map +0 -1
  786. package/dist/cli/waiver-audit.test.d.ts +0 -2
  787. package/dist/cli/waiver-audit.test.d.ts.map +0 -1
  788. package/dist/content/article-actions.test.d.ts +0 -2
  789. package/dist/content/article-actions.test.d.ts.map +0 -1
  790. package/dist/content/article-model.test.d.ts +0 -2
  791. package/dist/content/article-model.test.d.ts.map +0 -1
  792. package/dist/content/block-split.test.d.ts +0 -2
  793. package/dist/content/block-split.test.d.ts.map +0 -1
  794. package/dist/content/heading-components.test.d.ts +0 -2
  795. package/dist/content/heading-components.test.d.ts.map +0 -1
  796. package/dist/content/markdown.test.d.ts +0 -2
  797. package/dist/content/markdown.test.d.ts.map +0 -1
  798. package/dist/content/prose.module.css.test.d.ts +0 -2
  799. package/dist/content/prose.module.css.test.d.ts.map +0 -1
  800. package/dist/content/sanitize.test.d.ts +0 -2
  801. package/dist/content/sanitize.test.d.ts.map +0 -1
  802. package/dist/content/slug.test.d.ts +0 -2
  803. package/dist/content/slug.test.d.ts.map +0 -1
  804. package/dist/controls/actions.test.d.ts +0 -2
  805. package/dist/controls/actions.test.d.ts.map +0 -1
  806. package/dist/controls/actions.type-guard.test.d.ts +0 -2
  807. package/dist/controls/actions.type-guard.test.d.ts.map +0 -1
  808. package/dist/controls/control-group.test.d.ts +0 -2
  809. package/dist/controls/control-group.test.d.ts.map +0 -1
  810. package/dist/controls/controls.router.test.d.ts +0 -2
  811. package/dist/controls/controls.router.test.d.ts.map +0 -1
  812. package/dist/controls/filter-set.test.d.ts +0 -2
  813. package/dist/controls/filter-set.test.d.ts.map +0 -1
  814. package/dist/controls/peer-boundary.test.d.ts +0 -2
  815. package/dist/controls/peer-boundary.test.d.ts.map +0 -1
  816. package/dist/controls/props-contract.test.d.ts +0 -2
  817. package/dist/controls/props-contract.test.d.ts.map +0 -1
  818. package/dist/controls/range-filter.type-guard.test.d.ts +0 -2
  819. package/dist/controls/range-filter.type-guard.test.d.ts.map +0 -1
  820. package/dist/controls/sync-button.test.d.ts +0 -2
  821. package/dist/controls/sync-button.test.d.ts.map +0 -1
  822. package/dist/dashboard/query-state.test.d.ts +0 -2
  823. package/dist/dashboard/query-state.test.d.ts.map +0 -1
  824. package/dist/dashboard/settings-section.test.d.ts +0 -2
  825. package/dist/dashboard/settings-section.test.d.ts.map +0 -1
  826. package/dist/dashboard/stat-card.test.d.ts +0 -2
  827. package/dist/dashboard/stat-card.test.d.ts.map +0 -1
  828. package/dist/data/data-table.test.d.ts +0 -2
  829. package/dist/data/data-table.test.d.ts.map +0 -1
  830. package/dist/guard/check-source.test.d.ts +0 -2
  831. package/dist/guard/check-source.test.d.ts.map +0 -1
  832. package/dist/guard/grace.test.d.ts +0 -20
  833. package/dist/guard/grace.test.d.ts.map +0 -1
  834. package/dist/guard/guard-hook.test.d.ts +0 -2
  835. package/dist/guard/guard-hook.test.d.ts.map +0 -1
  836. package/dist/provider/index.test.d.ts +0 -2
  837. package/dist/provider/index.test.d.ts.map +0 -1
  838. package/dist/provider/lab-theme.test.d.ts +0 -2
  839. package/dist/provider/lab-theme.test.d.ts.map +0 -1
  840. package/dist/query/error-message.test.d.ts +0 -2
  841. package/dist/query/error-message.test.d.ts.map +0 -1
  842. package/dist/router-tanstack/multi-search-param-store.test.d.ts +0 -2
  843. package/dist/router-tanstack/multi-search-param-store.test.d.ts.map +0 -1
  844. package/dist/router-tanstack/nav.test.d.ts +0 -2
  845. package/dist/router-tanstack/nav.test.d.ts.map +0 -1
  846. package/dist/router-tanstack/search-param-store.test.d.ts +0 -2
  847. package/dist/router-tanstack/search-param-store.test.d.ts.map +0 -1
  848. package/dist/router-tanstack/search-store.router.test.d.ts +0 -2
  849. package/dist/router-tanstack/search-store.router.test.d.ts.map +0 -1
  850. package/dist/router-tanstack/search-store.test.d.ts +0 -2
  851. package/dist/router-tanstack/search-store.test.d.ts.map +0 -1
  852. package/dist/router-tanstack/use-nav.test.d.ts +0 -2
  853. package/dist/router-tanstack/use-nav.test.d.ts.map +0 -1
  854. package/dist/section/section.test.d.ts +0 -2
  855. package/dist/section/section.test.d.ts.map +0 -1
  856. package/dist/shell/app-mobile-nav.test.d.ts +0 -2
  857. package/dist/shell/app-mobile-nav.test.d.ts.map +0 -1
  858. package/dist/shell/app-sidebar.test.d.ts +0 -2
  859. package/dist/shell/app-sidebar.test.d.ts.map +0 -1
  860. package/dist/shell/index.test.d.ts +0 -2
  861. package/dist/shell/index.test.d.ts.map +0 -1
  862. package/dist/shell/mobile-nav-model.test.d.ts +0 -2
  863. package/dist/shell/mobile-nav-model.test.d.ts.map +0 -1
  864. package/dist/shell/page-bar.test.d.ts +0 -2
  865. package/dist/shell/page-bar.test.d.ts.map +0 -1
  866. package/dist/state/fields.test.d.ts +0 -2
  867. package/dist/state/fields.test.d.ts.map +0 -1
  868. package/dist/state/persisted.test.d.ts +0 -2
  869. package/dist/state/persisted.test.d.ts.map +0 -1
  870. package/dist/styles.floor.test.d.ts +0 -2
  871. package/dist/styles.floor.test.d.ts.map +0 -1
  872. package/dist/theme/border-coverage.test.d.ts +0 -18
  873. package/dist/theme/border-coverage.test.d.ts.map +0 -1
  874. package/dist/theme/contrast.test.d.ts +0 -2
  875. package/dist/theme/contrast.test.d.ts.map +0 -1
  876. package/dist/theme/ctl-theme.test.d.ts +0 -2
  877. package/dist/theme/ctl-theme.test.d.ts.map +0 -1
  878. package/dist/theme/ctl-tier-coverage.test.d.ts +0 -2
  879. package/dist/theme/ctl-tier-coverage.test.d.ts.map +0 -1
  880. package/dist/theme/density-option.test.d.ts +0 -2
  881. package/dist/theme/density-option.test.d.ts.map +0 -1
  882. package/dist/theme/density-relations.test.d.ts +0 -2
  883. package/dist/theme/density-relations.test.d.ts.map +0 -1
  884. package/dist/theme/derive-theme.test.d.ts +0 -2
  885. package/dist/theme/derive-theme.test.d.ts.map +0 -1
  886. package/dist/theme/divider-law.test.d.ts +0 -2
  887. package/dist/theme/divider-law.test.d.ts.map +0 -1
  888. package/dist/theme/fonts-option.test.d.ts +0 -2
  889. package/dist/theme/fonts-option.test.d.ts.map +0 -1
  890. package/dist/theme/icon-slot.test.d.ts +0 -2
  891. package/dist/theme/icon-slot.test.d.ts.map +0 -1
  892. package/dist/theme/layout-rhythm-css.test.d.ts +0 -2
  893. package/dist/theme/layout-rhythm-css.test.d.ts.map +0 -1
  894. package/dist/theme/radius-option.test.d.ts +0 -2
  895. package/dist/theme/radius-option.test.d.ts.map +0 -1
  896. package/dist/theme/radius.test.d.ts +0 -2
  897. package/dist/theme/radius.test.d.ts.map +0 -1
  898. package/dist/theme/shadow-surfaces.test.d.ts +0 -26
  899. package/dist/theme/shadow-surfaces.test.d.ts.map +0 -1
  900. package/dist/theme/spacing.test.d.ts +0 -2
  901. package/dist/theme/spacing.test.d.ts.map +0 -1
  902. package/dist/theme/use-basalt-spacing.test.d.ts +0 -2
  903. package/dist/theme/use-basalt-spacing.test.d.ts.map +0 -1
  904. package/dist/theme-lab/derive-controls.test.d.ts +0 -2
  905. package/dist/theme-lab/derive-controls.test.d.ts.map +0 -1
  906. package/dist/theme-lab/derive-state.test.d.ts +0 -2
  907. package/dist/theme-lab/derive-state.test.d.ts.map +0 -1
  908. package/dist/theme-lab/theme-lab.test.d.ts +0 -2
  909. package/dist/theme-lab/theme-lab.test.d.ts.map +0 -1
  910. package/dist/tokens/build-fonts-css.test.d.ts +0 -2
  911. package/dist/tokens/build-fonts-css.test.d.ts.map +0 -1
  912. package/dist/tokens/build-radius-css.test.d.ts +0 -2
  913. package/dist/tokens/build-radius-css.test.d.ts.map +0 -1
  914. package/dist/tokens/chart-margin.test.d.ts +0 -2
  915. package/dist/tokens/chart-margin.test.d.ts.map +0 -1
  916. package/dist/tokens/density.test.d.ts +0 -2
  917. package/dist/tokens/density.test.d.ts.map +0 -1
  918. package/dist/tokens/derive-radius.test.d.ts +0 -2
  919. package/dist/tokens/derive-radius.test.d.ts.map +0 -1
  920. package/dist/tokens/derive.test.d.ts +0 -2
  921. package/dist/tokens/derive.test.d.ts.map +0 -1
  922. package/dist/tokens/palette.test.d.ts +0 -2
  923. package/dist/tokens/palette.test.d.ts.map +0 -1
  924. package/dist/tokens/text-scale.test.d.ts +0 -2
  925. package/dist/tokens/text-scale.test.d.ts.map +0 -1
  926. package/dist/vite-color-mix.test.d.ts +0 -2
  927. package/dist/vite-color-mix.test.d.ts.map +0 -1
  928. package/dist/vite.test.d.ts +0 -2
  929. package/dist/vite.test.d.ts.map +0 -1
  930. package/dist/widget-header/delta-badge.test.d.ts +0 -2
  931. package/dist/widget-header/delta-badge.test.d.ts.map +0 -1
  932. package/dist/widget-header/no-mantine.test.d.ts +0 -2
  933. package/dist/widget-header/no-mantine.test.d.ts.map +0 -1
  934. package/dist/widget-header/widget-header.test.d.ts +0 -2
  935. package/dist/widget-header/widget-header.test.d.ts.map +0 -1
  936. package/src/agent/adapter.test.ts +0 -1640
  937. package/src/agent/ai-sdk-transport.test.ts +0 -658
  938. package/src/agent/coalesce.test.ts +0 -387
  939. package/src/agent/foreign.test.ts +0 -51
  940. package/src/agent/id.test.ts +0 -169
  941. package/src/agent/merge.test.ts +0 -206
  942. package/src/agent/part-list.test.tsx +0 -112
  943. package/src/agent/parts.test.ts +0 -720
  944. package/src/agent/thread.test.ts +0 -220
  945. package/src/agent/transport.test.ts +0 -70
  946. package/src/agent/use-agent-stream.test.tsx +0 -287
  947. package/src/agent/use-agent-thread-runs.foreign.test.tsx +0 -138
  948. package/src/agent/use-agent-thread-runs.resume.test.tsx +0 -294
  949. package/src/agent/use-agent-thread-runs.test.tsx +0 -1120
  950. package/src/agent/use-agent-thread-runs.wedge.test.tsx +0 -387
  951. package/src/agent-chat/composer.test.tsx +0 -924
  952. package/src/agent-chat/relative-time.test.ts +0 -95
  953. package/src/agent-chat/thread-feed-row.test.tsx +0 -510
  954. package/src/agent-chat/thread-feed.test.tsx +0 -241
  955. package/src/agent-chat/thread-message.test.tsx +0 -1285
  956. package/src/agent-chat/thread-workspace.test.tsx +0 -169
  957. package/src/agent-chat/tool-chip.test.tsx +0 -139
  958. package/src/agent-chat/virtualize.type-guard.test.ts +0 -49
  959. package/src/charts/cursor/resolve.test.ts +0 -151
  960. package/src/charts/cursor/store.test.ts +0 -64
  961. package/src/charts/kinds/BandStrip.test.tsx +0 -282
  962. package/src/charts/kinds/Bars.test.tsx +0 -183
  963. package/src/charts/kinds/DualPanel.test.tsx +0 -527
  964. package/src/charts/kinds/MirroredBars.test.tsx +0 -232
  965. package/src/charts/kinds/MultiLine.test.tsx +0 -218
  966. package/src/charts/kinds/StackedArea.test.tsx +0 -114
  967. package/src/charts/kinds/ZonedLine.test.tsx +0 -147
  968. package/src/charts/layout/auto-margin.test.ts +0 -42
  969. package/src/charts/primitives/CartesianChart.test.tsx +0 -647
  970. package/src/charts/primitives/ChartCard.test.tsx +0 -66
  971. package/src/charts/primitives/ChartFrame.test.tsx +0 -142
  972. package/src/charts/primitives/ChartLegend.test.tsx +0 -78
  973. package/src/charts/primitives/ChartTooltip.test.tsx +0 -44
  974. package/src/charts/primitives/XZoneRects.test.tsx +0 -123
  975. package/src/charts/series.test.ts +0 -112
  976. package/src/charts/utils/domain.test.ts +0 -54
  977. package/src/charts/utils/measure-text.test.ts +0 -36
  978. package/src/cli/check-coverage.test.ts +0 -297
  979. package/src/cli/check-theme.test.ts +0 -837
  980. package/src/cli/help.test.ts +0 -170
  981. package/src/cli/init-sync.test.ts +0 -343
  982. package/src/cli/placement-engine.test.ts +0 -298
  983. package/src/cli/shipped-versions.test.ts +0 -83
  984. package/src/cli/tarball-parity.test.ts +0 -44
  985. package/src/cli/template-format.test.ts +0 -64
  986. package/src/cli/template-ledger.test.ts +0 -219
  987. package/src/cli/tokens-css.test.ts +0 -249
  988. package/src/cli/toolchain-wiring.test.ts +0 -1358
  989. package/src/cli/waiver-audit.test.ts +0 -215
  990. package/src/content/article-actions.test.ts +0 -78
  991. package/src/content/article-model.test.ts +0 -119
  992. package/src/content/block-split.test.ts +0 -75
  993. package/src/content/heading-components.test.tsx +0 -65
  994. package/src/content/markdown.test.tsx +0 -603
  995. package/src/content/prose.module.css.test.ts +0 -39
  996. package/src/content/sanitize.test.ts +0 -659
  997. package/src/content/slug.test.ts +0 -62
  998. package/src/controls/actions.test.tsx +0 -252
  999. package/src/controls/actions.type-guard.test.ts +0 -63
  1000. package/src/controls/control-group.test.tsx +0 -229
  1001. package/src/controls/controls.router.test.tsx +0 -1053
  1002. package/src/controls/filter-set.test.tsx +0 -472
  1003. package/src/controls/peer-boundary.test.ts +0 -85
  1004. package/src/controls/props-contract.test.tsx +0 -137
  1005. package/src/controls/range-filter.type-guard.test.tsx +0 -122
  1006. package/src/controls/sync-button.test.tsx +0 -183
  1007. package/src/dashboard/query-state.test.tsx +0 -152
  1008. package/src/dashboard/settings-section.test.tsx +0 -56
  1009. package/src/dashboard/stat-card.test.tsx +0 -385
  1010. package/src/data/data-table.test.tsx +0 -434
  1011. package/src/guard/check-source.test.ts +0 -3388
  1012. package/src/guard/grace.test.ts +0 -158
  1013. package/src/guard/guard-hook.test.ts +0 -203
  1014. package/src/provider/index.test.tsx +0 -101
  1015. package/src/provider/lab-theme.test.ts +0 -147
  1016. package/src/query/error-message.test.ts +0 -67
  1017. package/src/router-tanstack/multi-search-param-store.test.ts +0 -124
  1018. package/src/router-tanstack/nav.test.ts +0 -111
  1019. package/src/router-tanstack/search-param-store.test.ts +0 -135
  1020. package/src/router-tanstack/search-store.router.test.tsx +0 -882
  1021. package/src/router-tanstack/search-store.test.ts +0 -578
  1022. package/src/router-tanstack/use-nav.test.tsx +0 -187
  1023. package/src/section/section.test.tsx +0 -204
  1024. package/src/shell/app-mobile-nav.test.tsx +0 -403
  1025. package/src/shell/app-sidebar.test.tsx +0 -509
  1026. package/src/shell/index.test.tsx +0 -428
  1027. package/src/shell/mobile-nav-model.test.ts +0 -517
  1028. package/src/shell/page-bar.test.tsx +0 -316
  1029. package/src/state/fields.test.tsx +0 -512
  1030. package/src/state/persisted.test.ts +0 -91
  1031. package/src/styles.floor.test.ts +0 -36
  1032. package/src/theme/border-coverage.test.ts +0 -272
  1033. package/src/theme/contrast.test.ts +0 -354
  1034. package/src/theme/ctl-theme.test.tsx +0 -275
  1035. package/src/theme/ctl-tier-coverage.test.ts +0 -170
  1036. package/src/theme/density-option.test.ts +0 -96
  1037. package/src/theme/density-relations.test.ts +0 -506
  1038. package/src/theme/derive-theme.test.ts +0 -101
  1039. package/src/theme/divider-law.test.ts +0 -259
  1040. package/src/theme/fonts-option.test.ts +0 -75
  1041. package/src/theme/icon-slot.test.tsx +0 -275
  1042. package/src/theme/layout-rhythm-css.test.ts +0 -72
  1043. package/src/theme/radius-option.test.ts +0 -86
  1044. package/src/theme/radius.test.ts +0 -142
  1045. package/src/theme/shadow-surfaces.test.ts +0 -488
  1046. package/src/theme/spacing.test.ts +0 -495
  1047. package/src/theme/use-basalt-spacing.test.tsx +0 -55
  1048. package/src/theme-lab/derive-controls.test.ts +0 -94
  1049. package/src/theme-lab/derive-state.test.ts +0 -71
  1050. package/src/theme-lab/theme-lab.test.ts +0 -46
  1051. package/src/tokens/build-fonts-css.test.ts +0 -52
  1052. package/src/tokens/build-radius-css.test.ts +0 -25
  1053. package/src/tokens/chart-margin.test.ts +0 -39
  1054. package/src/tokens/density.test.ts +0 -259
  1055. package/src/tokens/derive-radius.test.ts +0 -62
  1056. package/src/tokens/derive.test.ts +0 -30
  1057. package/src/tokens/palette.test.ts +0 -114
  1058. package/src/tokens/text-scale.test.ts +0 -51
  1059. package/src/vite-color-mix.test.ts +0 -46
  1060. package/src/vite.test.ts +0 -423
  1061. package/src/widget-header/delta-badge.test.tsx +0 -60
  1062. package/src/widget-header/no-mantine.test.ts +0 -33
  1063. package/src/widget-header/widget-header.test.tsx +0 -187
package/MIGRATING.md CHANGED
@@ -32,13 +32,457 @@ at 1.3.0, `./agent-chat` at 1.10.0.
32
32
 
33
33
  ## Unreleased
34
34
 
35
- **Nothing removed. Two exports added (`NumberFilter`, and three members on the number handle),
36
- one member added to every `FieldHandle` (`clear()`), four `StatCard` props added, and enforcement
37
- tightened: five oxlint rules plus one guard kind became `error`.** The store half of this minor also
35
+ **Nothing removed, and ONE thing changed shape: `inputProps` no longer returns `key`** — a silent
36
+ behaviour change at every field call site, caught by the new `basalt/forms-field-key` and described
37
+ in its own § below. Read that one before upgrading; the rest of the minor is additive, with
38
+ enforcement tightened: five oxlint rules plus one guard
39
+ kind became `error`, and new rule ids shipped at `warn`. The store half of this minor also
38
40
  fixed four inference and notification defects consumers hit while porting, plus two ways a fallback
39
41
  got pinned into localStorage — see § Stores below. Every level change honours the `theme-allow`
40
42
  grammar unchanged; only the severity of an unwaived finding moves.
41
43
 
44
+ **One behaviour change with a blast radius past this package: `AppShell.Main` is now the
45
+ scrollport, and the WINDOW no longer scrolls inside a `BasaltShell`.** Nothing was removed or
46
+ renamed, but four things a consumer may be doing stop working, and all four have a one-line remedy —
47
+ see § The shell scrollport below.
48
+
49
+ What is new, one line each — nothing here renames or removes anything:
50
+
51
+ - **`scrollParentOf` / `SCROLLPORT_ATTRIBUTE`** (`basalt-ui`) — resolve which box actually scrolls an
52
+ element (`null` = the document). The seam behind the shell scrollport change below.
53
+ - **`PageAside`** (`basalt-ui`) — the right-hand aside REGION a route claims, with the panel filter
54
+ surface in its body and a mobile projection into `PageBar` row 2 (`docs/ASIDE-SPEC.md`).
55
+ - **`PanelRow`** (`basalt-ui/controls`) — the aside's inspector/facet row: label above, control
56
+ below, `end` for a control that rides the label line. Every bound control renders one on the
57
+ `panel` surface.
58
+ - **`SliderControl`** (`basalt-ui/controls`) — a `field.number`-bound track for a weight or a
59
+ threshold. It always renders a `PanelRow`, so unlike the pill filters a `Section` body is a
60
+ legitimate home for it and `basalt/bound-control-outside-home` does not police it.
61
+ - **`MultiSelectFilter.counts` / `.max`** — per-option counts (a mono number plus a proportional
62
+ bar) and the panel facet cut-off before the `Show more` fold. Both optional; omitted is today's
63
+ rendering.
64
+ - **`field.number({ step })`** — the declared grain, republished on the handle. `field.number`
65
+ resolves `1` for an `int: true` field that declared none, so `NumberFilter` and `SliderControl`
66
+ cannot answer it differently.
67
+ - **`basalt/bound-control-outside-home`** — a NEW rule id at `warn` (grace to 1.30.0): a bound
68
+ basalt control written into a `Section` body or a page stack renders as a stray pill.
69
+ `control-outside-home` matches raw Mantine tags only, so this half of law C1 was unguarded. Homes
70
+ are the slot props plus the `FilterSet` / `PageAside` / `PanelRow` subtrees; the escape is
71
+ `theme-allow bound-control-outside-home — <why>`.
72
+ - **The chart phone tier** (`basalt-ui/charts`) — `resolveChartTier` / `chartTierMetrics` /
73
+ `useChartTier` / `useChartTierMetrics`, plus `VX.phoneChartWidth` (480). Below that MEASURED
74
+ container width (never a media query — a chart in a narrow grid cell on a desktop is as narrow as
75
+ one on a phone) a chart drops the legend and tick fonts one type step, tightens the `VX.margin`
76
+ FLOORS to 0.75×, shrinks the crosshair dot, narrows the tooltip 140 → 110, and caps the legend at
77
+ two entries with a `+N more` rollup. **This moves rendering, but only below 480px of measured
78
+ width** — nothing at desktop width changes. Opt back out per chart with an explicit
79
+ `legend.maxRows` / `margin` override. `docs/CHARTS-SPEC.md` §8.
80
+ - **`xLabelRotate` accepts `0`**, and left UNSET now auto-rotates to 45 at the phone tier when the
81
+ measured labels cannot fit three ticks side by side. `0` is the documented opt-out. Also on every
82
+ rotated axis, at every width: the LEFT margin now clears the rotated label's leftward projection
83
+ (`width × cos(angle)`), which previously ran the first label off the plot, and `smartTicks` drops
84
+ the grid tick before an appended final one when the two would overlap. Both are corrections to
85
+ §1's measured-gutter law, so a rotated or a densely-labelled axis will lay out slightly
86
+ differently; an explicit `margin` / `xTicks` / `xTickValues` still wins.
87
+ - **`SeriesStyle.curve`** (`basalt-ui/charts`) — `'monotone' | 'linear' | 'step' | 'stepAfter' |
88
+ 'stepBefore'`, plus the `curveFor` mapper and the newly re-exported `curveStep`/`curveStepBefore`.
89
+ Default `'monotone'`, which is what every kind hard-coded, so an omitted `curve` moves nothing.
90
+ Honoured by `MultiLine`, `DualPanel`, `ZonedLine`, `StackedArea` and `BarsLine.curve`. Two of
91
+ those read ONE curve for a whole shape rather than one per series: `ZonedLine` takes the PRIMARY
92
+ series' (its band, area and line are one reading), and `StackedArea` takes the TOPMOST VISIBLE
93
+ band that declares one — the last such entry in your `series` array (`AreaStack`'s bands share
94
+ their boundaries, so two curves would leave gaps between them). A hidden band's curve is ignored
95
+ either way, so a legend toggle can hand a stack to the next declarer down.
96
+ - **Single-series legend suppressed by default** (`basalt-ui/charts`) — since commit `5e0ade1`, a
97
+ chart with exactly one visible series and no `legend` prop renders no legend. Pass `legend={{}}`
98
+ (or any explicit config) to keep it.
99
+ - **`Bars`' baseline is now the axis' domain floor**, not `yScale(0)` — previously a y domain that
100
+ did not reach 0 drew the bar off the bottom of the plot; now it stops at the domain's own floor,
101
+ which also makes a log y-axis usable on `Bars`. A domain that includes 0 is unchanged.
102
+ - **Number formatters** (`basalt-ui/charts`) — `fmtCompact`, `fmtPercent`, `fmtCurrency`, `fmtInt`
103
+ and the `formatters` bundle, all `Intl`-backed with an explicit `locale` defaulting to the
104
+ runtime's. `utils/format.ts` shipped only two DATE formatters, so every call site hand-rolled
105
+ `` `$${v}k` ``. **Every formatter — the two date ones included — now returns an em dash for
106
+ non-finite input** (`NaN`, `±Infinity`, an `Invalid Date`) instead of `Intl`'s own `NaN` / `∞`.
107
+ A collapsed domain therefore stops painting its arithmetic accident as a tick label.
108
+ - **`ChartEmpty` / `ChartError` / `state` / `resolveChartState`** (`basalt-ui/charts`) — the chart
109
+ layer's own three-state placeholder set. `state?: { pending?, error?, empty? }` on
110
+ `CartesianChart` / `ChartFrame` / every kind resolves pending → error → empty, so a consumer no
111
+ longer needs the Mantine-coupled `QueryState` (unreachable from `./charts`) to tell a 500 apart
112
+ from an empty result. **`isPending` still works and is not deprecated** — it is an alias for
113
+ `state={{ pending: true }}`. `ChartError` announces as `role="alert"`; `ChartPending` and
114
+ `ChartEmpty` as `role="status"`, so a screen reader hears the resolution and not only the failure.
115
+ - **`BasaltProps` on every exported chart component** — `className` and `style` now reach the root
116
+ element of every kind, sparkline and primitive; `ChartCard` also takes
117
+ `classNames={{ root, header, body }}`. Additive: a component that ignored `className` now honours
118
+ it, so a stylesheet that previously had no effect starts having one.
119
+ - **`ChartTooltipFloat` server-renders.** It was the one `renderToString` casualty in the package
120
+ (an unconditional `createPortal`); it now emits nothing on the server and is unchanged in the
121
+ browser. Consumers carrying an SSR workaround around a chart tooltip can drop it.
122
+ - **`BREAKPOINTS`** (`basalt-ui/tokens`) — `{ article: 1200 }`. The one `@media` literal in the
123
+ package that was not derived from anything now has a named, testable counterpart; a `@media`
124
+ condition cannot read a custom property, so the literal stays and a test holds the two together.
125
+ - **`theme-lab/boot.ts`** — `applyOverrides`/`loadOverrides`/`readVar` moved into their own
126
+ Mantine-free, SSR-safe module (no-op / empty result with no `document`, instead of throwing).
127
+ `basalt-ui/theme-lab` still resolves all three, unchanged, alongside `ThemeLabControls` and
128
+ `DeriveControls` — nothing renamed or removed, and no new subpath was added.
129
+ - **`basalt/raw-size-literal` / `basalt/no-raw-font-size`** — no longer exempt a consumer's own
130
+ `src/tokens/` directory. The exemption was basalt-internal (the derive engine's own hardcoded
131
+ scale values) and leaked to any package with a same-named directory. Consumers with raw sizes
132
+ there move them to `--vx-*` tokens, or add a `theme-allow` waiver.
133
+ - **`BasaltProvider connectivity` prop** — `Omit<ConnectivityProviderProps, 'children'>`, threaded
134
+ straight through to the auto-mounted `ConnectivityProvider`. Reaches `override` for the first
135
+ time (the only prior route was mounting a second, shadowing `ConnectivityProvider`) — see
136
+ § BasaltProvider below.
137
+ - **Six new oxlint rule ids, all `warn`** — `basalt/provider-above-router`,
138
+ `basalt/duplicate-notifications-mount`, `basalt/query-dual-import`, `basalt/query-fn-unwrap`,
139
+ `basalt/forms-field-key` (grace to 1.30.0) and `basalt/deprecated-export` (permanently
140
+ advisory). `forms-field-key` is the one that matters most in this minor — it is the only thing
141
+ that reports the `inputProps` call sites below, which a compiler cannot see; see § `inputProps`.
142
+ The first four guard
143
+ four doctrines that shipped stated-but-unguarded under a `not guarded:` banner — the provider/
144
+ router mount order, the `BasaltOverlays` XOR `BasaltNotifications` double-mount, the
145
+ `basalt-ui/query` import seam, and `queryFn` wrapping in `unwrap()`. Each is honest about its
146
+ reach in its own message and its grace entry: all four read ONE file, and the two query rules
147
+ carry a documented text heuristic. Escape with `theme-allow <rule> — <why>` as usual. Nothing
148
+ fails a build: every one is `warn` in the shipped preset.
149
+ - **`basalt/deprecated-export`** — nudges an import or a prop basalt has deprecated but still ships,
150
+ reading the `DEPRECATED_EXPORTS` ledger beside the plugin. Today that is `field` from
151
+ `basalt-ui/forms` (autofixed to `inputProps as field`, so no call site moves) and the three
152
+ flattened `BasaltProvider` connectivity props. Permanently `warn` — a deprecation is a schedule,
153
+ not a defect. **On the `field` row, take the two fixes in order**: that rename lands the new
154
+ `inputProps` shape, which has no `key`, and `basalt/forms-field-key` then reports the same line
155
+ and inserts the `key`. Two `--fix` passes, or one manual edit writing both.
156
+ - **Dev-only duplicate-mount warnings** — `BasaltProvider` now warns when a second instance mounts
157
+ while the first is still mounted; `<BasaltOverlays notifications />` and `<BasaltNotifications />`
158
+ now warn when BOTH are mounted at once (previously prose-only in both cases). Both are
159
+ `console.warn`, dev builds only, no behavior change.
160
+ - **`WidgetGrid` + `WidgetGrid.Item` and `StatGroup`** (`basalt-ui`) — the dashboard column law,
161
+ owned once. `cols` is the DESKTOP count and the only number you state: `WidgetGrid` resolves
162
+ `base 1 → sm min(cols, 2) → lg cols`; `StatGroup` (the KPI row) resolves
163
+ `base 2 → sm min(cols, 3) → lg cols`. `<WidgetGrid.Item span={2}>` widens one cell and is clamped
164
+ to the live count at each breakpoint. `StatGroup divided` swaps the column gap for a hairline rail. **These two are the only
165
+ place `lg` exists in the package** — `sm` remains the only breakpoint a consumer writes
166
+ (`docs/CONTROLS-SPEC.md` §2). Replaces hand-written `SimpleGrid cols={{ base, md }}` /
167
+ `Grid.Col span={{ base: 12, md: 8 }}`; Mantine's responsive `cols` object is deliberately not a
168
+ prop.
169
+ - **`StatCard.query`** — `QueryStateLike`, the same structural subset `QueryState` takes. Supplied,
170
+ the card renders its pending / error / empty branch through `QueryState` at the `'section'` tier
171
+ INSIDE the body, directly under the header, which stays put. Omitted, nothing changes. `value` is
172
+ still yours to format — pass a placeholder while the query is pending.
173
+ - **`WidgetHeaderTitleProps` / `WidgetHeaderMetricProps` / `WidgetHeaderDeltaProps`** (`basalt-ui`)
174
+ — the named `Pick` slices of `WidgetHeaderProps` its composers share, cut along the three rows the
175
+ header paints. `StatCardProps` and `SettingsSectionProps` now compose them instead of re-declaring
176
+ props one at a time; **both gained props as a result** — `SettingsSection`/`DangerZone` now accept
177
+ and FORWARD `icon` and `info`. Nothing was removed from either (pinned by
178
+ `src/dashboard/stat-card-props.test.ts`). `Section` and `ChartCard` still cut their own subsets.
179
+ - **`tier` replaces `variant` on `QueryState` / `LoadingState` / `ErrorState` / `EmptyState`** —
180
+ `tier` is the package's word for "how loud is this" (`WidgetHeader`, `CtlSlot`), and `'section'`
181
+ meant two different things across the two spellings. `variant` is `@deprecated` and still
182
+ honoured; resolution is `tier ?? variant ?? 'page'`, so nothing moves until you change the prop.
183
+ `QueryStateTier` is the new type name; `QueryStateVariant` stays exported as an alias. No removal
184
+ is scheduled — this is a preferred spelling, not a sunset.
185
+ - **`WidgetHeader` and `QueryState` gained slot classes** — `classNames={{ root, title, metric,
186
+ icon }}` on the first, `classNames={{ root }}` on the second (the branch that is live). Additive.
187
+ `Section` now OMITS `classNames` from the `WidgetHeaderProps` it re-publishes, so its slot union
188
+ stays exactly `root | header | body` — a `<Section classNames={{ metric: … }}>` that used to
189
+ type-check (and do nothing) is now a compile error. Reach the header's own slots on a
190
+ `WidgetHeader`.
191
+ - **`Callout` extends `BasaltProps`** — `className`/`style` were already accepted and are now the
192
+ shared members, so `exactOptionalPropertyTypes` consumers can forward an `string | undefined`
193
+ through. No rendering change.
194
+ - **`PageAside` throws on a missing `title`** — it is both the header text and the region's
195
+ `aria-label`, so an omitted one shipped a nameless landmark rather than a crash. Now
196
+ `[basalt] PageAside: prop "title" is required — …`, in every build. `title` was never optional in
197
+ the type; this only reaches untyped JS and runtime-built props objects.
198
+ - **`BasaltDataTable` warns (dev only) when `stickyHeaderOffset` meets `maxHeight`/`minWidth`** —
199
+ the offset has always been DROPPED there (the sticky `<thead>` anchors to the scroll container's
200
+ own top edge, not the window). The behaviour is unchanged; it just says so now.
201
+ - **`query` on `Section`, `BasaltDataTable` and `BasaltVirtualList`** — law C3's uniform container
202
+ contract. Pass a `QueryStateLike` (a TanStack `UseQueryResult` is one) and the container resolves
203
+ the body: pending → its own placeholder (`QueryState`'s section-tier spinner / the table's
204
+ skeleton rows / the list's skeleton rows), error with no data → an `ErrorState` with the query's
205
+ own `refetch` behind Retry, anything else → the content, or the empty branch. **The table and the
206
+ list had NO error branch at all**, so a 500 rendered _No data to display._ / a blank box — the
207
+ false claim `QueryState` exists to delete. Additive: omit `query` and nothing changes.
208
+ `Section` also gains `empty?: QueryEmptyCopy` (copy for that branch, `QueryState`'s own type) and
209
+ `BasaltVirtualList` gains `emptyState?: ReactNode` (which works with or without `query`).
210
+ `isLoading` still works on both containers and is NOT deprecated; passing it beside `query` lets
211
+ `query` win and warns once in dev. The chrome stays drawn through every branch — a table keeps its
212
+ `<thead>`, toolbar and pagination bar, a `Section` keeps its header, chevron and `summary` — which
213
+ is why this is not `QueryState` wrapped around the container. A refetch that fails over rows
214
+ already on screen keeps the rows with no banner; compose `QueryState` AROUND the container for
215
+ that.
216
+ - **`BasaltDataTable.onRowActivate`** — `(row: T) => void`, fired by a click on the row and by Enter
217
+ on a focused one. The row → detail hook that pairs with `PageAside`. The row keeps its native
218
+ `<tr>` semantics and takes `tabIndex=0` + `data-activatable` rather than `role="button"` (a role
219
+ swap costs the column-header announcement that is the reason the data is in a table); the cursor
220
+ and focus ring come from a module class. A click originating inside the selection checkbox does
221
+ not activate.
222
+ - **`BasaltDataTable` row selection** — `enableRowSelection` prepends a checkbox column (header =
223
+ select-all on the page) and arms TanStack's row-selection feature; `rowSelection` /
224
+ `onRowSelectionChange` are the controlled pair over TanStack's own `RowSelectionState` (now
225
+ re-exported from `basalt-ui/data` and `basalt-ui/data/table`), and `getRowId` makes a selection
226
+ survive a re-sort or a refetch (the default id is the row INDEX). `bulkActions` renders a bar
227
+ above the table while ≥1 row is selected — the count, then the actions, through the SAME
228
+ `BarAction[]` vocabulary `PageBar` uses, so the ≤3-inline fold and the mobile kebab are basalt's
229
+ here too. **Its signature is `(rows: T[]) => BarAction[]`, a function and not a bare array**, and
230
+ deliberately: `BarActionItem.onClick` stays `() => void` (one unforked vocabulary across every
231
+ home), so the selected rows reach a handler through the closure you write — and an UNCONTROLLED
232
+ table can offer bulk actions at all, since the selection lives inside it.
233
+ - **`Section.actions` and `BasaltDataTable.actions` accept `BarAction[] | ReactNode`** — law C15.
234
+ Handed typed data, basalt owns the C6 budget and the C7 overflow fold (≤3 inline, the rest behind
235
+ `More`, one kebab below `sm`) exactly as `PageBar` does; handed a node, rendering is byte-for-byte
236
+ what it was. Every entry lands in `secondary` — a `BarAction[]` carries no primary marker, and C6's
237
+ "exactly one primary" stays the page bar's rule. `Section`'s ≤3 dev warning now counts an array
238
+ EXACTLY (`Children.count` read one as a single child). Both slots were `ReactNode` before, so no
239
+ call site moves.
240
+ - **`overlays.confirm` / `overlays.confirmDelete`** (`basalt-ui/commands`) — the two-button dialog
241
+ every consumer was registering as a `defineOverlays` entry with its own button pair, now
242
+ registry-free: `confirm({ title, body?, confirmLabel?, cancelLabel?, danger?, onConfirm,
243
+ onCancel? })` resolves `true`/`false` and fires exactly one callback, whichever exit the user takes
244
+ (cancel, escape, click-outside and the close button all count as `false`). `danger` paints the
245
+ confirm button in the theme's derived destructive family. `confirmDelete({ subject, count?,
246
+ onConfirm })` is the counted one-liner over it ("Delete 3 items?"). Both REJECT with a named
247
+ `[basalt] overlays.confirm: …` error when the `@mantine/modals` peer is absent, or when no
248
+ `ModalsProvider` is live — previously either returned a promise nothing would ever settle, because
249
+ the imperative API is a window event bus with nothing subscribed. `@mantine/modals` stays lazily
250
+ imported, so the peer is still optional. Additive: `defineOverlays` and `overlays.open` are
251
+ unchanged.
252
+ - **`registerModalsProvider()`** (`basalt-ui/commands`) — how a consumer who mounts
253
+ `<ModalsProvider>` THEMSELVES (with `<BasaltOverlays modals={false}>`, or with no `BasaltOverlays`
254
+ at all) tells `overlays.confirm` the layer is up. `<BasaltOverlays>` registers its own provider, so
255
+ the default path needs nothing. Call it from an effect and return its result as the cleanup:
256
+
257
+ ```tsx
258
+ useEffect(() => registerModalsProvider(), [])
259
+ ```
260
+
261
+ Availability is a COUNTER of live providers, not a flag, so two overlapping mounts (a route swap
262
+ mounting the next shell before unmounting the last) never report "no layer" while one is serving.
263
+ There is no way to detect the provider from outside React — its context is only readable through
264
+ `useModals()`, and `confirm` is an imperative call with no component to read it from — so the
265
+ registration is explicit and unregistered is indistinguishable from absent.
266
+
267
+ - **`notifyUndo` / `notifyUndoable`** (`basalt-ui/notifications`) — an undo window on top of the
268
+ existing toast machinery: `notifyUndo({ message, onUndo, window = 6000, onExpire })` shows a toast
269
+ carrying an `Undo` button and returns `{ id, dismiss() }`. The affordance and the grace period are
270
+ ONE number (`autoClose === window`), and exactly one of `onUndo` / `onExpire` runs, exactly once —
271
+ `onExpire` is where the optimistic mutation COMMITS. `dismiss()` settles the window immediately
272
+ (running `onExpire`), so a dismissed toast can never strand an uncommitted change.
273
+ `notifyUndoable(mutate, undo, opts)` is the same thing spelled for the optimistic shape. No new
274
+ store — the toast is recorded to the notification history like any other.
275
+ - **`NotifyOptions.historyMessage`** — what the persisted history records when `message` is a
276
+ composed ReactNode the store cannot stringify (`String(<Group/>)` is `[object Object]`). Defaults
277
+ to today's `String(message)`, so nothing moves unless you pass it. `notifyUndo` uses it.
278
+ - **`missingLayer`** (`basalt-ui`) — a message builder beside `requiredProp`/`oneOf`/`duplicateMount`
279
+ for "this call needs a layer that is not mounted or not installed". Additive.
280
+ - **`emit`'s payload now narrows per kind** (`basalt-ui/notifications`) — `NotificationSpec<P>` and
281
+ `NotificationAction<P>` are generic, `P` inferred from `toMessage`/`action.run`'s parameter, the
282
+ same mechanism `Overlay<P>` uses for `render`. Annotate the payload shape and `emit('kind', …)`
283
+ requires it, a wrong shape is a tsc error. A kind that annotates neither function keeps today's
284
+ `payload?: unknown` — additive, no existing `defineNotifications` call needs a change.
285
+ - **The form layer** (`basalt-ui/forms`) — `./forms` was an adapter with no layout, no submit
286
+ lifecycle, no array helper and no disabled propagation (audit B #5). Seven new exports, all
287
+ additive; `useBasaltForm`, `FormErrorSummary` and `useFormDraft`'s existing signature are
288
+ untouched. `inputProps` is the one exception, and it is not additive — see § `inputProps` no
289
+ longer returns `key` below.
290
+ - **`FormSection` / `FormRow` / `FormGroup` / `FormActions`** — the layout. `FormRow` IS law C1's
291
+ third home, the form row: label left / control right, label above below `sm`, the swap in CSS
292
+ (law C9). It does NOT replace `SettingsRow` — that stays the settings-page variant, and both
293
+ keep Mantine's `md` tier rather than mounting a `CtlSlot`. `FormActions` takes the same
294
+ `BarAction[] | ReactNode` union law C15 gave `Section.actions`.
295
+ - **`useFormSubmit(form, handler, options?)`** — `{ submit, isSubmitting, submitError, reset }`.
296
+ Catches the handler's throw and decodes it through `toErrorMessage` (override with `mapError`),
297
+ routes a thrown `{ fieldErrors }` envelope onto the fields via `form.setErrors`, and focuses the
298
+ first errored field on BOTH failure paths. `isSubmitting` is Mantine's own `form.submitting`,
299
+ not a second flag beside it.
300
+ - **`options.validateAsync`** — the async validation rule `useBasaltForm` has no room for:
301
+ `schemaResolver(schema, { sync: true })` is still hard-coded, so `validate()`/`isValid()` stay
302
+ synchronous, and the async rule runs at submit time after the schema and before the handler.
303
+ - **`FormStateProvider` / `useFormState`** — `{ disabled, submitting }`. The layout primitives
304
+ read it and disable their control region through a native `<fieldset disabled>`, so nothing has
305
+ to be threaded to each input and no child is cloned. Nesting ORs; it cannot re-enable.
306
+ - **`useFieldArray(form, path)`** — `{ items, append, remove, move, key }` over
307
+ `insertListItem`/`removeListItem`/`reorderListItem` + `form.key`. `key(index)` is POSITIONAL
308
+ (Mantine's list actions do not rotate the form key generation) — a user-reorderable list still
309
+ wants an id on the item.
310
+ - **`useFormDraft(form, { autosave })`** — `true`, or `{ debounceMs }`. The hook now owns its own
311
+ `form.watch` subscription, replacing the documented `saveDraftRef` + `onValuesChange` dance. It
312
+ is OFF by default and READ ONCE at mount (the watch set is a hook count), so every existing call
313
+ site behaves exactly as before. `DEFAULT_AUTOSAVE_DEBOUNCE_MS` is exported.
314
+ - **Still subpath-only.** The root barrel re-exports none of this, so a consumer without
315
+ `@mantine/form` is unaffected by importing `basalt-ui`.
316
+ - **Mobile "More" sheet rows now 40px with the sidebar's own insets** — `--vx-space-mobile-nav-row-
317
+ height` 44 → 40 (WCAG 2.5.5 AA touch floor, not the AAA figure the bar's own `mobileNavBarHeight`
318
+ still holds to). The rows themselves no longer force a bespoke touch padding over the theme's
319
+ `NavLink` styling; they now render with the SAME `--vx-space-row-inset-y`/`-x` padding and
320
+ `VX.text.md` the desktop sidebar row does. A nested (child) row gains the sidebar's own child
321
+ indent — a 1px `--vx-divider` left guide. Purely visual; no prop, export or behaviour changed.
322
+ - **`NotificationCenter` defaults to `width: '100%'`, not a hardcoded `320`** — it now sizes to its
323
+ host instead of assuming it always sits inside its own 320px popover. `NotificationBell` fixes the
324
+ 320px width at the `Popover` itself (`<Popover width={320}>`) instead, so nothing changes for that
325
+ call path; a consumer mounting `NotificationCenter` directly (a Drawer, an inline card) now gets a
326
+ component that shrinks to its container rather than overflowing it. `style` still merges over the
327
+ default, so `style={{ width: 280 }}` still wins.
328
+
329
+ ### `inputProps` no longer returns `key` — pair it with the new `fieldKey`
330
+
331
+ **This is the one thing in the minor that needs a code change at every call site, and the compiler
332
+ will not tell you about a single one of them.** It is a one-line-per-field edit:
333
+
334
+ ```tsx
335
+ /* before (1.27) */ <TextInput {...inputProps(form, 'email')} />
336
+ /* after */ <TextInput key={fieldKey(form, 'email')} {...inputProps(form, 'email')} />
337
+ ```
338
+
339
+ **Exactly what changed.** In 1.27 `inputProps(form, path)` returned `form.getInputProps(path)` **and
340
+ `key`** in one object, so a single spread covered both. It now returns `form.getInputProps(path)`
341
+ and nothing else; `fieldKey(form, path)` is the other half, written as a real JSX `key` attribute.
342
+ The bundle was basalt's own invention, and React 19 logs `A props object containing a "key" prop is
343
+ being spread into JSX` on every render of it — three fields, three warnings per page.
344
+ `key={form.key(path)} {...form.getInputProps(path)}` is Mantine's own documented idiom; `fieldKey` +
345
+ `inputProps` is that idiom with basalt's names.
346
+
347
+ **What breaks if you only upgrade and do nothing.** Nothing type-checks differently, nothing throws
348
+ and no warning is logged — the 1.27 call site is still a valid spread of a valid object. The element
349
+ simply has no `key` any more, so React reuses the DOM node and an uncontrolled input keeps its old
350
+ text through `form.reset()`, `form.setValues()` and a removed list row. That is the entire failure
351
+ mode: a form that stops resetting, with no signal anywhere.
352
+
353
+ **What catches it: `basalt/forms-field-key`**, new in this minor at `warn` (grace to 1.30.0). It
354
+ reports every `{...inputProps(…)}` spread whose element carries no sibling `key`, and it
355
+ **autofixes** — inserting `key={fieldKey(<same args>)}` and adding `fieldKey` to the existing
356
+ `basalt-ui/forms` import. Run `oxlint --fix` over the app and read the diff; the escape hatch for an
357
+ element genuinely remounted by its parent is `theme-allow forms-field-key — <why>`.
358
+
359
+ **The deprecated `field` alias did NOT follow `inputProps` here.** It is no longer
360
+ `export const field = inputProps`: it keeps the 1.27 return shape, `key` included, so
361
+ `{...field(form, 'x')}` behaves in 1.28.0 byte for byte as it did in 1.27 — including the React 19
362
+ key-spread warning. An alias would have changed what every existing call site DOES without changing
363
+ whether it compiles, and a deprecation is a schedule, not a behaviour change. `forms-field-key`
364
+ reports the `field(` spread too, with its own message pointing here; the alias itself is removed in
365
+ `1.29.0`.
366
+
367
+ ### `BasaltDataTable` — the root is a `<div>`, not a Fragment
368
+
369
+ **One structural change, no prop change.** The component returned a Fragment, so the header row, the
370
+ table (or its scroll container) and the pagination bar were DIRECT CHILDREN of whatever the caller
371
+ rendered it into. It now always renders a wrapper:
372
+
373
+ ```html
374
+ <div class="{classNames.root} {className}" style="{style}">
375
+ …header row… …table / Table.ScrollContainer… …pagination bar…
376
+ </div>
377
+ ```
378
+
379
+ A `className` needs a root to live on (`common/props.ts`), and a Fragment has none — so the wrapper
380
+ is what `className`, `style` and `classNames.root` all resolve against. It is unconditional: a table
381
+ with no title, no toolbar and no pagination still renders it.
382
+
383
+ **What breaks:** any CSS or test selector written against the OLD flat structure. A
384
+ `.page-grid > table`, a `:first-child` rule aimed at the table, an `:nth-child` counting the header
385
+ row and the pagination bar as siblings of your own content, or a flex/grid parent that laid those
386
+ three boxes out itself — all now see one child. Target the wrapper instead, and give it the layout:
387
+
388
+ ```css
389
+ /* before */ .page-grid > table { … }
390
+ /* after */ .page-grid > div > table { … } /* or: <BasaltDataTable classNames={{ root: 'my-table' }} /> */
391
+ ```
392
+
393
+ Pinned by `src/data/data-table.test.tsx` ("the root is one div carrying classNames.root, wrapping
394
+ the table and the pagination bar"), so it cannot revert silently.
395
+
396
+ ### BasaltProvider — a `connectivity` object replaces three flattened props
397
+
398
+ `sseUrl` / `healthUrl` / `healthIntervalMs` on `BasaltProvider` are now `@deprecated` aliases for
399
+ the corresponding fields on the new `connectivity` prop — **removed in 1.29.0**. `connectivity`
400
+ wins WHOLESALE once supplied, not per-key: passing `connectivity` at all makes basalt ignore the
401
+ three deprecated props entirely, even ones `connectivity` itself leaves unset. Supplying both logs a
402
+ dev-only warning. Move every deprecated field to `connectivity` in one pass, not one field at a time.
403
+
404
+ | Removed / deprecated | Replacement |
405
+ | ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
406
+ | `<BasaltProvider sseUrl={…} />` | `<BasaltProvider connectivity={{ sseUrl: … }} />` — `@deprecated`, removed 1.29.0 |
407
+ | `<BasaltProvider healthUrl={…} />` | `<BasaltProvider connectivity={{ healthUrl: … }} />` — `@deprecated`, removed 1.29.0 |
408
+ | `<BasaltProvider healthIntervalMs={…} />` | `<BasaltProvider connectivity={{ healthIntervalMs: … }} />` — `@deprecated`, removed 1.29.0 |
409
+ | (unreachable before this minor) | `<BasaltProvider connectivity={{ override: {…} }} />` — simulate a signal for testing/demo, no second `ConnectivityProvider` needed |
410
+
411
+ **`cssVariablesResolver` can no longer reach `BasaltProvider` through the passthrough
412
+ `MantineProviderProps` rest** — it was silently spreadable and would override basalt's own resolver
413
+ (the one thing the provider exists to install). `Omit`ted from the accepted prop type; pass any
414
+ palette customization through `createBasaltTheme(overrides, { derive, fonts, radius, density })`
415
+ instead.
416
+
417
+ ### `basalt-ui/connectivity` — `queryOnline` narrowed to `boolean`
418
+
419
+ `ConnectivitySnapshot['details'].queryOnline` and `ConnectivityOverride.queryOnline` drop the
420
+ `| null` arm. The JSDoc used to claim null meant "QueryClient not mounted", but `onlineManager` is a
421
+ module-level singleton read with no such check — the only null this field ever carried was the
422
+ pre-hydration SSR snapshot, which now reports an optimistic `true` (matching `browserOnline`'s own
423
+ SSR default) instead. Code branching on `queryOnline === null` was already dead; delete it.
424
+
425
+ ### `basalt-ui/state` — eight internal symbols dropped from the barrel
426
+
427
+ | Removed / renamed | Replacement | Note |
428
+ | ---------------------------------------------------------------------------------------------------------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
429
+ | `createStoreCore`, `resolveFieldCodec` (`basalt-ui/state`) | none | Both were `@internal` — the seam `createSearchStore` is built on, not a consumer API — and were never meant to be a public contract. No replacement needed. |
430
+ | `FieldCodec`, `StoreEntry`, `StoreCoreOptions`, `StoreCore`, `FieldUse`, `FieldWrite` (types, `basalt-ui/state`) | none | Also `@internal` — the supporting types behind `createStoreCore`/`resolveFieldCodec`, dropped alongside the two functions for the same reason. No replacement needed. |
431
+
432
+ ### `basalt-ui/forms` — `field` renamed to `inputProps`
433
+
434
+ Two unrelated exports shared the name `field`: the forms adapter's `getInputProps`+`key` bundler and
435
+ the `field.enum/multi/range/number/boolean/string` store-field builder in `basalt-ui/state` and
436
+ `basalt-ui/router-tanstack`. A page combining a form and a filter store had to alias one on import.
437
+
438
+ | Removed / renamed | Replacement | Note |
439
+ | --------------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
440
+ | `field` (`basalt-ui/forms`) | `inputProps` | Same signature — `inputProps(form, path)`. `field` still resolves from `basalt-ui/forms` as a `@deprecated` alias, so nothing breaks; the alias goes away the next time the forms surface changes, and that removal ships as a plain `feat:`, never a major. **Since the Unreleased minor the two are no longer the same function**: `inputProps` dropped `key` from its return and `field` did not — see § `inputProps` no longer returns `key`. |
441
+
442
+ The `field.*` store builder (`basalt-ui/state`, `basalt-ui/router-tanstack`) is untouched.
443
+
444
+ ### Shell — region seams, and what moved with them
445
+
446
+ **Every `AppShell` region now ends in a real, themed 1px `--vx-divider` line on its Main-facing
447
+ edge, with no opt-out** (`docs/DESIGN-SPEC.md` §5 "Region seams", §8 inversion #12): sidebar|main
448
+ (full height, under `layout="alt"` it owns the top-left corner), header|main (main column only),
449
+ main|aside (full height, absent when the aside is unclaimed), main|mobile-nav (below `sm`). Mantine
450
+ draws all four itself through `[data-with-border]`; the colour is one theme var,
451
+ `AppShell.extend({ vars: () => ({ root: { '--app-shell-border-color': 'var(--vx-divider)' } }) })`.
452
+ The aside's shell-form header also carries its own `border-bottom: 1px solid var(--vx-divider)`, so
453
+ the top belt's seam closes across the panel instead of dead-ending at the aside column.
454
+ **Delete any hand-drawn twin**: a `border-left` on your own aside-shaped panel, a `border-bottom`
455
+ under `PageBar` via `className`, a `withBorder` or a `--app-shell-border-color` override on your own
456
+ `AppShell` sections — the theme only pins the COLOUR; `withBorder` still adds or removes the edge
457
+ per section (Mantine gates the border CSS on `[data-with-border]`), so a leftover `withBorder={false}`
458
+ still suppresses the seam and must be deleted to get it, and a leftover `withBorder={true}` is
459
+ redundant (Mantine's own default).
460
+
461
+ - **`--vx-divider` moved.** Light is now `rgba(<derived ink>, 0.09)` (was
462
+ `color-mix(in srgb, #e5e5e5 65%, transparent)`) — visibly darker on light, tracks a non-default
463
+ `neutral`/`lightLevel` where the old hex did not, and never flips polarity at `lightLevel <= -3`
464
+ the way the fixed hex did. Dark moved too: `color-mix(in srgb, #ffffff 6%, transparent)` →
465
+ `rgba(255, 255, 255, 0.08)`.
466
+ - **The header's horizontal inset moved from `md` to `sm`**, so the breadcrumb's left edge and the
467
+ global actions' right edge land on the card column's edges. The sidebar brand row and the aside's
468
+ header now sit at the SAME `appShellHeaderHeight` band, so their centrelines meet the header's
469
+ across the seams. `SPACE_STEP.sidebarBrandInsetTop` / `--vx-space-sidebar-brand-inset-top` are
470
+ deleted with no replacement — the row IS the band now, not an inset inside it.
471
+ `PageAside`'s title renders the head-font `--vx-text-md`/550/ink title treatment, not the old mono
472
+ micro-label.
473
+ - **[S2] `PageBar` row 2 below `sm`** is two declared lines — the tabs, then the pill row — instead
474
+ of one overflowing `nowrap` line. `--basalt-page-bar-h` grows to match, and the `className` JSDoc
475
+ no longer suggests drawing a hairline under the bar.
476
+ - **[S3] `DeltaBadge.polarity` and `deltaPolarity`** on `WidgetHeader`/`StatCard`/`ChartCard` —
477
+ `'up-good'` (default, today's tone), `'up-bad'`, `'neutral'`. And `WidgetHeader tier="group"` — a
478
+ `Section` mounted inside `PageAside` now resolves it automatically and renders a mono micro-label
479
+ `h3` with a zero-gap row body; outside an aside nothing changes.
480
+ - **[S4] `AxisConfig.scale: 'log'`** on `CartesianChart` — 1-2-5 mantissa ticks, `autoMinCeil`
481
+ ignored on a log axis. Honoured by every kind whose domain isn't anchored at zero (`MultiLine`,
482
+ `ZonedLine`, un-stacked `Bars`); `StackedArea` and stacked `Bars` install a domain function with a
483
+ hard `0` floor and their marks anchor at the baseline, so a log scale on either yields `NaN`
484
+ geometry — don't opt in there. Additive; omitted stays linear.
485
+
42
486
  ### Stores — the `custom` flag, patched writes, lazy fallbacks, derived windows
43
487
 
44
488
  **Additive, except one type that got narrower on purpose.** `field.range({ presets, fallback })`
@@ -262,7 +706,7 @@ renders in a tiered slot, and keying the exemption on a single owner made the ve
262
706
  attribute came later in the file.
263
707
 
264
708
  **`basalt/control-outside-home` and `raw-selection-control` did NOT promote. They are re-dated to
265
- 1.28.0, and the reason is a measurement rather than caution:** the wave-7 consumer run left 9 warns
709
+ 1.30.0, and the reason is a measurement rather than caution:** the wave-7 consumer run left 9 warns
266
710
  in argo, and every one is a control inside a modal/form module whose `<Modal>` is rendered by the
267
711
  PARENT route — law C1's cross-file case, which is advisory by declaration because no scan of one
268
712
  file can see it. Both lanes now exempt a file whose BASENAME matches
@@ -286,6 +730,155 @@ half is deliberately NOT exempted the same way — a local `StatCard` beside an
286
730
  `import { StatCard as Base }` kept the name AND a piece of the original, which is the fork shape this
287
731
  rule most wants to see.
288
732
 
733
+ ### `basalt-ui/data` — a typed facet id, and a required `getItemKey`
734
+
735
+ **`BasaltDataTable`: a mistyped `facets[].columnId` used to render no pill, silently — `if
736
+ (!column) return null`.** It now throws in dev, naming the id and every known column id
737
+ (`facet columnId "…" matches no column`); production still degrades to no pill for that one facet.
738
+ `DataTableFacet` also gained a type parameter — `DataTableFacet<T = unknown>` — so `columnId` is
739
+ typed off the row shape wherever TanStack's `accessor`/manual `id` inference allows it
740
+ (`Extract<keyof T, string> | (string & {})`); the default keeps a bare `DataTableFacet[]`
741
+ compiling unchanged. `BasaltDataTableProps.facets` is now `DataTableFacet<T>[]`, and
742
+ `initialColumnPinning` moved from TanStack's own `ColumnPinningState` to a new, `T`-derived
743
+ `DataTableColumnPinning<T>` (structurally assignable to `ColumnPinningState`, so no cast is
744
+ needed at either end). Both are additive for existing call sites — an id that was already a real
745
+ column keeps compiling and rendering exactly as before.
746
+
747
+ **`BasaltVirtualList.getItemKey` is now required.** The index fallback hid stale rows across a
748
+ mutation: an insert/delete shifts every index below it, so the OLD item kept rendering at each
749
+ shifted index until an unrelated re-render happened to catch it up — in the one component whose
750
+ job is a long mutable list. Pass a real per-item key (`(item) => item.id`); there is no
751
+ replacement for the index fallback.
752
+
753
+ **`BasaltVirtualList` gained a ref.** `ref?: Ref<BasaltVirtualListHandle>` exposes
754
+ `scrollToIndex`/`scrollToOffset`/`scrollToEnd` (delegating to the internal
755
+ `@tanstack/react-virtual` instance) plus `getVirtualizer()` as the full escape hatch — mirrors
756
+ `./data/table`'s `useReactTable` re-export as the table's own. Additive; omitting `ref` changes
757
+ nothing.
758
+
759
+ ### `basalt-ui/commands` — `BasaltOverlays` no longer WRAPS your app in `ModalsProvider`
760
+
761
+ **Same props, same imperative API, one structural change: every layer — `ModalsProvider`
762
+ included — now renders as a SIBLING of `children` instead of an ancestor.** The old shape put the
763
+ whole app under a `React.lazy` Suspense boundary (`<Suspense fallback={<>{app}</>}>
764
+ <LazyModalsProvider>{app}</LazyModalsProvider></Suspense>`), and `React.lazy` suspends on its first
765
+ render even when the module is already warm. Two consequences, both real: the app's FIRST COMMIT was
766
+ deferred past a microtask — long enough for TanStack Router's async `loadMatches` to `setState` onto
767
+ a not-yet-mounted fiber ("Can't perform a React state update on a component that hasn't mounted
768
+ yet", once per full page load) — and the app tree mounted TWICE, once inside the fallback and once
769
+ resolved, so every effect in the app ran twice on boot.
770
+
771
+ Nothing to change for the overlay APIs. `modals.open` / `modals.openConfirmModal` (and so basalt's
772
+ own `overlays.open` / `overlays.close`) go through `@mantine/modals`' window CustomEvent bus, which
773
+ `ModalsProvider` subscribes to — being inside it was never a requirement, and the provider renders
774
+ its own managed `Modal` regardless of where it sits.
775
+
776
+ **The one thing a sibling cannot serve is React CONTEXT**: `useModals()` from `@mantine/modals`
777
+ called inside your app now throws its "was called outside of context" error. If you use it (or
778
+ `openContextModal`, which needs the provider's `modals` map that `BasaltOverlays` never passed
779
+ anyway), mount your own provider and turn basalt's off — two providers would both answer the event
780
+ bus and open every modal twice:
781
+
782
+ ```tsx
783
+ <BasaltOverlays modals={false}>
784
+ <ModalsProvider modals={CONTEXT_MODALS}>
785
+ <App />
786
+ </ModalsProvider>
787
+ </BasaltOverlays>
788
+ ```
789
+
790
+ ### `basalt-ui/controls` — the mobile `Filters (n)` sheet renders panel rows, not its own list
791
+
792
+ **The sheet's `SheetOptionList` (44px rows, a hairline between them, one per option) is gone.**
793
+ `useFilterSurface() === 'sheet'` now resolves to the SAME `PanelRow`/`PanelChoice`/facet-list body
794
+ `'panel'` already renders (`docs/CONTROLS-SPEC.md` §3: "sheet = panel rows inside a Drawer") — label
795
+ above, full-width control below, folding past `PANEL_TRACK_MAX` (3, a `Select`) or `max` (a
796
+ `MultiSelectFilter`'s `Show N more`) the same way the aside already did. A set with many options no
797
+ longer grows the sheet to a full column of option rows. `RangeFilter`'s sheet form is the panel's one
798
+ `Select` (presets plus a `Custom range…` row revealing the injected picker) instead of a
799
+ `SheetOptionList` with the picker behind a separate disclosure row.
800
+
801
+ Also fixed in the same pass: a `fullWidth` `SegmentedControl` (`PanelChoice`'s ≤3-option form, and
802
+ `ViewTabs`) now splits its options EVENLY — Mantine's own `.control` carries no `min-width`
803
+ override, so the initial `auto` floored each option at its content width and a `fullWidth` track
804
+ split unevenly; a long label now ellipsizes inside its equal share instead of forcing the column
805
+ wide. The active segment's fill is a second ink-mix step
806
+ (`color-mix(in srgb, var(--vx-ink) 12%, var(--vx-surface-panel))`), not a flat `--vx-surface-panel`,
807
+ so it stays visible against its own track when the whole control sits on a panel-coloured surface (a
808
+ `PanelRow`), where a flat panel fill read as barely-there next to the 6%-tinted track around it.
809
+
810
+ | Removed | Replacement | Note |
811
+ | ---------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
812
+ | `SheetOptionList`, `SheetField`, `SheetDisclosure` (`basalt-ui/controls`) | `PanelRow` / `PanelChoice` (already exported) | Were never part of the public `./controls` barrel — internal to `filter-sheet.tsx` — so this only breaks a consumer test that imported them directly out of `basalt-ui/controls/filter-sheet` or hooked a `role="radio"` `<fieldset>` DOM shape inside the sheet (now a `PanelChoice` `SegmentedControl`, `role="radiogroup"`, or a `Select`). |
813
+ | `SheetRow`, `sheetRowClassNames` (`basalt-ui/controls`) | none | Also internal-only. `ToggleFilter`'s sheet form is now a `PanelRow` whose `Switch` rides the label line, the same shape the panel surface always used. |
814
+ | `.sheetOption` / `.sheetList` / `.sheetField` / `.sheetRow` / `.sheetDisclosureBody` / `.sheetLabel` (`controls.module.css`) | `panel-row.module.css`'s `.row`/`.head`/`.control`/`.label` | CSS-module classes were never a public contract; named for a consumer that vendored a copy of the sheet's old CSS. |
815
+
816
+ ### The shell scrollport — Main scrolls, not the window
817
+
818
+ `BasaltShell` dropped Mantine's `layout="alt"` (the header now spans the full viewport width, above
819
+ the sidebar and the aside, instead of being inset beside the sidebar) and gave `AppShell.Main` a
820
+ bounded height with `overflow: auto`. Main is therefore THE scrolling element: the document's
821
+ `scrollHeight` equals the viewport height, the browser scrollbar sits on Main's own right edge
822
+ (inside the aside, where the content is) instead of at the far edge of the window, and
823
+ `window.scrollY` is pinned at 0.
824
+
825
+ Main carries two handles: `data-basalt-scrollport` (basalt's own, and what `scrollParentOf` looks
826
+ for) and `data-scroll-restoration-id="basalt-main"` (the attribute `@tanstack/router-core`'s scroll
827
+ restoration reads, so a router-driven app restores this element rather than the window).
828
+
829
+ What to change in a consumer:
830
+
831
+ | If your app… | Do this |
832
+ | ------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
833
+ | reads `window.scrollY` / listens for `scroll` on `window` | `const port = scrollParentOf(el)` and read `port.scrollTop` / listen on `port` — `null` still means the window, so shell-less code is unchanged |
834
+ | scrolls with `window.scrollTo` / `document.scrollingElement` | target `document.querySelector('[data-basalt-scrollport]')` first, with the document as the fallback |
835
+ | uses window-based scroll restoration | point it at `[data-scroll-restoration-id="basalt-main"]`; TanStack Router picks it up with no config |
836
+ | overrides `--vx-space-sticky-header-clearance` | the token NO LONGER includes the app-shell header height — it is `anchors.stackMd` (12px at level 0), pure breathing room, because BOTH the header and the page-bar band are regions outside the scrollport |
837
+ | passes `BasaltDataTable stickyHeaderOffset` inside a shell | drop it entirely. Nothing overhangs the scrollport any more, so a sticky table head wants `top: 0`, which is the default |
838
+ | computes a viewport-filling body from `--basalt-page-bar-h` | inside a shell that is just `100%` now — the band is outside Main rather than scrolling with it. The var is still published |
839
+ | passes `mobileNav.getScrollElement` only to reach the page scroller | you can drop it — the default resolves the scrollport now |
840
+
841
+ Three rendering changes ride along, all visible without any code change:
842
+
843
+ - **The brand moved out of the sidebar and into the header.** The header spans the full viewport
844
+ width now, so the sidebar's `appShellHeaderHeight` brand row painted as a SECOND 48px band under
845
+ the header seam. It is the header's leading zone instead — `--app-shell-navbar-offset` wide, so it
846
+ still tracks the rail collapse and still ends on the sidebar\|main seam — and the sidebar column
847
+ starts at `SidebarSearch`. `brand`, `brand.menu` and the collapse toggle are unchanged; only the
848
+ markup's home moved. Two consequences for a consumer mounting `AppSidebar` DIRECTLY (rather than
849
+ through `BasaltShell`, which is the supported path): it no longer paints a brand row, and its
850
+ `onToggleCollapse` prop is no longer read there — `BasaltShell` feeds it to the header instead.
851
+ - **`PageBar` row 2 is a shell-owned BAND**, not a row in the page: it portals into an outlet
852
+ `BasaltShell` renders between the header and the scrollport, exactly as row 1 portals into the
853
+ header. It spans Main's width, carries `--vx-surface-bg` and one `--vx-divider` hairline, and is a
854
+ zero-height, seam-less box on a route with no `PageBar`. It is no longer sticky and no longer
855
+ depends on where you wrote `<PageBar>` — nested in a `Stack` or written as Main's direct child now
856
+ produce identical geometry. Its padding-block tightened from `--vx-space-stack-sm` to
857
+ `--vx-space-stack-xs`, so the bar is 8px shorter.
858
+ - **`BasaltDataTable` contains itself horizontally by default.** A table with neither `maxHeight`
859
+ nor `minWidth` used to render a bare `<table>`, which sizes to its own min-content — a five-column
860
+ table measured 448px inside a 390px viewport and dragged the whole page sideways. Every table now
861
+ renders inside `Table.ScrollContainer type="native"` (`minWidth: 0` when you set none), so a wide
862
+ table scrolls inside its own card. `stickyHeader` with neither prop cannot take that container —
863
+ an `overflow-x` box computes `overflow-y` to `auto` and becomes the header's scrollport, and with
864
+ no height cap it has no scroll range, so the header would go inert — so it takes a wrapper whose
865
+ overflow is **measured** instead: while the table fits its container the wrapper declares no
866
+ overflow at all and the page-sticky header sticks exactly as before; once the table is wider the
867
+ wrapper flips to `overflow-x: auto`, the columns stay reachable, and the header is inert at that
868
+ width. The flip is a live `ResizeObserver` reading in both directions, so the wrapper goes back to
869
+ bare when the space returns (the window widened, the sidebar collapsed, the aside closed), and it
870
+ publishes `data-contained="true|false"`. The dev warning on that shape now states the trade rather
871
+ than a defect and points at `maxHeight` for a table that must both scroll and stick. Pinning takes
872
+ the same wrapper: the `overflow-x: auto` `Box` a pinned, uncapped, sticky table used to get is
873
+ gone, because it was the inert-header shape it was meant to avoid. **The TOOLBAR was the other
874
+ half of the same defect and is fixed with it**: the toolbar `Group` is the header row's flex item
875
+ (`CtlSlot` between them is `display: contents`) and carried `flex: 0 0 auto`, so a 220px search
876
+ beside a 230px facet pill row was an unshrinkable 461px box in a 302px column — `AppShell.Main`
877
+ measured `scrollWidth` 505 against `clientWidth` 390 at 390x844. It is now `flex: 0 1 auto` with
878
+ `min-width: 0`, and the search's `w={220}` became a flex BASIS (`flex: 0 1 220px`, floored at
879
+ `12ch`, capped at `100%`). The field still resolves to 220px wherever 220 fits and still never
880
+ grows with the table; below that the search and the pills wrap onto their own lines.
881
+
289
882
  ## 1.26.0 — the control tier, the page bar and the store
290
883
 
291
884
  **One export removed and two deprecated — see § Stores below; two shell PROPS removed — see
@@ -305,7 +898,7 @@ happened to the nine rows below.
305
898
  (`shadow-basalt-export`). Both ledgers now hold only the wave-6 control guards listed under
306
899
  § Guards — six plugin rules and two guard kinds, each `{ since: '1.26.0', promote: '1.27.0' }` —
307
900
  which the C16 gate forced to promote or be deleted at 1.27.0. Five rules and one kind promoted there;
308
- the C1 pair was re-dated to 1.28.0 against a measurement (see `## Unreleased` above). A theme-allow escape written against
901
+ the C1 pair was re-dated to 1.30.0 against a measurement (see `## Unreleased` above). A theme-allow escape written against
309
902
  any of these still works unchanged; only the SEVERITY of an unwaived finding moves from `warn` to
310
903
  `error`.
311
904
 
@@ -616,21 +1209,21 @@ A consumer that uses `DateRangePicker` installs `@mantine/dates` and imports
616
1209
 
617
1210
  **Nothing removed. Eight new oxlint rules and two new guard kinds. `Ships` below is the level as of
618
1211
  THIS minor** — eight land `error`, and the C1 pair (`control-outside-home` and its text lane) is the
619
- only grace left, re-dated to 1.28.0 on a measurement (see § Guards — the promotions).\*\* Every one honours `theme-allow <id> — <why>` on the
1212
+ only grace left, re-dated to 1.30.0 on a measurement (see § Guards — the promotions).\*\* Every one honours `theme-allow <id> — <why>` on the
620
1213
  node and `theme-allow-file <id> — <why>` on the file, the same grammar as the rest.
621
1214
 
622
- | Rule / kind | Fires on | Ships |
623
- | ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
624
- | `basalt/hand-rolled-filter` | A raw Mantine `Select`/`SegmentedControl`/… handed to a TIERED home slot (`actions`/`filters`/`tabs`/`sync`/`filtersEnd` on `PageBar`/`Section`/`WidgetHeader`/`ChartCard`/`StatCard`/`BasaltDataTable`/`SettingsSection`/`FilterSet`) | error |
625
- | `basalt/page-bar-budget` | A second `PageBar` in the SAME returned tree, >4 `actions.secondary`, >3 `Section` actions, a second filled `Button`/`ActionIcon` in one slot (outside an overlay) | error |
626
- | `basalt/control-outside-home` | The same raw control with no home at all — exempt under a settings row / overlay / composer, in an `@mantine/form` file, in a file that DEFINES a basalt control, or in a file basenamed `*-{modal,drawer,popover,panel,form}.tsx` | warn → 1.28.0 |
627
- | `basalt/control-size-literal` | `size`/`w`/`fullWidth`/`visibleFrom`/`hiddenFrom` on anything inside a home slot (the slot sets the tier) | **error** |
628
- | `basalt/in-body-page-title` | `<Title order={1\|2}>` outside prose/overlay context and outside a `content/` path | **error** |
629
- | `basalt/responsive-twin` | The same control mounted twice, one `visibleFrom="X"` and one `hiddenFrom="X"` | **error** |
630
- | `basalt/search-literal-link` | A `search:` object literal in a `linkOptions()` inside `defineNav()`/`navGroup()` | **error** |
631
- | `basalt/use-search-from-literal` | `useSearch({ from: '<route>' })` | **error** |
632
- | `in-body-page-title` (guard kind) | The text lane of the same law — SAME id, so one annotation waives both lanes | **error** |
633
- | `raw-selection-control` (guard kind) | The text lane of `control-outside-home`, approximated by a 12-line host-tag window, plus the same overlay-basename exemption | warn → 1.28.0 |
1215
+ | Rule / kind | Fires on | Ships |
1216
+ | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------- |
1217
+ | `basalt/hand-rolled-filter` | A raw Mantine `Select`/`SegmentedControl`/… handed to a TIERED home slot (`actions`/`filters`/`tabs`/`sync`/`filtersEnd` on `PageBar`/`Section`/`WidgetHeader`/`ChartCard`/`StatCard`/`BasaltDataTable`/`SettingsSection`/`FilterSet`) | error |
1218
+ | `basalt/page-bar-budget` | A second `PageBar` in the SAME returned tree, >4 `actions.secondary`, >3 `Section` actions, a second filled `Button`/`ActionIcon` in one slot (outside an overlay) | error |
1219
+ | `basalt/control-outside-home` | The same raw control with no home at all — exempt under a settings row / overlay / composer, in an `@mantine/form` file, in a file that DEFINES a basalt control (and imports no `basalt-ui`), or in a file basenamed `*-{modal,drawer,popover,panel,form}.tsx` / `<Subject>{Modal,Drawer,Popover,Panel,Form}.tsx` | warn → 1.30.0 |
1220
+ | `basalt/control-size-literal` | `size`/`w`/`fullWidth`/`visibleFrom`/`hiddenFrom` on anything inside a home slot (the slot sets the tier) | **error** |
1221
+ | `basalt/in-body-page-title` | `<Title order={1\|2}>` outside prose/overlay context and outside a `content/` path | **error** |
1222
+ | `basalt/responsive-twin` | The same control mounted twice, one `visibleFrom="X"` and one `hiddenFrom="X"` | **error** |
1223
+ | `basalt/search-literal-link` | A `search:` object literal in a `linkOptions()` inside `defineNav()`/`navGroup()` | **error** |
1224
+ | `basalt/use-search-from-literal` | `useSearch({ from: '<route>' })` | **error** |
1225
+ | `in-body-page-title` (guard kind) | The text lane of the same law — SAME id, so one annotation waives both lanes | **error** |
1226
+ | `raw-selection-control` (guard kind) | The text lane of `control-outside-home`, approximated by a 12-line host-tag window, plus the same overlay-basename exemption | warn → 1.30.0 |
634
1227
 
635
1228
  **A `SettingsRow`'s `control` is not a tiered slot, so nothing in this table fires inside one.**
636
1229
  It is law C1's third home — the form row — and a form keeps Mantine's `md` tier
@@ -1488,8 +2081,8 @@ deleting an entry forces the level flip in the same commit.
1488
2081
  | `basalt/responsive-twin` | 1.26.0 as `warn` | **1.27.0** |
1489
2082
  | `basalt/search-literal-link` | 1.26.0 as `warn` | **1.27.0** |
1490
2083
  | `basalt/use-search-from-literal` | 1.26.0 as `warn` | **1.27.0** |
1491
- | `basalt/control-outside-home` | 1.26.0 as `warn` | still `warn`, `promote: '1.28.0'` — re-dated on 9 measured cross-file overlay warns in argo |
1492
- | `raw-selection-control` (guard kind) | 1.26.0 as `warn` | still `warn`, `promote: '1.28.0'` — the text lane of the row above |
2084
+ | `basalt/control-outside-home` | 1.26.0 as `warn` | still `warn`, `promote: '1.30.0'` — re-dated on 9 measured cross-file overlay warns in argo |
2085
+ | `raw-selection-control` (guard kind) | 1.26.0 as `warn` | still `warn`, `promote: '1.30.0'` — the text lane of the row above |
1493
2086
 
1494
2087
  `card-with-border`, `inline-display`, `raw-html-layout`, `raw-form-control`, `raw-font-family` and
1495
2088
  the other original guard kinds have been `error` since before 1.2.0 — they never had a grace minor.