@mieweb/ui 0.6.1-dev.148 → 0.6.1-dev.150

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.
Files changed (82) hide show
  1. package/dist/brands/index.cjs +22 -22
  2. package/dist/brands/index.js +5 -5
  3. package/dist/chunk-2T4JU5RH.cjs +1156 -0
  4. package/dist/chunk-2T4JU5RH.cjs.map +1 -0
  5. package/dist/chunk-3SSXDWD7.js +363 -0
  6. package/dist/chunk-3SSXDWD7.js.map +1 -0
  7. package/dist/{chunk-MARLXJQO.cjs → chunk-6R2ZPDN7.cjs} +7 -7
  8. package/dist/{chunk-MARLXJQO.cjs.map → chunk-6R2ZPDN7.cjs.map} +1 -1
  9. package/dist/{chunk-WHUD3XHR.cjs → chunk-7PA26KBF.cjs} +15 -3
  10. package/dist/chunk-7PA26KBF.cjs.map +1 -0
  11. package/dist/chunk-ASLZUFH4.js +1967 -0
  12. package/dist/chunk-ASLZUFH4.js.map +1 -0
  13. package/dist/chunk-FADQVM4M.cjs +2017 -0
  14. package/dist/chunk-FADQVM4M.cjs.map +1 -0
  15. package/dist/{chunk-DFT7TYKL.cjs → chunk-H4T5T65N.cjs} +6 -3
  16. package/dist/chunk-H4T5T65N.cjs.map +1 -0
  17. package/dist/chunk-I6CY5C6A.js +12 -0
  18. package/dist/chunk-I6CY5C6A.js.map +1 -0
  19. package/dist/chunk-JFLC7SHM.cjs +35 -0
  20. package/dist/chunk-JFLC7SHM.cjs.map +1 -0
  21. package/dist/chunk-LZPPH5BW.cjs +368 -0
  22. package/dist/chunk-LZPPH5BW.cjs.map +1 -0
  23. package/dist/{chunk-3OHVUXDG.js → chunk-M7BLVBL4.js} +6 -3
  24. package/dist/chunk-M7BLVBL4.js.map +1 -0
  25. package/dist/chunk-PM2I3QKM.cjs +1419 -0
  26. package/dist/chunk-PM2I3QKM.cjs.map +1 -0
  27. package/dist/{chunk-TW6DXMSD.js → chunk-R6PBBPU3.js} +2 -2
  28. package/dist/{chunk-TW6DXMSD.js.map → chunk-R6PBBPU3.js.map} +1 -1
  29. package/dist/{chunk-33PO3J4O.js → chunk-RXY5SD3O.js} +15 -3
  30. package/dist/chunk-RXY5SD3O.js.map +1 -0
  31. package/dist/{chunk-AEGYWRSL.js → chunk-TXYTMU3K.js} +3 -3
  32. package/dist/{chunk-AEGYWRSL.js.map → chunk-TXYTMU3K.js.map} +1 -1
  33. package/dist/chunk-UHPQYBXQ.js +1124 -0
  34. package/dist/chunk-UHPQYBXQ.js.map +1 -0
  35. package/dist/chunk-XQE26F3G.js +1383 -0
  36. package/dist/chunk-XQE26F3G.js.map +1 -0
  37. package/dist/{chunk-26YNFCOC.cjs → chunk-Z6NRP4Z5.cjs} +2 -2
  38. package/dist/{chunk-26YNFCOC.cjs.map → chunk-Z6NRP4Z5.cjs.map} +1 -1
  39. package/dist/components/Dropdown/index.cjs +7 -7
  40. package/dist/components/Dropdown/index.d.cts +1 -1
  41. package/dist/components/Dropdown/index.d.ts +1 -1
  42. package/dist/components/Dropdown/index.js +1 -1
  43. package/dist/components/RichTextEditor/index.cjs +5 -5
  44. package/dist/components/RichTextEditor/index.js +2 -2
  45. package/dist/components/SuperChat/index.cjs +1319 -0
  46. package/dist/components/SuperChat/index.cjs.map +1 -0
  47. package/dist/components/SuperChat/index.d.cts +189 -0
  48. package/dist/components/SuperChat/index.d.ts +189 -0
  49. package/dist/components/SuperChat/index.js +1282 -0
  50. package/dist/components/SuperChat/index.js.map +1 -0
  51. package/dist/components/SuperChat/plugins/index.cjs +1221 -0
  52. package/dist/components/SuperChat/plugins/index.cjs.map +1 -0
  53. package/dist/components/SuperChat/plugins/index.d.cts +253 -0
  54. package/dist/components/SuperChat/plugins/index.d.ts +253 -0
  55. package/dist/components/SuperChat/plugins/index.js +1181 -0
  56. package/dist/components/SuperChat/plugins/index.js.map +1 -0
  57. package/dist/datavis.cjs +18 -362
  58. package/dist/datavis.cjs.map +1 -1
  59. package/dist/datavis.js +1 -361
  60. package/dist/datavis.js.map +1 -1
  61. package/dist/index.cjs +1297 -5412
  62. package/dist/index.cjs.map +1 -1
  63. package/dist/index.d.cts +44 -240
  64. package/dist/index.d.ts +44 -240
  65. package/dist/index.js +759 -5037
  66. package/dist/index.js.map +1 -1
  67. package/dist/nitroTableGrid-FWRCDE4N.js +22 -0
  68. package/dist/nitroTableGrid-FWRCDE4N.js.map +1 -0
  69. package/dist/nitroTableGrid-IY75TQJ2.cjs +44 -0
  70. package/dist/nitroTableGrid-IY75TQJ2.cjs.map +1 -0
  71. package/dist/styles.css +1 -1
  72. package/dist/tailwind-preset.cjs +4 -4
  73. package/dist/tailwind-preset.js +1 -1
  74. package/dist/types-BFFgW6qy.d.ts +240 -0
  75. package/dist/types-BzeY_kYO.d.cts +242 -0
  76. package/dist/types-BzeY_kYO.d.ts +242 -0
  77. package/dist/types-CRt5IPNL.d.cts +240 -0
  78. package/package.json +41 -4
  79. package/dist/chunk-33PO3J4O.js.map +0 -1
  80. package/dist/chunk-3OHVUXDG.js.map +0 -1
  81. package/dist/chunk-DFT7TYKL.cjs.map +0 -1
  82. package/dist/chunk-WHUD3XHR.cjs.map +0 -1
@@ -0,0 +1,1221 @@
1
+ 'use strict';
2
+
3
+ var chunkJFLC7SHM_cjs = require('../../../chunk-JFLC7SHM.cjs');
4
+ var chunkFADQVM4M_cjs = require('../../../chunk-FADQVM4M.cjs');
5
+ require('../../../chunk-2T4JU5RH.cjs');
6
+ var chunkOR5DRJCW_cjs = require('../../../chunk-OR5DRJCW.cjs');
7
+ var React2 = require('react');
8
+ var rehypeHighlight = require('rehype-highlight');
9
+ var jsxRuntime = require('react/jsx-runtime');
10
+ var rehypeKatex = require('rehype-katex');
11
+ var remarkMath = require('remark-math');
12
+ var reactDom = require('react-dom');
13
+
14
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
15
+
16
+ function _interopNamespace(e) {
17
+ if (e && e.__esModule) return e;
18
+ var n = Object.create(null);
19
+ if (e) {
20
+ Object.keys(e).forEach(function (k) {
21
+ if (k !== 'default') {
22
+ var d = Object.getOwnPropertyDescriptor(e, k);
23
+ Object.defineProperty(n, k, d.get ? d : {
24
+ enumerable: true,
25
+ get: function () { return e[k]; }
26
+ });
27
+ }
28
+ });
29
+ }
30
+ n.default = e;
31
+ return Object.freeze(n);
32
+ }
33
+
34
+ var React2__namespace = /*#__PURE__*/_interopNamespace(React2);
35
+ var rehypeHighlight__default = /*#__PURE__*/_interopDefault(rehypeHighlight);
36
+ var rehypeKatex__default = /*#__PURE__*/_interopDefault(rehypeKatex);
37
+ var remarkMath__default = /*#__PURE__*/_interopDefault(remarkMath);
38
+
39
+ function CopyablePre({
40
+ node: _node,
41
+ ...props
42
+ }) {
43
+ const ref = React2__namespace.useRef(null);
44
+ const [copied, setCopied] = React2__namespace.useState(false);
45
+ const onCopy = React2__namespace.useCallback(() => {
46
+ const text = ref.current?.innerText ?? "";
47
+ if (!text) return;
48
+ const copy = navigator.clipboard?.writeText(text);
49
+ if (!copy) return;
50
+ void copy.then(
51
+ () => {
52
+ setCopied(true);
53
+ window.setTimeout(() => setCopied(false), 1500);
54
+ },
55
+ () => {
56
+ }
57
+ );
58
+ }, []);
59
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-slot": "superchat-code", className: "group relative my-2", children: [
60
+ /* @__PURE__ */ jsxRuntime.jsx(
61
+ "button",
62
+ {
63
+ type: "button",
64
+ onClick: onCopy,
65
+ "aria-label": copied ? "Copied" : "Copy code",
66
+ className: "absolute top-2 right-2 rounded-md bg-neutral-700/80 px-2 py-1 text-xs text-neutral-100 opacity-0 transition-opacity group-hover:opacity-100 hover:bg-neutral-600 focus-visible:opacity-100",
67
+ children: copied ? "Copied" : "Copy"
68
+ }
69
+ ),
70
+ /* @__PURE__ */ jsxRuntime.jsx(
71
+ "pre",
72
+ {
73
+ ...props,
74
+ ref,
75
+ className: chunkOR5DRJCW_cjs.cn(
76
+ "overflow-x-auto rounded-lg bg-neutral-900 p-3 text-sm text-neutral-100 dark:bg-neutral-950",
77
+ props.className
78
+ )
79
+ }
80
+ )
81
+ ] });
82
+ }
83
+ function createCodePlugin() {
84
+ return {
85
+ name: "code",
86
+ // `detect: false` + ignoreMissing keeps it predictable for streamed output.
87
+ rehypePlugins: [[rehypeHighlight__default.default, { detect: false, ignoreMissing: true }]],
88
+ components: {
89
+ pre: CopyablePre
90
+ },
91
+ // `.hljs-*` token classes are already permitted by the base schema's
92
+ // broadened `className` allow-list on code/pre/span.
93
+ sanitizeSchema: {
94
+ attributes: {
95
+ code: ["className"],
96
+ span: ["className"]
97
+ }
98
+ }
99
+ };
100
+ }
101
+ var KATEX_TAGS = [
102
+ "span",
103
+ "svg",
104
+ "path",
105
+ "line",
106
+ "math",
107
+ "semantics",
108
+ "annotation",
109
+ "mrow",
110
+ "mi",
111
+ "mo",
112
+ "mn",
113
+ "ms",
114
+ "mtext",
115
+ "msup",
116
+ "msub",
117
+ "msubsup",
118
+ "mfrac",
119
+ "msqrt",
120
+ "mroot",
121
+ "mover",
122
+ "munder",
123
+ "munderover",
124
+ "mtable",
125
+ "mtr",
126
+ "mtd",
127
+ "mspace",
128
+ "mpadded",
129
+ "mphantom",
130
+ "menclose",
131
+ "mstyle"
132
+ ];
133
+ function createMathPlugin() {
134
+ return {
135
+ name: "math",
136
+ remarkPlugins: [remarkMath__default.default],
137
+ // `output: 'htmlAndMathml'` (KaTeX default) gives accessible MathML too.
138
+ rehypePlugins: [[rehypeKatex__default.default, { throwOnError: false }]],
139
+ sanitizeSchema: {
140
+ tagNames: KATEX_TAGS,
141
+ attributes: {
142
+ "*": ["className"],
143
+ span: ["className", "style", "ariaHidden"],
144
+ svg: [
145
+ "xmlns",
146
+ "width",
147
+ "height",
148
+ "viewBox",
149
+ "preserveAspectRatio",
150
+ "style"
151
+ ],
152
+ path: ["d"],
153
+ line: ["x1", "y1", "x2", "y2", "stroke", "strokeWidth"],
154
+ math: ["xmlns", "display"],
155
+ annotation: ["encoding"]
156
+ }
157
+ }
158
+ };
159
+ }
160
+ var GENUI_TAG = "genui-widget";
161
+ function textOf(node) {
162
+ if (node.type === "text") return node.value ?? "";
163
+ return (node.children ?? []).map(textOf).join("");
164
+ }
165
+ function isGenuiPre(node) {
166
+ if (node.tagName !== "pre") return false;
167
+ const code = node.children?.find((c) => c.tagName === "code");
168
+ const className = code?.properties?.className;
169
+ const classes = Array.isArray(className) ? className : [className];
170
+ return classes.some(
171
+ (c) => typeof c === "string" && (c === "language-genui" || c === "genui")
172
+ );
173
+ }
174
+ function rehypeGenui() {
175
+ return (tree) => {
176
+ const walk = (node) => {
177
+ if (!node.children) return;
178
+ node.children = node.children.map((child) => {
179
+ if (isGenuiPre(child)) {
180
+ const code = child.children?.find((c) => c.tagName === "code");
181
+ const raw = code ? textOf(code) : "";
182
+ return {
183
+ type: "element",
184
+ tagName: GENUI_TAG,
185
+ properties: {},
186
+ children: [{ type: "text", value: raw }]
187
+ };
188
+ }
189
+ walk(child);
190
+ return child;
191
+ });
192
+ };
193
+ walk(tree);
194
+ };
195
+ }
196
+ function PendingCard({ label }) {
197
+ return /* @__PURE__ */ jsxRuntime.jsxs(
198
+ "div",
199
+ {
200
+ "data-slot": "superchat-genui-pending",
201
+ className: "my-2 flex items-center gap-2 rounded-lg border border-neutral-200 bg-neutral-50 px-3 py-2 text-sm text-neutral-600 dark:border-neutral-700 dark:bg-neutral-800/50 dark:text-neutral-300",
202
+ children: [
203
+ /* @__PURE__ */ jsxRuntime.jsx(
204
+ "span",
205
+ {
206
+ className: "h-3 w-3 animate-spin rounded-full border-2 border-neutral-400 border-t-transparent",
207
+ "aria-hidden": "true"
208
+ }
209
+ ),
210
+ label
211
+ ]
212
+ }
213
+ );
214
+ }
215
+ function InertFallback({ raw }) {
216
+ return /* @__PURE__ */ jsxRuntime.jsx(
217
+ "pre",
218
+ {
219
+ "data-slot": "superchat-genui-fallback",
220
+ className: "my-2 overflow-x-auto rounded-lg bg-neutral-900 p-3 text-sm text-neutral-100 dark:bg-neutral-950",
221
+ children: /* @__PURE__ */ jsxRuntime.jsx("code", { children: raw })
222
+ }
223
+ );
224
+ }
225
+ function ErrorCard({ message }) {
226
+ return /* @__PURE__ */ jsxRuntime.jsx(
227
+ "div",
228
+ {
229
+ "data-slot": "superchat-genui-error",
230
+ role: "alert",
231
+ className: "my-2 rounded-lg border border-red-300 bg-red-50 px-3 py-2 text-sm text-red-700 dark:border-red-700 dark:bg-red-900/30 dark:text-red-300",
232
+ children: message
233
+ }
234
+ );
235
+ }
236
+ function parsePayload(raw) {
237
+ const trimmed = raw.trim();
238
+ if (!trimmed) return { ok: false };
239
+ try {
240
+ const value = JSON.parse(trimmed);
241
+ if (!value || typeof value.widget !== "string") return { ok: false };
242
+ return { ok: true, value };
243
+ } catch {
244
+ return { ok: false };
245
+ }
246
+ }
247
+ async function validate(schema, data) {
248
+ if (!schema) return { ok: true, value: data };
249
+ const result = await schema["~standard"].validate(data);
250
+ if ("issues" in result && result.issues) {
251
+ return {
252
+ ok: false,
253
+ message: result.issues.map((i) => i.message).join("; ") || "Invalid widget payload"
254
+ };
255
+ }
256
+ return { ok: true, value: result.value };
257
+ }
258
+ function usePrefetchTrigger(policy, ref) {
259
+ const [ready, setReady] = React2__namespace.useState(policy === "eager");
260
+ React2__namespace.useEffect(() => {
261
+ if (ready) return;
262
+ if (policy === "idle") {
263
+ const requestIdle = window.requestIdleCallback;
264
+ const cancelIdle = window.cancelIdleCallback;
265
+ let idleId = null;
266
+ let timeoutId = null;
267
+ if (requestIdle) {
268
+ idleId = requestIdle(() => setReady(true));
269
+ } else {
270
+ timeoutId = window.setTimeout(() => setReady(true), 200);
271
+ }
272
+ return () => {
273
+ if (idleId !== null && cancelIdle) cancelIdle(idleId);
274
+ if (timeoutId !== null) window.clearTimeout(timeoutId);
275
+ };
276
+ }
277
+ const el = ref.current;
278
+ if (!el || typeof IntersectionObserver === "undefined") {
279
+ setReady(true);
280
+ return;
281
+ }
282
+ const obs = new IntersectionObserver((entries) => {
283
+ if (entries.some((e) => e.isIntersecting)) {
284
+ setReady(true);
285
+ obs.disconnect();
286
+ }
287
+ });
288
+ obs.observe(el);
289
+ return () => obs.disconnect();
290
+ }, [policy, ready, ref]);
291
+ return ready;
292
+ }
293
+ function GenUIBlock({ raw, registry }) {
294
+ const { messageId, streaming } = chunkJFLC7SHM_cjs.useTextRenderContext();
295
+ const placeholderRef = React2__namespace.useRef(null);
296
+ const parsed = React2__namespace.useMemo(() => parsePayload(raw), [raw]);
297
+ const entry = parsed.ok ? registry[parsed.value.widget] : void 0;
298
+ const policy = entry?.prefetch ?? (parsed.ok ? parsed.value.prefetch : void 0) ?? "visible";
299
+ const codeReady = usePrefetchTrigger(policy, placeholderRef);
300
+ const [Loaded, setLoaded] = React2__namespace.useState(null);
301
+ const [validated, setValidated] = React2__namespace.useState(null);
302
+ React2__namespace.useEffect(() => {
303
+ if (!entry || !codeReady) return;
304
+ let active = true;
305
+ void entry.component().then((m) => {
306
+ if (active) setLoaded(() => m.default);
307
+ }).catch(() => {
308
+ if (active)
309
+ setValidated({ ok: false, message: "Failed to load widget" });
310
+ });
311
+ return () => {
312
+ active = false;
313
+ };
314
+ }, [entry, codeReady]);
315
+ React2__namespace.useEffect(() => {
316
+ if (!entry || !parsed.ok || streaming) return;
317
+ let active = true;
318
+ const props = parsed.value.props;
319
+ void (async () => {
320
+ const result = await validate(entry.schema, props);
321
+ if (!active) return;
322
+ if (result.ok && entry.prefetchData) {
323
+ try {
324
+ await entry.prefetchData(result.value);
325
+ } catch {
326
+ }
327
+ }
328
+ if (active) setValidated(result);
329
+ })();
330
+ return () => {
331
+ active = false;
332
+ };
333
+ }, [entry, parsed, streaming]);
334
+ if (!parsed.ok) {
335
+ if (streaming) {
336
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref: placeholderRef, children: /* @__PURE__ */ jsxRuntime.jsx(PendingCard, { label: "Preparing widget\u2026" }) });
337
+ }
338
+ return /* @__PURE__ */ jsxRuntime.jsx(InertFallback, { raw });
339
+ }
340
+ if (parsed.ok && !entry) return /* @__PURE__ */ jsxRuntime.jsx(InertFallback, { raw });
341
+ if (streaming || !Loaded || !validated) {
342
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref: placeholderRef, children: /* @__PURE__ */ jsxRuntime.jsx(PendingCard, { label: "Preparing widget\u2026" }) });
343
+ }
344
+ if (!validated.ok) return /* @__PURE__ */ jsxRuntime.jsx(ErrorCard, { message: validated.message });
345
+ const meta = {
346
+ name: parsed.value.widget,
347
+ version: parsed.value.version,
348
+ messageId,
349
+ streaming
350
+ };
351
+ return /* @__PURE__ */ jsxRuntime.jsx(Loaded, { data: validated.value, meta });
352
+ }
353
+ function createGenUIPlugin(registry) {
354
+ const GenUIWidgetComponent = (props) => {
355
+ const raw = React2__namespace.Children.toArray(props.children).filter((c) => typeof c === "string").join("");
356
+ return /* @__PURE__ */ jsxRuntime.jsx(GenUIBlock, { raw, registry });
357
+ };
358
+ return {
359
+ name: "genui",
360
+ rehypePlugins: [rehypeGenui],
361
+ components: {
362
+ [GENUI_TAG]: GenUIWidgetComponent
363
+ },
364
+ sanitizeSchema: {
365
+ tagNames: [GENUI_TAG]
366
+ }
367
+ };
368
+ }
369
+ var MERMAID_TAG = "mermaid-diagram";
370
+ function textOf2(node) {
371
+ if (node.type === "text") return node.value ?? "";
372
+ return (node.children ?? []).map(textOf2).join("");
373
+ }
374
+ function isMermaidPre(node) {
375
+ if (node.tagName !== "pre") return false;
376
+ const code = node.children?.find((c) => c.tagName === "code");
377
+ const className = code?.properties?.className;
378
+ const classes = Array.isArray(className) ? className : [className];
379
+ return classes.some(
380
+ (c) => typeof c === "string" && (c === "language-mermaid" || c === "mermaid")
381
+ );
382
+ }
383
+ function rehypeMermaid() {
384
+ return (tree) => {
385
+ const walk = (node) => {
386
+ if (!node.children) return;
387
+ node.children = node.children.map((child) => {
388
+ if (isMermaidPre(child)) {
389
+ const code = child.children?.find((c) => c.tagName === "code");
390
+ const raw = code ? textOf2(code) : "";
391
+ return {
392
+ type: "element",
393
+ tagName: MERMAID_TAG,
394
+ properties: {},
395
+ children: [{ type: "text", value: raw }]
396
+ };
397
+ }
398
+ walk(child);
399
+ return child;
400
+ });
401
+ };
402
+ walk(tree);
403
+ };
404
+ }
405
+ function PendingCard2({ label }) {
406
+ return /* @__PURE__ */ jsxRuntime.jsxs(
407
+ "div",
408
+ {
409
+ "data-slot": "superchat-mermaid-pending",
410
+ className: "my-2 flex items-center gap-2 rounded-lg border border-neutral-200 bg-neutral-50 px-3 py-2 text-sm text-neutral-600 dark:border-neutral-700 dark:bg-neutral-800/50 dark:text-neutral-300",
411
+ children: [
412
+ /* @__PURE__ */ jsxRuntime.jsx(
413
+ "span",
414
+ {
415
+ className: "h-3 w-3 animate-spin rounded-full border-2 border-neutral-400 border-t-transparent",
416
+ "aria-hidden": "true"
417
+ }
418
+ ),
419
+ label
420
+ ]
421
+ }
422
+ );
423
+ }
424
+ function InertFallback2({ raw }) {
425
+ return /* @__PURE__ */ jsxRuntime.jsx(
426
+ "pre",
427
+ {
428
+ "data-slot": "superchat-mermaid-fallback",
429
+ className: "my-2 overflow-x-auto rounded-lg bg-neutral-900 p-3 text-sm text-neutral-100 dark:bg-neutral-950",
430
+ children: /* @__PURE__ */ jsxRuntime.jsx("code", { children: raw })
431
+ }
432
+ );
433
+ }
434
+ var mermaidReady = null;
435
+ var mermaidTheme = null;
436
+ function loadMermaid(dark) {
437
+ const theme = dark ? "dark" : "default";
438
+ if (!mermaidReady || mermaidTheme !== theme) {
439
+ mermaidReady = (mermaidReady ?? import('mermaid').then(({ default: mermaid }) => mermaid)).then((mermaid) => {
440
+ mermaidTheme = theme;
441
+ mermaid.initialize({
442
+ startOnLoad: false,
443
+ securityLevel: "strict",
444
+ theme
445
+ });
446
+ return mermaid;
447
+ });
448
+ }
449
+ return mermaidReady;
450
+ }
451
+ var mermaidSeq = 0;
452
+ function MermaidDiagram({ code }) {
453
+ const { streaming } = chunkJFLC7SHM_cjs.useTextRenderContext();
454
+ const [svg, setSvg] = React2__namespace.useState(null);
455
+ const [failed, setFailed] = React2__namespace.useState(false);
456
+ const idRef = React2__namespace.useRef(`superchat-mermaid-${mermaidSeq += 1}`);
457
+ const source = code.trim();
458
+ React2__namespace.useEffect(() => {
459
+ if (streaming || !source) return;
460
+ let active = true;
461
+ setSvg(null);
462
+ setFailed(false);
463
+ const dark = typeof document !== "undefined" && document.documentElement.classList.contains("dark");
464
+ void loadMermaid(dark).then((mermaid) => mermaid.render(idRef.current, source)).then(({ svg: rendered }) => {
465
+ if (active) setSvg(rendered);
466
+ }).catch(() => {
467
+ if (active) setFailed(true);
468
+ });
469
+ return () => {
470
+ active = false;
471
+ };
472
+ }, [source, streaming]);
473
+ if (!source && !streaming) return /* @__PURE__ */ jsxRuntime.jsx(InertFallback2, { raw: code });
474
+ if (failed) return /* @__PURE__ */ jsxRuntime.jsx(InertFallback2, { raw: code });
475
+ if (streaming || svg === null) {
476
+ return /* @__PURE__ */ jsxRuntime.jsx(PendingCard2, { label: "Rendering diagram\u2026" });
477
+ }
478
+ return /* @__PURE__ */ jsxRuntime.jsx(
479
+ "div",
480
+ {
481
+ "data-slot": "superchat-mermaid",
482
+ className: "my-2 overflow-x-auto",
483
+ dangerouslySetInnerHTML: { __html: svg }
484
+ }
485
+ );
486
+ }
487
+ function createMermaidPlugin() {
488
+ const MermaidComponent = (props) => {
489
+ const raw = React2__namespace.Children.toArray(props.children).filter((c) => typeof c === "string").join("");
490
+ return /* @__PURE__ */ jsxRuntime.jsx(MermaidDiagram, { code: raw });
491
+ };
492
+ return {
493
+ name: "mermaid",
494
+ rehypePlugins: [rehypeMermaid],
495
+ components: {
496
+ [MERMAID_TAG]: MermaidComponent
497
+ },
498
+ sanitizeSchema: {
499
+ tagNames: [MERMAID_TAG]
500
+ }
501
+ };
502
+ }
503
+ function filenameFromUrl(url, alt) {
504
+ if (alt && alt.trim()) return alt.trim();
505
+ try {
506
+ const path = new URL(url, "http://localhost").pathname;
507
+ const last = path.split("/").filter(Boolean).pop();
508
+ return last || "image";
509
+ } catch {
510
+ return "image";
511
+ }
512
+ }
513
+ function ZoomableImage({
514
+ node: _node,
515
+ ...props
516
+ }) {
517
+ const [open, setOpen] = React2__namespace.useState(false);
518
+ const src = typeof props.src === "string" ? props.src : "";
519
+ const alt = typeof props.alt === "string" ? props.alt : "";
520
+ const attachment = React2__namespace.useMemo(() => {
521
+ if (!src) return null;
522
+ return {
523
+ id: src,
524
+ type: "image",
525
+ url: src,
526
+ filename: filenameFromUrl(src, alt),
527
+ size: 0,
528
+ mimeType: "image/*",
529
+ state: "uploaded",
530
+ alt
531
+ };
532
+ }, [src, alt]);
533
+ if (!src) return null;
534
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
535
+ /* @__PURE__ */ jsxRuntime.jsx(
536
+ "button",
537
+ {
538
+ type: "button",
539
+ onClick: () => setOpen(true),
540
+ "aria-label": alt ? `View image: ${alt}` : "View image",
541
+ className: "focus-visible:ring-primary-500 my-2 inline-block cursor-zoom-in rounded-lg focus-visible:ring-2 focus-visible:outline-none",
542
+ children: /* @__PURE__ */ jsxRuntime.jsx(
543
+ "img",
544
+ {
545
+ ...props,
546
+ alt,
547
+ className: chunkOR5DRJCW_cjs.cn(
548
+ "max-h-80 max-w-full rounded-lg object-contain",
549
+ props.className
550
+ )
551
+ }
552
+ )
553
+ }
554
+ ),
555
+ open && typeof document !== "undefined" && reactDom.createPortal(
556
+ /* @__PURE__ */ jsxRuntime.jsx(
557
+ chunkFADQVM4M_cjs.LightboxModal,
558
+ {
559
+ attachment,
560
+ onClose: () => setOpen(false)
561
+ }
562
+ ),
563
+ document.body
564
+ )
565
+ ] });
566
+ }
567
+ function createImagePlugin() {
568
+ return {
569
+ name: "image",
570
+ components: {
571
+ img: ZoomableImage
572
+ },
573
+ // Allow inline (`data:`) and object-URL (`blob:`) image sources in addition
574
+ // to the default http/https, so pasted/attached images render. These are
575
+ // safe for `<img>` (scripts in SVG loaded via `src` do not execute).
576
+ sanitizeSchema: {
577
+ protocols: { src: ["data", "blob"] }
578
+ }
579
+ };
580
+ }
581
+ var NitroTableGrid = React2__namespace.lazy(() => import('../../../nitroTableGrid-IY75TQJ2.cjs'));
582
+ function textOf3(node) {
583
+ if (node.type === "text") return node.value ?? "";
584
+ return (node.children ?? []).map(textOf3).join("");
585
+ }
586
+ function rowsOf(parent) {
587
+ return (parent?.children ?? []).filter((c) => c.tagName === "tr");
588
+ }
589
+ function cellsOf(row, tag) {
590
+ return (row.children ?? []).filter((c) => c.tagName === tag);
591
+ }
592
+ function parseTable(node) {
593
+ if (!node || node.tagName !== "table") return null;
594
+ const thead = node.children?.find((c) => c.tagName === "thead");
595
+ const tbody = node.children?.find((c) => c.tagName === "tbody");
596
+ const headerRow = rowsOf(thead)[0];
597
+ if (!headerRow) return null;
598
+ const headers = cellsOf(headerRow, "th").map((c) => textOf3(c).trim());
599
+ if (headers.length === 0) return null;
600
+ const seen = /* @__PURE__ */ new Map();
601
+ const keys = headers.map((h) => {
602
+ const base = h || "column";
603
+ const count = seen.get(base) ?? 0;
604
+ seen.set(base, count + 1);
605
+ return count === 0 ? base : `${base} (${count + 1})`;
606
+ });
607
+ const rows = rowsOf(tbody).map((tr) => {
608
+ const cells = cellsOf(tr, "td");
609
+ const row = {};
610
+ keys.forEach((key, i) => {
611
+ row[key] = cells[i] ? textOf3(cells[i]).trim() : "";
612
+ });
613
+ return row;
614
+ });
615
+ return { headers: keys, rows };
616
+ }
617
+ function HtmlTable({
618
+ node: _node,
619
+ ...props
620
+ }) {
621
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "my-2 overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsx(
622
+ "table",
623
+ {
624
+ ...props,
625
+ className: chunkOR5DRJCW_cjs.cn(
626
+ "w-full border-collapse text-sm [&_td]:border [&_td]:border-neutral-200 [&_td]:px-2 [&_td]:py-1 dark:[&_td]:border-neutral-700 [&_th]:border [&_th]:border-neutral-200 [&_th]:px-2 [&_th]:py-1 [&_th]:text-left dark:[&_th]:border-neutral-700",
627
+ props.className
628
+ )
629
+ }
630
+ ) });
631
+ }
632
+ var GridErrorBoundary = class extends React2__namespace.Component {
633
+ state = { failed: false };
634
+ static getDerivedStateFromError() {
635
+ return { failed: true };
636
+ }
637
+ render() {
638
+ if (this.state.failed) return this.props.fallback;
639
+ return this.props.children;
640
+ }
641
+ };
642
+ function createNitroTablePlugin() {
643
+ const NitroTable = (props) => {
644
+ const node = props.node;
645
+ const fallback = /* @__PURE__ */ jsxRuntime.jsx(
646
+ HtmlTable,
647
+ {
648
+ ...props
649
+ }
650
+ );
651
+ const parsed = React2__namespace.useMemo(() => parseTable(node), [node]);
652
+ if (!parsed) return fallback;
653
+ return /* @__PURE__ */ jsxRuntime.jsx(GridErrorBoundary, { fallback, children: /* @__PURE__ */ jsxRuntime.jsx(React2__namespace.Suspense, { fallback, children: /* @__PURE__ */ jsxRuntime.jsx(NitroTableGrid, { headers: parsed.headers, rows: parsed.rows }) }) });
654
+ };
655
+ return {
656
+ name: "nitro-table",
657
+ components: {
658
+ table: NitroTable
659
+ }
660
+ };
661
+ }
662
+
663
+ // src/components/SuperChat/render/attachmentCache.ts
664
+ var DB_NAME = "mieweb-superchat";
665
+ var STORE = "attachments";
666
+ var META_STORE = "attachments_meta";
667
+ var DB_VERSION = 2;
668
+ var DEFAULT_MAX_BYTES = 100 * 1024 * 1024;
669
+ var maxBytes = DEFAULT_MAX_BYTES;
670
+ function hasIndexedDB() {
671
+ return typeof window !== "undefined" && !!window.indexedDB;
672
+ }
673
+ function openDB() {
674
+ if (!hasIndexedDB()) return Promise.resolve(null);
675
+ return new Promise((resolve) => {
676
+ let req;
677
+ try {
678
+ req = window.indexedDB.open(DB_NAME, DB_VERSION);
679
+ } catch {
680
+ resolve(null);
681
+ return;
682
+ }
683
+ req.onupgradeneeded = () => {
684
+ const db = req.result;
685
+ if (!db.objectStoreNames.contains(STORE)) {
686
+ db.createObjectStore(STORE, { keyPath: "id" });
687
+ }
688
+ if (!db.objectStoreNames.contains(META_STORE)) {
689
+ db.createObjectStore(META_STORE, { keyPath: "id" });
690
+ }
691
+ };
692
+ req.onsuccess = () => resolve(req.result);
693
+ req.onerror = () => resolve(null);
694
+ });
695
+ }
696
+ function tx(db, mode) {
697
+ return db.transaction(STORE, mode).objectStore(STORE);
698
+ }
699
+ function readAllMeta(db) {
700
+ return new Promise((resolve) => {
701
+ try {
702
+ const req = db.transaction(META_STORE, "readonly").objectStore(META_STORE).getAll();
703
+ req.onsuccess = () => resolve(req.result ?? []);
704
+ req.onerror = () => resolve([]);
705
+ } catch {
706
+ resolve([]);
707
+ }
708
+ });
709
+ }
710
+ async function touch(id) {
711
+ const db = await openDB();
712
+ if (!db) return;
713
+ await new Promise((resolve) => {
714
+ try {
715
+ const store = db.transaction(META_STORE, "readwrite").objectStore(META_STORE);
716
+ const getReq = store.get(id);
717
+ getReq.onsuccess = () => {
718
+ const meta = getReq.result;
719
+ if (meta) {
720
+ meta.lastAccessed = Date.now();
721
+ store.put(meta);
722
+ }
723
+ resolve();
724
+ };
725
+ getReq.onerror = () => resolve();
726
+ } catch {
727
+ resolve();
728
+ } finally {
729
+ db.close();
730
+ }
731
+ });
732
+ }
733
+ async function prune() {
734
+ const db = await openDB();
735
+ if (!db) return;
736
+ try {
737
+ const metas = await readAllMeta(db);
738
+ let total = metas.reduce((sum, m) => sum + (m.size || 0), 0);
739
+ if (total <= maxBytes) return;
740
+ const byAge = metas.slice().sort((a, b) => (a.lastAccessed || 0) - (b.lastAccessed || 0));
741
+ const victims = [];
742
+ for (const meta of byAge) {
743
+ if (total <= maxBytes) break;
744
+ if (metas.length - victims.length <= 1) break;
745
+ victims.push(meta.id);
746
+ total -= meta.size || 0;
747
+ }
748
+ if (!victims.length) return;
749
+ await new Promise((resolve) => {
750
+ try {
751
+ const t = db.transaction([STORE, META_STORE], "readwrite");
752
+ const blobs = t.objectStore(STORE);
753
+ const meta = t.objectStore(META_STORE);
754
+ for (const id of victims) {
755
+ blobs.delete(id);
756
+ meta.delete(id);
757
+ }
758
+ t.oncomplete = () => resolve();
759
+ t.onerror = () => resolve();
760
+ } catch {
761
+ resolve();
762
+ }
763
+ });
764
+ } finally {
765
+ db.close();
766
+ }
767
+ }
768
+ function dataUrlToBlob(dataUrl) {
769
+ const match = /^data:([^;,]*)(;base64)?,([\s\S]*)$/.exec(dataUrl);
770
+ if (!match) return null;
771
+ const mime = match[1] || "application/octet-stream";
772
+ const isBase64 = Boolean(match[2]);
773
+ const data = match[3];
774
+ try {
775
+ if (isBase64) {
776
+ const binary = window.atob(data);
777
+ const bytes = new Uint8Array(binary.length);
778
+ for (let i = 0; i < binary.length; i += 1) {
779
+ bytes[i] = binary.charCodeAt(i);
780
+ }
781
+ return new window.Blob([bytes], { type: mime });
782
+ }
783
+ return new window.Blob([decodeURIComponent(data)], { type: mime });
784
+ } catch {
785
+ return null;
786
+ }
787
+ }
788
+ var attachmentCache = {
789
+ /** Whether a persistent IndexedDB store is available in this environment. */
790
+ isAvailable: hasIndexedDB,
791
+ /**
792
+ * Tune the cache. `maxBytes` is the eviction budget (default 100 MB); when a
793
+ * `put` pushes the total past it, least-recently-used entries are dropped
794
+ * until it fits. Set `Infinity` to disable eviction.
795
+ */
796
+ configure(options) {
797
+ if (typeof options.maxBytes === "number" && options.maxBytes >= 0) {
798
+ maxBytes = options.maxBytes;
799
+ }
800
+ },
801
+ /** Total bytes currently held by the cache (0 when unavailable). */
802
+ async usage() {
803
+ const db = await openDB();
804
+ if (!db) return 0;
805
+ try {
806
+ const metas = await readAllMeta(db);
807
+ return metas.reduce((sum, m) => sum + (m.size || 0), 0);
808
+ } finally {
809
+ db.close();
810
+ }
811
+ },
812
+ /**
813
+ * Persist an attachment's bytes by id. Pass a `blob` or a `dataUrl`. Resolves
814
+ * to `true` when stored, `false` if unavailable or the input was unusable.
815
+ * Writing past the configured `maxBytes` evicts least-recently-used entries.
816
+ */
817
+ async put(input) {
818
+ const db = await openDB();
819
+ if (!db) return false;
820
+ const blob = input.blob ?? (input.dataUrl ? dataUrlToBlob(input.dataUrl) : null);
821
+ if (!blob) {
822
+ db.close();
823
+ return false;
824
+ }
825
+ const now = Date.now();
826
+ const entry = {
827
+ id: input.id,
828
+ name: input.name,
829
+ type: input.type || blob.type || "application/octet-stream",
830
+ blob,
831
+ size: blob.size,
832
+ cachedAt: now,
833
+ lastAccessed: now
834
+ };
835
+ const stored = await new Promise((resolve) => {
836
+ try {
837
+ const t = db.transaction([STORE, META_STORE], "readwrite");
838
+ t.objectStore(STORE).put(entry);
839
+ t.objectStore(META_STORE).put({
840
+ id: entry.id,
841
+ size: entry.size,
842
+ lastAccessed: now
843
+ });
844
+ t.oncomplete = () => resolve(true);
845
+ t.onerror = () => resolve(false);
846
+ } catch {
847
+ resolve(false);
848
+ } finally {
849
+ db.close();
850
+ }
851
+ });
852
+ if (stored) await prune();
853
+ return stored;
854
+ },
855
+ /** Read a cached attachment (blob + metadata) by id, or `undefined`. */
856
+ async get(id) {
857
+ const db = await openDB();
858
+ if (!db) return void 0;
859
+ const entry = await new Promise((resolve) => {
860
+ try {
861
+ const req = tx(db, "readonly").get(id);
862
+ req.onsuccess = () => resolve(req.result ?? void 0);
863
+ req.onerror = () => resolve(void 0);
864
+ } catch {
865
+ resolve(void 0);
866
+ } finally {
867
+ db.close();
868
+ }
869
+ });
870
+ if (entry) void touch(id);
871
+ return entry;
872
+ },
873
+ /**
874
+ * Resolve a fresh `blob:` object URL for a cached attachment, or `undefined`
875
+ * if it isn't cached. **The caller owns the URL** and must
876
+ * `URL.revokeObjectURL` it when done (the {@link useAttachmentUrl} hook does
877
+ * this automatically).
878
+ */
879
+ async getObjectURL(id) {
880
+ const entry = await attachmentCache.get(id);
881
+ if (!entry) return void 0;
882
+ try {
883
+ return window.URL.createObjectURL(entry.blob);
884
+ } catch {
885
+ return void 0;
886
+ }
887
+ },
888
+ /** Remove a cached attachment by id. */
889
+ async delete(id) {
890
+ const db = await openDB();
891
+ if (!db) return;
892
+ await new Promise((resolve) => {
893
+ try {
894
+ const t = db.transaction([STORE, META_STORE], "readwrite");
895
+ t.objectStore(STORE).delete(id);
896
+ t.objectStore(META_STORE).delete(id);
897
+ t.oncomplete = () => resolve();
898
+ t.onerror = () => resolve();
899
+ } catch {
900
+ resolve();
901
+ } finally {
902
+ db.close();
903
+ }
904
+ });
905
+ },
906
+ /** Drop every cached attachment. */
907
+ async clear() {
908
+ const db = await openDB();
909
+ if (!db) return;
910
+ await new Promise((resolve) => {
911
+ try {
912
+ const t = db.transaction([STORE, META_STORE], "readwrite");
913
+ t.objectStore(STORE).clear();
914
+ t.objectStore(META_STORE).clear();
915
+ t.oncomplete = () => resolve();
916
+ t.onerror = () => resolve();
917
+ } catch {
918
+ resolve();
919
+ } finally {
920
+ db.close();
921
+ }
922
+ });
923
+ }
924
+ };
925
+ var ATTACHMENT_TAG = "superchat-attachment";
926
+ var ATTACHMENT_FENCE = "superchat-attachment";
927
+ function attachmentMarkdown(payload) {
928
+ return ["```superchat-attachment", JSON.stringify(payload), "```"].join("\n");
929
+ }
930
+ function useAttachmentUrl(id, fallbackSrc) {
931
+ const [url, setUrl] = React2__namespace.useState(void 0);
932
+ const [status, setStatus] = React2__namespace.useState("idle");
933
+ React2__namespace.useEffect(() => {
934
+ let active = true;
935
+ let created;
936
+ if (!id && !fallbackSrc) {
937
+ setUrl(void 0);
938
+ setStatus("idle");
939
+ return;
940
+ }
941
+ setStatus("loading");
942
+ void (async () => {
943
+ if (id) {
944
+ const cached = await attachmentCache.getObjectURL(id);
945
+ if (!active) {
946
+ if (cached) window.URL.revokeObjectURL(cached);
947
+ return;
948
+ }
949
+ if (cached) {
950
+ created = cached;
951
+ setUrl(cached);
952
+ setStatus("ready");
953
+ return;
954
+ }
955
+ }
956
+ if (!active) return;
957
+ setUrl(fallbackSrc);
958
+ setStatus(fallbackSrc ? "ready" : "missing");
959
+ })();
960
+ return () => {
961
+ active = false;
962
+ if (created) window.URL.revokeObjectURL(created);
963
+ };
964
+ }, [id, fallbackSrc]);
965
+ return { url, status };
966
+ }
967
+ var ICON_PROPS = {
968
+ width: 20,
969
+ height: 20,
970
+ viewBox: "0 0 24 24",
971
+ fill: "none",
972
+ stroke: "currentColor",
973
+ strokeWidth: 1.75,
974
+ strokeLinecap: "round",
975
+ strokeLinejoin: "round",
976
+ "aria-hidden": true
977
+ };
978
+ function FileGlyph() {
979
+ return /* @__PURE__ */ jsxRuntime.jsxs("svg", { ...ICON_PROPS, children: [
980
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M14 3v4a1 1 0 0 0 1 1h4" }),
981
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M17 21H7a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h7l5 5v11a2 2 0 0 1-2 2Z" })
982
+ ] });
983
+ }
984
+ function DownloadGlyph() {
985
+ return /* @__PURE__ */ jsxRuntime.jsxs("svg", { ...ICON_PROPS, width: 16, height: 16, children: [
986
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 3v12" }),
987
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m7 12 5 5 5-5" }),
988
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 21h14" })
989
+ ] });
990
+ }
991
+ function kindOf(type) {
992
+ if (type.startsWith("image/")) return "image";
993
+ if (type.startsWith("video/")) return "video";
994
+ if (type.startsWith("audio/")) return "audio";
995
+ if (type === "application/pdf") return "pdf";
996
+ return "file";
997
+ }
998
+ function FileChip({
999
+ name,
1000
+ url,
1001
+ unavailable
1002
+ }) {
1003
+ const content = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1004
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-neutral-500 dark:text-neutral-400", children: /* @__PURE__ */ jsxRuntime.jsx(FileGlyph, {}) }),
1005
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate text-sm", children: name }),
1006
+ url && !unavailable ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-neutral-400", children: /* @__PURE__ */ jsxRuntime.jsx(DownloadGlyph, {}) }) : null
1007
+ ] });
1008
+ const className = chunkOR5DRJCW_cjs.cn(
1009
+ "my-2 flex max-w-sm items-center gap-2 rounded-lg border border-neutral-200 bg-neutral-50 px-3 py-2 dark:border-neutral-700 dark:bg-neutral-800",
1010
+ unavailable && "opacity-60"
1011
+ );
1012
+ if (url && !unavailable) {
1013
+ return /* @__PURE__ */ jsxRuntime.jsx(
1014
+ "a",
1015
+ {
1016
+ href: url,
1017
+ download: name,
1018
+ target: "_blank",
1019
+ rel: "noopener noreferrer",
1020
+ title: name,
1021
+ className: chunkOR5DRJCW_cjs.cn(
1022
+ className,
1023
+ "hover:border-neutral-300 hover:bg-neutral-100 dark:hover:border-neutral-600 dark:hover:bg-neutral-700"
1024
+ ),
1025
+ children: content
1026
+ }
1027
+ );
1028
+ }
1029
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, title: name, children: [
1030
+ content,
1031
+ unavailable ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs whitespace-nowrap text-neutral-400", children: "unavailable offline" }) : null
1032
+ ] });
1033
+ }
1034
+ function AttachmentBlock({ payload }) {
1035
+ const { id, type, name, src } = payload;
1036
+ const { url, status } = useAttachmentUrl(id || void 0, src);
1037
+ const kind = kindOf(type);
1038
+ React2__namespace.useEffect(() => {
1039
+ if (!id || !src || !attachmentCache.isAvailable()) return;
1040
+ let active = true;
1041
+ void attachmentCache.get(id).then((existing) => {
1042
+ if (active && !existing) {
1043
+ void attachmentCache.put({ id, name, type, dataUrl: src });
1044
+ }
1045
+ });
1046
+ return () => {
1047
+ active = false;
1048
+ };
1049
+ }, [id, src, name, type]);
1050
+ if (status === "loading") {
1051
+ return /* @__PURE__ */ jsxRuntime.jsx(
1052
+ "div",
1053
+ {
1054
+ "data-slot": "superchat-attachment",
1055
+ className: "my-2 h-10 max-w-sm animate-pulse rounded-lg bg-neutral-100 dark:bg-neutral-800",
1056
+ "aria-label": `Loading ${name}`
1057
+ }
1058
+ );
1059
+ }
1060
+ if (!url) {
1061
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-slot": "superchat-attachment", children: /* @__PURE__ */ jsxRuntime.jsx(FileChip, { name, unavailable: true }) });
1062
+ }
1063
+ let body;
1064
+ switch (kind) {
1065
+ case "image":
1066
+ body = /* @__PURE__ */ jsxRuntime.jsx(
1067
+ "img",
1068
+ {
1069
+ src: url,
1070
+ alt: name,
1071
+ className: "max-h-80 max-w-full rounded-lg object-contain"
1072
+ }
1073
+ );
1074
+ break;
1075
+ case "video":
1076
+ body = /* @__PURE__ */ jsxRuntime.jsx(
1077
+ "video",
1078
+ {
1079
+ src: url,
1080
+ controls: true,
1081
+ className: "max-h-80 max-w-full rounded-lg bg-black",
1082
+ children: /* @__PURE__ */ jsxRuntime.jsx("track", { kind: "captions" })
1083
+ }
1084
+ );
1085
+ break;
1086
+ case "audio":
1087
+ body = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-sm", children: [
1088
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-1 truncate text-xs text-neutral-500 dark:text-neutral-400", children: name }),
1089
+ /* @__PURE__ */ jsxRuntime.jsx("audio", { src: url, controls: true, className: "w-full", children: /* @__PURE__ */ jsxRuntime.jsx("track", { kind: "captions" }) })
1090
+ ] });
1091
+ break;
1092
+ case "pdf":
1093
+ body = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-2xl overflow-hidden rounded-lg border border-neutral-200 dark:border-neutral-700", children: [
1094
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2 border-b border-neutral-200 bg-neutral-50 px-3 py-1.5 dark:border-neutral-700 dark:bg-neutral-800", children: [
1095
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-sm", title: name, children: name }),
1096
+ /* @__PURE__ */ jsxRuntime.jsxs(
1097
+ "a",
1098
+ {
1099
+ href: url,
1100
+ download: name,
1101
+ target: "_blank",
1102
+ rel: "noopener noreferrer",
1103
+ className: "text-primary-700 hover:text-primary-800 dark:text-primary-300 inline-flex items-center gap-1 text-xs whitespace-nowrap",
1104
+ children: [
1105
+ /* @__PURE__ */ jsxRuntime.jsx(DownloadGlyph, {}),
1106
+ "Open"
1107
+ ]
1108
+ }
1109
+ )
1110
+ ] }),
1111
+ /* @__PURE__ */ jsxRuntime.jsx("iframe", { src: url, title: name, className: "h-96 w-full bg-white" })
1112
+ ] });
1113
+ break;
1114
+ default:
1115
+ body = /* @__PURE__ */ jsxRuntime.jsx(FileChip, { name, url });
1116
+ }
1117
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-slot": "superchat-attachment", children: body });
1118
+ }
1119
+ function textOf4(node) {
1120
+ if (node.type === "text") return node.value ?? "";
1121
+ return (node.children ?? []).map(textOf4).join("");
1122
+ }
1123
+ function isAttachmentPre(node) {
1124
+ if (node.tagName !== "pre") return false;
1125
+ const code = node.children?.find((c) => c.tagName === "code");
1126
+ const className = code?.properties?.className;
1127
+ const classes = Array.isArray(className) ? className : [className];
1128
+ return classes.some(
1129
+ (c) => typeof c === "string" && (c === `language-${ATTACHMENT_FENCE}` || c === ATTACHMENT_FENCE)
1130
+ );
1131
+ }
1132
+ function rehypeAttachment() {
1133
+ return (tree) => {
1134
+ const walk = (node) => {
1135
+ if (!node.children) return;
1136
+ node.children = node.children.map((child) => {
1137
+ if (isAttachmentPre(child)) {
1138
+ const code = child.children?.find((c) => c.tagName === "code");
1139
+ const raw = code ? textOf4(code) : "";
1140
+ return {
1141
+ type: "element",
1142
+ tagName: ATTACHMENT_TAG,
1143
+ properties: {},
1144
+ children: [{ type: "text", value: raw }]
1145
+ };
1146
+ }
1147
+ walk(child);
1148
+ return child;
1149
+ });
1150
+ };
1151
+ walk(tree);
1152
+ };
1153
+ }
1154
+ function childText(children) {
1155
+ return React2__namespace.Children.toArray(children).map((c) => typeof c === "string" ? c : "").join("");
1156
+ }
1157
+ function sanitizeSrc(src) {
1158
+ if (!src) return void 0;
1159
+ if (/^(?:blob:|https?:\/\/)/i.test(src)) return src;
1160
+ const dataMatch = /^data:([\w.+-]+\/[\w.+-]+)?[;,]/i.exec(src);
1161
+ if (dataMatch) {
1162
+ const mime = (dataMatch[1] ?? "text/plain").toLowerCase();
1163
+ const EXECUTABLE_MIME = /^(?:text\/html|application\/xhtml\+xml|image\/svg\+xml|text\/xml|application\/xml)$/;
1164
+ return EXECUTABLE_MIME.test(mime) ? void 0 : src;
1165
+ }
1166
+ return void 0;
1167
+ }
1168
+ function parsePayload2(raw) {
1169
+ try {
1170
+ const parsed = JSON.parse(raw);
1171
+ if (!parsed || typeof parsed.type !== "string") return null;
1172
+ const src = typeof parsed.src === "string" ? sanitizeSrc(parsed.src) : void 0;
1173
+ if (!parsed.id && !src) return null;
1174
+ return {
1175
+ id: typeof parsed.id === "string" ? parsed.id : void 0,
1176
+ type: parsed.type,
1177
+ name: typeof parsed.name === "string" ? parsed.name : "attachment",
1178
+ src
1179
+ };
1180
+ } catch {
1181
+ return null;
1182
+ }
1183
+ }
1184
+ function AttachmentElement({
1185
+ node: _node,
1186
+ children
1187
+ }) {
1188
+ const payload = parsePayload2(childText(children));
1189
+ if (!payload) return null;
1190
+ return /* @__PURE__ */ jsxRuntime.jsx(AttachmentBlock, { payload });
1191
+ }
1192
+ function createAttachmentPlugin() {
1193
+ return {
1194
+ name: "attachment",
1195
+ rehypePlugins: [rehypeAttachment],
1196
+ components: {
1197
+ [ATTACHMENT_TAG]: AttachmentElement
1198
+ },
1199
+ // The payload rides as a text child; only the custom tag needs allow-listing.
1200
+ sanitizeSchema: {
1201
+ tagNames: [ATTACHMENT_TAG]
1202
+ }
1203
+ };
1204
+ }
1205
+
1206
+ exports.ATTACHMENT_FENCE = ATTACHMENT_FENCE;
1207
+ exports.ATTACHMENT_TAG = ATTACHMENT_TAG;
1208
+ exports.GENUI_TAG = GENUI_TAG;
1209
+ exports.MERMAID_TAG = MERMAID_TAG;
1210
+ exports.attachmentCache = attachmentCache;
1211
+ exports.attachmentMarkdown = attachmentMarkdown;
1212
+ exports.createAttachmentPlugin = createAttachmentPlugin;
1213
+ exports.createCodePlugin = createCodePlugin;
1214
+ exports.createGenUIPlugin = createGenUIPlugin;
1215
+ exports.createImagePlugin = createImagePlugin;
1216
+ exports.createMathPlugin = createMathPlugin;
1217
+ exports.createMermaidPlugin = createMermaidPlugin;
1218
+ exports.createNitroTablePlugin = createNitroTablePlugin;
1219
+ exports.useAttachmentUrl = useAttachmentUrl;
1220
+ //# sourceMappingURL=index.cjs.map
1221
+ //# sourceMappingURL=index.cjs.map