basalt-ui 1.24.0 → 1.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (467) hide show
  1. package/AGENTS.md +8 -6
  2. package/CHANGELOG.md +25 -0
  3. package/MIGRATING.md +547 -21
  4. package/README.md +46 -33
  5. package/agent/rules/basalt-batteries.md +205 -0
  6. package/agent/rules/basalt-charts.md +125 -555
  7. package/agent/rules/basalt-controls.md +155 -0
  8. package/agent/rules/basalt-mantine.md +146 -439
  9. package/agent/rules/basalt-state.md +113 -96
  10. package/agent/rules/basalt-tokens.md +126 -288
  11. package/agent/skills/basalt-app/SKILL.md +70 -195
  12. package/agent/skills/basalt-charts/SKILL.md +54 -234
  13. package/agent/skills/basalt-design/SKILL.md +56 -248
  14. package/agent/templates/CLAUDE-block.md.tpl +31 -40
  15. package/agent/templates/DESIGN.md.tpl +22 -51
  16. package/configs/oxlint-plugin.js +1275 -31
  17. package/configs/oxlint-plugin.test.ts +947 -11
  18. package/configs/oxlint.json +11 -3
  19. package/dist/charts/cursor/resolve.d.ts +18 -0
  20. package/dist/charts/cursor/resolve.d.ts.map +1 -1
  21. package/dist/charts/cursor/resolve.js +15 -6
  22. package/dist/charts/cursor/scope.d.ts +6 -3
  23. package/dist/charts/cursor/scope.d.ts.map +1 -1
  24. package/dist/charts/cursor/store.d.ts +5 -1
  25. package/dist/charts/cursor/store.d.ts.map +1 -1
  26. package/dist/charts/cursor/store.js +4 -4
  27. package/dist/charts/hooks/useChartCursor.d.ts.map +1 -1
  28. package/dist/charts/hooks/useChartCursor.js +9 -8
  29. package/dist/charts/index.d.ts +2 -2
  30. package/dist/charts/index.d.ts.map +1 -1
  31. package/dist/charts/primitives/ChartCard.d.ts +34 -9
  32. package/dist/charts/primitives/ChartCard.d.ts.map +1 -1
  33. package/dist/charts/primitives/ChartCard.js +29 -114
  34. package/dist/charts/primitives/ChartCard.test.d.ts +2 -0
  35. package/dist/charts/primitives/ChartCard.test.d.ts.map +1 -0
  36. package/dist/charts/sparklines/BarSparkline.d.ts +26 -2
  37. package/dist/charts/sparklines/BarSparkline.d.ts.map +1 -1
  38. package/dist/charts/sparklines/BarSparkline.js +18 -4
  39. package/dist/cli/check-coverage.test.d.ts +2 -0
  40. package/dist/cli/check-coverage.test.d.ts.map +1 -0
  41. package/dist/cli/index.d.ts +67 -4
  42. package/dist/cli/index.d.ts.map +1 -1
  43. package/dist/cli/index.js +225 -7
  44. package/dist/connectivity/connectivity-indicator.d.ts +4 -1
  45. package/dist/connectivity/connectivity-indicator.d.ts.map +1 -1
  46. package/dist/connectivity/connectivity-indicator.js +1 -1
  47. package/dist/content/index.d.ts +5 -3
  48. package/dist/content/index.d.ts.map +1 -1
  49. package/dist/content/index.js +4 -2
  50. package/dist/content/prose.module.css +7 -28
  51. package/dist/controls/actions.d.ts +169 -0
  52. package/dist/controls/actions.d.ts.map +1 -0
  53. package/dist/controls/actions.js +287 -0
  54. package/dist/controls/actions.module.css +62 -0
  55. package/dist/controls/actions.module.css.d.ts +13 -0
  56. package/dist/controls/actions.test.d.ts +2 -0
  57. package/dist/controls/actions.test.d.ts.map +1 -0
  58. package/dist/controls/actions.type-guard.test.d.ts +2 -0
  59. package/dist/controls/actions.type-guard.test.d.ts.map +1 -0
  60. package/dist/controls/compare-filter.d.ts +41 -0
  61. package/dist/controls/compare-filter.d.ts.map +1 -0
  62. package/dist/controls/compare-filter.js +23 -0
  63. package/dist/controls/control-group.d.ts +19 -0
  64. package/dist/controls/control-group.d.ts.map +1 -0
  65. package/dist/controls/control-group.js +20 -0
  66. package/dist/controls/control-group.test.d.ts +2 -0
  67. package/dist/controls/control-group.test.d.ts.map +1 -0
  68. package/dist/controls/controls.module.css +542 -0
  69. package/dist/controls/controls.module.css.d.ts +35 -0
  70. package/dist/controls/controls.router.test.d.ts +2 -0
  71. package/dist/controls/controls.router.test.d.ts.map +1 -0
  72. package/dist/controls/enum-filter.d.ts +30 -0
  73. package/dist/controls/enum-filter.d.ts.map +1 -0
  74. package/dist/controls/enum-filter.js +91 -0
  75. package/dist/controls/filter-context.d.ts +55 -0
  76. package/dist/controls/filter-context.d.ts.map +1 -0
  77. package/dist/controls/filter-context.js +69 -0
  78. package/dist/controls/filter-pill.d.ts +28 -0
  79. package/dist/controls/filter-pill.d.ts.map +1 -0
  80. package/dist/controls/filter-pill.js +70 -0
  81. package/dist/controls/filter-set.d.ts +13 -0
  82. package/dist/controls/filter-set.d.ts.map +1 -0
  83. package/dist/controls/filter-set.js +125 -0
  84. package/dist/controls/filter-set.test.d.ts +2 -0
  85. package/dist/controls/filter-set.test.d.ts.map +1 -0
  86. package/dist/controls/filter-sheet.d.ts +117 -0
  87. package/dist/controls/filter-sheet.d.ts.map +1 -0
  88. package/dist/controls/filter-sheet.js +146 -0
  89. package/dist/controls/glyphs.d.ts +27 -0
  90. package/dist/controls/glyphs.d.ts.map +1 -0
  91. package/dist/controls/glyphs.js +49 -0
  92. package/dist/controls/index.d.ts +19 -0
  93. package/dist/controls/index.d.ts.map +1 -0
  94. package/dist/controls/index.js +44 -0
  95. package/dist/controls/multi-select-filter.d.ts +23 -0
  96. package/dist/controls/multi-select-filter.d.ts.map +1 -0
  97. package/dist/controls/multi-select-filter.js +89 -0
  98. package/dist/controls/peer-boundary.test.d.ts +2 -0
  99. package/dist/controls/peer-boundary.test.d.ts.map +1 -0
  100. package/dist/controls/props-contract.test.d.ts +2 -0
  101. package/dist/controls/props-contract.test.d.ts.map +1 -0
  102. package/dist/controls/range-filter.d.ts +29 -0
  103. package/dist/controls/range-filter.d.ts.map +1 -0
  104. package/dist/controls/range-filter.js +120 -0
  105. package/dist/controls/search-filter.d.ts +10 -0
  106. package/dist/controls/search-filter.d.ts.map +1 -0
  107. package/dist/controls/search-filter.js +81 -0
  108. package/dist/controls/select-filter.d.ts +74 -0
  109. package/dist/controls/select-filter.d.ts.map +1 -0
  110. package/dist/controls/select-filter.js +10 -0
  111. package/dist/controls/sync-button.d.ts +38 -0
  112. package/dist/controls/sync-button.d.ts.map +1 -0
  113. package/dist/controls/sync-button.js +119 -0
  114. package/dist/controls/sync-button.module.css +63 -0
  115. package/dist/controls/sync-button.module.css.d.ts +11 -0
  116. package/dist/controls/sync-button.test.d.ts +2 -0
  117. package/dist/controls/sync-button.test.d.ts.map +1 -0
  118. package/dist/controls/toggle-filter.d.ts +9 -0
  119. package/dist/controls/toggle-filter.d.ts.map +1 -0
  120. package/dist/controls/toggle-filter.js +42 -0
  121. package/dist/controls/view-tabs.d.ts +23 -0
  122. package/dist/controls/view-tabs.d.ts.map +1 -0
  123. package/dist/controls/view-tabs.js +59 -0
  124. package/dist/controls-dates/date-range-picker.d.ts +4 -0
  125. package/dist/controls-dates/date-range-picker.d.ts.map +1 -0
  126. package/dist/controls-dates/date-range-picker.js +18 -0
  127. package/dist/controls-dates/index.d.ts +9 -0
  128. package/dist/controls-dates/index.d.ts.map +1 -0
  129. package/dist/controls-dates/index.js +4 -0
  130. package/dist/dashboard/delta-badge.d.ts +6 -12
  131. package/dist/dashboard/delta-badge.d.ts.map +1 -1
  132. package/dist/dashboard/delta-badge.js +1 -50
  133. package/dist/dashboard/query-state.d.ts +1 -1
  134. package/dist/dashboard/settings-section.d.ts +6 -4
  135. package/dist/dashboard/settings-section.d.ts.map +1 -1
  136. package/dist/dashboard/settings-section.js +23 -16
  137. package/dist/dashboard/settings-section.module.css +10 -0
  138. package/dist/dashboard/settings-section.module.css.d.ts +1 -0
  139. package/dist/dashboard/settings-section.test.d.ts +2 -0
  140. package/dist/dashboard/settings-section.test.d.ts.map +1 -0
  141. package/dist/dashboard/stat-card.d.ts +44 -9
  142. package/dist/dashboard/stat-card.d.ts.map +1 -1
  143. package/dist/dashboard/stat-card.js +80 -48
  144. package/dist/dashboard/stat-card.module.css +82 -0
  145. package/dist/dashboard/stat-card.module.css.d.ts +11 -0
  146. package/dist/data/data-table.d.ts +102 -20
  147. package/dist/data/data-table.d.ts.map +1 -1
  148. package/dist/data/data-table.js +166 -65
  149. package/dist/data/table.d.ts +1 -1
  150. package/dist/data/table.d.ts.map +1 -1
  151. package/dist/guard/grace.test.d.ts +20 -0
  152. package/dist/guard/grace.test.d.ts.map +1 -0
  153. package/dist/guard/index.d.ts +66 -3
  154. package/dist/guard/index.d.ts.map +1 -1
  155. package/dist/guard/index.js +82 -7
  156. package/dist/guard/types.d.ts +3 -3
  157. package/dist/guard/types.d.ts.map +1 -1
  158. package/dist/index.d.ts +12 -2
  159. package/dist/index.d.ts.map +1 -1
  160. package/dist/index.js +13 -10
  161. package/dist/nav/types.d.ts +78 -2
  162. package/dist/nav/types.d.ts.map +1 -1
  163. package/dist/notifications/bell.d.ts +4 -1
  164. package/dist/notifications/bell.d.ts.map +1 -1
  165. package/dist/notifications/index.d.ts +1 -1
  166. package/dist/router-tanstack/field.d.ts +14 -0
  167. package/dist/router-tanstack/field.d.ts.map +1 -0
  168. package/dist/router-tanstack/field.js +4 -0
  169. package/dist/router-tanstack/index.d.ts +6 -2
  170. package/dist/router-tanstack/index.d.ts.map +1 -1
  171. package/dist/router-tanstack/index.js +4 -0
  172. package/dist/router-tanstack/multi-search-param-store.d.ts +4 -52
  173. package/dist/router-tanstack/multi-search-param-store.d.ts.map +1 -1
  174. package/dist/router-tanstack/multi-search-param-store.js +19 -27
  175. package/dist/router-tanstack/search-param-store.d.ts +3 -87
  176. package/dist/router-tanstack/search-param-store.d.ts.map +1 -1
  177. package/dist/router-tanstack/search-param-store.js +16 -45
  178. package/dist/router-tanstack/search-store.d.ts +81 -0
  179. package/dist/router-tanstack/search-store.d.ts.map +1 -0
  180. package/dist/router-tanstack/search-store.js +187 -0
  181. package/dist/router-tanstack/search-store.router.test.d.ts +2 -0
  182. package/dist/router-tanstack/search-store.router.test.d.ts.map +1 -0
  183. package/dist/router-tanstack/search-store.test.d.ts +2 -0
  184. package/dist/router-tanstack/search-store.test.d.ts.map +1 -0
  185. package/dist/router-tanstack/use-nav.d.ts +0 -2
  186. package/dist/router-tanstack/use-nav.d.ts.map +1 -1
  187. package/dist/router-tanstack/use-nav.js +34 -12
  188. package/dist/router-tanstack/use-nav.test.d.ts +2 -0
  189. package/dist/router-tanstack/use-nav.test.d.ts.map +1 -0
  190. package/dist/section/index.d.ts +2 -0
  191. package/dist/section/index.d.ts.map +1 -0
  192. package/dist/section/index.js +4 -0
  193. package/dist/section/section.d.ts +24 -0
  194. package/dist/section/section.d.ts.map +1 -0
  195. package/dist/section/section.js +126 -0
  196. package/dist/section/section.module.css +104 -0
  197. package/dist/section/section.module.css.d.ts +11 -0
  198. package/dist/section/section.test.d.ts +2 -0
  199. package/dist/section/section.test.d.ts.map +1 -0
  200. package/dist/shell/app-breadcrumbs.d.ts.map +1 -1
  201. package/dist/shell/app-breadcrumbs.js +18 -15
  202. package/dist/shell/app-header.module.css +77 -37
  203. package/dist/shell/app-header.module.css.d.ts +2 -1
  204. package/dist/shell/app-mobile-nav.d.ts +9 -2
  205. package/dist/shell/app-mobile-nav.d.ts.map +1 -1
  206. package/dist/shell/app-mobile-nav.js +98 -11
  207. package/dist/shell/app-mobile-nav.module.css +8 -0
  208. package/dist/shell/app-mobile-nav.module.css.d.ts +1 -0
  209. package/dist/shell/app-sidebar.d.ts +55 -28
  210. package/dist/shell/app-sidebar.d.ts.map +1 -1
  211. package/dist/shell/app-sidebar.js +116 -67
  212. package/dist/shell/app-sidebar.module.css +303 -20
  213. package/dist/shell/app-sidebar.module.css.d.ts +19 -1
  214. package/dist/shell/index.d.ts +55 -21
  215. package/dist/shell/index.d.ts.map +1 -1
  216. package/dist/shell/index.js +40 -18
  217. package/dist/shell/mobile-nav-model.d.ts +13 -2
  218. package/dist/shell/mobile-nav-model.d.ts.map +1 -1
  219. package/dist/shell/mobile-nav-model.js +15 -1
  220. package/dist/shell/nav-count-badge.d.ts +1 -1
  221. package/dist/shell/page-bar.d.ts +51 -0
  222. package/dist/shell/page-bar.d.ts.map +1 -0
  223. package/dist/shell/page-bar.js +154 -0
  224. package/dist/shell/page-bar.module.css +178 -0
  225. package/dist/shell/page-bar.module.css.d.ts +17 -0
  226. package/dist/shell/page-bar.test.d.ts +2 -0
  227. package/dist/shell/page-bar.test.d.ts.map +1 -0
  228. package/dist/shell/sidebar-block-model.d.ts +48 -0
  229. package/dist/shell/sidebar-block-model.d.ts.map +1 -0
  230. package/dist/shell/sidebar-block-model.js +39 -0
  231. package/dist/shell/sidebar-blocks.d.ts +32 -0
  232. package/dist/shell/sidebar-blocks.d.ts.map +1 -0
  233. package/dist/shell/sidebar-blocks.js +169 -0
  234. package/dist/shell/sidebar-search.d.ts +13 -1
  235. package/dist/shell/sidebar-search.d.ts.map +1 -1
  236. package/dist/shell/sidebar-search.js +34 -1
  237. package/dist/shell/sidebar-search.module.css +26 -0
  238. package/dist/shell/sidebar-search.module.css.d.ts +2 -0
  239. package/dist/state/fields.d.ts +392 -0
  240. package/dist/state/fields.d.ts.map +1 -0
  241. package/dist/state/fields.js +369 -0
  242. package/dist/state/fields.test.d.ts +2 -0
  243. package/dist/state/fields.test.d.ts.map +1 -0
  244. package/dist/state/persisted.d.ts +48 -0
  245. package/dist/state/persisted.d.ts.map +1 -0
  246. package/dist/state/persisted.js +105 -0
  247. package/dist/state.d.ts +11 -56
  248. package/dist/state.d.ts.map +1 -1
  249. package/dist/state.js +14 -120
  250. package/dist/styles.css +13 -0
  251. package/dist/surfaces.d.ts +106 -24
  252. package/dist/surfaces.d.ts.map +1 -1
  253. package/dist/surfaces.js +155 -19
  254. package/dist/theme/controls.module.css +16 -1
  255. package/dist/theme/ctl-theme.d.ts +32 -0
  256. package/dist/theme/ctl-theme.d.ts.map +1 -0
  257. package/dist/theme/ctl-theme.js +54 -0
  258. package/dist/theme/ctl-theme.test.d.ts +2 -0
  259. package/dist/theme/ctl-theme.test.d.ts.map +1 -0
  260. package/dist/theme/ctl-tier-coverage.test.d.ts +2 -0
  261. package/dist/theme/ctl-tier-coverage.test.d.ts.map +1 -0
  262. package/dist/theme/divider-law.test.d.ts +2 -0
  263. package/dist/theme/divider-law.test.d.ts.map +1 -0
  264. package/dist/theme/icon-slot.d.ts +44 -0
  265. package/dist/theme/icon-slot.d.ts.map +1 -0
  266. package/dist/theme/icon-slot.js +21 -0
  267. package/dist/theme/icon-slot.module.css +47 -0
  268. package/dist/theme/icon-slot.module.css.d.ts +8 -0
  269. package/dist/theme/icon-slot.test.d.ts +2 -0
  270. package/dist/theme/icon-slot.test.d.ts.map +1 -0
  271. package/dist/theme/index.d.ts +1 -0
  272. package/dist/theme/index.d.ts.map +1 -1
  273. package/dist/theme/index.js +82 -5
  274. package/dist/theme/layout-rhythm-css.test.d.ts +2 -0
  275. package/dist/theme/layout-rhythm-css.test.d.ts.map +1 -0
  276. package/dist/theme/segmented-control.module.css +20 -0
  277. package/dist/theme/shadow-surfaces.test.d.ts.map +1 -1
  278. package/dist/tokens/index.d.ts +12 -0
  279. package/dist/tokens/index.d.ts.map +1 -1
  280. package/dist/tokens/index.js +38 -8
  281. package/dist/tokens/palette.d.ts +97 -61
  282. package/dist/tokens/palette.d.ts.map +1 -1
  283. package/dist/tokens/palette.js +76 -38
  284. package/dist/tokens.css +10 -2
  285. package/dist/widget-header/delta-badge.d.ts +13 -0
  286. package/dist/widget-header/delta-badge.d.ts.map +1 -0
  287. package/dist/widget-header/delta-badge.js +29 -0
  288. package/dist/widget-header/delta-badge.test.d.ts +2 -0
  289. package/dist/widget-header/delta-badge.test.d.ts.map +1 -0
  290. package/dist/widget-header/index.d.ts +3 -0
  291. package/dist/widget-header/index.d.ts.map +1 -0
  292. package/dist/widget-header/index.js +6 -0
  293. package/dist/widget-header/no-mantine.test.d.ts +2 -0
  294. package/dist/widget-header/no-mantine.test.d.ts.map +1 -0
  295. package/dist/widget-header/widget-header.d.ts +37 -0
  296. package/dist/widget-header/widget-header.d.ts.map +1 -0
  297. package/dist/widget-header/widget-header.js +77 -0
  298. package/dist/widget-header/widget-header.module.css +335 -0
  299. package/dist/widget-header/widget-header.module.css.d.ts +24 -0
  300. package/dist/widget-header/widget-header.test.d.ts +2 -0
  301. package/dist/widget-header/widget-header.test.d.ts.map +1 -0
  302. package/llms.txt +30 -17
  303. package/package.json +14 -1
  304. package/src/charts/cursor/resolve.test.ts +29 -1
  305. package/src/charts/cursor/resolve.ts +38 -6
  306. package/src/charts/cursor/scope.tsx +6 -3
  307. package/src/charts/cursor/store.test.ts +19 -1
  308. package/src/charts/cursor/store.ts +10 -5
  309. package/src/charts/hooks/useChartCursor.ts +16 -8
  310. package/src/charts/index.ts +2 -2
  311. package/src/charts/primitives/CartesianChart.test.tsx +124 -0
  312. package/src/charts/primitives/ChartCard.test.tsx +66 -0
  313. package/src/charts/primitives/ChartCard.tsx +86 -146
  314. package/src/charts/sparklines/BarSparkline.tsx +43 -5
  315. package/src/cli/check-coverage.test.ts +297 -0
  316. package/src/cli/check-theme.test.ts +38 -14
  317. package/src/cli/index.ts +392 -16
  318. package/src/cli/init-sync.test.ts +97 -0
  319. package/src/connectivity/connectivity-indicator.tsx +16 -9
  320. package/src/content/index.ts +16 -3
  321. package/src/content/prose.module.css +7 -28
  322. package/src/content/prose.module.css.test.ts +8 -24
  323. package/src/controls/actions.module.css +62 -0
  324. package/src/controls/actions.module.css.d.ts +13 -0
  325. package/src/controls/actions.test.tsx +252 -0
  326. package/src/controls/actions.tsx +655 -0
  327. package/src/controls/actions.type-guard.test.ts +63 -0
  328. package/src/controls/compare-filter.tsx +64 -0
  329. package/src/controls/control-group.test.tsx +229 -0
  330. package/src/controls/control-group.tsx +63 -0
  331. package/src/controls/controls.module.css +542 -0
  332. package/src/controls/controls.module.css.d.ts +35 -0
  333. package/src/controls/controls.router.test.tsx +637 -0
  334. package/src/controls/enum-filter.tsx +159 -0
  335. package/src/controls/filter-context.tsx +153 -0
  336. package/src/controls/filter-pill.tsx +120 -0
  337. package/src/controls/filter-set.test.tsx +472 -0
  338. package/src/controls/filter-set.tsx +225 -0
  339. package/src/controls/filter-sheet.tsx +285 -0
  340. package/src/controls/glyphs.tsx +81 -0
  341. package/src/controls/index.ts +48 -0
  342. package/src/controls/multi-select-filter.tsx +140 -0
  343. package/src/controls/peer-boundary.test.ts +85 -0
  344. package/src/controls/props-contract.test.tsx +106 -0
  345. package/src/controls/range-filter.tsx +184 -0
  346. package/src/controls/search-filter.tsx +123 -0
  347. package/src/controls/select-filter.tsx +89 -0
  348. package/src/controls/sync-button.module.css +63 -0
  349. package/src/controls/sync-button.module.css.d.ts +11 -0
  350. package/src/controls/sync-button.test.tsx +183 -0
  351. package/src/controls/sync-button.tsx +197 -0
  352. package/src/controls/toggle-filter.tsx +60 -0
  353. package/src/controls/view-tabs.tsx +110 -0
  354. package/src/controls-dates/date-range-picker.tsx +42 -0
  355. package/src/controls-dates/index.ts +8 -0
  356. package/src/dashboard/delta-badge.tsx +4 -74
  357. package/src/dashboard/query-state.tsx +1 -1
  358. package/src/dashboard/settings-section.module.css +10 -0
  359. package/src/dashboard/settings-section.module.css.d.ts +1 -0
  360. package/src/dashboard/settings-section.test.tsx +56 -0
  361. package/src/dashboard/settings-section.tsx +33 -30
  362. package/src/dashboard/stat-card.module.css +82 -0
  363. package/src/dashboard/stat-card.module.css.d.ts +11 -0
  364. package/src/dashboard/stat-card.test.tsx +67 -1
  365. package/src/dashboard/stat-card.tsx +209 -68
  366. package/src/data/data-table.test.tsx +282 -6
  367. package/src/data/data-table.tsx +429 -94
  368. package/src/data/table.ts +2 -0
  369. package/src/guard/check-source.test.ts +126 -13
  370. package/src/guard/grace.test.ts +149 -0
  371. package/src/guard/index.ts +172 -29
  372. package/src/guard/types.ts +4 -2
  373. package/src/index.ts +46 -5
  374. package/src/nav/types.ts +84 -2
  375. package/src/notifications/bell.tsx +6 -3
  376. package/src/notifications/index.ts +1 -1
  377. package/src/router-tanstack/field.ts +31 -0
  378. package/src/router-tanstack/index.ts +24 -2
  379. package/src/router-tanstack/multi-search-param-store.test.ts +71 -3
  380. package/src/router-tanstack/multi-search-param-store.ts +46 -77
  381. package/src/router-tanstack/search-param-store.ts +42 -159
  382. package/src/router-tanstack/search-store.router.test.tsx +661 -0
  383. package/src/router-tanstack/search-store.test.ts +418 -0
  384. package/src/router-tanstack/search-store.ts +380 -0
  385. package/src/router-tanstack/use-nav.test.tsx +187 -0
  386. package/src/router-tanstack/use-nav.ts +72 -14
  387. package/src/section/index.ts +1 -0
  388. package/src/section/section.module.css +104 -0
  389. package/src/section/section.module.css.d.ts +11 -0
  390. package/src/section/section.test.tsx +204 -0
  391. package/src/section/section.tsx +220 -0
  392. package/src/shell/app-breadcrumbs.tsx +44 -31
  393. package/src/shell/app-header.module.css +77 -37
  394. package/src/shell/app-header.module.css.d.ts +2 -1
  395. package/src/shell/app-mobile-nav.module.css +8 -0
  396. package/src/shell/app-mobile-nav.module.css.d.ts +1 -0
  397. package/src/shell/app-mobile-nav.tsx +147 -8
  398. package/src/shell/app-sidebar-account.tsx +2 -2
  399. package/src/shell/app-sidebar.module.css +303 -20
  400. package/src/shell/app-sidebar.module.css.d.ts +19 -1
  401. package/src/shell/app-sidebar.test.tsx +456 -41
  402. package/src/shell/app-sidebar.tsx +276 -140
  403. package/src/shell/index.test.tsx +291 -5
  404. package/src/shell/index.tsx +137 -38
  405. package/src/shell/mobile-nav-model.test.ts +228 -7
  406. package/src/shell/mobile-nav-model.ts +53 -3
  407. package/src/shell/nav-count-badge.tsx +1 -1
  408. package/src/shell/page-bar.module.css +178 -0
  409. package/src/shell/page-bar.module.css.d.ts +17 -0
  410. package/src/shell/page-bar.test.tsx +316 -0
  411. package/src/shell/page-bar.tsx +315 -0
  412. package/src/shell/sidebar-block-model.ts +83 -0
  413. package/src/shell/sidebar-blocks.tsx +301 -0
  414. package/src/shell/sidebar-search.module.css +26 -0
  415. package/src/shell/sidebar-search.module.css.d.ts +2 -0
  416. package/src/shell/sidebar-search.tsx +71 -2
  417. package/src/state/fields.test.tsx +258 -0
  418. package/src/state/fields.ts +892 -0
  419. package/src/state/persisted.ts +211 -0
  420. package/src/state.ts +46 -240
  421. package/src/styles.css +13 -0
  422. package/src/surfaces.ts +203 -36
  423. package/src/theme/controls.module.css +16 -1
  424. package/src/theme/ctl-theme.test.tsx +275 -0
  425. package/src/theme/ctl-theme.tsx +138 -0
  426. package/src/theme/ctl-tier-coverage.test.ts +170 -0
  427. package/src/theme/density-relations.test.ts +106 -51
  428. package/src/theme/divider-law.test.ts +259 -0
  429. package/src/theme/icon-slot.module.css +47 -0
  430. package/src/theme/icon-slot.module.css.d.ts +8 -0
  431. package/src/theme/icon-slot.test.tsx +275 -0
  432. package/src/theme/icon-slot.tsx +59 -0
  433. package/src/theme/index.ts +165 -3
  434. package/src/theme/layout-rhythm-css.test.ts +72 -0
  435. package/src/theme/radius.test.ts +11 -1
  436. package/src/theme/segmented-control.module.css +20 -0
  437. package/src/theme/shadow-surfaces.test.ts +20 -7
  438. package/src/theme/spacing.test.ts +75 -27
  439. package/src/theme/use-basalt-spacing.ts +2 -2
  440. package/src/tokens/density.test.ts +7 -25
  441. package/src/tokens/index.ts +48 -8
  442. package/src/tokens/palette.ts +107 -73
  443. package/src/widget-header/delta-badge.test.tsx +60 -0
  444. package/src/widget-header/delta-badge.tsx +57 -0
  445. package/src/widget-header/index.ts +2 -0
  446. package/src/widget-header/no-mantine.test.ts +33 -0
  447. package/src/widget-header/widget-header.module.css +335 -0
  448. package/src/widget-header/widget-header.module.css.d.ts +24 -0
  449. package/src/widget-header/widget-header.test.tsx +187 -0
  450. package/src/widget-header/widget-header.tsx +168 -0
  451. package/agent/rules/basalt-agent.md +0 -452
  452. package/agent/rules/basalt-app.md +0 -246
  453. package/agent/rules/basalt-commands.md +0 -320
  454. package/agent/rules/basalt-content.md +0 -409
  455. package/agent/rules/basalt-data.md +0 -269
  456. package/agent/rules/basalt-forms.md +0 -186
  457. package/agent/rules/basalt-notifications.md +0 -264
  458. package/agent/rules/basalt-query.md +0 -187
  459. package/agent/rules/basalt-router.md +0 -336
  460. package/dist/content/article-filter-bar.d.ts +0 -40
  461. package/dist/content/article-filter-bar.d.ts.map +0 -1
  462. package/dist/content/article-filter-bar.js +0 -56
  463. package/dist/shell/page-header.d.ts +0 -13
  464. package/dist/shell/page-header.d.ts.map +0 -1
  465. package/dist/shell/page-header.js +0 -23
  466. package/src/content/article-filter-bar.tsx +0 -88
  467. package/src/shell/page-header.tsx +0 -35
@@ -0,0 +1,48 @@
1
+ /**
2
+ * The sidebar-block law — every default a `SidebarBlock` leaves unstated, plus the two persisted
3
+ * fold-key grammars.
4
+ *
5
+ * PURE BY CONTRACT, for the same reason `mobile-nav-model.ts` is: three consumers read these
6
+ * defaults and none of them may disagree. `app-sidebar.tsx` decides where a block renders and
7
+ * whether the rail keeps it, `sidebar-blocks.tsx` paints it, and `mobile-nav-model.ts` counts the
8
+ * More-sheet rows it will produce — a count that picks `menu` vs `sheet` before any of it renders.
9
+ * A default re-derived per call site is how the count and the renderer drift apart (see
10
+ * `accountRowCount`'s doc for the same failure with account rows).
11
+ */
12
+ import type { SidebarBlock } from '../nav/types.js';
13
+ /** Envelope version for a persisted fold flag. Bump only if the value stops being a boolean. */
14
+ export declare const FOLD_VERSION = 1;
15
+ /**
16
+ * `'nav'` renders after the nav sections inside the scroll region; `'bottom'` pins above the
17
+ * settings footer. A progress block is `'bottom'` — it is a pinned status row, not a nav tail.
18
+ */
19
+ export declare function sidebarBlockPlacement(block: SidebarBlock): 'nav' | 'bottom';
20
+ /**
21
+ * The collapsed-rail projection. A list block earns a dot only when it carries a `count` — a rail
22
+ * icon with no number behind it is a dot that means nothing — and a progress block a ring on the
23
+ * settings row. A `custom` block has no rail representation at all (arbitrary content in ~48px of
24
+ * icon column), which is exactly what `sidebarNavExtra` did before it.
25
+ */
26
+ export declare function sidebarBlockRail(block: SidebarBlock): 'dot' | 'ring' | 'hidden';
27
+ /**
28
+ * The mobile projection. A list is reachable from More by default — below `sm` the sidebar does
29
+ * not render at all, so a hidden list is unreachable, not merely unshown. A progress row defaults
30
+ * to `'hidden'`: it is ambient status, and every More row costs headroom the menu-vs-sheet
31
+ * threshold is measured against.
32
+ */
33
+ export declare function sidebarBlockMobile(block: SidebarBlock): 'more' | 'hidden';
34
+ /** Rows a list block paints, honouring `max` — the "Show more" toggle reveals the remainder. */
35
+ export declare function sidebarBlockVisibleCount(itemCount: number, max: number | undefined): number;
36
+ /**
37
+ * A section label as a storage-key segment. Lowercase, every run of non-alphanumerics collapsed to
38
+ * one `-`, no leading/trailing separator — `'Awaiting action'` → `'awaiting-action'`.
39
+ */
40
+ export declare function slugifyLabel(label: string): string;
41
+ /**
42
+ * `createPersistedState` namespaces every key as `basalt:<key>`, so these return the UNNAMESPACED
43
+ * halves — the real storage keys are `basalt:sidebar-block:<key>` and
44
+ * `basalt:sidebar-section:<label-slug>` (`docs/CONTROLS-SPEC.md` §2.3).
45
+ */
46
+ export declare function sidebarBlockFoldKey(blockKey: string): string;
47
+ export declare function sidebarSectionFoldKey(label: string): string;
48
+ //# sourceMappingURL=sidebar-block-model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sidebar-block-model.d.ts","sourceRoot":"","sources":["../../src/shell/sidebar-block-model.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAEhD,gGAAgG;AAChG,eAAO,MAAM,YAAY,IAAI,CAAA;AAE7B;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,YAAY,GAAG,KAAK,GAAG,QAAQ,CAG3E;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,YAAY,GAAG,KAAK,GAAG,MAAM,GAAG,QAAQ,CAS/E;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,GAAG,QAAQ,CAIzE;AAED,gGAAgG;AAChG,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAG3F;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKlD;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE3D"}
@@ -0,0 +1,39 @@
1
+ const FOLD_VERSION = 1;
2
+ function sidebarBlockPlacement(block) {
3
+ if (block.kind === "progress") return block.placement ?? "bottom";
4
+ return block.placement ?? "nav";
5
+ }
6
+ function sidebarBlockRail(block) {
7
+ if (block.kind === "custom") return "hidden";
8
+ if (block.kind === "progress") return block.rail ?? "ring";
9
+ if (block.icon === void 0 || block.count === void 0) return "hidden";
10
+ return block.rail ?? "dot";
11
+ }
12
+ function sidebarBlockMobile(block) {
13
+ if (block.kind === "custom") return "hidden";
14
+ if (block.kind === "progress") return block.mobile ?? "hidden";
15
+ return block.mobile ?? "more";
16
+ }
17
+ function sidebarBlockVisibleCount(itemCount, max) {
18
+ if (max === void 0 || max >= itemCount) return itemCount;
19
+ return Math.max(0, max);
20
+ }
21
+ function slugifyLabel(label) {
22
+ return label.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
23
+ }
24
+ function sidebarBlockFoldKey(blockKey) {
25
+ return `sidebar-block:${blockKey}`;
26
+ }
27
+ function sidebarSectionFoldKey(label) {
28
+ return `sidebar-section:${slugifyLabel(label)}`;
29
+ }
30
+ export {
31
+ FOLD_VERSION,
32
+ sidebarBlockFoldKey,
33
+ sidebarBlockMobile,
34
+ sidebarBlockPlacement,
35
+ sidebarBlockRail,
36
+ sidebarBlockVisibleCount,
37
+ sidebarSectionFoldKey,
38
+ slugifyLabel
39
+ };
@@ -0,0 +1,32 @@
1
+ import type { SidebarBlockTone, SidebarCustomBlock, SidebarListBlock, SidebarProgressBlock } from '../nav/types.js';
2
+ /**
3
+ * Fold/expand chevron. Lives here rather than in `app-sidebar.tsx` purely for direction: that
4
+ * module imports this one, so a glyph shared by a collapsible SECTION header and a collapsible
5
+ * BLOCK header has to sit on this side of the edge or the two files cycle.
6
+ */
7
+ export declare function IconChevron({ open }: {
8
+ open: boolean;
9
+ }): import("react").JSX.Element;
10
+ /**
11
+ * A persisted fold flag (`true` = folded). Exactly one hook call regardless of `key`, so swapping
12
+ * keys mid-life never moves the hook count.
13
+ *
14
+ * Every fold in the sidebar goes through this — block folds at `basalt:sidebar-block:<key>` and
15
+ * nav-section folds at `basalt:sidebar-section:<label-slug>`. Through 1.25.0 the section folds were
16
+ * one `useState` keyed by label, so every reload re-opened a section the user had closed.
17
+ */
18
+ export declare function usePersistedFold(key: string, initial: boolean): readonly [boolean, (next: boolean) => void];
19
+ /** Status dot — the icon fallback for a toned row. Reads `--vx-status-*` through `data-tone`. */
20
+ export declare function SidebarBlockToneDot({ tone }: {
21
+ tone: SidebarBlockTone;
22
+ }): import("react").JSX.Element;
23
+ /** `value` of `total` as a ring — the collapsed rail's stand-in for a progress block. */
24
+ export declare function SidebarProgressRing({ value, total }: {
25
+ value: number;
26
+ total: number;
27
+ }): import("react").JSX.Element;
28
+ /** One block, whichever kind it is. `AppSidebar` places it; this decides nothing but the paint. */
29
+ export declare function SidebarBlockView({ block, }: {
30
+ block: SidebarListBlock | SidebarProgressBlock | SidebarCustomBlock;
31
+ }): import("react").JSX.Element;
32
+ //# sourceMappingURL=sidebar-blocks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sidebar-blocks.d.ts","sourceRoot":"","sources":["../../src/shell/sidebar-blocks.tsx"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAEV,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,EAChB,oBAAoB,EACrB,MAAM,cAAc,CAAA;AAYrB;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,+BAgBtD;AAsBD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,OAAO,GACf,SAAS,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC,CAE7C;AAcD,iGAAiG;AACjG,wBAAgB,mBAAmB,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,+BAEvE;AAED,yFAAyF;AACzF,wBAAgB,mBAAmB,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,+BAwBrF;AA4JD,mGAAmG;AACnG,wBAAgB,gBAAgB,CAAC,EAC/B,KAAK,GACN,EAAE;IACD,KAAK,EAAE,gBAAgB,GAAG,oBAAoB,GAAG,kBAAkB,CAAA;CACpE,+BAIA"}
@@ -0,0 +1,169 @@
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import { Collapse, NavLink, Progress, Text, UnstyledButton } from "@mantine/core";
3
+ import { useState } from "react";
4
+ import { NavCountBadge } from "./nav-count-badge.js";
5
+ import { createPersistedState } from "../state.js";
6
+ import {
7
+ FOLD_VERSION,
8
+ sidebarBlockFoldKey,
9
+ sidebarBlockRail,
10
+ sidebarBlockVisibleCount
11
+ } from "./sidebar-block-model.js";
12
+ import { IconSlot } from "../theme/icon-slot.js";
13
+ import classes from "./app-sidebar.module.css";
14
+ function IconChevron({ open }) {
15
+ return /* @__PURE__ */ jsx(
16
+ "svg",
17
+ {
18
+ width: 12,
19
+ height: 12,
20
+ viewBox: "0 0 24 24",
21
+ fill: "none",
22
+ stroke: "currentColor",
23
+ strokeWidth: 2,
24
+ strokeLinecap: "round",
25
+ strokeLinejoin: "round",
26
+ "aria-hidden": true,
27
+ children: open ? /* @__PURE__ */ jsx("path", { d: "M6 9l6 6l6 -6" }) : /* @__PURE__ */ jsx("path", { d: "M9 6l6 6l-6 6" })
28
+ }
29
+ );
30
+ }
31
+ const foldStores = /* @__PURE__ */ new Map();
32
+ function foldStore(key, initial) {
33
+ const cached = foldStores.get(key);
34
+ if (cached) return cached;
35
+ const store = createPersistedState({ key, version: FOLD_VERSION, initial });
36
+ foldStores.set(key, store);
37
+ return store;
38
+ }
39
+ function usePersistedFold(key, initial) {
40
+ return foldStore(key, initial)();
41
+ }
42
+ function BlockLabel({ children }) {
43
+ return /* @__PURE__ */ jsx(Text, { component: "div", className: classes.sectionLabel, children });
44
+ }
45
+ function SidebarBlockToneDot({ tone }) {
46
+ return /* @__PURE__ */ jsx("span", { className: classes.blockToneDot, "data-tone": tone, "aria-hidden": true });
47
+ }
48
+ function SidebarProgressRing({ value, total }) {
49
+ const CIRCUMFERENCE = 2 * Math.PI * 8;
50
+ const ratio = total > 0 ? Math.min(1, Math.max(0, value / total)) : 0;
51
+ return /* @__PURE__ */ jsx("span", { className: classes.blockRing, "data-basalt-rail-ring": true, children: /* @__PURE__ */ jsxs("svg", { width: 20, height: 20, viewBox: "0 0 20 20", "aria-hidden": true, children: [
52
+ /* @__PURE__ */ jsx("circle", { cx: 10, cy: 10, r: 8, fill: "none", stroke: "var(--vx-divider)", strokeWidth: 2 }),
53
+ /* @__PURE__ */ jsx(
54
+ "circle",
55
+ {
56
+ cx: 10,
57
+ cy: 10,
58
+ r: 8,
59
+ fill: "none",
60
+ stroke: "var(--vx-accent)",
61
+ strokeWidth: 2,
62
+ strokeLinecap: "round",
63
+ strokeDasharray: CIRCUMFERENCE,
64
+ strokeDashoffset: CIRCUMFERENCE * (1 - ratio),
65
+ transform: "rotate(-90 10 10)"
66
+ }
67
+ )
68
+ ] }) });
69
+ }
70
+ function BlockRow({ item }) {
71
+ const rawLead = item.icon ?? (item.tone !== void 0 ? /* @__PURE__ */ jsx(SidebarBlockToneDot, { tone: item.tone }) : void 0);
72
+ const lead = rawLead === void 0 ? void 0 : /* @__PURE__ */ jsx(IconSlot, { children: rawLead });
73
+ const meta = item.meta !== void 0 ? /* @__PURE__ */ jsx(Text, { component: "span", className: classes.blockRowMeta, children: item.meta }) : void 0;
74
+ const interactive = item.Anchor !== void 0 || item.href !== void 0 || item.onClick !== void 0;
75
+ if (!interactive) {
76
+ return /* @__PURE__ */ jsxs("div", { className: `${classes.blockRow} ${classes.blockRowStatic}`, children: [
77
+ lead,
78
+ /* @__PURE__ */ jsx(Text, { component: "span", className: classes.blockRowLabel, children: item.label }),
79
+ meta
80
+ ] });
81
+ }
82
+ const shared = {
83
+ classNames: { root: classes.blockRow },
84
+ label: item.label,
85
+ ...lead !== void 0 && { leftSection: lead },
86
+ ...meta !== void 0 && { rightSection: meta },
87
+ ...item.onClick !== void 0 && { onClick: item.onClick }
88
+ };
89
+ const Anchor = item.Anchor;
90
+ if (Anchor) return /* @__PURE__ */ jsx(NavLink, { component: Anchor, ...shared });
91
+ return /* @__PURE__ */ jsx(NavLink, { component: "a", ...item.href !== void 0 && { href: item.href }, ...shared });
92
+ }
93
+ function ListBlock({ block }) {
94
+ const [folded, setFolded] = usePersistedFold(sidebarBlockFoldKey(block.key), false);
95
+ const [showAll, setShowAll] = useState(false);
96
+ const rail = sidebarBlockRail(block);
97
+ const visible = showAll ? block.items.length : sidebarBlockVisibleCount(block.items.length, block.max);
98
+ const hidden = block.items.length - visible;
99
+ const label = /* @__PURE__ */ jsxs(Fragment, { children: [
100
+ block.icon !== void 0 && /* @__PURE__ */ jsxs("span", { className: classes.blockIcon, children: [
101
+ block.icon,
102
+ rail === "dot" && /* @__PURE__ */ jsx("span", { className: classes.blockDot, "aria-hidden": true })
103
+ ] }),
104
+ /* @__PURE__ */ jsx(BlockLabel, { children: block.label }),
105
+ block.count ? /* @__PURE__ */ jsx(NavCountBadge, { count: block.count }) : null
106
+ ] });
107
+ const body = /* @__PURE__ */ jsxs("div", { className: classes.blockItems, children: [
108
+ block.items.slice(0, visible).map((item) => /* @__PURE__ */ jsx(BlockRow, { item }, item.key)),
109
+ hidden > 0 || showAll ? /* @__PURE__ */ jsx(
110
+ UnstyledButton,
111
+ {
112
+ className: classes.blockMore,
113
+ onClick: () => setShowAll(!showAll),
114
+ "aria-expanded": showAll,
115
+ children: showAll ? "Show less" : "Show more"
116
+ }
117
+ ) : null
118
+ ] });
119
+ return /* @__PURE__ */ jsx("div", { className: classes.block, "data-rail": rail, children: block.collapsible === true ? /* @__PURE__ */ jsxs(Fragment, { children: [
120
+ /* @__PURE__ */ jsxs(
121
+ UnstyledButton,
122
+ {
123
+ className: `${classes.blockHeader} ${classes.blockHeaderButton}`,
124
+ onClick: () => setFolded(!folded),
125
+ "aria-expanded": !folded,
126
+ children: [
127
+ label,
128
+ /* @__PURE__ */ jsx(IconChevron, { open: !folded })
129
+ ]
130
+ }
131
+ ),
132
+ /* @__PURE__ */ jsx(Collapse, { expanded: !folded, children: body })
133
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
134
+ /* @__PURE__ */ jsx("div", { className: classes.blockHeader, children: label }),
135
+ body
136
+ ] }) });
137
+ }
138
+ function ProgressBlock({ block }) {
139
+ const percent = block.total > 0 ? Math.min(100, Math.max(0, block.value / block.total * 100)) : 0;
140
+ const inner = /* @__PURE__ */ jsxs(Fragment, { children: [
141
+ /* @__PURE__ */ jsxs("div", { className: classes.blockProgressHead, children: [
142
+ /* @__PURE__ */ jsx(BlockLabel, { children: block.label }),
143
+ /* @__PURE__ */ jsxs(Text, { component: "span", className: classes.blockRowMeta, children: [
144
+ block.value,
145
+ " of ",
146
+ block.total
147
+ ] })
148
+ ] }),
149
+ /* @__PURE__ */ jsx(Progress, { value: percent, size: "xs", "aria-label": block.label })
150
+ ] });
151
+ return /* @__PURE__ */ jsx("div", { className: classes.block, "data-rail": sidebarBlockRail(block), children: block.onClick !== void 0 ? /* @__PURE__ */ jsx(UnstyledButton, { className: classes.blockProgress, onClick: block.onClick, children: inner }) : /* @__PURE__ */ jsx("div", { className: classes.blockProgress, children: inner }) });
152
+ }
153
+ function CustomBlock({ block }) {
154
+ return /* @__PURE__ */ jsx("div", { className: classes.block, "data-rail": "hidden", children: block.node });
155
+ }
156
+ function SidebarBlockView({
157
+ block
158
+ }) {
159
+ if (block.kind === "list") return /* @__PURE__ */ jsx(ListBlock, { block });
160
+ if (block.kind === "progress") return /* @__PURE__ */ jsx(ProgressBlock, { block });
161
+ return /* @__PURE__ */ jsx(CustomBlock, { block });
162
+ }
163
+ export {
164
+ IconChevron,
165
+ SidebarBlockToneDot,
166
+ SidebarBlockView,
167
+ SidebarProgressRing,
168
+ usePersistedFold
169
+ };
@@ -1,3 +1,14 @@
1
+ import type { BarAction } from '../controls/actions.js';
2
+ /**
3
+ * The ⌘K row's trailing icon buttons — ONE or TWO, by type (`docs/CONTROLS-SPEC.md` §2.3).
4
+ *
5
+ * The tuple IS the enforcement: a third button pushes the search trigger under the width where its
6
+ * placeholder stays readable, and there is no third thing a sidebar search row is for. Each entry
7
+ * renders icon-only at the `icon` tier (24px, `--ai-size-icon`) with `label` demoted to the
8
+ * accessible name; a `kind: 'menu'` entry becomes an `OverflowMenu` kebab, a `kind: 'custom'` one
9
+ * is mounted verbatim.
10
+ */
11
+ export type SidebarSearchActions = [BarAction] | [BarAction, BarAction];
1
12
  export type SidebarSearchConfig = {
2
13
  /** Opens the search palette — e.g. `openSpotlight` from `basalt-ui/commands`. */
3
14
  onOpen: () => void;
@@ -6,7 +17,8 @@ export type SidebarSearchConfig = {
6
17
  /** Keyboard-shortcut hint shown on the right (e.g. '⌘K'). Auto-detected mac/other when omitted. */
7
18
  shortcut?: string;
8
19
  };
9
- export declare function SidebarSearch({ onOpen, placeholder, shortcut, collapsed, }: SidebarSearchConfig & {
20
+ export declare function SidebarSearch({ onOpen, placeholder, shortcut, actions, collapsed, }: SidebarSearchConfig & {
21
+ actions?: SidebarSearchActions;
10
22
  collapsed?: boolean;
11
23
  }): import("react").JSX.Element;
12
24
  //# sourceMappingURL=sidebar-search.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sidebar-search.d.ts","sourceRoot":"","sources":["../../src/shell/sidebar-search.tsx"],"names":[],"mappings":"AAYA,MAAM,MAAM,mBAAmB,GAAG;IAChC,iFAAiF;IACjF,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,2CAA2C;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,mGAAmG;IACnG,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAA;AAsBD,wBAAgB,aAAa,CAAC,EAC5B,MAAM,EACN,WAAuB,EACvB,QAAQ,EACR,SAAS,GACV,EAAE,mBAAmB,GAAG;IAAE,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,+BAiC/C"}
1
+ {"version":3,"file":"sidebar-search.d.ts","sourceRoot":"","sources":["../../src/shell/sidebar-search.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAGpD;;;;;;;;GAQG;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;AAEvE,MAAM,MAAM,mBAAmB,GAAG;IAChC,iFAAiF;IACjF,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,2CAA2C;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,mGAAmG;IACnG,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAA;AAgED,wBAAgB,aAAa,CAAC,EAC5B,MAAM,EACN,WAAuB,EACvB,QAAQ,EACR,OAAO,EACP,SAAS,GACV,EAAE,mBAAmB,GAAG;IAAE,OAAO,CAAC,EAAE,oBAAoB,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,+BA6C/E"}
@@ -1,5 +1,6 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { ActionIcon, Kbd, Text, UnstyledButton } from "@mantine/core";
3
+ import { OverflowMenu } from "../controls/actions.js";
3
4
  import classes from "./sidebar-search.module.css";
4
5
  function IconSearch() {
5
6
  return /* @__PURE__ */ jsxs(
@@ -21,10 +22,37 @@ function IconSearch() {
21
22
  }
22
23
  );
23
24
  }
25
+ function initial(label) {
26
+ return [...label][0]?.toUpperCase() ?? "?";
27
+ }
28
+ function SearchAction({ action }) {
29
+ if (action.kind === "custom") return action.node;
30
+ if (action.kind === "menu") {
31
+ return /* @__PURE__ */ jsx(OverflowMenu, { actions: action.items, trigger: "kebab", label: action.label });
32
+ }
33
+ const shared = {
34
+ variant: "subtle",
35
+ size: "icon",
36
+ className: classes.actionBtn,
37
+ "aria-label": action.label,
38
+ disabled: action.disabled === true,
39
+ ...action.onClick !== void 0 && { onClick: action.onClick }
40
+ };
41
+ const body = action.icon ?? initial(action.label);
42
+ const Anchor = action.Anchor;
43
+ if (Anchor !== void 0) {
44
+ return /* @__PURE__ */ jsx(ActionIcon, { component: Anchor, ...shared, children: body });
45
+ }
46
+ if (action.link !== void 0) {
47
+ return /* @__PURE__ */ jsx(ActionIcon, { component: "a", href: action.link.to, ...shared, children: body });
48
+ }
49
+ return /* @__PURE__ */ jsx(ActionIcon, { ...shared, children: body });
50
+ }
24
51
  function SidebarSearch({
25
52
  onOpen,
26
53
  placeholder = "Search\u2026",
27
54
  shortcut,
55
+ actions,
28
56
  collapsed
29
57
  }) {
30
58
  const isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPod|iPad/i.test(navigator.platform);
@@ -42,7 +70,7 @@ function SidebarSearch({
42
70
  }
43
71
  );
44
72
  }
45
- return /* @__PURE__ */ jsxs(
73
+ const trigger = /* @__PURE__ */ jsxs(
46
74
  UnstyledButton,
47
75
  {
48
76
  type: "button",
@@ -56,6 +84,11 @@ function SidebarSearch({
56
84
  ]
57
85
  }
58
86
  );
87
+ if (actions === void 0) return trigger;
88
+ return /* @__PURE__ */ jsxs("div", { className: classes.row, children: [
89
+ trigger,
90
+ actions.map((action) => /* @__PURE__ */ jsx(SearchAction, { action }, action.key))
91
+ ] });
59
92
  }
60
93
  export {
61
94
  SidebarSearch
@@ -5,6 +5,18 @@
5
5
  * button as a matched pair, so the two must never drift onto different depth tokens.
6
6
  */
7
7
 
8
+ /*
9
+ * The row that appears ONLY when `search.actions` is supplied — one or two icon-only buttons beside
10
+ * the trigger. Without actions the trigger stays the row's sole node (no wrapper), so the DOM of
11
+ * every consumer that doesn't use them is untouched.
12
+ */
13
+ .row {
14
+ display: flex;
15
+ align-items: center;
16
+ gap: var(--vx-space-sidebar-search-gap);
17
+ min-width: 0;
18
+ }
19
+
8
20
  .trigger {
9
21
  display: flex;
10
22
  align-items: center;
@@ -74,3 +86,17 @@
74
86
  background-color: color-mix(in srgb, var(--vx-ink) 6%, transparent) !important;
75
87
  color: var(--vx-ink) !important;
76
88
  }
89
+
90
+ /* Trailing search-row action — the same ghost treatment as `.ghostIcon` / `.railBtn`, at the `icon`
91
+ * tier (24px) the component asks for explicitly. Never re-points `--ai-size`: unlike `.railBtn`,
92
+ * this button is NOT a second state of the trigger and must not track its height. */
93
+ .actionBtn {
94
+ flex: none;
95
+ color: var(--vx-faint) !important;
96
+ border-radius: var(--vx-radius-ctrl) !important;
97
+ }
98
+
99
+ .actionBtn:hover {
100
+ background-color: color-mix(in srgb, var(--vx-ink) 6%, transparent) !important;
101
+ color: var(--vx-ink) !important;
102
+ }
@@ -4,8 +4,10 @@
4
4
  * (`noUncheckedIndexedAccess`, `noPropertyAccessFromIndexSignature`, `exactOptionalPropertyTypes`).
5
5
  */
6
6
  declare const classes: {
7
+ readonly row: string
7
8
  readonly trigger: string
8
9
  readonly label: string
9
10
  readonly railBtn: string
11
+ readonly actionBtn: string
10
12
  }
11
13
  export default classes