@seed-ship/mcp-ui-solid 4.0.2 → 4.0.4

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.
@@ -1,6 +1,6 @@
1
- import { delegateEvents, createComponent, getNextElement, template, getNextMarker, insert, runHydrationEvents, effect, setStyleProperty, classList, memo, setProperty } from "solid-js/web";
2
- import { createMemo, createSignal, Show, For } from "solid-js";
3
- var _tmpl$ = /* @__PURE__ */ template(`<div class="text-xs text-amber-600 dark:text-amber-400 p-2">[DataPreviewSection] Invalid content format`), _tmpl$2 = /* @__PURE__ */ template(`<span class=font-medium>`), _tmpl$3 = /* @__PURE__ */ template(`<span class="px-1.5 py-0.5 rounded bg-blue-50 dark:bg-blue-900/20 text-blue-700 dark:text-blue-300">`), _tmpl$4 = /* @__PURE__ */ template(`<div class="flex items-center gap-1"><button class="px-2 py-1 text-xs rounded border border-gray-300 dark:border-gray-600 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"title="Export CSV">CSV</button><button class="px-2 py-1 text-xs rounded border border-gray-300 dark:border-gray-600 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"title="Export JSON">JSON`), _tmpl$5 = /* @__PURE__ */ template(`<div class="flex items-center gap-1"><button class="px-2 py-1 rounded hover:bg-gray-100 dark:hover:bg-gray-700 disabled:opacity-40 transition-colors">&laquo;</button><span><!$><!/> / <!$><!/></span><button class="px-2 py-1 rounded hover:bg-gray-100 dark:hover:bg-gray-700 disabled:opacity-40 transition-colors">&raquo;`), _tmpl$6 = /* @__PURE__ */ template(`<div class=data-preview-section><div class="flex items-center justify-between mb-2"><div class="flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400"><!$><!/><!$><!/></div><!$><!/></div><div class="overflow-x-auto rounded border border-gray-200 dark:border-gray-700"><table class="w-full text-sm"><thead><tr class="bg-gray-50 dark:bg-gray-800"></tr></thead><tbody></tbody></table></div><div class="flex items-center justify-between mt-2 text-xs text-gray-500 dark:text-gray-400"><span></span><!$><!/>`), _tmpl$7 = /* @__PURE__ */ template(`<th class="px-3 py-2 font-medium text-xs text-gray-600 dark:text-gray-400 uppercase tracking-wider border-b border-gray-200 dark:border-gray-700">`), _tmpl$8 = /* @__PURE__ */ template(`<tr class="border-b border-gray-100 dark:border-gray-800 hover:bg-gray-50 dark:hover:bg-gray-800/50 transition-colors">`), _tmpl$9 = /* @__PURE__ */ template(`<td class="px-3 py-2 text-gray-800 dark:text-gray-200">`);
1
+ import { delegateEvents, createComponent, getNextElement, template, getNextMarker, insert, effect, setAttribute, runHydrationEvents, setStyleProperty, classList, memo, setProperty } from "solid-js/web";
2
+ import { createMemo, createSignal, createEffect, Show, For } from "solid-js";
3
+ var _tmpl$ = /* @__PURE__ */ template(`<div class="text-xs text-amber-600 dark:text-amber-400 p-2">[DataPreviewSection] Invalid content format`), _tmpl$2 = /* @__PURE__ */ template(`<span class=font-medium>`), _tmpl$3 = /* @__PURE__ */ template(`<span class="px-1.5 py-0.5 rounded bg-blue-50 dark:bg-blue-900/20 text-blue-700 dark:text-blue-300">`), _tmpl$4 = /* @__PURE__ */ template(`<div class="flex items-center gap-1"><button class="px-2 py-1 text-xs rounded border border-gray-300 dark:border-gray-600 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors">CSV</button><button class="px-2 py-1 text-xs rounded border border-gray-300 dark:border-gray-600 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors">JSON`), _tmpl$5 = /* @__PURE__ */ template(`<span><!$><!/><!$><!/>`), _tmpl$6 = /* @__PURE__ */ template(`<span>`), _tmpl$7 = /* @__PURE__ */ template(`<div class="flex items-center gap-1"><button class="px-2 py-1 rounded hover:bg-gray-100 dark:hover:bg-gray-700 disabled:opacity-40 disabled:cursor-not-allowed transition-colors">&#x25C0; Prev</button><span class=px-2>Page <!$><!/> / <!$><!/></span><button class="px-2 py-1 rounded hover:bg-gray-100 dark:hover:bg-gray-700 disabled:opacity-40 disabled:cursor-not-allowed transition-colors">Next &#x25B6;`), _tmpl$8 = /* @__PURE__ */ template(`<div class=data-preview-section><div class="flex items-center justify-between mb-2"><div class="flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400"><!$><!/><!$><!/></div><!$><!/></div><div class="overflow-x-auto rounded border border-gray-200 dark:border-gray-700"><table class="w-full text-sm"><thead><tr class="bg-gray-50 dark:bg-gray-800"></tr></thead><tbody></tbody></table></div><div class="flex items-center justify-between mt-2 text-xs text-gray-500 dark:text-gray-400"><!$><!/><!$><!/><!$><!/>`), _tmpl$9 = /* @__PURE__ */ template(`<th class="px-3 py-2 font-medium text-xs text-gray-600 dark:text-gray-400 uppercase tracking-wider border-b border-gray-200 dark:border-gray-700 cursor-pointer select-none hover:bg-gray-100 dark:hover:bg-gray-700/50 transition-colors"><span class="inline-flex items-center gap-1"><!$><!/><span class="text-[10px] leading-none">`), _tmpl$0 = /* @__PURE__ */ template(`<tr class="border-b border-gray-100 dark:border-gray-800 hover:bg-gray-50 dark:hover:bg-gray-800/50 transition-colors">`), _tmpl$1 = /* @__PURE__ */ template(`<td class="px-3 py-2 text-gray-800 dark:text-gray-200">`);
4
4
  function formatNumber(value, format) {
5
5
  if (typeof value !== "number" || !isFinite(value)) return String(value ?? "");
6
6
  if (format === "percent") return `${(value * 100).toFixed(1)}%`;
@@ -22,6 +22,30 @@ function formatCell(value, col) {
22
22
  }
23
23
  return String(value);
24
24
  }
25
+ function compareValues(a, b, type) {
26
+ if (a == null && b == null) return 0;
27
+ if (a == null) return 1;
28
+ if (b == null) return -1;
29
+ if (type === "number") {
30
+ const na = typeof a === "number" ? a : Number(a);
31
+ const nb = typeof b === "number" ? b : Number(b);
32
+ if (isNaN(na) && isNaN(nb)) return 0;
33
+ if (isNaN(na)) return 1;
34
+ if (isNaN(nb)) return -1;
35
+ return na - nb;
36
+ }
37
+ if (type === "date") {
38
+ const da = new Date(String(a)).getTime();
39
+ const db = new Date(String(b)).getTime();
40
+ if (isNaN(da) && isNaN(db)) return 0;
41
+ if (isNaN(da)) return 1;
42
+ if (isNaN(db)) return -1;
43
+ return da - db;
44
+ }
45
+ return String(a).localeCompare(String(b), "fr", {
46
+ sensitivity: "base"
47
+ });
48
+ }
25
49
  function toCSV(columns, rows) {
26
50
  const header = columns.map((c) => `"${c.label.replace(/"/g, '""')}"`).join(";");
27
51
  const body = rows.map((row) => columns.map((c) => {
@@ -59,47 +83,88 @@ function resolveContent(raw) {
59
83
  return null;
60
84
  }
61
85
  function DataPreviewSection(props) {
86
+ var _a;
62
87
  const content = createMemo(() => {
63
88
  const resolved = resolveContent(props.content);
64
89
  if (!resolved) {
65
- console.warn("[MCP-UI] DataPreviewSection: invalid content — expected { columns: [...], rows: [...] }, got:", props.content);
90
+ console.warn("[MCP-UI] DataPreviewSection: invalid content — expected { columns, rows }", props.content);
66
91
  }
67
92
  return resolved;
68
93
  });
69
94
  const columns = () => {
70
- var _a;
71
- return ((_a = content()) == null ? void 0 : _a.columns) || [];
95
+ var _a2;
96
+ return ((_a2 = content()) == null ? void 0 : _a2.columns) || [];
72
97
  };
73
- const rows = () => {
74
- var _a;
75
- return ((_a = content()) == null ? void 0 : _a.rows) || [];
98
+ const rawRows = () => {
99
+ var _a2;
100
+ return ((_a2 = content()) == null ? void 0 : _a2.rows) || [];
76
101
  };
77
- const pageSize = () => {
78
- var _a;
79
- return ((_a = content()) == null ? void 0 : _a.pageSize) || 25;
102
+ const pageSizeVal = () => {
103
+ var _a2;
104
+ return ((_a2 = content()) == null ? void 0 : _a2.pageSize) ?? 25;
105
+ };
106
+ const showPageInfo = () => {
107
+ var _a2;
108
+ return ((_a2 = content()) == null ? void 0 : _a2.showPageInfo) !== false;
109
+ };
110
+ const [page, setPage] = createSignal(((_a = content()) == null ? void 0 : _a.initialPage) ?? 0);
111
+ const [sortKey, setSortKey] = createSignal(null);
112
+ const [sortDir, setSortDir] = createSignal(null);
113
+ createEffect(() => {
114
+ var _a2, _b;
115
+ const p = page();
116
+ (_b = (_a2 = content()) == null ? void 0 : _a2.onPageChange) == null ? void 0 : _b.call(_a2, p);
117
+ });
118
+ const handleSort = (key) => {
119
+ if (sortKey() === key) {
120
+ if (sortDir() === "asc") setSortDir("desc");
121
+ else {
122
+ setSortKey(null);
123
+ setSortDir(null);
124
+ }
125
+ } else {
126
+ setSortKey(key);
127
+ setSortDir("asc");
128
+ }
129
+ setPage(0);
80
130
  };
81
- const [page, setPage] = createSignal(0);
82
- const totalRows = () => rows().length;
83
- const totalPages = () => Math.max(1, Math.ceil(totalRows() / pageSize()));
84
- const pagedRows = createMemo(() => {
85
- const start = page() * pageSize();
86
- return rows().slice(start, start + pageSize());
131
+ const sortedRows = createMemo(() => {
132
+ const r = rawRows();
133
+ const key = sortKey();
134
+ const dir = sortDir();
135
+ if (!key || !dir) return r;
136
+ const col = columns().find((c) => c.key === key);
137
+ return [...r].sort((a, b) => {
138
+ const cmp = compareValues(a[key], b[key], col == null ? void 0 : col.type);
139
+ return dir === "desc" ? -cmp : cmp;
140
+ });
87
141
  });
142
+ const isPaginated = () => pageSizeVal() > 0 && sortedRows().length > pageSizeVal();
143
+ const totalPages = () => isPaginated() ? Math.ceil(sortedRows().length / pageSizeVal()) : 1;
144
+ const visibleRows = createMemo(() => {
145
+ if (!isPaginated()) return sortedRows();
146
+ const start = page() * pageSizeVal();
147
+ return sortedRows().slice(start, start + pageSizeVal());
148
+ });
149
+ const rangeStart = () => isPaginated() ? page() * pageSizeVal() + 1 : 1;
150
+ const rangeEnd = () => isPaginated() ? Math.min((page() + 1) * pageSizeVal(), sortedRows().length) : sortedRows().length;
88
151
  const handleExportCSV = () => {
89
152
  const c = content();
90
153
  if (!c) return;
91
- const csv = toCSV(c.columns, c.rows);
92
- downloadFile(csv, "data-export.csv", "text/csv;charset=utf-8");
154
+ downloadFile(toCSV(c.columns, sortedRows()), "data-export.csv", "text/csv;charset=utf-8");
93
155
  };
94
156
  const handleExportJSON = () => {
95
- const json = JSON.stringify(rows(), null, 2);
96
- downloadFile(json, "data-export.json", "application/json");
157
+ downloadFile(JSON.stringify(sortedRows(), null, 2), "data-export.json", "application/json");
97
158
  };
98
159
  const columnAlign = (col) => {
99
160
  if (col.align) return col.align;
100
161
  if (col.type === "number") return "right";
101
162
  return "left";
102
163
  };
164
+ const sortIndicator = (key) => {
165
+ if (sortKey() !== key) return "↕";
166
+ return sortDir() === "asc" ? "↑" : "↓";
167
+ };
103
168
  return createComponent(Show, {
104
169
  get when() {
105
170
  return content();
@@ -108,7 +173,7 @@ function DataPreviewSection(props) {
108
173
  return getNextElement(_tmpl$);
109
174
  },
110
175
  children: (c) => (() => {
111
- var _el$2 = getNextElement(_tmpl$6), _el$3 = _el$2.firstChild, _el$4 = _el$3.firstChild, _el$7 = _el$4.firstChild, [_el$8, _co$] = getNextMarker(_el$7.nextSibling), _el$9 = _el$8.nextSibling, [_el$0, _co$2] = getNextMarker(_el$9.nextSibling), _el$12 = _el$4.nextSibling, [_el$13, _co$3] = getNextMarker(_el$12.nextSibling), _el$14 = _el$3.nextSibling, _el$15 = _el$14.firstChild, _el$16 = _el$15.firstChild, _el$17 = _el$16.firstChild, _el$18 = _el$16.nextSibling, _el$19 = _el$14.nextSibling, _el$20 = _el$19.firstChild, _el$30 = _el$20.nextSibling, [_el$31, _co$6] = getNextMarker(_el$30.nextSibling);
176
+ var _el$2 = getNextElement(_tmpl$8), _el$3 = _el$2.firstChild, _el$4 = _el$3.firstChild, _el$7 = _el$4.firstChild, [_el$8, _co$] = getNextMarker(_el$7.nextSibling), _el$9 = _el$8.nextSibling, [_el$0, _co$2] = getNextMarker(_el$9.nextSibling), _el$12 = _el$4.nextSibling, [_el$13, _co$3] = getNextMarker(_el$12.nextSibling), _el$14 = _el$3.nextSibling, _el$15 = _el$14.firstChild, _el$16 = _el$15.firstChild, _el$17 = _el$16.firstChild, _el$18 = _el$16.nextSibling, _el$19 = _el$14.nextSibling, _el$36 = _el$19.firstChild, [_el$37, _co$8] = getNextMarker(_el$36.nextSibling), _el$38 = _el$37.nextSibling, [_el$39, _co$9] = getNextMarker(_el$38.nextSibling), _el$40 = _el$39.nextSibling, [_el$41, _co$0] = getNextMarker(_el$40.nextSibling);
112
177
  insert(_el$4, createComponent(Show, {
113
178
  get when() {
114
179
  return c().source;
@@ -137,6 +202,15 @@ function DataPreviewSection(props) {
137
202
  var _el$1 = getNextElement(_tmpl$4), _el$10 = _el$1.firstChild, _el$11 = _el$10.nextSibling;
138
203
  _el$10.$$click = handleExportCSV;
139
204
  _el$11.$$click = handleExportJSON;
205
+ effect((_p$) => {
206
+ var _v$ = `Export CSV (${sortedRows().length} rows)`, _v$2 = `Export JSON (${sortedRows().length} rows)`;
207
+ _v$ !== _p$.e && setAttribute(_el$10, "title", _p$.e = _v$);
208
+ _v$2 !== _p$.t && setAttribute(_el$11, "title", _p$.t = _v$2);
209
+ return _p$;
210
+ }, {
211
+ e: void 0,
212
+ t: void 0
213
+ });
140
214
  runHydrationEvents();
141
215
  return _el$1;
142
216
  }
@@ -146,62 +220,99 @@ function DataPreviewSection(props) {
146
220
  return columns();
147
221
  },
148
222
  children: (col) => (() => {
149
- var _el$32 = getNextElement(_tmpl$7);
150
- insert(_el$32, () => col.label);
151
- effect((_$p) => setStyleProperty(_el$32, "text-align", columnAlign(col)));
152
- return _el$32;
223
+ var _el$42 = getNextElement(_tmpl$9), _el$43 = _el$42.firstChild, _el$45 = _el$43.firstChild, [_el$46, _co$1] = getNextMarker(_el$45.nextSibling), _el$44 = _el$46.nextSibling;
224
+ _el$42.$$click = () => handleSort(col.key);
225
+ insert(_el$43, () => col.label, _el$46, _co$1);
226
+ insert(_el$44, () => sortIndicator(col.key));
227
+ effect((_p$) => {
228
+ var _v$5 = columnAlign(col), _v$6 = `Sort by ${col.label}`, _v$7 = {
229
+ "opacity-30": sortKey() !== col.key,
230
+ "opacity-100 text-blue-600 dark:text-blue-400": sortKey() === col.key
231
+ };
232
+ _v$5 !== _p$.e && setStyleProperty(_el$42, "text-align", _p$.e = _v$5);
233
+ _v$6 !== _p$.t && setAttribute(_el$42, "title", _p$.t = _v$6);
234
+ _p$.a = classList(_el$44, _v$7, _p$.a);
235
+ return _p$;
236
+ }, {
237
+ e: void 0,
238
+ t: void 0,
239
+ a: void 0
240
+ });
241
+ runHydrationEvents();
242
+ return _el$42;
153
243
  })()
154
244
  }));
155
245
  insert(_el$18, createComponent(For, {
156
246
  get each() {
157
- return pagedRows();
247
+ return visibleRows();
158
248
  },
159
249
  children: (row, i) => (() => {
160
- var _el$33 = getNextElement(_tmpl$8);
161
- insert(_el$33, createComponent(For, {
250
+ var _el$47 = getNextElement(_tmpl$0);
251
+ insert(_el$47, createComponent(For, {
162
252
  get each() {
163
253
  return columns();
164
254
  },
165
255
  children: (col) => (() => {
166
- var _el$34 = getNextElement(_tmpl$9);
167
- insert(_el$34, () => formatCell(row[col.key], col));
168
- effect((_$p) => setStyleProperty(_el$34, "text-align", columnAlign(col)));
169
- return _el$34;
256
+ var _el$48 = getNextElement(_tmpl$1);
257
+ insert(_el$48, () => formatCell(row[col.key], col));
258
+ effect((_$p) => setStyleProperty(_el$48, "text-align", columnAlign(col)));
259
+ return _el$48;
170
260
  })()
171
261
  }));
172
- effect((_$p) => classList(_el$33, {
262
+ effect((_$p) => classList(_el$47, {
173
263
  "bg-gray-25 dark:bg-gray-850": i() % 2 === 1
174
264
  }, _$p));
175
- return _el$33;
265
+ return _el$47;
176
266
  })()
177
267
  }));
178
- insert(_el$20, (() => {
179
- var _c$ = memo(() => !!c().totalRows);
180
- return () => _c$() ? `${totalRows()} / ${c().totalRows.toLocaleString("fr-FR")} rows` : `${totalRows()} row${totalRows() !== 1 ? "s" : ""}`;
181
- })());
182
268
  insert(_el$19, createComponent(Show, {
183
269
  get when() {
184
- return totalPages() > 1;
270
+ return showPageInfo();
271
+ },
272
+ get children() {
273
+ var _el$20 = getNextElement(_tmpl$5), _el$21 = _el$20.firstChild, [_el$22, _co$4] = getNextMarker(_el$21.nextSibling), _el$23 = _el$22.nextSibling, [_el$24, _co$5] = getNextMarker(_el$23.nextSibling);
274
+ insert(_el$20, (() => {
275
+ var _c$ = memo(() => !!isPaginated());
276
+ return () => _c$() ? `Showing ${rangeStart()}–${rangeEnd()} of ${sortedRows().length.toLocaleString("fr-FR")}` : `${sortedRows().length} row${sortedRows().length !== 1 ? "s" : ""}`;
277
+ })(), _el$22, _co$4);
278
+ insert(_el$20, (() => {
279
+ var _c$2 = memo(() => !!(c().totalRows && c().totalRows > sortedRows().length));
280
+ return () => _c$2() ? ` (${c().totalRows.toLocaleString("fr-FR")} total)` : "";
281
+ })(), _el$24, _co$5);
282
+ return _el$20;
283
+ }
284
+ }), _el$37, _co$8);
285
+ insert(_el$19, createComponent(Show, {
286
+ get when() {
287
+ return !showPageInfo();
288
+ },
289
+ get children() {
290
+ return getNextElement(_tmpl$6);
291
+ }
292
+ }), _el$39, _co$9);
293
+ insert(_el$19, createComponent(Show, {
294
+ get when() {
295
+ return isPaginated();
185
296
  },
186
297
  get children() {
187
- var _el$21 = getNextElement(_tmpl$5), _el$22 = _el$21.firstChild, _el$23 = _el$22.nextSibling, _el$25 = _el$23.firstChild, [_el$26, _co$4] = getNextMarker(_el$25.nextSibling), _el$24 = _el$26.nextSibling, _el$27 = _el$24.nextSibling, [_el$28, _co$5] = getNextMarker(_el$27.nextSibling), _el$29 = _el$23.nextSibling;
188
- _el$22.$$click = () => setPage((p) => p - 1);
189
- insert(_el$23, () => page() + 1, _el$26, _co$4);
190
- insert(_el$23, totalPages, _el$28, _co$5);
191
- _el$29.$$click = () => setPage((p) => p + 1);
298
+ var _el$26 = getNextElement(_tmpl$7), _el$27 = _el$26.firstChild, _el$28 = _el$27.nextSibling, _el$29 = _el$28.firstChild, _el$31 = _el$29.nextSibling, [_el$32, _co$6] = getNextMarker(_el$31.nextSibling), _el$30 = _el$32.nextSibling, _el$33 = _el$30.nextSibling, [_el$34, _co$7] = getNextMarker(_el$33.nextSibling), _el$35 = _el$28.nextSibling;
299
+ _el$27.$$click = () => setPage((p) => p - 1);
300
+ insert(_el$28, () => page() + 1, _el$32, _co$6);
301
+ insert(_el$28, totalPages, _el$34, _co$7);
302
+ _el$35.$$click = () => setPage((p) => p + 1);
192
303
  effect((_p$) => {
193
- var _v$ = page() === 0, _v$2 = page() >= totalPages() - 1;
194
- _v$ !== _p$.e && setProperty(_el$22, "disabled", _p$.e = _v$);
195
- _v$2 !== _p$.t && setProperty(_el$29, "disabled", _p$.t = _v$2);
304
+ var _v$3 = page() === 0, _v$4 = page() >= totalPages() - 1;
305
+ _v$3 !== _p$.e && setProperty(_el$27, "disabled", _p$.e = _v$3);
306
+ _v$4 !== _p$.t && setProperty(_el$35, "disabled", _p$.t = _v$4);
196
307
  return _p$;
197
308
  }, {
198
309
  e: void 0,
199
310
  t: void 0
200
311
  });
201
312
  runHydrationEvents();
202
- return _el$21;
313
+ return _el$26;
203
314
  }
204
- }), _el$31, _co$6);
315
+ }), _el$41, _co$0);
205
316
  return _el$2;
206
317
  })()
207
318
  });
@@ -1 +1 @@
1
- {"version":3,"file":"DataPreviewSection.js","sources":["../../src/components/DataPreviewSection.tsx"],"sourcesContent":["/**\n * DataPreviewSection — paginated data table with export\n * v4.0.1: Fixed rendering — defensive guards for store proxy content\n *\n * @experimental\n *\n * Features:\n * - Column types (number right-aligned, string left-aligned)\n * - Pagination (configurable page size)\n * - CSV / JSON export buttons\n * - Source attribution + freshness label\n * - Number formatting (FR locale)\n */\n\nimport { createSignal, createMemo, For, Show } from 'solid-js'\nimport type { DataPreviewContent, DataPreviewColumn } from '../types/chat-bus'\n\nexport interface DataPreviewSectionProps {\n content: DataPreviewContent\n}\n\n/** Format a number for display (French locale) */\nfunction formatNumber(value: unknown, format?: string): string {\n if (typeof value !== 'number' || !isFinite(value)) return String(value ?? '')\n if (format === 'percent') return `${(value * 100).toFixed(1)}%`\n if (format === 'currency') return `${value.toLocaleString('fr-FR')} EUR`\n if (Number.isInteger(value)) return value.toLocaleString('fr-FR')\n return value.toLocaleString('fr-FR', { maximumFractionDigits: 2 })\n}\n\n/** Format a cell value based on column type */\nfunction formatCell(value: unknown, col: DataPreviewColumn): string {\n if (value == null) return '\\u2014'\n if (col.type === 'number') return formatNumber(value, col.format)\n if (col.type === 'date' && typeof value === 'string') {\n try {\n return new Date(value).toLocaleDateString('fr-FR')\n } catch {\n return value\n }\n }\n return String(value)\n}\n\n/** Generate CSV from columns + rows */\nfunction toCSV(columns: DataPreviewColumn[], rows: Record<string, unknown>[]): string {\n const header = columns.map(c => `\"${c.label.replace(/\"/g, '\"\"')}\"`).join(';')\n const body = rows.map(row =>\n columns.map(c => {\n const val = row[c.key]\n if (val == null) return ''\n if (typeof val === 'string') return `\"${val.replace(/\"/g, '\"\"')}\"`\n return String(val)\n }).join(';')\n ).join('\\n')\n return `${header}\\n${body}`\n}\n\n/** Trigger browser download */\nfunction downloadFile(content: string, filename: string, mimeType: string) {\n const blob = new Blob([content], { type: mimeType })\n const url = URL.createObjectURL(blob)\n const a = document.createElement('a')\n a.href = url\n a.download = filename\n a.click()\n URL.revokeObjectURL(url)\n}\n\n/**\n * Extract a valid DataPreviewContent from props.content.\n * Handles: direct DataPreviewContent, or wrapped in an extra layer.\n */\nfunction resolveContent(raw: unknown): DataPreviewContent | null {\n if (!raw || typeof raw !== 'object') return null\n const obj = raw as Record<string, unknown>\n\n // Direct shape: { columns: [...], rows: [...] }\n if (Array.isArray(obj.columns) && Array.isArray(obj.rows)) {\n return obj as unknown as DataPreviewContent\n }\n\n // Wrapped shape: { content: { columns: [...], rows: [...] } }\n if (obj.content && typeof obj.content === 'object') {\n const inner = obj.content as Record<string, unknown>\n if (Array.isArray(inner.columns) && Array.isArray(inner.rows)) {\n return inner as unknown as DataPreviewContent\n }\n }\n\n return null\n}\n\nexport function DataPreviewSection(props: DataPreviewSectionProps) {\n const content = createMemo(() => {\n const resolved = resolveContent(props.content)\n if (!resolved) {\n console.warn(\n '[MCP-UI] DataPreviewSection: invalid content — expected { columns: [...], rows: [...] }, got:',\n props.content\n )\n }\n return resolved\n })\n\n const columns = () => content()?.columns || []\n const rows = () => content()?.rows || []\n const pageSize = () => content()?.pageSize || 25\n const [page, setPage] = createSignal(0)\n\n const totalRows = () => rows().length\n const totalPages = () => Math.max(1, Math.ceil(totalRows() / pageSize()))\n\n const pagedRows = createMemo(() => {\n const start = page() * pageSize()\n return rows().slice(start, start + pageSize())\n })\n\n const handleExportCSV = () => {\n const c = content()\n if (!c) return\n const csv = toCSV(c.columns, c.rows)\n downloadFile(csv, 'data-export.csv', 'text/csv;charset=utf-8')\n }\n\n const handleExportJSON = () => {\n const json = JSON.stringify(rows(), null, 2)\n downloadFile(json, 'data-export.json', 'application/json')\n }\n\n const columnAlign = (col: DataPreviewColumn) => {\n if (col.align) return col.align\n if (col.type === 'number') return 'right'\n return 'left'\n }\n\n return (\n <Show when={content()} fallback={\n <div class=\"text-xs text-amber-600 dark:text-amber-400 p-2\">\n [DataPreviewSection] Invalid content format\n </div>\n }>\n {(c) => (\n <div class=\"data-preview-section\">\n {/* Header with source + export */}\n <div class=\"flex items-center justify-between mb-2\">\n <div class=\"flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400\">\n <Show when={c().source}>\n <span class=\"font-medium\">{c().source}</span>\n </Show>\n <Show when={c().freshness}>\n <span class=\"px-1.5 py-0.5 rounded bg-blue-50 dark:bg-blue-900/20 text-blue-700 dark:text-blue-300\">\n {c().freshness}\n </span>\n </Show>\n </div>\n\n <Show when={c().exportable !== false}>\n <div class=\"flex items-center gap-1\">\n <button\n class=\"px-2 py-1 text-xs rounded border border-gray-300 dark:border-gray-600 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors\"\n onClick={handleExportCSV}\n title=\"Export CSV\"\n >\n CSV\n </button>\n <button\n class=\"px-2 py-1 text-xs rounded border border-gray-300 dark:border-gray-600 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors\"\n onClick={handleExportJSON}\n title=\"Export JSON\"\n >\n JSON\n </button>\n </div>\n </Show>\n </div>\n\n {/* Table */}\n <div class=\"overflow-x-auto rounded border border-gray-200 dark:border-gray-700\">\n <table class=\"w-full text-sm\">\n <thead>\n <tr class=\"bg-gray-50 dark:bg-gray-800\">\n <For each={columns()}>\n {(col) => (\n <th\n class=\"px-3 py-2 font-medium text-xs text-gray-600 dark:text-gray-400 uppercase tracking-wider border-b border-gray-200 dark:border-gray-700\"\n style={{ \"text-align\": columnAlign(col) }}\n >\n {col.label}\n </th>\n )}\n </For>\n </tr>\n </thead>\n <tbody>\n <For each={pagedRows()}>\n {(row, i) => (\n <tr\n class=\"border-b border-gray-100 dark:border-gray-800 hover:bg-gray-50 dark:hover:bg-gray-800/50 transition-colors\"\n classList={{ 'bg-gray-25 dark:bg-gray-850': i() % 2 === 1 }}\n >\n <For each={columns()}>\n {(col) => (\n <td\n class=\"px-3 py-2 text-gray-800 dark:text-gray-200\"\n style={{ \"text-align\": columnAlign(col) }}\n >\n {formatCell(row[col.key], col)}\n </td>\n )}\n </For>\n </tr>\n )}\n </For>\n </tbody>\n </table>\n </div>\n\n {/* Footer: pagination + row count */}\n <div class=\"flex items-center justify-between mt-2 text-xs text-gray-500 dark:text-gray-400\">\n <span>\n {c().totalRows\n ? `${totalRows()} / ${c().totalRows!.toLocaleString('fr-FR')} rows`\n : `${totalRows()} row${totalRows() !== 1 ? 's' : ''}`}\n </span>\n\n <Show when={totalPages() > 1}>\n <div class=\"flex items-center gap-1\">\n <button\n class=\"px-2 py-1 rounded hover:bg-gray-100 dark:hover:bg-gray-700 disabled:opacity-40 transition-colors\"\n disabled={page() === 0}\n onClick={() => setPage(p => p - 1)}\n >\n &laquo;\n </button>\n <span>{page() + 1} / {totalPages()}</span>\n <button\n class=\"px-2 py-1 rounded hover:bg-gray-100 dark:hover:bg-gray-700 disabled:opacity-40 transition-colors\"\n disabled={page() >= totalPages() - 1}\n onClick={() => setPage(p => p + 1)}\n >\n &raquo;\n </button>\n </div>\n </Show>\n </div>\n </div>\n )}\n </Show>\n )\n}\n"],"names":["formatNumber","value","format","isFinite","String","toFixed","toLocaleString","Number","isInteger","maximumFractionDigits","formatCell","col","type","Date","toLocaleDateString","toCSV","columns","rows","header","map","c","label","replace","join","body","row","val","key","downloadFile","content","filename","mimeType","blob","Blob","url","URL","createObjectURL","a","document","createElement","href","download","click","revokeObjectURL","resolveContent","raw","obj","Array","isArray","inner","DataPreviewSection","props","createMemo","resolved","console","warn","pageSize","page","setPage","createSignal","totalRows","length","totalPages","Math","max","ceil","pagedRows","start","slice","handleExportCSV","csv","handleExportJSON","json","JSON","stringify","columnAlign","align","_$createComponent","Show","when","fallback","_$getNextElement","_tmpl$","children","_el$2","_tmpl$6","_el$3","firstChild","_el$4","_el$7","_el$8","_co$","_$getNextMarker","nextSibling","_el$9","_el$0","_co$2","_el$12","_el$13","_co$3","_el$14","_el$15","_el$16","_el$17","_el$18","_el$19","_el$20","_el$30","_el$31","_co$6","_$insert","source","_el$5","_tmpl$2","freshness","_el$6","_tmpl$3","exportable","_el$1","_tmpl$4","_el$10","_el$11","$$click","_$runHydrationEvents","For","each","_el$32","_tmpl$7","_$effect","_$p","_$setStyleProperty","i","_el$33","_tmpl$8","_el$34","_tmpl$9","_$classList","_c$","_$memo","_el$21","_tmpl$5","_el$22","_el$23","_el$25","_el$26","_co$4","_el$24","_el$27","_el$28","_co$5","_el$29","p","_p$","_v$","_v$2","e","_$setProperty","t","undefined","_$delegateEvents"],"mappings":"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"}
1
+ {"version":3,"file":"DataPreviewSection.js","sources":["../../src/components/DataPreviewSection.tsx"],"sourcesContent":["/**\n * DataPreviewSection — paginated, sortable data table with export\n * v4.0.4: Full pagination spec (auto-activate, pageSize=0 disable, showPageInfo, onPageChange)\n *\n * @experimental\n */\n\nimport { createSignal, createMemo, createEffect, For, Show } from 'solid-js'\nimport type { DataPreviewContent, DataPreviewColumn } from '../types/chat-bus'\n\nexport interface DataPreviewSectionProps {\n content: DataPreviewContent\n}\n\ntype SortDir = 'asc' | 'desc' | null\n\n// ─── Formatting helpers ─────────────────────────────────────\n\nfunction formatNumber(value: unknown, format?: string): string {\n if (typeof value !== 'number' || !isFinite(value)) return String(value ?? '')\n if (format === 'percent') return `${(value * 100).toFixed(1)}%`\n if (format === 'currency') return `${value.toLocaleString('fr-FR')} EUR`\n if (Number.isInteger(value)) return value.toLocaleString('fr-FR')\n return value.toLocaleString('fr-FR', { maximumFractionDigits: 2 })\n}\n\nfunction formatCell(value: unknown, col: DataPreviewColumn): string {\n if (value == null) return '\\u2014'\n if (col.type === 'number') return formatNumber(value, col.format)\n if (col.type === 'date' && typeof value === 'string') {\n try { return new Date(value).toLocaleDateString('fr-FR') } catch { return value }\n }\n return String(value)\n}\n\nfunction compareValues(a: unknown, b: unknown, type?: string): number {\n if (a == null && b == null) return 0\n if (a == null) return 1\n if (b == null) return -1\n if (type === 'number') {\n const na = typeof a === 'number' ? a : Number(a)\n const nb = typeof b === 'number' ? b : Number(b)\n if (isNaN(na) && isNaN(nb)) return 0\n if (isNaN(na)) return 1\n if (isNaN(nb)) return -1\n return na - nb\n }\n if (type === 'date') {\n const da = new Date(String(a)).getTime()\n const db = new Date(String(b)).getTime()\n if (isNaN(da) && isNaN(db)) return 0\n if (isNaN(da)) return 1\n if (isNaN(db)) return -1\n return da - db\n }\n return String(a).localeCompare(String(b), 'fr', { sensitivity: 'base' })\n}\n\n// ─── Export helpers ─────────────────────────────────────────\n\nfunction toCSV(columns: DataPreviewColumn[], rows: Record<string, unknown>[]): string {\n const header = columns.map(c => `\"${c.label.replace(/\"/g, '\"\"')}\"`).join(';')\n const body = rows.map(row =>\n columns.map(c => {\n const val = row[c.key]\n if (val == null) return ''\n if (typeof val === 'string') return `\"${val.replace(/\"/g, '\"\"')}\"`\n return String(val)\n }).join(';')\n ).join('\\n')\n return `${header}\\n${body}`\n}\n\nfunction downloadFile(content: string, filename: string, mimeType: string) {\n const blob = new Blob([content], { type: mimeType })\n const url = URL.createObjectURL(blob)\n const a = document.createElement('a')\n a.href = url\n a.download = filename\n a.click()\n URL.revokeObjectURL(url)\n}\n\n// ─── Content resolver ───────────────────────────────────────\n\nfunction resolveContent(raw: unknown): DataPreviewContent | null {\n if (!raw || typeof raw !== 'object') return null\n const obj = raw as Record<string, unknown>\n if (Array.isArray(obj.columns) && Array.isArray(obj.rows)) {\n return obj as unknown as DataPreviewContent\n }\n if (obj.content && typeof obj.content === 'object') {\n const inner = obj.content as Record<string, unknown>\n if (Array.isArray(inner.columns) && Array.isArray(inner.rows)) {\n return inner as unknown as DataPreviewContent\n }\n }\n return null\n}\n\n// ─── Component ──────────────────────────────────────────────\n\nexport function DataPreviewSection(props: DataPreviewSectionProps) {\n const content = createMemo(() => {\n const resolved = resolveContent(props.content)\n if (!resolved) {\n console.warn('[MCP-UI] DataPreviewSection: invalid content — expected { columns, rows }', props.content)\n }\n return resolved\n })\n\n const columns = () => content()?.columns || []\n const rawRows = () => content()?.rows || []\n const pageSizeVal = () => content()?.pageSize ?? 25\n const showPageInfo = () => content()?.showPageInfo !== false\n\n const [page, setPage] = createSignal(content()?.initialPage ?? 0)\n const [sortKey, setSortKey] = createSignal<string | null>(null)\n const [sortDir, setSortDir] = createSignal<SortDir>(null)\n\n // Notify parent on page change\n createEffect(() => {\n const p = page()\n content()?.onPageChange?.(p)\n })\n\n const handleSort = (key: string) => {\n if (sortKey() === key) {\n if (sortDir() === 'asc') setSortDir('desc')\n else { setSortKey(null); setSortDir(null) }\n } else {\n setSortKey(key)\n setSortDir('asc')\n }\n setPage(0)\n }\n\n const sortedRows = createMemo(() => {\n const r = rawRows()\n const key = sortKey()\n const dir = sortDir()\n if (!key || !dir) return r\n const col = columns().find(c => c.key === key)\n return [...r].sort((a, b) => {\n const cmp = compareValues(a[key], b[key], col?.type)\n return dir === 'desc' ? -cmp : cmp\n })\n })\n\n // Pagination: auto-enabled when rows > pageSize, disabled when pageSize=0\n const isPaginated = () => pageSizeVal() > 0 && sortedRows().length > pageSizeVal()\n const totalPages = () => isPaginated() ? Math.ceil(sortedRows().length / pageSizeVal()) : 1\n\n const visibleRows = createMemo(() => {\n if (!isPaginated()) return sortedRows()\n const start = page() * pageSizeVal()\n return sortedRows().slice(start, start + pageSizeVal())\n })\n\n const rangeStart = () => isPaginated() ? page() * pageSizeVal() + 1 : 1\n const rangeEnd = () => isPaginated()\n ? Math.min((page() + 1) * pageSizeVal(), sortedRows().length)\n : sortedRows().length\n\n // Export ALL rows (not just page)\n const handleExportCSV = () => {\n const c = content()\n if (!c) return\n downloadFile(toCSV(c.columns, sortedRows()), 'data-export.csv', 'text/csv;charset=utf-8')\n }\n const handleExportJSON = () => {\n downloadFile(JSON.stringify(sortedRows(), null, 2), 'data-export.json', 'application/json')\n }\n\n const columnAlign = (col: DataPreviewColumn) => {\n if (col.align) return col.align\n if (col.type === 'number') return 'right'\n return 'left'\n }\n\n const sortIndicator = (key: string) => {\n if (sortKey() !== key) return '\\u2195'\n return sortDir() === 'asc' ? '\\u2191' : '\\u2193'\n }\n\n return (\n <Show when={content()} fallback={\n <div class=\"text-xs text-amber-600 dark:text-amber-400 p-2\">\n [DataPreviewSection] Invalid content format\n </div>\n }>\n {(c) => (\n <div class=\"data-preview-section\">\n {/* Header: source + export */}\n <div class=\"flex items-center justify-between mb-2\">\n <div class=\"flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400\">\n <Show when={c().source}>\n <span class=\"font-medium\">{c().source}</span>\n </Show>\n <Show when={c().freshness}>\n <span class=\"px-1.5 py-0.5 rounded bg-blue-50 dark:bg-blue-900/20 text-blue-700 dark:text-blue-300\">\n {c().freshness}\n </span>\n </Show>\n </div>\n <Show when={c().exportable !== false}>\n <div class=\"flex items-center gap-1\">\n <button\n class=\"px-2 py-1 text-xs rounded border border-gray-300 dark:border-gray-600 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors\"\n onClick={handleExportCSV}\n title={`Export CSV (${sortedRows().length} rows)`}\n >\n CSV\n </button>\n <button\n class=\"px-2 py-1 text-xs rounded border border-gray-300 dark:border-gray-600 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors\"\n onClick={handleExportJSON}\n title={`Export JSON (${sortedRows().length} rows)`}\n >\n JSON\n </button>\n </div>\n </Show>\n </div>\n\n {/* Table */}\n <div class=\"overflow-x-auto rounded border border-gray-200 dark:border-gray-700\">\n <table class=\"w-full text-sm\">\n <thead>\n <tr class=\"bg-gray-50 dark:bg-gray-800\">\n <For each={columns()}>\n {(col) => (\n <th\n class=\"px-3 py-2 font-medium text-xs text-gray-600 dark:text-gray-400 uppercase tracking-wider border-b border-gray-200 dark:border-gray-700 cursor-pointer select-none hover:bg-gray-100 dark:hover:bg-gray-700/50 transition-colors\"\n style={{ \"text-align\": columnAlign(col) }}\n onClick={() => handleSort(col.key)}\n title={`Sort by ${col.label}`}\n >\n <span class=\"inline-flex items-center gap-1\">\n {col.label}\n <span\n class=\"text-[10px] leading-none\"\n classList={{\n 'opacity-30': sortKey() !== col.key,\n 'opacity-100 text-blue-600 dark:text-blue-400': sortKey() === col.key,\n }}\n >\n {sortIndicator(col.key)}\n </span>\n </span>\n </th>\n )}\n </For>\n </tr>\n </thead>\n <tbody>\n <For each={visibleRows()}>\n {(row, i) => (\n <tr\n class=\"border-b border-gray-100 dark:border-gray-800 hover:bg-gray-50 dark:hover:bg-gray-800/50 transition-colors\"\n classList={{ 'bg-gray-25 dark:bg-gray-850': i() % 2 === 1 }}\n >\n <For each={columns()}>\n {(col) => (\n <td\n class=\"px-3 py-2 text-gray-800 dark:text-gray-200\"\n style={{ \"text-align\": columnAlign(col) }}\n >\n {formatCell(row[col.key], col)}\n </td>\n )}\n </For>\n </tr>\n )}\n </For>\n </tbody>\n </table>\n </div>\n\n {/* Footer: pagination + page info */}\n <div class=\"flex items-center justify-between mt-2 text-xs text-gray-500 dark:text-gray-400\">\n <Show when={showPageInfo()}>\n <span>\n {isPaginated()\n ? `Showing ${rangeStart()}\\u2013${rangeEnd()} of ${sortedRows().length.toLocaleString('fr-FR')}`\n : `${sortedRows().length} row${sortedRows().length !== 1 ? 's' : ''}`\n }\n {c().totalRows && c().totalRows! > sortedRows().length\n ? ` (${c().totalRows!.toLocaleString('fr-FR')} total)`\n : ''\n }\n </span>\n </Show>\n <Show when={!showPageInfo()}><span /></Show>\n\n <Show when={isPaginated()}>\n <div class=\"flex items-center gap-1\">\n <button\n class=\"px-2 py-1 rounded hover:bg-gray-100 dark:hover:bg-gray-700 disabled:opacity-40 disabled:cursor-not-allowed transition-colors\"\n disabled={page() === 0}\n onClick={() => setPage(p => p - 1)}\n >\n &#x25C0; Prev\n </button>\n <span class=\"px-2\">Page {page() + 1} / {totalPages()}</span>\n <button\n class=\"px-2 py-1 rounded hover:bg-gray-100 dark:hover:bg-gray-700 disabled:opacity-40 disabled:cursor-not-allowed transition-colors\"\n disabled={page() >= totalPages() - 1}\n onClick={() => setPage(p => p + 1)}\n >\n Next &#x25B6;\n </button>\n </div>\n </Show>\n </div>\n </div>\n )}\n </Show>\n )\n}\n"],"names":["formatNumber","value","format","isFinite","String","toFixed","toLocaleString","Number","isInteger","maximumFractionDigits","formatCell","col","type","Date","toLocaleDateString","compareValues","a","b","na","nb","isNaN","da","getTime","db","localeCompare","sensitivity","toCSV","columns","rows","header","map","c","label","replace","join","body","row","val","key","downloadFile","content","filename","mimeType","blob","Blob","url","URL","createObjectURL","document","createElement","href","download","click","revokeObjectURL","resolveContent","raw","obj","Array","isArray","inner","DataPreviewSection","props","createMemo","resolved","console","warn","rawRows","pageSizeVal","pageSize","showPageInfo","page","setPage","createSignal","initialPage","sortKey","setSortKey","sortDir","setSortDir","createEffect","p","onPageChange","handleSort","sortedRows","r","dir","find","sort","cmp","isPaginated","length","totalPages","Math","ceil","visibleRows","start","slice","rangeStart","rangeEnd","min","handleExportCSV","handleExportJSON","JSON","stringify","columnAlign","align","sortIndicator","_$createComponent","Show","when","fallback","_$getNextElement","_tmpl$","children","_el$2","_tmpl$8","_el$3","firstChild","_el$4","_el$7","_el$8","_co$","_$getNextMarker","nextSibling","_el$9","_el$0","_co$2","_el$12","_el$13","_co$3","_el$14","_el$15","_el$16","_el$17","_el$18","_el$19","_el$36","_el$37","_co$8","_el$38","_el$39","_co$9","_el$40","_el$41","_co$0","_$insert","source","_el$5","_tmpl$2","freshness","_el$6","_tmpl$3","exportable","_el$1","_tmpl$4","_el$10","_el$11","$$click","_$effect","_p$","_v$","_v$2","e","_$setAttribute","t","undefined","_$runHydrationEvents","For","each","_el$42","_tmpl$9","_el$43","_el$45","_el$46","_co$1","_el$44","_v$5","_v$6","_v$7","_$setStyleProperty","_$classList","i","_el$47","_tmpl$0","_el$48","_tmpl$1","_$p","_el$20","_tmpl$5","_el$21","_el$22","_co$4","_el$23","_el$24","_co$5","_c$","_$memo","_c$2","totalRows","_tmpl$6","_el$26","_tmpl$7","_el$27","_el$28","_el$29","_el$31","_el$32","_co$6","_el$30","_el$33","_el$34","_co$7","_el$35","_v$3","_v$4","_$setProperty","_$delegateEvents"],"mappings":"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"}