basalt-ui 1.30.2 → 1.32.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 (357) hide show
  1. package/AGENTS.md +1 -1
  2. package/CHANGELOG.md +54 -0
  3. package/MIGRATING.md +256 -12
  4. package/agent/rules/basalt-controls.md +19 -19
  5. package/agent/rules/basalt-mantine.md +5 -5
  6. package/configs/oxlint-plugin.js +371 -4
  7. package/configs/oxlint-plugin.test.ts +327 -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 +47 -82
  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 +138 -145
  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 +68 -111
  47. package/dist/charts/kinds/band-chrome.d.ts +31 -0
  48. package/dist/charts/kinds/band-chrome.d.ts.map +1 -0
  49. package/dist/charts/kinds/band-chrome.js +71 -0
  50. package/dist/charts/kinds/donut-layout.d.ts +47 -0
  51. package/dist/charts/kinds/donut-layout.d.ts.map +1 -0
  52. package/dist/charts/kinds/donut-layout.js +52 -0
  53. package/dist/charts/layout/auto-margin.d.ts +7 -2
  54. package/dist/charts/layout/auto-margin.d.ts.map +1 -1
  55. package/dist/charts/layout/auto-margin.js +12 -3
  56. package/dist/charts/layout/end-labels.d.ts +64 -0
  57. package/dist/charts/layout/end-labels.d.ts.map +1 -0
  58. package/dist/charts/layout/end-labels.js +76 -0
  59. package/dist/charts/primitives/Axes.d.ts +32 -4
  60. package/dist/charts/primitives/Axes.d.ts.map +1 -1
  61. package/dist/charts/primitives/Axes.js +62 -16
  62. package/dist/charts/primitives/CartesianChart.d.ts +7 -6
  63. package/dist/charts/primitives/CartesianChart.d.ts.map +1 -1
  64. package/dist/charts/primitives/CartesianChart.js +264 -145
  65. package/dist/charts/primitives/ChartCard.d.ts +0 -14
  66. package/dist/charts/primitives/ChartCard.d.ts.map +1 -1
  67. package/dist/charts/primitives/ChartCard.js +56 -21
  68. package/dist/charts/primitives/ChartFrame.d.ts +28 -22
  69. package/dist/charts/primitives/ChartFrame.d.ts.map +1 -1
  70. package/dist/charts/primitives/ChartFrame.js +116 -34
  71. package/dist/charts/primitives/ChartLegend.d.ts +19 -15
  72. package/dist/charts/primitives/ChartLegend.d.ts.map +1 -1
  73. package/dist/charts/primitives/ChartLegend.js +86 -73
  74. package/dist/charts/primitives/ChartTooltip.d.ts +5 -0
  75. package/dist/charts/primitives/ChartTooltip.d.ts.map +1 -1
  76. package/dist/charts/primitives/ChartTooltip.js +20 -4
  77. package/dist/charts/primitives/Crosshair.js +2 -2
  78. package/dist/charts/primitives/HoverOverlay.d.ts +29 -9
  79. package/dist/charts/primitives/HoverOverlay.d.ts.map +1 -1
  80. package/dist/charts/primitives/HoverOverlay.js +54 -27
  81. package/dist/charts/primitives/HoverOverlay.module.css +13 -0
  82. package/dist/charts/primitives/HoverOverlay.module.css.d.ts +8 -0
  83. package/dist/charts/primitives/chart-card-context.d.ts +33 -0
  84. package/dist/charts/primitives/chart-card-context.d.ts.map +1 -0
  85. package/dist/charts/primitives/chart-card-context.js +18 -0
  86. package/dist/charts/primitives/chart-frame-layout.d.ts +93 -113
  87. package/dist/charts/primitives/chart-frame-layout.d.ts.map +1 -1
  88. package/dist/charts/primitives/chart-frame-layout.js +75 -34
  89. package/dist/charts/primitives/chart-layout.d.ts +112 -0
  90. package/dist/charts/primitives/chart-layout.d.ts.map +1 -0
  91. package/dist/charts/primitives/chart-layout.js +175 -0
  92. package/dist/charts/primitives/chart-tier.d.ts +13 -11
  93. package/dist/charts/primitives/chart-tier.d.ts.map +1 -1
  94. package/dist/charts/primitives/chart-tier.js +42 -13
  95. package/dist/charts/primitives/legend-disclosure.d.ts +27 -0
  96. package/dist/charts/primitives/legend-disclosure.d.ts.map +1 -0
  97. package/dist/charts/primitives/legend-disclosure.js +153 -0
  98. package/dist/charts/series.d.ts +4 -1
  99. package/dist/charts/series.d.ts.map +1 -1
  100. package/dist/charts/utils/ticks.d.ts +27 -8
  101. package/dist/charts/utils/ticks.d.ts.map +1 -1
  102. package/dist/charts/utils/ticks.js +35 -11
  103. package/dist/common/errors.d.ts +11 -1
  104. package/dist/common/errors.d.ts.map +1 -1
  105. package/dist/common/errors.js +16 -2
  106. package/dist/common/hit-floor.d.ts +10 -0
  107. package/dist/common/hit-floor.d.ts.map +1 -0
  108. package/dist/common/hit-floor.js +6 -0
  109. package/dist/{shell → common}/isomorphic-layout-effect.d.ts +4 -3
  110. package/dist/common/isomorphic-layout-effect.d.ts.map +1 -0
  111. package/dist/common/use-measured-widths.d.ts +37 -0
  112. package/dist/common/use-measured-widths.d.ts.map +1 -0
  113. package/dist/common/use-measured-widths.js +51 -0
  114. package/dist/common/use-media-query.d.ts +6 -0
  115. package/dist/common/use-media-query.d.ts.map +1 -0
  116. package/dist/common/use-media-query.js +40 -0
  117. package/dist/common/validate.d.ts +9 -0
  118. package/dist/common/validate.d.ts.map +1 -1
  119. package/dist/common/validate.js +9 -4
  120. package/dist/content/article-layout.d.ts +4 -2
  121. package/dist/content/article-layout.d.ts.map +1 -1
  122. package/dist/content/article-layout.js +43 -3
  123. package/dist/content/article-layout.module.css +45 -4
  124. package/dist/content/article-layout.module.css.d.ts +3 -0
  125. package/dist/content/code-block.d.ts.map +1 -1
  126. package/dist/content/code-block.js +40 -2
  127. package/dist/content/code-block.module.css +32 -2
  128. package/dist/content/prose.module.css +13 -8
  129. package/dist/controls/actions.d.ts +29 -6
  130. package/dist/controls/actions.d.ts.map +1 -1
  131. package/dist/controls/actions.js +158 -27
  132. package/dist/controls/actions.module.css +14 -1
  133. package/dist/controls/actions.module.css.d.ts +1 -0
  134. package/dist/controls/controls.module.css +13 -31
  135. package/dist/controls/enum-filter.js +2 -2
  136. package/dist/controls/filter-context.d.ts +10 -0
  137. package/dist/controls/filter-context.d.ts.map +1 -1
  138. package/dist/controls/filter-context.js +2 -0
  139. package/dist/controls/filter-pill.d.ts.map +1 -1
  140. package/dist/controls/filter-pill.js +1 -0
  141. package/dist/controls/index.d.ts +1 -1
  142. package/dist/controls/index.d.ts.map +1 -1
  143. package/dist/controls/index.js +0 -2
  144. package/dist/controls/multi-select-filter.js +2 -2
  145. package/dist/controls/sync-button.module.css +2 -1
  146. package/dist/dashboard/section.d.ts.map +1 -1
  147. package/dist/dashboard/section.js +1 -0
  148. package/dist/dashboard/section.module.css +1 -26
  149. package/dist/dashboard/stat-card.d.ts +1 -1
  150. package/dist/dashboard/stat-card.d.ts.map +1 -1
  151. package/dist/dashboard/stat-card.js +4 -1
  152. package/dist/dashboard/stat-card.module.css +6 -9
  153. package/dist/dashboard/stat-group.module.css +33 -66
  154. package/dist/dashboard/widget-grid.d.ts.map +1 -1
  155. package/dist/dashboard/widget-grid.module.css +11 -38
  156. package/dist/dashboard/widget-header.d.ts +14 -4
  157. package/dist/dashboard/widget-header.d.ts.map +1 -1
  158. package/dist/dashboard/widget-header.js +23 -6
  159. package/dist/dashboard/widget-header.module.css +145 -133
  160. package/dist/dashboard/widget-header.module.css.d.ts +2 -0
  161. package/dist/data/data-table-state.d.ts +83 -0
  162. package/dist/data/data-table-state.d.ts.map +1 -0
  163. package/dist/data/data-table-state.js +139 -0
  164. package/dist/data/data-table.d.ts +56 -2
  165. package/dist/data/data-table.d.ts.map +1 -1
  166. package/dist/data/data-table.js +436 -336
  167. package/dist/data/data-table.module.css +94 -0
  168. package/dist/data/data-table.module.css.d.ts +11 -0
  169. package/dist/data/virtual-list.d.ts.map +1 -1
  170. package/dist/data/virtual-list.js +10 -0
  171. package/dist/forms/form-layout.d.ts.map +1 -1
  172. package/dist/forms/form-layout.js +3 -3
  173. package/dist/forms/form-layout.module.css +20 -5
  174. package/dist/forms/form-layout.module.css.d.ts +1 -0
  175. package/dist/guard/index.d.ts +8 -2
  176. package/dist/guard/index.d.ts.map +1 -1
  177. package/dist/guard/index.js +68 -2
  178. package/dist/guard/types.d.ts +3 -3
  179. package/dist/guard/types.d.ts.map +1 -1
  180. package/dist/index.d.ts +1 -1
  181. package/dist/index.d.ts.map +1 -1
  182. package/dist/index.js +3 -1
  183. package/dist/notifications/center.d.ts.map +1 -1
  184. package/dist/provider/index.d.ts +20 -1
  185. package/dist/provider/index.d.ts.map +1 -1
  186. package/dist/provider/index.js +30 -8
  187. package/dist/shell/app-brand.d.ts.map +1 -1
  188. package/dist/shell/app-brand.js +1 -0
  189. package/dist/shell/app-brand.module.css +2 -2
  190. package/dist/shell/app-header.module.css +18 -8
  191. package/dist/shell/app-main.module.css +54 -3
  192. package/dist/shell/app-main.module.css.d.ts +1 -0
  193. package/dist/shell/app-mobile-nav.module.css +16 -4
  194. package/dist/shell/app-sidebar.module.css +4 -6
  195. package/dist/shell/aside-docking.d.ts +31 -0
  196. package/dist/shell/aside-docking.d.ts.map +1 -0
  197. package/dist/shell/aside-docking.js +19 -0
  198. package/dist/shell/index.d.ts +1 -0
  199. package/dist/shell/index.d.ts.map +1 -1
  200. package/dist/shell/index.js +56 -16
  201. package/dist/shell/mobile-nav-model.d.ts +1 -1
  202. package/dist/shell/page-aside.d.ts +22 -3
  203. package/dist/shell/page-aside.d.ts.map +1 -1
  204. package/dist/shell/page-aside.js +27 -13
  205. package/dist/shell/page-bar.d.ts.map +1 -1
  206. package/dist/shell/page-bar.js +10 -5
  207. package/dist/shell/page-bar.module.css +10 -34
  208. package/dist/shell/use-breakpoint.d.ts +3 -4
  209. package/dist/shell/use-breakpoint.d.ts.map +1 -1
  210. package/dist/shell/use-breakpoint.js +3 -25
  211. package/dist/shell/use-size-class.d.ts +6 -0
  212. package/dist/shell/use-size-class.d.ts.map +1 -0
  213. package/dist/shell/use-size-class.js +19 -0
  214. package/dist/state/persisted-or-local.d.ts +4 -1
  215. package/dist/state/persisted-or-local.d.ts.map +1 -1
  216. package/dist/state/persisted-or-local.js +4 -3
  217. package/dist/state/persisted.d.ts +10 -0
  218. package/dist/state/persisted.d.ts.map +1 -1
  219. package/dist/state/persisted.js +44 -14
  220. package/dist/styles.css +41 -0
  221. package/dist/surfaces.d.ts +4 -4
  222. package/dist/surfaces.d.ts.map +1 -1
  223. package/dist/surfaces.js +11 -3
  224. package/dist/theme/controls.module.css +7 -0
  225. package/dist/theme/ctl-theme.d.ts +1 -0
  226. package/dist/theme/ctl-theme.d.ts.map +1 -1
  227. package/dist/theme/ctl-theme.js +12 -4
  228. package/dist/theme/floating.module.css +37 -0
  229. package/dist/theme/floating.module.css.d.ts +3 -0
  230. package/dist/theme/index.d.ts +2 -2
  231. package/dist/theme/index.d.ts.map +1 -1
  232. package/dist/theme/index.js +34 -5
  233. package/dist/theme/nav-link.module.css +7 -0
  234. package/dist/theme-lab/derive-controls.d.ts.map +1 -1
  235. package/dist/tokens/index.d.ts +7 -16
  236. package/dist/tokens/index.d.ts.map +1 -1
  237. package/dist/tokens/index.js +23 -28
  238. package/dist/tokens/palette.d.ts +5 -27
  239. package/dist/tokens/palette.d.ts.map +1 -1
  240. package/dist/tokens/palette.js +8 -30
  241. package/dist/tokens/size-classes.d.ts +40 -0
  242. package/dist/tokens/size-classes.d.ts.map +1 -0
  243. package/dist/tokens/size-classes.js +29 -0
  244. package/dist/tokens.css +8 -4
  245. package/llms.txt +3 -3
  246. package/package.json +18 -17
  247. package/src/agent-chat/composer.tsx +74 -47
  248. package/src/agent-chat/thread-workspace.tsx +8 -11
  249. package/src/agent-chat/use-keyboard-inset.ts +68 -0
  250. package/src/charts/cursor/touch-pin.ts +138 -0
  251. package/src/charts/hooks/use-discrete-cursor.ts +335 -0
  252. package/src/charts/hooks/use-hysteresis.ts +26 -0
  253. package/src/charts/hooks/useBandPlot.ts +90 -27
  254. package/src/charts/hooks/useChartCursor.ts +211 -26
  255. package/src/charts/index.ts +0 -8
  256. package/src/charts/kinds/BandStrip.tsx +25 -61
  257. package/src/charts/kinds/Donut.tsx +153 -62
  258. package/src/charts/kinds/DualPanel.tsx +21 -26
  259. package/src/charts/kinds/Heatmap.tsx +61 -22
  260. package/src/charts/kinds/MirroredBars.tsx +23 -65
  261. package/src/charts/kinds/band-chrome.tsx +91 -0
  262. package/src/charts/kinds/donut-layout.ts +82 -0
  263. package/src/charts/layout/auto-margin.ts +24 -5
  264. package/src/charts/layout/end-labels.ts +135 -0
  265. package/src/charts/primitives/Axes.tsx +112 -21
  266. package/src/charts/primitives/CartesianChart.tsx +282 -111
  267. package/src/charts/primitives/ChartCard.tsx +119 -48
  268. package/src/charts/primitives/ChartFrame.tsx +204 -60
  269. package/src/charts/primitives/ChartLegend.tsx +115 -78
  270. package/src/charts/primitives/ChartTooltip.tsx +24 -3
  271. package/src/charts/primitives/Crosshair.tsx +2 -2
  272. package/src/charts/primitives/HoverOverlay.module.css +13 -0
  273. package/src/charts/primitives/HoverOverlay.module.css.d.ts +8 -0
  274. package/src/charts/primitives/HoverOverlay.tsx +62 -20
  275. package/src/charts/primitives/chart-card-context.ts +46 -0
  276. package/src/charts/primitives/chart-frame-layout.ts +207 -182
  277. package/src/charts/primitives/chart-layout.ts +318 -0
  278. package/src/charts/primitives/chart-tier.tsx +66 -21
  279. package/src/charts/primitives/legend-disclosure.tsx +177 -0
  280. package/src/charts/series.ts +4 -1
  281. package/src/charts/utils/ticks.ts +95 -19
  282. package/src/common/errors.ts +25 -1
  283. package/src/common/hit-floor.ts +9 -0
  284. package/src/{shell → common}/isomorphic-layout-effect.ts +4 -3
  285. package/src/common/use-measured-widths.ts +88 -0
  286. package/src/common/use-media-query.ts +56 -0
  287. package/src/common/validate.ts +17 -4
  288. package/src/content/article-layout.module.css +45 -4
  289. package/src/content/article-layout.module.css.d.ts +3 -0
  290. package/src/content/article-layout.tsx +60 -5
  291. package/src/content/code-block.module.css +32 -2
  292. package/src/content/code-block.tsx +47 -3
  293. package/src/content/prose.module.css +13 -8
  294. package/src/controls/actions.module.css +14 -1
  295. package/src/controls/actions.module.css.d.ts +1 -0
  296. package/src/controls/actions.tsx +223 -75
  297. package/src/controls/controls.module.css +13 -31
  298. package/src/controls/enum-filter.tsx +2 -2
  299. package/src/controls/filter-context.tsx +11 -0
  300. package/src/controls/filter-pill.tsx +1 -0
  301. package/src/controls/index.ts +0 -1
  302. package/src/controls/multi-select-filter.tsx +2 -2
  303. package/src/controls/sync-button.module.css +2 -1
  304. package/src/dashboard/section.module.css +1 -26
  305. package/src/dashboard/section.tsx +1 -0
  306. package/src/dashboard/stat-card.module.css +6 -9
  307. package/src/dashboard/stat-card.tsx +6 -3
  308. package/src/dashboard/stat-group.module.css +33 -66
  309. package/src/dashboard/widget-grid.module.css +11 -38
  310. package/src/dashboard/widget-grid.tsx +7 -6
  311. package/src/dashboard/widget-header.module.css +145 -133
  312. package/src/dashboard/widget-header.module.css.d.ts +2 -0
  313. package/src/dashboard/widget-header.tsx +45 -11
  314. package/src/data/data-table-state.ts +218 -0
  315. package/src/data/data-table.module.css +94 -0
  316. package/src/data/data-table.module.css.d.ts +11 -0
  317. package/src/data/data-table.tsx +547 -299
  318. package/src/data/virtual-list.tsx +31 -0
  319. package/src/forms/form-layout.module.css +20 -5
  320. package/src/forms/form-layout.module.css.d.ts +1 -0
  321. package/src/forms/form-layout.tsx +12 -10
  322. package/src/guard/index.ts +188 -3
  323. package/src/guard/types.ts +3 -2
  324. package/src/index.ts +2 -0
  325. package/src/notifications/center.tsx +3 -0
  326. package/src/provider/index.tsx +60 -7
  327. package/src/shell/app-brand.module.css +2 -2
  328. package/src/shell/app-brand.tsx +1 -0
  329. package/src/shell/app-header.module.css +18 -8
  330. package/src/shell/app-main.module.css +54 -3
  331. package/src/shell/app-main.module.css.d.ts +1 -0
  332. package/src/shell/app-mobile-nav.module.css +16 -4
  333. package/src/shell/app-sidebar.module.css +4 -6
  334. package/src/shell/aside-docking.ts +54 -0
  335. package/src/shell/index.tsx +178 -129
  336. package/src/shell/mobile-nav-model.ts +1 -1
  337. package/src/shell/page-aside.tsx +70 -21
  338. package/src/shell/page-bar.module.css +10 -34
  339. package/src/shell/page-bar.tsx +10 -5
  340. package/src/shell/use-breakpoint.ts +9 -45
  341. package/src/shell/use-size-class.ts +31 -0
  342. package/src/state/persisted-or-local.ts +10 -4
  343. package/src/state/persisted.ts +76 -17
  344. package/src/styles.css +41 -0
  345. package/src/surfaces.ts +9 -1
  346. package/src/theme/controls.module.css +7 -0
  347. package/src/theme/ctl-theme.tsx +15 -3
  348. package/src/theme/floating.module.css +37 -0
  349. package/src/theme/floating.module.css.d.ts +3 -0
  350. package/src/theme/index.ts +46 -8
  351. package/src/theme/nav-link.module.css +7 -0
  352. package/src/theme-lab/derive-controls.tsx +2 -0
  353. package/src/tokens/index.ts +20 -30
  354. package/src/tokens/palette.ts +6 -28
  355. package/src/tokens/size-classes.ts +46 -0
  356. package/dist/shell/isomorphic-layout-effect.d.ts.map +0 -1
  357. /package/dist/{shell → common}/isomorphic-layout-effect.js +0 -0
@@ -71,8 +71,6 @@ export type GlobalAction = {
71
71
  /** @default 'bar' for the first two, `'more'` for the rest */
72
72
  mobile?: 'bar' | 'more' | 'hidden';
73
73
  };
74
- /** Secondaries rendered inline on desktop; the rest fold into `More` (`docs/CONTROLS-SPEC.md` §2.1). */
75
- export declare const DESKTOP_SECONDARY_MAX = 3;
76
74
  /** `GlobalAction`s without an explicit `mobile` that still land on the mobile bar. */
77
75
  export declare const MOBILE_GLOBAL_BAR_MAX = 2;
78
76
  /**
@@ -100,6 +98,13 @@ export declare function barActionMobile(action: BarAction, isPrimary: boolean):
100
98
  export declare function globalActionMobile(action: GlobalAction, index: number): 'bar' | 'more' | 'hidden';
101
99
  /** A `GlobalAction` reaching a `BarAction` slot — the kebab renders one row shape, not two. */
102
100
  export declare function globalActionAsBarAction(action: GlobalAction): BarActionCustom;
101
+ /**
102
+ * The DOM contract between `PageBar` row 1 and {@link useMeasuredFold} — module-internal, not part
103
+ * of any barrel. `PAGE_BAR_END_ATTR` marks the elastic row the fold measures; `BAR_KEY_ATTR` tags
104
+ * each rendered action with its `key` so a measured box maps back to its action.
105
+ */
106
+ export declare const PAGE_BAR_END_ATTR = "data-basalt-page-bar-end";
107
+ export declare const BAR_KEY_ATTR = "data-bar-key";
103
108
  export type OverflowMenuProps = BasaltProps & {
104
109
  actions: readonly BarAction[];
105
110
  /**
@@ -149,12 +154,30 @@ type BarActionRowProps = ActionGroupProps & {
149
154
  */
150
155
  syncNode?: ReactNode;
151
156
  };
157
+ type FoldStep = 'icon' | 'overflow';
158
+ /**
159
+ * The measured fold as a pure decision. `room` is the row's available width, `fixed` everything in it
160
+ * that never folds (primary, sync, joined runs, custom nodes), each foldable `item` its labelled and
161
+ * icon-only width (`icon` absent when it ships no icon). Folds from the LAST item back: first to
162
+ * icon-only where an icon exists, then into `More`. Items that stay whole are absent from the result.
163
+ */
164
+ export declare function planBarFold(input: {
165
+ room: number;
166
+ fixed: number;
167
+ gap: number;
168
+ hasMenus: boolean;
169
+ items: readonly {
170
+ key: string;
171
+ full: number;
172
+ icon: number | undefined;
173
+ }[];
174
+ }): Record<string, FoldStep>;
152
175
  export declare function BarActionRow({ primary, secondary, host, viewport, mobileOnly, syncNode, className, style, }: BarActionRowProps): ReactNode;
153
176
  /**
154
177
  * A home's `actions` slot, projected for both viewports.
155
178
  *
156
- * Desktop: `primary` as a `filled` button · up to `DESKTOP_SECONDARY_MAX` secondaries as `default`
157
- * buttons · everything past that, plus every `kind: 'menu'`, in one `More` menu.
179
+ * Desktop: `primary` as a `filled` button · secondaries as `default` buttons, folded by the row's
180
+ * measured width (icon-only, then into `More`) · every `kind: 'menu'` in that same `More` menu.
158
181
  * Mobile: `primary` as an icon button when it ships an icon and a compact labelled button when it
159
182
  * does not · one kebab holding every `mobile: 'more'` action · `mobile: 'hidden'` drops the action
160
183
  * entirely.
@@ -192,8 +215,8 @@ export type SlotActions = BarAction[] | ReactNode;
192
215
  export declare function isBarActionList(actions: SlotActions): actions is BarAction[];
193
216
  /**
194
217
  * Renders a {@link SlotActions} slot: the typed form goes through the SAME projection `PageBar` and
195
- * `ActionGroup` use — inline up to {@link DESKTOP_SECONDARY_MAX}, the rest folded into `More`, and a
196
- * mobile kebab below `sm` — and the node form is returned untouched.
218
+ * `ActionGroup` use — inline, `kind: 'menu'` folded into `More`, and a mobile kebab below `sm` — and
219
+ * the node form is returned untouched.
197
220
  *
198
221
  * Every entry lands in `secondary`: a `BarAction[]` carries no primary marker, and law C6's "exactly
199
222
  * one primary" is the page bar's rule, enforced by `ActionGroupProps.primary` being singular. A home
@@ -1 +1 @@
1
- {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/controls/actions.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/controls/actions.tsx"],"names":[],"mappings":"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"}
@@ -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
  */
@@ -49,8 +49,13 @@
49
49
  flex-shrink: 0;
50
50
  }
51
51
 
52
+ /* theme-allow-file raw-media-query — the ControlRow's own C9 swap (pills inline, the rest in a
53
+ sheet) keys on the SIZE CLASS by design: the sheet is compact-class chrome, the same axis the
54
+ shell's bottom bar reads. Every width query here is `SIZE_CLASSES.medium`, pinned by
55
+ `breakpoint-literals.test.ts`. */
56
+
52
57
  /* Below `sm` only the first `inline` slots are pills; the rest live in the sheet. */
53
- @media (max-width: 47.99375em) {
58
+ @media (max-width: 52.49375em) {
54
59
  .pillSlot:not([data-inline]) {
55
60
  display: none;
56
61
  }
@@ -60,7 +65,7 @@
60
65
  * Folding is a DESKTOP concern only — scoped to `min-width` so a width measured on a wide viewport
61
66
  * can never hide a slot the mobile `inline` budget is supposed to keep.
62
67
  */
63
- @media (min-width: 48em) {
68
+ @media (min-width: 52.5em) {
64
69
  .pillSlot[data-folded] {
65
70
  display: none;
66
71
  }
@@ -71,7 +76,7 @@
71
76
  display: none;
72
77
  }
73
78
 
74
- @media (min-width: 48em) {
79
+ @media (min-width: 52.5em) {
75
80
  .foldPill[data-shown] {
76
81
  display: inline-flex;
77
82
  }
@@ -81,7 +86,7 @@
81
86
  display: none;
82
87
  }
83
88
 
84
- @media (max-width: 47.99375em) {
89
+ @media (max-width: 52.49375em) {
85
90
  .sheetPill {
86
91
  display: inline-flex;
87
92
  }
@@ -101,10 +106,11 @@
101
106
  * outline the row reads as loose text. Declared here rather than by relaxing the resolver, which
102
107
  * would put a hairline back on every default button in the app.
103
108
  *
104
- * The ≥36px touch target below `sm` (C15) is drawn as a `::before` overlay so the visible box stays
105
- * 30px.
109
+ * The touch target (C15) is the shared `[data-basalt-hit]` overlay (`styles.css`), capped at the
110
+ * chip-row gap so neighbouring pills never overlap; the visible box stays 30px.
106
111
  */
107
112
  .pill {
113
+ --vx-hit-gap: var(--vx-space-control-gap);
108
114
  position: relative;
109
115
  max-width: 15rem;
110
116
  border-color: color-mix(in srgb, var(--vx-ink) 12%, transparent);
@@ -157,30 +163,6 @@
157
163
  color: var(--vx-ink);
158
164
  }
159
165
 
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
166
  /* Label at the tier's own step and weight (`docs/CONTROLS-SPEC.md` §3) — Mantine's Button label
185
167
  * inherits the root's `--button-fz` but carries the body weight, which reads light against the
186
168
  * 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,8 @@
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
+ /* theme-allow raw-media-query — the control's own C9 icon-only swap at the compact size class */
49
+ @media (max-width: 52.49375em) {
49
50
  .label,
50
51
  .age {
51
52
  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,