@miragon/mcp-toolkit-ui 2.5.0 → 2.7.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 (348) hide show
  1. package/README.md +8 -2
  2. package/dist/app/builder/BuilderBanners.d.ts +7 -2
  3. package/dist/app/builder/BuilderBanners.d.ts.map +1 -1
  4. package/dist/app/builder/BuilderBanners.js +8 -3
  5. package/dist/app/builder/BuilderBanners.js.map +1 -1
  6. package/dist/app/builder/CanvasRow.d.ts.map +1 -1
  7. package/dist/app/builder/CanvasRow.js +12 -14
  8. package/dist/app/builder/CanvasRow.js.map +1 -1
  9. package/dist/app/builder/CatalogueSheet.d.ts.map +1 -1
  10. package/dist/app/builder/CatalogueSheet.js +6 -5
  11. package/dist/app/builder/CatalogueSheet.js.map +1 -1
  12. package/dist/app/builder/EmptyHint.d.ts +4 -0
  13. package/dist/app/builder/EmptyHint.d.ts.map +1 -1
  14. package/dist/app/builder/EmptyHint.js +6 -1
  15. package/dist/app/builder/EmptyHint.js.map +1 -1
  16. package/dist/app/builder/LayoutSurface.js +3 -3
  17. package/dist/app/builder/LayoutSurface.js.map +1 -1
  18. package/dist/app/builder/PipelineStrip.d.ts +3 -1
  19. package/dist/app/builder/PipelineStrip.d.ts.map +1 -1
  20. package/dist/app/builder/PipelineStrip.js +11 -6
  21. package/dist/app/builder/PipelineStrip.js.map +1 -1
  22. package/dist/app/builder/SaveDialog.d.ts.map +1 -1
  23. package/dist/app/builder/SaveDialog.js +2 -2
  24. package/dist/app/builder/SaveDialog.js.map +1 -1
  25. package/dist/app/builder/Toolbar.d.ts +3 -1
  26. package/dist/app/builder/Toolbar.d.ts.map +1 -1
  27. package/dist/app/builder/Toolbar.js +9 -3
  28. package/dist/app/builder/Toolbar.js.map +1 -1
  29. package/dist/app/builder/Workspace.js +2 -2
  30. package/dist/app/builder/Workspace.js.map +1 -1
  31. package/dist/app/builder/builder-model.d.ts +3 -2
  32. package/dist/app/builder/builder-model.d.ts.map +1 -1
  33. package/dist/app/builder/builder-model.js +5 -4
  34. package/dist/app/builder/builder-model.js.map +1 -1
  35. package/dist/app/builder/labels.d.ts +13 -62
  36. package/dist/app/builder/labels.d.ts.map +1 -1
  37. package/dist/app/builder/labels.js +9 -58
  38. package/dist/app/builder/labels.js.map +1 -1
  39. package/dist/app/builder/status-chip.d.ts.map +1 -1
  40. package/dist/app/builder/status-chip.js +3 -2
  41. package/dist/app/builder/status-chip.js.map +1 -1
  42. package/dist/app/builder/use-builder-catalogue.d.ts +1 -0
  43. package/dist/app/builder/use-builder-catalogue.d.ts.map +1 -1
  44. package/dist/app/builder/use-builder-catalogue.js +6 -0
  45. package/dist/app/builder/use-builder-catalogue.js.map +1 -1
  46. package/dist/app/builder/use-save-dashboard.d.ts +3 -1
  47. package/dist/app/builder/use-save-dashboard.d.ts.map +1 -1
  48. package/dist/app/builder/use-save-dashboard.js +3 -1
  49. package/dist/app/builder/use-save-dashboard.js.map +1 -1
  50. package/dist/app/index.d.ts +1 -1
  51. package/dist/app/index.d.ts.map +1 -1
  52. package/dist/app/index.js.map +1 -1
  53. package/dist/app/layout-builder.d.ts +7 -2
  54. package/dist/app/layout-builder.d.ts.map +1 -1
  55. package/dist/app/layout-builder.js +17 -5
  56. package/dist/app/layout-builder.js.map +1 -1
  57. package/dist/app/mcp-app-view-chrome.d.ts +94 -20
  58. package/dist/app/mcp-app-view-chrome.d.ts.map +1 -1
  59. package/dist/app/mcp-app-view-chrome.js +109 -40
  60. package/dist/app/mcp-app-view-chrome.js.map +1 -1
  61. package/dist/app/mcp-app-view-states.d.ts +15 -0
  62. package/dist/app/mcp-app-view-states.d.ts.map +1 -0
  63. package/dist/app/mcp-app-view-states.js +34 -0
  64. package/dist/app/mcp-app-view-states.js.map +1 -0
  65. package/dist/app/mcp-app-view.d.ts +40 -5
  66. package/dist/app/mcp-app-view.d.ts.map +1 -1
  67. package/dist/app/mcp-app-view.js +174 -128
  68. package/dist/app/mcp-app-view.js.map +1 -1
  69. package/dist/app/mcp-toolkit-app.d.ts +2 -1
  70. package/dist/app/mcp-toolkit-app.d.ts.map +1 -1
  71. package/dist/app/mcp-toolkit-app.js +25 -3
  72. package/dist/app/mcp-toolkit-app.js.map +1 -1
  73. package/dist/app/use-view-lifecycle.d.ts +38 -0
  74. package/dist/app/use-view-lifecycle.d.ts.map +1 -0
  75. package/dist/app/use-view-lifecycle.js +79 -0
  76. package/dist/app/use-view-lifecycle.js.map +1 -0
  77. package/dist/app/view-lifecycle.d.ts +109 -0
  78. package/dist/app/view-lifecycle.d.ts.map +1 -0
  79. package/dist/app/view-lifecycle.js +120 -0
  80. package/dist/app/view-lifecycle.js.map +1 -0
  81. package/dist/app/widget-props-sheet.d.ts +3 -9
  82. package/dist/app/widget-props-sheet.d.ts.map +1 -1
  83. package/dist/app/widget-props-sheet.js +6 -13
  84. package/dist/app/widget-props-sheet.js.map +1 -1
  85. package/dist/app/widget-renderer.d.ts +41 -1
  86. package/dist/app/widget-renderer.d.ts.map +1 -1
  87. package/dist/app/widget-renderer.js +82 -31
  88. package/dist/app/widget-renderer.js.map +1 -1
  89. package/dist/components/DrillButton.d.ts.map +1 -1
  90. package/dist/components/DrillButton.js +2 -1
  91. package/dist/components/DrillButton.js.map +1 -1
  92. package/dist/components/EmptyState.d.ts +33 -0
  93. package/dist/components/EmptyState.d.ts.map +1 -0
  94. package/dist/components/EmptyState.js +17 -0
  95. package/dist/components/EmptyState.js.map +1 -0
  96. package/dist/components/ErrorState.d.ts +50 -0
  97. package/dist/components/ErrorState.d.ts.map +1 -0
  98. package/dist/components/ErrorState.js +60 -0
  99. package/dist/components/ErrorState.js.map +1 -0
  100. package/dist/components/FilterBar.d.ts +1 -1
  101. package/dist/components/FilterBar.d.ts.map +1 -1
  102. package/dist/components/FilterBar.js +7 -4
  103. package/dist/components/FilterBar.js.map +1 -1
  104. package/dist/components/GroupCard.d.ts.map +1 -1
  105. package/dist/components/GroupCard.js +2 -1
  106. package/dist/components/GroupCard.js.map +1 -1
  107. package/dist/components/KpiGrid.d.ts +10 -3
  108. package/dist/components/KpiGrid.d.ts.map +1 -1
  109. package/dist/components/KpiGrid.js +31 -9
  110. package/dist/components/KpiGrid.js.map +1 -1
  111. package/dist/components/ListFooter.d.ts +3 -2
  112. package/dist/components/ListFooter.d.ts.map +1 -1
  113. package/dist/components/ListFooter.js +14 -4
  114. package/dist/components/ListFooter.js.map +1 -1
  115. package/dist/components/Pills.d.ts +10 -6
  116. package/dist/components/Pills.d.ts.map +1 -1
  117. package/dist/components/Pills.js +12 -6
  118. package/dist/components/Pills.js.map +1 -1
  119. package/dist/components/Toast.d.ts +37 -0
  120. package/dist/components/Toast.d.ts.map +1 -0
  121. package/dist/components/Toast.js +91 -0
  122. package/dist/components/Toast.js.map +1 -0
  123. package/dist/components/WidgetHeader.js +1 -1
  124. package/dist/hooks/use-tool-result-recovery.d.ts +23 -1
  125. package/dist/hooks/use-tool-result-recovery.d.ts.map +1 -1
  126. package/dist/hooks/use-tool-result-recovery.js +21 -7
  127. package/dist/hooks/use-tool-result-recovery.js.map +1 -1
  128. package/dist/hooks/use-view-data.d.ts +6 -0
  129. package/dist/hooks/use-view-data.d.ts.map +1 -1
  130. package/dist/hooks/use-view-data.js +6 -1
  131. package/dist/hooks/use-view-data.js.map +1 -1
  132. package/dist/index.d.ts +12 -5
  133. package/dist/index.d.ts.map +1 -1
  134. package/dist/index.js +14 -4
  135. package/dist/index.js.map +1 -1
  136. package/dist/lib/focus-ring.d.ts +18 -0
  137. package/dist/lib/focus-ring.d.ts.map +1 -0
  138. package/dist/lib/focus-ring.js +18 -0
  139. package/dist/lib/focus-ring.js.map +1 -0
  140. package/dist/lib/icon-stroke.d.ts +12 -0
  141. package/dist/lib/icon-stroke.d.ts.map +1 -0
  142. package/dist/lib/icon-stroke.js +12 -0
  143. package/dist/lib/icon-stroke.js.map +1 -0
  144. package/dist/lib/toast-model.d.ts +46 -0
  145. package/dist/lib/toast-model.d.ts.map +1 -0
  146. package/dist/lib/toast-model.js +36 -0
  147. package/dist/lib/toast-model.js.map +1 -0
  148. package/dist/lib/tone-utils.d.ts +43 -9
  149. package/dist/lib/tone-utils.d.ts.map +1 -1
  150. package/dist/lib/tone-utils.js +36 -7
  151. package/dist/lib/tone-utils.js.map +1 -1
  152. package/dist/locale/index.d.ts +3 -1
  153. package/dist/locale/index.d.ts.map +1 -1
  154. package/dist/locale/index.js +2 -1
  155. package/dist/locale/index.js.map +1 -1
  156. package/dist/locale/locale-provider.d.ts +42 -1
  157. package/dist/locale/locale-provider.d.ts.map +1 -1
  158. package/dist/locale/locale-provider.js +44 -3
  159. package/dist/locale/locale-provider.js.map +1 -1
  160. package/dist/locale/message-types.d.ts +223 -0
  161. package/dist/locale/message-types.d.ts.map +1 -0
  162. package/dist/locale/message-types.js +7 -0
  163. package/dist/locale/message-types.js.map +1 -0
  164. package/dist/locale/messages-de.d.ts +9 -0
  165. package/dist/locale/messages-de.d.ts.map +1 -0
  166. package/dist/locale/messages-de.js +151 -0
  167. package/dist/locale/messages-de.js.map +1 -0
  168. package/dist/locale/messages-en.d.ts +8 -0
  169. package/dist/locale/messages-en.d.ts.map +1 -0
  170. package/dist/locale/messages-en.js +150 -0
  171. package/dist/locale/messages-en.js.map +1 -0
  172. package/dist/locale/toolkit-messages.d.ts +39 -0
  173. package/dist/locale/toolkit-messages.d.ts.map +1 -0
  174. package/dist/locale/toolkit-messages.js +50 -0
  175. package/dist/locale/toolkit-messages.js.map +1 -0
  176. package/dist/primitives/alert.d.ts.map +1 -1
  177. package/dist/primitives/alert.js +4 -2
  178. package/dist/primitives/alert.js.map +1 -1
  179. package/dist/primitives/badge.d.ts +1 -1
  180. package/dist/primitives/badge.d.ts.map +1 -1
  181. package/dist/primitives/badge.js +14 -6
  182. package/dist/primitives/badge.js.map +1 -1
  183. package/dist/primitives/button.d.ts.map +1 -1
  184. package/dist/primitives/button.js +12 -8
  185. package/dist/primitives/button.js.map +1 -1
  186. package/dist/primitives/card.js +4 -4
  187. package/dist/primitives/card.js.map +1 -1
  188. package/dist/primitives/dialog.d.ts +7 -3
  189. package/dist/primitives/dialog.d.ts.map +1 -1
  190. package/dist/primitives/dialog.js +14 -7
  191. package/dist/primitives/dialog.js.map +1 -1
  192. package/dist/primitives/input.d.ts.map +1 -1
  193. package/dist/primitives/input.js +4 -1
  194. package/dist/primitives/input.js.map +1 -1
  195. package/dist/primitives/scroll-area.js +1 -1
  196. package/dist/primitives/scroll-area.js.map +1 -1
  197. package/dist/primitives/select.d.ts.map +1 -1
  198. package/dist/primitives/select.js +5 -2
  199. package/dist/primitives/select.js.map +1 -1
  200. package/dist/primitives/sheet.d.ts +3 -1
  201. package/dist/primitives/sheet.d.ts.map +1 -1
  202. package/dist/primitives/sheet.js +12 -6
  203. package/dist/primitives/sheet.js.map +1 -1
  204. package/dist/primitives/skeleton.js +1 -1
  205. package/dist/primitives/skeleton.js.map +1 -1
  206. package/dist/primitives/switch.d.ts.map +1 -1
  207. package/dist/primitives/switch.js +2 -1
  208. package/dist/primitives/switch.js.map +1 -1
  209. package/dist/primitives/tabs.d.ts.map +1 -1
  210. package/dist/primitives/tabs.js +5 -3
  211. package/dist/primitives/tabs.js.map +1 -1
  212. package/dist/render-cases.d.ts.map +1 -1
  213. package/dist/render-cases.js +20 -2
  214. package/dist/render-cases.js.map +1 -1
  215. package/dist/render-scan.d.ts +25 -0
  216. package/dist/render-scan.d.ts.map +1 -0
  217. package/dist/render-scan.js +66 -0
  218. package/dist/render-scan.js.map +1 -0
  219. package/dist/theme/cd-tokens.d.ts +66 -0
  220. package/dist/theme/cd-tokens.d.ts.map +1 -0
  221. package/dist/theme/cd-tokens.js +64 -0
  222. package/dist/theme/cd-tokens.js.map +1 -0
  223. package/dist/theme/create-theme.d.ts +196 -39
  224. package/dist/theme/create-theme.d.ts.map +1 -1
  225. package/dist/theme/create-theme.js +189 -13
  226. package/dist/theme/create-theme.js.map +1 -1
  227. package/dist/theme/fonts.d.ts +38 -0
  228. package/dist/theme/fonts.d.ts.map +1 -0
  229. package/dist/theme/fonts.js +56 -0
  230. package/dist/theme/fonts.js.map +1 -0
  231. package/dist/theme/host-fonts.d.ts +39 -0
  232. package/dist/theme/host-fonts.d.ts.map +1 -0
  233. package/dist/theme/host-fonts.js +44 -0
  234. package/dist/theme/host-fonts.js.map +1 -0
  235. package/dist/theme/index.d.ts +8 -1
  236. package/dist/theme/index.d.ts.map +1 -1
  237. package/dist/theme/index.js +5 -1
  238. package/dist/theme/index.js.map +1 -1
  239. package/dist/theme/portal-container.d.ts +16 -0
  240. package/dist/theme/portal-container.d.ts.map +1 -0
  241. package/dist/theme/portal-container.js +19 -0
  242. package/dist/theme/portal-container.js.map +1 -0
  243. package/dist/theme/presets.d.ts +24 -9
  244. package/dist/theme/presets.d.ts.map +1 -1
  245. package/dist/theme/presets.js +44 -11
  246. package/dist/theme/presets.js.map +1 -1
  247. package/dist/theme/theme-provider.d.ts +27 -9
  248. package/dist/theme/theme-provider.d.ts.map +1 -1
  249. package/dist/theme/theme-provider.js +42 -20
  250. package/dist/theme/theme-provider.js.map +1 -1
  251. package/package.json +13 -8
  252. package/src/app/builder/BuilderBanners.tsx +26 -13
  253. package/src/app/builder/CanvasRow.tsx +22 -21
  254. package/src/app/builder/CatalogueSheet.tsx +16 -14
  255. package/src/app/builder/EmptyHint.tsx +16 -11
  256. package/src/app/builder/LayoutSurface.tsx +7 -7
  257. package/src/app/builder/PipelineStrip.tsx +26 -17
  258. package/src/app/builder/SaveDialog.tsx +11 -12
  259. package/src/app/builder/Toolbar.tsx +19 -7
  260. package/src/app/builder/Workspace.tsx +5 -3
  261. package/src/app/builder/builder-feedback.test.tsx +75 -0
  262. package/src/app/builder/builder-model.test.ts +5 -0
  263. package/src/app/builder/builder-model.ts +5 -4
  264. package/src/app/builder/labels.ts +15 -121
  265. package/src/app/builder/status-chip.tsx +8 -4
  266. package/src/app/builder/use-builder-catalogue.ts +6 -0
  267. package/src/app/builder/use-save-dashboard.ts +5 -0
  268. package/src/app/index.ts +8 -1
  269. package/src/app/layout-builder.tsx +23 -3
  270. package/src/app/mcp-app-view-chrome.test.tsx +347 -14
  271. package/src/app/mcp-app-view-chrome.tsx +278 -100
  272. package/src/app/mcp-app-view-states.tsx +100 -0
  273. package/src/app/mcp-app-view.test.tsx +258 -0
  274. package/src/app/mcp-app-view.tsx +292 -185
  275. package/src/app/mcp-toolkit-app.tsx +31 -7
  276. package/src/app/use-view-lifecycle.ts +116 -0
  277. package/src/app/view-lifecycle.test.ts +227 -0
  278. package/src/app/view-lifecycle.ts +174 -0
  279. package/src/app/widget-props-sheet.tsx +13 -26
  280. package/src/app/widget-renderer.render.test.tsx +131 -0
  281. package/src/app/widget-renderer.tsx +136 -38
  282. package/src/components/DrillButton.tsx +2 -1
  283. package/src/components/EmptyState.tsx +81 -0
  284. package/src/components/ErrorState.tsx +182 -0
  285. package/src/components/FilterBar.tsx +9 -6
  286. package/src/components/GroupCard.tsx +3 -2
  287. package/src/components/KpiGrid.tsx +75 -44
  288. package/src/components/ListFooter.tsx +17 -6
  289. package/src/components/Pills.tsx +20 -11
  290. package/src/components/Toast.tsx +188 -0
  291. package/src/components/WidgetHeader.tsx +1 -1
  292. package/src/components/feedback-states.test.tsx +225 -0
  293. package/src/components/tone-figures.test.tsx +54 -0
  294. package/src/fonts.css +19 -0
  295. package/src/globals.css +9 -165
  296. package/src/hooks/use-tool-result-recovery.test.ts +25 -1
  297. package/src/hooks/use-tool-result-recovery.ts +34 -6
  298. package/src/hooks/use-view-data.test.tsx +60 -0
  299. package/src/hooks/use-view-data.ts +12 -1
  300. package/src/i18n-coverage.test.tsx +323 -0
  301. package/src/index.ts +57 -5
  302. package/src/lib/focus-ring.ts +20 -0
  303. package/src/lib/icon-stroke.test.ts +59 -0
  304. package/src/lib/icon-stroke.ts +13 -0
  305. package/src/lib/toast-model.test.ts +68 -0
  306. package/src/lib/toast-model.ts +63 -0
  307. package/src/lib/tone-utils.test.ts +47 -14
  308. package/src/lib/tone-utils.ts +61 -13
  309. package/src/locale/index.ts +13 -1
  310. package/src/locale/locale-provider.test.tsx +87 -0
  311. package/src/locale/locale-provider.tsx +90 -3
  312. package/src/locale/message-types.ts +221 -0
  313. package/src/locale/messages-de.ts +159 -0
  314. package/src/locale/messages-en.ts +157 -0
  315. package/src/locale/toolkit-messages.test.ts +216 -0
  316. package/src/locale/toolkit-messages.ts +82 -0
  317. package/src/no-hardcoded-copy.test.ts +432 -0
  318. package/src/primitives/alert.tsx +4 -2
  319. package/src/primitives/badge.tsx +14 -7
  320. package/src/primitives/button.tsx +13 -8
  321. package/src/primitives/card.tsx +4 -4
  322. package/src/primitives/dialog.tsx +32 -7
  323. package/src/primitives/input.tsx +5 -3
  324. package/src/primitives/scroll-area.tsx +1 -1
  325. package/src/primitives/select.tsx +6 -3
  326. package/src/primitives/sheet.tsx +26 -6
  327. package/src/primitives/skeleton.tsx +1 -1
  328. package/src/primitives/switch.tsx +4 -2
  329. package/src/primitives/tabs.tsx +9 -6
  330. package/src/render-cases.tsx +45 -1
  331. package/src/render-scan.ts +75 -0
  332. package/src/theme/cd-tokens.generated.css +48 -0
  333. package/src/theme/cd-tokens.test.ts +107 -0
  334. package/src/theme/cd-tokens.ts +67 -0
  335. package/src/theme/create-theme.test.ts +243 -5
  336. package/src/theme/create-theme.ts +313 -41
  337. package/src/theme/fonts.test.ts +85 -0
  338. package/src/theme/fonts.ts +72 -0
  339. package/src/theme/host-fonts.test.ts +135 -0
  340. package/src/theme/host-fonts.ts +52 -0
  341. package/src/theme/index.ts +15 -1
  342. package/src/theme/portal-container.ts +20 -0
  343. package/src/theme/presets.ts +44 -11
  344. package/src/theme/theme-css.test.ts +568 -0
  345. package/src/theme/theme-provider.test.tsx +82 -0
  346. package/src/theme/theme-provider.tsx +60 -24
  347. package/src/theme.css +314 -0
  348. package/ui-catalog.json +344 -17
@@ -1,7 +1,9 @@
1
1
  import { memo } from "react"
2
- import { Check, Eye, Layers, Library, Save } from "lucide-react"
2
+ import { Check, Eye, Layers, Library, LucideProvider, Save } from "lucide-react"
3
+ import { DENSE_ICON_STROKE } from "../../lib/icon-stroke.js"
3
4
  import { Badge } from "../../primitives/badge.js"
4
5
  import { Button } from "../../primitives/button.js"
6
+ import { TONE_DOT, TONE_SOFT } from "../../lib/tone-utils.js"
5
7
  import { cn } from "../../lib/utils.js"
6
8
  import type { LayoutBuilderLabels, RefreshStatus } from "./labels.js"
7
9
  import { StatusChip } from "./status-chip.js"
@@ -41,7 +43,7 @@ function ToolbarImpl({
41
43
  <span
42
44
  className={cn(
43
45
  "inline-flex size-6 items-center justify-center rounded-md",
44
- previewMode ? "bg-emerald-500/10 text-emerald-500" : "bg-primary/10 text-primary",
46
+ previewMode ? TONE_SOFT.success : TONE_SOFT.info,
45
47
  )}
46
48
  aria-hidden="true"
47
49
  >
@@ -55,20 +57,21 @@ function ToolbarImpl({
55
57
 
56
58
  <div className="text-muted-foreground hidden items-center gap-3 text-[11px] sm:flex">
57
59
  <span className="inline-flex items-center gap-1.5">
58
- <span className="size-1.5 rounded-full bg-emerald-500" />
60
+ <span aria-hidden="true" className={`size-1.5 rounded-full ${TONE_DOT.success}`} />
59
61
  <span>
60
- <span className="text-foreground font-medium">{liveKeys}</span> live
62
+ <span className="text-foreground font-medium">{liveKeys}</span> {L.statsLive}
61
63
  </span>
62
64
  </span>
63
65
  <span className="bg-border h-3 w-px" aria-hidden="true" />
64
66
  <span>
65
- <span className="text-foreground font-medium">{reachableCount}</span> reachable
67
+ <span className="text-foreground font-medium">{reachableCount}</span> {L.statsReachable}
66
68
  </span>
67
69
  {unreachableCount > 0 && (
68
70
  <>
69
71
  <span className="bg-border h-3 w-px" aria-hidden="true" />
70
72
  <span>
71
- <span className="text-foreground font-medium">{unreachableCount}</span> unreachable
73
+ <span className="text-foreground font-medium">{unreachableCount}</span>{" "}
74
+ {L.statsUnreachable}
72
75
  </span>
73
76
  </>
74
77
  )}
@@ -92,4 +95,13 @@ function ToolbarImpl({
92
95
  )
93
96
  }
94
97
 
95
- export const Toolbar = memo(ToolbarImpl)
98
+ /** A dense chrome bar: its Lucide icons draw at stroke 2 (CI §11), not the view's 2.5. */
99
+ function DenseToolbar(props: Parameters<typeof ToolbarImpl>[0]) {
100
+ return (
101
+ <LucideProvider strokeWidth={DENSE_ICON_STROKE}>
102
+ <ToolbarImpl {...props} />
103
+ </LucideProvider>
104
+ )
105
+ }
106
+
107
+ export const Toolbar = memo(DenseToolbar)
@@ -82,7 +82,7 @@ function WorkspaceImpl({
82
82
  <div className="flex flex-col gap-3 pr-1">
83
83
  {paletteByApp.map(([app, ws]) => (
84
84
  <div key={app} className="flex flex-col gap-1">
85
- <div className="text-muted-foreground/80 text-[10px] font-semibold tracking-wide uppercase">
85
+ <div className="text-muted-foreground text-[10px] font-semibold tracking-wide uppercase">
86
86
  {app}
87
87
  </div>
88
88
  {ws.map((w) => (
@@ -160,10 +160,12 @@ function PaletteItemImpl({ w, onClick }: { w: ReachableWidget; onClick: () => vo
160
160
  >
161
161
  <span className="flex w-full items-center justify-between gap-2">
162
162
  <span className="truncate font-mono">{w.id}</span>
163
- <GripVertical className="text-muted-foreground/40 group-hover:text-muted-foreground size-3" />
163
+ <GripVertical className="text-muted-foreground group-hover:text-accent-foreground size-3" />
164
164
  </span>
165
165
  {w.requires.length > 0 && (
166
- <span className="text-muted-foreground/80 truncate font-mono text-[10px]">
166
+ // On the hovered --accent surface quiet text takes the surface's
167
+ // foreground: --muted-foreground drops to 3.66:1 there in dark.
168
+ <span className="text-muted-foreground group-hover:text-accent-foreground truncate font-mono text-[10px]">
167
169
  ← {w.requires.join(", ")}
168
170
  </span>
169
171
  )}
@@ -0,0 +1,75 @@
1
+ import type { ReactNode } from "react"
2
+ import { renderToStaticMarkup } from "react-dom/server"
3
+ import { describe, expect, it } from "vitest"
4
+ import { LocaleProvider } from "../../locale/locale-provider.js"
5
+ import { TOOLKIT_MESSAGES } from "../../locale/toolkit-messages.js"
6
+ import { attribute, decodeEntities, openingTags } from "../../render-scan.js"
7
+ import { BuilderBanners } from "./BuilderBanners.js"
8
+ import { EmptyHint } from "./EmptyHint.js"
9
+
10
+ /**
11
+ * The builder's feedback states on their SSR markup: a failure says what
12
+ * happened and what to do in catalog words, keeps the raw reason under
13
+ * "Details", and offers the next step; the empty state leads with the blue
14
+ * primary button (CI §9).
15
+ */
16
+
17
+ const de = TOOLKIT_MESSAGES.de
18
+ const inGerman = (node: ReactNode) =>
19
+ renderToStaticMarkup(<LocaleProvider locale="de-DE">{node}</LocaleProvider>)
20
+ const noop = (): void => {}
21
+ const RAW = "MCP error -32602: Tool get-builder-catalogue not found"
22
+
23
+ describe("BuilderBanners: catalogue failure", () => {
24
+ const html = inGerman(
25
+ <BuilderBanners
26
+ L={de.builder}
27
+ catalogueToolName="get-builder-catalogue"
28
+ refreshError={RAW}
29
+ validationIssues={[]}
30
+ onRetry={noop}
31
+ />,
32
+ )
33
+
34
+ it("is the kit's inline error state, announced as an alert", () => {
35
+ const root = openingTags(html, "div").find((t) => /data-slot="error-state"/.test(t)) ?? ""
36
+ expect(attribute(root, "role")).toBe("alert")
37
+ expect(attribute(root, "data-variant")).toBe("inline")
38
+ })
39
+
40
+ it("says what happened and what to do in German, with a retry", () => {
41
+ const text = decodeEntities(html)
42
+ expect(text).toContain(de.builder.catalogueError)
43
+ expect(text).toContain(de.builder.catalogueErrorHint)
44
+ expect(text).toContain(`${de.common.retry}</button>`)
45
+ })
46
+
47
+ it("keeps the raw reason under Details only, never in a sentence the user reads", () => {
48
+ const details = /<details[^>]*>([\s\S]*?)<\/details>/.exec(html)?.[1] ?? ""
49
+ expect(decodeEntities(details)).toContain(`get-builder-catalogue: ${RAW}`)
50
+ const outside = decodeEntities(html.replace(/<details[\s\S]*?<\/details>/g, ""))
51
+ expect(outside).not.toContain(RAW)
52
+ })
53
+
54
+ it("has no retry without a handler", () => {
55
+ const bare = inGerman(
56
+ <BuilderBanners
57
+ L={de.builder}
58
+ catalogueToolName="get-builder-catalogue"
59
+ refreshError={RAW}
60
+ validationIssues={[]}
61
+ />,
62
+ )
63
+ expect(bare).not.toContain("<button")
64
+ })
65
+ })
66
+
67
+ describe("EmptyHint", () => {
68
+ it("offers its one next step as the primary (blue) button", () => {
69
+ const html = inGerman(<EmptyHint L={de.builder} onGotoPipeline={noop} />)
70
+ const buttons = openingTags(html, "button")
71
+ expect(buttons).toHaveLength(1)
72
+ expect(attribute(buttons[0] ?? "", "data-variant")).toBe("default")
73
+ expect(decodeEntities(html)).toContain(`${de.builder.openDataSources}</button>`)
74
+ })
75
+ })
@@ -260,6 +260,11 @@ describe("formatLiveKeyValue", () => {
260
260
  expect(formatLiveKeyValue("abc")).toBe("live: abc")
261
261
  })
262
262
 
263
+ it("takes the localized prefix", () => {
264
+ expect(formatLiveKeyValue("abc", "vorhanden")).toBe("vorhanden: abc")
265
+ expect(formatLiveKeyValue(42, "vorhanden")).toBe("vorhanden: 42")
266
+ })
267
+
263
268
  it("JSON-stringifies non-string values", () => {
264
269
  expect(formatLiveKeyValue(42)).toBe("live: 42")
265
270
  expect(formatLiveKeyValue({ a: 1 })).toBe('live: {"a":1}')
@@ -136,14 +136,15 @@ export function entriesToKeys(entries: KeyEntry[]): Record<string, unknown> {
136
136
  * Compact preview of a value as it currently lives in the pipeline.
137
137
  * Used as the placeholder when the editor's `rawValue` is empty so the
138
138
  * user can see what the server is actually working with right now
139
- * without the editor overwriting their (empty) input.
139
+ * without the editor overwriting their (empty) input. `prefix` is the
140
+ * localized word for "live" (the builder passes its catalog's).
140
141
  */
141
- export function formatLiveKeyValue(value: unknown): string | undefined {
142
+ export function formatLiveKeyValue(value: unknown, prefix = "live"): string | undefined {
142
143
  if (value === undefined) return undefined
143
144
  if (value === "") return undefined
144
- if (typeof value === "string") return `live: ${value}`
145
+ if (typeof value === "string") return `${prefix}: ${value}`
145
146
  try {
146
- return `live: ${JSON.stringify(value)}`
147
+ return `${prefix}: ${JSON.stringify(value)}`
147
148
  } catch {
148
149
  return undefined
149
150
  }
@@ -4,130 +4,24 @@
4
4
  * Extracted from `layout-builder.tsx` so the presentational sub-components
5
5
  * (Toolbar, PipelineStrip, Workspace, CatalogueSheet, SaveDialog, PreviewPane)
6
6
  * can depend on the labels without importing the orchestrating container —
7
- * which would create an import cycle. React-free and `mcp-use`-free.
7
+ * which would create an import cycle. React-free and `mcp-use`-free. The
8
+ * strings themselves live in the toolkit catalog (`locale/messages-*.ts`).
8
9
  */
9
10
 
10
- export interface LayoutBuilderLabels {
11
- title?: string
12
- builderBadge?: string
13
- previewBadge?: string
14
- catalogue?: string
15
- save?: string
16
- done?: string
17
- viewLayoutTab?: string
18
- viewPipelineTab?: string
19
- viewPreviewTab?: string
20
- saveDialogTitle?: string
21
- saveDialogDescription?: string
22
- saveNameLabel?: string
23
- saveDescriptionLabel?: string
24
- saveConfirm?: string
25
- cancel?: string
26
- pipelineHeader?: string
27
- keysHeader?: string
28
- stepsHeader?: string
29
- keyName?: string
30
- keyValue?: string
31
- stepContextId?: string
32
- stepPickerLabel?: string
33
- addKey?: string
34
- addStep?: string
35
- emptyKeys?: string
36
- emptySteps?: string
37
- statusUpToDate?: string
38
- statusPending?: string
39
- statusRefreshing?: string
40
- paletteHeader?: string
41
- paletteEmpty?: string
42
- canvasEmpty?: string
43
- canvasDropHint?: string
44
- addRow?: string
45
- addTab?: string
46
- removeRow?: string
47
- renameTab?: string
48
- removeTab?: string
49
- tabsLabel?: string
50
- catalogueDescription?: string
51
- catalogueKeys?: string
52
- catalogueSteps?: string
53
- catalogueUnreachable?: string
54
- catalogueUnreachableEmpty?: string
55
- catalogueProducedBy?: string
56
- catalogueConsumedBy?: string
57
- catalogueNeedsKeys?: string
58
- cataloguePickKey?: string
59
- catalogueAddProducingStep?: string
60
- catalogueLive?: string
61
- catalogueMissing?: string
62
- /** Banner shown when the catalogue fetch fails (prefixes the reason). */
63
- catalogueError?: string
64
- /** Heading for the pipeline-validation warning banner. */
65
- validationWarning?: string
66
- /** Inline message when a save fails (prefixes the reason). */
67
- saveError?: string
68
- /** Inline message when a tab rename is rejected (duplicate label). */
69
- renameDuplicate?: string
70
- }
11
+ import { TOOLKIT_MESSAGES, type BuilderMessages } from "../../locale/toolkit-messages.js"
71
12
 
72
- export const DEFAULT_LABELS: Required<LayoutBuilderLabels> = {
73
- title: "View Builder",
74
- builderBadge: "Builder",
75
- previewBadge: "Preview",
76
- catalogue: "Catalogue",
77
- save: "Save",
78
- done: "Done",
79
- viewLayoutTab: "Layout",
80
- viewPipelineTab: "Pipeline",
81
- viewPreviewTab: "Preview",
82
- saveDialogTitle: "Save dashboard",
83
- saveDialogDescription:
84
- "Persists the current layout along with the keys and steps that populate it.",
85
- saveNameLabel: "Name",
86
- saveDescriptionLabel: "Description",
87
- saveConfirm: "Save dashboard",
88
- cancel: "Cancel",
89
- pipelineHeader: "Pipeline",
90
- keysHeader: "Keys",
91
- stepsHeader: "Steps",
92
- keyName: "key",
93
- keyValue: 'value, "literal", true, {…}',
94
- stepContextId: "ctx id",
95
- stepPickerLabel: "pick a step",
96
- addKey: "Add key",
97
- addStep: "Add step",
98
- emptyKeys: "No keys seeded.",
99
- emptySteps: "No steps configured.",
100
- statusUpToDate: "Up to date",
101
- statusPending: "Applying soon…",
102
- statusRefreshing: "Applying…",
103
- paletteHeader: "Palette",
104
- paletteEmpty: "No widgets reachable yet — seed a key or add a step.",
105
- canvasEmpty: "Drag a widget here, or click one in the palette.",
106
- canvasDropHint: "Drop to add",
107
- addRow: "Add row",
108
- addTab: "Add tab",
109
- removeRow: "Remove row",
110
- renameTab: "Rename tab",
111
- removeTab: "Remove tab",
112
- tabsLabel: "Tabs",
113
- catalogueDescription:
114
- "Every key and widget the framework knows about, whether or not it's reachable right now.",
115
- catalogueKeys: "Keys",
116
- catalogueSteps: "Steps",
117
- catalogueUnreachable: "Unreachable widgets",
118
- catalogueUnreachableEmpty: "Every registered widget is reachable.",
119
- catalogueProducedBy: "produced by",
120
- catalogueConsumedBy: "consumed by",
121
- catalogueNeedsKeys: "needs",
122
- cataloguePickKey: "Add as key",
123
- catalogueAddProducingStep: "Add producing step",
124
- catalogueLive: "live",
125
- catalogueMissing: "missing",
126
- catalogueError: "Couldn't refresh the builder catalogue",
127
- validationWarning: "This pipeline won't render as configured",
128
- saveError: "Couldn't save",
129
- renameDuplicate: "A tab with that name already exists.",
130
- }
13
+ /**
14
+ * Override strings for every user-facing caption in the builder. Each field
15
+ * defaults to the active locale's toolkit catalog (`useToolkitMessages().builder`).
16
+ */
17
+ export type LayoutBuilderLabels = Partial<BuilderMessages>
18
+
19
+ /**
20
+ * English builder strings.
21
+ * @deprecated Read the active locale's strings with `useToolkitMessages().builder`
22
+ * (or `TOOLKIT_MESSAGES.en.builder`); this alias stays for existing imports.
23
+ */
24
+ export const DEFAULT_LABELS: Required<LayoutBuilderLabels> = TOOLKIT_MESSAGES.en.builder
131
25
 
132
26
  /**
133
27
  * MIME type used to carry a widget id across the palette → canvas drag.
@@ -1,4 +1,5 @@
1
1
  import { CircleDot, Loader2 } from "lucide-react"
2
+ import { TONE_DOT, TONE_TEXT } from "../../lib/tone-utils.js"
2
3
  import type { LayoutBuilderLabels, RefreshStatus } from "./labels.js"
3
4
 
4
5
  /**
@@ -22,15 +23,18 @@ export function StatusChip({
22
23
  }
23
24
  if (status === "pending") {
24
25
  return (
25
- <span className="inline-flex items-center gap-1.5 text-amber-600 dark:text-amber-400">
26
- <span className="size-1.5 animate-pulse rounded-full bg-amber-500" />
26
+ <span className={`inline-flex items-center gap-1.5 ${TONE_TEXT.warning}`}>
27
+ <span
28
+ aria-hidden="true"
29
+ className={`size-1.5 animate-pulse rounded-full ${TONE_DOT.warning}`}
30
+ />
27
31
  {L.statusPending}
28
32
  </span>
29
33
  )
30
34
  }
31
35
  return (
32
- <span className="text-primary inline-flex items-center gap-1.5">
33
- <Loader2 className="size-3 animate-spin" />
36
+ <span className={`inline-flex items-center gap-1.5 ${TONE_TEXT.info}`}>
37
+ <Loader2 aria-hidden="true" className="size-3 animate-spin" />
34
38
  {L.statusRefreshing}
35
39
  </span>
36
40
  )
@@ -111,6 +111,11 @@ export function useBuilderCatalogue({
111
111
  useEffect(() => {
112
112
  refreshRef.current = refreshBuilder
113
113
  }, [refreshBuilder])
114
+ // Retry of the catalogue error state: fetch again right away, with the
115
+ // current keys and steps.
116
+ const retryCatalogue = useCallback(() => {
117
+ void refreshRef.current()
118
+ }, [])
114
119
  const isFirstRun = useRef(true)
115
120
  useEffect(() => {
116
121
  if (isFirstRun.current) {
@@ -178,6 +183,7 @@ export function useBuilderCatalogue({
178
183
  validationIssues,
179
184
  status,
180
185
  refreshError,
186
+ retryCatalogue,
181
187
  widgetById,
182
188
  propsSchemaByWidgetId,
183
189
  paletteByApp,
@@ -22,6 +22,7 @@ export function useSaveDashboard({
22
22
  stepEntries,
23
23
  draft,
24
24
  onSaved,
25
+ onSuccess,
25
26
  }: {
26
27
  callTool: (name: string, args: object) => Promise<unknown>
27
28
  saveToolName: string
@@ -31,6 +32,8 @@ export function useSaveDashboard({
31
32
  stepEntries: PipelineStepRef[]
32
33
  draft: DraftLayout
33
34
  onSaved?: (result: { id: string; name: string }) => void
35
+ /** Confirms every successful save (the builder raises a toast), with the saved name. */
36
+ onSuccess?: (name: string) => void
34
37
  }) {
35
38
  const [isBusy, setBusy] = useState(false)
36
39
  const [saveOpen, setSaveOpen] = useState(false)
@@ -56,6 +59,7 @@ export function useSaveDashboard({
56
59
  })
57
60
  const saved = parseToolResult<{ id?: string; name?: string } | null>(result)
58
61
  setSaveOpen(false)
62
+ onSuccess?.(saved?.name ?? saveName.trim())
59
63
  if (saved?.id && onSaved) {
60
64
  onSaved({
61
65
  id: saved.id,
@@ -75,6 +79,7 @@ export function useSaveDashboard({
75
79
  draft,
76
80
  keyEntries,
77
81
  onSaved,
82
+ onSuccess,
78
83
  saveDescription,
79
84
  saveName,
80
85
  saveToolName,
package/src/app/index.ts CHANGED
@@ -1,5 +1,12 @@
1
1
  export { McpAppView } from "./mcp-app-view.js"
2
- export type { McpAppViewProps, McpAppViewLabels } from "./mcp-app-view.js"
2
+ export type {
3
+ McpAppViewProps,
4
+ McpAppViewLabels,
5
+ DescribeStep,
6
+ DescribeViewError,
7
+ ViewTitleLevel,
8
+ ViewTitleMode,
9
+ } from "./mcp-app-view.js"
3
10
  export { McpToolkitApp, mountMcpToolkitApp } from "./mcp-toolkit-app.js"
4
11
  export {
5
12
  WidgetRenderer,
@@ -7,7 +7,7 @@ import {
7
7
  initBuilderState,
8
8
  type BuilderDraftState,
9
9
  } from "./builder/builder-reducer.js"
10
- import { DEFAULT_LABELS, type LayoutBuilderLabels } from "./builder/labels.js"
10
+ import type { LayoutBuilderLabels } from "./builder/labels.js"
11
11
  import { Toolbar } from "./builder/Toolbar.js"
12
12
  import { PipelineStrip } from "./builder/PipelineStrip.js"
13
13
  import { CatalogueSheet } from "./builder/CatalogueSheet.js"
@@ -21,6 +21,8 @@ import { useBuilderCatalogue } from "./builder/use-builder-catalogue.js"
21
21
  import { useKeyStepEntries } from "./builder/use-key-step-entries.js"
22
22
  import { useSaveDashboard } from "./builder/use-save-dashboard.js"
23
23
  import { Tabs, TabsContent, TabsList, TabsTrigger } from "../primitives/tabs.js"
24
+ import { ToastProvider, useToast } from "../components/Toast.js"
25
+ import { useToolkitMessages } from "../locale/locale-provider.js"
24
26
  import { type WidgetComponent } from "./widget-renderer.js"
25
27
 
26
28
  // -------------------------------------------------------------------------- //
@@ -73,7 +75,20 @@ export interface LayoutBuilderProps {
73
75
  // Main component
74
76
  // -------------------------------------------------------------------------- //
75
77
 
76
- export function LayoutBuilder({
78
+ /**
79
+ * The visual view builder. Confirms a successful save with a toast (it mounts
80
+ * a `ToastProvider` when none is above it — inside `McpAppView` it shares the
81
+ * view's). Every caption follows the active locale (`labels` overrides).
82
+ */
83
+ export function LayoutBuilder(props: LayoutBuilderProps) {
84
+ return (
85
+ <ToastProvider>
86
+ <LayoutBuilderImpl {...props} />
87
+ </ToastProvider>
88
+ )
89
+ }
90
+
91
+ function LayoutBuilderImpl({
77
92
  initialLayout,
78
93
  title,
79
94
  initialKeys,
@@ -87,7 +102,9 @@ export function LayoutBuilder({
87
102
  onSaved,
88
103
  onExit,
89
104
  }: LayoutBuilderProps) {
90
- const L = useMemo(() => ({ ...DEFAULT_LABELS, ...labels }), [labels])
105
+ const messages = useToolkitMessages()
106
+ const L = useMemo(() => ({ ...messages.builder, ...labels }), [messages.builder, labels])
107
+ const toast = useToast()
91
108
 
92
109
  // ── Draft layout (pure reducer) ─────────────────────────────────────────
93
110
  // The draft plus the UI indices coupled to draft mutations
@@ -148,6 +165,7 @@ export function LayoutBuilder({
148
165
  validationIssues,
149
166
  status,
150
167
  refreshError,
168
+ retryCatalogue,
151
169
  widgetById,
152
170
  propsSchemaByWidgetId,
153
171
  paletteByApp,
@@ -176,6 +194,7 @@ export function LayoutBuilder({
176
194
  stepEntries,
177
195
  draft,
178
196
  onSaved,
197
+ onSuccess: (name) => toast.show({ tone: "success", title: L.saved(name) }),
179
198
  })
180
199
 
181
200
  // ── DnD ──────────────────────────────────────────────────────────────────
@@ -326,6 +345,7 @@ export function LayoutBuilder({
326
345
  catalogueToolName={catalogueToolName}
327
346
  refreshError={refreshError}
328
347
  validationIssues={validationIssues}
348
+ onRetry={retryCatalogue}
329
349
  />
330
350
 
331
351
  <Tabs value={view} onValueChange={(v) => setView(v as typeof view)}>