basalt-ui 1.28.0 → 1.29.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 (455) hide show
  1. package/AGENTS.md +11 -18
  2. package/CHANGELOG.md +13 -0
  3. package/MIGRATING.md +151 -7
  4. package/README.md +23 -66
  5. package/agent/rules/basalt-batteries.md +59 -182
  6. package/agent/rules/basalt-charts.md +56 -75
  7. package/agent/rules/basalt-controls.md +38 -69
  8. package/agent/rules/basalt-mantine.md +58 -103
  9. package/agent/rules/basalt-state.md +42 -60
  10. package/agent/rules/basalt-tokens.md +46 -67
  11. package/agent/skills/basalt-app/SKILL.md +2 -0
  12. package/agent/templates/CLAUDE-block.md.tpl +14 -14
  13. package/configs/oxlint-plugin.js +70 -167
  14. package/configs/oxlint-plugin.test.ts +20 -186
  15. package/configs/oxlint.json +0 -1
  16. package/dist/agent/ai-sdk-transport.d.ts.map +1 -1
  17. package/dist/agent/ai-sdk-transport.js +7 -4
  18. package/dist/agent/coalesce.js +1 -1
  19. package/dist/agent/merge.js +1 -1
  20. package/dist/agent/transport.d.ts +13 -2
  21. package/dist/agent/transport.d.ts.map +1 -1
  22. package/dist/agent/use-agent-thread-runs.d.ts +12 -1
  23. package/dist/agent/use-agent-thread-runs.d.ts.map +1 -1
  24. package/dist/agent/use-agent-thread-runs.js +20 -6
  25. package/dist/agent-chat/index.d.ts +1 -1
  26. package/dist/agent-chat/index.d.ts.map +1 -1
  27. package/dist/agent-chat/relative-time.js +1 -1
  28. package/dist/agent-chat/thread-detail-panel.js +1 -1
  29. package/dist/agent-chat/thread-feed-row.d.ts +32 -7
  30. package/dist/agent-chat/thread-feed-row.d.ts.map +1 -1
  31. package/dist/agent-chat/thread-feed-row.js +121 -86
  32. package/dist/agent-chat/thread-feed.d.ts +11 -1
  33. package/dist/agent-chat/thread-feed.d.ts.map +1 -1
  34. package/dist/agent-chat/thread-feed.js +10 -6
  35. package/dist/agent-chat/thread-message.js +1 -1
  36. package/dist/agent-chat/virtualize.d.ts +39 -0
  37. package/dist/agent-chat/virtualize.d.ts.map +1 -1
  38. package/dist/agent-chat/virtualize.js +15 -0
  39. package/dist/charts/index.d.ts +3 -3
  40. package/dist/charts/index.d.ts.map +1 -1
  41. package/dist/charts/index.js +8 -4
  42. package/dist/charts/kinds/BandStrip.js +1 -1
  43. package/dist/charts/kinds/Bars.d.ts +1 -3
  44. package/dist/charts/kinds/Bars.d.ts.map +1 -1
  45. package/dist/charts/kinds/Bars.js +1 -1
  46. package/dist/charts/kinds/DualPanel.d.ts +3 -1
  47. package/dist/charts/kinds/DualPanel.d.ts.map +1 -1
  48. package/dist/charts/kinds/DualPanel.js +1 -1
  49. package/dist/charts/kinds/StackedArea.js +1 -1
  50. package/dist/charts/kinds/ZonedLine.d.ts +1 -3
  51. package/dist/charts/kinds/ZonedLine.d.ts.map +1 -1
  52. package/dist/charts/primitives/Axes.d.ts +21 -2
  53. package/dist/charts/primitives/Axes.d.ts.map +1 -1
  54. package/dist/charts/primitives/Axes.js +34 -2
  55. package/dist/charts/primitives/ChartCard.d.ts +20 -4
  56. package/dist/charts/primitives/ChartCard.d.ts.map +1 -1
  57. package/dist/charts/primitives/ChartCard.js +62 -33
  58. package/dist/charts/primitives/ChartFrame.d.ts.map +1 -1
  59. package/dist/charts/primitives/ChartFrame.js +8 -1
  60. package/dist/charts/primitives/ChartPending.d.ts +12 -6
  61. package/dist/charts/primitives/ChartPending.d.ts.map +1 -1
  62. package/dist/charts/primitives/ChartPending.js +1 -1
  63. package/dist/charts/utils/format.d.ts +5 -92
  64. package/dist/charts/utils/format.d.ts.map +1 -1
  65. package/dist/charts/utils/format.js +10 -80
  66. package/dist/cli/audit-allows.d.ts +24 -0
  67. package/dist/cli/audit-allows.d.ts.map +1 -0
  68. package/dist/cli/audit-allows.js +240 -0
  69. package/dist/cli/check-theme.d.ts +10 -0
  70. package/dist/cli/check-theme.d.ts.map +1 -0
  71. package/dist/cli/check-theme.js +139 -0
  72. package/dist/cli/doctor.d.ts +47 -0
  73. package/dist/cli/doctor.d.ts.map +1 -0
  74. package/dist/cli/doctor.js +197 -0
  75. package/dist/cli/guard-hook.d.ts +9 -0
  76. package/dist/cli/guard-hook.d.ts.map +1 -0
  77. package/dist/cli/guard-hook.js +93 -0
  78. package/dist/cli/help.d.ts +9 -0
  79. package/dist/cli/help.d.ts.map +1 -0
  80. package/dist/cli/help.js +53 -0
  81. package/dist/cli/index.d.ts +360 -270
  82. package/dist/cli/index.d.ts.map +1 -1
  83. package/dist/cli/index.js +85 -1901
  84. package/dist/cli/init.d.ts +4 -0
  85. package/dist/cli/init.d.ts.map +1 -0
  86. package/dist/cli/init.js +165 -0
  87. package/dist/cli/sync.d.ts +43 -0
  88. package/dist/cli/sync.d.ts.map +1 -0
  89. package/dist/cli/sync.js +206 -0
  90. package/dist/cli/tokens-css.d.ts +51 -0
  91. package/dist/cli/tokens-css.d.ts.map +1 -0
  92. package/dist/cli/tokens-css.js +165 -0
  93. package/dist/commands/define-commands.js +1 -1
  94. package/dist/commands/define-overlays.js +1 -1
  95. package/dist/commands/index.d.ts +2 -1
  96. package/dist/commands/index.d.ts.map +1 -1
  97. package/dist/commands/index.js +6 -0
  98. package/dist/commands/overlays-mount.d.ts +7 -9
  99. package/dist/commands/overlays-mount.d.ts.map +1 -1
  100. package/dist/commands/shell-bridge.d.ts +57 -0
  101. package/dist/commands/shell-bridge.d.ts.map +1 -0
  102. package/dist/commands/shell-bridge.js +32 -0
  103. package/dist/common/errors.d.ts +35 -0
  104. package/dist/common/errors.d.ts.map +1 -1
  105. package/dist/common/errors.js +29 -1
  106. package/dist/common/index.d.ts +2 -0
  107. package/dist/common/index.d.ts.map +1 -1
  108. package/dist/common/index.js +6 -0
  109. package/dist/common/is-dev.d.ts.map +1 -0
  110. package/dist/{motion/index.d.ts → common/motion.d.ts} +1 -1
  111. package/dist/common/motion.d.ts.map +1 -0
  112. package/dist/common/props.d.ts +1 -1
  113. package/dist/common/props.d.ts.map +1 -1
  114. package/dist/common/validate.js +1 -1
  115. package/dist/content/markdown.d.ts +3 -4
  116. package/dist/content/markdown.d.ts.map +1 -1
  117. package/dist/content/markdown.js +1 -4
  118. package/dist/controls/actions.d.ts +1 -1
  119. package/dist/controls/actions.d.ts.map +1 -1
  120. package/dist/controls/panel-row.js +1 -1
  121. package/dist/controls/range-filter.js +1 -1
  122. package/dist/dashboard/delta-badge.d.ts +18 -10
  123. package/dist/dashboard/delta-badge.d.ts.map +1 -1
  124. package/dist/dashboard/delta-badge.js +33 -1
  125. package/dist/dashboard/empty-state.d.ts +1 -4
  126. package/dist/dashboard/empty-state.d.ts.map +1 -1
  127. package/dist/dashboard/empty-state.js +1 -2
  128. package/dist/dashboard/index.d.ts +4 -2
  129. package/dist/dashboard/index.d.ts.map +1 -1
  130. package/dist/dashboard/index.js +7 -1
  131. package/dist/dashboard/query-state.d.ts +4 -13
  132. package/dist/dashboard/query-state.d.ts.map +1 -1
  133. package/dist/dashboard/query-state.js +4 -7
  134. package/dist/{section → dashboard}/section.d.ts +2 -2
  135. package/dist/{section → dashboard}/section.d.ts.map +1 -1
  136. package/dist/{section → dashboard}/section.js +2 -2
  137. package/dist/dashboard/settings-section.d.ts +1 -1
  138. package/dist/dashboard/settings-section.d.ts.map +1 -1
  139. package/dist/dashboard/settings-section.js +1 -1
  140. package/dist/dashboard/stat-card.d.ts +1 -1
  141. package/dist/dashboard/stat-card.d.ts.map +1 -1
  142. package/dist/dashboard/stat-card.js +1 -1
  143. package/dist/dashboard/widget-header.d.ts.map +1 -0
  144. package/dist/data/data-table.js +2 -2
  145. package/dist/data/table.d.ts +1 -1
  146. package/dist/data/table.d.ts.map +1 -1
  147. package/dist/data/table.js +2 -16
  148. package/dist/data/virtual.d.ts +3 -3
  149. package/dist/dev-dock.d.ts +28 -0
  150. package/dist/dev-dock.d.ts.map +1 -0
  151. package/dist/dev-dock.js +85 -0
  152. package/dist/format/date.d.ts +62 -0
  153. package/dist/format/date.d.ts.map +1 -0
  154. package/dist/format/date.js +106 -0
  155. package/dist/format/index.d.ts +39 -0
  156. package/dist/format/index.d.ts.map +1 -0
  157. package/dist/format/index.js +54 -0
  158. package/dist/format/measure.d.ts +15 -0
  159. package/dist/format/measure.d.ts.map +1 -0
  160. package/dist/format/measure.js +16 -0
  161. package/dist/format/number.d.ts +69 -0
  162. package/dist/format/number.d.ts.map +1 -0
  163. package/dist/format/number.js +62 -0
  164. package/dist/format/shared.d.ts +27 -0
  165. package/dist/format/shared.d.ts.map +1 -0
  166. package/dist/format/shared.js +29 -0
  167. package/dist/forms/field.d.ts +4 -20
  168. package/dist/forms/field.d.ts.map +1 -1
  169. package/dist/forms/field.js +0 -4
  170. package/dist/forms/form-layout.d.ts +1 -1
  171. package/dist/forms/form-layout.d.ts.map +1 -1
  172. package/dist/forms/form-layout.js +1 -1
  173. package/dist/forms/index.d.ts +1 -1
  174. package/dist/forms/index.d.ts.map +1 -1
  175. package/dist/forms/index.js +1 -2
  176. package/dist/forms/use-form-submit.js +1 -1
  177. package/dist/guard/index.d.ts +2 -9
  178. package/dist/guard/index.d.ts.map +1 -1
  179. package/dist/guard/index.js +16 -26
  180. package/dist/guard/types.d.ts +8 -10
  181. package/dist/guard/types.d.ts.map +1 -1
  182. package/dist/index.d.ts +16 -11
  183. package/dist/index.d.ts.map +1 -1
  184. package/dist/index.js +23 -29
  185. package/dist/notifications/index.d.ts +5 -5
  186. package/dist/notifications/index.d.ts.map +1 -1
  187. package/dist/notifications/index.js +0 -2
  188. package/dist/notifications/mount-guard.d.ts.map +1 -1
  189. package/dist/notifications/mount-guard.js +2 -2
  190. package/dist/provider/connectivity-indicator.d.ts.map +1 -0
  191. package/dist/{connectivity → provider}/connectivity-provider.d.ts +1 -1
  192. package/dist/provider/connectivity-provider.d.ts.map +1 -0
  193. package/dist/{connectivity/types.d.ts → provider/connectivity-types.d.ts} +1 -1
  194. package/dist/provider/connectivity-types.d.ts.map +1 -0
  195. package/dist/provider/error-fallback.module.css +21 -0
  196. package/dist/provider/error-fallback.module.css.d.ts +9 -0
  197. package/dist/provider/index.d.ts +20 -36
  198. package/dist/provider/index.d.ts.map +1 -1
  199. package/dist/provider/index.js +42 -32
  200. package/dist/provider/lab-theme.js +1 -1
  201. package/dist/provider/use-connectivity.d.ts +3 -0
  202. package/dist/provider/use-connectivity.d.ts.map +1 -0
  203. package/dist/query-client.d.ts +63 -0
  204. package/dist/query-client.d.ts.map +1 -0
  205. package/dist/query-client.js +33 -0
  206. package/dist/{query/devtools.d.ts → query-devtools.d.ts} +2 -2
  207. package/dist/query-devtools.d.ts.map +1 -0
  208. package/dist/register.d.ts +17 -3
  209. package/dist/register.d.ts.map +1 -1
  210. package/dist/router-tanstack/index.d.ts +4 -7
  211. package/dist/router-tanstack/index.d.ts.map +1 -1
  212. package/dist/router-tanstack/index.js +1 -9
  213. package/dist/router-tanstack/nav.d.ts +1 -1
  214. package/dist/router-tanstack/nav.d.ts.map +1 -1
  215. package/dist/router-tanstack/search-store.d.ts +3 -6
  216. package/dist/router-tanstack/search-store.d.ts.map +1 -1
  217. package/dist/router-tanstack/use-nav.d.ts +1 -1
  218. package/dist/router-tanstack/use-nav.d.ts.map +1 -1
  219. package/dist/shell/app-breadcrumbs.d.ts +1 -1
  220. package/dist/shell/app-breadcrumbs.d.ts.map +1 -1
  221. package/dist/shell/app-main.module.css +11 -0
  222. package/dist/shell/app-mobile-nav.d.ts +1 -1
  223. package/dist/shell/app-mobile-nav.d.ts.map +1 -1
  224. package/dist/shell/app-mobile-nav.js +24 -2
  225. package/dist/shell/app-sidebar.d.ts +1 -1
  226. package/dist/shell/app-sidebar.d.ts.map +1 -1
  227. package/dist/shell/app-sidebar.js +31 -2
  228. package/dist/shell/app-sidebar.module.css +10 -0
  229. package/dist/shell/index.d.ts +10 -4
  230. package/dist/shell/index.d.ts.map +1 -1
  231. package/dist/shell/index.js +13 -17
  232. package/dist/shell/mobile-nav-model.d.ts +1 -1
  233. package/dist/shell/mobile-nav-model.d.ts.map +1 -1
  234. package/dist/{nav/types.d.ts → shell/nav-types.d.ts} +1 -1
  235. package/dist/shell/nav-types.d.ts.map +1 -0
  236. package/dist/shell/page-aside.d.ts.map +1 -1
  237. package/dist/shell/page-aside.js +2 -29
  238. package/dist/shell/page-title.d.ts +14 -0
  239. package/dist/shell/page-title.d.ts.map +1 -0
  240. package/dist/shell/page-title.js +25 -0
  241. package/dist/shell/page-title.module.css +33 -0
  242. package/dist/shell/page-title.module.css.d.ts +11 -0
  243. package/dist/shell/sidebar-block-model.d.ts +1 -1
  244. package/dist/shell/sidebar-block-model.d.ts.map +1 -1
  245. package/dist/shell/sidebar-blocks.d.ts +1 -1
  246. package/dist/shell/sidebar-blocks.d.ts.map +1 -1
  247. package/dist/shell/use-breakpoint.d.ts +11 -0
  248. package/dist/shell/use-breakpoint.d.ts.map +1 -0
  249. package/dist/shell/use-breakpoint.js +33 -0
  250. package/dist/state/fields.d.ts +3 -19
  251. package/dist/state/fields.d.ts.map +1 -1
  252. package/dist/state/fields.js +6 -16
  253. package/dist/styles.css +36 -0
  254. package/dist/surfaces.d.ts +18 -41
  255. package/dist/surfaces.d.ts.map +1 -1
  256. package/dist/surfaces.js +46 -59
  257. package/dist/theme/index.d.ts.map +1 -1
  258. package/dist/{theme-toggle/index.d.ts → theme/theme-toggle.d.ts} +1 -1
  259. package/dist/theme/theme-toggle.d.ts.map +1 -0
  260. package/dist/{theme-toggle/index.js → theme/theme-toggle.js} +1 -1
  261. package/dist/tokens/index.d.ts +1 -0
  262. package/dist/tokens/index.d.ts.map +1 -1
  263. package/dist/tokens/index.js +10 -0
  264. package/dist/tokens/palette.d.ts +12 -0
  265. package/dist/tokens/palette.d.ts.map +1 -1
  266. package/dist/tokens/palette.js +13 -1
  267. package/dist/tokens.css +1 -0
  268. package/llms.txt +9 -24
  269. package/package.json +12 -16
  270. package/src/agent/ai-sdk-transport.ts +11 -4
  271. package/src/agent/coalesce.ts +1 -1
  272. package/src/agent/merge.ts +1 -1
  273. package/src/agent/transport.ts +15 -2
  274. package/src/agent/use-agent-thread-runs.ts +65 -15
  275. package/src/agent-chat/index.ts +6 -4
  276. package/src/agent-chat/relative-time.ts +1 -1
  277. package/src/agent-chat/thread-detail-panel.tsx +1 -1
  278. package/src/agent-chat/thread-feed-row.tsx +105 -30
  279. package/src/agent-chat/thread-feed.tsx +51 -25
  280. package/src/agent-chat/thread-message.tsx +1 -1
  281. package/src/agent-chat/virtualize.ts +48 -0
  282. package/src/charts/index.ts +7 -10
  283. package/src/charts/kinds/BandStrip.tsx +1 -1
  284. package/src/charts/kinds/Bars.tsx +2 -5
  285. package/src/charts/kinds/DualPanel.tsx +4 -3
  286. package/src/charts/kinds/StackedArea.tsx +1 -1
  287. package/src/charts/kinds/ZonedLine.tsx +1 -4
  288. package/src/charts/primitives/Axes.tsx +49 -0
  289. package/src/charts/primitives/ChartCard.tsx +49 -6
  290. package/src/charts/primitives/ChartFrame.tsx +5 -1
  291. package/src/charts/primitives/ChartPending.tsx +14 -8
  292. package/src/charts/utils/format.ts +17 -186
  293. package/src/cli/audit-allows.ts +371 -0
  294. package/src/cli/check-theme.ts +197 -0
  295. package/src/cli/doctor.ts +331 -0
  296. package/src/cli/guard-hook.ts +115 -0
  297. package/src/cli/help.ts +101 -0
  298. package/src/cli/index.ts +269 -3439
  299. package/src/cli/init.ts +247 -0
  300. package/src/cli/sync.ts +324 -0
  301. package/src/cli/tokens-css.ts +252 -0
  302. package/src/commands/define-commands.ts +1 -1
  303. package/src/commands/define-overlays.ts +1 -1
  304. package/src/commands/index.ts +10 -1
  305. package/src/commands/overlays-mount.tsx +8 -10
  306. package/src/commands/shell-bridge.ts +86 -0
  307. package/src/common/errors.ts +70 -0
  308. package/src/common/index.ts +2 -0
  309. package/src/common/props.ts +1 -1
  310. package/src/common/validate.ts +1 -1
  311. package/src/content/markdown.tsx +4 -8
  312. package/src/controls/actions.tsx +1 -1
  313. package/src/controls/panel-row.tsx +1 -1
  314. package/src/controls/range-filter.tsx +1 -1
  315. package/src/dashboard/delta-badge.tsx +74 -7
  316. package/src/dashboard/empty-state.tsx +2 -6
  317. package/src/dashboard/index.ts +11 -2
  318. package/src/dashboard/query-state.tsx +5 -18
  319. package/src/{section → dashboard}/section.tsx +4 -4
  320. package/src/dashboard/settings-section.tsx +2 -2
  321. package/src/dashboard/stat-card.tsx +2 -2
  322. package/src/data/data-table.tsx +3 -3
  323. package/src/data/table.ts +6 -25
  324. package/src/data/virtual-list.tsx +1 -1
  325. package/src/data/virtual.ts +3 -3
  326. package/src/dev-dock.tsx +159 -0
  327. package/src/format/date.ts +184 -0
  328. package/src/format/index.ts +69 -0
  329. package/src/format/measure.ts +31 -0
  330. package/src/format/number.ts +129 -0
  331. package/src/format/shared.ts +63 -0
  332. package/src/forms/field.ts +4 -24
  333. package/src/forms/form-layout.tsx +2 -2
  334. package/src/forms/index.ts +1 -2
  335. package/src/forms/use-form-submit.ts +1 -1
  336. package/src/guard/index.ts +30 -56
  337. package/src/guard/types.ts +7 -10
  338. package/src/index.ts +38 -29
  339. package/src/notifications/index.ts +5 -7
  340. package/src/notifications/mount-guard.ts +7 -9
  341. package/src/{connectivity → provider}/connectivity-indicator.tsx +1 -1
  342. package/src/{connectivity → provider}/connectivity-provider.tsx +1 -1
  343. package/src/provider/error-fallback.module.css +21 -0
  344. package/src/provider/error-fallback.module.css.d.ts +9 -0
  345. package/src/provider/index.tsx +71 -71
  346. package/src/provider/lab-theme.ts +1 -1
  347. package/src/{connectivity → provider}/use-connectivity.ts +3 -3
  348. package/src/query-client.ts +100 -0
  349. package/src/{query/devtools.tsx → query-devtools.tsx} +5 -4
  350. package/src/register.ts +20 -4
  351. package/src/router-tanstack/index.ts +4 -15
  352. package/src/router-tanstack/nav.ts +1 -1
  353. package/src/router-tanstack/search-store.ts +3 -4
  354. package/src/router-tanstack/use-nav.ts +1 -1
  355. package/src/shell/app-breadcrumbs.tsx +1 -1
  356. package/src/shell/app-main.module.css +11 -0
  357. package/src/shell/app-mobile-nav.tsx +28 -1
  358. package/src/shell/app-sidebar.module.css +10 -0
  359. package/src/shell/app-sidebar.tsx +31 -2
  360. package/src/shell/index.tsx +23 -28
  361. package/src/shell/mobile-nav-model.ts +1 -1
  362. package/src/shell/page-aside.tsx +2 -52
  363. package/src/shell/page-title.module.css +33 -0
  364. package/src/shell/page-title.module.css.d.ts +11 -0
  365. package/src/shell/page-title.tsx +57 -0
  366. package/src/shell/sidebar-block-model.ts +1 -1
  367. package/src/shell/sidebar-blocks.tsx +1 -1
  368. package/src/shell/use-breakpoint.ts +73 -0
  369. package/src/state/fields.ts +7 -43
  370. package/src/styles.css +36 -0
  371. package/src/surfaces.ts +45 -60
  372. package/src/theme/index.ts +7 -0
  373. package/src/{theme-toggle/index.tsx → theme/theme-toggle.tsx} +1 -1
  374. package/src/tokens/index.ts +10 -0
  375. package/src/tokens/palette.ts +12 -0
  376. package/dist/connectivity/connectivity-indicator.d.ts.map +0 -1
  377. package/dist/connectivity/connectivity-provider.d.ts.map +0 -1
  378. package/dist/connectivity/index.d.ts +0 -14
  379. package/dist/connectivity/index.d.ts.map +0 -1
  380. package/dist/connectivity/index.js +0 -8
  381. package/dist/connectivity/types.d.ts.map +0 -1
  382. package/dist/connectivity/use-connectivity.d.ts +0 -3
  383. package/dist/connectivity/use-connectivity.d.ts.map +0 -1
  384. package/dist/data/index.d.ts +0 -38
  385. package/dist/data/index.d.ts.map +0 -1
  386. package/dist/data/index.js +0 -24
  387. package/dist/motion/index.d.ts.map +0 -1
  388. package/dist/nav/types.d.ts.map +0 -1
  389. package/dist/notifications/overlay.d.ts +0 -20
  390. package/dist/notifications/overlay.d.ts.map +0 -1
  391. package/dist/notifications/overlay.js +0 -14
  392. package/dist/query/devtools.d.ts.map +0 -1
  393. package/dist/query/error-message.d.ts +0 -41
  394. package/dist/query/error-message.d.ts.map +0 -1
  395. package/dist/query/error-message.js +0 -30
  396. package/dist/query/index.d.ts +0 -47
  397. package/dist/query/index.d.ts.map +0 -1
  398. package/dist/query/index.js +0 -56
  399. package/dist/router-tanstack/field.d.ts +0 -14
  400. package/dist/router-tanstack/field.d.ts.map +0 -1
  401. package/dist/router-tanstack/field.js +0 -4
  402. package/dist/router-tanstack/multi-search-param-store.d.ts +0 -43
  403. package/dist/router-tanstack/multi-search-param-store.d.ts.map +0 -1
  404. package/dist/router-tanstack/multi-search-param-store.js +0 -30
  405. package/dist/router-tanstack/search-param-store.d.ts +0 -42
  406. package/dist/router-tanstack/search-param-store.d.ts.map +0 -1
  407. package/dist/router-tanstack/search-param-store.js +0 -25
  408. package/dist/section/index.d.ts +0 -2
  409. package/dist/section/index.d.ts.map +0 -1
  410. package/dist/section/index.js +0 -4
  411. package/dist/theme-toggle/index.d.ts.map +0 -1
  412. package/dist/utils/is-dev.d.ts.map +0 -1
  413. package/dist/widget-header/delta-badge.d.ts +0 -19
  414. package/dist/widget-header/delta-badge.d.ts.map +0 -1
  415. package/dist/widget-header/delta-badge.js +0 -36
  416. package/dist/widget-header/index.d.ts +0 -3
  417. package/dist/widget-header/index.d.ts.map +0 -1
  418. package/dist/widget-header/index.js +0 -8
  419. package/dist/widget-header/widget-header.d.ts.map +0 -1
  420. package/src/connectivity/index.ts +0 -19
  421. package/src/data/index.ts +0 -69
  422. package/src/notifications/overlay.tsx +0 -66
  423. package/src/query/error-message.ts +0 -70
  424. package/src/query/index.ts +0 -97
  425. package/src/router-tanstack/field.ts +0 -36
  426. package/src/router-tanstack/multi-search-param-store.ts +0 -106
  427. package/src/router-tanstack/search-param-store.ts +0 -100
  428. package/src/section/index.ts +0 -1
  429. package/src/widget-header/delta-badge.tsx +0 -77
  430. package/src/widget-header/index.ts +0 -10
  431. /package/dist/{utils → common}/is-dev.d.ts +0 -0
  432. /package/dist/{utils → common}/is-dev.js +0 -0
  433. /package/dist/{motion/index.js → common/motion.js} +0 -0
  434. /package/dist/{section → dashboard}/section.module.css +0 -0
  435. /package/dist/{section → dashboard}/section.module.css.d.ts +0 -0
  436. /package/dist/{widget-header → dashboard}/widget-header.d.ts +0 -0
  437. /package/dist/{widget-header → dashboard}/widget-header.js +0 -0
  438. /package/dist/{widget-header → dashboard}/widget-header.module.css +0 -0
  439. /package/dist/{widget-header → dashboard}/widget-header.module.css.d.ts +0 -0
  440. /package/dist/{connectivity → provider}/connectivity-indicator.d.ts +0 -0
  441. /package/dist/{connectivity → provider}/connectivity-indicator.js +0 -0
  442. /package/dist/{connectivity → provider}/connectivity-provider.js +0 -0
  443. /package/dist/{connectivity/types.js → provider/connectivity-types.js} +0 -0
  444. /package/dist/{connectivity → provider}/use-connectivity.js +0 -0
  445. /package/dist/{query/devtools.js → query-devtools.js} +0 -0
  446. /package/dist/{nav/types.js → shell/nav-types.js} +0 -0
  447. /package/src/{utils → common}/is-dev.ts +0 -0
  448. /package/src/{motion/index.ts → common/motion.ts} +0 -0
  449. /package/src/{section → dashboard}/section.module.css +0 -0
  450. /package/src/{section → dashboard}/section.module.css.d.ts +0 -0
  451. /package/src/{widget-header → dashboard}/widget-header.module.css +0 -0
  452. /package/src/{widget-header → dashboard}/widget-header.module.css.d.ts +0 -0
  453. /package/src/{widget-header → dashboard}/widget-header.tsx +0 -0
  454. /package/src/{connectivity/types.ts → provider/connectivity-types.ts} +0 -0
  455. /package/src/{nav/types.ts → shell/nav-types.ts} +0 -0
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Date/time/duration formatting. `fmtAxisDate`/`fmtTooltipDate` moved here from
3
+ * `src/charts/utils/format.ts` (C5 consolidation) — that file now re-exports from this module.
4
+ * The rest (`clock`/`weekday`/`relativeTime`/`duration`/`durationClock`) are new, seeded from argo
5
+ * consumers (`features/{walking-pad,reading,astro-window,garmin-health}/{formatters,format,
6
+ * formulas}.ts` — read those files' own JSDoc for the exact call sites this generalizes).
7
+ */
8
+ import { dateFormat, NON_FINITE, toDate } from './shared'
9
+ import type { LocaleOption } from './shared'
10
+
11
+ const MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
12
+ const SHORT_DAYS = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
13
+
14
+ /** Axis-friendly short date: DD.MM. A non-finite or invalid date prints {@link NON_FINITE}. */
15
+ export function fmtAxisDate(value: unknown): string {
16
+ if (typeof value === 'number' && !Number.isFinite(value)) return NON_FINITE
17
+ if (value instanceof Date) {
18
+ if (Number.isNaN(value.getTime())) return NON_FINITE
19
+ const dd = String(value.getDate()).padStart(2, '0')
20
+ const mm = String(value.getMonth() + 1).padStart(2, '0')
21
+ return `${dd}.${mm}`
22
+ }
23
+ const s = String(value ?? '')
24
+ const match = s.match(/(\d{4})-(\d{2})-(\d{2})/)
25
+ if (match) return `${match[3]}.${match[2]}`
26
+ return s
27
+ }
28
+
29
+ /** Tooltip-friendly long date: "Mon Apr 21 2026". A non-finite or invalid date prints
30
+ * {@link NON_FINITE}. */
31
+ export function fmtTooltipDate(date: unknown): string {
32
+ if (typeof date === 'number' && !Number.isFinite(date)) return NON_FINITE
33
+ if (date instanceof Date) {
34
+ if (Number.isNaN(date.getTime())) return NON_FINITE
35
+ return `${SHORT_DAYS[date.getDay()]} ${MONTHS[date.getMonth()]} ${date.getDate()} ${date.getFullYear()}`
36
+ }
37
+ const s = String(date ?? '')
38
+ const match = s.match(/(\d{4})-(\d{2})-(\d{2})/)
39
+ if (!match) return s
40
+ const d = new Date(Number(match[1]), Number(match[2]) - 1, Number(match[3]))
41
+ return `${SHORT_DAYS[d.getDay()]} ${MONTHS[d.getMonth()]} ${d.getDate()} ${d.getFullYear()}`
42
+ }
43
+
44
+ export type ClockOptions = LocaleOption & {
45
+ /** IANA zone (`'Europe/Vienna'`). Default the runtime's own zone — the same "local" argo's
46
+ * `d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })` call sites meant. */
47
+ timeZone?: string
48
+ /** Render `:ss` too. Default false. */
49
+ seconds?: boolean
50
+ }
51
+
52
+ /** A local clock reading — `"09:41"`. Seeds: `m365-explorer/explorer-page.tsx`,
53
+ * `walking-pad/session-history.tsx` (both `toLocaleTimeString([...], { hour: '2-digit', minute:
54
+ * '2-digit' })`). A non-finite/unparseable input prints {@link NON_FINITE}. */
55
+ export function clock(value: Date | number | string, options: ClockOptions = {}): string {
56
+ const date = toDate(value)
57
+ if (date === null) return NON_FINITE
58
+ const { locale, timeZone, seconds = false } = options
59
+ return dateFormat(locale, {
60
+ hour: '2-digit',
61
+ minute: '2-digit',
62
+ ...(seconds && { second: '2-digit' }),
63
+ hour12: false,
64
+ ...(timeZone !== undefined && { timeZone }),
65
+ }).format(date)
66
+ }
67
+
68
+ export type WeekdayOptions = LocaleOption & {
69
+ /** `Intl.DateTimeFormat`'s own weekday widths. Default `'short'` (`"Mon"`). */
70
+ format?: 'short' | 'long' | 'narrow'
71
+ }
72
+
73
+ /** Weekday name — seeded from `astro-window/formulas.ts#fmtWeekday`. A plain `YYYY-MM-DD` string
74
+ * is parsed as a LOCAL calendar date (never UTC), matching that seed's own rationale: the weekday
75
+ * must not shift a day depending on the reader's timezone. A non-finite/unparseable input prints
76
+ * {@link NON_FINITE}. */
77
+ export function weekday(value: Date | number | string, options: WeekdayOptions = {}): string {
78
+ const date =
79
+ typeof value === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(value)
80
+ ? (() => {
81
+ const [y, m, d] = value.split('-').map(Number)
82
+ return new Date(y ?? 1970, (m ?? 1) - 1, d ?? 1)
83
+ })()
84
+ : toDate(value)
85
+ if (date === null) return NON_FINITE
86
+ const { locale, format = 'short' } = options
87
+ return dateFormat(locale, { weekday: format }).format(date)
88
+ }
89
+
90
+ export type RelativeTimeOptions = LocaleOption & {
91
+ /** The reference "now" instant, epoch ms. Default `Date.now()` — mainly for tests. */
92
+ now?: number
93
+ }
94
+
95
+ const RELATIVE_TIME_UNITS: readonly {
96
+ readonly unit: Intl.RelativeTimeFormatUnit
97
+ readonly ms: number
98
+ }[] = [
99
+ { unit: 'year', ms: 31_536_000_000 },
100
+ { unit: 'month', ms: 2_628_000_000 },
101
+ { unit: 'week', ms: 604_800_000 },
102
+ { unit: 'day', ms: 86_400_000 },
103
+ { unit: 'hour', ms: 3_600_000 },
104
+ { unit: 'minute', ms: 60_000 },
105
+ ]
106
+
107
+ const relativeTimeFormatterCache = new Map<string, Intl.RelativeTimeFormat>()
108
+
109
+ function relativeTimeFormat(locale: string | undefined): Intl.RelativeTimeFormat {
110
+ const key = locale ?? ''
111
+ const cached = relativeTimeFormatterCache.get(key)
112
+ if (cached !== undefined) return cached
113
+ const created = new Intl.RelativeTimeFormat(locale, { numeric: 'auto' })
114
+ relativeTimeFormatterCache.set(key, created)
115
+ return created
116
+ }
117
+
118
+ /**
119
+ * Short relative phrase — `"3 hours ago"`, `"in 2 days"`, `"just now"`. Seeded from
120
+ * `agent-chat/relative-time.ts#formatRelativeTime` (epoch-ms, 'en'-hardcoded), generalized with a
121
+ * `locale` option and accepting `Date`/ISO-string inputs too (argo's
122
+ * `reading/format.ts#relativeTime` and `garmin-health/formulas.ts#formatRelativeTime` both take an
123
+ * ISO string). A non-finite/unparseable input prints {@link NON_FINITE} rather than throwing —
124
+ * `Intl.RelativeTimeFormat.format` throws a `RangeError` on non-finite input, and this is
125
+ * render-path code where one bad timestamp must not blank a whole list.
126
+ */
127
+ export function relativeTime(
128
+ value: number | Date | string,
129
+ options: RelativeTimeOptions = {},
130
+ ): string {
131
+ const { locale, now = Date.now() } = options
132
+ const timestamp =
133
+ value instanceof Date ? value.getTime() : typeof value === 'number' ? value : Date.parse(value)
134
+ if (!Number.isFinite(timestamp)) return NON_FINITE
135
+ const diffMs = timestamp - now
136
+ const absMs = Math.abs(diffMs)
137
+ if (absMs < 60_000) return 'just now'
138
+ const unit = RELATIVE_TIME_UNITS.find(({ ms }) => absMs >= ms) ?? RELATIVE_TIME_UNITS.at(-1)!
139
+ return relativeTimeFormat(locale).format(Math.round(diffMs / unit.ms), unit.unit)
140
+ }
141
+
142
+ export type DurationUnit = 'seconds' | 'minutes'
143
+
144
+ export type DurationOptions = {
145
+ /** Unit of the input value. Default `'seconds'`. */
146
+ unit?: DurationUnit
147
+ }
148
+
149
+ /**
150
+ * Human duration — `"1h 02m"`, `"5m"`, `"42s"`. Minutes zero-pad once an hour is present (`"1h
151
+ * 02m"`, a clock-reading convention); alone they don't (`"5m"`). Seconds show only under a minute
152
+ * (`"42s"`). A non-finite value prints {@link NON_FINITE}.
153
+ *
154
+ * The one signature standing in for argo's four duration spellings: `walking-pad/
155
+ * formatters.ts#formatDuration` (seconds, `<60s` → `"Ns"` — this IS that shape),
156
+ * `reading/format.ts#formatReadTime` (seconds, no `<60s` branch, floors at `"0m"` — pass a value
157
+ * `>= 60` and the shapes match), `astro-window/formulas.ts#fmtMinutes` (minutes as input — pass
158
+ * `{ unit: 'minutes' }`). The fourth, `walking-pad/formatters.ts#formatDurationClock` (`h:mm:ss`),
159
+ * is {@link durationClock} below, not this.
160
+ */
161
+ export function duration(value: number, options: DurationOptions = {}): string {
162
+ if (!Number.isFinite(value)) return NON_FINITE
163
+ const { unit = 'seconds' } = options
164
+ const totalSeconds = Math.max(0, Math.round(unit === 'minutes' ? value * 60 : value))
165
+ if (totalSeconds < 60) return `${totalSeconds}s`
166
+ const totalMinutes = Math.round(totalSeconds / 60)
167
+ const h = Math.floor(totalMinutes / 60)
168
+ const m = totalMinutes % 60
169
+ if (h === 0) return `${m}m`
170
+ return `${h}h ${String(m).padStart(2, '0')}m`
171
+ }
172
+
173
+ /** Clock-style duration — `"1:02:03"`, `"04:12"`. Seeded from `walking-pad/
174
+ * formatters.ts#formatDurationClock`. A non-finite value prints {@link NON_FINITE}. */
175
+ export function durationClock(seconds: number): string {
176
+ if (!Number.isFinite(seconds)) return NON_FINITE
177
+ const total = Math.max(0, Math.round(seconds))
178
+ const h = Math.floor(total / 3600)
179
+ const m = Math.floor((total % 3600) / 60)
180
+ const s = total % 60
181
+ const mm = String(m).padStart(2, '0')
182
+ const ss = String(s).padStart(2, '0')
183
+ return h > 0 ? `${h}:${mm}:${ss}` : `${mm}:${ss}`
184
+ }
@@ -0,0 +1,69 @@
1
+ /**
2
+ * `basalt-ui/format` — Mantine-free, React-free `Intl`-backed formatting. One implementation for
3
+ * numbers/percentages/money, dates/times/durations and the two measurement units argo needed
4
+ * (`km`/`kcal`) — replacing argo's `features/*\/{formatters,formulas,format}.ts` (~350 of 643
5
+ * lines across four duration spellings) and the chart layer's own `charts/utils/format.ts`, which
6
+ * now re-exports from here.
7
+ *
8
+ * Every formatter takes `(value, opts?)`; `locale` on every `opts` defaults to `undefined` —
9
+ * `Intl`'s own "use the runtime's locale". Every non-finite/unparseable input prints the same
10
+ * {@link NON_FINITE} em dash rather than `"NaN"` or throwing.
11
+ *
12
+ * @example
13
+ * import { money, percent, duration, weekday, relativeTime } from 'basalt-ui/format'
14
+ *
15
+ * money(1234, { currency: 'USD' }) // "$1,234"
16
+ * percent(0.42) // "42%"
17
+ * duration(3_723) // "1h 02m"
18
+ * weekday('2026-09-02') // "Wed"
19
+ * relativeTime(Date.now() - 3_600_000) // "1 hour ago"
20
+ */
21
+ export {
22
+ compact,
23
+ deltaPct,
24
+ type DeltaPctOptions,
25
+ fmtCompact,
26
+ type FmtCompactOptions,
27
+ fmtCurrency,
28
+ type FmtCurrencyOptions,
29
+ fmtInt,
30
+ fmtPercent,
31
+ type FmtPercentOptions,
32
+ integer,
33
+ type LocaleOption,
34
+ money,
35
+ NON_FINITE,
36
+ percent,
37
+ } from './number'
38
+ export {
39
+ clock,
40
+ type ClockOptions,
41
+ duration,
42
+ durationClock,
43
+ type DurationOptions,
44
+ type DurationUnit,
45
+ fmtAxisDate,
46
+ fmtTooltipDate,
47
+ relativeTime,
48
+ type RelativeTimeOptions,
49
+ weekday,
50
+ type WeekdayOptions,
51
+ } from './date'
52
+ export { kcal, type KcalOptions, km, type KmOptions } from './measure'
53
+
54
+ import { fmtCompact, fmtCurrency, fmtInt, fmtPercent } from './number'
55
+ import { fmtAxisDate, fmtTooltipDate } from './date'
56
+
57
+ /**
58
+ * Every shipped chart-facing formatter under one name, so a chart can be handed the whole set
59
+ * (`format={formatters.compact}`). Unchanged shape from `charts/utils/format.ts` — this is the
60
+ * SAME object, not a second one, so an existing `formatters.x` call site keeps working verbatim.
61
+ */
62
+ export const formatters = {
63
+ compact: fmtCompact,
64
+ percent: fmtPercent,
65
+ currency: fmtCurrency,
66
+ int: fmtInt,
67
+ axisDate: fmtAxisDate,
68
+ tooltipDate: fmtTooltipDate,
69
+ } as const
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Distance/energy formatting — seeded from `walking-pad/formatters.ts#formatKm`/`#formatKcal`.
3
+ */
4
+ import { NON_FINITE } from './shared'
5
+
6
+ export type KmOptions = {
7
+ /** Fraction digits. Default 2 (`"5.30 km"`). */
8
+ digits?: number
9
+ }
10
+
11
+ /** Meters as kilometers — `"5.30 km"`. A non-finite value prints {@link NON_FINITE}. */
12
+ export function km(meters: number, options: KmOptions = {}): string {
13
+ if (!Number.isFinite(meters)) return NON_FINITE
14
+ const { digits = 2 } = options
15
+ return `${(meters / 1000).toFixed(digits)} km`
16
+ }
17
+
18
+ export type KcalOptions = {
19
+ /** Fraction digits once compacted to `k cal`. Default 2. Below 1000 kcal always rounds to a
20
+ * whole number, matching the seed (`formatKcal`). */
21
+ digits?: number
22
+ }
23
+
24
+ /** Kilocalories, compacting to `"k cal"` above 1000 — `"842 kcal"`, `"1.24 k cal"`. A non-finite
25
+ * value prints {@link NON_FINITE}. */
26
+ export function kcal(value: number, options: KcalOptions = {}): string {
27
+ if (!Number.isFinite(value)) return NON_FINITE
28
+ const { digits = 2 } = options
29
+ if (value >= 1000) return `${(value / 1000).toFixed(digits)} k cal`
30
+ return `${Math.round(value)} kcal`
31
+ }
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Number formatting — `Intl.NumberFormat` with the arguments already decided, so a caller states
3
+ * WHAT a number is rather than how to punctuate it. Moved here from `src/charts/utils/format.ts`
4
+ * (C5 consolidation) — that file now re-exports from this module so charts keep working through
5
+ * one implementation.
6
+ *
7
+ * `money`/`percent`/`integer`/`compact`/`deltaPct` are the argo-facing names (seeded from
8
+ * `features/*\/{formatters,formulas}.ts`); `fmtCurrency`/`fmtPercent`/`fmtInt`/`fmtCompact` are the
9
+ * original chart-formatter names, kept for source compatibility and delegated to by the new names.
10
+ */
11
+ import { NON_FINITE, numberFormat } from './shared'
12
+ import type { LocaleOption } from './shared'
13
+
14
+ export type { LocaleOption }
15
+ export { NON_FINITE }
16
+
17
+ /** The compact `K` suffix, matched only where it follows the digits it qualifies — so a currency
18
+ * prefix that happens to contain one (`HK$`) survives the lowercasing. */
19
+ const COMPACT_K = /(\d\s?)K/
20
+
21
+ export type FmtCompactOptions = LocaleOption & {
22
+ /** Significant-ish fraction digits on the compacted number. Default 1 (`1.2k`, `3.4M`). */
23
+ digits?: number
24
+ }
25
+
26
+ /**
27
+ * Compact notation: `1.2k`, `3.4M`, `-820`. The axis formatter for any count whose range spans
28
+ * more than three digits. A non-finite value prints {@link NON_FINITE}.
29
+ *
30
+ * Note `Intl`'s compact notation is LOCALE text, not a suffix table: `en` gives `1.2K`, and this
31
+ * lowercases the `K` to match the package's own numeral style while leaving every other locale's
32
+ * word (`1,2 Mio.`) untouched.
33
+ */
34
+ export function fmtCompact(value: number, options: FmtCompactOptions = {}): string {
35
+ if (!Number.isFinite(value)) return NON_FINITE
36
+ const { digits = 1, locale } = options
37
+ return numberFormat(locale, {
38
+ notation: 'compact',
39
+ compactDisplay: 'short',
40
+ maximumFractionDigits: digits,
41
+ })
42
+ .format(value)
43
+ .replace(COMPACT_K, '$1k')
44
+ }
45
+
46
+ /** `compact` — the `basalt-ui/format` name for {@link fmtCompact}. */
47
+ export const compact = fmtCompact
48
+
49
+ export type FmtPercentOptions = LocaleOption & {
50
+ /** Fraction digits. Default 0 (`42%`). */
51
+ digits?: number
52
+ /**
53
+ * What the incoming number MEANS. `'ratio'` (default) is `0.42 → 42%`; `'percent'` is
54
+ * `42 → 42%`. Required as an explicit option rather than guessed from magnitude.
55
+ */
56
+ input?: 'ratio' | 'percent'
57
+ }
58
+
59
+ /** Percentages, from either a ratio or an already-scaled percentage. A non-finite value prints
60
+ * {@link NON_FINITE}. */
61
+ export function fmtPercent(value: number, options: FmtPercentOptions = {}): string {
62
+ if (!Number.isFinite(value)) return NON_FINITE
63
+ const { digits = 0, input = 'ratio', locale } = options
64
+ return numberFormat(locale, {
65
+ style: 'percent',
66
+ minimumFractionDigits: digits,
67
+ maximumFractionDigits: digits,
68
+ }).format(input === 'percent' ? value / 100 : value)
69
+ }
70
+
71
+ /** `percent` — the `basalt-ui/format` name for {@link fmtPercent}. */
72
+ export const percent = fmtPercent
73
+
74
+ export type DeltaPctOptions = FmtPercentOptions
75
+
76
+ /**
77
+ * A signed percentage delta: `+4%`, `-12%`, `0%` — argo's `walking-pad/formatters.ts#formatPct`
78
+ * (a `+`-prefixed ratio) generalized onto `Intl`'s own `signDisplay: 'exceptZero'`, which adds the
79
+ * `+`/`-` sign the same way `Intl`'s own minus sign already does, and adds nothing for zero. A
80
+ * non-finite value prints {@link NON_FINITE}.
81
+ */
82
+ export function deltaPct(value: number, options: DeltaPctOptions = {}): string {
83
+ if (!Number.isFinite(value)) return NON_FINITE
84
+ const { digits = 0, input = 'ratio', locale } = options
85
+ return numberFormat(locale, {
86
+ style: 'percent',
87
+ signDisplay: 'exceptZero',
88
+ minimumFractionDigits: digits,
89
+ maximumFractionDigits: digits,
90
+ }).format(input === 'percent' ? value / 100 : value)
91
+ }
92
+
93
+ export type FmtCurrencyOptions = LocaleOption & {
94
+ /** ISO 4217 code — required. There is no default currency. */
95
+ currency: string
96
+ /** Compact notation for the amount (`$1.2k`). Default false. */
97
+ compact?: boolean
98
+ /** Fraction digits. Default 0 compacted, else the currency's own default (`undefined`). */
99
+ digits?: number
100
+ }
101
+
102
+ /** Money. `fmtCurrency(1234, { currency: 'USD' })` → `$1,234`. A non-finite amount prints
103
+ * {@link NON_FINITE}. */
104
+ export function fmtCurrency(value: number, options: FmtCurrencyOptions): string {
105
+ if (!Number.isFinite(value)) return NON_FINITE
106
+ const { currency, compact: isCompact = false, digits, locale } = options
107
+ const fractionDigits = digits ?? (isCompact ? 1 : 0)
108
+ return numberFormat(locale, {
109
+ style: 'currency',
110
+ currency,
111
+ ...(isCompact && { notation: 'compact', compactDisplay: 'short' }),
112
+ minimumFractionDigits: isCompact ? 0 : fractionDigits,
113
+ maximumFractionDigits: fractionDigits,
114
+ })
115
+ .format(value)
116
+ .replace(COMPACT_K, '$1k')
117
+ }
118
+
119
+ /** `money` — the `basalt-ui/format` name for {@link fmtCurrency}. */
120
+ export const money = fmtCurrency
121
+
122
+ /** Grouped integer: `12,480`. Rounds. A non-finite value prints {@link NON_FINITE}. */
123
+ export function fmtInt(value: number, options: LocaleOption = {}): string {
124
+ if (!Number.isFinite(value)) return NON_FINITE
125
+ return numberFormat(options.locale, { maximumFractionDigits: 0 }).format(value)
126
+ }
127
+
128
+ /** `integer` — the `basalt-ui/format` name for {@link fmtInt}. */
129
+ export const integer = fmtInt
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Shared low-level pieces of `basalt-ui/format` — the em-dash sentinel and the memoized
3
+ * `Intl.NumberFormat` cache every number formatter in this module reuses. Moved here (out of
4
+ * `src/charts/utils/format.ts`, C5 consolidation) so the subpath is the single implementation and
5
+ * `charts/utils/format.ts` becomes a thin re-export (`docs/CHARTS-SPEC.md` still calls it home for
6
+ * chart callers, but the code lives here now).
7
+ */
8
+
9
+ /**
10
+ * What EVERY formatter in this module prints for input it cannot represent — `NaN`, `±Infinity`,
11
+ * an `Invalid Date`. An em dash (U+2014). A formatter may say it does not know; it may not print a
12
+ * number that is not one.
13
+ */
14
+ export const NON_FINITE = '—'
15
+
16
+ /** Options every number formatter here accepts. */
17
+ export type LocaleOption = {
18
+ /** BCP-47 tag. Default `undefined` — the runtime's own locale. */
19
+ locale?: string
20
+ }
21
+
22
+ /**
23
+ * `Intl.NumberFormat` construction is the expensive half of formatting and a chart formats one
24
+ * label per tick per frame, so instances are memoized on their own arguments. The key is the
25
+ * serialized options because that is exactly what identifies an instance.
26
+ */
27
+ const formatterCache = new Map<string, Intl.NumberFormat>()
28
+
29
+ export function numberFormat(
30
+ locale: string | undefined,
31
+ options: Intl.NumberFormatOptions,
32
+ ): Intl.NumberFormat {
33
+ const key = `${locale ?? ''}|${JSON.stringify(options)}`
34
+ const cached = formatterCache.get(key)
35
+ if (cached !== undefined) return cached
36
+ const created = new Intl.NumberFormat(locale, options)
37
+ formatterCache.set(key, created)
38
+ return created
39
+ }
40
+
41
+ const dateFormatterCache = new Map<string, Intl.DateTimeFormat>()
42
+
43
+ export function dateFormat(
44
+ locale: string | undefined,
45
+ options: Intl.DateTimeFormatOptions,
46
+ ): Intl.DateTimeFormat {
47
+ const key = `${locale ?? ''}|${JSON.stringify(options)}`
48
+ const cached = dateFormatterCache.get(key)
49
+ if (cached !== undefined) return cached
50
+ const created = new Intl.DateTimeFormat(locale, options)
51
+ dateFormatterCache.set(key, created)
52
+ return created
53
+ }
54
+
55
+ /** Coerces the flexible `Date | number | string` inputs this module's date formatters accept into
56
+ * a `Date`. A `number` is treated as epoch milliseconds (matching `Date`'s own constructor and
57
+ * `agent-chat/relative-time.ts`'s prior contract) — a caller with epoch seconds multiplies by
58
+ * 1000 first. Returns `null` for a non-finite/unparseable input so every caller can share one
59
+ * {@link NON_FINITE} guard instead of re-deriving one. */
60
+ export function toDate(value: Date | number | string): Date | null {
61
+ const date = value instanceof Date ? value : new Date(value)
62
+ return Number.isNaN(date.getTime()) ? null : date
63
+ }
@@ -10,8 +10,10 @@
10
10
  * three warnings per page. The bundle was basalt's own invention; Mantine's documented idiom is
11
11
  * `key={form.key(path)} {...form.getInputProps(path)}`, and this is that idiom with basalt's names.
12
12
  *
13
- * The `@deprecated` `field` alias below did NOT follow it there — it still returns the 1.27 bundle,
14
- * because a deprecated export is a schedule and not a silent behaviour change. See its own doc.
13
+ * The `@deprecated` `field` alias that used to live here is removed (1.29.0, C1 consolidation) —
14
+ * `basalt-ui/forms`' `field` collided in name with the `field` store builder on `basalt-ui/state`,
15
+ * which was the whole reason for the rename in the first place. Write
16
+ * `key={fieldKey(form, path)} {...inputProps(form, path)}`.
15
17
  */
16
18
  import type { LooseKeys, UseFormReturnType } from '@mantine/form'
17
19
 
@@ -55,25 +57,3 @@ export function fieldKey<Values extends Record<string, unknown>, Path extends Lo
55
57
  ): string {
56
58
  return form.key(path)
57
59
  }
58
-
59
- /**
60
- * @deprecated Renamed to `inputProps` in 1.x — collides with the `field` store builder in
61
- * `basalt-ui/state`. Kept until the forms surface next changes; removal ships as a plain `feat:`,
62
- * never a major. Write `key={fieldKey(form, path)} {...inputProps(form, path)}` instead.
63
- *
64
- * **It is NOT `export const field = inputProps` any more, and the difference is the whole point.**
65
- * It returns the 1.27 shape — `getInputProps(path)` PLUS `key` — because an alias of the new
66
- * `inputProps` would have changed what every existing `<TextInput {...field(form, 'x')} />` does
67
- * without changing whether it compiles: the element loses its reconciler key, keeps its old text
68
- * through `form.reset()`, and nothing anywhere says so. A deprecated export is a SCHEDULE, not a
69
- * behaviour change (`../../CLAUDE.md`, "Deprecation lifecycle"), so this one keeps its behaviour
70
- * byte for byte — including the React 19 `A props object containing a "key" prop is being spread
71
- * into JSX` warning it has always produced. That warning is the migration signal; `1.29.0` removing
72
- * the export is the deadline. `basalt/forms-field-key` reports every remaining call site.
73
- */
74
- export function field<Values extends Record<string, unknown>, Path extends LooseKeys<Values>>(
75
- form: UseFormReturnType<Values>,
76
- path: Path,
77
- ): ReturnType<UseFormReturnType<Values>['getInputProps']> & { key: string } {
78
- return { ...form.getInputProps(path), key: form.key(path) }
79
- }
@@ -24,8 +24,8 @@ import type { BasaltProps, SlotStylesProps } from '../common/props'
24
24
  import { assertRequiredProps } from '../common/validate'
25
25
  import { BarActionSlot } from '../controls/actions'
26
26
  import type { SlotActions } from '../controls/actions'
27
- import { WidgetHeader } from '../widget-header'
28
- import type { WidgetHeaderTitleProps } from '../widget-header'
27
+ import { WidgetHeader } from '../dashboard'
28
+ import type { WidgetHeaderTitleProps } from '../dashboard'
29
29
  import { useFormState } from './form-state'
30
30
  import classes from './form-layout.module.css'
31
31
 
@@ -20,8 +20,7 @@ export type { UseBasaltFormOptions } from './create-form'
20
20
 
21
21
  // ── inputProps ────────────────────────────────────────────────────────────────
22
22
  // Two calls, never one object: `key` inside a spread is a React 19 warning. See field.ts.
23
- // `field` ships alongside as a @deprecated alias — see field.ts.
24
- export { inputProps, fieldKey, field } from './field'
23
+ export { inputProps, fieldKey } from './field'
25
24
 
26
25
  // ── layout — law C1's third home, the form row ────────────────────────────────
27
26
  export { FormSection, FormRow, FormGroup, FormActions } from './form-layout'
@@ -10,7 +10,7 @@
10
10
  import { useCallback, useRef, useState } from 'react'
11
11
  import type { SyntheticEvent } from 'react'
12
12
  import type { UseFormReturnType } from '@mantine/form'
13
- import { toErrorMessage } from '../query/error-message'
13
+ import { toErrorMessage } from '../common/errors'
14
14
 
15
15
  // ── The server field-error envelope ───────────────────────────────────────────
16
16