@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.
- package/CHANGELOG.md +167 -0
- package/README.md +154 -2
- package/dist/components/ActionGroupRenderer.cjs +6 -6
- package/dist/components/ActionGroupRenderer.cjs.map +1 -1
- package/dist/components/ActionGroupRenderer.js +6 -6
- package/dist/components/ActionGroupRenderer.js.map +1 -1
- package/dist/components/AutocompleteDropdown.cjs +6 -6
- package/dist/components/AutocompleteDropdown.cjs.map +1 -1
- package/dist/components/AutocompleteDropdown.js +6 -6
- package/dist/components/AutocompleteDropdown.js.map +1 -1
- package/dist/components/AutocompleteFormField.cjs +6 -5
- package/dist/components/AutocompleteFormField.cjs.map +1 -1
- package/dist/components/AutocompleteFormField.d.ts.map +1 -1
- package/dist/components/AutocompleteFormField.js +6 -5
- package/dist/components/AutocompleteFormField.js.map +1 -1
- package/dist/components/ChartJSRenderer.cjs +406 -70
- package/dist/components/ChartJSRenderer.cjs.map +1 -1
- package/dist/components/ChartJSRenderer.d.ts.map +1 -1
- package/dist/components/ChartJSRenderer.js +407 -71
- package/dist/components/ChartJSRenderer.js.map +1 -1
- package/dist/components/ChatPrompt.cjs +5 -5
- package/dist/components/ChatPrompt.cjs.map +1 -1
- package/dist/components/ChatPrompt.js +5 -5
- package/dist/components/ChatPrompt.js.map +1 -1
- package/dist/components/ComponentToolbar.cjs +5 -5
- package/dist/components/ComponentToolbar.cjs.map +1 -1
- package/dist/components/ComponentToolbar.js +5 -5
- package/dist/components/ComponentToolbar.js.map +1 -1
- package/dist/components/DegradedFallback.cjs +35 -3
- package/dist/components/DegradedFallback.cjs.map +1 -1
- package/dist/components/DegradedFallback.d.ts +7 -0
- package/dist/components/DegradedFallback.d.ts.map +1 -1
- package/dist/components/DegradedFallback.js +35 -3
- package/dist/components/DegradedFallback.js.map +1 -1
- package/dist/components/ExpandableWrapper.cjs +10 -7
- package/dist/components/ExpandableWrapper.cjs.map +1 -1
- package/dist/components/ExpandableWrapper.d.ts.map +1 -1
- package/dist/components/ExpandableWrapper.js +10 -7
- package/dist/components/ExpandableWrapper.js.map +1 -1
- package/dist/components/FormFieldRenderer.cjs +13 -12
- package/dist/components/FormFieldRenderer.cjs.map +1 -1
- package/dist/components/FormFieldRenderer.d.ts.map +1 -1
- package/dist/components/FormFieldRenderer.js +13 -12
- package/dist/components/FormFieldRenderer.js.map +1 -1
- package/dist/components/FormRenderer.cjs +1 -1
- package/dist/components/FormRenderer.cjs.map +1 -1
- package/dist/components/FormRenderer.js +1 -1
- package/dist/components/FormRenderer.js.map +1 -1
- package/dist/components/GenerativeUIErrorBoundary.cjs +1 -1
- package/dist/components/GenerativeUIErrorBoundary.cjs.map +1 -1
- package/dist/components/GenerativeUIErrorBoundary.js +1 -1
- package/dist/components/GenerativeUIErrorBoundary.js.map +1 -1
- package/dist/components/GhostText.cjs +2 -2
- package/dist/components/GhostText.cjs.map +1 -1
- package/dist/components/GhostText.js +2 -2
- package/dist/components/GhostText.js.map +1 -1
- package/dist/components/GraphRenderer.cjs +100 -29
- package/dist/components/GraphRenderer.cjs.map +1 -1
- package/dist/components/GraphRenderer.d.ts +1 -1
- package/dist/components/GraphRenderer.d.ts.map +1 -1
- package/dist/components/GraphRenderer.js +100 -29
- package/dist/components/GraphRenderer.js.map +1 -1
- package/dist/components/MissingValue.cjs +43 -0
- package/dist/components/MissingValue.cjs.map +1 -0
- package/dist/components/MissingValue.d.ts +27 -0
- package/dist/components/MissingValue.d.ts.map +1 -0
- package/dist/components/MissingValue.js +43 -0
- package/dist/components/MissingValue.js.map +1 -0
- package/dist/components/ModalRenderer.cjs +39 -31
- package/dist/components/ModalRenderer.cjs.map +1 -1
- package/dist/components/ModalRenderer.d.ts.map +1 -1
- package/dist/components/ModalRenderer.js +40 -32
- package/dist/components/ModalRenderer.js.map +1 -1
- package/dist/components/PortalDropdownMenu.cjs +6 -3
- package/dist/components/PortalDropdownMenu.cjs.map +1 -1
- package/dist/components/PortalDropdownMenu.d.ts.map +1 -1
- package/dist/components/PortalDropdownMenu.js +7 -4
- package/dist/components/PortalDropdownMenu.js.map +1 -1
- package/dist/components/ScratchpadPanel.cjs +38 -44
- package/dist/components/ScratchpadPanel.cjs.map +1 -1
- package/dist/components/ScratchpadPanel.d.ts.map +1 -1
- package/dist/components/ScratchpadPanel.js +38 -44
- package/dist/components/ScratchpadPanel.js.map +1 -1
- package/dist/components/UIResourceRenderer.cjs +255 -217
- package/dist/components/UIResourceRenderer.cjs.map +1 -1
- package/dist/components/UIResourceRenderer.d.ts.map +1 -1
- package/dist/components/UIResourceRenderer.js +255 -217
- package/dist/components/UIResourceRenderer.js.map +1 -1
- package/dist/components/chart-data-table.cjs +30 -5
- package/dist/components/chart-data-table.cjs.map +1 -1
- package/dist/components/chart-data-table.d.ts +18 -1
- package/dist/components/chart-data-table.d.ts.map +1 -1
- package/dist/components/chart-data-table.js +30 -5
- package/dist/components/chart-data-table.js.map +1 -1
- package/dist/components/chart-missing-plugin.cjs +194 -0
- package/dist/components/chart-missing-plugin.cjs.map +1 -0
- package/dist/components/chart-missing-plugin.d.ts +129 -0
- package/dist/components/chart-missing-plugin.d.ts.map +1 -0
- package/dist/components/chart-missing-plugin.js +194 -0
- package/dist/components/chart-missing-plugin.js.map +1 -0
- package/dist/context/MCPUIStringsContext.cjs +12 -1
- package/dist/context/MCPUIStringsContext.cjs.map +1 -1
- package/dist/context/MCPUIStringsContext.d.ts +62 -0
- package/dist/context/MCPUIStringsContext.d.ts.map +1 -1
- package/dist/context/MCPUIStringsContext.js +12 -1
- package/dist/context/MCPUIStringsContext.js.map +1 -1
- package/dist/services/component-registry.cjs +9 -2
- package/dist/services/component-registry.cjs.map +1 -1
- package/dist/services/component-registry.d.ts.map +1 -1
- package/dist/services/component-registry.js +9 -2
- package/dist/services/component-registry.js.map +1 -1
- package/dist/services/validation.cjs +31 -8
- package/dist/services/validation.cjs.map +1 -1
- package/dist/services/validation.d.ts.map +1 -1
- package/dist/services/validation.js +31 -8
- package/dist/services/validation.js.map +1 -1
- package/dist/types/index.d.ts +14 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/degraded-projections.cjs +19 -3
- package/dist/utils/degraded-projections.cjs.map +1 -1
- package/dist/utils/degraded-projections.d.ts +22 -2
- package/dist/utils/degraded-projections.d.ts.map +1 -1
- package/dist/utils/degraded-projections.js +19 -3
- package/dist/utils/degraded-projections.js.map +1 -1
- package/dist/utils/math-markdown.cjs +1 -1
- package/dist/utils/math-markdown.cjs.map +1 -1
- package/dist/utils/math-markdown.js +1 -1
- package/dist/utils/math-markdown.js.map +1 -1
- package/dist/utils/missing-value.cjs +60 -0
- package/dist/utils/missing-value.cjs.map +1 -0
- package/dist/utils/missing-value.d.ts +79 -0
- package/dist/utils/missing-value.d.ts.map +1 -0
- package/dist/utils/missing-value.js +60 -0
- package/dist/utils/missing-value.js.map +1 -0
- package/dist/utils/theme.cjs +91 -0
- package/dist/utils/theme.cjs.map +1 -0
- package/dist/utils/theme.d.ts +11 -0
- package/dist/utils/theme.d.ts.map +1 -0
- package/dist/utils/theme.js +91 -0
- package/dist/utils/theme.js.map +1 -0
- package/docs/SECURITY-DEPENDENCIES.md +81 -0
- package/docs/THEMING.md +205 -0
- package/package.json +7 -5
- package/src/components/ActionGroupRenderer.tsx +6 -6
- package/src/components/AutocompleteDropdown.tsx +17 -17
- package/src/components/AutocompleteFormField.tsx +10 -9
- package/src/components/ChartJSRenderer.tsx +609 -212
- package/src/components/ChatPrompt.tsx +16 -16
- package/src/components/ComponentToolbar.tsx +5 -5
- package/src/components/DegradedFallback.tsx +33 -11
- package/src/components/ExpandableWrapper.tsx +15 -11
- package/src/components/FormFieldRenderer.tsx +52 -51
- package/src/components/FormRenderer.tsx +12 -12
- package/src/components/GenerativeUIErrorBoundary.tsx +6 -6
- package/src/components/GhostText.tsx +7 -7
- package/src/components/GraphRenderer.tsx +83 -67
- package/src/components/MissingValue.tsx +61 -0
- package/src/components/ModalRenderer.tsx +11 -5
- package/src/components/PortalDropdownMenu.tsx +6 -2
- package/src/components/ScratchpadPanel.tsx +144 -141
- package/src/components/UIResourceRenderer.tsx +143 -110
- package/src/components/chart-data-table.ts +50 -6
- package/src/components/chart-missing-plugin.ts +336 -0
- package/src/context/MCPUIStringsContext.tsx +76 -0
- package/src/services/component-registry.ts +10 -2
- package/src/services/validation.ts +44 -9
- package/src/styles/autocomplete.css +53 -53
- package/src/types/index.ts +13 -1
- package/src/utils/degraded-projections.ts +44 -4
- package/src/utils/math-markdown.ts +1 -1
- package/src/utils/missing-value.ts +127 -0
- package/src/utils/theme.ts +101 -0
|
@@ -2,12 +2,12 @@ import { getNextElement, insert, createComponent, effect, setAttribute, classNam
|
|
|
2
2
|
import { Show, Switch, Match, For, createSignal, createEffect, onCleanup } from "solid-js";
|
|
3
3
|
import { FormFieldRenderer } from "./FormFieldRenderer.js";
|
|
4
4
|
import { useMCPUIStrings } from "../context/MCPUIStringsContext.js";
|
|
5
|
-
var _tmpl$ = /* @__PURE__ */ template(`<div class="w-full max-w-2xl mx-auto mb-2 bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 shadow-lg overflow-visible"role=dialog style="animation:chat-prompt-slide-up 0.2s ease-out"><div class="flex items-center justify-between px-4 py-2.5 border-b border-gray-100 dark:border-gray-700"><p class="text-sm font-medium text-gray-900 dark:text-white"></p><button></button></div><div class="px-4 py-3"></div><style>
|
|
5
|
+
var _tmpl$ = /* @__PURE__ */ template(`<div class="mcp-ui-root w-full max-w-2xl mx-auto mb-2 bg-[color:var(--mcp-ui-surface,var(--color-white,#fff))] dark:bg-[color:var(--mcp-ui-surface,var(--color-gray-800,#1f2937))] rounded-xl border border-[color:var(--mcp-ui-border,var(--color-gray-200,#e5e7eb))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-700,#374151))] shadow-[var(--mcp-ui-shadow,var(--shadow-lg))] overflow-visible"role=dialog style="animation:chat-prompt-slide-up 0.2s ease-out"><div class="flex items-center justify-between px-4 py-2.5 border-b border-[color:var(--mcp-ui-border,var(--color-gray-100,#f3f4f6))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-700,#374151))]"><p class="text-sm font-medium text-[color:var(--mcp-ui-fg,var(--color-gray-900,#111827))] dark:text-[color:var(--mcp-ui-fg,var(--color-white,#fff))]"></p><button></button></div><div class="px-4 py-3"></div><style>
|
|
6
6
|
@keyframes chat-prompt-slide-up {
|
|
7
7
|
from { opacity: 0; transform: translateY(8px); }
|
|
8
8
|
to { opacity: 1; transform: translateY(0); }
|
|
9
9
|
}
|
|
10
|
-
`), _tmpl$2 = /* @__PURE__ */ template(`<svg class="w-4 h-4"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$3 = /* @__PURE__ */ template(`<div>`), _tmpl$4 = /* @__PURE__ */ template(`<button type=button>`), _tmpl$5 = /* @__PURE__ */ template(`<span class=mr-2>`), _tmpl$6 = /* @__PURE__ */ template(`<span class="block text-xs text-gray-500 dark:text-gray-400 mt-0.5 font-normal">`), _tmpl$7 = /* @__PURE__ */ template(`<p class="text-sm text-gray-600 dark:text-gray-400 mb-3">`), _tmpl$8 = /* @__PURE__ */ template(`<div><!$><!/><div class="flex gap-2 justify-end"><button class="px-4 py-2 text-sm font-medium rounded-lg border border-gray-200 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"></button><button>`), _tmpl$9 = /* @__PURE__ */ template(`<p class="text-blue-400 animate-pulse">`), _tmpl$0 = /* @__PURE__ */ template(`<div class="px-3 py-2 bg-blue-50 dark:bg-blue-900
|
|
10
|
+
`), _tmpl$2 = /* @__PURE__ */ template(`<svg class="w-4 h-4"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$3 = /* @__PURE__ */ template(`<div>`), _tmpl$4 = /* @__PURE__ */ template(`<button type=button>`), _tmpl$5 = /* @__PURE__ */ template(`<span class=mr-2>`), _tmpl$6 = /* @__PURE__ */ template(`<span class="block text-xs text-[color:var(--mcp-ui-fg-muted,var(--color-gray-500,#6b7280))] dark:text-[color:var(--mcp-ui-fg-subtle,var(--color-gray-400,#9ca3af))] mt-0.5 font-normal">`), _tmpl$7 = /* @__PURE__ */ template(`<p class="text-sm text-[color:var(--mcp-ui-fg-muted,var(--color-gray-600,#4b5563))] dark:text-[color:var(--mcp-ui-fg-subtle,var(--color-gray-400,#9ca3af))] mb-3">`), _tmpl$8 = /* @__PURE__ */ template(`<div><!$><!/><div class="flex gap-2 justify-end"><button class="px-4 py-2 text-sm font-medium rounded-lg border border-[color:var(--mcp-ui-border,var(--color-gray-200,#e5e7eb))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-600,#4b5563))] text-[color:var(--mcp-ui-fg,var(--color-gray-700,#374151))] dark:text-[color:var(--mcp-ui-fg,var(--color-gray-300,#d1d5db))] 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"></button><button>`), _tmpl$9 = /* @__PURE__ */ template(`<p class="text-[color:var(--mcp-ui-accent,var(--color-blue-400))] animate-pulse">`), _tmpl$0 = /* @__PURE__ */ template(`<div class="px-3 py-2 bg-[color:var(--mcp-ui-accent-soft,var(--color-blue-50))] dark:bg-[color:var(--mcp-ui-accent-soft,color-mix(in_oklab,var(--color-blue-900)_20%,transparent))] rounded-lg border border-[color:var(--mcp-ui-accent-border,var(--color-blue-200))] dark:border-[color:var(--mcp-ui-accent-border,var(--color-blue-800))] text-sm">`), _tmpl$1 = /* @__PURE__ */ template(`<form class="flex flex-col gap-3"><!$><!/><!$><!/><div class="flex justify-end"><button type=submit class="px-4 py-2 text-sm font-medium rounded-lg text-[color:var(--mcp-ui-accent-fg,var(--color-white,#fff))] bg-[color:var(--mcp-ui-accent,var(--color-blue-600))] hover:bg-[color:var(--mcp-ui-accent-hover,var(--color-blue-700))] disabled:bg-[color:var(--mcp-ui-surface-muted,var(--color-gray-400,#9ca3af))] disabled:cursor-not-allowed transition-colors">`), _tmpl$10 = /* @__PURE__ */ template(`<p class="text-[color:var(--mcp-ui-accent,var(--color-blue-700))] dark:text-[color:var(--mcp-ui-accent,var(--color-blue-300))]">`);
|
|
11
11
|
const ChatPrompt = (props) => {
|
|
12
12
|
const strings = useMCPUIStrings();
|
|
13
13
|
if (!props.config) return null;
|
|
@@ -99,7 +99,7 @@ const ChatPrompt = (props) => {
|
|
|
99
99
|
}
|
|
100
100
|
}));
|
|
101
101
|
effect((_p$) => {
|
|
102
|
-
var _v$ = props.config.title, _v$2 = props.dismissLabel ? "px-3 py-1 text-xs font-medium text-blue-600 dark:text-blue-400 hover:bg-blue-50 dark:hover:bg-blue-900
|
|
102
|
+
var _v$ = props.config.title, _v$2 = props.dismissLabel ? "px-3 py-1 text-xs font-medium text-[color:var(--mcp-ui-accent,var(--color-blue-600))] dark:text-[color:var(--mcp-ui-accent,var(--color-blue-400))] hover:bg-[color:var(--mcp-ui-accent-soft,var(--color-blue-50))] dark:hover:bg-[color:var(--mcp-ui-accent-soft,color-mix(in_oklab,var(--color-blue-900)_20%,transparent))] rounded-lg transition-colors" : "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", _v$3 = props.dismissLabel || strings.dismiss;
|
|
103
103
|
_v$ !== _p$.e && setAttribute(_el$, "aria-label", _p$.e = _v$);
|
|
104
104
|
_v$2 !== _p$.t && className(_el$4, _p$.t = _v$2);
|
|
105
105
|
_v$3 !== _p$.a && setAttribute(_el$4, "aria-label", _p$.a = _v$3);
|
|
@@ -129,7 +129,7 @@ const ChoiceBody = (props) => {
|
|
|
129
129
|
return extra ? `${base} ${extra}` : base;
|
|
130
130
|
};
|
|
131
131
|
const buttonClass = () => {
|
|
132
|
-
const base = "px-4 py-2 text-sm font-medium rounded-lg border border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-700 text-gray-900 dark:text-white hover:bg-blue-50 hover:border-blue-300 dark:hover:bg-blue-900
|
|
132
|
+
const base = "px-4 py-2 text-sm font-medium rounded-lg border border-[color:var(--mcp-ui-border,var(--color-gray-200,#e5e7eb))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-600,#4b5563))] bg-[color:var(--mcp-ui-surface-muted,var(--color-gray-50,#f9fafb))] dark:bg-[color:var(--mcp-ui-surface-muted,var(--color-gray-700,#374151))] text-[color:var(--mcp-ui-fg,var(--color-gray-900,#111827))] dark:text-[color:var(--mcp-ui-fg,var(--color-white,#fff))] hover:bg-[color:var(--mcp-ui-accent-soft,var(--color-blue-50))] hover:border-[color:var(--mcp-ui-accent-border,var(--color-blue-300))] dark:hover:bg-[color:var(--mcp-ui-accent-soft,color-mix(in_oklab,var(--color-blue-900)_30%,transparent))] dark:hover:border-[color:var(--mcp-ui-accent-border,var(--color-blue-600))] transition-colors text-left";
|
|
133
133
|
const extra = props.config.buttonClass;
|
|
134
134
|
return extra ? `${base} ${extra}` : base;
|
|
135
135
|
};
|
|
@@ -199,7 +199,7 @@ const ConfirmBody = (props) => {
|
|
|
199
199
|
insert(_el$12, () => props.config.cancelLabel || strings.cancel);
|
|
200
200
|
addEventListener(_el$13, "click", props.onConfirm, true);
|
|
201
201
|
insert(_el$13, () => props.config.confirmLabel || strings.confirm);
|
|
202
|
-
effect(() => className(_el$13, `px-4 py-2 text-sm font-medium rounded-lg text-white transition-colors ${isDanger() ? "bg-red-600 hover:bg-red-700" : "bg-blue-600 hover:bg-blue-700"}`));
|
|
202
|
+
effect(() => className(_el$13, `px-4 py-2 text-sm font-medium rounded-lg text-[color:var(--mcp-ui-accent-fg,var(--color-white,#fff))] transition-colors ${isDanger() ? "bg-[color:var(--mcp-ui-danger,var(--color-red-600))] hover:bg-[color:var(--mcp-ui-danger-hover,var(--color-red-700))]" : "bg-[color:var(--mcp-ui-accent,var(--color-blue-600))] hover:bg-[color:var(--mcp-ui-accent-hover,var(--color-blue-700))]"}`));
|
|
203
203
|
runHydrationEvents();
|
|
204
204
|
return _el$1;
|
|
205
205
|
})();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatPrompt.js","sources":["../../src/components/ChatPrompt.tsx"],"sourcesContent":["/**\n * ChatPrompt — Ephemeral structured interaction above chat input\n * v2.4.0: choice, confirm, form subtypes\n *\n * @experimental — This component may change without major bump until v2.5.0.\n *\n * Renders above the chat input. User responds → consumer calls `onSubmit` →\n * prompt disappears.\n *\n * ## AbortSignal — known limitation (v5.1.0)\n *\n * **`ChatPrompt` itself does NOT listen to any `AbortSignal`.** It is a pure\n * presentation component: render a config, call `onSubmit` on user answer,\n * call `onDismiss` on X/Cancel. Lifecycle (including abort handling) is the\n * consumer's responsibility.\n *\n * `ChatCommands.showChatPrompt(config, signal?)` declares a `signal?` argument\n * in its type, but in v5.0.0/v5.1.0 mcp-ui ships **no default handler** for\n * this command — every consumer wires its own `bus.commands.handle('showChatPrompt', ...)`.\n * Each consumer's handler is responsible for:\n *\n * 1. Storing a `{ resolve, reject }` pair when the command fires.\n * 2. Calling `resolve(response)` from `onSubmit` / `resolve(dismissed)` from `onDismiss`.\n * 3. If a `signal` is provided: `signal.addEventListener('abort', () =>\n * reject(new DOMException('Prompt aborted', 'AbortError')))` and cleaning\n * up the listener on resolve/dismiss.\n *\n * The `DOMException('AbortError')` shape is the Web Platform convention\n * (matches `fetch()`, `Response.body.cancel()`, `WritableStream.abort()`).\n * Consumers can branch on `err.name === 'AbortError'` without importing any\n * mcp-ui type.\n *\n * A `createChatPromptController()` primitive centralising this wiring\n * (resolver lifecycle + re-entrance + abort) is planned for v5.2.0 — see\n * `docs/2026/r&d/mcpui-v5.1.0-consensus.md` for the design discussion.\n *\n * ## Re-entrance — known limitation (v5.1.0)\n *\n * Also handled by the consumer. If a new `showChatPrompt` arrives while a\n * previous one is active, the consumer's handler must decide whether to\n * auto-reject the previous Promise, queue, or throw. mcp-ui does not\n * currently enforce any policy. See the same design doc for the v5.2.0\n * direction (auto-reject with `PromptReplacedError`).\n */\n\nimport { Component, Show, For, createSignal, createEffect, onCleanup, Switch, Match } from 'solid-js'\nimport type {\n ChatPromptConfig,\n ChatPromptResponse,\n ChoicePromptConfig,\n ConfirmPromptConfig,\n FormPromptConfig,\n} from '../types/chat-bus'\nimport { FormFieldRenderer } from './FormFieldRenderer'\nimport { useMCPUIStrings } from '../context/MCPUIStringsContext'\nimport type { FormFieldParams } from '../types'\n\nexport interface ChatPromptProps {\n /** Prompt configuration */\n config: ChatPromptConfig\n /** Called when user responds */\n onSubmit: (response: ChatPromptResponse) => void\n /** Called when user dismisses (e.g. \"send as-is\") */\n onDismiss?: () => void\n /** Label for the dismiss button (replaces X icon). Default: shows X icon. */\n dismissLabel?: string\n}\n\n/**\n * @experimental\n * Ephemeral interaction component — choice buttons, confirmation dialog, or quick form.\n * Designed to sit between the chat messages and the input area.\n *\n * @example\n * <ChatPrompt\n * config={{ type: 'choice', title: 'Format?', config: { options: [...] } }}\n * onSubmit={(r) => bus.events.emit('onChatPromptResponse', { streamKey, response: r })}\n * onDismiss={() => setActivePrompt(null)}\n * />\n */\nexport const ChatPrompt: Component<ChatPromptProps> = (props) => {\n const strings = useMCPUIStrings()\n\n // F1: Guard against null/undefined config (e.g. after dismiss clears state)\n if (!props.config) return null\n\n return (\n <div\n class=\"w-full max-w-2xl mx-auto mb-2 bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 shadow-lg overflow-visible\"\n style={{ animation: 'chat-prompt-slide-up 0.2s ease-out' }}\n role=\"dialog\"\n aria-label={props.config.title}\n >\n {/* Header */}\n <div class=\"flex items-center justify-between px-4 py-2.5 border-b border-gray-100 dark:border-gray-700\">\n <p class=\"text-sm font-medium text-gray-900 dark:text-white\">{props.config.title}</p>\n <button\n onClick={() => {\n props.onDismiss?.()\n props.onSubmit({ type: props.config.type, value: '', label: '', dismissed: true })\n }}\n class={props.dismissLabel\n ? 'px-3 py-1 text-xs font-medium text-blue-600 dark:text-blue-400 hover:bg-blue-50 dark:hover:bg-blue-900/20 rounded-lg transition-colors'\n : '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 }\n aria-label={props.dismissLabel || strings.dismiss}\n >\n <Show when={props.dismissLabel} fallback={\n <svg class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n }>\n {props.dismissLabel}\n </Show>\n </button>\n </div>\n\n {/* Body — type-specific */}\n <div class=\"px-4 py-3\">\n <Switch>\n <Match when={props.config.type === 'choice'}>\n <ChoiceBody\n config={props.config.config as ChoicePromptConfig}\n onSelect={(value, label) => props.onSubmit({ type: 'choice', value, label })}\n />\n </Match>\n <Match when={props.config.type === 'confirm'}>\n <ConfirmBody\n config={props.config.config as ConfirmPromptConfig}\n onConfirm={() => props.onSubmit({ type: 'confirm', value: 'confirmed', label: (props.config.config as ConfirmPromptConfig).confirmLabel || strings.promptConfirmed })}\n onCancel={() => {\n props.onDismiss?.()\n props.onSubmit({ type: 'confirm', value: 'cancelled', label: (props.config.config as ConfirmPromptConfig).cancelLabel || strings.promptCancelled, dismissed: true })\n }}\n />\n </Match>\n <Match when={props.config.type === 'form'}>\n <FormBody\n config={props.config.config as FormPromptConfig}\n onSubmit={(data, label) => props.onSubmit({ type: 'form', value: data, label })}\n />\n </Match>\n </Switch>\n </div>\n\n <style>{`\n @keyframes chat-prompt-slide-up {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n }\n `}</style>\n </div>\n )\n}\n\n// ─── Choice ──────────────────────────────────────────────────\n\nconst ChoiceBody: Component<{\n config: ChoicePromptConfig\n onSelect: (value: string, label: string) => void\n}> = (props) => {\n const layoutClass = () => {\n const base = (() => {\n switch (props.config.layout) {\n case 'vertical': return 'flex flex-col gap-2'\n case 'grid': return 'grid grid-cols-2 gap-2'\n default: return 'flex flex-wrap gap-2'\n }\n })()\n const extra = props.config.containerClass\n return extra ? `${base} ${extra}` : base\n }\n\n const buttonClass = () => {\n const base = 'px-4 py-2 text-sm font-medium rounded-lg border border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-700 text-gray-900 dark:text-white hover:bg-blue-50 hover:border-blue-300 dark:hover:bg-blue-900/30 dark:hover:border-blue-600 transition-colors text-left'\n const extra = props.config.buttonClass\n return extra ? `${base} ${extra}` : base\n }\n\n return (\n <div class={layoutClass()}>\n <For each={props.config.options}>\n {(option, i) => (\n <button\n type=\"button\"\n onClick={() => props.onSelect(option.value, option.label)}\n class={buttonClass()}\n >\n <Show\n when={props.config.optionRenderer}\n fallback={\n <>\n <Show when={option.icon}>\n <span class=\"mr-2\">{option.icon}</span>\n </Show>\n {option.label}\n <Show when={option.description}>\n <span class=\"block text-xs text-gray-500 dark:text-gray-400 mt-0.5 font-normal\">{option.description}</span>\n </Show>\n </>\n }\n >\n {props.config.optionRenderer!(option, i())}\n </Show>\n </button>\n )}\n </For>\n </div>\n )\n}\n\n// ─── Confirm ─────────────────────────────────────────────────\n\nconst ConfirmBody: Component<{\n config: ConfirmPromptConfig\n onConfirm: () => void\n onCancel: () => void\n}> = (props) => {\n const strings = useMCPUIStrings()\n const isDanger = () => props.config.variant === 'danger'\n\n return (\n <div>\n <Show when={props.config.message}>\n <p class=\"text-sm text-gray-600 dark:text-gray-400 mb-3\">{props.config.message}</p>\n </Show>\n <div class=\"flex gap-2 justify-end\">\n <button\n onClick={props.onCancel}\n class=\"px-4 py-2 text-sm font-medium rounded-lg border border-gray-200 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors\"\n >\n {props.config.cancelLabel || strings.cancel}\n </button>\n <button\n onClick={props.onConfirm}\n class={`px-4 py-2 text-sm font-medium rounded-lg text-white transition-colors ${\n isDanger()\n ? 'bg-red-600 hover:bg-red-700'\n : 'bg-blue-600 hover:bg-blue-700'\n }`}\n >\n {props.config.confirmLabel || strings.confirm}\n </button>\n </div>\n </div>\n )\n}\n\n// ─── Form (delegates to FormFieldRenderer for all field types) ───\n\nconst FormBody: Component<{\n config: FormPromptConfig\n onSubmit: (data: Record<string, unknown>, label: string) => void\n}> = (props) => {\n const strings = useMCPUIStrings()\n const [formData, setFormData] = createSignal<Record<string, any>>({})\n const [dynamicOptions, setDynamicOptions] = createSignal<Record<string, Array<{ label: string; value: string }>>>({})\n const [previewText, setPreviewText] = createSignal<string>('')\n const [previewLoading, setPreviewLoading] = createSignal(false)\n let previewTimer: ReturnType<typeof setTimeout> | null = null\n\n const updateField = (name: string, value: any) => {\n setFormData((prev) => ({ ...prev, [name]: value }))\n }\n\n // --- depends_on: fetch child options when parent changes ---\n createEffect(() => {\n const data = formData()\n for (const field of props.config.fields || []) {\n const dep = field.dependsOn || (field as any).depends_on\n if (!dep) continue\n const parentValue = data[dep.field]\n if (!parentValue) continue\n\n const apiUrl = (dep.apiUrl || dep.api_url || '').replace('{value}', encodeURIComponent(parentValue))\n if (!apiUrl) continue\n\n const params = new URLSearchParams(dep.extraParams || dep.extra_params || {})\n fetch(`${apiUrl}?${params}`)\n .then((r) => r.json())\n .then((items) => {\n const arr = Array.isArray(items) ? items : items.results || items.features || []\n const labelKey = dep.labelField || dep.label_field || 'label'\n const valueKey = dep.valueField || dep.value_field || 'value'\n setDynamicOptions((prev) => ({\n ...prev,\n [field.name]: arr.map((item: any) => ({\n label: item[labelKey] || String(item),\n value: String(item[valueKey] || item[labelKey] || item),\n })),\n }))\n })\n .catch(() => {})\n }\n })\n\n // --- preview: debounced live preview ---\n createEffect(() => {\n const preview = props.config.preview\n if (!preview) return\n\n const data = formData()\n // Check if any preview field has a value\n const hasValues = preview.fields.some((f) => {\n const v = data[f]\n return v !== undefined && v !== '' && !(Array.isArray(v) && v.length === 0)\n })\n if (!hasValues) { setPreviewText(''); return }\n\n if (previewTimer) clearTimeout(previewTimer)\n previewTimer = setTimeout(async () => {\n setPreviewLoading(true)\n try {\n const body: Record<string, any> = {}\n for (const f of preview.fields) {\n if (data[f] !== undefined) body[f] = data[f]\n }\n const res = await fetch(preview.endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include',\n body: JSON.stringify(body),\n })\n if (res.ok) {\n const result = await res.json()\n setPreviewText(result.summary_fr || result.summary || result.message || JSON.stringify(result))\n }\n } catch {\n setPreviewText('')\n }\n setPreviewLoading(false)\n }, preview.debounceMs || 500)\n })\n\n onCleanup(() => { if (previewTimer) clearTimeout(previewTimer) })\n\n const handleSubmit = (e: Event) => {\n e.preventDefault()\n const data = formData()\n const label = Object.entries(data)\n .filter(([, v]) => v !== undefined && v !== '' && !(Array.isArray(v) && v.length === 0))\n .map(([k, v]) => `${k}: ${Array.isArray(v) ? v.join(', ') : v}`)\n .join(', ')\n props.onSubmit(data, label || strings.promptFormSubmitted)\n }\n\n const isValid = () => {\n const data = formData()\n return (props.config.fields || [])\n .filter((f) => f.required)\n .every((f) => {\n const val = data[f.name]\n if (Array.isArray(val)) return val.length > 0\n if (typeof val === 'boolean') return true\n return val !== undefined && val !== ''\n })\n }\n\n // Build field with dynamic options override\n const getField = (field: any): FormFieldParams => {\n const dynOpts = dynamicOptions()[field.name]\n if (dynOpts) {\n return { ...field, options: dynOpts } as FormFieldParams\n }\n return field as FormFieldParams\n }\n\n return (\n <form onSubmit={handleSubmit} class=\"flex flex-col gap-3\">\n <For each={props.config.fields}>\n {(field) => (\n <FormFieldRenderer\n field={getField(field)}\n value={formData()[field.name]}\n onChange={(val) => updateField(field.name, val)}\n formData={formData}\n />\n )}\n </For>\n\n {/* Live preview */}\n <Show when={previewText() || previewLoading()}>\n <div class=\"px-3 py-2 bg-blue-50 dark:bg-blue-900/20 rounded-lg border border-blue-200 dark:border-blue-800 text-sm\">\n <Show when={previewLoading()} fallback={\n <p class=\"text-blue-700 dark:text-blue-300\">{previewText()}</p>\n }>\n <p class=\"text-blue-400 animate-pulse\">{strings.promptLoadingPreview}</p>\n </Show>\n </div>\n </Show>\n\n <div class=\"flex justify-end\">\n <button\n type=\"submit\"\n disabled={!isValid()}\n class=\"px-4 py-2 text-sm font-medium rounded-lg text-white bg-blue-600 hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors\"\n >\n {props.config.submitLabel || strings.submit}\n </button>\n </div>\n </form>\n )\n}\n"],"names":["ChatPrompt","props","strings","useMCPUIStrings","config","_el$","_$getNextElement","_tmpl$","_el$2","firstChild","_el$3","_el$4","nextSibling","_el$5","_$insert","title","$$click","onDismiss","onSubmit","type","value","label","dismissed","_$createComponent","Show","when","dismissLabel","fallback","_tmpl$2","children","Switch","Match","ChoiceBody","onSelect","ConfirmBody","onConfirm","confirmLabel","promptConfirmed","onCancel","cancelLabel","promptCancelled","FormBody","data","_$effect","_p$","_v$","_v$2","_v$3","dismiss","e","_$setAttribute","t","_$className","a","undefined","_$runHydrationEvents","layoutClass","base","layout","extra","containerClass","buttonClass","_el$7","_tmpl$3","For","each","options","option","i","_el$8","_tmpl$4","optionRenderer","icon","_el$9","_tmpl$5","_$memo","description","_el$0","_tmpl$6","isDanger","variant","_el$1","_tmpl$8","_el$14","_el$15","_co$","_$getNextMarker","_el$11","_el$12","_el$13","message","_el$10","_tmpl$7","_$addEventListener","cancel","confirm","formData","setFormData","createSignal","dynamicOptions","setDynamicOptions","previewText","setPreviewText","previewLoading","setPreviewLoading","previewTimer","updateField","name","prev","createEffect","field","fields","dep","dependsOn","depends_on","parentValue","apiUrl","api_url","replace","encodeURIComponent","params","URLSearchParams","extraParams","extra_params","fetch","then","r","json","items","arr","Array","isArray","results","features","labelKey","labelField","label_field","valueKey","valueField","value_field","map","item","String","catch","preview","hasValues","some","f","v","length","setTimeout","body","res","endpoint","method","headers","credentials","JSON","stringify","ok","result","summary_fr","summary","debounceMs","onCleanup","handleSubmit","preventDefault","Object","entries","filter","k","join","promptFormSubmitted","isValid","required","every","val","getField","dynOpts","_el$16","_tmpl$1","_el$21","_el$22","_co$2","_el$23","_el$24","_co$3","_el$19","_el$20","addEventListener","FormFieldRenderer","onChange","_el$17","_tmpl$0","_el$25","_tmpl$10","_el$18","_tmpl$9","promptLoadingPreview","submitLabel","submit","_$setProperty","_$delegateEvents"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ChatPrompt.js","sources":["../../src/components/ChatPrompt.tsx"],"sourcesContent":["/**\n * ChatPrompt — Ephemeral structured interaction above chat input\n * v2.4.0: choice, confirm, form subtypes\n *\n * @experimental — This component may change without major bump until v2.5.0.\n *\n * Renders above the chat input. User responds → consumer calls `onSubmit` →\n * prompt disappears.\n *\n * ## AbortSignal — known limitation (v5.1.0)\n *\n * **`ChatPrompt` itself does NOT listen to any `AbortSignal`.** It is a pure\n * presentation component: render a config, call `onSubmit` on user answer,\n * call `onDismiss` on X/Cancel. Lifecycle (including abort handling) is the\n * consumer's responsibility.\n *\n * `ChatCommands.showChatPrompt(config, signal?)` declares a `signal?` argument\n * in its type, but in v5.0.0/v5.1.0 mcp-ui ships **no default handler** for\n * this command — every consumer wires its own `bus.commands.handle('showChatPrompt', ...)`.\n * Each consumer's handler is responsible for:\n *\n * 1. Storing a `{ resolve, reject }` pair when the command fires.\n * 2. Calling `resolve(response)` from `onSubmit` / `resolve(dismissed)` from `onDismiss`.\n * 3. If a `signal` is provided: `signal.addEventListener('abort', () =>\n * reject(new DOMException('Prompt aborted', 'AbortError')))` and cleaning\n * up the listener on resolve/dismiss.\n *\n * The `DOMException('AbortError')` shape is the Web Platform convention\n * (matches `fetch()`, `Response.body.cancel()`, `WritableStream.abort()`).\n * Consumers can branch on `err.name === 'AbortError'` without importing any\n * mcp-ui type.\n *\n * A `createChatPromptController()` primitive centralising this wiring\n * (resolver lifecycle + re-entrance + abort) is planned for v5.2.0 — see\n * `docs/2026/r&d/mcpui-v5.1.0-consensus.md` for the design discussion.\n *\n * ## Re-entrance — known limitation (v5.1.0)\n *\n * Also handled by the consumer. If a new `showChatPrompt` arrives while a\n * previous one is active, the consumer's handler must decide whether to\n * auto-reject the previous Promise, queue, or throw. mcp-ui does not\n * currently enforce any policy. See the same design doc for the v5.2.0\n * direction (auto-reject with `PromptReplacedError`).\n */\n\nimport { Component, Show, For, createSignal, createEffect, onCleanup, Switch, Match } from 'solid-js'\nimport type {\n ChatPromptConfig,\n ChatPromptResponse,\n ChoicePromptConfig,\n ConfirmPromptConfig,\n FormPromptConfig,\n} from '../types/chat-bus'\nimport { FormFieldRenderer } from './FormFieldRenderer'\nimport { useMCPUIStrings } from '../context/MCPUIStringsContext'\nimport type { FormFieldParams } from '../types'\n\nexport interface ChatPromptProps {\n /** Prompt configuration */\n config: ChatPromptConfig\n /** Called when user responds */\n onSubmit: (response: ChatPromptResponse) => void\n /** Called when user dismisses (e.g. \"send as-is\") */\n onDismiss?: () => void\n /** Label for the dismiss button (replaces X icon). Default: shows X icon. */\n dismissLabel?: string\n}\n\n/**\n * @experimental\n * Ephemeral interaction component — choice buttons, confirmation dialog, or quick form.\n * Designed to sit between the chat messages and the input area.\n *\n * @example\n * <ChatPrompt\n * config={{ type: 'choice', title: 'Format?', config: { options: [...] } }}\n * onSubmit={(r) => bus.events.emit('onChatPromptResponse', { streamKey, response: r })}\n * onDismiss={() => setActivePrompt(null)}\n * />\n */\nexport const ChatPrompt: Component<ChatPromptProps> = (props) => {\n const strings = useMCPUIStrings()\n\n // F1: Guard against null/undefined config (e.g. after dismiss clears state)\n if (!props.config) return null\n\n return (\n <div\n class=\"mcp-ui-root w-full max-w-2xl mx-auto mb-2 bg-[color:var(--mcp-ui-surface,var(--color-white,#fff))] dark:bg-[color:var(--mcp-ui-surface,var(--color-gray-800,#1f2937))] rounded-xl border border-[color:var(--mcp-ui-border,var(--color-gray-200,#e5e7eb))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-700,#374151))] shadow-[var(--mcp-ui-shadow,var(--shadow-lg))] overflow-visible\"\n style={{ animation: 'chat-prompt-slide-up 0.2s ease-out' }}\n role=\"dialog\"\n aria-label={props.config.title}\n >\n {/* Header */}\n <div class=\"flex items-center justify-between px-4 py-2.5 border-b border-[color:var(--mcp-ui-border,var(--color-gray-100,#f3f4f6))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-700,#374151))]\">\n <p class=\"text-sm font-medium text-[color:var(--mcp-ui-fg,var(--color-gray-900,#111827))] dark:text-[color:var(--mcp-ui-fg,var(--color-white,#fff))]\">{props.config.title}</p>\n <button\n onClick={() => {\n props.onDismiss?.()\n props.onSubmit({ type: props.config.type, value: '', label: '', dismissed: true })\n }}\n class={props.dismissLabel\n ? 'px-3 py-1 text-xs font-medium text-[color:var(--mcp-ui-accent,var(--color-blue-600))] dark:text-[color:var(--mcp-ui-accent,var(--color-blue-400))] hover:bg-[color:var(--mcp-ui-accent-soft,var(--color-blue-50))] dark:hover:bg-[color:var(--mcp-ui-accent-soft,color-mix(in_oklab,var(--color-blue-900)_20%,transparent))] rounded-lg transition-colors'\n : '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 }\n aria-label={props.dismissLabel || strings.dismiss}\n >\n <Show when={props.dismissLabel} fallback={\n <svg class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n }>\n {props.dismissLabel}\n </Show>\n </button>\n </div>\n\n {/* Body — type-specific */}\n <div class=\"px-4 py-3\">\n <Switch>\n <Match when={props.config.type === 'choice'}>\n <ChoiceBody\n config={props.config.config as ChoicePromptConfig}\n onSelect={(value, label) => props.onSubmit({ type: 'choice', value, label })}\n />\n </Match>\n <Match when={props.config.type === 'confirm'}>\n <ConfirmBody\n config={props.config.config as ConfirmPromptConfig}\n onConfirm={() => props.onSubmit({ type: 'confirm', value: 'confirmed', label: (props.config.config as ConfirmPromptConfig).confirmLabel || strings.promptConfirmed })}\n onCancel={() => {\n props.onDismiss?.()\n props.onSubmit({ type: 'confirm', value: 'cancelled', label: (props.config.config as ConfirmPromptConfig).cancelLabel || strings.promptCancelled, dismissed: true })\n }}\n />\n </Match>\n <Match when={props.config.type === 'form'}>\n <FormBody\n config={props.config.config as FormPromptConfig}\n onSubmit={(data, label) => props.onSubmit({ type: 'form', value: data, label })}\n />\n </Match>\n </Switch>\n </div>\n\n <style>{`\n @keyframes chat-prompt-slide-up {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n }\n `}</style>\n </div>\n )\n}\n\n// ─── Choice ──────────────────────────────────────────────────\n\nconst ChoiceBody: Component<{\n config: ChoicePromptConfig\n onSelect: (value: string, label: string) => void\n}> = (props) => {\n const layoutClass = () => {\n const base = (() => {\n switch (props.config.layout) {\n case 'vertical': return 'flex flex-col gap-2'\n case 'grid': return 'grid grid-cols-2 gap-2'\n default: return 'flex flex-wrap gap-2'\n }\n })()\n const extra = props.config.containerClass\n return extra ? `${base} ${extra}` : base\n }\n\n const buttonClass = () => {\n const base = 'px-4 py-2 text-sm font-medium rounded-lg border border-[color:var(--mcp-ui-border,var(--color-gray-200,#e5e7eb))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-600,#4b5563))] bg-[color:var(--mcp-ui-surface-muted,var(--color-gray-50,#f9fafb))] dark:bg-[color:var(--mcp-ui-surface-muted,var(--color-gray-700,#374151))] text-[color:var(--mcp-ui-fg,var(--color-gray-900,#111827))] dark:text-[color:var(--mcp-ui-fg,var(--color-white,#fff))] hover:bg-[color:var(--mcp-ui-accent-soft,var(--color-blue-50))] hover:border-[color:var(--mcp-ui-accent-border,var(--color-blue-300))] dark:hover:bg-[color:var(--mcp-ui-accent-soft,color-mix(in_oklab,var(--color-blue-900)_30%,transparent))] dark:hover:border-[color:var(--mcp-ui-accent-border,var(--color-blue-600))] transition-colors text-left'\n const extra = props.config.buttonClass\n return extra ? `${base} ${extra}` : base\n }\n\n return (\n <div class={layoutClass()}>\n <For each={props.config.options}>\n {(option, i) => (\n <button\n type=\"button\"\n onClick={() => props.onSelect(option.value, option.label)}\n class={buttonClass()}\n >\n <Show\n when={props.config.optionRenderer}\n fallback={\n <>\n <Show when={option.icon}>\n <span class=\"mr-2\">{option.icon}</span>\n </Show>\n {option.label}\n <Show when={option.description}>\n <span class=\"block text-xs text-[color:var(--mcp-ui-fg-muted,var(--color-gray-500,#6b7280))] dark:text-[color:var(--mcp-ui-fg-subtle,var(--color-gray-400,#9ca3af))] mt-0.5 font-normal\">{option.description}</span>\n </Show>\n </>\n }\n >\n {props.config.optionRenderer!(option, i())}\n </Show>\n </button>\n )}\n </For>\n </div>\n )\n}\n\n// ─── Confirm ─────────────────────────────────────────────────\n\nconst ConfirmBody: Component<{\n config: ConfirmPromptConfig\n onConfirm: () => void\n onCancel: () => void\n}> = (props) => {\n const strings = useMCPUIStrings()\n const isDanger = () => props.config.variant === 'danger'\n\n return (\n <div>\n <Show when={props.config.message}>\n <p class=\"text-sm text-[color:var(--mcp-ui-fg-muted,var(--color-gray-600,#4b5563))] dark:text-[color:var(--mcp-ui-fg-subtle,var(--color-gray-400,#9ca3af))] mb-3\">{props.config.message}</p>\n </Show>\n <div class=\"flex gap-2 justify-end\">\n <button\n onClick={props.onCancel}\n class=\"px-4 py-2 text-sm font-medium rounded-lg border border-[color:var(--mcp-ui-border,var(--color-gray-200,#e5e7eb))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-600,#4b5563))] text-[color:var(--mcp-ui-fg,var(--color-gray-700,#374151))] dark:text-[color:var(--mcp-ui-fg,var(--color-gray-300,#d1d5db))] 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 >\n {props.config.cancelLabel || strings.cancel}\n </button>\n <button\n onClick={props.onConfirm}\n class={`px-4 py-2 text-sm font-medium rounded-lg text-[color:var(--mcp-ui-accent-fg,var(--color-white,#fff))] transition-colors ${\n isDanger()\n ? 'bg-[color:var(--mcp-ui-danger,var(--color-red-600))] hover:bg-[color:var(--mcp-ui-danger-hover,var(--color-red-700))]'\n : 'bg-[color:var(--mcp-ui-accent,var(--color-blue-600))] hover:bg-[color:var(--mcp-ui-accent-hover,var(--color-blue-700))]'\n }`}\n >\n {props.config.confirmLabel || strings.confirm}\n </button>\n </div>\n </div>\n )\n}\n\n// ─── Form (delegates to FormFieldRenderer for all field types) ───\n\nconst FormBody: Component<{\n config: FormPromptConfig\n onSubmit: (data: Record<string, unknown>, label: string) => void\n}> = (props) => {\n const strings = useMCPUIStrings()\n const [formData, setFormData] = createSignal<Record<string, any>>({})\n const [dynamicOptions, setDynamicOptions] = createSignal<Record<string, Array<{ label: string; value: string }>>>({})\n const [previewText, setPreviewText] = createSignal<string>('')\n const [previewLoading, setPreviewLoading] = createSignal(false)\n let previewTimer: ReturnType<typeof setTimeout> | null = null\n\n const updateField = (name: string, value: any) => {\n setFormData((prev) => ({ ...prev, [name]: value }))\n }\n\n // --- depends_on: fetch child options when parent changes ---\n createEffect(() => {\n const data = formData()\n for (const field of props.config.fields || []) {\n const dep = field.dependsOn || (field as any).depends_on\n if (!dep) continue\n const parentValue = data[dep.field]\n if (!parentValue) continue\n\n const apiUrl = (dep.apiUrl || dep.api_url || '').replace('{value}', encodeURIComponent(parentValue))\n if (!apiUrl) continue\n\n const params = new URLSearchParams(dep.extraParams || dep.extra_params || {})\n fetch(`${apiUrl}?${params}`)\n .then((r) => r.json())\n .then((items) => {\n const arr = Array.isArray(items) ? items : items.results || items.features || []\n const labelKey = dep.labelField || dep.label_field || 'label'\n const valueKey = dep.valueField || dep.value_field || 'value'\n setDynamicOptions((prev) => ({\n ...prev,\n [field.name]: arr.map((item: any) => ({\n label: item[labelKey] || String(item),\n value: String(item[valueKey] || item[labelKey] || item),\n })),\n }))\n })\n .catch(() => {})\n }\n })\n\n // --- preview: debounced live preview ---\n createEffect(() => {\n const preview = props.config.preview\n if (!preview) return\n\n const data = formData()\n // Check if any preview field has a value\n const hasValues = preview.fields.some((f) => {\n const v = data[f]\n return v !== undefined && v !== '' && !(Array.isArray(v) && v.length === 0)\n })\n if (!hasValues) { setPreviewText(''); return }\n\n if (previewTimer) clearTimeout(previewTimer)\n previewTimer = setTimeout(async () => {\n setPreviewLoading(true)\n try {\n const body: Record<string, any> = {}\n for (const f of preview.fields) {\n if (data[f] !== undefined) body[f] = data[f]\n }\n const res = await fetch(preview.endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include',\n body: JSON.stringify(body),\n })\n if (res.ok) {\n const result = await res.json()\n setPreviewText(result.summary_fr || result.summary || result.message || JSON.stringify(result))\n }\n } catch {\n setPreviewText('')\n }\n setPreviewLoading(false)\n }, preview.debounceMs || 500)\n })\n\n onCleanup(() => { if (previewTimer) clearTimeout(previewTimer) })\n\n const handleSubmit = (e: Event) => {\n e.preventDefault()\n const data = formData()\n const label = Object.entries(data)\n .filter(([, v]) => v !== undefined && v !== '' && !(Array.isArray(v) && v.length === 0))\n .map(([k, v]) => `${k}: ${Array.isArray(v) ? v.join(', ') : v}`)\n .join(', ')\n props.onSubmit(data, label || strings.promptFormSubmitted)\n }\n\n const isValid = () => {\n const data = formData()\n return (props.config.fields || [])\n .filter((f) => f.required)\n .every((f) => {\n const val = data[f.name]\n if (Array.isArray(val)) return val.length > 0\n if (typeof val === 'boolean') return true\n return val !== undefined && val !== ''\n })\n }\n\n // Build field with dynamic options override\n const getField = (field: any): FormFieldParams => {\n const dynOpts = dynamicOptions()[field.name]\n if (dynOpts) {\n return { ...field, options: dynOpts } as FormFieldParams\n }\n return field as FormFieldParams\n }\n\n return (\n <form onSubmit={handleSubmit} class=\"flex flex-col gap-3\">\n <For each={props.config.fields}>\n {(field) => (\n <FormFieldRenderer\n field={getField(field)}\n value={formData()[field.name]}\n onChange={(val) => updateField(field.name, val)}\n formData={formData}\n />\n )}\n </For>\n\n {/* Live preview */}\n <Show when={previewText() || previewLoading()}>\n <div class=\"px-3 py-2 bg-[color:var(--mcp-ui-accent-soft,var(--color-blue-50))] dark:bg-[color:var(--mcp-ui-accent-soft,color-mix(in_oklab,var(--color-blue-900)_20%,transparent))] rounded-lg border border-[color:var(--mcp-ui-accent-border,var(--color-blue-200))] dark:border-[color:var(--mcp-ui-accent-border,var(--color-blue-800))] text-sm\">\n <Show when={previewLoading()} fallback={\n <p class=\"text-[color:var(--mcp-ui-accent,var(--color-blue-700))] dark:text-[color:var(--mcp-ui-accent,var(--color-blue-300))]\">{previewText()}</p>\n }>\n <p class=\"text-[color:var(--mcp-ui-accent,var(--color-blue-400))] animate-pulse\">{strings.promptLoadingPreview}</p>\n </Show>\n </div>\n </Show>\n\n <div class=\"flex justify-end\">\n <button\n type=\"submit\"\n disabled={!isValid()}\n class=\"px-4 py-2 text-sm font-medium rounded-lg text-[color:var(--mcp-ui-accent-fg,var(--color-white,#fff))] bg-[color:var(--mcp-ui-accent,var(--color-blue-600))] hover:bg-[color:var(--mcp-ui-accent-hover,var(--color-blue-700))] disabled:bg-[color:var(--mcp-ui-surface-muted,var(--color-gray-400,#9ca3af))] disabled:cursor-not-allowed transition-colors\"\n >\n {props.config.submitLabel || strings.submit}\n </button>\n </div>\n </form>\n )\n}\n"],"names":["ChatPrompt","props","strings","useMCPUIStrings","config","_el$","_$getNextElement","_tmpl$","_el$2","firstChild","_el$3","_el$4","nextSibling","_el$5","_$insert","title","$$click","onDismiss","onSubmit","type","value","label","dismissed","_$createComponent","Show","when","dismissLabel","fallback","_tmpl$2","children","Switch","Match","ChoiceBody","onSelect","ConfirmBody","onConfirm","confirmLabel","promptConfirmed","onCancel","cancelLabel","promptCancelled","FormBody","data","_$effect","_p$","_v$","_v$2","_v$3","dismiss","e","_$setAttribute","t","_$className","a","undefined","_$runHydrationEvents","layoutClass","base","layout","extra","containerClass","buttonClass","_el$7","_tmpl$3","For","each","options","option","i","_el$8","_tmpl$4","optionRenderer","icon","_el$9","_tmpl$5","_$memo","description","_el$0","_tmpl$6","isDanger","variant","_el$1","_tmpl$8","_el$14","_el$15","_co$","_$getNextMarker","_el$11","_el$12","_el$13","message","_el$10","_tmpl$7","_$addEventListener","cancel","confirm","formData","setFormData","createSignal","dynamicOptions","setDynamicOptions","previewText","setPreviewText","previewLoading","setPreviewLoading","previewTimer","updateField","name","prev","createEffect","field","fields","dep","dependsOn","depends_on","parentValue","apiUrl","api_url","replace","encodeURIComponent","params","URLSearchParams","extraParams","extra_params","fetch","then","r","json","items","arr","Array","isArray","results","features","labelKey","labelField","label_field","valueKey","valueField","value_field","map","item","String","catch","preview","hasValues","some","f","v","length","setTimeout","body","res","endpoint","method","headers","credentials","JSON","stringify","ok","result","summary_fr","summary","debounceMs","onCleanup","handleSubmit","preventDefault","Object","entries","filter","k","join","promptFormSubmitted","isValid","required","every","val","getField","dynOpts","_el$16","_tmpl$1","_el$21","_el$22","_co$2","_el$23","_el$24","_co$3","_el$19","_el$20","addEventListener","FormFieldRenderer","onChange","_el$17","_tmpl$0","_el$25","_tmpl$10","_el$18","_tmpl$9","promptLoadingPreview","submitLabel","submit","_$setProperty","_$delegateEvents"],"mappings":";;;;;;;;;;AAgFO,MAAMA,aAA0CC,CAAAA,UAAU;AAC/D,QAAMC,UAAUC,gBAAAA;AAGhB,MAAI,CAACF,MAAMG,OAAQ,QAAO;AAE1B,UAAA,MAAA;AAAA,QAAAC,OAAAC,eAAAC,MAAA,GAAAC,QAAAH,KAAAI,YAAAC,QAAAF,MAAAC,YAAAE,QAAAD,MAAAE,aAAAC,QAAAL,MAAAI;AAAAE,WAAAJ,OAAA,MAS6JT,MAAMG,OAAOW,KAAK;AAAAJ,UAAAK,UAE9J,MAAM;;AACbf,kBAAMgB,cAANhB;AACAA,YAAMiB,SAAS;AAAA,QAAEC,MAAMlB,MAAMG,OAAOe;AAAAA,QAAMC,OAAO;AAAA,QAAIC,OAAO;AAAA,QAAIC,WAAW;AAAA,MAAA,CAAM;AAAA,IACnF;AAACR,WAAAH,OAAAY,gBAOAC,MAAI;AAAA,MAAA,IAACC,OAAI;AAAA,eAAExB,MAAMyB;AAAAA,MAAY;AAAA,MAAA,IAAEC,WAAQ;AAAA,eAAArB,eAAAsB,OAAA;AAAA,MAAA;AAAA,MAAA,IAAAC,WAAA;AAAA,eAKrC5B,MAAMyB;AAAAA,MAAY;AAAA,IAAA,CAAA,CAAA;AAAAZ,WAAAD,OAAAU,gBAOtBO,QAAM;AAAA,MAAA,IAAAD,WAAA;AAAA,eAAA,CAAAN,gBACJQ,OAAK;AAAA,UAAA,IAACN,OAAI;AAAA,mBAAExB,MAAMG,OAAOe,SAAS;AAAA,UAAQ;AAAA,UAAA,IAAAU,WAAA;AAAA,mBAAAN,gBACxCS,YAAU;AAAA,cAAA,IACT5B,SAAM;AAAA,uBAAEH,MAAMG,OAAOA;AAAAA,cAA4B;AAAA,cACjD6B,UAAUA,CAACb,OAAOC,UAAUpB,MAAMiB,SAAS;AAAA,gBAAEC,MAAM;AAAA,gBAAUC;AAAAA,gBAAOC;AAAAA,cAAAA,CAAO;AAAA,YAAA,CAAC;AAAA,UAAA;AAAA,QAAA,CAAA,GAAAE,gBAG/EQ,OAAK;AAAA,UAAA,IAACN,OAAI;AAAA,mBAAExB,MAAMG,OAAOe,SAAS;AAAA,UAAS;AAAA,UAAA,IAAAU,WAAA;AAAA,mBAAAN,gBACzCW,aAAW;AAAA,cAAA,IACV9B,SAAM;AAAA,uBAAEH,MAAMG,OAAOA;AAAAA,cAA6B;AAAA,cAClD+B,WAAWA,MAAMlC,MAAMiB,SAAS;AAAA,gBAAEC,MAAM;AAAA,gBAAWC,OAAO;AAAA,gBAAaC,OAAQpB,MAAMG,OAAOA,OAA+BgC,gBAAgBlC,QAAQmC;AAAAA,cAAAA,CAAiB;AAAA,cACpKC,UAAUA,MAAM;;AACdrC,4BAAMgB,cAANhB;AACAA,sBAAMiB,SAAS;AAAA,kBAAEC,MAAM;AAAA,kBAAWC,OAAO;AAAA,kBAAaC,OAAQpB,MAAMG,OAAOA,OAA+BmC,eAAerC,QAAQsC;AAAAA,kBAAiBlB,WAAW;AAAA,gBAAA,CAAM;AAAA,cACrK;AAAA,YAAA,CAAC;AAAA,UAAA;AAAA,QAAA,CAAA,GAAAC,gBAGJQ,OAAK;AAAA,UAAA,IAACN,OAAI;AAAA,mBAAExB,MAAMG,OAAOe,SAAS;AAAA,UAAM;AAAA,UAAA,IAAAU,WAAA;AAAA,mBAAAN,gBACtCkB,UAAQ;AAAA,cAAA,IACPrC,SAAM;AAAA,uBAAEH,MAAMG,OAAOA;AAAAA,cAA0B;AAAA,cAC/Cc,UAAUA,CAACwB,MAAMrB,UAAUpB,MAAMiB,SAAS;AAAA,gBAAEC,MAAM;AAAA,gBAAQC,OAAOsB;AAAAA,gBAAMrB;AAAAA,cAAAA,CAAO;AAAA,YAAA,CAAC;AAAA,UAAA;AAAA,QAAA,CAAA,CAAA;AAAA,MAAA;AAAA,IAAA,CAAA,CAAA;AAAAsB,WAAAC,CAAAA,QAAA;AAAA,UAAAC,MAhD3E5C,MAAMG,OAAOW,OAAK+B,OAUnB7C,MAAMyB,eACT,8VACA,mZAAiZqB,OAEzY9C,MAAMyB,gBAAgBxB,QAAQ8C;AAAOH,cAAAD,IAAAK,KAAAC,aAAA7C,MAAA,cAAAuC,IAAAK,IAAAJ,GAAA;AAAAC,eAAAF,IAAAO,KAAAC,UAAAzC,OAAAiC,IAAAO,IAAAL,IAAA;AAAAC,eAAAH,IAAAS,KAAAH,aAAAvC,OAAA,cAAAiC,IAAAS,IAAAN,IAAA;AAAA,aAAAH;AAAAA,IAAA,GAAA;AAAA,MAAAK,GAAAK;AAAAA,MAAAH,GAAAG;AAAAA,MAAAD,GAAAC;AAAAA,IAAAA,CAAA;AAAAC,uBAAAA;AAAA,WAAAlD;AAAAA,EAAA,GAAA;AAgD3D;AAIA,MAAM2B,aAGA/B,CAAAA,UAAU;AACd,QAAMuD,cAAcA,MAAM;AACxB,UAAMC,QAAQ,MAAM;AAClB,cAAQxD,MAAMG,OAAOsD,QAAAA;AAAAA,QACnB,KAAK;AAAY,iBAAO;AAAA,QACxB,KAAK;AAAQ,iBAAO;AAAA,QACpB;AAAS,iBAAO;AAAA,MAAA;AAAA,IAEpB,GAAA;AACA,UAAMC,QAAQ1D,MAAMG,OAAOwD;AAC3B,WAAOD,QAAQ,GAAGF,IAAI,IAAIE,KAAK,KAAKF;AAAAA,EACtC;AAEA,QAAMI,cAAcA,MAAM;AACxB,UAAMJ,OAAO;AACb,UAAME,QAAQ1D,MAAMG,OAAOyD;AAC3B,WAAOF,QAAQ,GAAGF,IAAI,IAAIE,KAAK,KAAKF;AAAAA,EACtC;AAEA,UAAA,MAAA;AAAA,QAAAK,QAAAxD,eAAAyD,OAAA;AAAAjD,WAAAgD,OAAAvC,gBAEKyC,KAAG;AAAA,MAAA,IAACC,OAAI;AAAA,eAAEhE,MAAMG,OAAO8D;AAAAA,MAAO;AAAA,MAAArC,UAC5BA,CAACsC,QAAQC,OAAC,MAAA;AAAA,YAAAC,QAAA/D,eAAAgE,OAAA;AAAAD,cAAArD,UAGE,MAAMf,MAAMgC,SAASkC,OAAO/C,OAAO+C,OAAO9C,KAAK;AAACP,eAAAuD,OAAA9C,gBAGxDC,MAAI;AAAA,UAAA,IACHC,OAAI;AAAA,mBAAExB,MAAMG,OAAOmE;AAAAA,UAAc;AAAA,UAAA,IACjC5C,WAAQ;AAAA,mBAAA,CAAAJ,gBAEHC,MAAI;AAAA,cAAA,IAACC,OAAI;AAAA,uBAAE0C,OAAOK;AAAAA,cAAI;AAAA,cAAA,IAAA3C,WAAA;AAAA,oBAAA4C,QAAAnE,eAAAoE,OAAA;AAAA5D,uBAAA2D,OAAA,MACDN,OAAOK,IAAI;AAAA,uBAAAC;AAAAA,cAAA;AAAA,YAAA,CAAA,GAAAE,WAEhCR,OAAO9C,KAAK,GAAAE,gBACZC,MAAI;AAAA,cAAA,IAACC,OAAI;AAAA,uBAAE0C,OAAOS;AAAAA,cAAW;AAAA,cAAA,IAAA/C,WAAA;AAAA,oBAAAgD,QAAAvE,eAAAwE,OAAA;AAAAhE,uBAAA+D,OAAA,MAC8JV,OAAOS,WAAW;AAAA,uBAAAC;AAAAA,cAAA;AAAA,YAAA,CAAA,CAAA;AAAA,UAAA;AAAA,UAAA,IAAAhD,WAAA;AAAA,mBAKjN5B,MAAMG,OAAOmE,eAAgBJ,QAAQC,GAAG;AAAA,UAAC;AAAA,QAAA,CAAA,CAAA;AAAAzB,qBAAAS,UAAAiB,OAhBrCR,YAAAA,CAAa,CAAA;AAAAN,2BAAAA;AAAA,eAAAc;AAAAA,MAAA,GAAA;AAAA,IAAA,CAmBvB,CAAA;AAAA1B,iBAAAS,UAAAU,OAzBON,YAAAA,CAAa,CAAA;AAAA,WAAAM;AAAAA,EAAA,GAAA;AA6B7B;AAIA,MAAM5B,cAIAjC,CAAAA,UAAU;AACd,QAAMC,UAAUC,gBAAAA;AAChB,QAAM4E,WAAWA,MAAM9E,MAAMG,OAAO4E,YAAY;AAEhD,UAAA,MAAA;AAAA,QAAAC,QAAA3E,eAAA4E,OAAA,GAAAC,SAAAF,MAAAxE,YAAA,CAAA2E,QAAAC,IAAA,IAAAC,cAAAH,OAAAvE,WAAA,GAAA2E,SAAAH,OAAAxE,aAAA4E,SAAAD,OAAA9E,YAAAgF,SAAAD,OAAA5E;AAAAE,WAAAmE,OAAA1D,gBAEKC,MAAI;AAAA,MAAA,IAACC,OAAI;AAAA,eAAExB,MAAMG,OAAOsF;AAAAA,MAAO;AAAA,MAAA,IAAA7D,WAAA;AAAA,YAAA8D,SAAArF,eAAAsF,OAAA;AAAA9E,eAAA6E,QAAA,MACqI1F,MAAMG,OAAOsF,OAAO;AAAA,eAAAC;AAAAA,MAAA;AAAA,IAAA,CAAA,GAAAP,QAAAC,IAAA;AAAAQ,qBAAAL,QAAA,SAI5KvF,MAAMqC,UAAQ,IAAA;AAAAxB,WAAA0E,QAAA,MAGtBvF,MAAMG,OAAOmC,eAAerC,QAAQ4F,MAAM;AAAAD,qBAAAJ,QAAA,SAGlCxF,MAAMkC,WAAS,IAAA;AAAArB,WAAA2E,QAAA,MAOvBxF,MAAMG,OAAOgC,gBAAgBlC,QAAQ6F,OAAO;AAAApD,WAAA,MAAAS,UAAAqC,QANtC,2HACLV,aACI,0HACA,yHAAyH,EAC7H,CAAA;AAAAxB,uBAAAA;AAAA,WAAA0B;AAAAA,EAAA,GAAA;AAOZ;AAIA,MAAMxC,WAGAxC,CAAAA,UAAU;AACd,QAAMC,UAAUC,gBAAAA;AAChB,QAAM,CAAC6F,UAAUC,WAAW,IAAIC,aAAkC,CAAA,CAAE;AACpE,QAAM,CAACC,gBAAgBC,iBAAiB,IAAIF,aAAsE,CAAA,CAAE;AACpH,QAAM,CAACG,aAAaC,cAAc,IAAIJ,aAAqB,EAAE;AAC7D,QAAM,CAACK,gBAAgBC,iBAAiB,IAAIN,aAAa,KAAK;AAC9D,MAAIO,eAAqD;AAEzD,QAAMC,cAAcA,CAACC,MAAcvF,UAAe;AAChD6E,gBAAaW,CAAAA,UAAU;AAAA,MAAE,GAAGA;AAAAA,MAAM,CAACD,IAAI,GAAGvF;AAAAA,IAAAA,EAAQ;AAAA,EACpD;AAGAyF,eAAa,MAAM;AACjB,UAAMnE,OAAOsD,SAAAA;AACb,eAAWc,SAAS7G,MAAMG,OAAO2G,UAAU,CAAA,GAAI;AAC7C,YAAMC,MAAMF,MAAMG,aAAcH,MAAcI;AAC9C,UAAI,CAACF,IAAK;AACV,YAAMG,cAAczE,KAAKsE,IAAIF,KAAK;AAClC,UAAI,CAACK,YAAa;AAElB,YAAMC,UAAUJ,IAAII,UAAUJ,IAAIK,WAAW,IAAIC,QAAQ,WAAWC,mBAAmBJ,WAAW,CAAC;AACnG,UAAI,CAACC,OAAQ;AAEb,YAAMI,SAAS,IAAIC,gBAAgBT,IAAIU,eAAeV,IAAIW,gBAAgB,EAAE;AAC5EC,YAAM,GAAGR,MAAM,IAAII,MAAM,EAAE,EACxBK,KAAMC,CAAAA,MAAMA,EAAEC,KAAAA,CAAM,EACpBF,KAAMG,CAAAA,UAAU;AACf,cAAMC,MAAMC,MAAMC,QAAQH,KAAK,IAAIA,QAAQA,MAAMI,WAAWJ,MAAMK,YAAY,CAAA;AAC9E,cAAMC,WAAWtB,IAAIuB,cAAcvB,IAAIwB,eAAe;AACtD,cAAMC,WAAWzB,IAAI0B,cAAc1B,IAAI2B,eAAe;AACtDvC,0BAAmBQ,CAAAA,UAAU;AAAA,UAC3B,GAAGA;AAAAA,UACH,CAACE,MAAMH,IAAI,GAAGsB,IAAIW,IAAI,CAACC,UAAe;AAAA,YACpCxH,OAAOwH,KAAKP,QAAQ,KAAKQ,OAAOD,IAAI;AAAA,YACpCzH,OAAO0H,OAAOD,KAAKJ,QAAQ,KAAKI,KAAKP,QAAQ,KAAKO,IAAI;AAAA,UAAA,EACtD;AAAA,QAAA,EACF;AAAA,MACJ,CAAC,EACAE,MAAM,MAAM;AAAA,MAAC,CAAC;AAAA,IACnB;AAAA,EACF,CAAC;AAGDlC,eAAa,MAAM;AACjB,UAAMmC,UAAU/I,MAAMG,OAAO4I;AAC7B,QAAI,CAACA,QAAS;AAEd,UAAMtG,OAAOsD,SAAAA;AAEb,UAAMiD,YAAYD,QAAQjC,OAAOmC,KAAMC,CAAAA,MAAM;AAC3C,YAAMC,IAAI1G,KAAKyG,CAAC;AAChB,aAAOC,MAAM9F,UAAa8F,MAAM,MAAM,EAAElB,MAAMC,QAAQiB,CAAC,KAAKA,EAAEC,WAAW;AAAA,IAC3E,CAAC;AACD,QAAI,CAACJ,WAAW;AAAE3C,qBAAe,EAAE;AAAG;AAAA,IAAO;AAE7C,QAAIG,2BAA2BA,YAAY;AAC3CA,mBAAe6C,WAAW,YAAY;AACpC9C,wBAAkB,IAAI;AACtB,UAAI;AACF,cAAM+C,OAA4B,CAAA;AAClC,mBAAWJ,KAAKH,QAAQjC,QAAQ;AAC9B,cAAIrE,KAAKyG,CAAC,MAAM7F,aAAgB6F,CAAC,IAAIzG,KAAKyG,CAAC;AAAA,QAC7C;AACA,cAAMK,MAAM,MAAM5B,MAAMoB,QAAQS,UAAU;AAAA,UACxCC,QAAQ;AAAA,UACRC,SAAS;AAAA,YAAE,gBAAgB;AAAA,UAAA;AAAA,UAC3BC,aAAa;AAAA,UACbL,MAAMM,KAAKC,UAAUP,IAAI;AAAA,QAAA,CAC1B;AACD,YAAIC,IAAIO,IAAI;AACV,gBAAMC,SAAS,MAAMR,IAAIzB,KAAAA;AACzBzB,yBAAe0D,OAAOC,cAAcD,OAAOE,WAAWF,OAAOtE,WAAWmE,KAAKC,UAAUE,MAAM,CAAC;AAAA,QAChG;AAAA,MACF,QAAQ;AACN1D,uBAAe,EAAE;AAAA,MACnB;AACAE,wBAAkB,KAAK;AAAA,IACzB,GAAGwC,QAAQmB,cAAc,GAAG;AAAA,EAC9B,CAAC;AAEDC,YAAU,MAAM;AAAE,QAAI3D,2BAA2BA,YAAY;AAAA,EAAE,CAAC;AAEhE,QAAM4D,eAAeA,CAACpH,MAAa;AACjCA,MAAEqH,eAAAA;AACF,UAAM5H,OAAOsD,SAAAA;AACb,UAAM3E,QAAQkJ,OAAOC,QAAQ9H,IAAI,EAC9B+H,OAAO,CAAC,CAAA,EAAGrB,CAAC,MAAMA,MAAM9F,UAAa8F,MAAM,MAAM,EAAElB,MAAMC,QAAQiB,CAAC,KAAKA,EAAEC,WAAW,EAAE,EACtFT,IAAI,CAAC,CAAC8B,GAAGtB,CAAC,MAAM,GAAGsB,CAAC,KAAKxC,MAAMC,QAAQiB,CAAC,IAAIA,EAAEuB,KAAK,IAAI,IAAIvB,CAAC,EAAE,EAC9DuB,KAAK,IAAI;AACZ1K,UAAMiB,SAASwB,MAAMrB,SAASnB,QAAQ0K,mBAAmB;AAAA,EAC3D;AAEA,QAAMC,UAAUA,MAAM;AACpB,UAAMnI,OAAOsD,SAAAA;AACb,YAAQ/F,MAAMG,OAAO2G,UAAU,CAAA,GAC5B0D,OAAQtB,CAAAA,MAAMA,EAAE2B,QAAQ,EACxBC,MAAO5B,CAAAA,MAAM;AACZ,YAAM6B,MAAMtI,KAAKyG,EAAExC,IAAI;AACvB,UAAIuB,MAAMC,QAAQ6C,GAAG,EAAG,QAAOA,IAAI3B,SAAS;AAC5C,UAAI,OAAO2B,QAAQ,UAAW,QAAO;AACrC,aAAOA,QAAQ1H,UAAa0H,QAAQ;AAAA,IACtC,CAAC;AAAA,EACL;AAGA,QAAMC,WAAWA,CAACnE,UAAgC;AAChD,UAAMoE,UAAU/E,iBAAiBW,MAAMH,IAAI;AAC3C,QAAIuE,SAAS;AACX,aAAO;AAAA,QAAE,GAAGpE;AAAAA,QAAO5C,SAASgH;AAAAA,MAAAA;AAAAA,IAC9B;AACA,WAAOpE;AAAAA,EACT;AAEA,UAAA,MAAA;AAAA,QAAAqE,SAAA7K,eAAA8K,OAAA,GAAAC,SAAAF,OAAA1K,YAAA,CAAA6K,QAAAC,KAAA,IAAAjG,cAAA+F,OAAAzK,WAAA,GAAA4K,SAAAF,OAAA1K,aAAA,CAAA6K,QAAAC,KAAA,IAAApG,cAAAkG,OAAA5K,WAAA,GAAA+K,SAAAF,OAAA7K,aAAAgL,SAAAD,OAAAlL;AAAA0K,WAAAU,iBAAA,UACkBxB,YAAY;AAAAvJ,WAAAqK,QAAA5J,gBACzByC,KAAG;AAAA,MAAA,IAACC,OAAI;AAAA,eAAEhE,MAAMG,OAAO2G;AAAAA,MAAM;AAAA,MAAAlF,UAC1BiF,CAAAA,UAAKvF,gBACJuK,mBAAiB;AAAA,QAAA,IAChBhF,QAAK;AAAA,iBAAEmE,SAASnE,KAAK;AAAA,QAAC;AAAA,QAAA,IACtB1F,QAAK;AAAA,iBAAE4E,SAAAA,EAAWc,MAAMH,IAAI;AAAA,QAAC;AAAA,QAC7BoF,UAAWf,CAAAA,QAAQtE,YAAYI,MAAMH,MAAMqE,GAAG;AAAA,QAC9ChF;AAAAA,MAAAA,CAAkB;AAAA,IAAA,CAErB,GAAAsF,QAAAC,KAAA;AAAAzK,WAAAqK,QAAA5J,gBAIFC,MAAI;AAAA,MAAA,IAACC,OAAI;AAAA,eAAE4E,YAAAA,KAAiBE,eAAAA;AAAAA,MAAgB;AAAA,MAAA,IAAA1E,WAAA;AAAA,YAAAmK,SAAA1L,eAAA2L,OAAA;AAAAnL,eAAAkL,QAAAzK,gBAExCC,MAAI;AAAA,UAAA,IAACC,OAAI;AAAA,mBAAE8E,eAAAA;AAAAA,UAAgB;AAAA,UAAA,IAAE5E,WAAQ;AAAA,oBAAA,MAAA;AAAA,kBAAAuK,SAAA5L,eAAA6L,QAAA;AAAArL,qBAAAoL,QAC6F7F,WAAW;AAAA,qBAAA6F;AAAAA,YAAA,GAAA;AAAA,UAAA;AAAA,UAAA,IAAArK,WAAA;AAAA,gBAAAuK,SAAA9L,eAAA+L,OAAA;AAAAvL,mBAAAsL,QAAA,MAE1DlM,QAAQoM,oBAAoB;AAAA,mBAAAF;AAAAA,UAAA;AAAA,QAAA,CAAA,CAAA;AAAA,eAAAJ;AAAAA,MAAA;AAAA,IAAA,CAAA,GAAAP,QAAAC,KAAA;AAAA5K,WAAA8K,QAAA,MAW/G3L,MAAMG,OAAOmM,eAAerM,QAAQsM,MAAM;AAAA7J,WAAA,MAAA8J,YAAAb,oBAHjC,CAACf,QAAAA,CAAS,CAAA;AAAA,WAAAM;AAAAA,EAAA,GAAA;AAQ9B;AAACuB,eAAA,CAAA,OAAA,CAAA;"}
|
|
@@ -2,7 +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
|
-
var _tmpl$ = /* @__PURE__ */ web.template(`<div>`), _tmpl$2 = /* @__PURE__ */ web.template(`<button class="p-1.5 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-all shadow-sm"type=button><svg fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2>`);
|
|
5
|
+
var _tmpl$ = /* @__PURE__ */ web.template(`<div>`), _tmpl$2 = /* @__PURE__ */ web.template(`<button class="p-1.5 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-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-all shadow-[var(--mcp-ui-shadow,var(--shadow-sm))]"type=button><svg fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2>`);
|
|
6
6
|
const ICONS = {
|
|
7
7
|
copy: "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",
|
|
8
8
|
check: "M5 13l4 4L19 7",
|
|
@@ -31,7 +31,7 @@ const ComponentToolbar = (props) => {
|
|
|
31
31
|
action
|
|
32
32
|
})
|
|
33
33
|
}));
|
|
34
|
-
web.effect(() => web.className(_el$, `absolute ${positionClasses()} z-10 flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity`));
|
|
34
|
+
web.effect(() => web.className(_el$, `mcp-ui-root absolute ${positionClasses()} z-10 flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity`));
|
|
35
35
|
return _el$;
|
|
36
36
|
})();
|
|
37
37
|
};
|
|
@@ -47,9 +47,9 @@ const ToolbarButton = (props) => {
|
|
|
47
47
|
const iconPath = () => showCheck() ? ICONS.check : ICONS[props.action.icon];
|
|
48
48
|
const isActive = () => props.action.active;
|
|
49
49
|
const colorClass = () => {
|
|
50
|
-
if (showCheck()) return "text-green-500";
|
|
51
|
-
if (isActive()) return "text-blue-500 dark:text-blue-400";
|
|
52
|
-
return "text-gray-500 dark:text-gray-400";
|
|
50
|
+
if (showCheck()) return "text-[color:var(--mcp-ui-success,var(--color-green-500))]";
|
|
51
|
+
if (isActive()) return "text-[color:var(--mcp-ui-accent,var(--color-blue-500))] dark:text-[color:var(--mcp-ui-accent,var(--color-blue-400))]";
|
|
52
|
+
return "text-[color:var(--mcp-ui-fg-muted,var(--color-gray-500,#6b7280))] dark:text-[color:var(--mcp-ui-fg-subtle,var(--color-gray-400,#9ca3af))]";
|
|
53
53
|
};
|
|
54
54
|
return (() => {
|
|
55
55
|
var _el$2 = web.getNextElement(_tmpl$2), _el$3 = _el$2.firstChild, _el$4 = _el$3.firstChild;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComponentToolbar.cjs","sources":["../../src/components/ComponentToolbar.tsx"],"sourcesContent":["/**\n * ComponentToolbar - Unified toolbar for component actions\n * v2.2.5: Consistent icon set, position, and hover behavior across all components\n */\n\nimport { Component, For, createSignal } from 'solid-js'\n\n/** SVG icon paths for toolbar actions */\nconst ICONS = {\n copy: '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',\n check: 'M5 13l4 4L19 7',\n download: 'M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z',\n expand: 'M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5v-4m0 4h-4m4 0l-5-5',\n wordwrap: 'M3 10h10a4 4 0 010 8H9m4 0l-3-3m3 3l-3 3M3 6h18M3 14h4',\n} as const\n\nexport type ToolbarIcon = keyof typeof ICONS\n\nexport interface ToolbarAction {\n /** Icon to display */\n icon: ToolbarIcon\n /** Tooltip label */\n label: string\n /** Click handler */\n onClick: () => void\n /** Whether to show a success state (green check) after click */\n showFeedback?: boolean\n /** Active/toggled state (e.g. word wrap on) */\n active?: boolean\n}\n\nexport interface ComponentToolbarProps {\n /** Actions to display */\n actions: ToolbarAction[]\n /** Corner position */\n position?: 'top-right' | 'top-left' | 'bottom-right'\n}\n\n/**\n * Renders a row of small icon buttons, visible on parent hover (requires parent `group` class).\n *\n * @example\n * <div class=\"relative group\">\n * <MyContent />\n * <ComponentToolbar actions={[\n * { icon: 'copy', label: 'Copy', onClick: handleCopy, showFeedback: true },\n * { icon: 'download', label: 'Download CSV', onClick: handleDownload },\n * ]} />\n * </div>\n */\nexport const ComponentToolbar: Component<ComponentToolbarProps> = (props) => {\n const positionClasses = () => {\n switch (props.position) {\n case 'top-left': return 'top-2 left-2'\n case 'bottom-right': return 'bottom-2 right-2'\n default: return 'top-2 right-2'\n }\n }\n\n return (\n <div class={`absolute ${positionClasses()} z-10 flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity`}>\n <For each={props.actions}>\n {(action) => <ToolbarButton action={action} />}\n </For>\n </div>\n )\n}\n\n/** Individual toolbar button with optional feedback state */\nconst ToolbarButton: Component<{ action: ToolbarAction }> = (props) => {\n const [showCheck, setShowCheck] = createSignal(false)\n\n const handleClick = () => {\n props.action.onClick()\n if (props.action.showFeedback) {\n setShowCheck(true)\n setTimeout(() => setShowCheck(false), 2000)\n }\n }\n\n const iconPath = () => showCheck() ? ICONS.check : ICONS[props.action.icon]\n const isActive = () => props.action.active\n const colorClass = () => {\n if (showCheck()) return 'text-green-500'\n if (isActive()) return 'text-blue-500 dark:text-blue-400'\n return 'text-gray-500 dark:text-gray-400'\n }\n\n return (\n <button\n onClick={handleClick}\n class={`p-1.5 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-all shadow-sm`}\n title={props.action.label}\n aria-label={props.action.label}\n data-mcp-ui-action={props.action.icon}\n type=\"button\"\n >\n <svg class={`w-3 h-3 ${colorClass()}`} fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d={iconPath()} />\n </svg>\n </button>\n )\n}\n"],"names":["ICONS","copy","check","download","expand","wordwrap","ComponentToolbar","props","positionClasses","position","_el$","_$getNextElement","_tmpl$","_$insert","_$createComponent","For","each","actions","children","action","ToolbarButton","_$effect","_$className","showCheck","setShowCheck","createSignal","handleClick","onClick","showFeedback","setTimeout","iconPath","icon","isActive","active","colorClass","_el$2","_tmpl$2","_el$3","firstChild","_el$4","$$click","_p$","_v$","label","_v$2","_v$3","_v$4","_v$5","e","_$setAttribute","t","a","o","i","undefined","_$runHydrationEvents","_$delegateEvents"],"mappings":";;;;;AAQA,MAAMA,QAAQ;AAAA,EACZC,MAAM;AAAA,EACNC,OAAO;AAAA,EACPC,UAAU;AAAA,EACVC,QAAQ;AAAA,EACRC,UAAU;AACZ;AAoCO,MAAMC,mBAAsDC,CAAAA,UAAU;AAC3E,QAAMC,kBAAkBA,MAAM;AAC5B,YAAQD,MAAME,UAAAA;AAAAA,MACZ,KAAK;AAAY,eAAO;AAAA,MACxB,KAAK;AAAgB,eAAO;AAAA,MAC5B;AAAS,eAAO;AAAA,IAAA;AAAA,EAEpB;AAEA,UAAA,MAAA;AAAA,QAAAC,OAAAC,IAAAA,eAAAC,MAAA;AAAAC,eAAAH,MAAAI,IAAAA,gBAEKC,aAAG;AAAA,MAAA,IAACC,OAAI;AAAA,eAAET,MAAMU;AAAAA,MAAO;AAAA,MAAAC,UACpBC,CAAAA,WAAML,IAAAA,gBAAMM,eAAa;AAAA,QAACD;AAAAA,MAAAA,CAAc;AAAA,IAAA,CAAI,CAAA;AAAAE,eAAA,MAAAC,IAAAA,UAAAZ,MAFtC,
|
|
1
|
+
{"version":3,"file":"ComponentToolbar.cjs","sources":["../../src/components/ComponentToolbar.tsx"],"sourcesContent":["/**\n * ComponentToolbar - Unified toolbar for component actions\n * v2.2.5: Consistent icon set, position, and hover behavior across all components\n */\n\nimport { Component, For, createSignal } from 'solid-js'\n\n/** SVG icon paths for toolbar actions */\nconst ICONS = {\n copy: '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',\n check: 'M5 13l4 4L19 7',\n download: 'M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z',\n expand: 'M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5v-4m0 4h-4m4 0l-5-5',\n wordwrap: 'M3 10h10a4 4 0 010 8H9m4 0l-3-3m3 3l-3 3M3 6h18M3 14h4',\n} as const\n\nexport type ToolbarIcon = keyof typeof ICONS\n\nexport interface ToolbarAction {\n /** Icon to display */\n icon: ToolbarIcon\n /** Tooltip label */\n label: string\n /** Click handler */\n onClick: () => void\n /** Whether to show a success state (green check) after click */\n showFeedback?: boolean\n /** Active/toggled state (e.g. word wrap on) */\n active?: boolean\n}\n\nexport interface ComponentToolbarProps {\n /** Actions to display */\n actions: ToolbarAction[]\n /** Corner position */\n position?: 'top-right' | 'top-left' | 'bottom-right'\n}\n\n/**\n * Renders a row of small icon buttons, visible on parent hover (requires parent `group` class).\n *\n * @example\n * <div class=\"relative group\">\n * <MyContent />\n * <ComponentToolbar actions={[\n * { icon: 'copy', label: 'Copy', onClick: handleCopy, showFeedback: true },\n * { icon: 'download', label: 'Download CSV', onClick: handleDownload },\n * ]} />\n * </div>\n */\nexport const ComponentToolbar: Component<ComponentToolbarProps> = (props) => {\n const positionClasses = () => {\n switch (props.position) {\n case 'top-left': return 'top-2 left-2'\n case 'bottom-right': return 'bottom-2 right-2'\n default: return 'top-2 right-2'\n }\n }\n\n return (\n <div class={`mcp-ui-root absolute ${positionClasses()} z-10 flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity`}>\n <For each={props.actions}>\n {(action) => <ToolbarButton action={action} />}\n </For>\n </div>\n )\n}\n\n/** Individual toolbar button with optional feedback state */\nconst ToolbarButton: Component<{ action: ToolbarAction }> = (props) => {\n const [showCheck, setShowCheck] = createSignal(false)\n\n const handleClick = () => {\n props.action.onClick()\n if (props.action.showFeedback) {\n setShowCheck(true)\n setTimeout(() => setShowCheck(false), 2000)\n }\n }\n\n const iconPath = () => showCheck() ? ICONS.check : ICONS[props.action.icon]\n const isActive = () => props.action.active\n const colorClass = () => {\n if (showCheck()) return 'text-[color:var(--mcp-ui-success,var(--color-green-500))]'\n if (isActive()) return 'text-[color:var(--mcp-ui-accent,var(--color-blue-500))] dark:text-[color:var(--mcp-ui-accent,var(--color-blue-400))]'\n return 'text-[color:var(--mcp-ui-fg-muted,var(--color-gray-500,#6b7280))] dark:text-[color:var(--mcp-ui-fg-subtle,var(--color-gray-400,#9ca3af))]'\n }\n\n return (\n <button\n onClick={handleClick}\n class={`p-1.5 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-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-all shadow-[var(--mcp-ui-shadow,var(--shadow-sm))]`}\n title={props.action.label}\n aria-label={props.action.label}\n data-mcp-ui-action={props.action.icon}\n type=\"button\"\n >\n <svg class={`w-3 h-3 ${colorClass()}`} fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d={iconPath()} />\n </svg>\n </button>\n )\n}\n"],"names":["ICONS","copy","check","download","expand","wordwrap","ComponentToolbar","props","positionClasses","position","_el$","_$getNextElement","_tmpl$","_$insert","_$createComponent","For","each","actions","children","action","ToolbarButton","_$effect","_$className","showCheck","setShowCheck","createSignal","handleClick","onClick","showFeedback","setTimeout","iconPath","icon","isActive","active","colorClass","_el$2","_tmpl$2","_el$3","firstChild","_el$4","$$click","_p$","_v$","label","_v$2","_v$3","_v$4","_v$5","e","_$setAttribute","t","a","o","i","undefined","_$runHydrationEvents","_$delegateEvents"],"mappings":";;;;;AAQA,MAAMA,QAAQ;AAAA,EACZC,MAAM;AAAA,EACNC,OAAO;AAAA,EACPC,UAAU;AAAA,EACVC,QAAQ;AAAA,EACRC,UAAU;AACZ;AAoCO,MAAMC,mBAAsDC,CAAAA,UAAU;AAC3E,QAAMC,kBAAkBA,MAAM;AAC5B,YAAQD,MAAME,UAAAA;AAAAA,MACZ,KAAK;AAAY,eAAO;AAAA,MACxB,KAAK;AAAgB,eAAO;AAAA,MAC5B;AAAS,eAAO;AAAA,IAAA;AAAA,EAEpB;AAEA,UAAA,MAAA;AAAA,QAAAC,OAAAC,IAAAA,eAAAC,MAAA;AAAAC,eAAAH,MAAAI,IAAAA,gBAEKC,aAAG;AAAA,MAAA,IAACC,OAAI;AAAA,eAAET,MAAMU;AAAAA,MAAO;AAAA,MAAAC,UACpBC,CAAAA,WAAML,IAAAA,gBAAMM,eAAa;AAAA,QAACD;AAAAA,MAAAA,CAAc;AAAA,IAAA,CAAI,CAAA;AAAAE,eAAA,MAAAC,IAAAA,UAAAZ,MAFtC,wBAAwBF,gBAAAA,CAAiB,oFAAoF,CAAA;AAAA,WAAAE;AAAAA,EAAA,GAAA;AAM7I;AAGA,MAAMU,gBAAuDb,CAAAA,UAAU;AACrE,QAAM,CAACgB,WAAWC,YAAY,IAAIC,QAAAA,aAAa,KAAK;AAEpD,QAAMC,cAAcA,MAAM;AACxBnB,UAAMY,OAAOQ,QAAAA;AACb,QAAIpB,MAAMY,OAAOS,cAAc;AAC7BJ,mBAAa,IAAI;AACjBK,iBAAW,MAAML,aAAa,KAAK,GAAG,GAAI;AAAA,IAC5C;AAAA,EACF;AAEA,QAAMM,WAAWA,MAAMP,UAAAA,IAAcvB,MAAME,QAAQF,MAAMO,MAAMY,OAAOY,IAAI;AAC1E,QAAMC,WAAWA,MAAMzB,MAAMY,OAAOc;AACpC,QAAMC,aAAaA,MAAM;AACvB,QAAIX,UAAAA,EAAa,QAAO;AACxB,QAAIS,SAAAA,EAAY,QAAO;AACvB,WAAO;AAAA,EACT;AAEA,UAAA,MAAA;AAAA,QAAAG,QAAAxB,mBAAAyB,OAAA,GAAAC,QAAAF,MAAAG,YAAAC,QAAAF,MAAAC;AAAAH,UAAAK,UAEad;AAAWL,QAAAA,OAAAoB,CAAAA,QAAA;AAAA,UAAAC,MAEbnC,MAAMY,OAAOwB,OAAKC,OACbrC,MAAMY,OAAOwB,OAAKE,OACVtC,MAAMY,OAAOY,MAAIe,OAGzB,WAAWZ,YAAY,IAAEa,OACsCjB,SAAAA;AAAUY,cAAAD,IAAAO,KAAAC,IAAAA,aAAAd,OAAA,SAAAM,IAAAO,IAAAN,GAAA;AAAAE,eAAAH,IAAAS,KAAAD,IAAAA,aAAAd,OAAA,cAAAM,IAAAS,IAAAN,IAAA;AAAAC,eAAAJ,IAAAU,KAAAF,IAAAA,aAAAd,OAAA,sBAAAM,IAAAU,IAAAN,IAAA;AAAAC,eAAAL,IAAAW,KAAAH,IAAAA,aAAAZ,OAAA,SAAAI,IAAAW,IAAAN,IAAA;AAAAC,eAAAN,IAAAY,KAAAJ,IAAAA,aAAAV,OAAA,KAAAE,IAAAY,IAAAN,IAAA;AAAA,aAAAN;AAAAA,IAAA,GAAA;AAAA,MAAAO,GAAAM;AAAAA,MAAAJ,GAAAI;AAAAA,MAAAH,GAAAG;AAAAA,MAAAF,GAAAE;AAAAA,MAAAD,GAAAC;AAAAA,IAAAA,CAAA;AAAAC,2BAAAA;AAAA,WAAApB;AAAAA,EAAA,GAAA;AAI3F;AAACqB,IAAAA,eAAA,CAAA,OAAA,CAAA;;"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getNextElement, insert, createComponent, effect, className, template, setAttribute, runHydrationEvents, delegateEvents } from "solid-js/web";
|
|
2
2
|
import { For, createSignal } from "solid-js";
|
|
3
|
-
var _tmpl$ = /* @__PURE__ */ template(`<div>`), _tmpl$2 = /* @__PURE__ */ template(`<button class="p-1.5 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-all shadow-sm"type=button><svg fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2>`);
|
|
3
|
+
var _tmpl$ = /* @__PURE__ */ template(`<div>`), _tmpl$2 = /* @__PURE__ */ template(`<button class="p-1.5 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-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-all shadow-[var(--mcp-ui-shadow,var(--shadow-sm))]"type=button><svg fill=none viewBox="0 0 24 24"stroke=currentColor><path stroke-linecap=round stroke-linejoin=round stroke-width=2>`);
|
|
4
4
|
const ICONS = {
|
|
5
5
|
copy: "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",
|
|
6
6
|
check: "M5 13l4 4L19 7",
|
|
@@ -29,7 +29,7 @@ const ComponentToolbar = (props) => {
|
|
|
29
29
|
action
|
|
30
30
|
})
|
|
31
31
|
}));
|
|
32
|
-
effect(() => className(_el$, `absolute ${positionClasses()} z-10 flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity`));
|
|
32
|
+
effect(() => className(_el$, `mcp-ui-root absolute ${positionClasses()} z-10 flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity`));
|
|
33
33
|
return _el$;
|
|
34
34
|
})();
|
|
35
35
|
};
|
|
@@ -45,9 +45,9 @@ const ToolbarButton = (props) => {
|
|
|
45
45
|
const iconPath = () => showCheck() ? ICONS.check : ICONS[props.action.icon];
|
|
46
46
|
const isActive = () => props.action.active;
|
|
47
47
|
const colorClass = () => {
|
|
48
|
-
if (showCheck()) return "text-green-500";
|
|
49
|
-
if (isActive()) return "text-blue-500 dark:text-blue-400";
|
|
50
|
-
return "text-gray-500 dark:text-gray-400";
|
|
48
|
+
if (showCheck()) return "text-[color:var(--mcp-ui-success,var(--color-green-500))]";
|
|
49
|
+
if (isActive()) return "text-[color:var(--mcp-ui-accent,var(--color-blue-500))] dark:text-[color:var(--mcp-ui-accent,var(--color-blue-400))]";
|
|
50
|
+
return "text-[color:var(--mcp-ui-fg-muted,var(--color-gray-500,#6b7280))] dark:text-[color:var(--mcp-ui-fg-subtle,var(--color-gray-400,#9ca3af))]";
|
|
51
51
|
};
|
|
52
52
|
return (() => {
|
|
53
53
|
var _el$2 = getNextElement(_tmpl$2), _el$3 = _el$2.firstChild, _el$4 = _el$3.firstChild;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComponentToolbar.js","sources":["../../src/components/ComponentToolbar.tsx"],"sourcesContent":["/**\n * ComponentToolbar - Unified toolbar for component actions\n * v2.2.5: Consistent icon set, position, and hover behavior across all components\n */\n\nimport { Component, For, createSignal } from 'solid-js'\n\n/** SVG icon paths for toolbar actions */\nconst ICONS = {\n copy: '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',\n check: 'M5 13l4 4L19 7',\n download: 'M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z',\n expand: 'M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5v-4m0 4h-4m4 0l-5-5',\n wordwrap: 'M3 10h10a4 4 0 010 8H9m4 0l-3-3m3 3l-3 3M3 6h18M3 14h4',\n} as const\n\nexport type ToolbarIcon = keyof typeof ICONS\n\nexport interface ToolbarAction {\n /** Icon to display */\n icon: ToolbarIcon\n /** Tooltip label */\n label: string\n /** Click handler */\n onClick: () => void\n /** Whether to show a success state (green check) after click */\n showFeedback?: boolean\n /** Active/toggled state (e.g. word wrap on) */\n active?: boolean\n}\n\nexport interface ComponentToolbarProps {\n /** Actions to display */\n actions: ToolbarAction[]\n /** Corner position */\n position?: 'top-right' | 'top-left' | 'bottom-right'\n}\n\n/**\n * Renders a row of small icon buttons, visible on parent hover (requires parent `group` class).\n *\n * @example\n * <div class=\"relative group\">\n * <MyContent />\n * <ComponentToolbar actions={[\n * { icon: 'copy', label: 'Copy', onClick: handleCopy, showFeedback: true },\n * { icon: 'download', label: 'Download CSV', onClick: handleDownload },\n * ]} />\n * </div>\n */\nexport const ComponentToolbar: Component<ComponentToolbarProps> = (props) => {\n const positionClasses = () => {\n switch (props.position) {\n case 'top-left': return 'top-2 left-2'\n case 'bottom-right': return 'bottom-2 right-2'\n default: return 'top-2 right-2'\n }\n }\n\n return (\n <div class={`absolute ${positionClasses()} z-10 flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity`}>\n <For each={props.actions}>\n {(action) => <ToolbarButton action={action} />}\n </For>\n </div>\n )\n}\n\n/** Individual toolbar button with optional feedback state */\nconst ToolbarButton: Component<{ action: ToolbarAction }> = (props) => {\n const [showCheck, setShowCheck] = createSignal(false)\n\n const handleClick = () => {\n props.action.onClick()\n if (props.action.showFeedback) {\n setShowCheck(true)\n setTimeout(() => setShowCheck(false), 2000)\n }\n }\n\n const iconPath = () => showCheck() ? ICONS.check : ICONS[props.action.icon]\n const isActive = () => props.action.active\n const colorClass = () => {\n if (showCheck()) return 'text-green-500'\n if (isActive()) return 'text-blue-500 dark:text-blue-400'\n return 'text-gray-500 dark:text-gray-400'\n }\n\n return (\n <button\n onClick={handleClick}\n class={`p-1.5 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-all shadow-sm`}\n title={props.action.label}\n aria-label={props.action.label}\n data-mcp-ui-action={props.action.icon}\n type=\"button\"\n >\n <svg class={`w-3 h-3 ${colorClass()}`} fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d={iconPath()} />\n </svg>\n </button>\n )\n}\n"],"names":["ICONS","copy","check","download","expand","wordwrap","ComponentToolbar","props","positionClasses","position","_el$","_$getNextElement","_tmpl$","_$insert","_$createComponent","For","each","actions","children","action","ToolbarButton","_$effect","_$className","showCheck","setShowCheck","createSignal","handleClick","onClick","showFeedback","setTimeout","iconPath","icon","isActive","active","colorClass","_el$2","_tmpl$2","_el$3","firstChild","_el$4","$$click","_p$","_v$","label","_v$2","_v$3","_v$4","_v$5","e","_$setAttribute","t","a","o","i","undefined","_$runHydrationEvents","_$delegateEvents"],"mappings":";;;AAQA,MAAMA,QAAQ;AAAA,EACZC,MAAM;AAAA,EACNC,OAAO;AAAA,EACPC,UAAU;AAAA,EACVC,QAAQ;AAAA,EACRC,UAAU;AACZ;AAoCO,MAAMC,mBAAsDC,CAAAA,UAAU;AAC3E,QAAMC,kBAAkBA,MAAM;AAC5B,YAAQD,MAAME,UAAAA;AAAAA,MACZ,KAAK;AAAY,eAAO;AAAA,MACxB,KAAK;AAAgB,eAAO;AAAA,MAC5B;AAAS,eAAO;AAAA,IAAA;AAAA,EAEpB;AAEA,UAAA,MAAA;AAAA,QAAAC,OAAAC,eAAAC,MAAA;AAAAC,WAAAH,MAAAI,gBAEKC,KAAG;AAAA,MAAA,IAACC,OAAI;AAAA,eAAET,MAAMU;AAAAA,MAAO;AAAA,MAAAC,UACpBC,CAAAA,WAAML,gBAAMM,eAAa;AAAA,QAACD;AAAAA,MAAAA,CAAc;AAAA,IAAA,CAAI,CAAA;AAAAE,WAAA,MAAAC,UAAAZ,MAFtC,
|
|
1
|
+
{"version":3,"file":"ComponentToolbar.js","sources":["../../src/components/ComponentToolbar.tsx"],"sourcesContent":["/**\n * ComponentToolbar - Unified toolbar for component actions\n * v2.2.5: Consistent icon set, position, and hover behavior across all components\n */\n\nimport { Component, For, createSignal } from 'solid-js'\n\n/** SVG icon paths for toolbar actions */\nconst ICONS = {\n copy: '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',\n check: 'M5 13l4 4L19 7',\n download: 'M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z',\n expand: 'M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5v-4m0 4h-4m4 0l-5-5',\n wordwrap: 'M3 10h10a4 4 0 010 8H9m4 0l-3-3m3 3l-3 3M3 6h18M3 14h4',\n} as const\n\nexport type ToolbarIcon = keyof typeof ICONS\n\nexport interface ToolbarAction {\n /** Icon to display */\n icon: ToolbarIcon\n /** Tooltip label */\n label: string\n /** Click handler */\n onClick: () => void\n /** Whether to show a success state (green check) after click */\n showFeedback?: boolean\n /** Active/toggled state (e.g. word wrap on) */\n active?: boolean\n}\n\nexport interface ComponentToolbarProps {\n /** Actions to display */\n actions: ToolbarAction[]\n /** Corner position */\n position?: 'top-right' | 'top-left' | 'bottom-right'\n}\n\n/**\n * Renders a row of small icon buttons, visible on parent hover (requires parent `group` class).\n *\n * @example\n * <div class=\"relative group\">\n * <MyContent />\n * <ComponentToolbar actions={[\n * { icon: 'copy', label: 'Copy', onClick: handleCopy, showFeedback: true },\n * { icon: 'download', label: 'Download CSV', onClick: handleDownload },\n * ]} />\n * </div>\n */\nexport const ComponentToolbar: Component<ComponentToolbarProps> = (props) => {\n const positionClasses = () => {\n switch (props.position) {\n case 'top-left': return 'top-2 left-2'\n case 'bottom-right': return 'bottom-2 right-2'\n default: return 'top-2 right-2'\n }\n }\n\n return (\n <div class={`mcp-ui-root absolute ${positionClasses()} z-10 flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity`}>\n <For each={props.actions}>\n {(action) => <ToolbarButton action={action} />}\n </For>\n </div>\n )\n}\n\n/** Individual toolbar button with optional feedback state */\nconst ToolbarButton: Component<{ action: ToolbarAction }> = (props) => {\n const [showCheck, setShowCheck] = createSignal(false)\n\n const handleClick = () => {\n props.action.onClick()\n if (props.action.showFeedback) {\n setShowCheck(true)\n setTimeout(() => setShowCheck(false), 2000)\n }\n }\n\n const iconPath = () => showCheck() ? ICONS.check : ICONS[props.action.icon]\n const isActive = () => props.action.active\n const colorClass = () => {\n if (showCheck()) return 'text-[color:var(--mcp-ui-success,var(--color-green-500))]'\n if (isActive()) return 'text-[color:var(--mcp-ui-accent,var(--color-blue-500))] dark:text-[color:var(--mcp-ui-accent,var(--color-blue-400))]'\n return 'text-[color:var(--mcp-ui-fg-muted,var(--color-gray-500,#6b7280))] dark:text-[color:var(--mcp-ui-fg-subtle,var(--color-gray-400,#9ca3af))]'\n }\n\n return (\n <button\n onClick={handleClick}\n class={`p-1.5 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-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-all shadow-[var(--mcp-ui-shadow,var(--shadow-sm))]`}\n title={props.action.label}\n aria-label={props.action.label}\n data-mcp-ui-action={props.action.icon}\n type=\"button\"\n >\n <svg class={`w-3 h-3 ${colorClass()}`} fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d={iconPath()} />\n </svg>\n </button>\n )\n}\n"],"names":["ICONS","copy","check","download","expand","wordwrap","ComponentToolbar","props","positionClasses","position","_el$","_$getNextElement","_tmpl$","_$insert","_$createComponent","For","each","actions","children","action","ToolbarButton","_$effect","_$className","showCheck","setShowCheck","createSignal","handleClick","onClick","showFeedback","setTimeout","iconPath","icon","isActive","active","colorClass","_el$2","_tmpl$2","_el$3","firstChild","_el$4","$$click","_p$","_v$","label","_v$2","_v$3","_v$4","_v$5","e","_$setAttribute","t","a","o","i","undefined","_$runHydrationEvents","_$delegateEvents"],"mappings":";;;AAQA,MAAMA,QAAQ;AAAA,EACZC,MAAM;AAAA,EACNC,OAAO;AAAA,EACPC,UAAU;AAAA,EACVC,QAAQ;AAAA,EACRC,UAAU;AACZ;AAoCO,MAAMC,mBAAsDC,CAAAA,UAAU;AAC3E,QAAMC,kBAAkBA,MAAM;AAC5B,YAAQD,MAAME,UAAAA;AAAAA,MACZ,KAAK;AAAY,eAAO;AAAA,MACxB,KAAK;AAAgB,eAAO;AAAA,MAC5B;AAAS,eAAO;AAAA,IAAA;AAAA,EAEpB;AAEA,UAAA,MAAA;AAAA,QAAAC,OAAAC,eAAAC,MAAA;AAAAC,WAAAH,MAAAI,gBAEKC,KAAG;AAAA,MAAA,IAACC,OAAI;AAAA,eAAET,MAAMU;AAAAA,MAAO;AAAA,MAAAC,UACpBC,CAAAA,WAAML,gBAAMM,eAAa;AAAA,QAACD;AAAAA,MAAAA,CAAc;AAAA,IAAA,CAAI,CAAA;AAAAE,WAAA,MAAAC,UAAAZ,MAFtC,wBAAwBF,gBAAAA,CAAiB,oFAAoF,CAAA;AAAA,WAAAE;AAAAA,EAAA,GAAA;AAM7I;AAGA,MAAMU,gBAAuDb,CAAAA,UAAU;AACrE,QAAM,CAACgB,WAAWC,YAAY,IAAIC,aAAa,KAAK;AAEpD,QAAMC,cAAcA,MAAM;AACxBnB,UAAMY,OAAOQ,QAAAA;AACb,QAAIpB,MAAMY,OAAOS,cAAc;AAC7BJ,mBAAa,IAAI;AACjBK,iBAAW,MAAML,aAAa,KAAK,GAAG,GAAI;AAAA,IAC5C;AAAA,EACF;AAEA,QAAMM,WAAWA,MAAMP,UAAAA,IAAcvB,MAAME,QAAQF,MAAMO,MAAMY,OAAOY,IAAI;AAC1E,QAAMC,WAAWA,MAAMzB,MAAMY,OAAOc;AACpC,QAAMC,aAAaA,MAAM;AACvB,QAAIX,UAAAA,EAAa,QAAO;AACxB,QAAIS,SAAAA,EAAY,QAAO;AACvB,WAAO;AAAA,EACT;AAEA,UAAA,MAAA;AAAA,QAAAG,QAAAxB,eAAAyB,OAAA,GAAAC,QAAAF,MAAAG,YAAAC,QAAAF,MAAAC;AAAAH,UAAAK,UAEad;AAAWL,WAAAoB,CAAAA,QAAA;AAAA,UAAAC,MAEbnC,MAAMY,OAAOwB,OAAKC,OACbrC,MAAMY,OAAOwB,OAAKE,OACVtC,MAAMY,OAAOY,MAAIe,OAGzB,WAAWZ,YAAY,IAAEa,OACsCjB,SAAAA;AAAUY,cAAAD,IAAAO,KAAAC,aAAAd,OAAA,SAAAM,IAAAO,IAAAN,GAAA;AAAAE,eAAAH,IAAAS,KAAAD,aAAAd,OAAA,cAAAM,IAAAS,IAAAN,IAAA;AAAAC,eAAAJ,IAAAU,KAAAF,aAAAd,OAAA,sBAAAM,IAAAU,IAAAN,IAAA;AAAAC,eAAAL,IAAAW,KAAAH,aAAAZ,OAAA,SAAAI,IAAAW,IAAAN,IAAA;AAAAC,eAAAN,IAAAY,KAAAJ,aAAAV,OAAA,KAAAE,IAAAY,IAAAN,IAAA;AAAA,aAAAN;AAAAA,IAAA,GAAA;AAAA,MAAAO,GAAAM;AAAAA,MAAAJ,GAAAI;AAAAA,MAAAH,GAAAG;AAAAA,MAAAF,GAAAE;AAAAA,MAAAD,GAAAC;AAAAA,IAAAA,CAAA;AAAAC,uBAAAA;AAAA,WAAApB;AAAAA,EAAA,GAAA;AAI3F;AAACqB,eAAA,CAAA,OAAA,CAAA;"}
|
|
@@ -3,14 +3,27 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
3
3
|
const web = require("solid-js/web");
|
|
4
4
|
const solidJs = require("solid-js");
|
|
5
5
|
const MCPUIStringsContext = require("../context/MCPUIStringsContext.cjs");
|
|
6
|
+
const MissingValue = require("./MissingValue.cjs");
|
|
6
7
|
const formatString = require("../utils/format-string.cjs");
|
|
7
|
-
var _tmpl$ = /* @__PURE__ */ web.template(`<div class="mt-2 max-h-64 overflow-auto rounded border border-amber-200 dark:border-amber-800"><table class="w-full border-collapse text-left text-xs"><thead class="sticky top-0 bg-amber-100 dark:bg-amber-900
|
|
8
|
+
var _tmpl$ = /* @__PURE__ */ web.template(`<div class="mt-2 max-h-64 overflow-auto rounded border border-[color:var(--mcp-ui-warning-border,var(--color-amber-200))] dark:border-[color:var(--mcp-ui-warning-border,var(--color-amber-800))]"><table class="w-full border-collapse text-left text-xs"><thead class="sticky top-0 bg-[color:var(--mcp-ui-warning-soft,var(--color-amber-100))] dark:bg-[color:var(--mcp-ui-warning-soft,color-mix(in_oklab,var(--color-amber-900)_40%,transparent))]"><tr></tr></thead><tbody>`), _tmpl$2 = /* @__PURE__ */ web.template(`<p class="mt-1 text-[10px] text-[color:var(--mcp-ui-warning,var(--color-amber-600))] dark:text-[color:var(--mcp-ui-warning,var(--color-amber-400))]">`), _tmpl$3 = /* @__PURE__ */ web.template(`<div class="w-full rounded-lg border border-[color:var(--mcp-ui-warning-border,var(--color-amber-200))] bg-[color:var(--mcp-ui-warning-soft,var(--color-amber-50))] p-3 dark:border-[color:var(--mcp-ui-warning-border,var(--color-amber-800))] dark:bg-[color:var(--mcp-ui-warning-soft,color-mix(in_oklab,var(--color-amber-900)_20%,transparent))]"role=alert><p class="text-sm font-medium text-[color:var(--mcp-ui-warning,var(--color-amber-900))] dark:text-[color:var(--mcp-ui-warning,var(--color-amber-100))]"></p><p class="mt-0.5 text-xs text-[color:var(--mcp-ui-warning,var(--color-amber-700))] dark:text-[color:var(--mcp-ui-warning,var(--color-amber-300))]"></p><!$><!/>`), _tmpl$4 = /* @__PURE__ */ web.template(`<th class="px-2 py-1 font-medium text-[color:var(--mcp-ui-warning,var(--color-amber-900))] dark:text-[color:var(--mcp-ui-warning,var(--color-amber-100))]">`), _tmpl$5 = /* @__PURE__ */ web.template(`<tr class="border-t border-[color:var(--mcp-ui-warning-border,var(--color-amber-100))] dark:border-[color:var(--mcp-ui-warning-border,color-mix(in_oklab,var(--color-amber-800)_60%,transparent))]">`), _tmpl$6 = /* @__PURE__ */ web.template(`<td class="px-2 py-1 text-[color:var(--mcp-ui-warning,var(--color-amber-800))] dark:text-[color:var(--mcp-ui-warning,var(--color-amber-200))]">`);
|
|
8
9
|
const DegradedFallback = (props) => {
|
|
9
10
|
const strings = MCPUIStringsContext.useMCPUIStrings();
|
|
10
11
|
const maxRows = () => props.maxRows ?? 50;
|
|
11
12
|
const allRows = () => props.rows ?? [];
|
|
12
13
|
const shownRows = () => allRows().slice(0, maxRows());
|
|
13
14
|
const hiddenCount = () => Math.max(0, allRows().length - shownRows().length);
|
|
15
|
+
const isMissing = (rowIndex, colIndex) => {
|
|
16
|
+
var _a, _b;
|
|
17
|
+
return ((_b = (_a = props.missing) == null ? void 0 : _a[rowIndex]) == null ? void 0 : _b[colIndex]) === true;
|
|
18
|
+
};
|
|
19
|
+
const anyShownMissing = () => {
|
|
20
|
+
var _a;
|
|
21
|
+
const columnCount = ((_a = props.columns) == null ? void 0 : _a.length) ?? 0;
|
|
22
|
+
return shownRows().some((_row, r) => {
|
|
23
|
+
for (let c = 0; c < columnCount; c += 1) if (isMissing(r, c)) return true;
|
|
24
|
+
return false;
|
|
25
|
+
});
|
|
26
|
+
};
|
|
14
27
|
const hasTable = () => {
|
|
15
28
|
var _a;
|
|
16
29
|
return (((_a = props.columns) == null ? void 0 : _a.length) ?? 0) > 0 && allRows().length > 0;
|
|
@@ -40,7 +53,7 @@ const DegradedFallback = (props) => {
|
|
|
40
53
|
get each() {
|
|
41
54
|
return shownRows();
|
|
42
55
|
},
|
|
43
|
-
children: (row) => (() => {
|
|
56
|
+
children: (row, rowIndex) => (() => {
|
|
44
57
|
var _el$11 = web.getNextElement(_tmpl$5);
|
|
45
58
|
web.insert(_el$11, web.createComponent(solidJs.For, {
|
|
46
59
|
get each() {
|
|
@@ -48,7 +61,17 @@ const DegradedFallback = (props) => {
|
|
|
48
61
|
},
|
|
49
62
|
children: (_col, i) => (() => {
|
|
50
63
|
var _el$12 = web.getNextElement(_tmpl$6);
|
|
51
|
-
web.insert(_el$12, (
|
|
64
|
+
web.insert(_el$12, web.createComponent(solidJs.Show, {
|
|
65
|
+
get when() {
|
|
66
|
+
return isMissing(rowIndex(), i());
|
|
67
|
+
},
|
|
68
|
+
get fallback() {
|
|
69
|
+
return String(row[i()] ?? "");
|
|
70
|
+
},
|
|
71
|
+
get children() {
|
|
72
|
+
return web.createComponent(MissingValue.MissingValueMark, {});
|
|
73
|
+
}
|
|
74
|
+
}));
|
|
52
75
|
return _el$12;
|
|
53
76
|
})()
|
|
54
77
|
}));
|
|
@@ -57,6 +80,15 @@ const DegradedFallback = (props) => {
|
|
|
57
80
|
}));
|
|
58
81
|
return _el$4;
|
|
59
82
|
})(), web.createComponent(solidJs.Show, {
|
|
83
|
+
get when() {
|
|
84
|
+
return anyShownMissing();
|
|
85
|
+
},
|
|
86
|
+
get children() {
|
|
87
|
+
return web.createComponent(MissingValue.MissingValueLegend, {
|
|
88
|
+
"class": "mt-2"
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}), web.createComponent(solidJs.Show, {
|
|
60
92
|
get when() {
|
|
61
93
|
return hiddenCount() > 0;
|
|
62
94
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DegradedFallback.cjs","sources":["../../src/components/DegradedFallback.tsx"],"sourcesContent":["/**\n * DegradedFallback — the middle rung of the renderer fallback ladder\n * (audit 2026-05-30, P2.5).\n *\n * Each heavy renderer (graph / map / chart) follows the same contract:\n * 1. native render when its peer lib is available and succeeds;\n * 2. **degraded but useful** view when the native render throws — this\n * component: a visible notice + a plain data table so the user still\n * sees the underlying data instead of a blank space;\n * 3. (the caller also emits a `render:error` telemetry event).\n *\n * Pure / presentational — no peer deps, no side effects — so a render-path\n * failure in a heavy lib can never cascade into the fallback itself, and it\n * is trivially unit-testable. Rows/cells are rendered as text; callers are\n * responsible for stringifying complex cell values.\n */\n\nimport { Component, For, Show } from 'solid-js';\nimport { formatMCPUIString, useMCPUIStrings } from '../context/MCPUIStringsContext';\n\nexport interface DegradedFallbackProps {\n /** Short, human-readable reason the native render was skipped/failed. */\n message: string;\n /**\n * Column headers for the degraded data table. When omitted (or empty),\n * only the notice banner is shown.\n */\n columns?: string[];\n /** Row data — each row is an array of cells aligned to `columns`. */\n rows?: Array<Array<string | number>>;\n /**\n * Caption under the table. Defaults to a generic\n * \"interactive view unavailable\" line.\n */\n caption?: string;\n /** Max rows to render before truncating (default 50). */\n maxRows?: number;\n}\n\nexport const DegradedFallback: Component<DegradedFallbackProps> = (props) => {\n const strings = useMCPUIStrings();\n const maxRows = () => props.maxRows ?? 50;\n const allRows = () => props.rows ?? [];\n const shownRows = () => allRows().slice(0, maxRows());\n const hiddenCount = () => Math.max(0, allRows().length - shownRows().length);\n const hasTable = () => (props.columns?.length ?? 0) > 0 && allRows().length > 0;\n\n return (\n <div\n class=\"w-full rounded-lg border border-amber-200 bg-amber-50 p-3 dark:border-amber-800 dark:bg-amber-900
|
|
1
|
+
{"version":3,"file":"DegradedFallback.cjs","sources":["../../src/components/DegradedFallback.tsx"],"sourcesContent":["/**\n * DegradedFallback — the middle rung of the renderer fallback ladder\n * (audit 2026-05-30, P2.5).\n *\n * Each heavy renderer (graph / map / chart) follows the same contract:\n * 1. native render when its peer lib is available and succeeds;\n * 2. **degraded but useful** view when the native render throws — this\n * component: a visible notice + a plain data table so the user still\n * sees the underlying data instead of a blank space;\n * 3. (the caller also emits a `render:error` telemetry event).\n *\n * Pure / presentational — no peer deps, no side effects — so a render-path\n * failure in a heavy lib can never cascade into the fallback itself, and it\n * is trivially unit-testable. Rows/cells are rendered as text; callers are\n * responsible for stringifying complex cell values.\n */\n\nimport { Component, For, Show } from 'solid-js';\nimport { formatMCPUIString, useMCPUIStrings } from '../context/MCPUIStringsContext';\nimport { MissingValueLegend, MissingValueMark } from './MissingValue';\n\nexport interface DegradedFallbackProps {\n /** Short, human-readable reason the native render was skipped/failed. */\n message: string;\n /**\n * Column headers for the degraded data table. When omitted (or empty),\n * only the notice banner is shown.\n */\n columns?: string[];\n /** Row data — each row is an array of cells aligned to `columns`. */\n rows?: Array<Array<string | number>>;\n /**\n * Caption under the table. Defaults to a generic\n * \"interactive view unavailable\" line.\n */\n caption?: string;\n /** Max rows to render before truncating (default 50). */\n maxRows?: number;\n /**\n * Same shape as `rows`: `true` marks a cell whose value is missing, which\n * renders as `<MissingValueMark/>` instead of its text. A\n * `<MissingValueLegend/>` follows the table when a SHOWN cell is missing.\n * Omitted, the output is unchanged. @since v6.24.0\n */\n missing?: boolean[][];\n}\n\nexport const DegradedFallback: Component<DegradedFallbackProps> = (props) => {\n const strings = useMCPUIStrings();\n const maxRows = () => props.maxRows ?? 50;\n const allRows = () => props.rows ?? [];\n const shownRows = () => allRows().slice(0, maxRows());\n const hiddenCount = () => Math.max(0, allRows().length - shownRows().length);\n const isMissing = (rowIndex: number, colIndex: number) =>\n props.missing?.[rowIndex]?.[colIndex] === true;\n const anyShownMissing = () => {\n const columnCount = props.columns?.length ?? 0;\n return shownRows().some((_row, r) => {\n for (let c = 0; c < columnCount; c += 1) if (isMissing(r, c)) return true;\n return false;\n });\n };\n const hasTable = () => (props.columns?.length ?? 0) > 0 && allRows().length > 0;\n\n return (\n <div\n class=\"w-full rounded-lg border border-[color:var(--mcp-ui-warning-border,var(--color-amber-200))] bg-[color:var(--mcp-ui-warning-soft,var(--color-amber-50))] p-3 dark:border-[color:var(--mcp-ui-warning-border,var(--color-amber-800))] dark:bg-[color:var(--mcp-ui-warning-soft,color-mix(in_oklab,var(--color-amber-900)_20%,transparent))]\"\n role=\"alert\"\n >\n <p class=\"text-sm font-medium text-[color:var(--mcp-ui-warning,var(--color-amber-900))] dark:text-[color:var(--mcp-ui-warning,var(--color-amber-100))]\">{props.message}</p>\n <p class=\"mt-0.5 text-xs text-[color:var(--mcp-ui-warning,var(--color-amber-700))] dark:text-[color:var(--mcp-ui-warning,var(--color-amber-300))]\">\n {props.caption ?? strings.degradedCaption}\n </p>\n\n <Show when={hasTable()}>\n <div class=\"mt-2 max-h-64 overflow-auto rounded border border-[color:var(--mcp-ui-warning-border,var(--color-amber-200))] dark:border-[color:var(--mcp-ui-warning-border,var(--color-amber-800))]\">\n <table class=\"w-full border-collapse text-left text-xs\">\n <thead class=\"sticky top-0 bg-[color:var(--mcp-ui-warning-soft,var(--color-amber-100))] dark:bg-[color:var(--mcp-ui-warning-soft,color-mix(in_oklab,var(--color-amber-900)_40%,transparent))]\">\n <tr>\n <For each={props.columns}>\n {(col) => (\n <th class=\"px-2 py-1 font-medium text-[color:var(--mcp-ui-warning,var(--color-amber-900))] dark:text-[color:var(--mcp-ui-warning,var(--color-amber-100))]\">{col}</th>\n )}\n </For>\n </tr>\n </thead>\n <tbody>\n <For each={shownRows()}>\n {(row, rowIndex) => (\n <tr class=\"border-t border-[color:var(--mcp-ui-warning-border,var(--color-amber-100))] dark:border-[color:var(--mcp-ui-warning-border,color-mix(in_oklab,var(--color-amber-800)_60%,transparent))]\">\n <For each={props.columns}>\n {(_col, i) => (\n <td class=\"px-2 py-1 text-[color:var(--mcp-ui-warning,var(--color-amber-800))] dark:text-[color:var(--mcp-ui-warning,var(--color-amber-200))]\">\n <Show when={isMissing(rowIndex(), i())} fallback={String(row[i()] ?? '')}>\n <MissingValueMark />\n </Show>\n </td>\n )}\n </For>\n </tr>\n )}\n </For>\n </tbody>\n </table>\n </div>\n <Show when={anyShownMissing()}>\n <MissingValueLegend class=\"mt-2\" />\n </Show>\n <Show when={hiddenCount() > 0}>\n <p class=\"mt-1 text-[10px] text-[color:var(--mcp-ui-warning,var(--color-amber-600))] dark:text-[color:var(--mcp-ui-warning,var(--color-amber-400))]\">\n {formatMCPUIString(strings.degradedMoreRows, { count: hiddenCount() })}\n </p>\n </Show>\n </Show>\n </div>\n );\n};\n"],"names":["DegradedFallback","props","strings","useMCPUIStrings","maxRows","allRows","rows","shownRows","slice","hiddenCount","Math","max","length","isMissing","rowIndex","colIndex","missing","anyShownMissing","columnCount","columns","some","_row","r","c","hasTable","_el$","_$getNextElement","_tmpl$3","_el$2","firstChild","_el$3","nextSibling","_el$0","_el$1","_co$","_$getNextMarker","_$insert","message","caption","degradedCaption","_$createComponent","Show","when","children","_el$4","_tmpl$","_el$5","_el$6","_el$7","_el$8","For","each","col","_el$10","_tmpl$4","row","_el$11","_tmpl$5","_col","i","_el$12","_tmpl$6","fallback","String","MissingValueMark","MissingValueLegend","_el$9","_tmpl$2","formatMCPUIString","degradedMoreRows","count"],"mappings":"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"}
|
|
@@ -32,6 +32,13 @@ export interface DegradedFallbackProps {
|
|
|
32
32
|
caption?: string;
|
|
33
33
|
/** Max rows to render before truncating (default 50). */
|
|
34
34
|
maxRows?: number;
|
|
35
|
+
/**
|
|
36
|
+
* Same shape as `rows`: `true` marks a cell whose value is missing, which
|
|
37
|
+
* renders as `<MissingValueMark/>` instead of its text. A
|
|
38
|
+
* `<MissingValueLegend/>` follows the table when a SHOWN cell is missing.
|
|
39
|
+
* Omitted, the output is unchanged. @since v6.24.0
|
|
40
|
+
*/
|
|
41
|
+
missing?: boolean[][];
|
|
35
42
|
}
|
|
36
43
|
export declare const DegradedFallback: Component<DegradedFallbackProps>;
|
|
37
44
|
//# sourceMappingURL=DegradedFallback.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DegradedFallback.d.ts","sourceRoot":"","sources":["../../src/components/DegradedFallback.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,SAAS,EAAa,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"DegradedFallback.d.ts","sourceRoot":"","sources":["../../src/components/DegradedFallback.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,SAAS,EAAa,MAAM,UAAU,CAAC;AAIhD,MAAM,WAAW,qBAAqB;IACpC,yEAAyE;IACzE,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,qEAAqE;IACrE,IAAI,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC;IACrC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC;CACvB;AAED,eAAO,MAAM,gBAAgB,EAAE,SAAS,CAAC,qBAAqB,CAqE7D,CAAC"}
|
|
@@ -1,14 +1,27 @@
|
|
|
1
1
|
import { getNextElement, getNextMarker, insert, createComponent, template } from "solid-js/web";
|
|
2
2
|
import { Show, For } from "solid-js";
|
|
3
3
|
import { useMCPUIStrings } from "../context/MCPUIStringsContext.js";
|
|
4
|
+
import { MissingValueMark, MissingValueLegend } from "./MissingValue.js";
|
|
4
5
|
import { formatMCPUIString } from "../utils/format-string.js";
|
|
5
|
-
var _tmpl$ = /* @__PURE__ */ template(`<div class="mt-2 max-h-64 overflow-auto rounded border border-amber-200 dark:border-amber-800"><table class="w-full border-collapse text-left text-xs"><thead class="sticky top-0 bg-amber-100 dark:bg-amber-900
|
|
6
|
+
var _tmpl$ = /* @__PURE__ */ template(`<div class="mt-2 max-h-64 overflow-auto rounded border border-[color:var(--mcp-ui-warning-border,var(--color-amber-200))] dark:border-[color:var(--mcp-ui-warning-border,var(--color-amber-800))]"><table class="w-full border-collapse text-left text-xs"><thead class="sticky top-0 bg-[color:var(--mcp-ui-warning-soft,var(--color-amber-100))] dark:bg-[color:var(--mcp-ui-warning-soft,color-mix(in_oklab,var(--color-amber-900)_40%,transparent))]"><tr></tr></thead><tbody>`), _tmpl$2 = /* @__PURE__ */ template(`<p class="mt-1 text-[10px] text-[color:var(--mcp-ui-warning,var(--color-amber-600))] dark:text-[color:var(--mcp-ui-warning,var(--color-amber-400))]">`), _tmpl$3 = /* @__PURE__ */ template(`<div class="w-full rounded-lg border border-[color:var(--mcp-ui-warning-border,var(--color-amber-200))] bg-[color:var(--mcp-ui-warning-soft,var(--color-amber-50))] p-3 dark:border-[color:var(--mcp-ui-warning-border,var(--color-amber-800))] dark:bg-[color:var(--mcp-ui-warning-soft,color-mix(in_oklab,var(--color-amber-900)_20%,transparent))]"role=alert><p class="text-sm font-medium text-[color:var(--mcp-ui-warning,var(--color-amber-900))] dark:text-[color:var(--mcp-ui-warning,var(--color-amber-100))]"></p><p class="mt-0.5 text-xs text-[color:var(--mcp-ui-warning,var(--color-amber-700))] dark:text-[color:var(--mcp-ui-warning,var(--color-amber-300))]"></p><!$><!/>`), _tmpl$4 = /* @__PURE__ */ template(`<th class="px-2 py-1 font-medium text-[color:var(--mcp-ui-warning,var(--color-amber-900))] dark:text-[color:var(--mcp-ui-warning,var(--color-amber-100))]">`), _tmpl$5 = /* @__PURE__ */ template(`<tr class="border-t border-[color:var(--mcp-ui-warning-border,var(--color-amber-100))] dark:border-[color:var(--mcp-ui-warning-border,color-mix(in_oklab,var(--color-amber-800)_60%,transparent))]">`), _tmpl$6 = /* @__PURE__ */ template(`<td class="px-2 py-1 text-[color:var(--mcp-ui-warning,var(--color-amber-800))] dark:text-[color:var(--mcp-ui-warning,var(--color-amber-200))]">`);
|
|
6
7
|
const DegradedFallback = (props) => {
|
|
7
8
|
const strings = useMCPUIStrings();
|
|
8
9
|
const maxRows = () => props.maxRows ?? 50;
|
|
9
10
|
const allRows = () => props.rows ?? [];
|
|
10
11
|
const shownRows = () => allRows().slice(0, maxRows());
|
|
11
12
|
const hiddenCount = () => Math.max(0, allRows().length - shownRows().length);
|
|
13
|
+
const isMissing = (rowIndex, colIndex) => {
|
|
14
|
+
var _a, _b;
|
|
15
|
+
return ((_b = (_a = props.missing) == null ? void 0 : _a[rowIndex]) == null ? void 0 : _b[colIndex]) === true;
|
|
16
|
+
};
|
|
17
|
+
const anyShownMissing = () => {
|
|
18
|
+
var _a;
|
|
19
|
+
const columnCount = ((_a = props.columns) == null ? void 0 : _a.length) ?? 0;
|
|
20
|
+
return shownRows().some((_row, r) => {
|
|
21
|
+
for (let c = 0; c < columnCount; c += 1) if (isMissing(r, c)) return true;
|
|
22
|
+
return false;
|
|
23
|
+
});
|
|
24
|
+
};
|
|
12
25
|
const hasTable = () => {
|
|
13
26
|
var _a;
|
|
14
27
|
return (((_a = props.columns) == null ? void 0 : _a.length) ?? 0) > 0 && allRows().length > 0;
|
|
@@ -38,7 +51,7 @@ const DegradedFallback = (props) => {
|
|
|
38
51
|
get each() {
|
|
39
52
|
return shownRows();
|
|
40
53
|
},
|
|
41
|
-
children: (row) => (() => {
|
|
54
|
+
children: (row, rowIndex) => (() => {
|
|
42
55
|
var _el$11 = getNextElement(_tmpl$5);
|
|
43
56
|
insert(_el$11, createComponent(For, {
|
|
44
57
|
get each() {
|
|
@@ -46,7 +59,17 @@ const DegradedFallback = (props) => {
|
|
|
46
59
|
},
|
|
47
60
|
children: (_col, i) => (() => {
|
|
48
61
|
var _el$12 = getNextElement(_tmpl$6);
|
|
49
|
-
insert(_el$12, (
|
|
62
|
+
insert(_el$12, createComponent(Show, {
|
|
63
|
+
get when() {
|
|
64
|
+
return isMissing(rowIndex(), i());
|
|
65
|
+
},
|
|
66
|
+
get fallback() {
|
|
67
|
+
return String(row[i()] ?? "");
|
|
68
|
+
},
|
|
69
|
+
get children() {
|
|
70
|
+
return createComponent(MissingValueMark, {});
|
|
71
|
+
}
|
|
72
|
+
}));
|
|
50
73
|
return _el$12;
|
|
51
74
|
})()
|
|
52
75
|
}));
|
|
@@ -55,6 +78,15 @@ const DegradedFallback = (props) => {
|
|
|
55
78
|
}));
|
|
56
79
|
return _el$4;
|
|
57
80
|
})(), createComponent(Show, {
|
|
81
|
+
get when() {
|
|
82
|
+
return anyShownMissing();
|
|
83
|
+
},
|
|
84
|
+
get children() {
|
|
85
|
+
return createComponent(MissingValueLegend, {
|
|
86
|
+
"class": "mt-2"
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}), createComponent(Show, {
|
|
58
90
|
get when() {
|
|
59
91
|
return hiddenCount() > 0;
|
|
60
92
|
},
|