@arc-lo/ui 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.cjs ADDED
@@ -0,0 +1,2979 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var clsx = require('clsx');
5
+ var tailwindMerge = require('tailwind-merge');
6
+ var jsxRuntime = require('react/jsx-runtime');
7
+
8
+ var __defProp = Object.defineProperty;
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+
14
+ // src/streaming-text/index.ts
15
+ var streaming_text_exports = {};
16
+ __export(streaming_text_exports, {
17
+ Content: () => Content,
18
+ Cursor: () => Cursor,
19
+ ErrorFallback: () => ErrorFallback,
20
+ RateLimit: () => RateLimit,
21
+ Root: () => Root,
22
+ Skeleton: () => Skeleton,
23
+ Stop: () => Stop,
24
+ Toolbar: () => Toolbar,
25
+ useStreamingText: () => useStreamingText,
26
+ useStreamingTextContext: () => useStreamingTextContext
27
+ });
28
+ function cn(...inputs) {
29
+ return tailwindMerge.twMerge(clsx.clsx(inputs));
30
+ }
31
+
32
+ // src/lib/theme.ts
33
+ var themeVars = {
34
+ accent: "var(--arclo-accent, #6C5CE7)",
35
+ surface: "var(--arclo-surface, #ffffff)",
36
+ surfaceSecondary: "var(--arclo-surface-secondary, #f9fafb)",
37
+ border: "var(--arclo-border, #e5e7eb)",
38
+ text: "var(--arclo-text, #1a1a1a)",
39
+ textSecondary: "var(--arclo-text-secondary, #6b7280)",
40
+ textMuted: "var(--arclo-text-muted, #9ca3af)",
41
+ error: "var(--arclo-error, #ef4444)",
42
+ errorSurface: "var(--arclo-error-surface, #fef2f2)"};
43
+ function chunkText(text, mode) {
44
+ switch (mode) {
45
+ case "char":
46
+ return text.split("");
47
+ case "word":
48
+ return text.match(/\S+\s*/g) ?? [text];
49
+ case "line":
50
+ return text.match(/[^\n]*\n?/g)?.filter(Boolean) ?? [text];
51
+ }
52
+ }
53
+ function useStreamingText({
54
+ stream,
55
+ text,
56
+ speed = 30,
57
+ chunkSize = "char",
58
+ onDone,
59
+ onError,
60
+ onInterrupt
61
+ }) {
62
+ const [displayedText, setDisplayedText] = react.useState("");
63
+ const [fullText, setFullText] = react.useState("");
64
+ const [state, setState] = react.useState("pending");
65
+ const bufferRef = react.useRef([]);
66
+ const drainingRef = react.useRef(false);
67
+ const timerRef = react.useRef(null);
68
+ const interruptedRef = react.useRef(false);
69
+ const readerRef = react.useRef(null);
70
+ const speedRef = react.useRef(speed);
71
+ const fullTextRef = react.useRef("");
72
+ const onDoneRef = react.useRef(onDone);
73
+ const onErrorRef = react.useRef(onError);
74
+ const onInterruptRef = react.useRef(onInterrupt);
75
+ speedRef.current = speed;
76
+ onDoneRef.current = onDone;
77
+ onErrorRef.current = onError;
78
+ onInterruptRef.current = onInterrupt;
79
+ const startDraining = react.useCallback(() => {
80
+ if (drainingRef.current) return;
81
+ drainingRef.current = true;
82
+ function tick() {
83
+ if (bufferRef.current.length === 0) {
84
+ drainingRef.current = false;
85
+ return;
86
+ }
87
+ const chunk = bufferRef.current.shift();
88
+ setDisplayedText((prev) => prev + chunk);
89
+ timerRef.current = setTimeout(tick, speedRef.current);
90
+ }
91
+ tick();
92
+ }, []);
93
+ react.useEffect(() => {
94
+ if (!stream) return;
95
+ interruptedRef.current = false;
96
+ drainingRef.current = false;
97
+ bufferRef.current = [];
98
+ fullTextRef.current = "";
99
+ setDisplayedText("");
100
+ setFullText("");
101
+ setState("streaming");
102
+ let cancelled = false;
103
+ let reader;
104
+ try {
105
+ reader = stream.getReader();
106
+ } catch {
107
+ return;
108
+ }
109
+ readerRef.current = reader;
110
+ async function read() {
111
+ try {
112
+ while (true) {
113
+ const { done, value } = await reader.read();
114
+ if (cancelled || interruptedRef.current) break;
115
+ if (done) {
116
+ const waitForDrain = () => {
117
+ if (cancelled) return;
118
+ if (bufferRef.current.length === 0 && !drainingRef.current) {
119
+ setState("done");
120
+ onDoneRef.current?.(fullTextRef.current);
121
+ } else {
122
+ setTimeout(waitForDrain, 50);
123
+ }
124
+ };
125
+ waitForDrain();
126
+ return;
127
+ }
128
+ const chunks = chunkText(value, chunkSize);
129
+ bufferRef.current.push(...chunks);
130
+ fullTextRef.current += value;
131
+ setFullText(fullTextRef.current);
132
+ startDraining();
133
+ }
134
+ } catch (err) {
135
+ if (!cancelled && !interruptedRef.current) {
136
+ setState("error");
137
+ onErrorRef.current?.(
138
+ err instanceof Error ? err : new Error(String(err))
139
+ );
140
+ }
141
+ }
142
+ }
143
+ read();
144
+ return () => {
145
+ cancelled = true;
146
+ if (timerRef.current) clearTimeout(timerRef.current);
147
+ drainingRef.current = false;
148
+ reader.cancel().catch(() => {
149
+ });
150
+ };
151
+ }, [stream, chunkSize, startDraining]);
152
+ react.useEffect(() => {
153
+ if (text == null || stream) return;
154
+ interruptedRef.current = false;
155
+ drainingRef.current = false;
156
+ bufferRef.current = [];
157
+ fullTextRef.current = text;
158
+ setDisplayedText("");
159
+ setFullText(text);
160
+ setState("streaming");
161
+ const chunks = chunkText(text, chunkSize);
162
+ bufferRef.current = chunks;
163
+ startDraining();
164
+ const waitForDrain = () => {
165
+ if (bufferRef.current.length === 0 && !drainingRef.current) {
166
+ setState("done");
167
+ onDoneRef.current?.(text);
168
+ } else {
169
+ setTimeout(waitForDrain, 50);
170
+ }
171
+ };
172
+ setTimeout(waitForDrain, 100);
173
+ return () => {
174
+ if (timerRef.current) clearTimeout(timerRef.current);
175
+ drainingRef.current = false;
176
+ };
177
+ }, [text, stream, chunkSize, startDraining]);
178
+ const interrupt = react.useCallback(() => {
179
+ interruptedRef.current = true;
180
+ if (timerRef.current) clearTimeout(timerRef.current);
181
+ drainingRef.current = false;
182
+ readerRef.current?.cancel().catch(() => {
183
+ });
184
+ bufferRef.current = [];
185
+ setState("interrupted");
186
+ setDisplayedText((t) => {
187
+ onInterruptRef.current?.(t);
188
+ return t;
189
+ });
190
+ }, []);
191
+ const reset = react.useCallback(() => {
192
+ interruptedRef.current = false;
193
+ if (timerRef.current) clearTimeout(timerRef.current);
194
+ drainingRef.current = false;
195
+ bufferRef.current = [];
196
+ fullTextRef.current = "";
197
+ setDisplayedText("");
198
+ setFullText("");
199
+ setState("pending");
200
+ }, []);
201
+ const skipAnimation = react.useCallback(() => {
202
+ if (timerRef.current) clearTimeout(timerRef.current);
203
+ drainingRef.current = false;
204
+ bufferRef.current = [];
205
+ setDisplayedText(fullTextRef.current);
206
+ }, []);
207
+ return { displayedText, fullText, state, interrupt, reset, skipAnimation };
208
+ }
209
+ var StreamingTextContext = react.createContext(
210
+ null
211
+ );
212
+ function useStreamingTextContext() {
213
+ const ctx = react.useContext(StreamingTextContext);
214
+ if (!ctx) {
215
+ throw new Error(
216
+ "useStreamingTextContext must be used within <StreamingText.Root>"
217
+ );
218
+ }
219
+ return ctx;
220
+ }
221
+ var Root = react.forwardRef(
222
+ ({
223
+ stream,
224
+ text,
225
+ speed,
226
+ chunkSize,
227
+ onDone,
228
+ onError,
229
+ onInterrupt,
230
+ children,
231
+ className,
232
+ ...props
233
+ }, ref) => {
234
+ const ctx = useStreamingText({
235
+ stream,
236
+ text,
237
+ speed,
238
+ chunkSize,
239
+ onDone,
240
+ onError,
241
+ onInterrupt
242
+ });
243
+ return /* @__PURE__ */ jsxRuntime.jsx(StreamingTextContext.Provider, { value: ctx, children: /* @__PURE__ */ jsxRuntime.jsx(
244
+ "div",
245
+ {
246
+ ref,
247
+ "data-state": ctx.state,
248
+ className: cn("arclo-streaming-text", className),
249
+ ...props,
250
+ children: children ?? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
251
+ /* @__PURE__ */ jsxRuntime.jsx(Content, {}),
252
+ /* @__PURE__ */ jsxRuntime.jsx(Cursor, {})
253
+ ] })
254
+ }
255
+ ) });
256
+ }
257
+ );
258
+ Root.displayName = "StreamingText.Root";
259
+ var Content = react.forwardRef(
260
+ ({ render, className, ...props }, ref) => {
261
+ const { displayedText, state } = useStreamingTextContext();
262
+ return /* @__PURE__ */ jsxRuntime.jsx(
263
+ "div",
264
+ {
265
+ ref,
266
+ "data-state": state,
267
+ className: cn("arclo-streaming-content whitespace-pre-wrap", className),
268
+ ...props,
269
+ children: render ? render(displayedText) : displayedText
270
+ }
271
+ );
272
+ }
273
+ );
274
+ Content.displayName = "StreamingText.Content";
275
+ var Cursor = react.forwardRef(
276
+ ({ char = "\u258B", className, ...props }, ref) => {
277
+ const { state } = useStreamingTextContext();
278
+ const visible = state === "streaming" || state === "pending";
279
+ if (!visible) return null;
280
+ return /* @__PURE__ */ jsxRuntime.jsx(
281
+ "span",
282
+ {
283
+ ref,
284
+ "aria-hidden": true,
285
+ style: { color: themeVars.accent },
286
+ className: cn(
287
+ "arclo-streaming-cursor inline-block animate-pulse",
288
+ className
289
+ ),
290
+ ...props,
291
+ children: char
292
+ }
293
+ );
294
+ }
295
+ );
296
+ Cursor.displayName = "StreamingText.Cursor";
297
+ var Skeleton = react.forwardRef(
298
+ ({ lines = 3, className, ...props }, ref) => {
299
+ const { state } = useStreamingTextContext();
300
+ if (state !== "pending") return null;
301
+ return /* @__PURE__ */ jsxRuntime.jsx(
302
+ "div",
303
+ {
304
+ ref,
305
+ role: "status",
306
+ "aria-label": "Loading",
307
+ className: cn("arclo-streaming-skeleton space-y-2", className),
308
+ ...props,
309
+ children: Array.from({ length: lines }, (_, i) => /* @__PURE__ */ jsxRuntime.jsx(
310
+ "div",
311
+ {
312
+ className: cn(
313
+ "h-4 rounded bg-gray-200 animate-pulse",
314
+ i === lines - 1 && "w-2/3"
315
+ )
316
+ },
317
+ i
318
+ ))
319
+ }
320
+ );
321
+ }
322
+ );
323
+ Skeleton.displayName = "StreamingText.Skeleton";
324
+ var ErrorFallback = react.forwardRef(
325
+ ({ message = "Something went wrong.", onRetry, className, ...props }, ref) => {
326
+ const { state } = useStreamingTextContext();
327
+ if (state !== "error") return null;
328
+ return /* @__PURE__ */ jsxRuntime.jsxs(
329
+ "div",
330
+ {
331
+ ref,
332
+ role: "alert",
333
+ style: {
334
+ borderColor: themeVars.error,
335
+ backgroundColor: themeVars.errorSurface,
336
+ color: themeVars.error
337
+ },
338
+ className: cn(
339
+ "arclo-streaming-error rounded-lg border p-4 text-sm",
340
+ className
341
+ ),
342
+ ...props,
343
+ children: [
344
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: message }),
345
+ onRetry && /* @__PURE__ */ jsxRuntime.jsx(
346
+ "button",
347
+ {
348
+ type: "button",
349
+ onClick: onRetry,
350
+ className: "mt-2 text-red-600 underline hover:text-red-800 cursor-pointer",
351
+ children: "Try again"
352
+ }
353
+ )
354
+ ]
355
+ }
356
+ );
357
+ }
358
+ );
359
+ ErrorFallback.displayName = "StreamingText.ErrorFallback";
360
+ var RateLimit = react.forwardRef(
361
+ ({
362
+ retryAfter,
363
+ message = "Rate limit reached. Please wait.",
364
+ className,
365
+ ...props
366
+ }, ref) => {
367
+ const { state } = useStreamingTextContext();
368
+ if (state !== "ratelimit") return null;
369
+ return /* @__PURE__ */ jsxRuntime.jsxs(
370
+ "div",
371
+ {
372
+ ref,
373
+ role: "status",
374
+ className: cn(
375
+ "arclo-streaming-ratelimit rounded-lg border border-amber-200 bg-amber-50 p-4 text-sm text-amber-800",
376
+ className
377
+ ),
378
+ ...props,
379
+ children: [
380
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: message }),
381
+ retryAfter != null && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-1 text-amber-600", children: [
382
+ "Retry in ",
383
+ retryAfter,
384
+ "s"
385
+ ] })
386
+ ]
387
+ }
388
+ );
389
+ }
390
+ );
391
+ RateLimit.displayName = "StreamingText.RateLimit";
392
+ var Toolbar = react.forwardRef(
393
+ ({ showIn = ["done", "interrupted"], children, className, ...props }, ref) => {
394
+ const { state } = useStreamingTextContext();
395
+ if (!showIn.includes(state)) return null;
396
+ return /* @__PURE__ */ jsxRuntime.jsx(
397
+ "div",
398
+ {
399
+ ref,
400
+ className: cn(
401
+ "arclo-streaming-toolbar mt-2 flex items-center gap-2 animate-in fade-in duration-150",
402
+ className
403
+ ),
404
+ ...props,
405
+ children
406
+ }
407
+ );
408
+ }
409
+ );
410
+ Toolbar.displayName = "StreamingText.Toolbar";
411
+ var Stop = react.forwardRef(
412
+ ({ children, className, ...props }, ref) => {
413
+ const { state, interrupt } = useStreamingTextContext();
414
+ if (state !== "streaming") return null;
415
+ return /* @__PURE__ */ jsxRuntime.jsx(
416
+ "button",
417
+ {
418
+ ref,
419
+ type: "button",
420
+ onClick: interrupt,
421
+ className: cn(
422
+ "arclo-streaming-stop rounded-md border border-gray-300 px-3 py-1.5 text-sm hover:bg-gray-50 cursor-pointer",
423
+ className
424
+ ),
425
+ ...props,
426
+ children: children ?? "Stop generating"
427
+ }
428
+ );
429
+ }
430
+ );
431
+ Stop.displayName = "StreamingText.Stop";
432
+
433
+ // src/prompt-box/index.ts
434
+ var prompt_box_exports = {};
435
+ __export(prompt_box_exports, {
436
+ Chip: () => Chip,
437
+ Chips: () => Chips,
438
+ Footer: () => Footer,
439
+ Input: () => Input,
440
+ Root: () => Root2,
441
+ SubmitButton: () => SubmitButton,
442
+ Suggestions: () => Suggestions,
443
+ usePromptBoxContext: () => usePromptBoxContext
444
+ });
445
+ var PromptBoxContext = react.createContext(null);
446
+ function usePromptBoxContext() {
447
+ const ctx = react.useContext(PromptBoxContext);
448
+ if (!ctx) {
449
+ throw new Error(
450
+ "usePromptBoxContext must be used within <PromptBox.Root>"
451
+ );
452
+ }
453
+ return ctx;
454
+ }
455
+ var Root2 = react.forwardRef(
456
+ ({
457
+ value: controlledValue,
458
+ defaultValue = "",
459
+ onSubmit,
460
+ onValueChange,
461
+ isSubmitting = false,
462
+ disabled = false,
463
+ children,
464
+ className,
465
+ ...props
466
+ }, ref) => {
467
+ const [internalValue, setInternalValue] = react.useState(defaultValue);
468
+ const value = controlledValue ?? internalValue;
469
+ const setValue = react.useCallback(
470
+ (v) => {
471
+ if (controlledValue === void 0) setInternalValue(v);
472
+ onValueChange?.(v);
473
+ },
474
+ [controlledValue, onValueChange]
475
+ );
476
+ const submit = react.useCallback(() => {
477
+ if (!value.trim() || isSubmitting || disabled) return;
478
+ onSubmit?.(value);
479
+ }, [value, isSubmitting, disabled, onSubmit]);
480
+ const handleFormSubmit = react.useCallback(
481
+ (e) => {
482
+ e.preventDefault();
483
+ submit();
484
+ },
485
+ [submit]
486
+ );
487
+ return /* @__PURE__ */ jsxRuntime.jsx(
488
+ PromptBoxContext.Provider,
489
+ {
490
+ value: { value, setValue, submit, isSubmitting, disabled },
491
+ children: /* @__PURE__ */ jsxRuntime.jsx(
492
+ "form",
493
+ {
494
+ ref,
495
+ onSubmit: handleFormSubmit,
496
+ style: {
497
+ backgroundColor: themeVars.surface,
498
+ borderColor: themeVars.border,
499
+ color: themeVars.text
500
+ },
501
+ className: cn(
502
+ "arclo-prompt-box rounded-2xl border shadow-sm transition-all focus-within:shadow-md",
503
+ disabled && "opacity-50 pointer-events-none",
504
+ className
505
+ ),
506
+ ...props,
507
+ children: children ?? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
508
+ /* @__PURE__ */ jsxRuntime.jsx(Input, {}),
509
+ /* @__PURE__ */ jsxRuntime.jsx(Footer, { children: /* @__PURE__ */ jsxRuntime.jsx(SubmitButton, {}) })
510
+ ] })
511
+ }
512
+ )
513
+ }
514
+ );
515
+ }
516
+ );
517
+ Root2.displayName = "PromptBox.Root";
518
+ var Chips = react.forwardRef(
519
+ ({ children, className, ...props }, ref) => {
520
+ return /* @__PURE__ */ jsxRuntime.jsx(
521
+ "div",
522
+ {
523
+ ref,
524
+ className: cn(
525
+ "arclo-prompt-chips flex flex-wrap gap-2 px-4 pt-4 pb-1",
526
+ className
527
+ ),
528
+ ...props,
529
+ children
530
+ }
531
+ );
532
+ }
533
+ );
534
+ Chips.displayName = "PromptBox.Chips";
535
+ var Chip = react.forwardRef(
536
+ ({ children, onRemove, className, ...props }, ref) => {
537
+ return /* @__PURE__ */ jsxRuntime.jsxs(
538
+ "span",
539
+ {
540
+ ref,
541
+ className: cn(
542
+ "arclo-prompt-chip inline-flex items-center gap-1.5 rounded-lg bg-gray-100 px-2.5 py-1 text-xs font-medium text-gray-600",
543
+ className
544
+ ),
545
+ ...props,
546
+ children: [
547
+ children,
548
+ onRemove && /* @__PURE__ */ jsxRuntime.jsx(
549
+ "button",
550
+ {
551
+ type: "button",
552
+ onClick: onRemove,
553
+ className: "text-gray-400 hover:text-gray-600 transition-colors cursor-pointer",
554
+ "aria-label": "Remove",
555
+ children: "\xD7"
556
+ }
557
+ )
558
+ ]
559
+ }
560
+ );
561
+ }
562
+ );
563
+ Chip.displayName = "PromptBox.Chip";
564
+ var Input = react.forwardRef(
565
+ ({ minRows = 1, maxRows = 8, className, onKeyDown, ...props }, ref) => {
566
+ const { value, setValue, submit, isSubmitting, disabled } = usePromptBoxContext();
567
+ const internalRef = react.useRef(null);
568
+ const textareaRef = ref ?? internalRef;
569
+ react.useEffect(() => {
570
+ const el = textareaRef.current;
571
+ if (!el) return;
572
+ el.style.height = "auto";
573
+ const lineHeight = parseInt(getComputedStyle(el).lineHeight) || 20;
574
+ const minH = lineHeight * minRows;
575
+ const maxH = lineHeight * maxRows;
576
+ el.style.height = `${Math.min(Math.max(el.scrollHeight, minH), maxH)}px`;
577
+ }, [value, minRows, maxRows, textareaRef]);
578
+ const handleKeyDown = react.useCallback(
579
+ (e) => {
580
+ if (e.key === "Enter" && !e.shiftKey) {
581
+ e.preventDefault();
582
+ submit();
583
+ }
584
+ onKeyDown?.(e);
585
+ },
586
+ [submit, onKeyDown]
587
+ );
588
+ return /* @__PURE__ */ jsxRuntime.jsx(
589
+ "textarea",
590
+ {
591
+ ref: textareaRef,
592
+ value,
593
+ onChange: (e) => setValue(e.target.value),
594
+ onKeyDown: handleKeyDown,
595
+ disabled: disabled || isSubmitting,
596
+ rows: minRows,
597
+ placeholder: "Ask anything...",
598
+ className: cn(
599
+ "arclo-prompt-input w-full resize-none bg-transparent px-4 py-3 text-[15px] leading-relaxed outline-none placeholder:text-gray-400 [scrollbar-width:thin] [scrollbar-color:theme(colors.gray.300)_transparent] [&::-webkit-scrollbar]:w-1.5 [&::-webkit-scrollbar-track]:bg-transparent [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:bg-gray-300",
600
+ className
601
+ ),
602
+ ...props
603
+ }
604
+ );
605
+ }
606
+ );
607
+ Input.displayName = "PromptBox.Input";
608
+ var Footer = react.forwardRef(
609
+ ({ children, className, ...props }, ref) => {
610
+ return /* @__PURE__ */ jsxRuntime.jsx(
611
+ "div",
612
+ {
613
+ ref,
614
+ className: cn(
615
+ "arclo-prompt-footer flex items-center justify-between px-4 pb-3 pt-1",
616
+ className
617
+ ),
618
+ ...props,
619
+ children
620
+ }
621
+ );
622
+ }
623
+ );
624
+ Footer.displayName = "PromptBox.Footer";
625
+ var SubmitButton = react.forwardRef(
626
+ ({ children, className, ...props }, ref) => {
627
+ const { value, isSubmitting, disabled } = usePromptBoxContext();
628
+ const isEmpty = !value.trim();
629
+ return /* @__PURE__ */ jsxRuntime.jsx(
630
+ "button",
631
+ {
632
+ ref,
633
+ type: "submit",
634
+ disabled: isEmpty || isSubmitting || disabled,
635
+ style: { backgroundColor: themeVars.accent },
636
+ className: cn(
637
+ "arclo-prompt-submit ml-auto rounded-xl px-4 py-2 text-sm font-medium text-white transition-all hover:brightness-90 disabled:opacity-25 cursor-pointer disabled:cursor-default",
638
+ className
639
+ ),
640
+ ...props,
641
+ children: children ?? (isSubmitting ? "Sending..." : "Send")
642
+ }
643
+ );
644
+ }
645
+ );
646
+ SubmitButton.displayName = "PromptBox.SubmitButton";
647
+ var Suggestions = react.forwardRef(({ suggestions, onSelect, className, ...props }, ref) => {
648
+ const { setValue } = usePromptBoxContext();
649
+ if (suggestions.length === 0) return null;
650
+ return /* @__PURE__ */ jsxRuntime.jsx(
651
+ "div",
652
+ {
653
+ ref,
654
+ className: cn(
655
+ "arclo-prompt-suggestions flex flex-wrap gap-2 px-4 pb-2 pt-1",
656
+ className
657
+ ),
658
+ ...props,
659
+ children: suggestions.map((s) => /* @__PURE__ */ jsxRuntime.jsx(
660
+ "button",
661
+ {
662
+ type: "button",
663
+ onClick: () => {
664
+ setValue(s);
665
+ onSelect?.(s);
666
+ },
667
+ className: "rounded-full border border-gray-200 px-3.5 py-1.5 text-xs text-gray-500 transition-all hover:border-gray-300 hover:bg-gray-50 hover:text-gray-700 cursor-pointer",
668
+ children: s
669
+ },
670
+ s
671
+ ))
672
+ }
673
+ );
674
+ });
675
+ Suggestions.displayName = "PromptBox.Suggestions";
676
+
677
+ // src/feedback-bar/index.ts
678
+ var feedback_bar_exports = {};
679
+ __export(feedback_bar_exports, {
680
+ Copy: () => Copy,
681
+ Regenerate: () => Regenerate,
682
+ Root: () => Root3,
683
+ ThumbsDown: () => ThumbsDown,
684
+ ThumbsUp: () => ThumbsUp
685
+ });
686
+ var FeedbackBarContext = react.createContext(null);
687
+ function useFeedbackBarContext() {
688
+ const ctx = react.useContext(FeedbackBarContext);
689
+ if (!ctx) {
690
+ throw new Error("FeedbackBar parts must be used within <FeedbackBar.Root>");
691
+ }
692
+ return ctx;
693
+ }
694
+ var Root3 = react.forwardRef(
695
+ ({ onFeedback, children, className, ...props }, ref) => {
696
+ const [feedback, setFeedbackState] = react.useState(null);
697
+ const [copied, setCopied] = react.useState(false);
698
+ const setFeedback = react.useCallback(
699
+ (v) => {
700
+ setFeedbackState(v);
701
+ onFeedback?.(v);
702
+ },
703
+ [onFeedback]
704
+ );
705
+ return /* @__PURE__ */ jsxRuntime.jsx(
706
+ FeedbackBarContext.Provider,
707
+ {
708
+ value: { feedback, setFeedback, copied, setCopied },
709
+ children: /* @__PURE__ */ jsxRuntime.jsx(
710
+ "div",
711
+ {
712
+ ref,
713
+ role: "toolbar",
714
+ "aria-label": "Response actions",
715
+ className: cn(
716
+ "arclo-feedback-bar flex items-center gap-1",
717
+ className
718
+ ),
719
+ ...props,
720
+ children: children ?? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
721
+ /* @__PURE__ */ jsxRuntime.jsx(ThumbsUp, {}),
722
+ /* @__PURE__ */ jsxRuntime.jsx(ThumbsDown, {}),
723
+ /* @__PURE__ */ jsxRuntime.jsx(Copy, {})
724
+ ] })
725
+ }
726
+ )
727
+ }
728
+ );
729
+ }
730
+ );
731
+ Root3.displayName = "FeedbackBar.Root";
732
+ var btnClass = "arclo-feedback-btn inline-flex items-center justify-center rounded-md p-1.5 text-gray-400 transition-colors hover:bg-gray-100 hover:text-gray-600 cursor-pointer";
733
+ var ThumbsUp = react.forwardRef(
734
+ ({ className, ...props }, ref) => {
735
+ const { feedback, setFeedback } = useFeedbackBarContext();
736
+ const active = feedback === "up";
737
+ return /* @__PURE__ */ jsxRuntime.jsx(
738
+ "button",
739
+ {
740
+ ref,
741
+ type: "button",
742
+ "aria-label": "Good response",
743
+ "aria-pressed": active,
744
+ onClick: () => setFeedback(active ? null : "up"),
745
+ style: active ? { color: themeVars.accent } : void 0,
746
+ className: cn(btnClass, className),
747
+ ...props,
748
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
749
+ "svg",
750
+ {
751
+ width: "16",
752
+ height: "16",
753
+ viewBox: "0 0 24 24",
754
+ fill: "none",
755
+ stroke: "currentColor",
756
+ strokeWidth: "2",
757
+ strokeLinecap: "round",
758
+ strokeLinejoin: "round",
759
+ children: [
760
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M7 10v12" }),
761
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2h0a3.13 3.13 0 0 1 3 3.88Z" })
762
+ ]
763
+ }
764
+ )
765
+ }
766
+ );
767
+ }
768
+ );
769
+ ThumbsUp.displayName = "FeedbackBar.ThumbsUp";
770
+ var ThumbsDown = react.forwardRef(({ className, ...props }, ref) => {
771
+ const { feedback, setFeedback } = useFeedbackBarContext();
772
+ const active = feedback === "down";
773
+ return /* @__PURE__ */ jsxRuntime.jsx(
774
+ "button",
775
+ {
776
+ ref,
777
+ type: "button",
778
+ "aria-label": "Bad response",
779
+ "aria-pressed": active,
780
+ onClick: () => setFeedback(active ? null : "down"),
781
+ className: cn(btnClass, active && "text-red-500", className),
782
+ ...props,
783
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
784
+ "svg",
785
+ {
786
+ width: "16",
787
+ height: "16",
788
+ viewBox: "0 0 24 24",
789
+ fill: "none",
790
+ stroke: "currentColor",
791
+ strokeWidth: "2",
792
+ strokeLinecap: "round",
793
+ strokeLinejoin: "round",
794
+ children: [
795
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M17 14V2" }),
796
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M9 18.12 10 14H4.17a2 2 0 0 1-1.92-2.56l2.33-8A2 2 0 0 1 6.5 2H20a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-2.76a2 2 0 0 0-1.79 1.11L12 22h0a3.13 3.13 0 0 1-3-3.88Z" })
797
+ ]
798
+ }
799
+ )
800
+ }
801
+ );
802
+ });
803
+ ThumbsDown.displayName = "FeedbackBar.ThumbsDown";
804
+ var Copy = react.forwardRef(
805
+ ({ text, className, ...props }, ref) => {
806
+ const { copied, setCopied } = useFeedbackBarContext();
807
+ const handleCopy = react.useCallback(async () => {
808
+ const content = text ?? ref?.current?.closest("[data-arclo-copyable]")?.textContent ?? "";
809
+ await navigator.clipboard.writeText(content);
810
+ setCopied(true);
811
+ setTimeout(() => setCopied(false), 2e3);
812
+ }, [text, ref, setCopied]);
813
+ return /* @__PURE__ */ jsxRuntime.jsx(
814
+ "button",
815
+ {
816
+ ref,
817
+ type: "button",
818
+ "aria-label": copied ? "Copied" : "Copy",
819
+ onClick: handleCopy,
820
+ className: cn(btnClass, copied && "text-emerald-600", className),
821
+ ...props,
822
+ children: copied ? /* @__PURE__ */ jsxRuntime.jsx(
823
+ "svg",
824
+ {
825
+ width: "16",
826
+ height: "16",
827
+ viewBox: "0 0 24 24",
828
+ fill: "none",
829
+ stroke: "currentColor",
830
+ strokeWidth: "2",
831
+ strokeLinecap: "round",
832
+ strokeLinejoin: "round",
833
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 6 9 17l-5-5" })
834
+ }
835
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(
836
+ "svg",
837
+ {
838
+ width: "16",
839
+ height: "16",
840
+ viewBox: "0 0 24 24",
841
+ fill: "none",
842
+ stroke: "currentColor",
843
+ strokeWidth: "2",
844
+ strokeLinecap: "round",
845
+ strokeLinejoin: "round",
846
+ children: [
847
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { width: "14", height: "14", x: "8", y: "8", rx: "2", ry: "2" }),
848
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" })
849
+ ]
850
+ }
851
+ )
852
+ }
853
+ );
854
+ }
855
+ );
856
+ Copy.displayName = "FeedbackBar.Copy";
857
+ var Regenerate = react.forwardRef(({ onRegenerate, className, ...props }, ref) => {
858
+ return /* @__PURE__ */ jsxRuntime.jsx(
859
+ "button",
860
+ {
861
+ ref,
862
+ type: "button",
863
+ "aria-label": "Regenerate response",
864
+ onClick: onRegenerate,
865
+ className: cn(btnClass, className),
866
+ ...props,
867
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
868
+ "svg",
869
+ {
870
+ width: "16",
871
+ height: "16",
872
+ viewBox: "0 0 24 24",
873
+ fill: "none",
874
+ stroke: "currentColor",
875
+ strokeWidth: "2",
876
+ strokeLinecap: "round",
877
+ strokeLinejoin: "round",
878
+ children: [
879
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" }),
880
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 3v5h5" }),
881
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16" }),
882
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M16 16h5v5" })
883
+ ]
884
+ }
885
+ )
886
+ }
887
+ );
888
+ });
889
+ Regenerate.displayName = "FeedbackBar.Regenerate";
890
+
891
+ // src/thinking-block/index.ts
892
+ var thinking_block_exports = {};
893
+ __export(thinking_block_exports, {
894
+ Content: () => Content2,
895
+ Root: () => Root4,
896
+ Trigger: () => Trigger
897
+ });
898
+ var ThinkingBlockContext = react.createContext(
899
+ null
900
+ );
901
+ function useThinkingBlockContext() {
902
+ const ctx = react.useContext(ThinkingBlockContext);
903
+ if (!ctx) {
904
+ throw new Error(
905
+ "ThinkingBlock parts must be used within <ThinkingBlock.Root>"
906
+ );
907
+ }
908
+ return ctx;
909
+ }
910
+ var Root4 = react.forwardRef(
911
+ ({
912
+ state = "thinking",
913
+ defaultOpen = true,
914
+ collapseOnDone = true,
915
+ duration = null,
916
+ children,
917
+ className,
918
+ ...props
919
+ }, ref) => {
920
+ const [isOpen, setIsOpen] = react.useState(defaultOpen);
921
+ react.useEffect(() => {
922
+ if (state === "done" && collapseOnDone) {
923
+ const timer = setTimeout(() => setIsOpen(false), 500);
924
+ return () => clearTimeout(timer);
925
+ }
926
+ }, [state, collapseOnDone]);
927
+ const toggle = react.useCallback(() => setIsOpen((o) => !o), []);
928
+ return /* @__PURE__ */ jsxRuntime.jsx(ThinkingBlockContext.Provider, { value: { state, isOpen, toggle, duration }, children: /* @__PURE__ */ jsxRuntime.jsx(
929
+ "div",
930
+ {
931
+ ref,
932
+ "data-state": state,
933
+ "data-open": isOpen,
934
+ className: cn(
935
+ "arclo-thinking-block rounded-xl border border-gray-200 overflow-hidden transition-all",
936
+ state === "thinking" && "border-[var(--arclo-accent,#6C5CE7)]/20 bg-[var(--arclo-accent,#6C5CE7)]/[0.02]",
937
+ state === "done" && "border-gray-200 bg-white",
938
+ state === "error" && "border-red-200 bg-red-50/30",
939
+ className
940
+ ),
941
+ ...props,
942
+ children: children ?? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
943
+ /* @__PURE__ */ jsxRuntime.jsx(Trigger, {}),
944
+ /* @__PURE__ */ jsxRuntime.jsx(Content2, {})
945
+ ] })
946
+ }
947
+ ) });
948
+ }
949
+ );
950
+ Root4.displayName = "ThinkingBlock.Root";
951
+ var Trigger = react.forwardRef(
952
+ ({ label, className, children, ...props }, ref) => {
953
+ const { state, isOpen, toggle, duration } = useThinkingBlockContext();
954
+ const defaultLabel = state === "thinking" ? "Thinking..." : state === "error" ? "Thinking failed" : duration != null ? `Thought for ${duration}s` : "Thought process";
955
+ return /* @__PURE__ */ jsxRuntime.jsxs(
956
+ "button",
957
+ {
958
+ ref,
959
+ type: "button",
960
+ onClick: toggle,
961
+ "aria-expanded": isOpen,
962
+ className: cn(
963
+ "arclo-thinking-trigger flex w-full items-center gap-2 px-4 py-3 text-left text-sm transition-colors cursor-pointer hover:bg-gray-50/50",
964
+ className
965
+ ),
966
+ ...props,
967
+ children: [
968
+ state === "thinking" && /* @__PURE__ */ jsxRuntime.jsx(
969
+ "svg",
970
+ {
971
+ className: "h-4 w-4 shrink-0 animate-spin",
972
+ style: { color: themeVars.accent },
973
+ viewBox: "0 0 24 24",
974
+ fill: "none",
975
+ children: /* @__PURE__ */ jsxRuntime.jsx(
976
+ "circle",
977
+ {
978
+ cx: "12",
979
+ cy: "12",
980
+ r: "10",
981
+ stroke: "currentColor",
982
+ strokeWidth: "3",
983
+ strokeDasharray: "60",
984
+ strokeDashoffset: "20",
985
+ strokeLinecap: "round"
986
+ }
987
+ )
988
+ }
989
+ ),
990
+ state === "done" && /* @__PURE__ */ jsxRuntime.jsx(
991
+ "svg",
992
+ {
993
+ className: "h-4 w-4 shrink-0",
994
+ style: { color: themeVars.accent },
995
+ viewBox: "0 0 24 24",
996
+ fill: "none",
997
+ stroke: "currentColor",
998
+ strokeWidth: "2",
999
+ strokeLinecap: "round",
1000
+ strokeLinejoin: "round",
1001
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m12 3-1.912 5.813a2 2 0 0 1-1.275 1.275L3 12l5.813 1.912a2 2 0 0 1 1.275 1.275L12 21l1.912-5.813a2 2 0 0 1 1.275-1.275L21 12l-5.813-1.912a2 2 0 0 1-1.275-1.275L12 3Z" })
1002
+ }
1003
+ ),
1004
+ state === "error" && /* @__PURE__ */ jsxRuntime.jsxs(
1005
+ "svg",
1006
+ {
1007
+ className: "h-4 w-4 shrink-0 text-red-500",
1008
+ viewBox: "0 0 24 24",
1009
+ fill: "none",
1010
+ stroke: "currentColor",
1011
+ strokeWidth: "2",
1012
+ strokeLinecap: "round",
1013
+ children: [
1014
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "10" }),
1015
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m15 9-6 6M9 9l6 6" })
1016
+ ]
1017
+ }
1018
+ ),
1019
+ /* @__PURE__ */ jsxRuntime.jsx(
1020
+ "span",
1021
+ {
1022
+ className: cn(
1023
+ "flex-1 font-medium",
1024
+ state === "thinking" && "text-[var(--arclo-accent,#6C5CE7)]",
1025
+ state === "done" && "text-gray-500",
1026
+ state === "error" && "text-red-600"
1027
+ ),
1028
+ children: children ?? label ?? defaultLabel
1029
+ }
1030
+ ),
1031
+ /* @__PURE__ */ jsxRuntime.jsx(
1032
+ "svg",
1033
+ {
1034
+ className: cn(
1035
+ "h-4 w-4 shrink-0 text-gray-400 transition-transform duration-200",
1036
+ isOpen && "rotate-180"
1037
+ ),
1038
+ viewBox: "0 0 24 24",
1039
+ fill: "none",
1040
+ stroke: "currentColor",
1041
+ strokeWidth: "2",
1042
+ strokeLinecap: "round",
1043
+ strokeLinejoin: "round",
1044
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m6 9 6 6 6-6" })
1045
+ }
1046
+ )
1047
+ ]
1048
+ }
1049
+ );
1050
+ }
1051
+ );
1052
+ Trigger.displayName = "ThinkingBlock.Trigger";
1053
+ var Content2 = react.forwardRef(
1054
+ ({ children, className, ...props }, ref) => {
1055
+ const { isOpen, state } = useThinkingBlockContext();
1056
+ if (!isOpen) return null;
1057
+ return /* @__PURE__ */ jsxRuntime.jsx(
1058
+ "div",
1059
+ {
1060
+ ref,
1061
+ className: cn(
1062
+ "arclo-thinking-content border-t border-gray-100 px-4 py-3",
1063
+ className
1064
+ ),
1065
+ ...props,
1066
+ children: children ?? /* @__PURE__ */ jsxRuntime.jsx(
1067
+ "p",
1068
+ {
1069
+ className: cn(
1070
+ "text-sm leading-relaxed",
1071
+ state === "thinking" ? "text-gray-600 italic" : "text-gray-500"
1072
+ ),
1073
+ children: state === "thinking" ? "Analyzing the request..." : "No content provided."
1074
+ }
1075
+ )
1076
+ }
1077
+ );
1078
+ }
1079
+ );
1080
+ Content2.displayName = "ThinkingBlock.Content";
1081
+
1082
+ // src/tool-call/index.ts
1083
+ var tool_call_exports = {};
1084
+ __export(tool_call_exports, {
1085
+ Header: () => Header,
1086
+ Input: () => Input2,
1087
+ Output: () => Output,
1088
+ Root: () => Root5
1089
+ });
1090
+ var ToolCallContext = react.createContext(null);
1091
+ function useToolCallContext() {
1092
+ const ctx = react.useContext(ToolCallContext);
1093
+ if (!ctx) {
1094
+ throw new Error("ToolCall parts must be used within <ToolCall.Root>");
1095
+ }
1096
+ return ctx;
1097
+ }
1098
+ var Root5 = react.forwardRef(
1099
+ ({
1100
+ toolName,
1101
+ status = "pending",
1102
+ defaultOpen = false,
1103
+ children,
1104
+ className,
1105
+ ...props
1106
+ }, ref) => {
1107
+ const [isOpen, setIsOpen] = react.useState(defaultOpen);
1108
+ const toggle = react.useCallback(() => setIsOpen((o) => !o), []);
1109
+ return /* @__PURE__ */ jsxRuntime.jsx(ToolCallContext.Provider, { value: { status, toolName, isOpen, toggle }, children: /* @__PURE__ */ jsxRuntime.jsx(
1110
+ "div",
1111
+ {
1112
+ ref,
1113
+ "data-status": status,
1114
+ className: cn(
1115
+ "arclo-tool-call rounded-xl border overflow-hidden transition-all",
1116
+ status === "pending" && "border-gray-200 bg-gray-50/50",
1117
+ status === "running" && "border-blue-200 bg-blue-50/30",
1118
+ status === "success" && "border-emerald-200 bg-emerald-50/30",
1119
+ status === "error" && "border-red-200 bg-red-50/30",
1120
+ className
1121
+ ),
1122
+ ...props,
1123
+ children: children ?? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsx(Header, {}) })
1124
+ }
1125
+ ) });
1126
+ }
1127
+ );
1128
+ Root5.displayName = "ToolCall.Root";
1129
+ var Header = react.forwardRef(
1130
+ ({ children, className, ...props }, ref) => {
1131
+ const { status, toolName, isOpen, toggle } = useToolCallContext();
1132
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1133
+ "button",
1134
+ {
1135
+ ref,
1136
+ type: "button",
1137
+ onClick: toggle,
1138
+ "aria-expanded": isOpen,
1139
+ className: cn(
1140
+ "arclo-tool-call-header flex w-full items-center gap-3 px-4 py-3 text-left text-sm cursor-pointer hover:bg-gray-50/50 transition-colors",
1141
+ className
1142
+ ),
1143
+ ...props,
1144
+ children: [
1145
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "shrink-0", children: [
1146
+ status === "pending" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-5 w-5 items-center justify-center rounded-full bg-gray-200", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-2 w-2 rounded-full bg-gray-400" }) }),
1147
+ status === "running" && /* @__PURE__ */ jsxRuntime.jsx(
1148
+ "svg",
1149
+ {
1150
+ className: "h-5 w-5 animate-spin text-blue-500",
1151
+ viewBox: "0 0 24 24",
1152
+ fill: "none",
1153
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1154
+ "circle",
1155
+ {
1156
+ cx: "12",
1157
+ cy: "12",
1158
+ r: "10",
1159
+ stroke: "currentColor",
1160
+ strokeWidth: "3",
1161
+ strokeDasharray: "60",
1162
+ strokeDashoffset: "20",
1163
+ strokeLinecap: "round"
1164
+ }
1165
+ )
1166
+ }
1167
+ ),
1168
+ status === "success" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-5 w-5 items-center justify-center rounded-full bg-emerald-100", children: /* @__PURE__ */ jsxRuntime.jsx(
1169
+ "svg",
1170
+ {
1171
+ className: "h-3 w-3 text-emerald-600",
1172
+ viewBox: "0 0 24 24",
1173
+ fill: "none",
1174
+ stroke: "currentColor",
1175
+ strokeWidth: "3",
1176
+ strokeLinecap: "round",
1177
+ strokeLinejoin: "round",
1178
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 6 9 17l-5-5" })
1179
+ }
1180
+ ) }),
1181
+ status === "error" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-5 w-5 items-center justify-center rounded-full bg-red-100", children: /* @__PURE__ */ jsxRuntime.jsx(
1182
+ "svg",
1183
+ {
1184
+ className: "h-3 w-3 text-red-600",
1185
+ viewBox: "0 0 24 24",
1186
+ fill: "none",
1187
+ stroke: "currentColor",
1188
+ strokeWidth: "3",
1189
+ strokeLinecap: "round",
1190
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m15 9-6 6M9 9l6 6" })
1191
+ }
1192
+ ) })
1193
+ ] }),
1194
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
1195
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
1196
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-xs font-semibold text-gray-700 truncate", children: toolName }),
1197
+ /* @__PURE__ */ jsxRuntime.jsxs(
1198
+ "span",
1199
+ {
1200
+ className: cn(
1201
+ "rounded-full px-2 py-0.5 text-[10px] font-medium",
1202
+ status === "pending" && "bg-gray-100 text-gray-500",
1203
+ status === "running" && "bg-blue-100 text-blue-600",
1204
+ status === "success" && "bg-emerald-100 text-emerald-600",
1205
+ status === "error" && "bg-red-100 text-red-600"
1206
+ ),
1207
+ children: [
1208
+ status === "pending" && "Queued",
1209
+ status === "running" && "Running",
1210
+ status === "success" && "Done",
1211
+ status === "error" && "Failed"
1212
+ ]
1213
+ }
1214
+ )
1215
+ ] }),
1216
+ children
1217
+ ] }),
1218
+ /* @__PURE__ */ jsxRuntime.jsx(
1219
+ "svg",
1220
+ {
1221
+ className: cn(
1222
+ "h-4 w-4 shrink-0 text-gray-400 transition-transform duration-200",
1223
+ isOpen && "rotate-180"
1224
+ ),
1225
+ viewBox: "0 0 24 24",
1226
+ fill: "none",
1227
+ stroke: "currentColor",
1228
+ strokeWidth: "2",
1229
+ strokeLinecap: "round",
1230
+ strokeLinejoin: "round",
1231
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m6 9 6 6 6-6" })
1232
+ }
1233
+ )
1234
+ ]
1235
+ }
1236
+ );
1237
+ }
1238
+ );
1239
+ Header.displayName = "ToolCall.Header";
1240
+ var Input2 = react.forwardRef(
1241
+ ({ label = "Input", children, className, ...props }, ref) => {
1242
+ const { isOpen } = useToolCallContext();
1243
+ if (!isOpen) return null;
1244
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1245
+ "div",
1246
+ {
1247
+ ref,
1248
+ className: cn(
1249
+ "arclo-tool-call-input border-t border-gray-100 px-4 py-3",
1250
+ className
1251
+ ),
1252
+ ...props,
1253
+ children: [
1254
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-1.5 text-[10px] font-semibold uppercase tracking-wider text-gray-400", children: label }),
1255
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg bg-gray-50 p-3 font-mono text-xs text-gray-600 overflow-x-auto", children })
1256
+ ]
1257
+ }
1258
+ );
1259
+ }
1260
+ );
1261
+ Input2.displayName = "ToolCall.Input";
1262
+ var Output = react.forwardRef(
1263
+ ({ label = "Output", children, className, ...props }, ref) => {
1264
+ const { isOpen, status } = useToolCallContext();
1265
+ if (!isOpen || status === "pending" || status === "running") return null;
1266
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1267
+ "div",
1268
+ {
1269
+ ref,
1270
+ className: cn(
1271
+ "arclo-tool-call-output border-t border-gray-100 px-4 py-3",
1272
+ className
1273
+ ),
1274
+ ...props,
1275
+ children: [
1276
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-1.5 text-[10px] font-semibold uppercase tracking-wider text-gray-400", children: label }),
1277
+ /* @__PURE__ */ jsxRuntime.jsx(
1278
+ "div",
1279
+ {
1280
+ className: cn(
1281
+ "rounded-lg p-3 font-mono text-xs overflow-x-auto",
1282
+ status === "success" && "bg-emerald-50 text-emerald-800",
1283
+ status === "error" && "bg-red-50 text-red-800"
1284
+ ),
1285
+ children
1286
+ }
1287
+ )
1288
+ ]
1289
+ }
1290
+ );
1291
+ }
1292
+ );
1293
+ Output.displayName = "ToolCall.Output";
1294
+
1295
+ // src/chat-thread/index.ts
1296
+ var chat_thread_exports = {};
1297
+ __export(chat_thread_exports, {
1298
+ AssistantMessage: () => AssistantMessage,
1299
+ Message: () => Message,
1300
+ Messages: () => Messages,
1301
+ Root: () => Root6,
1302
+ ScrollAnchor: () => ScrollAnchor,
1303
+ SystemMessage: () => SystemMessage,
1304
+ UserMessage: () => UserMessage
1305
+ });
1306
+ var Root6 = react.forwardRef(
1307
+ ({ children, className, ...props }, ref) => {
1308
+ return /* @__PURE__ */ jsxRuntime.jsx(
1309
+ "div",
1310
+ {
1311
+ ref,
1312
+ className: cn("arclo-chat-thread flex flex-col", className),
1313
+ ...props,
1314
+ children
1315
+ }
1316
+ );
1317
+ }
1318
+ );
1319
+ Root6.displayName = "ChatThread.Root";
1320
+ var Messages = react.forwardRef(
1321
+ ({ children, className, ...props }, ref) => {
1322
+ return /* @__PURE__ */ jsxRuntime.jsx(
1323
+ "div",
1324
+ {
1325
+ ref,
1326
+ className: cn(
1327
+ "arclo-chat-messages flex-1 overflow-y-auto space-y-4 p-4 [scrollbar-width:thin] [scrollbar-color:theme(colors.gray.300)_transparent] [&::-webkit-scrollbar]:w-1.5 [&::-webkit-scrollbar-track]:bg-transparent [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:bg-gray-300",
1328
+ className
1329
+ ),
1330
+ ...props,
1331
+ children
1332
+ }
1333
+ );
1334
+ }
1335
+ );
1336
+ Messages.displayName = "ChatThread.Messages";
1337
+ var Message = react.forwardRef(
1338
+ ({ role, avatar, name, timestamp, children, className, ...props }, ref) => {
1339
+ if (role === "system") {
1340
+ return /* @__PURE__ */ jsxRuntime.jsx(
1341
+ "div",
1342
+ {
1343
+ ref,
1344
+ "data-role": role,
1345
+ className: cn(
1346
+ "arclo-chat-message flex justify-center",
1347
+ className
1348
+ ),
1349
+ ...props,
1350
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
1351
+ "div",
1352
+ {
1353
+ className: "max-w-md rounded-lg px-4 py-2 text-center text-xs",
1354
+ style: { color: themeVars.textMuted },
1355
+ children: [
1356
+ (name || timestamp) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-1 flex items-center justify-center gap-2", children: [
1357
+ avatar,
1358
+ name && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: name }),
1359
+ timestamp && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-60", children: timestamp })
1360
+ ] }),
1361
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children })
1362
+ ]
1363
+ }
1364
+ )
1365
+ }
1366
+ );
1367
+ }
1368
+ const isUser = role === "user";
1369
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1370
+ "div",
1371
+ {
1372
+ ref,
1373
+ "data-role": role,
1374
+ className: cn(
1375
+ "arclo-chat-message flex gap-3",
1376
+ isUser ? "flex-row-reverse" : "flex-row",
1377
+ className
1378
+ ),
1379
+ ...props,
1380
+ children: [
1381
+ avatar && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0 mt-1", children: avatar }),
1382
+ /* @__PURE__ */ jsxRuntime.jsxs(
1383
+ "div",
1384
+ {
1385
+ className: cn("max-w-[80%] min-w-0", isUser ? "items-end" : "items-start"),
1386
+ children: [
1387
+ (name || timestamp) && /* @__PURE__ */ jsxRuntime.jsxs(
1388
+ "div",
1389
+ {
1390
+ className: cn(
1391
+ "mb-1 flex items-center gap-2 text-xs",
1392
+ isUser ? "justify-end" : "justify-start"
1393
+ ),
1394
+ style: { color: themeVars.textSecondary },
1395
+ children: [
1396
+ name && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: name }),
1397
+ timestamp && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-60", children: timestamp })
1398
+ ]
1399
+ }
1400
+ ),
1401
+ /* @__PURE__ */ jsxRuntime.jsx(
1402
+ "div",
1403
+ {
1404
+ className: cn(
1405
+ "rounded-2xl px-4 py-3 text-sm leading-relaxed",
1406
+ isUser ? "rounded-tr-sm" : "rounded-tl-sm"
1407
+ ),
1408
+ style: isUser ? {
1409
+ backgroundColor: themeVars.accent,
1410
+ color: "#ffffff"
1411
+ } : {
1412
+ backgroundColor: themeVars.surfaceSecondary,
1413
+ color: themeVars.text,
1414
+ border: `1px solid ${themeVars.border}`
1415
+ },
1416
+ children
1417
+ }
1418
+ )
1419
+ ]
1420
+ }
1421
+ )
1422
+ ]
1423
+ }
1424
+ );
1425
+ }
1426
+ );
1427
+ Message.displayName = "ChatThread.Message";
1428
+ var UserMessage = react.forwardRef(
1429
+ (props, ref) => /* @__PURE__ */ jsxRuntime.jsx(Message, { ref, role: "user", ...props })
1430
+ );
1431
+ UserMessage.displayName = "ChatThread.UserMessage";
1432
+ var AssistantMessage = react.forwardRef((props, ref) => /* @__PURE__ */ jsxRuntime.jsx(Message, { ref, role: "assistant", ...props }));
1433
+ AssistantMessage.displayName = "ChatThread.AssistantMessage";
1434
+ var SystemMessage = react.forwardRef((props, ref) => /* @__PURE__ */ jsxRuntime.jsx(Message, { ref, role: "system", ...props }));
1435
+ SystemMessage.displayName = "ChatThread.SystemMessage";
1436
+ var ScrollAnchor = react.forwardRef(
1437
+ ({ className, ...props }, ref) => {
1438
+ const innerRef = react.useRef(null);
1439
+ const setRef = (node) => {
1440
+ innerRef.current = node;
1441
+ if (typeof ref === "function") ref(node);
1442
+ else if (ref) ref.current = node;
1443
+ };
1444
+ react.useEffect(() => {
1445
+ const el = innerRef.current;
1446
+ if (!el) return;
1447
+ const observer = new MutationObserver(() => {
1448
+ el.scrollIntoView({ behavior: "smooth", block: "end" });
1449
+ });
1450
+ const parent = el.parentElement;
1451
+ if (parent) {
1452
+ observer.observe(parent, { childList: true, subtree: true });
1453
+ }
1454
+ return () => observer.disconnect();
1455
+ }, []);
1456
+ return /* @__PURE__ */ jsxRuntime.jsx(
1457
+ "div",
1458
+ {
1459
+ ref: setRef,
1460
+ "aria-hidden": true,
1461
+ className: cn("arclo-chat-scroll-anchor h-px", className),
1462
+ ...props
1463
+ }
1464
+ );
1465
+ }
1466
+ );
1467
+ ScrollAnchor.displayName = "ChatThread.ScrollAnchor";
1468
+ var levelConfig = {
1469
+ high: {
1470
+ label: "High confidence",
1471
+ classes: "bg-emerald-50 text-emerald-700 border-emerald-200"
1472
+ },
1473
+ medium: {
1474
+ label: "Medium confidence",
1475
+ classes: "bg-amber-50 text-amber-700 border-amber-200"
1476
+ },
1477
+ low: {
1478
+ label: "Low confidence",
1479
+ classes: "bg-red-50 text-red-700 border-red-200"
1480
+ },
1481
+ unknown: {
1482
+ label: "Confidence unknown",
1483
+ classes: "bg-gray-50 text-gray-500 border-gray-200"
1484
+ }
1485
+ };
1486
+ var ConfidenceBadge = react.forwardRef(
1487
+ ({ level, label, variant = "badge", className, ...props }, ref) => {
1488
+ const config = levelConfig[level];
1489
+ const displayLabel = label ?? config.label;
1490
+ if (variant === "dot") {
1491
+ return /* @__PURE__ */ jsxRuntime.jsx(
1492
+ "span",
1493
+ {
1494
+ ref,
1495
+ role: "status",
1496
+ "aria-label": displayLabel,
1497
+ title: displayLabel,
1498
+ className: cn(
1499
+ "arclo-confidence-dot inline-block h-2.5 w-2.5 shrink-0 rounded-full",
1500
+ level === "high" && "bg-emerald-500",
1501
+ level === "medium" && "bg-amber-500",
1502
+ level === "low" && "bg-red-500",
1503
+ level === "unknown" && "bg-gray-400",
1504
+ className
1505
+ ),
1506
+ ...props
1507
+ }
1508
+ );
1509
+ }
1510
+ if (variant === "inline") {
1511
+ return /* @__PURE__ */ jsxRuntime.jsx(
1512
+ "span",
1513
+ {
1514
+ ref,
1515
+ role: "status",
1516
+ className: cn(
1517
+ "arclo-confidence-inline text-xs italic",
1518
+ level === "high" && "text-emerald-600",
1519
+ level === "medium" && "text-amber-600",
1520
+ level === "low" && "text-red-600",
1521
+ level === "unknown" && "text-gray-400",
1522
+ className
1523
+ ),
1524
+ ...props,
1525
+ children: displayLabel
1526
+ }
1527
+ );
1528
+ }
1529
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1530
+ "span",
1531
+ {
1532
+ ref,
1533
+ role: "status",
1534
+ className: cn(
1535
+ "arclo-confidence-badge inline-flex items-center gap-1.5 rounded-full border px-3 py-1 text-xs font-medium",
1536
+ config.classes,
1537
+ className
1538
+ ),
1539
+ ...props,
1540
+ children: [
1541
+ /* @__PURE__ */ jsxRuntime.jsx(
1542
+ "span",
1543
+ {
1544
+ className: cn(
1545
+ "h-2 w-2 shrink-0 rounded-full",
1546
+ level === "high" && "bg-emerald-500",
1547
+ level === "medium" && "bg-amber-500",
1548
+ level === "low" && "bg-red-500",
1549
+ level === "unknown" && "bg-gray-400"
1550
+ )
1551
+ }
1552
+ ),
1553
+ displayLabel
1554
+ ]
1555
+ }
1556
+ );
1557
+ }
1558
+ );
1559
+ ConfidenceBadge.displayName = "ConfidenceBadge";
1560
+ var CitationInline = react.forwardRef(
1561
+ ({
1562
+ index,
1563
+ href,
1564
+ sourceTitle,
1565
+ preview,
1566
+ variant = "superscript",
1567
+ className,
1568
+ ...props
1569
+ }, ref) => {
1570
+ const [showPreview, setShowPreview] = react.useState(false);
1571
+ const label = variant === "bracket" ? `[${index}]` : `${index}`;
1572
+ const Tag = href ? "a" : "span";
1573
+ const linkProps = href ? { href, target: "_blank", rel: "noopener noreferrer" } : {};
1574
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1575
+ "span",
1576
+ {
1577
+ ref,
1578
+ className: cn("arclo-citation relative inline-block", className),
1579
+ onMouseEnter: () => setShowPreview(true),
1580
+ onMouseLeave: () => setShowPreview(false),
1581
+ ...props,
1582
+ children: [
1583
+ /* @__PURE__ */ jsxRuntime.jsx(
1584
+ Tag,
1585
+ {
1586
+ ...linkProps,
1587
+ className: cn(
1588
+ "arclo-citation-trigger transition-colors cursor-pointer",
1589
+ variant === "superscript" && "align-super text-[0.65em] text-blue-600 hover:text-blue-800",
1590
+ variant === "bracket" && "text-sm text-blue-600 hover:text-blue-800",
1591
+ variant === "pill" && "inline-flex h-5 w-5 items-center justify-center rounded-full bg-blue-100 text-[0.6rem] font-medium text-blue-700 hover:bg-blue-200"
1592
+ ),
1593
+ "aria-label": sourceTitle ? `Source: ${sourceTitle}` : `Citation ${index}`,
1594
+ children: label
1595
+ }
1596
+ ),
1597
+ preview && showPreview && /* @__PURE__ */ jsxRuntime.jsxs(
1598
+ "div",
1599
+ {
1600
+ role: "tooltip",
1601
+ className: "arclo-citation-preview absolute bottom-full left-1/2 z-50 mb-2 w-64 -translate-x-1/2 rounded-lg border border-gray-200 bg-white p-3 text-sm shadow-lg",
1602
+ children: [
1603
+ sourceTitle && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-1 font-medium text-gray-900", children: sourceTitle }),
1604
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-600", children: preview }),
1605
+ href && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 truncate text-xs text-blue-500", children: href }),
1606
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-1/2 top-full -translate-x-1/2 border-4 border-transparent border-t-white" })
1607
+ ]
1608
+ }
1609
+ )
1610
+ ]
1611
+ }
1612
+ );
1613
+ }
1614
+ );
1615
+ CitationInline.displayName = "CitationInline";
1616
+ var CitationGroup = react.forwardRef(
1617
+ ({ children, className, ...props }, ref) => {
1618
+ return /* @__PURE__ */ jsxRuntime.jsx(
1619
+ "span",
1620
+ {
1621
+ ref,
1622
+ className: cn("arclo-citation-group inline-flex gap-0.5", className),
1623
+ ...props,
1624
+ children
1625
+ }
1626
+ );
1627
+ }
1628
+ );
1629
+ CitationGroup.displayName = "CitationGroup";
1630
+ var typeConfig = {
1631
+ safety: {
1632
+ icon: "\u{1F6E1}",
1633
+ defaultReason: "I can't help with that request for safety reasons.",
1634
+ accent: "border-red-200 bg-red-50"
1635
+ },
1636
+ capability: {
1637
+ icon: "\u26A1",
1638
+ defaultReason: "I'm not able to do that right now.",
1639
+ accent: "border-amber-200 bg-amber-50"
1640
+ },
1641
+ policy: {
1642
+ icon: "\u{1F4CB}",
1643
+ defaultReason: "That request falls outside my usage policy.",
1644
+ accent: "border-orange-200 bg-orange-50"
1645
+ },
1646
+ context: {
1647
+ icon: "\u{1F50D}",
1648
+ defaultReason: "I don't have enough context to help with that.",
1649
+ accent: "border-blue-200 bg-blue-50"
1650
+ }
1651
+ };
1652
+ var RefusalCard = react.forwardRef(
1653
+ ({
1654
+ reason,
1655
+ type = "capability",
1656
+ suggestions,
1657
+ onSuggestionClick,
1658
+ icon,
1659
+ className,
1660
+ children,
1661
+ ...props
1662
+ }, ref) => {
1663
+ const config = typeConfig[type];
1664
+ const displayReason = reason ?? config.defaultReason;
1665
+ return /* @__PURE__ */ jsxRuntime.jsx(
1666
+ "div",
1667
+ {
1668
+ ref,
1669
+ role: "alert",
1670
+ "data-refusal-type": type,
1671
+ className: cn(
1672
+ "arclo-refusal-card rounded-lg border p-4",
1673
+ config.accent,
1674
+ className
1675
+ ),
1676
+ ...props,
1677
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-3", children: [
1678
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-lg", "aria-hidden": true, children: icon ?? config.icon }),
1679
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1", children: [
1680
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-800", children: displayReason }),
1681
+ children,
1682
+ suggestions && suggestions.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3", children: [
1683
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-1.5 text-xs font-medium text-gray-500", children: "Try instead:" }),
1684
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2", children: suggestions.map((s) => /* @__PURE__ */ jsxRuntime.jsx(
1685
+ "button",
1686
+ {
1687
+ type: "button",
1688
+ onClick: () => onSuggestionClick?.(s),
1689
+ className: "rounded-full border border-gray-200 bg-white px-3 py-1 text-xs text-gray-600 transition-colors hover:bg-gray-50 cursor-pointer",
1690
+ children: s
1691
+ },
1692
+ s
1693
+ )) })
1694
+ ] })
1695
+ ] })
1696
+ ] })
1697
+ }
1698
+ );
1699
+ }
1700
+ );
1701
+ RefusalCard.displayName = "RefusalCard";
1702
+ function parseMarkdown(text) {
1703
+ const blocks = [];
1704
+ const lines = text.split("\n");
1705
+ let i = 0;
1706
+ while (i < lines.length) {
1707
+ const line = lines[i];
1708
+ if (line.trim() === "") {
1709
+ i++;
1710
+ continue;
1711
+ }
1712
+ if (/^(-{3,}|\*{3,}|_{3,})\s*$/.test(line)) {
1713
+ blocks.push({ type: "hr", content: "" });
1714
+ i++;
1715
+ continue;
1716
+ }
1717
+ const headingMatch = line.match(/^(#{1,6})\s+(.+)$/);
1718
+ if (headingMatch) {
1719
+ blocks.push({
1720
+ type: "heading",
1721
+ content: headingMatch[2],
1722
+ level: headingMatch[1].length
1723
+ });
1724
+ i++;
1725
+ continue;
1726
+ }
1727
+ const codeMatch = line.match(/^```(\w*)/);
1728
+ if (codeMatch) {
1729
+ const lang = codeMatch[1] || void 0;
1730
+ const codeLines = [];
1731
+ i++;
1732
+ while (i < lines.length && !lines[i].startsWith("```")) {
1733
+ codeLines.push(lines[i]);
1734
+ i++;
1735
+ }
1736
+ blocks.push({
1737
+ type: "code",
1738
+ content: codeLines.join("\n"),
1739
+ lang
1740
+ });
1741
+ i++;
1742
+ continue;
1743
+ }
1744
+ if (line.startsWith("> ")) {
1745
+ const quoteLines = [];
1746
+ while (i < lines.length && lines[i].startsWith("> ")) {
1747
+ quoteLines.push(lines[i].slice(2));
1748
+ i++;
1749
+ }
1750
+ blocks.push({ type: "blockquote", content: quoteLines.join("\n") });
1751
+ continue;
1752
+ }
1753
+ if (/^[-*+]\s/.test(line)) {
1754
+ const items = [];
1755
+ while (i < lines.length && /^[-*+]\s/.test(lines[i])) {
1756
+ items.push(lines[i].replace(/^[-*+]\s/, ""));
1757
+ i++;
1758
+ }
1759
+ blocks.push({ type: "list", content: "", items, ordered: false });
1760
+ continue;
1761
+ }
1762
+ if (/^\d+\.\s/.test(line)) {
1763
+ const items = [];
1764
+ while (i < lines.length && /^\d+\.\s/.test(lines[i])) {
1765
+ items.push(lines[i].replace(/^\d+\.\s/, ""));
1766
+ i++;
1767
+ }
1768
+ blocks.push({ type: "list", content: "", items, ordered: true });
1769
+ continue;
1770
+ }
1771
+ const paraLines = [];
1772
+ while (i < lines.length && lines[i].trim() !== "" && !lines[i].startsWith("#") && !lines[i].startsWith("```") && !lines[i].startsWith("> ") && !/^[-*+]\s/.test(lines[i]) && !/^\d+\.\s/.test(lines[i]) && !/^(-{3,}|\*{3,}|_{3,})\s*$/.test(lines[i])) {
1773
+ paraLines.push(lines[i]);
1774
+ i++;
1775
+ }
1776
+ if (paraLines.length > 0) {
1777
+ blocks.push({ type: "paragraph", content: paraLines.join("\n") });
1778
+ }
1779
+ }
1780
+ return blocks;
1781
+ }
1782
+ function renderInline(text) {
1783
+ const parts = [];
1784
+ const regex = /(\*\*(.+?)\*\*)|(\*(.+?)\*)|(`(.+?)`)|(\[(.+?)\]\((.+?)\))/g;
1785
+ let lastIndex = 0;
1786
+ let match;
1787
+ while ((match = regex.exec(text)) !== null) {
1788
+ if (match.index > lastIndex) {
1789
+ parts.push(text.slice(lastIndex, match.index));
1790
+ }
1791
+ if (match[1]) {
1792
+ parts.push(
1793
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { className: "font-semibold", children: match[2] }, match.index)
1794
+ );
1795
+ } else if (match[3]) {
1796
+ parts.push(
1797
+ /* @__PURE__ */ jsxRuntime.jsx("em", { className: "italic", children: match[4] }, match.index)
1798
+ );
1799
+ } else if (match[5]) {
1800
+ parts.push(
1801
+ /* @__PURE__ */ jsxRuntime.jsx(
1802
+ "code",
1803
+ {
1804
+ className: "rounded bg-gray-100 px-1.5 py-0.5 text-[0.85em] font-mono text-gray-800",
1805
+ children: match[6]
1806
+ },
1807
+ match.index
1808
+ )
1809
+ );
1810
+ } else if (match[7]) {
1811
+ parts.push(
1812
+ /* @__PURE__ */ jsxRuntime.jsx(
1813
+ "a",
1814
+ {
1815
+ href: match[9],
1816
+ target: "_blank",
1817
+ rel: "noopener noreferrer",
1818
+ className: "text-[#6C5CE7] underline underline-offset-2 hover:text-[#5A4BD1]",
1819
+ children: match[8]
1820
+ },
1821
+ match.index
1822
+ )
1823
+ );
1824
+ }
1825
+ lastIndex = match.index + match[0].length;
1826
+ }
1827
+ if (lastIndex < text.length) {
1828
+ parts.push(text.slice(lastIndex));
1829
+ }
1830
+ return parts.length > 0 ? parts : [text];
1831
+ }
1832
+ var MarkdownRenderer = react.forwardRef(({ content, renderCode, className, ...props }, ref) => {
1833
+ const blocks = react.useMemo(() => parseMarkdown(content), [content]);
1834
+ return /* @__PURE__ */ jsxRuntime.jsx(
1835
+ "div",
1836
+ {
1837
+ ref,
1838
+ className: cn(
1839
+ "arclo-markdown space-y-4 text-sm leading-relaxed text-gray-700",
1840
+ className
1841
+ ),
1842
+ ...props,
1843
+ children: blocks.map((block, i) => {
1844
+ switch (block.type) {
1845
+ case "heading": {
1846
+ const Tag = `h${block.level}`;
1847
+ return /* @__PURE__ */ jsxRuntime.jsx(
1848
+ Tag,
1849
+ {
1850
+ className: cn(
1851
+ "font-semibold text-gray-900",
1852
+ block.level === 1 && "text-2xl",
1853
+ block.level === 2 && "text-xl",
1854
+ block.level === 3 && "text-lg",
1855
+ (block.level ?? 4) >= 4 && "text-base"
1856
+ ),
1857
+ children: renderInline(block.content)
1858
+ },
1859
+ i
1860
+ );
1861
+ }
1862
+ case "paragraph":
1863
+ return /* @__PURE__ */ jsxRuntime.jsx("p", { children: renderInline(block.content) }, i);
1864
+ case "code":
1865
+ if (renderCode) {
1866
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { children: renderCode(block.content, block.lang) }, i);
1867
+ }
1868
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1869
+ "div",
1870
+ {
1871
+ className: "overflow-hidden rounded-xl border border-gray-200 bg-gray-50",
1872
+ children: [
1873
+ block.lang && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-gray-200 bg-gray-50 px-4 py-1.5 text-[11px] font-medium uppercase tracking-wider text-gray-400", children: block.lang }),
1874
+ /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "overflow-x-auto p-4 text-[13px] leading-relaxed", children: /* @__PURE__ */ jsxRuntime.jsx("code", { className: "font-mono text-gray-800", children: block.content }) })
1875
+ ]
1876
+ },
1877
+ i
1878
+ );
1879
+ case "list": {
1880
+ const Tag = block.ordered ? "ol" : "ul";
1881
+ return /* @__PURE__ */ jsxRuntime.jsx(
1882
+ Tag,
1883
+ {
1884
+ className: cn(
1885
+ "space-y-1 pl-6",
1886
+ block.ordered ? "list-decimal" : "list-disc"
1887
+ ),
1888
+ children: block.items?.map((item, j) => /* @__PURE__ */ jsxRuntime.jsx("li", { className: "text-gray-700", children: renderInline(item) }, j))
1889
+ },
1890
+ i
1891
+ );
1892
+ }
1893
+ case "blockquote":
1894
+ return /* @__PURE__ */ jsxRuntime.jsx(
1895
+ "blockquote",
1896
+ {
1897
+ className: "border-l-3 border-gray-300 pl-4 text-gray-500 italic",
1898
+ children: renderInline(block.content)
1899
+ },
1900
+ i
1901
+ );
1902
+ case "hr":
1903
+ return /* @__PURE__ */ jsxRuntime.jsx("hr", { className: "border-gray-200" }, i);
1904
+ default:
1905
+ return null;
1906
+ }
1907
+ })
1908
+ }
1909
+ );
1910
+ });
1911
+ MarkdownRenderer.displayName = "MarkdownRenderer";
1912
+ var stateDefaults = {
1913
+ idle: { label: "Ready", colorKey: "gray" },
1914
+ thinking: { label: "Thinking...", colorKey: "amber" },
1915
+ streaming: { label: "Writing...", colorKey: "purple" },
1916
+ "tool-calling": { label: "Using tools...", colorKey: "blue" },
1917
+ error: { label: "Error", colorKey: "red" }
1918
+ };
1919
+ var colorMap = {
1920
+ purple: { base: themeVars.accent, bright: "var(--arclo-accent-bright, rgb(167,139,250))" },
1921
+ amber: { base: "rgb(217,119,6)", bright: "rgb(251,191,36)" },
1922
+ blue: { base: "rgb(37,99,235)", bright: "rgb(96,165,250)" },
1923
+ red: { base: "rgb(239,68,68)", bright: "rgb(252,129,129)" },
1924
+ gray: { base: "rgb(156,163,175)", bright: "rgb(209,213,219)" }
1925
+ };
1926
+ var StatusIndicator = react.forwardRef(
1927
+ ({
1928
+ state = "idle",
1929
+ label,
1930
+ icon,
1931
+ color,
1932
+ animation = "sweep",
1933
+ className,
1934
+ ...props
1935
+ }, ref) => {
1936
+ const id = react.useId().replace(/:/g, "");
1937
+ const defaults = stateDefaults[state];
1938
+ const resolvedColor = color ?? defaults.colorKey;
1939
+ const colors = colorMap[resolvedColor] ?? colorMap.gray;
1940
+ const displayLabel = label ?? defaults.label;
1941
+ const isActive = state !== "idle" && state !== "error";
1942
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1943
+ "span",
1944
+ {
1945
+ ref,
1946
+ "data-state": state,
1947
+ className: cn(
1948
+ "arclo-status-indicator inline-flex items-center gap-1.5 text-sm font-medium",
1949
+ className
1950
+ ),
1951
+ style: { color: colors.base },
1952
+ ...props,
1953
+ children: [
1954
+ /* @__PURE__ */ jsxRuntime.jsx(
1955
+ "style",
1956
+ {
1957
+ dangerouslySetInnerHTML: {
1958
+ __html: `
1959
+ @keyframes arclo-sweep-${id} {
1960
+ 0%, 100% { color: ${colors.base}; opacity: 0.5; }
1961
+ 50% { color: ${colors.bright}; opacity: 1; }
1962
+ }
1963
+ @keyframes arclo-pulse-${id} {
1964
+ 0%, 100% { opacity: 1; }
1965
+ 50% { opacity: 0.4; }
1966
+ }
1967
+ @keyframes arclo-spin-${id} {
1968
+ from { transform: rotate(0deg); }
1969
+ to { transform: rotate(360deg); }
1970
+ }`
1971
+ }
1972
+ }
1973
+ ),
1974
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0", children: icon ?? /* @__PURE__ */ jsxRuntime.jsx(
1975
+ "svg",
1976
+ {
1977
+ width: "14",
1978
+ height: "14",
1979
+ viewBox: "0 0 24 24",
1980
+ fill: "currentColor",
1981
+ style: isActive ? { animation: `arclo-spin-${id} 3s linear infinite` } : void 0,
1982
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 2l2.4 7.2H22l-6 4.8 2.4 7.2L12 16.4 5.6 21.2 8 14 2 9.2h7.6L12 2z" })
1983
+ }
1984
+ ) }),
1985
+ isActive && animation === "sweep" ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-label": displayLabel, children: displayLabel.split("").map((char, i) => /* @__PURE__ */ jsxRuntime.jsx(
1986
+ "span",
1987
+ {
1988
+ style: {
1989
+ display: "inline-block",
1990
+ animation: `arclo-sweep-${id} 1.5s ease-in-out infinite`,
1991
+ animationDelay: `${i * 0.08}s`
1992
+ },
1993
+ children: char === " " ? "\xA0" : char
1994
+ },
1995
+ i
1996
+ )) }) : /* @__PURE__ */ jsxRuntime.jsx(
1997
+ "span",
1998
+ {
1999
+ style: isActive && animation === "pulse" ? {
2000
+ animation: `arclo-pulse-${id} 1.5s ease-in-out infinite`
2001
+ } : void 0,
2002
+ children: displayLabel
2003
+ }
2004
+ )
2005
+ ]
2006
+ }
2007
+ );
2008
+ }
2009
+ );
2010
+ StatusIndicator.displayName = "StatusIndicator";
2011
+ function formatNumber(n) {
2012
+ if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
2013
+ if (n >= 1e3) return `${(n / 1e3).toFixed(1)}k`;
2014
+ return n.toLocaleString();
2015
+ }
2016
+ var TokenUsage = react.forwardRef(
2017
+ ({ inputTokens, outputTokens, maxTokens, cost, className, ...props }, ref) => {
2018
+ const total = inputTokens + outputTokens;
2019
+ const inputPct = maxTokens > 0 ? inputTokens / maxTokens * 100 : 0;
2020
+ const outputPct = maxTokens > 0 ? outputTokens / maxTokens * 100 : 0;
2021
+ const totalPct = Math.min(inputPct + outputPct, 100);
2022
+ const isHigh = totalPct > 80;
2023
+ const isMedium = totalPct > 50 && totalPct <= 80;
2024
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2025
+ "div",
2026
+ {
2027
+ ref,
2028
+ className: cn(
2029
+ "arclo-token-usage rounded-lg border border-gray-200 bg-white p-4",
2030
+ className
2031
+ ),
2032
+ ...props,
2033
+ children: [
2034
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-2 flex items-center justify-between text-xs text-gray-500", children: [
2035
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-medium text-gray-700", children: [
2036
+ formatNumber(total),
2037
+ " ",
2038
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-normal text-gray-400", children: [
2039
+ "/ ",
2040
+ formatNumber(maxTokens),
2041
+ " tokens"
2042
+ ] })
2043
+ ] }),
2044
+ cost != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-medium text-gray-600", children: [
2045
+ "$",
2046
+ cost.toFixed(4)
2047
+ ] })
2048
+ ] }),
2049
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative h-2.5 w-full overflow-hidden rounded-full bg-gray-100", children: [
2050
+ /* @__PURE__ */ jsxRuntime.jsx(
2051
+ "div",
2052
+ {
2053
+ className: cn(
2054
+ "absolute inset-y-0 left-0 rounded-l-full transition-all duration-300",
2055
+ isHigh ? "bg-red-400" : isMedium ? "bg-amber-400" : "bg-blue-400"
2056
+ ),
2057
+ style: { width: `${Math.min(inputPct, 100)}%` }
2058
+ }
2059
+ ),
2060
+ /* @__PURE__ */ jsxRuntime.jsx(
2061
+ "div",
2062
+ {
2063
+ className: cn(
2064
+ "absolute inset-y-0 transition-all duration-300",
2065
+ isHigh ? "bg-red-300" : isMedium ? "bg-amber-300" : "bg-violet-400",
2066
+ outputPct > 0 && inputPct + outputPct >= 100 && "rounded-r-full"
2067
+ ),
2068
+ style: {
2069
+ left: `${Math.min(inputPct, 100)}%`,
2070
+ width: `${Math.min(outputPct, 100 - Math.min(inputPct, 100))}%`
2071
+ }
2072
+ }
2073
+ )
2074
+ ] }),
2075
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex items-center gap-4 text-[11px] text-gray-500", children: [
2076
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1.5", children: [
2077
+ /* @__PURE__ */ jsxRuntime.jsx(
2078
+ "span",
2079
+ {
2080
+ className: cn(
2081
+ "inline-block h-2 w-2 rounded-full",
2082
+ isHigh ? "bg-red-400" : isMedium ? "bg-amber-400" : "bg-blue-400"
2083
+ )
2084
+ }
2085
+ ),
2086
+ "Input: ",
2087
+ formatNumber(inputTokens)
2088
+ ] }),
2089
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1.5", children: [
2090
+ /* @__PURE__ */ jsxRuntime.jsx(
2091
+ "span",
2092
+ {
2093
+ className: cn(
2094
+ "inline-block h-2 w-2 rounded-full",
2095
+ isHigh ? "bg-red-300" : isMedium ? "bg-amber-300" : "bg-violet-400"
2096
+ )
2097
+ }
2098
+ ),
2099
+ "Output: ",
2100
+ formatNumber(outputTokens)
2101
+ ] })
2102
+ ] })
2103
+ ]
2104
+ }
2105
+ );
2106
+ }
2107
+ );
2108
+ TokenUsage.displayName = "TokenUsage";
2109
+ var ModelSelector = react.forwardRef(
2110
+ ({ models, value, onChange, className, ...props }, ref) => {
2111
+ const [open, setOpen] = react.useState(false);
2112
+ const containerRef = react.useRef(null);
2113
+ const selected = models.find((m) => m.id === value);
2114
+ react.useEffect(() => {
2115
+ if (!open) return;
2116
+ function handleClick(e) {
2117
+ if (containerRef.current && !containerRef.current.contains(e.target)) {
2118
+ setOpen(false);
2119
+ }
2120
+ }
2121
+ document.addEventListener("mousedown", handleClick);
2122
+ return () => document.removeEventListener("mousedown", handleClick);
2123
+ }, [open]);
2124
+ react.useEffect(() => {
2125
+ if (!open) return;
2126
+ function handleKey(e) {
2127
+ if (e.key === "Escape") setOpen(false);
2128
+ }
2129
+ document.addEventListener("keydown", handleKey);
2130
+ return () => document.removeEventListener("keydown", handleKey);
2131
+ }, [open]);
2132
+ return /* @__PURE__ */ jsxRuntime.jsx(
2133
+ "div",
2134
+ {
2135
+ ref,
2136
+ className: cn("arclo-model-selector relative inline-block", className),
2137
+ ...props,
2138
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: containerRef, children: [
2139
+ /* @__PURE__ */ jsxRuntime.jsxs(
2140
+ "button",
2141
+ {
2142
+ type: "button",
2143
+ onClick: () => setOpen((o) => !o),
2144
+ "aria-expanded": open,
2145
+ "aria-haspopup": "listbox",
2146
+ className: "cursor-pointer inline-flex items-center gap-2 rounded-lg border border-gray-200 bg-white px-3 py-2 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-50",
2147
+ children: [
2148
+ /* @__PURE__ */ jsxRuntime.jsx(
2149
+ "svg",
2150
+ {
2151
+ width: "14",
2152
+ height: "14",
2153
+ viewBox: "0 0 24 24",
2154
+ fill: "none",
2155
+ stroke: "currentColor",
2156
+ strokeWidth: "2",
2157
+ strokeLinecap: "round",
2158
+ strokeLinejoin: "round",
2159
+ className: "shrink-0 text-gray-400",
2160
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 2l2.4 7.2H22l-6 4.8 2.4 7.2L12 16.4 5.6 21.2 8 14 2 9.2h7.6L12 2z" })
2161
+ }
2162
+ ),
2163
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: selected?.name ?? value }),
2164
+ selected?.badge && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded-full bg-[#6C5CE7]/10 px-2 py-0.5 text-[10px] font-semibold text-[#6C5CE7]", children: selected.badge }),
2165
+ /* @__PURE__ */ jsxRuntime.jsx(
2166
+ "svg",
2167
+ {
2168
+ width: "12",
2169
+ height: "12",
2170
+ viewBox: "0 0 24 24",
2171
+ fill: "none",
2172
+ stroke: "currentColor",
2173
+ strokeWidth: "2",
2174
+ strokeLinecap: "round",
2175
+ strokeLinejoin: "round",
2176
+ className: cn(
2177
+ "shrink-0 text-gray-400 transition-transform",
2178
+ open && "rotate-180"
2179
+ ),
2180
+ children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "6 9 12 15 18 9" })
2181
+ }
2182
+ )
2183
+ ]
2184
+ }
2185
+ ),
2186
+ open && /* @__PURE__ */ jsxRuntime.jsx(
2187
+ "div",
2188
+ {
2189
+ role: "listbox",
2190
+ className: "absolute left-0 z-50 mt-1 w-72 overflow-hidden rounded-xl border border-gray-200 bg-white shadow-lg",
2191
+ children: models.map((model) => {
2192
+ const isSelected = model.id === value;
2193
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2194
+ "button",
2195
+ {
2196
+ type: "button",
2197
+ role: "option",
2198
+ "aria-selected": isSelected,
2199
+ onClick: () => {
2200
+ onChange(model.id);
2201
+ setOpen(false);
2202
+ },
2203
+ className: cn(
2204
+ "cursor-pointer flex w-full items-start gap-3 px-4 py-3 text-left transition-colors hover:bg-gray-50",
2205
+ isSelected && "bg-gray-50"
2206
+ ),
2207
+ children: [
2208
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
2209
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
2210
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium text-gray-800", children: model.name }),
2211
+ model.badge && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded-full bg-[#6C5CE7]/10 px-2 py-0.5 text-[10px] font-semibold text-[#6C5CE7]", children: model.badge })
2212
+ ] }),
2213
+ model.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-0.5 text-xs text-gray-400 truncate", children: model.description })
2214
+ ] }),
2215
+ isSelected && /* @__PURE__ */ jsxRuntime.jsx(
2216
+ "svg",
2217
+ {
2218
+ width: "16",
2219
+ height: "16",
2220
+ viewBox: "0 0 24 24",
2221
+ fill: "none",
2222
+ stroke: "currentColor",
2223
+ strokeWidth: "2",
2224
+ strokeLinecap: "round",
2225
+ strokeLinejoin: "round",
2226
+ className: "mt-0.5 shrink-0 text-[#6C5CE7]",
2227
+ children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "20 6 9 17 4 12" })
2228
+ }
2229
+ )
2230
+ ]
2231
+ },
2232
+ model.id
2233
+ );
2234
+ })
2235
+ }
2236
+ )
2237
+ ] })
2238
+ }
2239
+ );
2240
+ }
2241
+ );
2242
+ ModelSelector.displayName = "ModelSelector";
2243
+ function relevanceColor(score) {
2244
+ if (score >= 0.8) return { bar: "bg-emerald-400", text: "text-emerald-600" };
2245
+ if (score >= 0.5) return { bar: "bg-amber-400", text: "text-amber-600" };
2246
+ return { bar: "bg-red-400", text: "text-red-600" };
2247
+ }
2248
+ function relevanceLabel(score) {
2249
+ if (score >= 0.8) return "High";
2250
+ if (score >= 0.5) return "Medium";
2251
+ return "Low";
2252
+ }
2253
+ var SourceCard = react.forwardRef(
2254
+ ({ title, url, content, relevance, variant = "full", className, ...props }, ref) => {
2255
+ const colors = relevanceColor(relevance);
2256
+ const pct = Math.round(relevance * 100);
2257
+ if (variant === "compact") {
2258
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2259
+ "div",
2260
+ {
2261
+ ref,
2262
+ "data-variant": "compact",
2263
+ className: cn(
2264
+ "arclo-source-card flex items-start gap-3 rounded-lg border border-gray-200 bg-white px-3 py-2.5",
2265
+ className
2266
+ ),
2267
+ ...props,
2268
+ children: [
2269
+ /* @__PURE__ */ jsxRuntime.jsx(
2270
+ "span",
2271
+ {
2272
+ className: cn("mt-1 inline-block h-2 w-2 shrink-0 rounded-full", colors.bar),
2273
+ title: `${pct}% relevance`
2274
+ }
2275
+ ),
2276
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
2277
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
2278
+ url ? /* @__PURE__ */ jsxRuntime.jsx(
2279
+ "a",
2280
+ {
2281
+ href: url,
2282
+ target: "_blank",
2283
+ rel: "noopener noreferrer",
2284
+ className: "truncate text-sm font-medium text-gray-800 hover:text-[#6C5CE7] hover:underline",
2285
+ children: title
2286
+ }
2287
+ ) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-sm font-medium text-gray-800", children: title }),
2288
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("shrink-0 text-[10px] font-semibold", colors.text), children: [
2289
+ pct,
2290
+ "%"
2291
+ ] })
2292
+ ] }),
2293
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-0.5 truncate text-xs text-gray-400", children: content })
2294
+ ] })
2295
+ ]
2296
+ }
2297
+ );
2298
+ }
2299
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2300
+ "div",
2301
+ {
2302
+ ref,
2303
+ "data-variant": "full",
2304
+ className: cn(
2305
+ "arclo-source-card overflow-hidden rounded-lg border border-gray-200 bg-white",
2306
+ className
2307
+ ),
2308
+ ...props,
2309
+ children: [
2310
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative h-1.5 w-full bg-gray-100", children: /* @__PURE__ */ jsxRuntime.jsx(
2311
+ "div",
2312
+ {
2313
+ className: cn("absolute inset-y-0 left-0 transition-all duration-300", colors.bar),
2314
+ style: { width: `${pct}%` }
2315
+ }
2316
+ ) }),
2317
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4", children: [
2318
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-2", children: [
2319
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
2320
+ url ? /* @__PURE__ */ jsxRuntime.jsx(
2321
+ "a",
2322
+ {
2323
+ href: url,
2324
+ target: "_blank",
2325
+ rel: "noopener noreferrer",
2326
+ className: "text-sm font-medium text-gray-800 hover:text-[#6C5CE7] hover:underline",
2327
+ children: title
2328
+ }
2329
+ ) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium text-gray-800", children: title }),
2330
+ url && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-0.5 truncate text-xs text-gray-400", children: url })
2331
+ ] }),
2332
+ /* @__PURE__ */ jsxRuntime.jsxs(
2333
+ "span",
2334
+ {
2335
+ className: cn(
2336
+ "shrink-0 rounded-full border px-2 py-0.5 text-[10px] font-semibold",
2337
+ relevance >= 0.8 && "border-emerald-200 bg-emerald-50 text-emerald-700",
2338
+ relevance >= 0.5 && relevance < 0.8 && "border-amber-200 bg-amber-50 text-amber-700",
2339
+ relevance < 0.5 && "border-red-200 bg-red-50 text-red-700"
2340
+ ),
2341
+ children: [
2342
+ relevanceLabel(relevance),
2343
+ " ",
2344
+ pct,
2345
+ "%"
2346
+ ]
2347
+ }
2348
+ )
2349
+ ] }),
2350
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 line-clamp-3 text-sm leading-relaxed text-gray-500", children: content })
2351
+ ] })
2352
+ ]
2353
+ }
2354
+ );
2355
+ }
2356
+ );
2357
+ SourceCard.displayName = "SourceCard";
2358
+ function FileIcon({
2359
+ type,
2360
+ className
2361
+ }) {
2362
+ const base = cn("shrink-0", className);
2363
+ if (type === "image") {
2364
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2365
+ "svg",
2366
+ {
2367
+ className: base,
2368
+ viewBox: "0 0 24 24",
2369
+ fill: "none",
2370
+ stroke: "currentColor",
2371
+ strokeWidth: "1.5",
2372
+ strokeLinecap: "round",
2373
+ strokeLinejoin: "round",
2374
+ children: [
2375
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }),
2376
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "8.5", cy: "8.5", r: "1.5" }),
2377
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m21 15-5-5L5 21" })
2378
+ ]
2379
+ }
2380
+ );
2381
+ }
2382
+ if (type === "pdf") {
2383
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2384
+ "svg",
2385
+ {
2386
+ className: base,
2387
+ viewBox: "0 0 24 24",
2388
+ fill: "none",
2389
+ stroke: "currentColor",
2390
+ strokeWidth: "1.5",
2391
+ strokeLinecap: "round",
2392
+ strokeLinejoin: "round",
2393
+ children: [
2394
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z" }),
2395
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M14 2v6h6" }),
2396
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M9 15v-1h2a1 1 0 0 1 0 2H9" })
2397
+ ]
2398
+ }
2399
+ );
2400
+ }
2401
+ if (type === "code") {
2402
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2403
+ "svg",
2404
+ {
2405
+ className: base,
2406
+ viewBox: "0 0 24 24",
2407
+ fill: "none",
2408
+ stroke: "currentColor",
2409
+ strokeWidth: "1.5",
2410
+ strokeLinecap: "round",
2411
+ strokeLinejoin: "round",
2412
+ children: [
2413
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z" }),
2414
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M14 2v6h6" }),
2415
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m10 13-2 2 2 2" }),
2416
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m14 17 2-2-2-2" })
2417
+ ]
2418
+ }
2419
+ );
2420
+ }
2421
+ if (type === "csv") {
2422
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2423
+ "svg",
2424
+ {
2425
+ className: base,
2426
+ viewBox: "0 0 24 24",
2427
+ fill: "none",
2428
+ stroke: "currentColor",
2429
+ strokeWidth: "1.5",
2430
+ strokeLinecap: "round",
2431
+ strokeLinejoin: "round",
2432
+ children: [
2433
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z" }),
2434
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M14 2v6h6" }),
2435
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 15h8" }),
2436
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 11h8" }),
2437
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 11v8" })
2438
+ ]
2439
+ }
2440
+ );
2441
+ }
2442
+ if (type === "text") {
2443
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2444
+ "svg",
2445
+ {
2446
+ className: base,
2447
+ viewBox: "0 0 24 24",
2448
+ fill: "none",
2449
+ stroke: "currentColor",
2450
+ strokeWidth: "1.5",
2451
+ strokeLinecap: "round",
2452
+ strokeLinejoin: "round",
2453
+ children: [
2454
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z" }),
2455
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M14 2v6h6" }),
2456
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M16 13H8" }),
2457
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M16 17H8" }),
2458
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10 9H8" })
2459
+ ]
2460
+ }
2461
+ );
2462
+ }
2463
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2464
+ "svg",
2465
+ {
2466
+ className: base,
2467
+ viewBox: "0 0 24 24",
2468
+ fill: "none",
2469
+ stroke: "currentColor",
2470
+ strokeWidth: "1.5",
2471
+ strokeLinecap: "round",
2472
+ strokeLinejoin: "round",
2473
+ children: [
2474
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z" }),
2475
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M14 2v6h6" })
2476
+ ]
2477
+ }
2478
+ );
2479
+ }
2480
+ var FileAttachment = react.forwardRef(
2481
+ ({
2482
+ name,
2483
+ size,
2484
+ type = "other",
2485
+ preview,
2486
+ progress,
2487
+ onRemove,
2488
+ variant = "chip",
2489
+ className,
2490
+ ...props
2491
+ }, ref) => {
2492
+ if (variant === "card") {
2493
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2494
+ "div",
2495
+ {
2496
+ ref,
2497
+ className: cn(
2498
+ "arclo-file-attachment-card group relative inline-flex w-48 flex-col overflow-hidden rounded-xl border border-gray-200 bg-white",
2499
+ className
2500
+ ),
2501
+ ...props,
2502
+ children: [
2503
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex h-28 items-center justify-center bg-gray-50", children: [
2504
+ preview ? /* @__PURE__ */ jsxRuntime.jsx(
2505
+ "img",
2506
+ {
2507
+ src: preview,
2508
+ alt: name,
2509
+ className: "h-full w-full object-cover"
2510
+ }
2511
+ ) : /* @__PURE__ */ jsxRuntime.jsx(FileIcon, { type, className: "h-10 w-10 text-gray-300" }),
2512
+ onRemove && /* @__PURE__ */ jsxRuntime.jsx(
2513
+ "button",
2514
+ {
2515
+ type: "button",
2516
+ onClick: onRemove,
2517
+ "aria-label": `Remove ${name}`,
2518
+ className: "absolute right-1.5 top-1.5 flex h-6 w-6 items-center justify-center rounded-full bg-black/50 text-white opacity-0 transition-opacity hover:bg-black/70 group-hover:opacity-100 cursor-pointer",
2519
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2520
+ "svg",
2521
+ {
2522
+ className: "h-3 w-3",
2523
+ viewBox: "0 0 24 24",
2524
+ fill: "none",
2525
+ stroke: "currentColor",
2526
+ strokeWidth: "2.5",
2527
+ strokeLinecap: "round",
2528
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m18 6-12 12M6 6l12 12" })
2529
+ }
2530
+ )
2531
+ }
2532
+ )
2533
+ ] }),
2534
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-0.5 px-3 py-2", children: [
2535
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-xs font-medium text-gray-700", children: name }),
2536
+ size && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-gray-400", children: size })
2537
+ ] }),
2538
+ progress != null && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-1 w-full bg-gray-100", children: /* @__PURE__ */ jsxRuntime.jsx(
2539
+ "div",
2540
+ {
2541
+ className: "h-full rounded-r-full bg-[#6C5CE7] transition-all duration-300",
2542
+ style: { width: `${Math.min(100, Math.max(0, progress))}%` }
2543
+ }
2544
+ ) })
2545
+ ]
2546
+ }
2547
+ );
2548
+ }
2549
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2550
+ "div",
2551
+ {
2552
+ ref,
2553
+ className: cn(
2554
+ "arclo-file-attachment-chip group inline-flex items-center gap-2 rounded-lg border border-gray-200 bg-white px-3 py-2",
2555
+ className
2556
+ ),
2557
+ ...props,
2558
+ children: [
2559
+ /* @__PURE__ */ jsxRuntime.jsx(FileIcon, { type, className: "h-4 w-4 text-gray-400" }),
2560
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col", children: [
2561
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-xs font-medium text-gray-700", children: name }),
2562
+ (size || progress != null) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
2563
+ size && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-gray-400", children: size }),
2564
+ progress != null && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-1 w-16 rounded-full bg-gray-100", children: /* @__PURE__ */ jsxRuntime.jsx(
2565
+ "div",
2566
+ {
2567
+ className: "h-full rounded-full bg-[#6C5CE7] transition-all duration-300",
2568
+ style: {
2569
+ width: `${Math.min(100, Math.max(0, progress))}%`
2570
+ }
2571
+ }
2572
+ ) })
2573
+ ] })
2574
+ ] }),
2575
+ onRemove && /* @__PURE__ */ jsxRuntime.jsx(
2576
+ "button",
2577
+ {
2578
+ type: "button",
2579
+ onClick: onRemove,
2580
+ "aria-label": `Remove ${name}`,
2581
+ className: "ml-1 flex h-4 w-4 shrink-0 items-center justify-center rounded-full text-gray-300 transition-colors hover:bg-gray-100 hover:text-gray-500 cursor-pointer",
2582
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2583
+ "svg",
2584
+ {
2585
+ className: "h-3 w-3",
2586
+ viewBox: "0 0 24 24",
2587
+ fill: "none",
2588
+ stroke: "currentColor",
2589
+ strokeWidth: "2.5",
2590
+ strokeLinecap: "round",
2591
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m18 6-12 12M6 6l12 12" })
2592
+ }
2593
+ )
2594
+ }
2595
+ )
2596
+ ]
2597
+ }
2598
+ );
2599
+ }
2600
+ );
2601
+ FileAttachment.displayName = "FileAttachment";
2602
+ var CodeBlock = react.forwardRef(
2603
+ ({
2604
+ code,
2605
+ language,
2606
+ showLineNumbers = false,
2607
+ maxHeight = "400px",
2608
+ onCopy,
2609
+ className,
2610
+ ...props
2611
+ }, ref) => {
2612
+ const [copied, setCopied] = react.useState(false);
2613
+ const handleCopy = react.useCallback(() => {
2614
+ navigator.clipboard.writeText(code).then(() => {
2615
+ setCopied(true);
2616
+ onCopy?.();
2617
+ setTimeout(() => setCopied(false), 2e3);
2618
+ });
2619
+ }, [code, onCopy]);
2620
+ const lines = code.split("\n");
2621
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2622
+ "div",
2623
+ {
2624
+ ref,
2625
+ className: cn(
2626
+ "arclo-code-block overflow-hidden rounded-xl border",
2627
+ className
2628
+ ),
2629
+ style: { backgroundColor: "#1e1e2e", borderColor: "#313244" },
2630
+ ...props,
2631
+ children: [
2632
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 py-2", style: { borderBottom: "1px solid #313244" }, children: [
2633
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[11px] font-medium uppercase tracking-wider", style: { color: "#a6adc8" }, children: language ?? "code" }),
2634
+ /* @__PURE__ */ jsxRuntime.jsx(
2635
+ "button",
2636
+ {
2637
+ type: "button",
2638
+ onClick: handleCopy,
2639
+ className: "flex items-center gap-1.5 rounded-md px-2 py-1 text-[11px] transition-colors cursor-pointer",
2640
+ style: { color: "#a6adc8" },
2641
+ children: copied ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2642
+ /* @__PURE__ */ jsxRuntime.jsx(
2643
+ "svg",
2644
+ {
2645
+ className: "h-3.5 w-3.5 text-emerald-400",
2646
+ viewBox: "0 0 24 24",
2647
+ fill: "none",
2648
+ stroke: "currentColor",
2649
+ strokeWidth: "2",
2650
+ strokeLinecap: "round",
2651
+ strokeLinejoin: "round",
2652
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 6 9 17l-5-5" })
2653
+ }
2654
+ ),
2655
+ "Copied"
2656
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2657
+ /* @__PURE__ */ jsxRuntime.jsxs(
2658
+ "svg",
2659
+ {
2660
+ className: "h-3.5 w-3.5",
2661
+ viewBox: "0 0 24 24",
2662
+ fill: "none",
2663
+ stroke: "currentColor",
2664
+ strokeWidth: "2",
2665
+ strokeLinecap: "round",
2666
+ strokeLinejoin: "round",
2667
+ children: [
2668
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2" }),
2669
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
2670
+ ]
2671
+ }
2672
+ ),
2673
+ "Copy"
2674
+ ] })
2675
+ }
2676
+ )
2677
+ ] }),
2678
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-auto [scrollbar-width:thin] [scrollbar-color:theme(colors.gray.700)_transparent] [&::-webkit-scrollbar]:w-1.5 [&::-webkit-scrollbar-track]:bg-transparent [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:bg-gray-700", style: { maxHeight }, children: /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "p-4 text-[13px] leading-relaxed", children: /* @__PURE__ */ jsxRuntime.jsx("code", { className: "font-mono", style: { color: "#cdd6f4" }, children: lines.map((line, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex", children: [
2679
+ showLineNumbers && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mr-4 inline-block w-8 shrink-0 select-none text-right", style: { color: "#585b70" }, children: i + 1 }),
2680
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children: line || "\n" })
2681
+ ] }, i)) }) }) })
2682
+ ]
2683
+ }
2684
+ );
2685
+ }
2686
+ );
2687
+ CodeBlock.displayName = "CodeBlock";
2688
+ var ConversationBranch = react.forwardRef(({ current, total, onPrevious, onNext, className, ...props }, ref) => {
2689
+ const atStart = current <= 1;
2690
+ const atEnd = current >= total;
2691
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2692
+ "div",
2693
+ {
2694
+ ref,
2695
+ className: cn(
2696
+ "arclo-conversation-branch inline-flex items-center gap-1 rounded-lg border border-gray-200 bg-white",
2697
+ className
2698
+ ),
2699
+ ...props,
2700
+ children: [
2701
+ /* @__PURE__ */ jsxRuntime.jsx(
2702
+ "button",
2703
+ {
2704
+ type: "button",
2705
+ onClick: onPrevious,
2706
+ disabled: atStart,
2707
+ "aria-label": "Previous branch",
2708
+ className: cn(
2709
+ "flex h-7 w-7 items-center justify-center rounded-l-lg transition-colors cursor-pointer",
2710
+ atStart ? "cursor-not-allowed text-gray-200" : "text-gray-400 hover:bg-gray-50 hover:text-gray-600"
2711
+ ),
2712
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2713
+ "svg",
2714
+ {
2715
+ className: "h-3.5 w-3.5",
2716
+ viewBox: "0 0 24 24",
2717
+ fill: "none",
2718
+ stroke: "currentColor",
2719
+ strokeWidth: "2",
2720
+ strokeLinecap: "round",
2721
+ strokeLinejoin: "round",
2722
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m15 18-6-6 6-6" })
2723
+ }
2724
+ )
2725
+ }
2726
+ ),
2727
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "select-none px-1 text-xs font-medium tabular-nums text-gray-500", children: [
2728
+ current,
2729
+ "/",
2730
+ total
2731
+ ] }),
2732
+ /* @__PURE__ */ jsxRuntime.jsx(
2733
+ "button",
2734
+ {
2735
+ type: "button",
2736
+ onClick: onNext,
2737
+ disabled: atEnd,
2738
+ "aria-label": "Next branch",
2739
+ className: cn(
2740
+ "flex h-7 w-7 items-center justify-center rounded-r-lg transition-colors cursor-pointer",
2741
+ atEnd ? "cursor-not-allowed text-gray-200" : "text-gray-400 hover:bg-gray-50 hover:text-gray-600"
2742
+ ),
2743
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2744
+ "svg",
2745
+ {
2746
+ className: "h-3.5 w-3.5",
2747
+ viewBox: "0 0 24 24",
2748
+ fill: "none",
2749
+ stroke: "currentColor",
2750
+ strokeWidth: "2",
2751
+ strokeLinecap: "round",
2752
+ strokeLinejoin: "round",
2753
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m9 18 6-6-6-6" })
2754
+ }
2755
+ )
2756
+ }
2757
+ )
2758
+ ]
2759
+ }
2760
+ );
2761
+ });
2762
+ ConversationBranch.displayName = "ConversationBranch";
2763
+ var TopicCard = react.forwardRef(
2764
+ ({ title, description, icon, onSelect, variant = "card", className, ...props }, ref) => {
2765
+ if (variant === "compact") {
2766
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2767
+ "button",
2768
+ {
2769
+ ref,
2770
+ type: "button",
2771
+ onClick: () => onSelect?.(title),
2772
+ className: cn(
2773
+ "arclo-topic-card inline-flex shrink-0 items-center gap-2 rounded-full border px-3.5 py-2 text-left transition-all cursor-pointer",
2774
+ "hover:shadow-sm",
2775
+ className
2776
+ ),
2777
+ style: {
2778
+ backgroundColor: themeVars.surface,
2779
+ borderColor: themeVars.border
2780
+ },
2781
+ ...props,
2782
+ children: [
2783
+ icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-sm", children: icon }),
2784
+ /* @__PURE__ */ jsxRuntime.jsx(
2785
+ "span",
2786
+ {
2787
+ className: "text-xs font-medium whitespace-nowrap",
2788
+ style: { color: themeVars.text },
2789
+ children: title
2790
+ }
2791
+ )
2792
+ ]
2793
+ }
2794
+ );
2795
+ }
2796
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2797
+ "button",
2798
+ {
2799
+ ref,
2800
+ type: "button",
2801
+ onClick: () => onSelect?.(title),
2802
+ className: cn(
2803
+ "arclo-topic-card group flex w-full items-start gap-3 rounded-xl border p-4 text-left transition-all cursor-pointer",
2804
+ "hover:scale-[1.01] hover:shadow-sm",
2805
+ className
2806
+ ),
2807
+ style: {
2808
+ backgroundColor: themeVars.surface,
2809
+ borderColor: themeVars.border
2810
+ },
2811
+ ...props,
2812
+ children: [
2813
+ icon && /* @__PURE__ */ jsxRuntime.jsx(
2814
+ "span",
2815
+ {
2816
+ className: "mt-0.5 flex h-8 w-8 shrink-0 items-center justify-center rounded-lg text-sm",
2817
+ style: {
2818
+ backgroundColor: `color-mix(in srgb, ${themeVars.accent} 10%, transparent)`,
2819
+ color: themeVars.accent
2820
+ },
2821
+ children: icon
2822
+ }
2823
+ ),
2824
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
2825
+ /* @__PURE__ */ jsxRuntime.jsx(
2826
+ "p",
2827
+ {
2828
+ className: "text-sm font-medium leading-snug",
2829
+ style: { color: themeVars.text },
2830
+ children: title
2831
+ }
2832
+ ),
2833
+ description && /* @__PURE__ */ jsxRuntime.jsx(
2834
+ "p",
2835
+ {
2836
+ className: "mt-1 text-xs leading-relaxed",
2837
+ style: { color: themeVars.textMuted },
2838
+ children: description
2839
+ }
2840
+ )
2841
+ ] }),
2842
+ /* @__PURE__ */ jsxRuntime.jsx(
2843
+ "svg",
2844
+ {
2845
+ className: "mt-1 h-4 w-4 shrink-0 opacity-0 transition-opacity group-hover:opacity-100",
2846
+ style: { color: themeVars.textMuted },
2847
+ viewBox: "0 0 24 24",
2848
+ fill: "none",
2849
+ stroke: "currentColor",
2850
+ strokeWidth: "2",
2851
+ strokeLinecap: "round",
2852
+ strokeLinejoin: "round",
2853
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 12h14M12 5l7 7-7 7" })
2854
+ }
2855
+ )
2856
+ ]
2857
+ }
2858
+ );
2859
+ }
2860
+ );
2861
+ TopicCard.displayName = "TopicCard";
2862
+ var SuggestTopics = react.forwardRef(
2863
+ ({ variant = "grid", columns = 2, children, className, ...props }, ref) => {
2864
+ const scrollRef = react.useRef(null);
2865
+ const isDragging = react.useRef(false);
2866
+ const startX = react.useRef(0);
2867
+ const scrollLeft = react.useRef(0);
2868
+ const hasDragged = react.useRef(false);
2869
+ const onMouseDown = react.useCallback((e) => {
2870
+ const el = scrollRef.current;
2871
+ if (!el) return;
2872
+ isDragging.current = true;
2873
+ hasDragged.current = false;
2874
+ startX.current = e.pageX - el.offsetLeft;
2875
+ scrollLeft.current = el.scrollLeft;
2876
+ el.style.cursor = "grabbing";
2877
+ el.style.userSelect = "none";
2878
+ }, []);
2879
+ const onMouseMove = react.useCallback((e) => {
2880
+ if (!isDragging.current) return;
2881
+ const el = scrollRef.current;
2882
+ if (!el) return;
2883
+ e.preventDefault();
2884
+ const x = e.pageX - el.offsetLeft;
2885
+ const walk = (x - startX.current) * 1.5;
2886
+ if (Math.abs(walk) > 3) hasDragged.current = true;
2887
+ el.scrollLeft = scrollLeft.current - walk;
2888
+ }, []);
2889
+ const onMouseUp = react.useCallback(() => {
2890
+ isDragging.current = false;
2891
+ const el = scrollRef.current;
2892
+ if (el) {
2893
+ el.style.cursor = "grab";
2894
+ el.style.userSelect = "";
2895
+ }
2896
+ }, []);
2897
+ const onClickCapture = react.useCallback((e) => {
2898
+ if (hasDragged.current) {
2899
+ e.stopPropagation();
2900
+ e.preventDefault();
2901
+ hasDragged.current = false;
2902
+ }
2903
+ }, []);
2904
+ if (variant === "compact") {
2905
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2906
+ "div",
2907
+ {
2908
+ ref: (node) => {
2909
+ scrollRef.current = node;
2910
+ if (typeof ref === "function") ref(node);
2911
+ else if (ref) ref.current = node;
2912
+ },
2913
+ className: cn(
2914
+ "arclo-suggest-topics",
2915
+ className
2916
+ ),
2917
+ style: {
2918
+ display: "flex",
2919
+ gap: "0.5rem",
2920
+ overflowX: "auto",
2921
+ cursor: "grab",
2922
+ scrollbarWidth: "none",
2923
+ msOverflowStyle: "none"
2924
+ },
2925
+ onMouseDown,
2926
+ onMouseMove,
2927
+ onMouseUp,
2928
+ onMouseLeave: onMouseUp,
2929
+ onClickCapture,
2930
+ ...props,
2931
+ children: [
2932
+ children,
2933
+ /* @__PURE__ */ jsxRuntime.jsx("style", { dangerouslySetInnerHTML: { __html: `.arclo-suggest-topics::-webkit-scrollbar { display: none; }` } })
2934
+ ]
2935
+ }
2936
+ );
2937
+ }
2938
+ return /* @__PURE__ */ jsxRuntime.jsx(
2939
+ "div",
2940
+ {
2941
+ ref,
2942
+ className: cn(
2943
+ "arclo-suggest-topics grid gap-3",
2944
+ columns === 1 && "grid-cols-1",
2945
+ columns === 2 && "grid-cols-1 sm:grid-cols-2",
2946
+ columns === 3 && "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",
2947
+ className
2948
+ ),
2949
+ ...props,
2950
+ children
2951
+ }
2952
+ );
2953
+ }
2954
+ );
2955
+ SuggestTopics.displayName = "SuggestTopics";
2956
+
2957
+ exports.ChatThread = chat_thread_exports;
2958
+ exports.CitationGroup = CitationGroup;
2959
+ exports.CitationInline = CitationInline;
2960
+ exports.CodeBlock = CodeBlock;
2961
+ exports.ConfidenceBadge = ConfidenceBadge;
2962
+ exports.ConversationBranch = ConversationBranch;
2963
+ exports.FeedbackBar = feedback_bar_exports;
2964
+ exports.FileAttachment = FileAttachment;
2965
+ exports.MarkdownRenderer = MarkdownRenderer;
2966
+ exports.ModelSelector = ModelSelector;
2967
+ exports.PromptBox = prompt_box_exports;
2968
+ exports.RefusalCard = RefusalCard;
2969
+ exports.SourceCard = SourceCard;
2970
+ exports.StatusIndicator = StatusIndicator;
2971
+ exports.StreamingText = streaming_text_exports;
2972
+ exports.SuggestTopics = SuggestTopics;
2973
+ exports.ThinkingBlock = thinking_block_exports;
2974
+ exports.TokenUsage = TokenUsage;
2975
+ exports.ToolCall = tool_call_exports;
2976
+ exports.TopicCard = TopicCard;
2977
+ exports.useStreamingText = useStreamingText;
2978
+ //# sourceMappingURL=index.cjs.map
2979
+ //# sourceMappingURL=index.cjs.map