@copilotz/chat-ui 0.1.20 → 0.1.22
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 +93 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +116 -22
- package/dist/index.js.map +1 -1
- package/dist/styles.css +57 -0
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -38,6 +38,8 @@ interface ChatMessage {
|
|
|
38
38
|
id: string;
|
|
39
39
|
role: 'user' | 'assistant' | 'system';
|
|
40
40
|
content: string;
|
|
41
|
+
/** Optional model reasoning stream (when the backend emits reasoning tokens separately). */
|
|
42
|
+
reasoning?: string;
|
|
41
43
|
timestamp: number;
|
|
42
44
|
attachments?: MediaAttachment[];
|
|
43
45
|
isStreaming?: boolean;
|
package/dist/index.d.ts
CHANGED
|
@@ -38,6 +38,8 @@ interface ChatMessage {
|
|
|
38
38
|
id: string;
|
|
39
39
|
role: 'user' | 'assistant' | 'system';
|
|
40
40
|
content: string;
|
|
41
|
+
/** Optional model reasoning stream (when the backend emits reasoning tokens separately). */
|
|
42
|
+
reasoning?: string;
|
|
41
43
|
timestamp: number;
|
|
42
44
|
attachments?: MediaAttachment[];
|
|
43
45
|
isStreaming?: boolean;
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/components/chat/ChatUI.tsx
|
|
2
|
-
import { useState as useState8, useEffect as useEffect10, useRef as
|
|
2
|
+
import { useState as useState8, useEffect as useEffect10, useRef as useRef7, useCallback as useCallback4, useMemo as useMemo4 } from "react";
|
|
3
3
|
import { useVirtualizer } from "@tanstack/react-virtual";
|
|
4
4
|
|
|
5
5
|
// src/config/chatConfig.ts
|
|
@@ -245,7 +245,7 @@ var configUtils = {
|
|
|
245
245
|
};
|
|
246
246
|
|
|
247
247
|
// src/components/chat/Message.tsx
|
|
248
|
-
import React, { useState, useMemo, useEffect, memo } from "react";
|
|
248
|
+
import React, { useState, useMemo, useEffect, useRef, memo } from "react";
|
|
249
249
|
import ReactMarkdown from "react-markdown";
|
|
250
250
|
import remarkGfm from "remark-gfm";
|
|
251
251
|
import rehypeHighlight from "rehype-highlight";
|
|
@@ -553,7 +553,8 @@ import {
|
|
|
553
553
|
Wrench,
|
|
554
554
|
Clock,
|
|
555
555
|
ChevronRight,
|
|
556
|
-
ChevronDown
|
|
556
|
+
ChevronDown,
|
|
557
|
+
BrainCircuit
|
|
557
558
|
} from "lucide-react";
|
|
558
559
|
import { Fragment, jsx as jsx7, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
559
560
|
var ThinkingIndicator = memo(function ThinkingIndicator2({ label = "Thinking..." }) {
|
|
@@ -584,6 +585,90 @@ var ThinkingIndicator = memo(function ThinkingIndicator2({ label = "Thinking..."
|
|
|
584
585
|
/* @__PURE__ */ jsx7("span", { className: "text-sm text-muted-foreground animate-pulse", children: label })
|
|
585
586
|
] });
|
|
586
587
|
});
|
|
588
|
+
var ThinkingBlock = memo(function ThinkingBlock2({ content, isStreaming = false, label = "Thinking", chunkSize = 12e3 }) {
|
|
589
|
+
const [open, setOpen] = useState(isStreaming);
|
|
590
|
+
const [thinkingActive, setThinkingActive] = useState(false);
|
|
591
|
+
const contentLenRef = useRef(0);
|
|
592
|
+
useEffect(() => {
|
|
593
|
+
if (!isStreaming) {
|
|
594
|
+
setThinkingActive(false);
|
|
595
|
+
contentLenRef.current = 0;
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
if (content.length > contentLenRef.current) {
|
|
599
|
+
contentLenRef.current = content.length;
|
|
600
|
+
setThinkingActive(true);
|
|
601
|
+
}
|
|
602
|
+
}, [content.length, isStreaming]);
|
|
603
|
+
useEffect(() => {
|
|
604
|
+
if (!thinkingActive || !isStreaming) return;
|
|
605
|
+
const timer = setTimeout(() => setThinkingActive(false), 1e3);
|
|
606
|
+
return () => clearTimeout(timer);
|
|
607
|
+
}, [thinkingActive, isStreaming, content.length]);
|
|
608
|
+
useEffect(() => {
|
|
609
|
+
if (isStreaming && content.length > 0) setOpen(true);
|
|
610
|
+
}, [isStreaming, content.length]);
|
|
611
|
+
return /* @__PURE__ */ jsxs2("div", { className: "mb-3 relative rounded-lg overflow-hidden", children: [
|
|
612
|
+
thinkingActive && /* @__PURE__ */ jsx7(
|
|
613
|
+
"div",
|
|
614
|
+
{
|
|
615
|
+
className: "absolute inset-0 rounded-lg pointer-events-none",
|
|
616
|
+
style: {
|
|
617
|
+
padding: "1px",
|
|
618
|
+
background: "linear-gradient(135deg, hsl(var(--primary) / 0.4), hsl(var(--muted-foreground) / 0.2), hsl(var(--primary) / 0.4))",
|
|
619
|
+
backgroundSize: "200% 200%",
|
|
620
|
+
animation: "thinking-shimmer 2s ease-in-out infinite"
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
),
|
|
624
|
+
/* @__PURE__ */ jsxs2(
|
|
625
|
+
"div",
|
|
626
|
+
{
|
|
627
|
+
className: `relative rounded-lg border bg-muted/30 ${thinkingActive ? "border-transparent" : "border-muted-foreground/20"}`,
|
|
628
|
+
style: thinkingActive ? { margin: "1px" } : void 0,
|
|
629
|
+
children: [
|
|
630
|
+
/* @__PURE__ */ jsxs2(
|
|
631
|
+
"button",
|
|
632
|
+
{
|
|
633
|
+
type: "button",
|
|
634
|
+
className: "flex w-full items-center gap-2 px-3 py-2 text-left text-xs font-medium text-muted-foreground hover:text-foreground/70 transition-colors",
|
|
635
|
+
onClick: () => setOpen((v) => !v),
|
|
636
|
+
children: [
|
|
637
|
+
/* @__PURE__ */ jsx7(BrainCircuit, { className: `h-3.5 w-3.5 flex-shrink-0 ${thinkingActive ? "animate-pulse text-primary" : ""}` }),
|
|
638
|
+
/* @__PURE__ */ jsxs2("span", { className: "flex-1", children: [
|
|
639
|
+
label,
|
|
640
|
+
thinkingActive && /* @__PURE__ */ jsxs2("span", { className: "ml-1 inline-flex gap-0.5", children: [
|
|
641
|
+
/* @__PURE__ */ jsx7("span", { className: "inline-block w-1 h-1 bg-current rounded-full animate-bounce", style: { animationDelay: "0ms" } }),
|
|
642
|
+
/* @__PURE__ */ jsx7("span", { className: "inline-block w-1 h-1 bg-current rounded-full animate-bounce", style: { animationDelay: "150ms" } }),
|
|
643
|
+
/* @__PURE__ */ jsx7("span", { className: "inline-block w-1 h-1 bg-current rounded-full animate-bounce", style: { animationDelay: "300ms" } })
|
|
644
|
+
] })
|
|
645
|
+
] }),
|
|
646
|
+
open ? /* @__PURE__ */ jsx7(ChevronDown, { className: "h-3 w-3" }) : /* @__PURE__ */ jsx7(ChevronRight, { className: "h-3 w-3" })
|
|
647
|
+
]
|
|
648
|
+
}
|
|
649
|
+
),
|
|
650
|
+
open && /* @__PURE__ */ jsx7("div", { className: "px-3 pb-3", children: /* @__PURE__ */ jsxs2("div", { className: "border-l-2 border-muted-foreground/20 pl-3", children: [
|
|
651
|
+
/* @__PURE__ */ jsx7(
|
|
652
|
+
PlainTextContent,
|
|
653
|
+
{
|
|
654
|
+
content,
|
|
655
|
+
className: "text-xs text-muted-foreground/80 leading-5",
|
|
656
|
+
chunkSize
|
|
657
|
+
}
|
|
658
|
+
),
|
|
659
|
+
thinkingActive && /* @__PURE__ */ jsx7("span", { className: "inline-block w-1.5 h-3 bg-muted-foreground/40 animate-pulse ml-0.5" })
|
|
660
|
+
] }) })
|
|
661
|
+
]
|
|
662
|
+
}
|
|
663
|
+
),
|
|
664
|
+
/* @__PURE__ */ jsx7("style", { children: `
|
|
665
|
+
@keyframes thinking-shimmer {
|
|
666
|
+
0%, 100% { background-position: 0% 50%; }
|
|
667
|
+
50% { background-position: 100% 50%; }
|
|
668
|
+
}
|
|
669
|
+
` })
|
|
670
|
+
] });
|
|
671
|
+
});
|
|
587
672
|
var markdownComponents = {
|
|
588
673
|
code: ({ node, className, children, ...props }) => {
|
|
589
674
|
const inline = props.inline;
|
|
@@ -974,6 +1059,15 @@ var Message = memo(({
|
|
|
974
1059
|
] })
|
|
975
1060
|
] })
|
|
976
1061
|
] }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
1062
|
+
!messageIsUser && message.reasoning && message.reasoning.trim().length > 0 && /* @__PURE__ */ jsx7(
|
|
1063
|
+
ThinkingBlock,
|
|
1064
|
+
{
|
|
1065
|
+
content: message.reasoning,
|
|
1066
|
+
isStreaming: message.isStreaming,
|
|
1067
|
+
label: thinkingLabel,
|
|
1068
|
+
chunkSize: normalizedChunkChars
|
|
1069
|
+
}
|
|
1070
|
+
),
|
|
977
1071
|
enableToolCallsDisplay && message.toolCalls && message.toolCalls.length > 0 && /* @__PURE__ */ jsx7("div", { className: "mb-3", children: /* @__PURE__ */ jsx7(ToolCallsDisplay, { toolCalls: message.toolCalls, label: toolUsedLabel }) }),
|
|
978
1072
|
/* @__PURE__ */ jsx7(
|
|
979
1073
|
StreamingText,
|
|
@@ -1048,7 +1142,7 @@ var Message = memo(({
|
|
|
1048
1142
|
}, arePropsEqual);
|
|
1049
1143
|
|
|
1050
1144
|
// src/components/chat/Sidebar.tsx
|
|
1051
|
-
import { useState as useState4, useRef as
|
|
1145
|
+
import { useState as useState4, useRef as useRef5, useEffect as useEffect7 } from "react";
|
|
1052
1146
|
|
|
1053
1147
|
// src/components/ui/input.tsx
|
|
1054
1148
|
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
@@ -2297,7 +2391,7 @@ var Sidebar2 = ({
|
|
|
2297
2391
|
const [deleteThreadId, setDeleteThreadId] = useState4(null);
|
|
2298
2392
|
const [editingThreadId, setEditingThreadId] = useState4(null);
|
|
2299
2393
|
const [editTitle, setEditTitle] = useState4("");
|
|
2300
|
-
const inputRef =
|
|
2394
|
+
const inputRef = useRef5(null);
|
|
2301
2395
|
const { setOpen } = useSidebar();
|
|
2302
2396
|
useEffect7(() => {
|
|
2303
2397
|
if (editingThreadId && inputRef.current) {
|
|
@@ -2716,7 +2810,7 @@ var ChatHeader = ({
|
|
|
2716
2810
|
};
|
|
2717
2811
|
|
|
2718
2812
|
// src/components/chat/ChatInput.tsx
|
|
2719
|
-
import { useState as useState6, useRef as
|
|
2813
|
+
import { useState as useState6, useRef as useRef6, useCallback as useCallback3, useEffect as useEffect9, memo as memo2 } from "react";
|
|
2720
2814
|
|
|
2721
2815
|
// src/components/chat/UserContext.tsx
|
|
2722
2816
|
import { createContext as createContext2, useCallback as useCallback2, useContext as useContext2, useEffect as useEffect8, useMemo as useMemo3, useState as useState5 } from "react";
|
|
@@ -2860,7 +2954,7 @@ var FileUploadItem = memo2(function FileUploadItem2({ file, progress, onCancel }
|
|
|
2860
2954
|
var AttachmentPreview = memo2(function AttachmentPreview2({ attachment, onRemove }) {
|
|
2861
2955
|
const [isPlaying, setIsPlaying] = useState6(false);
|
|
2862
2956
|
const [audioPlaybackSrc, setAudioPlaybackSrc] = useState6(attachment.dataUrl);
|
|
2863
|
-
const audioRef =
|
|
2957
|
+
const audioRef = useRef6(null);
|
|
2864
2958
|
useEffect9(() => {
|
|
2865
2959
|
if (attachment.kind !== "audio" || !attachment.dataUrl.startsWith("data:")) {
|
|
2866
2960
|
setAudioPlaybackSrc(attachment.dataUrl);
|
|
@@ -3053,12 +3147,12 @@ var ChatInput = memo2(function ChatInput2({
|
|
|
3053
3147
|
const { setContext } = useChatUserContext();
|
|
3054
3148
|
const [recordingDuration, setRecordingDuration] = useState6(0);
|
|
3055
3149
|
const [uploadProgress, setUploadProgress] = useState6(/* @__PURE__ */ new Map());
|
|
3056
|
-
const textareaRef =
|
|
3057
|
-
const fileInputRef =
|
|
3058
|
-
const mediaRecorderRef =
|
|
3059
|
-
const recordingStartTime =
|
|
3060
|
-
const recordingInterval =
|
|
3061
|
-
const mediaStreamRef =
|
|
3150
|
+
const textareaRef = useRef6(null);
|
|
3151
|
+
const fileInputRef = useRef6(null);
|
|
3152
|
+
const mediaRecorderRef = useRef6(null);
|
|
3153
|
+
const recordingStartTime = useRef6(0);
|
|
3154
|
+
const recordingInterval = useRef6(null);
|
|
3155
|
+
const mediaStreamRef = useRef6(null);
|
|
3062
3156
|
useEffect9(() => {
|
|
3063
3157
|
return () => {
|
|
3064
3158
|
if (mediaStreamRef.current) {
|
|
@@ -3922,18 +4016,18 @@ var ChatUI = ({
|
|
|
3922
4016
|
setState((prev) => ({ ...prev, selectedThreadId: currentThreadId }));
|
|
3923
4017
|
}
|
|
3924
4018
|
}, [currentThreadId]);
|
|
3925
|
-
const initialInputApplied =
|
|
3926
|
-
const initialInputConsumedRef =
|
|
4019
|
+
const initialInputApplied = useRef7(false);
|
|
4020
|
+
const initialInputConsumedRef = useRef7(false);
|
|
3927
4021
|
useEffect10(() => {
|
|
3928
4022
|
if (initialInput && !initialInputApplied.current) {
|
|
3929
4023
|
setInputValue(initialInput);
|
|
3930
4024
|
initialInputApplied.current = true;
|
|
3931
4025
|
}
|
|
3932
4026
|
}, [initialInput]);
|
|
3933
|
-
const scrollAreaRef =
|
|
3934
|
-
const stateRef =
|
|
3935
|
-
const inputValueRef =
|
|
3936
|
-
const attachmentsRef =
|
|
4027
|
+
const scrollAreaRef = useRef7(null);
|
|
4028
|
+
const stateRef = useRef7(state);
|
|
4029
|
+
const inputValueRef = useRef7(inputValue);
|
|
4030
|
+
const attachmentsRef = useRef7(attachments);
|
|
3937
4031
|
useEffect10(() => {
|
|
3938
4032
|
stateRef.current = state;
|
|
3939
4033
|
}, [state]);
|
|
@@ -3982,7 +4076,7 @@ var ChatUI = ({
|
|
|
3982
4076
|
return () => clearTimeout(t);
|
|
3983
4077
|
}
|
|
3984
4078
|
}, [state.showSidebar, isMobile, config.customComponent]);
|
|
3985
|
-
const prevMessageCountRef =
|
|
4079
|
+
const prevMessageCountRef = useRef7(0);
|
|
3986
4080
|
useEffect10(() => {
|
|
3987
4081
|
if (messages.length === 0) {
|
|
3988
4082
|
prevMessageCountRef.current = 0;
|
|
@@ -4395,7 +4489,7 @@ var ChatUI = ({
|
|
|
4395
4489
|
};
|
|
4396
4490
|
|
|
4397
4491
|
// src/components/chat/ThreadManager.tsx
|
|
4398
|
-
import { useState as useState9, useRef as
|
|
4492
|
+
import { useState as useState9, useRef as useRef8, useEffect as useEffect11 } from "react";
|
|
4399
4493
|
import {
|
|
4400
4494
|
Plus as Plus4,
|
|
4401
4495
|
MessageSquare as MessageSquare2,
|
|
@@ -4414,7 +4508,7 @@ import { Fragment as Fragment6, jsx as jsx25, jsxs as jsxs15 } from "react/jsx-r
|
|
|
4414
4508
|
var ThreadItem = ({ thread, isActive, config, onSelect, onRename, onDelete, onArchive }) => {
|
|
4415
4509
|
const [isEditing, setIsEditing] = useState9(false);
|
|
4416
4510
|
const [editTitle, setEditTitle] = useState9(thread.title);
|
|
4417
|
-
const inputRef =
|
|
4511
|
+
const inputRef = useRef8(null);
|
|
4418
4512
|
useEffect11(() => {
|
|
4419
4513
|
if (isEditing && inputRef.current) {
|
|
4420
4514
|
inputRef.current.focus();
|