@kat-ai/react 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,956 @@
1
+ // src/citations/CitationDialog.tsx
2
+ import { useState, useEffect } from "react";
3
+ import ReactMarkdown from "react-markdown";
4
+ import remarkMath from "remark-math";
5
+ import rehypeKatex from "rehype-katex";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ function extractPageFromUrl(url) {
8
+ if (!url) return null;
9
+ try {
10
+ const parsed = new URL(url, typeof window !== "undefined" ? window.location.origin : "http://localhost");
11
+ const searchPage = parsed.searchParams.get("page");
12
+ const hashPart = url.split("#")[1];
13
+ const hashParams = new URLSearchParams(hashPart?.replace(/^\?/, "") || "");
14
+ const hashPage = hashParams.get("page");
15
+ const candidate = hashPage || searchPage;
16
+ if (candidate) {
17
+ const num = Number.parseInt(candidate, 10);
18
+ return Number.isFinite(num) && num > 0 ? num : null;
19
+ }
20
+ } catch {
21
+ }
22
+ return null;
23
+ }
24
+ function parseCitationMeta(url) {
25
+ if (!url) return null;
26
+ try {
27
+ const hashPart = url.split("#")[1];
28
+ const hashParams = new URLSearchParams(hashPart?.replace(/^\?/, "") || "");
29
+ const metaRaw = hashParams.get("meta");
30
+ if (!metaRaw) return null;
31
+ const parsed = JSON.parse(metaRaw);
32
+ return parsed;
33
+ } catch {
34
+ return null;
35
+ }
36
+ }
37
+ function CitationDialog({ url, isOpen, onClose, citation }) {
38
+ const [content, setContent] = useState("");
39
+ const [pdfUrl, setPdfUrl] = useState(null);
40
+ const [isPdf, setIsPdf] = useState(false);
41
+ const [pageNumber, setPageNumber] = useState(null);
42
+ const [citationMeta, setCitationMeta] = useState(null);
43
+ const [loading, setLoading] = useState(false);
44
+ const [error, setError] = useState(null);
45
+ useEffect(() => {
46
+ if (isOpen && (url || citation)) {
47
+ let cancelled = false;
48
+ const loadCitation = async () => {
49
+ setLoading(true);
50
+ setError(null);
51
+ setContent("");
52
+ setPdfUrl(null);
53
+ setIsPdf(false);
54
+ setPageNumber(null);
55
+ if (citation) {
56
+ const meta2 = {
57
+ label: citation.label,
58
+ source: citation.referenceSummary,
59
+ fileName: citation.fileName,
60
+ preview: citation.preview,
61
+ // Map other fields if available in reference metadata
62
+ ...citation.reference?.file?.metadata || {}
63
+ };
64
+ setCitationMeta(meta2);
65
+ if (citation.content) {
66
+ setContent(citation.content);
67
+ setLoading(false);
68
+ return;
69
+ }
70
+ }
71
+ const targetUrl = url || citation?.reference?.file?.signedUrl || citation?.reference?.file?.signed_url;
72
+ if (!targetUrl) {
73
+ if (citation?.content) {
74
+ setContent(citation.content);
75
+ setLoading(false);
76
+ } else {
77
+ setError("No content or URL available");
78
+ setLoading(false);
79
+ }
80
+ return;
81
+ }
82
+ const meta = parseCitationMeta(targetUrl);
83
+ if (!citationMeta) {
84
+ setCitationMeta(meta);
85
+ }
86
+ const [baseUrl, hashFragment] = targetUrl.split("#");
87
+ const fragment = hashFragment ? `#${hashFragment}` : "";
88
+ const apiUrlBase = baseUrl.startsWith("/api/citation") ? baseUrl : `/api/citation?url=${encodeURIComponent(baseUrl)}`;
89
+ const apiUrlWithFragment = `${apiUrlBase}${fragment}`;
90
+ const derivedPage = extractPageFromUrl(apiUrlWithFragment) ?? meta?.page ?? null;
91
+ setPageNumber(derivedPage);
92
+ let urlToCheck = baseUrl.toLowerCase();
93
+ try {
94
+ let decoded = urlToCheck;
95
+ for (let i = 0; i < 3; i++) {
96
+ const newDecoded = decodeURIComponent(decoded);
97
+ if (newDecoded === decoded) break;
98
+ decoded = newDecoded;
99
+ }
100
+ urlToCheck = decoded;
101
+ } catch {
102
+ }
103
+ const looksLikePdf = urlToCheck.includes(".pdf") || urlToCheck.includes("content-type=application/pdf") || urlToCheck.includes("application/pdf") || targetUrl.toLowerCase().includes("pdf") || citation?.contentType === "application/pdf";
104
+ if (looksLikePdf) {
105
+ if (!cancelled) {
106
+ setPdfUrl(apiUrlWithFragment);
107
+ setIsPdf(true);
108
+ setPageNumber(derivedPage);
109
+ setLoading(false);
110
+ }
111
+ return;
112
+ }
113
+ try {
114
+ const res = await fetch(apiUrlBase);
115
+ if (!res.ok) {
116
+ const errorData = await res.json().catch(() => ({ error: res.statusText }));
117
+ throw new Error(errorData.error || `Failed to fetch: ${res.status} ${res.statusText}`);
118
+ }
119
+ const contentType = res.headers.get("content-type") || "";
120
+ if (contentType.includes("application/pdf")) {
121
+ if (!cancelled) {
122
+ setPdfUrl(apiUrlWithFragment);
123
+ setIsPdf(true);
124
+ setPageNumber(derivedPage);
125
+ }
126
+ return;
127
+ }
128
+ const text = await res.text();
129
+ if (!cancelled) {
130
+ setContent(text);
131
+ }
132
+ } catch (err) {
133
+ console.error("Error fetching citation content:", err);
134
+ if (!cancelled) {
135
+ setError(err instanceof Error ? err.message : "Failed to load content");
136
+ }
137
+ } finally {
138
+ if (!cancelled) {
139
+ setLoading(false);
140
+ }
141
+ }
142
+ };
143
+ loadCitation();
144
+ return () => {
145
+ cancelled = true;
146
+ };
147
+ } else {
148
+ setContent("");
149
+ setError(null);
150
+ setPdfUrl(null);
151
+ setIsPdf(false);
152
+ setPageNumber(null);
153
+ setCitationMeta(null);
154
+ setLoading(false);
155
+ }
156
+ }, [isOpen, url, citation]);
157
+ useEffect(() => {
158
+ const handleEscape = (e) => {
159
+ if (e.key === "Escape" && isOpen) {
160
+ onClose();
161
+ }
162
+ };
163
+ if (isOpen) {
164
+ document.addEventListener("keydown", handleEscape);
165
+ document.body.style.overflow = "hidden";
166
+ }
167
+ return () => {
168
+ document.removeEventListener("keydown", handleEscape);
169
+ document.body.style.overflow = "unset";
170
+ };
171
+ }, [isOpen, onClose]);
172
+ const renderCitationInfo = () => {
173
+ if (!citationMeta && !pageNumber) return null;
174
+ const meta = citationMeta || {};
175
+ const infoItems = [
176
+ { label: "Page", value: pageNumber ?? meta.page ?? "Not provided" },
177
+ { label: "Label", value: meta.label },
178
+ { label: "Source", value: meta.source },
179
+ { label: "File", value: meta.fileName },
180
+ { label: "Row ID", value: meta.rowId },
181
+ { label: "Category", value: meta.category },
182
+ { label: "Source Type", value: meta.sourceType }
183
+ ].filter((item) => item.value !== void 0 && item.value !== null && item.value !== "");
184
+ return /* @__PURE__ */ jsx("div", { style: {
185
+ padding: "12px 14px",
186
+ backgroundColor: "#1a1a1a",
187
+ border: "1px solid #2a2a2a",
188
+ borderRadius: "8px",
189
+ color: "#d0d0d0",
190
+ fontSize: "14px",
191
+ lineHeight: "1.6"
192
+ }, children: /* @__PURE__ */ jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: "10px", alignItems: "center" }, children: infoItems.map((item) => /* @__PURE__ */ jsxs("span", { style: {
193
+ padding: "6px 10px",
194
+ borderRadius: "6px",
195
+ backgroundColor: "#0f172a",
196
+ color: "#7dd3fc",
197
+ border: "1px solid #1f2937",
198
+ fontWeight: 600,
199
+ fontSize: "13px"
200
+ }, children: [
201
+ item.label,
202
+ ": ",
203
+ String(item.value)
204
+ ] }, item.label)) }) });
205
+ };
206
+ if (!isOpen) return null;
207
+ return /* @__PURE__ */ jsxs(
208
+ "div",
209
+ {
210
+ style: {
211
+ position: "fixed",
212
+ top: 0,
213
+ left: 0,
214
+ right: 0,
215
+ bottom: 0,
216
+ backgroundColor: "rgba(0, 0, 0, 0.8)",
217
+ backdropFilter: "blur(8px)",
218
+ zIndex: 1e3,
219
+ display: "flex",
220
+ alignItems: "center",
221
+ justifyContent: "center",
222
+ padding: "16px",
223
+ animation: "fadeIn 0.2s ease-out"
224
+ },
225
+ onClick: (e) => {
226
+ if (e.target === e.currentTarget) {
227
+ onClose();
228
+ }
229
+ },
230
+ children: [
231
+ /* @__PURE__ */ jsx("style", { children: `
232
+ @keyframes fadeIn {
233
+ from {
234
+ opacity: 0;
235
+ }
236
+ to {
237
+ opacity: 1;
238
+ }
239
+ }
240
+ @keyframes slideUp {
241
+ from {
242
+ opacity: 0;
243
+ transform: translateY(20px);
244
+ }
245
+ to {
246
+ opacity: 1;
247
+ transform: translateY(0);
248
+ }
249
+ }
250
+ @keyframes spin {
251
+ to {
252
+ transform: rotate(360deg);
253
+ }
254
+ }
255
+ .citation-dialog-scrollbar::-webkit-scrollbar {
256
+ width: 8px;
257
+ }
258
+ .citation-dialog-scrollbar::-webkit-scrollbar-track {
259
+ background: #111111;
260
+ border-radius: 4px;
261
+ }
262
+ .citation-dialog-scrollbar::-webkit-scrollbar-thumb {
263
+ background: #1a1a1a;
264
+ border-radius: 4px;
265
+ }
266
+ .citation-dialog-scrollbar::-webkit-scrollbar-thumb:hover {
267
+ background: #2a2a2a;
268
+ }
269
+ ` }),
270
+ /* @__PURE__ */ jsxs(
271
+ "div",
272
+ {
273
+ style: {
274
+ backgroundColor: "#111111",
275
+ borderRadius: "12px",
276
+ border: "1px solid #1a1a1a",
277
+ width: "100%",
278
+ maxWidth: "950px",
279
+ maxHeight: "92vh",
280
+ display: "flex",
281
+ flexDirection: "column",
282
+ boxShadow: "0 20px 60px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255, 255, 255, 0.05)",
283
+ animation: "slideUp 0.3s ease-out",
284
+ overflow: "hidden"
285
+ },
286
+ onClick: (e) => e.stopPropagation(),
287
+ children: [
288
+ /* @__PURE__ */ jsxs(
289
+ "div",
290
+ {
291
+ style: {
292
+ padding: "20px 28px",
293
+ borderBottom: "1px solid #1a1a1a",
294
+ display: "flex",
295
+ alignItems: "center",
296
+ justifyContent: "space-between",
297
+ background: "linear-gradient(to bottom, #111111, #0a0a0a)"
298
+ },
299
+ children: [
300
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "12px" }, children: [
301
+ /* @__PURE__ */ jsx(
302
+ "div",
303
+ {
304
+ style: {
305
+ width: "36px",
306
+ height: "36px",
307
+ borderRadius: "8px",
308
+ background: "linear-gradient(135deg, #0070f3 0%, #0051cc 100%)",
309
+ display: "flex",
310
+ alignItems: "center",
311
+ justifyContent: "center",
312
+ fontSize: "18px",
313
+ boxShadow: "0 2px 8px rgba(0, 112, 243, 0.3)"
314
+ },
315
+ children: "\u{1F4C4}"
316
+ }
317
+ ),
318
+ /* @__PURE__ */ jsxs("div", { children: [
319
+ /* @__PURE__ */ jsx("h2", { style: {
320
+ color: "#ffffff",
321
+ margin: 0,
322
+ fontSize: "20px",
323
+ fontWeight: "600",
324
+ letterSpacing: "-0.01em",
325
+ lineHeight: "1.2"
326
+ }, children: "Source Document" }),
327
+ /* @__PURE__ */ jsx("div", { style: {
328
+ fontSize: "13px",
329
+ color: "#888888",
330
+ marginTop: "4px",
331
+ fontWeight: "400"
332
+ }, children: "Reference information" })
333
+ ] })
334
+ ] }),
335
+ /* @__PURE__ */ jsx(
336
+ "button",
337
+ {
338
+ onClick: onClose,
339
+ style: {
340
+ background: "transparent",
341
+ border: "1px solid #1a1a1a",
342
+ color: "#888888",
343
+ fontSize: "20px",
344
+ cursor: "pointer",
345
+ padding: "8px",
346
+ lineHeight: 1,
347
+ borderRadius: "6px",
348
+ transition: "all 0.2s ease",
349
+ width: "36px",
350
+ height: "36px",
351
+ display: "flex",
352
+ alignItems: "center",
353
+ justifyContent: "center"
354
+ },
355
+ onMouseEnter: (e) => {
356
+ e.currentTarget.style.backgroundColor = "#1a1a1a";
357
+ e.currentTarget.style.borderColor = "#2a2a2a";
358
+ e.currentTarget.style.color = "#ffffff";
359
+ },
360
+ onMouseLeave: (e) => {
361
+ e.currentTarget.style.backgroundColor = "transparent";
362
+ e.currentTarget.style.borderColor = "#1a1a1a";
363
+ e.currentTarget.style.color = "#888888";
364
+ },
365
+ "aria-label": "Close dialog",
366
+ children: "\xD7"
367
+ }
368
+ )
369
+ ]
370
+ }
371
+ ),
372
+ /* @__PURE__ */ jsxs(
373
+ "div",
374
+ {
375
+ className: "citation-dialog-scrollbar",
376
+ style: {
377
+ flex: 1,
378
+ overflowY: "auto",
379
+ padding: "24px",
380
+ color: "#ffffff",
381
+ background: "#111111"
382
+ },
383
+ children: [
384
+ loading && /* @__PURE__ */ jsxs("div", { style: {
385
+ textAlign: "center",
386
+ padding: "4rem 2rem",
387
+ display: "flex",
388
+ flexDirection: "column",
389
+ alignItems: "center",
390
+ gap: "1rem"
391
+ }, children: [
392
+ /* @__PURE__ */ jsx(
393
+ "div",
394
+ {
395
+ style: {
396
+ width: "40px",
397
+ height: "40px",
398
+ border: "3px solid #2a2a2a",
399
+ borderTopColor: "#4a9eff",
400
+ borderRadius: "50%",
401
+ animation: "spin 0.8s linear infinite"
402
+ }
403
+ }
404
+ ),
405
+ /* @__PURE__ */ jsx("div", { style: {
406
+ color: "#a0a0a0",
407
+ fontSize: "0.95rem",
408
+ fontWeight: "500"
409
+ }, children: "Loading document..." })
410
+ ] }),
411
+ error && /* @__PURE__ */ jsxs(
412
+ "div",
413
+ {
414
+ style: {
415
+ padding: "1.25rem 1.5rem",
416
+ backgroundColor: "#2a1a1a",
417
+ borderRadius: "8px",
418
+ color: "#ff6b6b",
419
+ border: "1px solid #4a2a2a",
420
+ display: "flex",
421
+ alignItems: "flex-start",
422
+ gap: "0.75rem"
423
+ },
424
+ children: [
425
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "1.25rem" }, children: "\u26A0\uFE0F" }),
426
+ /* @__PURE__ */ jsxs("div", { children: [
427
+ /* @__PURE__ */ jsx("strong", { style: { display: "block", marginBottom: "0.25rem", fontSize: "0.95rem" }, children: "Error loading document" }),
428
+ /* @__PURE__ */ jsx("div", { style: { fontSize: "0.875rem", color: "#ff9999" }, children: error })
429
+ ] })
430
+ ]
431
+ }
432
+ ),
433
+ !loading && !error && isPdf && pdfUrl && /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "16px" }, children: [
434
+ renderCitationInfo(),
435
+ /* @__PURE__ */ jsx("div", { style: {
436
+ borderRadius: "8px",
437
+ overflow: "hidden",
438
+ border: "1px solid #1a1a1a",
439
+ backgroundColor: "#0a0a0a",
440
+ minHeight: "60vh"
441
+ }, children: /* @__PURE__ */ jsx(
442
+ "object",
443
+ {
444
+ data: pdfUrl,
445
+ type: "application/pdf",
446
+ width: "100%",
447
+ height: "100%",
448
+ "aria-label": "PDF viewer",
449
+ style: { display: "block", minHeight: "70vh" },
450
+ children: /* @__PURE__ */ jsx(
451
+ "iframe",
452
+ {
453
+ src: pdfUrl,
454
+ title: "PDF viewer",
455
+ style: { width: "100%", height: "70vh", border: "none" }
456
+ }
457
+ )
458
+ }
459
+ ) }),
460
+ /* @__PURE__ */ jsxs("div", { style: {
461
+ display: "flex",
462
+ alignItems: "center",
463
+ justifyContent: "space-between",
464
+ gap: "12px",
465
+ flexWrap: "wrap"
466
+ }, children: [
467
+ /* @__PURE__ */ jsx("div", { style: { color: "#888888", fontSize: "13px" }, children: "Prefer a new tab? Open the PDF directly." }),
468
+ /* @__PURE__ */ jsx(
469
+ "button",
470
+ {
471
+ onClick: () => window.open(pdfUrl, "_blank", "noopener,noreferrer"),
472
+ style: {
473
+ display: "flex",
474
+ alignItems: "center",
475
+ gap: "8px",
476
+ padding: "10px 16px",
477
+ backgroundColor: "#0070f3",
478
+ color: "#ffffff",
479
+ border: "none",
480
+ borderRadius: "6px",
481
+ fontSize: "14px",
482
+ fontWeight: "600",
483
+ cursor: "pointer",
484
+ transition: "all 0.2s ease"
485
+ },
486
+ onMouseEnter: (e) => {
487
+ e.currentTarget.style.backgroundColor = "#0051cc";
488
+ e.currentTarget.style.transform = "translateY(-1px)";
489
+ },
490
+ onMouseLeave: (e) => {
491
+ e.currentTarget.style.backgroundColor = "#0070f3";
492
+ e.currentTarget.style.transform = "translateY(0)";
493
+ },
494
+ children: /* @__PURE__ */ jsx("span", { children: "Open in new tab" })
495
+ }
496
+ )
497
+ ] })
498
+ ] }),
499
+ !loading && !error && !isPdf && content && /* @__PURE__ */ jsxs("div", { style: {
500
+ maxWidth: "800px",
501
+ margin: "0 auto"
502
+ }, children: [
503
+ /* @__PURE__ */ jsx("div", { style: { marginBottom: "16px" }, children: renderCitationInfo() }),
504
+ /* @__PURE__ */ jsx(
505
+ ReactMarkdown,
506
+ {
507
+ remarkPlugins: [remarkMath],
508
+ rehypePlugins: [rehypeKatex],
509
+ components: {
510
+ p: ({ children }) => /* @__PURE__ */ jsx("p", { style: {
511
+ marginBottom: "1.25rem",
512
+ marginTop: 0,
513
+ lineHeight: "1.75",
514
+ color: "#d0d0d0",
515
+ fontSize: "0.95rem"
516
+ }, children }),
517
+ h1: ({ children }) => /* @__PURE__ */ jsx("h1", { style: {
518
+ fontSize: "2rem",
519
+ fontWeight: "700",
520
+ marginBottom: "1.25rem",
521
+ marginTop: "0",
522
+ color: "#fff",
523
+ borderBottom: "2px solid #2a2a2a",
524
+ paddingBottom: "0.75rem",
525
+ letterSpacing: "-0.02em",
526
+ lineHeight: "1.3"
527
+ }, children }),
528
+ h2: ({ children }) => /* @__PURE__ */ jsx("h2", { style: {
529
+ fontSize: "1.5rem",
530
+ fontWeight: "600",
531
+ marginBottom: "1rem",
532
+ marginTop: "1.75rem",
533
+ color: "#fff",
534
+ letterSpacing: "-0.01em",
535
+ lineHeight: "1.4"
536
+ }, children }),
537
+ h3: ({ children }) => /* @__PURE__ */ jsx("h3", { style: {
538
+ fontSize: "1.25rem",
539
+ fontWeight: "600",
540
+ marginBottom: "0.75rem",
541
+ marginTop: "1.5rem",
542
+ color: "#f0f0f0",
543
+ lineHeight: "1.4"
544
+ }, children }),
545
+ h4: ({ children }) => /* @__PURE__ */ jsx("h4", { style: {
546
+ fontSize: "1.1rem",
547
+ fontWeight: "600",
548
+ marginBottom: "0.75rem",
549
+ marginTop: "1.25rem",
550
+ color: "#f0f0f0",
551
+ lineHeight: "1.4"
552
+ }, children }),
553
+ strong: ({ children }) => /* @__PURE__ */ jsx("strong", { style: {
554
+ fontWeight: "600",
555
+ color: "#fff"
556
+ }, children }),
557
+ em: ({ children }) => /* @__PURE__ */ jsx("em", { style: {
558
+ fontStyle: "italic",
559
+ color: "#d0d0d0"
560
+ }, children }),
561
+ ul: ({ children }) => /* @__PURE__ */ jsx("ul", { style: {
562
+ marginBottom: "1.25rem",
563
+ paddingLeft: "1.75rem",
564
+ listStyleType: "disc",
565
+ lineHeight: "1.75"
566
+ }, children }),
567
+ ol: ({ children }) => /* @__PURE__ */ jsx("ol", { style: {
568
+ marginBottom: "1.25rem",
569
+ paddingLeft: "1.75rem",
570
+ listStyleType: "decimal",
571
+ lineHeight: "1.75"
572
+ }, children }),
573
+ li: ({ children }) => /* @__PURE__ */ jsx("li", { style: {
574
+ marginBottom: "0.5rem",
575
+ lineHeight: "1.75",
576
+ color: "#d0d0d0",
577
+ paddingLeft: "0.25rem"
578
+ }, children }),
579
+ code: ({ children }) => /* @__PURE__ */ jsx("code", { style: {
580
+ backgroundColor: "#0f0f0f",
581
+ padding: "0.2rem 0.5rem",
582
+ borderRadius: "4px",
583
+ fontSize: "0.875em",
584
+ fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace',
585
+ color: "#a0e0a0",
586
+ border: "1px solid #1a1a1a"
587
+ }, children }),
588
+ pre: ({ children }) => /* @__PURE__ */ jsx("pre", { style: {
589
+ backgroundColor: "#0f0f0f",
590
+ padding: "1.25rem",
591
+ borderRadius: "8px",
592
+ overflow: "auto",
593
+ marginBottom: "1.25rem",
594
+ border: "1px solid #2a2a2a",
595
+ fontSize: "0.875rem",
596
+ lineHeight: "1.6"
597
+ }, children }),
598
+ blockquote: ({ children }) => /* @__PURE__ */ jsx("blockquote", { style: {
599
+ borderLeft: "4px solid #4a9eff",
600
+ paddingLeft: "1.25rem",
601
+ marginLeft: 0,
602
+ marginBottom: "1.25rem",
603
+ color: "#c0c0c0",
604
+ fontStyle: "italic",
605
+ backgroundColor: "#1f1f1f",
606
+ padding: "1rem 1.25rem",
607
+ borderRadius: "0 6px 6px 0"
608
+ }, children }),
609
+ a: ({ href, children }) => /* @__PURE__ */ jsx(
610
+ "a",
611
+ {
612
+ href,
613
+ target: "_blank",
614
+ rel: "noopener noreferrer",
615
+ style: {
616
+ color: "#4a9eff",
617
+ textDecoration: "none",
618
+ borderBottom: "1px solid rgba(74, 158, 255, 0.3)",
619
+ transition: "all 0.2s"
620
+ },
621
+ onMouseEnter: (e) => {
622
+ e.currentTarget.style.color = "#6bb0ff";
623
+ e.currentTarget.style.borderBottomColor = "rgba(107, 176, 255, 0.6)";
624
+ },
625
+ onMouseLeave: (e) => {
626
+ e.currentTarget.style.color = "#4a9eff";
627
+ e.currentTarget.style.borderBottomColor = "rgba(74, 158, 255, 0.3)";
628
+ },
629
+ children
630
+ }
631
+ ),
632
+ table: ({ children }) => /* @__PURE__ */ jsx("div", { style: {
633
+ overflowX: "auto",
634
+ marginBottom: "1.25rem"
635
+ }, children: /* @__PURE__ */ jsx("table", { style: {
636
+ width: "100%",
637
+ borderCollapse: "collapse"
638
+ }, children }) }),
639
+ th: ({ children }) => /* @__PURE__ */ jsx("th", { style: {
640
+ border: "1px solid #2a2a2a",
641
+ padding: "0.75rem",
642
+ backgroundColor: "#1f1f1f",
643
+ textAlign: "left",
644
+ fontWeight: "600",
645
+ color: "#fff",
646
+ fontSize: "0.9rem"
647
+ }, children }),
648
+ td: ({ children }) => /* @__PURE__ */ jsx("td", { style: {
649
+ border: "1px solid #2a2a2a",
650
+ padding: "0.75rem",
651
+ color: "#d0d0d0",
652
+ fontSize: "0.9rem"
653
+ }, children }),
654
+ hr: () => /* @__PURE__ */ jsx("hr", { style: {
655
+ border: "none",
656
+ borderTop: "1px solid #2a2a2a",
657
+ margin: "2rem 0"
658
+ } })
659
+ },
660
+ children: content
661
+ }
662
+ )
663
+ ] })
664
+ ]
665
+ }
666
+ )
667
+ ]
668
+ }
669
+ )
670
+ ]
671
+ }
672
+ );
673
+ }
674
+
675
+ // src/citations/CitationDisplay.tsx
676
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
677
+ function stripMarkdown(text) {
678
+ if (!text) return "";
679
+ return text.replace(/^#+\s*/gm, "").replace(/\*\*([^*]+)\*\*/g, "$1").replace(/__([^_]+)__/g, "$1").replace(/\*([^*]+)\*/g, "$1").replace(/_([^_]+)_/g, "$1").replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/`{1,3}[^`]*`{1,3}/g, "").replace(/\s+/g, " ").trim();
680
+ }
681
+ function formatReferenceSummary(summary, maxLength) {
682
+ if (!summary) return "";
683
+ const cleaned = stripMarkdown(summary);
684
+ if (cleaned.length <= maxLength) {
685
+ return cleaned;
686
+ }
687
+ return cleaned.substring(0, maxLength - 3) + "...";
688
+ }
689
+ function CitationDisplay({
690
+ citations,
691
+ onCitationClick,
692
+ chipColor = "#2a1a3a",
693
+ borderColor = "#4a2a5a",
694
+ maxSummaryLength = 40
695
+ }) {
696
+ if (!citations || citations.length === 0) {
697
+ return null;
698
+ }
699
+ return /* @__PURE__ */ jsx2("div", { style: { display: "flex", flexWrap: "wrap", gap: "0.35rem", marginTop: "0.5rem" }, children: citations.map((citation, idx) => {
700
+ const displaySummary = formatReferenceSummary(citation.referenceSummary, maxSummaryLength);
701
+ const tooltipText = stripMarkdown(citation.preview || citation.referenceSummary || "");
702
+ return /* @__PURE__ */ jsxs2(
703
+ "span",
704
+ {
705
+ title: tooltipText,
706
+ onClick: () => onCitationClick(citation),
707
+ style: {
708
+ padding: "0.35rem 0.5rem",
709
+ backgroundColor: chipColor,
710
+ borderRadius: "4px",
711
+ border: `1px solid ${borderColor}`,
712
+ fontSize: "0.75rem",
713
+ color: "#d0a0f0",
714
+ cursor: "pointer",
715
+ maxWidth: "100%",
716
+ overflow: "hidden",
717
+ textOverflow: "ellipsis",
718
+ whiteSpace: "nowrap",
719
+ display: "inline-flex",
720
+ alignItems: "center",
721
+ gap: "4px"
722
+ },
723
+ children: [
724
+ /* @__PURE__ */ jsxs2("span", { style: { fontWeight: 600 }, children: [
725
+ "[",
726
+ citation.label,
727
+ "]"
728
+ ] }),
729
+ displaySummary && /* @__PURE__ */ jsx2("span", { children: displaySummary })
730
+ ]
731
+ },
732
+ citation.label || idx
733
+ );
734
+ }) });
735
+ }
736
+
737
+ // src/multichoice/MultiChoiceWidget.tsx
738
+ import { useState as useState2, useCallback } from "react";
739
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
740
+ function MultiChoiceWidget({
741
+ options,
742
+ onSelect,
743
+ freeTextPlaceholder = "Or type your own answer...",
744
+ chipColor = "rgba(139, 92, 246, 0.15)",
745
+ borderColor = "rgba(139, 92, 246, 0.3)",
746
+ accentColor = "rgba(139, 92, 246, 0.5)",
747
+ textColor = "#d4b8ff",
748
+ disabled = false
749
+ }) {
750
+ const [showFreeText, setShowFreeText] = useState2(false);
751
+ const [freeTextValue, setFreeTextValue] = useState2("");
752
+ const handleOptionClick = useCallback(
753
+ (option) => {
754
+ if (disabled) return;
755
+ onSelect(option.label);
756
+ },
757
+ [onSelect, disabled]
758
+ );
759
+ const handleOtherClick = useCallback(() => {
760
+ if (disabled) return;
761
+ setShowFreeText(true);
762
+ }, [disabled]);
763
+ const handleFreeTextSubmit = useCallback(() => {
764
+ if (disabled || !freeTextValue.trim()) return;
765
+ onSelect(freeTextValue.trim());
766
+ setFreeTextValue("");
767
+ setShowFreeText(false);
768
+ }, [onSelect, freeTextValue, disabled]);
769
+ const handleKeyDown = useCallback(
770
+ (e) => {
771
+ if (e.key === "Enter") {
772
+ e.preventDefault();
773
+ handleFreeTextSubmit();
774
+ } else if (e.key === "Escape") {
775
+ setShowFreeText(false);
776
+ setFreeTextValue("");
777
+ }
778
+ },
779
+ [handleFreeTextSubmit]
780
+ );
781
+ const baseChipStyle = {
782
+ padding: "0.5rem 0.875rem",
783
+ backgroundColor: chipColor,
784
+ borderRadius: "9999px",
785
+ border: `1px solid ${borderColor}`,
786
+ fontSize: "0.875rem",
787
+ color: textColor,
788
+ cursor: disabled ? "not-allowed" : "pointer",
789
+ opacity: disabled ? 0.5 : 1,
790
+ transition: "all 0.15s ease",
791
+ display: "inline-flex",
792
+ alignItems: "center",
793
+ gap: "0.375rem"
794
+ };
795
+ const hoverChipStyle = {
796
+ ...baseChipStyle,
797
+ backgroundColor: accentColor,
798
+ borderColor: textColor
799
+ };
800
+ return /* @__PURE__ */ jsxs3(
801
+ "div",
802
+ {
803
+ style: {
804
+ display: "flex",
805
+ flexDirection: "column",
806
+ gap: "0.75rem",
807
+ marginTop: "0.75rem"
808
+ },
809
+ children: [
810
+ /* @__PURE__ */ jsxs3(
811
+ "div",
812
+ {
813
+ style: {
814
+ display: "flex",
815
+ flexWrap: "wrap",
816
+ gap: "0.5rem"
817
+ },
818
+ children: [
819
+ options.map((option) => /* @__PURE__ */ jsx3(
820
+ "button",
821
+ {
822
+ onClick: () => handleOptionClick(option),
823
+ disabled,
824
+ title: option.description,
825
+ style: baseChipStyle,
826
+ onMouseEnter: (e) => {
827
+ if (!disabled) {
828
+ Object.assign(e.currentTarget.style, hoverChipStyle);
829
+ }
830
+ },
831
+ onMouseLeave: (e) => {
832
+ Object.assign(e.currentTarget.style, baseChipStyle);
833
+ },
834
+ children: option.label
835
+ },
836
+ option.id
837
+ )),
838
+ !showFreeText && /* @__PURE__ */ jsxs3(
839
+ "button",
840
+ {
841
+ onClick: handleOtherClick,
842
+ disabled,
843
+ style: {
844
+ ...baseChipStyle,
845
+ backgroundColor: "transparent",
846
+ borderStyle: "dashed"
847
+ },
848
+ onMouseEnter: (e) => {
849
+ if (!disabled) {
850
+ e.currentTarget.style.backgroundColor = chipColor;
851
+ e.currentTarget.style.borderStyle = "solid";
852
+ }
853
+ },
854
+ onMouseLeave: (e) => {
855
+ e.currentTarget.style.backgroundColor = "transparent";
856
+ e.currentTarget.style.borderStyle = "dashed";
857
+ },
858
+ children: [
859
+ /* @__PURE__ */ jsx3("span", { style: { fontSize: "1rem", lineHeight: 1 }, children: "+" }),
860
+ "Other"
861
+ ]
862
+ }
863
+ )
864
+ ]
865
+ }
866
+ ),
867
+ showFreeText && /* @__PURE__ */ jsxs3(
868
+ "div",
869
+ {
870
+ style: {
871
+ display: "flex",
872
+ gap: "0.5rem",
873
+ alignItems: "center"
874
+ },
875
+ children: [
876
+ /* @__PURE__ */ jsx3(
877
+ "input",
878
+ {
879
+ type: "text",
880
+ value: freeTextValue,
881
+ onChange: (e) => setFreeTextValue(e.target.value),
882
+ onKeyDown: handleKeyDown,
883
+ placeholder: freeTextPlaceholder,
884
+ disabled,
885
+ autoFocus: true,
886
+ style: {
887
+ flex: 1,
888
+ padding: "0.5rem 0.75rem",
889
+ backgroundColor: "rgba(0, 0, 0, 0.2)",
890
+ border: `1px solid ${borderColor}`,
891
+ borderRadius: "0.5rem",
892
+ color: textColor,
893
+ fontSize: "0.875rem",
894
+ outline: "none"
895
+ },
896
+ onFocus: (e) => {
897
+ e.currentTarget.style.borderColor = accentColor;
898
+ },
899
+ onBlur: (e) => {
900
+ e.currentTarget.style.borderColor = borderColor;
901
+ }
902
+ }
903
+ ),
904
+ /* @__PURE__ */ jsx3(
905
+ "button",
906
+ {
907
+ onClick: handleFreeTextSubmit,
908
+ disabled: disabled || !freeTextValue.trim(),
909
+ style: {
910
+ padding: "0.5rem 1rem",
911
+ backgroundColor: freeTextValue.trim() ? accentColor : chipColor,
912
+ border: `1px solid ${freeTextValue.trim() ? textColor : borderColor}`,
913
+ borderRadius: "0.5rem",
914
+ color: textColor,
915
+ fontSize: "0.875rem",
916
+ cursor: disabled || !freeTextValue.trim() ? "not-allowed" : "pointer",
917
+ opacity: disabled || !freeTextValue.trim() ? 0.5 : 1,
918
+ transition: "all 0.15s ease"
919
+ },
920
+ children: "Send"
921
+ }
922
+ ),
923
+ /* @__PURE__ */ jsx3(
924
+ "button",
925
+ {
926
+ onClick: () => {
927
+ setShowFreeText(false);
928
+ setFreeTextValue("");
929
+ },
930
+ disabled,
931
+ style: {
932
+ padding: "0.5rem",
933
+ backgroundColor: "transparent",
934
+ border: "none",
935
+ color: textColor,
936
+ fontSize: "1rem",
937
+ cursor: disabled ? "not-allowed" : "pointer",
938
+ opacity: disabled ? 0.5 : 0.7
939
+ },
940
+ title: "Cancel",
941
+ children: "\xD7"
942
+ }
943
+ )
944
+ ]
945
+ }
946
+ )
947
+ ]
948
+ }
949
+ );
950
+ }
951
+ export {
952
+ CitationDialog,
953
+ CitationDisplay,
954
+ MultiChoiceWidget
955
+ };
956
+ //# sourceMappingURL=index.mjs.map