@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
package/index.js CHANGED
@@ -1,9 +1,7 @@
1
1
  "use strict";
2
- var __create = Object.create;
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
6
  var __export = (target, all) => {
9
7
  for (var name in all)
@@ -17,183 +15,21 @@ var __copyProps = (to, from, except, desc) => {
17
15
  }
18
16
  return to;
19
17
  };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
19
 
30
20
  // libs/ui/src/index.ts
31
21
  var index_exports = {};
32
22
  __export(index_exports, {
33
- ActionItemSchema: () => ActionItemSchema,
34
- ActionListOptionsSchema: () => ActionListOptionsSchema,
35
23
  AdapterRegistry: () => AdapterRegistry,
36
- Alert: () => Alert,
37
- AlertOptionsSchema: () => AlertOptionsSchema,
38
- AlertVariantSchema: () => AlertVariantSchema,
39
- AvatarGroupOptionsSchema: () => AvatarGroupOptionsSchema,
40
- AvatarOptionsSchema: () => AvatarOptionsSchema,
41
- AvatarShapeSchema: () => AvatarShapeSchema,
42
- AvatarSizeSchema: () => AvatarSizeSchema,
43
- AvatarSpacingSchema: () => AvatarSpacingSchema,
44
- AvatarStatusSchema: () => AvatarStatusSchema,
45
- AvatarWithTextOptionsSchema: () => AvatarWithTextOptionsSchema,
46
24
  BRIDGE_SCRIPT_TAGS: () => import_uipack.BRIDGE_SCRIPT_TAGS,
47
- Badge: () => Badge,
48
- BadgeGroupOptionsSchema: () => BadgeGroupOptionsSchema,
49
- BadgeOptionsSchema: () => BadgeOptionsSchema,
50
- BadgeSizeSchema: () => BadgeSizeSchema,
51
- BadgeVariantSchema: () => BadgeVariantSchema,
52
- Button: () => Button,
53
- ButtonGroupOptionsSchema: () => ButtonGroupOptionsSchema,
54
- ButtonOptionsSchema: () => ButtonOptionsSchema,
55
- ButtonSizeSchema: () => ButtonSizeSchema,
56
- ButtonVariantSchema: () => ButtonVariantSchema,
57
- Card: () => Card,
58
- CardGroupOptionsSchema: () => CardGroupOptionsSchema,
59
- CardOptionsSchema: () => CardOptionsSchema,
60
- CardSizeSchema: () => CardSizeSchema,
61
- CardVariantSchema: () => CardVariantSchema,
62
- CheckboxOptionsSchema: () => CheckboxOptionsSchema,
63
- ConfirmModalOptionsSchema: () => ConfirmModalOptionsSchema,
64
- ConfirmModalVariantSchema: () => ConfirmModalVariantSchema,
65
- DescriptionItemSchema: () => DescriptionItemSchema,
66
- DescriptionListOptionsSchema: () => DescriptionListOptionsSchema,
67
- DrawerOptionsSchema: () => DrawerOptionsSchema,
68
- DrawerPositionSchema: () => DrawerPositionSchema,
69
- FeatureItemSchema: () => FeatureItemSchema,
70
- FeatureListOptionsSchema: () => FeatureListOptionsSchema,
71
- FmcpAlert: () => FmcpAlert,
72
- FmcpBadge: () => FmcpBadge,
73
- FmcpButton: () => FmcpButton,
74
- FmcpCard: () => FmcpCard,
75
- FmcpElement: () => FmcpElement,
76
- FmcpInput: () => FmcpInput,
77
- FmcpSelect: () => FmcpSelect,
78
- FormActionsOptionsSchema: () => FormActionsOptionsSchema,
79
- FormEnctypeSchema: () => FormEnctypeSchema,
80
- FormMethodSchema: () => FormMethodSchema,
81
- FormOptionsSchema: () => FormOptionsSchema,
82
- FormRowOptionsSchema: () => FormRowOptionsSchema,
83
- FormSectionOptionsSchema: () => FormSectionOptionsSchema,
84
25
  FrontMcpBridge: () => FrontMcpBridge,
85
- InputOptionsSchema: () => InputOptionsSchema,
86
- InputSizeSchema: () => InputSizeSchema,
87
- InputStateSchema: () => InputStateSchema,
88
- InputTypeSchema: () => InputTypeSchema,
89
26
  McpBridgeProvider: () => McpBridgeProvider,
90
- ModalOptionsSchema: () => ModalOptionsSchema,
91
- ModalSizeSchema: () => ModalSizeSchema,
92
- ModalTriggerOptionsSchema: () => ModalTriggerOptionsSchema,
93
- PaginationOptionsSchema: () => PaginationOptionsSchema,
94
- PermissionItemSchema: () => PermissionItemSchema,
95
- PermissionListOptionsSchema: () => PermissionListOptionsSchema,
96
- RadioGroupOptionsSchema: () => RadioGroupOptionsSchema,
97
- RadioOptionItemSchema: () => RadioOptionItemSchema,
98
- ReactRenderer: () => ReactRenderer,
99
- ReactRendererAdapter: () => ReactRendererAdapter,
100
- SelectOptionItemSchema: () => SelectOptionItemSchema,
101
- SelectOptionsSchema: () => SelectOptionsSchema,
102
- TableAlignSchema: () => TableAlignSchema,
103
- TableColumnSchema: () => TableColumnSchema,
104
- TableOptionsSchema: () => TableOptionsSchema,
105
- TableSortDirectionSchema: () => TableSortDirectionSchema,
106
- TextareaOptionsSchema: () => TextareaOptionsSchema,
107
- TextareaResizeSchema: () => TextareaResizeSchema,
108
- ToastOptionsSchema: () => ToastOptionsSchema,
109
- ToastPositionSchema: () => ToastPositionSchema,
110
27
  UNIVERSAL_BRIDGE_SCRIPT: () => import_uipack.UNIVERSAL_BRIDGE_SCRIPT,
111
- actionList: () => actionList,
112
- activeBadge: () => activeBadge,
113
- alert: () => alert,
114
- authLayout: () => authLayout,
115
- authLayoutBuilder: () => authLayoutBuilder,
116
- avatar: () => avatar,
117
- avatarGroup: () => avatarGroup,
118
- avatarWithText: () => avatarWithText,
119
- awayDot: () => awayDot,
120
- badge: () => badge,
121
- badgeGroup: () => badgeGroup,
122
- baseLayout: () => baseLayout,
123
- betaBadge: () => betaBadge,
124
- busyDot: () => busyDot,
125
- button: () => button,
126
- buttonGroup: () => buttonGroup,
127
- card: () => card,
128
- cardGroup: () => cardGroup,
129
- checkbox: () => checkbox,
130
- confirmModal: () => confirmModal,
131
- consentLayout: () => consentLayout,
132
- consentLayoutBuilder: () => consentLayoutBuilder,
133
28
  createBridge: () => createBridge,
134
- createLayoutBuilder: () => createLayoutBuilder,
135
- createReactAdapter: () => createReactAdapter,
136
- csrfInput: () => csrfInput,
137
- dangerAlert: () => dangerAlert,
138
- dangerButton: () => dangerButton,
139
29
  defaultRegistry: () => defaultRegistry,
140
- descriptionList: () => descriptionList,
141
- drawer: () => drawer,
142
- errorBadge: () => errorBadge,
143
- errorLayout: () => errorLayout,
144
- errorLayoutBuilder: () => errorLayoutBuilder,
145
- escapeHtml: () => import_utils2.escapeHtml,
146
- featureList: () => featureList,
147
- form: () => form,
148
- formActions: () => formActions,
149
- formRow: () => formRow,
150
- formSection: () => formSection,
151
30
  generateBridgeIIFE: () => import_uipack.generateBridgeIIFE,
152
31
  generatePlatformBundle: () => import_uipack.generatePlatformBundle,
153
- ghostButton: () => ghostButton,
154
- hiddenInput: () => hiddenInput,
155
- inactiveBadge: () => inactiveBadge,
156
- infoAlert: () => infoAlert,
157
- input: () => input,
158
- linkButton: () => linkButton,
159
- loadReactAdapter: () => loadReactAdapter,
160
- loadingLayout: () => loadingLayout,
161
- modal: () => modal,
162
- modalTrigger: () => modalTrigger,
163
- newBadge: () => newBadge,
164
- offlineDot: () => offlineDot,
165
- onlineDot: () => onlineDot,
166
- outlineButton: () => outlineButton,
167
- pagination: () => pagination,
168
- pendingBadge: () => pendingBadge,
169
- permissionList: () => permissionList,
170
- primaryButton: () => primaryButton,
171
- radioGroup: () => radioGroup,
172
- reactRenderer: () => reactRenderer,
173
32
  registerAdapter: () => registerAdapter,
174
- registerAllComponents: () => registerAllComponents,
175
- registerFmcpAlert: () => registerFmcpAlert,
176
- registerFmcpBadge: () => registerFmcpBadge,
177
- registerFmcpButton: () => registerFmcpButton,
178
- registerFmcpCard: () => registerFmcpCard,
179
- registerFmcpInput: () => registerFmcpInput,
180
- registerFmcpSelect: () => registerFmcpSelect,
181
- renderAlert: () => renderAlert,
182
- renderAlertSync: () => renderAlertSync,
183
- renderBadge: () => renderBadge,
184
- renderBadgeSync: () => renderBadgeSync,
185
- renderButton: () => renderButton,
186
- renderButtonSync: () => renderButtonSync,
187
- renderCard: () => renderCard,
188
- renderCardSync: () => renderCardSync,
189
- secondaryButton: () => secondaryButton,
190
- select: () => select,
191
- successAlert: () => successAlert,
192
- successLayout: () => successLayout,
193
- table: () => table,
194
- textarea: () => textarea,
195
- toast: () => toast,
196
- toastContainer: () => toastContainer,
197
33
  useCallTool: () => useCallTool,
198
34
  useCapability: () => useCapability,
199
35
  useDisplayMode: () => useDisplayMode,
@@ -206,2718 +42,10 @@ __export(index_exports, {
206
42
  useTheme: () => useTheme,
207
43
  useToolCalls: () => useToolCalls,
208
44
  useToolInput: () => useToolInput,
209
- useToolOutput: () => useToolOutput,
210
- warningAlert: () => warningAlert,
211
- widgetLayout: () => widgetLayout
45
+ useToolOutput: () => useToolOutput
212
46
  });
213
47
  module.exports = __toCommonJS(index_exports);
214
48
 
215
- // libs/ui/src/components/button.schema.ts
216
- var import_zod = require("zod");
217
- var ButtonVariantSchema = import_zod.z.enum(["primary", "secondary", "outline", "ghost", "danger", "success", "link"]);
218
- var ButtonSizeSchema = import_zod.z.enum(["xs", "sm", "md", "lg", "xl"]);
219
- var ButtonOptionsSchema = import_zod.z.object({
220
- /** Button variant */
221
- variant: ButtonVariantSchema.optional(),
222
- /** Button size */
223
- size: ButtonSizeSchema.optional(),
224
- /** Button type attribute */
225
- type: import_zod.z.enum(["button", "submit", "reset"]).optional(),
226
- /** Disabled state */
227
- disabled: import_zod.z.boolean().optional(),
228
- /** Loading state */
229
- loading: import_zod.z.boolean().optional(),
230
- /** Full width */
231
- fullWidth: import_zod.z.boolean().optional(),
232
- /** Icon before text (HTML string) */
233
- iconBefore: import_zod.z.string().optional(),
234
- /** Icon after text (HTML string) */
235
- iconAfter: import_zod.z.string().optional(),
236
- /** Icon only (no text) */
237
- iconOnly: import_zod.z.boolean().optional(),
238
- /** Additional CSS classes */
239
- className: import_zod.z.string().optional(),
240
- /** Button ID */
241
- id: import_zod.z.string().optional(),
242
- /** Name attribute */
243
- name: import_zod.z.string().optional(),
244
- /** Value attribute */
245
- value: import_zod.z.string().optional(),
246
- /** Click handler (URL for links) */
247
- href: import_zod.z.string().optional(),
248
- /** Open in new tab */
249
- target: import_zod.z.enum(["_blank", "_self"]).optional(),
250
- /** Data attributes */
251
- data: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).optional(),
252
- /** ARIA label */
253
- ariaLabel: import_zod.z.string().optional()
254
- }).strict();
255
- var ButtonGroupOptionsSchema = import_zod.z.object({
256
- /** Attach buttons visually */
257
- attached: import_zod.z.boolean().optional(),
258
- /** Direction */
259
- direction: import_zod.z.enum(["horizontal", "vertical"]).optional(),
260
- /** Gap between buttons */
261
- gap: import_zod.z.enum(["sm", "md", "lg"]).optional(),
262
- /** Additional CSS classes */
263
- className: import_zod.z.string().optional()
264
- }).strict();
265
-
266
- // libs/ui/src/components/card.schema.ts
267
- var import_zod2 = require("zod");
268
- var CardVariantSchema = import_zod2.z.enum(["default", "outlined", "elevated", "filled", "ghost"]);
269
- var CardSizeSchema = import_zod2.z.enum(["sm", "md", "lg"]);
270
- var CardOptionsSchema = import_zod2.z.object({
271
- /** Card variant */
272
- variant: CardVariantSchema.optional(),
273
- /** Card size (padding) */
274
- size: CardSizeSchema.optional(),
275
- /** Card title */
276
- title: import_zod2.z.string().optional(),
277
- /** Card subtitle/description */
278
- subtitle: import_zod2.z.string().optional(),
279
- /** Header actions (HTML string) */
280
- headerActions: import_zod2.z.string().optional(),
281
- /** Footer content (HTML string) */
282
- footer: import_zod2.z.string().optional(),
283
- /** Additional CSS classes */
284
- className: import_zod2.z.string().optional(),
285
- /** Card ID */
286
- id: import_zod2.z.string().optional(),
287
- /** Data attributes */
288
- data: import_zod2.z.record(import_zod2.z.string(), import_zod2.z.string()).optional(),
289
- /** Clickable card (adds hover effects) */
290
- clickable: import_zod2.z.boolean().optional(),
291
- /** Click handler URL */
292
- href: import_zod2.z.string().optional()
293
- }).strict();
294
- var CardGroupOptionsSchema = import_zod2.z.object({
295
- /** Direction */
296
- direction: import_zod2.z.enum(["horizontal", "vertical"]).optional(),
297
- /** Gap between cards */
298
- gap: import_zod2.z.enum(["sm", "md", "lg"]).optional(),
299
- /** Additional CSS classes */
300
- className: import_zod2.z.string().optional()
301
- }).strict();
302
-
303
- // libs/ui/src/components/badge.schema.ts
304
- var import_zod3 = require("zod");
305
- var BadgeVariantSchema = import_zod3.z.enum([
306
- "default",
307
- "primary",
308
- "secondary",
309
- "success",
310
- "warning",
311
- "danger",
312
- "info",
313
- "outline"
314
- ]);
315
- var BadgeSizeSchema = import_zod3.z.enum(["sm", "md", "lg"]);
316
- var BadgeOptionsSchema = import_zod3.z.object({
317
- /** Badge variant */
318
- variant: BadgeVariantSchema.optional(),
319
- /** Badge size */
320
- size: BadgeSizeSchema.optional(),
321
- /** Rounded pill style */
322
- pill: import_zod3.z.boolean().optional(),
323
- /** Icon before text (HTML string) */
324
- icon: import_zod3.z.string().optional(),
325
- /** Dot indicator (no text) */
326
- dot: import_zod3.z.boolean().optional(),
327
- /** Additional CSS classes */
328
- className: import_zod3.z.string().optional(),
329
- /** Removable badge */
330
- removable: import_zod3.z.boolean().optional()
331
- }).strict();
332
- var BadgeGroupOptionsSchema = import_zod3.z.object({
333
- /** Gap between badges */
334
- gap: import_zod3.z.enum(["sm", "md", "lg"]).optional(),
335
- /** Additional CSS classes */
336
- className: import_zod3.z.string().optional()
337
- }).strict();
338
-
339
- // libs/ui/src/components/alert.schema.ts
340
- var import_zod4 = require("zod");
341
- var AlertVariantSchema = import_zod4.z.enum(["info", "success", "warning", "danger", "neutral"]);
342
- var AlertOptionsSchema = import_zod4.z.object({
343
- /** Alert variant */
344
- variant: AlertVariantSchema.optional(),
345
- /** Alert title */
346
- title: import_zod4.z.string().optional(),
347
- /** Show icon */
348
- showIcon: import_zod4.z.boolean().optional(),
349
- /** Custom icon (HTML string, overrides default) */
350
- icon: import_zod4.z.string().optional(),
351
- /** Dismissible alert */
352
- dismissible: import_zod4.z.boolean().optional(),
353
- /** Additional CSS classes */
354
- className: import_zod4.z.string().optional(),
355
- /** Alert ID */
356
- id: import_zod4.z.string().optional(),
357
- /** Actions (HTML string for buttons) */
358
- actions: import_zod4.z.string().optional()
359
- }).strict();
360
- var ToastPositionSchema = import_zod4.z.enum([
361
- "top-right",
362
- "top-left",
363
- "bottom-right",
364
- "bottom-left",
365
- "top-center",
366
- "bottom-center"
367
- ]);
368
- var ToastOptionsSchema = import_zod4.z.object({
369
- /** Toast variant */
370
- variant: AlertVariantSchema.optional(),
371
- /** Toast title */
372
- title: import_zod4.z.string().optional(),
373
- /** Duration in ms (0 = no auto-dismiss) */
374
- duration: import_zod4.z.number().min(0).optional(),
375
- /** Position */
376
- position: ToastPositionSchema.optional(),
377
- /** Toast ID */
378
- id: import_zod4.z.string().optional()
379
- }).strict();
380
-
381
- // libs/ui/src/components/avatar.schema.ts
382
- var import_zod5 = require("zod");
383
- var AvatarSizeSchema = import_zod5.z.enum(["xs", "sm", "md", "lg", "xl", "2xl"]);
384
- var AvatarShapeSchema = import_zod5.z.enum(["circle", "square", "rounded"]);
385
- var AvatarStatusSchema = import_zod5.z.enum(["online", "offline", "busy", "away", "none"]);
386
- var AvatarOptionsSchema = import_zod5.z.object({
387
- /** Image source URL */
388
- src: import_zod5.z.string().optional(),
389
- /** Alt text / name (required) */
390
- alt: import_zod5.z.string(),
391
- /** Avatar size */
392
- size: AvatarSizeSchema.optional(),
393
- /** Avatar shape */
394
- shape: AvatarShapeSchema.optional(),
395
- /** Status indicator */
396
- status: AvatarStatusSchema.optional(),
397
- /** Additional CSS classes */
398
- className: import_zod5.z.string().optional(),
399
- /** Click handler URL */
400
- href: import_zod5.z.string().optional(),
401
- /** Custom initials (overrides auto-generation) */
402
- initials: import_zod5.z.string().optional(),
403
- /** Background color for initials (CSS color) */
404
- bgColor: import_zod5.z.string().optional()
405
- }).strict();
406
- var AvatarSpacingSchema = import_zod5.z.enum(["tight", "normal", "loose"]);
407
- var AvatarGroupOptionsSchema = import_zod5.z.object({
408
- /** Maximum visible avatars */
409
- max: import_zod5.z.number().min(1).optional(),
410
- /** Avatar size */
411
- size: AvatarSizeSchema.optional(),
412
- /** Overlap amount */
413
- spacing: AvatarSpacingSchema.optional(),
414
- /** Additional CSS classes */
415
- className: import_zod5.z.string().optional()
416
- }).strict();
417
- var AvatarWithTextOptionsSchema = AvatarOptionsSchema.extend({
418
- /** Primary text (name) */
419
- name: import_zod5.z.string(),
420
- /** Secondary text (email, role, etc.) */
421
- subtitle: import_zod5.z.string().optional(),
422
- /** Text alignment */
423
- align: import_zod5.z.enum(["left", "right"]).optional()
424
- }).strict();
425
-
426
- // libs/ui/src/components/modal.schema.ts
427
- var import_zod6 = require("zod");
428
- var ModalSizeSchema = import_zod6.z.enum(["sm", "md", "lg", "xl", "full"]);
429
- var ModalOptionsSchema = import_zod6.z.object({
430
- /** Modal ID (required) */
431
- id: import_zod6.z.string(),
432
- /** Modal title */
433
- title: import_zod6.z.string().optional(),
434
- /** Modal size */
435
- size: ModalSizeSchema.optional(),
436
- /** Show close button */
437
- showClose: import_zod6.z.boolean().optional(),
438
- /** Close on backdrop click */
439
- closeOnBackdrop: import_zod6.z.boolean().optional(),
440
- /** Close on escape key */
441
- closeOnEscape: import_zod6.z.boolean().optional(),
442
- /** Footer content (HTML string) */
443
- footer: import_zod6.z.string().optional(),
444
- /** Additional CSS classes for modal */
445
- className: import_zod6.z.string().optional(),
446
- /** Initially visible */
447
- open: import_zod6.z.boolean().optional()
448
- }).strict();
449
- var ConfirmModalVariantSchema = import_zod6.z.enum(["info", "warning", "danger"]);
450
- var ConfirmModalOptionsSchema = import_zod6.z.object({
451
- /** Modal ID (required) */
452
- id: import_zod6.z.string(),
453
- /** Confirm message */
454
- message: import_zod6.z.string(),
455
- /** Title */
456
- title: import_zod6.z.string().optional(),
457
- /** Variant/severity */
458
- variant: ConfirmModalVariantSchema.optional(),
459
- /** Confirm button text */
460
- confirmText: import_zod6.z.string().optional(),
461
- /** Cancel button text */
462
- cancelText: import_zod6.z.string().optional(),
463
- /** Initially visible */
464
- open: import_zod6.z.boolean().optional(),
465
- /** Confirm action URL */
466
- confirmHref: import_zod6.z.string().optional()
467
- }).strict();
468
- var DrawerPositionSchema = import_zod6.z.enum(["left", "right", "top", "bottom"]);
469
- var DrawerOptionsSchema = import_zod6.z.object({
470
- /** Drawer ID (required) */
471
- id: import_zod6.z.string(),
472
- /** Position */
473
- position: DrawerPositionSchema.optional(),
474
- /** Size (width for left/right, height for top/bottom) */
475
- size: ModalSizeSchema.optional(),
476
- /** Drawer title */
477
- title: import_zod6.z.string().optional(),
478
- /** Show close button */
479
- showClose: import_zod6.z.boolean().optional(),
480
- /** Footer content (HTML string) */
481
- footer: import_zod6.z.string().optional(),
482
- /** Additional CSS classes */
483
- className: import_zod6.z.string().optional(),
484
- /** Initially visible */
485
- open: import_zod6.z.boolean().optional()
486
- }).strict();
487
- var ModalTriggerOptionsSchema = import_zod6.z.object({
488
- /** Target modal ID (required) */
489
- targetId: import_zod6.z.string(),
490
- /** Trigger text */
491
- text: import_zod6.z.string().optional(),
492
- /** HTML tag to use */
493
- tag: import_zod6.z.enum(["button", "a", "span", "div"]).optional(),
494
- /** Additional CSS classes */
495
- className: import_zod6.z.string().optional()
496
- }).strict();
497
-
498
- // libs/ui/src/components/table.schema.ts
499
- var import_zod7 = require("zod");
500
- var TableAlignSchema = import_zod7.z.enum(["left", "center", "right"]);
501
- var TableSortDirectionSchema = import_zod7.z.enum(["asc", "desc"]).nullable();
502
- var TableColumnSchema = import_zod7.z.object({
503
- /** Column key (property name) */
504
- key: import_zod7.z.string(),
505
- /** Column header text */
506
- header: import_zod7.z.string(),
507
- /** Column width (CSS value) */
508
- width: import_zod7.z.string().optional(),
509
- /** Text alignment */
510
- align: TableAlignSchema.optional(),
511
- /** Sortable column */
512
- sortable: import_zod7.z.boolean().optional(),
513
- /** Current sort direction */
514
- sortDirection: TableSortDirectionSchema.optional(),
515
- /** Custom cell renderer (function - cannot validate at runtime) */
516
- render: import_zod7.z.any().optional(),
517
- /** Additional header CSS classes */
518
- headerClass: import_zod7.z.string().optional(),
519
- /** Additional cell CSS classes */
520
- cellClass: import_zod7.z.string().optional()
521
- }).strict();
522
- var TableOptionsSchema = import_zod7.z.object({
523
- /** Column definitions */
524
- columns: import_zod7.z.array(TableColumnSchema),
525
- /** Table ID */
526
- id: import_zod7.z.string().optional(),
527
- /** Show row selection checkboxes */
528
- selectable: import_zod7.z.boolean().optional(),
529
- /** Row hover effect */
530
- hoverable: import_zod7.z.boolean().optional(),
531
- /** Striped rows */
532
- striped: import_zod7.z.boolean().optional(),
533
- /** Bordered cells */
534
- bordered: import_zod7.z.boolean().optional(),
535
- /** Compact size */
536
- compact: import_zod7.z.boolean().optional(),
537
- /** Fixed header (sticky) */
538
- stickyHeader: import_zod7.z.boolean().optional(),
539
- /** Additional CSS classes */
540
- className: import_zod7.z.string().optional(),
541
- /** Empty state message */
542
- emptyMessage: import_zod7.z.string().optional(),
543
- /** Empty state HTML */
544
- emptyContent: import_zod7.z.string().optional(),
545
- /** Loading state */
546
- loading: import_zod7.z.boolean().optional(),
547
- /** Row key property for selection */
548
- rowKey: import_zod7.z.string().optional(),
549
- /** Row click handler (URL template with {key}) */
550
- onRowClick: import_zod7.z.string().optional()
551
- }).strict();
552
- var PaginationOptionsSchema = import_zod7.z.object({
553
- /** Current page (1-indexed) */
554
- page: import_zod7.z.number().min(1),
555
- /** Total pages */
556
- totalPages: import_zod7.z.number().min(0),
557
- /** Total items count */
558
- totalItems: import_zod7.z.number().min(0).optional(),
559
- /** Items per page */
560
- pageSize: import_zod7.z.number().min(1).optional(),
561
- /** Page size options */
562
- pageSizeOptions: import_zod7.z.array(import_zod7.z.number()).optional(),
563
- /** Show first/last buttons */
564
- showFirstLast: import_zod7.z.boolean().optional(),
565
- /** Show page count */
566
- showPageCount: import_zod7.z.boolean().optional(),
567
- /** Show item count */
568
- showItemCount: import_zod7.z.boolean().optional(),
569
- /** Show page size selector */
570
- showPageSize: import_zod7.z.boolean().optional(),
571
- /** Max visible page buttons */
572
- maxVisiblePages: import_zod7.z.number().min(1).optional(),
573
- /** Additional CSS classes */
574
- className: import_zod7.z.string().optional()
575
- }).strict();
576
-
577
- // libs/ui/src/components/form.schema.ts
578
- var import_zod8 = require("zod");
579
- var InputTypeSchema = import_zod8.z.enum([
580
- "text",
581
- "email",
582
- "password",
583
- "number",
584
- "tel",
585
- "url",
586
- "search",
587
- "date",
588
- "time",
589
- "datetime-local",
590
- "hidden"
591
- ]);
592
- var InputSizeSchema = import_zod8.z.enum(["sm", "md", "lg"]);
593
- var InputStateSchema = import_zod8.z.enum(["default", "error", "success", "warning"]);
594
- var InputOptionsSchema = import_zod8.z.object({
595
- /** Input type */
596
- type: InputTypeSchema.optional(),
597
- /** Input name (required) */
598
- name: import_zod8.z.string(),
599
- /** Input ID (defaults to name) */
600
- id: import_zod8.z.string().optional(),
601
- /** Input value */
602
- value: import_zod8.z.string().optional(),
603
- /** Placeholder text */
604
- placeholder: import_zod8.z.string().optional(),
605
- /** Label text */
606
- label: import_zod8.z.string().optional(),
607
- /** Helper text */
608
- helper: import_zod8.z.string().optional(),
609
- /** Error message */
610
- error: import_zod8.z.string().optional(),
611
- /** Input size */
612
- size: InputSizeSchema.optional(),
613
- /** Input state */
614
- state: InputStateSchema.optional(),
615
- /** Required field */
616
- required: import_zod8.z.boolean().optional(),
617
- /** Disabled state */
618
- disabled: import_zod8.z.boolean().optional(),
619
- /** Readonly state */
620
- readonly: import_zod8.z.boolean().optional(),
621
- /** Autocomplete attribute */
622
- autocomplete: import_zod8.z.string().optional(),
623
- /** Pattern for validation */
624
- pattern: import_zod8.z.string().optional(),
625
- /** Min value (for number/date) */
626
- min: import_zod8.z.union([import_zod8.z.string(), import_zod8.z.number()]).optional(),
627
- /** Max value (for number/date) */
628
- max: import_zod8.z.union([import_zod8.z.string(), import_zod8.z.number()]).optional(),
629
- /** Step value (for number) */
630
- step: import_zod8.z.union([import_zod8.z.string(), import_zod8.z.number()]).optional(),
631
- /** Additional CSS classes */
632
- className: import_zod8.z.string().optional(),
633
- /** Data attributes */
634
- data: import_zod8.z.record(import_zod8.z.string(), import_zod8.z.string()).optional(),
635
- /** Icon before input (HTML string) */
636
- iconBefore: import_zod8.z.string().optional(),
637
- /** Icon after input (HTML string) */
638
- iconAfter: import_zod8.z.string().optional()
639
- }).strict();
640
- var SelectOptionItemSchema = import_zod8.z.object({
641
- value: import_zod8.z.string(),
642
- label: import_zod8.z.string(),
643
- disabled: import_zod8.z.boolean().optional(),
644
- selected: import_zod8.z.boolean().optional()
645
- }).strict();
646
- var SelectOptionsSchema = import_zod8.z.object({
647
- /** Input name (required) */
648
- name: import_zod8.z.string(),
649
- /** Input ID (defaults to name) */
650
- id: import_zod8.z.string().optional(),
651
- /** Input value */
652
- value: import_zod8.z.string().optional(),
653
- /** Placeholder text */
654
- placeholder: import_zod8.z.string().optional(),
655
- /** Label text */
656
- label: import_zod8.z.string().optional(),
657
- /** Helper text */
658
- helper: import_zod8.z.string().optional(),
659
- /** Error message */
660
- error: import_zod8.z.string().optional(),
661
- /** Input size */
662
- size: InputSizeSchema.optional(),
663
- /** Input state */
664
- state: InputStateSchema.optional(),
665
- /** Required field */
666
- required: import_zod8.z.boolean().optional(),
667
- /** Disabled state */
668
- disabled: import_zod8.z.boolean().optional(),
669
- /** Readonly state */
670
- readonly: import_zod8.z.boolean().optional(),
671
- /** Additional CSS classes */
672
- className: import_zod8.z.string().optional(),
673
- /** Data attributes */
674
- data: import_zod8.z.record(import_zod8.z.string(), import_zod8.z.string()).optional(),
675
- /** Icon before input (HTML string) */
676
- iconBefore: import_zod8.z.string().optional(),
677
- /** Icon after input (HTML string) */
678
- iconAfter: import_zod8.z.string().optional(),
679
- /** Select options (required) */
680
- options: import_zod8.z.array(SelectOptionItemSchema),
681
- /** Multiple selection */
682
- multiple: import_zod8.z.boolean().optional()
683
- }).strict();
684
- var TextareaResizeSchema = import_zod8.z.enum(["none", "vertical", "horizontal", "both"]);
685
- var TextareaOptionsSchema = import_zod8.z.object({
686
- /** Input name (required) */
687
- name: import_zod8.z.string(),
688
- /** Input ID (defaults to name) */
689
- id: import_zod8.z.string().optional(),
690
- /** Input value */
691
- value: import_zod8.z.string().optional(),
692
- /** Placeholder text */
693
- placeholder: import_zod8.z.string().optional(),
694
- /** Label text */
695
- label: import_zod8.z.string().optional(),
696
- /** Helper text */
697
- helper: import_zod8.z.string().optional(),
698
- /** Error message */
699
- error: import_zod8.z.string().optional(),
700
- /** Input size */
701
- size: InputSizeSchema.optional(),
702
- /** Input state */
703
- state: InputStateSchema.optional(),
704
- /** Required field */
705
- required: import_zod8.z.boolean().optional(),
706
- /** Disabled state */
707
- disabled: import_zod8.z.boolean().optional(),
708
- /** Readonly state */
709
- readonly: import_zod8.z.boolean().optional(),
710
- /** Autocomplete attribute */
711
- autocomplete: import_zod8.z.string().optional(),
712
- /** Additional CSS classes */
713
- className: import_zod8.z.string().optional(),
714
- /** Data attributes */
715
- data: import_zod8.z.record(import_zod8.z.string(), import_zod8.z.string()).optional(),
716
- /** Icon before input (HTML string) */
717
- iconBefore: import_zod8.z.string().optional(),
718
- /** Icon after input (HTML string) */
719
- iconAfter: import_zod8.z.string().optional(),
720
- /** Number of rows */
721
- rows: import_zod8.z.number().min(1).optional(),
722
- /** Resize behavior */
723
- resize: TextareaResizeSchema.optional()
724
- }).strict();
725
- var CheckboxOptionsSchema = import_zod8.z.object({
726
- /** Input name (required) */
727
- name: import_zod8.z.string(),
728
- /** Input ID */
729
- id: import_zod8.z.string().optional(),
730
- /** Input value */
731
- value: import_zod8.z.string().optional(),
732
- /** Label text (required) */
733
- label: import_zod8.z.string(),
734
- /** Checked state */
735
- checked: import_zod8.z.boolean().optional(),
736
- /** Disabled state */
737
- disabled: import_zod8.z.boolean().optional(),
738
- /** Helper text */
739
- helper: import_zod8.z.string().optional(),
740
- /** Error message */
741
- error: import_zod8.z.string().optional(),
742
- /** Additional CSS classes */
743
- className: import_zod8.z.string().optional()
744
- }).strict();
745
- var RadioOptionItemSchema = import_zod8.z.object({
746
- value: import_zod8.z.string(),
747
- label: import_zod8.z.string(),
748
- disabled: import_zod8.z.boolean().optional()
749
- }).strict();
750
- var RadioGroupOptionsSchema = import_zod8.z.object({
751
- /** Group name (required) */
752
- name: import_zod8.z.string(),
753
- /** Radio options (required) */
754
- options: import_zod8.z.array(RadioOptionItemSchema),
755
- /** Selected value */
756
- value: import_zod8.z.string().optional(),
757
- /** Label for the group */
758
- label: import_zod8.z.string().optional(),
759
- /** Helper text */
760
- helper: import_zod8.z.string().optional(),
761
- /** Error message */
762
- error: import_zod8.z.string().optional(),
763
- /** Layout direction */
764
- direction: import_zod8.z.enum(["horizontal", "vertical"]).optional(),
765
- /** Additional CSS classes */
766
- className: import_zod8.z.string().optional()
767
- }).strict();
768
- var FormMethodSchema = import_zod8.z.enum(["get", "post", "dialog"]);
769
- var FormEnctypeSchema = import_zod8.z.enum(["application/x-www-form-urlencoded", "multipart/form-data", "text/plain"]);
770
- var FormOptionsSchema = import_zod8.z.object({
771
- /** Form action URL */
772
- action: import_zod8.z.string().optional(),
773
- /** Form method */
774
- method: FormMethodSchema.optional(),
775
- /** Form ID */
776
- id: import_zod8.z.string().optional(),
777
- /** Form enctype */
778
- enctype: FormEnctypeSchema.optional(),
779
- /** Disable browser validation */
780
- novalidate: import_zod8.z.boolean().optional(),
781
- /** Autocomplete behavior */
782
- autocomplete: import_zod8.z.enum(["on", "off"]).optional(),
783
- /** Additional CSS classes */
784
- className: import_zod8.z.string().optional()
785
- }).strict();
786
- var FormRowOptionsSchema = import_zod8.z.object({
787
- /** Number of columns */
788
- cols: import_zod8.z.number().min(1).max(12).optional(),
789
- /** Gap between columns */
790
- gap: import_zod8.z.enum(["sm", "md", "lg"]).optional(),
791
- /** Additional CSS classes */
792
- className: import_zod8.z.string().optional()
793
- }).strict();
794
- var FormSectionOptionsSchema = import_zod8.z.object({
795
- /** Section title */
796
- title: import_zod8.z.string().optional(),
797
- /** Section description */
798
- description: import_zod8.z.string().optional(),
799
- /** Additional CSS classes */
800
- className: import_zod8.z.string().optional()
801
- }).strict();
802
- var FormActionsOptionsSchema = import_zod8.z.object({
803
- /** Alignment */
804
- align: import_zod8.z.enum(["left", "center", "right", "between"]).optional(),
805
- /** Additional CSS classes */
806
- className: import_zod8.z.string().optional()
807
- }).strict();
808
-
809
- // libs/ui/src/components/list.schema.ts
810
- var import_zod9 = require("zod");
811
- var PermissionItemSchema = import_zod9.z.object({
812
- /** Scope identifier */
813
- scope: import_zod9.z.string(),
814
- /** Display name */
815
- name: import_zod9.z.string(),
816
- /** Description */
817
- description: import_zod9.z.string().optional(),
818
- /** Icon HTML */
819
- icon: import_zod9.z.string().optional(),
820
- /** Required permission (cannot be unchecked) */
821
- required: import_zod9.z.boolean().optional(),
822
- /** Checked by default */
823
- checked: import_zod9.z.boolean().optional(),
824
- /** Sensitive/dangerous permission */
825
- sensitive: import_zod9.z.boolean().optional()
826
- }).strict();
827
- var PermissionListOptionsSchema = import_zod9.z.object({
828
- /** List ID */
829
- id: import_zod9.z.string().optional(),
830
- /** Checkable permissions */
831
- checkable: import_zod9.z.boolean().optional(),
832
- /** Input name for checkable */
833
- inputName: import_zod9.z.string().optional(),
834
- /** Group title */
835
- title: import_zod9.z.string().optional(),
836
- /** Additional CSS classes */
837
- className: import_zod9.z.string().optional()
838
- }).strict();
839
- var FeatureItemSchema = import_zod9.z.object({
840
- /** Feature name */
841
- name: import_zod9.z.string(),
842
- /** Feature description */
843
- description: import_zod9.z.string().optional(),
844
- /** Icon HTML */
845
- icon: import_zod9.z.string().optional(),
846
- /** Included in plan */
847
- included: import_zod9.z.boolean().optional()
848
- }).strict();
849
- var FeatureListOptionsSchema = import_zod9.z.object({
850
- /** Group title */
851
- title: import_zod9.z.string().optional(),
852
- /** Show included/excluded styling */
853
- showStatus: import_zod9.z.boolean().optional(),
854
- /** Additional CSS classes */
855
- className: import_zod9.z.string().optional()
856
- }).strict();
857
- var DescriptionItemSchema = import_zod9.z.object({
858
- /** Term/label */
859
- term: import_zod9.z.string(),
860
- /** Description/value */
861
- description: import_zod9.z.string(),
862
- /** Copy button */
863
- copyable: import_zod9.z.boolean().optional()
864
- }).strict();
865
- var DescriptionListOptionsSchema = import_zod9.z.object({
866
- /** Layout direction */
867
- direction: import_zod9.z.enum(["horizontal", "vertical"]).optional(),
868
- /** Striped rows */
869
- striped: import_zod9.z.boolean().optional(),
870
- /** Additional CSS classes */
871
- className: import_zod9.z.string().optional()
872
- }).strict();
873
- var ActionItemSchema = import_zod9.z.object({
874
- /** Action label */
875
- label: import_zod9.z.string(),
876
- /** Action description */
877
- description: import_zod9.z.string().optional(),
878
- /** Icon HTML */
879
- icon: import_zod9.z.string().optional(),
880
- /** Click URL */
881
- href: import_zod9.z.string().optional(),
882
- /** Destructive action styling */
883
- destructive: import_zod9.z.boolean().optional(),
884
- /** Disabled state */
885
- disabled: import_zod9.z.boolean().optional()
886
- }).strict();
887
- var ActionListOptionsSchema = import_zod9.z.object({
888
- /** Divided items */
889
- divided: import_zod9.z.boolean().optional(),
890
- /** Additional CSS classes */
891
- className: import_zod9.z.string().optional()
892
- }).strict();
893
-
894
- // libs/ui/src/layouts/base.ts
895
- var import_theme = require("@frontmcp/uipack/theme");
896
- var import_utils = require("@frontmcp/uipack/utils");
897
- var import_utils2 = require("@frontmcp/uipack/utils");
898
- function getSizeClass(size) {
899
- const sizeMap = {
900
- xs: "max-w-sm",
901
- sm: "max-w-md",
902
- md: "max-w-lg",
903
- lg: "max-w-xl",
904
- xl: "max-w-2xl",
905
- "2xl": "max-w-3xl",
906
- "3xl": "max-w-4xl",
907
- full: "max-w-full"
908
- };
909
- return sizeMap[size];
910
- }
911
- function getAlignmentClasses(alignment) {
912
- const alignMap = {
913
- center: "min-h-screen flex items-center justify-center",
914
- top: "min-h-screen flex flex-col items-center pt-12",
915
- start: "min-h-screen"
916
- };
917
- return alignMap[alignment];
918
- }
919
- function getBackgroundClasses(background) {
920
- switch (background) {
921
- case "gradient":
922
- return "bg-gradient-to-br from-primary to-secondary";
923
- case "pattern":
924
- return 'bg-surface bg-[url("data:image/svg+xml,...")]';
925
- // Pattern would be defined
926
- case "solid":
927
- return "bg-background";
928
- case "none":
929
- default:
930
- return "";
931
- }
932
- }
933
- function buildMetaTags(options) {
934
- const tags = [];
935
- if (options.description) {
936
- tags.push(`<meta name="description" content="${(0, import_utils.escapeHtml)(options.description)}">`);
937
- }
938
- if (options.og) {
939
- if (options.og.title) {
940
- tags.push(`<meta property="og:title" content="${(0, import_utils.escapeHtml)(options.og.title)}">`);
941
- }
942
- if (options.og.description) {
943
- tags.push(`<meta property="og:description" content="${(0, import_utils.escapeHtml)(options.og.description)}">`);
944
- }
945
- if (options.og.image) {
946
- tags.push(`<meta property="og:image" content="${(0, import_utils.escapeHtml)(options.og.image)}">`);
947
- }
948
- if (options.og.type) {
949
- tags.push(`<meta property="og:type" content="${(0, import_utils.escapeHtml)(options.og.type)}">`);
950
- }
951
- }
952
- if (options.favicon) {
953
- tags.push(`<link rel="icon" href="${(0, import_utils.escapeHtml)(options.favicon)}">`);
954
- }
955
- return tags.join("\n ");
956
- }
957
- function buildBodyAttrs(attrs) {
958
- if (!attrs) return "";
959
- return Object.entries(attrs).map(([key, value]) => `${key}="${(0, import_utils.escapeHtml)(value)}"`).join(" ");
960
- }
961
- function baseLayout(content, options) {
962
- const {
963
- title,
964
- pageType: _pageType = "custom",
965
- size = "md",
966
- alignment = "center",
967
- background = "solid",
968
- platform = import_theme.OPENAI_PLATFORM,
969
- theme: themeOverrides,
970
- includeHtmx,
971
- includeAlpine = false,
972
- includeIcons = false,
973
- headExtra = "",
974
- bodyAttrs,
975
- bodyClass = "",
976
- titleSuffix = "FrontMCP"
977
- } = options;
978
- const theme = themeOverrides ? (0, import_theme.mergeThemes)(import_theme.DEFAULT_THEME, themeOverrides) : import_theme.DEFAULT_THEME;
979
- const shouldIncludeHtmx = includeHtmx ?? platform.supportsHtmx;
980
- const useCdn = (0, import_theme.canUseCdn)(platform);
981
- const useInline = (0, import_theme.needsInlineScripts)(platform);
982
- const fontPreconnect = useCdn ? (0, import_theme.buildFontPreconnect)() : "";
983
- const fontStylesheets = useCdn ? (0, import_theme.buildFontStylesheets)({ inter: true }) : "";
984
- const scripts = (0, import_theme.buildCdnScripts)({
985
- tailwind: platform.supportsTailwind,
986
- htmx: shouldIncludeHtmx,
987
- alpine: includeAlpine,
988
- icons: includeIcons,
989
- inline: useInline
990
- });
991
- const themeCss = (0, import_theme.buildThemeCss)(theme);
992
- const customCss = theme.customCss || "";
993
- const styleBlock = platform.supportsTailwind ? `<style type="text/tailwindcss">
994
- @theme {
995
- ${themeCss}
996
- }
997
- ${customCss}
998
- </style>` : "";
999
- const sizeClass = getSizeClass(size);
1000
- const alignmentClasses = getAlignmentClasses(alignment);
1001
- const backgroundClasses = getBackgroundClasses(background);
1002
- const allBodyClasses = [backgroundClasses, "font-sans antialiased", bodyClass].filter(Boolean).join(" ");
1003
- const metaTags = buildMetaTags(options);
1004
- const bodyAttrStr = buildBodyAttrs(bodyAttrs);
1005
- const wrappedContent = alignment === "center" ? `<div class="${alignmentClasses} p-4">
1006
- <div class="w-full ${sizeClass}">
1007
- ${content}
1008
- </div>
1009
- </div>` : `<div class="${alignmentClasses}">
1010
- <div class="w-full ${sizeClass} mx-auto px-4 py-8">
1011
- ${content}
1012
- </div>
1013
- </div>`;
1014
- return `<!DOCTYPE html>
1015
- <html lang="en">
1016
- <head>
1017
- <meta charset="UTF-8">
1018
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
1019
- <title>${(0, import_utils.escapeHtml)(title)}${titleSuffix ? ` - ${(0, import_utils.escapeHtml)(titleSuffix)}` : ""}</title>
1020
- ${metaTags}
1021
-
1022
- <!-- Fonts -->
1023
- ${fontPreconnect}
1024
- ${fontStylesheets}
1025
-
1026
- <!-- Tailwind CSS -->
1027
- ${scripts}
1028
- ${styleBlock}
1029
-
1030
- ${headExtra}
1031
- </head>
1032
- <body class="${(0, import_utils.escapeHtml)(allBodyClasses)}"${bodyAttrStr ? ` ${bodyAttrStr}` : ""}>
1033
- ${wrappedContent}
1034
- </body>
1035
- </html>`;
1036
- }
1037
- function createLayoutBuilder(defaults) {
1038
- return (content, options = {}) => {
1039
- let mergedTheme = import_theme.DEFAULT_THEME;
1040
- if (defaults.theme) {
1041
- mergedTheme = (0, import_theme.mergeThemes)(mergedTheme, defaults.theme);
1042
- }
1043
- if (options.theme) {
1044
- mergedTheme = (0, import_theme.mergeThemes)(mergedTheme, options.theme);
1045
- }
1046
- const merged = {
1047
- ...defaults,
1048
- ...options,
1049
- theme: mergedTheme
1050
- };
1051
- if (!merged.title) {
1052
- throw new Error("createLayoutBuilder: title is required either in defaults or options");
1053
- }
1054
- return baseLayout(content, merged);
1055
- };
1056
- }
1057
-
1058
- // libs/ui/src/components/button.ts
1059
- var import_validation = require("@frontmcp/uipack/validation");
1060
- function getVariantClasses(variant) {
1061
- const variants = {
1062
- primary: "bg-primary hover:bg-primary/90 text-white shadow-sm",
1063
- secondary: "bg-secondary hover:bg-secondary/90 text-white shadow-sm",
1064
- outline: "border-2 border-primary text-primary hover:bg-primary/10",
1065
- ghost: "text-text-primary hover:bg-gray-100",
1066
- danger: "bg-danger hover:bg-danger/90 text-white shadow-sm",
1067
- success: "bg-success hover:bg-success/90 text-white shadow-sm",
1068
- link: "text-primary hover:text-primary/80 hover:underline"
1069
- };
1070
- return variants[variant];
1071
- }
1072
- function getSizeClasses(size, iconOnly) {
1073
- if (iconOnly) {
1074
- const iconSizes = {
1075
- xs: "p-1.5",
1076
- sm: "p-2",
1077
- md: "p-2.5",
1078
- lg: "p-3",
1079
- xl: "p-4"
1080
- };
1081
- return iconSizes[size];
1082
- }
1083
- const sizes = {
1084
- xs: "px-2.5 py-1.5 text-xs",
1085
- sm: "px-3 py-2 text-sm",
1086
- md: "px-4 py-2.5 text-sm",
1087
- lg: "px-5 py-3 text-base",
1088
- xl: "px-6 py-3.5 text-lg"
1089
- };
1090
- return sizes[size];
1091
- }
1092
- function sanitizeDataKey(key) {
1093
- const sanitized = key.toLowerCase().replace(/[^a-z0-9_-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
1094
- if (!sanitized) {
1095
- console.warn(`[frontmcp/ui] Dropping invalid data-* key: "${key}"`);
1096
- return null;
1097
- }
1098
- return sanitized;
1099
- }
1100
- var loadingSpinner = `<svg class="animate-spin -ml-1 mr-2 h-4 w-4" fill="none" viewBox="0 0 24 24">
1101
- <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
1102
- <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>
1103
- </svg>`;
1104
- function isValidHrefProtocol(href) {
1105
- const trimmed = href.trim().toLowerCase();
1106
- return trimmed.startsWith("http://") || trimmed.startsWith("https://") || trimmed.startsWith("/") || trimmed.startsWith("#") || trimmed.startsWith("mailto:") || trimmed.startsWith("tel:");
1107
- }
1108
- function button(text, options = {}) {
1109
- const validation = (0, import_validation.validateOptions)(options, {
1110
- schema: ButtonOptionsSchema,
1111
- componentName: "button"
1112
- });
1113
- if (!validation.success) {
1114
- return validation.error;
1115
- }
1116
- const validatedOptions = validation.data;
1117
- const {
1118
- variant = "primary",
1119
- size = "md",
1120
- type = "button",
1121
- disabled = false,
1122
- loading = false,
1123
- fullWidth = false,
1124
- iconBefore,
1125
- iconAfter,
1126
- iconOnly = false,
1127
- className = "",
1128
- id,
1129
- name,
1130
- value,
1131
- href,
1132
- target,
1133
- data,
1134
- ariaLabel
1135
- } = validatedOptions;
1136
- if (!iconOnly && !text.trim()) {
1137
- console.warn("[frontmcp/ui] Button has empty text. Consider providing text or using iconOnly with ariaLabel.");
1138
- }
1139
- if (iconOnly && !ariaLabel && !text.trim()) {
1140
- console.warn(
1141
- "[frontmcp/ui] iconOnly button requires non-empty text or ariaLabel for accessibility; control will have no label."
1142
- );
1143
- }
1144
- if (href && !isValidHrefProtocol(href)) {
1145
- console.warn(`[frontmcp/ui] Button href contains potentially dangerous protocol: "${href.slice(0, 20)}..."`);
1146
- }
1147
- const variantClasses = getVariantClasses(variant);
1148
- const sizeClasses = getSizeClasses(size, iconOnly);
1149
- const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
1150
- const baseClasses = [
1151
- "inline-flex items-center justify-center",
1152
- "font-medium",
1153
- "rounded-lg",
1154
- "transition-colors duration-200",
1155
- "focus:outline-none focus:ring-2 focus:ring-primary/50 focus:ring-offset-2",
1156
- disabled || loading ? "opacity-50 cursor-not-allowed" : "cursor-pointer",
1157
- fullWidth ? "w-full" : "",
1158
- variantClasses,
1159
- sizeClasses,
1160
- safeClassName
1161
- ].filter(Boolean).join(" ");
1162
- const dataAttrs = data ? Object.entries(data).map(([key, val]) => {
1163
- const safeKey = sanitizeDataKey(key);
1164
- return safeKey ? `data-${safeKey}="${(0, import_utils2.escapeHtml)(val)}"` : "";
1165
- }).filter(Boolean).join(" ") : "";
1166
- const idAttr = id ? `id="${(0, import_utils2.escapeHtml)(id)}"` : "";
1167
- const nameAttr = name ? `name="${(0, import_utils2.escapeHtml)(name)}"` : "";
1168
- const valueAttr = value ? `value="${(0, import_utils2.escapeHtml)(value)}"` : "";
1169
- const disabledAttr = disabled || loading ? "disabled" : "";
1170
- const targetAttr = target ? `target="${(0, import_utils2.escapeHtml)(target)}"` : "";
1171
- const relAttr = target === "_blank" ? 'rel="noopener noreferrer"' : "";
1172
- const trimmedText = text.trim();
1173
- const effectiveAriaLabel = ariaLabel ?? (iconOnly && trimmedText ? trimmedText : void 0);
1174
- const ariaLabelAttr = effectiveAriaLabel ? `aria-label="${(0, import_utils2.escapeHtml)(effectiveAriaLabel)}"` : "";
1175
- const iconBeforeHtml = iconBefore && !loading ? `<span class="${iconOnly ? "" : "mr-2"}">${iconBefore}</span>` : "";
1176
- const iconAfterHtml = iconAfter && !loading ? `<span class="${iconOnly ? "" : "ml-2"}">${iconAfter}</span>` : "";
1177
- const loadingHtml = loading ? loadingSpinner : "";
1178
- const textHtml = iconOnly ? "" : (0, import_utils2.escapeHtml)(text);
1179
- const contentHtml = `${loadingHtml}${iconBeforeHtml}${textHtml}${iconAfterHtml}`;
1180
- if (href && !disabled && !loading && isValidHrefProtocol(href)) {
1181
- return `<a href="${(0, import_utils2.escapeHtml)(
1182
- href
1183
- )}" class="${baseClasses}" ${idAttr} ${dataAttrs} ${ariaLabelAttr} ${targetAttr} ${relAttr}>
1184
- ${contentHtml}
1185
- </a>`;
1186
- }
1187
- return `<button type="${type}" class="${baseClasses}" ${idAttr} ${nameAttr} ${valueAttr} ${disabledAttr} ${dataAttrs} ${ariaLabelAttr}>
1188
- ${contentHtml}
1189
- </button>`;
1190
- }
1191
- function buttonGroup(buttons, options = {}) {
1192
- if (buttons.length === 0) {
1193
- console.warn("[frontmcp/ui] buttonGroup called with empty buttons array");
1194
- return "";
1195
- }
1196
- const validation = (0, import_validation.validateOptions)(options, {
1197
- schema: ButtonGroupOptionsSchema,
1198
- componentName: "buttonGroup"
1199
- });
1200
- if (!validation.success) {
1201
- return validation.error;
1202
- }
1203
- const validatedOptions = validation.data;
1204
- const { attached = false, direction = "horizontal", gap = "md", className = "" } = validatedOptions;
1205
- const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
1206
- if (attached) {
1207
- const classes = direction === "horizontal" ? "inline-flex rounded-lg shadow-sm [&>*:first-child]:rounded-r-none [&>*:last-child]:rounded-l-none [&>*:not(:first-child):not(:last-child)]:rounded-none [&>*:not(:first-child)]:-ml-px" : "inline-flex flex-col rounded-lg shadow-sm [&>*:first-child]:rounded-b-none [&>*:last-child]:rounded-t-none [&>*:not(:first-child):not(:last-child)]:rounded-none [&>*:not(:first-child)]:-mt-px";
1208
- return `<div class="${classes} ${safeClassName}">${buttons.join("")}</div>`;
1209
- }
1210
- const gapClasses = { sm: "gap-2", md: "gap-3", lg: "gap-4" };
1211
- const directionClasses = direction === "horizontal" ? "flex flex-row" : "flex flex-col";
1212
- return `<div class="${directionClasses} ${gapClasses[gap]} ${safeClassName}">${buttons.join("")}</div>`;
1213
- }
1214
- var primaryButton = (text, opts) => button(text, { ...opts, variant: "primary" });
1215
- var secondaryButton = (text, opts) => button(text, { ...opts, variant: "secondary" });
1216
- var outlineButton = (text, opts) => button(text, { ...opts, variant: "outline" });
1217
- var ghostButton = (text, opts) => button(text, { ...opts, variant: "ghost" });
1218
- var dangerButton = (text, opts) => button(text, { ...opts, variant: "danger" });
1219
- var linkButton = (text, opts) => button(text, { ...opts, variant: "link" });
1220
-
1221
- // libs/ui/src/components/card.ts
1222
- var import_runtime = require("@frontmcp/uipack/runtime");
1223
- function getVariantClasses2(variant) {
1224
- const variants = {
1225
- default: "bg-white border border-border rounded-xl shadow-sm",
1226
- outlined: "bg-transparent border-2 border-border rounded-xl",
1227
- elevated: "bg-white rounded-xl shadow-lg",
1228
- filled: "bg-gray-50 rounded-xl",
1229
- ghost: "bg-transparent"
1230
- };
1231
- return variants[variant];
1232
- }
1233
- function getSizeClasses2(size) {
1234
- const sizes = {
1235
- sm: "p-4",
1236
- md: "p-6",
1237
- lg: "p-8"
1238
- };
1239
- return sizes[size];
1240
- }
1241
- function buildDataAttrs(data) {
1242
- if (!data) return "";
1243
- return Object.entries(data).map(([key, value]) => `data-${key}="${(0, import_utils2.escapeHtml)(value)}"`).join(" ");
1244
- }
1245
- function card(content, options = {}) {
1246
- const {
1247
- variant = "default",
1248
- size = "md",
1249
- title,
1250
- subtitle,
1251
- headerActions,
1252
- footer,
1253
- className = "",
1254
- id,
1255
- data,
1256
- clickable = false,
1257
- href,
1258
- sanitize = false
1259
- } = options;
1260
- const safeContent = sanitize ? (0, import_runtime.sanitizeHtmlContent)(content) : content;
1261
- const safeHeaderActions = sanitize && headerActions ? (0, import_runtime.sanitizeHtmlContent)(headerActions) : headerActions;
1262
- const safeFooter = sanitize && footer ? (0, import_runtime.sanitizeHtmlContent)(footer) : footer;
1263
- const variantClasses = getVariantClasses2(variant);
1264
- const sizeClasses = getSizeClasses2(size);
1265
- const clickableClasses = clickable ? "cursor-pointer hover:shadow-md transition-shadow" : "";
1266
- const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
1267
- const allClasses = [variantClasses, sizeClasses, clickableClasses, safeClassName].filter(Boolean).join(" ");
1268
- const dataAttrs = buildDataAttrs(data);
1269
- const idAttr = id ? `id="${(0, import_utils2.escapeHtml)(id)}"` : "";
1270
- const hasHeader = title || subtitle || safeHeaderActions;
1271
- const headerHtml = hasHeader ? `<div class="flex items-start justify-between mb-4">
1272
- <div>
1273
- ${title ? `<h3 class="text-lg font-semibold text-text-primary">${(0, import_utils2.escapeHtml)(title)}</h3>` : ""}
1274
- ${subtitle ? `<p class="text-sm text-text-secondary mt-1">${(0, import_utils2.escapeHtml)(subtitle)}</p>` : ""}
1275
- </div>
1276
- ${safeHeaderActions ? `<div class="flex items-center gap-2">${safeHeaderActions}</div>` : ""}
1277
- </div>` : "";
1278
- const footerHtml = safeFooter ? `<div class="mt-4 pt-4 border-t border-divider">${safeFooter}</div>` : "";
1279
- if (href) {
1280
- return `<a href="${(0, import_utils2.escapeHtml)(href)}" class="${allClasses}" ${idAttr} ${dataAttrs}>
1281
- ${headerHtml}
1282
- ${safeContent}
1283
- ${footerHtml}
1284
- </a>`;
1285
- }
1286
- return `<div class="${allClasses}" ${idAttr} ${dataAttrs}>
1287
- ${headerHtml}
1288
- ${safeContent}
1289
- ${footerHtml}
1290
- </div>`;
1291
- }
1292
- function cardGroup(cards, options = {}) {
1293
- const { direction = "vertical", gap = "md", className = "" } = options;
1294
- const gapClasses = { sm: "gap-2", md: "gap-4", lg: "gap-6" };
1295
- const directionClasses = direction === "horizontal" ? "flex flex-row flex-wrap" : "flex flex-col";
1296
- const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
1297
- return `<div class="${directionClasses} ${gapClasses[gap]} ${safeClassName}">
1298
- ${cards.join("\n")}
1299
- </div>`;
1300
- }
1301
-
1302
- // libs/ui/src/components/form.ts
1303
- var import_runtime2 = require("@frontmcp/uipack/runtime");
1304
- function getInputSizeClasses(size) {
1305
- const sizes = {
1306
- sm: "px-3 py-1.5 text-sm",
1307
- md: "px-4 py-2.5 text-sm",
1308
- lg: "px-5 py-3 text-base"
1309
- };
1310
- return sizes[size];
1311
- }
1312
- function getInputStateClasses(state) {
1313
- const states = {
1314
- default: "border-border focus:border-primary focus:ring-primary/20",
1315
- error: "border-danger focus:border-danger focus:ring-danger/20",
1316
- success: "border-success focus:border-success focus:ring-success/20",
1317
- warning: "border-warning focus:border-warning focus:ring-warning/20"
1318
- };
1319
- return states[state];
1320
- }
1321
- function buildDataAttrs2(data) {
1322
- if (!data) return "";
1323
- return Object.entries(data).map(([key, value]) => `data-${key}="${(0, import_utils2.escapeHtml)(value)}"`).join(" ");
1324
- }
1325
- function input(options) {
1326
- const {
1327
- type = "text",
1328
- name,
1329
- id = name,
1330
- value = "",
1331
- placeholder = "",
1332
- label,
1333
- helper,
1334
- error,
1335
- size = "md",
1336
- state = error ? "error" : "default",
1337
- required = false,
1338
- disabled = false,
1339
- readonly = false,
1340
- autocomplete,
1341
- pattern,
1342
- min,
1343
- max,
1344
- step,
1345
- className = "",
1346
- data,
1347
- iconBefore,
1348
- iconAfter,
1349
- sanitize = false
1350
- } = options;
1351
- const safeIconBefore = sanitize && iconBefore ? (0, import_runtime2.sanitizeHtmlContent)(iconBefore) : iconBefore;
1352
- const safeIconAfter = sanitize && iconAfter ? (0, import_runtime2.sanitizeHtmlContent)(iconAfter) : iconAfter;
1353
- const sizeClasses = getInputSizeClasses(size);
1354
- const stateClasses = getInputStateClasses(state);
1355
- const hasIcon = safeIconBefore || safeIconAfter;
1356
- const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
1357
- const baseClasses = [
1358
- "w-full rounded-lg border bg-white",
1359
- "transition-colors duration-200",
1360
- "focus:outline-none focus:ring-2",
1361
- disabled ? "opacity-50 cursor-not-allowed bg-gray-50" : "",
1362
- sizeClasses,
1363
- stateClasses,
1364
- hasIcon ? (safeIconBefore ? "pl-10" : "") + (safeIconAfter ? " pr-10" : "") : "",
1365
- safeClassName
1366
- ].filter(Boolean).join(" ");
1367
- const dataAttrs = buildDataAttrs2(data);
1368
- const inputAttrs = [
1369
- `type="${type}"`,
1370
- `name="${(0, import_utils2.escapeHtml)(name)}"`,
1371
- `id="${(0, import_utils2.escapeHtml)(id)}"`,
1372
- value ? `value="${(0, import_utils2.escapeHtml)(value)}"` : "",
1373
- placeholder ? `placeholder="${(0, import_utils2.escapeHtml)(placeholder)}"` : "",
1374
- required ? "required" : "",
1375
- disabled ? "disabled" : "",
1376
- readonly ? "readonly" : "",
1377
- autocomplete ? `autocomplete="${(0, import_utils2.escapeHtml)(autocomplete)}"` : "",
1378
- pattern ? `pattern="${(0, import_utils2.escapeHtml)(pattern)}"` : "",
1379
- min !== void 0 ? `min="${(0, import_utils2.escapeHtml)(String(min))}"` : "",
1380
- max !== void 0 ? `max="${(0, import_utils2.escapeHtml)(String(max))}"` : "",
1381
- step !== void 0 ? `step="${(0, import_utils2.escapeHtml)(String(step))}"` : "",
1382
- `class="${baseClasses}"`,
1383
- dataAttrs
1384
- ].filter(Boolean).join(" ");
1385
- const labelHtml = label ? `<label for="${(0, import_utils2.escapeHtml)(id)}" class="block text-sm font-medium text-text-primary mb-1.5">
1386
- ${(0, import_utils2.escapeHtml)(label)}${required ? '<span class="text-danger ml-1">*</span>' : ""}
1387
- </label>` : "";
1388
- const helperHtml = helper && !error ? `<p class="mt-1.5 text-sm text-text-secondary">${(0, import_utils2.escapeHtml)(helper)}</p>` : "";
1389
- const errorHtml = error ? `<p class="mt-1.5 text-sm text-danger">${(0, import_utils2.escapeHtml)(error)}</p>` : "";
1390
- const iconBeforeHtml = safeIconBefore ? `<span class="absolute left-3 top-1/2 -translate-y-1/2 text-text-secondary">${safeIconBefore}</span>` : "";
1391
- const iconAfterHtml = safeIconAfter ? `<span class="absolute right-3 top-1/2 -translate-y-1/2 text-text-secondary">${safeIconAfter}</span>` : "";
1392
- const inputHtml = hasIcon ? `<div class="relative">
1393
- ${iconBeforeHtml}
1394
- <input ${inputAttrs}>
1395
- ${iconAfterHtml}
1396
- </div>` : `<input ${inputAttrs}>`;
1397
- return `<div class="form-field">
1398
- ${labelHtml}
1399
- ${inputHtml}
1400
- ${helperHtml}
1401
- ${errorHtml}
1402
- </div>`;
1403
- }
1404
- function select(options) {
1405
- const {
1406
- name,
1407
- id = name,
1408
- options: selectOptions,
1409
- value,
1410
- label,
1411
- helper,
1412
- error,
1413
- size = "md",
1414
- state = error ? "error" : "default",
1415
- required = false,
1416
- disabled = false,
1417
- multiple = false,
1418
- className = "",
1419
- data
1420
- } = options;
1421
- const sizeClasses = getInputSizeClasses(size);
1422
- const stateClasses = getInputStateClasses(state);
1423
- const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
1424
- const baseClasses = [
1425
- "w-full rounded-lg border bg-white",
1426
- "transition-colors duration-200",
1427
- "focus:outline-none focus:ring-2",
1428
- disabled ? "opacity-50 cursor-not-allowed bg-gray-50" : "",
1429
- sizeClasses,
1430
- stateClasses,
1431
- safeClassName
1432
- ].filter(Boolean).join(" ");
1433
- const dataAttrs = buildDataAttrs2(data);
1434
- const optionsHtml = selectOptions.map((opt) => {
1435
- const selected = opt.selected || opt.value === value ? "selected" : "";
1436
- const optDisabled = opt.disabled ? "disabled" : "";
1437
- return `<option value="${(0, import_utils2.escapeHtml)(opt.value)}" ${selected} ${optDisabled}>${(0, import_utils2.escapeHtml)(opt.label)}</option>`;
1438
- }).join("\n");
1439
- const labelHtml = label ? `<label for="${(0, import_utils2.escapeHtml)(id)}" class="block text-sm font-medium text-text-primary mb-1.5">
1440
- ${(0, import_utils2.escapeHtml)(label)}${required ? '<span class="text-danger ml-1">*</span>' : ""}
1441
- </label>` : "";
1442
- const helperHtml = helper && !error ? `<p class="mt-1.5 text-sm text-text-secondary">${(0, import_utils2.escapeHtml)(helper)}</p>` : "";
1443
- const errorHtml = error ? `<p class="mt-1.5 text-sm text-danger">${(0, import_utils2.escapeHtml)(error)}</p>` : "";
1444
- return `<div class="form-field">
1445
- ${labelHtml}
1446
- <select
1447
- name="${(0, import_utils2.escapeHtml)(name)}"
1448
- id="${(0, import_utils2.escapeHtml)(id)}"
1449
- class="${baseClasses}"
1450
- ${required ? "required" : ""}
1451
- ${disabled ? "disabled" : ""}
1452
- ${multiple ? "multiple" : ""}
1453
- ${dataAttrs}
1454
- >
1455
- ${optionsHtml}
1456
- </select>
1457
- ${helperHtml}
1458
- ${errorHtml}
1459
- </div>`;
1460
- }
1461
- function textarea(options) {
1462
- const {
1463
- name,
1464
- id = name,
1465
- value = "",
1466
- placeholder = "",
1467
- label,
1468
- helper,
1469
- error,
1470
- size = "md",
1471
- state = error ? "error" : "default",
1472
- required = false,
1473
- disabled = false,
1474
- readonly = false,
1475
- rows = 4,
1476
- resize = "vertical",
1477
- className = "",
1478
- data
1479
- } = options;
1480
- const sizeClasses = getInputSizeClasses(size);
1481
- const stateClasses = getInputStateClasses(state);
1482
- const resizeClasses = {
1483
- none: "resize-none",
1484
- vertical: "resize-y",
1485
- horizontal: "resize-x",
1486
- both: "resize"
1487
- };
1488
- const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
1489
- const baseClasses = [
1490
- "w-full rounded-lg border bg-white",
1491
- "transition-colors duration-200",
1492
- "focus:outline-none focus:ring-2",
1493
- disabled ? "opacity-50 cursor-not-allowed bg-gray-50" : "",
1494
- sizeClasses,
1495
- stateClasses,
1496
- resizeClasses[resize],
1497
- safeClassName
1498
- ].filter(Boolean).join(" ");
1499
- const dataAttrs = buildDataAttrs2(data);
1500
- const labelHtml = label ? `<label for="${(0, import_utils2.escapeHtml)(id)}" class="block text-sm font-medium text-text-primary mb-1.5">
1501
- ${(0, import_utils2.escapeHtml)(label)}${required ? '<span class="text-danger ml-1">*</span>' : ""}
1502
- </label>` : "";
1503
- const helperHtml = helper && !error ? `<p class="mt-1.5 text-sm text-text-secondary">${(0, import_utils2.escapeHtml)(helper)}</p>` : "";
1504
- const errorHtml = error ? `<p class="mt-1.5 text-sm text-danger">${(0, import_utils2.escapeHtml)(error)}</p>` : "";
1505
- return `<div class="form-field">
1506
- ${labelHtml}
1507
- <textarea
1508
- name="${(0, import_utils2.escapeHtml)(name)}"
1509
- id="${(0, import_utils2.escapeHtml)(id)}"
1510
- rows="${rows}"
1511
- class="${baseClasses}"
1512
- ${placeholder ? `placeholder="${(0, import_utils2.escapeHtml)(placeholder)}"` : ""}
1513
- ${required ? "required" : ""}
1514
- ${disabled ? "disabled" : ""}
1515
- ${readonly ? "readonly" : ""}
1516
- ${dataAttrs}
1517
- >${(0, import_utils2.escapeHtml)(value)}</textarea>
1518
- ${helperHtml}
1519
- ${errorHtml}
1520
- </div>`;
1521
- }
1522
- function checkbox(options) {
1523
- const {
1524
- name,
1525
- id = name,
1526
- value = "true",
1527
- label,
1528
- checked = false,
1529
- disabled = false,
1530
- helper,
1531
- error,
1532
- className = ""
1533
- } = options;
1534
- const checkboxClasses = [
1535
- "h-4 w-4 rounded border-border text-primary",
1536
- "focus:ring-2 focus:ring-primary/20 focus:ring-offset-0",
1537
- disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer"
1538
- ].join(" ");
1539
- const helperHtml = helper && !error ? `<p class="text-sm text-text-secondary">${(0, import_utils2.escapeHtml)(helper)}</p>` : "";
1540
- const errorHtml = error ? `<p class="text-sm text-danger">${(0, import_utils2.escapeHtml)(error)}</p>` : "";
1541
- const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
1542
- return `<div class="form-field ${safeClassName}">
1543
- <label class="flex items-start gap-3 ${disabled ? "cursor-not-allowed" : "cursor-pointer"}">
1544
- <input
1545
- type="checkbox"
1546
- name="${(0, import_utils2.escapeHtml)(name)}"
1547
- id="${(0, import_utils2.escapeHtml)(id)}"
1548
- value="${(0, import_utils2.escapeHtml)(value)}"
1549
- class="${checkboxClasses}"
1550
- ${checked ? "checked" : ""}
1551
- ${disabled ? "disabled" : ""}
1552
- >
1553
- <div>
1554
- <span class="text-sm font-medium text-text-primary">${(0, import_utils2.escapeHtml)(label)}</span>
1555
- ${helperHtml}
1556
- ${errorHtml}
1557
- </div>
1558
- </label>
1559
- </div>`;
1560
- }
1561
- function radioGroup(options) {
1562
- const { name, options: radioOptions, value, label, helper, error, direction = "vertical", className = "" } = options;
1563
- const directionClasses = direction === "horizontal" ? "flex flex-row flex-wrap gap-4" : "flex flex-col gap-2";
1564
- const radioClasses = "h-4 w-4 border-border text-primary focus:ring-2 focus:ring-primary/20 focus:ring-offset-0";
1565
- const radiosHtml = radioOptions.map((opt, index) => {
1566
- const radioId = `${name}-${index}`;
1567
- const checked = opt.value === value ? "checked" : "";
1568
- const disabled = opt.disabled ? "disabled" : "";
1569
- const cursorClass = opt.disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer";
1570
- return `<label class="flex items-center gap-2 ${cursorClass}">
1571
- <input
1572
- type="radio"
1573
- name="${(0, import_utils2.escapeHtml)(name)}"
1574
- id="${(0, import_utils2.escapeHtml)(radioId)}"
1575
- value="${(0, import_utils2.escapeHtml)(opt.value)}"
1576
- class="${radioClasses}"
1577
- ${checked}
1578
- ${disabled}
1579
- >
1580
- <span class="text-sm text-text-primary">${(0, import_utils2.escapeHtml)(opt.label)}</span>
1581
- </label>`;
1582
- }).join("\n");
1583
- const labelHtml = label ? `<label class="block text-sm font-medium text-text-primary mb-2">${(0, import_utils2.escapeHtml)(label)}</label>` : "";
1584
- const helperHtml = helper && !error ? `<p class="mt-1.5 text-sm text-text-secondary">${(0, import_utils2.escapeHtml)(helper)}</p>` : "";
1585
- const errorHtml = error ? `<p class="mt-1.5 text-sm text-danger">${(0, import_utils2.escapeHtml)(error)}</p>` : "";
1586
- const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
1587
- return `<div class="form-field ${safeClassName}" role="radiogroup">
1588
- ${labelHtml}
1589
- <div class="${directionClasses}">
1590
- ${radiosHtml}
1591
- </div>
1592
- ${helperHtml}
1593
- ${errorHtml}
1594
- </div>`;
1595
- }
1596
- function form(content, options = {}) {
1597
- const { action, method = "post", id, className = "", preventDefault = false, autocomplete, enctype } = options;
1598
- const attrs = [
1599
- action ? `action="${(0, import_utils2.escapeHtml)(action)}"` : "",
1600
- `method="${method}"`,
1601
- id ? `id="${(0, import_utils2.escapeHtml)(id)}"` : "",
1602
- className ? `class="${(0, import_utils2.escapeHtml)(className)}"` : "",
1603
- autocomplete ? `autocomplete="${autocomplete}"` : "",
1604
- enctype ? `enctype="${enctype}"` : "",
1605
- preventDefault ? 'onsubmit="return false;"' : ""
1606
- ].filter(Boolean).join(" ");
1607
- return `<form ${attrs}>${content}</form>`;
1608
- }
1609
- var GRID_COLS_MAP = {
1610
- 1: "grid-cols-1",
1611
- 2: "grid-cols-2",
1612
- 3: "grid-cols-3",
1613
- 4: "grid-cols-4",
1614
- 5: "grid-cols-5",
1615
- 6: "grid-cols-6",
1616
- 7: "grid-cols-7",
1617
- 8: "grid-cols-8",
1618
- 9: "grid-cols-9",
1619
- 10: "grid-cols-10",
1620
- 11: "grid-cols-11",
1621
- 12: "grid-cols-12"
1622
- };
1623
- function formRow(fields, options = {}) {
1624
- const { gap = "md", className = "" } = options;
1625
- const gapClasses = { sm: "gap-2", md: "gap-4", lg: "gap-6" };
1626
- const gridCols = GRID_COLS_MAP[fields.length] ?? "grid-cols-1";
1627
- const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
1628
- return `<div class="grid ${gridCols} ${gapClasses[gap]} ${safeClassName}">
1629
- ${fields.join("\n")}
1630
- </div>`;
1631
- }
1632
- function formSection(content, options = {}) {
1633
- const { title, description, className = "" } = options;
1634
- const headerHtml = title ? `<div class="mb-4">
1635
- <h3 class="text-lg font-semibold text-text-primary">${(0, import_utils2.escapeHtml)(title)}</h3>
1636
- ${description ? `<p class="text-sm text-text-secondary mt-1">${(0, import_utils2.escapeHtml)(description)}</p>` : ""}
1637
- </div>` : "";
1638
- const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
1639
- return `<div class="form-section ${safeClassName}">
1640
- ${headerHtml}
1641
- <div class="space-y-4">
1642
- ${content}
1643
- </div>
1644
- </div>`;
1645
- }
1646
- function formActions(buttons, options = {}) {
1647
- const { align = "right", className = "" } = options;
1648
- const alignClasses = {
1649
- left: "justify-start",
1650
- center: "justify-center",
1651
- right: "justify-end",
1652
- between: "justify-between"
1653
- };
1654
- const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
1655
- return `<div class="flex items-center gap-3 pt-4 ${alignClasses[align]} ${safeClassName}">
1656
- ${buttons.join("\n")}
1657
- </div>`;
1658
- }
1659
- function hiddenInput(name, value) {
1660
- return `<input type="hidden" name="${(0, import_utils2.escapeHtml)(name)}" value="${(0, import_utils2.escapeHtml)(value)}">`;
1661
- }
1662
- function csrfInput(token) {
1663
- return hiddenInput("_csrf", token);
1664
- }
1665
-
1666
- // libs/ui/src/components/badge.ts
1667
- var import_runtime3 = require("@frontmcp/uipack/runtime");
1668
- function getVariantClasses3(variant) {
1669
- const variants = {
1670
- default: "bg-gray-100 text-gray-800",
1671
- primary: "bg-primary/10 text-primary",
1672
- secondary: "bg-secondary/10 text-secondary",
1673
- success: "bg-success/10 text-success",
1674
- warning: "bg-warning/10 text-warning",
1675
- danger: "bg-danger/10 text-danger",
1676
- info: "bg-blue-100 text-blue-800",
1677
- outline: "border border-border text-text-primary bg-transparent"
1678
- };
1679
- return variants[variant];
1680
- }
1681
- function getSizeClasses3(size, dot) {
1682
- if (dot) {
1683
- const dotSizes = {
1684
- sm: "w-2 h-2",
1685
- md: "w-2.5 h-2.5",
1686
- lg: "w-3 h-3"
1687
- };
1688
- return dotSizes[size];
1689
- }
1690
- const sizes = {
1691
- sm: "px-2 py-0.5 text-xs",
1692
- md: "px-2.5 py-1 text-xs",
1693
- lg: "px-3 py-1.5 text-sm"
1694
- };
1695
- return sizes[size];
1696
- }
1697
- function badge(text, options = {}) {
1698
- const {
1699
- variant = "default",
1700
- size = "md",
1701
- pill = false,
1702
- icon,
1703
- dot = false,
1704
- className = "",
1705
- removable = false,
1706
- sanitize = false
1707
- } = options;
1708
- const safeIcon = sanitize && icon ? (0, import_runtime3.sanitizeHtmlContent)(icon) : icon;
1709
- const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
1710
- if (dot) {
1711
- const dotVariants = {
1712
- default: "bg-gray-400",
1713
- primary: "bg-primary",
1714
- secondary: "bg-secondary",
1715
- success: "bg-success",
1716
- warning: "bg-warning",
1717
- danger: "bg-danger",
1718
- info: "bg-blue-500",
1719
- outline: "border border-current"
1720
- };
1721
- const dotClasses = ["inline-block rounded-full", getSizeClasses3(size, true), dotVariants[variant], safeClassName].filter(Boolean).join(" ");
1722
- return `<span class="${dotClasses}" aria-label="${(0, import_utils2.escapeHtml)(text)}" title="${(0, import_utils2.escapeHtml)(text)}"></span>`;
1723
- }
1724
- const variantClasses = getVariantClasses3(variant);
1725
- const sizeClasses = getSizeClasses3(size, false);
1726
- const baseClasses = [
1727
- "inline-flex items-center font-medium",
1728
- pill ? "rounded-full" : "rounded-md",
1729
- variantClasses,
1730
- sizeClasses,
1731
- safeClassName
1732
- ].filter(Boolean).join(" ");
1733
- const iconHtml = safeIcon ? `<span class="mr-1">${safeIcon}</span>` : "";
1734
- const removeHtml = removable ? `<button
1735
- type="button"
1736
- class="ml-1.5 -mr-1 hover:opacity-70 transition-opacity"
1737
- onclick="this.parentElement.remove()"
1738
- aria-label="Remove"
1739
- >
1740
- <svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1741
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
1742
- </svg>
1743
- </button>` : "";
1744
- return `<span class="${baseClasses}">
1745
- ${iconHtml}${(0, import_utils2.escapeHtml)(text)}${removeHtml}
1746
- </span>`;
1747
- }
1748
- function badgeGroup(badges, options = {}) {
1749
- const { gap = "sm", className = "" } = options;
1750
- const gapClasses = { sm: "gap-1", md: "gap-2", lg: "gap-3" };
1751
- const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
1752
- return `<div class="inline-flex flex-wrap ${gapClasses[gap]} ${safeClassName}">
1753
- ${badges.join("\n")}
1754
- </div>`;
1755
- }
1756
- var activeBadge = (text = "Active") => badge(text, { variant: "success", dot: false });
1757
- var inactiveBadge = (text = "Inactive") => badge(text, { variant: "default", dot: false });
1758
- var pendingBadge = (text = "Pending") => badge(text, { variant: "warning", dot: false });
1759
- var errorBadge = (text = "Error") => badge(text, { variant: "danger", dot: false });
1760
- var newBadge = (text = "New") => badge(text, { variant: "primary", size: "sm", pill: true });
1761
- var betaBadge = (text = "Beta") => badge(text, { variant: "secondary", size: "sm", pill: true });
1762
- var onlineDot = (label = "Online") => badge(label, { variant: "success", dot: true });
1763
- var offlineDot = (label = "Offline") => badge(label, { variant: "default", dot: true });
1764
- var busyDot = (label = "Busy") => badge(label, { variant: "danger", dot: true });
1765
- var awayDot = (label = "Away") => badge(label, { variant: "warning", dot: true });
1766
-
1767
- // libs/ui/src/components/alert.ts
1768
- var import_runtime4 = require("@frontmcp/uipack/runtime");
1769
- var alertIcons = {
1770
- info: `<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1771
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
1772
- </svg>`,
1773
- success: `<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1774
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/>
1775
- </svg>`,
1776
- warning: `<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1777
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>
1778
- </svg>`,
1779
- danger: `<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1780
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"/>
1781
- </svg>`,
1782
- neutral: `<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1783
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
1784
- </svg>`
1785
- };
1786
- function getVariantClasses4(variant) {
1787
- const variants = {
1788
- info: {
1789
- container: "bg-blue-50 border-blue-200 text-blue-800",
1790
- icon: "text-blue-500"
1791
- },
1792
- success: {
1793
- container: "bg-success/10 border-success/30 text-success",
1794
- icon: "text-success"
1795
- },
1796
- warning: {
1797
- container: "bg-warning/10 border-warning/30 text-warning",
1798
- icon: "text-warning"
1799
- },
1800
- danger: {
1801
- container: "bg-danger/10 border-danger/30 text-danger",
1802
- icon: "text-danger"
1803
- },
1804
- neutral: {
1805
- container: "bg-gray-50 border-gray-200 text-gray-800",
1806
- icon: "text-gray-500"
1807
- }
1808
- };
1809
- return variants[variant];
1810
- }
1811
- function alert(message, options = {}) {
1812
- const {
1813
- variant = "info",
1814
- title,
1815
- showIcon = true,
1816
- icon,
1817
- dismissible = false,
1818
- className = "",
1819
- id,
1820
- actions,
1821
- sanitize = false
1822
- } = options;
1823
- const safeIcon = sanitize && icon ? (0, import_runtime4.sanitizeHtmlContent)(icon) : icon;
1824
- const safeActions = sanitize && actions ? (0, import_runtime4.sanitizeHtmlContent)(actions) : actions;
1825
- const variantClasses = getVariantClasses4(variant);
1826
- const safeClassName = className ? (0, import_utils2.escapeHtml)(className) : "";
1827
- const baseClasses = ["rounded-lg border p-4", variantClasses.container, safeClassName].filter(Boolean).join(" ");
1828
- const iconHtml = showIcon ? `<div class="flex-shrink-0 ${variantClasses.icon}">
1829
- ${safeIcon || alertIcons[variant]}
1830
- </div>` : "";
1831
- const titleHtml = title ? `<h3 class="font-semibold">${(0, import_utils2.escapeHtml)(title)}</h3>` : "";
1832
- const dismissHtml = dismissible ? `<button
1833
- type="button"
1834
- class="flex-shrink-0 ml-auto -mr-1 -mt-1 p-1 rounded hover:bg-black/5 transition-colors"
1835
- onclick="this.closest('.alert').remove()"
1836
- aria-label="Dismiss"
1837
- >
1838
- <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1839
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
1840
- </svg>
1841
- </button>` : "";
1842
- const actionsHtml = safeActions ? `<div class="mt-3">${safeActions}</div>` : "";
1843
- const idAttr = id ? `id="${(0, import_utils2.escapeHtml)(id)}"` : "";
1844
- return `<div class="alert ${baseClasses}" role="alert" ${idAttr}>
1845
- <div class="flex gap-3">
1846
- ${iconHtml}
1847
- <div class="flex-1">
1848
- ${titleHtml}
1849
- <div class="${title ? "mt-1" : ""}">${(0, import_utils2.escapeHtml)(message)}</div>
1850
- ${actionsHtml}
1851
- </div>
1852
- ${dismissHtml}
1853
- </div>
1854
- </div>`;
1855
- }
1856
- var infoAlert = (message, opts) => alert(message, { ...opts, variant: "info" });
1857
- var successAlert = (message, opts) => alert(message, { ...opts, variant: "success" });
1858
- var warningAlert = (message, opts) => alert(message, { ...opts, variant: "warning" });
1859
- var dangerAlert = (message, opts) => alert(message, { ...opts, variant: "danger" });
1860
- function toast(message, options = {}) {
1861
- const { variant = "info", title, duration = 5e3, position = "top-right", id = `toast-${Date.now()}` } = options;
1862
- const variantClasses = getVariantClasses4(variant);
1863
- const positionClasses = {
1864
- "top-right": "top-4 right-4",
1865
- "top-left": "top-4 left-4",
1866
- "bottom-right": "bottom-4 right-4",
1867
- "bottom-left": "bottom-4 left-4",
1868
- "top-center": "top-4 left-1/2 -translate-x-1/2",
1869
- "bottom-center": "bottom-4 left-1/2 -translate-x-1/2"
1870
- };
1871
- const titleHtml = title ? `<h4 class="font-semibold">${(0, import_utils2.escapeHtml)(title)}</h4>` : "";
1872
- const autoDismissScript = duration > 0 ? `<script>
1873
- setTimeout(() => {
1874
- const toast = document.getElementById('${id}');
1875
- if (toast) {
1876
- toast.classList.add('opacity-0', 'translate-x-2');
1877
- setTimeout(() => toast.remove(), 300);
1878
- }
1879
- }, ${duration});
1880
- </script>` : "";
1881
- return `<div
1882
- id="${(0, import_utils2.escapeHtml)(id)}"
1883
- class="fixed ${positionClasses[position]} z-50 min-w-[300px] max-w-md rounded-lg border shadow-lg ${variantClasses.container} transition-all duration-300 transform"
1884
- role="alert"
1885
- >
1886
- <div class="flex gap-3 p-4">
1887
- <div class="flex-shrink-0 ${variantClasses.icon}">
1888
- ${alertIcons[variant]}
1889
- </div>
1890
- <div class="flex-1">
1891
- ${titleHtml}
1892
- <p class="${title ? "mt-1 text-sm opacity-90" : ""}">${(0, import_utils2.escapeHtml)(message)}</p>
1893
- </div>
1894
- <button
1895
- type="button"
1896
- class="flex-shrink-0 p-1 rounded hover:bg-black/5 transition-colors"
1897
- onclick="this.closest('#${id}').remove()"
1898
- aria-label="Close"
1899
- >
1900
- <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1901
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
1902
- </svg>
1903
- </button>
1904
- </div>
1905
- </div>
1906
- ${autoDismissScript}`;
1907
- }
1908
- function toastContainer(position = "top-right", id = "toast-container") {
1909
- const positionClasses = {
1910
- "top-right": "top-4 right-4",
1911
- "top-left": "top-4 left-4",
1912
- "bottom-right": "bottom-4 right-4",
1913
- "bottom-left": "bottom-4 left-4",
1914
- "top-center": "top-4 left-1/2 -translate-x-1/2",
1915
- "bottom-center": "bottom-4 left-1/2 -translate-x-1/2"
1916
- };
1917
- return `<div id="${(0, import_utils2.escapeHtml)(id)}" class="fixed ${positionClasses[position]} z-50 flex flex-col gap-2"></div>`;
1918
- }
1919
-
1920
- // libs/ui/src/components/avatar.ts
1921
- function getSizeClasses4(size) {
1922
- const sizes = {
1923
- xs: { container: "w-6 h-6", text: "text-xs", status: "w-2 h-2 border" },
1924
- sm: { container: "w-8 h-8", text: "text-xs", status: "w-2.5 h-2.5 border" },
1925
- md: { container: "w-10 h-10", text: "text-sm", status: "w-3 h-3 border-2" },
1926
- lg: { container: "w-12 h-12", text: "text-base", status: "w-3.5 h-3.5 border-2" },
1927
- xl: { container: "w-16 h-16", text: "text-lg", status: "w-4 h-4 border-2" },
1928
- "2xl": { container: "w-24 h-24", text: "text-2xl", status: "w-5 h-5 border-2" }
1929
- };
1930
- return sizes[size];
1931
- }
1932
- function getShapeClasses(shape) {
1933
- const shapes = {
1934
- circle: "rounded-full",
1935
- square: "rounded-none",
1936
- rounded: "rounded-lg"
1937
- };
1938
- return shapes[shape];
1939
- }
1940
- function getStatusClasses(status) {
1941
- const statuses = {
1942
- online: "bg-success",
1943
- offline: "bg-gray-400",
1944
- busy: "bg-danger",
1945
- away: "bg-warning",
1946
- none: ""
1947
- };
1948
- return statuses[status];
1949
- }
1950
- function generateInitials(name) {
1951
- const parts = name.trim().split(/\s+/);
1952
- if (parts.length === 1) {
1953
- return parts[0].charAt(0).toUpperCase();
1954
- }
1955
- return (parts[0].charAt(0) + parts[parts.length - 1].charAt(0)).toUpperCase();
1956
- }
1957
- function generateBgColor(name) {
1958
- const colors = [
1959
- "bg-blue-500",
1960
- "bg-green-500",
1961
- "bg-yellow-500",
1962
- "bg-purple-500",
1963
- "bg-pink-500",
1964
- "bg-indigo-500",
1965
- "bg-red-500",
1966
- "bg-orange-500",
1967
- "bg-teal-500",
1968
- "bg-cyan-500"
1969
- ];
1970
- let hash = 0;
1971
- for (let i = 0; i < name.length; i++) {
1972
- hash = name.charCodeAt(i) + ((hash << 5) - hash);
1973
- }
1974
- return colors[Math.abs(hash) % colors.length];
1975
- }
1976
- function avatar(options) {
1977
- const { src, alt, size = "md", shape = "circle", status = "none", className = "", href, initials, bgColor } = options;
1978
- const sizeClasses = getSizeClasses4(size);
1979
- const shapeClasses = getShapeClasses(shape);
1980
- const statusColor = getStatusClasses(status);
1981
- const displayInitials = initials || generateInitials(alt);
1982
- const displayBgColor = bgColor || generateBgColor(alt);
1983
- const containerClasses = [
1984
- "relative inline-flex items-center justify-center",
1985
- "overflow-hidden",
1986
- sizeClasses.container,
1987
- shapeClasses,
1988
- className
1989
- ].filter(Boolean).join(" ");
1990
- const contentHtml = src ? `<img src="${(0, import_utils2.escapeHtml)(src)}" alt="${(0, import_utils2.escapeHtml)(alt)}" class="w-full h-full object-cover">` : `<span class="font-medium text-white ${sizeClasses.text}">${(0, import_utils2.escapeHtml)(displayInitials)}</span>`;
1991
- const bgClasses = src ? "bg-gray-200" : displayBgColor;
1992
- const statusHtml = status !== "none" ? `<span class="absolute bottom-0 right-0 block ${sizeClasses.status} ${shapeClasses} ${statusColor} border-white"></span>` : "";
1993
- const innerHtml = `
1994
- <div class="${containerClasses} ${bgClasses}">
1995
- ${contentHtml}
1996
- ${statusHtml}
1997
- </div>
1998
- `;
1999
- if (href) {
2000
- return `<a href="${(0, import_utils2.escapeHtml)(href)}" class="inline-block">${innerHtml}</a>`;
2001
- }
2002
- return innerHtml;
2003
- }
2004
- function avatarGroup(avatars, options = {}) {
2005
- const { max = 5, size = "md", spacing = "normal", className = "" } = options;
2006
- const spacingClasses = {
2007
- tight: "-space-x-3",
2008
- normal: "-space-x-2",
2009
- loose: "-space-x-1"
2010
- };
2011
- const visibleAvatars = avatars.slice(0, max);
2012
- const remainingCount = avatars.length - max;
2013
- const avatarsHtml = visibleAvatars.map((opts, index) => {
2014
- const avatarHtml = avatar({ ...opts, size });
2015
- return `<div class="relative ring-2 ring-white rounded-full" style="z-index: ${visibleAvatars.length - index}">
2016
- ${avatarHtml}
2017
- </div>`;
2018
- }).join("\n");
2019
- const sizeClasses = getSizeClasses4(size);
2020
- const overflowHtml = remainingCount > 0 ? `<div class="relative ring-2 ring-white rounded-full" style="z-index: 0">
2021
- <div class="${sizeClasses.container} rounded-full bg-gray-200 flex items-center justify-center">
2022
- <span class="${sizeClasses.text} font-medium text-gray-600">+${remainingCount}</span>
2023
- </div>
2024
- </div>` : "";
2025
- return `<div class="flex ${spacingClasses[spacing]} ${className}">
2026
- ${avatarsHtml}
2027
- ${overflowHtml}
2028
- </div>`;
2029
- }
2030
- function avatarWithText(options) {
2031
- const { name, subtitle, align = "left", ...avatarOptions } = options;
2032
- const avatarHtml = avatar({ ...avatarOptions, alt: avatarOptions.alt || name });
2033
- const textHtml = `
2034
- <div class="${align === "right" ? "text-right" : ""}">
2035
- <div class="font-medium text-text-primary">${(0, import_utils2.escapeHtml)(name)}</div>
2036
- ${subtitle ? `<div class="text-sm text-text-secondary">${(0, import_utils2.escapeHtml)(subtitle)}</div>` : ""}
2037
- </div>
2038
- `;
2039
- const flexDirection = align === "right" ? "flex-row-reverse" : "flex-row";
2040
- return `<div class="flex items-center gap-3 ${flexDirection}">
2041
- ${avatarHtml}
2042
- ${textHtml}
2043
- </div>`;
2044
- }
2045
-
2046
- // libs/ui/src/components/modal.ts
2047
- function isSafeUrl(url) {
2048
- if (!url) return false;
2049
- const lower = url.toLowerCase().trim();
2050
- const isSafe = lower.startsWith("http://") || lower.startsWith("https://") || lower.startsWith("/") || lower.startsWith("#") || lower.startsWith("mailto:") || lower.startsWith("tel:");
2051
- if (!isSafe) {
2052
- console.warn(`[FrontMCP] Blocked unsafe URL scheme in modal confirmHref: "${url.substring(0, 50)}..."`);
2053
- }
2054
- return isSafe;
2055
- }
2056
- function getSizeClasses5(size) {
2057
- const sizes = {
2058
- sm: "max-w-sm",
2059
- md: "max-w-md",
2060
- lg: "max-w-lg",
2061
- xl: "max-w-2xl",
2062
- full: "max-w-full mx-4"
2063
- };
2064
- return sizes[size];
2065
- }
2066
- function modal(content, options) {
2067
- const {
2068
- id,
2069
- title,
2070
- size = "md",
2071
- showClose = true,
2072
- closeOnBackdrop = true,
2073
- closeOnEscape = true,
2074
- footer,
2075
- className = "",
2076
- open = false
2077
- } = options;
2078
- const sizeClasses = getSizeClasses5(size);
2079
- const visibilityClasses = open ? "" : "hidden";
2080
- const headerHtml = title || showClose ? `<div class="flex items-center justify-between p-4 border-b border-divider">
2081
- ${title ? `<h3 class="text-lg font-semibold text-text-primary">${(0, import_utils2.escapeHtml)(title)}</h3>` : "<div></div>"}
2082
- ${showClose ? `
2083
- <button
2084
- type="button"
2085
- class="p-1 rounded-lg text-text-secondary hover:text-text-primary hover:bg-gray-100 transition-colors"
2086
- onclick="document.getElementById('${(0, import_utils2.escapeHtml)(id)}').classList.add('hidden')"
2087
- aria-label="Close"
2088
- >
2089
- <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2090
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
2091
- </svg>
2092
- </button>
2093
- ` : ""}
2094
- </div>` : "";
2095
- const footerHtml = footer ? `<div class="flex items-center justify-end gap-3 p-4 border-t border-divider">
2096
- ${footer}
2097
- </div>` : "";
2098
- const backdropClickHandler = closeOnBackdrop ? `onclick="if (event.target === this) this.classList.add('hidden')"` : "";
2099
- const escapeHandler = closeOnEscape ? `<script>
2100
- document.addEventListener('keydown', function(e) {
2101
- if (e.key === 'Escape') {
2102
- document.getElementById('${(0, import_utils2.escapeHtml)(id)}')?.classList.add('hidden');
2103
- }
2104
- });
2105
- </script>` : "";
2106
- return `
2107
- <div
2108
- id="${(0, import_utils2.escapeHtml)(id)}"
2109
- class="fixed inset-0 z-50 overflow-y-auto ${visibilityClasses}"
2110
- ${backdropClickHandler}
2111
- role="dialog"
2112
- aria-modal="true"
2113
- aria-labelledby="${(0, import_utils2.escapeHtml)(id)}-title"
2114
- >
2115
- <!-- Backdrop -->
2116
- <div class="fixed inset-0 bg-black/50 transition-opacity"></div>
2117
-
2118
- <!-- Modal container -->
2119
- <div class="flex min-h-full items-center justify-center p-4">
2120
- <div class="relative w-full ${sizeClasses} bg-white rounded-xl shadow-xl ${className}">
2121
- ${headerHtml}
2122
- <div class="p-4">
2123
- ${content}
2124
- </div>
2125
- ${footerHtml}
2126
- </div>
2127
- </div>
2128
- </div>
2129
- ${escapeHandler}
2130
- `;
2131
- }
2132
- function modalTrigger(triggerContent, modalId, options = {}) {
2133
- const { className = "", tag = "button" } = options;
2134
- const attrs = `
2135
- class="${className}"
2136
- onclick="document.getElementById('${(0, import_utils2.escapeHtml)(modalId)}').classList.remove('hidden')"
2137
- `;
2138
- if (tag === "button") {
2139
- return `<button type="button" ${attrs}>${triggerContent}</button>`;
2140
- }
2141
- return `<${tag} ${attrs}>${triggerContent}</${tag}>`;
2142
- }
2143
- function confirmModal(options) {
2144
- const {
2145
- id,
2146
- title = "Confirm Action",
2147
- message,
2148
- confirmText = "Confirm",
2149
- cancelText = "Cancel",
2150
- variant = "primary",
2151
- icon,
2152
- confirmHref
2153
- } = options;
2154
- const variantClasses = {
2155
- primary: "bg-primary hover:bg-primary/90 text-white",
2156
- danger: "bg-danger hover:bg-danger/90 text-white",
2157
- warning: "bg-warning hover:bg-warning/90 text-white"
2158
- };
2159
- const iconColors = {
2160
- primary: "text-primary bg-primary/10",
2161
- danger: "text-danger bg-danger/10",
2162
- warning: "text-warning bg-warning/10"
2163
- };
2164
- const defaultIcons = {
2165
- primary: `<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2166
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
2167
- </svg>`,
2168
- danger: `<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2169
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>
2170
- </svg>`,
2171
- warning: `<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2172
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>
2173
- </svg>`
2174
- };
2175
- const displayIcon = icon || defaultIcons[variant];
2176
- const content = `
2177
- <div class="text-center">
2178
- <div class="mx-auto w-12 h-12 rounded-full ${iconColors[variant]} flex items-center justify-center mb-4">
2179
- ${displayIcon}
2180
- </div>
2181
- <h3 class="text-lg font-semibold text-text-primary mb-2">${(0, import_utils2.escapeHtml)(title)}</h3>
2182
- <p class="text-text-secondary">${(0, import_utils2.escapeHtml)(message)}</p>
2183
- </div>
2184
- `;
2185
- const confirmButton = confirmHref && isSafeUrl(confirmHref) ? `<a
2186
- href="${(0, import_utils2.escapeHtml)(confirmHref)}"
2187
- class="px-4 py-2 rounded-lg ${variantClasses[variant]} transition-colors"
2188
- >
2189
- ${(0, import_utils2.escapeHtml)(confirmText)}
2190
- </a>` : `<button
2191
- type="button"
2192
- class="px-4 py-2 rounded-lg ${variantClasses[variant]} transition-colors"
2193
- onclick="document.getElementById('${(0, import_utils2.escapeHtml)(id)}').classList.add('hidden')"
2194
- >
2195
- ${(0, import_utils2.escapeHtml)(confirmText)}
2196
- </button>`;
2197
- const footer = `
2198
- <button
2199
- type="button"
2200
- class="px-4 py-2 rounded-lg border border-border text-text-primary hover:bg-gray-50 transition-colors"
2201
- onclick="document.getElementById('${(0, import_utils2.escapeHtml)(id)}').classList.add('hidden')"
2202
- >
2203
- ${(0, import_utils2.escapeHtml)(cancelText)}
2204
- </button>
2205
- ${confirmButton}
2206
- `;
2207
- return modal(content, {
2208
- id,
2209
- size: "sm",
2210
- showClose: false,
2211
- footer
2212
- });
2213
- }
2214
- function drawer(content, options) {
2215
- const {
2216
- id,
2217
- title,
2218
- position = "right",
2219
- size = "md",
2220
- showClose = true,
2221
- closeOnBackdrop = true,
2222
- footer,
2223
- className = "",
2224
- open = false
2225
- } = options;
2226
- const sizeClasses = {
2227
- left: { sm: "w-64", md: "w-80", lg: "w-96", xl: "w-[32rem]" },
2228
- right: { sm: "w-64", md: "w-80", lg: "w-96", xl: "w-[32rem]" },
2229
- top: { sm: "h-32", md: "h-48", lg: "h-64", xl: "h-96" },
2230
- bottom: { sm: "h-32", md: "h-48", lg: "h-64", xl: "h-96" }
2231
- };
2232
- const positionClasses = {
2233
- left: "inset-y-0 left-0",
2234
- right: "inset-y-0 right-0",
2235
- top: "inset-x-0 top-0",
2236
- bottom: "inset-x-0 bottom-0"
2237
- };
2238
- const fullSizeClasses = {
2239
- left: "h-full",
2240
- right: "h-full",
2241
- top: "w-full",
2242
- bottom: "w-full"
2243
- };
2244
- const visibilityClasses = open ? "" : "hidden";
2245
- const headerHtml = title || showClose ? `<div class="flex items-center justify-between p-4 border-b border-divider">
2246
- ${title ? `<h3 class="text-lg font-semibold text-text-primary">${(0, import_utils2.escapeHtml)(title)}</h3>` : "<div></div>"}
2247
- ${showClose ? `
2248
- <button
2249
- type="button"
2250
- class="p-1 rounded-lg text-text-secondary hover:text-text-primary hover:bg-gray-100 transition-colors"
2251
- onclick="document.getElementById('${(0, import_utils2.escapeHtml)(id)}').classList.add('hidden')"
2252
- aria-label="Close"
2253
- >
2254
- <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2255
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
2256
- </svg>
2257
- </button>
2258
- ` : ""}
2259
- </div>` : "";
2260
- const footerHtml = footer ? `<div class="p-4 border-t border-divider">${footer}</div>` : "";
2261
- const backdropClickHandler = closeOnBackdrop ? `onclick="if (event.target === this) this.classList.add('hidden')"` : "";
2262
- return `
2263
- <div
2264
- id="${(0, import_utils2.escapeHtml)(id)}"
2265
- class="fixed inset-0 z-50 ${visibilityClasses}"
2266
- ${backdropClickHandler}
2267
- role="dialog"
2268
- aria-modal="true"
2269
- >
2270
- <!-- Backdrop -->
2271
- <div class="fixed inset-0 bg-black/50 transition-opacity"></div>
2272
-
2273
- <!-- Drawer -->
2274
- <div class="fixed ${positionClasses[position]} ${sizeClasses[position][size]} ${fullSizeClasses[position]} bg-white shadow-xl flex flex-col ${className}">
2275
- ${headerHtml}
2276
- <div class="flex-1 overflow-y-auto p-4">
2277
- ${content}
2278
- </div>
2279
- ${footerHtml}
2280
- </div>
2281
- </div>
2282
- `;
2283
- }
2284
-
2285
- // libs/ui/src/components/table.ts
2286
- function getAlignClasses(align = "left") {
2287
- const alignments = {
2288
- left: "text-left",
2289
- center: "text-center",
2290
- right: "text-right"
2291
- };
2292
- return alignments[align];
2293
- }
2294
- function buildSortIndicator(direction) {
2295
- if (direction === "asc") {
2296
- return `<svg class="w-4 h-4 ml-1 inline-block" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2297
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 15l7-7 7 7"/>
2298
- </svg>`;
2299
- }
2300
- if (direction === "desc") {
2301
- return `<svg class="w-4 h-4 ml-1 inline-block" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2302
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
2303
- </svg>`;
2304
- }
2305
- return `<svg class="w-4 h-4 ml-1 inline-block opacity-30" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2306
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16V4m0 0L3 8m4-4l4 4m6 0v12m0 0l4-4m-4 4l-4-4"/>
2307
- </svg>`;
2308
- }
2309
- function buildTableHeader(columns, options) {
2310
- const { selectable, compact } = options;
2311
- const paddingClass = compact ? "px-3 py-2" : "px-4 py-3";
2312
- const selectAllCell = selectable ? `<th class="${paddingClass} w-12">
2313
- <input
2314
- type="checkbox"
2315
- class="w-4 h-4 rounded border-border text-primary focus:ring-primary/20"
2316
- aria-label="Select all"
2317
- >
2318
- </th>` : "";
2319
- const headerCells = columns.map((col) => {
2320
- const alignClass = getAlignClasses(col.align);
2321
- const widthStyle = col.width ? `style="width: ${col.width}"` : "";
2322
- const sortableClasses = col.sortable ? "cursor-pointer hover:bg-gray-50" : "";
2323
- return `<th
2324
- class="${paddingClass} ${alignClass} font-semibold text-text-primary ${sortableClasses} ${col.headerClass || ""}"
2325
- ${widthStyle}
2326
- >
2327
- ${col.sortable ? `<span class="inline-flex items-center">${(0, import_utils2.escapeHtml)(col.header)}${buildSortIndicator(
2328
- col.sortDirection || null
2329
- )}</span>` : (0, import_utils2.escapeHtml)(col.header)}
2330
- </th>`;
2331
- }).join("\n");
2332
- return `<thead class="bg-gray-50 border-b border-border">
2333
- <tr>
2334
- ${selectAllCell}
2335
- ${headerCells}
2336
- </tr>
2337
- </thead>`;
2338
- }
2339
- function buildTableBody(data, columns, options) {
2340
- const { selectable, hoverable, striped, bordered, compact, rowKey = "id", onRowClick } = options;
2341
- const paddingClass = compact ? "px-3 py-2" : "px-4 py-3";
2342
- if (data.length === 0) {
2343
- const colspan = columns.length + (selectable ? 1 : 0);
2344
- const emptyContent = options.emptyContent || `
2345
- <div class="text-center py-8">
2346
- <svg class="w-12 h-12 mx-auto text-gray-300 mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2347
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4"/>
2348
- </svg>
2349
- <p class="text-text-secondary">${options.emptyMessage || "No data available"}</p>
2350
- </div>
2351
- `;
2352
- return `<tbody>
2353
- <tr>
2354
- <td colspan="${colspan}">${emptyContent}</td>
2355
- </tr>
2356
- </tbody>`;
2357
- }
2358
- const rows = data.map((row, rowIndex) => {
2359
- const rowId = String(row[rowKey] || rowIndex);
2360
- const rowClasses = [
2361
- hoverable ? "hover:bg-gray-50" : "",
2362
- striped && rowIndex % 2 === 1 ? "bg-gray-50/50" : "",
2363
- bordered ? "border-b border-border" : "",
2364
- onRowClick ? "cursor-pointer" : ""
2365
- ].filter(Boolean).join(" ");
2366
- const clickHandler = onRowClick ? `onclick="window.location.href='${(0, import_utils2.escapeHtml)(onRowClick.replace("{key}", rowId))}'"` : "";
2367
- const selectCell = selectable ? `<td class="${paddingClass}" onclick="event.stopPropagation()">
2368
- <input
2369
- type="checkbox"
2370
- class="w-4 h-4 rounded border-border text-primary focus:ring-primary/20"
2371
- name="selected[]"
2372
- value="${(0, import_utils2.escapeHtml)(rowId)}"
2373
- aria-label="Select row"
2374
- >
2375
- </td>` : "";
2376
- const cells = columns.map((col) => {
2377
- const value = row[col.key];
2378
- const alignClass = getAlignClasses(col.align);
2379
- const cellContent = col.render ? col.render(value, row, rowIndex) : (0, import_utils2.escapeHtml)(String(value ?? ""));
2380
- return `<td class="${paddingClass} ${alignClass} ${col.cellClass || ""}">${cellContent}</td>`;
2381
- }).join("\n");
2382
- return `<tr class="${rowClasses}" ${clickHandler}>
2383
- ${selectCell}
2384
- ${cells}
2385
- </tr>`;
2386
- }).join("\n");
2387
- return `<tbody class="divide-y divide-border">${rows}</tbody>`;
2388
- }
2389
- function buildLoadingOverlay() {
2390
- return `<div class="absolute inset-0 bg-white/70 flex items-center justify-center">
2391
- <svg class="animate-spin w-8 h-8 text-primary" fill="none" viewBox="0 0 24 24">
2392
- <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
2393
- <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>
2394
- </svg>
2395
- </div>`;
2396
- }
2397
- function table(data, options) {
2398
- const { id, bordered, stickyHeader, className = "", loading = false } = options;
2399
- const tableClasses = ["w-full", bordered ? "border border-border" : "", "text-sm"].filter(Boolean).join(" ");
2400
- const wrapperClasses = ["relative overflow-x-auto", stickyHeader ? "max-h-96 overflow-y-auto" : "", className].filter(Boolean).join(" ");
2401
- const idAttr = id ? `id="${(0, import_utils2.escapeHtml)(id)}"` : "";
2402
- const header = buildTableHeader(options.columns, options);
2403
- const body = buildTableBody(data, options.columns, options);
2404
- const loadingOverlay = loading ? buildLoadingOverlay() : "";
2405
- return `<div class="${wrapperClasses}" ${idAttr}>
2406
- <table class="${tableClasses}">
2407
- ${header}
2408
- ${body}
2409
- </table>
2410
- ${loadingOverlay}
2411
- </div>`;
2412
- }
2413
- function pagination(options) {
2414
- const {
2415
- page,
2416
- totalPages,
2417
- totalItems,
2418
- pageSize = 10,
2419
- showPageSize = false,
2420
- pageSizeOptions = [10, 25, 50, 100],
2421
- className = "",
2422
- baseUrl = ""
2423
- } = options;
2424
- const buildPageLink = (pageNum, label, disabled, active) => {
2425
- const baseClasses = "px-3 py-2 text-sm rounded-lg transition-colors";
2426
- const stateClasses = disabled ? "text-gray-300 cursor-not-allowed" : active ? "bg-primary text-white" : "text-text-primary hover:bg-gray-100";
2427
- if (disabled) {
2428
- return `<span class="${baseClasses} ${stateClasses}">${label}</span>`;
2429
- }
2430
- const pageUrl = baseUrl ? `${baseUrl}${baseUrl.includes("?") ? "&" : "?"}page=${pageNum}` : `?page=${pageNum}`;
2431
- return `<a href="${(0, import_utils2.escapeHtml)(pageUrl)}" class="${baseClasses} ${stateClasses}">${label}</a>`;
2432
- };
2433
- const pageNumbers = [];
2434
- const maxVisible = 5;
2435
- if (totalPages <= maxVisible) {
2436
- for (let i = 1; i <= totalPages; i++) {
2437
- pageNumbers.push(i);
2438
- }
2439
- } else {
2440
- pageNumbers.push(1);
2441
- let start = Math.max(2, page - 1);
2442
- let end = Math.min(totalPages - 1, page + 1);
2443
- if (page <= 2) {
2444
- end = 4;
2445
- } else if (page >= totalPages - 1) {
2446
- start = totalPages - 3;
2447
- }
2448
- if (start > 2) {
2449
- pageNumbers.push(-1);
2450
- }
2451
- for (let i = start; i <= end; i++) {
2452
- pageNumbers.push(i);
2453
- }
2454
- if (end < totalPages - 1) {
2455
- pageNumbers.push(-1);
2456
- }
2457
- pageNumbers.push(totalPages);
2458
- }
2459
- const pagesHtml = pageNumbers.map((num) => {
2460
- if (num === -1) {
2461
- return '<span class="px-2 py-2 text-text-secondary">...</span>';
2462
- }
2463
- return buildPageLink(num, String(num), false, num === page);
2464
- }).join("\n");
2465
- const prevLink = buildPageLink(page - 1, "&larr; Previous", page <= 1, false);
2466
- const nextLink = buildPageLink(page + 1, "Next &rarr;", page >= totalPages, false);
2467
- const infoHtml = totalItems !== void 0 ? `<span class="text-sm text-text-secondary">
2468
- Showing ${(page - 1) * pageSize + 1} to ${Math.min(page * pageSize, totalItems)} of ${totalItems} results
2469
- </span>` : "";
2470
- const pageSizeHtml = showPageSize ? `<select
2471
- class="ml-4 px-2 py-1 text-sm border border-border rounded-lg bg-white"
2472
- onchange="window.location.href = '${baseUrl}${baseUrl.includes("?") ? "&" : "?"}page=1&pageSize=' + this.value"
2473
- >
2474
- ${pageSizeOptions.map((size) => `<option value="${size}" ${size === pageSize ? "selected" : ""}>${size} per page</option>`).join("")}
2475
- </select>` : "";
2476
- return `<div class="flex items-center justify-between ${className}">
2477
- <div class="flex items-center">
2478
- ${infoHtml}
2479
- ${pageSizeHtml}
2480
- </div>
2481
- <div class="flex items-center gap-1">
2482
- ${prevLink}
2483
- ${pagesHtml}
2484
- ${nextLink}
2485
- </div>
2486
- </div>`;
2487
- }
2488
-
2489
- // libs/ui/src/components/list.ts
2490
- var permissionIcons = {
2491
- read: `<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2492
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>
2493
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"/>
2494
- </svg>`,
2495
- write: `<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2496
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/>
2497
- </svg>`,
2498
- delete: `<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2499
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/>
2500
- </svg>`,
2501
- profile: `<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2502
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"/>
2503
- </svg>`,
2504
- email: `<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2505
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"/>
2506
- </svg>`,
2507
- settings: `<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2508
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"/>
2509
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>
2510
- </svg>`,
2511
- default: `<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2512
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"/>
2513
- </svg>`
2514
- };
2515
- function getPermissionIcon(scope, customIcon) {
2516
- if (customIcon) return customIcon;
2517
- const scopeLower = scope.toLowerCase();
2518
- if (scopeLower.includes("read")) return permissionIcons["read"];
2519
- if (scopeLower.includes("write") || scopeLower.includes("create") || scopeLower.includes("update"))
2520
- return permissionIcons["write"];
2521
- if (scopeLower.includes("delete")) return permissionIcons["delete"];
2522
- if (scopeLower.includes("profile")) return permissionIcons["profile"];
2523
- if (scopeLower.includes("email")) return permissionIcons["email"];
2524
- if (scopeLower.includes("settings") || scopeLower.includes("config")) return permissionIcons["settings"];
2525
- return permissionIcons["default"];
2526
- }
2527
- function permissionList(permissions, options = {}) {
2528
- const { id, checkable = false, inputName = "scopes", title, className = "" } = options;
2529
- const titleHtml = title ? `<h4 class="font-medium text-text-primary mb-3">${(0, import_utils2.escapeHtml)(title)}</h4>` : "";
2530
- const itemsHtml = permissions.map((perm, index) => {
2531
- const icon = getPermissionIcon(perm.scope, perm.icon);
2532
- const sensitiveClasses = perm.sensitive ? "border-warning/30 bg-warning/5" : "border-border";
2533
- const sensitiveLabel = perm.sensitive ? '<span class="text-xs text-warning font-medium ml-2">Sensitive</span>' : "";
2534
- const checkboxHtml = checkable ? `<input
2535
- type="checkbox"
2536
- name="${(0, import_utils2.escapeHtml)(inputName)}[]"
2537
- value="${(0, import_utils2.escapeHtml)(perm.scope)}"
2538
- class="w-4 h-4 rounded border-border text-primary focus:ring-primary/20"
2539
- ${perm.checked || perm.required ? "checked" : ""}
2540
- ${perm.required ? "disabled" : ""}
2541
- id="${id ? (0, import_utils2.escapeHtml)(id) : "perm"}-${index}"
2542
- >` : `<div class="w-5 h-5 rounded-full bg-success/10 text-success flex items-center justify-center">
2543
- <svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2544
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M5 13l4 4L19 7"/>
2545
- </svg>
2546
- </div>`;
2547
- return `<div class="flex items-start gap-3 p-3 border ${sensitiveClasses} rounded-lg">
2548
- <div class="flex-shrink-0 mt-0.5 text-text-secondary">
2549
- ${icon}
2550
- </div>
2551
- <div class="flex-1 min-w-0">
2552
- <div class="flex items-center">
2553
- <span class="font-medium text-text-primary">${(0, import_utils2.escapeHtml)(perm.name)}</span>
2554
- ${perm.required ? '<span class="text-xs text-text-secondary ml-2">(Required)</span>' : ""}
2555
- ${sensitiveLabel}
2556
- </div>
2557
- ${perm.description ? `<p class="text-sm text-text-secondary mt-0.5">${(0, import_utils2.escapeHtml)(perm.description)}</p>` : ""}
2558
- </div>
2559
- <div class="flex-shrink-0">
2560
- ${checkboxHtml}
2561
- </div>
2562
- </div>`;
2563
- }).join("\n");
2564
- const idAttr = id ? `id="${(0, import_utils2.escapeHtml)(id)}"` : "";
2565
- return `<div class="permission-list ${className}" ${idAttr}>
2566
- ${titleHtml}
2567
- <div class="space-y-2">
2568
- ${itemsHtml}
2569
- </div>
2570
- </div>`;
2571
- }
2572
- function featureList(features, options = {}) {
2573
- const { style = "check", includedIcon, excludedIcon, className = "" } = options;
2574
- const defaultIncludedIcon = `<svg class="w-5 h-5 text-success" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2575
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
2576
- </svg>`;
2577
- const defaultExcludedIcon = `<svg class="w-5 h-5 text-gray-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2578
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
2579
- </svg>`;
2580
- const itemsHtml = features.map((feature, index) => {
2581
- const included = feature.included !== false;
2582
- let iconHtml;
2583
- if (style === "check") {
2584
- iconHtml = included ? includedIcon || defaultIncludedIcon : excludedIcon || defaultExcludedIcon;
2585
- } else if (style === "bullet") {
2586
- iconHtml = `<span class="w-2 h-2 rounded-full ${included ? "bg-primary" : "bg-gray-300"}"></span>`;
2587
- } else {
2588
- iconHtml = `<span class="text-sm font-medium ${included ? "text-primary" : "text-gray-400"}">${index + 1}.</span>`;
2589
- }
2590
- const textClasses = included ? "text-text-primary" : "text-text-secondary line-through";
2591
- return `<li class="flex items-start gap-3">
2592
- <div class="flex-shrink-0 mt-0.5">${iconHtml}</div>
2593
- <div class="flex-1">
2594
- <span class="${textClasses}">${(0, import_utils2.escapeHtml)(feature.name)}</span>
2595
- ${feature.description ? `<p class="text-sm text-text-secondary">${(0, import_utils2.escapeHtml)(feature.description)}</p>` : ""}
2596
- </div>
2597
- </li>`;
2598
- }).join("\n");
2599
- return `<ul class="space-y-3 ${className}">${itemsHtml}</ul>`;
2600
- }
2601
- function descriptionList(items, options = {}) {
2602
- const { layout = "stacked", dividers = false, className = "" } = options;
2603
- const copyScript = `
2604
- <script>
2605
- function copyToClipboard(text, btn) {
2606
- navigator.clipboard.writeText(text).then(() => {
2607
- const originalText = btn.innerHTML;
2608
- btn.innerHTML = '<svg class="w-4 h-4 text-success" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>';
2609
- setTimeout(() => btn.innerHTML = originalText, 2000);
2610
- });
2611
- }
2612
- </script>
2613
- `;
2614
- const hasCopyable = items.some((item) => item.copyable);
2615
- if (layout === "horizontal") {
2616
- const itemsHtml2 = items.map((item) => {
2617
- const copyBtn = item.copyable ? `<button type="button" onclick="copyToClipboard('${(0, import_utils2.escapeHtml)(
2618
- item.description
2619
- )}', this)" class="ml-2 p-1 rounded hover:bg-gray-100 transition-colors">
2620
- <svg class="w-4 h-4 text-text-secondary" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2621
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"/>
2622
- </svg>
2623
- </button>` : "";
2624
- return `<div class="py-3 sm:grid sm:grid-cols-3 sm:gap-4 ${dividers ? "border-b border-divider" : ""}">
2625
- <dt class="text-sm font-medium text-text-secondary">${(0, import_utils2.escapeHtml)(item.term)}</dt>
2626
- <dd class="mt-1 sm:mt-0 sm:col-span-2 text-sm text-text-primary flex items-center">
2627
- ${(0, import_utils2.escapeHtml)(item.description)}
2628
- ${copyBtn}
2629
- </dd>
2630
- </div>`;
2631
- }).join("\n");
2632
- return `<dl class="${className}">${itemsHtml2}</dl>${hasCopyable ? copyScript : ""}`;
2633
- }
2634
- if (layout === "grid") {
2635
- const itemsHtml2 = items.map((item) => {
2636
- const copyBtn = item.copyable ? `<button type="button" onclick="copyToClipboard('${(0, import_utils2.escapeHtml)(
2637
- item.description
2638
- )}', this)" class="absolute top-2 right-2 p-1 rounded hover:bg-gray-100 transition-colors">
2639
- <svg class="w-4 h-4 text-text-secondary" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2640
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"/>
2641
- </svg>
2642
- </button>` : "";
2643
- return `<div class="relative p-4 bg-gray-50 rounded-lg">
2644
- <dt class="text-sm font-medium text-text-secondary">${(0, import_utils2.escapeHtml)(item.term)}</dt>
2645
- <dd class="mt-1 text-sm text-text-primary font-medium">${(0, import_utils2.escapeHtml)(item.description)}</dd>
2646
- ${copyBtn}
2647
- </div>`;
2648
- }).join("\n");
2649
- return `<dl class="grid grid-cols-2 gap-4 ${className}">${itemsHtml2}</dl>${hasCopyable ? copyScript : ""}`;
2650
- }
2651
- const itemsHtml = items.map((item) => {
2652
- const copyBtn = item.copyable ? `<button type="button" onclick="copyToClipboard('${(0, import_utils2.escapeHtml)(
2653
- item.description
2654
- )}', this)" class="ml-2 p-1 rounded hover:bg-gray-100 transition-colors">
2655
- <svg class="w-4 h-4 text-text-secondary" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2656
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"/>
2657
- </svg>
2658
- </button>` : "";
2659
- return `<div class="${dividers ? "py-3 border-b border-divider last:border-0" : "py-2"}">
2660
- <dt class="text-sm text-text-secondary">${(0, import_utils2.escapeHtml)(item.term)}</dt>
2661
- <dd class="mt-1 text-sm text-text-primary font-medium flex items-center">
2662
- ${(0, import_utils2.escapeHtml)(item.description)}
2663
- ${copyBtn}
2664
- </dd>
2665
- </div>`;
2666
- }).join("\n");
2667
- return `<dl class="${className}">${itemsHtml}</dl>${hasCopyable ? copyScript : ""}`;
2668
- }
2669
- function actionList(items, className = "") {
2670
- const itemsHtml = items.map((item) => {
2671
- const baseClasses = [
2672
- "flex items-center gap-3 px-4 py-3 transition-colors",
2673
- item.disabled ? "opacity-50 cursor-not-allowed" : item.destructive ? "hover:bg-danger/5 text-danger cursor-pointer" : "hover:bg-gray-50 cursor-pointer"
2674
- ].join(" ");
2675
- const iconHtml = item.icon ? `<span class="flex-shrink-0 ${item.destructive ? "text-danger" : "text-text-secondary"}">${item.icon}</span>` : "";
2676
- const contentHtml = `
2677
- ${iconHtml}
2678
- <div class="flex-1 min-w-0">
2679
- <div class="font-medium ${item.destructive ? "text-danger" : "text-text-primary"}">${(0, import_utils2.escapeHtml)(
2680
- item.label
2681
- )}</div>
2682
- ${item.description ? `<p class="text-sm text-text-secondary">${(0, import_utils2.escapeHtml)(item.description)}</p>` : ""}
2683
- </div>
2684
- <svg class="w-5 h-5 text-text-secondary" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2685
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/>
2686
- </svg>
2687
- `;
2688
- if (item.disabled) {
2689
- return `<div class="${baseClasses}">${contentHtml}</div>`;
2690
- }
2691
- if (item.href) {
2692
- return `<a href="${(0, import_utils2.escapeHtml)(item.href)}" class="${baseClasses}">${contentHtml}</a>`;
2693
- }
2694
- return `<div class="${baseClasses}">${contentHtml}</div>`;
2695
- }).join("\n");
2696
- return `<div class="divide-y divide-divider ${className}">${itemsHtml}</div>`;
2697
- }
2698
-
2699
- // libs/ui/src/layouts/presets.ts
2700
- function authLayout(content, options) {
2701
- const { showBranding = true, logo, footer, ...baseOptions } = options;
2702
- const brandingHtml = showBranding && logo ? `<div class="text-center mb-8">${logo}</div>` : showBranding ? `<div class="text-center mb-8">
2703
- <div class="inline-flex items-center justify-center w-16 h-16 rounded-xl bg-gradient-to-br from-primary to-secondary mb-4">
2704
- <svg class="w-8 h-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2705
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"/>
2706
- </svg>
2707
- </div>
2708
- </div>` : "";
2709
- const footerHtml = footer ? `<div class="mt-8 text-center text-sm text-text-secondary">${footer}</div>` : "";
2710
- const wrappedContent = `
2711
- <div class="bg-white rounded-2xl shadow-xl p-8">
2712
- ${brandingHtml}
2713
- ${content}
2714
- </div>
2715
- ${footerHtml}
2716
- `;
2717
- return baseLayout(wrappedContent, {
2718
- ...baseOptions,
2719
- pageType: "auth",
2720
- size: baseOptions.size ?? "sm",
2721
- alignment: "center",
2722
- background: "gradient"
2723
- });
2724
- }
2725
- function consentLayout(content, options) {
2726
- const { clientName, clientIcon, userInfo, ...baseOptions } = options;
2727
- const headerHtml = clientName ? `<div class="text-center mb-6">
2728
- ${clientIcon ? `<img src="${(0, import_utils2.escapeHtml)(clientIcon)}" alt="${(0, import_utils2.escapeHtml)(
2729
- clientName
2730
- )}" class="w-16 h-16 rounded-xl mx-auto mb-4">` : `<div class="inline-flex items-center justify-center w-16 h-16 rounded-xl bg-gradient-to-br from-primary to-secondary text-white font-bold text-2xl mx-auto mb-4">
2731
- ${(0, import_utils2.escapeHtml)(clientName.charAt(0).toUpperCase())}
2732
- </div>`}
2733
- <h1 class="text-2xl font-bold text-text-primary">${(0, import_utils2.escapeHtml)(clientName)}</h1>
2734
- </div>` : "";
2735
- const userInfoHtml = userInfo ? `<div class="flex items-center gap-3 p-3 bg-gray-50 rounded-lg mb-6">
2736
- ${userInfo.avatar ? `<img src="${(0, import_utils2.escapeHtml)(userInfo.avatar)}" class="w-10 h-10 rounded-full">` : `<div class="w-10 h-10 rounded-full bg-primary text-white flex items-center justify-center font-medium">
2737
- ${(0, import_utils2.escapeHtml)((userInfo.name || userInfo.email || "U").charAt(0).toUpperCase())}
2738
- </div>`}
2739
- <div>
2740
- ${userInfo.name ? `<div class="font-medium text-text-primary">${(0, import_utils2.escapeHtml)(userInfo.name)}</div>` : ""}
2741
- ${userInfo.email ? `<div class="text-sm text-text-secondary">${(0, import_utils2.escapeHtml)(userInfo.email)}</div>` : ""}
2742
- </div>
2743
- </div>` : "";
2744
- const wrappedContent = `
2745
- ${headerHtml}
2746
- ${userInfoHtml}
2747
- ${content}
2748
- `;
2749
- return baseLayout(wrappedContent, {
2750
- ...baseOptions,
2751
- pageType: "consent",
2752
- size: baseOptions.size ?? "lg",
2753
- alignment: "top",
2754
- background: "solid"
2755
- });
2756
- }
2757
- function errorLayout(content, options) {
2758
- const {
2759
- errorCode,
2760
- errorTitle = "Something went wrong",
2761
- errorMessage,
2762
- showRetry = true,
2763
- retryUrl,
2764
- showHome = true,
2765
- homeUrl = "/",
2766
- ...baseOptions
2767
- } = options;
2768
- const errorHtml = `
2769
- <div class="text-center">
2770
- <!-- Error icon -->
2771
- <div class="inline-flex items-center justify-center w-20 h-20 rounded-full bg-danger/10 mb-6">
2772
- <svg class="w-10 h-10 text-danger" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2773
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>
2774
- </svg>
2775
- </div>
2776
-
2777
- ${errorCode ? `<p class="text-6xl font-bold text-danger mb-2">${(0, import_utils2.escapeHtml)(errorCode)}</p>` : ""}
2778
- <h1 class="text-2xl font-bold text-text-primary mb-4">${(0, import_utils2.escapeHtml)(errorTitle)}</h1>
2779
- ${errorMessage ? `<p class="text-text-secondary mb-8">${(0, import_utils2.escapeHtml)(errorMessage)}</p>` : ""}
2780
-
2781
- ${content}
2782
-
2783
- <div class="flex gap-4 justify-center mt-8">
2784
- ${showRetry ? `<button onclick="${retryUrl ? `window.location.href='${(0, import_utils2.escapeHtml)(retryUrl)}'` : "window.location.reload()"}" class="px-6 py-3 bg-primary hover:bg-primary/90 text-white font-medium rounded-lg transition-colors">Try Again</button>` : ""}
2785
- ${showHome ? `<a href="${(0, import_utils2.escapeHtml)(
2786
- homeUrl
2787
- )}" class="px-6 py-3 bg-gray-100 hover:bg-gray-200 text-text-primary font-medium rounded-lg transition-colors">Go Home</a>` : ""}
2788
- </div>
2789
- </div>
2790
- `;
2791
- return baseLayout(errorHtml, {
2792
- ...baseOptions,
2793
- pageType: "error",
2794
- size: "sm",
2795
- alignment: "center",
2796
- background: "solid",
2797
- title: baseOptions.title ?? errorTitle
2798
- });
2799
- }
2800
- function loadingLayout(content, options) {
2801
- const { message = "Loading...", showSpinner = true, showProgress = false, progress = 0, ...baseOptions } = options;
2802
- const spinnerHtml = showSpinner ? `<div class="inline-flex items-center justify-center w-16 h-16 mb-6">
2803
- <svg class="animate-spin w-12 h-12 text-primary" fill="none" viewBox="0 0 24 24">
2804
- <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
2805
- <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>
2806
- </svg>
2807
- </div>` : "";
2808
- const progressHtml = showProgress ? `<div class="w-full bg-gray-200 rounded-full h-2 mb-4">
2809
- <div class="bg-primary h-2 rounded-full transition-all duration-300" style="width: ${progress}%"></div>
2810
- </div>` : "";
2811
- const loadingHtml = `
2812
- <div class="text-center">
2813
- ${spinnerHtml}
2814
- <h2 class="text-xl font-medium text-text-primary mb-2">${(0, import_utils2.escapeHtml)(message)}</h2>
2815
- ${progressHtml}
2816
- ${content}
2817
- </div>
2818
- `;
2819
- return baseLayout(loadingHtml, {
2820
- ...baseOptions,
2821
- pageType: "loading",
2822
- size: "sm",
2823
- alignment: "center",
2824
- background: "solid",
2825
- title: baseOptions.title ?? "Loading"
2826
- });
2827
- }
2828
- function successLayout(content, options) {
2829
- const {
2830
- successTitle = "Success!",
2831
- successMessage,
2832
- continueText = "Continue",
2833
- continueUrl,
2834
- autoClose,
2835
- ...baseOptions
2836
- } = options;
2837
- const autoCloseScript = autoClose ? `<script>
2838
- let countdown = ${autoClose};
2839
- const countdownEl = document.getElementById('countdown');
2840
- const interval = setInterval(() => {
2841
- countdown--;
2842
- if (countdownEl) countdownEl.textContent = countdown;
2843
- if (countdown <= 0) {
2844
- clearInterval(interval);
2845
- ${continueUrl ? `window.location.href = '${(0, import_utils2.escapeHtml)(continueUrl)}';` : "window.close();"}
2846
- }
2847
- }, 1000);
2848
- </script>` : "";
2849
- const successHtml = `
2850
- <div class="text-center">
2851
- <!-- Success icon -->
2852
- <div class="inline-flex items-center justify-center w-20 h-20 rounded-full bg-success/10 mb-6">
2853
- <svg class="w-10 h-10 text-success" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2854
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
2855
- </svg>
2856
- </div>
2857
-
2858
- <h1 class="text-2xl font-bold text-text-primary mb-4">${(0, import_utils2.escapeHtml)(successTitle)}</h1>
2859
- ${successMessage ? `<p class="text-text-secondary mb-8">${(0, import_utils2.escapeHtml)(successMessage)}</p>` : ""}
2860
-
2861
- ${content}
2862
-
2863
- ${continueUrl ? `<a href="${(0, import_utils2.escapeHtml)(
2864
- continueUrl
2865
- )}" class="inline-block mt-6 px-6 py-3 bg-primary hover:bg-primary/90 text-white font-medium rounded-lg transition-colors">${(0, import_utils2.escapeHtml)(
2866
- continueText
2867
- )}</a>` : ""}
2868
-
2869
- ${autoClose ? `<p class="mt-4 text-sm text-text-secondary">Closing in <span id="countdown">${autoClose}</span> seconds...</p>` : ""}
2870
- </div>
2871
- ${autoCloseScript}
2872
- `;
2873
- return baseLayout(successHtml, {
2874
- ...baseOptions,
2875
- pageType: "success",
2876
- size: "sm",
2877
- alignment: "center",
2878
- background: "solid",
2879
- title: baseOptions.title ?? successTitle
2880
- });
2881
- }
2882
- function widgetLayout(content, options) {
2883
- const { maxWidth = "100%", showBorder = false, transparent = true, ...baseOptions } = options;
2884
- const containerClasses = [
2885
- "widget-container",
2886
- showBorder ? "border border-border rounded-lg" : "",
2887
- transparent ? "" : "bg-surface"
2888
- ].filter(Boolean).join(" ");
2889
- const wrappedContent = `
2890
- <div class="${containerClasses}" style="max-width: ${(0, import_utils2.escapeHtml)(maxWidth)}">
2891
- ${content}
2892
- </div>
2893
- `;
2894
- return baseLayout(wrappedContent, {
2895
- ...baseOptions,
2896
- pageType: "widget",
2897
- size: "full",
2898
- alignment: "start",
2899
- background: "none"
2900
- });
2901
- }
2902
- var authLayoutBuilder = createLayoutBuilder({
2903
- pageType: "auth",
2904
- size: "sm",
2905
- alignment: "center",
2906
- background: "gradient"
2907
- });
2908
- var consentLayoutBuilder = createLayoutBuilder({
2909
- pageType: "consent",
2910
- size: "lg",
2911
- alignment: "top",
2912
- background: "solid"
2913
- });
2914
- var errorLayoutBuilder = createLayoutBuilder({
2915
- pageType: "error",
2916
- size: "sm",
2917
- alignment: "center",
2918
- background: "solid"
2919
- });
2920
-
2921
49
  // libs/ui/src/bridge/core/adapter-registry.ts
2922
50
  var AdapterRegistry = class {
2923
51
  _adapters = /* @__PURE__ */ new Map();
@@ -3465,1361 +593,70 @@ async function createBridge(config, registry) {
3465
593
  // libs/ui/src/bridge/runtime/index.ts
3466
594
  var import_uipack = require("@frontmcp/uipack");
3467
595
 
3468
- // libs/ui/src/web-components/core/base-element.ts
3469
- var import_validation2 = require("@frontmcp/uipack/validation");
3470
-
3471
- // libs/ui/src/web-components/core/attribute-parser.ts
3472
- function parseAttributeValue(attrName, value) {
3473
- if (attrName.startsWith("data-fmcp-")) {
3474
- return { key: null, value: void 0 };
3475
- }
3476
- if (attrName.startsWith("data-")) {
3477
- const dataKey = attrName.slice(5);
3478
- return {
3479
- key: dataKey,
3480
- value: value ?? "",
3481
- isData: true
596
+ // libs/ui/src/react/hooks/context.tsx
597
+ var import_react = require("react");
598
+ var import_jsx_runtime = require("react/jsx-runtime");
599
+ var McpBridgeContext = (0, import_react.createContext)(null);
600
+ function McpBridgeProvider({ children, config, onReady, onError }) {
601
+ const [bridge, setBridge] = (0, import_react.useState)(null);
602
+ const [loading, setLoading] = (0, import_react.useState)(true);
603
+ const [error, setError] = (0, import_react.useState)(null);
604
+ (0, import_react.useEffect)(() => {
605
+ let mounted = true;
606
+ let bridgeInstance = null;
607
+ const initBridge = async () => {
608
+ try {
609
+ bridgeInstance = new FrontMcpBridge(config);
610
+ await bridgeInstance.initialize();
611
+ if (mounted) {
612
+ setBridge(bridgeInstance);
613
+ setLoading(false);
614
+ onReady?.(bridgeInstance);
615
+ }
616
+ } catch (err) {
617
+ if (mounted) {
618
+ const error2 = err instanceof Error ? err : new Error(String(err));
619
+ setError(error2);
620
+ setLoading(false);
621
+ onError?.(error2);
622
+ }
623
+ }
3482
624
  };
3483
- }
3484
- const camelName = kebabToCamel(attrName);
3485
- if (value === null || value === "") {
3486
- return { key: camelName, value: true };
3487
- }
3488
- if (value === "true") {
3489
- return { key: camelName, value: true };
3490
- }
3491
- if (value === "false") {
3492
- return { key: camelName, value: false };
3493
- }
3494
- const numValue = Number(value);
3495
- if (!isNaN(numValue) && value.trim() !== "") {
3496
- return { key: camelName, value: numValue };
3497
- }
3498
- if (value.startsWith("{") || value.startsWith("[")) {
3499
- try {
3500
- return { key: camelName, value: JSON.parse(value) };
3501
- } catch {
3502
- }
3503
- }
3504
- return { key: camelName, value };
625
+ initBridge();
626
+ return () => {
627
+ mounted = false;
628
+ if (bridgeInstance) {
629
+ bridgeInstance.dispose();
630
+ }
631
+ };
632
+ }, [config, onReady, onError]);
633
+ const contextValue = (0, import_react.useMemo)(
634
+ () => ({
635
+ bridge,
636
+ loading,
637
+ error,
638
+ ready: !loading && !error && bridge !== null,
639
+ adapterId: bridge?.adapterId,
640
+ capabilities: bridge?.capabilities
641
+ }),
642
+ [bridge, loading, error]
643
+ );
644
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(McpBridgeContext.Provider, { value: contextValue, children });
3505
645
  }
3506
- function kebabToCamel(str) {
3507
- return str.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
3508
- }
3509
- function camelToKebab(str) {
3510
- return str.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
3511
- }
3512
- function getObservedAttributesFromSchema(schema) {
3513
- const attributes = [];
3514
- const schemaAny = schema;
3515
- if (schemaAny.shape) {
3516
- for (const key of Object.keys(schemaAny.shape)) {
3517
- attributes.push(camelToKebab(key));
3518
- }
3519
- }
3520
- const commonAttrs = ["class", "id", "style"];
3521
- attributes.push(...commonAttrs);
3522
- return [...new Set(attributes)];
3523
- }
3524
- function mergeAttributeIntoOptions(options, parsed) {
3525
- if (parsed.key === null || parsed.value === void 0) {
3526
- return options;
3527
- }
3528
- const result = { ...options };
3529
- if (parsed.isData) {
3530
- const data = result["data"] ?? {};
3531
- data[parsed.key] = String(parsed.value);
3532
- result["data"] = data;
3533
- } else {
3534
- result[parsed.key] = parsed.value;
3535
- }
3536
- return result;
3537
- }
3538
-
3539
- // libs/ui/src/web-components/core/base-element.ts
3540
- var HTMLElementBase = typeof HTMLElement !== "undefined" ? HTMLElement : class {
3541
- innerHTML = "";
3542
- dispatchEvent() {
3543
- return true;
3544
- }
3545
- getAttribute() {
3546
- return null;
3547
- }
3548
- };
3549
- var FmcpElement = class extends HTMLElementBase {
3550
- /** Internal options state */
3551
- _options = {};
3552
- /** Content passed as children (captured on connect) */
3553
- _content = "";
3554
- /** Whether component has been connected to DOM */
3555
- _connected = false;
3556
- /** Whether a render is pending (for batching) */
3557
- _pendingRender = false;
3558
- /** Whether initial render has completed */
3559
- _initialRenderComplete = false;
3560
- // ============================================
3561
- // Lifecycle Callbacks
3562
- // ============================================
3563
- /**
3564
- * Called when element is added to DOM.
3565
- * Captures content, parses attributes, and renders.
3566
- *
3567
- * Supports SSR hydration via `data-ssr` attribute:
3568
- * - If `data-ssr` is present, content was pre-rendered by server
3569
- * - Web component adopts existing content without re-rendering
3570
- * - This enables progressive enhancement for LLM platforms
3571
- */
3572
- connectedCallback() {
3573
- this._connected = true;
3574
- const isHydrating = this.hasAttribute("data-ssr");
3575
- if (isHydrating) {
3576
- this._content = this.innerHTML;
3577
- this._initialRenderComplete = true;
3578
- this.removeAttribute("data-ssr");
3579
- this._parseAttributes();
3580
- return;
3581
- }
3582
- if (!this._initialRenderComplete) {
3583
- this._content = this.innerHTML;
3584
- }
3585
- this._parseAttributes();
3586
- this._render();
3587
- }
3588
- /**
3589
- * Called when element is removed from DOM.
3590
- */
3591
- disconnectedCallback() {
3592
- this._connected = false;
3593
- }
3594
- /**
3595
- * Called when an observed attribute changes.
3596
- * Updates options and schedules re-render.
3597
- */
3598
- attributeChangedCallback(name, oldValue, newValue) {
3599
- if (oldValue === newValue) return;
3600
- this._updateOptionFromAttribute(name, newValue);
3601
- this._scheduleRender();
3602
- }
3603
- // ============================================
3604
- // Property Accessors (React/Vue Compatibility)
3605
- // ============================================
3606
- /**
3607
- * Set all options at once (React pattern).
3608
- *
3609
- * @example
3610
- * ```typescript
3611
- * const el = document.querySelector('fmcp-button');
3612
- * el.options = { variant: 'danger', size: 'lg' };
3613
- * ```
3614
- */
3615
- set options(value) {
3616
- this._options = { ...this._options, ...value };
3617
- this._scheduleRender();
3618
- }
3619
- /**
3620
- * Get current options.
3621
- */
3622
- get options() {
3623
- return { ...this._options };
3624
- }
3625
- // ============================================
3626
- // Attribute Parsing
3627
- // ============================================
3628
- /**
3629
- * Parse all current attributes into options.
3630
- */
3631
- _parseAttributes() {
3632
- for (const attr of Array.from(this.attributes)) {
3633
- this._updateOptionFromAttribute(attr.name, attr.value);
3634
- }
3635
- }
3636
- /**
3637
- * Update a single option from an attribute change.
3638
- */
3639
- _updateOptionFromAttribute(attrName, value) {
3640
- const parsed = parseAttributeValue(attrName, value);
3641
- this._options = mergeAttributeIntoOptions(this._options, parsed);
3642
- }
3643
- // ============================================
3644
- // Rendering
3645
- // ============================================
3646
- /**
3647
- * Schedule a render on next microtask.
3648
- * Batches multiple attribute/property changes.
3649
- */
3650
- _scheduleRender() {
3651
- if (!this._connected || this._pendingRender) return;
3652
- this._pendingRender = true;
3653
- queueMicrotask(() => {
3654
- this._pendingRender = false;
3655
- if (this._connected) {
3656
- this._render();
3657
- }
3658
- });
3659
- }
3660
- /**
3661
- * Perform the actual render.
3662
- * Validates options and updates innerHTML.
3663
- */
3664
- _render() {
3665
- const mergedOptions = {
3666
- ...this.config.defaults,
3667
- ...this._options
3668
- };
3669
- const result = this.config.schema.safeParse(mergedOptions);
3670
- if (!result.success) {
3671
- const firstError = result.error.issues[0];
3672
- const invalidParam = firstError?.path.join(".") || "options";
3673
- this.innerHTML = (0, import_validation2.validationErrorBox)({
3674
- componentName: this.config.name,
3675
- invalidParam
3676
- });
3677
- this._initialRenderComplete = true;
3678
- return;
3679
- }
3680
- const html = this.renderHtml(result.data, this._content);
3681
- this.innerHTML = html;
3682
- this._initialRenderComplete = true;
3683
- this.dispatchEvent(
3684
- new CustomEvent("fmcp:render", {
3685
- bubbles: true,
3686
- detail: { options: result.data }
3687
- })
3688
- );
3689
- }
3690
- // ============================================
3691
- // Public API
3692
- // ============================================
3693
- /**
3694
- * Force an immediate re-render.
3695
- *
3696
- * @example
3697
- * ```typescript
3698
- * el.options = { loading: true };
3699
- * el.refresh(); // Force immediate render
3700
- * ```
3701
- */
3702
- refresh() {
3703
- if (this._connected) {
3704
- this._render();
3705
- }
3706
- }
3707
- /**
3708
- * Get the first child element (the actual rendered component).
3709
- *
3710
- * @typeParam T - Expected element type
3711
- * @returns The first child element or null
3712
- *
3713
- * @example
3714
- * ```typescript
3715
- * const button = el.getInnerElement<HTMLButtonElement>();
3716
- * button?.focus();
3717
- * ```
3718
- */
3719
- getInnerElement() {
3720
- return this.firstElementChild;
3721
- }
3722
- /**
3723
- * Update content and re-render.
3724
- *
3725
- * @param content - New content string
3726
- */
3727
- setContent(content) {
3728
- this._content = content;
3729
- this._scheduleRender();
3730
- }
3731
- };
3732
-
3733
- // libs/ui/src/web-components/elements/fmcp-button.ts
3734
- var FmcpButton = class extends FmcpElement {
3735
- config = {
3736
- name: "button",
3737
- schema: ButtonOptionsSchema,
3738
- defaults: {
3739
- variant: "primary",
3740
- size: "md",
3741
- type: "button"
3742
- }
3743
- };
3744
- /**
3745
- * Attributes to observe for changes.
3746
- */
3747
- static get observedAttributes() {
3748
- return getObservedAttributesFromSchema(ButtonOptionsSchema);
3749
- }
3750
- /**
3751
- * Render the button HTML using the button() function.
3752
- */
3753
- renderHtml(options, content) {
3754
- return button(content, options);
3755
- }
3756
- // ============================================
3757
- // Property Setters (Individual Props)
3758
- // ============================================
3759
- set variant(value) {
3760
- this._options.variant = value;
3761
- this._scheduleRender();
3762
- }
3763
- get variant() {
3764
- return this._options.variant;
3765
- }
3766
- set size(value) {
3767
- this._options.size = value;
3768
- this._scheduleRender();
3769
- }
3770
- get size() {
3771
- return this._options.size;
3772
- }
3773
- set type(value) {
3774
- this._options.type = value;
3775
- this._scheduleRender();
3776
- }
3777
- get type() {
3778
- return this._options.type;
3779
- }
3780
- set disabled(value) {
3781
- this._options.disabled = value;
3782
- this._scheduleRender();
3783
- }
3784
- get disabled() {
3785
- return this._options.disabled ?? false;
3786
- }
3787
- set loading(value) {
3788
- this._options.loading = value;
3789
- this._scheduleRender();
3790
- }
3791
- get loading() {
3792
- return this._options.loading ?? false;
3793
- }
3794
- set fullWidth(value) {
3795
- this._options.fullWidth = value;
3796
- this._scheduleRender();
3797
- }
3798
- get fullWidth() {
3799
- return this._options.fullWidth ?? false;
3800
- }
3801
- set iconOnly(value) {
3802
- this._options.iconOnly = value;
3803
- this._scheduleRender();
3804
- }
3805
- get iconOnly() {
3806
- return this._options.iconOnly ?? false;
3807
- }
3808
- set iconBefore(value) {
3809
- this._options.iconBefore = value;
3810
- this._scheduleRender();
3811
- }
3812
- get iconBefore() {
3813
- return this._options.iconBefore;
3814
- }
3815
- set iconAfter(value) {
3816
- this._options.iconAfter = value;
3817
- this._scheduleRender();
3818
- }
3819
- get iconAfter() {
3820
- return this._options.iconAfter;
3821
- }
3822
- set href(value) {
3823
- this._options.href = value;
3824
- this._scheduleRender();
3825
- }
3826
- get href() {
3827
- return this._options.href;
3828
- }
3829
- set buttonAriaLabel(value) {
3830
- this._options.ariaLabel = value;
3831
- this._scheduleRender();
3832
- }
3833
- get buttonAriaLabel() {
3834
- return this._options.ariaLabel;
3835
- }
3836
- // ============================================
3837
- // Event Forwarding
3838
- // ============================================
3839
- connectedCallback() {
3840
- super.connectedCallback();
3841
- this.addEventListener("click", this._handleClick.bind(this));
3842
- }
3843
- _handleClick(e) {
3844
- const innerButton = this.getInnerElement();
3845
- if (innerButton && (e.target === innerButton || innerButton.contains(e.target))) {
3846
- this.dispatchEvent(
3847
- new CustomEvent("fmcp:click", {
3848
- bubbles: true,
3849
- detail: { options: this.options }
3850
- })
3851
- );
3852
- }
3853
- }
3854
- // ============================================
3855
- // Public API
3856
- // ============================================
3857
- /**
3858
- * Focus the inner button element.
3859
- */
3860
- focus() {
3861
- const inner = this.getInnerElement();
3862
- inner?.focus();
3863
- }
3864
- /**
3865
- * Blur the inner button element.
3866
- */
3867
- blur() {
3868
- const inner = this.getInnerElement();
3869
- inner?.blur();
3870
- }
3871
- /**
3872
- * Click the inner button programmatically.
3873
- */
3874
- click() {
3875
- const inner = this.getInnerElement();
3876
- inner?.click();
3877
- }
3878
- };
3879
- function registerFmcpButton() {
3880
- if (typeof customElements !== "undefined" && !customElements.get("fmcp-button")) {
3881
- customElements.define("fmcp-button", FmcpButton);
3882
- }
3883
- }
3884
-
3885
- // libs/ui/src/web-components/elements/fmcp-card.ts
3886
- var FmcpCard = class extends FmcpElement {
3887
- config = {
3888
- name: "card",
3889
- schema: CardOptionsSchema,
3890
- defaults: {
3891
- variant: "default",
3892
- size: "md"
3893
- }
3894
- };
3895
- static get observedAttributes() {
3896
- return getObservedAttributesFromSchema(CardOptionsSchema);
3897
- }
3898
- renderHtml(options, content) {
3899
- return card(content, options);
3900
- }
3901
- // Property setters
3902
- set variant(value) {
3903
- this._options.variant = value;
3904
- this._scheduleRender();
3905
- }
3906
- get variant() {
3907
- return this._options.variant;
3908
- }
3909
- set size(value) {
3910
- this._options.size = value;
3911
- this._scheduleRender();
3912
- }
3913
- get size() {
3914
- return this._options.size;
3915
- }
3916
- set cardTitle(value) {
3917
- this._options.title = value;
3918
- this._scheduleRender();
3919
- }
3920
- get cardTitle() {
3921
- return this._options.title;
3922
- }
3923
- set subtitle(value) {
3924
- this._options.subtitle = value;
3925
- this._scheduleRender();
3926
- }
3927
- get subtitle() {
3928
- return this._options.subtitle;
3929
- }
3930
- set clickable(value) {
3931
- this._options.clickable = value;
3932
- this._scheduleRender();
3933
- }
3934
- get clickable() {
3935
- return this._options.clickable ?? false;
3936
- }
3937
- set href(value) {
3938
- this._options.href = value;
3939
- this._scheduleRender();
3940
- }
3941
- get href() {
3942
- return this._options.href;
3943
- }
3944
- set footer(value) {
3945
- this._options.footer = value;
3946
- this._scheduleRender();
3947
- }
3948
- get footer() {
3949
- return this._options.footer;
3950
- }
3951
- set headerActions(value) {
3952
- this._options.headerActions = value;
3953
- this._scheduleRender();
3954
- }
3955
- get headerActions() {
3956
- return this._options.headerActions;
3957
- }
3958
- };
3959
- function registerFmcpCard() {
3960
- if (typeof customElements !== "undefined" && !customElements.get("fmcp-card")) {
3961
- customElements.define("fmcp-card", FmcpCard);
3962
- }
3963
- }
3964
-
3965
- // libs/ui/src/web-components/elements/fmcp-alert.ts
3966
- var FmcpAlert = class extends FmcpElement {
3967
- config = {
3968
- name: "alert",
3969
- schema: AlertOptionsSchema,
3970
- defaults: {
3971
- variant: "info",
3972
- showIcon: true
3973
- }
3974
- };
3975
- static get observedAttributes() {
3976
- return getObservedAttributesFromSchema(AlertOptionsSchema);
3977
- }
3978
- renderHtml(options, content) {
3979
- return alert(content, options);
3980
- }
3981
- // Property setters
3982
- set variant(value) {
3983
- this._options.variant = value;
3984
- this._scheduleRender();
3985
- }
3986
- get variant() {
3987
- return this._options.variant;
3988
- }
3989
- set alertTitle(value) {
3990
- this._options.title = value;
3991
- this._scheduleRender();
3992
- }
3993
- get alertTitle() {
3994
- return this._options.title;
3995
- }
3996
- set showIcon(value) {
3997
- this._options.showIcon = value;
3998
- this._scheduleRender();
3999
- }
4000
- get showIcon() {
4001
- return this._options.showIcon ?? true;
4002
- }
4003
- set dismissible(value) {
4004
- this._options.dismissible = value;
4005
- this._scheduleRender();
4006
- }
4007
- get dismissible() {
4008
- return this._options.dismissible ?? false;
4009
- }
4010
- set actions(value) {
4011
- this._options.actions = value;
4012
- this._scheduleRender();
4013
- }
4014
- get actions() {
4015
- return this._options.actions;
4016
- }
4017
- };
4018
- function registerFmcpAlert() {
4019
- if (typeof customElements !== "undefined" && !customElements.get("fmcp-alert")) {
4020
- customElements.define("fmcp-alert", FmcpAlert);
4021
- }
4022
- }
4023
-
4024
- // libs/ui/src/web-components/elements/fmcp-badge.ts
4025
- var FmcpBadge = class extends FmcpElement {
4026
- config = {
4027
- name: "badge",
4028
- schema: BadgeOptionsSchema,
4029
- defaults: {
4030
- variant: "default",
4031
- size: "md"
4032
- }
4033
- };
4034
- static get observedAttributes() {
4035
- return getObservedAttributesFromSchema(BadgeOptionsSchema);
4036
- }
4037
- renderHtml(options, content) {
4038
- return badge(content, options);
4039
- }
4040
- // Property setters
4041
- set variant(value) {
4042
- this._options.variant = value;
4043
- this._scheduleRender();
4044
- }
4045
- get variant() {
4046
- return this._options.variant;
4047
- }
4048
- set size(value) {
4049
- this._options.size = value;
4050
- this._scheduleRender();
4051
- }
4052
- get size() {
4053
- return this._options.size;
4054
- }
4055
- set pill(value) {
4056
- this._options.pill = value;
4057
- this._scheduleRender();
4058
- }
4059
- get pill() {
4060
- return this._options.pill ?? false;
4061
- }
4062
- set dot(value) {
4063
- this._options.dot = value;
4064
- this._scheduleRender();
4065
- }
4066
- get dot() {
4067
- return this._options.dot ?? false;
4068
- }
4069
- set removable(value) {
4070
- this._options.removable = value;
4071
- this._scheduleRender();
4072
- }
4073
- get removable() {
4074
- return this._options.removable ?? false;
4075
- }
4076
- set icon(value) {
4077
- this._options.icon = value;
4078
- this._scheduleRender();
4079
- }
4080
- get icon() {
4081
- return this._options.icon;
4082
- }
4083
- };
4084
- function registerFmcpBadge() {
4085
- if (typeof customElements !== "undefined" && !customElements.get("fmcp-badge")) {
4086
- customElements.define("fmcp-badge", FmcpBadge);
4087
- }
4088
- }
4089
-
4090
- // libs/ui/src/web-components/elements/fmcp-input.ts
4091
- var FmcpInput = class extends FmcpElement {
4092
- config = {
4093
- name: "input",
4094
- schema: InputOptionsSchema,
4095
- defaults: {
4096
- type: "text",
4097
- size: "md",
4098
- state: "default"
4099
- }
4100
- };
4101
- static get observedAttributes() {
4102
- return [
4103
- "name",
4104
- "type",
4105
- "id",
4106
- "value",
4107
- "placeholder",
4108
- "label",
4109
- "helper",
4110
- "error",
4111
- "size",
4112
- "state",
4113
- "required",
4114
- "disabled",
4115
- "readonly",
4116
- "autocomplete",
4117
- "pattern",
4118
- "min",
4119
- "max",
4120
- "step",
4121
- "class",
4122
- "icon-before",
4123
- "icon-after"
4124
- ];
4125
- }
4126
- renderHtml(options, _content) {
4127
- return input(options);
4128
- }
4129
- // ============================================
4130
- // Property Setters
4131
- // ============================================
4132
- set name(value) {
4133
- this._options.name = value;
4134
- this._scheduleRender();
4135
- }
4136
- get name() {
4137
- return this._options.name ?? "";
4138
- }
4139
- set type(value) {
4140
- this._options.type = value;
4141
- this._scheduleRender();
4142
- }
4143
- get type() {
4144
- return this._options.type;
4145
- }
4146
- set label(value) {
4147
- this._options.label = value;
4148
- this._scheduleRender();
4149
- }
4150
- get label() {
4151
- return this._options.label;
4152
- }
4153
- set placeholder(value) {
4154
- this._options.placeholder = value;
4155
- this._scheduleRender();
4156
- }
4157
- get placeholder() {
4158
- return this._options.placeholder;
4159
- }
4160
- set helper(value) {
4161
- this._options.helper = value;
4162
- this._scheduleRender();
4163
- }
4164
- get helper() {
4165
- return this._options.helper;
4166
- }
4167
- set error(value) {
4168
- this._options.error = value;
4169
- this._scheduleRender();
4170
- }
4171
- get error() {
4172
- return this._options.error;
4173
- }
4174
- set size(value) {
4175
- this._options.size = value;
4176
- this._scheduleRender();
4177
- }
4178
- get size() {
4179
- return this._options.size;
4180
- }
4181
- set state(value) {
4182
- this._options.state = value;
4183
- this._scheduleRender();
4184
- }
4185
- get state() {
4186
- return this._options.state;
4187
- }
4188
- set required(value) {
4189
- this._options.required = value;
4190
- this._scheduleRender();
4191
- }
4192
- get required() {
4193
- return this._options.required ?? false;
4194
- }
4195
- set disabled(value) {
4196
- this._options.disabled = value;
4197
- this._scheduleRender();
4198
- }
4199
- get disabled() {
4200
- return this._options.disabled ?? false;
4201
- }
4202
- set readonly(value) {
4203
- this._options.readonly = value;
4204
- this._scheduleRender();
4205
- }
4206
- get readonly() {
4207
- return this._options.readonly ?? false;
4208
- }
4209
- // ============================================
4210
- // Form Integration
4211
- // ============================================
4212
- connectedCallback() {
4213
- super.connectedCallback();
4214
- this.addEventListener("input", this._handleInput.bind(this));
4215
- this.addEventListener("change", this._handleChange.bind(this));
4216
- }
4217
- _handleInput(e) {
4218
- const inputEl = this.querySelector("input");
4219
- if (inputEl && (e.target === inputEl || inputEl.contains(e.target))) {
4220
- this.dispatchEvent(
4221
- new CustomEvent("fmcp:input", {
4222
- bubbles: true,
4223
- detail: { value: inputEl.value, name: this._options.name }
4224
- })
4225
- );
4226
- }
4227
- }
4228
- _handleChange(e) {
4229
- const inputEl = this.querySelector("input");
4230
- if (inputEl && (e.target === inputEl || inputEl.contains(e.target))) {
4231
- this.dispatchEvent(
4232
- new CustomEvent("fmcp:change", {
4233
- bubbles: true,
4234
- detail: { value: inputEl.value, name: this._options.name }
4235
- })
4236
- );
4237
- }
4238
- }
4239
- /**
4240
- * Get current input value.
4241
- */
4242
- get value() {
4243
- const inputEl = this.querySelector("input");
4244
- return inputEl?.value ?? this._options.value ?? "";
4245
- }
4246
- /**
4247
- * Set input value.
4248
- */
4249
- set value(val) {
4250
- const inputEl = this.querySelector("input");
4251
- if (inputEl) {
4252
- inputEl.value = val;
4253
- }
4254
- this._options.value = val;
4255
- }
4256
- /**
4257
- * Get validity state.
4258
- */
4259
- get validity() {
4260
- return this.querySelector("input")?.validity;
4261
- }
4262
- /**
4263
- * Check validity.
4264
- */
4265
- checkValidity() {
4266
- return this.querySelector("input")?.checkValidity() ?? true;
4267
- }
4268
- /**
4269
- * Report validity.
4270
- */
4271
- reportValidity() {
4272
- return this.querySelector("input")?.reportValidity() ?? true;
4273
- }
4274
- /**
4275
- * Focus the input.
4276
- */
4277
- focus() {
4278
- this.querySelector("input")?.focus();
4279
- }
4280
- /**
4281
- * Blur the input.
4282
- */
4283
- blur() {
4284
- this.querySelector("input")?.blur();
4285
- }
4286
- /**
4287
- * Select all text.
4288
- */
4289
- select() {
4290
- this.querySelector("input")?.select();
4291
- }
4292
- };
4293
- function registerFmcpInput() {
4294
- if (typeof customElements !== "undefined" && !customElements.get("fmcp-input")) {
4295
- customElements.define("fmcp-input", FmcpInput);
4296
- }
4297
- }
4298
-
4299
- // libs/ui/src/web-components/elements/fmcp-select.ts
4300
- var FmcpSelect = class extends FmcpElement {
4301
- config = {
4302
- name: "select",
4303
- schema: SelectOptionsSchema,
4304
- defaults: {
4305
- size: "md",
4306
- state: "default"
4307
- }
4308
- };
4309
- /** Select options stored separately since they're complex objects */
4310
- _selectOptions = [];
4311
- static get observedAttributes() {
4312
- return [
4313
- "name",
4314
- "id",
4315
- "value",
4316
- "placeholder",
4317
- "label",
4318
- "helper",
4319
- "error",
4320
- "size",
4321
- "state",
4322
- "required",
4323
- "disabled",
4324
- "multiple",
4325
- "class"
4326
- ];
4327
- }
4328
- renderHtml(options, _content) {
4329
- const mergedOptions = {
4330
- ...options,
4331
- options: this._selectOptions.length > 0 ? this._selectOptions : options.options
4332
- };
4333
- return select(mergedOptions);
4334
- }
4335
- // ============================================
4336
- // Property Setters
4337
- // ============================================
4338
- set name(value) {
4339
- this._options.name = value;
4340
- this._scheduleRender();
4341
- }
4342
- get name() {
4343
- return this._options.name ?? "";
4344
- }
4345
- set label(value) {
4346
- this._options.label = value;
4347
- this._scheduleRender();
4348
- }
4349
- get label() {
4350
- return this._options.label;
4351
- }
4352
- set placeholder(value) {
4353
- this._options.placeholder = value;
4354
- this._scheduleRender();
4355
- }
4356
- get placeholder() {
4357
- return this._options.placeholder;
4358
- }
4359
- set helper(value) {
4360
- this._options.helper = value;
4361
- this._scheduleRender();
4362
- }
4363
- get helper() {
4364
- return this._options.helper;
4365
- }
4366
- set error(value) {
4367
- this._options.error = value;
4368
- this._scheduleRender();
4369
- }
4370
- get error() {
4371
- return this._options.error;
4372
- }
4373
- set size(value) {
4374
- this._options.size = value;
4375
- this._scheduleRender();
4376
- }
4377
- get size() {
4378
- return this._options.size;
4379
- }
4380
- set state(value) {
4381
- this._options.state = value;
4382
- this._scheduleRender();
4383
- }
4384
- get state() {
4385
- return this._options.state;
4386
- }
4387
- set required(value) {
4388
- this._options.required = value;
4389
- this._scheduleRender();
4390
- }
4391
- get required() {
4392
- return this._options.required ?? false;
4393
- }
4394
- set disabled(value) {
4395
- this._options.disabled = value;
4396
- this._scheduleRender();
4397
- }
4398
- get disabled() {
4399
- return this._options.disabled ?? false;
4400
- }
4401
- set multiple(value) {
4402
- this._options.multiple = value;
4403
- this._scheduleRender();
4404
- }
4405
- get multiple() {
4406
- return this._options.multiple ?? false;
4407
- }
4408
- /**
4409
- * Set select options (array of { value, label, disabled?, selected? })
4410
- */
4411
- set selectOptions(value) {
4412
- this._selectOptions = value;
4413
- this._scheduleRender();
4414
- }
4415
- get selectOptions() {
4416
- return this._selectOptions;
4417
- }
4418
- // ============================================
4419
- // Form Integration
4420
- // ============================================
4421
- connectedCallback() {
4422
- super.connectedCallback();
4423
- this.addEventListener("change", this._handleChange.bind(this));
4424
- }
4425
- _handleChange(e) {
4426
- const selectEl = this.querySelector("select");
4427
- if (selectEl && (e.target === selectEl || selectEl.contains(e.target))) {
4428
- this.dispatchEvent(
4429
- new CustomEvent("fmcp:change", {
4430
- bubbles: true,
4431
- detail: {
4432
- value: selectEl.value,
4433
- name: this._options.name,
4434
- selectedOptions: Array.from(selectEl.selectedOptions).map((opt) => opt.value)
4435
- }
4436
- })
4437
- );
4438
- }
4439
- }
4440
- /**
4441
- * Get current select value.
4442
- */
4443
- get value() {
4444
- const selectEl = this.querySelector("select");
4445
- return selectEl?.value ?? this._options.value ?? "";
4446
- }
4447
- /**
4448
- * Set select value.
4449
- */
4450
- set value(val) {
4451
- const selectEl = this.querySelector("select");
4452
- if (selectEl) {
4453
- selectEl.value = val;
4454
- }
4455
- this._options.value = val;
4456
- }
4457
- /**
4458
- * Get selected options (for multiple select).
4459
- */
4460
- get selectedOptions() {
4461
- const selectEl = this.querySelector("select");
4462
- return selectEl ? Array.from(selectEl.selectedOptions).map((opt) => opt.value) : [];
4463
- }
4464
- /**
4465
- * Get validity state.
4466
- */
4467
- get validity() {
4468
- return this.querySelector("select")?.validity;
4469
- }
4470
- /**
4471
- * Check validity.
4472
- */
4473
- checkValidity() {
4474
- return this.querySelector("select")?.checkValidity() ?? true;
4475
- }
4476
- /**
4477
- * Report validity.
4478
- */
4479
- reportValidity() {
4480
- return this.querySelector("select")?.reportValidity() ?? true;
4481
- }
4482
- /**
4483
- * Focus the select.
4484
- */
4485
- focus() {
4486
- this.querySelector("select")?.focus();
4487
- }
4488
- /**
4489
- * Blur the select.
4490
- */
4491
- blur() {
4492
- this.querySelector("select")?.blur();
4493
- }
4494
- };
4495
- function registerFmcpSelect() {
4496
- if (typeof customElements !== "undefined" && !customElements.get("fmcp-select")) {
4497
- customElements.define("fmcp-select", FmcpSelect);
4498
- }
4499
- }
4500
-
4501
- // libs/ui/src/web-components/register.ts
4502
- function registerAllComponents() {
4503
- registerFmcpButton();
4504
- registerFmcpCard();
4505
- registerFmcpAlert();
4506
- registerFmcpBadge();
4507
- registerFmcpInput();
4508
- registerFmcpSelect();
4509
- }
4510
- if (typeof window !== "undefined" && typeof document !== "undefined") {
4511
- const script = document.currentScript;
4512
- if (script?.hasAttribute("data-auto-register")) {
4513
- registerAllComponents();
4514
- }
4515
- }
4516
-
4517
- // libs/ui/src/react/Card.tsx
4518
- var import_styles = require("@frontmcp/uipack/styles");
4519
-
4520
- // libs/ui/src/render/prerender.ts
4521
- async function renderToString(element) {
4522
- const { prerender } = await import("react-dom/static");
4523
- const { prelude } = await prerender(element);
4524
- const reader = prelude.getReader();
4525
- const chunks = [];
4526
- while (true) {
4527
- const { done, value } = await reader.read();
4528
- if (done) break;
4529
- if (value) chunks.push(value);
4530
- }
4531
- const totalLength = chunks.reduce((acc, chunk) => acc + chunk.length, 0);
4532
- const combined = new Uint8Array(totalLength);
4533
- let offset = 0;
4534
- for (const chunk of chunks) {
4535
- combined.set(chunk, offset);
4536
- offset += chunk.length;
4537
- }
4538
- return new TextDecoder().decode(combined);
4539
- }
4540
- function renderToStringSync(element) {
4541
- const ReactDOMServer = require("react-dom/server");
4542
- return ReactDOMServer.renderToStaticMarkup(element);
4543
- }
4544
-
4545
- // libs/ui/src/react/Card.tsx
4546
- var import_jsx_runtime = require("react/jsx-runtime");
4547
- function Card({
4548
- title,
4549
- subtitle,
4550
- headerActions,
4551
- footer,
4552
- variant = "default",
4553
- size = "md",
4554
- className,
4555
- id,
4556
- clickable,
4557
- href,
4558
- children
4559
- }) {
4560
- const variantClasses = (0, import_styles.getCardVariantClasses)(variant);
4561
- const sizeClasses = (0, import_styles.getCardSizeClasses)(size);
4562
- const clickableClasses = clickable ? "cursor-pointer hover:shadow-md transition-shadow" : "";
4563
- const allClasses = (0, import_styles.cn)(variantClasses, sizeClasses, clickableClasses, className);
4564
- const hasHeader = title || subtitle || headerActions;
4565
- const content = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
4566
- hasHeader && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-start justify-between mb-4", children: [
4567
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
4568
- title && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { className: "text-lg font-semibold text-text-primary", children: title }),
4569
- subtitle && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-sm text-text-secondary mt-1", children: subtitle })
4570
- ] }),
4571
- headerActions && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex items-center gap-2", children: headerActions })
4572
- ] }),
4573
- children,
4574
- footer && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "mt-4 pt-4 border-t border-divider", children: footer })
4575
- ] });
4576
- if (href) {
4577
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { href, className: allClasses, id, children: content });
4578
- }
4579
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: allClasses, id, children: content });
4580
- }
4581
- async function renderCard(props) {
4582
- const { children, headerActions, footer, ...rest } = props;
4583
- const element = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
4584
- Card,
4585
- {
4586
- ...rest,
4587
- headerActions: headerActions ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { dangerouslySetInnerHTML: { __html: headerActions } }) : void 0,
4588
- footer: footer ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { dangerouslySetInnerHTML: { __html: footer } }) : void 0,
4589
- children: children ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { dangerouslySetInnerHTML: { __html: children } }) : void 0
4590
- }
4591
- );
4592
- return renderToString(element);
4593
- }
4594
- function renderCardSync(props) {
4595
- const { children, headerActions, footer, ...rest } = props;
4596
- const element = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
4597
- Card,
4598
- {
4599
- ...rest,
4600
- headerActions: headerActions ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { dangerouslySetInnerHTML: { __html: headerActions } }) : void 0,
4601
- footer: footer ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { dangerouslySetInnerHTML: { __html: footer } }) : void 0,
4602
- children: children ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { dangerouslySetInnerHTML: { __html: children } }) : void 0
4603
- }
4604
- );
4605
- return renderToStringSync(element);
4606
- }
4607
-
4608
- // libs/ui/src/react/Badge.tsx
4609
- var import_styles2 = require("@frontmcp/uipack/styles");
4610
- var import_jsx_runtime2 = require("react/jsx-runtime");
4611
- function Badge({
4612
- variant = "default",
4613
- size = "md",
4614
- pill = false,
4615
- icon,
4616
- dot = false,
4617
- className,
4618
- removable = false,
4619
- onRemove,
4620
- children
4621
- }) {
4622
- if (dot) {
4623
- const dotClasses = (0, import_styles2.cn)(
4624
- "inline-block rounded-full",
4625
- (0, import_styles2.getBadgeDotSizeClasses)(size),
4626
- (0, import_styles2.getBadgeDotVariantClasses)(variant),
4627
- className
4628
- );
4629
- const label = typeof children === "string" ? children : void 0;
4630
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: dotClasses, "aria-label": label, title: label });
4631
- }
4632
- const variantClasses = (0, import_styles2.getBadgeVariantClasses)(variant);
4633
- const sizeClasses = (0, import_styles2.getBadgeSizeClasses)(size);
4634
- const baseClasses = (0, import_styles2.cn)(
4635
- "inline-flex items-center font-medium",
4636
- pill ? "rounded-full" : "rounded-md",
4637
- variantClasses,
4638
- sizeClasses,
4639
- className
4640
- );
4641
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: baseClasses, children: [
4642
- icon && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "mr-1", children: icon }),
4643
- children,
4644
- removable && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
4645
- "button",
4646
- {
4647
- type: "button",
4648
- className: "ml-1.5 -mr-1 hover:opacity-70 transition-opacity",
4649
- "aria-label": "Remove",
4650
- onClick: onRemove,
4651
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M6 18L18 6M6 6l12 12" }) })
4652
- }
4653
- )
4654
- ] });
4655
- }
4656
- async function renderBadge(props) {
4657
- const { children, icon, ...rest } = props;
4658
- const element = /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Badge, { ...rest, icon: icon ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { dangerouslySetInnerHTML: { __html: icon } }) : void 0, children });
4659
- return renderToString(element);
4660
- }
4661
- function renderBadgeSync(props) {
4662
- const { children, icon, ...rest } = props;
4663
- const element = /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Badge, { ...rest, icon: icon ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { dangerouslySetInnerHTML: { __html: icon } }) : void 0, children });
4664
- return renderToStringSync(element);
4665
- }
4666
-
4667
- // libs/ui/src/react/Button.tsx
4668
- var import_styles3 = require("@frontmcp/uipack/styles");
4669
- var import_jsx_runtime3 = require("react/jsx-runtime");
4670
- function Button({
4671
- variant = "primary",
4672
- size = "md",
4673
- disabled = false,
4674
- loading = false,
4675
- fullWidth = false,
4676
- iconPosition = "left",
4677
- icon,
4678
- iconOnly = false,
4679
- type = "button",
4680
- className,
4681
- onClick,
4682
- children
4683
- }) {
4684
- const variantClasses = (0, import_styles3.getButtonVariantClasses)(variant);
4685
- const sizeClasses = (0, import_styles3.getButtonSizeClasses)(size, iconOnly);
4686
- const disabledClasses = disabled || loading ? "opacity-50 cursor-not-allowed" : "";
4687
- const widthClasses = fullWidth ? "w-full" : "";
4688
- const allClasses = (0, import_styles3.cn)(import_styles3.BUTTON_BASE_CLASSES, variantClasses, sizeClasses, disabledClasses, widthClasses, className);
4689
- const iconElement = icon && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: iconPosition === "left" ? "mr-2" : "ml-2", children: icon });
4690
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("button", { type, className: allClasses, disabled: disabled || loading, onClick, children: [
4691
- loading && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "mr-2", dangerouslySetInnerHTML: { __html: import_styles3.LOADING_SPINNER } }),
4692
- !loading && icon && iconPosition === "left" && iconElement,
4693
- !iconOnly && children,
4694
- !loading && icon && iconPosition === "right" && iconElement
4695
- ] });
4696
- }
4697
- async function renderButton(props) {
4698
- const { children, icon, ...rest } = props;
4699
- const element = /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Button, { ...rest, icon: icon ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { dangerouslySetInnerHTML: { __html: icon } }) : void 0, children });
4700
- return renderToString(element);
4701
- }
4702
- function renderButtonSync(props) {
4703
- const { children, icon, ...rest } = props;
4704
- const element = /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Button, { ...rest, icon: icon ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { dangerouslySetInnerHTML: { __html: icon } }) : void 0, children });
4705
- return renderToStringSync(element);
4706
- }
4707
-
4708
- // libs/ui/src/react/Alert.tsx
4709
- var import_styles4 = require("@frontmcp/uipack/styles");
4710
- var import_jsx_runtime4 = require("react/jsx-runtime");
4711
- function Alert({
4712
- variant = "info",
4713
- title,
4714
- icon,
4715
- showIcon = true,
4716
- dismissible = false,
4717
- onDismiss,
4718
- className,
4719
- children
4720
- }) {
4721
- const variantStyles = (0, import_styles4.getAlertVariantClasses)(variant);
4722
- const allClasses = (0, import_styles4.cn)(import_styles4.ALERT_BASE_CLASSES, variantStyles.container, className);
4723
- const iconContent = icon || (showIcon ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
4724
- "span",
4725
- {
4726
- className: (0, import_styles4.cn)("flex-shrink-0", variantStyles.icon),
4727
- dangerouslySetInnerHTML: { __html: import_styles4.ALERT_ICONS[variant] }
4728
- }
4729
- ) : null);
4730
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: allClasses, role: "alert", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex", children: [
4731
- iconContent && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex-shrink-0 mr-3", children: iconContent }),
4732
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex-1", children: [
4733
- title && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h4", { className: "font-semibold mb-1", children: title }),
4734
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "text-sm", children })
4735
- ] }),
4736
- dismissible && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
4737
- "button",
4738
- {
4739
- type: "button",
4740
- className: "flex-shrink-0 ml-3 hover:opacity-70 transition-opacity",
4741
- "aria-label": "Dismiss",
4742
- onClick: onDismiss,
4743
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { dangerouslySetInnerHTML: { __html: import_styles4.CLOSE_ICON } })
4744
- }
4745
- )
4746
- ] }) });
4747
- }
4748
- async function renderAlert(props) {
4749
- const { children, icon, ...rest } = props;
4750
- const element = /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Alert, { ...rest, icon: icon ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { dangerouslySetInnerHTML: { __html: icon } }) : void 0, children });
4751
- return renderToString(element);
4752
- }
4753
- function renderAlertSync(props) {
4754
- const { children, icon, ...rest } = props;
4755
- const element = /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Alert, { ...rest, icon: icon ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { dangerouslySetInnerHTML: { __html: icon } }) : void 0, children });
4756
- return renderToStringSync(element);
4757
- }
4758
-
4759
- // libs/ui/src/react/hooks/context.tsx
4760
- var import_react = require("react");
4761
- var import_jsx_runtime5 = require("react/jsx-runtime");
4762
- var McpBridgeContext = (0, import_react.createContext)(null);
4763
- function McpBridgeProvider({ children, config, onReady, onError }) {
4764
- const [bridge, setBridge] = (0, import_react.useState)(null);
4765
- const [loading, setLoading] = (0, import_react.useState)(true);
4766
- const [error, setError] = (0, import_react.useState)(null);
4767
- (0, import_react.useEffect)(() => {
4768
- let mounted = true;
4769
- let bridgeInstance = null;
4770
- const initBridge = async () => {
4771
- try {
4772
- bridgeInstance = new FrontMcpBridge(config);
4773
- await bridgeInstance.initialize();
4774
- if (mounted) {
4775
- setBridge(bridgeInstance);
4776
- setLoading(false);
4777
- onReady?.(bridgeInstance);
4778
- }
4779
- } catch (err) {
4780
- if (mounted) {
4781
- const error2 = err instanceof Error ? err : new Error(String(err));
4782
- setError(error2);
4783
- setLoading(false);
4784
- onError?.(error2);
4785
- }
4786
- }
4787
- };
4788
- initBridge();
4789
- return () => {
4790
- mounted = false;
4791
- if (bridgeInstance) {
4792
- bridgeInstance.dispose();
4793
- }
4794
- };
4795
- }, [config, onReady, onError]);
4796
- const contextValue = (0, import_react.useMemo)(
4797
- () => ({
4798
- bridge,
4799
- loading,
4800
- error,
4801
- ready: !loading && !error && bridge !== null,
4802
- adapterId: bridge?.adapterId,
4803
- capabilities: bridge?.capabilities
4804
- }),
4805
- [bridge, loading, error]
4806
- );
4807
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(McpBridgeContext.Provider, { value: contextValue, children });
4808
- }
4809
- var SSR_DEFAULT_CONTEXT = {
4810
- bridge: null,
4811
- loading: false,
4812
- error: null,
4813
- ready: false,
4814
- adapterId: void 0,
4815
- capabilities: void 0
4816
- };
4817
- function useMcpBridgeContext() {
4818
- const context = (0, import_react.useContext)(McpBridgeContext);
4819
- if (!context) {
4820
- return SSR_DEFAULT_CONTEXT;
4821
- }
4822
- return context;
646
+ var SSR_DEFAULT_CONTEXT = {
647
+ bridge: null,
648
+ loading: false,
649
+ error: null,
650
+ ready: false,
651
+ adapterId: void 0,
652
+ capabilities: void 0
653
+ };
654
+ function useMcpBridgeContext() {
655
+ const context = (0, import_react.useContext)(McpBridgeContext);
656
+ if (!context) {
657
+ return SSR_DEFAULT_CONTEXT;
658
+ }
659
+ return context;
4823
660
  }
4824
661
  function useMcpBridge() {
4825
662
  const { bridge } = useMcpBridgeContext();
@@ -5102,583 +939,3 @@ function useOpenLink() {
5102
939
  [bridge]
5103
940
  );
5104
941
  }
5105
-
5106
- // libs/ui/src/renderers/react.renderer.ts
5107
- var import_renderers = require("@frontmcp/uipack/renderers");
5108
- var VALID_JS_IDENTIFIER = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
5109
- function isValidComponentName(name) {
5110
- return VALID_JS_IDENTIFIER.test(name);
5111
- }
5112
- function sanitizeComponentName(name) {
5113
- if (isValidComponentName(name)) {
5114
- return name;
5115
- }
5116
- const sanitized = name.replace(/[^a-zA-Z0-9_$]/g, "_").replace(/^[0-9]/, "_$&");
5117
- return sanitized || "Component";
5118
- }
5119
- var REACT_CDN = {
5120
- react: "https://esm.sh/react@19",
5121
- reactDom: "https://esm.sh/react-dom@19/client"
5122
- };
5123
- var INLINE_REACT_PLACEHOLDER = `
5124
- // React runtime not available inline yet.
5125
- // For blocked-network platforms, use pre-rendered HTML templates.
5126
- console.warn('[FrontMCP] React hydration not available on this platform.');
5127
- `;
5128
- var ReactRenderer = class {
5129
- type = "react";
5130
- priority = 20;
5131
- // Higher priority than HTML
5132
- /**
5133
- * Check if this renderer can handle the given template.
5134
- *
5135
- * Accepts:
5136
- * - React component functions (imported, already transpiled)
5137
- * - Strings containing JSX syntax
5138
- */
5139
- canHandle(template) {
5140
- if (typeof template === "function" && (0, import_renderers.isReactComponent)(template)) {
5141
- return true;
5142
- }
5143
- if (typeof template === "string" && (0, import_renderers.containsJsx)(template)) {
5144
- return true;
5145
- }
5146
- return false;
5147
- }
5148
- /**
5149
- * Transpile the template if needed.
5150
- *
5151
- * For imported React components, no transpilation is needed.
5152
- * For JSX strings, SWC transpilation is performed.
5153
- */
5154
- async transpile(template, options) {
5155
- if (typeof template === "function") {
5156
- const hash = (0, import_renderers.hashString)(template.toString());
5157
- return {
5158
- code: "",
5159
- // No transpiled code for already-compiled components
5160
- hash,
5161
- cached: true
5162
- };
5163
- }
5164
- if (typeof template === "string") {
5165
- return (0, import_renderers.transpileJsx)(template, {
5166
- development: options?.sourceMaps ?? false
5167
- });
5168
- }
5169
- throw new Error("Invalid template type for ReactRenderer");
5170
- }
5171
- /**
5172
- * Render the template to HTML for client-side rendering.
5173
- *
5174
- * Unlike SSR, this method generates HTML that will be rendered
5175
- * client-side by React in the browser. No server-side React required.
5176
- *
5177
- * The generated HTML includes:
5178
- * - A container div for the React root
5179
- * - The component code (transpiled if needed)
5180
- * - Props embedded as a data attribute
5181
- * - A render script that initializes the component
5182
- */
5183
- async render(template, context, _options) {
5184
- const props = {
5185
- input: context.input,
5186
- output: context.output,
5187
- structuredContent: context.structuredContent,
5188
- helpers: context.helpers
5189
- };
5190
- const escapedProps = JSON.stringify(props).replace(/&/g, "&amp;").replace(/'/g, "&#39;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
5191
- const rootId = `frontmcp-react-${(0, import_renderers.hashString)(Date.now().toString()).slice(0, 8)}`;
5192
- let componentCode;
5193
- let componentName;
5194
- if (typeof template === "function") {
5195
- const rawName = template.name || "Component";
5196
- componentName = sanitizeComponentName(rawName);
5197
- componentCode = `
5198
- // Component should be registered via window.__frontmcp_components['${componentName}']
5199
- (function() {
5200
- if (!window.__frontmcp_components || !window.__frontmcp_components['${componentName}']) {
5201
- console.error('[FrontMCP] Component "${componentName}" not registered. Use buildHydrationScript() to register components.');
5202
- }
5203
- })();
5204
- `;
5205
- } else if (typeof template === "string") {
5206
- const transpiled = await this.transpile(template);
5207
- const match = transpiled.code.match(/function\s+(\w+)/);
5208
- const rawName = match?.[1] || "Widget";
5209
- componentName = sanitizeComponentName(rawName);
5210
- componentCode = transpiled.code;
5211
- } else {
5212
- throw new Error("Invalid template type for ReactRenderer");
5213
- }
5214
- const html = `
5215
- <div id="${rootId}" data-frontmcp-react data-component="${componentName}" data-props='${escapedProps}'>
5216
- <div class="flex items-center justify-center p-4 text-gray-500">
5217
- <svg class="animate-spin h-5 w-5 mr-2" viewBox="0 0 24 24">
5218
- <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" fill="none"></circle>
5219
- <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>
5220
- </svg>
5221
- Loading...
5222
- </div>
5223
- </div>
5224
- <script type="module">
5225
- (function() {
5226
- ${componentCode}
5227
-
5228
- // Wait for React to be available
5229
- function waitForReact(callback, maxAttempts) {
5230
- var attempts = 0;
5231
- var check = function() {
5232
- if (typeof React !== 'undefined' && typeof ReactDOM !== 'undefined') {
5233
- callback();
5234
- } else if (attempts < maxAttempts) {
5235
- attempts++;
5236
- setTimeout(check, 50);
5237
- } else {
5238
- console.error('[FrontMCP] React not loaded after ' + maxAttempts + ' attempts');
5239
- }
5240
- };
5241
- check();
5242
- }
5243
-
5244
- waitForReact(function() {
5245
- try {
5246
- var root = document.getElementById('${rootId}');
5247
- if (!root) return;
5248
-
5249
- var propsJson = root.getAttribute('data-props');
5250
- var props = propsJson ? JSON.parse(propsJson.replace(/&amp;/g, '&').replace(/&#39;/g, "'").replace(/&lt;/g, '<').replace(/&gt;/g, '>')) : {};
5251
-
5252
- // Get the component
5253
- var Component = ${componentName};
5254
-
5255
- // Check if it's registered globally
5256
- if (typeof Component === 'undefined' && window.__frontmcp_components) {
5257
- Component = window.__frontmcp_components['${componentName}'];
5258
- }
5259
-
5260
- if (typeof Component === 'function') {
5261
- var element = React.createElement(Component, props);
5262
- var reactRoot = ReactDOM.createRoot(root);
5263
- reactRoot.render(element);
5264
- } else {
5265
- console.error('[FrontMCP] Component "${componentName}" not found');
5266
- }
5267
- } catch (err) {
5268
- console.error('[FrontMCP] React render error:', err);
5269
- }
5270
- }, 100);
5271
- })();
5272
- </script>
5273
- `;
5274
- return html.trim();
5275
- }
5276
- /**
5277
- * Get runtime scripts for client-side functionality.
5278
- */
5279
- getRuntimeScripts(platform) {
5280
- if (platform.networkMode === "blocked") {
5281
- return {
5282
- headScripts: "",
5283
- inlineScripts: INLINE_REACT_PLACEHOLDER,
5284
- isInline: true
5285
- };
5286
- }
5287
- return {
5288
- headScripts: `
5289
- <script crossorigin src="${REACT_CDN.react}"></script>
5290
- <script crossorigin src="${REACT_CDN.reactDom}"></script>
5291
- `,
5292
- isInline: false
5293
- };
5294
- }
5295
- };
5296
- var reactRenderer = new ReactRenderer();
5297
-
5298
- // libs/ui/src/renderers/react.adapter.ts
5299
- var mountedRoots = /* @__PURE__ */ new WeakMap();
5300
- var ReactRendererAdapter = class {
5301
- type = "react";
5302
- // Lazy-loaded React runtime
5303
- react = null;
5304
- reactDOM = null;
5305
- loadPromise = null;
5306
- /**
5307
- * Check if this adapter can handle the given content.
5308
- */
5309
- canHandle(content) {
5310
- if (typeof content === "function") {
5311
- return true;
5312
- }
5313
- if (typeof content === "string") {
5314
- if (content.includes("React.createElement") || content.includes("jsx(") || content.includes("jsxs(")) {
5315
- return true;
5316
- }
5317
- const funcIndex = content.indexOf("function");
5318
- if (funcIndex !== -1) {
5319
- const afterFunc = content.slice(funcIndex, Math.min(funcIndex + 2e3, content.length));
5320
- if (afterFunc.includes("return") && afterFunc.includes("<")) {
5321
- return true;
5322
- }
5323
- }
5324
- return false;
5325
- }
5326
- return false;
5327
- }
5328
- /**
5329
- * Render React component to a string.
5330
- * This is a client-side fallback - SSR should be done at build time.
5331
- */
5332
- async render(content, context, _options) {
5333
- return `<div data-frontmcp-react data-tool="${context.toolName}">${content}</div>`;
5334
- }
5335
- /**
5336
- * Render React component directly to the DOM.
5337
- */
5338
- async renderToDOM(content, target, context, options) {
5339
- try {
5340
- await this.ensureReactLoaded();
5341
- if (!this.react || !this.reactDOM) {
5342
- throw new Error("React runtime not available");
5343
- }
5344
- const componentName = target.getAttribute("data-component");
5345
- const component = this.getComponent(componentName, content);
5346
- if (!component) {
5347
- target.innerHTML = content;
5348
- return { success: true };
5349
- }
5350
- const element = this.react.createElement(component, {
5351
- input: context.input,
5352
- output: context.output,
5353
- structuredContent: context.structuredContent,
5354
- toolName: context.toolName
5355
- });
5356
- if (options?.hydrate && this.reactDOM.hydrateRoot) {
5357
- const root = this.reactDOM.hydrateRoot(target, element);
5358
- mountedRoots.set(target, root);
5359
- } else if (this.reactDOM.createRoot) {
5360
- const root = this.reactDOM.createRoot(target);
5361
- root.render(element);
5362
- mountedRoots.set(target, root);
5363
- } else if (this.reactDOM.render) {
5364
- this.reactDOM.render(element, target);
5365
- mountedRoots.set(target, {
5366
- unmount: () => this.reactDOM?.unmountComponentAtNode?.(target)
5367
- });
5368
- } else {
5369
- throw new Error("No suitable React render method available");
5370
- }
5371
- target.dispatchEvent(
5372
- new CustomEvent("frontmcp:rendered", {
5373
- bubbles: true,
5374
- detail: { type: "react", toolName: context.toolName }
5375
- })
5376
- );
5377
- return { success: true };
5378
- } catch (error) {
5379
- const message = error instanceof Error ? error.message : String(error);
5380
- console.error("[FrontMCP] React render failed:", message);
5381
- return { success: false, error: message };
5382
- }
5383
- }
5384
- /**
5385
- * Hydrate existing SSR content with React.
5386
- */
5387
- async hydrate(target, context, options) {
5388
- return this.renderToDOM("", target, context, { ...options, hydrate: true });
5389
- }
5390
- /**
5391
- * Update rendered React component with new data.
5392
- */
5393
- async update(target, context) {
5394
- try {
5395
- await this.ensureReactLoaded();
5396
- if (!this.react) {
5397
- throw new Error("React runtime not available");
5398
- }
5399
- const existingRoot = mountedRoots.get(target);
5400
- const componentName = target.getAttribute("data-component");
5401
- const component = this.getComponent(componentName, "");
5402
- if (!component) {
5403
- return { success: false, error: "No component found for update" };
5404
- }
5405
- const element = this.react.createElement(component, {
5406
- input: context.input,
5407
- output: context.output,
5408
- structuredContent: context.structuredContent,
5409
- toolName: context.toolName
5410
- });
5411
- if (existingRoot && "render" in existingRoot) {
5412
- existingRoot.render(element);
5413
- return { success: true };
5414
- }
5415
- return this.renderToDOM("", target, context);
5416
- } catch (error) {
5417
- const message = error instanceof Error ? error.message : String(error);
5418
- console.error("[FrontMCP] React update failed:", message);
5419
- return { success: false, error: message };
5420
- }
5421
- }
5422
- /**
5423
- * Clean up React root.
5424
- */
5425
- destroy(target) {
5426
- const root = mountedRoots.get(target);
5427
- if (root) {
5428
- root.unmount();
5429
- mountedRoots.delete(target);
5430
- }
5431
- }
5432
- /**
5433
- * Ensure React is loaded.
5434
- */
5435
- async ensureReactLoaded() {
5436
- if (this.react && this.reactDOM) {
5437
- return;
5438
- }
5439
- if (this.loadPromise) {
5440
- return this.loadPromise;
5441
- }
5442
- this.loadPromise = this.loadReact();
5443
- return this.loadPromise;
5444
- }
5445
- /**
5446
- * Load React runtime.
5447
- */
5448
- async loadReact() {
5449
- const win = typeof window !== "undefined" ? window : globalThis;
5450
- if (win.React) {
5451
- this.react = win.React;
5452
- }
5453
- if (win.ReactDOM) {
5454
- this.reactDOM = win.ReactDOM;
5455
- }
5456
- if (this.react && this.reactDOM) {
5457
- return;
5458
- }
5459
- try {
5460
- if (!this.react) {
5461
- const reactModule = await import(
5462
- /* webpackIgnore: true */
5463
- "react"
5464
- );
5465
- this.react = reactModule.default || reactModule;
5466
- }
5467
- if (!this.reactDOM) {
5468
- const reactDOMModule = await import(
5469
- /* webpackIgnore: true */
5470
- "react-dom/client"
5471
- );
5472
- this.reactDOM = reactDOMModule.default || reactDOMModule;
5473
- }
5474
- } catch {
5475
- if (!this.react || !this.reactDOM) {
5476
- console.warn("[FrontMCP] React runtime not available. Ensure React is loaded via CDN or bundled.");
5477
- }
5478
- }
5479
- }
5480
- /**
5481
- * Get a React component by name or from content.
5482
- */
5483
- getComponent(componentName, content) {
5484
- const win = typeof window !== "undefined" ? window : globalThis;
5485
- if (componentName && win.__frontmcp_components) {
5486
- const registered = win.__frontmcp_components?.[componentName];
5487
- if (registered) {
5488
- return registered;
5489
- }
5490
- }
5491
- if (content && typeof content === "function") {
5492
- return content;
5493
- }
5494
- return null;
5495
- }
5496
- };
5497
- function createReactAdapter() {
5498
- return new ReactRendererAdapter();
5499
- }
5500
- async function loadReactAdapter() {
5501
- return createReactAdapter();
5502
- }
5503
- // Annotate the CommonJS export names for ESM import in node:
5504
- 0 && (module.exports = {
5505
- ActionItemSchema,
5506
- ActionListOptionsSchema,
5507
- AdapterRegistry,
5508
- Alert,
5509
- AlertOptionsSchema,
5510
- AlertVariantSchema,
5511
- AvatarGroupOptionsSchema,
5512
- AvatarOptionsSchema,
5513
- AvatarShapeSchema,
5514
- AvatarSizeSchema,
5515
- AvatarSpacingSchema,
5516
- AvatarStatusSchema,
5517
- AvatarWithTextOptionsSchema,
5518
- BRIDGE_SCRIPT_TAGS,
5519
- Badge,
5520
- BadgeGroupOptionsSchema,
5521
- BadgeOptionsSchema,
5522
- BadgeSizeSchema,
5523
- BadgeVariantSchema,
5524
- Button,
5525
- ButtonGroupOptionsSchema,
5526
- ButtonOptionsSchema,
5527
- ButtonSizeSchema,
5528
- ButtonVariantSchema,
5529
- Card,
5530
- CardGroupOptionsSchema,
5531
- CardOptionsSchema,
5532
- CardSizeSchema,
5533
- CardVariantSchema,
5534
- CheckboxOptionsSchema,
5535
- ConfirmModalOptionsSchema,
5536
- ConfirmModalVariantSchema,
5537
- DescriptionItemSchema,
5538
- DescriptionListOptionsSchema,
5539
- DrawerOptionsSchema,
5540
- DrawerPositionSchema,
5541
- FeatureItemSchema,
5542
- FeatureListOptionsSchema,
5543
- FmcpAlert,
5544
- FmcpBadge,
5545
- FmcpButton,
5546
- FmcpCard,
5547
- FmcpElement,
5548
- FmcpInput,
5549
- FmcpSelect,
5550
- FormActionsOptionsSchema,
5551
- FormEnctypeSchema,
5552
- FormMethodSchema,
5553
- FormOptionsSchema,
5554
- FormRowOptionsSchema,
5555
- FormSectionOptionsSchema,
5556
- FrontMcpBridge,
5557
- InputOptionsSchema,
5558
- InputSizeSchema,
5559
- InputStateSchema,
5560
- InputTypeSchema,
5561
- McpBridgeProvider,
5562
- ModalOptionsSchema,
5563
- ModalSizeSchema,
5564
- ModalTriggerOptionsSchema,
5565
- PaginationOptionsSchema,
5566
- PermissionItemSchema,
5567
- PermissionListOptionsSchema,
5568
- RadioGroupOptionsSchema,
5569
- RadioOptionItemSchema,
5570
- ReactRenderer,
5571
- ReactRendererAdapter,
5572
- SelectOptionItemSchema,
5573
- SelectOptionsSchema,
5574
- TableAlignSchema,
5575
- TableColumnSchema,
5576
- TableOptionsSchema,
5577
- TableSortDirectionSchema,
5578
- TextareaOptionsSchema,
5579
- TextareaResizeSchema,
5580
- ToastOptionsSchema,
5581
- ToastPositionSchema,
5582
- UNIVERSAL_BRIDGE_SCRIPT,
5583
- actionList,
5584
- activeBadge,
5585
- alert,
5586
- authLayout,
5587
- authLayoutBuilder,
5588
- avatar,
5589
- avatarGroup,
5590
- avatarWithText,
5591
- awayDot,
5592
- badge,
5593
- badgeGroup,
5594
- baseLayout,
5595
- betaBadge,
5596
- busyDot,
5597
- button,
5598
- buttonGroup,
5599
- card,
5600
- cardGroup,
5601
- checkbox,
5602
- confirmModal,
5603
- consentLayout,
5604
- consentLayoutBuilder,
5605
- createBridge,
5606
- createLayoutBuilder,
5607
- createReactAdapter,
5608
- csrfInput,
5609
- dangerAlert,
5610
- dangerButton,
5611
- defaultRegistry,
5612
- descriptionList,
5613
- drawer,
5614
- errorBadge,
5615
- errorLayout,
5616
- errorLayoutBuilder,
5617
- escapeHtml,
5618
- featureList,
5619
- form,
5620
- formActions,
5621
- formRow,
5622
- formSection,
5623
- generateBridgeIIFE,
5624
- generatePlatformBundle,
5625
- ghostButton,
5626
- hiddenInput,
5627
- inactiveBadge,
5628
- infoAlert,
5629
- input,
5630
- linkButton,
5631
- loadReactAdapter,
5632
- loadingLayout,
5633
- modal,
5634
- modalTrigger,
5635
- newBadge,
5636
- offlineDot,
5637
- onlineDot,
5638
- outlineButton,
5639
- pagination,
5640
- pendingBadge,
5641
- permissionList,
5642
- primaryButton,
5643
- radioGroup,
5644
- reactRenderer,
5645
- registerAdapter,
5646
- registerAllComponents,
5647
- registerFmcpAlert,
5648
- registerFmcpBadge,
5649
- registerFmcpButton,
5650
- registerFmcpCard,
5651
- registerFmcpInput,
5652
- registerFmcpSelect,
5653
- renderAlert,
5654
- renderAlertSync,
5655
- renderBadge,
5656
- renderBadgeSync,
5657
- renderButton,
5658
- renderButtonSync,
5659
- renderCard,
5660
- renderCardSync,
5661
- secondaryButton,
5662
- select,
5663
- successAlert,
5664
- successLayout,
5665
- table,
5666
- textarea,
5667
- toast,
5668
- toastContainer,
5669
- useCallTool,
5670
- useCapability,
5671
- useDisplayMode,
5672
- useHostContext,
5673
- useMcpBridge,
5674
- useMcpBridgeContext,
5675
- useOpenLink,
5676
- useSendMessage,
5677
- useStructuredContent,
5678
- useTheme,
5679
- useToolCalls,
5680
- useToolInput,
5681
- useToolOutput,
5682
- warningAlert,
5683
- widgetLayout
5684
- });