@frontmcp/ui 0.12.2 → 1.0.0-beta.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 (310) hide show
  1. package/README.md +279 -72
  2. package/bridge/adapters/claude.adapter.d.ts.map +1 -1
  3. package/bridge/adapters/gemini.adapter.d.ts.map +1 -1
  4. package/bridge/index.js +2 -36
  5. package/components/Alert/Alert.d.ts +11 -0
  6. package/components/Alert/Alert.d.ts.map +1 -0
  7. package/components/Alert/index.d.ts +4 -0
  8. package/components/Alert/index.d.ts.map +1 -0
  9. package/components/Alert/index.js +61 -0
  10. package/components/Avatar/Avatar.d.ts +10 -0
  11. package/components/Avatar/Avatar.d.ts.map +1 -0
  12. package/components/Avatar/index.d.ts +4 -0
  13. package/components/Avatar/index.d.ts.map +1 -0
  14. package/components/Avatar/index.js +43 -0
  15. package/components/Badge/Badge.d.ts +13 -0
  16. package/components/Badge/Badge.d.ts.map +1 -0
  17. package/components/Badge/index.d.ts +4 -0
  18. package/components/Badge/index.d.ts.map +1 -0
  19. package/{render → components/Badge}/index.js +54 -42
  20. package/components/Button/Button.d.ts +16 -0
  21. package/components/Button/Button.d.ts.map +1 -0
  22. package/components/Button/index.d.ts +4 -0
  23. package/components/Button/index.d.ts.map +1 -0
  24. package/components/Button/index.js +91 -0
  25. package/components/Card/Card.d.ts +25 -0
  26. package/components/Card/Card.d.ts.map +1 -0
  27. package/components/Card/index.d.ts +4 -0
  28. package/components/Card/index.d.ts.map +1 -0
  29. package/components/Card/index.js +110 -0
  30. package/components/List/List.d.ts +15 -0
  31. package/components/List/List.d.ts.map +1 -0
  32. package/components/List/index.d.ts +4 -0
  33. package/components/List/index.d.ts.map +1 -0
  34. package/components/List/index.js +58 -0
  35. package/components/Loader/Loader.d.ts +28 -0
  36. package/components/Loader/Loader.d.ts.map +1 -0
  37. package/components/Loader/LoaderContext.d.ts +20 -0
  38. package/components/Loader/LoaderContext.d.ts.map +1 -0
  39. package/components/Loader/index.d.ts +6 -0
  40. package/components/Loader/index.d.ts.map +1 -0
  41. package/components/Loader/index.js +174 -0
  42. package/components/Modal/Modal.d.ts +22 -0
  43. package/components/Modal/Modal.d.ts.map +1 -0
  44. package/components/Modal/index.d.ts +4 -0
  45. package/components/Modal/index.d.ts.map +1 -0
  46. package/components/Modal/index.js +80 -0
  47. package/components/Select/Select.d.ts +21 -0
  48. package/components/Select/Select.d.ts.map +1 -0
  49. package/components/Select/index.d.ts +4 -0
  50. package/components/Select/index.d.ts.map +1 -0
  51. package/components/Select/index.js +78 -0
  52. package/components/Table/Table.d.ts +15 -0
  53. package/components/Table/Table.d.ts.map +1 -0
  54. package/components/Table/index.d.ts +4 -0
  55. package/components/Table/index.d.ts.map +1 -0
  56. package/components/Table/index.js +70 -0
  57. package/components/TextField/TextField.d.ts +19 -0
  58. package/components/TextField/TextField.d.ts.map +1 -0
  59. package/components/TextField/index.d.ts +4 -0
  60. package/components/TextField/index.d.ts.map +1 -0
  61. package/components/TextField/index.js +77 -0
  62. package/components/index.d.ts +22 -28
  63. package/components/index.d.ts.map +1 -1
  64. package/components/index.js +523 -2521
  65. package/esm/bridge/index.mjs +2 -6
  66. package/esm/components/Alert/index.mjs +28 -0
  67. package/esm/components/Avatar/index.mjs +10 -0
  68. package/esm/components/Badge/index.mjs +56 -0
  69. package/esm/components/Button/index.mjs +58 -0
  70. package/esm/components/Card/index.mjs +77 -0
  71. package/esm/components/List/index.mjs +25 -0
  72. package/esm/components/Loader/index.mjs +141 -0
  73. package/esm/components/Modal/index.mjs +47 -0
  74. package/esm/components/Select/index.mjs +45 -0
  75. package/esm/components/Table/index.mjs +37 -0
  76. package/esm/components/TextField/index.mjs +44 -0
  77. package/esm/components/index.mjs +513 -2415
  78. package/esm/index.mjs +62 -4652
  79. package/esm/package.json +372 -16
  80. package/esm/react/index.mjs +2 -285
  81. package/esm/renderer/charts/index.mjs +336 -0
  82. package/esm/renderer/common/index.mjs +135 -0
  83. package/esm/renderer/csv/index.mjs +193 -0
  84. package/esm/renderer/flow/index.mjs +259 -0
  85. package/esm/renderer/html/index.mjs +99 -0
  86. package/esm/renderer/image/index.mjs +125 -0
  87. package/esm/renderer/index.mjs +2173 -0
  88. package/esm/renderer/maps/index.mjs +217 -0
  89. package/esm/renderer/math/index.mjs +229 -0
  90. package/esm/renderer/mdx/index.mjs +261 -0
  91. package/esm/renderer/media/index.mjs +235 -0
  92. package/esm/renderer/mermaid/index.mjs +220 -0
  93. package/esm/renderer/pdf/index.mjs +229 -0
  94. package/esm/renderer/react/index.mjs +230 -0
  95. package/esm/runtime/index.mjs +194 -0
  96. package/esm/theme/index.mjs +93 -0
  97. package/index.d.ts +10 -18
  98. package/index.d.ts.map +1 -1
  99. package/index.js +63 -4806
  100. package/package.json +372 -16
  101. package/react/index.d.ts +8 -54
  102. package/react/index.d.ts.map +1 -1
  103. package/react/index.js +2 -295
  104. package/renderer/auto-detect.d.ts +39 -0
  105. package/renderer/auto-detect.d.ts.map +1 -0
  106. package/renderer/charts/index.d.ts +22 -0
  107. package/renderer/charts/index.d.ts.map +1 -0
  108. package/renderer/charts/index.js +367 -0
  109. package/renderer/common/index.d.ts +5 -0
  110. package/renderer/common/index.d.ts.map +1 -0
  111. package/renderer/common/index.js +158 -0
  112. package/renderer/common/inject-stylesheet.d.ts +9 -0
  113. package/renderer/common/inject-stylesheet.d.ts.map +1 -0
  114. package/renderer/common/lazy-import.d.ts +85 -0
  115. package/renderer/common/lazy-import.d.ts.map +1 -0
  116. package/renderer/common/use-lazy-module.d.ts +13 -0
  117. package/renderer/common/use-lazy-module.d.ts.map +1 -0
  118. package/renderer/common/use-renderer-theme.d.ts +35 -0
  119. package/renderer/common/use-renderer-theme.d.ts.map +1 -0
  120. package/renderer/csv/index.d.ts +12 -0
  121. package/renderer/csv/index.d.ts.map +1 -0
  122. package/renderer/csv/index.js +224 -0
  123. package/renderer/flow/index.d.ts +40 -0
  124. package/renderer/flow/index.d.ts.map +1 -0
  125. package/renderer/flow/index.js +290 -0
  126. package/renderer/html/index.d.ts +12 -0
  127. package/renderer/html/index.d.ts.map +1 -0
  128. package/renderer/html/index.js +130 -0
  129. package/renderer/image/index.d.ts +11 -0
  130. package/renderer/image/index.d.ts.map +1 -0
  131. package/renderer/image/index.js +156 -0
  132. package/renderer/index.d.ts +32 -0
  133. package/renderer/index.d.ts.map +1 -0
  134. package/renderer/index.js +2206 -0
  135. package/renderer/maps/index.d.ts +27 -0
  136. package/renderer/maps/index.d.ts.map +1 -0
  137. package/renderer/maps/index.js +248 -0
  138. package/renderer/math/index.d.ts +11 -0
  139. package/renderer/math/index.d.ts.map +1 -0
  140. package/renderer/math/index.js +260 -0
  141. package/renderer/mdx/index.d.ts +10 -0
  142. package/renderer/mdx/index.d.ts.map +1 -0
  143. package/renderer/mdx/index.js +292 -0
  144. package/renderer/media/index.d.ts +20 -0
  145. package/renderer/media/index.d.ts.map +1 -0
  146. package/renderer/media/index.js +266 -0
  147. package/renderer/mermaid/index.d.ts +11 -0
  148. package/renderer/mermaid/index.d.ts.map +1 -0
  149. package/renderer/mermaid/index.js +251 -0
  150. package/renderer/pdf/index.d.ts +10 -0
  151. package/renderer/pdf/index.d.ts.map +1 -0
  152. package/renderer/pdf/index.js +260 -0
  153. package/renderer/react/index.d.ts +45 -0
  154. package/renderer/react/index.d.ts.map +1 -0
  155. package/renderer/react/index.js +261 -0
  156. package/renderer/types.d.ts +24 -0
  157. package/renderer/types.d.ts.map +1 -0
  158. package/runtime/babel-runtime.d.ts +70 -0
  159. package/runtime/babel-runtime.d.ts.map +1 -0
  160. package/runtime/content-detector.d.ts +43 -0
  161. package/runtime/content-detector.d.ts.map +1 -0
  162. package/runtime/index.d.ts +10 -0
  163. package/runtime/index.d.ts.map +1 -0
  164. package/runtime/index.js +217 -0
  165. package/theme/FrontMcpThemeProvider.d.ts +4 -0
  166. package/theme/FrontMcpThemeProvider.d.ts.map +1 -0
  167. package/theme/create-theme.d.ts +9 -0
  168. package/theme/create-theme.d.ts.map +1 -0
  169. package/theme/index.d.ts +5 -0
  170. package/theme/index.d.ts.map +1 -0
  171. package/theme/index.js +126 -0
  172. package/theme/types.d.ts +28 -0
  173. package/theme/types.d.ts.map +1 -0
  174. package/theme/use-theme.d.ts +3 -0
  175. package/theme/use-theme.d.ts.map +1 -0
  176. package/bundler/browser-components.d.ts +0 -42
  177. package/bundler/browser-components.d.ts.map +0 -1
  178. package/bundler/bundler.d.ts +0 -282
  179. package/bundler/bundler.d.ts.map +0 -1
  180. package/bundler/index.d.ts +0 -43
  181. package/bundler/index.d.ts.map +0 -1
  182. package/bundler/index.js +0 -3168
  183. package/bundler/types.d.ts +0 -883
  184. package/bundler/types.d.ts.map +0 -1
  185. package/components/alert.d.ts +0 -83
  186. package/components/alert.d.ts.map +0 -1
  187. package/components/alert.schema.d.ts +0 -98
  188. package/components/alert.schema.d.ts.map +0 -1
  189. package/components/avatar.d.ts +0 -77
  190. package/components/avatar.d.ts.map +0 -1
  191. package/components/avatar.schema.d.ts +0 -170
  192. package/components/avatar.schema.d.ts.map +0 -1
  193. package/components/badge.d.ts +0 -78
  194. package/components/badge.d.ts.map +0 -1
  195. package/components/badge.schema.d.ts +0 -91
  196. package/components/badge.schema.d.ts.map +0 -1
  197. package/components/button.d.ts +0 -100
  198. package/components/button.d.ts.map +0 -1
  199. package/components/button.schema.d.ts +0 -120
  200. package/components/button.schema.d.ts.map +0 -1
  201. package/components/card.d.ts +0 -76
  202. package/components/card.d.ts.map +0 -1
  203. package/components/card.schema.d.ts +0 -93
  204. package/components/card.schema.d.ts.map +0 -1
  205. package/components/form.d.ts +0 -227
  206. package/components/form.d.ts.map +0 -1
  207. package/components/form.schema.d.ts +0 -365
  208. package/components/form.schema.d.ts.map +0 -1
  209. package/components/list.d.ts +0 -121
  210. package/components/list.d.ts.map +0 -1
  211. package/components/list.schema.d.ts +0 -129
  212. package/components/list.schema.d.ts.map +0 -1
  213. package/components/modal.d.ts +0 -100
  214. package/components/modal.d.ts.map +0 -1
  215. package/components/modal.schema.d.ts +0 -151
  216. package/components/modal.schema.d.ts.map +0 -1
  217. package/components/table.d.ts +0 -91
  218. package/components/table.d.ts.map +0 -1
  219. package/components/table.schema.d.ts +0 -123
  220. package/components/table.schema.d.ts.map +0 -1
  221. package/esm/bundler/index.mjs +0 -3136
  222. package/esm/layouts/index.mjs +0 -409
  223. package/esm/render/index.mjs +0 -45
  224. package/esm/renderers/index.mjs +0 -621
  225. package/esm/universal/index.mjs +0 -1946
  226. package/esm/web-components/index.mjs +0 -2023
  227. package/layouts/base.d.ts +0 -86
  228. package/layouts/base.d.ts.map +0 -1
  229. package/layouts/index.d.ts +0 -8
  230. package/layouts/index.d.ts.map +0 -1
  231. package/layouts/index.js +0 -437
  232. package/layouts/presets.d.ts +0 -134
  233. package/layouts/presets.d.ts.map +0 -1
  234. package/react/Alert.d.ts +0 -101
  235. package/react/Alert.d.ts.map +0 -1
  236. package/react/Badge.d.ts +0 -100
  237. package/react/Badge.d.ts.map +0 -1
  238. package/react/Button.d.ts +0 -108
  239. package/react/Button.d.ts.map +0 -1
  240. package/react/Card.d.ts +0 -103
  241. package/react/Card.d.ts.map +0 -1
  242. package/react/types.d.ts +0 -105
  243. package/react/types.d.ts.map +0 -1
  244. package/render/index.d.ts +0 -8
  245. package/render/index.d.ts.map +0 -1
  246. package/render/prerender.d.ts +0 -57
  247. package/render/prerender.d.ts.map +0 -1
  248. package/renderers/index.d.ts +0 -26
  249. package/renderers/index.d.ts.map +0 -1
  250. package/renderers/index.js +0 -666
  251. package/renderers/mdx.renderer.d.ts +0 -99
  252. package/renderers/mdx.renderer.d.ts.map +0 -1
  253. package/renderers/react.adapter.d.ts +0 -70
  254. package/renderers/react.adapter.d.ts.map +0 -1
  255. package/renderers/react.renderer.d.ts +0 -105
  256. package/renderers/react.renderer.d.ts.map +0 -1
  257. package/renderers/transpiler.d.ts +0 -49
  258. package/renderers/transpiler.d.ts.map +0 -1
  259. package/universal/UniversalApp.d.ts +0 -108
  260. package/universal/UniversalApp.d.ts.map +0 -1
  261. package/universal/cached-runtime.d.ts +0 -139
  262. package/universal/cached-runtime.d.ts.map +0 -1
  263. package/universal/context.d.ts +0 -122
  264. package/universal/context.d.ts.map +0 -1
  265. package/universal/index.d.ts +0 -57
  266. package/universal/index.d.ts.map +0 -1
  267. package/universal/index.js +0 -2032
  268. package/universal/renderers/html.renderer.d.ts +0 -36
  269. package/universal/renderers/html.renderer.d.ts.map +0 -1
  270. package/universal/renderers/index.d.ts +0 -112
  271. package/universal/renderers/index.d.ts.map +0 -1
  272. package/universal/renderers/markdown.renderer.d.ts +0 -33
  273. package/universal/renderers/markdown.renderer.d.ts.map +0 -1
  274. package/universal/renderers/mdx.renderer.d.ts +0 -38
  275. package/universal/renderers/mdx.renderer.d.ts.map +0 -1
  276. package/universal/renderers/react.renderer.d.ts +0 -46
  277. package/universal/renderers/react.renderer.d.ts.map +0 -1
  278. package/universal/runtime-builder.d.ts +0 -33
  279. package/universal/runtime-builder.d.ts.map +0 -1
  280. package/universal/store.d.ts +0 -135
  281. package/universal/store.d.ts.map +0 -1
  282. package/universal/types.d.ts +0 -199
  283. package/universal/types.d.ts.map +0 -1
  284. package/web-components/core/attribute-parser.d.ts +0 -82
  285. package/web-components/core/attribute-parser.d.ts.map +0 -1
  286. package/web-components/core/base-element.d.ts +0 -197
  287. package/web-components/core/base-element.d.ts.map +0 -1
  288. package/web-components/core/index.d.ts +0 -9
  289. package/web-components/core/index.d.ts.map +0 -1
  290. package/web-components/elements/fmcp-alert.d.ts +0 -46
  291. package/web-components/elements/fmcp-alert.d.ts.map +0 -1
  292. package/web-components/elements/fmcp-badge.d.ts +0 -47
  293. package/web-components/elements/fmcp-badge.d.ts.map +0 -1
  294. package/web-components/elements/fmcp-button.d.ts +0 -117
  295. package/web-components/elements/fmcp-button.d.ts.map +0 -1
  296. package/web-components/elements/fmcp-card.d.ts +0 -53
  297. package/web-components/elements/fmcp-card.d.ts.map +0 -1
  298. package/web-components/elements/fmcp-input.d.ts +0 -96
  299. package/web-components/elements/fmcp-input.d.ts.map +0 -1
  300. package/web-components/elements/fmcp-select.d.ts +0 -100
  301. package/web-components/elements/fmcp-select.d.ts.map +0 -1
  302. package/web-components/elements/index.d.ts +0 -13
  303. package/web-components/elements/index.d.ts.map +0 -1
  304. package/web-components/index.d.ts +0 -49
  305. package/web-components/index.d.ts.map +0 -1
  306. package/web-components/index.js +0 -2058
  307. package/web-components/register.d.ts +0 -57
  308. package/web-components/register.d.ts.map +0 -1
  309. package/web-components/types.d.ts +0 -122
  310. package/web-components/types.d.ts.map +0 -1
@@ -1,621 +0,0 @@
1
- // libs/ui/src/renderers/react.renderer.ts
2
- import { isReactComponent, containsJsx, hashString, transpileJsx } from "@frontmcp/uipack/renderers";
3
- var VALID_JS_IDENTIFIER = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
4
- function isValidComponentName(name) {
5
- return VALID_JS_IDENTIFIER.test(name);
6
- }
7
- function sanitizeComponentName(name) {
8
- if (isValidComponentName(name)) {
9
- return name;
10
- }
11
- const sanitized = name.replace(/[^a-zA-Z0-9_$]/g, "_").replace(/^[0-9]/, "_$&");
12
- return sanitized || "Component";
13
- }
14
- var REACT_CDN = {
15
- react: "https://esm.sh/react@19",
16
- reactDom: "https://esm.sh/react-dom@19/client"
17
- };
18
- var INLINE_REACT_PLACEHOLDER = `
19
- // React runtime not available inline yet.
20
- // For blocked-network platforms, use pre-rendered HTML templates.
21
- console.warn('[FrontMCP] React hydration not available on this platform.');
22
- `;
23
- var ReactRenderer = class {
24
- type = "react";
25
- priority = 20;
26
- // Higher priority than HTML
27
- /**
28
- * Check if this renderer can handle the given template.
29
- *
30
- * Accepts:
31
- * - React component functions (imported, already transpiled)
32
- * - Strings containing JSX syntax
33
- */
34
- canHandle(template) {
35
- if (typeof template === "function" && isReactComponent(template)) {
36
- return true;
37
- }
38
- if (typeof template === "string" && containsJsx(template)) {
39
- return true;
40
- }
41
- return false;
42
- }
43
- /**
44
- * Transpile the template if needed.
45
- *
46
- * For imported React components, no transpilation is needed.
47
- * For JSX strings, SWC transpilation is performed.
48
- */
49
- async transpile(template, options) {
50
- if (typeof template === "function") {
51
- const hash = hashString(template.toString());
52
- return {
53
- code: "",
54
- // No transpiled code for already-compiled components
55
- hash,
56
- cached: true
57
- };
58
- }
59
- if (typeof template === "string") {
60
- return transpileJsx(template, {
61
- development: options?.sourceMaps ?? false
62
- });
63
- }
64
- throw new Error("Invalid template type for ReactRenderer");
65
- }
66
- /**
67
- * Render the template to HTML for client-side rendering.
68
- *
69
- * Unlike SSR, this method generates HTML that will be rendered
70
- * client-side by React in the browser. No server-side React required.
71
- *
72
- * The generated HTML includes:
73
- * - A container div for the React root
74
- * - The component code (transpiled if needed)
75
- * - Props embedded as a data attribute
76
- * - A render script that initializes the component
77
- */
78
- async render(template, context, _options) {
79
- const props = {
80
- input: context.input,
81
- output: context.output,
82
- structuredContent: context.structuredContent,
83
- helpers: context.helpers
84
- };
85
- const escapedProps = JSON.stringify(props).replace(/&/g, "&amp;").replace(/'/g, "&#39;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
86
- const rootId = `frontmcp-react-${hashString(Date.now().toString()).slice(0, 8)}`;
87
- let componentCode;
88
- let componentName;
89
- if (typeof template === "function") {
90
- const rawName = template.name || "Component";
91
- componentName = sanitizeComponentName(rawName);
92
- componentCode = `
93
- // Component should be registered via window.__frontmcp_components['${componentName}']
94
- (function() {
95
- if (!window.__frontmcp_components || !window.__frontmcp_components['${componentName}']) {
96
- console.error('[FrontMCP] Component "${componentName}" not registered. Use buildHydrationScript() to register components.');
97
- }
98
- })();
99
- `;
100
- } else if (typeof template === "string") {
101
- const transpiled = await this.transpile(template);
102
- const match = transpiled.code.match(/function\s+(\w+)/);
103
- const rawName = match?.[1] || "Widget";
104
- componentName = sanitizeComponentName(rawName);
105
- componentCode = transpiled.code;
106
- } else {
107
- throw new Error("Invalid template type for ReactRenderer");
108
- }
109
- const html = `
110
- <div id="${rootId}" data-frontmcp-react data-component="${componentName}" data-props='${escapedProps}'>
111
- <div class="flex items-center justify-center p-4 text-gray-500">
112
- <svg class="animate-spin h-5 w-5 mr-2" viewBox="0 0 24 24">
113
- <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" fill="none"></circle>
114
- <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
115
- </svg>
116
- Loading...
117
- </div>
118
- </div>
119
- <script type="module">
120
- (function() {
121
- ${componentCode}
122
-
123
- // Wait for React to be available
124
- function waitForReact(callback, maxAttempts) {
125
- var attempts = 0;
126
- var check = function() {
127
- if (typeof React !== 'undefined' && typeof ReactDOM !== 'undefined') {
128
- callback();
129
- } else if (attempts < maxAttempts) {
130
- attempts++;
131
- setTimeout(check, 50);
132
- } else {
133
- console.error('[FrontMCP] React not loaded after ' + maxAttempts + ' attempts');
134
- }
135
- };
136
- check();
137
- }
138
-
139
- waitForReact(function() {
140
- try {
141
- var root = document.getElementById('${rootId}');
142
- if (!root) return;
143
-
144
- var propsJson = root.getAttribute('data-props');
145
- var props = propsJson ? JSON.parse(propsJson.replace(/&amp;/g, '&').replace(/&#39;/g, "'").replace(/&lt;/g, '<').replace(/&gt;/g, '>')) : {};
146
-
147
- // Get the component
148
- var Component = ${componentName};
149
-
150
- // Check if it's registered globally
151
- if (typeof Component === 'undefined' && window.__frontmcp_components) {
152
- Component = window.__frontmcp_components['${componentName}'];
153
- }
154
-
155
- if (typeof Component === 'function') {
156
- var element = React.createElement(Component, props);
157
- var reactRoot = ReactDOM.createRoot(root);
158
- reactRoot.render(element);
159
- } else {
160
- console.error('[FrontMCP] Component "${componentName}" not found');
161
- }
162
- } catch (err) {
163
- console.error('[FrontMCP] React render error:', err);
164
- }
165
- }, 100);
166
- })();
167
- </script>
168
- `;
169
- return html.trim();
170
- }
171
- /**
172
- * Get runtime scripts for client-side functionality.
173
- */
174
- getRuntimeScripts(platform) {
175
- if (platform.networkMode === "blocked") {
176
- return {
177
- headScripts: "",
178
- inlineScripts: INLINE_REACT_PLACEHOLDER,
179
- isInline: true
180
- };
181
- }
182
- return {
183
- headScripts: `
184
- <script crossorigin src="${REACT_CDN.react}"></script>
185
- <script crossorigin src="${REACT_CDN.reactDom}"></script>
186
- `,
187
- isInline: false
188
- };
189
- }
190
- };
191
- var reactRenderer = new ReactRenderer();
192
-
193
- // libs/ui/src/renderers/react.adapter.ts
194
- var mountedRoots = /* @__PURE__ */ new WeakMap();
195
- var ReactRendererAdapter = class {
196
- type = "react";
197
- // Lazy-loaded React runtime
198
- react = null;
199
- reactDOM = null;
200
- loadPromise = null;
201
- /**
202
- * Check if this adapter can handle the given content.
203
- */
204
- canHandle(content) {
205
- if (typeof content === "function") {
206
- return true;
207
- }
208
- if (typeof content === "string") {
209
- if (content.includes("React.createElement") || content.includes("jsx(") || content.includes("jsxs(")) {
210
- return true;
211
- }
212
- const funcIndex = content.indexOf("function");
213
- if (funcIndex !== -1) {
214
- const afterFunc = content.slice(funcIndex, Math.min(funcIndex + 2e3, content.length));
215
- if (afterFunc.includes("return") && afterFunc.includes("<")) {
216
- return true;
217
- }
218
- }
219
- return false;
220
- }
221
- return false;
222
- }
223
- /**
224
- * Render React component to a string.
225
- * This is a client-side fallback - SSR should be done at build time.
226
- */
227
- async render(content, context, _options) {
228
- return `<div data-frontmcp-react data-tool="${context.toolName}">${content}</div>`;
229
- }
230
- /**
231
- * Render React component directly to the DOM.
232
- */
233
- async renderToDOM(content, target, context, options) {
234
- try {
235
- await this.ensureReactLoaded();
236
- if (!this.react || !this.reactDOM) {
237
- throw new Error("React runtime not available");
238
- }
239
- const componentName = target.getAttribute("data-component");
240
- const component = this.getComponent(componentName, content);
241
- if (!component) {
242
- target.innerHTML = content;
243
- return { success: true };
244
- }
245
- const element = this.react.createElement(component, {
246
- input: context.input,
247
- output: context.output,
248
- structuredContent: context.structuredContent,
249
- toolName: context.toolName
250
- });
251
- if (options?.hydrate && this.reactDOM.hydrateRoot) {
252
- const root = this.reactDOM.hydrateRoot(target, element);
253
- mountedRoots.set(target, root);
254
- } else if (this.reactDOM.createRoot) {
255
- const root = this.reactDOM.createRoot(target);
256
- root.render(element);
257
- mountedRoots.set(target, root);
258
- } else if (this.reactDOM.render) {
259
- this.reactDOM.render(element, target);
260
- mountedRoots.set(target, {
261
- unmount: () => this.reactDOM?.unmountComponentAtNode?.(target)
262
- });
263
- } else {
264
- throw new Error("No suitable React render method available");
265
- }
266
- target.dispatchEvent(
267
- new CustomEvent("frontmcp:rendered", {
268
- bubbles: true,
269
- detail: { type: "react", toolName: context.toolName }
270
- })
271
- );
272
- return { success: true };
273
- } catch (error) {
274
- const message = error instanceof Error ? error.message : String(error);
275
- console.error("[FrontMCP] React render failed:", message);
276
- return { success: false, error: message };
277
- }
278
- }
279
- /**
280
- * Hydrate existing SSR content with React.
281
- */
282
- async hydrate(target, context, options) {
283
- return this.renderToDOM("", target, context, { ...options, hydrate: true });
284
- }
285
- /**
286
- * Update rendered React component with new data.
287
- */
288
- async update(target, context) {
289
- try {
290
- await this.ensureReactLoaded();
291
- if (!this.react) {
292
- throw new Error("React runtime not available");
293
- }
294
- const existingRoot = mountedRoots.get(target);
295
- const componentName = target.getAttribute("data-component");
296
- const component = this.getComponent(componentName, "");
297
- if (!component) {
298
- return { success: false, error: "No component found for update" };
299
- }
300
- const element = this.react.createElement(component, {
301
- input: context.input,
302
- output: context.output,
303
- structuredContent: context.structuredContent,
304
- toolName: context.toolName
305
- });
306
- if (existingRoot && "render" in existingRoot) {
307
- existingRoot.render(element);
308
- return { success: true };
309
- }
310
- return this.renderToDOM("", target, context);
311
- } catch (error) {
312
- const message = error instanceof Error ? error.message : String(error);
313
- console.error("[FrontMCP] React update failed:", message);
314
- return { success: false, error: message };
315
- }
316
- }
317
- /**
318
- * Clean up React root.
319
- */
320
- destroy(target) {
321
- const root = mountedRoots.get(target);
322
- if (root) {
323
- root.unmount();
324
- mountedRoots.delete(target);
325
- }
326
- }
327
- /**
328
- * Ensure React is loaded.
329
- */
330
- async ensureReactLoaded() {
331
- if (this.react && this.reactDOM) {
332
- return;
333
- }
334
- if (this.loadPromise) {
335
- return this.loadPromise;
336
- }
337
- this.loadPromise = this.loadReact();
338
- return this.loadPromise;
339
- }
340
- /**
341
- * Load React runtime.
342
- */
343
- async loadReact() {
344
- const win = typeof window !== "undefined" ? window : globalThis;
345
- if (win.React) {
346
- this.react = win.React;
347
- }
348
- if (win.ReactDOM) {
349
- this.reactDOM = win.ReactDOM;
350
- }
351
- if (this.react && this.reactDOM) {
352
- return;
353
- }
354
- try {
355
- if (!this.react) {
356
- const reactModule = await import(
357
- /* webpackIgnore: true */
358
- "react"
359
- );
360
- this.react = reactModule.default || reactModule;
361
- }
362
- if (!this.reactDOM) {
363
- const reactDOMModule = await import(
364
- /* webpackIgnore: true */
365
- "react-dom/client"
366
- );
367
- this.reactDOM = reactDOMModule.default || reactDOMModule;
368
- }
369
- } catch {
370
- if (!this.react || !this.reactDOM) {
371
- console.warn("[FrontMCP] React runtime not available. Ensure React is loaded via CDN or bundled.");
372
- }
373
- }
374
- }
375
- /**
376
- * Get a React component by name or from content.
377
- */
378
- getComponent(componentName, content) {
379
- const win = typeof window !== "undefined" ? window : globalThis;
380
- if (componentName && win.__frontmcp_components) {
381
- const registered = win.__frontmcp_components?.[componentName];
382
- if (registered) {
383
- return registered;
384
- }
385
- }
386
- if (content && typeof content === "function") {
387
- return content;
388
- }
389
- return null;
390
- }
391
- };
392
- function createReactAdapter() {
393
- return new ReactRendererAdapter();
394
- }
395
- async function loadReactAdapter() {
396
- return createReactAdapter();
397
- }
398
-
399
- // libs/ui/src/renderers/mdx.renderer.ts
400
- import { containsMdxSyntax, hashString as hashString2, transpileCache, componentCache } from "@frontmcp/uipack/renderers";
401
- function buildReactCdnUrls(version = "19") {
402
- return {
403
- react: `https://esm.sh/react@${version}`,
404
- reactDom: `https://esm.sh/react-dom@${version}/client`
405
- };
406
- }
407
- var REACT_CDN2 = buildReactCdnUrls("19");
408
- var INLINE_MDX_PLACEHOLDER = `
409
- // MDX runtime not available inline yet.
410
- // For blocked-network platforms, use pre-rendered HTML templates.
411
- console.warn('[FrontMCP] MDX hydration not available on this platform.');
412
- `;
413
- var MdxRenderer = class {
414
- type = "mdx";
415
- priority = 10;
416
- // Between HTML (0) and React (20)
417
- /**
418
- * Lazy-loaded modules.
419
- */
420
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
421
- React = null;
422
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
423
- ReactDOMServer = null;
424
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
425
- jsxRuntime = null;
426
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
427
- mdxEvaluate = null;
428
- /**
429
- * Check if this renderer can handle the given template.
430
- *
431
- * Accepts strings containing MDX syntax (Markdown + JSX).
432
- */
433
- canHandle(template) {
434
- if (typeof template !== "string") {
435
- return false;
436
- }
437
- return containsMdxSyntax(template);
438
- }
439
- /**
440
- * Prepare MDX template for rendering.
441
- * Caches the template hash for deduplication. Actual MDX compilation
442
- * happens during render() via @mdx-js/mdx evaluate().
443
- */
444
- async transpile(template, _options) {
445
- const hash = hashString2(template);
446
- const cached = transpileCache.getByKey(hash);
447
- if (cached) {
448
- return { ...cached, cached: true };
449
- }
450
- const transpileResult = {
451
- code: template,
452
- hash,
453
- cached: false
454
- };
455
- transpileCache.setByKey(hash, transpileResult);
456
- return transpileResult;
457
- }
458
- /**
459
- * Render MDX template to HTML string.
460
- *
461
- * Uses @mdx-js/mdx's evaluate() for clean compilation + execution,
462
- * then renders the resulting React component to HTML via SSR.
463
- */
464
- async render(template, context, options) {
465
- await this.loadReact();
466
- await this.loadMdx();
467
- if (!this.mdxEvaluate) {
468
- throw new Error("MDX compilation requires @mdx-js/mdx. Install it: npm install @mdx-js/mdx");
469
- }
470
- const templateHash = hashString2(template);
471
- const cacheKey = `mdx-component:${templateHash}`;
472
- let Content = componentCache.get(cacheKey);
473
- if (!Content) {
474
- const result = await this.mdxEvaluate(template, {
475
- ...this.jsxRuntime,
476
- Fragment: this.React.Fragment,
477
- development: false
478
- });
479
- Content = result.default;
480
- componentCache.set(cacheKey, Content);
481
- }
482
- const mdxComponents = {
483
- ...options?.mdxComponents,
484
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
485
- wrapper: ({ children }) => {
486
- return this.React.createElement("div", { className: "mdx-content" }, children);
487
- }
488
- };
489
- const props = {
490
- input: context.input,
491
- output: context.output,
492
- structuredContent: context.structuredContent,
493
- helpers: context.helpers
494
- };
495
- const reservedProps = /* @__PURE__ */ new Set(["input", "output", "structuredContent", "helpers", "components"]);
496
- const outputProps = typeof context.output === "object" && context.output !== null ? Object.fromEntries(Object.entries(context.output).filter(([key]) => !reservedProps.has(key))) : {};
497
- const spreadProps = {
498
- ...outputProps,
499
- ...props
500
- };
501
- const element = this.React.createElement(Content, {
502
- components: mdxComponents,
503
- ...spreadProps
504
- });
505
- const html = this.ReactDOMServer.renderToString(element);
506
- if (options?.hydrate) {
507
- const escapedProps = JSON.stringify(props).replace(/&/g, "&amp;").replace(/'/g, "&#39;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
508
- return `<div data-mdx-hydrate="true" data-props='${escapedProps}'>${html}</div>`;
509
- }
510
- return html;
511
- }
512
- /**
513
- * Get runtime scripts for client-side functionality.
514
- */
515
- getRuntimeScripts(platform) {
516
- if (platform.networkMode === "blocked") {
517
- return {
518
- headScripts: "",
519
- inlineScripts: INLINE_MDX_PLACEHOLDER,
520
- isInline: true
521
- };
522
- }
523
- return {
524
- headScripts: `
525
- <script crossorigin src="${REACT_CDN2.react}"></script>
526
- <script crossorigin src="${REACT_CDN2.reactDom}"></script>
527
- `,
528
- isInline: false
529
- };
530
- }
531
- /**
532
- * Load React and ReactDOMServer modules.
533
- */
534
- async loadReact() {
535
- if (this.React && this.ReactDOMServer && this.jsxRuntime) {
536
- return;
537
- }
538
- try {
539
- const [react, reactDomServer, jsxRuntime] = await Promise.all([
540
- import("react"),
541
- import("react-dom/server"),
542
- import("react/jsx-runtime")
543
- ]);
544
- this.React = react;
545
- this.ReactDOMServer = reactDomServer;
546
- this.jsxRuntime = jsxRuntime;
547
- } catch {
548
- throw new Error("React is required for MdxRenderer. Install react and react-dom: npm install react react-dom");
549
- }
550
- }
551
- /**
552
- * Load @mdx-js/mdx evaluate function.
553
- */
554
- async loadMdx() {
555
- if (this.mdxEvaluate) {
556
- return;
557
- }
558
- try {
559
- const mdx = await import("@mdx-js/mdx");
560
- this.mdxEvaluate = mdx.evaluate;
561
- } catch {
562
- console.warn(
563
- "[@frontmcp/ui] @mdx-js/mdx not available. MDX rendering disabled. Install @mdx-js/mdx to enable: npm install @mdx-js/mdx"
564
- );
565
- }
566
- }
567
- };
568
- var mdxRenderer = new MdxRenderer();
569
-
570
- // libs/ui/src/renderers/transpiler.ts
571
- import { transpileJsx as transpileJsx2 } from "@frontmcp/uipack/renderers";
572
- async function executeTranspiledCode(code, context = {}) {
573
- let React;
574
- let jsxRuntime;
575
- try {
576
- React = await import("react");
577
- jsxRuntime = await import("react/jsx-runtime");
578
- } catch {
579
- throw new Error("React is required for JSX templates. Install react: npm install react react-dom");
580
- }
581
- const exports = {};
582
- const module = { exports };
583
- const require2 = (id) => {
584
- switch (id) {
585
- case "react":
586
- return React;
587
- case "react/jsx-runtime":
588
- return jsxRuntime;
589
- case "react/jsx-dev-runtime":
590
- return jsxRuntime;
591
- default:
592
- if (context[id]) {
593
- return context[id];
594
- }
595
- throw new Error(`Module '${id}' not available in JSX template context`);
596
- }
597
- };
598
- try {
599
- const fn = new Function("exports", "require", "module", "__filename", "__dirname", "React", "context", code);
600
- fn(exports, require2, module, "template.js", "/", React, context);
601
- const exportKeys = Object.keys(module.exports);
602
- return module.exports["default"] || (exportKeys.length > 0 ? module.exports[exportKeys[0]] : null) || module.exports;
603
- } catch (error) {
604
- throw new Error(`Failed to execute transpiled JSX: ${error instanceof Error ? error.message : String(error)}`);
605
- }
606
- }
607
- async function transpileAndExecute(source, context = {}) {
608
- const result = await transpileJsx2(source);
609
- return executeTranspiledCode(result.code, context);
610
- }
611
- export {
612
- MdxRenderer,
613
- ReactRenderer,
614
- ReactRendererAdapter,
615
- createReactAdapter,
616
- executeTranspiledCode,
617
- loadReactAdapter,
618
- mdxRenderer,
619
- reactRenderer,
620
- transpileAndExecute
621
- };