@seed-ship/mcp-ui-solid 5.6.0 → 5.7.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 +39 -0
- package/dist/components/UIResourceRenderer.cjs +40 -11
- package/dist/components/UIResourceRenderer.cjs.map +1 -1
- package/dist/components/UIResourceRenderer.d.ts +36 -1
- package/dist/components/UIResourceRenderer.d.ts.map +1 -1
- package/dist/components/UIResourceRenderer.js +40 -11
- package/dist/components/UIResourceRenderer.js.map +1 -1
- package/dist/index.cjs +1 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/mcp-ui-spec/dist/schemas.cjs +9 -1
- package/dist/mcp-ui-spec/dist/schemas.cjs.map +1 -1
- package/dist/mcp-ui-spec/dist/schemas.js +9 -1
- package/dist/mcp-ui-spec/dist/schemas.js.map +1 -1
- package/dist/types/index.d.ts +26 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types.d.cts +26 -0
- package/dist/types.d.ts +26 -0
- package/docs/briefs/BRIEF-citations-in-table-cells.md +365 -0
- package/package.json +3 -3
- package/src/components/TableRenderer.citation.test.tsx +157 -0
- package/src/components/UIResourceRenderer.tsx +133 -12
- package/src/index.ts +5 -0
- package/src/types/index.ts +30 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -57,7 +57,42 @@ export interface UIResourceRendererProps {
|
|
|
57
57
|
* v4.3.8
|
|
58
58
|
*/
|
|
59
59
|
export declare function highlightQuery(html: string, query: string): string;
|
|
60
|
-
|
|
60
|
+
/**
|
|
61
|
+
* Citation context — opt-in input to `renderCellValue` (v5.7.0).
|
|
62
|
+
*
|
|
63
|
+
* When passed, `[N]`, `Citation [N]`, `[CITATION N]` and `[📄 CITATION N]`
|
|
64
|
+
* markers in the cell text are normalized then replaced with chip HTML.
|
|
65
|
+
* Chips carry `data-citation-page`, `data-citation-doc`, and
|
|
66
|
+
* `data-citation-verified` attributes (already in the DOMPurify whitelist
|
|
67
|
+
* since v5.6.0) so a host's `target.closest('[data-citation-page]')`
|
|
68
|
+
* delegated click handler routes the click to the source-doc panel.
|
|
69
|
+
*
|
|
70
|
+
* See `mcp-ui-solid/docs/briefs/BRIEF-citations-in-table-cells.md`.
|
|
71
|
+
*/
|
|
72
|
+
export interface CitationCtx {
|
|
73
|
+
/**
|
|
74
|
+
* `Record<id, mapping>` keyed by the citation marker number (string-keyed
|
|
75
|
+
* because JSON serialization always produces strings; the runtime call
|
|
76
|
+
* sites accept either number or string ids and normalize internally).
|
|
77
|
+
*/
|
|
78
|
+
map: Record<string | number, {
|
|
79
|
+
page: number | string;
|
|
80
|
+
file?: string;
|
|
81
|
+
file_id?: number | string;
|
|
82
|
+
}>;
|
|
83
|
+
/**
|
|
84
|
+
* Optional override returning sanitized chip HTML for one marker. Wins
|
|
85
|
+
* over the default `defaultCitationChip` shape. Function inputs are
|
|
86
|
+
* intentionally `any`-loose so consumers can swap shapes (e.g. web
|
|
87
|
+
* citations vs doc citations) without subtyping the entry shape here.
|
|
88
|
+
*/
|
|
89
|
+
render?: (id: number, mapping: {
|
|
90
|
+
page: number | string;
|
|
91
|
+
file?: string;
|
|
92
|
+
file_id?: number | string;
|
|
93
|
+
} | undefined) => string;
|
|
94
|
+
}
|
|
95
|
+
export declare function renderCellValue(value: any, citationCtx?: CitationCtx): string;
|
|
61
96
|
/**
|
|
62
97
|
* Main UIResourceRenderer component
|
|
63
98
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UIResourceRenderer.d.ts","sourceRoot":"","sources":["../../src/components/UIResourceRenderer.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,SAAS,EAAyE,MAAM,UAAU,CAAA;AAE3G,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,aAAa,EAA0B,MAAM,UAAU,CAAA;AAM5F;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,aAAa,GAAG,QAAQ,CAAA;AA8DpE;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC;;OAEG;IACH,OAAO,EAAE,WAAW,GAAG,QAAQ,CAAA;IAE/B;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAElB;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAA;IAExC;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IAEd;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,mBAAmB,CAAA;CAChC;AAiJD;;GAEG;AACH;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAYlE;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,GAAG,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"UIResourceRenderer.d.ts","sourceRoot":"","sources":["../../src/components/UIResourceRenderer.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,SAAS,EAAyE,MAAM,UAAU,CAAA;AAE3G,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,aAAa,EAA0B,MAAM,UAAU,CAAA;AAM5F;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,aAAa,GAAG,QAAQ,CAAA;AA8DpE;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC;;OAEG;IACH,OAAO,EAAE,WAAW,GAAG,QAAQ,CAAA;IAE/B;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAElB;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAA;IAExC;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IAEd;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,mBAAmB,CAAA;CAChC;AAiJD;;GAEG;AACH;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAYlE;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,GAAG,EAAE,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC,CAAA;IACjG;;;;;OAKG;IACH,MAAM,CAAC,EAAE,CACP,EAAE,EAAE,MAAM,EACV,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,GAAG,SAAS,KACrF,MAAM,CAAA;CACZ;AA8DD,wBAAgB,eAAe,CAAC,KAAK,EAAE,GAAG,EAAE,WAAW,CAAC,EAAE,WAAW,GAAG,MAAM,CAkG7E;AA8nCD;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,SAAS,CAAC,uBAAuB,CA6GjE,CAAA"}
|
|
@@ -219,7 +219,27 @@ function highlightQuery(html, query) {
|
|
|
219
219
|
return text.replace(regex, '<mark class="bg-yellow-200 dark:bg-[#222F49] text-inherit rounded px-0.5">$1</mark>');
|
|
220
220
|
});
|
|
221
221
|
}
|
|
222
|
-
function
|
|
222
|
+
function defaultCitationChip(pageNum, fileName, verified = true) {
|
|
223
|
+
const safeDocName = encodeURIComponent(fileName || "");
|
|
224
|
+
const label = fileName ? `${fileName} - ${pageNum}` : `${pageNum}`;
|
|
225
|
+
if (!verified) {
|
|
226
|
+
return `<span class="citation-ref inline-flex items-center gap-0.5 align-middle opacity-60"><span class="text-gray-500 line-through">[${label}]</span></span>`;
|
|
227
|
+
}
|
|
228
|
+
return ['<span class="citation-ref inline-flex items-center gap-0.5 align-middle">', `<span class="text-gray-500">[${label}]</span>`, '<button class="inline-flex items-center ml-0.5 px-1 py-0.5 text-xs bg-gray-800 hover:bg-gray-700 border border-gray-600 hover:border-teal-500 rounded cursor-pointer transition-colors align-middle"', ` data-citation-page="${pageNum}"`, ` data-citation-doc="${safeDocName}"`, ' data-citation-verified="true"', ` title="View source - ${label}">`, '<svg class="w-3 h-3" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>', "</button>", "</span>"].join("");
|
|
229
|
+
}
|
|
230
|
+
function transformCellCitations(text, ctx) {
|
|
231
|
+
let out = text.replace(new RegExp("(?<![p.])\\[(\\d{1,2})\\](?!\\()", "g"), "[📄 CITATION $1]");
|
|
232
|
+
out = out.replace(/\bCitations?\s*\[(\d+)\]/gi, "[📄 CITATION $1]");
|
|
233
|
+
out = out.replace(/\[CITATION\s+(\d+)\]/gi, "[📄 CITATION $1]");
|
|
234
|
+
return out.replace(/[【[]\s*📄\s*CITATION\s*(\d+)\s*[】\]]/gi, (_m, idStr) => {
|
|
235
|
+
const id = parseInt(idStr, 10);
|
|
236
|
+
const mapping = ctx.map[id] ?? ctx.map[String(id)];
|
|
237
|
+
if (ctx.render) return ctx.render(id, mapping);
|
|
238
|
+
if (mapping) return defaultCitationChip(mapping.page, mapping.file ?? "", true);
|
|
239
|
+
return Object.keys(ctx.map).length > 0 ? "" : `[réf. ${id}]`;
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
function renderCellValue(value, citationCtx) {
|
|
223
243
|
if (value === null || value === void 0) {
|
|
224
244
|
return "-";
|
|
225
245
|
}
|
|
@@ -255,20 +275,25 @@ function renderCellValue(value) {
|
|
|
255
275
|
ADD_ATTR: ["target", "rel"]
|
|
256
276
|
});
|
|
257
277
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
return purify.sanitize(strValue, {
|
|
261
|
-
ALLOWED_TAGS: ["a", "strong", "em", "b", "i", "code", "span", "br", "button", "svg", "path"],
|
|
262
|
-
ALLOWED_ATTR: ["href", "target", "rel", "class", "data-citation-page", "data-citation-source", "data-citation-doc", "data-citation-verified", "title", "fill", "stroke", "viewBox", "stroke-linecap", "stroke-linejoin", "stroke-width", "d"],
|
|
263
|
-
ADD_ATTR: ["target", "rel"]
|
|
264
|
-
});
|
|
278
|
+
if (citationCtx) {
|
|
279
|
+
strValue = transformCellCitations(strValue, citationCtx);
|
|
265
280
|
}
|
|
266
|
-
const hasMarkdown = /[*_
|
|
281
|
+
const hasMarkdown = /[*_`#]/.test(strValue);
|
|
267
282
|
if (hasMarkdown) {
|
|
268
283
|
const parsed = k.parse(strValue, {
|
|
269
284
|
async: false
|
|
270
285
|
});
|
|
271
286
|
return purify.sanitize(parsed, {
|
|
287
|
+
ALLOWED_TAGS: ["a", "strong", "em", "b", "i", "code", "span", "br", "button", "svg", "path", "p", "ul", "ol", "li", "pre", "blockquote", "h1", "h2", "h3", "h4", "h5", "h6"],
|
|
288
|
+
ALLOWED_ATTR: ["href", "target", "rel", "class", "data-citation-page", "data-citation-source", "data-citation-doc", "data-citation-verified", "title", "fill", "stroke", "viewBox", "stroke-linecap", "stroke-linejoin", "stroke-width", "d"],
|
|
289
|
+
ADD_ATTR: ["target", "rel"]
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
const hasHtml = /<[a-z][\s\S]*>/i.test(strValue);
|
|
293
|
+
if (hasHtml) {
|
|
294
|
+
return purify.sanitize(strValue, {
|
|
295
|
+
ALLOWED_TAGS: ["a", "strong", "em", "b", "i", "code", "span", "br", "button", "svg", "path"],
|
|
296
|
+
ALLOWED_ATTR: ["href", "target", "rel", "class", "data-citation-page", "data-citation-source", "data-citation-doc", "data-citation-verified", "title", "fill", "stroke", "viewBox", "stroke-linecap", "stroke-linejoin", "stroke-width", "d"],
|
|
272
297
|
ADD_ATTR: ["target", "rel"]
|
|
273
298
|
});
|
|
274
299
|
}
|
|
@@ -277,6 +302,10 @@ function renderCellValue(value) {
|
|
|
277
302
|
function TableRenderer(props) {
|
|
278
303
|
const tableParams = props.component.params;
|
|
279
304
|
let scrollContainerRef;
|
|
305
|
+
const citationCtx = tableParams.citationMap ? {
|
|
306
|
+
map: tableParams.citationMap,
|
|
307
|
+
render: tableParams.citationRender
|
|
308
|
+
} : void 0;
|
|
280
309
|
const allRows = () => tableParams.rows || [];
|
|
281
310
|
const columns = () => tableParams.columns || [];
|
|
282
311
|
const [sortKey, setSortKey] = createSignal(null);
|
|
@@ -517,7 +546,7 @@ ${dataRows}`;
|
|
|
517
546
|
},
|
|
518
547
|
children: (column) => (() => {
|
|
519
548
|
var _el$23 = getNextElement(_tmpl$10), _el$24 = _el$23.firstChild;
|
|
520
|
-
effect(() => setProperty(_el$24, "innerHTML", highlightQuery(renderCellValue(row[column.key]), debouncedQuery())));
|
|
549
|
+
effect(() => setProperty(_el$24, "innerHTML", highlightQuery(renderCellValue(row[column.key], citationCtx), debouncedQuery())));
|
|
521
550
|
return _el$23;
|
|
522
551
|
})()
|
|
523
552
|
}));
|
|
@@ -550,7 +579,7 @@ ${dataRows}`;
|
|
|
550
579
|
},
|
|
551
580
|
children: (column) => (() => {
|
|
552
581
|
var _el$27 = getNextElement(_tmpl$10), _el$28 = _el$27.firstChild;
|
|
553
|
-
effect(() => setProperty(_el$28, "innerHTML", highlightQuery(renderCellValue(row[column.key]), debouncedQuery())));
|
|
582
|
+
effect(() => setProperty(_el$28, "innerHTML", highlightQuery(renderCellValue(row[column.key], citationCtx), debouncedQuery())));
|
|
554
583
|
return _el$27;
|
|
555
584
|
})()
|
|
556
585
|
}));
|