basalt-ui 1.30.2 → 1.31.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 (334) hide show
  1. package/AGENTS.md +1 -1
  2. package/CHANGELOG.md +31 -0
  3. package/MIGRATING.md +172 -12
  4. package/agent/rules/basalt-controls.md +19 -19
  5. package/agent/rules/basalt-mantine.md +1 -1
  6. package/configs/oxlint-plugin.js +254 -4
  7. package/configs/oxlint-plugin.test.ts +145 -2
  8. package/configs/oxlint.json +2 -1
  9. package/dist/agent-chat/composer.d.ts.map +1 -1
  10. package/dist/agent-chat/composer.js +41 -43
  11. package/dist/agent-chat/thread-workspace.d.ts +2 -2
  12. package/dist/agent-chat/thread-workspace.d.ts.map +1 -1
  13. package/dist/agent-chat/thread-workspace.js +3 -4
  14. package/dist/agent-chat/use-keyboard-inset.d.ts +2 -0
  15. package/dist/agent-chat/use-keyboard-inset.d.ts.map +1 -0
  16. package/dist/agent-chat/use-keyboard-inset.js +34 -0
  17. package/dist/charts/cursor/touch-pin.d.ts +45 -0
  18. package/dist/charts/cursor/touch-pin.d.ts.map +1 -0
  19. package/dist/charts/cursor/touch-pin.js +79 -0
  20. package/dist/charts/hooks/use-discrete-cursor.d.ts +66 -0
  21. package/dist/charts/hooks/use-discrete-cursor.d.ts.map +1 -0
  22. package/dist/charts/hooks/use-discrete-cursor.js +198 -0
  23. package/dist/charts/hooks/use-hysteresis.d.ts +18 -0
  24. package/dist/charts/hooks/use-hysteresis.d.ts.map +1 -0
  25. package/dist/charts/hooks/use-hysteresis.js +12 -0
  26. package/dist/charts/hooks/useBandPlot.d.ts +7 -0
  27. package/dist/charts/hooks/useBandPlot.d.ts.map +1 -1
  28. package/dist/charts/hooks/useBandPlot.js +62 -18
  29. package/dist/charts/hooks/useChartCursor.d.ts +40 -11
  30. package/dist/charts/hooks/useChartCursor.d.ts.map +1 -1
  31. package/dist/charts/hooks/useChartCursor.js +102 -11
  32. package/dist/charts/index.d.ts +0 -1
  33. package/dist/charts/index.d.ts.map +1 -1
  34. package/dist/charts/index.js +0 -10
  35. package/dist/charts/kinds/BandStrip.d.ts.map +1 -1
  36. package/dist/charts/kinds/BandStrip.js +54 -41
  37. package/dist/charts/kinds/Donut.d.ts +9 -3
  38. package/dist/charts/kinds/Donut.d.ts.map +1 -1
  39. package/dist/charts/kinds/Donut.js +110 -48
  40. package/dist/charts/kinds/DualPanel.d.ts.map +1 -1
  41. package/dist/charts/kinds/DualPanel.js +145 -131
  42. package/dist/charts/kinds/Heatmap.d.ts +7 -0
  43. package/dist/charts/kinds/Heatmap.d.ts.map +1 -1
  44. package/dist/charts/kinds/Heatmap.js +37 -16
  45. package/dist/charts/kinds/MirroredBars.d.ts.map +1 -1
  46. package/dist/charts/kinds/MirroredBars.js +83 -68
  47. package/dist/charts/kinds/donut-layout.d.ts +47 -0
  48. package/dist/charts/kinds/donut-layout.d.ts.map +1 -0
  49. package/dist/charts/kinds/donut-layout.js +52 -0
  50. package/dist/charts/layout/auto-margin.d.ts +7 -2
  51. package/dist/charts/layout/auto-margin.d.ts.map +1 -1
  52. package/dist/charts/layout/auto-margin.js +12 -3
  53. package/dist/charts/layout/end-labels.d.ts +64 -0
  54. package/dist/charts/layout/end-labels.d.ts.map +1 -0
  55. package/dist/charts/layout/end-labels.js +76 -0
  56. package/dist/charts/primitives/Axes.d.ts +32 -4
  57. package/dist/charts/primitives/Axes.d.ts.map +1 -1
  58. package/dist/charts/primitives/Axes.js +62 -16
  59. package/dist/charts/primitives/CartesianChart.d.ts +7 -6
  60. package/dist/charts/primitives/CartesianChart.d.ts.map +1 -1
  61. package/dist/charts/primitives/CartesianChart.js +271 -125
  62. package/dist/charts/primitives/ChartCard.d.ts +0 -14
  63. package/dist/charts/primitives/ChartCard.d.ts.map +1 -1
  64. package/dist/charts/primitives/ChartCard.js +74 -21
  65. package/dist/charts/primitives/ChartFrame.d.ts +28 -22
  66. package/dist/charts/primitives/ChartFrame.d.ts.map +1 -1
  67. package/dist/charts/primitives/ChartFrame.js +133 -34
  68. package/dist/charts/primitives/ChartLegend.d.ts +19 -15
  69. package/dist/charts/primitives/ChartLegend.d.ts.map +1 -1
  70. package/dist/charts/primitives/ChartLegend.js +212 -71
  71. package/dist/charts/primitives/ChartTooltip.d.ts.map +1 -1
  72. package/dist/charts/primitives/ChartTooltip.js +4 -3
  73. package/dist/charts/primitives/Crosshair.js +2 -2
  74. package/dist/charts/primitives/HoverOverlay.d.ts +6 -1
  75. package/dist/charts/primitives/HoverOverlay.d.ts.map +1 -1
  76. package/dist/charts/primitives/HoverOverlay.js +37 -26
  77. package/dist/charts/primitives/HoverOverlay.module.css +13 -0
  78. package/dist/charts/primitives/HoverOverlay.module.css.d.ts +8 -0
  79. package/dist/charts/primitives/chart-card-context.d.ts +29 -0
  80. package/dist/charts/primitives/chart-card-context.d.ts.map +1 -0
  81. package/dist/charts/primitives/chart-card-context.js +13 -0
  82. package/dist/charts/primitives/chart-frame-layout.d.ts +93 -113
  83. package/dist/charts/primitives/chart-frame-layout.d.ts.map +1 -1
  84. package/dist/charts/primitives/chart-frame-layout.js +76 -29
  85. package/dist/charts/primitives/chart-layout.d.ts +112 -0
  86. package/dist/charts/primitives/chart-layout.d.ts.map +1 -0
  87. package/dist/charts/primitives/chart-layout.js +175 -0
  88. package/dist/charts/primitives/chart-tier.d.ts +13 -11
  89. package/dist/charts/primitives/chart-tier.d.ts.map +1 -1
  90. package/dist/charts/primitives/chart-tier.js +42 -13
  91. package/dist/charts/series.d.ts +4 -1
  92. package/dist/charts/series.d.ts.map +1 -1
  93. package/dist/charts/utils/ticks.d.ts +27 -8
  94. package/dist/charts/utils/ticks.d.ts.map +1 -1
  95. package/dist/charts/utils/ticks.js +35 -11
  96. package/dist/common/errors.d.ts +11 -1
  97. package/dist/common/errors.d.ts.map +1 -1
  98. package/dist/common/errors.js +16 -2
  99. package/dist/common/hit-floor.d.ts +10 -0
  100. package/dist/common/hit-floor.d.ts.map +1 -0
  101. package/dist/common/hit-floor.js +6 -0
  102. package/dist/{shell → common}/isomorphic-layout-effect.d.ts +4 -3
  103. package/dist/common/isomorphic-layout-effect.d.ts.map +1 -0
  104. package/dist/common/use-measured-widths.d.ts +37 -0
  105. package/dist/common/use-measured-widths.d.ts.map +1 -0
  106. package/dist/common/use-measured-widths.js +51 -0
  107. package/dist/common/use-media-query.d.ts +6 -0
  108. package/dist/common/use-media-query.d.ts.map +1 -0
  109. package/dist/common/use-media-query.js +40 -0
  110. package/dist/common/validate.d.ts +9 -0
  111. package/dist/common/validate.d.ts.map +1 -1
  112. package/dist/common/validate.js +9 -4
  113. package/dist/content/article-layout.d.ts +4 -2
  114. package/dist/content/article-layout.d.ts.map +1 -1
  115. package/dist/content/article-layout.js +43 -3
  116. package/dist/content/article-layout.module.css +45 -4
  117. package/dist/content/article-layout.module.css.d.ts +3 -0
  118. package/dist/content/code-block.d.ts.map +1 -1
  119. package/dist/content/code-block.js +40 -2
  120. package/dist/content/code-block.module.css +32 -2
  121. package/dist/content/prose.module.css +13 -8
  122. package/dist/controls/actions.d.ts +29 -6
  123. package/dist/controls/actions.d.ts.map +1 -1
  124. package/dist/controls/actions.js +158 -27
  125. package/dist/controls/actions.module.css +14 -1
  126. package/dist/controls/actions.module.css.d.ts +1 -0
  127. package/dist/controls/controls.module.css +8 -31
  128. package/dist/controls/enum-filter.js +2 -2
  129. package/dist/controls/filter-context.d.ts +10 -0
  130. package/dist/controls/filter-context.d.ts.map +1 -1
  131. package/dist/controls/filter-context.js +2 -0
  132. package/dist/controls/filter-pill.d.ts.map +1 -1
  133. package/dist/controls/filter-pill.js +1 -0
  134. package/dist/controls/index.d.ts +1 -1
  135. package/dist/controls/index.d.ts.map +1 -1
  136. package/dist/controls/index.js +0 -2
  137. package/dist/controls/multi-select-filter.js +2 -2
  138. package/dist/controls/sync-button.module.css +1 -1
  139. package/dist/dashboard/section.d.ts.map +1 -1
  140. package/dist/dashboard/section.js +1 -0
  141. package/dist/dashboard/section.module.css +1 -26
  142. package/dist/dashboard/stat-card.d.ts +1 -1
  143. package/dist/dashboard/stat-card.d.ts.map +1 -1
  144. package/dist/dashboard/stat-card.js +4 -1
  145. package/dist/dashboard/stat-card.module.css +6 -9
  146. package/dist/dashboard/stat-group.module.css +16 -4
  147. package/dist/dashboard/widget-grid.d.ts.map +1 -1
  148. package/dist/dashboard/widget-header.d.ts +14 -4
  149. package/dist/dashboard/widget-header.d.ts.map +1 -1
  150. package/dist/dashboard/widget-header.js +23 -6
  151. package/dist/dashboard/widget-header.module.css +145 -133
  152. package/dist/dashboard/widget-header.module.css.d.ts +2 -0
  153. package/dist/data/data-table.d.ts +23 -0
  154. package/dist/data/data-table.d.ts.map +1 -1
  155. package/dist/data/data-table.js +339 -141
  156. package/dist/data/data-table.module.css +94 -0
  157. package/dist/data/data-table.module.css.d.ts +11 -0
  158. package/dist/data/virtual-list.d.ts.map +1 -1
  159. package/dist/data/virtual-list.js +10 -0
  160. package/dist/forms/form-layout.d.ts.map +1 -1
  161. package/dist/forms/form-layout.js +3 -3
  162. package/dist/forms/form-layout.module.css +30 -5
  163. package/dist/forms/form-layout.module.css.d.ts +1 -0
  164. package/dist/guard/index.d.ts +8 -2
  165. package/dist/guard/index.d.ts.map +1 -1
  166. package/dist/guard/index.js +67 -2
  167. package/dist/guard/types.d.ts +3 -3
  168. package/dist/guard/types.d.ts.map +1 -1
  169. package/dist/index.d.ts +1 -1
  170. package/dist/index.d.ts.map +1 -1
  171. package/dist/index.js +3 -1
  172. package/dist/provider/index.d.ts +20 -1
  173. package/dist/provider/index.d.ts.map +1 -1
  174. package/dist/provider/index.js +22 -2
  175. package/dist/shell/app-brand.d.ts.map +1 -1
  176. package/dist/shell/app-brand.js +1 -0
  177. package/dist/shell/app-brand.module.css +2 -2
  178. package/dist/shell/app-header.module.css +18 -8
  179. package/dist/shell/app-main.module.css +54 -3
  180. package/dist/shell/app-main.module.css.d.ts +1 -0
  181. package/dist/shell/app-mobile-nav.module.css +16 -4
  182. package/dist/shell/app-sidebar.module.css +4 -6
  183. package/dist/shell/index.d.ts +12 -0
  184. package/dist/shell/index.d.ts.map +1 -1
  185. package/dist/shell/index.js +57 -16
  186. package/dist/shell/mobile-nav-model.d.ts +1 -1
  187. package/dist/shell/page-aside.d.ts +22 -3
  188. package/dist/shell/page-aside.d.ts.map +1 -1
  189. package/dist/shell/page-aside.js +27 -13
  190. package/dist/shell/page-bar.d.ts.map +1 -1
  191. package/dist/shell/page-bar.js +10 -5
  192. package/dist/shell/page-bar.module.css +10 -34
  193. package/dist/shell/use-breakpoint.d.ts +3 -4
  194. package/dist/shell/use-breakpoint.d.ts.map +1 -1
  195. package/dist/shell/use-breakpoint.js +3 -25
  196. package/dist/shell/use-size-class.d.ts +6 -0
  197. package/dist/shell/use-size-class.d.ts.map +1 -0
  198. package/dist/shell/use-size-class.js +19 -0
  199. package/dist/state/persisted-or-local.d.ts +4 -1
  200. package/dist/state/persisted-or-local.d.ts.map +1 -1
  201. package/dist/state/persisted-or-local.js +4 -3
  202. package/dist/state/persisted.d.ts +10 -0
  203. package/dist/state/persisted.d.ts.map +1 -1
  204. package/dist/state/persisted.js +44 -14
  205. package/dist/styles.css +41 -0
  206. package/dist/surfaces.d.ts +4 -4
  207. package/dist/surfaces.d.ts.map +1 -1
  208. package/dist/surfaces.js +11 -3
  209. package/dist/theme/controls.module.css +7 -0
  210. package/dist/theme/ctl-theme.d.ts +1 -0
  211. package/dist/theme/ctl-theme.d.ts.map +1 -1
  212. package/dist/theme/ctl-theme.js +12 -4
  213. package/dist/theme/floating.module.css +36 -0
  214. package/dist/theme/floating.module.css.d.ts +3 -0
  215. package/dist/theme/index.d.ts +2 -2
  216. package/dist/theme/index.d.ts.map +1 -1
  217. package/dist/theme/index.js +34 -5
  218. package/dist/theme/nav-link.module.css +7 -0
  219. package/dist/tokens/index.d.ts +7 -16
  220. package/dist/tokens/index.d.ts.map +1 -1
  221. package/dist/tokens/index.js +23 -28
  222. package/dist/tokens/palette.d.ts +5 -27
  223. package/dist/tokens/palette.d.ts.map +1 -1
  224. package/dist/tokens/palette.js +8 -30
  225. package/dist/tokens/size-classes.d.ts +40 -0
  226. package/dist/tokens/size-classes.d.ts.map +1 -0
  227. package/dist/tokens/size-classes.js +29 -0
  228. package/dist/tokens.css +8 -4
  229. package/llms.txt +3 -3
  230. package/package.json +17 -17
  231. package/src/agent-chat/composer.tsx +74 -47
  232. package/src/agent-chat/thread-workspace.tsx +8 -11
  233. package/src/agent-chat/use-keyboard-inset.ts +68 -0
  234. package/src/charts/cursor/touch-pin.ts +138 -0
  235. package/src/charts/hooks/use-discrete-cursor.ts +335 -0
  236. package/src/charts/hooks/use-hysteresis.ts +26 -0
  237. package/src/charts/hooks/useBandPlot.ts +90 -27
  238. package/src/charts/hooks/useChartCursor.ts +211 -26
  239. package/src/charts/index.ts +0 -8
  240. package/src/charts/kinds/BandStrip.tsx +11 -1
  241. package/src/charts/kinds/Donut.tsx +153 -62
  242. package/src/charts/kinds/DualPanel.tsx +19 -4
  243. package/src/charts/kinds/Heatmap.tsx +61 -22
  244. package/src/charts/kinds/MirroredBars.tsx +15 -3
  245. package/src/charts/kinds/donut-layout.ts +82 -0
  246. package/src/charts/layout/auto-margin.ts +24 -5
  247. package/src/charts/layout/end-labels.ts +135 -0
  248. package/src/charts/primitives/Axes.tsx +112 -21
  249. package/src/charts/primitives/CartesianChart.tsx +282 -68
  250. package/src/charts/primitives/ChartCard.tsx +141 -48
  251. package/src/charts/primitives/ChartFrame.tsx +243 -60
  252. package/src/charts/primitives/ChartLegend.tsx +257 -73
  253. package/src/charts/primitives/ChartTooltip.tsx +8 -3
  254. package/src/charts/primitives/Crosshair.tsx +2 -2
  255. package/src/charts/primitives/HoverOverlay.module.css +13 -0
  256. package/src/charts/primitives/HoverOverlay.module.css.d.ts +8 -0
  257. package/src/charts/primitives/HoverOverlay.tsx +15 -4
  258. package/src/charts/primitives/chart-card-context.ts +37 -0
  259. package/src/charts/primitives/chart-frame-layout.ts +214 -177
  260. package/src/charts/primitives/chart-layout.ts +318 -0
  261. package/src/charts/primitives/chart-tier.tsx +66 -21
  262. package/src/charts/series.ts +4 -1
  263. package/src/charts/utils/ticks.ts +95 -19
  264. package/src/common/errors.ts +25 -1
  265. package/src/common/hit-floor.ts +9 -0
  266. package/src/{shell → common}/isomorphic-layout-effect.ts +4 -3
  267. package/src/common/use-measured-widths.ts +88 -0
  268. package/src/common/use-media-query.ts +56 -0
  269. package/src/common/validate.ts +17 -4
  270. package/src/content/article-layout.module.css +45 -4
  271. package/src/content/article-layout.module.css.d.ts +3 -0
  272. package/src/content/article-layout.tsx +60 -5
  273. package/src/content/code-block.module.css +32 -2
  274. package/src/content/code-block.tsx +47 -3
  275. package/src/content/prose.module.css +13 -8
  276. package/src/controls/actions.module.css +14 -1
  277. package/src/controls/actions.module.css.d.ts +1 -0
  278. package/src/controls/actions.tsx +223 -75
  279. package/src/controls/controls.module.css +8 -31
  280. package/src/controls/enum-filter.tsx +2 -2
  281. package/src/controls/filter-context.tsx +11 -0
  282. package/src/controls/filter-pill.tsx +1 -0
  283. package/src/controls/index.ts +0 -1
  284. package/src/controls/multi-select-filter.tsx +2 -2
  285. package/src/controls/sync-button.module.css +1 -1
  286. package/src/dashboard/section.module.css +1 -26
  287. package/src/dashboard/section.tsx +1 -0
  288. package/src/dashboard/stat-card.module.css +6 -9
  289. package/src/dashboard/stat-card.tsx +6 -3
  290. package/src/dashboard/stat-group.module.css +16 -4
  291. package/src/dashboard/widget-grid.tsx +7 -6
  292. package/src/dashboard/widget-header.module.css +145 -133
  293. package/src/dashboard/widget-header.module.css.d.ts +2 -0
  294. package/src/dashboard/widget-header.tsx +45 -11
  295. package/src/data/data-table.module.css +94 -0
  296. package/src/data/data-table.module.css.d.ts +11 -0
  297. package/src/data/data-table.tsx +503 -164
  298. package/src/data/virtual-list.tsx +31 -0
  299. package/src/forms/form-layout.module.css +30 -5
  300. package/src/forms/form-layout.module.css.d.ts +1 -0
  301. package/src/forms/form-layout.tsx +12 -10
  302. package/src/guard/index.ts +183 -3
  303. package/src/guard/types.ts +3 -2
  304. package/src/index.ts +2 -0
  305. package/src/provider/index.tsx +53 -1
  306. package/src/shell/app-brand.module.css +2 -2
  307. package/src/shell/app-brand.tsx +1 -0
  308. package/src/shell/app-header.module.css +18 -8
  309. package/src/shell/app-main.module.css +54 -3
  310. package/src/shell/app-main.module.css.d.ts +1 -0
  311. package/src/shell/app-mobile-nav.module.css +16 -4
  312. package/src/shell/app-sidebar.module.css +4 -6
  313. package/src/shell/index.tsx +200 -129
  314. package/src/shell/mobile-nav-model.ts +1 -1
  315. package/src/shell/page-aside.tsx +70 -21
  316. package/src/shell/page-bar.module.css +10 -34
  317. package/src/shell/page-bar.tsx +10 -5
  318. package/src/shell/use-breakpoint.ts +9 -45
  319. package/src/shell/use-size-class.ts +31 -0
  320. package/src/state/persisted-or-local.ts +10 -4
  321. package/src/state/persisted.ts +76 -17
  322. package/src/styles.css +41 -0
  323. package/src/surfaces.ts +9 -1
  324. package/src/theme/controls.module.css +7 -0
  325. package/src/theme/ctl-theme.tsx +15 -3
  326. package/src/theme/floating.module.css +36 -0
  327. package/src/theme/floating.module.css.d.ts +3 -0
  328. package/src/theme/index.ts +46 -8
  329. package/src/theme/nav-link.module.css +7 -0
  330. package/src/tokens/index.ts +20 -30
  331. package/src/tokens/palette.ts +6 -28
  332. package/src/tokens/size-classes.ts +46 -0
  333. package/dist/shell/isomorphic-layout-effect.d.ts.map +0 -1
  334. /package/dist/{shell → common}/isomorphic-layout-effect.js +0 -0
@@ -1,10 +1,11 @@
1
1
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
- import { ActionIcon, Button, Group, Menu } from "@mantine/core";
3
- import { createContext, isValidElement, useContext, useEffect } from "react";
2
+ import { ActionIcon, Box, Button, Group, Menu } from "@mantine/core";
3
+ import { createContext, isValidElement, useContext, useEffect, useRef, useState } from "react";
4
+ import { useMeasuredWidths } from "../common/use-measured-widths.js";
5
+ import { useIsomorphicLayoutEffect } from "../common/isomorphic-layout-effect.js";
4
6
  import { IconSlot } from "../theme/icon-slot.js";
5
7
  import { ControlGroup } from "./control-group.js";
6
8
  import classes from "./actions.module.css";
7
- const DESKTOP_SECONDARY_MAX = 3;
8
9
  const MOBILE_GLOBAL_BAR_MAX = 2;
9
10
  const NO_EXTRAS = {
10
11
  mobileMoreActions: [],
@@ -49,16 +50,17 @@ function ChevronGlyph() {
49
50
  }
50
51
  const MOBILE_PRIMARY_PADDING_X = 10;
51
52
  const BAR_GAP = 6;
53
+ const PAGE_BAR_END_ATTR = "data-basalt-page-bar-end";
54
+ const BAR_KEY_ATTR = "data-bar-key";
52
55
  function BarButton({
53
56
  action,
54
57
  variant,
55
- px,
56
- tier
58
+ px
57
59
  }) {
58
60
  const shared = {
59
61
  variant,
60
62
  ...px !== void 0 && { px },
61
- ...tier,
63
+ [BAR_KEY_ATTR]: action.key,
62
64
  disabled: action.disabled === true,
63
65
  loading: action.loading === true,
64
66
  // EVERY icon in this file goes through `IconSlot` — the box is the framework's, never the
@@ -78,12 +80,11 @@ function BarButton({
78
80
  }
79
81
  function BarIconButton({
80
82
  action,
81
- variant,
82
- tier
83
+ variant
83
84
  }) {
84
85
  const shared = {
85
86
  variant,
86
- ...tier,
87
+ [BAR_KEY_ATTR]: action.key,
87
88
  "aria-label": action.label,
88
89
  disabled: action.disabled === true,
89
90
  loading: action.loading === true,
@@ -192,6 +193,103 @@ function joinRuns(actions, opts) {
192
193
  }
193
194
  return runs;
194
195
  }
196
+ const MORE_WIDTH = 80;
197
+ function planBarFold(input) {
198
+ const { room, fixed, gap, hasMenus, items } = input;
199
+ const steps = items.map(() => void 0);
200
+ const used = () => items.reduce(
201
+ (sum, item, i) => {
202
+ const step = steps[i];
203
+ if (step === "overflow") return sum;
204
+ return sum + gap + (step === "icon" ? item.icon ?? item.full : item.full);
205
+ },
206
+ fixed + (hasMenus || steps.includes("overflow") ? MORE_WIDTH + gap : 0)
207
+ );
208
+ for (let i = items.length - 1; i >= 0 && used() > room; i -= 1) {
209
+ if (items[i].icon !== void 0) steps[i] = "icon";
210
+ }
211
+ for (let i = items.length - 1; i >= 0 && used() > room; i -= 1) steps[i] = "overflow";
212
+ return Object.fromEntries(items.flatMap((item, i) => steps[i] ? [[item.key, steps[i]]] : []));
213
+ }
214
+ function flowItems(el) {
215
+ return Array.from(el.children).flatMap(
216
+ (child) => getComputedStyle(child).display === "contents" ? flowItems(child) : [child]
217
+ );
218
+ }
219
+ function useMeasuredFold(input) {
220
+ const { host, runs, hasMenus } = input;
221
+ const groupRef = useRef(null);
222
+ const [folds, setFolds] = useState({});
223
+ const [epoch, setEpoch] = useState(0);
224
+ const foldsRef = useRef(folds);
225
+ const runsRef = useRef(runs);
226
+ const signature = `${hasMenus ? "menus" : "nomenus"}|${runs.map(
227
+ (run) => `${run[0].key}:${run.map((a) => a.kind === void 0 ? a.label : "").join(",")}`
228
+ ).join("|")}`;
229
+ const measuredSignature = useRef(signature);
230
+ useIsomorphicLayoutEffect(() => {
231
+ foldsRef.current = folds;
232
+ runsRef.current = runs;
233
+ });
234
+ const measured = useMeasuredWidths({
235
+ resolveRoot: () => groupRef.current?.closest(`[${PAGE_BAR_END_ATTR}]`) ?? null,
236
+ signature,
237
+ nonce: epoch,
238
+ onMeasure: (row, boxes) => {
239
+ if (measuredSignature.current !== signature) {
240
+ measuredSignature.current = signature;
241
+ if (Object.keys(foldsRef.current).length > 0) {
242
+ foldsRef.current = {};
243
+ setFolds({});
244
+ setEpoch((n) => n + 1);
245
+ return;
246
+ }
247
+ }
248
+ const group = groupRef.current;
249
+ if (group === null) return;
250
+ const currentRuns = runsRef.current;
251
+ const foldable = new Set(
252
+ currentRuns.filter((run) => run[0].kind === void 0).map((run) => run[0].key)
253
+ );
254
+ const elements = Array.from(group.children).filter(
255
+ (el) => el instanceof HTMLElement && foldable.has(el.getAttribute(BAR_KEY_ATTR) ?? "")
256
+ );
257
+ for (const el of elements) {
258
+ const key = el.getAttribute(BAR_KEY_ATTR);
259
+ if (foldsRef.current[key] === void 0 && el.offsetWidth > 0) {
260
+ boxes.current.set(key, { width: el.offsetWidth, height: el.offsetHeight });
261
+ }
262
+ }
263
+ const items = currentRuns.flatMap((run) => {
264
+ const rep = run[0];
265
+ if (rep.kind !== void 0) return [];
266
+ const seen = boxes.current.get(rep.key);
267
+ if (seen === void 0) return [];
268
+ const icon = run.length === 1 && rep.icon !== void 0 ? seen.height : void 0;
269
+ return [{ key: rep.key, full: seen.width, icon }];
270
+ });
271
+ const rects = flowItems(row).map((el) => el.getBoundingClientRect()).filter((r) => r.width > 0);
272
+ if (row.clientWidth <= 0 || rects.length === 0 || items.length === 0) return;
273
+ const used = Math.max(...rects.map((r) => r.right)) - Math.min(...rects.map((r) => r.left));
274
+ const rendered = elements.reduce((sum, el) => sum + el.offsetWidth + BAR_GAP, 0);
275
+ const moreNow = hasMenus || Object.values(foldsRef.current).includes("overflow");
276
+ const fixed = used - rendered - (moreNow ? MORE_WIDTH + BAR_GAP : 0);
277
+ const next = planBarFold({ room: row.clientWidth, fixed, gap: BAR_GAP, hasMenus, items });
278
+ const prev = foldsRef.current;
279
+ const same = Object.keys(next).length === Object.keys(prev).length && Object.entries(next).every(([key, step]) => prev[key] === step);
280
+ if (!same) setFolds(next);
281
+ }
282
+ });
283
+ useIsomorphicLayoutEffect(() => {
284
+ let disposed = false;
285
+ void document.fonts?.ready?.then(() => disposed ? void 0 : measured.remeasure()).catch(() => {
286
+ });
287
+ return () => {
288
+ disposed = true;
289
+ };
290
+ }, [host, signature]);
291
+ return { folds, groupRef };
292
+ }
195
293
  function BarActionRow({
196
294
  primary,
197
295
  secondary,
@@ -207,8 +305,13 @@ function BarActionRow({
207
305
  const list = secondary ?? [];
208
306
  const flat = list.filter((a) => a.kind !== "menu");
209
307
  const menus = list.filter((a) => a.kind === "menu");
210
- const inline = flat.slice(0, DESKTOP_SECONDARY_MAX);
211
- const desktopOverflow = [...flat.slice(DESKTOP_SECONDARY_MAX), ...menus];
308
+ const allRuns = joinRuns(flat, { viewport: "desktop" });
309
+ const { folds, groupRef } = useMeasuredFold({ host, runs: allRuns, hasMenus: menus.length > 0 });
310
+ const runs = allRuns.filter((run) => folds[run[0].key] !== "overflow");
311
+ const desktopOverflow = [
312
+ ...allRuns.flatMap((run) => folds[run[0].key] === "overflow" ? run : []),
313
+ ...menus
314
+ ];
212
315
  const wantsMobile = viewport === "both";
213
316
  const mobileList = [...list, ...mobileOnly];
214
317
  const mobileBar = wantsMobile ? [
@@ -230,19 +333,51 @@ function BarActionRow({
230
333
  const hasDesktop = primary !== void 0 || list.length > 0;
231
334
  const hasMobile = mobileBar.length > 0 || claimsKebab;
232
335
  if (!hasDesktop && !hasMobile && syncNode === void 0) return null;
233
- const desktopLead = inline.length > 0 || desktopOverflow.length > 0 || syncNode === void 0;
336
+ const desktopLead = flat.length > 0 || menus.length > 0 || syncNode === void 0;
234
337
  const rootProps = {
235
338
  ...className !== void 0 && { className },
236
339
  ...style !== void 0 && { style }
237
340
  };
238
341
  return /* @__PURE__ */ jsxs(Fragment, { children: [
239
- hasDesktop && desktopLead && /* @__PURE__ */ jsxs(Group, { gap: BAR_GAP, wrap: "nowrap", visibleFrom: "sm", ...rootProps, children: [
240
- joinRuns(inline, { viewport: "desktop" }).map(
241
- (run) => run.length === 1 ? /* @__PURE__ */ jsx(BarEntry, { action: run[0], emphasis: "secondary" }, run[0].key) : /* @__PURE__ */ jsx(ControlGroup, { children: run.map((action) => /* @__PURE__ */ jsx(BarEntry, { action, emphasis: "secondary", iconOnly: true }, action.key)) }, `join-${run[0].key}`)
242
- ),
243
- /* @__PURE__ */ jsx(OverflowMenu, { actions: desktopOverflow }),
244
- syncNode === void 0 && desktopPrimary
245
- ] }),
342
+ hasDesktop && desktopLead && /* @__PURE__ */ jsxs(
343
+ Group,
344
+ {
345
+ ref: groupRef,
346
+ gap: BAR_GAP,
347
+ wrap: "nowrap",
348
+ visibleFrom: "sm",
349
+ ...host === "slot" && { [PAGE_BAR_END_ATTR]: "" },
350
+ ...rootProps,
351
+ children: [
352
+ runs.map(
353
+ (run) => run.length === 1 ? /* @__PURE__ */ jsx(
354
+ BarEntry,
355
+ {
356
+ action: run[0],
357
+ emphasis: "secondary",
358
+ iconOnly: folds[run[0].key] === "icon"
359
+ },
360
+ run[0].key
361
+ ) : (
362
+ // Tagged so the joined set is measured and folded AS ONE BOX — its members are
363
+ // grandchildren of this `Group`, invisible to the direct-children scan
364
+ // `useMeasuredFold` runs, so the run needs its own `BAR_KEY_ATTR` one level up.
365
+ /* @__PURE__ */ jsx(
366
+ Box,
367
+ {
368
+ className: classes.joinBox,
369
+ ...{ [BAR_KEY_ATTR]: run[0].key },
370
+ children: /* @__PURE__ */ jsx(ControlGroup, { children: run.map((action) => /* @__PURE__ */ jsx(BarEntry, { action, emphasis: "secondary", iconOnly: true }, action.key)) })
371
+ },
372
+ `join-${run[0].key}`
373
+ )
374
+ )
375
+ ),
376
+ /* @__PURE__ */ jsx(OverflowMenu, { actions: desktopOverflow }),
377
+ syncNode === void 0 && desktopPrimary
378
+ ]
379
+ }
380
+ ),
246
381
  syncNode,
247
382
  syncNode !== void 0 && desktopPrimary !== null && /* @__PURE__ */ jsx(Group, { gap: BAR_GAP, wrap: "nowrap", visibleFrom: "sm", ...!desktopLead && rootProps, children: desktopPrimary }),
248
383
  hasMobile && /* @__PURE__ */ jsxs(Group, { gap: BAR_GAP, wrap: "nowrap", hiddenFrom: "sm", ...rootProps, children: [
@@ -291,12 +426,6 @@ function BarEntry({
291
426
  if (iconOnly === true && action.icon !== void 0) {
292
427
  return /* @__PURE__ */ jsx(BarIconButton, { action, variant: "default" });
293
428
  }
294
- if (emphasis === "secondary" && action.icon !== void 0) {
295
- return /* @__PURE__ */ jsxs(Fragment, { children: [
296
- /* @__PURE__ */ jsx(BarIconButton, { action, variant: "default", tier: { hiddenFrom: "md" } }),
297
- /* @__PURE__ */ jsx(BarButton, { action, variant: "default", tier: { visibleFrom: "md" } })
298
- ] });
299
- }
300
429
  return /* @__PURE__ */ jsx(BarButton, { action, variant: emphasis === "primary" ? "filled" : "default" });
301
430
  }
302
431
  function MobileBarEntry({
@@ -315,14 +444,16 @@ function MobileBarEntry({
315
444
  }
316
445
  export {
317
446
  ActionGroup,
447
+ BAR_KEY_ATTR,
318
448
  BarActionRow,
319
449
  BarActionSlot,
320
450
  BarExtrasProvider,
321
- DESKTOP_SECONDARY_MAX,
322
451
  MOBILE_GLOBAL_BAR_MAX,
323
452
  OverflowMenu,
453
+ PAGE_BAR_END_ATTR,
324
454
  barActionMobile,
325
455
  globalActionAsBarAction,
326
456
  globalActionMobile,
327
- isBarActionList
457
+ isBarActionList,
458
+ planBarFold
328
459
  };
@@ -24,7 +24,7 @@
24
24
  padding: 0 var(--vx-space-row-inset-x);
25
25
  }
26
26
 
27
- @media (max-width: 47.99375em) {
27
+ @media (pointer: coarse) {
28
28
  .menuItem,
29
29
  .customRow {
30
30
  min-height: var(--vx-space-sheet-row-height);
@@ -60,3 +60,16 @@
60
60
 
61
61
  color: var(--vx-faint);
62
62
  }
63
+
64
+ /*
65
+ * The `Box` wrapping a joined `ControlGroup` run (`BAR_KEY_ATTR`, one level up from the group
66
+ * itself) so `useMeasuredFold` can measure the whole run as a single box. Without `flex: none` this
67
+ * wrapper is an ORDINARY flex item of the desktop row (`flex: 0 1 auto`, Mantine `Box`'s default) —
68
+ * exactly the shrink target the row's own fold arithmetic squeezes first, so its `offsetWidth` read
69
+ * back a compressed width instead of the run's real max-content width. `ControlGroup` itself
70
+ * already carries this on its own root (`.group`, `controls.module.css`) — this wrapper needs the
71
+ * same property one box further out.
72
+ */
73
+ .joinBox {
74
+ flex: none;
75
+ }
@@ -9,5 +9,6 @@ declare const classes: {
9
9
  readonly customSlot: string
10
10
  readonly kebabIcon: string
11
11
  readonly chevronIcon: string
12
+ readonly joinBox: string
12
13
  }
13
14
  export default classes
@@ -4,7 +4,7 @@
4
4
  * Two form factors per control, ONE mount each, switched by CSS only (C9): the `pill` surface
5
5
  * (bordered 30px chip + popover) and the `sheet` surface (`PanelRow` label-above-control rows
6
6
  * inside the mobile `Filters (n)` Drawer — the same rows the aside's `panel` surface renders;
7
- * `panel-row.module.css` owns their geometry). `48em` / `47.99375em` are the `sm` breakpoint in the
7
+ * `panel-row.module.css` owns their geometry). `52.5em` / `52.49375em` are the `sm` size-class boundary in the
8
8
  * exact literal form every other basalt CSS module uses — a media query cannot resolve a custom
9
9
  * property, so the breakpoint cannot be a token (see `content/prose.module.css`'s note).
10
10
  */
@@ -50,7 +50,7 @@
50
50
  }
51
51
 
52
52
  /* Below `sm` only the first `inline` slots are pills; the rest live in the sheet. */
53
- @media (max-width: 47.99375em) {
53
+ @media (max-width: 52.49375em) {
54
54
  .pillSlot:not([data-inline]) {
55
55
  display: none;
56
56
  }
@@ -60,7 +60,7 @@
60
60
  * Folding is a DESKTOP concern only — scoped to `min-width` so a width measured on a wide viewport
61
61
  * can never hide a slot the mobile `inline` budget is supposed to keep.
62
62
  */
63
- @media (min-width: 48em) {
63
+ @media (min-width: 52.5em) {
64
64
  .pillSlot[data-folded] {
65
65
  display: none;
66
66
  }
@@ -71,7 +71,7 @@
71
71
  display: none;
72
72
  }
73
73
 
74
- @media (min-width: 48em) {
74
+ @media (min-width: 52.5em) {
75
75
  .foldPill[data-shown] {
76
76
  display: inline-flex;
77
77
  }
@@ -81,7 +81,7 @@
81
81
  display: none;
82
82
  }
83
83
 
84
- @media (max-width: 47.99375em) {
84
+ @media (max-width: 52.49375em) {
85
85
  .sheetPill {
86
86
  display: inline-flex;
87
87
  }
@@ -101,10 +101,11 @@
101
101
  * outline the row reads as loose text. Declared here rather than by relaxing the resolver, which
102
102
  * would put a hairline back on every default button in the app.
103
103
  *
104
- * The ≥36px touch target below `sm` (C15) is drawn as a `::before` overlay so the visible box stays
105
- * 30px.
104
+ * The touch target (C15) is the shared `[data-basalt-hit]` overlay (`styles.css`), capped at the
105
+ * chip-row gap so neighbouring pills never overlap; the visible box stays 30px.
106
106
  */
107
107
  .pill {
108
+ --vx-hit-gap: var(--vx-space-control-gap);
108
109
  position: relative;
109
110
  max-width: 15rem;
110
111
  border-color: color-mix(in srgb, var(--vx-ink) 12%, transparent);
@@ -157,30 +158,6 @@
157
158
  color: var(--vx-ink);
158
159
  }
159
160
 
160
- @media (max-width: 47.99375em) {
161
- /* Mantine's Button root clips to its box; the overlay must escape it to be hit-testable. Loading
162
- * buttons keep the clip their overlay depends on (same pairing as page-bar.module.css). */
163
- .pill:not([data-loading]) {
164
- overflow: visible;
165
- }
166
-
167
- .pill::before {
168
- content: '';
169
- position: absolute;
170
- /* Both operands scale with `--mantine-scale` (same reconstruction the theme uses for every
171
- * other ctl-tier box, `theme/index.ts`'s `ctlSizeVars`) so the overlay stays centred on — and
172
- * sized off — the ACTUAL scaled pill box, not its unscaled rem value. */
173
- inset-block: calc(
174
- (
175
- calc(var(--vx-space-control-height-ctl, 1.875rem) * var(--mantine-scale, 1)) -
176
- calc(var(--vx-space-touch-control-height, 2.25rem) * var(--mantine-scale, 1))
177
- ) /
178
- 2
179
- );
180
- inset-inline: 0;
181
- }
182
- }
183
-
184
161
  /* Label at the tier's own step and weight (`docs/CONTROLS-SPEC.md` §3) — Mantine's Button label
185
162
  * inherits the root's `--button-fz` but carries the body weight, which reads light against the
186
163
  * bordered box. */
@@ -1,7 +1,7 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { Button, Radio, Stack } from "@mantine/core";
3
3
  import classes from "./controls.module.css";
4
- import { useFilterRegistration, useFilterSurface } from "./filter-context.js";
4
+ import { POPOVER_ROW_HIT_GAP, useFilterRegistration, useFilterSurface } from "./filter-context.js";
5
5
  import { FilterPill } from "./filter-pill.js";
6
6
  import { useControlName } from "./filter-sheet.js";
7
7
  import { PanelChoice, PanelRow } from "./panel-row.js";
@@ -66,7 +66,7 @@ function EnumFilter({
66
66
  setValue(next);
67
67
  },
68
68
  children: [
69
- /* @__PURE__ */ jsx(Stack, { gap: 2, children: options.map((option) => /* @__PURE__ */ jsx(
69
+ /* @__PURE__ */ jsx(Stack, { gap: POPOVER_ROW_HIT_GAP, style: { "--vx-hit-gap": "var(--stack-gap)" }, children: options.map((option) => /* @__PURE__ */ jsx(
70
70
  Radio,
71
71
  {
72
72
  value: option.value,
@@ -1,4 +1,14 @@
1
1
  import type { ReactNode } from 'react';
2
+ /**
3
+ * The real gap a popover row (`EnumFilter`'s `Radio.Group`, `MultiSelectFilter`'s `Checkbox.Group`)
4
+ * needs so its `[data-basalt-hit]::after` overlay can reach the full 44px coarse floor with no
5
+ * overlap into the next row — same derivation as the chart legend's dots mode (`DOTS_HIT_GAP`):
6
+ * `hit - rowHeight - 2 + 4` headroom, rowHeight being Mantine's default `Radio`/`Checkbox` label row
7
+ * (~21px). A bare `gap={2}` left the `--vx-hit-gap` cap able to buy only ~4px of the 44
8
+ * (code-foundations F1). Shared rather than duplicated per file: both popover rows share the exact
9
+ * same row height and floor, so one drift point beats two hand-kept copies.
10
+ */
11
+ export declare const POPOVER_ROW_HIT_GAP = 25;
2
12
  /**
3
13
  * Which form a control renders. Provided by `FilterSet` (`'pill'` / `'sheet'`) and by `PageAside`
4
14
  * (`'panel'`); `'pill'` when there is neither.
@@ -1 +1 @@
1
- {"version":3,"file":"filter-context.d.ts","sourceRoot":"","sources":["../../src/controls/filter-context.tsx"],"names":[],"mappings":"AAgCA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtC;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAA;AAItD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,IAAI,aAAa,CAEhD;AAED,uFAAuF;AACvF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,gGAAgG;IAChG,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;IAC1B,oEAAoE;IACpE,QAAQ,CAAC,KAAK,EAAE,MAAM,IAAI,CAAA;CAC3B,CAAA;AAED,KAAK,cAAc,GAAG;IACpB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,kBAAkB,GAAG,IAAI,CAAA;IAC7D,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;CAC9B,CAAA;AAID,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAA;IAC/B;oGACgG;IAChG,QAAQ,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI,CAAA;IACxC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;CAC7B,CAAA;AAED,gGAAgG;AAChG,wBAAgB,cAAc,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,mBAAmB,GAAG,SAAS,CAM9F;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,IAAI,GAAG,IAAI,CAkBhF;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAA;IACjC,mEAAmE;IACnE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,sCAAsC;IACtC,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAA;CAC9B,CAAA;AAED;;;;GAIG;AACH,wBAAgB,eAAe,IAAI,YAAY,CAiC9C"}
1
+ {"version":3,"file":"filter-context.d.ts","sourceRoot":"","sources":["../../src/controls/filter-context.tsx"],"names":[],"mappings":"AAgCA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtC;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,KAAK,CAAA;AAErC;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAA;AAItD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,IAAI,aAAa,CAEhD;AAED,uFAAuF;AACvF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,gGAAgG;IAChG,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;IAC1B,oEAAoE;IACpE,QAAQ,CAAC,KAAK,EAAE,MAAM,IAAI,CAAA;CAC3B,CAAA;AAED,KAAK,cAAc,GAAG;IACpB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,kBAAkB,GAAG,IAAI,CAAA;IAC7D,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;CAC9B,CAAA;AAID,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAA;IAC/B;oGACgG;IAChG,QAAQ,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI,CAAA;IACxC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;CAC7B,CAAA;AAED,gGAAgG;AAChG,wBAAgB,cAAc,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,mBAAmB,GAAG,SAAS,CAM9F;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,IAAI,GAAG,IAAI,CAkBhF;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAA;IACjC,mEAAmE;IACnE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,sCAAsC;IACtC,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAA;CAC9B,CAAA;AAED;;;;GAIG;AACH,wBAAgB,eAAe,IAAI,YAAY,CAiC9C"}
@@ -9,6 +9,7 @@ import {
9
9
  useRef,
10
10
  useState
11
11
  } from "react";
12
+ const POPOVER_ROW_HIT_GAP = 25;
12
13
  const FilterSurfaceContext = createContext("pill");
13
14
  function useFilterSurface() {
14
15
  return useContext(FilterSurfaceContext);
@@ -63,6 +64,7 @@ function useFilterCensus() {
63
64
  }
64
65
  export {
65
66
  FilterSetScope,
67
+ POPOVER_ROW_HIT_GAP,
66
68
  useFilterCensus,
67
69
  useFilterRegistration,
68
70
  useFilterSurface
@@ -1 +1 @@
1
- {"version":3,"file":"filter-pill.d.ts","sourceRoot":"","sources":["../../src/controls/filter-pill.tsx"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAKlD,MAAM,MAAM,eAAe,GAAG,WAAW,GAAG;IAC1C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,CAAA;IACzB,iGAAiG;IACjG,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAA;IACzB;sFACkF;IAClF,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;IAC1B,kDAAkD;IAClD,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;IAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IAC7B,qEAAqE;IACrE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;IAC1B,6FAA6F;IAC7F,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAA;IAC5B,0FAA0F;IAC1F,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CACzB,CAAA;AAED,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,IAAI,EACJ,MAAM,EACN,OAAO,EACP,QAAQ,EACR,OAAO,EACP,SAAS,EACT,OAAO,EACP,SAAS,EACT,KAAK,EACL,SAAS,EACT,KAAK,GACN,EAAE,eAAe,GAAG,SAAS,CA4D7B"}
1
+ {"version":3,"file":"filter-pill.d.ts","sourceRoot":"","sources":["../../src/controls/filter-pill.tsx"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAKlD,MAAM,MAAM,eAAe,GAAG,WAAW,GAAG;IAC1C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,CAAA;IACzB,iGAAiG;IACjG,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAA;IACzB;sFACkF;IAClF,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;IAC1B,kDAAkD;IAClD,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;IAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IAC7B,qEAAqE;IACrE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;IAC1B,6FAA6F;IAC7F,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAA;IAC5B,0FAA0F;IAC1F,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CACzB,CAAA;AAED,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,IAAI,EACJ,MAAM,EACN,OAAO,EACP,QAAQ,EACR,OAAO,EACP,SAAS,EACT,OAAO,EACP,SAAS,EACT,KAAK,EACL,SAAS,EACT,KAAK,GACN,EAAE,eAAe,GAAG,SAAS,CA6D7B"}
@@ -26,6 +26,7 @@ function FilterPill({
26
26
  variant: "default",
27
27
  size: "ctl",
28
28
  className: cx(classes.pill, className),
29
+ "data-basalt-hit": true,
29
30
  classNames: { label: classes.pillLabel },
30
31
  ...style !== void 0 && { style },
31
32
  ...active === true && { "data-active": true },
@@ -5,7 +5,7 @@
5
5
  * desktop/mobile swap in CSS (law C9). Actions and sync land in wave 3; the filter/tab family
6
6
  * follows in wave 4.
7
7
  */
8
- export { ActionGroup, OverflowMenu, DESKTOP_SECONDARY_MAX, MOBILE_GLOBAL_BAR_MAX, barActionMobile, globalActionMobile, type BarAction, type BarActionItem, type BarActionMenu, type BarActionCustom, type ActionGroupProps, type GlobalAction, type OverflowMenuProps, } from './actions.js';
8
+ export { ActionGroup, OverflowMenu, MOBILE_GLOBAL_BAR_MAX, barActionMobile, globalActionMobile, type BarAction, type BarActionItem, type BarActionMenu, type BarActionCustom, type ActionGroupProps, type GlobalAction, type OverflowMenuProps, } from './actions.js';
9
9
  export { SyncButton, formatAge, AGE_REFRESH_MS, type SyncButtonProps } from './sync-button.js';
10
10
  export { ControlGroup, type ControlGroupProps } from './control-group.js';
11
11
  export { FilterSet, type FilterSetProps } from './filter-set.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/controls/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,WAAW,EACX,YAAY,EACZ,qBAAqB,EACrB,qBAAqB,EACrB,eAAe,EACf,kBAAkB,EAClB,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,YAAY,EACjB,KAAK,iBAAiB,GACvB,MAAM,WAAW,CAAA;AAClB,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,cAAc,EAAE,KAAK,eAAe,EAAE,MAAM,eAAe,CAAA;AAC3F,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAMtE,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAA;AAC7D,OAAO,EAAE,WAAW,EAAE,KAAK,sBAAsB,EAAE,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAChG,OAAO,EACL,aAAa,EACb,cAAc,EACd,KAAK,kBAAkB,EACvB,KAAK,YAAY,GAClB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACL,YAAY,EACZ,KAAK,YAAY,EACjB,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EACtB,KAAK,uBAAuB,GAC7B,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,iBAAiB,EAAE,KAAK,sBAAsB,EAAE,MAAM,uBAAuB,CAAA;AACtF,OAAO,EAAE,YAAY,EAAE,KAAK,kBAAkB,EAAE,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAC/F,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AACtE,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AACtE,OAAO,EAAE,QAAQ,EAAE,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAA;AAM/E,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAA;AAC1D,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,kBAAkB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/controls/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,WAAW,EACX,YAAY,EACZ,qBAAqB,EACrB,eAAe,EACf,kBAAkB,EAClB,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,YAAY,EACjB,KAAK,iBAAiB,GACvB,MAAM,WAAW,CAAA;AAClB,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,cAAc,EAAE,KAAK,eAAe,EAAE,MAAM,eAAe,CAAA;AAC3F,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAMtE,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAA;AAC7D,OAAO,EAAE,WAAW,EAAE,KAAK,sBAAsB,EAAE,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAChG,OAAO,EACL,aAAa,EACb,cAAc,EACd,KAAK,kBAAkB,EACvB,KAAK,YAAY,GAClB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACL,YAAY,EACZ,KAAK,YAAY,EACjB,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EACtB,KAAK,uBAAuB,GAC7B,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,iBAAiB,EAAE,KAAK,sBAAsB,EAAE,MAAM,uBAAuB,CAAA;AACtF,OAAO,EAAE,YAAY,EAAE,KAAK,kBAAkB,EAAE,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAC/F,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AACtE,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AACtE,OAAO,EAAE,QAAQ,EAAE,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAA;AAM/E,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAA;AAC1D,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,kBAAkB,CAAA"}
@@ -1,7 +1,6 @@
1
1
  import {
2
2
  ActionGroup,
3
3
  OverflowMenu,
4
- DESKTOP_SECONDARY_MAX,
5
4
  MOBILE_GLOBAL_BAR_MAX,
6
5
  barActionMobile,
7
6
  globalActionMobile
@@ -30,7 +29,6 @@ export {
30
29
  COMPARE_VALUES,
31
30
  CompareFilter,
32
31
  ControlGroup,
33
- DESKTOP_SECONDARY_MAX,
34
32
  FilterSet,
35
33
  MOBILE_GLOBAL_BAR_MAX,
36
34
  MultiSelectFilter,
@@ -3,7 +3,7 @@ import { Button, Checkbox, Stack } from "@mantine/core";
3
3
  import { useState } from "react";
4
4
  import { assertRequiredProps } from "../common/validate.js";
5
5
  import classes from "./controls.module.css";
6
- import { useFilterRegistration, useFilterSurface } from "./filter-context.js";
6
+ import { POPOVER_ROW_HIT_GAP, useFilterRegistration, useFilterSurface } from "./filter-context.js";
7
7
  import { FilterPill } from "./filter-pill.js";
8
8
  import { CheckGlyph, useControlName } from "./filter-sheet.js";
9
9
  import { PanelRow } from "./panel-row.js";
@@ -64,7 +64,7 @@ function MultiSelectFilter(props) {
64
64
  setValue(next);
65
65
  },
66
66
  children: [
67
- /* @__PURE__ */ jsx(Stack, { gap: 2, children: options.map((option) => /* @__PURE__ */ jsx(
67
+ /* @__PURE__ */ jsx(Stack, { gap: POPOVER_ROW_HIT_GAP, style: { "--vx-hit-gap": "var(--stack-gap)" }, children: options.map((option) => /* @__PURE__ */ jsx(
68
68
  Checkbox,
69
69
  {
70
70
  value: option.value,
@@ -45,7 +45,7 @@
45
45
  * width itself, pinned to the `ctl` height so the box is square. This module is unlayered, so it
46
46
  * outranks `@layer mantine` regardless of specificity.
47
47
  */
48
- @media (max-width: 47.99375em) {
48
+ @media (max-width: 52.49375em) {
49
49
  .label,
50
50
  .age {
51
51
  display: none;
@@ -1 +1 @@
1
- {"version":3,"file":"section.d.ts","sourceRoot":"","sources":["../../src/dashboard/section.tsx"],"names":[],"mappings":"AAiDA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtC,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAKnE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAGtD,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAGnE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAGxD;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAA;AAMpD,MAAM,MAAM,YAAY,GAAG,IAAI,CAAC,iBAAiB,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAAC,GACnF,WAAW,GACX,eAAe,CAAC,WAAW,CAAC,GAAG;IAC7B;;;;;OAKG;IACH,OAAO,CAAC,EAAE,WAAW,CAAA;IACrB;;;;;;;;;OASG;IACH,KAAK,CAAC,EAAE,cAAc,CAAC,OAAO,CAAC,CAAA;IAC/B;;;;OAIG;IACH,KAAK,CAAC,EAAE,cAAc,CAAA;IACtB,gGAAgG;IAChG,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB;8CAC0C;IAC1C,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB;uBACmB;IACnB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;uGACmG;IACnG,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB;;uDAEmD;IACnD,OAAO,CAAC,EAAE,SAAS,CAAA;IACnB,qGAAqG;IACrG,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,QAAQ,EAAE,SAAS,CAAA;CACpB,CAAA;AAyDH,wBAAgB,OAAO,CAAC,EACtB,OAAO,EACP,KAAK,EACL,KAAK,EACL,IAAI,EACJ,WAAmB,EACnB,UAAU,EACV,WAAkB,EAClB,OAAO,EACP,EAAE,EACF,QAAQ,EACR,SAAS,EACT,KAAK,EACL,UAAU,EACV,GAAG,WAAW,EACf,EAAE,YAAY,+BA4Fd"}
1
+ {"version":3,"file":"section.d.ts","sourceRoot":"","sources":["../../src/dashboard/section.tsx"],"names":[],"mappings":"AAiDA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtC,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAKnE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAGtD,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAGnE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAGxD;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAA;AAMpD,MAAM,MAAM,YAAY,GAAG,IAAI,CAAC,iBAAiB,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAAC,GACnF,WAAW,GACX,eAAe,CAAC,WAAW,CAAC,GAAG;IAC7B;;;;;OAKG;IACH,OAAO,CAAC,EAAE,WAAW,CAAA;IACrB;;;;;;;;;OASG;IACH,KAAK,CAAC,EAAE,cAAc,CAAC,OAAO,CAAC,CAAA;IAC/B;;;;OAIG;IACH,KAAK,CAAC,EAAE,cAAc,CAAA;IACtB,gGAAgG;IAChG,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB;8CAC0C;IAC1C,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB;uBACmB;IACnB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;uGACmG;IACnG,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB;;uDAEmD;IACnD,OAAO,CAAC,EAAE,SAAS,CAAA;IACnB,qGAAqG;IACrG,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,QAAQ,EAAE,SAAS,CAAA;CACpB,CAAA;AA0DH,wBAAgB,OAAO,CAAC,EACtB,OAAO,EACP,KAAK,EACL,KAAK,EACL,IAAI,EACJ,WAAmB,EACnB,UAAU,EACV,WAAkB,EAClB,OAAO,EACP,EAAE,EACF,QAAQ,EACR,SAAS,EACT,KAAK,EACL,UAAU,EACV,GAAG,WAAW,EACf,EAAE,YAAY,+BA4Fd"}
@@ -25,6 +25,7 @@ function ChevronToggle({
25
25
  {
26
26
  type: "button",
27
27
  className: classes.chevron,
28
+ "data-basalt-hit": true,
28
29
  "data-open": open,
29
30
  "aria-expanded": open,
30
31
  "aria-controls": controls,
@@ -18,6 +18,7 @@
18
18
  * query at all).
19
19
  */
20
20
  .root {
21
+ container: basalt-card / inline-size;
21
22
  display: flex;
22
23
  flex-direction: column;
23
24
  gap: var(--vx-space-section-gap, 0.75rem);
@@ -95,29 +96,3 @@
95
96
  .chevron[data-open='false'] svg {
96
97
  transform: rotate(-90deg);
97
98
  }
98
-
99
- /*
100
- * Law C15 — the chevron is a 12px glyph in a 20px box, which is a fine mouse target and an
101
- * unusable thumb one. Below `sm` an `::after` overlay lifts the HIT area to
102
- * `--vx-space-touch-control-height` (36px at level 0) while the visible glyph stays put — the same
103
- * overlay `shell/page-bar.module.css` draws for the bar's own controls. `overflow: visible` is part
104
- * of the fix, not tidying: an overlay that extends past the box is clipped by any `overflow:
105
- * hidden` on the host (which is what made the identical overlay a no-op on Mantine's Button roots).
106
- */
107
- @media (max-width: 47.99375em) {
108
- .chevron {
109
- overflow: visible;
110
- }
111
-
112
- .chevron::after {
113
- content: '';
114
- position: absolute;
115
- top: 50%;
116
- left: 50%;
117
- translate: -50% -50%;
118
- width: 100%;
119
- height: 100%;
120
- min-width: var(--vx-space-touch-control-height, 2.25rem);
121
- min-height: var(--vx-space-touch-control-height, 2.25rem);
122
- }
123
- }
@@ -102,7 +102,7 @@ export type StatCardProps = BasaltProps & SlotStylesProps<StatCardSlot> & Widget
102
102
  */
103
103
  sparkline?: ReactNode | ((size: StatCardSparklineSize) => ReactNode);
104
104
  /** Where `sparkline` sits. `'bleed'` (default) is today's full-width row bled to the card edges;
105
- * `'right'` sits it beside the hero value row. Collapses to `'bleed'` below `sm`. */
105
+ * `'right'` sits it beside the hero value row. Collapses to `'bleed'` in a card narrower than 480px. */
106
106
  sparklinePlacement?: 'bleed' | 'right';
107
107
  /** Header-right slot (e.g. a ghost "..." menu trigger) — wrapped in `CtlSlot tier="widget"`, so a
108
108
  * raw `ActionIcon` with no `size` lands on the 24px step the 28px header row holds (C1/C5). */
@@ -1 +1 @@
1
- {"version":3,"file":"stat-card.d.ts","sourceRoot":"","sources":["../../src/dashboard/stat-card.tsx"],"names":[],"mappings":"AAgGA,OAAO,KAAK,EAAiB,SAAS,EAAE,MAAM,OAAO,CAAA;AAErD,OAAO,KAAK,EACV,sBAAsB,EACtB,uBAAuB,EACvB,sBAAsB,EACvB,MAAM,iBAAiB,CAAA;AAIxB,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AAEzE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAGnD;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,IAAI,CAAA;AAE/B;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAA;AAEnE;;;;;;;GAOG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,YAAY,CAAA;CAC7B,CAAA;AAcD;;;;;;;;GAQG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAkDD;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,aAAa,GAAG,WAAW,GACrC,eAAe,CAAC,YAAY,CAAC,GAC7B,sBAAsB,GACtB,IAAI,CAAC,uBAAuB,EAAE,OAAO,CAAC,GACtC,sBAAsB,GAAG;IACvB;iEAC6D;IAC7D,KAAK,EAAE,MAAM,CAAA;IACb;;;;;;;;;;;;OAYG;IACH,SAAS,CAAC,EAAE,SAAS,oBAAoB,EAAE,CAAA;IAC3C;;;;;;;;;;;;;OAaG;IACH,KAAK,CAAC,EAAE,cAAc,CAAC,OAAO,CAAC,CAAA;IAC/B;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,IAAI,EAAE,qBAAqB,KAAK,SAAS,CAAC,CAAA;IACpE;yFACqF;IACrF,kBAAkB,CAAC,EAAE,OAAO,GAAG,OAAO,CAAA;IACtC;mGAC+F;IAC/F,OAAO,CAAC,EAAE,SAAS,CAAA;IACnB;;;+EAG2E;IAC3E,IAAI,CAAC,EAAE,YAAY,CAAA;CACpB,CAAA;AAEH,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,IAAI,EACJ,QAAQ,EACR,IAAI,EACJ,KAAK,EACL,IAAI,EACJ,SAAS,EACT,KAAK,EACL,KAAK,EACL,WAAW,EACX,aAAa,EACb,WAAW,EACX,UAAU,EACV,SAAS,EACT,kBAA4B,EAC5B,OAAO,EACP,IAAI,EACJ,SAAS,EACT,KAAK,EACL,UAAU,GACX,EAAE,aAAa,+BAkKf"}
1
+ {"version":3,"file":"stat-card.d.ts","sourceRoot":"","sources":["../../src/dashboard/stat-card.tsx"],"names":[],"mappings":"AAgGA,OAAO,KAAK,EAAiB,SAAS,EAAE,MAAM,OAAO,CAAA;AAErD,OAAO,KAAK,EACV,sBAAsB,EACtB,uBAAuB,EACvB,sBAAsB,EACvB,MAAM,iBAAiB,CAAA;AAIxB,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AAEzE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAGnD;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,IAAI,CAAA;AAE/B;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAA;AAEnE;;;;;;;GAOG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,YAAY,CAAA;CAC7B,CAAA;AAcD;;;;;;;;GAQG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAkDD;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,aAAa,GAAG,WAAW,GACrC,eAAe,CAAC,YAAY,CAAC,GAC7B,sBAAsB,GACtB,IAAI,CAAC,uBAAuB,EAAE,OAAO,CAAC,GACtC,sBAAsB,GAAG;IACvB;iEAC6D;IAC7D,KAAK,EAAE,MAAM,CAAA;IACb;;;;;;;;;;;;OAYG;IACH,SAAS,CAAC,EAAE,SAAS,oBAAoB,EAAE,CAAA;IAC3C;;;;;;;;;;;;;OAaG;IACH,KAAK,CAAC,EAAE,cAAc,CAAC,OAAO,CAAC,CAAA;IAC/B;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,IAAI,EAAE,qBAAqB,KAAK,SAAS,CAAC,CAAA;IACpE;4GACwG;IACxG,kBAAkB,CAAC,EAAE,OAAO,GAAG,OAAO,CAAA;IACtC;mGAC+F;IAC/F,OAAO,CAAC,EAAE,SAAS,CAAA;IACnB;;;+EAG2E;IAC3E,IAAI,CAAC,EAAE,YAAY,CAAA;CACpB,CAAA;AAEH,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,IAAI,EACJ,QAAQ,EACR,IAAI,EACJ,KAAK,EACL,IAAI,EACJ,SAAS,EACT,KAAK,EACL,KAAK,EACL,WAAW,EACX,aAAa,EACb,WAAW,EACX,UAAU,EACV,SAAS,EACT,kBAA4B,EAC5B,OAAO,EACP,IAAI,EACJ,SAAS,EACT,KAAK,EACL,UAAU,GACX,EAAE,aAAa,+BAqKf"}
@@ -88,7 +88,7 @@ function StatCard({
88
88
  ),
89
89
  ...!bleeds && {
90
90
  // CUSTOM PROPERTIES, not `flexBasis`/`height` directly. A React inline style beats every
91
- // stylesheet rule, so an inline `flexBasis: 72` also applied below `sm` — where `'right'`
91
+ // stylesheet rule, so an inline `flexBasis: 72` also applied in a narrow card — where `'right'`
92
92
  // collapses `.metricsRow` to a COLUMN and flex-basis is therefore the main-axis HEIGHT.
93
93
  // The mobile sparkline rendered in a 72px-tall box holding 26px of bars, which is the dead
94
94
  // band under every KPI value on a phone. Handed to CSS as values instead, the media query
@@ -128,6 +128,9 @@ function StatCard({
128
128
  // Anchors the tone rail. Set unconditionally so a card's stacking context does not change
129
129
  // depending on whether it happens to have crossed a threshold this render.
130
130
  position: "relative",
131
+ // The card's own width drives its chrome (`widget-header.module.css`, `.metricsRow`).
132
+ containerType: "inline-size",
133
+ containerName: "basalt-card",
131
134
  ...style
132
135
  },
133
136
  "data-tone": tone,