@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
@@ -7,8 +7,18 @@
7
7
  * `parseKeyValue ↔ keysToEntries ↔ entriesToKeys` round-trip and
8
8
  * `draftToLayout` — unit-testable in isolation.
9
9
  */
10
- import type { LayoutConfig, PipelineContext, RowDef } from "@miragon/mcp-toolkit-core"
11
- import { normalizeLayout } from "@miragon/mcp-toolkit-core"
10
+ import type {
11
+ DisplayText,
12
+ LayoutConfig,
13
+ PipelineContext,
14
+ PipelineStepRef,
15
+ RowDef,
16
+ } from "@miragon/mcp-toolkit-core"
17
+ import {
18
+ normalizeLayout,
19
+ PROPS_SCHEMA_DISPLAY_KEYWORD,
20
+ resolveLocalizedText,
21
+ } from "@miragon/mcp-toolkit-core"
12
22
 
13
23
  // -------------------------------------------------------------------------- //
14
24
  // Draft types
@@ -212,3 +222,332 @@ export function toPipelineContext(ctx: WireContext): PipelineContext {
212
222
  }
213
223
  return { steps, keys: ctx.keys, errors: ctx.errors }
214
224
  }
225
+
226
+ // -------------------------------------------------------------------------- //
227
+ // Display text — what the builder calls a widget, a step or a props field
228
+ // -------------------------------------------------------------------------- //
229
+
230
+ /** Resolves an i18n key in the active locale; `undefined` when it is unknown. */
231
+ export type DisplayKeyResolver = (key: string) => string | undefined
232
+
233
+ /**
234
+ * A {@link DisplayKeyResolver} over a translate function that echoes unknown
235
+ * keys (the `createTranslator` / `useTranslate` contract): the echo, or a
236
+ * blank result, means "unknown", so the caller falls back to its inline text.
237
+ */
238
+ export function keyResolverFrom(translate: (key: string) => string): DisplayKeyResolver {
239
+ return (key) => {
240
+ const text = translate(key).trim()
241
+ return text.length > 0 && text !== key ? text : undefined
242
+ }
243
+ }
244
+
245
+ /**
246
+ * The i18n key's text when the resolver knows it, else the inline (per-locale)
247
+ * text. Display text crosses the wire (the catalogue, a `propsSchema`), so a
248
+ * key that is not a string is ignored instead of reaching the translator.
249
+ */
250
+ function keyedText(
251
+ key: unknown,
252
+ text: DisplayText["title"],
253
+ locale: string,
254
+ resolveKey: DisplayKeyResolver | undefined,
255
+ ): string | undefined {
256
+ const viaKey = typeof key === "string" && resolveKey ? resolveKey(key) : undefined
257
+ return viaKey ?? resolveLocalizedText(text, locale)
258
+ }
259
+
260
+ /** How the builder names one entry: a label, the technical id as a quiet hint, a one-liner. */
261
+ export interface DisplayLabel {
262
+ /** The name people read: the entry's title, else its id. */
263
+ label: string
264
+ /** The technical id, set only when the label is a real title (so it is never shown twice). */
265
+ hint?: string
266
+ /** The one-line summary, when the entry has one. */
267
+ summary?: string
268
+ }
269
+
270
+ /**
271
+ * The builder's name for a widget or a step: its `titleKey` (when `resolveKey`
272
+ * knows it), its `title` in `locale`, else the id. The id comes back as `hint`
273
+ * only next to a real title. The `description` is the LLM's text and never
274
+ * appears here.
275
+ */
276
+ export function displayLabel(
277
+ entry: DisplayText,
278
+ id: string,
279
+ locale: string,
280
+ resolveKey?: DisplayKeyResolver,
281
+ ): DisplayLabel {
282
+ const title = keyedText(entry.titleKey, entry.title, locale, resolveKey)
283
+ const summary = keyedText(entry.summaryKey, entry.summary, locale, resolveKey)
284
+ return {
285
+ label: title ?? id,
286
+ ...(title !== undefined && title !== id ? { hint: id } : {}),
287
+ ...(summary !== undefined ? { summary } : {}),
288
+ }
289
+ }
290
+
291
+ /** A props-sheet field: its label, the raw property name as a hint, and its help line. */
292
+ export interface PropFieldText {
293
+ label: string
294
+ /** The property name, set only when the label differs from it. */
295
+ hint?: string
296
+ help?: string
297
+ }
298
+
299
+ function isRecord(value: unknown): value is Record<string, unknown> {
300
+ return typeof value === "object" && value !== null && !Array.isArray(value)
301
+ }
302
+
303
+ /**
304
+ * The props sheet's text for one `propsSchema` property. Label: the
305
+ * `x-display` title (key or text), else the standard JSON Schema `title`,
306
+ * else the property name. Help: the `x-display` summary, else the property's
307
+ * `description`.
308
+ */
309
+ export function propFieldText(
310
+ name: string,
311
+ prop: Record<string, unknown>,
312
+ locale: string,
313
+ resolveKey?: DisplayKeyResolver,
314
+ ): PropFieldText {
315
+ const raw = prop[PROPS_SCHEMA_DISPLAY_KEYWORD]
316
+ const display: DisplayText = isRecord(raw) ? raw : {}
317
+ const schemaTitle = typeof prop.title === "string" ? prop.title : undefined
318
+ const label =
319
+ keyedText(display.titleKey, display.title, locale, resolveKey) ??
320
+ resolveLocalizedText(schemaTitle, locale) ??
321
+ name
322
+ const schemaHelp = typeof prop.description === "string" ? prop.description : undefined
323
+ const help =
324
+ keyedText(display.summaryKey, display.summary, locale, resolveKey) ??
325
+ resolveLocalizedText(schemaHelp, locale)
326
+ return {
327
+ label,
328
+ ...(label !== name ? { hint: name } : {}),
329
+ ...(help !== undefined ? { help } : {}),
330
+ }
331
+ }
332
+
333
+ // -------------------------------------------------------------------------- //
334
+ // Draft status — what Apply, Discard and the unsaved marker compare
335
+ // -------------------------------------------------------------------------- //
336
+
337
+ /**
338
+ * Whether the draft holds at least one element on ANY tab, not only the
339
+ * active one: a new, still empty tab must not disable "Save as dashboard" or
340
+ * the preview while another tab has content.
341
+ */
342
+ export function draftHasCells(draft: DraftLayout): boolean {
343
+ const rows = draft.kind === "tabs" ? draft.tabs.flatMap((t) => t.rows) : draft.rows
344
+ return rows.some((r) => r.row.length > 0)
345
+ }
346
+
347
+ /**
348
+ * A comparable fingerprint of what Apply and Save hand on: the layout, the
349
+ * keys (blank names dropped, values parsed) and the steps that name a step.
350
+ * An empty key or step row the user has not filled in changes nothing.
351
+ */
352
+ export function builderSnapshot(
353
+ draft: DraftLayout,
354
+ keyEntries: KeyEntry[],
355
+ stepEntries: PipelineStepRef[],
356
+ ): string {
357
+ return JSON.stringify({
358
+ layout: draftToLayout(draft),
359
+ keys: entriesToKeys(keyEntries),
360
+ steps: stepEntries.filter((s) => s.step.trim().length > 0),
361
+ })
362
+ }
363
+
364
+ /** What Apply hands to `onExit`: the draft, plus the live context it was previewed with. */
365
+ export interface BuilderExitCommit {
366
+ layout: LayoutConfig
367
+ keys?: Record<string, unknown>
368
+ steps?: PipelineStepRef[]
369
+ title?: string
370
+ context?: WireContext
371
+ }
372
+
373
+ /**
374
+ * The commit of Apply: the layout, keys and steps exactly as a save would send
375
+ * them, and the live context in its wire shape (`stepIds` + keyed `stepData`)
376
+ * so the view renders the just-built layout without another round trip.
377
+ */
378
+ export function toExitCommit(
379
+ draft: DraftLayout,
380
+ keyEntries: KeyEntry[],
381
+ stepEntries: PipelineStepRef[],
382
+ title: string | undefined,
383
+ live: PipelineContext,
384
+ ): BuilderExitCommit {
385
+ return {
386
+ layout: draftToLayout(draft),
387
+ keys: entriesToKeys(keyEntries),
388
+ steps: stepEntries.filter((s) => s.step.trim().length > 0),
389
+ title,
390
+ context: {
391
+ keys: live.keys,
392
+ stepIds: Object.keys(live.steps),
393
+ stepData: Object.fromEntries(
394
+ Object.entries(live.steps).map(([id, result]) => [
395
+ id,
396
+ { data: result.data, keys: result.keys, _app: result._app, _dataType: result._dataType },
397
+ ]),
398
+ ),
399
+ errors: live.errors,
400
+ },
401
+ }
402
+ }
403
+
404
+ export interface DraftStatus {
405
+ /**
406
+ * The draft differs from the view as it was before editing: what Discard
407
+ * takes out of the view, so it decides whether Discard asks first.
408
+ */
409
+ changed: boolean
410
+ /**
411
+ * The draft has changes that would be lost: it differs from the view before
412
+ * editing AND from the last saved dashboard (a draft equal to either one
413
+ * loses nothing). Drives the unsaved marker and tells the discard
414
+ * confirmation whether a dashboard keeps the changes.
415
+ */
416
+ unsaved: boolean
417
+ }
418
+
419
+ /** Compares the current {@link builderSnapshot} with the pre-edit one and the last saved one. */
420
+ export function draftStatus(current: string, baseline: string, saved: string | null): DraftStatus {
421
+ const changed = current !== baseline
422
+ return { changed, unsaved: changed && current !== saved }
423
+ }
424
+
425
+ // -------------------------------------------------------------------------- //
426
+ // Leaving — Apply commits, Discard restores (asking first when the view loses changes)
427
+ // -------------------------------------------------------------------------- //
428
+
429
+ /** The builder's leave actions, built by {@link builderLeave}. */
430
+ export interface BuilderLeave {
431
+ /** Apply: hands the commit to `onExit`. Absent without `onExit` (no view to apply to). */
432
+ apply?: () => void
433
+ /** Discard: asks first when the view would lose changes, else leaves at once. */
434
+ discard: () => void
435
+ /** Discard without asking (the confirmation's own action). */
436
+ discardNow: () => void
437
+ }
438
+
439
+ /**
440
+ * The builder's leave actions. Apply hands `commit()` to `onExit`. Discard
441
+ * calls `onExit()` WITHOUT a commit, so the view stays as it was before
442
+ * editing; without `onExit` it calls `onReset()`, which restores the draft in
443
+ * place. Discard asks first (`confirm`) only when the draft `changed` the
444
+ * view: a draft that matches the view before editing loses nothing, even when
445
+ * it differs from a saved dashboard.
446
+ */
447
+ export function builderLeave({
448
+ changed,
449
+ onExit,
450
+ onReset,
451
+ commit,
452
+ confirm,
453
+ }: {
454
+ changed: boolean
455
+ onExit?: (commit?: BuilderExitCommit) => void
456
+ onReset: () => void
457
+ commit: () => BuilderExitCommit
458
+ confirm: () => void
459
+ }): BuilderLeave {
460
+ // Never hands its own arguments on: a click event must not reach `onExit` as a commit.
461
+ const discardNow = () => {
462
+ if (onExit) onExit()
463
+ else onReset()
464
+ }
465
+ return {
466
+ ...(onExit ? { apply: () => onExit(commit()) } : {}),
467
+ discard: () => {
468
+ if (changed) confirm()
469
+ else discardNow()
470
+ },
471
+ discardNow,
472
+ }
473
+ }
474
+
475
+ // -------------------------------------------------------------------------- //
476
+ // Keyboard — tab rename without a double-click
477
+ // -------------------------------------------------------------------------- //
478
+
479
+ /**
480
+ * What a key press on a tab trigger does: F2 renames any tab; Enter renames
481
+ * the tab that is already active (on another tab Enter keeps selecting it,
482
+ * the tabs' own behaviour). `null` leaves the key to the tabs.
483
+ */
484
+ export function tabTriggerKeyAction(key: string, isActive: boolean): "rename" | null {
485
+ if (key === "F2") return "rename"
486
+ if (key === "Enter" && isActive) return "rename"
487
+ return null
488
+ }
489
+
490
+ /** What a key press in a tab's rename field does: Enter commits, Escape cancels. */
491
+ export function renameFieldKeyAction(key: string): "commit" | "cancel" | null {
492
+ if (key === "Enter") return "commit"
493
+ if (key === "Escape") return "cancel"
494
+ return null
495
+ }
496
+
497
+ /**
498
+ * Hands the focus back to a tab once its rename field closes by keyboard.
499
+ * The tab strip holds it, by the tab's INDEX: a rename that changes the label
500
+ * mounts a new tab, so a request held by the tab itself would go with the old
501
+ * one and leave the focus on the document body.
502
+ */
503
+ export interface TabRefocus {
504
+ /** The trigger of tab `tabIdx` takes the focus the next time it attaches. */
505
+ request: (tabIdx: number) => void
506
+ /** The ref callback of tab `tabIdx`'s trigger: focuses it once while a request for it is open. */
507
+ attach: (tabIdx: number, el: { focus: () => void } | null) => void
508
+ /** The two props that wire tab `tabIdx` to this hand-back: its trigger's ref and its request. */
509
+ forTab: (tabIdx: number) => TabRefocusProps
510
+ }
511
+
512
+ /** What one tab gets from {@link TabRefocus.forTab}. */
513
+ export interface TabRefocusProps {
514
+ triggerRef: (el: { focus: () => void } | null) => void
515
+ onRefocus: () => void
516
+ }
517
+
518
+ /** A {@link TabRefocus} with no open request. */
519
+ export function createTabRefocus(): TabRefocus {
520
+ let pending: number | null = null
521
+ const request = (tabIdx: number) => {
522
+ pending = tabIdx
523
+ }
524
+ const attach = (tabIdx: number, el: { focus: () => void } | null) => {
525
+ if (el === null || pending !== tabIdx) return
526
+ pending = null
527
+ el.focus()
528
+ }
529
+ return {
530
+ request,
531
+ attach,
532
+ forTab: (tabIdx) => ({
533
+ triggerRef: (el) => attach(tabIdx, el),
534
+ onRefocus: () => request(tabIdx),
535
+ }),
536
+ }
537
+ }
538
+
539
+ // -------------------------------------------------------------------------- //
540
+ // Views — the data sources live behind "Advanced"
541
+ // -------------------------------------------------------------------------- //
542
+
543
+ export type BuilderView = "layout" | "pipeline" | "preview"
544
+
545
+ /** The builder's views in tab order: the data sources ("pipeline") only in advanced mode. */
546
+ export function builderViews(advanced: boolean): BuilderView[] {
547
+ return advanced ? ["layout", "pipeline", "preview"] : ["layout", "preview"]
548
+ }
549
+
550
+ /** The view to show after advanced mode switches: a view that is now hidden falls back to the layout. */
551
+ export function viewAfterAdvancedToggle(view: BuilderView, advanced: boolean): BuilderView {
552
+ return builderViews(advanced).includes(view) ? view : "layout"
553
+ }