@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.
@@ -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
- export declare function renderCellValue(value: any): string;
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,CA4ElD;AAsnCD;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,SAAS,CAAC,uBAAuB,CA6GjE,CAAA"}
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 renderCellValue(value) {
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
- const hasHtml = /<[a-z][\s\S]*>/i.test(strValue);
259
- if (hasHtml) {
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 = /[*_`[\]#]/.test(strValue);
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
  }));