@webmcp-auto-ui/ui 2.5.31 → 2.5.33
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/package.json +15 -2
- package/src/agent/DiagnosticModal.svelte +126 -50
- package/src/agent/EphemeralBubble.svelte +13 -3
- package/src/agent/MCPserversList.svelte +147 -0
- package/src/agent/McpConnector.svelte +10 -1
- package/src/agent/RecipeBrowser.svelte +384 -0
- package/src/agent/RemoteMCPserversDemo.svelte +5 -121
- package/src/agent/ToolBrowser.svelte +133 -0
- package/src/agent/WebMCPserversList.svelte +2 -0
- package/src/agent/useAgentLoop.svelte.ts +396 -0
- package/src/base/chat-inline.svelte +64 -0
- package/src/base/dialog-content.svelte +3 -1
- package/src/components/HeaderControls.svelte +78 -0
- package/src/index.ts +13 -35
- package/src/stores/canvas.svelte.ts +0 -6
- package/src/widgets/SafeImage.svelte +67 -0
- package/src/widgets/WidgetRenderer.svelte +153 -78
- package/src/widgets/notebook/executors/index.ts +0 -1
- package/src/widgets/notebook/executors/sql.ts +32 -182
- package/src/widgets/notebook/import-modal-api.ts +237 -0
- package/src/widgets/notebook/import-modal.svelte +738 -0
- package/src/widgets/notebook/left-pane.ts +1 -1
- package/src/widgets/notebook/notebook.svelte +75 -0
- package/src/widgets/notebook/notebook.ts +38 -73
- package/src/widgets/notebook/prose.ts +6 -3
- package/src/widgets/notebook/shared.ts +68 -49
- package/src/widgets/rich/cards.svelte +74 -0
- package/src/widgets/rich/carousel.svelte +126 -0
- package/src/widgets/rich/chart-rich.svelte +221 -0
- package/src/widgets/rich/chat-input.svelte +52 -0
- package/src/widgets/rich/data-table.svelte +132 -0
- package/src/widgets/rich/gallery.svelte +115 -0
- package/src/widgets/rich/grid-data.svelte +85 -0
- package/src/widgets/rich/hemicycle.svelte +95 -0
- package/src/widgets/rich/js-sandbox.svelte +67 -0
- package/src/widgets/rich/json-viewer.svelte +82 -0
- package/src/widgets/rich/log.svelte +62 -0
- package/src/widgets/rich/profile.svelte +91 -0
- package/src/widgets/rich/sankey.svelte +73 -0
- package/src/widgets/rich/stat-card.svelte +60 -0
- package/src/widgets/rich/timeline.svelte +95 -0
- package/src/widgets/rich/trombinoscope.svelte +87 -0
- package/src/widgets/simple/actions.svelte +36 -0
- package/src/widgets/simple/alert.svelte +52 -0
- package/src/widgets/simple/chart.svelte +38 -0
- package/src/widgets/simple/code.svelte +30 -0
- package/src/widgets/simple/kv.svelte +31 -0
- package/src/widgets/simple/list.svelte +35 -0
- package/src/widgets/simple/stat.svelte +36 -0
- package/src/widgets/simple/tags.svelte +34 -0
- package/src/widgets/simple/text.svelte +130 -0
- package/src/widgets/helpers/safe-image.ts +0 -78
- package/src/widgets/notebook/import-modals.ts +0 -560
- package/src/widgets/notebook/recipe-browser.ts +0 -350
- package/src/widgets/rich/cards.ts +0 -181
- package/src/widgets/rich/carousel.ts +0 -319
- package/src/widgets/rich/chart-rich.ts +0 -386
- package/src/widgets/rich/d3.ts +0 -503
- package/src/widgets/rich/data-table.ts +0 -342
- package/src/widgets/rich/gallery.ts +0 -350
- package/src/widgets/rich/grid-data.ts +0 -173
- package/src/widgets/rich/hemicycle.ts +0 -313
- package/src/widgets/rich/js-sandbox.ts +0 -122
- package/src/widgets/rich/json-viewer.ts +0 -202
- package/src/widgets/rich/log.ts +0 -143
- package/src/widgets/rich/map.ts +0 -218
- package/src/widgets/rich/profile.ts +0 -256
- package/src/widgets/rich/sankey.ts +0 -257
- package/src/widgets/rich/stat-card.ts +0 -125
- package/src/widgets/rich/timeline.ts +0 -179
- package/src/widgets/rich/trombinoscope.ts +0 -246
- package/src/widgets/simple/actions.ts +0 -89
- package/src/widgets/simple/alert.ts +0 -100
- package/src/widgets/simple/chart.ts +0 -189
- package/src/widgets/simple/code.ts +0 -79
- package/src/widgets/simple/kv.ts +0 -68
- package/src/widgets/simple/list.ts +0 -89
- package/src/widgets/simple/stat.ts +0 -58
- package/src/widgets/simple/tags.ts +0 -125
- package/src/widgets/simple/text.ts +0 -198
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Vanilla renderer for the "text" / TextBlock widget.
|
|
3
|
-
*
|
|
4
|
-
* Mirrors the Svelte TextBlock.svelte output: a <div class="tb-md ..."> whose
|
|
5
|
-
* innerHTML is produced by a minimal, XSS-safe markdown -> HTML function.
|
|
6
|
-
*
|
|
7
|
-
* XSS note: renderMarkdown() escapes &, <, >, " BEFORE applying inline rules,
|
|
8
|
-
* so user-controlled text can only reach the DOM as already-escaped entities or
|
|
9
|
-
* as the structural tags we explicitly emit (h1-6, p, strong, em, code, pre, ul,
|
|
10
|
-
* ol, li, a, hr). Using innerHTML here is therefore safe — the function is the
|
|
11
|
-
* single source of trust for sanitization.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
export interface TextBlockData {
|
|
15
|
-
content?: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/** Minimal markdown → HTML renderer (no deps, naturally XSS-safe: only produces known tags) */
|
|
19
|
-
function renderMarkdown(src: string): string {
|
|
20
|
-
if (!src) return '';
|
|
21
|
-
|
|
22
|
-
// Escape HTML entities first (XSS protection)
|
|
23
|
-
const esc = (s: string) =>
|
|
24
|
-
s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
25
|
-
|
|
26
|
-
const lines = src.split('\n');
|
|
27
|
-
const out: string[] = [];
|
|
28
|
-
let inCode = false;
|
|
29
|
-
let codeLines: string[] = [];
|
|
30
|
-
let inUl = false;
|
|
31
|
-
let inOl = false;
|
|
32
|
-
|
|
33
|
-
const closeList = () => {
|
|
34
|
-
if (inUl) { out.push('</ul>'); inUl = false; }
|
|
35
|
-
if (inOl) { out.push('</ol>'); inOl = false; }
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
/** Inline formatting: bold, italic, code, links */
|
|
39
|
-
const inline = (s: string): string => {
|
|
40
|
-
return esc(s)
|
|
41
|
-
.replace(/`([^`]+)`/g, '<code>$1</code>')
|
|
42
|
-
.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>')
|
|
43
|
-
.replace(/\*([^*]+)\*/g, '<em>$1</em>')
|
|
44
|
-
// Whitelist URL protocols to block javascript:/data:/vbscript: XSS via markdown links.
|
|
45
|
-
.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_m, label, href) =>
|
|
46
|
-
/^(https?:|\/|#|mailto:)/i.test(href)
|
|
47
|
-
? `<a href="${href}" target="_blank" rel="noopener">${label}</a>`
|
|
48
|
-
: label,
|
|
49
|
-
);
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
for (const line of lines) {
|
|
53
|
-
// Fenced code block toggle
|
|
54
|
-
if (line.trimStart().startsWith('```')) {
|
|
55
|
-
if (!inCode) {
|
|
56
|
-
closeList();
|
|
57
|
-
inCode = true;
|
|
58
|
-
codeLines = [];
|
|
59
|
-
} else {
|
|
60
|
-
out.push(`<pre><code>${esc(codeLines.join('\n'))}</code></pre>`);
|
|
61
|
-
inCode = false;
|
|
62
|
-
}
|
|
63
|
-
continue;
|
|
64
|
-
}
|
|
65
|
-
if (inCode) { codeLines.push(line); continue; }
|
|
66
|
-
|
|
67
|
-
const trimmed = line.trim();
|
|
68
|
-
|
|
69
|
-
// Empty line → close lists, push break
|
|
70
|
-
if (!trimmed) { closeList(); out.push(''); continue; }
|
|
71
|
-
|
|
72
|
-
// Headers
|
|
73
|
-
const hMatch = trimmed.match(/^(#{1,6})\s+(.+)$/);
|
|
74
|
-
if (hMatch) {
|
|
75
|
-
closeList();
|
|
76
|
-
const level = hMatch[1].length;
|
|
77
|
-
out.push(`<h${level}>${inline(hMatch[2])}</h${level}>`);
|
|
78
|
-
continue;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Unordered list
|
|
82
|
-
if (/^[-*+]\s+/.test(trimmed)) {
|
|
83
|
-
if (inOl) { out.push('</ol>'); inOl = false; }
|
|
84
|
-
if (!inUl) { out.push('<ul>'); inUl = true; }
|
|
85
|
-
out.push(`<li>${inline(trimmed.replace(/^[-*+]\s+/, ''))}</li>`);
|
|
86
|
-
continue;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Ordered list
|
|
90
|
-
const olMatch = trimmed.match(/^(\d+)\.\s+(.+)$/);
|
|
91
|
-
if (olMatch) {
|
|
92
|
-
if (inUl) { out.push('</ul>'); inUl = false; }
|
|
93
|
-
if (!inOl) { out.push('<ol>'); inOl = true; }
|
|
94
|
-
out.push(`<li>${inline(olMatch[2])}</li>`);
|
|
95
|
-
continue;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// Horizontal rule
|
|
99
|
-
if (/^[-*_]{3,}$/.test(trimmed)) {
|
|
100
|
-
closeList();
|
|
101
|
-
out.push('<hr>');
|
|
102
|
-
continue;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Regular paragraph line
|
|
106
|
-
closeList();
|
|
107
|
-
out.push(`<p>${inline(trimmed)}</p>`);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// Close any open blocks
|
|
111
|
-
if (inCode) out.push(`<pre><code>${esc(codeLines.join('\n'))}</code></pre>`);
|
|
112
|
-
closeList();
|
|
113
|
-
|
|
114
|
-
return out.join('\n');
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/** Scoped styles — emitted once per document, matching TextBlock.svelte :global rules. */
|
|
118
|
-
const STYLE_ID = 'autoui-text-widget-styles';
|
|
119
|
-
const STYLE_CSS = `
|
|
120
|
-
.tb-md { color: var(--color-text2); }
|
|
121
|
-
.tb-md h1 { font-size: 1.5em; font-weight: 700; color: var(--color-text1); margin: 0.8em 0 0.4em; }
|
|
122
|
-
.tb-md h2 { font-size: 1.25em; font-weight: 600; color: var(--color-text1); margin: 0.7em 0 0.35em; }
|
|
123
|
-
.tb-md h3 { font-size: 1.1em; font-weight: 600; color: var(--color-text1); margin: 0.6em 0 0.3em; }
|
|
124
|
-
.tb-md h4, .tb-md h5, .tb-md h6 { font-size: 1em; font-weight: 600; color: var(--color-text1); margin: 0.5em 0 0.25em; }
|
|
125
|
-
.tb-md p { margin: 0.4em 0; }
|
|
126
|
-
.tb-md strong { font-weight: 600; color: var(--color-text1); }
|
|
127
|
-
.tb-md em { font-style: italic; }
|
|
128
|
-
.tb-md a { color: var(--color-accent); text-decoration: underline; text-underline-offset: 2px; }
|
|
129
|
-
.tb-md a:hover { opacity: 0.8; }
|
|
130
|
-
.tb-md ul, .tb-md ol { margin: 0.4em 0; padding-left: 1.5em; }
|
|
131
|
-
.tb-md ul { list-style: disc; }
|
|
132
|
-
.tb-md ol { list-style: decimal; }
|
|
133
|
-
.tb-md li { margin: 0.15em 0; }
|
|
134
|
-
.tb-md code { font-family: 'IBM Plex Mono', ui-monospace, monospace; font-size: 0.9em; background: var(--color-surface2); padding: 0.15em 0.35em; border-radius: 4px; }
|
|
135
|
-
.tb-md pre { background: var(--color-surface2); border-radius: 6px; padding: 0.75em 1em; margin: 0.5em 0; overflow-x: auto; }
|
|
136
|
-
.tb-md pre code { background: none; padding: 0; font-size: 0.85em; }
|
|
137
|
-
.tb-md hr { border: none; border-top: 1px solid var(--color-surface2); margin: 0.8em 0; }
|
|
138
|
-
`;
|
|
139
|
-
|
|
140
|
-
function ensureStyles(doc: Document): void {
|
|
141
|
-
if (doc.getElementById(STYLE_ID)) return;
|
|
142
|
-
const style = doc.createElement('style');
|
|
143
|
-
style.id = STYLE_ID;
|
|
144
|
-
style.textContent = STYLE_CSS;
|
|
145
|
-
doc.head.appendChild(style);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Mount a text / markdown widget into `container`.
|
|
150
|
-
*
|
|
151
|
-
* Returns an `unmount()` function that clears the container and removes any
|
|
152
|
-
* attached listeners.
|
|
153
|
-
*/
|
|
154
|
-
export function render(container: HTMLElement, data: any): () => void {
|
|
155
|
-
const payload = (data ?? {}) as Partial<TextBlockData>;
|
|
156
|
-
const content = typeof payload.content === 'string' ? payload.content : '';
|
|
157
|
-
|
|
158
|
-
ensureStyles(container.ownerDocument ?? document);
|
|
159
|
-
|
|
160
|
-
const root = container.ownerDocument.createElement('div');
|
|
161
|
-
root.className = 'tb-md p-4 md:p-5 text-sm leading-relaxed';
|
|
162
|
-
|
|
163
|
-
if (!content.trim()) {
|
|
164
|
-
// Empty-state placeholder — keeps layout, signals absence to a11y tree.
|
|
165
|
-
const placeholder = container.ownerDocument.createElement('p');
|
|
166
|
-
placeholder.textContent = '';
|
|
167
|
-
placeholder.setAttribute('aria-label', 'empty text block');
|
|
168
|
-
placeholder.style.opacity = '0.5';
|
|
169
|
-
placeholder.style.fontStyle = 'italic';
|
|
170
|
-
root.appendChild(placeholder);
|
|
171
|
-
} else {
|
|
172
|
-
// Safe: renderMarkdown() escapes user text before emitting tags.
|
|
173
|
-
root.innerHTML = renderMarkdown(content);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// Delegated click handler — lets links emit widget:interact for host apps
|
|
177
|
-
// (e.g. analytics / canvas telemetry) without blocking default navigation.
|
|
178
|
-
const onClick = (ev: MouseEvent) => {
|
|
179
|
-
const target = ev.target as HTMLElement | null;
|
|
180
|
-
if (!target) return;
|
|
181
|
-
const anchor = target.closest('a');
|
|
182
|
-
if (!anchor || !root.contains(anchor)) return;
|
|
183
|
-
container.dispatchEvent(
|
|
184
|
-
new CustomEvent('widget:interact', {
|
|
185
|
-
detail: { action: 'link', payload: { href: (anchor as HTMLAnchorElement).href } },
|
|
186
|
-
bubbles: true,
|
|
187
|
-
}),
|
|
188
|
-
);
|
|
189
|
-
};
|
|
190
|
-
root.addEventListener('click', onClick);
|
|
191
|
-
|
|
192
|
-
container.appendChild(root);
|
|
193
|
-
|
|
194
|
-
return () => {
|
|
195
|
-
root.removeEventListener('click', onClick);
|
|
196
|
-
container.innerHTML = '';
|
|
197
|
-
};
|
|
198
|
-
}
|