basalt-ui 1.26.0 → 1.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1069) hide show
  1. package/AGENTS.md +23 -23
  2. package/CHANGELOG.md +67 -0
  3. package/MIGRATING.md +896 -37
  4. package/README.md +33 -3
  5. package/agent/rules/basalt-batteries.md +25 -10
  6. package/agent/rules/basalt-controls.md +73 -43
  7. package/agent/rules/basalt-mantine.md +17 -6
  8. package/agent/rules/basalt-state.md +5 -0
  9. package/agent/rules/basalt-tokens.md +1 -1
  10. package/configs/oxlint-plugin.js +1286 -73
  11. package/configs/oxlint-plugin.test.ts +1338 -29
  12. package/configs/oxlint.json +12 -5
  13. package/dist/agent/coalesce.d.ts.map +1 -1
  14. package/dist/agent/coalesce.js +2 -1
  15. package/dist/agent/merge.d.ts.map +1 -1
  16. package/dist/agent/merge.js +2 -1
  17. package/dist/agent/part-list.d.ts.map +1 -1
  18. package/dist/agent/part-list.js +2 -0
  19. package/dist/agent/stick-to-bottom.d.ts +3 -6
  20. package/dist/agent/stick-to-bottom.d.ts.map +1 -1
  21. package/dist/agent/stick-to-bottom.js +6 -3
  22. package/dist/agent-chat/composer.d.ts +6 -2
  23. package/dist/agent-chat/composer.d.ts.map +1 -1
  24. package/dist/agent-chat/composer.js +49 -33
  25. package/dist/agent-chat/relative-time.d.ts +0 -9
  26. package/dist/agent-chat/relative-time.d.ts.map +1 -1
  27. package/dist/agent-chat/relative-time.js +2 -1
  28. package/dist/agent-chat/thread-detail-panel.d.ts +3 -2
  29. package/dist/agent-chat/thread-detail-panel.d.ts.map +1 -1
  30. package/dist/agent-chat/thread-detail-panel.js +8 -5
  31. package/dist/agent-chat/thread-feed-row.d.ts +2 -1
  32. package/dist/agent-chat/thread-feed-row.d.ts.map +1 -1
  33. package/dist/agent-chat/thread-feed-row.js +92 -92
  34. package/dist/agent-chat/thread-feed.d.ts +3 -2
  35. package/dist/agent-chat/thread-feed.d.ts.map +1 -1
  36. package/dist/agent-chat/thread-feed.js +8 -3
  37. package/dist/agent-chat/thread-message.d.ts +4 -3
  38. package/dist/agent-chat/thread-message.d.ts.map +1 -1
  39. package/dist/agent-chat/thread-message.js +70 -31
  40. package/dist/agent-chat/thread-outcome-card.d.ts +3 -2
  41. package/dist/agent-chat/thread-outcome-card.d.ts.map +1 -1
  42. package/dist/agent-chat/thread-outcome-card.js +9 -2
  43. package/dist/agent-chat/thread-workspace.d.ts +7 -2
  44. package/dist/agent-chat/thread-workspace.d.ts.map +1 -1
  45. package/dist/agent-chat/thread-workspace.js +62 -29
  46. package/dist/agent-chat/tool-chip.d.ts +3 -2
  47. package/dist/agent-chat/tool-chip.d.ts.map +1 -1
  48. package/dist/agent-chat/tool-chip.js +7 -2
  49. package/dist/charts/hooks/useBandPlot.d.ts.map +1 -1
  50. package/dist/charts/hooks/useBandPlot.js +15 -8
  51. package/dist/charts/index.d.ts +8 -7
  52. package/dist/charts/index.d.ts.map +1 -1
  53. package/dist/charts/index.js +45 -5
  54. package/dist/charts/kinds/BandStrip.d.ts +10 -7
  55. package/dist/charts/kinds/BandStrip.d.ts.map +1 -1
  56. package/dist/charts/kinds/BandStrip.js +12 -7
  57. package/dist/charts/kinds/Bars.d.ts +12 -6
  58. package/dist/charts/kinds/Bars.d.ts.map +1 -1
  59. package/dist/charts/kinds/Bars.js +37 -11
  60. package/dist/charts/kinds/Donut.d.ts +6 -5
  61. package/dist/charts/kinds/Donut.d.ts.map +1 -1
  62. package/dist/charts/kinds/Donut.js +19 -2
  63. package/dist/charts/kinds/DualPanel.d.ts +6 -5
  64. package/dist/charts/kinds/DualPanel.d.ts.map +1 -1
  65. package/dist/charts/kinds/DualPanel.js +36 -8
  66. package/dist/charts/kinds/Heatmap.d.ts +10 -6
  67. package/dist/charts/kinds/Heatmap.d.ts.map +1 -1
  68. package/dist/charts/kinds/Heatmap.js +58 -31
  69. package/dist/charts/kinds/MirroredBars.d.ts +6 -5
  70. package/dist/charts/kinds/MirroredBars.d.ts.map +1 -1
  71. package/dist/charts/kinds/MirroredBars.js +9 -2
  72. package/dist/charts/kinds/MultiLine.d.ts +11 -6
  73. package/dist/charts/kinds/MultiLine.d.ts.map +1 -1
  74. package/dist/charts/kinds/MultiLine.js +24 -15
  75. package/dist/charts/kinds/StackedArea.d.ts +18 -8
  76. package/dist/charts/kinds/StackedArea.d.ts.map +1 -1
  77. package/dist/charts/kinds/StackedArea.js +29 -4
  78. package/dist/charts/kinds/ZonedLine.d.ts +12 -8
  79. package/dist/charts/kinds/ZonedLine.d.ts.map +1 -1
  80. package/dist/charts/kinds/ZonedLine.js +33 -23
  81. package/dist/charts/layout/auto-margin.d.ts +65 -8
  82. package/dist/charts/layout/auto-margin.d.ts.map +1 -1
  83. package/dist/charts/layout/auto-margin.js +45 -10
  84. package/dist/charts/layout/log-ticks.d.ts +27 -0
  85. package/dist/charts/layout/log-ticks.d.ts.map +1 -0
  86. package/dist/charts/layout/log-ticks.js +42 -0
  87. package/dist/charts/primitives/Axes.d.ts +11 -2
  88. package/dist/charts/primitives/Axes.d.ts.map +1 -1
  89. package/dist/charts/primitives/Axes.js +15 -5
  90. package/dist/charts/primitives/CartesianChart.d.ts +45 -7
  91. package/dist/charts/primitives/CartesianChart.d.ts.map +1 -1
  92. package/dist/charts/primitives/CartesianChart.js +86 -28
  93. package/dist/charts/primitives/ChartCard.d.ts +27 -2
  94. package/dist/charts/primitives/ChartCard.d.ts.map +1 -1
  95. package/dist/charts/primitives/ChartCard.js +37 -17
  96. package/dist/charts/primitives/ChartFrame.d.ts +30 -4
  97. package/dist/charts/primitives/ChartFrame.d.ts.map +1 -1
  98. package/dist/charts/primitives/ChartFrame.js +45 -15
  99. package/dist/charts/primitives/ChartLegend.d.ts +13 -2
  100. package/dist/charts/primitives/ChartLegend.d.ts.map +1 -1
  101. package/dist/charts/primitives/ChartLegend.js +33 -13
  102. package/dist/charts/primitives/ChartPending.d.ts +77 -4
  103. package/dist/charts/primitives/ChartPending.d.ts.map +1 -1
  104. package/dist/charts/primitives/ChartPending.js +100 -6
  105. package/dist/charts/primitives/ChartTooltip.d.ts +7 -0
  106. package/dist/charts/primitives/ChartTooltip.d.ts.map +1 -1
  107. package/dist/charts/primitives/ChartTooltip.js +18 -5
  108. package/dist/charts/primitives/Crosshair.d.ts +3 -0
  109. package/dist/charts/primitives/Crosshair.d.ts.map +1 -1
  110. package/dist/charts/primitives/Crosshair.js +3 -1
  111. package/dist/charts/primitives/chart-frame-layout.d.ts +95 -0
  112. package/dist/charts/primitives/chart-frame-layout.d.ts.map +1 -0
  113. package/dist/charts/primitives/chart-frame-layout.js +89 -0
  114. package/dist/charts/primitives/chart-tier.d.ts +16 -0
  115. package/dist/charts/primitives/chart-tier.d.ts.map +1 -0
  116. package/dist/charts/primitives/chart-tier.js +20 -0
  117. package/dist/charts/series.d.ts +55 -1
  118. package/dist/charts/series.d.ts.map +1 -1
  119. package/dist/charts/series.js +27 -1
  120. package/dist/charts/sparklines/BarSparkline.d.ts +3 -3
  121. package/dist/charts/sparklines/BarSparkline.d.ts.map +1 -1
  122. package/dist/charts/sparklines/BarSparkline.js +9 -3
  123. package/dist/charts/sparklines/LineSparkline.d.ts +3 -3
  124. package/dist/charts/sparklines/LineSparkline.d.ts.map +1 -1
  125. package/dist/charts/sparklines/LineSparkline.js +15 -3
  126. package/dist/charts/sparklines/index.d.ts +2 -2
  127. package/dist/charts/sparklines/index.d.ts.map +1 -1
  128. package/dist/charts/utils/format.d.ts +92 -2
  129. package/dist/charts/utils/format.d.ts.map +1 -1
  130. package/dist/charts/utils/format.js +64 -1
  131. package/dist/charts/utils/ticks.d.ts +81 -2
  132. package/dist/charts/utils/ticks.d.ts.map +1 -1
  133. package/dist/charts/utils/ticks.js +54 -4
  134. package/dist/cli/index.d.ts.map +1 -1
  135. package/dist/cli/index.js +2 -2
  136. package/dist/commands/ShortcutsHelp.d.ts +3 -2
  137. package/dist/commands/ShortcutsHelp.d.ts.map +1 -1
  138. package/dist/commands/ShortcutsHelp.js +8 -2
  139. package/dist/commands/define-commands.d.ts.map +1 -1
  140. package/dist/commands/define-commands.js +2 -2
  141. package/dist/commands/define-overlays.d.ts +102 -0
  142. package/dist/commands/define-overlays.d.ts.map +1 -1
  143. package/dist/commands/define-overlays.js +102 -2
  144. package/dist/commands/index.d.ts +10 -1
  145. package/dist/commands/index.d.ts.map +1 -1
  146. package/dist/commands/index.js +3 -1
  147. package/dist/commands/overlays-mount.d.ts +13 -6
  148. package/dist/commands/overlays-mount.d.ts.map +1 -1
  149. package/dist/commands/overlays-mount.js +23 -14
  150. package/dist/common/errors.d.ts +34 -0
  151. package/dist/common/errors.d.ts.map +1 -0
  152. package/dist/common/errors.js +36 -0
  153. package/dist/common/index.d.ts +15 -0
  154. package/dist/common/index.d.ts.map +1 -0
  155. package/dist/common/index.js +29 -0
  156. package/dist/common/props.d.ts +63 -0
  157. package/dist/common/props.d.ts.map +1 -0
  158. package/dist/common/props.js +6 -0
  159. package/dist/common/query-state-like.d.ts +43 -0
  160. package/dist/common/query-state-like.d.ts.map +1 -0
  161. package/dist/common/query-state-like.js +20 -0
  162. package/dist/common/refs.d.ts +29 -0
  163. package/dist/common/refs.d.ts.map +1 -0
  164. package/dist/common/refs.js +29 -0
  165. package/dist/common/scroll-parent.d.ts +23 -0
  166. package/dist/common/scroll-parent.d.ts.map +1 -0
  167. package/dist/common/scroll-parent.js +21 -0
  168. package/dist/common/validate.d.ts +38 -0
  169. package/dist/common/validate.d.ts.map +1 -0
  170. package/dist/common/validate.js +36 -0
  171. package/dist/connectivity/connectivity-indicator.d.ts +3 -1
  172. package/dist/connectivity/connectivity-indicator.d.ts.map +1 -1
  173. package/dist/connectivity/connectivity-indicator.js +3 -1
  174. package/dist/connectivity/connectivity-provider.d.ts.map +1 -1
  175. package/dist/connectivity/connectivity-provider.js +4 -1
  176. package/dist/connectivity/index.d.ts +1 -0
  177. package/dist/connectivity/index.d.ts.map +1 -1
  178. package/dist/connectivity/types.d.ts +2 -2
  179. package/dist/connectivity/types.d.ts.map +1 -1
  180. package/dist/connectivity/use-connectivity.d.ts.map +1 -1
  181. package/dist/content/article-layout.module.css +11 -4
  182. package/dist/content/callout.d.ts +8 -4
  183. package/dist/content/callout.d.ts.map +1 -1
  184. package/dist/content/callout.js +15 -8
  185. package/dist/content/guide.d.ts +5 -4
  186. package/dist/content/guide.d.ts.map +1 -1
  187. package/dist/content/guide.js +13 -4
  188. package/dist/content/heading-anchor.d.ts +24 -2
  189. package/dist/content/heading-anchor.d.ts.map +1 -1
  190. package/dist/content/heading-anchor.js +23 -9
  191. package/dist/content/index.d.ts.map +1 -1
  192. package/dist/content/markdown.d.ts.map +1 -1
  193. package/dist/content/markdown.js +2 -0
  194. package/dist/content/prose.module.css +9 -7
  195. package/dist/content/reading-progress.d.ts +10 -4
  196. package/dist/content/reading-progress.d.ts.map +1 -1
  197. package/dist/content/reading-progress.js +26 -10
  198. package/dist/content/slug.d.ts +4 -0
  199. package/dist/content/slug.d.ts.map +1 -1
  200. package/dist/content/toc.d.ts +11 -0
  201. package/dist/content/toc.d.ts.map +1 -1
  202. package/dist/content/toc.js +23 -10
  203. package/dist/controls/actions.d.ts +49 -6
  204. package/dist/controls/actions.d.ts.map +1 -1
  205. package/dist/controls/actions.js +39 -8
  206. package/dist/controls/compare-filter.d.ts +3 -2
  207. package/dist/controls/compare-filter.d.ts.map +1 -1
  208. package/dist/controls/compare-filter.js +17 -2
  209. package/dist/controls/control-group.d.ts +3 -3
  210. package/dist/controls/control-group.d.ts.map +1 -1
  211. package/dist/controls/control-group.js +9 -2
  212. package/dist/controls/controls.module.css +169 -186
  213. package/dist/controls/controls.module.css.d.ts +9 -11
  214. package/dist/controls/enum-filter.d.ts +13 -3
  215. package/dist/controls/enum-filter.d.ts.map +1 -1
  216. package/dist/controls/enum-filter.js +32 -15
  217. package/dist/controls/filter-context.d.ts +15 -6
  218. package/dist/controls/filter-context.d.ts.map +1 -1
  219. package/dist/controls/filter-pill.d.ts +3 -3
  220. package/dist/controls/filter-pill.d.ts.map +1 -1
  221. package/dist/controls/filter-pill.js +4 -1
  222. package/dist/controls/filter-set.d.ts +3 -2
  223. package/dist/controls/filter-set.d.ts.map +1 -1
  224. package/dist/controls/filter-set.js +66 -41
  225. package/dist/controls/filter-sheet.d.ts +20 -80
  226. package/dist/controls/filter-sheet.d.ts.map +1 -1
  227. package/dist/controls/filter-sheet.js +9 -95
  228. package/dist/controls/index.d.ts +3 -0
  229. package/dist/controls/index.d.ts.map +1 -1
  230. package/dist/controls/index.js +6 -0
  231. package/dist/controls/multi-select-filter.d.ts +18 -2
  232. package/dist/controls/multi-select-filter.d.ts.map +1 -1
  233. package/dist/controls/multi-select-filter.js +124 -22
  234. package/dist/controls/number-filter.d.ts +28 -0
  235. package/dist/controls/number-filter.d.ts.map +1 -0
  236. package/dist/controls/number-filter.js +172 -0
  237. package/dist/controls/panel-row.d.ts +132 -0
  238. package/dist/controls/panel-row.d.ts.map +1 -0
  239. package/dist/controls/panel-row.js +173 -0
  240. package/dist/controls/panel-row.module.css +86 -0
  241. package/dist/controls/panel-row.module.css.d.ts +13 -0
  242. package/dist/controls/range-filter.d.ts +20 -5
  243. package/dist/controls/range-filter.d.ts.map +1 -1
  244. package/dist/controls/range-filter.js +75 -38
  245. package/dist/controls/search-filter.d.ts +3 -2
  246. package/dist/controls/search-filter.d.ts.map +1 -1
  247. package/dist/controls/search-filter.js +26 -11
  248. package/dist/controls/select-filter.d.ts +2 -1
  249. package/dist/controls/select-filter.d.ts.map +1 -1
  250. package/dist/controls/select-filter.js +4 -0
  251. package/dist/controls/slider-control.d.ts +36 -0
  252. package/dist/controls/slider-control.d.ts.map +1 -0
  253. package/dist/controls/slider-control.js +64 -0
  254. package/dist/controls/sync-button.d.ts +3 -2
  255. package/dist/controls/sync-button.d.ts.map +1 -1
  256. package/dist/controls/sync-button.js +16 -3
  257. package/dist/controls/toggle-filter.d.ts +3 -2
  258. package/dist/controls/toggle-filter.d.ts.map +1 -1
  259. package/dist/controls/toggle-filter.js +29 -12
  260. package/dist/controls/view-tabs.d.ts +3 -2
  261. package/dist/controls/view-tabs.d.ts.map +1 -1
  262. package/dist/controls/view-tabs.js +43 -11
  263. package/dist/controls-dates/date-range-picker.d.ts +1 -1
  264. package/dist/controls-dates/date-range-picker.d.ts.map +1 -1
  265. package/dist/controls-dates/date-range-picker.js +6 -1
  266. package/dist/dashboard/delta-badge.d.ts +5 -1
  267. package/dist/dashboard/delta-badge.d.ts.map +1 -1
  268. package/dist/dashboard/empty-state.d.ts +10 -3
  269. package/dist/dashboard/empty-state.d.ts.map +1 -1
  270. package/dist/dashboard/empty-state.js +37 -6
  271. package/dist/dashboard/index.d.ts +6 -4
  272. package/dist/dashboard/index.d.ts.map +1 -1
  273. package/dist/dashboard/index.js +10 -2
  274. package/dist/dashboard/query-state.d.ts +48 -27
  275. package/dist/dashboard/query-state.d.ts.map +1 -1
  276. package/dist/dashboard/query-state.js +111 -57
  277. package/dist/dashboard/settings-section.d.ts +19 -9
  278. package/dist/dashboard/settings-section.d.ts.map +1 -1
  279. package/dist/dashboard/settings-section.js +74 -25
  280. package/dist/dashboard/stat-card.d.ts +76 -19
  281. package/dist/dashboard/stat-card.d.ts.map +1 -1
  282. package/dist/dashboard/stat-card.js +78 -38
  283. package/dist/dashboard/stat-card.module.css +112 -26
  284. package/dist/dashboard/stat-card.module.css.d.ts +5 -0
  285. package/dist/dashboard/stat-group.d.ts +41 -0
  286. package/dist/dashboard/stat-group.d.ts.map +1 -0
  287. package/dist/dashboard/stat-group.js +30 -0
  288. package/dist/dashboard/stat-group.module.css +66 -0
  289. package/dist/dashboard/stat-group.module.css.d.ts +8 -0
  290. package/dist/dashboard/widget-grid.d.ts +27 -0
  291. package/dist/dashboard/widget-grid.d.ts.map +1 -0
  292. package/dist/dashboard/widget-grid.js +41 -0
  293. package/dist/dashboard/widget-grid.module.css +53 -0
  294. package/dist/dashboard/widget-grid.module.css.d.ts +9 -0
  295. package/dist/data/data-table.d.ts +151 -12
  296. package/dist/data/data-table.d.ts.map +1 -1
  297. package/dist/data/data-table.js +392 -138
  298. package/dist/data/data-table.module.css +64 -0
  299. package/dist/data/data-table.module.css.d.ts +11 -0
  300. package/dist/data/index.d.ts +2 -2
  301. package/dist/data/index.d.ts.map +1 -1
  302. package/dist/data/index.js +24 -2
  303. package/dist/data/query-branch.d.ts +28 -0
  304. package/dist/data/query-branch.d.ts.map +1 -0
  305. package/dist/data/query-branch.js +10 -0
  306. package/dist/data/table.d.ts +2 -2
  307. package/dist/data/table.d.ts.map +1 -1
  308. package/dist/data/virtual-list.d.ts +65 -6
  309. package/dist/data/virtual-list.d.ts.map +1 -1
  310. package/dist/data/virtual-list.js +89 -38
  311. package/dist/data/virtual.d.ts +1 -1
  312. package/dist/data/virtual.d.ts.map +1 -1
  313. package/dist/forms/FormErrorSummary.d.ts +4 -3
  314. package/dist/forms/FormErrorSummary.d.ts.map +1 -1
  315. package/dist/forms/FormErrorSummary.js +6 -4
  316. package/dist/forms/create-form.d.ts +2 -2
  317. package/dist/forms/field.d.ts +46 -6
  318. package/dist/forms/field.d.ts.map +1 -1
  319. package/dist/forms/field.js +10 -5
  320. package/dist/forms/form-layout.d.ts +142 -0
  321. package/dist/forms/form-layout.d.ts.map +1 -0
  322. package/dist/forms/form-layout.js +110 -0
  323. package/dist/forms/form-layout.module.css +145 -0
  324. package/dist/forms/form-layout.module.css.d.ts +20 -0
  325. package/dist/forms/form-state.d.ts +42 -0
  326. package/dist/forms/form-state.d.ts.map +1 -0
  327. package/dist/forms/form-state.js +26 -0
  328. package/dist/forms/index.d.ts +22 -6
  329. package/dist/forms/index.d.ts.map +1 -1
  330. package/dist/forms/index.js +19 -3
  331. package/dist/forms/use-field-array.d.ts +60 -0
  332. package/dist/forms/use-field-array.d.ts.map +1 -0
  333. package/dist/forms/use-field-array.js +20 -0
  334. package/dist/forms/use-form-draft.d.ts +25 -10
  335. package/dist/forms/use-form-draft.d.ts.map +1 -1
  336. package/dist/forms/use-form-draft.js +55 -18
  337. package/dist/forms/use-form-submit.d.ts +88 -0
  338. package/dist/forms/use-form-submit.d.ts.map +1 -0
  339. package/dist/forms/use-form-submit.js +63 -0
  340. package/dist/guard/index.d.ts +1 -1
  341. package/dist/guard/index.d.ts.map +1 -1
  342. package/dist/guard/index.js +27 -11
  343. package/dist/index.d.ts +10 -8
  344. package/dist/index.d.ts.map +1 -1
  345. package/dist/index.js +44 -4
  346. package/dist/nav/types.d.ts +15 -6
  347. package/dist/nav/types.d.ts.map +1 -1
  348. package/dist/notifications/bell.d.ts +3 -2
  349. package/dist/notifications/bell.d.ts.map +1 -1
  350. package/dist/notifications/bell.js +73 -56
  351. package/dist/notifications/center.d.ts +15 -4
  352. package/dist/notifications/center.d.ts.map +1 -1
  353. package/dist/notifications/center.js +5 -2
  354. package/dist/notifications/define-notifications.d.ts +56 -14
  355. package/dist/notifications/define-notifications.d.ts.map +1 -1
  356. package/dist/notifications/define-notifications.js +2 -1
  357. package/dist/notifications/index.d.ts +6 -2
  358. package/dist/notifications/index.d.ts.map +1 -1
  359. package/dist/notifications/index.js +5 -1
  360. package/dist/notifications/mount-guard.d.ts +8 -0
  361. package/dist/notifications/mount-guard.d.ts.map +1 -0
  362. package/dist/notifications/mount-guard.js +19 -0
  363. package/dist/notifications/notify.d.ts +58 -1
  364. package/dist/notifications/notify.d.ts.map +1 -1
  365. package/dist/notifications/notify.js +46 -2
  366. package/dist/notifications/overlay.d.ts.map +1 -1
  367. package/dist/notifications/overlay.js +2 -0
  368. package/dist/notifications/store.d.ts +7 -0
  369. package/dist/notifications/store.d.ts.map +1 -1
  370. package/dist/provider/index.d.ts +37 -5
  371. package/dist/provider/index.d.ts.map +1 -1
  372. package/dist/provider/index.js +66 -28
  373. package/dist/provider/lab-theme.d.ts.map +1 -1
  374. package/dist/provider/lab-theme.js +2 -1
  375. package/dist/query/devtools.d.ts.map +1 -1
  376. package/dist/query/devtools.js +1 -0
  377. package/dist/router-tanstack/field.d.ts +1 -1
  378. package/dist/router-tanstack/field.d.ts.map +1 -1
  379. package/dist/router-tanstack/index.d.ts +1 -1
  380. package/dist/router-tanstack/index.d.ts.map +1 -1
  381. package/dist/router-tanstack/search-store.d.ts +4 -1
  382. package/dist/router-tanstack/search-store.d.ts.map +1 -1
  383. package/dist/router-tanstack/search-store.js +92 -8
  384. package/dist/router-tanstack/use-nav.d.ts.map +1 -1
  385. package/dist/router-tanstack/use-nav.js +1 -1
  386. package/dist/section/index.d.ts +1 -1
  387. package/dist/section/index.d.ts.map +1 -1
  388. package/dist/section/section.d.ts +36 -2
  389. package/dist/section/section.d.ts.map +1 -1
  390. package/dist/section/section.js +49 -57
  391. package/dist/section/section.module.css +11 -0
  392. package/dist/shell/account-types.d.ts +5 -2
  393. package/dist/shell/account-types.d.ts.map +1 -1
  394. package/dist/shell/app-brand.d.ts +13 -0
  395. package/dist/shell/app-brand.d.ts.map +1 -0
  396. package/dist/shell/app-brand.js +94 -0
  397. package/dist/shell/app-brand.module.css +109 -0
  398. package/dist/shell/app-brand.module.css.d.ts +14 -0
  399. package/dist/shell/app-breadcrumbs.d.ts +4 -2
  400. package/dist/shell/app-breadcrumbs.d.ts.map +1 -1
  401. package/dist/shell/app-breadcrumbs.js +33 -22
  402. package/dist/shell/app-header.module.css +10 -5
  403. package/dist/shell/app-main.module.css +107 -0
  404. package/dist/shell/app-main.module.css.d.ts +11 -0
  405. package/dist/shell/app-mobile-nav.d.ts +3 -2
  406. package/dist/shell/app-mobile-nav.d.ts.map +1 -1
  407. package/dist/shell/app-mobile-nav.js +29 -15
  408. package/dist/shell/app-mobile-nav.module.css +48 -27
  409. package/dist/shell/app-mobile-nav.module.css.d.ts +0 -1
  410. package/dist/shell/app-sidebar-account.d.ts +2 -1
  411. package/dist/shell/app-sidebar-account.d.ts.map +1 -1
  412. package/dist/shell/app-sidebar-account.js +57 -22
  413. package/dist/shell/app-sidebar.d.ts +9 -3
  414. package/dist/shell/app-sidebar.d.ts.map +1 -1
  415. package/dist/shell/app-sidebar.js +55 -109
  416. package/dist/shell/app-sidebar.module.css +53 -96
  417. package/dist/shell/app-sidebar.module.css.d.ts +0 -5
  418. package/dist/shell/index.d.ts +14 -6
  419. package/dist/shell/index.d.ts.map +1 -1
  420. package/dist/shell/index.js +47 -12
  421. package/dist/shell/isomorphic-layout-effect.d.ts +14 -0
  422. package/dist/shell/isomorphic-layout-effect.d.ts.map +1 -0
  423. package/dist/shell/isomorphic-layout-effect.js +5 -0
  424. package/dist/shell/mobile-nav-model.d.ts.map +1 -1
  425. package/dist/shell/mobile-nav-model.js +27 -6
  426. package/dist/shell/nav-count-badge.d.ts +5 -3
  427. package/dist/shell/nav-count-badge.d.ts.map +1 -1
  428. package/dist/shell/nav-count-badge.js +3 -1
  429. package/dist/shell/page-aside.d.ts +43 -0
  430. package/dist/shell/page-aside.d.ts.map +1 -0
  431. package/dist/shell/page-aside.js +202 -0
  432. package/dist/shell/page-aside.module.css +174 -0
  433. package/dist/shell/page-aside.module.css.d.ts +14 -0
  434. package/dist/shell/page-bar.d.ts +55 -15
  435. package/dist/shell/page-bar.d.ts.map +1 -1
  436. package/dist/shell/page-bar.js +130 -41
  437. package/dist/shell/page-bar.module.css +107 -13
  438. package/dist/shell/page-bar.module.css.d.ts +4 -1
  439. package/dist/shell/sidebar-search.d.ts +4 -2
  440. package/dist/shell/sidebar-search.d.ts.map +1 -1
  441. package/dist/shell/sidebar-search.js +9 -4
  442. package/dist/shell/sidebar-search.module.css +1 -1
  443. package/dist/state/fields.d.ts +227 -34
  444. package/dist/state/fields.d.ts.map +1 -1
  445. package/dist/state/fields.js +77 -30
  446. package/dist/state/persisted-or-local.d.ts +9 -0
  447. package/dist/state/persisted-or-local.d.ts.map +1 -0
  448. package/dist/state/persisted-or-local.js +24 -0
  449. package/dist/state/persisted.d.ts +12 -0
  450. package/dist/state/persisted.d.ts.map +1 -1
  451. package/dist/state/persisted.js +36 -18
  452. package/dist/state.d.ts +1 -1
  453. package/dist/state.d.ts.map +1 -1
  454. package/dist/state.js +2 -6
  455. package/dist/surfaces.d.ts +12 -11
  456. package/dist/surfaces.d.ts.map +1 -1
  457. package/dist/surfaces.js +43 -12
  458. package/dist/theme/ctl-theme.d.ts.map +1 -1
  459. package/dist/theme/index.d.ts.map +1 -1
  460. package/dist/theme/index.js +102 -17
  461. package/dist/theme/nav-link.module.css +37 -26
  462. package/dist/theme/segmented-control.module.css +22 -0
  463. package/dist/theme/segmented-control.module.css.d.ts +1 -0
  464. package/dist/theme-lab/boot.d.ts +66 -0
  465. package/dist/theme-lab/boot.d.ts.map +1 -0
  466. package/dist/theme-lab/boot.js +82 -0
  467. package/dist/theme-lab/index.d.ts +4 -43
  468. package/dist/theme-lab/index.d.ts.map +1 -1
  469. package/dist/theme-lab/index.js +9 -69
  470. package/dist/theme-toggle/index.d.ts +3 -2
  471. package/dist/theme-toggle/index.d.ts.map +1 -1
  472. package/dist/theme-toggle/index.js +8 -2
  473. package/dist/tokens/index.d.ts +42 -0
  474. package/dist/tokens/index.d.ts.map +1 -1
  475. package/dist/tokens/index.js +35 -6
  476. package/dist/tokens/palette.d.ts +45 -25
  477. package/dist/tokens/palette.d.ts.map +1 -1
  478. package/dist/tokens/palette.js +31 -14
  479. package/dist/tokens.css +4 -5
  480. package/dist/utils/is-dev.d.ts +3 -0
  481. package/dist/utils/is-dev.d.ts.map +1 -0
  482. package/dist/utils/is-dev.js +6 -0
  483. package/dist/widget-header/delta-badge.d.ts +7 -1
  484. package/dist/widget-header/delta-badge.d.ts.map +1 -1
  485. package/dist/widget-header/delta-badge.js +8 -1
  486. package/dist/widget-header/index.d.ts +2 -2
  487. package/dist/widget-header/index.d.ts.map +1 -1
  488. package/dist/widget-header/index.js +3 -1
  489. package/dist/widget-header/widget-header.d.ts +99 -4
  490. package/dist/widget-header/widget-header.d.ts.map +1 -1
  491. package/dist/widget-header/widget-header.js +45 -18
  492. package/dist/widget-header/widget-header.module.css +87 -7
  493. package/dist/widget-header/widget-header.module.css.d.ts +1 -0
  494. package/llms.txt +6 -6
  495. package/package.json +49 -25
  496. package/src/agent/coalesce.ts +2 -1
  497. package/src/agent/merge.ts +2 -1
  498. package/src/agent/part-list.tsx +2 -0
  499. package/src/agent/stick-to-bottom.tsx +9 -11
  500. package/src/agent-chat/composer.tsx +124 -103
  501. package/src/agent-chat/relative-time.ts +2 -1
  502. package/src/agent-chat/thread-detail-panel.tsx +9 -5
  503. package/src/agent-chat/thread-feed-row.tsx +17 -9
  504. package/src/agent-chat/thread-feed.tsx +9 -3
  505. package/src/agent-chat/thread-message.tsx +48 -13
  506. package/src/agent-chat/thread-outcome-card.tsx +9 -1
  507. package/src/agent-chat/thread-workspace.tsx +72 -33
  508. package/src/agent-chat/tool-chip.tsx +8 -2
  509. package/src/charts/hooks/useBandPlot.ts +26 -8
  510. package/src/charts/index.ts +39 -4
  511. package/src/charts/kinds/BandStrip.tsx +36 -14
  512. package/src/charts/kinds/Bars.tsx +67 -16
  513. package/src/charts/kinds/Donut.tsx +30 -3
  514. package/src/charts/kinds/DualPanel.tsx +56 -10
  515. package/src/charts/kinds/Heatmap.tsx +90 -33
  516. package/src/charts/kinds/MirroredBars.tsx +21 -3
  517. package/src/charts/kinds/MultiLine.tsx +61 -18
  518. package/src/charts/kinds/StackedArea.tsx +77 -6
  519. package/src/charts/kinds/ZonedLine.tsx +71 -31
  520. package/src/charts/layout/auto-margin.ts +134 -21
  521. package/src/charts/layout/log-ticks.ts +90 -0
  522. package/src/charts/primitives/Axes.tsx +33 -5
  523. package/src/charts/primitives/CartesianChart.tsx +194 -41
  524. package/src/charts/primitives/ChartCard.tsx +66 -25
  525. package/src/charts/primitives/ChartFrame.tsx +107 -26
  526. package/src/charts/primitives/ChartLegend.tsx +43 -13
  527. package/src/charts/primitives/ChartPending.tsx +185 -7
  528. package/src/charts/primitives/ChartTooltip.tsx +37 -5
  529. package/src/charts/primitives/Crosshair.tsx +6 -3
  530. package/src/charts/primitives/chart-frame-layout.ts +212 -0
  531. package/src/charts/primitives/chart-tier.tsx +37 -0
  532. package/src/charts/series.ts +77 -1
  533. package/src/charts/sparklines/BarSparkline.tsx +11 -3
  534. package/src/charts/sparklines/LineSparkline.tsx +18 -4
  535. package/src/charts/sparklines/index.ts +2 -2
  536. package/src/charts/utils/format.ts +163 -2
  537. package/src/charts/utils/ticks.ts +149 -4
  538. package/src/cli/index.ts +8 -3
  539. package/src/commands/ShortcutsHelp.tsx +10 -3
  540. package/src/commands/define-commands.ts +2 -2
  541. package/src/commands/define-overlays.ts +216 -1
  542. package/src/commands/index.ts +12 -0
  543. package/src/commands/overlays-mount.tsx +60 -26
  544. package/src/common/errors.ts +73 -0
  545. package/src/common/index.ts +21 -0
  546. package/src/common/props.ts +71 -0
  547. package/src/common/query-state-like.ts +64 -0
  548. package/src/common/refs.ts +58 -0
  549. package/src/common/scroll-parent.ts +42 -0
  550. package/src/common/validate.ts +94 -0
  551. package/src/connectivity/connectivity-indicator.tsx +6 -1
  552. package/src/connectivity/connectivity-provider.tsx +4 -1
  553. package/src/connectivity/index.ts +1 -0
  554. package/src/connectivity/types.ts +5 -2
  555. package/src/connectivity/use-connectivity.ts +3 -2
  556. package/src/content/article-layout.module.css +11 -4
  557. package/src/content/callout.tsx +13 -7
  558. package/src/content/guide.tsx +14 -4
  559. package/src/content/heading-anchor.tsx +14 -3
  560. package/src/content/index.ts +2 -0
  561. package/src/content/markdown.tsx +2 -0
  562. package/src/content/prose.module.css +9 -7
  563. package/src/content/reading-progress.tsx +40 -15
  564. package/src/content/slug.ts +4 -0
  565. package/src/content/toc.tsx +47 -10
  566. package/src/controls/actions.tsx +89 -9
  567. package/src/controls/compare-filter.tsx +20 -3
  568. package/src/controls/control-group.tsx +11 -4
  569. package/src/controls/controls.module.css +169 -186
  570. package/src/controls/controls.module.css.d.ts +9 -11
  571. package/src/controls/enum-filter.tsx +46 -19
  572. package/src/controls/filter-context.tsx +21 -8
  573. package/src/controls/filter-pill.tsx +6 -3
  574. package/src/controls/filter-set.tsx +32 -13
  575. package/src/controls/filter-sheet.tsx +44 -194
  576. package/src/controls/index.ts +8 -0
  577. package/src/controls/multi-select-filter.tsx +179 -29
  578. package/src/controls/number-filter.tsx +329 -0
  579. package/src/controls/panel-row.module.css +86 -0
  580. package/src/controls/panel-row.module.css.d.ts +13 -0
  581. package/src/controls/panel-row.tsx +392 -0
  582. package/src/controls/range-filter.tsx +133 -43
  583. package/src/controls/search-filter.tsx +31 -13
  584. package/src/controls/select-filter.tsx +11 -1
  585. package/src/controls/slider-control.tsx +159 -0
  586. package/src/controls/sync-button.tsx +13 -3
  587. package/src/controls/toggle-filter.tsx +37 -17
  588. package/src/controls/view-tabs.tsx +63 -11
  589. package/src/controls-dates/date-range-picker.tsx +8 -1
  590. package/src/dashboard/delta-badge.tsx +5 -1
  591. package/src/dashboard/empty-state.tsx +72 -25
  592. package/src/dashboard/index.ts +19 -2
  593. package/src/dashboard/query-state.tsx +154 -84
  594. package/src/dashboard/settings-section.tsx +87 -31
  595. package/src/dashboard/stat-card.module.css +112 -26
  596. package/src/dashboard/stat-card.module.css.d.ts +5 -0
  597. package/src/dashboard/stat-card.tsx +207 -68
  598. package/src/dashboard/stat-group.module.css +66 -0
  599. package/src/dashboard/stat-group.module.css.d.ts +8 -0
  600. package/src/dashboard/stat-group.tsx +74 -0
  601. package/src/dashboard/widget-grid.module.css +53 -0
  602. package/src/dashboard/widget-grid.module.css.d.ts +9 -0
  603. package/src/dashboard/widget-grid.tsx +127 -0
  604. package/src/data/data-table.module.css +64 -0
  605. package/src/data/data-table.module.css.d.ts +11 -0
  606. package/src/data/data-table.tsx +927 -346
  607. package/src/data/index.ts +30 -2
  608. package/src/data/query-branch.ts +53 -0
  609. package/src/data/table.ts +5 -0
  610. package/src/data/virtual-list.tsx +189 -55
  611. package/src/data/virtual.ts +5 -1
  612. package/src/forms/FormErrorSummary.tsx +13 -6
  613. package/src/forms/create-form.ts +2 -2
  614. package/src/forms/field.ts +60 -11
  615. package/src/forms/form-layout.module.css +145 -0
  616. package/src/forms/form-layout.module.css.d.ts +20 -0
  617. package/src/forms/form-layout.tsx +305 -0
  618. package/src/forms/form-state.tsx +94 -0
  619. package/src/forms/index.ts +38 -7
  620. package/src/forms/use-field-array.ts +94 -0
  621. package/src/forms/use-form-draft.ts +145 -53
  622. package/src/forms/use-form-submit.ts +199 -0
  623. package/src/guard/index.ts +91 -23
  624. package/src/index.ts +79 -10
  625. package/src/nav/types.ts +15 -6
  626. package/src/notifications/bell.tsx +18 -4
  627. package/src/notifications/center.tsx +18 -5
  628. package/src/notifications/define-notifications.ts +64 -18
  629. package/src/notifications/index.ts +12 -1
  630. package/src/notifications/mount-guard.ts +41 -0
  631. package/src/notifications/notify.tsx +122 -3
  632. package/src/notifications/overlay.tsx +2 -0
  633. package/src/notifications/store.ts +7 -0
  634. package/src/provider/index.tsx +101 -13
  635. package/src/provider/lab-theme.ts +2 -1
  636. package/src/query/devtools.tsx +1 -0
  637. package/src/router-tanstack/field.ts +5 -0
  638. package/src/router-tanstack/index.ts +4 -0
  639. package/src/router-tanstack/search-store.ts +171 -12
  640. package/src/router-tanstack/use-nav.ts +18 -13
  641. package/src/section/index.ts +1 -1
  642. package/src/section/section.module.css +11 -0
  643. package/src/section/section.tsx +163 -96
  644. package/src/shell/account-types.ts +5 -2
  645. package/src/shell/app-brand.module.css +109 -0
  646. package/src/shell/app-brand.module.css.d.ts +14 -0
  647. package/src/shell/app-brand.tsx +140 -0
  648. package/src/shell/app-breadcrumbs.tsx +19 -9
  649. package/src/shell/app-header.module.css +10 -5
  650. package/src/shell/app-main.module.css +107 -0
  651. package/src/shell/app-main.module.css.d.ts +11 -0
  652. package/src/shell/app-mobile-nav.module.css +48 -27
  653. package/src/shell/app-mobile-nav.module.css.d.ts +0 -1
  654. package/src/shell/app-mobile-nav.tsx +43 -11
  655. package/src/shell/app-sidebar-account.tsx +29 -6
  656. package/src/shell/app-sidebar.module.css +53 -96
  657. package/src/shell/app-sidebar.module.css.d.ts +0 -5
  658. package/src/shell/app-sidebar.tsx +40 -113
  659. package/src/shell/index.tsx +156 -65
  660. package/src/shell/isomorphic-layout-effect.ts +14 -0
  661. package/src/shell/mobile-nav-model.ts +66 -10
  662. package/src/shell/nav-count-badge.tsx +6 -1
  663. package/src/shell/page-aside.module.css +174 -0
  664. package/src/shell/page-aside.module.css.d.ts +14 -0
  665. package/src/shell/page-aside.tsx +377 -0
  666. package/src/shell/page-bar.module.css +107 -13
  667. package/src/shell/page-bar.module.css.d.ts +4 -1
  668. package/src/shell/page-bar.tsx +294 -94
  669. package/src/shell/sidebar-search.module.css +1 -1
  670. package/src/shell/sidebar-search.tsx +13 -4
  671. package/src/state/fields.ts +360 -69
  672. package/src/state/persisted-or-local.ts +50 -0
  673. package/src/state/persisted.ts +76 -26
  674. package/src/state.ts +4 -7
  675. package/src/surfaces.ts +43 -12
  676. package/src/theme/ctl-theme.tsx +10 -0
  677. package/src/theme/index.ts +129 -16
  678. package/src/theme/nav-link.module.css +37 -26
  679. package/src/theme/segmented-control.module.css +22 -0
  680. package/src/theme/segmented-control.module.css.d.ts +1 -0
  681. package/src/theme-lab/boot.ts +140 -0
  682. package/src/theme-lab/index.tsx +21 -112
  683. package/src/theme-toggle/index.tsx +10 -3
  684. package/src/tokens/index.ts +50 -6
  685. package/src/tokens/palette.ts +58 -30
  686. package/src/utils/is-dev.ts +4 -0
  687. package/src/widget-header/delta-badge.tsx +25 -5
  688. package/src/widget-header/index.ts +10 -2
  689. package/src/widget-header/widget-header.module.css +87 -7
  690. package/src/widget-header/widget-header.module.css.d.ts +1 -0
  691. package/src/widget-header/widget-header.tsx +166 -42
  692. package/dist/agent/adapter.test.d.ts +0 -2
  693. package/dist/agent/adapter.test.d.ts.map +0 -1
  694. package/dist/agent/ai-sdk-transport.test.d.ts +0 -2
  695. package/dist/agent/ai-sdk-transport.test.d.ts.map +0 -1
  696. package/dist/agent/coalesce.test.d.ts +0 -2
  697. package/dist/agent/coalesce.test.d.ts.map +0 -1
  698. package/dist/agent/foreign.test.d.ts +0 -2
  699. package/dist/agent/foreign.test.d.ts.map +0 -1
  700. package/dist/agent/id.test.d.ts +0 -2
  701. package/dist/agent/id.test.d.ts.map +0 -1
  702. package/dist/agent/merge.test.d.ts +0 -2
  703. package/dist/agent/merge.test.d.ts.map +0 -1
  704. package/dist/agent/part-list.test.d.ts +0 -2
  705. package/dist/agent/part-list.test.d.ts.map +0 -1
  706. package/dist/agent/parts.test.d.ts +0 -2
  707. package/dist/agent/parts.test.d.ts.map +0 -1
  708. package/dist/agent/thread.test.d.ts +0 -2
  709. package/dist/agent/thread.test.d.ts.map +0 -1
  710. package/dist/agent/transport.test.d.ts +0 -2
  711. package/dist/agent/transport.test.d.ts.map +0 -1
  712. package/dist/agent/use-agent-stream.test.d.ts +0 -2
  713. package/dist/agent/use-agent-stream.test.d.ts.map +0 -1
  714. package/dist/agent/use-agent-thread-runs.foreign.test.d.ts +0 -2
  715. package/dist/agent/use-agent-thread-runs.foreign.test.d.ts.map +0 -1
  716. package/dist/agent/use-agent-thread-runs.resume.test.d.ts +0 -2
  717. package/dist/agent/use-agent-thread-runs.resume.test.d.ts.map +0 -1
  718. package/dist/agent/use-agent-thread-runs.test.d.ts +0 -2
  719. package/dist/agent/use-agent-thread-runs.test.d.ts.map +0 -1
  720. package/dist/agent/use-agent-thread-runs.wedge.test.d.ts +0 -2
  721. package/dist/agent/use-agent-thread-runs.wedge.test.d.ts.map +0 -1
  722. package/dist/agent-chat/composer.test.d.ts +0 -2
  723. package/dist/agent-chat/composer.test.d.ts.map +0 -1
  724. package/dist/agent-chat/relative-time.test.d.ts +0 -2
  725. package/dist/agent-chat/relative-time.test.d.ts.map +0 -1
  726. package/dist/agent-chat/thread-feed-row.test.d.ts +0 -2
  727. package/dist/agent-chat/thread-feed-row.test.d.ts.map +0 -1
  728. package/dist/agent-chat/thread-feed.test.d.ts +0 -2
  729. package/dist/agent-chat/thread-feed.test.d.ts.map +0 -1
  730. package/dist/agent-chat/thread-message.test.d.ts +0 -2
  731. package/dist/agent-chat/thread-message.test.d.ts.map +0 -1
  732. package/dist/agent-chat/thread-workspace.test.d.ts +0 -2
  733. package/dist/agent-chat/thread-workspace.test.d.ts.map +0 -1
  734. package/dist/agent-chat/tool-chip.test.d.ts +0 -2
  735. package/dist/agent-chat/tool-chip.test.d.ts.map +0 -1
  736. package/dist/agent-chat/virtualize.type-guard.test.d.ts +0 -2
  737. package/dist/agent-chat/virtualize.type-guard.test.d.ts.map +0 -1
  738. package/dist/charts/cursor/resolve.test.d.ts +0 -2
  739. package/dist/charts/cursor/resolve.test.d.ts.map +0 -1
  740. package/dist/charts/cursor/store.test.d.ts +0 -2
  741. package/dist/charts/cursor/store.test.d.ts.map +0 -1
  742. package/dist/charts/kinds/BandStrip.test.d.ts +0 -2
  743. package/dist/charts/kinds/BandStrip.test.d.ts.map +0 -1
  744. package/dist/charts/kinds/Bars.test.d.ts +0 -2
  745. package/dist/charts/kinds/Bars.test.d.ts.map +0 -1
  746. package/dist/charts/kinds/DualPanel.test.d.ts +0 -2
  747. package/dist/charts/kinds/DualPanel.test.d.ts.map +0 -1
  748. package/dist/charts/kinds/MirroredBars.test.d.ts +0 -2
  749. package/dist/charts/kinds/MirroredBars.test.d.ts.map +0 -1
  750. package/dist/charts/kinds/MultiLine.test.d.ts +0 -2
  751. package/dist/charts/kinds/MultiLine.test.d.ts.map +0 -1
  752. package/dist/charts/kinds/StackedArea.test.d.ts +0 -2
  753. package/dist/charts/kinds/StackedArea.test.d.ts.map +0 -1
  754. package/dist/charts/kinds/ZonedLine.test.d.ts +0 -2
  755. package/dist/charts/kinds/ZonedLine.test.d.ts.map +0 -1
  756. package/dist/charts/layout/auto-margin.test.d.ts +0 -2
  757. package/dist/charts/layout/auto-margin.test.d.ts.map +0 -1
  758. package/dist/charts/primitives/CartesianChart.test.d.ts +0 -2
  759. package/dist/charts/primitives/CartesianChart.test.d.ts.map +0 -1
  760. package/dist/charts/primitives/ChartCard.test.d.ts +0 -2
  761. package/dist/charts/primitives/ChartCard.test.d.ts.map +0 -1
  762. package/dist/charts/primitives/ChartFrame.test.d.ts +0 -2
  763. package/dist/charts/primitives/ChartFrame.test.d.ts.map +0 -1
  764. package/dist/charts/primitives/ChartLegend.test.d.ts +0 -2
  765. package/dist/charts/primitives/ChartLegend.test.d.ts.map +0 -1
  766. package/dist/charts/primitives/ChartTooltip.test.d.ts +0 -2
  767. package/dist/charts/primitives/ChartTooltip.test.d.ts.map +0 -1
  768. package/dist/charts/primitives/XZoneRects.test.d.ts +0 -2
  769. package/dist/charts/primitives/XZoneRects.test.d.ts.map +0 -1
  770. package/dist/charts/series.test.d.ts +0 -2
  771. package/dist/charts/series.test.d.ts.map +0 -1
  772. package/dist/charts/utils/domain.test.d.ts +0 -2
  773. package/dist/charts/utils/domain.test.d.ts.map +0 -1
  774. package/dist/charts/utils/measure-text.test.d.ts +0 -2
  775. package/dist/charts/utils/measure-text.test.d.ts.map +0 -1
  776. package/dist/cli/check-coverage.test.d.ts +0 -2
  777. package/dist/cli/check-coverage.test.d.ts.map +0 -1
  778. package/dist/cli/check-theme.test.d.ts +0 -2
  779. package/dist/cli/check-theme.test.d.ts.map +0 -1
  780. package/dist/cli/help.test.d.ts +0 -2
  781. package/dist/cli/help.test.d.ts.map +0 -1
  782. package/dist/cli/init-sync.test.d.ts +0 -2
  783. package/dist/cli/init-sync.test.d.ts.map +0 -1
  784. package/dist/cli/placement-engine.test.d.ts +0 -2
  785. package/dist/cli/placement-engine.test.d.ts.map +0 -1
  786. package/dist/cli/shipped-versions.test.d.ts +0 -2
  787. package/dist/cli/shipped-versions.test.d.ts.map +0 -1
  788. package/dist/cli/tarball-parity.test.d.ts +0 -2
  789. package/dist/cli/tarball-parity.test.d.ts.map +0 -1
  790. package/dist/cli/template-format.test.d.ts +0 -2
  791. package/dist/cli/template-format.test.d.ts.map +0 -1
  792. package/dist/cli/template-ledger.test.d.ts +0 -2
  793. package/dist/cli/template-ledger.test.d.ts.map +0 -1
  794. package/dist/cli/tokens-css.test.d.ts +0 -2
  795. package/dist/cli/tokens-css.test.d.ts.map +0 -1
  796. package/dist/cli/toolchain-wiring.test.d.ts +0 -2
  797. package/dist/cli/toolchain-wiring.test.d.ts.map +0 -1
  798. package/dist/cli/waiver-audit.test.d.ts +0 -2
  799. package/dist/cli/waiver-audit.test.d.ts.map +0 -1
  800. package/dist/content/article-actions.test.d.ts +0 -2
  801. package/dist/content/article-actions.test.d.ts.map +0 -1
  802. package/dist/content/article-model.test.d.ts +0 -2
  803. package/dist/content/article-model.test.d.ts.map +0 -1
  804. package/dist/content/block-split.test.d.ts +0 -2
  805. package/dist/content/block-split.test.d.ts.map +0 -1
  806. package/dist/content/heading-components.test.d.ts +0 -2
  807. package/dist/content/heading-components.test.d.ts.map +0 -1
  808. package/dist/content/markdown.test.d.ts +0 -2
  809. package/dist/content/markdown.test.d.ts.map +0 -1
  810. package/dist/content/prose.module.css.test.d.ts +0 -2
  811. package/dist/content/prose.module.css.test.d.ts.map +0 -1
  812. package/dist/content/sanitize.test.d.ts +0 -2
  813. package/dist/content/sanitize.test.d.ts.map +0 -1
  814. package/dist/content/slug.test.d.ts +0 -2
  815. package/dist/content/slug.test.d.ts.map +0 -1
  816. package/dist/controls/actions.test.d.ts +0 -2
  817. package/dist/controls/actions.test.d.ts.map +0 -1
  818. package/dist/controls/actions.type-guard.test.d.ts +0 -2
  819. package/dist/controls/actions.type-guard.test.d.ts.map +0 -1
  820. package/dist/controls/control-group.test.d.ts +0 -2
  821. package/dist/controls/control-group.test.d.ts.map +0 -1
  822. package/dist/controls/controls.router.test.d.ts +0 -2
  823. package/dist/controls/controls.router.test.d.ts.map +0 -1
  824. package/dist/controls/filter-set.test.d.ts +0 -2
  825. package/dist/controls/filter-set.test.d.ts.map +0 -1
  826. package/dist/controls/peer-boundary.test.d.ts +0 -2
  827. package/dist/controls/peer-boundary.test.d.ts.map +0 -1
  828. package/dist/controls/props-contract.test.d.ts +0 -2
  829. package/dist/controls/props-contract.test.d.ts.map +0 -1
  830. package/dist/controls/sync-button.test.d.ts +0 -2
  831. package/dist/controls/sync-button.test.d.ts.map +0 -1
  832. package/dist/dashboard/query-state.test.d.ts +0 -2
  833. package/dist/dashboard/query-state.test.d.ts.map +0 -1
  834. package/dist/dashboard/settings-section.test.d.ts +0 -2
  835. package/dist/dashboard/settings-section.test.d.ts.map +0 -1
  836. package/dist/dashboard/stat-card.test.d.ts +0 -2
  837. package/dist/dashboard/stat-card.test.d.ts.map +0 -1
  838. package/dist/data/data-table.test.d.ts +0 -2
  839. package/dist/data/data-table.test.d.ts.map +0 -1
  840. package/dist/guard/check-source.test.d.ts +0 -2
  841. package/dist/guard/check-source.test.d.ts.map +0 -1
  842. package/dist/guard/grace.test.d.ts +0 -20
  843. package/dist/guard/grace.test.d.ts.map +0 -1
  844. package/dist/guard/guard-hook.test.d.ts +0 -2
  845. package/dist/guard/guard-hook.test.d.ts.map +0 -1
  846. package/dist/provider/index.test.d.ts +0 -2
  847. package/dist/provider/index.test.d.ts.map +0 -1
  848. package/dist/provider/lab-theme.test.d.ts +0 -2
  849. package/dist/provider/lab-theme.test.d.ts.map +0 -1
  850. package/dist/query/error-message.test.d.ts +0 -2
  851. package/dist/query/error-message.test.d.ts.map +0 -1
  852. package/dist/router-tanstack/multi-search-param-store.test.d.ts +0 -2
  853. package/dist/router-tanstack/multi-search-param-store.test.d.ts.map +0 -1
  854. package/dist/router-tanstack/nav.test.d.ts +0 -2
  855. package/dist/router-tanstack/nav.test.d.ts.map +0 -1
  856. package/dist/router-tanstack/search-param-store.test.d.ts +0 -2
  857. package/dist/router-tanstack/search-param-store.test.d.ts.map +0 -1
  858. package/dist/router-tanstack/search-store.router.test.d.ts +0 -2
  859. package/dist/router-tanstack/search-store.router.test.d.ts.map +0 -1
  860. package/dist/router-tanstack/search-store.test.d.ts +0 -2
  861. package/dist/router-tanstack/search-store.test.d.ts.map +0 -1
  862. package/dist/router-tanstack/use-nav.test.d.ts +0 -2
  863. package/dist/router-tanstack/use-nav.test.d.ts.map +0 -1
  864. package/dist/section/section.test.d.ts +0 -2
  865. package/dist/section/section.test.d.ts.map +0 -1
  866. package/dist/shell/app-mobile-nav.test.d.ts +0 -2
  867. package/dist/shell/app-mobile-nav.test.d.ts.map +0 -1
  868. package/dist/shell/app-sidebar.test.d.ts +0 -2
  869. package/dist/shell/app-sidebar.test.d.ts.map +0 -1
  870. package/dist/shell/index.test.d.ts +0 -2
  871. package/dist/shell/index.test.d.ts.map +0 -1
  872. package/dist/shell/mobile-nav-model.test.d.ts +0 -2
  873. package/dist/shell/mobile-nav-model.test.d.ts.map +0 -1
  874. package/dist/shell/page-bar.test.d.ts +0 -2
  875. package/dist/shell/page-bar.test.d.ts.map +0 -1
  876. package/dist/state/fields.test.d.ts +0 -2
  877. package/dist/state/fields.test.d.ts.map +0 -1
  878. package/dist/styles.floor.test.d.ts +0 -2
  879. package/dist/styles.floor.test.d.ts.map +0 -1
  880. package/dist/theme/border-coverage.test.d.ts +0 -18
  881. package/dist/theme/border-coverage.test.d.ts.map +0 -1
  882. package/dist/theme/contrast.test.d.ts +0 -2
  883. package/dist/theme/contrast.test.d.ts.map +0 -1
  884. package/dist/theme/ctl-theme.test.d.ts +0 -2
  885. package/dist/theme/ctl-theme.test.d.ts.map +0 -1
  886. package/dist/theme/ctl-tier-coverage.test.d.ts +0 -2
  887. package/dist/theme/ctl-tier-coverage.test.d.ts.map +0 -1
  888. package/dist/theme/density-option.test.d.ts +0 -2
  889. package/dist/theme/density-option.test.d.ts.map +0 -1
  890. package/dist/theme/density-relations.test.d.ts +0 -2
  891. package/dist/theme/density-relations.test.d.ts.map +0 -1
  892. package/dist/theme/derive-theme.test.d.ts +0 -2
  893. package/dist/theme/derive-theme.test.d.ts.map +0 -1
  894. package/dist/theme/divider-law.test.d.ts +0 -2
  895. package/dist/theme/divider-law.test.d.ts.map +0 -1
  896. package/dist/theme/fonts-option.test.d.ts +0 -2
  897. package/dist/theme/fonts-option.test.d.ts.map +0 -1
  898. package/dist/theme/icon-slot.test.d.ts +0 -2
  899. package/dist/theme/icon-slot.test.d.ts.map +0 -1
  900. package/dist/theme/layout-rhythm-css.test.d.ts +0 -2
  901. package/dist/theme/layout-rhythm-css.test.d.ts.map +0 -1
  902. package/dist/theme/radius-option.test.d.ts +0 -2
  903. package/dist/theme/radius-option.test.d.ts.map +0 -1
  904. package/dist/theme/radius.test.d.ts +0 -2
  905. package/dist/theme/radius.test.d.ts.map +0 -1
  906. package/dist/theme/shadow-surfaces.test.d.ts +0 -26
  907. package/dist/theme/shadow-surfaces.test.d.ts.map +0 -1
  908. package/dist/theme/spacing.test.d.ts +0 -2
  909. package/dist/theme/spacing.test.d.ts.map +0 -1
  910. package/dist/theme/use-basalt-spacing.test.d.ts +0 -2
  911. package/dist/theme/use-basalt-spacing.test.d.ts.map +0 -1
  912. package/dist/theme-lab/derive-controls.test.d.ts +0 -2
  913. package/dist/theme-lab/derive-controls.test.d.ts.map +0 -1
  914. package/dist/theme-lab/derive-state.test.d.ts +0 -2
  915. package/dist/theme-lab/derive-state.test.d.ts.map +0 -1
  916. package/dist/theme-lab/theme-lab.test.d.ts +0 -2
  917. package/dist/theme-lab/theme-lab.test.d.ts.map +0 -1
  918. package/dist/tokens/build-fonts-css.test.d.ts +0 -2
  919. package/dist/tokens/build-fonts-css.test.d.ts.map +0 -1
  920. package/dist/tokens/build-radius-css.test.d.ts +0 -2
  921. package/dist/tokens/build-radius-css.test.d.ts.map +0 -1
  922. package/dist/tokens/chart-margin.test.d.ts +0 -2
  923. package/dist/tokens/chart-margin.test.d.ts.map +0 -1
  924. package/dist/tokens/density.test.d.ts +0 -2
  925. package/dist/tokens/density.test.d.ts.map +0 -1
  926. package/dist/tokens/derive-radius.test.d.ts +0 -2
  927. package/dist/tokens/derive-radius.test.d.ts.map +0 -1
  928. package/dist/tokens/derive.test.d.ts +0 -2
  929. package/dist/tokens/derive.test.d.ts.map +0 -1
  930. package/dist/tokens/palette.test.d.ts +0 -2
  931. package/dist/tokens/palette.test.d.ts.map +0 -1
  932. package/dist/tokens/text-scale.test.d.ts +0 -2
  933. package/dist/tokens/text-scale.test.d.ts.map +0 -1
  934. package/dist/vite-color-mix.test.d.ts +0 -2
  935. package/dist/vite-color-mix.test.d.ts.map +0 -1
  936. package/dist/vite.test.d.ts +0 -2
  937. package/dist/vite.test.d.ts.map +0 -1
  938. package/dist/widget-header/delta-badge.test.d.ts +0 -2
  939. package/dist/widget-header/delta-badge.test.d.ts.map +0 -1
  940. package/dist/widget-header/no-mantine.test.d.ts +0 -2
  941. package/dist/widget-header/no-mantine.test.d.ts.map +0 -1
  942. package/dist/widget-header/widget-header.test.d.ts +0 -2
  943. package/dist/widget-header/widget-header.test.d.ts.map +0 -1
  944. package/src/agent/adapter.test.ts +0 -1640
  945. package/src/agent/ai-sdk-transport.test.ts +0 -658
  946. package/src/agent/coalesce.test.ts +0 -387
  947. package/src/agent/foreign.test.ts +0 -51
  948. package/src/agent/id.test.ts +0 -169
  949. package/src/agent/merge.test.ts +0 -206
  950. package/src/agent/part-list.test.tsx +0 -112
  951. package/src/agent/parts.test.ts +0 -720
  952. package/src/agent/thread.test.ts +0 -220
  953. package/src/agent/transport.test.ts +0 -70
  954. package/src/agent/use-agent-stream.test.tsx +0 -287
  955. package/src/agent/use-agent-thread-runs.foreign.test.tsx +0 -138
  956. package/src/agent/use-agent-thread-runs.resume.test.tsx +0 -294
  957. package/src/agent/use-agent-thread-runs.test.tsx +0 -1120
  958. package/src/agent/use-agent-thread-runs.wedge.test.tsx +0 -387
  959. package/src/agent-chat/composer.test.tsx +0 -924
  960. package/src/agent-chat/relative-time.test.ts +0 -95
  961. package/src/agent-chat/thread-feed-row.test.tsx +0 -510
  962. package/src/agent-chat/thread-feed.test.tsx +0 -241
  963. package/src/agent-chat/thread-message.test.tsx +0 -1285
  964. package/src/agent-chat/thread-workspace.test.tsx +0 -169
  965. package/src/agent-chat/tool-chip.test.tsx +0 -139
  966. package/src/agent-chat/virtualize.type-guard.test.ts +0 -49
  967. package/src/charts/cursor/resolve.test.ts +0 -151
  968. package/src/charts/cursor/store.test.ts +0 -64
  969. package/src/charts/kinds/BandStrip.test.tsx +0 -282
  970. package/src/charts/kinds/Bars.test.tsx +0 -183
  971. package/src/charts/kinds/DualPanel.test.tsx +0 -527
  972. package/src/charts/kinds/MirroredBars.test.tsx +0 -232
  973. package/src/charts/kinds/MultiLine.test.tsx +0 -218
  974. package/src/charts/kinds/StackedArea.test.tsx +0 -114
  975. package/src/charts/kinds/ZonedLine.test.tsx +0 -147
  976. package/src/charts/layout/auto-margin.test.ts +0 -42
  977. package/src/charts/primitives/CartesianChart.test.tsx +0 -647
  978. package/src/charts/primitives/ChartCard.test.tsx +0 -66
  979. package/src/charts/primitives/ChartFrame.test.tsx +0 -142
  980. package/src/charts/primitives/ChartLegend.test.tsx +0 -78
  981. package/src/charts/primitives/ChartTooltip.test.tsx +0 -44
  982. package/src/charts/primitives/XZoneRects.test.tsx +0 -123
  983. package/src/charts/series.test.ts +0 -112
  984. package/src/charts/utils/domain.test.ts +0 -54
  985. package/src/charts/utils/measure-text.test.ts +0 -36
  986. package/src/cli/check-coverage.test.ts +0 -297
  987. package/src/cli/check-theme.test.ts +0 -837
  988. package/src/cli/help.test.ts +0 -170
  989. package/src/cli/init-sync.test.ts +0 -343
  990. package/src/cli/placement-engine.test.ts +0 -298
  991. package/src/cli/shipped-versions.test.ts +0 -83
  992. package/src/cli/tarball-parity.test.ts +0 -44
  993. package/src/cli/template-format.test.ts +0 -64
  994. package/src/cli/template-ledger.test.ts +0 -219
  995. package/src/cli/tokens-css.test.ts +0 -249
  996. package/src/cli/toolchain-wiring.test.ts +0 -1358
  997. package/src/cli/waiver-audit.test.ts +0 -215
  998. package/src/content/article-actions.test.ts +0 -78
  999. package/src/content/article-model.test.ts +0 -119
  1000. package/src/content/block-split.test.ts +0 -75
  1001. package/src/content/heading-components.test.tsx +0 -65
  1002. package/src/content/markdown.test.tsx +0 -603
  1003. package/src/content/prose.module.css.test.ts +0 -39
  1004. package/src/content/sanitize.test.ts +0 -659
  1005. package/src/content/slug.test.ts +0 -62
  1006. package/src/controls/actions.test.tsx +0 -252
  1007. package/src/controls/actions.type-guard.test.ts +0 -63
  1008. package/src/controls/control-group.test.tsx +0 -229
  1009. package/src/controls/controls.router.test.tsx +0 -637
  1010. package/src/controls/filter-set.test.tsx +0 -472
  1011. package/src/controls/peer-boundary.test.ts +0 -85
  1012. package/src/controls/props-contract.test.tsx +0 -106
  1013. package/src/controls/sync-button.test.tsx +0 -183
  1014. package/src/dashboard/query-state.test.tsx +0 -152
  1015. package/src/dashboard/settings-section.test.tsx +0 -56
  1016. package/src/dashboard/stat-card.test.tsx +0 -154
  1017. package/src/data/data-table.test.tsx +0 -434
  1018. package/src/guard/check-source.test.ts +0 -3355
  1019. package/src/guard/grace.test.ts +0 -149
  1020. package/src/guard/guard-hook.test.ts +0 -203
  1021. package/src/provider/index.test.tsx +0 -101
  1022. package/src/provider/lab-theme.test.ts +0 -147
  1023. package/src/query/error-message.test.ts +0 -67
  1024. package/src/router-tanstack/multi-search-param-store.test.ts +0 -124
  1025. package/src/router-tanstack/nav.test.ts +0 -111
  1026. package/src/router-tanstack/search-param-store.test.ts +0 -135
  1027. package/src/router-tanstack/search-store.router.test.tsx +0 -661
  1028. package/src/router-tanstack/search-store.test.ts +0 -418
  1029. package/src/router-tanstack/use-nav.test.tsx +0 -187
  1030. package/src/section/section.test.tsx +0 -204
  1031. package/src/shell/app-mobile-nav.test.tsx +0 -403
  1032. package/src/shell/app-sidebar.test.tsx +0 -509
  1033. package/src/shell/index.test.tsx +0 -428
  1034. package/src/shell/mobile-nav-model.test.ts +0 -517
  1035. package/src/shell/page-bar.test.tsx +0 -316
  1036. package/src/state/fields.test.tsx +0 -258
  1037. package/src/styles.floor.test.ts +0 -36
  1038. package/src/theme/border-coverage.test.ts +0 -272
  1039. package/src/theme/contrast.test.ts +0 -354
  1040. package/src/theme/ctl-theme.test.tsx +0 -275
  1041. package/src/theme/ctl-tier-coverage.test.ts +0 -170
  1042. package/src/theme/density-option.test.ts +0 -96
  1043. package/src/theme/density-relations.test.ts +0 -506
  1044. package/src/theme/derive-theme.test.ts +0 -101
  1045. package/src/theme/divider-law.test.ts +0 -259
  1046. package/src/theme/fonts-option.test.ts +0 -75
  1047. package/src/theme/icon-slot.test.tsx +0 -275
  1048. package/src/theme/layout-rhythm-css.test.ts +0 -72
  1049. package/src/theme/radius-option.test.ts +0 -86
  1050. package/src/theme/radius.test.ts +0 -142
  1051. package/src/theme/shadow-surfaces.test.ts +0 -488
  1052. package/src/theme/spacing.test.ts +0 -495
  1053. package/src/theme/use-basalt-spacing.test.tsx +0 -55
  1054. package/src/theme-lab/derive-controls.test.ts +0 -94
  1055. package/src/theme-lab/derive-state.test.ts +0 -71
  1056. package/src/theme-lab/theme-lab.test.ts +0 -46
  1057. package/src/tokens/build-fonts-css.test.ts +0 -52
  1058. package/src/tokens/build-radius-css.test.ts +0 -25
  1059. package/src/tokens/chart-margin.test.ts +0 -39
  1060. package/src/tokens/density.test.ts +0 -259
  1061. package/src/tokens/derive-radius.test.ts +0 -62
  1062. package/src/tokens/derive.test.ts +0 -30
  1063. package/src/tokens/palette.test.ts +0 -114
  1064. package/src/tokens/text-scale.test.ts +0 -51
  1065. package/src/vite-color-mix.test.ts +0 -46
  1066. package/src/vite.test.ts +0 -423
  1067. package/src/widget-header/delta-badge.test.tsx +0 -60
  1068. package/src/widget-header/no-mantine.test.ts +0 -33
  1069. package/src/widget-header/widget-header.test.tsx +0 -187
@@ -10,7 +10,7 @@
10
10
  * consumer.
11
11
  */
12
12
  import { useSyncExternalStore } from 'react'
13
- import { createPersistedState, readPersistedValue } from './persisted'
13
+ import { createPersistedState, readPersistedValue, writePersistedValue } from './persisted'
14
14
 
15
15
  // ── Store fields — the vocabulary both store factories share ──────────────────────────────────
16
16
 
@@ -48,6 +48,28 @@ export type ResolveLane<L> = {
48
48
  history: L extends { history: 'push' } ? 'push' : 'replace'
49
49
  }
50
50
 
51
+ /**
52
+ * A field's fallback: the value, or a THUNK evaluated at read time (`field.string({ fallback: () =>
53
+ * todayIso() })`). A thunk is re-evaluated on every read while nothing is written, and is never
54
+ * itself persisted — a write stores the value the control produced, like any other.
55
+ *
56
+ * The LOCAL and MEMORY lanes only. `createSearchStore` throws at definition for a thunk on a
57
+ * URL-lane field: `validateSearch` would evaluate it on every navigation and pin the result into the
58
+ * URL, so a deep link would carry a value nobody chose.
59
+ */
60
+ export type FieldFallback<T> = T | (() => T)
61
+
62
+ /** Resolves a per-preset window at call time. Returns ISO dates — what `toWindow` hands an API. */
63
+ export type RangeWindow = (now: Date) => { from: string; to: string }
64
+
65
+ /**
66
+ * Per-preset window resolvers for a range field. A preset WITH one resolves through `toWindow()` to
67
+ * `{ from, to }`; a preset without keeps `{ window: preset }` — which is what lets a derived preset
68
+ * (`3m`, `ytd`) live in the same field as a server-understood one (`7d`) instead of forcing a
69
+ * hand-rolled `presetToParams` beside the store.
70
+ */
71
+ export type RangeWindows<P extends string> = Partial<Record<P, RangeWindow>>
72
+
51
73
  /** The value of a range field: one preset, plus two ISO dates when the preset is `'custom'`. */
52
74
  export type RangeValue<P extends string> = {
53
75
  preset: P
@@ -61,14 +83,14 @@ export type RangeParams = { preset?: string; from?: string; to?: string }
61
83
  export type EnumField<T extends string = string, Ln extends ResolvedLane = ResolvedLane> = {
62
84
  readonly kind: 'enum'
63
85
  readonly values: readonly T[]
64
- readonly fallback: T
86
+ readonly fallback: FieldFallback<T>
65
87
  readonly lane: Ln
66
88
  }
67
89
 
68
90
  export type MultiField<T extends string = string, Ln extends ResolvedLane = ResolvedLane> = {
69
91
  readonly kind: 'multi'
70
92
  readonly values: readonly T[]
71
- readonly fallback: readonly T[]
93
+ readonly fallback: FieldFallback<readonly T[]>
72
94
  readonly lane: Ln
73
95
  }
74
96
 
@@ -77,42 +99,65 @@ export type RangeField<
77
99
  C extends boolean = boolean,
78
100
  Pm extends RangeParams = RangeParams,
79
101
  Ln extends ResolvedLane = ResolvedLane,
102
+ W extends string = never,
80
103
  > = {
81
104
  readonly kind: 'range'
82
105
  /** The declared presets — `'custom'` is NOT one of them, it is `custom: true`'s consequence. */
83
106
  readonly presets: readonly P[]
84
- readonly fallback: RangeValue<P>
107
+ readonly fallback: FieldFallback<RangeValue<P>>
85
108
  /** `true` → the preset `'custom'` plus `from`/`to` ISO dates are legal values. */
86
109
  readonly custom: C
87
110
  readonly params: Pm
111
+ /**
112
+ * The declared window resolvers, keyed by preset — `W` is exactly the presets that HAVE one, so
113
+ * `toWindow`'s return type can drop them from its `{ window }` branch and an API param type
114
+ * accepts the result with no cast.
115
+ *
116
+ * `W` defaults to `never` (`window: {}`), which is what keeps every `RangeField<P>` assignable to
117
+ * the widened `AnyField` a control's props take: a narrower resolver map is assignable to `{}`,
118
+ * and a widened handle's `toWindow` then excludes nothing rather than everything.
119
+ */
120
+ readonly window: RangeWindows<W>
88
121
  readonly lane: Ln
89
122
  }
90
123
 
91
124
  /**
92
125
  * The preset union a range field's VALUES range over: the declared presets, plus `'custom'` unless
93
- * the field opted out. `C` widened to `boolean` (a `RangeField<P>` in a control's props) keeps
94
- * `'custom'`, so a widened handle can still carry a custom window.
126
+ * the field opted out.
127
+ *
128
+ * `C` widened to `boolean` (a bare `RangeField<P>`) keeps `'custom'` — but a PROP typed that way
129
+ * accepts only a custom-capable handle, because the handle's setter is contravariant in the value:
130
+ * `field.range` without `custom: true` hands out a `RangeField<P, false>`, whose setter refuses a
131
+ * `'custom'` preset. A wrapper that must take any range handle is generic over the flag
132
+ * (`<P extends string, C extends boolean>` + `FieldHandle<RangeField<P, C>>`); one that only ever
133
+ * takes the preset-only shape pins `RangeField<P, false>`.
95
134
  */
96
135
  export type RangePresets<P, C> = (P & string) | (C extends false ? never : 'custom')
97
136
 
98
137
  export type NumberField<Ln extends ResolvedLane = ResolvedLane> = {
99
138
  readonly kind: 'number'
100
- readonly fallback: number
139
+ readonly fallback: FieldFallback<number>
101
140
  readonly min: number | undefined
102
141
  readonly max: number | undefined
103
142
  readonly int: boolean
143
+ /**
144
+ * The declared grain, ALREADY resolved — `field.number` fills in `1` for an `int: true` field
145
+ * that declared none, so the "an integer field steps by one" rule lives at that one call site and
146
+ * every reader (the handle, `NumberFilter`, `SliderControl`) reads a single answer.
147
+ */
148
+ readonly step: number | undefined
104
149
  readonly lane: Ln
105
150
  }
106
151
 
107
152
  export type BooleanField<Ln extends ResolvedLane = ResolvedLane> = {
108
153
  readonly kind: 'boolean'
109
- readonly fallback: boolean
154
+ readonly fallback: FieldFallback<boolean>
110
155
  readonly lane: Ln
111
156
  }
112
157
 
113
158
  export type StringField<Ln extends ResolvedLane = ResolvedLane> = {
114
159
  readonly kind: 'string'
115
- readonly fallback: string
160
+ readonly fallback: FieldFallback<string>
116
161
  readonly max: number | undefined
117
162
  readonly lane: Ln
118
163
  }
@@ -144,6 +189,31 @@ export type FieldValue<F extends AnyField> = F extends {
144
189
  ? string
145
190
  : never
146
191
 
192
+ /**
193
+ * The second, optional argument of a `FieldHandle` setter.
194
+ *
195
+ * @example field.tab.use()[1]('overview', { patch: { detailDate: undefined } })
196
+ */
197
+ export type FieldSetOptions = {
198
+ /**
199
+ * Extra search params merged into the SAME navigate as the field's own write — the URL lane only
200
+ * (a local/memory-lane write has no navigate to merge into, and ignores this). For keys the STORE
201
+ * DOES NOT OWN: clearing a sibling param the page put there (`{ detailDate: undefined }`) used to
202
+ * need a second `navigate` beside the setter, which either lost the field's write or produced two
203
+ * history entries. The field's own params always win, so a `patch` cannot corrupt the value being
204
+ * set.
205
+ *
206
+ * A key ANOTHER field of the same store owns is refused — it would reach the URL while the
207
+ * mirror kept the old value, so the next paramless visit and every `linkSearch` link disagree
208
+ * with the page the write happened on. `createSearchStore` throws in dev and logs in production;
209
+ * write that field through its own setter instead.
210
+ *
211
+ * A write from a route that does not validate the field persists only (A1) and drops the patch
212
+ * with it — there is no navigate to merge into. Dev warns once per field.
213
+ */
214
+ readonly patch?: Record<string, unknown>
215
+ }
216
+
147
217
  /** One option of an enum / multi / range field, labelled through `store.labels()`. */
148
218
  export type FieldOption = { value: string; label: string }
149
219
 
@@ -152,18 +222,63 @@ type RangeHandleExtras<F> = F extends {
152
222
  kind: 'range'
153
223
  presets: readonly (infer P)[]
154
224
  custom: infer C
225
+ window: RangeWindows<infer W>
155
226
  }
156
227
  ? {
157
228
  /**
158
229
  * The API-facing projection of a range value: a preset becomes `{ window }`, a custom range
159
230
  * becomes `{ from, to }`. Replaces every hand-rolled `presetToParams`.
231
+ *
232
+ * A preset declared with a `window` resolver (`field.range({ window: { '3m': ... } })`)
233
+ * becomes `{ from, to }` too — the resolver runs at CALL time with the current `Date`, so a
234
+ * derived window (`3m`, `ytd`) is never stale and never leaves the store.
235
+ *
236
+ * Those presets are EXCLUDED from the `{ window }` branch, so the result assigns to an API
237
+ * param type that only knows the server-understood windows with no cast — which is the half
238
+ * that lets a consumer delete the switch rather than move it. A `custom: true` field keeps
239
+ * `'custom'` in the union: a custom preset with no dates resolves to `{ window: 'custom' }`,
240
+ * so that one still needs a guard before it reaches such a type.
160
241
  */
161
242
  readonly toWindow: (
162
243
  v: RangeValue<RangePresets<P, C>>,
163
- ) => { window: RangePresets<P, C> } | { from: string; to: string }
244
+ ) => { window: Exclude<RangePresets<P, C>, W> } | { from: string; to: string }
164
245
  }
165
246
  : { readonly toWindow?: undefined }
166
247
 
248
+ /**
249
+ * A number handle's declared bounds, republished from the field — `RangeHandleExtras`' shape for the
250
+ * numeric kind, and there for the same reason: a control cannot ask the field descriptor anything,
251
+ * it only ever sees the handle.
252
+ *
253
+ * The codec has always CLAMPED to these on write, so before this the only way a `NumberFilter` could
254
+ * learn its own limits was for the call site to pass them a second time — a second answer to a
255
+ * question the field already owns, and one that silently stops matching the moment the field moves.
256
+ * With them on the handle the input can bound its own stepper, which turns the clamp from a
257
+ * correction the user watches happen into a value they cannot type in the first place.
258
+ *
259
+ * `int` is the third member because it is the same class of fact: it decides whether the stepper
260
+ * refuses decimals, and the codec already rejects a non-integer for that field. `step` is the
261
+ * fourth for the same reason, and it is where the "an `int` field steps by one" rule is RESOLVED —
262
+ * once, in `field.number`, rather than re-derived by every control that draws a stepper or a track.
263
+ */
264
+ type NumberHandleExtras<F> = F extends { kind: 'number' }
265
+ ? {
266
+ /** The field's `min`, or `undefined` when it declared none. Clamped on write regardless. */
267
+ readonly min: number | undefined
268
+ /** The field's `max`, or `undefined` when it declared none. Clamped on write regardless. */
269
+ readonly max: number | undefined
270
+ /** `field.number({ int: true })` — a non-integer is refused by the codec, not rounded. */
271
+ readonly int: boolean
272
+ /** The field's `step`, `1` for an `int` field that declared none, else `undefined`. */
273
+ readonly step: number | undefined
274
+ }
275
+ : {
276
+ readonly min?: undefined
277
+ readonly max?: undefined
278
+ readonly int?: undefined
279
+ readonly step?: undefined
280
+ }
281
+
167
282
  /**
168
283
  * The binding every basalt control takes instead of `value`/`onChange` (C2). One field, both lanes,
169
284
  * one resolution law. Handed out by `createSearchStore().field.<name>` /
@@ -179,12 +294,97 @@ export type FieldHandle<F extends AnyField> = {
179
294
  * so a control renders on a sibling or child route with no `from`), else localStorage, else the
180
295
  * fallback. Writes navigate when the matched route validates the param, then persist.
181
296
  */
182
- use(): readonly [FieldValue<F>, (next: FieldValue<F>) => void]
297
+ use(): readonly [FieldValue<F>, (next: FieldValue<F>, opts?: FieldSetOptions) => void]
298
+ /**
299
+ * UNSET the field — what a control's reset calls, and deliberately not `set(fallback)`. The
300
+ * persist lane DELETES the field's key from the mirror, the memory lane drops its value, and the
301
+ * URL lane navigates back to the fallback params (plus dropping the mirror key under it).
302
+ *
303
+ * Writing the fallback instead pins it: a THUNK fallback (`() => todayIso()`) resolves at the
304
+ * moment of the reset, so a reader who pressed `Reset all` today was handed today's date
305
+ * tomorrow, with the field counted as active in `Filters (n)`. Unsetting lets the fallback keep
306
+ * resolving, which is what `FieldFallback`'s contract says it does.
307
+ *
308
+ * Callable outside render (an event handler is the only realistic caller); on the URL lane it
309
+ * navigates through the last render of `use()`, so a handle that no mount has read clears the
310
+ * mirror only.
311
+ */
312
+ clear(): void
183
313
  isDefault(v: FieldValue<F>): boolean
184
- } & RangeHandleExtras<F>
314
+ } & RangeHandleExtras<F> &
315
+ NumberHandleExtras<F>
185
316
 
186
317
  // ── field.* — declarative field builders ──────────────────────────────────────────────────────
187
318
 
319
+ /**
320
+ * `field.range`'s options. `C` is the `custom` flag, pinned per overload — never inferred; `W` is
321
+ * inferred from `window`'s KEYS (constrained to the declared presets, so a typo is still an error
322
+ * here) and is what carries the resolved presets into `toWindow`'s return type.
323
+ */
324
+ type RangeOptions<P extends string, C extends boolean, Pm extends RangeParams, W extends P> = {
325
+ presets: readonly P[]
326
+ fallback: FieldFallback<NoInfer<P>>
327
+ custom?: C
328
+ params?: Pm
329
+ /** Per-preset window resolvers — the presets `toWindow()` answers with `{ from, to }`. */
330
+ window?: RangeWindows<W>
331
+ }
332
+
333
+ /**
334
+ * A time window: THREE URL params (preset + `from` + `to`, each renamable through `params`), so a
335
+ * consumer's existing deep links and loaders keep their shape. `custom: true` additionally
336
+ * allows the preset `'custom'` with two ISO dates. `window` resolves a DERIVED preset (`3m`, `ytd`)
337
+ * to `{ from, to }` through `toWindow()` while it stays one preset in the URL.
338
+ *
339
+ * A second `field.range` in the same store — or a second range store composed into the same
340
+ * route's `validateSearch` — MUST rename `from`/`to` via `params`: every range defaults to the
341
+ * literal param names `'from'`/`'to'`, and two fields silently sharing them makes the later one's
342
+ * `toSearch` overwrite the earlier one's dates. `createStoreCore` throws at definition for the
343
+ * in-store case; the cross-store case is not detectable by either store alone.
344
+ *
345
+ * THREE overloads, one per `custom` shape, because a single `custom?: C` signature is inferred
346
+ * against `AnyField` when the call sits inline in `createSearchStore({ fields })` — the contextual
347
+ * return type wins, `C` widens to `boolean`, and every value type gains a `'custom'` preset the
348
+ * field never allowed. Overloads have no `C` to widen: an omitted or `false` flag picks the first,
349
+ * a literal `true` the second, and a value typed `boolean` the third (widened, as declared).
350
+ */
351
+ function rangeField<
352
+ const P extends string,
353
+ const Pm extends RangeParams = RangeParams,
354
+ const L extends FieldLane = FieldLane,
355
+ const W extends P = never,
356
+ >(o: RangeOptions<P, false, Pm, W>, lane?: L): RangeField<P, false, Pm, ResolveLane<L>, W>
357
+ function rangeField<
358
+ const P extends string,
359
+ const Pm extends RangeParams = RangeParams,
360
+ const L extends FieldLane = FieldLane,
361
+ const W extends P = never,
362
+ >(o: RangeOptions<P, true, Pm, W>, lane?: L): RangeField<P, true, Pm, ResolveLane<L>, W>
363
+ function rangeField<
364
+ const P extends string,
365
+ const Pm extends RangeParams = RangeParams,
366
+ const L extends FieldLane = FieldLane,
367
+ const W extends P = never,
368
+ >(o: RangeOptions<P, boolean, Pm, W>, lane?: L): RangeField<P, boolean, Pm, ResolveLane<L>, W>
369
+ function rangeField(
370
+ o: RangeOptions<string, boolean, RangeParams, string>,
371
+ lane?: FieldLane,
372
+ ): RangeField<string, boolean, RangeParams, ResolvedLane, string> {
373
+ const { fallback } = o
374
+ return {
375
+ kind: 'range',
376
+ presets: o.presets,
377
+ // A thunk fallback stays a thunk — wrapped so the lazy value is read at the same moment every
378
+ // other lane reads one, not once here at definition.
379
+ fallback:
380
+ typeof fallback === 'function' ? () => ({ preset: fallback() }) : { preset: fallback },
381
+ custom: o.custom ?? false,
382
+ params: o.params ?? {},
383
+ window: o.window ?? {},
384
+ lane: resolveLane(lane),
385
+ }
386
+ }
387
+
188
388
  /**
189
389
  * The field vocabulary. Every builder returns plain declarative data — no closures, no router, no
190
390
  * storage — which is what lets one field definition drive `createSearchStore` (URL + storage) and
@@ -206,7 +406,7 @@ export const field = {
206
406
  /** A closed string enum — a tab, a compare mode, a single-select filter. */
207
407
  enum<const T extends string, const L extends FieldLane = FieldLane>(
208
408
  values: readonly T[],
209
- fallback: NoInfer<T>,
409
+ fallback: FieldFallback<NoInfer<T>>,
210
410
  lane?: L,
211
411
  ): EnumField<T, ResolveLane<L>> {
212
412
  return { kind: 'enum', values, fallback, lane: resolveLane(lane) as ResolveLane<L> }
@@ -215,47 +415,30 @@ export const field = {
215
415
  /** An any-of set over the same closed enum. Decoding is deduped and canonically re-sorted. */
216
416
  multi<const T extends string, const L extends FieldLane = FieldLane>(
217
417
  values: readonly T[],
218
- fallback: readonly NoInfer<T>[] = [],
418
+ fallback: FieldFallback<readonly NoInfer<T>[]> = [],
219
419
  lane?: L,
220
420
  ): MultiField<T, ResolveLane<L>> {
221
421
  return { kind: 'multi', values, fallback, lane: resolveLane(lane) as ResolveLane<L> }
222
422
  },
223
423
 
424
+ range: rangeField,
425
+
224
426
  /**
225
- * A time window: THREE URL params (preset + `from` + `to`, each renamable through `params`), so a
226
- * consumer's existing deep links and loaders keep their shape. `custom: true` additionally
227
- * allows the preset `'custom'` with two ISO dates.
427
+ * A number — pagination, a threshold, a weight. Out-of-range input clamps to `min`/`max`.
228
428
  *
229
- * A second `field.range` in the same store — or a second range store composed into the same
230
- * route's `validateSearch` — MUST rename `from`/`to` via `params`: every range defaults to the
231
- * literal param names `'from'`/`'to'`, and two fields silently sharing them makes the later one's
232
- * `toSearch` overwrite the earlier one's dates. `createStoreCore` throws at definition for the
233
- * in-store case; the cross-store case is not detectable by either store alone.
429
+ * `step` is the grain a stepper or a slider bound to this field moves by, and it is resolved
430
+ * HERE rather than at either control: an `int: true` field that declares no `step` steps by 1,
431
+ * which is the only sane grain for a field whose codec refuses a decimal — stating it once means
432
+ * `NumberFilter` and `SliderControl` cannot answer it differently.
234
433
  */
235
- range<
236
- const P extends string,
237
- const C extends boolean = false,
238
- const Pm extends RangeParams = RangeParams,
239
- const L extends FieldLane = FieldLane,
240
- >(
241
- o: { presets: readonly P[]; fallback: NoInfer<P>; custom?: C; params?: Pm },
242
- lane?: L,
243
- ): RangeField<P, C, Pm, ResolveLane<L>> {
244
- return {
245
- kind: 'range',
246
- presets: o.presets,
247
- fallback: { preset: o.fallback },
248
- // The only cast left, and it is narrow: `C` is inferred from this very literal, so the
249
- // runtime boolean IS `C` — `?? false` is what the compiler cannot see through.
250
- custom: (o.custom ?? false) as C,
251
- params: (o.params ?? {}) as Pm,
252
- lane: resolveLane(lane) as ResolveLane<L>,
253
- }
254
- },
255
-
256
- /** A number — pagination, a threshold. Out-of-range input clamps to `min`/`max`. */
257
434
  number<const L extends FieldLane = FieldLane>(
258
- o: { fallback: number; min?: number; max?: number; int?: boolean },
435
+ o: {
436
+ fallback: FieldFallback<number>
437
+ min?: number
438
+ max?: number
439
+ int?: boolean
440
+ step?: number
441
+ },
259
442
  lane?: L,
260
443
  ): NumberField<ResolveLane<L>> {
261
444
  return {
@@ -264,13 +447,14 @@ export const field = {
264
447
  min: o.min,
265
448
  max: o.max,
266
449
  int: o.int === true,
450
+ step: o.step ?? (o.int === true ? 1 : undefined),
267
451
  lane: resolveLane(lane) as ResolveLane<L>,
268
452
  }
269
453
  },
270
454
 
271
455
  /** A toggle. Accepts `true`/`false` and the strings `'true'`/`'false'` from a hand-typed URL. */
272
456
  boolean<const L extends FieldLane = FieldLane>(
273
- fallback: boolean,
457
+ fallback: FieldFallback<boolean>,
274
458
  lane?: L,
275
459
  ): BooleanField<ResolveLane<L>> {
276
460
  return { kind: 'boolean', fallback, lane: resolveLane(lane) as ResolveLane<L> }
@@ -278,7 +462,7 @@ export const field = {
278
462
 
279
463
  /** Free text — a search box. Defaults to `history: 'replace'` like every other field. */
280
464
  string<const L extends FieldLane = FieldLane>(
281
- o?: { fallback?: string; max?: number },
465
+ o?: { fallback?: FieldFallback<string>; max?: number },
282
466
  lane?: L,
283
467
  ): StringField<ResolveLane<L>> {
284
468
  return {
@@ -358,7 +542,25 @@ export type FieldCodec = {
358
542
  * route does not, and a write there persists only (A1).
359
543
  */
360
544
  readonly primary: string
545
+ /**
546
+ * The fallback, ALREADY resolved — a getter, because `field.*({ fallback: () => … })` is a thunk
547
+ * that must run at read time and re-run while nothing is written. Every call site reads it as a
548
+ * plain value, which is why the laziness is invisible past this line.
549
+ */
361
550
  readonly fallback: unknown
551
+ /** Range only: the per-preset window resolvers `toWindow` answers a derived preset through. */
552
+ readonly windows?: RangeWindows<string>
553
+ /**
554
+ * Number only: the declared bounds and grain the codec clamps to, republished so `handle` can put
555
+ * them on the handle. The codec is the only thing that reads the field descriptor, so a control
556
+ * that needs a limit has to be handed it from here — see {@link NumberHandleExtras}.
557
+ */
558
+ readonly bounds?: {
559
+ readonly min: number | undefined
560
+ readonly max: number | undefined
561
+ readonly int: boolean
562
+ readonly step: number | undefined
563
+ }
362
564
  /**
363
565
  * Validate a STORED (or caller-supplied) value. `null` = unusable.
364
566
  *
@@ -376,6 +578,14 @@ export type FieldCodec = {
376
578
  readonly optionValues: readonly string[]
377
579
  }
378
580
 
581
+ /**
582
+ * Resolve a possibly-lazy fallback. `typeof === 'function'` is an exact discriminator here: no field
583
+ * kind has a function as a legal VALUE, so a function can only ever be the thunk form.
584
+ */
585
+ function resolveFallback(raw: unknown): unknown {
586
+ return typeof raw === 'function' ? (raw as () => unknown)() : raw
587
+ }
588
+
379
589
  const ISO_DATE_RE = /^\d{4}-\d{2}-\d{2}(?:T[\d:.]+(?:Z|[+-]\d{2}:\d{2})?)?$/
380
590
 
381
591
  function isIsoDate(raw: unknown): raw is string {
@@ -467,7 +677,10 @@ export function resolveFieldCodec(
467
677
  lane: f.lane,
468
678
  params: [presetParam, fromParam, toParam],
469
679
  primary: presetParam,
470
- fallback: f.fallback,
680
+ get fallback() {
681
+ return resolveFallback(f.fallback)
682
+ },
683
+ windows: f.window,
471
684
  decode,
472
685
  fromSearch: (search) =>
473
686
  decode({
@@ -507,7 +720,13 @@ export function resolveFieldCodec(
507
720
  if (f.max !== undefined && value > f.max) value = f.max
508
721
  return value
509
722
  }
510
- return single(name, f, decode)
723
+ // The same values the clamp above reads (plus the already-resolved `step`), handed on so the
724
+ // CONTROL can bound its input rather than watch the clamp correct it after the fact. Threaded
725
+ // THROUGH `single` rather than spread onto its result: `fallback` is a getter, and a spread
726
+ // would evaluate it once here and freeze a thunk fallback at definition.
727
+ return single(name, f, decode, {
728
+ bounds: { min: f.min, max: f.max, int: f.int, step: f.step },
729
+ })
511
730
  }
512
731
  case 'boolean': {
513
732
  return single(name, f, decodeBoolean)
@@ -525,7 +744,14 @@ export function resolveFieldCodec(
525
744
  }
526
745
  }
527
746
 
528
- /** Codec shell for every kind that owns exactly one URL param. */
747
+ /**
748
+ * Codec shell for every kind that owns exactly one URL param.
749
+ *
750
+ * NEVER spread the returned object: `fallback` is a GETTER over a possibly-lazy fallback, and an
751
+ * object spread evaluates it once and copies the result as a plain value — which froze the number
752
+ * kind's thunk fallback at store definition for one minor. Anything a kind needs to add goes
753
+ * through `extra`.
754
+ */
529
755
  function single(
530
756
  name: string,
531
757
  f: AnyField,
@@ -535,6 +761,8 @@ function single(
535
761
  equals?: (a: unknown, b: unknown) => boolean
536
762
  /** URL-side decoder when it differs from the storage-side one (multi, legacy layout only). */
537
763
  decodeUrl?: (raw: unknown) => unknown
764
+ /** Number only: the declared bounds and grain, republished onto the handle. */
765
+ bounds?: FieldCodec['bounds']
538
766
  },
539
767
  ): FieldCodec {
540
768
  const decodeUrl = extra?.decodeUrl ?? decode
@@ -543,7 +771,10 @@ function single(
543
771
  lane: f.lane,
544
772
  params: [name],
545
773
  primary: name,
546
- fallback: f.fallback,
774
+ get fallback() {
775
+ return resolveFallback(f.fallback)
776
+ },
777
+ ...(extra?.bounds !== undefined && { bounds: extra.bounds }),
547
778
  decode,
548
779
  fromSearch: (search) => decodeUrl(search[name]),
549
780
  toSearch: (value) => ({ [name]: value }),
@@ -556,6 +787,17 @@ function single(
556
787
 
557
788
  type StoreRecord = Record<string, unknown>
558
789
 
790
+ /**
791
+ * A field's write, untyped — the shape both factories build and `handle` hands out. `opts` is the
792
+ * public `FieldSetOptions`; only the URL lane can act on it.
793
+ *
794
+ * @internal — see `FieldCodec`.
795
+ */
796
+ export type FieldWrite = (next: unknown, opts?: FieldSetOptions) => void
797
+
798
+ /** One field's `use()`, untyped. @internal — see `FieldCodec`. */
799
+ export type FieldUse = () => readonly [unknown, FieldWrite]
800
+
559
801
  /** One named field plus its codec, in declaration order. @internal — see `FieldCodec`. */
560
802
  export type StoreEntry = { readonly name: string; readonly codec: FieldCodec }
561
803
 
@@ -594,19 +836,25 @@ export type StoreCore = {
594
836
  * Lives here rather than in either factory because BOTH have such a field: `createLocalStore`'s
595
837
  * `persist: false`, and `createSearchStore`'s `{ url: false, persist: false }`.
596
838
  */
597
- memoryUse(entry: StoreEntry): () => readonly [unknown, (next: unknown) => void]
839
+ memoryUse(entry: StoreEntry): FieldUse
598
840
  /** The memory lane's value for one field, resolved — its fallback while nothing was written. */
599
841
  readMemoryValue(entry: StoreEntry): unknown
600
842
  /** Subscribes to the whole memory lane. The snapshot is a write counter, so it is always stable. */
601
843
  useMemoryVersion(): number
602
844
  /** Drops every memory value, so the next read resolves to the fallback. What `useReset` calls. */
603
845
  resetMemory(): void
846
+ /**
847
+ * Deletes ONE field's key from the localStorage record, so the next read falls through to the
848
+ * live fallback. Not a hook: `FieldHandle.clear()` runs in an event handler, where the persisted
849
+ * setter from `usePersistedRecord()` is not in reach — it writes through the same envelope and
850
+ * wakes the same per-key listeners (`writePersistedValue`).
851
+ */
852
+ clearField(name: string): void
853
+ /** The memory lane's half of the same: drops ONE field's value. */
854
+ clearMemory(name: string): void
604
855
  /** Every stored field, flattened into URL-param shape, `undefined` entries dropped. */
605
856
  readStoredFlat(): StoreRecord
606
- handle(
607
- entry: StoreEntry,
608
- use: () => readonly [unknown, (next: unknown) => void],
609
- ): FieldHandle<AnyField>
857
+ handle(entry: StoreEntry, use: FieldUse, clear: () => void): FieldHandle<AnyField>
610
858
  }
611
859
 
612
860
  function isRecord(raw: unknown): raw is StoreRecord {
@@ -650,6 +898,7 @@ function createMemoryLane(): {
650
898
  getVersion: () => number
651
899
  resolve: (entry: StoreEntry) => unknown
652
900
  write: (name: string, value: unknown) => void
901
+ remove: (name: string) => void
653
902
  clear: () => void
654
903
  } {
655
904
  const values = new Map<string, unknown>()
@@ -679,6 +928,10 @@ function createMemoryLane(): {
679
928
  values.set(name, value)
680
929
  bump()
681
930
  },
931
+ remove: (name) => {
932
+ if (!values.delete(name)) return
933
+ bump()
934
+ },
682
935
  clear: () => {
683
936
  if (values.size === 0) return
684
937
  values.clear()
@@ -744,6 +997,14 @@ export function createStoreCore(o: StoreCoreOptions): StoreCore {
744
997
  return entry.codec.optionValues.map((value) => ({ value, label: map?.[value] ?? value }))
745
998
  }
746
999
 
1000
+ const clearField = (name: string): void => {
1001
+ const record = readRecord()
1002
+ if (!Object.hasOwn(record, name)) return
1003
+ const next = { ...record }
1004
+ delete next[name]
1005
+ writePersistedValue(o.key, version, fromRecord(next))
1006
+ }
1007
+
747
1008
  const writeField = (
748
1009
  setRecord: (next: StoreRecord) => void,
749
1010
  name: string,
@@ -754,30 +1015,50 @@ export function createStoreCore(o: StoreCoreOptions): StoreCore {
754
1015
  setRecord({ ...readRecord(), [name]: value })
755
1016
  }
756
1017
 
757
- const handle = (
758
- entry: StoreEntry,
759
- use: () => readonly [unknown, (next: unknown) => void],
760
- ): FieldHandle<AnyField> => {
1018
+ const handle = (entry: StoreEntry, use: FieldUse, clear: () => void): FieldHandle<AnyField> => {
761
1019
  const { codec } = entry
762
1020
  const built: Record<string, unknown> = {
763
1021
  kind: codec.kind,
764
- fallback: codec.fallback,
765
1022
  use,
1023
+ clear,
766
1024
  isDefault: (v: unknown) => codec.equals(v, codec.fallback),
767
1025
  }
768
1026
  if (codec.kind === 'range') {
769
- built['toWindow'] = (v: RangeValue<string>) =>
770
- v.preset === 'custom' && v.from !== undefined && v.to !== undefined
771
- ? { from: v.from, to: v.to }
772
- : { window: v.preset }
1027
+ built['toWindow'] = (v: RangeValue<string>) => {
1028
+ if (v.preset === 'custom' && v.from !== undefined && v.to !== undefined) {
1029
+ return { from: v.from, to: v.to }
1030
+ }
1031
+ // `Object.hasOwn`, not a bare lookup: a preset named like an Object.prototype member
1032
+ // (`toString`) would otherwise resolve to that method and be CALLED.
1033
+ const windows = codec.windows
1034
+ if (windows !== undefined && Object.hasOwn(windows, v.preset)) {
1035
+ const resolver = windows[v.preset]
1036
+ if (resolver !== undefined) return resolver(new Date())
1037
+ }
1038
+ return { window: v.preset }
1039
+ }
1040
+ }
1041
+ if (codec.kind === 'number') {
1042
+ // Plain properties, not getters: unlike `options` (relabelled by `labels()` after the handles
1043
+ // exist) and `fallback` (possibly a thunk), a field's bounds are fixed at definition.
1044
+ const bounds = codec.bounds
1045
+ built['min'] = bounds?.min
1046
+ built['max'] = bounds?.max
1047
+ built['int'] = bounds?.int ?? false
1048
+ built['step'] = bounds?.step
773
1049
  }
774
- // A GETTER, not a snapshot, and installed with defineProperty rather than declared in the
1050
+ // GETTERS, not snapshots, and installed with defineProperty rather than declared in the
775
1051
  // literal: `labels()` runs on the store after the handles exist, and an object spread would
776
- // evaluate the getter once at spread time and freeze the unlabelled options.
1052
+ // evaluate the getter once at spread time and freeze the unlabelled options. `fallback` is a
1053
+ // getter for the same class of reason — a lazy fallback is resolved per read, not per handle.
777
1054
  Object.defineProperty(built, 'options', {
778
1055
  enumerable: true,
779
1056
  get: (): readonly FieldOption[] => optionsFor(entry),
780
1057
  })
1058
+ Object.defineProperty(built, 'fallback', {
1059
+ enumerable: true,
1060
+ get: (): unknown => codec.fallback,
1061
+ })
781
1062
  return built as unknown as FieldHandle<AnyField>
782
1063
  }
783
1064
 
@@ -802,6 +1083,8 @@ export function createStoreCore(o: StoreCoreOptions): StoreCore {
802
1083
  useMemoryVersion: () =>
803
1084
  useSyncExternalStore(memory.subscribe, memory.getVersion, memory.getVersion),
804
1085
  resetMemory: () => memory.clear(),
1086
+ clearField,
1087
+ clearMemory: (name) => memory.remove(name),
805
1088
  setLabels(map) {
806
1089
  for (const [name, entry] of Object.entries(map)) {
807
1090
  if (entry !== undefined) labels.set(name, entry)
@@ -848,6 +1131,10 @@ export type LocalStore<S extends Record<string, AnyField>> = {
848
1131
  * That is the honest home for a value a reader should not be handed back tomorrow (a scratch
849
1132
  * comparison, a temporary drill-down) without dropping to `useState` and losing the handle.
850
1133
  *
1134
+ * A fallback may be a THUNK (`field.string({ fallback: () => todayIso() })`) — resolved at read
1135
+ * time, re-resolved while nothing is written, and never persisted on its own. Every lane here
1136
+ * qualifies; `createSearchStore` allows it off the URL lane only, and throws otherwise.
1137
+ *
851
1138
  * @example
852
1139
  * const chart = createLocalStore({
853
1140
  * key: 'momentum-chart',
@@ -875,8 +1162,12 @@ export function createLocalStore<const S extends Record<string, AnyField>>(o: {
875
1162
 
876
1163
  const field = {} as { [K in keyof S]: FieldHandle<S[K]> }
877
1164
  for (const entry of core.entries) {
878
- const use = entry.codec.lane.persist ? persistedUse(entry) : core.memoryUse(entry)
879
- field[entry.name as keyof S] = core.handle(entry, use) as unknown as FieldHandle<S[keyof S]>
1165
+ const persisted = entry.codec.lane.persist
1166
+ const use = persisted ? persistedUse(entry) : core.memoryUse(entry)
1167
+ const clear = persisted ? () => core.clearField(entry.name) : () => core.clearMemory(entry.name)
1168
+ field[entry.name as keyof S] = core.handle(entry, use, clear) as unknown as FieldHandle<
1169
+ S[keyof S]
1170
+ >
880
1171
  }
881
1172
 
882
1173
  const store: LocalStore<S> = {