@miragon/mcp-toolkit-ui 0.10.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 (320) hide show
  1. package/README.md +36 -0
  2. package/dist/app/adapt-data-widget.d.ts +33 -0
  3. package/dist/app/adapt-data-widget.d.ts.map +1 -0
  4. package/dist/app/adapt-data-widget.js +35 -0
  5. package/dist/app/adapt-data-widget.js.map +1 -0
  6. package/dist/app/builder/CatalogueSheet.d.ts +13 -0
  7. package/dist/app/builder/CatalogueSheet.d.ts.map +1 -0
  8. package/dist/app/builder/CatalogueSheet.js +33 -0
  9. package/dist/app/builder/CatalogueSheet.js.map +1 -0
  10. package/dist/app/builder/PipelineStrip.d.ts +22 -0
  11. package/dist/app/builder/PipelineStrip.d.ts.map +1 -0
  12. package/dist/app/builder/PipelineStrip.js +31 -0
  13. package/dist/app/builder/PipelineStrip.js.map +1 -0
  14. package/dist/app/builder/PreviewPane.d.ts +13 -0
  15. package/dist/app/builder/PreviewPane.d.ts.map +1 -0
  16. package/dist/app/builder/PreviewPane.js +21 -0
  17. package/dist/app/builder/PreviewPane.js.map +1 -0
  18. package/dist/app/builder/SaveDialog.d.ts +14 -0
  19. package/dist/app/builder/SaveDialog.d.ts.map +1 -0
  20. package/dist/app/builder/SaveDialog.js +14 -0
  21. package/dist/app/builder/SaveDialog.js.map +1 -0
  22. package/dist/app/builder/Toolbar.d.ts +17 -0
  23. package/dist/app/builder/Toolbar.d.ts.map +1 -0
  24. package/dist/app/builder/Toolbar.js +15 -0
  25. package/dist/app/builder/Toolbar.js.map +1 -0
  26. package/dist/app/builder/Workspace.d.ts +28 -0
  27. package/dist/app/builder/Workspace.d.ts.map +1 -0
  28. package/dist/app/builder/Workspace.js +117 -0
  29. package/dist/app/builder/Workspace.js.map +1 -0
  30. package/dist/app/builder/builder-model.d.ts +86 -0
  31. package/dist/app/builder/builder-model.d.ts.map +1 -0
  32. package/dist/app/builder/builder-model.js +174 -0
  33. package/dist/app/builder/builder-model.js.map +1 -0
  34. package/dist/app/builder/builder-reducer.d.ts +71 -0
  35. package/dist/app/builder/builder-reducer.d.ts.map +1 -0
  36. package/dist/app/builder/builder-reducer.js +201 -0
  37. package/dist/app/builder/builder-reducer.js.map +1 -0
  38. package/dist/app/builder/labels.d.ts +78 -0
  39. package/dist/app/builder/labels.d.ts.map +1 -0
  40. package/dist/app/builder/labels.js +71 -0
  41. package/dist/app/builder/labels.js.map +1 -0
  42. package/dist/app/builder/status-chip.d.ts +10 -0
  43. package/dist/app/builder/status-chip.d.ts.map +1 -0
  44. package/dist/app/builder/status-chip.js +16 -0
  45. package/dist/app/builder/status-chip.js.map +1 -0
  46. package/dist/app/host-bridge.d.ts +211 -0
  47. package/dist/app/host-bridge.d.ts.map +1 -0
  48. package/dist/app/host-bridge.js +247 -0
  49. package/dist/app/host-bridge.js.map +1 -0
  50. package/dist/app/index.d.ts +16 -0
  51. package/dist/app/index.d.ts.map +1 -0
  52. package/dist/app/index.js +18 -0
  53. package/dist/app/index.js.map +1 -0
  54. package/dist/app/layout-builder.d.ts +48 -0
  55. package/dist/app/layout-builder.d.ts.map +1 -0
  56. package/dist/app/layout-builder.js +418 -0
  57. package/dist/app/layout-builder.js.map +1 -0
  58. package/dist/app/mcp-app-view.d.ts +43 -0
  59. package/dist/app/mcp-app-view.d.ts.map +1 -0
  60. package/dist/app/mcp-app-view.js +169 -0
  61. package/dist/app/mcp-app-view.js.map +1 -0
  62. package/dist/app/mcp-toolkit-app.d.ts +18 -0
  63. package/dist/app/mcp-toolkit-app.d.ts.map +1 -0
  64. package/dist/app/mcp-toolkit-app.js +22 -0
  65. package/dist/app/mcp-toolkit-app.js.map +1 -0
  66. package/dist/app/use-host-actions.d.ts +57 -0
  67. package/dist/app/use-host-actions.d.ts.map +1 -0
  68. package/dist/app/use-host-actions.js +42 -0
  69. package/dist/app/use-host-actions.js.map +1 -0
  70. package/dist/app/widget-fixture.d.ts +180 -0
  71. package/dist/app/widget-fixture.d.ts.map +1 -0
  72. package/dist/app/widget-fixture.js +273 -0
  73. package/dist/app/widget-fixture.js.map +1 -0
  74. package/dist/app/widget-props-sheet.d.ts +20 -0
  75. package/dist/app/widget-props-sheet.d.ts.map +1 -0
  76. package/dist/app/widget-props-sheet.js +87 -0
  77. package/dist/app/widget-props-sheet.js.map +1 -0
  78. package/dist/app/widget-renderer.d.ts +87 -0
  79. package/dist/app/widget-renderer.d.ts.map +1 -0
  80. package/dist/app/widget-renderer.js +105 -0
  81. package/dist/app/widget-renderer.js.map +1 -0
  82. package/dist/components/DrillButton.d.ts +22 -0
  83. package/dist/components/DrillButton.d.ts.map +1 -0
  84. package/dist/components/DrillButton.js +13 -0
  85. package/dist/components/DrillButton.js.map +1 -0
  86. package/dist/components/FilterBar.d.ts +28 -0
  87. package/dist/components/FilterBar.d.ts.map +1 -0
  88. package/dist/components/FilterBar.js +12 -0
  89. package/dist/components/FilterBar.js.map +1 -0
  90. package/dist/components/GridLayout.d.ts +26 -0
  91. package/dist/components/GridLayout.d.ts.map +1 -0
  92. package/dist/components/GridLayout.js +31 -0
  93. package/dist/components/GridLayout.js.map +1 -0
  94. package/dist/components/GroupCard.d.ts +21 -0
  95. package/dist/components/GroupCard.d.ts.map +1 -0
  96. package/dist/components/GroupCard.js +24 -0
  97. package/dist/components/GroupCard.js.map +1 -0
  98. package/dist/components/KpiGrid.d.ts +43 -0
  99. package/dist/components/KpiGrid.d.ts.map +1 -0
  100. package/dist/components/KpiGrid.js +35 -0
  101. package/dist/components/KpiGrid.js.map +1 -0
  102. package/dist/components/ListFooter.d.ts +22 -0
  103. package/dist/components/ListFooter.d.ts.map +1 -0
  104. package/dist/components/ListFooter.js +13 -0
  105. package/dist/components/ListFooter.js.map +1 -0
  106. package/dist/components/Pills.d.ts +25 -0
  107. package/dist/components/Pills.d.ts.map +1 -0
  108. package/dist/components/Pills.js +17 -0
  109. package/dist/components/Pills.js.map +1 -0
  110. package/dist/components/SectionHeading.d.ts +16 -0
  111. package/dist/components/SectionHeading.d.ts.map +1 -0
  112. package/dist/components/SectionHeading.js +10 -0
  113. package/dist/components/SectionHeading.js.map +1 -0
  114. package/dist/components/WidgetHeader.d.ts +21 -0
  115. package/dist/components/WidgetHeader.d.ts.map +1 -0
  116. package/dist/components/WidgetHeader.js +11 -0
  117. package/dist/components/WidgetHeader.js.map +1 -0
  118. package/dist/hooks/index.d.ts +11 -0
  119. package/dist/hooks/index.d.ts.map +1 -0
  120. package/dist/hooks/index.js +7 -0
  121. package/dist/hooks/index.js.map +1 -0
  122. package/dist/hooks/use-debounced-value.d.ts +7 -0
  123. package/dist/hooks/use-debounced-value.d.ts.map +1 -0
  124. package/dist/hooks/use-debounced-value.js +15 -0
  125. package/dist/hooks/use-debounced-value.js.map +1 -0
  126. package/dist/hooks/use-mobile.d.ts +6 -0
  127. package/dist/hooks/use-mobile.d.ts.map +1 -0
  128. package/dist/hooks/use-mobile.js +19 -0
  129. package/dist/hooks/use-mobile.js.map +1 -0
  130. package/dist/hooks/use-tool-query.d.ts +21 -0
  131. package/dist/hooks/use-tool-query.d.ts.map +1 -0
  132. package/dist/hooks/use-tool-query.js +47 -0
  133. package/dist/hooks/use-tool-query.js.map +1 -0
  134. package/dist/hooks/use-tool-result-recovery.d.ts +54 -0
  135. package/dist/hooks/use-tool-result-recovery.d.ts.map +1 -0
  136. package/dist/hooks/use-tool-result-recovery.js +93 -0
  137. package/dist/hooks/use-tool-result-recovery.js.map +1 -0
  138. package/dist/hooks/use-view-data.d.ts +19 -0
  139. package/dist/hooks/use-view-data.d.ts.map +1 -0
  140. package/dist/hooks/use-view-data.js +18 -0
  141. package/dist/hooks/use-view-data.js.map +1 -0
  142. package/dist/hooks/use-view-tool-query.d.ts +18 -0
  143. package/dist/hooks/use-view-tool-query.d.ts.map +1 -0
  144. package/dist/hooks/use-view-tool-query.js +29 -0
  145. package/dist/hooks/use-view-tool-query.js.map +1 -0
  146. package/dist/index.d.ts +47 -0
  147. package/dist/index.d.ts.map +1 -0
  148. package/dist/index.js +56 -0
  149. package/dist/index.js.map +1 -0
  150. package/dist/lib/parse-tool-result.d.ts +39 -0
  151. package/dist/lib/parse-tool-result.d.ts.map +1 -0
  152. package/dist/lib/parse-tool-result.js +66 -0
  153. package/dist/lib/parse-tool-result.js.map +1 -0
  154. package/dist/lib/tone-utils.d.ts +18 -0
  155. package/dist/lib/tone-utils.d.ts.map +1 -0
  156. package/dist/lib/tone-utils.js +25 -0
  157. package/dist/lib/tone-utils.js.map +1 -0
  158. package/dist/lib/utils.d.ts +3 -0
  159. package/dist/lib/utils.d.ts.map +1 -0
  160. package/dist/lib/utils.js +6 -0
  161. package/dist/lib/utils.js.map +1 -0
  162. package/dist/locale/index.d.ts +3 -0
  163. package/dist/locale/index.d.ts.map +1 -0
  164. package/dist/locale/index.js +7 -0
  165. package/dist/locale/index.js.map +1 -0
  166. package/dist/locale/locale-provider.d.ts +50 -0
  167. package/dist/locale/locale-provider.d.ts.map +1 -0
  168. package/dist/locale/locale-provider.js +47 -0
  169. package/dist/locale/locale-provider.js.map +1 -0
  170. package/dist/primitives/alert.d.ts +10 -0
  171. package/dist/primitives/alert.d.ts.map +1 -0
  172. package/dist/primitives/alert.js +25 -0
  173. package/dist/primitives/alert.js.map +1 -0
  174. package/dist/primitives/badge.d.ts +8 -0
  175. package/dist/primitives/badge.d.ts.map +1 -0
  176. package/dist/primitives/badge.js +34 -0
  177. package/dist/primitives/badge.js.map +1 -0
  178. package/dist/primitives/button.d.ts +11 -0
  179. package/dist/primitives/button.d.ts.map +1 -0
  180. package/dist/primitives/button.js +36 -0
  181. package/dist/primitives/button.js.map +1 -0
  182. package/dist/primitives/card.d.ts +12 -0
  183. package/dist/primitives/card.d.ts.map +1 -0
  184. package/dist/primitives/card.js +25 -0
  185. package/dist/primitives/card.js.map +1 -0
  186. package/dist/primitives/dialog.d.ts +18 -0
  187. package/dist/primitives/dialog.d.ts.map +1 -0
  188. package/dist/primitives/dialog.js +38 -0
  189. package/dist/primitives/dialog.js.map +1 -0
  190. package/dist/primitives/input.d.ts +4 -0
  191. package/dist/primitives/input.d.ts.map +1 -0
  192. package/dist/primitives/input.js +7 -0
  193. package/dist/primitives/input.js.map +1 -0
  194. package/dist/primitives/scroll-area.d.ts +6 -0
  195. package/dist/primitives/scroll-area.d.ts.map +1 -0
  196. package/dist/primitives/scroll-area.js +11 -0
  197. package/dist/primitives/scroll-area.js.map +1 -0
  198. package/dist/primitives/select.d.ts +16 -0
  199. package/dist/primitives/select.d.ts.map +1 -0
  200. package/dist/primitives/select.js +38 -0
  201. package/dist/primitives/select.js.map +1 -0
  202. package/dist/primitives/separator.d.ts +4 -0
  203. package/dist/primitives/separator.d.ts.map +1 -0
  204. package/dist/primitives/separator.js +9 -0
  205. package/dist/primitives/separator.js.map +1 -0
  206. package/dist/primitives/sheet.d.ts +15 -0
  207. package/dist/primitives/sheet.d.ts.map +1 -0
  208. package/dist/primitives/sheet.js +41 -0
  209. package/dist/primitives/sheet.js.map +1 -0
  210. package/dist/primitives/skeleton.d.ts +3 -0
  211. package/dist/primitives/skeleton.d.ts.map +1 -0
  212. package/dist/primitives/skeleton.js +7 -0
  213. package/dist/primitives/skeleton.js.map +1 -0
  214. package/dist/primitives/switch.d.ts +5 -0
  215. package/dist/primitives/switch.d.ts.map +1 -0
  216. package/dist/primitives/switch.js +8 -0
  217. package/dist/primitives/switch.js.map +1 -0
  218. package/dist/primitives/table.d.ts +11 -0
  219. package/dist/primitives/table.d.ts.map +1 -0
  220. package/dist/primitives/table.js +28 -0
  221. package/dist/primitives/table.js.map +1 -0
  222. package/dist/primitives/tabs.d.ts +12 -0
  223. package/dist/primitives/tabs.d.ts.map +1 -0
  224. package/dist/primitives/tabs.js +29 -0
  225. package/dist/primitives/tabs.js.map +1 -0
  226. package/dist/providers/query-provider.d.ts +11 -0
  227. package/dist/providers/query-provider.d.ts.map +1 -0
  228. package/dist/providers/query-provider.js +20 -0
  229. package/dist/providers/query-provider.js.map +1 -0
  230. package/dist/theme/create-theme.d.ts +130 -0
  231. package/dist/theme/create-theme.d.ts.map +1 -0
  232. package/dist/theme/create-theme.js +65 -0
  233. package/dist/theme/create-theme.js.map +1 -0
  234. package/dist/theme/index.d.ts +7 -0
  235. package/dist/theme/index.d.ts.map +1 -0
  236. package/dist/theme/index.js +7 -0
  237. package/dist/theme/index.js.map +1 -0
  238. package/dist/theme/presets.d.ts +25 -0
  239. package/dist/theme/presets.d.ts.map +1 -0
  240. package/dist/theme/presets.js +68 -0
  241. package/dist/theme/presets.js.map +1 -0
  242. package/dist/theme/theme-provider.d.ts +69 -0
  243. package/dist/theme/theme-provider.d.ts.map +1 -0
  244. package/dist/theme/theme-provider.js +79 -0
  245. package/dist/theme/theme-provider.js.map +1 -0
  246. package/package.json +71 -0
  247. package/src/app/adapt-data-widget.tsx +51 -0
  248. package/src/app/builder/CatalogueSheet.tsx +230 -0
  249. package/src/app/builder/PipelineStrip.tsx +260 -0
  250. package/src/app/builder/PreviewPane.tsx +72 -0
  251. package/src/app/builder/SaveDialog.tsx +95 -0
  252. package/src/app/builder/Toolbar.tsx +95 -0
  253. package/src/app/builder/Workspace.tsx +483 -0
  254. package/src/app/builder/builder-model.test.ts +351 -0
  255. package/src/app/builder/builder-model.ts +213 -0
  256. package/src/app/builder/builder-reducer.test.ts +441 -0
  257. package/src/app/builder/builder-reducer.ts +289 -0
  258. package/src/app/builder/labels.ts +139 -0
  259. package/src/app/builder/status-chip.tsx +37 -0
  260. package/src/app/host-bridge.test.ts +206 -0
  261. package/src/app/host-bridge.tsx +371 -0
  262. package/src/app/index.ts +51 -0
  263. package/src/app/layout-builder.tsx +872 -0
  264. package/src/app/mcp-app-view.tsx +367 -0
  265. package/src/app/mcp-toolkit-app.tsx +25 -0
  266. package/src/app/use-host-actions.test.ts +16 -0
  267. package/src/app/use-host-actions.tsx +88 -0
  268. package/src/app/widget-fixture.test.ts +108 -0
  269. package/src/app/widget-fixture.tsx +441 -0
  270. package/src/app/widget-props-sheet.tsx +285 -0
  271. package/src/app/widget-renderer.test.ts +42 -0
  272. package/src/app/widget-renderer.tsx +200 -0
  273. package/src/components/DrillButton.tsx +37 -0
  274. package/src/components/FilterBar.tsx +68 -0
  275. package/src/components/GridLayout.tsx +49 -0
  276. package/src/components/GroupCard.tsx +52 -0
  277. package/src/components/KpiGrid.tsx +134 -0
  278. package/src/components/ListFooter.tsx +48 -0
  279. package/src/components/Pills.tsx +45 -0
  280. package/src/components/SectionHeading.tsx +26 -0
  281. package/src/components/WidgetHeader.tsx +51 -0
  282. package/src/globals.css +168 -0
  283. package/src/hooks/index.ts +17 -0
  284. package/src/hooks/use-debounced-value.ts +15 -0
  285. package/src/hooks/use-mobile.ts +24 -0
  286. package/src/hooks/use-tool-query.ts +63 -0
  287. package/src/hooks/use-tool-result-recovery.test.ts +65 -0
  288. package/src/hooks/use-tool-result-recovery.ts +144 -0
  289. package/src/hooks/use-view-data.ts +31 -0
  290. package/src/hooks/use-view-tool-query.ts +38 -0
  291. package/src/index.ts +134 -0
  292. package/src/lib/parse-tool-result.test.ts +139 -0
  293. package/src/lib/parse-tool-result.ts +89 -0
  294. package/src/lib/tone-utils.test.ts +35 -0
  295. package/src/lib/tone-utils.ts +38 -0
  296. package/src/lib/utils.ts +6 -0
  297. package/src/locale/index.ts +7 -0
  298. package/src/locale/locale-provider.tsx +81 -0
  299. package/src/primitives/alert.tsx +60 -0
  300. package/src/primitives/badge.tsx +49 -0
  301. package/src/primitives/button.tsx +62 -0
  302. package/src/primitives/card.tsx +92 -0
  303. package/src/primitives/dialog.tsx +144 -0
  304. package/src/primitives/input.tsx +21 -0
  305. package/src/primitives/scroll-area.tsx +54 -0
  306. package/src/primitives/select.tsx +173 -0
  307. package/src/primitives/separator.tsx +21 -0
  308. package/src/primitives/sheet.tsx +134 -0
  309. package/src/primitives/skeleton.tsx +13 -0
  310. package/src/primitives/switch.tsx +24 -0
  311. package/src/primitives/table.tsx +87 -0
  312. package/src/primitives/tabs.tsx +79 -0
  313. package/src/providers/query-provider.tsx +38 -0
  314. package/src/theme/create-theme.test.ts +108 -0
  315. package/src/theme/create-theme.ts +158 -0
  316. package/src/theme/index.ts +9 -0
  317. package/src/theme/presets.ts +82 -0
  318. package/src/theme/theme-provider.tsx +152 -0
  319. package/src/ui-catalog.test.ts +112 -0
  320. package/ui-catalog.json +1280 -0
@@ -0,0 +1,273 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { createContext, useContext, useEffect, useMemo, useRef, useSyncExternalStore, } from "react";
3
+ import { useWidget } from "mcp-use/react";
4
+ import { AppQueryProvider } from "../providers/query-provider.js";
5
+ import { HostBridgeProvider, createStandaloneHostBridge } from "./host-bridge.js";
6
+ /**
7
+ * Key `mcp-use` writes the serialized model-context string under when it flushes
8
+ * to `window.openai.setWidgetState`. Mirrors `MODEL_CONTEXT_KEY` in
9
+ * `mcp-use/react` (not exported, so duplicated here). The harness intercepts
10
+ * `setWidgetState` and reads this field to surface what the model would see.
11
+ */
12
+ const MODEL_CONTEXT_KEY = "__model_context";
13
+ /**
14
+ * Pure, host-free registry of fake tool implementations. Drives every
15
+ * `callTool` path the harness exposes (`window.openai.callTool`, the toolkit's
16
+ * `AppQueryProvider` bridge). Kept free of React/DOM so its semantics are unit
17
+ * testable in a plain Node environment.
18
+ *
19
+ * Resolution rules:
20
+ * - A registered **function** entry is called with `args` and its return value
21
+ * (awaited) is wrapped into a {@link FixtureToolResult}.
22
+ * - A registered **value** entry is returned as-is when it already looks like a
23
+ * tool response (has `structuredContent`/`content`), otherwise wrapped under
24
+ * `structuredContent` so widgets that read structured data Just Work.
25
+ * - An **unknown** tool rejects with a descriptive error. This is the
26
+ * error-friendly path: the rejection flows into the widget's own error state
27
+ * (TanStack Query `error`, `mcp-use` `isError`) instead of crashing the
28
+ * harness, and the message names the missing tool so the gap is obvious.
29
+ */
30
+ export class FixtureCallToolRegistry {
31
+ entries = new Map();
32
+ constructor(initial) {
33
+ if (initial) {
34
+ for (const [name, entry] of Object.entries(initial))
35
+ this.register(name, entry);
36
+ }
37
+ }
38
+ /** Register (or overwrite) the fixture for a tool name. */
39
+ register(name, resultOrHandler) {
40
+ this.entries.set(name, resultOrHandler);
41
+ return this;
42
+ }
43
+ /** True if a fixture is registered for `name`. */
44
+ has(name) {
45
+ return this.entries.has(name);
46
+ }
47
+ /** Registered tool names, for diagnostics / the harness log. */
48
+ names() {
49
+ return [...this.entries.keys()];
50
+ }
51
+ /**
52
+ * Resolve a tool call against the registered fixtures. Always returns a
53
+ * promise so callers can `await` uniformly regardless of whether the fixture
54
+ * was a static value or an async handler.
55
+ */
56
+ async call(name, args = {}) {
57
+ if (!this.entries.has(name)) {
58
+ throw new Error(`[widget-fixture] No fixture registered for tool "${name}". ` +
59
+ `Registered: ${this.names().length ? this.names().join(", ") : "(none)"}.`);
60
+ }
61
+ const entry = this.entries.get(name);
62
+ const raw = typeof entry === "function" ? await entry(args) : entry;
63
+ return toToolResult(raw);
64
+ }
65
+ }
66
+ /**
67
+ * Wrap an arbitrary fixture value into a {@link FixtureToolResult}. Values that
68
+ * already carry `structuredContent` or `content` are passed through untouched
69
+ * so a fixture can opt into the full envelope; everything else is placed under
70
+ * `structuredContent` (the field `parseToolResult` reads first) and mirrored
71
+ * into a `content` text block so `mcp-use`'s text-oriented decoder also sees it.
72
+ */
73
+ function toToolResult(raw) {
74
+ if (raw != null && typeof raw === "object" && ("structuredContent" in raw || "content" in raw)) {
75
+ return raw;
76
+ }
77
+ return {
78
+ structuredContent: raw,
79
+ content: [{ type: "text", text: typeof raw === "string" ? raw : JSON.stringify(raw) }],
80
+ };
81
+ }
82
+ const FixtureHostContext = createContext(null);
83
+ /**
84
+ * Access the active fixture registry from inside a {@link WidgetFixtureHost}.
85
+ * Returns `null` outside a harness — callers should treat that as "no fixture
86
+ * host present" rather than an error.
87
+ */
88
+ export function useFixtureHost() {
89
+ return useContext(FixtureHostContext);
90
+ }
91
+ /**
92
+ * Default host-context globals a widget sees in the harness. Chosen to be
93
+ * harmless and inert: inline display, light theme, desktop, no safe-area
94
+ * insets. Overridable per-mount via {@link WidgetFixtureHostProps.globals}.
95
+ */
96
+ const DEFAULT_GLOBALS = {
97
+ theme: "light",
98
+ displayMode: "inline",
99
+ locale: "en-US",
100
+ maxHeight: 4096,
101
+ safeArea: { insets: { top: 0, right: 0, bottom: 0, left: 0 } },
102
+ userAgent: {
103
+ device: { type: "desktop" },
104
+ capabilities: { hover: true, touch: false },
105
+ },
106
+ };
107
+ /**
108
+ * Build the `window.openai` shim the `mcp-use` React hooks read from. Routes
109
+ * `callTool` through the fixture registry and reports every other bridge verb
110
+ * to `onHostAction`. Returns `null` outside a browser-like environment (SSR)
111
+ * so the harness degrades to a plain render rather than throwing.
112
+ */
113
+ function buildOpenAiShim(registry, toolOutput, toolInput, globals, onHostAction, onModelContext) {
114
+ if (typeof window === "undefined")
115
+ return null;
116
+ return {
117
+ ...DEFAULT_GLOBALS,
118
+ ...globals,
119
+ toolInput,
120
+ toolOutput,
121
+ toolResponseMetadata: null,
122
+ widgetState: null,
123
+ callTool: async (name, args) => {
124
+ onHostAction?.({ type: "callTool", name, args });
125
+ return registry.call(name, args);
126
+ },
127
+ sendFollowUpMessage: (args) => {
128
+ onHostAction?.({ type: "sendFollowUpMessage", prompt: args.prompt });
129
+ return Promise.resolve();
130
+ },
131
+ openExternal: (payload) => {
132
+ onHostAction?.({ type: "openExternal", href: payload.href });
133
+ },
134
+ requestDisplayMode: (args) => {
135
+ onHostAction?.({ type: "requestDisplayMode", mode: args.mode });
136
+ return Promise.resolve({ mode: args.mode });
137
+ },
138
+ setWidgetState: (state) => {
139
+ onHostAction?.({ type: "setWidgetState", state });
140
+ // `mcp-use` flushes the serialized `<ModelContext>` tree through
141
+ // setWidgetState under MODEL_CONTEXT_KEY — surface it as the model view.
142
+ const ctx = state?.[MODEL_CONTEXT_KEY];
143
+ if (typeof ctx === "string")
144
+ onModelContext?.(ctx);
145
+ return Promise.resolve();
146
+ },
147
+ notifyIntrinsicHeight: () => Promise.resolve(),
148
+ };
149
+ }
150
+ /**
151
+ * Renders nothing but mounts a `useWidget()` so `mcp-use` registers its
152
+ * model-context flush handler — even for widgets that never call `useWidget`
153
+ * themselves (e.g. a simple `({ keys })` card). Without this, a widget's
154
+ * `<ModelContext>` would render but never flush, and `onModelContext` would
155
+ * stay silent. The flush routes through our `setWidgetState` shim above.
156
+ */
157
+ function ModelContextPump() {
158
+ useWidget();
159
+ return null;
160
+ }
161
+ /**
162
+ * Build the `WidgetProps` envelope the harness passes to the widget. Seeds a
163
+ * single pipeline step from `data` (keyed by `dataType` when given) and uses
164
+ * `data` as the `keys` map, so widgets that read `keys[...]` and adapted
165
+ * widgets that scan `context.steps` are both satisfied from one fixture.
166
+ *
167
+ * Exported for unit testing the envelope shape without rendering React.
168
+ */
169
+ export function buildFixtureWidgetProps(data, dataType) {
170
+ const steps = {};
171
+ if (dataType) {
172
+ steps.fixture = {
173
+ _app: "fixture",
174
+ _step: "fixture",
175
+ _dataType: dataType,
176
+ data,
177
+ keys: data,
178
+ };
179
+ }
180
+ const context = { steps, keys: data, errors: [] };
181
+ return { keys: data, context };
182
+ }
183
+ /**
184
+ * Storybook-style harness for MCP widgets. Renders a single widget with fixture
185
+ * data and a mocked host environment so it can be developed in isolation —
186
+ * without booting a real MCP host or backend.
187
+ *
188
+ * ### What it mocks
189
+ * - **`window.openai`** — the `mcp-use` Apps-SDK bridge `useWidget`/`useCallTool`
190
+ * read from. Installed on mount, removed on unmount. `callTool` is routed to a
191
+ * {@link FixtureCallToolRegistry} built from `tools`; `sendFollowUpMessage`,
192
+ * `openExternal`, etc. are reported to `onHostAction`.
193
+ * - **The toolkit `AppQueryProvider`** — so widgets that fetch via `useToolQuery`
194
+ * (e.g. generated `use*` hooks) resolve against the same registry.
195
+ * - **`ModelContext`** — a flush handler captures the serialized context string
196
+ * and forwards it to `onModelContext`, so you can *see* what the model would.
197
+ * - **A {@link HostBridge}** — a `createStandaloneHostBridge` over the same
198
+ * registry and callbacks, provided via `HostBridgeProvider`, so widgets
199
+ * written against `useHostBridge` (the host-portable pattern) are simulated
200
+ * from the same single source as the `window.openai` shim above.
201
+ *
202
+ * ### Boundaries
203
+ * `mcp-use`'s hooks select their provider from `window.openai` presence; this
204
+ * harness deliberately drives the Apps-SDK path (sets `window.openai`) rather
205
+ * than the `postMessage` bridge, which only activates inside a cross-origin
206
+ * iframe. The shim is intentionally minimal — it is not a host, and host
207
+ * features beyond the bridge verbs above are out of scope.
208
+ */
209
+ export function WidgetFixtureHost({ widget: Widget, data = {}, dataType, tools, globals, onModelContext, onHostAction, }) {
210
+ // One registry per `tools` identity. Rebuilt when the fixture map changes so
211
+ // edits in the playground take effect without a full remount.
212
+ const registry = useMemo(() => new FixtureCallToolRegistry(tools), [tools]);
213
+ // Latest callbacks without re-installing the shim on every render. Updated in
214
+ // an effect (not during render) so the shim's closures always see the newest
215
+ // handler while the `window.openai` install effect stays stable.
216
+ const onHostActionRef = useRef(onHostAction);
217
+ const onModelContextRef = useRef(onModelContext);
218
+ useEffect(() => {
219
+ onHostActionRef.current = onHostAction;
220
+ onModelContextRef.current = onModelContext;
221
+ });
222
+ const widgetProps = useMemo(() => buildFixtureWidgetProps(data, dataType), [data, dataType]);
223
+ // Install the `window.openai` shim for the lifetime of this mount. Wake any
224
+ // already-mounted `mcp-use` hooks via the `set_globals` event they listen for.
225
+ useEffect(() => {
226
+ if (typeof window === "undefined")
227
+ return;
228
+ const shim = buildOpenAiShim(registry, data ?? null, data ?? {}, globals ?? {}, (action) => onHostActionRef.current?.(action), (text) => onModelContextRef.current?.(text));
229
+ if (!shim)
230
+ return;
231
+ const prev = window.openai;
232
+ window.openai = shim;
233
+ window.dispatchEvent(new CustomEvent("openai:set_globals", { detail: { globals: shim } }));
234
+ return () => {
235
+ ;
236
+ window.openai = prev;
237
+ };
238
+ }, [registry, data, globals]);
239
+ const callTool = useMemo(() => async (name, args) => registry.call(name, args ?? {}), [registry]);
240
+ // A standalone host bridge over the same registry + callbacks, so portable
241
+ // widgets written against `useHostBridge` (rather than the `mcp-use` host
242
+ // hooks) are simulated from the *same* source as the `window.openai` shim.
243
+ // It logs through the same `HostActionLog` channel, so the playground's
244
+ // activity log shows tool calls, follow-ups, and links identically whether the
245
+ // widget uses the mcp-use path or the host bridge. Reading globals.theme keeps
246
+ // the bridge's reported theme in sync with the shim. Depends on the callback
247
+ // props directly (not the refs) — a fresh Provider value on callback change is
248
+ // fine for a dev harness, and keeps the bridge's closures pure of ref reads.
249
+ const bridgeTheme = (globals?.theme ?? DEFAULT_GLOBALS.theme) === "dark" ? "dark" : "light";
250
+ const bridge = useMemo(() => createStandaloneHostBridge({
251
+ callTool: (name, args) => {
252
+ onHostAction?.({ type: "callTool", name, args });
253
+ return registry.call(name, args);
254
+ },
255
+ getData: () => data ?? null,
256
+ onFollowup: (prompt) => onHostAction?.({ type: "sendFollowUpMessage", prompt }),
257
+ onOpenExternal: (href) => onHostAction?.({ type: "openExternal", href }),
258
+ onModelContext: (text) => onModelContext?.(text),
259
+ theme: bridgeTheme,
260
+ }), [registry, data, bridgeTheme, onHostAction, onModelContext]);
261
+ const value = useMemo(() => ({ registry }), [registry]);
262
+ // Mount the model-context pump only on the client. The pump calls `mcp-use`'s
263
+ // `useWidget`, whose `useSyncExternalStore` lacks a server snapshot and throws
264
+ // under `react-dom/server` — gating it keeps the harness (and any widget
265
+ // rendered through it) SSR-safe. `useSyncExternalStore` with a `false` server
266
+ // snapshot is the idiomatic "are we on the client?" check (no setState-in-effect).
267
+ const isClient = useSyncExternalStore(() => () => { }, () => true, () => false);
268
+ // Spread `widgetProps` (keys/context) AND a `data` alias so both adapted
269
+ // widgets and raw `({ data })` widgets read their fixture from one mount.
270
+ const RenderWidget = Widget;
271
+ return (_jsxs(FixtureHostContext.Provider, { value: value, children: [isClient && _jsx(ModelContextPump, {}), _jsx(HostBridgeProvider, { bridge: bridge, children: _jsx(AppQueryProvider, { callTool: callTool, children: _jsx(RenderWidget, { ...widgetProps, data: data }) }) })] }));
272
+ }
273
+ //# sourceMappingURL=widget-fixture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"widget-fixture.js","sourceRoot":"","sources":["../../src/app/widget-fixture.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ export interface WidgetPropsSheetLabels {
2
+ title?: string;
3
+ description?: string;
4
+ apply?: string;
5
+ cancel?: string;
6
+ reset?: string;
7
+ noProps?: string;
8
+ unsetOption?: string;
9
+ }
10
+ export interface WidgetPropsSheetProps {
11
+ open: boolean;
12
+ onOpenChange: (open: boolean) => void;
13
+ widgetId: string;
14
+ schema: Record<string, unknown> | undefined;
15
+ value: Record<string, unknown> | undefined;
16
+ onApply: (next: Record<string, unknown> | undefined) => void;
17
+ labels?: WidgetPropsSheetLabels;
18
+ }
19
+ export declare function WidgetPropsSheet({ open, onOpenChange, widgetId, schema, value, onApply, labels, }: WidgetPropsSheetProps): import("react").JSX.Element;
20
+ //# sourceMappingURL=widget-props-sheet.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"widget-props-sheet.d.ts","sourceRoot":"","sources":["../../src/app/widget-props-sheet.tsx"],"names":[],"mappings":"AAkDA,MAAM,WAAW,sBAAsB;IACrC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAcD,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAA;IAC3C,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAA;IAC1C,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,KAAK,IAAI,CAAA;IAC5D,MAAM,CAAC,EAAE,sBAAsB,CAAA;CAChC;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,IAAI,EACJ,YAAY,EACZ,QAAQ,EACR,MAAM,EACN,KAAK,EACL,OAAO,EACP,MAAM,GACP,EAAE,qBAAqB,+BA6EvB"}
@@ -0,0 +1,87 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from "react";
3
+ import { Button } from "../primitives/button.js";
4
+ import { Input } from "../primitives/input.js";
5
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "../primitives/select.js";
6
+ import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, } from "../primitives/sheet.js";
7
+ import { Switch } from "../primitives/switch.js";
8
+ const DEFAULT_LABELS = {
9
+ title: "Configure widget",
10
+ description: "Set per-instance props for this widget.",
11
+ apply: "Apply",
12
+ cancel: "Cancel",
13
+ reset: "Reset",
14
+ noProps: "This widget takes no per-instance props.",
15
+ unsetOption: "(unset)",
16
+ };
17
+ const UNSET_SENTINEL = "__unset__";
18
+ export function WidgetPropsSheet({ open, onOpenChange, widgetId, schema, value, onApply, labels, }) {
19
+ const L = { ...DEFAULT_LABELS, ...labels };
20
+ const obj = (schema ?? {});
21
+ const [draft, setDraft] = useState(value ?? {});
22
+ // Reset the form to the saved value on the open→true transition so a
23
+ // user who closes the sheet without applying gets their unsaved edits
24
+ // discarded next time. Render-time state update with a "prev" tracker
25
+ // is the React-recommended alternative to a setState-in-effect.
26
+ const [prevOpen, setPrevOpen] = useState(open);
27
+ if (open !== prevOpen) {
28
+ setPrevOpen(open);
29
+ if (open)
30
+ setDraft(value ?? {});
31
+ }
32
+ const properties = obj.properties ?? {};
33
+ const propEntries = Object.entries(properties);
34
+ const handleApply = () => {
35
+ const cleaned = {};
36
+ for (const [k, v] of Object.entries(draft)) {
37
+ if (v === "" || v === undefined || v === null)
38
+ continue;
39
+ cleaned[k] = v;
40
+ }
41
+ onApply(Object.keys(cleaned).length > 0 ? cleaned : undefined);
42
+ onOpenChange(false);
43
+ };
44
+ return (_jsx(Sheet, { open: open, onOpenChange: onOpenChange, children: _jsxs(SheetContent, { className: "w-[400px] sm:max-w-md", children: [_jsxs(SheetHeader, { children: [_jsx(SheetTitle, { children: L.title }), _jsxs(SheetDescription, { children: [_jsx("span", { className: "bg-muted rounded px-1 font-mono text-xs", children: widgetId }), " \u2014", " ", L.description] })] }), _jsx("div", { className: "flex flex-col gap-4 px-4 py-4", children: propEntries.length === 0 ? (_jsx("p", { className: "text-muted-foreground text-sm", children: L.noProps })) : (propEntries.map(([key, prop]) => (_jsx(PropertyField, { name: key, prop: prop, value: draft[key], unsetLabel: L.unsetOption, onChange: (v) => setDraft((prev) => {
45
+ if (v === undefined) {
46
+ const rest = {};
47
+ for (const [k, val] of Object.entries(prev)) {
48
+ if (k !== key)
49
+ rest[k] = val;
50
+ }
51
+ return rest;
52
+ }
53
+ return { ...prev, [key]: v };
54
+ }) }, key)))) }), _jsxs("div", { className: "flex items-center justify-end gap-2 border-t px-4 py-3", children: [_jsx(Button, { variant: "ghost", onClick: () => setDraft({}), children: L.reset }), _jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), children: L.cancel }), _jsx(Button, { onClick: handleApply, children: L.apply })] })] }) }));
55
+ }
56
+ function PropertyField({ name, prop, value, unsetLabel, onChange, }) {
57
+ const id = `prop-${name}`;
58
+ if (prop.type === "string" && Array.isArray(prop.enum)) {
59
+ const options = prop.enum.filter((v) => typeof v === "string");
60
+ const current = typeof value === "string" && value !== "" ? value : UNSET_SENTINEL;
61
+ return (_jsx(FieldShell, { id: id, name: name, description: prop.description, children: _jsxs(Select, { value: current, onValueChange: (v) => onChange(v === UNSET_SENTINEL ? undefined : v), children: [_jsx(SelectTrigger, { id: id, children: _jsx(SelectValue, { placeholder: unsetLabel }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: UNSET_SENTINEL, children: unsetLabel }), options.map((opt) => (_jsx(SelectItem, { value: opt, children: opt }, opt)))] })] }) }));
62
+ }
63
+ if (prop.type === "string") {
64
+ const current = typeof value === "string" ? value : "";
65
+ return (_jsx(FieldShell, { id: id, name: name, description: prop.description, children: _jsx(Input, { id: id, value: current, onChange: (e) => onChange(e.target.value === "" ? undefined : e.target.value) }) }));
66
+ }
67
+ if (prop.type === "number" || prop.type === "integer") {
68
+ const current = typeof value === "number" ? String(value) : "";
69
+ return (_jsx(FieldShell, { id: id, name: name, description: prop.description, children: _jsx(Input, { id: id, type: "number", value: current, onChange: (e) => {
70
+ const raw = e.target.value;
71
+ if (raw === "")
72
+ return onChange(undefined);
73
+ const parsed = prop.type === "integer" ? Number.parseInt(raw, 10) : Number.parseFloat(raw);
74
+ if (Number.isFinite(parsed))
75
+ onChange(parsed);
76
+ } }) }));
77
+ }
78
+ if (prop.type === "boolean") {
79
+ const current = value === true;
80
+ return (_jsx(FieldShell, { id: id, name: name, description: prop.description, children: _jsx(Switch, { id: id, checked: current, onCheckedChange: (checked) => onChange(checked || undefined) }) }));
81
+ }
82
+ return (_jsx(FieldShell, { id: id, name: name, description: prop.description, children: _jsxs("p", { className: "text-muted-foreground text-xs italic", children: ["Unsupported type \"", prop.type ?? "(none)", "\" \u2014 edit raw JSON to set this field."] }) }));
83
+ }
84
+ function FieldShell({ id, name, description, children, }) {
85
+ return (_jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx("label", { htmlFor: id, className: "text-sm font-medium", children: name }), children, description ? _jsx("p", { className: "text-muted-foreground text-xs", children: description }) : null] }));
86
+ }
87
+ //# sourceMappingURL=widget-props-sheet.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"widget-props-sheet.js","sourceRoot":"","sources":["../../src/app/widget-props-sheet.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,87 @@
1
+ import { Component, type ComponentType, type ReactNode, type ErrorInfo } from "react";
2
+ import type { LayoutConfig, PipelineContext, WidgetProps } from "@miragon/mcp-toolkit-core";
3
+ export type WidgetComponent = ComponentType<WidgetProps>;
4
+ /**
5
+ * Catches render-time crashes from a single widget so one broken widget
6
+ * can't take down the entire iframe view (or the builder canvas/preview).
7
+ *
8
+ * Exported so the visual builder's canvas + preview render sites reuse the
9
+ * same isolation the rendered `WidgetRenderer` already had — every place a
10
+ * widget component is rendered goes through {@link RenderedWidget}, which
11
+ * wraps the component in this boundary.
12
+ */
13
+ export declare class WidgetErrorBoundary extends Component<{
14
+ widgetId: string;
15
+ children: ReactNode;
16
+ }, {
17
+ error: Error | null;
18
+ }> {
19
+ state: {
20
+ error: Error | null;
21
+ };
22
+ static getDerivedStateFromError(error: Error): {
23
+ error: Error;
24
+ };
25
+ componentDidCatch(error: Error, info: ErrorInfo): void;
26
+ render(): string | number | bigint | boolean | import("react").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | null | undefined;
27
+ }
28
+ /**
29
+ * True when the pipeline context carries no widget data at all — no step
30
+ * results and no keys. A widget rendered against an empty context typically
31
+ * paints an empty shell (Finding [4]); callers use this to swap in a
32
+ * "data appears after refresh" hint instead.
33
+ *
34
+ * Intentionally coarse (per-view, not per-widget): the toolkit can't know
35
+ * which slice each widget reads without running its adapter, so it only
36
+ * degrades when there is provably nothing for any widget to show.
37
+ */
38
+ export declare function contextHasNoData(context: PipelineContext): boolean;
39
+ /**
40
+ * The single render site for a layout cell's widget, shared across the
41
+ * rendered view (`RowsRenderer`), the builder canvas, and the builder
42
+ * preview so all three isolate crashes identically:
43
+ * - missing component → "not bundled" fallback,
44
+ * - render crash → caught by {@link WidgetErrorBoundary} (Finding [1]),
45
+ * - (builder only, opt-in) empty pipeline context → a dezent
46
+ * "no data yet" hint (Finding [4]).
47
+ *
48
+ * The empty-state hint is gated behind `showEmptyHint` and defaults off so
49
+ * the shipped rendered view is unchanged: self-fetching control widgets
50
+ * there render correctly against an empty key-only context. The builder's
51
+ * canvas/preview opt in because their live context is empty until the first
52
+ * catalogue refresh resolves, and an empty widget shell reads as broken.
53
+ *
54
+ * `notBundledClassName` lets each surface match its own chrome (the builder
55
+ * uses denser padding/text than the rendered view).
56
+ */
57
+ export declare function RenderedWidget({ widget: Widget, widgetId, props, cellProps, showEmptyHint, notBundledClassName, }: {
58
+ widget: WidgetComponent | undefined;
59
+ widgetId: string;
60
+ props: WidgetProps;
61
+ cellProps?: Record<string, unknown>;
62
+ showEmptyHint?: boolean;
63
+ notBundledClassName?: string;
64
+ }): import("react").JSX.Element;
65
+ export interface WidgetRendererProps {
66
+ layout: LayoutConfig;
67
+ keys: Record<string, unknown>;
68
+ stepData?: Record<string, {
69
+ data: unknown;
70
+ keys: Record<string, unknown>;
71
+ _app: string;
72
+ _dataType: string;
73
+ }>;
74
+ errors: {
75
+ stepId: string;
76
+ reason: string;
77
+ }[];
78
+ /**
79
+ * Map of widget ID to React component. Consumers provide this so that the
80
+ * renderer can dispatch layout entries like `{widget: "camunda7:incident-panel"}`
81
+ * to the concrete component. The map is usually aggregated from each module's
82
+ * widget exports at the consumer's `main.tsx` entry point.
83
+ */
84
+ widgets: Record<string, WidgetComponent>;
85
+ }
86
+ export declare function WidgetRenderer({ layout, keys, stepData, errors, widgets }: WidgetRendererProps): import("react").JSX.Element;
87
+ //# sourceMappingURL=widget-renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"widget-renderer.d.ts","sourceRoot":"","sources":["../../src/app/widget-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,aAAa,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AACrF,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAU,WAAW,EAAE,MAAM,2BAA2B,CAAA;AAMnG,MAAM,MAAM,eAAe,GAAG,aAAa,CAAC,WAAW,CAAC,CAAA;AAExD;;;;;;;;GAQG;AACH,qBAAa,mBAAoB,SAAQ,SAAS,CAChD;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,SAAS,CAAA;CAAE,EACzC;IAAE,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;CAAE,CACxB;IACU,KAAK,EAAE;QAAE,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;KAAE,CAAkB;IACzD,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,KAAK;;;IAGnC,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS;IAG/C,MAAM;CAYhB;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAElE;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EAAE,MAAM,EACd,QAAQ,EACR,KAAK,EACL,SAAS,EACT,aAAqB,EACrB,mBAAkG,GACnG,EAAE;IACD,MAAM,EAAE,eAAe,GAAG,SAAS,CAAA;IACnC,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,WAAW,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACnC,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC7B,+BAgBA;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,YAAY,CAAA;IACpB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC7B,QAAQ,CAAC,EAAE,MAAM,CACf,MAAM,EACN;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAClF,CAAA;IACD,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IAC5C;;;;;OAKG;IACH,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAA;CACzC;AA0CD,wBAAgB,cAAc,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,mBAAmB,+BAmC9F"}
@@ -0,0 +1,105 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import { Component } from "react";
3
+ import { normalizeLayout } from "@miragon/mcp-toolkit-core";
4
+ import { GridLayout, GridItem } from "../components/GridLayout.js";
5
+ import { Card, CardContent } from "../primitives/card.js";
6
+ import { Tabs, TabsList, TabsTrigger, TabsContent } from "../primitives/tabs.js";
7
+ /**
8
+ * Catches render-time crashes from a single widget so one broken widget
9
+ * can't take down the entire iframe view (or the builder canvas/preview).
10
+ *
11
+ * Exported so the visual builder's canvas + preview render sites reuse the
12
+ * same isolation the rendered `WidgetRenderer` already had — every place a
13
+ * widget component is rendered goes through {@link RenderedWidget}, which
14
+ * wraps the component in this boundary.
15
+ */
16
+ export class WidgetErrorBoundary extends Component {
17
+ state = { error: null };
18
+ static getDerivedStateFromError(error) {
19
+ return { error };
20
+ }
21
+ componentDidCatch(error, info) {
22
+ console.error(`Widget ${this.props.widgetId} crashed:`, error, info);
23
+ }
24
+ render() {
25
+ if (this.state.error) {
26
+ return (_jsx(Card, { children: _jsxs(CardContent, { className: "text-muted-foreground py-3 text-sm", children: ["Widget \"", this.props.widgetId, "\" failed to render."] }) }));
27
+ }
28
+ return this.props.children;
29
+ }
30
+ }
31
+ /**
32
+ * True when the pipeline context carries no widget data at all — no step
33
+ * results and no keys. A widget rendered against an empty context typically
34
+ * paints an empty shell (Finding [4]); callers use this to swap in a
35
+ * "data appears after refresh" hint instead.
36
+ *
37
+ * Intentionally coarse (per-view, not per-widget): the toolkit can't know
38
+ * which slice each widget reads without running its adapter, so it only
39
+ * degrades when there is provably nothing for any widget to show.
40
+ */
41
+ export function contextHasNoData(context) {
42
+ return Object.keys(context.steps).length === 0 && Object.keys(context.keys).length === 0;
43
+ }
44
+ /**
45
+ * The single render site for a layout cell's widget, shared across the
46
+ * rendered view (`RowsRenderer`), the builder canvas, and the builder
47
+ * preview so all three isolate crashes identically:
48
+ * - missing component → "not bundled" fallback,
49
+ * - render crash → caught by {@link WidgetErrorBoundary} (Finding [1]),
50
+ * - (builder only, opt-in) empty pipeline context → a dezent
51
+ * "no data yet" hint (Finding [4]).
52
+ *
53
+ * The empty-state hint is gated behind `showEmptyHint` and defaults off so
54
+ * the shipped rendered view is unchanged: self-fetching control widgets
55
+ * there render correctly against an empty key-only context. The builder's
56
+ * canvas/preview opt in because their live context is empty until the first
57
+ * catalogue refresh resolves, and an empty widget shell reads as broken.
58
+ *
59
+ * `notBundledClassName` lets each surface match its own chrome (the builder
60
+ * uses denser padding/text than the rendered view).
61
+ */
62
+ export function RenderedWidget({ widget: Widget, widgetId, props, cellProps, showEmptyHint = false, notBundledClassName = "text-muted-foreground rounded border border-dashed p-4 text-center text-xs", }) {
63
+ if (!Widget) {
64
+ return _jsxs("div", { className: notBundledClassName, children: ["Widget \"", widgetId, "\" not bundled."] });
65
+ }
66
+ if (showEmptyHint && contextHasNoData(props.context)) {
67
+ return (_jsx("div", { className: notBundledClassName, children: "No data for this widget yet \u2014 it appears after a refresh." }));
68
+ }
69
+ return (_jsx(WidgetErrorBoundary, { widgetId: widgetId, children: _jsx(Widget, { ...props, widgetProps: cellProps }) }));
70
+ }
71
+ function RowsRenderer({ rows, props, widgets, }) {
72
+ return (_jsx("div", { className: "flex flex-col gap-4", children: rows.map((row, rowIdx) => (_jsx(GridLayout, { children: row.row.map((cell, cellIdx) => {
73
+ const WidgetComponent = widgets[cell.widget];
74
+ // Keep the rendered view's original behaviour of skipping cells
75
+ // whose component isn't bundled (no placeholder in the shipped
76
+ // view), while still routing the resolvable ones through the
77
+ // shared `RenderedWidget` for error-boundary + empty-state.
78
+ if (!WidgetComponent)
79
+ return null;
80
+ // Use a composite key so the same widget can appear in multiple
81
+ // cells of one row (e.g. side-by-side scoped dashboards) without
82
+ // colliding on React's reconciliation key.
83
+ return (_jsx(GridItem, { span: cell.span ?? 12, children: _jsx(RenderedWidget, { widget: WidgetComponent, widgetId: cell.widget, props: props, cellProps: cell.props }) }, `${cell.widget}-${cellIdx}`));
84
+ }) }, rowIdx))) }));
85
+ }
86
+ export function WidgetRenderer({ layout, keys, stepData, errors, widgets }) {
87
+ const steps = {};
88
+ if (stepData) {
89
+ for (const [id, result] of Object.entries(stepData)) {
90
+ steps[id] = { ...result, _step: id };
91
+ }
92
+ }
93
+ const pipelineContext = {
94
+ steps,
95
+ keys,
96
+ errors,
97
+ };
98
+ const widgetProps = { keys, context: pipelineContext };
99
+ const normalized = normalizeLayout(layout);
100
+ if ("tabs" in normalized) {
101
+ return (_jsxs(Tabs, { defaultValue: normalized.tabs[0]?.label, children: [_jsx(TabsList, { children: normalized.tabs.map((tab) => (_jsx(TabsTrigger, { value: tab.label, children: tab.label }, tab.label))) }), normalized.tabs.map((tab) => (_jsx(TabsContent, { value: tab.label, children: _jsx(RowsRenderer, { rows: tab.rows, props: widgetProps, widgets: widgets }) }, tab.label)))] }));
102
+ }
103
+ return _jsx(RowsRenderer, { rows: normalized.rows, props: widgetProps, widgets: widgets });
104
+ }
105
+ //# sourceMappingURL=widget-renderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"widget-renderer.js","sourceRoot":"","sources":["../../src/app/widget-renderer.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAsD,MAAM,OAAO,CAAA;AAErF,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAC3D,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAA;AAClE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACzD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAIhF;;;;;;;;GAQG;AACH,MAAM,OAAO,mBAAoB,SAAQ,SAGxC;IACU,KAAK,GAA4B,EAAE,KAAK,EAAE,IAAI,EAAE,CAAA;IACzD,MAAM,CAAC,wBAAwB,CAAC,KAAY;QAC1C,OAAO,EAAE,KAAK,EAAE,CAAA;IAClB,CAAC;IACQ,iBAAiB,CAAC,KAAY,EAAE,IAAe;QACtD,OAAO,CAAC,KAAK,CAAC,UAAU,IAAI,CAAC,KAAK,CAAC,QAAQ,WAAW,EAAE,KAAK,EAAE,IAAI,CAAC,CAAA;IACtE,CAAC;IACQ,MAAM;QACb,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACrB,OAAO,CACL,KAAC,IAAI,cACH,MAAC,WAAW,IAAC,SAAS,EAAC,oCAAoC,0BAChD,IAAI,CAAC,KAAK,CAAC,QAAQ,4BAChB,GACT,CACR,CAAA;QACH,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAA;IAC5B,CAAC;CACF;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAwB;IACvD,OAAO,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAA;AAC1F,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,cAAc,CAAC,EAC7B,MAAM,EAAE,MAAM,EACd,QAAQ,EACR,KAAK,EACL,SAAS,EACT,aAAa,GAAG,KAAK,EACrB,mBAAmB,GAAG,4EAA4E,GAQnG;IACC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,eAAK,SAAS,EAAE,mBAAmB,0BAAW,QAAQ,uBAAqB,CAAA;IACpF,CAAC;IACD,IAAI,aAAa,IAAI,gBAAgB,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QACrD,OAAO,CACL,cAAK,SAAS,EAAE,mBAAmB,+EAE7B,CACP,CAAA;IACH,CAAC;IACD,OAAO,CACL,KAAC,mBAAmB,IAAC,QAAQ,EAAE,QAAQ,YACrC,KAAC,MAAM,OAAK,KAAK,EAAE,WAAW,EAAE,SAAS,GAAI,GACzB,CACvB,CAAA;AACH,CAAC;AAmBD,SAAS,YAAY,CAAC,EACpB,IAAI,EACJ,KAAK,EACL,OAAO,GAKR;IACC,OAAO,CACL,cAAK,SAAS,EAAC,qBAAqB,YACjC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,CACzB,KAAC,UAAU,cACR,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE;gBAC7B,MAAM,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;gBAC5C,gEAAgE;gBAChE,+DAA+D;gBAC/D,6DAA6D;gBAC7D,4DAA4D;gBAC5D,IAAI,CAAC,eAAe;oBAAE,OAAO,IAAI,CAAA;gBACjC,gEAAgE;gBAChE,iEAAiE;gBACjE,2CAA2C;gBAC3C,OAAO,CACL,KAAC,QAAQ,IAAmC,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,EAAE,YAC/D,KAAC,cAAc,IACb,MAAM,EAAE,eAAe,EACvB,QAAQ,EAAE,IAAI,CAAC,MAAM,EACrB,KAAK,EAAE,KAAK,EACZ,SAAS,EAAE,IAAI,CAAC,KAAK,GACrB,IANW,GAAG,IAAI,CAAC,MAAM,IAAI,OAAO,EAAE,CAO/B,CACZ,CAAA;YACH,CAAC,CAAC,IArBa,MAAM,CAsBV,CACd,CAAC,GACE,CACP,CAAA;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAuB;IAC7F,MAAM,KAAK,GAAqD,EAAE,CAAA;IAClE,IAAI,QAAQ,EAAE,CAAC;QACb,KAAK,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YACpD,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,CAAA;QACtC,CAAC;IACH,CAAC;IACD,MAAM,eAAe,GAAoB;QACvC,KAAK;QACL,IAAI;QACJ,MAAM;KACP,CAAA;IACD,MAAM,WAAW,GAAgB,EAAE,IAAI,EAAE,OAAO,EAAE,eAAe,EAAE,CAAA;IACnE,MAAM,UAAU,GAAG,eAAe,CAAC,MAAM,CAAC,CAAA;IAE1C,IAAI,MAAM,IAAI,UAAU,EAAE,CAAC;QACzB,OAAO,CACL,MAAC,IAAI,IAAC,YAAY,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,aAC3C,KAAC,QAAQ,cACN,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAC5B,KAAC,WAAW,IAAiB,KAAK,EAAE,GAAG,CAAC,KAAK,YAC1C,GAAG,CAAC,KAAK,IADM,GAAG,CAAC,KAAK,CAEb,CACf,CAAC,GACO,EACV,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAC5B,KAAC,WAAW,IAAiB,KAAK,EAAE,GAAG,CAAC,KAAK,YAC3C,KAAC,YAAY,IAAC,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,GAAI,IADtD,GAAG,CAAC,KAAK,CAEb,CACf,CAAC,IACG,CACR,CAAA;IACH,CAAC;IAED,OAAO,KAAC,YAAY,IAAC,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,GAAI,CAAA;AACtF,CAAC"}