@miragon/mcp-toolkit-ui 2.7.0 → 2.8.1

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 (388) hide show
  1. package/README.md +7 -4
  2. package/dist/app/adapt-data-widget.d.ts +1 -22
  3. package/dist/app/adapt-data-widget.d.ts.map +1 -1
  4. package/dist/app/adapt-data-widget.js +1 -35
  5. package/dist/app/adapt-data-widget.js.map +1 -1
  6. package/dist/app/builder/BuilderBanners.js +1 -1
  7. package/dist/app/builder/BuilderBanners.js.map +1 -1
  8. package/dist/app/builder/CanvasRow.d.ts +4 -2
  9. package/dist/app/builder/CanvasRow.d.ts.map +1 -1
  10. package/dist/app/builder/CanvasRow.js +21 -7
  11. package/dist/app/builder/CanvasRow.js.map +1 -1
  12. package/dist/app/builder/CatalogueSheet.d.ts.map +1 -1
  13. package/dist/app/builder/CatalogueSheet.js +11 -4
  14. package/dist/app/builder/CatalogueSheet.js.map +1 -1
  15. package/dist/app/builder/CellPropsSheet.d.ts +7 -3
  16. package/dist/app/builder/CellPropsSheet.d.ts.map +1 -1
  17. package/dist/app/builder/CellPropsSheet.js +10 -3
  18. package/dist/app/builder/CellPropsSheet.js.map +1 -1
  19. package/dist/app/builder/DiscardDialog.d.ts +18 -0
  20. package/dist/app/builder/DiscardDialog.d.ts.map +1 -0
  21. package/dist/app/builder/DiscardDialog.js +18 -0
  22. package/dist/app/builder/DiscardDialog.js.map +1 -0
  23. package/dist/app/builder/LayoutSurface.d.ts +33 -9
  24. package/dist/app/builder/LayoutSurface.d.ts.map +1 -1
  25. package/dist/app/builder/LayoutSurface.js +74 -23
  26. package/dist/app/builder/LayoutSurface.js.map +1 -1
  27. package/dist/app/builder/PipelineStrip.d.ts +2 -1
  28. package/dist/app/builder/PipelineStrip.d.ts.map +1 -1
  29. package/dist/app/builder/PipelineStrip.js +26 -13
  30. package/dist/app/builder/PipelineStrip.js.map +1 -1
  31. package/dist/app/builder/SaveDialog.d.ts +9 -1
  32. package/dist/app/builder/SaveDialog.d.ts.map +1 -1
  33. package/dist/app/builder/SaveDialog.js +8 -2
  34. package/dist/app/builder/SaveDialog.js.map +1 -1
  35. package/dist/app/builder/Toolbar.d.ts +12 -4
  36. package/dist/app/builder/Toolbar.d.ts.map +1 -1
  37. package/dist/app/builder/Toolbar.js +18 -7
  38. package/dist/app/builder/Toolbar.js.map +1 -1
  39. package/dist/app/builder/Workspace.d.ts +23 -3
  40. package/dist/app/builder/Workspace.d.ts.map +1 -1
  41. package/dist/app/builder/Workspace.js +58 -8
  42. package/dist/app/builder/Workspace.js.map +1 -1
  43. package/dist/app/builder/builder-model.d.ts +143 -1
  44. package/dist/app/builder/builder-model.d.ts.map +1 -1
  45. package/dist/app/builder/builder-model.js +191 -1
  46. package/dist/app/builder/builder-model.js.map +1 -1
  47. package/dist/app/builder/reveal.d.ts +10 -0
  48. package/dist/app/builder/reveal.d.ts.map +1 -0
  49. package/dist/app/builder/reveal.js +10 -0
  50. package/dist/app/builder/reveal.js.map +1 -0
  51. package/dist/app/builder/use-builder-catalogue.d.ts +4 -1
  52. package/dist/app/builder/use-builder-catalogue.d.ts.map +1 -1
  53. package/dist/app/builder/use-builder-catalogue.js +44 -17
  54. package/dist/app/builder/use-builder-catalogue.js.map +1 -1
  55. package/dist/app/builder/use-builder-session.d.ts +30 -0
  56. package/dist/app/builder/use-builder-session.d.ts.map +1 -0
  57. package/dist/app/builder/use-builder-session.js +58 -0
  58. package/dist/app/builder/use-builder-session.js.map +1 -0
  59. package/dist/app/builder/use-display-resolver.d.ts +17 -0
  60. package/dist/app/builder/use-display-resolver.d.ts.map +1 -0
  61. package/dist/app/builder/use-display-resolver.js +16 -0
  62. package/dist/app/builder/use-display-resolver.js.map +1 -0
  63. package/dist/app/index.d.ts +8 -3
  64. package/dist/app/index.d.ts.map +1 -1
  65. package/dist/app/index.js +8 -2
  66. package/dist/app/index.js.map +1 -1
  67. package/dist/app/layout-builder.d.ts +13 -25
  68. package/dist/app/layout-builder.d.ts.map +1 -1
  69. package/dist/app/layout-builder.js +75 -81
  70. package/dist/app/layout-builder.js.map +1 -1
  71. package/dist/app/mcp-app-view-chrome.d.ts +12 -3
  72. package/dist/app/mcp-app-view-chrome.d.ts.map +1 -1
  73. package/dist/app/mcp-app-view-chrome.js +21 -5
  74. package/dist/app/mcp-app-view-chrome.js.map +1 -1
  75. package/dist/app/mcp-app-view-states.d.ts +11 -3
  76. package/dist/app/mcp-app-view-states.d.ts.map +1 -1
  77. package/dist/app/mcp-app-view-states.js +29 -8
  78. package/dist/app/mcp-app-view-states.js.map +1 -1
  79. package/dist/app/mcp-app-view.d.ts +33 -1
  80. package/dist/app/mcp-app-view.d.ts.map +1 -1
  81. package/dist/app/mcp-app-view.js +181 -127
  82. package/dist/app/mcp-app-view.js.map +1 -1
  83. package/dist/app/mcp-toolkit-app.d.ts +6 -1
  84. package/dist/app/mcp-toolkit-app.d.ts.map +1 -1
  85. package/dist/app/mcp-toolkit-app.js +8 -1
  86. package/dist/app/mcp-toolkit-app.js.map +1 -1
  87. package/dist/app/mcp-use-host-bridge.d.ts +15 -6
  88. package/dist/app/mcp-use-host-bridge.d.ts.map +1 -1
  89. package/dist/app/mcp-use-host-bridge.js +51 -22
  90. package/dist/app/mcp-use-host-bridge.js.map +1 -1
  91. package/dist/app/model-context.d.ts +71 -0
  92. package/dist/app/model-context.d.ts.map +1 -0
  93. package/dist/app/model-context.js +101 -0
  94. package/dist/app/model-context.js.map +1 -0
  95. package/dist/app/use-build-mode-focus.d.ts +33 -0
  96. package/dist/app/use-build-mode-focus.d.ts.map +1 -0
  97. package/dist/app/use-build-mode-focus.js +59 -0
  98. package/dist/app/use-build-mode-focus.js.map +1 -0
  99. package/dist/app/use-view-actions.d.ts +31 -0
  100. package/dist/app/use-view-actions.d.ts.map +1 -0
  101. package/dist/app/use-view-actions.js +81 -0
  102. package/dist/app/use-view-actions.js.map +1 -0
  103. package/dist/app/use-view-lifecycle.d.ts +4 -0
  104. package/dist/app/use-view-lifecycle.d.ts.map +1 -1
  105. package/dist/app/use-view-lifecycle.js +2 -0
  106. package/dist/app/use-view-lifecycle.js.map +1 -1
  107. package/dist/app/view-lifecycle.d.ts +80 -4
  108. package/dist/app/view-lifecycle.d.ts.map +1 -1
  109. package/dist/app/view-lifecycle.js +90 -3
  110. package/dist/app/view-lifecycle.js.map +1 -1
  111. package/dist/app/widget-fixture.d.ts +10 -3
  112. package/dist/app/widget-fixture.d.ts.map +1 -1
  113. package/dist/app/widget-fixture.js +21 -8
  114. package/dist/app/widget-fixture.js.map +1 -1
  115. package/dist/app/widget-props-sheet.d.ts +3 -1
  116. package/dist/app/widget-props-sheet.d.ts.map +1 -1
  117. package/dist/app/widget-props-sheet.js +22 -10
  118. package/dist/app/widget-props-sheet.js.map +1 -1
  119. package/dist/app/widget-renderer.js +1 -1
  120. package/dist/app/widget-renderer.js.map +1 -1
  121. package/dist/components/DrillButton.d.ts +14 -6
  122. package/dist/components/DrillButton.d.ts.map +1 -1
  123. package/dist/components/DrillButton.js +14 -7
  124. package/dist/components/DrillButton.js.map +1 -1
  125. package/dist/components/EmptyState.d.ts.map +1 -1
  126. package/dist/components/EmptyState.js +4 -2
  127. package/dist/components/EmptyState.js.map +1 -1
  128. package/dist/components/ErrorState.d.ts +5 -2
  129. package/dist/components/ErrorState.d.ts.map +1 -1
  130. package/dist/components/ErrorState.js +25 -8
  131. package/dist/components/ErrorState.js.map +1 -1
  132. package/dist/components/FilterBar.d.ts +15 -4
  133. package/dist/components/FilterBar.d.ts.map +1 -1
  134. package/dist/components/FilterBar.js +11 -6
  135. package/dist/components/FilterBar.js.map +1 -1
  136. package/dist/components/KpiGrid.d.ts +66 -21
  137. package/dist/components/KpiGrid.d.ts.map +1 -1
  138. package/dist/components/KpiGrid.js +101 -34
  139. package/dist/components/KpiGrid.js.map +1 -1
  140. package/dist/components/ListFooter.d.ts +31 -4
  141. package/dist/components/ListFooter.d.ts.map +1 -1
  142. package/dist/components/ListFooter.js +30 -11
  143. package/dist/components/ListFooter.js.map +1 -1
  144. package/dist/components/PagedListFooter.d.ts +57 -0
  145. package/dist/components/PagedListFooter.d.ts.map +1 -0
  146. package/dist/components/PagedListFooter.js +27 -0
  147. package/dist/components/PagedListFooter.js.map +1 -0
  148. package/dist/components/Pills.d.ts +27 -7
  149. package/dist/components/Pills.d.ts.map +1 -1
  150. package/dist/components/Pills.js +21 -6
  151. package/dist/components/Pills.js.map +1 -1
  152. package/dist/components/SectionHeading.d.ts +3 -1
  153. package/dist/components/SectionHeading.d.ts.map +1 -1
  154. package/dist/components/SectionHeading.js +6 -2
  155. package/dist/components/SectionHeading.js.map +1 -1
  156. package/dist/components/Toast.d.ts +9 -3
  157. package/dist/components/Toast.d.ts.map +1 -1
  158. package/dist/components/Toast.js +31 -16
  159. package/dist/components/Toast.js.map +1 -1
  160. package/dist/components/WidgetHeader.d.ts +34 -10
  161. package/dist/components/WidgetHeader.d.ts.map +1 -1
  162. package/dist/components/WidgetHeader.js +11 -6
  163. package/dist/components/WidgetHeader.js.map +1 -1
  164. package/dist/hooks/index.d.ts +4 -4
  165. package/dist/hooks/index.d.ts.map +1 -1
  166. package/dist/hooks/index.js +1 -1
  167. package/dist/hooks/index.js.map +1 -1
  168. package/dist/hooks/tool-result-recovery-model.d.ts +155 -0
  169. package/dist/hooks/tool-result-recovery-model.d.ts.map +1 -0
  170. package/dist/hooks/tool-result-recovery-model.js +273 -0
  171. package/dist/hooks/tool-result-recovery-model.js.map +1 -0
  172. package/dist/hooks/use-tool-query.d.ts +56 -14
  173. package/dist/hooks/use-tool-query.d.ts.map +1 -1
  174. package/dist/hooks/use-tool-query.js +102 -25
  175. package/dist/hooks/use-tool-query.js.map +1 -1
  176. package/dist/hooks/use-tool-result-recovery.d.ts +47 -52
  177. package/dist/hooks/use-tool-result-recovery.d.ts.map +1 -1
  178. package/dist/hooks/use-tool-result-recovery.js +58 -120
  179. package/dist/hooks/use-tool-result-recovery.js.map +1 -1
  180. package/dist/hooks/use-view-data.d.ts +52 -10
  181. package/dist/hooks/use-view-data.d.ts.map +1 -1
  182. package/dist/hooks/use-view-data.js +81 -16
  183. package/dist/hooks/use-view-data.js.map +1 -1
  184. package/dist/hooks/use-view-tool-query.d.ts +12 -7
  185. package/dist/hooks/use-view-tool-query.d.ts.map +1 -1
  186. package/dist/hooks/use-view-tool-query.js +15 -14
  187. package/dist/hooks/use-view-tool-query.js.map +1 -1
  188. package/dist/index.d.ts +17 -10
  189. package/dist/index.d.ts.map +1 -1
  190. package/dist/index.js +18 -6
  191. package/dist/index.js.map +1 -1
  192. package/dist/lib/focus-return.d.ts +61 -0
  193. package/dist/lib/focus-return.d.ts.map +1 -0
  194. package/dist/lib/focus-return.js +46 -0
  195. package/dist/lib/focus-return.js.map +1 -0
  196. package/dist/lib/parse-tool-result.d.ts +23 -1
  197. package/dist/lib/parse-tool-result.d.ts.map +1 -1
  198. package/dist/lib/parse-tool-result.js +38 -2
  199. package/dist/lib/parse-tool-result.js.map +1 -1
  200. package/dist/lib/toast-model.d.ts +41 -1
  201. package/dist/lib/toast-model.d.ts.map +1 -1
  202. package/dist/lib/toast-model.js +67 -1
  203. package/dist/lib/toast-model.js.map +1 -1
  204. package/dist/lib/tone-utils.d.ts +58 -6
  205. package/dist/lib/tone-utils.d.ts.map +1 -1
  206. package/dist/lib/tone-utils.js +66 -4
  207. package/dist/lib/tone-utils.js.map +1 -1
  208. package/dist/lib/tool-query.d.ts +107 -0
  209. package/dist/lib/tool-query.d.ts.map +1 -0
  210. package/dist/lib/tool-query.js +182 -0
  211. package/dist/lib/tool-query.js.map +1 -0
  212. package/dist/lib/tool-result-observer.d.ts +108 -0
  213. package/dist/lib/tool-result-observer.d.ts.map +1 -0
  214. package/dist/lib/tool-result-observer.js +158 -0
  215. package/dist/lib/tool-result-observer.js.map +1 -0
  216. package/dist/lib/typography.d.ts +37 -0
  217. package/dist/lib/typography.d.ts.map +1 -0
  218. package/dist/lib/typography.js +41 -0
  219. package/dist/lib/typography.js.map +1 -0
  220. package/dist/lib/utils.d.ts.map +1 -1
  221. package/dist/lib/utils.js +11 -1
  222. package/dist/lib/utils.js.map +1 -1
  223. package/dist/locale/index.d.ts +1 -1
  224. package/dist/locale/index.d.ts.map +1 -1
  225. package/dist/locale/message-types.d.ts +117 -4
  226. package/dist/locale/message-types.d.ts.map +1 -1
  227. package/dist/locale/messages-de.d.ts.map +1 -1
  228. package/dist/locale/messages-de.js +44 -10
  229. package/dist/locale/messages-de.js.map +1 -1
  230. package/dist/locale/messages-en.d.ts.map +1 -1
  231. package/dist/locale/messages-en.js +44 -10
  232. package/dist/locale/messages-en.js.map +1 -1
  233. package/dist/locale/toolkit-messages.d.ts +19 -1
  234. package/dist/locale/toolkit-messages.d.ts.map +1 -1
  235. package/dist/locale/toolkit-messages.js +54 -1
  236. package/dist/locale/toolkit-messages.js.map +1 -1
  237. package/dist/primitives/alert.d.ts +1 -1
  238. package/dist/primitives/alert.d.ts.map +1 -1
  239. package/dist/primitives/alert.js +2 -0
  240. package/dist/primitives/alert.js.map +1 -1
  241. package/dist/primitives/badge.d.ts +1 -1
  242. package/dist/primitives/badge.d.ts.map +1 -1
  243. package/dist/primitives/badge.js +9 -4
  244. package/dist/primitives/badge.js.map +1 -1
  245. package/dist/primitives/button.d.ts +1 -1
  246. package/dist/primitives/button.js +1 -1
  247. package/dist/primitives/button.js.map +1 -1
  248. package/dist/primitives/dialog.d.ts +1 -1
  249. package/dist/primitives/dialog.d.ts.map +1 -1
  250. package/dist/primitives/dialog.js +10 -3
  251. package/dist/primitives/dialog.js.map +1 -1
  252. package/dist/primitives/select.js +1 -1
  253. package/dist/primitives/select.js.map +1 -1
  254. package/dist/primitives/sheet.d.ts +1 -1
  255. package/dist/primitives/sheet.d.ts.map +1 -1
  256. package/dist/primitives/sheet.js +6 -2
  257. package/dist/primitives/sheet.js.map +1 -1
  258. package/dist/providers/query-provider.d.ts +32 -1
  259. package/dist/providers/query-provider.d.ts.map +1 -1
  260. package/dist/providers/query-provider.js +53 -4
  261. package/dist/providers/query-provider.js.map +1 -1
  262. package/dist/render-cases-primitives.js +1 -1
  263. package/dist/render-cases-primitives.js.map +1 -1
  264. package/dist/render-cases.d.ts.map +1 -1
  265. package/dist/render-cases.js +30 -6
  266. package/dist/render-cases.js.map +1 -1
  267. package/dist/render-effects.d.ts +42 -0
  268. package/dist/render-effects.d.ts.map +1 -0
  269. package/dist/render-effects.js +81 -0
  270. package/dist/render-effects.js.map +1 -0
  271. package/dist/theme/create-theme.d.ts +19 -1
  272. package/dist/theme/create-theme.d.ts.map +1 -1
  273. package/dist/theme/create-theme.js +15 -0
  274. package/dist/theme/create-theme.js.map +1 -1
  275. package/package.json +5 -4
  276. package/src/app/adapt-data-widget.tsx +2 -42
  277. package/src/app/builder/BuilderBanners.tsx +1 -1
  278. package/src/app/builder/CanvasRow.tsx +63 -17
  279. package/src/app/builder/CatalogueSheet.tsx +50 -29
  280. package/src/app/builder/CellPropsSheet.tsx +17 -2
  281. package/src/app/builder/DiscardDialog.tsx +59 -0
  282. package/src/app/builder/LayoutSurface.tsx +206 -66
  283. package/src/app/builder/PipelineStrip.tsx +253 -153
  284. package/src/app/builder/SaveDialog.tsx +14 -2
  285. package/src/app/builder/Toolbar.tsx +144 -59
  286. package/src/app/builder/Workspace.tsx +226 -58
  287. package/src/app/builder/builder-model.ts +341 -2
  288. package/src/app/builder/builder-model.ux.test.ts +456 -0
  289. package/src/app/builder/builder-ux.test.tsx +844 -0
  290. package/src/app/builder/reveal.ts +10 -0
  291. package/src/app/builder/use-builder-catalogue.ts +56 -19
  292. package/src/app/builder/use-builder-session.ts +68 -0
  293. package/src/app/builder/use-display-resolver.ts +24 -0
  294. package/src/app/index.ts +12 -2
  295. package/src/app/layout-builder.tsx +178 -191
  296. package/src/app/mcp-app-view-chrome.test.tsx +141 -1
  297. package/src/app/mcp-app-view-chrome.tsx +56 -6
  298. package/src/app/mcp-app-view-states.tsx +51 -11
  299. package/src/app/mcp-app-view.effects.test.tsx +292 -0
  300. package/src/app/mcp-app-view.test.tsx +222 -2
  301. package/src/app/mcp-app-view.tsx +267 -117
  302. package/src/app/mcp-toolkit-app.test.tsx +40 -0
  303. package/src/app/mcp-toolkit-app.tsx +8 -1
  304. package/src/app/mcp-use-host-bridge.test.tsx +180 -0
  305. package/src/app/mcp-use-host-bridge.tsx +67 -24
  306. package/src/app/model-context.test.tsx +116 -0
  307. package/src/app/model-context.tsx +125 -0
  308. package/src/app/use-build-mode-focus.ts +62 -0
  309. package/src/app/use-view-actions.ts +89 -0
  310. package/src/app/use-view-lifecycle.ts +6 -0
  311. package/src/app/view-lifecycle.test.ts +216 -0
  312. package/src/app/view-lifecycle.ts +165 -5
  313. package/src/app/widget-fixture.effects.test.tsx +51 -0
  314. package/src/app/widget-fixture.render.test.tsx +81 -0
  315. package/src/app/widget-fixture.tsx +34 -11
  316. package/src/app/widget-props-sheet.tsx +57 -16
  317. package/src/app/widget-renderer.tsx +1 -1
  318. package/src/components/DrillButton.test.tsx +48 -0
  319. package/src/components/DrillButton.tsx +26 -11
  320. package/src/components/EmptyState.tsx +6 -4
  321. package/src/components/ErrorState.tsx +31 -9
  322. package/src/components/FilterBar.test.tsx +82 -0
  323. package/src/components/FilterBar.tsx +52 -26
  324. package/src/components/KpiGrid.test.tsx +279 -0
  325. package/src/components/KpiGrid.tsx +297 -90
  326. package/src/components/ListFooter.test.tsx +116 -0
  327. package/src/components/ListFooter.tsx +102 -15
  328. package/src/components/PagedListFooter.test.tsx +140 -0
  329. package/src/components/PagedListFooter.tsx +107 -0
  330. package/src/components/Pills.test.tsx +77 -0
  331. package/src/components/Pills.tsx +63 -10
  332. package/src/components/SectionHeading.tsx +9 -3
  333. package/src/components/Toast.tsx +37 -19
  334. package/src/components/WidgetHeader.test.tsx +78 -0
  335. package/src/components/WidgetHeader.tsx +63 -16
  336. package/src/components/feedback-states.test.tsx +98 -9
  337. package/src/components/tone-figures.test.tsx +8 -4
  338. package/src/hooks/index.ts +6 -3
  339. package/src/hooks/tool-result-recovery-model.test.ts +744 -0
  340. package/src/hooks/tool-result-recovery-model.ts +418 -0
  341. package/src/hooks/use-tool-query.effects.test.tsx +205 -0
  342. package/src/hooks/use-tool-query.ts +156 -33
  343. package/src/hooks/use-tool-result-recovery.effects.test.tsx +141 -0
  344. package/src/hooks/use-tool-result-recovery.test.ts +3 -4
  345. package/src/hooks/use-tool-result-recovery.ts +84 -142
  346. package/src/hooks/use-view-data.test.tsx +118 -9
  347. package/src/hooks/use-view-data.ts +128 -18
  348. package/src/hooks/use-view-tool-query.ts +25 -19
  349. package/src/i18n-coverage.test.tsx +104 -2
  350. package/src/index.ts +48 -11
  351. package/src/lib/focus-return.test.ts +288 -0
  352. package/src/lib/focus-return.ts +96 -0
  353. package/src/lib/parse-tool-result.test.ts +46 -1
  354. package/src/lib/parse-tool-result.ts +40 -2
  355. package/src/lib/toast-model.test.ts +166 -1
  356. package/src/lib/toast-model.ts +104 -2
  357. package/src/lib/tone-utils.test.ts +86 -10
  358. package/src/lib/tone-utils.ts +89 -8
  359. package/src/lib/tool-query.test.ts +569 -0
  360. package/src/lib/tool-query.ts +253 -0
  361. package/src/lib/tool-result-observer.test.ts +296 -0
  362. package/src/lib/tool-result-observer.ts +211 -0
  363. package/src/lib/typography.test.ts +45 -0
  364. package/src/lib/typography.ts +47 -0
  365. package/src/lib/utils.ts +12 -1
  366. package/src/locale/index.ts +1 -0
  367. package/src/locale/message-types.ts +118 -2
  368. package/src/locale/messages-de.ts +49 -10
  369. package/src/locale/messages-en.ts +49 -10
  370. package/src/locale/toolkit-messages.test.ts +133 -0
  371. package/src/locale/toolkit-messages.ts +63 -2
  372. package/src/primitives/alert.tsx +3 -0
  373. package/src/primitives/badge.tsx +9 -4
  374. package/src/primitives/button.tsx +1 -1
  375. package/src/primitives/dialog.tsx +10 -1
  376. package/src/primitives/select.tsx +1 -1
  377. package/src/primitives/sheet.tsx +7 -0
  378. package/src/providers/query-provider.test.tsx +154 -0
  379. package/src/providers/query-provider.tsx +66 -5
  380. package/src/render-cases-primitives.tsx +1 -1
  381. package/src/render-cases.tsx +38 -6
  382. package/src/render-effects.tsx +96 -0
  383. package/src/theme/cd-tokens.test.ts +3 -1
  384. package/src/theme/create-theme.test.ts +10 -0
  385. package/src/theme/create-theme.ts +28 -0
  386. package/src/theme/theme-css.test.ts +51 -0
  387. package/src/theme.css +31 -1
  388. package/ui-catalog.json +448 -41
@@ -1,57 +1,124 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { FOCUS_RING_INSET } from "../lib/focus-ring.js";
3
- import { TONE_DOT } from "../lib/tone-utils.js";
2
+ import { useId } from "react";
3
+ import { ChevronRight, Minus, TrendingDown, TrendingUp } from "lucide-react";
4
+ import { FOCUS_RING_INSET, FOCUS_RING } from "../lib/focus-ring.js";
5
+ import { resolveTone, TONE_BORDER, TONE_DOT, TONE_ICON, TONE_TINT, } from "../lib/tone-utils.js";
6
+ import { MICRO_LABEL } from "../lib/typography.js";
7
+ import { cn } from "../lib/utils.js";
8
+ import { Skeleton } from "../primitives/skeleton.js";
4
9
  /**
5
- * Trend direction → tone. The tone shows ONLY as a dot before the trend line;
6
- * the figures stay in the foreground (no coloured digits, CI §3.3).
10
+ * Direction → tone when no `trendTone` is set (incident-biased: up reads as
11
+ * worse). The tone shows ONLY as the direction icon's colour or a dot; the
12
+ * trend words stay neutral (no coloured digits, CI §3.3).
7
13
  */
8
14
  const TREND_TONE = {
9
15
  up: "danger",
10
16
  down: "success",
11
17
  flat: "neutral",
12
18
  };
19
+ const TREND_ICON = {
20
+ up: TrendingUp,
21
+ down: TrendingDown,
22
+ flat: Minus,
23
+ };
24
+ /**
25
+ * Columns per cell count. 4+ cells fall back to 2 columns in narrow frames
26
+ * (inline chat views are often under 500 px, where five cells side by side
27
+ * leave ~40 px each); 6 steps through 3.
28
+ */
13
29
  const COL_CLASS = {
14
30
  1: "grid-cols-1",
15
31
  2: "grid-cols-2",
16
32
  3: "grid-cols-3",
17
- 4: "grid-cols-4",
18
- 5: "grid-cols-5",
19
- 6: "grid-cols-6",
33
+ 4: "grid-cols-2 sm:grid-cols-4",
34
+ 5: "grid-cols-2 sm:grid-cols-5",
35
+ 6: "grid-cols-2 sm:grid-cols-3 lg:grid-cols-6",
20
36
  };
37
+ /** The responsive column classes for `count` cells (clamped to 1–6). */
38
+ export function kpiColumns(count) {
39
+ const cols = Math.min(Math.max(Math.trunc(count) || 1, 1), 6);
40
+ return COL_CLASS[cols] ?? "grid-cols-1";
41
+ }
21
42
  /** A small status dot; decorative — the label next to it carries the meaning. */
22
- function ToneDot({ tone, size }) {
23
- return _jsx("span", { "aria-hidden": "true", className: `${size} shrink-0 rounded-full ${TONE_DOT[tone]}` });
43
+ function ToneDot({ tone, className }) {
44
+ return (_jsx("span", { "aria-hidden": "true", "data-tone": tone, className: cn("shrink-0 rounded-full", className, TONE_DOT[tone]) }));
45
+ }
46
+ /**
47
+ * The trend line: neutral words (the foreground next to a state, quiet
48
+ * without one) and the state beside them as a direction icon or a dot in the
49
+ * tone — never as coloured digits.
50
+ */
51
+ function TrendLine({ cell }) {
52
+ const direction = cell.trendDirection;
53
+ const tone = cell.trendTone !== undefined
54
+ ? resolveTone(cell.trendTone)
55
+ : direction
56
+ ? TREND_TONE[direction]
57
+ : "neutral";
58
+ const marked = tone !== "neutral";
59
+ const Icon = direction ? TREND_ICON[direction] : undefined;
60
+ return (_jsxs("div", { "data-slot": "kpi-trend", className: "text-small mt-1.5 flex items-center gap-1.5", children: [Icon ? (_jsx(Icon, { "aria-hidden": "true", className: cn("size-4 shrink-0", TONE_ICON[tone]) })) : (marked && _jsx(ToneDot, { tone: tone, className: "size-1.5" })), _jsx("span", { className: marked ? "text-foreground" : "text-muted-foreground", children: cell.trend })] }));
61
+ }
62
+ /** Label, figure, fraction and trend — shared by the strip and soft variants. */
63
+ function KpiCellBody({ cell, variant }) {
64
+ const tone = resolveTone(cell.tone);
65
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: cn("text-small flex items-center justify-between gap-2 font-medium", variant === "strip" ? "text-muted-foreground" : "text-foreground"), children: [_jsxs("span", { className: "inline-flex min-w-0 items-center gap-1.5", children: [variant === "strip" && tone !== "neutral" && _jsx(ToneDot, { tone: tone, className: "size-2" }), _jsx("span", { className: "min-w-0 break-words", children: cell.label })] }), cell.onClick && _jsx(ChevronRight, { "aria-hidden": "true", className: "size-4 shrink-0" })] }), _jsxs("div", { className: "text-title text-foreground mt-1.5 leading-none tracking-tight break-words tabular-nums", children: [cell.value, cell.fraction && (_jsx("span", { className: "text-dense text-muted-foreground ml-0.5 font-normal", children: cell.fraction }))] }), cell.trend && _jsx(TrendLine, { cell: cell })] }));
66
+ }
67
+ /** One cell: a button when clickable (named by its visible text), else a plain box. */
68
+ function KpiCellView({ cell, variant, className, }) {
69
+ const hintId = useId();
70
+ const body = _jsx(KpiCellBody, { cell: cell, variant: variant });
71
+ const tone = cell.tone === undefined ? undefined : resolveTone(cell.tone);
72
+ if (!cell.onClick) {
73
+ return (_jsx("div", { "data-tone": tone, className: className, children: body }));
74
+ }
75
+ return (_jsxs("button", { type: "button", onClick: cell.onClick, "aria-label": cell.ariaLabel, "aria-describedby": cell.actionHint ? hintId : undefined, "data-tone": tone, className: cn("cursor-pointer text-left transition-colors", variant === "strip" ? cn("hover:bg-muted", FOCUS_RING_INSET) : FOCUS_RING, className), children: [body, cell.actionHint && (_jsx("span", { id: hintId, hidden: true, children: cell.actionHint }))] }));
76
+ }
77
+ /** A soft card: the tone's tint and edge around neutral text. */
78
+ function softCardClass(tone) {
79
+ const t = resolveTone(tone);
80
+ return cn("text-foreground rounded-lg border p-4", TONE_TINT[t], TONE_BORDER[t]);
24
81
  }
25
82
  /**
26
- * The trend line under a value: a tone dot plus the trend text in the
27
- * foreground — never in a tone colour. Without a tone it stays quiet text.
83
+ * The strip's dividers. Each cell draws its own right and bottom rule, and the
84
+ * grid reaches 1 px past its clipping frame, so the rules on the outer edges
85
+ * fall away at any column count. An empty track in a short last row (5 cells
86
+ * in 2 columns, 7 in 6) keeps the card colour: a `gap-px` grid on a
87
+ * `bg-border` container would paint it as a solid block of the divider colour.
28
88
  */
29
- function KpiTrend({ trend, direction, }) {
30
- const tone = direction ? TREND_TONE[direction] : "neutral";
31
- const textClass = tone === "neutral" ? "text-muted-foreground" : "text-foreground";
32
- return (_jsxs("div", { className: `mt-1.5 inline-flex items-center gap-1.5 text-xs ${textClass}`, children: [tone !== "neutral" && _jsx(ToneDot, { tone: tone, size: "size-1.5" }), trend] }));
89
+ const STRIP_FRAME = "bg-card overflow-hidden";
90
+ const STRIP_GRID = "-mr-px -mb-px grid";
91
+ const STRIP_CELL = "border-border min-w-0 border-r border-b px-5 py-4";
92
+ function KpiStripHeader({ header }) {
93
+ return (_jsxs("div", { className: cn("border-border bg-muted text-muted-foreground flex items-center gap-2 border-b px-4 py-2", MICRO_LABEL), children: [_jsx("span", { children: header.label }), header.badge && (_jsx("span", { className: "border-border bg-card text-muted-foreground text-small rounded-sm border px-1.5 font-medium", children: header.badge }))] }));
33
94
  }
34
- /** One cell's label row, figure and optional trend — status as dots, never as coloured digits. */
35
- function KpiCellContent({ cell }) {
36
- return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "text-muted-foreground flex items-center justify-between gap-2 text-xs font-medium", children: [_jsxs("span", { className: "inline-flex min-w-0 items-center gap-1.5", children: [cell.tone && cell.tone !== "neutral" && _jsx(ToneDot, { tone: cell.tone, size: "size-2" }), _jsx("span", { children: cell.label })] }), cell.onClick && (_jsx("span", { "aria-hidden": "true", className: "text-sm leading-none", children: "\u203A" }))] }), _jsxs("div", { className: "text-foreground mt-1.5 text-2xl leading-none font-bold tracking-tight tabular-nums", children: [cell.value, cell.fraction && (_jsx("span", { className: "text-muted-foreground ml-0.5 text-sm font-normal", children: cell.fraction }))] }), cell.trend && _jsx(KpiTrend, { trend: cell.trend, direction: cell.trendDirection })] }));
95
+ /**
96
+ * A row of headline metrics — the canonical way to show KPIs in a widget
97
+ * (replaces the single-metric KPICard). Cells flow as columns (1–6), falling
98
+ * back to 2 columns in narrow frames. A cell's `tone` shows as a dot next to
99
+ * its label (or as a soft card's tint and edge); figures stay in the
100
+ * foreground colour. A clickable cell is a button whose accessible name is
101
+ * its visible label and value; `actionHint` describes what the click does.
102
+ */
103
+ export function KpiGrid({ cells, boxed = false, header, variant = "strip", ariaLabel, className, }) {
104
+ const colClass = kpiColumns(cells.length);
105
+ const group = ariaLabel ? { role: "group", "aria-label": ariaLabel } : {};
106
+ if (variant === "soft") {
107
+ return (_jsx("div", { ...group, "data-slot": "kpi-grid", className: cn("grid gap-4", colClass, className), children: cells.map((cell, idx) => (_jsx(KpiCellView, { cell: cell, variant: "soft", className: cn("min-w-0", softCardClass(cell.tone)) }, idx))) }));
108
+ }
109
+ return (_jsxs("div", { ...group, "data-slot": "kpi-grid", className: cn(boxed && "border-border overflow-hidden rounded-lg border", className), children: [header && _jsx(KpiStripHeader, { header: header }), _jsx("div", { "data-slot": "kpi-strip", className: cn(STRIP_FRAME, !boxed && "border-border border-y"), children: _jsx("div", { className: cn(STRIP_GRID, colClass), children: cells.map((cell, idx) => (_jsx(KpiCellView, { cell: cell, variant: "strip", className: STRIP_CELL }, idx))) }) })] }));
37
110
  }
38
111
  /**
39
- * Bordered strip of KPI cells — the canonical way to show a row of headline
40
- * metrics in a widget (replaces the single-metric KPICard). Cells flow as
41
- * columns (1–6) and can be made clickable to drill into a detail view. Use
42
- * `boxed` + `header` for a labelled metric block; unboxed (default) renders the
43
- * lighter `border-y` strip. A cell's `tone` shows as a status dot next to its
44
- * label; figures stay in the foreground colour.
112
+ * Loading placeholder with {@link KpiGrid}'s geometry (same wrapper, grid and
113
+ * cell padding in both variants), so the layout doesn't jump when the data
114
+ * arrives. `aria-busy`; pair it with a status line if the wait is long.
45
115
  */
46
- export function KpiGrid({ cells, boxed = false, header }) {
47
- const cols = Math.min(Math.max(cells.length, 1), 6);
48
- const colClass = COL_CLASS[cols] ?? "grid-cols-4";
49
- const wrapperClass = boxed ? "border-border overflow-hidden rounded-lg border" : "";
50
- const stripClass = boxed ? "" : "border-border border-y";
51
- return (_jsxs("div", { className: wrapperClass, children: [header && (_jsxs("div", { className: "border-border bg-muted text-muted-foreground flex items-center gap-2 border-b px-4 py-2 text-[11px] font-semibold tracking-wide uppercase", children: [_jsx("span", { children: header.label }), header.badge && (_jsx("span", { className: "border-border bg-card text-muted-foreground rounded-sm border px-1.5 py-0 text-[10px] font-medium normal-case", children: header.badge }))] })), _jsx("div", { className: `grid ${colClass} ${stripClass}`, children: cells.map((cell, idx) => {
52
- const borderClass = idx < cells.length - 1 ? "border-border border-r" : "";
53
- const content = _jsx(KpiCellContent, { cell: cell });
54
- return cell.onClick ? (_jsx("button", { type: "button", onClick: cell.onClick, "aria-label": cell.ariaLabel, className: `hover:bg-muted cursor-pointer px-5 py-4 text-left transition-colors ${FOCUS_RING_INSET} ${borderClass}`, children: content }, idx)) : (_jsx("div", { className: `px-5 py-4 ${borderClass}`, children: content }, idx));
55
- }) })] }));
116
+ export function KpiGridSkeleton({ cells, variant = "strip", boxed = false, className, }) {
117
+ const colClass = kpiColumns(cells);
118
+ const count = Math.max(Math.trunc(cells) || 0, 0);
119
+ if (variant === "soft") {
120
+ return (_jsx("div", { "aria-busy": "true", className: cn("grid gap-4", colClass, className), children: Array.from({ length: count }, (_, idx) => (_jsxs("div", { className: "bg-muted border-border rounded-lg border p-4", children: [_jsx(Skeleton, { className: "h-4 w-20" }), _jsx(Skeleton, { className: "mt-2 h-7 w-14" })] }, idx))) }));
121
+ }
122
+ return (_jsx("div", { "aria-busy": "true", className: cn(boxed && "border-border overflow-hidden rounded-lg border", className), children: _jsx("div", { "data-slot": "kpi-strip", className: cn(STRIP_FRAME, !boxed && "border-border border-y"), children: _jsx("div", { className: cn(STRIP_GRID, colClass), children: Array.from({ length: count }, (_, idx) => (_jsxs("div", { className: STRIP_CELL, children: [_jsx(Skeleton, { className: "h-4 w-16" }), _jsx(Skeleton, { className: "mt-2.5 h-7 w-14" })] }, idx))) }) }) }));
56
123
  }
57
124
  //# sourceMappingURL=KpiGrid.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"KpiGrid.js","sourceRoot":"","sources":["../../src/components/KpiGrid.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"KpiGrid.js","sourceRoot":"","sources":["../../src/components/KpiGrid.tsx"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import type { ListFooterMessages } from "../locale/message-types.js";
1
2
  export interface ListFooterProps {
2
3
  /** How many rows are currently rendered. */
3
4
  shown: number;
@@ -11,13 +12,39 @@ export interface ListFooterProps {
11
12
  onLoadMore: () => void;
12
13
  /** Plural noun for the count, e.g. `"instances"`. Default: the locale's word for rows. */
13
14
  noun?: string;
15
+ /**
16
+ * A new first page is in flight while these rows stay on screen (a search,
17
+ * a filter, a refetch): the status line adds a visible "Updating…".
18
+ */
19
+ refreshing?: boolean;
20
+ /**
21
+ * The rows on screen are the PREVIOUS result (a changed search or filter is
22
+ * in flight or failed): the count and "Load more" hide, so the old count
23
+ * never reads as the new search's answer.
24
+ */
25
+ stale?: boolean;
26
+ /** Override strings of the active catalog's `listFooter` section. */
27
+ labels?: Partial<ListFooterMessages>;
28
+ /**
29
+ * Make the count line a polite live region (`role="status"`). Default
30
+ * `true`. Set `false` only where the caller already announces the count in
31
+ * a live region of its own, so a screen reader hears it once.
32
+ */
33
+ announce?: boolean;
34
+ className?: string;
14
35
  }
15
36
  /**
16
37
  * Footer for a paginated list: an honest "Showing X of Y" total plus an
17
38
  * explicit "Load more" control. Deliberately not infinite scroll — the user
18
- * gets the total, a reachable footer, and control over fetching. Renders
19
- * nothing when `total` is 0. Text and number format follow the active locale
20
- * (`LocaleProvider`, else the host's inside `McpAppView`).
39
+ * gets the total, a reachable footer, and control over fetching. The count
40
+ * is a polite live region (`role="status"`), so a keyboard or screen-reader
41
+ * user hears the new total after "Load more" or a filter change; while a
42
+ * first page is in flight it also says "Updating…". With nothing to count and
43
+ * nothing in flight it shows nothing, but the live region stays mounted
44
+ * (visually hidden) and says "No entries": a search that finds nothing is
45
+ * announced too, and the region is never re-created with its news already in
46
+ * it (a screen reader stays silent then). Text and number format follow the
47
+ * active locale (`LocaleProvider`, else the host's inside `McpAppView`).
21
48
  */
22
- export declare function ListFooter({ shown, total, hasMore, loadingMore, onLoadMore, noun, }: ListFooterProps): import("react").JSX.Element | null;
49
+ export declare function ListFooter({ shown, total, hasMore, loadingMore, onLoadMore, noun, refreshing, stale, labels, announce, className, }: ListFooterProps): import("react").JSX.Element | null;
23
50
  //# sourceMappingURL=ListFooter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ListFooter.d.ts","sourceRoot":"","sources":["../../src/components/ListFooter.tsx"],"names":[],"mappings":"AAIA,MAAM,WAAW,eAAe;IAC9B,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAA;IACb,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAA;IACb,uCAAuC;IACvC,OAAO,EAAE,OAAO,CAAA;IAChB,gFAAgF;IAChF,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,mDAAmD;IACnD,UAAU,EAAE,MAAM,IAAI,CAAA;IACtB,0FAA0F;IAC1F,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,KAAK,EACL,OAAO,EACP,WAAmB,EACnB,UAAU,EACV,IAAI,GACL,EAAE,eAAe,sCAyBjB"}
1
+ {"version":3,"file":"ListFooter.d.ts","sourceRoot":"","sources":["../../src/components/ListFooter.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAA;AAGpE,MAAM,WAAW,eAAe;IAC9B,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAA;IACb,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAA;IACb,uCAAuC;IACvC,OAAO,EAAE,OAAO,CAAA;IAChB,gFAAgF;IAChF,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,mDAAmD;IACnD,UAAU,EAAE,MAAM,IAAI,CAAA;IACtB,0FAA0F;IAC1F,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,qEAAqE;IACrE,MAAM,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAA;IACpC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,KAAK,EACL,OAAO,EACP,WAAmB,EACnB,UAAU,EACV,IAAI,EACJ,UAAkB,EAClB,KAAa,EACb,MAAM,EACN,QAAe,EACf,SAAS,GACV,EAAE,eAAe,sCAwCjB"}
@@ -1,23 +1,42 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { FOCUS_RING } from "../lib/focus-ring.js";
3
+ import { cn } from "../lib/utils.js";
3
4
  import { useToolkitLocale, useToolkitMessages } from "../locale/locale-provider.js";
4
5
  import { formatCount } from "../locale/toolkit-messages.js";
5
6
  /**
6
7
  * Footer for a paginated list: an honest "Showing X of Y" total plus an
7
8
  * explicit "Load more" control. Deliberately not infinite scroll — the user
8
- * gets the total, a reachable footer, and control over fetching. Renders
9
- * nothing when `total` is 0. Text and number format follow the active locale
10
- * (`LocaleProvider`, else the host's inside `McpAppView`).
9
+ * gets the total, a reachable footer, and control over fetching. The count
10
+ * is a polite live region (`role="status"`), so a keyboard or screen-reader
11
+ * user hears the new total after "Load more" or a filter change; while a
12
+ * first page is in flight it also says "Updating…". With nothing to count and
13
+ * nothing in flight it shows nothing, but the live region stays mounted
14
+ * (visually hidden) and says "No entries": a search that finds nothing is
15
+ * announced too, and the region is never re-created with its news already in
16
+ * it (a screen reader stays silent then). Text and number format follow the
17
+ * active locale (`LocaleProvider`, else the host's inside `McpAppView`).
11
18
  */
12
- export function ListFooter({ shown, total, hasMore, loadingMore = false, onLoadMore, noun, }) {
13
- const locale = useToolkitLocale();
14
- const { listFooter } = useToolkitMessages();
15
- if (total <= 0)
19
+ export function ListFooter({ shown, total, hasMore, loadingMore = false, onLoadMore, noun, refreshing = false, stale = false, labels, announce = true, className, }) {
20
+ const listFooter = { ...useToolkitMessages().listFooter, ...labels };
21
+ const counted = total > 0 && !stale;
22
+ const visible = counted || refreshing;
23
+ // Without a live region of its own there is nothing to keep mounted.
24
+ if (!visible && !announce)
16
25
  return null;
17
- return (_jsxs("div", { className: "text-muted-foreground flex items-center justify-between gap-3 px-1 py-2 text-xs", children: [_jsx("span", { children: listFooter.showing({
26
+ return (_jsxs("div", { "data-slot": "list-footer",
27
+ // The same element tree in both states, so React keeps the live region.
28
+ className: visible ? cn(FOOTER_CLASS, className) : "sr-only", children: [_jsx("p", { role: announce ? "status" : undefined, "data-slot": "list-footer-status", className: "flex flex-wrap items-center gap-x-2", children: _jsx(StatusLine, { messages: listFooter, shown: shown, total: total, noun: noun, counted: counted, refreshing: refreshing,
29
+ // Zero rows, not a stale previous result (its failure the caller reports).
30
+ empty: !visible && !stale }) }), counted && hasMore && (_jsx("button", { type: "button", onClick: onLoadMore, disabled: loadingMore, className: `border-border text-foreground hover:border-focus hover:bg-accent hover:text-accent-foreground inline-flex items-center gap-1 rounded-md border px-3 py-1.5 font-medium transition-colors disabled:opacity-50 ${FOCUS_RING}`, children: loadingMore ? listFooter.loadingMore : listFooter.loadMore }))] }));
31
+ }
32
+ const FOOTER_CLASS = "text-small text-muted-foreground flex items-center justify-between gap-3 px-1 py-2";
33
+ /** What the live region says: the count, "Updating…", or "No entries" at zero rows. */
34
+ function StatusLine({ messages, shown, total, noun, counted, refreshing, empty, }) {
35
+ const locale = useToolkitLocale();
36
+ return (_jsxs(_Fragment, { children: [empty && _jsx("span", { children: messages.noResults }), counted && (_jsx("span", { children: messages.showing({
18
37
  shown: formatCount(shown, locale),
19
38
  total: formatCount(total, locale),
20
- noun: noun ?? listFooter.defaultNoun,
21
- }) }), hasMore && (_jsx("button", { type: "button", onClick: onLoadMore, disabled: loadingMore, className: `border-border text-foreground hover:border-focus hover:bg-accent hover:text-accent-foreground inline-flex items-center gap-1 rounded-md border px-3 py-1.5 font-medium transition-colors disabled:opacity-50 ${FOCUS_RING}`, children: loadingMore ? listFooter.loadingMore : listFooter.loadMore }))] }));
39
+ noun: noun ?? messages.defaultNoun,
40
+ }) })), refreshing && _jsx("span", { "data-slot": "list-footer-updating", children: messages.updating })] }));
22
41
  }
23
42
  //# sourceMappingURL=ListFooter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ListFooter.js","sourceRoot":"","sources":["../../src/components/ListFooter.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACjD,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAA;AACnF,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAA;AAiB3D;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAC,EACzB,KAAK,EACL,KAAK,EACL,OAAO,EACP,WAAW,GAAG,KAAK,EACnB,UAAU,EACV,IAAI,GACY;IAChB,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAA;IACjC,MAAM,EAAE,UAAU,EAAE,GAAG,kBAAkB,EAAE,CAAA;IAC3C,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,IAAI,CAAA;IAC3B,OAAO,CACL,eAAK,SAAS,EAAC,iFAAiF,aAC9F,yBACG,UAAU,CAAC,OAAO,CAAC;oBAClB,KAAK,EAAE,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC;oBACjC,KAAK,EAAE,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC;oBACjC,IAAI,EAAE,IAAI,IAAI,UAAU,CAAC,WAAW;iBACrC,CAAC,GACG,EACN,OAAO,IAAI,CACV,iBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,UAAU,EACnB,QAAQ,EAAE,WAAW,EACrB,SAAS,EAAE,gNAAgN,UAAU,EAAE,YAEtO,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,GACpD,CACV,IACG,CACP,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"ListFooter.js","sourceRoot":"","sources":["../../src/components/ListFooter.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACjD,OAAO,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAA;AACpC,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAA;AAEnF,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAA;AAqC3D;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,UAAU,CAAC,EACzB,KAAK,EACL,KAAK,EACL,OAAO,EACP,WAAW,GAAG,KAAK,EACnB,UAAU,EACV,IAAI,EACJ,UAAU,GAAG,KAAK,EAClB,KAAK,GAAG,KAAK,EACb,MAAM,EACN,QAAQ,GAAG,IAAI,EACf,SAAS,GACO;IAChB,MAAM,UAAU,GAAG,EAAE,GAAG,kBAAkB,EAAE,CAAC,UAAU,EAAE,GAAG,MAAM,EAAE,CAAA;IACpE,MAAM,OAAO,GAAG,KAAK,GAAG,CAAC,IAAI,CAAC,KAAK,CAAA;IACnC,MAAM,OAAO,GAAG,OAAO,IAAI,UAAU,CAAA;IACrC,qEAAqE;IACrE,IAAI,CAAC,OAAO,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAA;IACtC,OAAO,CACL,4BACY,aAAa;QACvB,wEAAwE;QACxE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,aAE5D,YACE,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,eAC3B,oBAAoB,EAC9B,SAAS,EAAC,qCAAqC,YAE/C,KAAC,UAAU,IACT,QAAQ,EAAE,UAAU,EACpB,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,UAAU;oBACtB,2EAA2E;oBAC3E,KAAK,EAAE,CAAC,OAAO,IAAI,CAAC,KAAK,GACzB,GACA,EACH,OAAO,IAAI,OAAO,IAAI,CACrB,iBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,UAAU,EACnB,QAAQ,EAAE,WAAW,EACrB,SAAS,EAAE,gNAAgN,UAAU,EAAE,YAEtO,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,GACpD,CACV,IACG,CACP,CAAA;AACH,CAAC;AAED,MAAM,YAAY,GAChB,oFAAoF,CAAA;AAEtF,uFAAuF;AACvF,SAAS,UAAU,CAAC,EAClB,QAAQ,EACR,KAAK,EACL,KAAK,EACL,IAAI,EACJ,OAAO,EACP,UAAU,EACV,KAAK,GASN;IACC,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAA;IACjC,OAAO,CACL,8BACG,KAAK,IAAI,yBAAO,QAAQ,CAAC,SAAS,GAAQ,EAC1C,OAAO,IAAI,CACV,yBACG,QAAQ,CAAC,OAAO,CAAC;oBAChB,KAAK,EAAE,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC;oBACjC,KAAK,EAAE,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC;oBACjC,IAAI,EAAE,IAAI,IAAI,QAAQ,CAAC,WAAW;iBACnC,CAAC,GACG,CACR,EACA,UAAU,IAAI,4BAAgB,sBAAsB,YAAE,QAAQ,CAAC,QAAQ,GAAQ,IAC/E,CACJ,CAAA;AACH,CAAC"}
@@ -0,0 +1,57 @@
1
+ import type { ListFooterMessages } from "../locale/message-types.js";
2
+ /**
3
+ * What {@link PagedListFooter} reads from a paged list — structural, so a
4
+ * paged-query hook's result (`items`, `total`, `loadMore`, …) passes as is.
5
+ */
6
+ export interface PagedListState {
7
+ /** The rows on screen (all loaded pages); its length is the "shown" count. */
8
+ items: readonly unknown[];
9
+ /** The server's total for the rows on screen. */
10
+ total: number;
11
+ /** Whether another page exists. */
12
+ hasMore: boolean;
13
+ /** Fetch the next page (also the retry of a failed load-more). */
14
+ loadMore: () => void;
15
+ /** A next page is in flight. */
16
+ loadingMore?: boolean;
17
+ /** A first page is in flight while rows are on screen (a search, a filter, a refetch). */
18
+ refreshing?: boolean;
19
+ /** The rows on screen are the previous result: a changed search or filter is in flight or failed. */
20
+ stale?: boolean;
21
+ /**
22
+ * The first page that is on screen, if any. A first-page {@link error} only
23
+ * belongs in the footer while one is shown; without rows on screen it is
24
+ * the load error the caller's loading guard renders.
25
+ */
26
+ firstPage?: unknown;
27
+ /** The first-page failure (see {@link firstPage}). */
28
+ error?: Error | null;
29
+ /** Re-run the first page — the retry of {@link error}. */
30
+ retry?: () => void;
31
+ /** The last load-more failure; {@link loadMore} retries it, the rows above stay current. */
32
+ loadMoreError?: Error | null;
33
+ }
34
+ export interface PagedListFooterProps {
35
+ /** The paged list's state. */
36
+ paged: PagedListState;
37
+ /** Plural noun for "Showing X of Y {noun}". Default: the locale's word for rows. */
38
+ noun?: string;
39
+ /** Override strings of the active catalog's `listFooter` section. */
40
+ labels?: Partial<ListFooterMessages>;
41
+ /** Retry button label of both error lines. Default: the locale's "Try again". */
42
+ retryLabel?: string;
43
+ }
44
+ /**
45
+ * The tail of a paged list: its failures and the honest {@link ListFooter}.
46
+ * Two failures stay apart because their retries differ — a failed first page
47
+ * over the rows still on screen ("You're seeing the previous result", its
48
+ * retry re-runs page 0) and a failed load-more ("The entries above are
49
+ * current", its retry fetches the next offset). Each is an inline
50
+ * `ErrorState` (role="alert") with the raw reason under "Details". The
51
+ * footer's count line is a polite live region that says "Updating…" while a
52
+ * first page is in flight, hides the count while the rows are stale, and
53
+ * stays mounted at zero rows ("No entries", visually hidden), so a search
54
+ * that finds nothing is announced.
55
+ */
56
+ export declare function PagedListFooter({ paged, noun, labels, retryLabel }: PagedListFooterProps): import("react").JSX.Element;
57
+ //# sourceMappingURL=PagedListFooter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PagedListFooter.d.ts","sourceRoot":"","sources":["../../src/components/PagedListFooter.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAA;AAIpE;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,8EAA8E;IAC9E,KAAK,EAAE,SAAS,OAAO,EAAE,CAAA;IACzB,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAA;IACb,mCAAmC;IACnC,OAAO,EAAE,OAAO,CAAA;IAChB,kEAAkE;IAClE,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,gCAAgC;IAChC,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,0FAA0F;IAC1F,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,qGAAqG;IACrG,KAAK,CAAC,EAAE,OAAO,CAAA;IACf;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,sDAAsD;IACtD,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,CAAA;IACpB,0DAA0D;IAC1D,KAAK,CAAC,EAAE,MAAM,IAAI,CAAA;IAClB,4FAA4F;IAC5F,aAAa,CAAC,EAAE,KAAK,GAAG,IAAI,CAAA;CAC7B;AAED,MAAM,WAAW,oBAAoB;IACnC,8BAA8B;IAC9B,KAAK,EAAE,cAAc,CAAA;IACrB,oFAAoF;IACpF,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,qEAAqE;IACrE,MAAM,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAA;IACpC,iFAAiF;IACjF,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAOD;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,oBAAoB,+BAwCxF"}
@@ -0,0 +1,27 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useToolkitMessages } from "../locale/locale-provider.js";
3
+ import { ErrorState } from "./ErrorState.js";
4
+ import { ListFooter } from "./ListFooter.js";
5
+ /** The raw reason of a failure, for the "Details" disclosure (never the sentence). */
6
+ function rawReason(error) {
7
+ return error.message || error.name;
8
+ }
9
+ /**
10
+ * The tail of a paged list: its failures and the honest {@link ListFooter}.
11
+ * Two failures stay apart because their retries differ — a failed first page
12
+ * over the rows still on screen ("You're seeing the previous result", its
13
+ * retry re-runs page 0) and a failed load-more ("The entries above are
14
+ * current", its retry fetches the next offset). Each is an inline
15
+ * `ErrorState` (role="alert") with the raw reason under "Details". The
16
+ * footer's count line is a polite live region that says "Updating…" while a
17
+ * first page is in flight, hides the count while the rows are stale, and
18
+ * stays mounted at zero rows ("No entries", visually hidden), so a search
19
+ * that finds nothing is announced.
20
+ */
21
+ export function PagedListFooter({ paged, noun, labels, retryLabel }) {
22
+ const catalog = useToolkitMessages().listFooter;
23
+ const L = { ...catalog, ...labels };
24
+ const refreshError = paged.firstPage != null ? (paged.error ?? null) : null;
25
+ return (_jsxs("div", { "data-slot": "paged-list-footer", className: "flex flex-col gap-2", children: [refreshError && (_jsx(ErrorState, { variant: "inline", tone: "warning", title: L.refreshFailed, description: L.refreshFailedHint, details: rawReason(refreshError), onRetry: paged.retry, retryLabel: retryLabel })), paged.loadMoreError && (_jsx(ErrorState, { variant: "inline", title: L.loadMoreFailed, description: L.loadMoreFailedHint, details: rawReason(paged.loadMoreError), onRetry: paged.loadMore, retryLabel: retryLabel })), _jsx(ListFooter, { shown: paged.items.length, total: paged.total, hasMore: paged.hasMore, loadingMore: paged.loadingMore, onLoadMore: paged.loadMore, noun: noun, refreshing: paged.refreshing, stale: paged.stale, labels: labels })] }));
26
+ }
27
+ //# sourceMappingURL=PagedListFooter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PagedListFooter.js","sourceRoot":"","sources":["../../src/components/PagedListFooter.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAA;AAEjE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AA8C5C,sFAAsF;AACtF,SAAS,SAAS,CAAC,KAAY;IAC7B,OAAO,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,IAAI,CAAA;AACpC,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,eAAe,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAwB;IACvF,MAAM,OAAO,GAAG,kBAAkB,EAAE,CAAC,UAAU,CAAA;IAC/C,MAAM,CAAC,GAAG,EAAE,GAAG,OAAO,EAAE,GAAG,MAAM,EAAE,CAAA;IACnC,MAAM,YAAY,GAAG,KAAK,CAAC,SAAS,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAC3E,OAAO,CACL,4BAAe,mBAAmB,EAAC,SAAS,EAAC,qBAAqB,aAC/D,YAAY,IAAI,CACf,KAAC,UAAU,IACT,OAAO,EAAC,QAAQ,EAChB,IAAI,EAAC,SAAS,EACd,KAAK,EAAE,CAAC,CAAC,aAAa,EACtB,WAAW,EAAE,CAAC,CAAC,iBAAiB,EAChC,OAAO,EAAE,SAAS,CAAC,YAAY,CAAC,EAChC,OAAO,EAAE,KAAK,CAAC,KAAK,EACpB,UAAU,EAAE,UAAU,GACtB,CACH,EACA,KAAK,CAAC,aAAa,IAAI,CACtB,KAAC,UAAU,IACT,OAAO,EAAC,QAAQ,EAChB,KAAK,EAAE,CAAC,CAAC,cAAc,EACvB,WAAW,EAAE,CAAC,CAAC,kBAAkB,EACjC,OAAO,EAAE,SAAS,CAAC,KAAK,CAAC,aAAa,CAAC,EACvC,OAAO,EAAE,KAAK,CAAC,QAAQ,EACvB,UAAU,EAAE,UAAU,GACtB,CACH,EACD,KAAC,UAAU,IACT,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,EACzB,KAAK,EAAE,KAAK,CAAC,KAAK,EAClB,OAAO,EAAE,KAAK,CAAC,OAAO,EACtB,WAAW,EAAE,KAAK,CAAC,WAAW,EAC9B,UAAU,EAAE,KAAK,CAAC,QAAQ,EAC1B,IAAI,EAAE,IAAI,EACV,UAAU,EAAE,KAAK,CAAC,UAAU,EAC5B,KAAK,EAAE,KAAK,CAAC,KAAK,EAClB,MAAM,EAAE,MAAM,GACd,IACE,CACP,CAAA;AACH,CAAC"}
@@ -1,10 +1,11 @@
1
- import type { ReactNode } from "react";
2
- import { type ToneVariant } from "../lib/tone-utils.js";
1
+ import type { ReactElement, ReactNode } from "react";
2
+ import { type ToneName } from "../lib/tone-utils.js";
3
3
  export interface LivePillProps {
4
4
  /** Status tone driving the dot, tint and border. Default `"info"`. */
5
- tone?: ToneVariant;
5
+ tone?: ToneName;
6
6
  /** Pill label. Defaults to the locale's "Live". */
7
7
  children?: ReactNode;
8
+ className?: string;
8
9
  }
9
10
  /**
10
11
  * Small tinted pill with a pulsing dot. Use in a widget header to signal that
@@ -12,18 +13,37 @@ export interface LivePillProps {
12
13
  * text in the foreground), so it inherits the active theme. The pulse stops
13
14
  * under `prefers-reduced-motion`.
14
15
  */
15
- export declare function LivePill({ tone, children }: LivePillProps): import("react").JSX.Element;
16
+ export declare function LivePill({ tone, children, className }: LivePillProps): import("react").JSX.Element;
17
+ /** The words a {@link StatusBadge} must carry: text, a number or an element — never nothing. */
18
+ export type StatusBadgeText = string | number | ReactElement | (string | number | ReactElement)[];
19
+ export interface StatusBadgeProps {
20
+ /** The state, in words ("Suspended", "3 open incidents"). Required: colour is never the only signal. */
21
+ children: StatusBadgeText;
22
+ /** The state's tone: tint, edge and dot. */
23
+ tone: ToneName;
24
+ className?: string;
25
+ }
26
+ /**
27
+ * A state in words, marked in its tone: tint, edge and a static dot next to
28
+ * foreground text (CI §3.3: the colour marks the state, the words say it).
29
+ * For a detail-page header (`WidgetHeader`'s `badge`) or a table cell. The
30
+ * text is required — a badge without words would make colour the only
31
+ * signal. The pulsing dot is {@link LivePill}'s live-data semantic.
32
+ */
33
+ export declare function StatusBadge({ children, tone, className }: StatusBadgeProps): import("react").JSX.Element;
16
34
  export interface CountPillProps {
17
35
  /** Status tone driving the tint and border. Default `"neutral"`. */
18
- tone?: ToneVariant;
36
+ tone?: ToneName;
19
37
  /** The count/value to display (tabular numbers). */
20
38
  children: ReactNode;
39
+ className?: string;
21
40
  }
22
41
  /**
23
42
  * Compact count badge — tabular numbers on a tinted background with a border
24
43
  * in the tone. Use as the right-aligned indicator on a list/group row (e.g. a
25
44
  * per-group item count). The number stays in the foreground in every tone
26
- * (no coloured digits): the tint and the border carry the tone.
45
+ * (no coloured digits): the tint and the border carry the tone. A count
46
+ * without a state stays `neutral`.
27
47
  */
28
- export declare function CountPill({ tone, children }: CountPillProps): import("react").JSX.Element;
48
+ export declare function CountPill({ tone, children, className }: CountPillProps): import("react").JSX.Element;
29
49
  //# sourceMappingURL=Pills.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Pills.d.ts","sourceRoot":"","sources":["../../src/components/Pills.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtC,OAAO,EAAoC,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAEzF,MAAM,WAAW,aAAa;IAC5B,sEAAsE;IACtE,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB,mDAAmD;IACnD,QAAQ,CAAC,EAAE,SAAS,CAAA;CACrB;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,EAAE,IAAa,EAAE,QAAQ,EAAE,EAAE,aAAa,+BAalE;AAED,MAAM,WAAW,cAAc;IAC7B,oEAAoE;IACpE,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB,oDAAoD;IACpD,QAAQ,EAAE,SAAS,CAAA;CACpB;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,EAAE,IAAgB,EAAE,QAAQ,EAAE,EAAE,cAAc,+BAQvE"}
1
+ {"version":3,"file":"Pills.d.ts","sourceRoot":"","sources":["../../src/components/Pills.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEpD,OAAO,EAAiD,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAGnG,MAAM,WAAW,aAAa;IAC5B,sEAAsE;IACtE,IAAI,CAAC,EAAE,QAAQ,CAAA;IACf,mDAAmD;IACnD,QAAQ,CAAC,EAAE,SAAS,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,EAAE,IAAa,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,aAAa,+BAmB7E;AAED,gGAAgG;AAChG,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,MAAM,GAAG,YAAY,GAAG,CAAC,MAAM,GAAG,MAAM,GAAG,YAAY,CAAC,EAAE,CAAA;AAEjG,MAAM,WAAW,gBAAgB;IAC/B,wGAAwG;IACxG,QAAQ,EAAE,eAAe,CAAA;IACzB,4CAA4C;IAC5C,IAAI,EAAE,QAAQ,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,gBAAgB,+BAiB1E;AAED,MAAM,WAAW,cAAc;IAC7B,oEAAoE;IACpE,IAAI,CAAC,EAAE,QAAQ,CAAA;IACf,oDAAoD;IACpD,QAAQ,EAAE,SAAS,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,EAAE,IAAgB,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,cAAc,+BAclF"}
@@ -1,23 +1,38 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useToolkitMessages } from "../locale/locale-provider.js";
3
- import { TONE_BORDER, TONE_DOT, TONE_SOFT } from "../lib/tone-utils.js";
3
+ import { resolveTone, TONE_BORDER, TONE_DOT, TONE_SOFT } from "../lib/tone-utils.js";
4
+ import { cn } from "../lib/utils.js";
4
5
  /**
5
6
  * Small tinted pill with a pulsing dot. Use in a widget header to signal that
6
7
  * the data is live/real-time. Tone-based (tint, border and dot in the tone,
7
8
  * text in the foreground), so it inherits the active theme. The pulse stops
8
9
  * under `prefers-reduced-motion`.
9
10
  */
10
- export function LivePill({ tone = "info", children }) {
11
+ export function LivePill({ tone = "info", children, className }) {
11
12
  const messages = useToolkitMessages();
12
- return (_jsxs("span", { className: `inline-flex items-center gap-1.5 rounded-sm border px-2 py-0.5 text-xs font-semibold ${TONE_SOFT[tone]} ${TONE_BORDER[tone]}`, children: [_jsx("span", { "aria-hidden": "true", className: `size-1.5 animate-pulse rounded-full ${TONE_DOT[tone]}` }), children ?? messages.pills.live] }));
13
+ const t = resolveTone(tone, "info");
14
+ return (_jsxs("span", { className: cn("text-small inline-flex items-center gap-1.5 rounded-sm border px-2 py-0.5 font-semibold", TONE_SOFT[t], TONE_BORDER[t], className), children: [_jsx("span", { "aria-hidden": "true", className: cn("size-1.5 rounded-full motion-safe:animate-pulse", TONE_DOT[t]) }), children ?? messages.pills.live] }));
15
+ }
16
+ /**
17
+ * A state in words, marked in its tone: tint, edge and a static dot next to
18
+ * foreground text (CI §3.3: the colour marks the state, the words say it).
19
+ * For a detail-page header (`WidgetHeader`'s `badge`) or a table cell. The
20
+ * text is required — a badge without words would make colour the only
21
+ * signal. The pulsing dot is {@link LivePill}'s live-data semantic.
22
+ */
23
+ export function StatusBadge({ children, tone, className }) {
24
+ const t = resolveTone(tone);
25
+ return (_jsxs("span", { "data-slot": "status-badge", "data-tone": t, className: cn("text-small inline-flex w-fit items-center gap-1.5 rounded-sm border px-2.5 py-0.5 font-semibold", TONE_SOFT[t], TONE_BORDER[t], className), children: [_jsx("span", { "aria-hidden": "true", className: cn("size-1.5 shrink-0 rounded-full", TONE_DOT[t]) }), children] }));
13
26
  }
14
27
  /**
15
28
  * Compact count badge — tabular numbers on a tinted background with a border
16
29
  * in the tone. Use as the right-aligned indicator on a list/group row (e.g. a
17
30
  * per-group item count). The number stays in the foreground in every tone
18
- * (no coloured digits): the tint and the border carry the tone.
31
+ * (no coloured digits): the tint and the border carry the tone. A count
32
+ * without a state stays `neutral`.
19
33
  */
20
- export function CountPill({ tone = "neutral", children }) {
21
- return (_jsx("span", { className: `inline-flex min-w-[2.5rem] items-center justify-center rounded-sm border px-2.5 py-0.5 text-sm font-semibold tabular-nums ${TONE_SOFT[tone]} ${TONE_BORDER[tone]}`, children: children }));
34
+ export function CountPill({ tone = "neutral", children, className }) {
35
+ const t = resolveTone(tone);
36
+ return (_jsx("span", { className: cn("text-dense inline-flex min-w-10 items-center justify-center rounded-sm border px-2.5 py-0.5 font-semibold tabular-nums", TONE_SOFT[t], TONE_BORDER[t], className), children: children }));
22
37
  }
23
38
  //# sourceMappingURL=Pills.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Pills.js","sourceRoot":"","sources":["../../src/components/Pills.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAA;AACjE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAoB,MAAM,sBAAsB,CAAA;AASzF;;;;;GAKG;AACH,MAAM,UAAU,QAAQ,CAAC,EAAE,IAAI,GAAG,MAAM,EAAE,QAAQ,EAAiB;IACjE,MAAM,QAAQ,GAAG,kBAAkB,EAAE,CAAA;IACrC,OAAO,CACL,gBACE,SAAS,EAAE,wFAAwF,SAAS,CAAC,IAAI,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,EAAE,aAEzI,8BACc,MAAM,EAClB,SAAS,EAAE,uCAAuC,QAAQ,CAAC,IAAI,CAAC,EAAE,GAClE,EACD,QAAQ,IAAI,QAAQ,CAAC,KAAK,CAAC,IAAI,IAC3B,CACR,CAAA;AACH,CAAC;AASD;;;;;GAKG;AACH,MAAM,UAAU,SAAS,CAAC,EAAE,IAAI,GAAG,SAAS,EAAE,QAAQ,EAAkB;IACtE,OAAO,CACL,eACE,SAAS,EAAE,6HAA6H,SAAS,CAAC,IAAI,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,EAAE,YAE7K,QAAQ,GACJ,CACR,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"Pills.js","sourceRoot":"","sources":["../../src/components/Pills.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAA;AACjE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAiB,MAAM,sBAAsB,CAAA;AACnG,OAAO,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAA;AAUpC;;;;;GAKG;AACH,MAAM,UAAU,QAAQ,CAAC,EAAE,IAAI,GAAG,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAiB;IAC5E,MAAM,QAAQ,GAAG,kBAAkB,EAAE,CAAA;IACrC,MAAM,CAAC,GAAG,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;IACnC,OAAO,CACL,gBACE,SAAS,EAAE,EAAE,CACX,yFAAyF,EACzF,SAAS,CAAC,CAAC,CAAC,EACZ,WAAW,CAAC,CAAC,CAAC,EACd,SAAS,CACV,aAED,8BACc,MAAM,EAClB,SAAS,EAAE,EAAE,CAAC,iDAAiD,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,GAC7E,EACD,QAAQ,IAAI,QAAQ,CAAC,KAAK,CAAC,IAAI,IAC3B,CACR,CAAA;AACH,CAAC;AAaD;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAoB;IACzE,MAAM,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC,CAAA;IAC3B,OAAO,CACL,6BACY,cAAc,eACb,CAAC,EACZ,SAAS,EAAE,EAAE,CACX,iGAAiG,EACjG,SAAS,CAAC,CAAC,CAAC,EACZ,WAAW,CAAC,CAAC,CAAC,EACd,SAAS,CACV,aAED,8BAAkB,MAAM,EAAC,SAAS,EAAE,EAAE,CAAC,gCAAgC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAI,EACxF,QAAQ,IACJ,CACR,CAAA;AACH,CAAC;AAUD;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAC,EAAE,IAAI,GAAG,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAkB;IACjF,MAAM,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC,CAAA;IAC3B,OAAO,CACL,eACE,SAAS,EAAE,EAAE,CACX,wHAAwH,EACxH,SAAS,CAAC,CAAC,CAAC,EACZ,WAAW,CAAC,CAAC,CAAC,EACd,SAAS,CACV,YAEA,QAAQ,GACJ,CACR,CAAA;AACH,CAAC"}
@@ -10,7 +10,9 @@ export interface SectionHeadingProps {
10
10
  /**
11
11
  * Section title row — a small semibold heading with an optional muted hint or
12
12
  * control on the right. Use to label a block inside a widget body (e.g. a list
13
- * or sub-table) without the visual weight of a full card header.
13
+ * or sub-table) without the visual weight of a full card header. The title is
14
+ * a caption ({@link MICRO_LABEL}: 13 px semibold, normal case); a section that
15
+ * needs a real heading takes `text-section` (21 px) instead.
14
16
  */
15
17
  export declare function SectionHeading({ title, hint, trailing }: SectionHeadingProps): import("react").JSX.Element;
16
18
  //# sourceMappingURL=SectionHeading.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SectionHeading.d.ts","sourceRoot":"","sources":["../../src/components/SectionHeading.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtC,MAAM,WAAW,mBAAmB;IAClC,yBAAyB;IACzB,KAAK,EAAE,SAAS,CAAA;IAChB,kFAAkF;IAClF,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,SAAS,CAAA;CACrB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,mBAAmB,+BAS5E"}
1
+ {"version":3,"file":"SectionHeading.d.ts","sourceRoot":"","sources":["../../src/components/SectionHeading.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAItC,MAAM,WAAW,mBAAmB;IAClC,yBAAyB;IACzB,KAAK,EAAE,SAAS,CAAA;IAChB,kFAAkF;IAClF,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,SAAS,CAAA;CACrB;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,mBAAmB,+BAW5E"}
@@ -1,10 +1,14 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { MICRO_LABEL } from "../lib/typography.js";
3
+ import { cn } from "../lib/utils.js";
2
4
  /**
3
5
  * Section title row — a small semibold heading with an optional muted hint or
4
6
  * control on the right. Use to label a block inside a widget body (e.g. a list
5
- * or sub-table) without the visual weight of a full card header.
7
+ * or sub-table) without the visual weight of a full card header. The title is
8
+ * a caption ({@link MICRO_LABEL}: 13 px semibold, normal case); a section that
9
+ * needs a real heading takes `text-section` (21 px) instead.
6
10
  */
7
11
  export function SectionHeading({ title, hint, trailing }) {
8
- return (_jsxs("div", { className: "text-muted-foreground mb-3 flex items-center justify-between text-sm font-semibold", children: [_jsx("span", { children: title }), (hint || trailing) && (_jsx("span", { className: "text-muted-foreground text-xs font-medium", children: trailing ?? hint }))] }));
12
+ return (_jsxs("div", { className: cn("text-muted-foreground mb-3 flex items-center justify-between", MICRO_LABEL), children: [_jsx("span", { children: title }), (hint || trailing) && (_jsx("span", { className: "text-muted-foreground text-small font-medium", children: trailing ?? hint }))] }));
9
13
  }
10
14
  //# sourceMappingURL=SectionHeading.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SectionHeading.js","sourceRoot":"","sources":["../../src/components/SectionHeading.tsx"],"names":[],"mappings":";AAWA;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAuB;IAC3E,OAAO,CACL,eAAK,SAAS,EAAC,oFAAoF,aACjG,yBAAO,KAAK,GAAQ,EACnB,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI,CACrB,eAAM,SAAS,EAAC,2CAA2C,YAAE,QAAQ,IAAI,IAAI,GAAQ,CACtF,IACG,CACP,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"SectionHeading.js","sourceRoot":"","sources":["../../src/components/SectionHeading.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAClD,OAAO,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAA;AAWpC;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAuB;IAC3E,OAAO,CACL,eACE,SAAS,EAAE,EAAE,CAAC,8DAA8D,EAAE,WAAW,CAAC,aAE1F,yBAAO,KAAK,GAAQ,EACnB,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI,CACrB,eAAM,SAAS,EAAC,8CAA8C,YAAE,QAAQ,IAAI,IAAI,GAAQ,CACzF,IACG,CACP,CAAA;AACH,CAAC"}