@seed-ship/mcp-ui-solid 6.23.0 → 6.25.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 (172) hide show
  1. package/CHANGELOG.md +167 -0
  2. package/README.md +154 -2
  3. package/dist/components/ActionGroupRenderer.cjs +6 -6
  4. package/dist/components/ActionGroupRenderer.cjs.map +1 -1
  5. package/dist/components/ActionGroupRenderer.js +6 -6
  6. package/dist/components/ActionGroupRenderer.js.map +1 -1
  7. package/dist/components/AutocompleteDropdown.cjs +6 -6
  8. package/dist/components/AutocompleteDropdown.cjs.map +1 -1
  9. package/dist/components/AutocompleteDropdown.js +6 -6
  10. package/dist/components/AutocompleteDropdown.js.map +1 -1
  11. package/dist/components/AutocompleteFormField.cjs +6 -5
  12. package/dist/components/AutocompleteFormField.cjs.map +1 -1
  13. package/dist/components/AutocompleteFormField.d.ts.map +1 -1
  14. package/dist/components/AutocompleteFormField.js +6 -5
  15. package/dist/components/AutocompleteFormField.js.map +1 -1
  16. package/dist/components/ChartJSRenderer.cjs +406 -70
  17. package/dist/components/ChartJSRenderer.cjs.map +1 -1
  18. package/dist/components/ChartJSRenderer.d.ts.map +1 -1
  19. package/dist/components/ChartJSRenderer.js +407 -71
  20. package/dist/components/ChartJSRenderer.js.map +1 -1
  21. package/dist/components/ChatPrompt.cjs +5 -5
  22. package/dist/components/ChatPrompt.cjs.map +1 -1
  23. package/dist/components/ChatPrompt.js +5 -5
  24. package/dist/components/ChatPrompt.js.map +1 -1
  25. package/dist/components/ComponentToolbar.cjs +5 -5
  26. package/dist/components/ComponentToolbar.cjs.map +1 -1
  27. package/dist/components/ComponentToolbar.js +5 -5
  28. package/dist/components/ComponentToolbar.js.map +1 -1
  29. package/dist/components/DegradedFallback.cjs +35 -3
  30. package/dist/components/DegradedFallback.cjs.map +1 -1
  31. package/dist/components/DegradedFallback.d.ts +7 -0
  32. package/dist/components/DegradedFallback.d.ts.map +1 -1
  33. package/dist/components/DegradedFallback.js +35 -3
  34. package/dist/components/DegradedFallback.js.map +1 -1
  35. package/dist/components/ExpandableWrapper.cjs +10 -7
  36. package/dist/components/ExpandableWrapper.cjs.map +1 -1
  37. package/dist/components/ExpandableWrapper.d.ts.map +1 -1
  38. package/dist/components/ExpandableWrapper.js +10 -7
  39. package/dist/components/ExpandableWrapper.js.map +1 -1
  40. package/dist/components/FormFieldRenderer.cjs +13 -12
  41. package/dist/components/FormFieldRenderer.cjs.map +1 -1
  42. package/dist/components/FormFieldRenderer.d.ts.map +1 -1
  43. package/dist/components/FormFieldRenderer.js +13 -12
  44. package/dist/components/FormFieldRenderer.js.map +1 -1
  45. package/dist/components/FormRenderer.cjs +1 -1
  46. package/dist/components/FormRenderer.cjs.map +1 -1
  47. package/dist/components/FormRenderer.js +1 -1
  48. package/dist/components/FormRenderer.js.map +1 -1
  49. package/dist/components/GenerativeUIErrorBoundary.cjs +1 -1
  50. package/dist/components/GenerativeUIErrorBoundary.cjs.map +1 -1
  51. package/dist/components/GenerativeUIErrorBoundary.js +1 -1
  52. package/dist/components/GenerativeUIErrorBoundary.js.map +1 -1
  53. package/dist/components/GhostText.cjs +2 -2
  54. package/dist/components/GhostText.cjs.map +1 -1
  55. package/dist/components/GhostText.js +2 -2
  56. package/dist/components/GhostText.js.map +1 -1
  57. package/dist/components/GraphRenderer.cjs +100 -29
  58. package/dist/components/GraphRenderer.cjs.map +1 -1
  59. package/dist/components/GraphRenderer.d.ts +1 -1
  60. package/dist/components/GraphRenderer.d.ts.map +1 -1
  61. package/dist/components/GraphRenderer.js +100 -29
  62. package/dist/components/GraphRenderer.js.map +1 -1
  63. package/dist/components/MissingValue.cjs +43 -0
  64. package/dist/components/MissingValue.cjs.map +1 -0
  65. package/dist/components/MissingValue.d.ts +27 -0
  66. package/dist/components/MissingValue.d.ts.map +1 -0
  67. package/dist/components/MissingValue.js +43 -0
  68. package/dist/components/MissingValue.js.map +1 -0
  69. package/dist/components/ModalRenderer.cjs +39 -31
  70. package/dist/components/ModalRenderer.cjs.map +1 -1
  71. package/dist/components/ModalRenderer.d.ts.map +1 -1
  72. package/dist/components/ModalRenderer.js +40 -32
  73. package/dist/components/ModalRenderer.js.map +1 -1
  74. package/dist/components/PortalDropdownMenu.cjs +6 -3
  75. package/dist/components/PortalDropdownMenu.cjs.map +1 -1
  76. package/dist/components/PortalDropdownMenu.d.ts.map +1 -1
  77. package/dist/components/PortalDropdownMenu.js +7 -4
  78. package/dist/components/PortalDropdownMenu.js.map +1 -1
  79. package/dist/components/ScratchpadPanel.cjs +38 -44
  80. package/dist/components/ScratchpadPanel.cjs.map +1 -1
  81. package/dist/components/ScratchpadPanel.d.ts.map +1 -1
  82. package/dist/components/ScratchpadPanel.js +38 -44
  83. package/dist/components/ScratchpadPanel.js.map +1 -1
  84. package/dist/components/UIResourceRenderer.cjs +255 -217
  85. package/dist/components/UIResourceRenderer.cjs.map +1 -1
  86. package/dist/components/UIResourceRenderer.d.ts.map +1 -1
  87. package/dist/components/UIResourceRenderer.js +255 -217
  88. package/dist/components/UIResourceRenderer.js.map +1 -1
  89. package/dist/components/chart-data-table.cjs +30 -5
  90. package/dist/components/chart-data-table.cjs.map +1 -1
  91. package/dist/components/chart-data-table.d.ts +18 -1
  92. package/dist/components/chart-data-table.d.ts.map +1 -1
  93. package/dist/components/chart-data-table.js +30 -5
  94. package/dist/components/chart-data-table.js.map +1 -1
  95. package/dist/components/chart-missing-plugin.cjs +194 -0
  96. package/dist/components/chart-missing-plugin.cjs.map +1 -0
  97. package/dist/components/chart-missing-plugin.d.ts +129 -0
  98. package/dist/components/chart-missing-plugin.d.ts.map +1 -0
  99. package/dist/components/chart-missing-plugin.js +194 -0
  100. package/dist/components/chart-missing-plugin.js.map +1 -0
  101. package/dist/context/MCPUIStringsContext.cjs +12 -1
  102. package/dist/context/MCPUIStringsContext.cjs.map +1 -1
  103. package/dist/context/MCPUIStringsContext.d.ts +62 -0
  104. package/dist/context/MCPUIStringsContext.d.ts.map +1 -1
  105. package/dist/context/MCPUIStringsContext.js +12 -1
  106. package/dist/context/MCPUIStringsContext.js.map +1 -1
  107. package/dist/services/component-registry.cjs +9 -2
  108. package/dist/services/component-registry.cjs.map +1 -1
  109. package/dist/services/component-registry.d.ts.map +1 -1
  110. package/dist/services/component-registry.js +9 -2
  111. package/dist/services/component-registry.js.map +1 -1
  112. package/dist/services/validation.cjs +31 -8
  113. package/dist/services/validation.cjs.map +1 -1
  114. package/dist/services/validation.d.ts.map +1 -1
  115. package/dist/services/validation.js +31 -8
  116. package/dist/services/validation.js.map +1 -1
  117. package/dist/types/index.d.ts +14 -2
  118. package/dist/types/index.d.ts.map +1 -1
  119. package/dist/utils/degraded-projections.cjs +19 -3
  120. package/dist/utils/degraded-projections.cjs.map +1 -1
  121. package/dist/utils/degraded-projections.d.ts +22 -2
  122. package/dist/utils/degraded-projections.d.ts.map +1 -1
  123. package/dist/utils/degraded-projections.js +19 -3
  124. package/dist/utils/degraded-projections.js.map +1 -1
  125. package/dist/utils/math-markdown.cjs +1 -1
  126. package/dist/utils/math-markdown.cjs.map +1 -1
  127. package/dist/utils/math-markdown.js +1 -1
  128. package/dist/utils/math-markdown.js.map +1 -1
  129. package/dist/utils/missing-value.cjs +60 -0
  130. package/dist/utils/missing-value.cjs.map +1 -0
  131. package/dist/utils/missing-value.d.ts +79 -0
  132. package/dist/utils/missing-value.d.ts.map +1 -0
  133. package/dist/utils/missing-value.js +60 -0
  134. package/dist/utils/missing-value.js.map +1 -0
  135. package/dist/utils/theme.cjs +91 -0
  136. package/dist/utils/theme.cjs.map +1 -0
  137. package/dist/utils/theme.d.ts +11 -0
  138. package/dist/utils/theme.d.ts.map +1 -0
  139. package/dist/utils/theme.js +91 -0
  140. package/dist/utils/theme.js.map +1 -0
  141. package/docs/SECURITY-DEPENDENCIES.md +81 -0
  142. package/docs/THEMING.md +205 -0
  143. package/package.json +7 -5
  144. package/src/components/ActionGroupRenderer.tsx +6 -6
  145. package/src/components/AutocompleteDropdown.tsx +17 -17
  146. package/src/components/AutocompleteFormField.tsx +10 -9
  147. package/src/components/ChartJSRenderer.tsx +609 -212
  148. package/src/components/ChatPrompt.tsx +16 -16
  149. package/src/components/ComponentToolbar.tsx +5 -5
  150. package/src/components/DegradedFallback.tsx +33 -11
  151. package/src/components/ExpandableWrapper.tsx +15 -11
  152. package/src/components/FormFieldRenderer.tsx +52 -51
  153. package/src/components/FormRenderer.tsx +12 -12
  154. package/src/components/GenerativeUIErrorBoundary.tsx +6 -6
  155. package/src/components/GhostText.tsx +7 -7
  156. package/src/components/GraphRenderer.tsx +83 -67
  157. package/src/components/MissingValue.tsx +61 -0
  158. package/src/components/ModalRenderer.tsx +11 -5
  159. package/src/components/PortalDropdownMenu.tsx +6 -2
  160. package/src/components/ScratchpadPanel.tsx +144 -141
  161. package/src/components/UIResourceRenderer.tsx +143 -110
  162. package/src/components/chart-data-table.ts +50 -6
  163. package/src/components/chart-missing-plugin.ts +336 -0
  164. package/src/context/MCPUIStringsContext.tsx +76 -0
  165. package/src/services/component-registry.ts +10 -2
  166. package/src/services/validation.ts +44 -9
  167. package/src/styles/autocomplete.css +53 -53
  168. package/src/types/index.ts +13 -1
  169. package/src/utils/degraded-projections.ts +44 -4
  170. package/src/utils/math-markdown.ts +1 -1
  171. package/src/utils/missing-value.ts +127 -0
  172. package/src/utils/theme.ts +101 -0
@@ -1,7 +1,8 @@
1
- import { createComponent, Portal, getNextElement, getNextMarker, insert, effect, setAttribute, runHydrationEvents, className, style, template, delegateEvents } from "solid-js/web";
1
+ import { getNextElement, createComponent, Portal, getNextMarker, use, insert, effect, setAttribute, runHydrationEvents, className, style, template, delegateEvents } from "solid-js/web";
2
2
  import { createSignal, createEffect, onCleanup, Show } from "solid-js";
3
+ import { bindPortalTheme } from "../utils/theme.js";
3
4
  import { useMCPUIStrings } from "../context/MCPUIStringsContext.js";
4
- var _tmpl$ = /* @__PURE__ */ template(`<h2 id=modal-title class="text-lg font-semibold text-gray-900 dark:text-white">`), _tmpl$2 = /* @__PURE__ */ template(`<div>`), _tmpl$3 = /* @__PURE__ */ template(`<button class="p-1 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"><svg class="w-5 h-5"fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M6 18L18 6M6 6l12 12">`), _tmpl$4 = /* @__PURE__ */ template(`<div class="flex items-center justify-between p-4 border-b border-gray-200 dark:border-gray-700"><!$><!/><!$><!/><!$><!/>`), _tmpl$5 = /* @__PURE__ */ template(`<div class="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/50 backdrop-blur-sm"role=dialog aria-modal=true tabindex=-1 style="animation:modal-fade-in 0.15s ease-out"><div style="animation:modal-scale-in 0.15s ease-out"><!$><!/><div class=p-4>`), _tmpl$6 = /* @__PURE__ */ template(`<style>
5
+ var _tmpl$ = /* @__PURE__ */ template(`<span hidden aria-hidden=true>`), _tmpl$2 = /* @__PURE__ */ template(`<h2 id=modal-title class="text-lg font-semibold text-[color:var(--mcp-ui-fg,var(--color-gray-900,#111827))] dark:text-[color:var(--mcp-ui-fg,var(--color-white,#fff))]">`), _tmpl$3 = /* @__PURE__ */ template(`<div>`), _tmpl$4 = /* @__PURE__ */ template(`<button class="p-1 text-[color:var(--mcp-ui-fg-subtle,var(--color-gray-400,#9ca3af))] hover:text-[color:var(--mcp-ui-fg-muted,var(--color-gray-600,#4b5563))] dark:hover:text-[color:var(--mcp-ui-fg,var(--color-gray-300,#d1d5db))] rounded-full hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-100,#f3f4f6))] dark:hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-700,#374151))] transition-colors"><svg class="w-5 h-5"fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2 d="M6 18L18 6M6 6l12 12">`), _tmpl$5 = /* @__PURE__ */ template(`<div class="flex items-center justify-between p-4 border-b border-[color:var(--mcp-ui-border,var(--color-gray-200,#e5e7eb))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-700,#374151))]"><!$><!/><!$><!/><!$><!/>`), _tmpl$6 = /* @__PURE__ */ template(`<div class="mcp-ui-root fixed inset-0 z-50 flex items-center justify-center p-4 bg-[color:var(--mcp-ui-overlay,color-mix(in_oklab,var(--color-black,#000)_50%,transparent))] backdrop-blur-sm"role=dialog aria-modal=true tabindex=-1 style="animation:modal-fade-in 0.15s ease-out"><div style="animation:modal-scale-in 0.15s ease-out"><!$><!/><div class=p-4>`), _tmpl$7 = /* @__PURE__ */ template(`<style>
5
6
  @keyframes modal-fade-in {
6
7
  from { opacity: 0; }
7
8
  to { opacity: 1; }
@@ -14,6 +15,7 @@ var _tmpl$ = /* @__PURE__ */ template(`<h2 id=modal-title class="text-lg font-se
14
15
  const ModalRenderer = (props) => {
15
16
  const strings = useMCPUIStrings();
16
17
  const [isVisible, setIsVisible] = createSignal(false);
18
+ let themeAnchor;
17
19
  const params = () => {
18
20
  var _a;
19
21
  return props.params || ((_a = props.component) == null ? void 0 : _a.params) || {};
@@ -80,7 +82,12 @@ const ModalRenderer = (props) => {
80
82
  return "max-w-2xl";
81
83
  }
82
84
  };
83
- return createComponent(Show, {
85
+ return [(() => {
86
+ var _el$ = getNextElement(_tmpl$);
87
+ var _ref$ = themeAnchor;
88
+ typeof _ref$ === "function" ? use(_ref$, _el$) : themeAnchor = _el$;
89
+ return _el$;
90
+ })(), createComponent(Show, {
84
91
  get when() {
85
92
  return isVisible();
86
93
  },
@@ -88,62 +95,63 @@ const ModalRenderer = (props) => {
88
95
  return createComponent(Portal, {
89
96
  get children() {
90
97
  return [(() => {
91
- var _el$ = getNextElement(_tmpl$5), _el$2 = _el$.firstChild, _el$12 = _el$2.firstChild, [_el$13, _co$4] = getNextMarker(_el$12.nextSibling), _el$11 = _el$13.nextSibling;
92
- _el$.$$click = handleBackdropClick;
93
- _el$2.$$click = (e) => e.stopPropagation();
94
- insert(_el$2, createComponent(Show, {
98
+ var _el$2 = getNextElement(_tmpl$6), _el$3 = _el$2.firstChild, _el$13 = _el$3.firstChild, [_el$14, _co$4] = getNextMarker(_el$13.nextSibling), _el$12 = _el$14.nextSibling;
99
+ _el$2.$$click = handleBackdropClick;
100
+ use((element) => bindPortalTheme(element, () => themeAnchor), _el$2);
101
+ _el$3.$$click = (e) => e.stopPropagation();
102
+ insert(_el$3, createComponent(Show, {
95
103
  get when() {
96
104
  var _a, _b;
97
105
  return ((_a = params()) == null ? void 0 : _a.title) || ((_b = params()) == null ? void 0 : _b.showClose) !== false;
98
106
  },
99
107
  get children() {
100
- var _el$3 = getNextElement(_tmpl$4), _el$7 = _el$3.firstChild, [_el$8, _co$] = getNextMarker(_el$7.nextSibling), _el$9 = _el$8.nextSibling, [_el$0, _co$2] = getNextMarker(_el$9.nextSibling), _el$1 = _el$0.nextSibling, [_el$10, _co$3] = getNextMarker(_el$1.nextSibling);
101
- insert(_el$3, createComponent(Show, {
108
+ var _el$4 = getNextElement(_tmpl$5), _el$8 = _el$4.firstChild, [_el$9, _co$] = getNextMarker(_el$8.nextSibling), _el$0 = _el$9.nextSibling, [_el$1, _co$2] = getNextMarker(_el$0.nextSibling), _el$10 = _el$1.nextSibling, [_el$11, _co$3] = getNextMarker(_el$10.nextSibling);
109
+ insert(_el$4, createComponent(Show, {
102
110
  get when() {
103
111
  var _a;
104
112
  return (_a = params()) == null ? void 0 : _a.title;
105
113
  },
106
114
  get children() {
107
- var _el$4 = getNextElement(_tmpl$);
108
- insert(_el$4, () => params().title);
109
- return _el$4;
115
+ var _el$5 = getNextElement(_tmpl$2);
116
+ insert(_el$5, () => params().title);
117
+ return _el$5;
110
118
  }
111
- }), _el$8, _co$);
112
- insert(_el$3, createComponent(Show, {
119
+ }), _el$9, _co$);
120
+ insert(_el$4, createComponent(Show, {
113
121
  get when() {
114
122
  var _a;
115
123
  return !((_a = params()) == null ? void 0 : _a.title);
116
124
  },
117
125
  get children() {
118
- return getNextElement(_tmpl$2);
126
+ return getNextElement(_tmpl$3);
119
127
  }
120
- }), _el$0, _co$2);
121
- insert(_el$3, createComponent(Show, {
128
+ }), _el$1, _co$2);
129
+ insert(_el$4, createComponent(Show, {
122
130
  get when() {
123
131
  var _a;
124
132
  return ((_a = params()) == null ? void 0 : _a.showClose) !== false;
125
133
  },
126
134
  get children() {
127
- var _el$6 = getNextElement(_tmpl$3);
128
- _el$6.$$click = handleClose;
129
- effect(() => setAttribute(_el$6, "aria-label", strings.modalClose));
135
+ var _el$7 = getNextElement(_tmpl$4);
136
+ _el$7.$$click = handleClose;
137
+ effect(() => setAttribute(_el$7, "aria-label", strings.modalClose));
130
138
  runHydrationEvents();
131
- return _el$6;
139
+ return _el$7;
132
140
  }
133
- }), _el$10, _co$3);
134
- return _el$3;
141
+ }), _el$11, _co$3);
142
+ return _el$4;
135
143
  }
136
- }), _el$13, _co$4);
137
- insert(_el$11, () => props.children);
144
+ }), _el$14, _co$4);
145
+ insert(_el$12, () => props.children);
138
146
  effect((_p$) => {
139
147
  var _a, _b;
140
- var _v$ = ((_a = params()) == null ? void 0 : _a.title) ? "modal-title" : void 0, _v$2 = `relative w-full ${sizeClass()} bg-white dark:bg-gray-800 rounded-lg shadow-xl`, _v$3 = ((_b = params()) == null ? void 0 : _b.maxHeight) ? {
148
+ var _v$ = ((_a = params()) == null ? void 0 : _a.title) ? "modal-title" : void 0, _v$2 = `relative w-full ${sizeClass()} bg-[color:var(--mcp-ui-surface,var(--color-white,#fff))] dark:bg-[color:var(--mcp-ui-surface,var(--color-gray-800,#1f2937))] rounded-lg shadow-[var(--mcp-ui-shadow,var(--shadow-xl))]`, _v$3 = ((_b = params()) == null ? void 0 : _b.maxHeight) ? {
141
149
  "max-height": params().maxHeight,
142
150
  "overflow-y": "auto"
143
151
  } : {};
144
- _v$ !== _p$.e && setAttribute(_el$, "aria-labelledby", _p$.e = _v$);
145
- _v$2 !== _p$.t && className(_el$2, _p$.t = _v$2);
146
- _p$.a = style(_el$11, _v$3, _p$.a);
152
+ _v$ !== _p$.e && setAttribute(_el$2, "aria-labelledby", _p$.e = _v$);
153
+ _v$2 !== _p$.t && className(_el$3, _p$.t = _v$2);
154
+ _p$.a = style(_el$12, _v$3, _p$.a);
147
155
  return _p$;
148
156
  }, {
149
157
  e: void 0,
@@ -151,12 +159,12 @@ const ModalRenderer = (props) => {
151
159
  a: void 0
152
160
  });
153
161
  runHydrationEvents();
154
- return _el$;
155
- })(), getNextElement(_tmpl$6)];
162
+ return _el$2;
163
+ })(), getNextElement(_tmpl$7)];
156
164
  }
157
165
  });
158
166
  }
159
- });
167
+ })];
160
168
  };
161
169
  delegateEvents(["click"]);
162
170
  export {
@@ -1 +1 @@
1
- {"version":3,"file":"ModalRenderer.js","sources":["../../src/components/ModalRenderer.tsx"],"sourcesContent":["/**\n * ModalRenderer - Dialog overlay component\n * Sprint 3: UX Improvements\n */\n\nimport { Component, Show, createSignal, createEffect, onCleanup, JSX } from 'solid-js'\nimport { Portal } from 'solid-js/web'\nimport type { UIComponent, ModalComponentParams } from '../types'\nimport { useMCPUIStrings } from '../context/MCPUIStringsContext'\n\nexport interface ModalRendererProps {\n /**\n * UIComponent with modal params (for declarative use)\n */\n component?: UIComponent\n\n /**\n * Direct modal params (alternative to component)\n */\n params?: ModalComponentParams\n\n /**\n * External open state control\n */\n isOpen?: boolean\n\n /**\n * Callback when modal is closed\n */\n onClose?: () => void\n\n /**\n * Modal content (preferred for programmatic use)\n */\n children?: JSX.Element\n}\n\n/**\n * Modal/Dialog overlay component with Portal rendering\n *\n * @example Programmatic usage\n * ```tsx\n * function MyComponent() {\n * const { isOpen, open, close } = useModal()\n *\n * return (\n * <>\n * <button onClick={open}>Open Modal</button>\n * <ModalRenderer\n * isOpen={isOpen()}\n * onClose={close}\n * params={{ title: 'My Modal', size: 'md' }}\n * >\n * <p>Modal content here</p>\n * </ModalRenderer>\n * </>\n * )\n * }\n * ```\n *\n * @example Declarative usage\n * ```tsx\n * const modalComponent: UIComponent = {\n * id: 'details-modal',\n * type: 'modal',\n * position: { colStart: 1, colSpan: 12 },\n * params: {\n * title: 'User Details',\n * size: 'lg',\n * },\n * }\n * <ModalRenderer component={modalComponent} isOpen={true} onClose={close} />\n * ```\n */\nexport const ModalRenderer: Component<ModalRendererProps> = (props) => {\n const strings = useMCPUIStrings()\n const [isVisible, setIsVisible] = createSignal(false)\n\n const params = () => props.params || (props.component?.params as ModalComponentParams) || {}\n\n // Sync with external isOpen prop\n createEffect(() => {\n if (props.isOpen !== undefined) {\n setIsVisible(props.isOpen)\n }\n })\n\n // Handle escape key\n createEffect(() => {\n if (!isVisible()) return\n\n const handleEscape = (e: KeyboardEvent) => {\n if (e.key === 'Escape' && params()?.closeOnEscape !== false) {\n handleClose()\n }\n }\n\n document.addEventListener('keydown', handleEscape)\n onCleanup(() => document.removeEventListener('keydown', handleEscape))\n })\n\n // Prevent body scroll when modal is open\n createEffect(() => {\n if (isVisible()) {\n document.body.style.overflow = 'hidden'\n } else {\n document.body.style.overflow = ''\n }\n onCleanup(() => {\n document.body.style.overflow = ''\n })\n })\n\n // Focus trap - focus the modal when it opens\n createEffect(() => {\n if (isVisible()) {\n // Small delay to ensure the modal is rendered\n setTimeout(() => {\n const modal = document.querySelector('[role=\"dialog\"]')\n if (modal instanceof HTMLElement) {\n modal.focus()\n }\n }, 10)\n }\n })\n\n const handleClose = () => {\n setIsVisible(false)\n props.onClose?.()\n }\n\n const handleBackdropClick = (e: MouseEvent) => {\n if (e.target === e.currentTarget && params()?.closeOnBackdrop !== false) {\n handleClose()\n }\n }\n\n const sizeClass = () => {\n switch (params()?.size) {\n case 'sm':\n return 'max-w-md'\n case 'lg':\n return 'max-w-4xl'\n case 'xl':\n return 'max-w-6xl'\n case 'full':\n return 'max-w-full mx-4'\n default: // md\n return 'max-w-2xl'\n }\n }\n\n return (\n <Show when={isVisible()}>\n <Portal>\n {/* Backdrop */}\n <div\n class=\"fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/50 backdrop-blur-sm\"\n style={{ animation: 'modal-fade-in 0.15s ease-out' }}\n onClick={handleBackdropClick}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={params()?.title ? 'modal-title' : undefined}\n tabIndex={-1}\n >\n {/* Modal container */}\n <div\n class={`relative w-full ${sizeClass()} bg-white dark:bg-gray-800 rounded-lg shadow-xl`}\n style={{ animation: 'modal-scale-in 0.15s ease-out' }}\n onClick={(e) => e.stopPropagation()}\n >\n {/* Header */}\n <Show when={params()?.title || params()?.showClose !== false}>\n <div class=\"flex items-center justify-between p-4 border-b border-gray-200 dark:border-gray-700\">\n <Show when={params()?.title}>\n <h2\n id=\"modal-title\"\n class=\"text-lg font-semibold text-gray-900 dark:text-white\"\n >\n {params()!.title}\n </h2>\n </Show>\n <Show when={!params()?.title}>\n <div />\n </Show>\n <Show when={params()?.showClose !== false}>\n <button\n onClick={handleClose}\n class=\"p-1 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors\"\n aria-label={strings.modalClose}\n >\n <svg\n class=\"w-5 h-5\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n </Show>\n </div>\n </Show>\n\n {/* Content */}\n <div\n class=\"p-4\"\n style={params()?.maxHeight ? { 'max-height': params()!.maxHeight, 'overflow-y': 'auto' } : {}}\n >\n {props.children}\n </div>\n </div>\n </div>\n\n {/* CSS Animations */}\n <style>{`\n @keyframes modal-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n @keyframes modal-scale-in {\n from { opacity: 0; transform: scale(0.95); }\n to { opacity: 1; transform: scale(1); }\n }\n `}</style>\n </Portal>\n </Show>\n )\n}\n"],"names":["ModalRenderer","props","strings","useMCPUIStrings","isVisible","setIsVisible","createSignal","params","component","createEffect","isOpen","undefined","handleEscape","e","key","closeOnEscape","handleClose","document","addEventListener","onCleanup","removeEventListener","body","style","overflow","setTimeout","modal","querySelector","HTMLElement","focus","onClose","handleBackdropClick","target","currentTarget","closeOnBackdrop","sizeClass","size","_$createComponent","Show","when","children","Portal","_el$","_$getNextElement","_tmpl$5","_el$2","firstChild","_el$12","_el$13","_co$4","_$getNextMarker","nextSibling","_el$11","$$click","stopPropagation","_$insert","title","showClose","_el$3","_tmpl$4","_el$7","_el$8","_co$","_el$9","_el$0","_co$2","_el$1","_el$10","_co$3","_el$4","_tmpl$","_tmpl$2","_el$6","_tmpl$3","_$effect","_$setAttribute","modalClose","_$runHydrationEvents","_p$","_v$","_v$2","_v$3","maxHeight","t","_$className","a","_$style","_tmpl$6","_$delegateEvents"],"mappings":"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"}
1
+ {"version":3,"file":"ModalRenderer.js","sources":["../../src/components/ModalRenderer.tsx"],"sourcesContent":["/**\n * ModalRenderer - Dialog overlay component\n * Sprint 3: UX Improvements\n */\n\nimport { Component, Show, createSignal, createEffect, onCleanup, JSX } from 'solid-js'\nimport { Portal } from 'solid-js/web'\nimport { bindPortalTheme } from '../utils/theme'\nimport type { UIComponent, ModalComponentParams } from '../types'\nimport { useMCPUIStrings } from '../context/MCPUIStringsContext'\n\nexport interface ModalRendererProps {\n /**\n * UIComponent with modal params (for declarative use)\n */\n component?: UIComponent\n\n /**\n * Direct modal params (alternative to component)\n */\n params?: ModalComponentParams\n\n /**\n * External open state control\n */\n isOpen?: boolean\n\n /**\n * Callback when modal is closed\n */\n onClose?: () => void\n\n /**\n * Modal content (preferred for programmatic use)\n */\n children?: JSX.Element\n}\n\n/**\n * Modal/Dialog overlay component with Portal rendering\n *\n * @example Programmatic usage\n * ```tsx\n * function MyComponent() {\n * const { isOpen, open, close } = useModal()\n *\n * return (\n * <>\n * <button onClick={open}>Open Modal</button>\n * <ModalRenderer\n * isOpen={isOpen()}\n * onClose={close}\n * params={{ title: 'My Modal', size: 'md' }}\n * >\n * <p>Modal content here</p>\n * </ModalRenderer>\n * </>\n * )\n * }\n * ```\n *\n * @example Declarative usage\n * ```tsx\n * const modalComponent: UIComponent = {\n * id: 'details-modal',\n * type: 'modal',\n * position: { colStart: 1, colSpan: 12 },\n * params: {\n * title: 'User Details',\n * size: 'lg',\n * },\n * }\n * <ModalRenderer component={modalComponent} isOpen={true} onClose={close} />\n * ```\n */\nexport const ModalRenderer: Component<ModalRendererProps> = (props) => {\n const strings = useMCPUIStrings()\n const [isVisible, setIsVisible] = createSignal(false)\n let themeAnchor: HTMLSpanElement | undefined\n\n const params = () => props.params || (props.component?.params as ModalComponentParams) || {}\n\n // Sync with external isOpen prop\n createEffect(() => {\n if (props.isOpen !== undefined) {\n setIsVisible(props.isOpen)\n }\n })\n\n // Handle escape key\n createEffect(() => {\n if (!isVisible()) return\n\n const handleEscape = (e: KeyboardEvent) => {\n if (e.key === 'Escape' && params()?.closeOnEscape !== false) {\n handleClose()\n }\n }\n\n document.addEventListener('keydown', handleEscape)\n onCleanup(() => document.removeEventListener('keydown', handleEscape))\n })\n\n // Prevent body scroll when modal is open\n createEffect(() => {\n if (isVisible()) {\n document.body.style.overflow = 'hidden'\n } else {\n document.body.style.overflow = ''\n }\n onCleanup(() => {\n document.body.style.overflow = ''\n })\n })\n\n // Focus trap - focus the modal when it opens\n createEffect(() => {\n if (isVisible()) {\n // Small delay to ensure the modal is rendered\n setTimeout(() => {\n const modal = document.querySelector('[role=\"dialog\"]')\n if (modal instanceof HTMLElement) {\n modal.focus()\n }\n }, 10)\n }\n })\n\n const handleClose = () => {\n setIsVisible(false)\n props.onClose?.()\n }\n\n const handleBackdropClick = (e: MouseEvent) => {\n if (e.target === e.currentTarget && params()?.closeOnBackdrop !== false) {\n handleClose()\n }\n }\n\n const sizeClass = () => {\n switch (params()?.size) {\n case 'sm':\n return 'max-w-md'\n case 'lg':\n return 'max-w-4xl'\n case 'xl':\n return 'max-w-6xl'\n case 'full':\n return 'max-w-full mx-4'\n default: // md\n return 'max-w-2xl'\n }\n }\n\n return (\n <>\n <span hidden aria-hidden=\"true\" ref={themeAnchor} />\n <Show when={isVisible()}>\n <Portal>\n {/* Backdrop */}\n <div\n ref={(element) => bindPortalTheme(element, () => themeAnchor)}\n class=\"mcp-ui-root fixed inset-0 z-50 flex items-center justify-center p-4 bg-[color:var(--mcp-ui-overlay,color-mix(in_oklab,var(--color-black,#000)_50%,transparent))] backdrop-blur-sm\"\n style={{ animation: 'modal-fade-in 0.15s ease-out' }}\n onClick={handleBackdropClick}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={params()?.title ? 'modal-title' : undefined}\n tabIndex={-1}\n >\n {/* Modal container */}\n <div\n class={`relative w-full ${sizeClass()} bg-[color:var(--mcp-ui-surface,var(--color-white,#fff))] dark:bg-[color:var(--mcp-ui-surface,var(--color-gray-800,#1f2937))] rounded-lg shadow-[var(--mcp-ui-shadow,var(--shadow-xl))]`}\n style={{ animation: 'modal-scale-in 0.15s ease-out' }}\n onClick={(e) => e.stopPropagation()}\n >\n {/* Header */}\n <Show when={params()?.title || params()?.showClose !== false}>\n <div class=\"flex items-center justify-between p-4 border-b border-[color:var(--mcp-ui-border,var(--color-gray-200,#e5e7eb))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-700,#374151))]\">\n <Show when={params()?.title}>\n <h2\n id=\"modal-title\"\n class=\"text-lg font-semibold text-[color:var(--mcp-ui-fg,var(--color-gray-900,#111827))] dark:text-[color:var(--mcp-ui-fg,var(--color-white,#fff))]\"\n >\n {params()!.title}\n </h2>\n </Show>\n <Show when={!params()?.title}>\n <div />\n </Show>\n <Show when={params()?.showClose !== false}>\n <button\n onClick={handleClose}\n class=\"p-1 text-[color:var(--mcp-ui-fg-subtle,var(--color-gray-400,#9ca3af))] hover:text-[color:var(--mcp-ui-fg-muted,var(--color-gray-600,#4b5563))] dark:hover:text-[color:var(--mcp-ui-fg,var(--color-gray-300,#d1d5db))] rounded-full hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-100,#f3f4f6))] dark:hover:bg-[color:var(--mcp-ui-surface-hover,var(--color-gray-700,#374151))] transition-colors\"\n aria-label={strings.modalClose}\n >\n <svg\n class=\"w-5 h-5\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n </Show>\n </div>\n </Show>\n\n {/* Content */}\n <div\n class=\"p-4\"\n style={params()?.maxHeight ? { 'max-height': params()!.maxHeight, 'overflow-y': 'auto' } : {}}\n >\n {props.children}\n </div>\n </div>\n </div>\n\n {/* CSS Animations */}\n <style>{`\n @keyframes modal-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n @keyframes modal-scale-in {\n from { opacity: 0; transform: scale(0.95); }\n to { opacity: 1; transform: scale(1); }\n }\n `}</style>\n </Portal>\n </Show>\n </>\n )\n}\n"],"names":["ModalRenderer","props","strings","useMCPUIStrings","isVisible","setIsVisible","createSignal","themeAnchor","params","component","createEffect","isOpen","undefined","handleEscape","e","key","closeOnEscape","handleClose","document","addEventListener","onCleanup","removeEventListener","body","style","overflow","setTimeout","modal","querySelector","HTMLElement","focus","onClose","handleBackdropClick","target","currentTarget","closeOnBackdrop","sizeClass","size","_el$","_$getNextElement","_tmpl$","_ref$","_$use","_$createComponent","Show","when","children","Portal","_el$2","_tmpl$6","_el$3","firstChild","_el$13","_el$14","_co$4","_$getNextMarker","nextSibling","_el$12","$$click","element","bindPortalTheme","stopPropagation","_$insert","title","showClose","_el$4","_tmpl$5","_el$8","_el$9","_co$","_el$0","_el$1","_co$2","_el$10","_el$11","_co$3","_el$5","_tmpl$2","_tmpl$3","_el$7","_tmpl$4","_$effect","_$setAttribute","modalClose","_$runHydrationEvents","_p$","_v$","_v$2","_v$3","maxHeight","t","_$className","a","_$style","_tmpl$7","_$delegateEvents"],"mappings":"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"}
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const web = require("solid-js/web");
4
4
  const solidJs = require("solid-js");
5
+ const theme = require("../utils/theme.cjs");
5
6
  var _tmpl$ = /* @__PURE__ */ web.template(`<div role=menu data-mcp-ui-portal=menu style=position:fixed;z-index:9999>`);
6
7
  const PortalDropdownMenu = (props) => {
7
8
  const [position, setPosition] = solidJs.createSignal({
@@ -56,11 +57,13 @@ const PortalDropdownMenu = (props) => {
56
57
  return web.createComponent(web.Portal, {
57
58
  get children() {
58
59
  var _el$ = web.getNextElement(_tmpl$);
59
- var _ref$ = menuRef;
60
- typeof _ref$ === "function" ? web.use(_ref$, _el$) : menuRef = _el$;
60
+ web.use((element) => {
61
+ menuRef = element;
62
+ theme.bindPortalTheme(element, () => props.trigger);
63
+ }, _el$);
61
64
  web.insert(_el$, () => props.children);
62
65
  web.effect((_p$) => {
63
- var _v$ = `${position().top}px`, _v$2 = `${position().left}px`, _v$3 = `${props.width ?? 144}px`, _v$4 = `bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded-lg shadow-lg py-1 text-sm ${props.class ?? ""}`;
66
+ var _v$ = `${position().top}px`, _v$2 = `${position().left}px`, _v$3 = `${props.width ?? 144}px`, _v$4 = `mcp-ui-root bg-[color:var(--mcp-ui-surface,var(--color-white,#fff))] dark:bg-[color:var(--mcp-ui-surface,var(--color-gray-800,#1f2937))] border border-[color:var(--mcp-ui-border,var(--color-gray-200,#e5e7eb))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-600,#4b5563))] rounded-lg shadow-[var(--mcp-ui-shadow,var(--shadow-lg))] py-1 text-sm ${props.class ?? ""}`;
64
67
  _v$ !== _p$.e && web.setStyleProperty(_el$, "top", _p$.e = _v$);
65
68
  _v$2 !== _p$.t && web.setStyleProperty(_el$, "left", _p$.t = _v$2);
66
69
  _v$3 !== _p$.a && web.setStyleProperty(_el$, "width", _p$.a = _v$3);
@@ -1 +1 @@
1
- {"version":3,"file":"PortalDropdownMenu.cjs","sources":["../../src/components/PortalDropdownMenu.tsx"],"sourcesContent":["/**\n * PortalDropdownMenu (v6.4.0) — generic dropdown that mounts via\n * `<Portal>` on `document.body` instead of an in-tree `position: absolute`\n * sibling. Eliminates two pain points around the legacy in-tree pattern :\n *\n * 1. **`overflow: hidden` clipping** — when the trigger lives inside a\n * chat bubble or a card with `overflow: hidden`, an absolutely\n * positioned menu sibling gets clipped at the ancestor's boundary.\n * Mounting on `document.body` escapes the clip stack entirely.\n * 2. **`z-index` wars** — chat surfaces stack composer / message rails\n * above the message list, and ancestor `z-index` creates a new\n * stacking context that captures the in-tree menu. A portal is a\n * sibling of the document, so a single `z-index: 9999` wins.\n *\n * The menu is positioned with `position: fixed` from the trigger's\n * `getBoundingClientRect()`. We re-measure on `scroll` (capture phase, so\n * nested scrollables also fire) and `resize` to keep the menu pinned\n * while the user interacts with surrounding chrome.\n *\n * Close affordances : click outside, Escape, programmatic via `onClose`.\n */\n\nimport { Component, JSX, Show, createSignal, createEffect, onCleanup } from 'solid-js'\nimport { Portal } from 'solid-js/web'\n\nexport interface PortalDropdownMenuProps {\n /**\n * Whether the menu is currently open. Controlled by the parent.\n */\n open: boolean\n\n /**\n * Called when the menu wants to close (outside click / Escape / item\n * click — it's the parent's job to actually flip `open` to false).\n */\n onClose: () => void\n\n /**\n * Trigger element used as the positioning anchor. The menu's right\n * edge is aligned to the trigger's right edge, top to its bottom + 4px.\n */\n trigger: HTMLElement | undefined\n\n /**\n * Menu width in pixels. Used to compute the left coordinate so the menu's\n * right edge aligns with the trigger's right edge. Default : `144` (the\n * legacy table menu width — `w-36`).\n */\n width?: number\n\n /**\n * Menu content. Wrapped in the rounded / shadowed container — keep\n * children minimal (just the items).\n */\n children: JSX.Element\n\n /**\n * Optional additional class names for the menu container, appended after\n * the default Tailwind classes. Useful to override width or padding.\n */\n class?: string\n}\n\nexport const PortalDropdownMenu: Component<PortalDropdownMenuProps> = (props) => {\n const [position, setPosition] = createSignal({ top: 0, left: 0 })\n let menuRef: HTMLDivElement | undefined\n\n const updatePosition = () => {\n const t = props.trigger\n if (!t) return\n const rect = t.getBoundingClientRect()\n const w = props.width ?? 144\n setPosition({\n top: rect.bottom + 4,\n left: rect.right - w,\n })\n }\n\n // Measure once when the menu opens, then react to viewport changes.\n createEffect(() => {\n if (!props.open) return\n updatePosition()\n\n const onDown = (e: MouseEvent) => {\n const target = e.target as Node\n if (menuRef?.contains(target) || props.trigger?.contains(target)) return\n props.onClose()\n }\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') props.onClose()\n }\n const onScrollOrResize = () => updatePosition()\n\n document.addEventListener('mousedown', onDown)\n document.addEventListener('keydown', onKey)\n // Capture phase so scrolls inside nested containers (e.g. chat virtual\n // list) also re-position the menu. `passive: true` because we never\n // preventDefault here.\n window.addEventListener('scroll', onScrollOrResize, { capture: true, passive: true })\n window.addEventListener('resize', onScrollOrResize)\n\n onCleanup(() => {\n document.removeEventListener('mousedown', onDown)\n document.removeEventListener('keydown', onKey)\n window.removeEventListener('scroll', onScrollOrResize, { capture: true })\n window.removeEventListener('resize', onScrollOrResize)\n })\n })\n\n return (\n <Show when={props.open}>\n <Portal>\n <div\n ref={menuRef}\n role=\"menu\"\n data-mcp-ui-portal=\"menu\"\n style={{\n position: 'fixed',\n top: `${position().top}px`,\n left: `${position().left}px`,\n 'z-index': 9999,\n width: `${props.width ?? 144}px`,\n }}\n class={`bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded-lg shadow-lg py-1 text-sm ${props.class ?? ''}`}\n >\n {props.children}\n </div>\n </Portal>\n </Show>\n )\n}\n"],"names":["PortalDropdownMenu","props","position","setPosition","createSignal","top","left","menuRef","updatePosition","t","trigger","rect","getBoundingClientRect","w","width","bottom","right","createEffect","open","onDown","e","target","contains","onClose","onKey","key","onScrollOrResize","document","addEventListener","window","capture","passive","onCleanup","removeEventListener","_$createComponent","Show","when","children","Portal","_el$","_$getNextElement","_tmpl$","_ref$","_$use","_$insert","_$effect","_p$","_v$","_v$2","_v$3","_v$4","class","_$setStyleProperty","a","o","_$className","undefined"],"mappings":"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"}
1
+ {"version":3,"file":"PortalDropdownMenu.cjs","sources":["../../src/components/PortalDropdownMenu.tsx"],"sourcesContent":["/**\n * PortalDropdownMenu (v6.4.0) — generic dropdown that mounts via\n * `<Portal>` on `document.body` instead of an in-tree `position: absolute`\n * sibling. Eliminates two pain points around the legacy in-tree pattern :\n *\n * 1. **`overflow: hidden` clipping** — when the trigger lives inside a\n * chat bubble or a card with `overflow: hidden`, an absolutely\n * positioned menu sibling gets clipped at the ancestor's boundary.\n * Mounting on `document.body` escapes the clip stack entirely.\n * 2. **`z-index` wars** — chat surfaces stack composer / message rails\n * above the message list, and ancestor `z-index` creates a new\n * stacking context that captures the in-tree menu. A portal is a\n * sibling of the document, so a single `z-index: 9999` wins.\n *\n * The menu is positioned with `position: fixed` from the trigger's\n * `getBoundingClientRect()`. We re-measure on `scroll` (capture phase, so\n * nested scrollables also fire) and `resize` to keep the menu pinned\n * while the user interacts with surrounding chrome.\n *\n * Close affordances : click outside, Escape, programmatic via `onClose`.\n */\n\nimport { Component, JSX, Show, createSignal, createEffect, onCleanup } from 'solid-js'\nimport { Portal } from 'solid-js/web'\nimport { bindPortalTheme } from '../utils/theme'\n\nexport interface PortalDropdownMenuProps {\n /**\n * Whether the menu is currently open. Controlled by the parent.\n */\n open: boolean\n\n /**\n * Called when the menu wants to close (outside click / Escape / item\n * click — it's the parent's job to actually flip `open` to false).\n */\n onClose: () => void\n\n /**\n * Trigger element used as the positioning anchor. The menu's right\n * edge is aligned to the trigger's right edge, top to its bottom + 4px.\n */\n trigger: HTMLElement | undefined\n\n /**\n * Menu width in pixels. Used to compute the left coordinate so the menu's\n * right edge aligns with the trigger's right edge. Default : `144` (the\n * legacy table menu width — `w-36`).\n */\n width?: number\n\n /**\n * Menu content. Wrapped in the rounded / shadowed container — keep\n * children minimal (just the items).\n */\n children: JSX.Element\n\n /**\n * Optional additional class names for the menu container, appended after\n * the default Tailwind classes. Useful to override width or padding.\n */\n class?: string\n}\n\nexport const PortalDropdownMenu: Component<PortalDropdownMenuProps> = (props) => {\n const [position, setPosition] = createSignal({ top: 0, left: 0 })\n let menuRef: HTMLDivElement | undefined\n\n const updatePosition = () => {\n const t = props.trigger\n if (!t) return\n const rect = t.getBoundingClientRect()\n const w = props.width ?? 144\n setPosition({\n top: rect.bottom + 4,\n left: rect.right - w,\n })\n }\n\n // Measure once when the menu opens, then react to viewport changes.\n createEffect(() => {\n if (!props.open) return\n updatePosition()\n\n const onDown = (e: MouseEvent) => {\n const target = e.target as Node\n if (menuRef?.contains(target) || props.trigger?.contains(target)) return\n props.onClose()\n }\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') props.onClose()\n }\n const onScrollOrResize = () => updatePosition()\n\n document.addEventListener('mousedown', onDown)\n document.addEventListener('keydown', onKey)\n // Capture phase so scrolls inside nested containers (e.g. chat virtual\n // list) also re-position the menu. `passive: true` because we never\n // preventDefault here.\n window.addEventListener('scroll', onScrollOrResize, { capture: true, passive: true })\n window.addEventListener('resize', onScrollOrResize)\n\n onCleanup(() => {\n document.removeEventListener('mousedown', onDown)\n document.removeEventListener('keydown', onKey)\n window.removeEventListener('scroll', onScrollOrResize, { capture: true })\n window.removeEventListener('resize', onScrollOrResize)\n })\n })\n\n return (\n <Show when={props.open}>\n <Portal>\n <div\n ref={(element) => {\n menuRef = element\n bindPortalTheme(element, () => props.trigger)\n }}\n role=\"menu\"\n data-mcp-ui-portal=\"menu\"\n style={{\n position: 'fixed',\n top: `${position().top}px`,\n left: `${position().left}px`,\n 'z-index': 9999,\n width: `${props.width ?? 144}px`,\n }}\n class={`mcp-ui-root bg-[color:var(--mcp-ui-surface,var(--color-white,#fff))] dark:bg-[color:var(--mcp-ui-surface,var(--color-gray-800,#1f2937))] border border-[color:var(--mcp-ui-border,var(--color-gray-200,#e5e7eb))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-600,#4b5563))] rounded-lg shadow-[var(--mcp-ui-shadow,var(--shadow-lg))] py-1 text-sm ${props.class ?? ''}`}\n >\n {props.children}\n </div>\n </Portal>\n </Show>\n )\n}\n"],"names":["PortalDropdownMenu","props","position","setPosition","createSignal","top","left","menuRef","updatePosition","t","trigger","rect","getBoundingClientRect","w","width","bottom","right","createEffect","open","onDown","e","target","contains","onClose","onKey","key","onScrollOrResize","document","addEventListener","window","capture","passive","onCleanup","removeEventListener","_$createComponent","Show","when","children","Portal","_el$","_$getNextElement","_tmpl$","_$use","element","bindPortalTheme","_$insert","_$effect","_p$","_v$","_v$2","_v$3","_v$4","class","_$setStyleProperty","a","o","_$className","undefined"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"PortalDropdownMenu.d.ts","sourceRoot":"","sources":["../../src/components/PortalDropdownMenu.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,SAAS,EAAE,GAAG,EAA+C,MAAM,UAAU,CAAA;AAGtF,MAAM,WAAW,uBAAuB;IACtC;;OAEG;IACH,IAAI,EAAE,OAAO,CAAA;IAEb;;;OAGG;IACH,OAAO,EAAE,MAAM,IAAI,CAAA;IAEnB;;;OAGG;IACH,OAAO,EAAE,WAAW,GAAG,SAAS,CAAA;IAEhC;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IAEd;;;OAGG;IACH,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAA;IAErB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,eAAO,MAAM,kBAAkB,EAAE,SAAS,CAAC,uBAAuB,CAmEjE,CAAA"}
1
+ {"version":3,"file":"PortalDropdownMenu.d.ts","sourceRoot":"","sources":["../../src/components/PortalDropdownMenu.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,SAAS,EAAE,GAAG,EAA+C,MAAM,UAAU,CAAA;AAItF,MAAM,WAAW,uBAAuB;IACtC;;OAEG;IACH,IAAI,EAAE,OAAO,CAAA;IAEb;;;OAGG;IACH,OAAO,EAAE,MAAM,IAAI,CAAA;IAEnB;;;OAGG;IACH,OAAO,EAAE,WAAW,GAAG,SAAS,CAAA;IAEhC;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IAEd;;;OAGG;IACH,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAA;IAErB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,eAAO,MAAM,kBAAkB,EAAE,SAAS,CAAC,uBAAuB,CAsEjE,CAAA"}
@@ -1,5 +1,6 @@
1
- import { createComponent, Portal, getNextElement, insert, effect, setStyleProperty, className, template, use } from "solid-js/web";
1
+ import { createComponent, Portal, getNextElement, use, insert, effect, setStyleProperty, className, template } from "solid-js/web";
2
2
  import { createSignal, createEffect, onCleanup, Show } from "solid-js";
3
+ import { bindPortalTheme } from "../utils/theme.js";
3
4
  var _tmpl$ = /* @__PURE__ */ template(`<div role=menu data-mcp-ui-portal=menu style=position:fixed;z-index:9999>`);
4
5
  const PortalDropdownMenu = (props) => {
5
6
  const [position, setPosition] = createSignal({
@@ -54,11 +55,13 @@ const PortalDropdownMenu = (props) => {
54
55
  return createComponent(Portal, {
55
56
  get children() {
56
57
  var _el$ = getNextElement(_tmpl$);
57
- var _ref$ = menuRef;
58
- typeof _ref$ === "function" ? use(_ref$, _el$) : menuRef = _el$;
58
+ use((element) => {
59
+ menuRef = element;
60
+ bindPortalTheme(element, () => props.trigger);
61
+ }, _el$);
59
62
  insert(_el$, () => props.children);
60
63
  effect((_p$) => {
61
- var _v$ = `${position().top}px`, _v$2 = `${position().left}px`, _v$3 = `${props.width ?? 144}px`, _v$4 = `bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded-lg shadow-lg py-1 text-sm ${props.class ?? ""}`;
64
+ var _v$ = `${position().top}px`, _v$2 = `${position().left}px`, _v$3 = `${props.width ?? 144}px`, _v$4 = `mcp-ui-root bg-[color:var(--mcp-ui-surface,var(--color-white,#fff))] dark:bg-[color:var(--mcp-ui-surface,var(--color-gray-800,#1f2937))] border border-[color:var(--mcp-ui-border,var(--color-gray-200,#e5e7eb))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-600,#4b5563))] rounded-lg shadow-[var(--mcp-ui-shadow,var(--shadow-lg))] py-1 text-sm ${props.class ?? ""}`;
62
65
  _v$ !== _p$.e && setStyleProperty(_el$, "top", _p$.e = _v$);
63
66
  _v$2 !== _p$.t && setStyleProperty(_el$, "left", _p$.t = _v$2);
64
67
  _v$3 !== _p$.a && setStyleProperty(_el$, "width", _p$.a = _v$3);
@@ -1 +1 @@
1
- {"version":3,"file":"PortalDropdownMenu.js","sources":["../../src/components/PortalDropdownMenu.tsx"],"sourcesContent":["/**\n * PortalDropdownMenu (v6.4.0) — generic dropdown that mounts via\n * `<Portal>` on `document.body` instead of an in-tree `position: absolute`\n * sibling. Eliminates two pain points around the legacy in-tree pattern :\n *\n * 1. **`overflow: hidden` clipping** — when the trigger lives inside a\n * chat bubble or a card with `overflow: hidden`, an absolutely\n * positioned menu sibling gets clipped at the ancestor's boundary.\n * Mounting on `document.body` escapes the clip stack entirely.\n * 2. **`z-index` wars** — chat surfaces stack composer / message rails\n * above the message list, and ancestor `z-index` creates a new\n * stacking context that captures the in-tree menu. A portal is a\n * sibling of the document, so a single `z-index: 9999` wins.\n *\n * The menu is positioned with `position: fixed` from the trigger's\n * `getBoundingClientRect()`. We re-measure on `scroll` (capture phase, so\n * nested scrollables also fire) and `resize` to keep the menu pinned\n * while the user interacts with surrounding chrome.\n *\n * Close affordances : click outside, Escape, programmatic via `onClose`.\n */\n\nimport { Component, JSX, Show, createSignal, createEffect, onCleanup } from 'solid-js'\nimport { Portal } from 'solid-js/web'\n\nexport interface PortalDropdownMenuProps {\n /**\n * Whether the menu is currently open. Controlled by the parent.\n */\n open: boolean\n\n /**\n * Called when the menu wants to close (outside click / Escape / item\n * click — it's the parent's job to actually flip `open` to false).\n */\n onClose: () => void\n\n /**\n * Trigger element used as the positioning anchor. The menu's right\n * edge is aligned to the trigger's right edge, top to its bottom + 4px.\n */\n trigger: HTMLElement | undefined\n\n /**\n * Menu width in pixels. Used to compute the left coordinate so the menu's\n * right edge aligns with the trigger's right edge. Default : `144` (the\n * legacy table menu width — `w-36`).\n */\n width?: number\n\n /**\n * Menu content. Wrapped in the rounded / shadowed container — keep\n * children minimal (just the items).\n */\n children: JSX.Element\n\n /**\n * Optional additional class names for the menu container, appended after\n * the default Tailwind classes. Useful to override width or padding.\n */\n class?: string\n}\n\nexport const PortalDropdownMenu: Component<PortalDropdownMenuProps> = (props) => {\n const [position, setPosition] = createSignal({ top: 0, left: 0 })\n let menuRef: HTMLDivElement | undefined\n\n const updatePosition = () => {\n const t = props.trigger\n if (!t) return\n const rect = t.getBoundingClientRect()\n const w = props.width ?? 144\n setPosition({\n top: rect.bottom + 4,\n left: rect.right - w,\n })\n }\n\n // Measure once when the menu opens, then react to viewport changes.\n createEffect(() => {\n if (!props.open) return\n updatePosition()\n\n const onDown = (e: MouseEvent) => {\n const target = e.target as Node\n if (menuRef?.contains(target) || props.trigger?.contains(target)) return\n props.onClose()\n }\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') props.onClose()\n }\n const onScrollOrResize = () => updatePosition()\n\n document.addEventListener('mousedown', onDown)\n document.addEventListener('keydown', onKey)\n // Capture phase so scrolls inside nested containers (e.g. chat virtual\n // list) also re-position the menu. `passive: true` because we never\n // preventDefault here.\n window.addEventListener('scroll', onScrollOrResize, { capture: true, passive: true })\n window.addEventListener('resize', onScrollOrResize)\n\n onCleanup(() => {\n document.removeEventListener('mousedown', onDown)\n document.removeEventListener('keydown', onKey)\n window.removeEventListener('scroll', onScrollOrResize, { capture: true })\n window.removeEventListener('resize', onScrollOrResize)\n })\n })\n\n return (\n <Show when={props.open}>\n <Portal>\n <div\n ref={menuRef}\n role=\"menu\"\n data-mcp-ui-portal=\"menu\"\n style={{\n position: 'fixed',\n top: `${position().top}px`,\n left: `${position().left}px`,\n 'z-index': 9999,\n width: `${props.width ?? 144}px`,\n }}\n class={`bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded-lg shadow-lg py-1 text-sm ${props.class ?? ''}`}\n >\n {props.children}\n </div>\n </Portal>\n </Show>\n )\n}\n"],"names":["PortalDropdownMenu","props","position","setPosition","createSignal","top","left","menuRef","updatePosition","t","trigger","rect","getBoundingClientRect","w","width","bottom","right","createEffect","open","onDown","e","target","contains","onClose","onKey","key","onScrollOrResize","document","addEventListener","window","capture","passive","onCleanup","removeEventListener","_$createComponent","Show","when","children","Portal","_el$","_$getNextElement","_tmpl$","_ref$","_$use","_$insert","_$effect","_p$","_v$","_v$2","_v$3","_v$4","class","_$setStyleProperty","a","o","_$className","undefined"],"mappings":";;;AA+DO,MAAMA,qBAA0DC,CAAAA,UAAU;AAC/E,QAAM,CAACC,UAAUC,WAAW,IAAIC,aAAa;AAAA,IAAEC,KAAK;AAAA,IAAGC,MAAM;AAAA,EAAA,CAAG;AAChE,MAAIC;AAEJ,QAAMC,iBAAiBA,MAAM;AAC3B,UAAMC,IAAIR,MAAMS;AAChB,QAAI,CAACD,EAAG;AACR,UAAME,OAAOF,EAAEG,sBAAAA;AACf,UAAMC,IAAIZ,MAAMa,SAAS;AACzBX,gBAAY;AAAA,MACVE,KAAKM,KAAKI,SAAS;AAAA,MACnBT,MAAMK,KAAKK,QAAQH;AAAAA,IAAAA,CACpB;AAAA,EACH;AAGAI,eAAa,MAAM;AACjB,QAAI,CAAChB,MAAMiB,KAAM;AACjBV,mBAAAA;AAEA,UAAMW,SAASA,CAACC,MAAkB;;AAChC,YAAMC,SAASD,EAAEC;AACjB,WAAId,mCAASe,SAASD,cAAWpB,WAAMS,YAANT,mBAAeqB,SAASD,SAAS;AAClEpB,YAAMsB,QAAAA;AAAAA,IACR;AACA,UAAMC,QAAQA,CAACJ,MAAqB;AAClC,UAAIA,EAAEK,QAAQ,SAAUxB,OAAMsB,QAAAA;AAAAA,IAChC;AACA,UAAMG,mBAAmBA,MAAMlB,eAAAA;AAE/BmB,aAASC,iBAAiB,aAAaT,MAAM;AAC7CQ,aAASC,iBAAiB,WAAWJ,KAAK;AAI1CK,WAAOD,iBAAiB,UAAUF,kBAAkB;AAAA,MAAEI,SAAS;AAAA,MAAMC,SAAS;AAAA,IAAA,CAAM;AACpFF,WAAOD,iBAAiB,UAAUF,gBAAgB;AAElDM,cAAU,MAAM;AACdL,eAASM,oBAAoB,aAAad,MAAM;AAChDQ,eAASM,oBAAoB,WAAWT,KAAK;AAC7CK,aAAOI,oBAAoB,UAAUP,kBAAkB;AAAA,QAAEI,SAAS;AAAA,MAAA,CAAM;AACxED,aAAOI,oBAAoB,UAAUP,gBAAgB;AAAA,IACvD,CAAC;AAAA,EACH,CAAC;AAED,SAAAQ,gBACGC,MAAI;AAAA,IAAA,IAACC,OAAI;AAAA,aAAEnC,MAAMiB;AAAAA,IAAI;AAAA,IAAA,IAAAmB,WAAA;AAAA,aAAAH,gBACnBI,QAAM;AAAA,QAAA,IAAAD,WAAA;AAAA,cAAAE,OAAAC,eAAAC,MAAA;AAAA,cAAAC,QAEEnC;AAAO,iBAAAmC,UAAA,aAAAC,IAAAD,OAAAH,IAAA,IAAPhC,UAAOgC;AAAAK,iBAAAL,MAAA,MAYXtC,MAAMoC,QAAQ;AAAAQ,iBAAAC,CAAAA,QAAA;AAAA,gBAAAC,MAPR,GAAG7C,SAAAA,EAAWG,GAAG,MAAI2C,OACpB,GAAG9C,SAAAA,EAAWI,IAAI,MAAI2C,OAErB,GAAGhD,MAAMa,SAAS,GAAG,MAAIoC,OAE3B,2GAA2GjD,MAAMkD,SAAS,EAAE;AAAEJ,oBAAAD,IAAA1B,KAAAgC,iBAAAb,MAAA,OAAAO,IAAA1B,IAAA2B,GAAA;AAAAC,qBAAAF,IAAArC,KAAA2C,iBAAAb,MAAA,QAAAO,IAAArC,IAAAuC,IAAA;AAAAC,qBAAAH,IAAAO,KAAAD,iBAAAb,MAAA,SAAAO,IAAAO,IAAAJ,IAAA;AAAAC,qBAAAJ,IAAAQ,KAAAC,UAAAhB,MAAAO,IAAAQ,IAAAJ,IAAA;AAAA,mBAAAJ;AAAAA,UAAA,GAAA;AAAA,YAAA1B,GAAAoC;AAAAA,YAAA/C,GAAA+C;AAAAA,YAAAH,GAAAG;AAAAA,YAAAF,GAAAE;AAAAA,UAAAA,CAAA;AAAA,iBAAAjB;AAAAA,QAAA;AAAA,MAAA,CAAA;AAAA,IAAA;AAAA,EAAA,CAAA;AAO/I;"}
1
+ {"version":3,"file":"PortalDropdownMenu.js","sources":["../../src/components/PortalDropdownMenu.tsx"],"sourcesContent":["/**\n * PortalDropdownMenu (v6.4.0) — generic dropdown that mounts via\n * `<Portal>` on `document.body` instead of an in-tree `position: absolute`\n * sibling. Eliminates two pain points around the legacy in-tree pattern :\n *\n * 1. **`overflow: hidden` clipping** — when the trigger lives inside a\n * chat bubble or a card with `overflow: hidden`, an absolutely\n * positioned menu sibling gets clipped at the ancestor's boundary.\n * Mounting on `document.body` escapes the clip stack entirely.\n * 2. **`z-index` wars** — chat surfaces stack composer / message rails\n * above the message list, and ancestor `z-index` creates a new\n * stacking context that captures the in-tree menu. A portal is a\n * sibling of the document, so a single `z-index: 9999` wins.\n *\n * The menu is positioned with `position: fixed` from the trigger's\n * `getBoundingClientRect()`. We re-measure on `scroll` (capture phase, so\n * nested scrollables also fire) and `resize` to keep the menu pinned\n * while the user interacts with surrounding chrome.\n *\n * Close affordances : click outside, Escape, programmatic via `onClose`.\n */\n\nimport { Component, JSX, Show, createSignal, createEffect, onCleanup } from 'solid-js'\nimport { Portal } from 'solid-js/web'\nimport { bindPortalTheme } from '../utils/theme'\n\nexport interface PortalDropdownMenuProps {\n /**\n * Whether the menu is currently open. Controlled by the parent.\n */\n open: boolean\n\n /**\n * Called when the menu wants to close (outside click / Escape / item\n * click — it's the parent's job to actually flip `open` to false).\n */\n onClose: () => void\n\n /**\n * Trigger element used as the positioning anchor. The menu's right\n * edge is aligned to the trigger's right edge, top to its bottom + 4px.\n */\n trigger: HTMLElement | undefined\n\n /**\n * Menu width in pixels. Used to compute the left coordinate so the menu's\n * right edge aligns with the trigger's right edge. Default : `144` (the\n * legacy table menu width — `w-36`).\n */\n width?: number\n\n /**\n * Menu content. Wrapped in the rounded / shadowed container — keep\n * children minimal (just the items).\n */\n children: JSX.Element\n\n /**\n * Optional additional class names for the menu container, appended after\n * the default Tailwind classes. Useful to override width or padding.\n */\n class?: string\n}\n\nexport const PortalDropdownMenu: Component<PortalDropdownMenuProps> = (props) => {\n const [position, setPosition] = createSignal({ top: 0, left: 0 })\n let menuRef: HTMLDivElement | undefined\n\n const updatePosition = () => {\n const t = props.trigger\n if (!t) return\n const rect = t.getBoundingClientRect()\n const w = props.width ?? 144\n setPosition({\n top: rect.bottom + 4,\n left: rect.right - w,\n })\n }\n\n // Measure once when the menu opens, then react to viewport changes.\n createEffect(() => {\n if (!props.open) return\n updatePosition()\n\n const onDown = (e: MouseEvent) => {\n const target = e.target as Node\n if (menuRef?.contains(target) || props.trigger?.contains(target)) return\n props.onClose()\n }\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') props.onClose()\n }\n const onScrollOrResize = () => updatePosition()\n\n document.addEventListener('mousedown', onDown)\n document.addEventListener('keydown', onKey)\n // Capture phase so scrolls inside nested containers (e.g. chat virtual\n // list) also re-position the menu. `passive: true` because we never\n // preventDefault here.\n window.addEventListener('scroll', onScrollOrResize, { capture: true, passive: true })\n window.addEventListener('resize', onScrollOrResize)\n\n onCleanup(() => {\n document.removeEventListener('mousedown', onDown)\n document.removeEventListener('keydown', onKey)\n window.removeEventListener('scroll', onScrollOrResize, { capture: true })\n window.removeEventListener('resize', onScrollOrResize)\n })\n })\n\n return (\n <Show when={props.open}>\n <Portal>\n <div\n ref={(element) => {\n menuRef = element\n bindPortalTheme(element, () => props.trigger)\n }}\n role=\"menu\"\n data-mcp-ui-portal=\"menu\"\n style={{\n position: 'fixed',\n top: `${position().top}px`,\n left: `${position().left}px`,\n 'z-index': 9999,\n width: `${props.width ?? 144}px`,\n }}\n class={`mcp-ui-root bg-[color:var(--mcp-ui-surface,var(--color-white,#fff))] dark:bg-[color:var(--mcp-ui-surface,var(--color-gray-800,#1f2937))] border border-[color:var(--mcp-ui-border,var(--color-gray-200,#e5e7eb))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-600,#4b5563))] rounded-lg shadow-[var(--mcp-ui-shadow,var(--shadow-lg))] py-1 text-sm ${props.class ?? ''}`}\n >\n {props.children}\n </div>\n </Portal>\n </Show>\n )\n}\n"],"names":["PortalDropdownMenu","props","position","setPosition","createSignal","top","left","menuRef","updatePosition","t","trigger","rect","getBoundingClientRect","w","width","bottom","right","createEffect","open","onDown","e","target","contains","onClose","onKey","key","onScrollOrResize","document","addEventListener","window","capture","passive","onCleanup","removeEventListener","_$createComponent","Show","when","children","Portal","_el$","_$getNextElement","_tmpl$","_$use","element","bindPortalTheme","_$insert","_$effect","_p$","_v$","_v$2","_v$3","_v$4","class","_$setStyleProperty","a","o","_$className","undefined"],"mappings":";;;;AAgEO,MAAMA,qBAA0DC,CAAAA,UAAU;AAC/E,QAAM,CAACC,UAAUC,WAAW,IAAIC,aAAa;AAAA,IAAEC,KAAK;AAAA,IAAGC,MAAM;AAAA,EAAA,CAAG;AAChE,MAAIC;AAEJ,QAAMC,iBAAiBA,MAAM;AAC3B,UAAMC,IAAIR,MAAMS;AAChB,QAAI,CAACD,EAAG;AACR,UAAME,OAAOF,EAAEG,sBAAAA;AACf,UAAMC,IAAIZ,MAAMa,SAAS;AACzBX,gBAAY;AAAA,MACVE,KAAKM,KAAKI,SAAS;AAAA,MACnBT,MAAMK,KAAKK,QAAQH;AAAAA,IAAAA,CACpB;AAAA,EACH;AAGAI,eAAa,MAAM;AACjB,QAAI,CAAChB,MAAMiB,KAAM;AACjBV,mBAAAA;AAEA,UAAMW,SAASA,CAACC,MAAkB;;AAChC,YAAMC,SAASD,EAAEC;AACjB,WAAId,mCAASe,SAASD,cAAWpB,WAAMS,YAANT,mBAAeqB,SAASD,SAAS;AAClEpB,YAAMsB,QAAAA;AAAAA,IACR;AACA,UAAMC,QAAQA,CAACJ,MAAqB;AAClC,UAAIA,EAAEK,QAAQ,SAAUxB,OAAMsB,QAAAA;AAAAA,IAChC;AACA,UAAMG,mBAAmBA,MAAMlB,eAAAA;AAE/BmB,aAASC,iBAAiB,aAAaT,MAAM;AAC7CQ,aAASC,iBAAiB,WAAWJ,KAAK;AAI1CK,WAAOD,iBAAiB,UAAUF,kBAAkB;AAAA,MAAEI,SAAS;AAAA,MAAMC,SAAS;AAAA,IAAA,CAAM;AACpFF,WAAOD,iBAAiB,UAAUF,gBAAgB;AAElDM,cAAU,MAAM;AACdL,eAASM,oBAAoB,aAAad,MAAM;AAChDQ,eAASM,oBAAoB,WAAWT,KAAK;AAC7CK,aAAOI,oBAAoB,UAAUP,kBAAkB;AAAA,QAAEI,SAAS;AAAA,MAAA,CAAM;AACxED,aAAOI,oBAAoB,UAAUP,gBAAgB;AAAA,IACvD,CAAC;AAAA,EACH,CAAC;AAED,SAAAQ,gBACGC,MAAI;AAAA,IAAA,IAACC,OAAI;AAAA,aAAEnC,MAAMiB;AAAAA,IAAI;AAAA,IAAA,IAAAmB,WAAA;AAAA,aAAAH,gBACnBI,QAAM;AAAA,QAAA,IAAAD,WAAA;AAAA,cAAAE,OAAAC,eAAAC,MAAA;AAAAC,cAEGC,CAAAA,YAAY;AAChBpC,sBAAUoC;AACVC,4BAAgBD,SAAS,MAAM1C,MAAMS,OAAO;AAAA,UAC9C,GAAC6B,IAAA;AAAAM,iBAAAN,MAAA,MAYAtC,MAAMoC,QAAQ;AAAAS,iBAAAC,CAAAA,QAAA;AAAA,gBAAAC,MAPR,GAAG9C,SAAAA,EAAWG,GAAG,MAAI4C,OACpB,GAAG/C,SAAAA,EAAWI,IAAI,MAAI4C,OAErB,GAAGjD,MAAMa,SAAS,GAAG,MAAIqC,OAE3B,mWAAmWlD,MAAMmD,SAAS,EAAE;AAAEJ,oBAAAD,IAAA3B,KAAAiC,iBAAAd,MAAA,OAAAQ,IAAA3B,IAAA4B,GAAA;AAAAC,qBAAAF,IAAAtC,KAAA4C,iBAAAd,MAAA,QAAAQ,IAAAtC,IAAAwC,IAAA;AAAAC,qBAAAH,IAAAO,KAAAD,iBAAAd,MAAA,SAAAQ,IAAAO,IAAAJ,IAAA;AAAAC,qBAAAJ,IAAAQ,KAAAC,UAAAjB,MAAAQ,IAAAQ,IAAAJ,IAAA;AAAA,mBAAAJ;AAAAA,UAAA,GAAA;AAAA,YAAA3B,GAAAqC;AAAAA,YAAAhD,GAAAgD;AAAAA,YAAAH,GAAAG;AAAAA,YAAAF,GAAAE;AAAAA,UAAAA,CAAA;AAAA,iBAAAlB;AAAAA,QAAA;AAAA,MAAA,CAAA;AAAA,IAAA;AAAA,EAAA,CAAA;AAOvY;"}