@seed-ship/mcp-ui-solid 6.19.1 → 6.20.0
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 +519 -0
- package/README.md +791 -1
- package/dist/adapters/connector.cjs +15 -4
- package/dist/adapters/connector.cjs.map +1 -1
- package/dist/adapters/connector.d.ts +38 -0
- package/dist/adapters/connector.d.ts.map +1 -1
- package/dist/adapters/connector.js +15 -4
- package/dist/adapters/connector.js.map +1 -1
- package/dist/adapters/index.d.ts +4 -3
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/macro-run.cjs +25 -13
- package/dist/adapters/macro-run.cjs.map +1 -1
- package/dist/adapters/macro-run.d.ts +37 -2
- package/dist/adapters/macro-run.d.ts.map +1 -1
- package/dist/adapters/macro-run.js +25 -13
- package/dist/adapters/macro-run.js.map +1 -1
- package/dist/adapters.cjs +2 -0
- package/dist/adapters.cjs.map +1 -1
- package/dist/adapters.js +4 -2
- package/dist/components/ActionGroupRenderer.cjs +3 -1
- package/dist/components/ActionGroupRenderer.cjs.map +1 -1
- package/dist/components/ActionGroupRenderer.d.ts.map +1 -1
- package/dist/components/ActionGroupRenderer.js +3 -1
- package/dist/components/ActionGroupRenderer.js.map +1 -1
- package/dist/components/AgentCard.cjs +11 -8
- package/dist/components/AgentCard.cjs.map +1 -1
- package/dist/components/AgentCard.d.ts.map +1 -1
- package/dist/components/AgentCard.js +11 -8
- package/dist/components/AgentCard.js.map +1 -1
- package/dist/components/AgentHandoff.cjs +6 -1
- package/dist/components/AgentHandoff.cjs.map +1 -1
- package/dist/components/AgentHandoff.d.ts.map +1 -1
- package/dist/components/AgentHandoff.js +6 -1
- package/dist/components/AgentHandoff.js.map +1 -1
- package/dist/components/ArtifactRenderer.cjs +25 -6
- package/dist/components/ArtifactRenderer.cjs.map +1 -1
- package/dist/components/ArtifactRenderer.d.ts.map +1 -1
- package/dist/components/ArtifactRenderer.js +25 -6
- package/dist/components/ArtifactRenderer.js.map +1 -1
- package/dist/components/AutocompleteDropdown.cjs +30 -24
- package/dist/components/AutocompleteDropdown.cjs.map +1 -1
- package/dist/components/AutocompleteDropdown.d.ts.map +1 -1
- package/dist/components/AutocompleteDropdown.js +30 -24
- package/dist/components/AutocompleteDropdown.js.map +1 -1
- package/dist/components/AutocompleteFormField.cjs +3 -1
- package/dist/components/AutocompleteFormField.cjs.map +1 -1
- package/dist/components/AutocompleteFormField.d.ts.map +1 -1
- package/dist/components/AutocompleteFormField.js +4 -2
- package/dist/components/AutocompleteFormField.js.map +1 -1
- package/dist/components/BriefingDiff.cjs +45 -39
- package/dist/components/BriefingDiff.cjs.map +1 -1
- package/dist/components/BriefingDiff.d.ts.map +1 -1
- package/dist/components/BriefingDiff.js +45 -39
- package/dist/components/BriefingDiff.js.map +1 -1
- package/dist/components/CarouselRenderer.cjs +8 -2
- package/dist/components/CarouselRenderer.cjs.map +1 -1
- package/dist/components/CarouselRenderer.d.ts.map +1 -1
- package/dist/components/CarouselRenderer.js +8 -2
- package/dist/components/CarouselRenderer.js.map +1 -1
- package/dist/components/ChartJSRenderer.cjs +60 -36
- package/dist/components/ChartJSRenderer.cjs.map +1 -1
- package/dist/components/ChartJSRenderer.d.ts.map +1 -1
- package/dist/components/ChartJSRenderer.js +61 -37
- package/dist/components/ChartJSRenderer.js.map +1 -1
- package/dist/components/ChatPrompt.cjs +15 -9
- package/dist/components/ChatPrompt.cjs.map +1 -1
- package/dist/components/ChatPrompt.d.ts.map +1 -1
- package/dist/components/ChatPrompt.js +15 -9
- package/dist/components/ChatPrompt.js.map +1 -1
- package/dist/components/CodeBlockRenderer.cjs +34 -16
- package/dist/components/CodeBlockRenderer.cjs.map +1 -1
- package/dist/components/CodeBlockRenderer.d.ts.map +1 -1
- package/dist/components/CodeBlockRenderer.js +34 -16
- package/dist/components/CodeBlockRenderer.js.map +1 -1
- package/dist/components/DataPreviewSection.cjs +91 -44
- package/dist/components/DataPreviewSection.cjs.map +1 -1
- package/dist/components/DataPreviewSection.d.ts.map +1 -1
- package/dist/components/DataPreviewSection.js +92 -45
- package/dist/components/DataPreviewSection.js.map +1 -1
- package/dist/components/DegradedFallback.cjs +20 -16
- package/dist/components/DegradedFallback.cjs.map +1 -1
- package/dist/components/DegradedFallback.d.ts.map +1 -1
- package/dist/components/DegradedFallback.js +20 -16
- package/dist/components/DegradedFallback.js.map +1 -1
- package/dist/components/FooterRenderer.cjs +21 -17
- package/dist/components/FooterRenderer.cjs.map +1 -1
- package/dist/components/FooterRenderer.d.ts.map +1 -1
- package/dist/components/FooterRenderer.js +21 -17
- package/dist/components/FooterRenderer.js.map +1 -1
- package/dist/components/FormFieldRenderer.cjs +116 -93
- package/dist/components/FormFieldRenderer.cjs.map +1 -1
- package/dist/components/FormFieldRenderer.d.ts.map +1 -1
- package/dist/components/FormFieldRenderer.js +116 -93
- package/dist/components/FormFieldRenderer.js.map +1 -1
- package/dist/components/FormRenderer.cjs +55 -31
- package/dist/components/FormRenderer.cjs.map +1 -1
- package/dist/components/FormRenderer.d.ts.map +1 -1
- package/dist/components/FormRenderer.js +55 -31
- package/dist/components/FormRenderer.js.map +1 -1
- package/dist/components/GenerativeUIErrorBoundary.cjs +20 -15
- package/dist/components/GenerativeUIErrorBoundary.cjs.map +1 -1
- package/dist/components/GenerativeUIErrorBoundary.d.ts.map +1 -1
- package/dist/components/GenerativeUIErrorBoundary.js +20 -15
- package/dist/components/GenerativeUIErrorBoundary.js.map +1 -1
- package/dist/components/GraphRenderer.cjs +56 -33
- package/dist/components/GraphRenderer.cjs.map +1 -1
- package/dist/components/GraphRenderer.d.ts.map +1 -1
- package/dist/components/GraphRenderer.js +56 -33
- package/dist/components/GraphRenderer.js.map +1 -1
- package/dist/components/ImageGalleryRenderer.cjs +13 -4
- package/dist/components/ImageGalleryRenderer.cjs.map +1 -1
- package/dist/components/ImageGalleryRenderer.d.ts.map +1 -1
- package/dist/components/ImageGalleryRenderer.js +13 -4
- package/dist/components/ImageGalleryRenderer.js.map +1 -1
- package/dist/components/LightboxOverlay.cjs +16 -8
- package/dist/components/LightboxOverlay.cjs.map +1 -1
- package/dist/components/LightboxOverlay.d.ts.map +1 -1
- package/dist/components/LightboxOverlay.js +17 -9
- package/dist/components/LightboxOverlay.js.map +1 -1
- package/dist/components/MapRenderer.cjs +59 -29
- package/dist/components/MapRenderer.cjs.map +1 -1
- package/dist/components/MapRenderer.d.ts +10 -2
- package/dist/components/MapRenderer.d.ts.map +1 -1
- package/dist/components/MapRenderer.js +60 -30
- package/dist/components/MapRenderer.js.map +1 -1
- package/dist/components/ModalRenderer.cjs +4 -1
- package/dist/components/ModalRenderer.cjs.map +1 -1
- package/dist/components/ModalRenderer.d.ts.map +1 -1
- package/dist/components/ModalRenderer.js +5 -2
- package/dist/components/ModalRenderer.js.map +1 -1
- package/dist/components/ScratchpadPanel.cjs +578 -535
- package/dist/components/ScratchpadPanel.cjs.map +1 -1
- package/dist/components/ScratchpadPanel.d.ts.map +1 -1
- package/dist/components/ScratchpadPanel.js +578 -535
- package/dist/components/ScratchpadPanel.js.map +1 -1
- package/dist/components/StreamingUIRenderer.cjs +92 -28
- package/dist/components/StreamingUIRenderer.cjs.map +1 -1
- package/dist/components/StreamingUIRenderer.d.ts.map +1 -1
- package/dist/components/StreamingUIRenderer.js +92 -28
- package/dist/components/StreamingUIRenderer.js.map +1 -1
- package/dist/components/UIResourceRenderer.cjs +456 -363
- package/dist/components/UIResourceRenderer.cjs.map +1 -1
- package/dist/components/UIResourceRenderer.d.ts +21 -0
- package/dist/components/UIResourceRenderer.d.ts.map +1 -1
- package/dist/components/UIResourceRenderer.js +458 -365
- package/dist/components/UIResourceRenderer.js.map +1 -1
- package/dist/components/VerifiedText.cjs +39 -20
- package/dist/components/VerifiedText.cjs.map +1 -1
- package/dist/components/VerifiedText.d.ts +2 -1
- package/dist/components/VerifiedText.d.ts.map +1 -1
- package/dist/components/VerifiedText.js +39 -20
- package/dist/components/VerifiedText.js.map +1 -1
- package/dist/components/VideoRenderer.cjs +10 -5
- package/dist/components/VideoRenderer.cjs.map +1 -1
- package/dist/components/VideoRenderer.d.ts.map +1 -1
- package/dist/components/VideoRenderer.js +10 -5
- package/dist/components/VideoRenderer.js.map +1 -1
- package/dist/components/chart-data-table.cjs +38 -17
- package/dist/components/chart-data-table.cjs.map +1 -1
- package/dist/components/chart-data-table.d.ts +30 -1
- package/dist/components/chart-data-table.d.ts.map +1 -1
- package/dist/components/chart-data-table.js +38 -17
- package/dist/components/chart-data-table.js.map +1 -1
- package/dist/context/MCPActionContext.cjs +3 -1
- package/dist/context/MCPActionContext.cjs.map +1 -1
- package/dist/context/MCPActionContext.d.ts.map +1 -1
- package/dist/context/MCPActionContext.js +3 -1
- package/dist/context/MCPActionContext.js.map +1 -1
- package/dist/context/MCPUIStringsContext.cjs +285 -2
- package/dist/context/MCPUIStringsContext.cjs.map +1 -1
- package/dist/context/MCPUIStringsContext.d.ts +600 -3
- package/dist/context/MCPUIStringsContext.d.ts.map +1 -1
- package/dist/context/MCPUIStringsContext.js +285 -2
- package/dist/context/MCPUIStringsContext.js.map +1 -1
- package/dist/hooks/index.d.ts +2 -2
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/useStreamingUI.cjs +28 -10
- package/dist/hooks/useStreamingUI.cjs.map +1 -1
- package/dist/hooks/useStreamingUI.d.ts +37 -0
- package/dist/hooks/useStreamingUI.d.ts.map +1 -1
- package/dist/hooks/useStreamingUI.js +28 -10
- package/dist/hooks/useStreamingUI.js.map +1 -1
- package/dist/hooks.cjs +1 -0
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.js +2 -1
- package/dist/index.cjs +23 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -3
- package/dist/index.d.ts +9 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -3
- package/dist/index.js.map +1 -1
- package/dist/services/validation.cjs +41 -16
- package/dist/services/validation.cjs.map +1 -1
- package/dist/services/validation.d.ts +47 -2
- package/dist/services/validation.d.ts.map +1 -1
- package/dist/services/validation.js +41 -16
- package/dist/services/validation.js.map +1 -1
- package/dist/utils/degraded-projections.cjs +37 -12
- package/dist/utils/degraded-projections.cjs.map +1 -1
- package/dist/utils/degraded-projections.d.ts +39 -3
- package/dist/utils/degraded-projections.d.ts.map +1 -1
- package/dist/utils/degraded-projections.js +37 -12
- package/dist/utils/degraded-projections.js.map +1 -1
- package/dist/utils/format-string.cjs +10 -0
- package/dist/utils/format-string.cjs.map +1 -0
- package/dist/utils/format-string.d.ts +26 -0
- package/dist/utils/format-string.d.ts.map +1 -0
- package/dist/utils/format-string.js +10 -0
- package/dist/utils/format-string.js.map +1 -0
- package/dist/validation.cjs +3 -0
- package/dist/validation.cjs.map +1 -1
- package/dist/validation.d.cts +2 -1
- package/dist/validation.d.ts +2 -1
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +4 -1
- package/package.json +1 -1
- package/src/adapters/connector.ts +58 -4
- package/src/adapters/index.ts +12 -2
- package/src/adapters/macro-run.ts +71 -11
- package/src/components/ActionGroupRenderer.tsx +3 -1
- package/src/components/AgentCard.tsx +27 -9
- package/src/components/AgentHandoff.tsx +4 -1
- package/src/components/ArtifactRenderer.tsx +17 -5
- package/src/components/AutocompleteDropdown.tsx +8 -6
- package/src/components/AutocompleteFormField.tsx +5 -1
- package/src/components/BriefingDiff.tsx +11 -3
- package/src/components/CarouselRenderer.tsx +4 -2
- package/src/components/ChartJSRenderer.tsx +18 -9
- package/src/components/ChatPrompt.tsx +13 -8
- package/src/components/CodeBlockRenderer.tsx +12 -10
- package/src/components/DataPreviewSection.tsx +92 -26
- package/src/components/DegradedFallback.tsx +4 -2
- package/src/components/FooterRenderer.tsx +3 -1
- package/src/components/FormFieldRenderer.tsx +34 -19
- package/src/components/FormRenderer.tsx +38 -10
- package/src/components/GenerativeUIErrorBoundary.tsx +8 -3
- package/src/components/GraphRenderer.tsx +31 -16
- package/src/components/ImageGalleryRenderer.tsx +8 -4
- package/src/components/LightboxOverlay.tsx +6 -4
- package/src/components/MapRenderer.tsx +57 -20
- package/src/components/ModalRenderer.tsx +3 -1
- package/src/components/ScratchpadPanel.tsx +95 -44
- package/src/components/StreamingUIRenderer.tsx +41 -11
- package/src/components/UIResourceRenderer.tsx +145 -63
- package/src/components/VerifiedText.tsx +19 -9
- package/src/components/VideoRenderer.tsx +6 -4
- package/src/components/chart-data-table.ts +68 -14
- package/src/context/MCPActionContext.tsx +4 -1
- package/src/context/MCPUIStringsContext.tsx +1004 -1
- package/src/hooks/index.ts +2 -1
- package/src/hooks/useStreamingUI.ts +64 -10
- package/src/index.ts +23 -0
- package/src/services/validation.ts +93 -16
- package/src/utils/degraded-projections.ts +75 -12
- package/src/utils/format-string.ts +33 -0
- package/src/validation.ts +5 -0
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { Show, For } from 'solid-js'
|
|
9
9
|
import type { AgentCardContent } from '../types/chat-bus'
|
|
10
|
+
import { useMCPUIStrings } from '../context/MCPUIStringsContext'
|
|
10
11
|
|
|
11
12
|
export interface AgentCardProps {
|
|
12
13
|
content: AgentCardContent
|
|
@@ -23,15 +24,31 @@ const AVATAR_MAP: Record<string, string> = {
|
|
|
23
24
|
robot: '\uD83E\uDD16',
|
|
24
25
|
}
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
/**
|
|
28
|
+
* Status styling. The record stays module-level, but it carries a
|
|
29
|
+
* `labelKey` rather than English: the label is resolved from
|
|
30
|
+
* `useMCPUIStrings()` at render time so a host provider can localize it.
|
|
31
|
+
*/
|
|
32
|
+
type AgentStatusLabelKey =
|
|
33
|
+
| 'agentStatusIdle'
|
|
34
|
+
| 'agentStatusRunning'
|
|
35
|
+
| 'agentStatusWaiting'
|
|
36
|
+
| 'agentStatusDone'
|
|
37
|
+
| 'agentStatusError'
|
|
38
|
+
|
|
39
|
+
const STATUS_CONFIG: Record<
|
|
40
|
+
string,
|
|
41
|
+
{ labelKey: AgentStatusLabelKey; color: string; pulse: boolean }
|
|
42
|
+
> = {
|
|
43
|
+
idle: { labelKey: 'agentStatusIdle', color: 'bg-gray-400', pulse: false },
|
|
44
|
+
running: { labelKey: 'agentStatusRunning', color: 'bg-blue-500', pulse: true },
|
|
45
|
+
waiting: { labelKey: 'agentStatusWaiting', color: 'bg-amber-500', pulse: true },
|
|
46
|
+
done: { labelKey: 'agentStatusDone', color: 'bg-green-500', pulse: false },
|
|
47
|
+
error: { labelKey: 'agentStatusError', color: 'bg-red-500', pulse: false },
|
|
32
48
|
}
|
|
33
49
|
|
|
34
50
|
export function AgentCard(props: AgentCardProps) {
|
|
51
|
+
const strings = useMCPUIStrings()
|
|
35
52
|
const c = () => props.content
|
|
36
53
|
const status = () => STATUS_CONFIG[c().status] || STATUS_CONFIG.idle
|
|
37
54
|
const avatar = () => AVATAR_MAP[c().avatar || ''] || c().avatar || '\uD83E\uDD16'
|
|
@@ -54,8 +71,8 @@ export function AgentCard(props: AgentCardProps) {
|
|
|
54
71
|
<div class="flex items-center gap-2">
|
|
55
72
|
<span class="font-medium text-sm text-gray-900 dark:text-white truncate">{c().name}</span>
|
|
56
73
|
{/* Status dot */}
|
|
57
|
-
<span class={`inline-block w-2 h-2 rounded-full ${status().color} ${status().pulse ? 'animate-pulse' : ''}`} title={status().
|
|
58
|
-
<span class="text-xs text-gray-500 dark:text-gray-400">{status().
|
|
74
|
+
<span class={`inline-block w-2 h-2 rounded-full ${status().color} ${status().pulse ? 'animate-pulse' : ''}`} title={strings[status().labelKey]} />
|
|
75
|
+
<span class="text-xs text-gray-500 dark:text-gray-400">{strings[status().labelKey]}</span>
|
|
59
76
|
</div>
|
|
60
77
|
|
|
61
78
|
{/* Model */}
|
|
@@ -97,13 +114,14 @@ export interface AgentStatusBadgeProps {
|
|
|
97
114
|
}
|
|
98
115
|
|
|
99
116
|
export function AgentStatusBadge(props: AgentStatusBadgeProps) {
|
|
117
|
+
const strings = useMCPUIStrings()
|
|
100
118
|
const status = () => STATUS_CONFIG[props.status] || STATUS_CONFIG.idle
|
|
101
119
|
|
|
102
120
|
return (
|
|
103
121
|
<span class="inline-flex items-center gap-1.5 text-xs">
|
|
104
122
|
<span class={`w-2 h-2 rounded-full ${status().color} ${status().pulse ? 'animate-pulse' : ''}`} />
|
|
105
123
|
<span class="text-gray-600 dark:text-gray-300">{props.agentName}</span>
|
|
106
|
-
<span class="text-gray-400 dark:text-gray-500">{status().
|
|
124
|
+
<span class="text-gray-400 dark:text-gray-500">{strings[status().labelKey]}</span>
|
|
107
125
|
</span>
|
|
108
126
|
)
|
|
109
127
|
}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { Show } from 'solid-js'
|
|
9
9
|
import type { AgentHandoffContent } from '../types/chat-bus'
|
|
10
|
+
import { formatMCPUIString, useMCPUIStrings } from '../context/MCPUIStringsContext'
|
|
10
11
|
|
|
11
12
|
export interface AgentHandoffProps {
|
|
12
13
|
content: AgentHandoffContent
|
|
@@ -24,6 +25,7 @@ function getAvatar(key?: string): string {
|
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
export function AgentHandoff(props: AgentHandoffProps) {
|
|
28
|
+
const strings = useMCPUIStrings()
|
|
27
29
|
const c = () => props.content
|
|
28
30
|
|
|
29
31
|
if (typeof console !== 'undefined') {
|
|
@@ -49,7 +51,8 @@ export function AgentHandoff(props: AgentHandoffProps) {
|
|
|
49
51
|
</div>
|
|
50
52
|
<Show when={c().summary || c().itemCount}>
|
|
51
53
|
<span class="text-[10px] text-gray-500 dark:text-gray-400 text-center">
|
|
52
|
-
{c().summary ||
|
|
54
|
+
{c().summary ||
|
|
55
|
+
formatMCPUIString(strings.handoffItems, { count: c().itemCount ?? 0 })}
|
|
53
56
|
</span>
|
|
54
57
|
</Show>
|
|
55
58
|
</div>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Component } from 'solid-js'
|
|
2
2
|
import { safeUrl } from '../utils/safe-url'
|
|
3
|
+
import { formatMCPUIString, useMCPUIStrings } from '../context/MCPUIStringsContext'
|
|
3
4
|
|
|
4
5
|
export interface ArtifactComponentParams {
|
|
5
6
|
url: string
|
|
@@ -10,6 +11,7 @@ export interface ArtifactComponentParams {
|
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
export const ArtifactRenderer: Component<{ params: ArtifactComponentParams }> = (props) => {
|
|
14
|
+
const strings = useMCPUIStrings()
|
|
13
15
|
const getIcon = () => {
|
|
14
16
|
if (props.params.mimeType?.includes('csv')) return '📊'
|
|
15
17
|
if (props.params.mimeType?.includes('json')) return '{}'
|
|
@@ -19,9 +21,19 @@ export const ArtifactRenderer: Component<{ params: ArtifactComponentParams }> =
|
|
|
19
21
|
|
|
20
22
|
const formatSize = (bytes?: number) => {
|
|
21
23
|
if (!bytes) return ''
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
const oneDecimal = (n: number) =>
|
|
25
|
+
new Intl.NumberFormat(strings.locale, {
|
|
26
|
+
minimumFractionDigits: 1,
|
|
27
|
+
maximumFractionDigits: 1,
|
|
28
|
+
useGrouping: false,
|
|
29
|
+
}).format(n)
|
|
30
|
+
if (bytes < 1024) {
|
|
31
|
+
return formatMCPUIString(strings.sizeBytes, {
|
|
32
|
+
size: new Intl.NumberFormat(strings.locale, { maximumFractionDigits: 0 }).format(bytes),
|
|
33
|
+
})
|
|
34
|
+
}
|
|
35
|
+
if (bytes < 1024 * 1024) return formatMCPUIString(strings.sizeKilobytes, { size: oneDecimal(bytes / 1024) })
|
|
36
|
+
return formatMCPUIString(strings.sizeMegabytes, { size: oneDecimal(bytes / (1024 * 1024)) })
|
|
25
37
|
}
|
|
26
38
|
|
|
27
39
|
return (
|
|
@@ -35,7 +47,7 @@ export const ArtifactRenderer: Component<{ params: ArtifactComponentParams }> =
|
|
|
35
47
|
{props.params.filename}
|
|
36
48
|
</h4>
|
|
37
49
|
<p class="text-xs text-gray-500 dark:text-gray-400">
|
|
38
|
-
{formatSize(props.params.size)} • {props.params.description ||
|
|
50
|
+
{formatSize(props.params.size)} • {props.params.description || strings.artifactDescription}
|
|
39
51
|
</p>
|
|
40
52
|
</div>
|
|
41
53
|
</div>
|
|
@@ -48,7 +60,7 @@ export const ArtifactRenderer: Component<{ params: ArtifactComponentParams }> =
|
|
|
48
60
|
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
49
61
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
|
|
50
62
|
</svg>
|
|
51
|
-
|
|
63
|
+
{strings.download}
|
|
52
64
|
</a>
|
|
53
65
|
</div>
|
|
54
66
|
)
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { Component, For, Show, createMemo, JSX } from 'solid-js'
|
|
9
9
|
import type { AutocompleteOption } from '../types'
|
|
10
|
+
import { useMCPUIStrings } from '../context/MCPUIStringsContext'
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Props for AutocompleteDropdown
|
|
@@ -142,6 +143,7 @@ const DefaultOptionRenderer: Component<{
|
|
|
142
143
|
* AutocompleteDropdown Component
|
|
143
144
|
*/
|
|
144
145
|
export const AutocompleteDropdown: Component<AutocompleteDropdownProps> = (props) => {
|
|
146
|
+
const strings = useMCPUIStrings()
|
|
145
147
|
const positionStyles = createMemo((): JSX.CSSProperties => {
|
|
146
148
|
if (props.position === 'top') {
|
|
147
149
|
return {
|
|
@@ -175,7 +177,7 @@ export const AutocompleteDropdown: Component<AutocompleteDropdownProps> = (props
|
|
|
175
177
|
class={`mcp-autocomplete-dropdown ${props.class || ''}`}
|
|
176
178
|
style={containerStyles()}
|
|
177
179
|
role="listbox"
|
|
178
|
-
aria-label=
|
|
180
|
+
aria-label={strings.autocompleteSuggestions}
|
|
179
181
|
>
|
|
180
182
|
{/* Loading state */}
|
|
181
183
|
<Show when={props.isLoading}>
|
|
@@ -201,7 +203,7 @@ export const AutocompleteDropdown: Component<AutocompleteDropdownProps> = (props
|
|
|
201
203
|
animation: 'mcp-spin 0.6s linear infinite'
|
|
202
204
|
}}
|
|
203
205
|
/>
|
|
204
|
-
{props.loadingMessage ||
|
|
206
|
+
{props.loadingMessage || strings.autocompleteLoading}
|
|
205
207
|
</div>
|
|
206
208
|
</Show>
|
|
207
209
|
|
|
@@ -216,7 +218,7 @@ export const AutocompleteDropdown: Component<AutocompleteDropdownProps> = (props
|
|
|
216
218
|
'text-align': 'center'
|
|
217
219
|
}}
|
|
218
220
|
>
|
|
219
|
-
{props.emptyMessage ||
|
|
221
|
+
{props.emptyMessage || strings.autocompleteEmpty}
|
|
220
222
|
</div>
|
|
221
223
|
</Show>
|
|
222
224
|
|
|
@@ -302,7 +304,7 @@ export const AutocompleteDropdown: Component<AutocompleteDropdownProps> = (props
|
|
|
302
304
|
'font-family': 'inherit',
|
|
303
305
|
'font-size': '0.7rem'
|
|
304
306
|
}}>↓</kbd>
|
|
305
|
-
{
|
|
307
|
+
{strings.autocompleteHintNavigate}
|
|
306
308
|
<kbd style={{
|
|
307
309
|
'background-color': '#e5e7eb',
|
|
308
310
|
padding: '1px 4px',
|
|
@@ -310,7 +312,7 @@ export const AutocompleteDropdown: Component<AutocompleteDropdownProps> = (props
|
|
|
310
312
|
'font-family': 'inherit',
|
|
311
313
|
'font-size': '0.7rem'
|
|
312
314
|
}}>Enter</kbd>
|
|
313
|
-
{
|
|
315
|
+
{strings.autocompleteHintSelect}
|
|
314
316
|
<kbd style={{
|
|
315
317
|
'background-color': '#e5e7eb',
|
|
316
318
|
padding: '1px 4px',
|
|
@@ -318,7 +320,7 @@ export const AutocompleteDropdown: Component<AutocompleteDropdownProps> = (props
|
|
|
318
320
|
'font-family': 'inherit',
|
|
319
321
|
'font-size': '0.7rem'
|
|
320
322
|
}}>Esc</kbd>
|
|
321
|
-
{
|
|
323
|
+
{strings.autocompleteHintDismiss}
|
|
322
324
|
</div>
|
|
323
325
|
</Show>
|
|
324
326
|
</div>
|
|
@@ -10,6 +10,7 @@ import type { FormFieldParams, FieldAutocompleteConfig, AutocompleteContext } fr
|
|
|
10
10
|
import { useConditionalField } from '../hooks/useConditionalField'
|
|
11
11
|
import { useAutocomplete } from '../hooks/useAutocomplete'
|
|
12
12
|
import { useAutocompleteContextSafe } from '../context/AutocompleteContext'
|
|
13
|
+
import { useMCPUIStrings } from '../context/MCPUIStringsContext'
|
|
13
14
|
import { GhostText } from './GhostText'
|
|
14
15
|
import { AutocompleteDropdown } from './AutocompleteDropdown'
|
|
15
16
|
|
|
@@ -62,6 +63,7 @@ export interface AutocompleteFormFieldProps {
|
|
|
62
63
|
* AutocompleteFormField Component
|
|
63
64
|
*/
|
|
64
65
|
export const AutocompleteFormField: Component<AutocompleteFormFieldProps> = (props) => {
|
|
66
|
+
const strings = useMCPUIStrings()
|
|
65
67
|
// Check if autocomplete context is available
|
|
66
68
|
const autocompleteCtx = useAutocompleteContextSafe()
|
|
67
69
|
|
|
@@ -205,7 +207,9 @@ export const AutocompleteFormField: Component<AutocompleteFormFieldProps> = (pro
|
|
|
205
207
|
inputValue={localValue()}
|
|
206
208
|
ghostText={autocomplete.ghostText()}
|
|
207
209
|
visible={autocomplete.isOpen()}
|
|
208
|
-
hintText={
|
|
210
|
+
hintText={
|
|
211
|
+
autocomplete.ghostText() ? strings.autocompleteTabToAccept : undefined
|
|
212
|
+
}
|
|
209
213
|
isLoading={autocomplete.isLoading()}
|
|
210
214
|
/>
|
|
211
215
|
</Show>
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { For, Show } from 'solid-js'
|
|
9
9
|
import type { BriefingDiffContent } from '../types/chat-bus'
|
|
10
|
+
import { formatMCPUIString, useMCPUIStrings } from '../context/MCPUIStringsContext'
|
|
10
11
|
|
|
11
12
|
export interface BriefingDiffProps {
|
|
12
13
|
content: BriefingDiffContent
|
|
@@ -19,6 +20,7 @@ const CHANGE_CONFIG: Record<string, { icon: string; color: string; bg: string }>
|
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
export function BriefingDiff(props: BriefingDiffProps) {
|
|
23
|
+
const strings = useMCPUIStrings()
|
|
22
24
|
const c = () => props.content
|
|
23
25
|
|
|
24
26
|
if (typeof console !== 'undefined') {
|
|
@@ -45,13 +47,19 @@ export function BriefingDiff(props: BriefingDiffProps) {
|
|
|
45
47
|
{(stats) => (
|
|
46
48
|
<div class="flex items-center gap-3 text-xs">
|
|
47
49
|
<Show when={stats().added > 0}>
|
|
48
|
-
<span class="text-green-600 dark:text-green-400"
|
|
50
|
+
<span class="text-green-600 dark:text-green-400">
|
|
51
|
+
{formatMCPUIString(strings.briefingAdded, { count: stats().added })}
|
|
52
|
+
</span>
|
|
49
53
|
</Show>
|
|
50
54
|
<Show when={stats().removed > 0}>
|
|
51
|
-
<span class="text-red-600 dark:text-red-400">
|
|
55
|
+
<span class="text-red-600 dark:text-red-400">
|
|
56
|
+
{formatMCPUIString(strings.briefingRemoved, { count: stats().removed })}
|
|
57
|
+
</span>
|
|
52
58
|
</Show>
|
|
53
59
|
<Show when={stats().changed > 0}>
|
|
54
|
-
<span class="text-amber-600 dark:text-amber-400">
|
|
60
|
+
<span class="text-amber-600 dark:text-amber-400">
|
|
61
|
+
{formatMCPUIString(strings.briefingChanged, { count: stats().changed })}
|
|
62
|
+
</span>
|
|
55
63
|
</Show>
|
|
56
64
|
</div>
|
|
57
65
|
)}
|
|
@@ -3,6 +3,7 @@ import { isServer } from 'solid-js/web'
|
|
|
3
3
|
import { useRenderContext } from './RenderContext'
|
|
4
4
|
import type { UIComponent } from '../types'
|
|
5
5
|
import { ExpandableWrapper, useExpanded } from './ExpandableWrapper'
|
|
6
|
+
import { useMCPUIStrings } from '../context/MCPUIStringsContext'
|
|
6
7
|
|
|
7
8
|
export interface CarouselRendererProps {
|
|
8
9
|
items: UIComponent[]
|
|
@@ -15,6 +16,7 @@ export interface CarouselRendererProps {
|
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
export const CarouselRenderer: Component<CarouselRendererProps> = (props) => {
|
|
19
|
+
const strings = useMCPUIStrings()
|
|
18
20
|
let scrollContainer: HTMLDivElement | undefined
|
|
19
21
|
const [canScrollLeft, setCanScrollLeft] = createSignal(false)
|
|
20
22
|
const [canScrollRight, setCanScrollRight] = createSignal(true)
|
|
@@ -42,9 +44,9 @@ export const CarouselRenderer: Component<CarouselRendererProps> = (props) => {
|
|
|
42
44
|
|
|
43
45
|
return (
|
|
44
46
|
<ExpandableWrapper
|
|
45
|
-
title={
|
|
47
|
+
title={strings.carouselTitle}
|
|
46
48
|
copyData={JSON.stringify(props.items, null, 2)}
|
|
47
|
-
copyLabel=
|
|
49
|
+
copyLabel={strings.carouselCopy}
|
|
48
50
|
toolbarVariant={props.toolbarVariant}
|
|
49
51
|
>
|
|
50
52
|
<div class={`relative group ${isExpanded() ? 'flex-1 min-h-0 flex flex-col' : ''}`}>
|
|
@@ -24,7 +24,7 @@ import { ExpandableWrapper, useExpanded } from './ExpandableWrapper';
|
|
|
24
24
|
import { DegradedFallback } from './DegradedFallback';
|
|
25
25
|
import { chartToDataTable } from './chart-data-table';
|
|
26
26
|
import { useTelemetry } from '../context/MCPUITelemetryContext';
|
|
27
|
-
import { useMCPUIStrings } from '../context/MCPUIStringsContext';
|
|
27
|
+
import { formatMCPUIString, useMCPUIStrings } from '../context/MCPUIStringsContext';
|
|
28
28
|
|
|
29
29
|
// Lazy load Chart.js to avoid bundling if not used
|
|
30
30
|
let ChartJS: any = null;
|
|
@@ -113,9 +113,18 @@ export const ChartJSRenderer: Component<ChartJSRendererProps> = (props) => {
|
|
|
113
113
|
let renderVersion = 0;
|
|
114
114
|
|
|
115
115
|
const params = () => props.component.params as ChartComponentParams;
|
|
116
|
-
const tableData = createMemo(() => chartToDataTable(params()));
|
|
117
116
|
const telemetry = useTelemetry();
|
|
118
117
|
const strings = useMCPUIStrings();
|
|
118
|
+
// The accessible data table is a pure projection: its column headers come
|
|
119
|
+
// from the chrome strings, injected rather than hardcoded in the helper.
|
|
120
|
+
const tableData = createMemo(() =>
|
|
121
|
+
chartToDataTable(params(), {
|
|
122
|
+
series: strings.chartTableSeries,
|
|
123
|
+
point: strings.chartTablePoint,
|
|
124
|
+
label: strings.degradedColLabel,
|
|
125
|
+
seriesName: strings.degradedSeries,
|
|
126
|
+
})
|
|
127
|
+
);
|
|
119
128
|
const descriptionId = createUniqueId();
|
|
120
129
|
const title = () => params().title || strings.chartView;
|
|
121
130
|
|
|
@@ -205,7 +214,7 @@ export const ChartJSRenderer: Component<ChartJSRendererProps> = (props) => {
|
|
|
205
214
|
setIsLoading(false);
|
|
206
215
|
} catch (err) {
|
|
207
216
|
if (version !== renderVersion) return;
|
|
208
|
-
const error = err instanceof Error ? err : new Error(
|
|
217
|
+
const error = err instanceof Error ? err : new Error(strings.chartRenderError);
|
|
209
218
|
setError(error.message);
|
|
210
219
|
setIsLoading(false);
|
|
211
220
|
// Fallback ladder (P2.5): record the failure so it's observable, then
|
|
@@ -241,7 +250,7 @@ export const ChartJSRenderer: Component<ChartJSRendererProps> = (props) => {
|
|
|
241
250
|
<ExpandableWrapper
|
|
242
251
|
title={title()}
|
|
243
252
|
copyData={copyDataJSON()}
|
|
244
|
-
copyLabel=
|
|
253
|
+
copyLabel={strings.chartCopy}
|
|
245
254
|
toolbarVariant={props.toolbarVariant}
|
|
246
255
|
>
|
|
247
256
|
<ContextAwareChartLayout
|
|
@@ -294,8 +303,8 @@ export const ChartJSRenderer: Component<ChartJSRendererProps> = (props) => {
|
|
|
294
303
|
onClick={handleExportPNG}
|
|
295
304
|
disabled={activeView() !== 'chart' || isLoading() || Boolean(error())}
|
|
296
305
|
class="opacity-0 group-hover:opacity-60 hover:!opacity-100 disabled:!opacity-30 disabled:cursor-not-allowed px-2 py-1 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"
|
|
297
|
-
title=
|
|
298
|
-
aria-label=
|
|
306
|
+
title={strings.chartDownloadPng}
|
|
307
|
+
aria-label={strings.chartDownloadPngAria}
|
|
299
308
|
>
|
|
300
309
|
<svg
|
|
301
310
|
class="w-3 h-3 text-gray-500 dark:text-gray-400"
|
|
@@ -323,8 +332,8 @@ export const ChartJSRenderer: Component<ChartJSRendererProps> = (props) => {
|
|
|
323
332
|
instead of a bare "Chart Error" message. */}
|
|
324
333
|
<Show when={error() && activeView() === 'chart'}>
|
|
325
334
|
<DegradedFallback
|
|
326
|
-
message={
|
|
327
|
-
caption=
|
|
335
|
+
message={formatMCPUIString(strings.chartRenderFailed, { error: String(error()) })}
|
|
336
|
+
caption={strings.chartDegradedCaption}
|
|
328
337
|
{...tableData()}
|
|
329
338
|
/>
|
|
330
339
|
</Show>
|
|
@@ -405,7 +414,7 @@ export const ChartJSRenderer: Component<ChartJSRendererProps> = (props) => {
|
|
|
405
414
|
<div class="absolute inset-0 flex items-center justify-center bg-white/80 dark:bg-gray-800/80">
|
|
406
415
|
<div class="flex flex-col items-center gap-2">
|
|
407
416
|
<div class="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600" />
|
|
408
|
-
<span class="text-sm text-gray-500 dark:text-gray-400">
|
|
417
|
+
<span class="text-sm text-gray-500 dark:text-gray-400">{strings.chartLoading}</span>
|
|
409
418
|
</div>
|
|
410
419
|
</div>
|
|
411
420
|
</Show>
|
|
@@ -52,6 +52,7 @@ import type {
|
|
|
52
52
|
FormPromptConfig,
|
|
53
53
|
} from '../types/chat-bus'
|
|
54
54
|
import { FormFieldRenderer } from './FormFieldRenderer'
|
|
55
|
+
import { useMCPUIStrings } from '../context/MCPUIStringsContext'
|
|
55
56
|
import type { FormFieldParams } from '../types'
|
|
56
57
|
|
|
57
58
|
export interface ChatPromptProps {
|
|
@@ -78,6 +79,8 @@ export interface ChatPromptProps {
|
|
|
78
79
|
* />
|
|
79
80
|
*/
|
|
80
81
|
export const ChatPrompt: Component<ChatPromptProps> = (props) => {
|
|
82
|
+
const strings = useMCPUIStrings()
|
|
83
|
+
|
|
81
84
|
// F1: Guard against null/undefined config (e.g. after dismiss clears state)
|
|
82
85
|
if (!props.config) return null
|
|
83
86
|
|
|
@@ -100,7 +103,7 @@ export const ChatPrompt: Component<ChatPromptProps> = (props) => {
|
|
|
100
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/20 rounded-lg transition-colors'
|
|
101
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'
|
|
102
105
|
}
|
|
103
|
-
aria-label={props.dismissLabel ||
|
|
106
|
+
aria-label={props.dismissLabel || strings.dismiss}
|
|
104
107
|
>
|
|
105
108
|
<Show when={props.dismissLabel} fallback={
|
|
106
109
|
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
@@ -124,10 +127,10 @@ export const ChatPrompt: Component<ChatPromptProps> = (props) => {
|
|
|
124
127
|
<Match when={props.config.type === 'confirm'}>
|
|
125
128
|
<ConfirmBody
|
|
126
129
|
config={props.config.config as ConfirmPromptConfig}
|
|
127
|
-
onConfirm={() => props.onSubmit({ type: 'confirm', value: 'confirmed', label: (props.config.config as ConfirmPromptConfig).confirmLabel ||
|
|
130
|
+
onConfirm={() => props.onSubmit({ type: 'confirm', value: 'confirmed', label: (props.config.config as ConfirmPromptConfig).confirmLabel || strings.promptConfirmed })}
|
|
128
131
|
onCancel={() => {
|
|
129
132
|
props.onDismiss?.()
|
|
130
|
-
props.onSubmit({ type: 'confirm', value: 'cancelled', label: (props.config.config as ConfirmPromptConfig).cancelLabel ||
|
|
133
|
+
props.onSubmit({ type: 'confirm', value: 'cancelled', label: (props.config.config as ConfirmPromptConfig).cancelLabel || strings.promptCancelled, dismissed: true })
|
|
131
134
|
}}
|
|
132
135
|
/>
|
|
133
136
|
</Match>
|
|
@@ -213,6 +216,7 @@ const ConfirmBody: Component<{
|
|
|
213
216
|
onConfirm: () => void
|
|
214
217
|
onCancel: () => void
|
|
215
218
|
}> = (props) => {
|
|
219
|
+
const strings = useMCPUIStrings()
|
|
216
220
|
const isDanger = () => props.config.variant === 'danger'
|
|
217
221
|
|
|
218
222
|
return (
|
|
@@ -225,7 +229,7 @@ const ConfirmBody: Component<{
|
|
|
225
229
|
onClick={props.onCancel}
|
|
226
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"
|
|
227
231
|
>
|
|
228
|
-
{props.config.cancelLabel ||
|
|
232
|
+
{props.config.cancelLabel || strings.cancel}
|
|
229
233
|
</button>
|
|
230
234
|
<button
|
|
231
235
|
onClick={props.onConfirm}
|
|
@@ -235,7 +239,7 @@ const ConfirmBody: Component<{
|
|
|
235
239
|
: 'bg-blue-600 hover:bg-blue-700'
|
|
236
240
|
}`}
|
|
237
241
|
>
|
|
238
|
-
{props.config.confirmLabel ||
|
|
242
|
+
{props.config.confirmLabel || strings.confirm}
|
|
239
243
|
</button>
|
|
240
244
|
</div>
|
|
241
245
|
</div>
|
|
@@ -248,6 +252,7 @@ const FormBody: Component<{
|
|
|
248
252
|
config: FormPromptConfig
|
|
249
253
|
onSubmit: (data: Record<string, unknown>, label: string) => void
|
|
250
254
|
}> = (props) => {
|
|
255
|
+
const strings = useMCPUIStrings()
|
|
251
256
|
const [formData, setFormData] = createSignal<Record<string, any>>({})
|
|
252
257
|
const [dynamicOptions, setDynamicOptions] = createSignal<Record<string, Array<{ label: string; value: string }>>>({})
|
|
253
258
|
const [previewText, setPreviewText] = createSignal<string>('')
|
|
@@ -336,7 +341,7 @@ const FormBody: Component<{
|
|
|
336
341
|
.filter(([, v]) => v !== undefined && v !== '' && !(Array.isArray(v) && v.length === 0))
|
|
337
342
|
.map(([k, v]) => `${k}: ${Array.isArray(v) ? v.join(', ') : v}`)
|
|
338
343
|
.join(', ')
|
|
339
|
-
props.onSubmit(data, label ||
|
|
344
|
+
props.onSubmit(data, label || strings.promptFormSubmitted)
|
|
340
345
|
}
|
|
341
346
|
|
|
342
347
|
const isValid = () => {
|
|
@@ -379,7 +384,7 @@ const FormBody: Component<{
|
|
|
379
384
|
<Show when={previewLoading()} fallback={
|
|
380
385
|
<p class="text-blue-700 dark:text-blue-300">{previewText()}</p>
|
|
381
386
|
}>
|
|
382
|
-
<p class="text-blue-400 animate-pulse">
|
|
387
|
+
<p class="text-blue-400 animate-pulse">{strings.promptLoadingPreview}</p>
|
|
383
388
|
</Show>
|
|
384
389
|
</div>
|
|
385
390
|
</Show>
|
|
@@ -390,7 +395,7 @@ const FormBody: Component<{
|
|
|
390
395
|
disabled={!isValid()}
|
|
391
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"
|
|
392
397
|
>
|
|
393
|
-
{props.config.submitLabel ||
|
|
398
|
+
{props.config.submitLabel || strings.submit}
|
|
394
399
|
</button>
|
|
395
400
|
</div>
|
|
396
401
|
</form>
|
|
@@ -10,6 +10,7 @@ import type { UIComponent, CodeComponentParams } from '../types'
|
|
|
10
10
|
import { ExpandableWrapper, useExpanded } from './ExpandableWrapper'
|
|
11
11
|
import { highlightQuery } from './UIResourceRenderer'
|
|
12
12
|
import { escapeHtml } from '../utils/escape-html'
|
|
13
|
+
import { useMCPUIStrings } from '../context/MCPUIStringsContext'
|
|
13
14
|
|
|
14
15
|
/** Map of `params.language` → file extension for the v6.2.0 download button. */
|
|
15
16
|
const LANGUAGE_EXTENSIONS: Record<string, string> = {
|
|
@@ -45,6 +46,7 @@ export interface CodeBlockRendererProps {
|
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
export const CodeBlockRenderer: Component<CodeBlockRendererProps> = (props) => {
|
|
49
|
+
const strings = useMCPUIStrings()
|
|
48
50
|
const [highlightedCode, setHighlightedCode] = createSignal<string>('')
|
|
49
51
|
const [isCopied, setIsCopied] = createSignal(false)
|
|
50
52
|
const [isHljsLoaded, setIsHljsLoaded] = createSignal(false)
|
|
@@ -201,12 +203,12 @@ export const CodeBlockRenderer: Component<CodeBlockRendererProps> = (props) => {
|
|
|
201
203
|
}
|
|
202
204
|
|
|
203
205
|
return (
|
|
204
|
-
<ExpandableWrapper title={params()?.filename || params()?.language ||
|
|
206
|
+
<ExpandableWrapper title={params()?.filename || params()?.language || strings.codeTitle} copyData={params()?.code} copyLabel={strings.codeCopy} toolbarVariant={props.toolbarVariant}>
|
|
205
207
|
<div class={`w-full bg-gray-50 dark:bg-gray-900 rounded-lg border border-gray-200 dark:border-gray-700 overflow-hidden text-sm flex flex-col ${isExpanded() ? 'flex-1 min-h-0' : ''}`}>
|
|
206
208
|
{/* Header */}
|
|
207
209
|
<div class="flex items-center justify-between px-4 py-2 bg-gray-100 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 shrink-0">
|
|
208
210
|
<div class="font-mono text-xs text-gray-600 dark:text-gray-400">
|
|
209
|
-
{params()?.filename || params()?.language ||
|
|
211
|
+
{params()?.filename || params()?.language || strings.codeTitle}
|
|
210
212
|
</div>
|
|
211
213
|
<div class="flex items-center gap-2">
|
|
212
214
|
{/* Search input (v6.2.0) */}
|
|
@@ -214,16 +216,16 @@ export const CodeBlockRenderer: Component<CodeBlockRendererProps> = (props) => {
|
|
|
214
216
|
type="text"
|
|
215
217
|
value={searchQuery()}
|
|
216
218
|
onInput={(e) => setSearchQuery(e.currentTarget.value)}
|
|
217
|
-
placeholder=
|
|
219
|
+
placeholder={strings.codeSearchPlaceholder}
|
|
218
220
|
class="px-2 py-0.5 text-xs border border-gray-200 dark:border-gray-600 rounded bg-white dark:bg-gray-700 text-gray-900 dark:text-white placeholder-gray-400 focus:border-blue-400 focus:ring-1 focus:ring-blue-400 outline-none w-32"
|
|
219
|
-
aria-label=
|
|
221
|
+
aria-label={strings.codeSearchAria}
|
|
220
222
|
/>
|
|
221
223
|
{/* Download button (v6.2.0) */}
|
|
222
224
|
<button
|
|
223
225
|
onClick={handleDownload}
|
|
224
226
|
class="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 focus:outline-none transition-colors"
|
|
225
|
-
aria-label=
|
|
226
|
-
title=
|
|
227
|
+
aria-label={strings.codeDownloadAria}
|
|
228
|
+
title={strings.codeDownload}
|
|
227
229
|
>
|
|
228
230
|
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
229
231
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="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" />
|
|
@@ -233,8 +235,8 @@ export const CodeBlockRenderer: Component<CodeBlockRendererProps> = (props) => {
|
|
|
233
235
|
<button
|
|
234
236
|
onClick={() => setWordWrap(!wordWrap())}
|
|
235
237
|
class={`focus:outline-none transition-colors ${wordWrap() ? 'text-blue-500 dark:text-blue-400' : 'text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200'}`}
|
|
236
|
-
aria-label=
|
|
237
|
-
title={wordWrap() ?
|
|
238
|
+
aria-label={strings.codeToggleWordWrap}
|
|
239
|
+
title={wordWrap() ? strings.codeWordWrapDisable : strings.codeWordWrapEnable}
|
|
238
240
|
>
|
|
239
241
|
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
240
242
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 10h10a4 4 0 010 8H9m4 0l-3-3m3 3l-3 3M3 6h18M3 14h4" />
|
|
@@ -244,8 +246,8 @@ export const CodeBlockRenderer: Component<CodeBlockRendererProps> = (props) => {
|
|
|
244
246
|
<button
|
|
245
247
|
onClick={handleCopy}
|
|
246
248
|
class="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 focus:outline-none transition-colors"
|
|
247
|
-
aria-label=
|
|
248
|
-
title=
|
|
249
|
+
aria-label={strings.codeCopy}
|
|
250
|
+
title={strings.codeCopy}
|
|
249
251
|
>
|
|
250
252
|
<Show when={isCopied()} fallback={
|
|
251
253
|
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|