@copilotkit/react-ui 0.14.1 → 0.15.0-alpha.1
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/.turbo/turbo-build.log +279 -196
- package/CHANGELOG.md +22 -0
- package/dist/chunk-47SYBLI2.mjs +110 -0
- package/dist/chunk-47SYBLI2.mjs.map +1 -0
- package/dist/chunk-6H3Y2XEI.mjs +56 -0
- package/dist/chunk-6H3Y2XEI.mjs.map +1 -0
- package/dist/chunk-7YXG7D47.mjs +191 -0
- package/dist/chunk-7YXG7D47.mjs.map +1 -0
- package/dist/chunk-DN3OI5WF.mjs +72 -0
- package/dist/chunk-DN3OI5WF.mjs.map +1 -0
- package/dist/chunk-DPUPEOGG.mjs +14 -0
- package/dist/chunk-DPUPEOGG.mjs.map +1 -0
- package/dist/chunk-FZRTAML3.mjs +3 -0
- package/dist/chunk-GPEJCUWA.mjs +14 -0
- package/dist/chunk-GPEJCUWA.mjs.map +1 -0
- package/dist/chunk-NXWVWC33.mjs +117 -0
- package/dist/chunk-NXWVWC33.mjs.map +1 -0
- package/dist/chunk-P4GBO6MW.mjs +3 -0
- package/dist/chunk-P4GBO6MW.mjs.map +1 -0
- package/dist/chunk-QFASQEFJ.mjs +51 -0
- package/dist/chunk-QFASQEFJ.mjs.map +1 -0
- package/dist/chunk-UIRFLYXI.mjs +53 -0
- package/dist/chunk-UIRFLYXI.mjs.map +1 -0
- package/dist/chunk-WB3YULQ4.mjs +3 -0
- package/dist/chunk-WB3YULQ4.mjs.map +1 -0
- package/dist/chunk-WM6BS77F.mjs +53 -0
- package/dist/chunk-WM6BS77F.mjs.map +1 -0
- package/dist/chunk-X3Z2EVFV.mjs +26 -0
- package/dist/chunk-X3Z2EVFV.mjs.map +1 -0
- package/dist/chunk-X4T6ZUVM.mjs +14 -0
- package/dist/chunk-X4T6ZUVM.mjs.map +1 -0
- package/dist/chunk-Y2RUG4B3.mjs +21 -0
- package/dist/chunk-Y2RUG4B3.mjs.map +1 -0
- package/dist/chunk-ZVAH2Z2W.mjs +61 -0
- package/dist/chunk-ZVAH2Z2W.mjs.map +1 -0
- package/dist/components/chat/Button.d.ts +7 -0
- package/dist/components/chat/Button.mjs +6 -0
- package/dist/components/chat/Button.mjs.map +1 -0
- package/dist/components/chat/Chat.d.ts +95 -0
- package/dist/components/chat/Chat.mjs +16 -0
- package/dist/components/chat/Chat.mjs.map +1 -0
- package/dist/components/chat/ChatContext.d.ts +105 -0
- package/dist/components/chat/ChatContext.mjs +5 -0
- package/dist/components/chat/ChatContext.mjs.map +1 -0
- package/dist/components/chat/CodeBlock.d.ts +14 -0
- package/dist/components/chat/CodeBlock.mjs +6 -0
- package/dist/components/chat/CodeBlock.mjs.map +1 -0
- package/dist/components/chat/Header.d.ts +7 -0
- package/dist/components/chat/Header.mjs +6 -0
- package/dist/components/chat/Header.mjs.map +1 -0
- package/dist/components/chat/Icons.d.ts +15 -0
- package/dist/components/chat/Icons.mjs +4 -0
- package/dist/components/chat/Icons.mjs.map +1 -0
- package/dist/components/chat/Input.d.ts +7 -0
- package/dist/components/chat/Input.mjs +7 -0
- package/dist/components/chat/Input.mjs.map +1 -0
- package/dist/components/chat/Markdown.d.ts +8 -0
- package/dist/components/chat/Markdown.mjs +7 -0
- package/dist/components/chat/Markdown.mjs.map +1 -0
- package/dist/components/chat/Messages.d.ts +7 -0
- package/dist/components/chat/Messages.mjs +9 -0
- package/dist/components/chat/Messages.mjs.map +1 -0
- package/dist/components/chat/Popup.d.ts +9 -0
- package/dist/components/chat/Popup.mjs +17 -0
- package/dist/components/chat/Popup.mjs.map +1 -0
- package/dist/components/chat/Response.d.ts +7 -0
- package/dist/components/chat/Response.mjs +6 -0
- package/dist/components/chat/Response.mjs.map +1 -0
- package/dist/components/chat/Sidebar.d.ts +12 -0
- package/dist/components/chat/Sidebar.mjs +17 -0
- package/dist/components/chat/Sidebar.mjs.map +1 -0
- package/dist/components/chat/Textarea.d.ts +13 -0
- package/dist/components/chat/Textarea.mjs +4 -0
- package/dist/components/chat/Textarea.mjs.map +1 -0
- package/dist/components/chat/Window.d.ts +6 -0
- package/dist/components/chat/Window.mjs +4 -0
- package/dist/components/chat/Window.mjs.map +1 -0
- package/dist/components/chat/index.d.ts +7 -0
- package/dist/components/chat/index.mjs +20 -0
- package/dist/components/chat/index.mjs.map +1 -0
- package/dist/components/chat/props.d.ts +33 -0
- package/dist/components/chat/props.mjs +3 -0
- package/dist/components/chat/props.mjs.map +1 -0
- package/dist/components/chat-components/copilot-chat.mjs +1 -1
- package/dist/components/chat-components/ui/badge.d.ts +1 -1
- package/dist/components/index.d.ts +5 -0
- package/dist/components/index.mjs +18 -2
- package/dist/components/sidebar/copilot-sidebar-ui-provider.mjs +1 -1
- package/dist/components/sidebar/copilot-sidebar.mjs +1 -1
- package/dist/index.css +452 -0
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.mjs +18 -2
- package/package.json +5 -5
- package/src/components/chat/Button.tsx +24 -0
- package/src/components/chat/Chat.tsx +186 -0
- package/src/components/chat/ChatContext.tsx +176 -0
- package/src/components/chat/CodeBlock.tsx +149 -0
- package/src/components/chat/Header.tsx +16 -0
- package/src/components/chat/Icons.tsx +179 -0
- package/src/components/chat/Input.tsx +51 -0
- package/src/components/chat/Markdown.tsx +62 -0
- package/src/components/chat/Messages.tsx +113 -0
- package/src/components/chat/Popup.tsx +10 -0
- package/src/components/chat/Response.tsx +13 -0
- package/src/components/chat/Sidebar.tsx +28 -0
- package/src/components/chat/Textarea.tsx +61 -0
- package/src/components/chat/Window.tsx +141 -0
- package/src/components/chat/index.tsx +3 -0
- package/src/components/chat/props.ts +36 -0
- package/src/components/index.ts +2 -0
- package/src/css/animations.css +29 -0
- package/src/css/button.css +54 -0
- package/src/css/colors.css +61 -0
- package/src/css/header.css +43 -0
- package/src/css/input.css +79 -0
- package/src/css/messages.css +57 -0
- package/src/css/popup.css +22 -0
- package/src/css/response.css +29 -0
- package/src/css/sidebar.css +34 -0
- package/src/css/window.css +58 -0
- package/src/styles.css +11 -0
- package/dist/chunk-U6NJWGTV.mjs +0 -3
- /package/dist/{chunk-U6NJWGTV.mjs.map → chunk-FZRTAML3.mjs.map} +0 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import React, { useEffect, useMemo } from "react";
|
|
2
|
+
import { MessagesProps } from "./props";
|
|
3
|
+
import { useChatContext } from "./ChatContext";
|
|
4
|
+
import { nanoid } from "nanoid";
|
|
5
|
+
import { Message } from "@copilotkit/react-core";
|
|
6
|
+
import { Markdown } from "./Markdown";
|
|
7
|
+
|
|
8
|
+
export const Messages: React.FC<MessagesProps> = ({ messages, inProgress }) => {
|
|
9
|
+
const context = useChatContext();
|
|
10
|
+
const initialMessages = useMemo(
|
|
11
|
+
() => makeInitialMessages(context.labels.initial),
|
|
12
|
+
[context.labels.initial],
|
|
13
|
+
);
|
|
14
|
+
messages = [...initialMessages, ...messages];
|
|
15
|
+
|
|
16
|
+
const messagesEndRef = React.useRef<HTMLDivElement>(null);
|
|
17
|
+
|
|
18
|
+
const scrollToBottom = () => {
|
|
19
|
+
if (messagesEndRef.current) {
|
|
20
|
+
messagesEndRef.current.scrollIntoView({
|
|
21
|
+
behavior: "auto",
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
scrollToBottom();
|
|
28
|
+
}, [messages]);
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<div className="copilotKitMessages">
|
|
32
|
+
{messages.map((message, index) => {
|
|
33
|
+
const isCurrentMessage = index === messages.length - 1;
|
|
34
|
+
|
|
35
|
+
if (message.role === "user") {
|
|
36
|
+
return (
|
|
37
|
+
<div key={index} className="copilotKitMessage copilotKitUserMessage">
|
|
38
|
+
{message.content}
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
41
|
+
} else if (message.role == "assistant") {
|
|
42
|
+
if (isCurrentMessage && inProgress && !message.content) {
|
|
43
|
+
return (
|
|
44
|
+
<div key={index} className={`copilotKitMessage copilotKitAssistantMessage`}>
|
|
45
|
+
{context.icons.spinnerIcon}
|
|
46
|
+
</div>
|
|
47
|
+
);
|
|
48
|
+
} else if (
|
|
49
|
+
(!inProgress || index != messages.length - 1) &&
|
|
50
|
+
!message.content &&
|
|
51
|
+
message.function_call
|
|
52
|
+
) {
|
|
53
|
+
return (
|
|
54
|
+
<div key={index} className={`copilotKitMessage copilotKitAssistantMessage`}>
|
|
55
|
+
{context.labels.done}
|
|
56
|
+
</div>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
// TODO: Add back partial message
|
|
60
|
+
// This shows up when the assistant is executing a function
|
|
61
|
+
//
|
|
62
|
+
// else if (message.status === "partial") {
|
|
63
|
+
// return (
|
|
64
|
+
// <div key={index} className={`copilotKitMessage copilotKitAssistantMessage`}>
|
|
65
|
+
// {context.labels.thinking} {context.icons.spinnerIcon}
|
|
66
|
+
// </div>
|
|
67
|
+
// );
|
|
68
|
+
// }
|
|
69
|
+
else {
|
|
70
|
+
return (
|
|
71
|
+
<div key={index} className={`copilotKitMessage copilotKitAssistantMessage`}>
|
|
72
|
+
<Markdown content={message.content} />
|
|
73
|
+
</div>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// TODO: Add back function and error messages
|
|
78
|
+
//
|
|
79
|
+
// else if (message.role === "function" && message.status === "success") {
|
|
80
|
+
// return (
|
|
81
|
+
// <div key={index} className={`copilotKitMessage copilotKitAssistantMessage`}>
|
|
82
|
+
// {context.labels.done}
|
|
83
|
+
// </div>
|
|
84
|
+
// );
|
|
85
|
+
// } else if (message.status === "error") {
|
|
86
|
+
// return (
|
|
87
|
+
// <div key={index} className={`copilotKitMessage copilotKitAssistantMessage`}>
|
|
88
|
+
// {context.labels.error}
|
|
89
|
+
// </div>
|
|
90
|
+
// );
|
|
91
|
+
// }
|
|
92
|
+
})}
|
|
93
|
+
<div ref={messagesEndRef} />
|
|
94
|
+
</div>
|
|
95
|
+
);
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
function makeInitialMessages(initial?: string | string[]): Message[] {
|
|
99
|
+
let initialArray: string[] = [];
|
|
100
|
+
if (initial) {
|
|
101
|
+
if (Array.isArray(initial)) {
|
|
102
|
+
initialArray.push(...initial);
|
|
103
|
+
} else {
|
|
104
|
+
initialArray.push(initial);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return initialArray.map((message) => ({
|
|
109
|
+
id: nanoid(),
|
|
110
|
+
role: "assistant",
|
|
111
|
+
content: message,
|
|
112
|
+
}));
|
|
113
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { CopilotKitChat, CopilotKitChatProps } from "./Chat";
|
|
3
|
+
|
|
4
|
+
export const CopilotKitPopup: React.FC<CopilotKitChatProps> = (props) => {
|
|
5
|
+
props = {
|
|
6
|
+
...props,
|
|
7
|
+
className: props.className ? props.className + " copilotKitPopup" : "copilotKitPopup",
|
|
8
|
+
};
|
|
9
|
+
return <CopilotKitChat {...props} />;
|
|
10
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { useChatContext } from "./ChatContext";
|
|
3
|
+
import { ResponseButtonProps } from "./props";
|
|
4
|
+
|
|
5
|
+
export const ResponseButton: React.FC<ResponseButtonProps> = ({ onClick, inProgress }) => {
|
|
6
|
+
const context = useChatContext();
|
|
7
|
+
return (
|
|
8
|
+
<button onClick={onClick} className="copilotKitResponseButton">
|
|
9
|
+
<span>{inProgress ? context.icons.stopIcon : context.icons.regenerateIcon}</span>
|
|
10
|
+
{inProgress ? context.labels.stopGenerating : context.labels.regenerateResponse}
|
|
11
|
+
</button>
|
|
12
|
+
);
|
|
13
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import { CopilotKitChat, CopilotKitChatProps } from "./Chat";
|
|
3
|
+
|
|
4
|
+
interface CopilotKitSidebarProps extends CopilotKitChatProps {
|
|
5
|
+
children?: React.ReactNode;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const CopilotKitSidebar: React.FC<CopilotKitSidebarProps> = (props) => {
|
|
9
|
+
props = {
|
|
10
|
+
...props,
|
|
11
|
+
className: props.className ? props.className + " copilotKitSidebar" : "copilotKitSidebar",
|
|
12
|
+
};
|
|
13
|
+
const [expandedClassName, setExpandedClassName] = useState(
|
|
14
|
+
props.defaultOpen ? "sidebarExpanded" : "",
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
const onSetOpen = (open: boolean) => {
|
|
18
|
+
props.onSetOpen?.(open);
|
|
19
|
+
setExpandedClassName(open ? "sidebarExpanded" : "");
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<div className={`copilotKitSidebarContentWrapper ${expandedClassName}`}>
|
|
24
|
+
{props.children}
|
|
25
|
+
<CopilotKitChat {...props} {...{ onSetOpen }} />
|
|
26
|
+
</div>
|
|
27
|
+
);
|
|
28
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import React, { useState, useRef, useEffect, forwardRef, useImperativeHandle } from "react";
|
|
2
|
+
|
|
3
|
+
interface AutoResizingTextareaProps {
|
|
4
|
+
maxRows?: number;
|
|
5
|
+
placeholder?: string;
|
|
6
|
+
value: string;
|
|
7
|
+
onChange: (event: React.ChangeEvent<HTMLTextAreaElement>) => void;
|
|
8
|
+
onKeyDown?: (event: React.KeyboardEvent<HTMLTextAreaElement>) => void;
|
|
9
|
+
autoFocus?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const AutoResizingTextarea = forwardRef<HTMLTextAreaElement, AutoResizingTextareaProps>(
|
|
13
|
+
({ maxRows = 1, placeholder, value, onChange, onKeyDown, autoFocus }, ref) => {
|
|
14
|
+
const internalTextareaRef = useRef<HTMLTextAreaElement>(null);
|
|
15
|
+
const [maxHeight, setMaxHeight] = useState<number>(0);
|
|
16
|
+
|
|
17
|
+
useImperativeHandle(ref, () => internalTextareaRef.current as HTMLTextAreaElement);
|
|
18
|
+
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
const calculateMaxHeight = () => {
|
|
21
|
+
const textarea = internalTextareaRef.current;
|
|
22
|
+
if (textarea) {
|
|
23
|
+
textarea.style.height = "auto";
|
|
24
|
+
const singleRowHeight = textarea.scrollHeight;
|
|
25
|
+
setMaxHeight(singleRowHeight * maxRows);
|
|
26
|
+
if (autoFocus) {
|
|
27
|
+
textarea.focus();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
calculateMaxHeight();
|
|
33
|
+
}, [maxRows]);
|
|
34
|
+
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
const textarea = internalTextareaRef.current;
|
|
37
|
+
if (textarea) {
|
|
38
|
+
textarea.style.height = "auto";
|
|
39
|
+
textarea.style.height = `${Math.min(textarea.scrollHeight, maxHeight)}px`;
|
|
40
|
+
}
|
|
41
|
+
}, [value, maxHeight]);
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<textarea
|
|
45
|
+
ref={internalTextareaRef}
|
|
46
|
+
value={value}
|
|
47
|
+
onChange={onChange}
|
|
48
|
+
onKeyDown={onKeyDown}
|
|
49
|
+
placeholder={placeholder}
|
|
50
|
+
style={{
|
|
51
|
+
overflow: "hidden",
|
|
52
|
+
resize: "none",
|
|
53
|
+
maxHeight: `${maxHeight}px`,
|
|
54
|
+
}}
|
|
55
|
+
rows={1}
|
|
56
|
+
/>
|
|
57
|
+
);
|
|
58
|
+
},
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
export default AutoResizingTextarea;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import React, { useCallback, useEffect } from "react";
|
|
2
|
+
import { WindowProps } from "./props";
|
|
3
|
+
|
|
4
|
+
export const Window = ({
|
|
5
|
+
open,
|
|
6
|
+
setOpen,
|
|
7
|
+
children,
|
|
8
|
+
clickOutsideToClose,
|
|
9
|
+
hotkey,
|
|
10
|
+
hitEscapeToClose,
|
|
11
|
+
}: WindowProps) => {
|
|
12
|
+
const windowRef = React.useRef<HTMLDivElement>(null);
|
|
13
|
+
|
|
14
|
+
const handleClickOutside = useCallback(
|
|
15
|
+
(event: MouseEvent) => {
|
|
16
|
+
if (!clickOutsideToClose) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const parentElement = windowRef.current?.parentElement;
|
|
21
|
+
|
|
22
|
+
if (open && parentElement && !parentElement.contains(event.target as any)) {
|
|
23
|
+
setOpen(false);
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
[clickOutsideToClose, open, setOpen],
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const handleKeyDown = useCallback(
|
|
30
|
+
(event: KeyboardEvent) => {
|
|
31
|
+
const target = event.target as HTMLElement;
|
|
32
|
+
const isInput =
|
|
33
|
+
target.tagName === "INPUT" ||
|
|
34
|
+
target.tagName === "SELECT" ||
|
|
35
|
+
target.tagName === "TEXTAREA" ||
|
|
36
|
+
target.isContentEditable;
|
|
37
|
+
|
|
38
|
+
const isDescendantOfWrapper = windowRef.current?.contains(target);
|
|
39
|
+
|
|
40
|
+
if (
|
|
41
|
+
open &&
|
|
42
|
+
event.key === "Escape" &&
|
|
43
|
+
(!isInput || isDescendantOfWrapper) &&
|
|
44
|
+
hitEscapeToClose
|
|
45
|
+
) {
|
|
46
|
+
setOpen(false);
|
|
47
|
+
} else if (
|
|
48
|
+
event.key === hotkey &&
|
|
49
|
+
((isMacOS() && event.metaKey) || (!isMacOS() && event.ctrlKey)) &&
|
|
50
|
+
(!isInput || isDescendantOfWrapper)
|
|
51
|
+
) {
|
|
52
|
+
setOpen(!open);
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
[hitEscapeToClose, hotkey, open, setOpen],
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
const adjustForMobile = useCallback(() => {
|
|
59
|
+
const copilotKitWindow = windowRef.current;
|
|
60
|
+
const vv = window.visualViewport;
|
|
61
|
+
if (!copilotKitWindow || !vv) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (window.innerWidth < 640 && open) {
|
|
66
|
+
copilotKitWindow.style.height = `${vv.height}px`;
|
|
67
|
+
copilotKitWindow.style.left = `${vv.offsetLeft}px`;
|
|
68
|
+
copilotKitWindow.style.top = `${vv.offsetTop}px`;
|
|
69
|
+
|
|
70
|
+
document.body.style.position = "fixed";
|
|
71
|
+
document.body.style.width = "100%";
|
|
72
|
+
document.body.style.height = `${window.innerHeight}px`;
|
|
73
|
+
document.body.style.overflow = "hidden";
|
|
74
|
+
document.body.style.touchAction = "none";
|
|
75
|
+
|
|
76
|
+
// Prevent scrolling on iOS
|
|
77
|
+
document.body.addEventListener("touchmove", preventScroll, {
|
|
78
|
+
passive: false,
|
|
79
|
+
});
|
|
80
|
+
} else {
|
|
81
|
+
copilotKitWindow.style.height = "";
|
|
82
|
+
copilotKitWindow.style.left = "";
|
|
83
|
+
copilotKitWindow.style.top = "";
|
|
84
|
+
document.body.style.position = "";
|
|
85
|
+
document.body.style.height = "";
|
|
86
|
+
document.body.style.width = "";
|
|
87
|
+
document.body.style.overflow = "";
|
|
88
|
+
document.body.style.top = "";
|
|
89
|
+
document.body.style.touchAction = "";
|
|
90
|
+
|
|
91
|
+
document.body.removeEventListener("touchmove", preventScroll);
|
|
92
|
+
}
|
|
93
|
+
}, [open]);
|
|
94
|
+
|
|
95
|
+
useEffect(() => {
|
|
96
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
97
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
98
|
+
if (window.visualViewport) {
|
|
99
|
+
window.visualViewport.addEventListener("resize", adjustForMobile);
|
|
100
|
+
adjustForMobile();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return () => {
|
|
104
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
105
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
106
|
+
if (window.visualViewport) {
|
|
107
|
+
window.visualViewport.removeEventListener("resize", adjustForMobile);
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
}, [adjustForMobile, handleClickOutside, handleKeyDown]);
|
|
111
|
+
|
|
112
|
+
return (
|
|
113
|
+
<div className={`copilotKitWindow${open ? " open" : ""}`} ref={windowRef}>
|
|
114
|
+
{children}
|
|
115
|
+
</div>
|
|
116
|
+
);
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const preventScroll = (event: TouchEvent): void => {
|
|
120
|
+
let targetElement = event.target as Element;
|
|
121
|
+
|
|
122
|
+
// Function to check if the target has the parent with a given class
|
|
123
|
+
const hasParentWithClass = (element: Element, className: string): boolean => {
|
|
124
|
+
while (element && element !== document.body) {
|
|
125
|
+
if (element.classList.contains(className)) {
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
element = element.parentElement!;
|
|
129
|
+
}
|
|
130
|
+
return false;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
// Check if the target of the touch event is inside an element with the 'copilotKitMessages' class
|
|
134
|
+
if (!hasParentWithClass(targetElement, "copilotKitMessages")) {
|
|
135
|
+
event.preventDefault();
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
function isMacOS() {
|
|
140
|
+
return /Mac|iMac|Macintosh/i.test(navigator.userAgent);
|
|
141
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Message } from "@copilotkit/react-core";
|
|
2
|
+
|
|
3
|
+
export interface ButtonProps {
|
|
4
|
+
open: boolean;
|
|
5
|
+
setOpen: (open: boolean) => void;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface WindowProps {
|
|
9
|
+
open: boolean;
|
|
10
|
+
setOpen: (open: boolean) => void;
|
|
11
|
+
clickOutsideToClose: boolean;
|
|
12
|
+
hitEscapeToClose: boolean;
|
|
13
|
+
hotkey: string;
|
|
14
|
+
children?: React.ReactNode;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface HeaderProps {
|
|
18
|
+
open: boolean;
|
|
19
|
+
setOpen: (open: boolean) => void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface MessagesProps {
|
|
23
|
+
messages: Message[];
|
|
24
|
+
inProgress: boolean;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface InputProps {
|
|
28
|
+
inProgress: boolean;
|
|
29
|
+
onSend: (text: string) => void;
|
|
30
|
+
children?: React.ReactNode;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface ResponseButtonProps {
|
|
34
|
+
onClick: () => void;
|
|
35
|
+
inProgress: boolean;
|
|
36
|
+
}
|
package/src/components/index.ts
CHANGED
|
@@ -5,3 +5,5 @@ export { CopilotSidebarUIProvider } from "./sidebar/copilot-sidebar-ui-provider"
|
|
|
5
5
|
export { CopilotSidebar } from "./sidebar/copilot-sidebar";
|
|
6
6
|
export { CopilotSidebarContext } from "./sidebar/sidebar-context";
|
|
7
7
|
export type { CopilotSidebarContextType } from "./sidebar/sidebar-context";
|
|
8
|
+
|
|
9
|
+
export * from "./chat";
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
.copilotKitActivityDot1 {
|
|
2
|
+
animation: copilotKitActivityDotsAnimation 1.05s infinite;
|
|
3
|
+
}
|
|
4
|
+
.copilotKitActivityDot2 {
|
|
5
|
+
animation-delay: 0.1s;
|
|
6
|
+
}
|
|
7
|
+
.copilotKitActivityDot3 {
|
|
8
|
+
animation-delay: 0.2s;
|
|
9
|
+
}
|
|
10
|
+
@keyframes copilotKitActivityDotsAnimation {
|
|
11
|
+
0%,
|
|
12
|
+
57.14% {
|
|
13
|
+
animation-timing-function: cubic-bezier(0.33, 0.66, 0.66, 1);
|
|
14
|
+
transform: translate(0);
|
|
15
|
+
}
|
|
16
|
+
28.57% {
|
|
17
|
+
animation-timing-function: cubic-bezier(0.33, 0, 0.66, 0.33);
|
|
18
|
+
transform: translateY(-6px);
|
|
19
|
+
}
|
|
20
|
+
100% {
|
|
21
|
+
transform: translate(0);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@keyframes copilotKitSpinAnimation {
|
|
26
|
+
to {
|
|
27
|
+
transform: rotate(360deg);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
.copilotKitButton {
|
|
2
|
+
width: 3.5rem;
|
|
3
|
+
height: 3.5rem;
|
|
4
|
+
display: flex;
|
|
5
|
+
align-items: center;
|
|
6
|
+
justify-content: center;
|
|
7
|
+
border-radius: 50%;
|
|
8
|
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
9
|
+
outline: none;
|
|
10
|
+
position: relative;
|
|
11
|
+
transform: scale(1);
|
|
12
|
+
transition: transform 200ms;
|
|
13
|
+
background-color: var(--copilot-kit-button-background-color);
|
|
14
|
+
color: var(--copilot-kit-button-icon-color);
|
|
15
|
+
cursor: pointer;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.copilotKitButton:hover {
|
|
19
|
+
transform: scale(1.1);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.copilotKitButton:active {
|
|
23
|
+
transform: scale(0.75);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.copilotKitButtonIcon {
|
|
27
|
+
transition: opacity 100ms, transform 300ms;
|
|
28
|
+
position: absolute;
|
|
29
|
+
top: 50%;
|
|
30
|
+
left: 50%;
|
|
31
|
+
transform: translate(-50%, -50%);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* State when the chat is open */
|
|
35
|
+
.copilotKitButton.open .copilotKitButtonIconOpen {
|
|
36
|
+
transform: translate(-50%, -50%) scale(0) rotate(90deg);
|
|
37
|
+
opacity: 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.copilotKitButton.open .copilotKitButtonIconClose {
|
|
41
|
+
transform: translate(-50%, -50%) scale(1) rotate(0deg);
|
|
42
|
+
opacity: 1;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/* State when the chat is closed */
|
|
46
|
+
.copilotKitButton:not(.open) .copilotKitButtonIconOpen {
|
|
47
|
+
transform: translate(-50%, -50%) scale(1) rotate(0deg);
|
|
48
|
+
opacity: 1;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.copilotKitButton:not(.open) .copilotKitButtonIconClose {
|
|
52
|
+
transform: translate(-50%, -50%) scale(0) rotate(-90deg);
|
|
53
|
+
opacity: 0;
|
|
54
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--copilot-kit-primary-color: rgb(59 130 246);
|
|
3
|
+
--copilot-kit-contrast-color: rgb(255 255 255);
|
|
4
|
+
--copilot-kit-secondary-color: rgb(243 244 246);
|
|
5
|
+
--copilot-kit-secondary-contrast-color: rgb(0 0 0);
|
|
6
|
+
--copilot-kit-background-color: rgb(255 255 255);
|
|
7
|
+
--copilot-kit-muted-color: rgb(106 106 106);
|
|
8
|
+
--copilot-kit-separator-color: rgba(0, 0, 0, 0.08);
|
|
9
|
+
--copilot-kit-scrollbar-color: rgba(0, 0, 0, 0.2);
|
|
10
|
+
|
|
11
|
+
--copilot-kit-button-background-color: var(--copilot-kit-primary-color);
|
|
12
|
+
|
|
13
|
+
/* The color of the icon in the open/close button */
|
|
14
|
+
--copilot-kit-button-icon-color: var(--copilot-kit-contrast-color);
|
|
15
|
+
|
|
16
|
+
/* The background color of the header of the chat window */
|
|
17
|
+
--copilot-kit-header-background-color: var(--copilot-kit-primary-color);
|
|
18
|
+
|
|
19
|
+
/* The color of the title in the header of the chat window */
|
|
20
|
+
--copilot-kit-header-title-color: var(--copilot-kit-contrast-color);
|
|
21
|
+
|
|
22
|
+
/* The color of the close button in the header of the chat window */
|
|
23
|
+
--copilot-kit-header-close-button-color: var(--copilot-kit-contrast-color);
|
|
24
|
+
|
|
25
|
+
/* The color of the separator between the header and the messages area */
|
|
26
|
+
--copilot-kit-header-separator-color: var(--copilot-kit-separator-color);
|
|
27
|
+
|
|
28
|
+
/* The background color of the input area */
|
|
29
|
+
--copilot-kit-input-background-color: var(--copilot-kit-background-color);
|
|
30
|
+
|
|
31
|
+
/* The color of the send button */
|
|
32
|
+
--copilot-kit-input-send-button-color: var(--copilot-kit-primary-color);
|
|
33
|
+
|
|
34
|
+
/* The color of the send button when disabled */
|
|
35
|
+
--copilot-kit-input-send-button-disabled-color: var(--copilot-kit-muted-color);
|
|
36
|
+
|
|
37
|
+
/* The color of the placeholder text in the input area */
|
|
38
|
+
--copilot-kit-input-placeholder-color: var(--copilot-kit-muted-color);
|
|
39
|
+
|
|
40
|
+
/* The color of the text in the input area */
|
|
41
|
+
--copilot-kit-input-color: var(--copilot-kit-secondary-contrast-color);
|
|
42
|
+
|
|
43
|
+
/* The color of the separator between the input area and the messages area */
|
|
44
|
+
--copilot-kit-input-separator-color: var(--copilot-kit-separator-color);
|
|
45
|
+
|
|
46
|
+
/* The background color of the messages area */
|
|
47
|
+
--copilot-kit-messages-background-color: var(--copilot-kit-background-color);
|
|
48
|
+
|
|
49
|
+
/* The background color of a user message */
|
|
50
|
+
--copilot-kit-message-user-background-color: var(--copilot-kit-primary-color);
|
|
51
|
+
--copilot-kit-message-user-color: var(--copilot-kit-contrast-color);
|
|
52
|
+
|
|
53
|
+
/* The background color of a assistant message */
|
|
54
|
+
--copilot-kit-message-assistant-background-color: var(--copilot-kit-secondary-color);
|
|
55
|
+
--copilot-kit-message-assistant-color: var(--copilot-kit-secondary-contrast-color);
|
|
56
|
+
|
|
57
|
+
/* The color of the response control button */
|
|
58
|
+
--copilot-kit-response-button-border-color: var(--copilot-kit-separator-color);
|
|
59
|
+
--copilot-kit-response-button-color: #333;
|
|
60
|
+
--copilot-kit-response-button-background-color: #fff;
|
|
61
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
.copilotKitHeader {
|
|
2
|
+
height: 56px;
|
|
3
|
+
font-weight: 500;
|
|
4
|
+
display: flex;
|
|
5
|
+
justify-content: center;
|
|
6
|
+
align-items: center;
|
|
7
|
+
position: relative;
|
|
8
|
+
background-color: var(--copilot-kit-header-background-color);
|
|
9
|
+
color: var(--copilot-kit-header-title-color);
|
|
10
|
+
border-top-left-radius: 0;
|
|
11
|
+
border-top-right-radius: 0;
|
|
12
|
+
border-bottom: 1px solid var(--copilot-kit-header-separator-color);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.copilotKitSidebar .copilotKitHeader {
|
|
16
|
+
border-radius: 0;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
@media (min-width: 640px) {
|
|
20
|
+
.copilotKitHeader {
|
|
21
|
+
padding-left: 24px;
|
|
22
|
+
padding-right: 24px;
|
|
23
|
+
border-top-left-radius: 8px;
|
|
24
|
+
border-top-right-radius: 8px;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.copilotKitHeader > button {
|
|
29
|
+
border: 0;
|
|
30
|
+
padding: 0px;
|
|
31
|
+
position: absolute;
|
|
32
|
+
top: 50%;
|
|
33
|
+
right: 16px;
|
|
34
|
+
transform: translateY(-50%);
|
|
35
|
+
outline: none;
|
|
36
|
+
color: var(--copilot-kit-header-close-button-color);
|
|
37
|
+
background-color: transparent;
|
|
38
|
+
cursor: pointer;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.copilotKitHeader > button:focus {
|
|
42
|
+
outline: none;
|
|
43
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
.copilotKitInput {
|
|
2
|
+
border-top: 1px solid var(--copilot-kit-input-separator-color);
|
|
3
|
+
padding-left: 2rem;
|
|
4
|
+
padding-right: 2.5rem;
|
|
5
|
+
padding-top: 1rem;
|
|
6
|
+
padding-bottom: 1rem;
|
|
7
|
+
display: flex;
|
|
8
|
+
align-items: center;
|
|
9
|
+
cursor: text;
|
|
10
|
+
position: relative;
|
|
11
|
+
border-bottom-left-radius: 0.75rem;
|
|
12
|
+
border-bottom-right-radius: 0.75rem;
|
|
13
|
+
background-color: var(--copilot-kit-input-background-color);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.copilotKitInput > button {
|
|
17
|
+
position: absolute;
|
|
18
|
+
right: 0.5rem;
|
|
19
|
+
padding: 0.25rem;
|
|
20
|
+
cursor: pointer;
|
|
21
|
+
transition-property: transform;
|
|
22
|
+
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
23
|
+
transition-duration: 200ms;
|
|
24
|
+
transform: scale(1);
|
|
25
|
+
color: rgba(0, 0, 0, 0.25);
|
|
26
|
+
-webkit-appearance: button;
|
|
27
|
+
appearance: button;
|
|
28
|
+
background-color: transparent;
|
|
29
|
+
background-image: none;
|
|
30
|
+
text-transform: none;
|
|
31
|
+
font-family: inherit;
|
|
32
|
+
font-size: 100%;
|
|
33
|
+
font-weight: inherit;
|
|
34
|
+
line-height: inherit;
|
|
35
|
+
border: 0;
|
|
36
|
+
margin: 0;
|
|
37
|
+
text-indent: 0px;
|
|
38
|
+
text-shadow: none;
|
|
39
|
+
display: inline-block;
|
|
40
|
+
text-align: center;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.copilotKitInput > button:not([disabled]) {
|
|
44
|
+
color: var(--copilot-kit-input-send-button-color);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.copilotKitInput > button:not([disabled]):hover {
|
|
48
|
+
transform: scale(1.1);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.copilotKitInput > button[disabled] {
|
|
52
|
+
color: var(--copilot-kit-input-send-button-disabled-color);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.copilotKitInput > textarea {
|
|
56
|
+
width: 100%;
|
|
57
|
+
outline: 2px solid transparent;
|
|
58
|
+
outline-offset: 2px;
|
|
59
|
+
resize: none;
|
|
60
|
+
white-space: pre-wrap;
|
|
61
|
+
overflow-wrap: break-word;
|
|
62
|
+
-webkit-font-smoothing: antialiased;
|
|
63
|
+
-moz-osx-font-smoothing: grayscale;
|
|
64
|
+
cursor: text;
|
|
65
|
+
font-size: 0.875rem;
|
|
66
|
+
line-height: 1.25rem;
|
|
67
|
+
margin: 0;
|
|
68
|
+
padding: 0;
|
|
69
|
+
font-family: inherit;
|
|
70
|
+
font-weight: inherit;
|
|
71
|
+
color: var(--copilot-kit-input-color);
|
|
72
|
+
border: 0px;
|
|
73
|
+
background-color: var(--copilot-kit-input-background-color);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.copilotKitInput > textarea::placeholder {
|
|
77
|
+
color: var(--copilot-kit-input-placeholder-color);
|
|
78
|
+
opacity: 1;
|
|
79
|
+
}
|