@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
|
@@ -86,22 +86,22 @@ export const ChatPrompt: Component<ChatPromptProps> = (props) => {
|
|
|
86
86
|
|
|
87
87
|
return (
|
|
88
88
|
<div
|
|
89
|
-
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"
|
|
89
|
+
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"
|
|
90
90
|
style={{ animation: 'chat-prompt-slide-up 0.2s ease-out' }}
|
|
91
91
|
role="dialog"
|
|
92
92
|
aria-label={props.config.title}
|
|
93
93
|
>
|
|
94
94
|
{/* Header */}
|
|
95
|
-
<div class="flex items-center justify-between px-4 py-2.5 border-b border-gray-100 dark:border-gray-700">
|
|
96
|
-
<p class="text-sm font-medium text-gray-900 dark:text-white">{props.config.title}</p>
|
|
95
|
+
<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))]">
|
|
96
|
+
<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>
|
|
97
97
|
<button
|
|
98
98
|
onClick={() => {
|
|
99
99
|
props.onDismiss?.()
|
|
100
100
|
props.onSubmit({ type: props.config.type, value: '', label: '', dismissed: true })
|
|
101
101
|
}}
|
|
102
102
|
class={props.dismissLabel
|
|
103
|
-
? 'px-3 py-1 text-xs font-medium text-blue-600 dark:text-blue-400 hover:bg-blue-50 dark:hover:bg-blue-900
|
|
104
|
-
: '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'
|
|
103
|
+
? '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'
|
|
104
|
+
: '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'
|
|
105
105
|
}
|
|
106
106
|
aria-label={props.dismissLabel || strings.dismiss}
|
|
107
107
|
>
|
|
@@ -172,7 +172,7 @@ const ChoiceBody: Component<{
|
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
const buttonClass = () => {
|
|
175
|
-
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
|
|
175
|
+
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'
|
|
176
176
|
const extra = props.config.buttonClass
|
|
177
177
|
return extra ? `${base} ${extra}` : base
|
|
178
178
|
}
|
|
@@ -195,7 +195,7 @@ const ChoiceBody: Component<{
|
|
|
195
195
|
</Show>
|
|
196
196
|
{option.label}
|
|
197
197
|
<Show when={option.description}>
|
|
198
|
-
<span class="block text-xs text-gray-500 dark:text-gray-400 mt-0.5 font-normal">{option.description}</span>
|
|
198
|
+
<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>
|
|
199
199
|
</Show>
|
|
200
200
|
</>
|
|
201
201
|
}
|
|
@@ -222,21 +222,21 @@ const ConfirmBody: Component<{
|
|
|
222
222
|
return (
|
|
223
223
|
<div>
|
|
224
224
|
<Show when={props.config.message}>
|
|
225
|
-
<p class="text-sm text-gray-600 dark:text-gray-400 mb-3">{props.config.message}</p>
|
|
225
|
+
<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>
|
|
226
226
|
</Show>
|
|
227
227
|
<div class="flex gap-2 justify-end">
|
|
228
228
|
<button
|
|
229
229
|
onClick={props.onCancel}
|
|
230
|
-
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"
|
|
230
|
+
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"
|
|
231
231
|
>
|
|
232
232
|
{props.config.cancelLabel || strings.cancel}
|
|
233
233
|
</button>
|
|
234
234
|
<button
|
|
235
235
|
onClick={props.onConfirm}
|
|
236
|
-
class={`px-4 py-2 text-sm font-medium rounded-lg text-white transition-colors ${
|
|
236
|
+
class={`px-4 py-2 text-sm font-medium rounded-lg text-[color:var(--mcp-ui-accent-fg,var(--color-white,#fff))] transition-colors ${
|
|
237
237
|
isDanger()
|
|
238
|
-
? 'bg-red-600 hover:bg-red-700'
|
|
239
|
-
: 'bg-blue-600 hover:bg-blue-700'
|
|
238
|
+
? 'bg-[color:var(--mcp-ui-danger,var(--color-red-600))] hover:bg-[color:var(--mcp-ui-danger-hover,var(--color-red-700))]'
|
|
239
|
+
: 'bg-[color:var(--mcp-ui-accent,var(--color-blue-600))] hover:bg-[color:var(--mcp-ui-accent-hover,var(--color-blue-700))]'
|
|
240
240
|
}`}
|
|
241
241
|
>
|
|
242
242
|
{props.config.confirmLabel || strings.confirm}
|
|
@@ -380,11 +380,11 @@ const FormBody: Component<{
|
|
|
380
380
|
|
|
381
381
|
{/* Live preview */}
|
|
382
382
|
<Show when={previewText() || previewLoading()}>
|
|
383
|
-
<div class="px-3 py-2 bg-blue-50 dark:bg-blue-900
|
|
383
|
+
<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">
|
|
384
384
|
<Show when={previewLoading()} fallback={
|
|
385
|
-
<p class="text-blue-700 dark:text-blue-300">{previewText()}</p>
|
|
385
|
+
<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>
|
|
386
386
|
}>
|
|
387
|
-
<p class="text-blue-400 animate-pulse">{strings.promptLoadingPreview}</p>
|
|
387
|
+
<p class="text-[color:var(--mcp-ui-accent,var(--color-blue-400))] animate-pulse">{strings.promptLoadingPreview}</p>
|
|
388
388
|
</Show>
|
|
389
389
|
</div>
|
|
390
390
|
</Show>
|
|
@@ -393,7 +393,7 @@ const FormBody: Component<{
|
|
|
393
393
|
<button
|
|
394
394
|
type="submit"
|
|
395
395
|
disabled={!isValid()}
|
|
396
|
-
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"
|
|
396
|
+
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"
|
|
397
397
|
>
|
|
398
398
|
{props.config.submitLabel || strings.submit}
|
|
399
399
|
</button>
|
|
@@ -58,7 +58,7 @@ export const ComponentToolbar: Component<ComponentToolbarProps> = (props) => {
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
return (
|
|
61
|
-
<div class={`absolute ${positionClasses()} z-10 flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity`}>
|
|
61
|
+
<div class={`mcp-ui-root absolute ${positionClasses()} z-10 flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity`}>
|
|
62
62
|
<For each={props.actions}>
|
|
63
63
|
{(action) => <ToolbarButton action={action} />}
|
|
64
64
|
</For>
|
|
@@ -81,15 +81,15 @@ const ToolbarButton: Component<{ action: ToolbarAction }> = (props) => {
|
|
|
81
81
|
const iconPath = () => showCheck() ? ICONS.check : ICONS[props.action.icon]
|
|
82
82
|
const isActive = () => props.action.active
|
|
83
83
|
const colorClass = () => {
|
|
84
|
-
if (showCheck()) return 'text-green-500'
|
|
85
|
-
if (isActive()) return 'text-blue-500 dark:text-blue-400'
|
|
86
|
-
return 'text-gray-500 dark:text-gray-400'
|
|
84
|
+
if (showCheck()) return 'text-[color:var(--mcp-ui-success,var(--color-green-500))]'
|
|
85
|
+
if (isActive()) return 'text-[color:var(--mcp-ui-accent,var(--color-blue-500))] dark:text-[color:var(--mcp-ui-accent,var(--color-blue-400))]'
|
|
86
|
+
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))]'
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
return (
|
|
90
90
|
<button
|
|
91
91
|
onClick={handleClick}
|
|
92
|
-
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`}
|
|
92
|
+
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))]`}
|
|
93
93
|
title={props.action.label}
|
|
94
94
|
aria-label={props.action.label}
|
|
95
95
|
data-mcp-ui-action={props.action.icon}
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
import { Component, For, Show } from 'solid-js';
|
|
19
19
|
import { formatMCPUIString, useMCPUIStrings } from '../context/MCPUIStringsContext';
|
|
20
|
+
import { MissingValueLegend, MissingValueMark } from './MissingValue';
|
|
20
21
|
|
|
21
22
|
export interface DegradedFallbackProps {
|
|
22
23
|
/** Short, human-readable reason the native render was skipped/failed. */
|
|
@@ -35,6 +36,13 @@ export interface DegradedFallbackProps {
|
|
|
35
36
|
caption?: string;
|
|
36
37
|
/** Max rows to render before truncating (default 50). */
|
|
37
38
|
maxRows?: number;
|
|
39
|
+
/**
|
|
40
|
+
* Same shape as `rows`: `true` marks a cell whose value is missing, which
|
|
41
|
+
* renders as `<MissingValueMark/>` instead of its text. A
|
|
42
|
+
* `<MissingValueLegend/>` follows the table when a SHOWN cell is missing.
|
|
43
|
+
* Omitted, the output is unchanged. @since v6.24.0
|
|
44
|
+
*/
|
|
45
|
+
missing?: boolean[][];
|
|
38
46
|
}
|
|
39
47
|
|
|
40
48
|
export const DegradedFallback: Component<DegradedFallbackProps> = (props) => {
|
|
@@ -43,38 +51,49 @@ export const DegradedFallback: Component<DegradedFallbackProps> = (props) => {
|
|
|
43
51
|
const allRows = () => props.rows ?? [];
|
|
44
52
|
const shownRows = () => allRows().slice(0, maxRows());
|
|
45
53
|
const hiddenCount = () => Math.max(0, allRows().length - shownRows().length);
|
|
54
|
+
const isMissing = (rowIndex: number, colIndex: number) =>
|
|
55
|
+
props.missing?.[rowIndex]?.[colIndex] === true;
|
|
56
|
+
const anyShownMissing = () => {
|
|
57
|
+
const columnCount = props.columns?.length ?? 0;
|
|
58
|
+
return shownRows().some((_row, r) => {
|
|
59
|
+
for (let c = 0; c < columnCount; c += 1) if (isMissing(r, c)) return true;
|
|
60
|
+
return false;
|
|
61
|
+
});
|
|
62
|
+
};
|
|
46
63
|
const hasTable = () => (props.columns?.length ?? 0) > 0 && allRows().length > 0;
|
|
47
64
|
|
|
48
65
|
return (
|
|
49
66
|
<div
|
|
50
|
-
class="w-full rounded-lg border border-amber-200 bg-amber-50 p-3 dark:border-amber-800 dark:bg-amber-900
|
|
67
|
+
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))]"
|
|
51
68
|
role="alert"
|
|
52
69
|
>
|
|
53
|
-
<p class="text-sm font-medium text-amber-900 dark:text-amber-100">{props.message}</p>
|
|
54
|
-
<p class="mt-0.5 text-xs text-amber-700 dark:text-amber-300">
|
|
70
|
+
<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>
|
|
71
|
+
<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))]">
|
|
55
72
|
{props.caption ?? strings.degradedCaption}
|
|
56
73
|
</p>
|
|
57
74
|
|
|
58
75
|
<Show when={hasTable()}>
|
|
59
|
-
<div class="mt-2 max-h-64 overflow-auto rounded border border-amber-200 dark:border-amber-800">
|
|
76
|
+
<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))]">
|
|
60
77
|
<table class="w-full border-collapse text-left text-xs">
|
|
61
|
-
<thead class="sticky top-0 bg-amber-100 dark:bg-amber-900
|
|
78
|
+
<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))]">
|
|
62
79
|
<tr>
|
|
63
80
|
<For each={props.columns}>
|
|
64
81
|
{(col) => (
|
|
65
|
-
<th class="px-2 py-1 font-medium text-amber-900 dark:text-amber-100">{col}</th>
|
|
82
|
+
<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>
|
|
66
83
|
)}
|
|
67
84
|
</For>
|
|
68
85
|
</tr>
|
|
69
86
|
</thead>
|
|
70
87
|
<tbody>
|
|
71
88
|
<For each={shownRows()}>
|
|
72
|
-
{(row) => (
|
|
73
|
-
<tr class="border-t border-amber-100 dark:border-amber-800
|
|
89
|
+
{(row, rowIndex) => (
|
|
90
|
+
<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))]">
|
|
74
91
|
<For each={props.columns}>
|
|
75
92
|
{(_col, i) => (
|
|
76
|
-
<td class="px-2 py-1 text-amber-800 dark:text-amber-200">
|
|
77
|
-
{String(row[i()] ?? '')}
|
|
93
|
+
<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))]">
|
|
94
|
+
<Show when={isMissing(rowIndex(), i())} fallback={String(row[i()] ?? '')}>
|
|
95
|
+
<MissingValueMark />
|
|
96
|
+
</Show>
|
|
78
97
|
</td>
|
|
79
98
|
)}
|
|
80
99
|
</For>
|
|
@@ -84,8 +103,11 @@ export const DegradedFallback: Component<DegradedFallbackProps> = (props) => {
|
|
|
84
103
|
</tbody>
|
|
85
104
|
</table>
|
|
86
105
|
</div>
|
|
106
|
+
<Show when={anyShownMissing()}>
|
|
107
|
+
<MissingValueLegend class="mt-2" />
|
|
108
|
+
</Show>
|
|
87
109
|
<Show when={hiddenCount() > 0}>
|
|
88
|
-
<p class="mt-1 text-[10px] text-amber-600 dark:text-amber-400">
|
|
110
|
+
<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))]">
|
|
89
111
|
{formatMCPUIString(strings.degradedMoreRows, { count: hiddenCount() })}
|
|
90
112
|
</p>
|
|
91
113
|
</Show>
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import { Component, Show, createSignal, createEffect, onCleanup, JSX, createContext, useContext, Accessor } from 'solid-js'
|
|
10
10
|
import { Portal } from 'solid-js/web'
|
|
11
|
+
import { bindPortalTheme } from '../utils/theme'
|
|
11
12
|
import { useMCPUIStrings } from '../context/MCPUIStringsContext'
|
|
12
13
|
|
|
13
14
|
/** Context for child components to know if they're in expanded/fullscreen view */
|
|
@@ -154,7 +155,7 @@ export const ExpandableWrapper: Component<ExpandableWrapperProps> = (props) => {
|
|
|
154
155
|
}
|
|
155
156
|
|
|
156
157
|
return (
|
|
157
|
-
<div class="relative group">
|
|
158
|
+
<div class="mcp-ui-root relative group">
|
|
158
159
|
{/* Inline slot — content lives here when not expanded */}
|
|
159
160
|
<div ref={inlineSlotRef}>
|
|
160
161
|
<div ref={contentRef}>
|
|
@@ -172,12 +173,12 @@ export const ExpandableWrapper: Component<ExpandableWrapperProps> = (props) => {
|
|
|
172
173
|
props.toolbarVariant === 'always-visible'
|
|
173
174
|
? 'opacity-60 hover:opacity-100'
|
|
174
175
|
: 'opacity-0 group-hover:opacity-70 hover:!opacity-100'
|
|
175
|
-
} 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`}
|
|
176
|
+
} 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))]`}
|
|
176
177
|
title={strings.expand}
|
|
177
178
|
aria-label={strings.expand}
|
|
178
179
|
data-mcp-ui-action="expand"
|
|
179
180
|
>
|
|
180
|
-
<svg class="w-3.5 h-3.5 text-gray-500 dark:text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
181
|
+
<svg class="w-3.5 h-3.5 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))]" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
181
182
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5v-4m0 4h-4m4 0l-5-5" />
|
|
182
183
|
</svg>
|
|
183
184
|
</button>
|
|
@@ -186,7 +187,7 @@ export const ExpandableWrapper: Component<ExpandableWrapperProps> = (props) => {
|
|
|
186
187
|
<Show when={isExpanded()}>
|
|
187
188
|
<Portal>
|
|
188
189
|
<div
|
|
189
|
-
class="fixed inset-0 z-50 flex flex-col bg-black
|
|
190
|
+
class="fixed inset-0 z-50 flex flex-col bg-[color:var(--mcp-ui-overlay,color-mix(in_oklab,var(--color-black,#000)_50%,transparent))] backdrop-blur-sm"
|
|
190
191
|
style={{ animation: 'expandable-fade-in 0.15s ease-out' }}
|
|
191
192
|
onClick={handleBackdropClick}
|
|
192
193
|
onPointerDown={handleBackdropPointerDown}
|
|
@@ -195,17 +196,20 @@ export const ExpandableWrapper: Component<ExpandableWrapperProps> = (props) => {
|
|
|
195
196
|
aria-modal="true"
|
|
196
197
|
aria-label={props.title || strings.expandedView}
|
|
197
198
|
tabIndex={-1}
|
|
198
|
-
ref={
|
|
199
|
+
ref={(element) => {
|
|
200
|
+
dialogRef = element
|
|
201
|
+
bindPortalTheme(element, () => inlineSlotRef)
|
|
202
|
+
}}
|
|
199
203
|
>
|
|
200
204
|
{/* Modal panel */}
|
|
201
205
|
<div
|
|
202
|
-
class="relative flex flex-col m-4 flex-1 bg-white dark:bg-gray-800 rounded-lg shadow-xl overflow-hidden"
|
|
206
|
+
class="relative flex flex-col m-4 flex-1 bg-[color:var(--mcp-ui-surface,var(--color-white,#fff))] dark:bg-[color:var(--mcp-ui-surface,var(--color-gray-800,#1f2937))] rounded-lg shadow-[var(--mcp-ui-shadow,var(--shadow-xl))] overflow-hidden"
|
|
203
207
|
style={{ animation: 'expandable-scale-in 0.15s ease-out' }}
|
|
204
208
|
onClick={(e) => e.stopPropagation()}
|
|
205
209
|
>
|
|
206
210
|
{/* Header */}
|
|
207
|
-
<div class="flex items-center justify-between px-4 py-3 border-b border-gray-200 dark:border-gray-700 flex-shrink-0">
|
|
208
|
-
<h2 class="text-lg font-semibold text-gray-900 dark:text-white truncate">
|
|
211
|
+
<div class="flex items-center justify-between px-4 py-3 border-b border-[color:var(--mcp-ui-border,var(--color-gray-200,#e5e7eb))] dark:border-[color:var(--mcp-ui-border,var(--color-gray-700,#374151))] flex-shrink-0">
|
|
212
|
+
<h2 class="text-lg font-semibold text-[color:var(--mcp-ui-fg,var(--color-gray-900,#111827))] dark:text-[color:var(--mcp-ui-fg,var(--color-white,#fff))] truncate">
|
|
209
213
|
{props.title || strings.expandedView}
|
|
210
214
|
</h2>
|
|
211
215
|
<div class="flex items-center gap-2">
|
|
@@ -214,7 +218,7 @@ export const ExpandableWrapper: Component<ExpandableWrapperProps> = (props) => {
|
|
|
214
218
|
<button
|
|
215
219
|
type="button"
|
|
216
220
|
onClick={handleCopy}
|
|
217
|
-
class="p-1.5 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"
|
|
221
|
+
class="p-1.5 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"
|
|
218
222
|
title={props.copyLabel || strings.copyToClipboard}
|
|
219
223
|
aria-label={props.copyLabel || strings.copyToClipboard}
|
|
220
224
|
data-mcp-ui-action="copy"
|
|
@@ -222,7 +226,7 @@ export const ExpandableWrapper: Component<ExpandableWrapperProps> = (props) => {
|
|
|
222
226
|
<Show
|
|
223
227
|
when={!copied()}
|
|
224
228
|
fallback={
|
|
225
|
-
<svg class="w-5 h-5 text-green-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
229
|
+
<svg class="w-5 h-5 text-[color:var(--mcp-ui-success,var(--color-green-500))]" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
226
230
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
|
227
231
|
</svg>
|
|
228
232
|
}
|
|
@@ -237,7 +241,7 @@ export const ExpandableWrapper: Component<ExpandableWrapperProps> = (props) => {
|
|
|
237
241
|
<button
|
|
238
242
|
type="button"
|
|
239
243
|
onClick={handleClose}
|
|
240
|
-
class="p-1.5 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"
|
|
244
|
+
class="p-1.5 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"
|
|
241
245
|
aria-label={strings.closeExpandedView}
|
|
242
246
|
data-mcp-ui-action="close"
|
|
243
247
|
>
|