@copilotkit/react-ui 1.4.0-pre-1-4-0-alpha.10 → 1.4.0-pre-1-4-0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/CHANGELOG.md +175 -26
  2. package/dist/{chunk-QK6XA3PL.mjs → chunk-H5CXJBR5.mjs} +3 -3
  3. package/dist/{chunk-TEZWY2BL.mjs → chunk-M2NVAJQA.mjs} +2 -2
  4. package/dist/{chunk-C5KOJ3IH.mjs → chunk-ORHE7FYT.mjs} +2 -2
  5. package/dist/{chunk-OJ5NVSTU.mjs → chunk-PY7YBFPA.mjs} +2 -2
  6. package/dist/{chunk-CPMIEVKK.mjs → chunk-RKPANT3F.mjs} +65 -15
  7. package/dist/chunk-RKPANT3F.mjs.map +1 -0
  8. package/dist/components/chat/Chat.js +62 -13
  9. package/dist/components/chat/Chat.js.map +1 -1
  10. package/dist/components/chat/Chat.mjs +2 -2
  11. package/dist/components/chat/Messages.d.ts +6 -1
  12. package/dist/components/chat/Messages.js +66 -15
  13. package/dist/components/chat/Messages.js.map +1 -1
  14. package/dist/components/chat/Messages.mjs +5 -3
  15. package/dist/components/chat/Modal.js +62 -13
  16. package/dist/components/chat/Modal.js.map +1 -1
  17. package/dist/components/chat/Modal.mjs +3 -3
  18. package/dist/components/chat/Popup.js +62 -13
  19. package/dist/components/chat/Popup.js.map +1 -1
  20. package/dist/components/chat/Popup.mjs +4 -4
  21. package/dist/components/chat/Sidebar.js +62 -13
  22. package/dist/components/chat/Sidebar.js.map +1 -1
  23. package/dist/components/chat/Sidebar.mjs +4 -4
  24. package/dist/components/chat/index.js +62 -13
  25. package/dist/components/chat/index.js.map +1 -1
  26. package/dist/components/chat/index.mjs +5 -5
  27. package/dist/components/index.js +62 -13
  28. package/dist/components/index.js.map +1 -1
  29. package/dist/components/index.mjs +5 -5
  30. package/dist/index.js +62 -13
  31. package/dist/index.js.map +1 -1
  32. package/dist/index.mjs +5 -5
  33. package/package.json +7 -7
  34. package/src/components/chat/Messages.tsx +72 -15
  35. package/dist/chunk-CPMIEVKK.mjs.map +0 -1
  36. /package/dist/{chunk-QK6XA3PL.mjs.map → chunk-H5CXJBR5.mjs.map} +0 -0
  37. /package/dist/{chunk-TEZWY2BL.mjs.map → chunk-M2NVAJQA.mjs.map} +0 -0
  38. /package/dist/{chunk-C5KOJ3IH.mjs.map → chunk-ORHE7FYT.mjs.map} +0 -0
  39. /package/dist/{chunk-OJ5NVSTU.mjs.map → chunk-PY7YBFPA.mjs.map} +0 -0
@@ -2,7 +2,7 @@ import {
2
2
  CopilotChat,
3
3
  WrappedCopilotChat,
4
4
  useCopilotChatLogic
5
- } from "../../chunk-C5KOJ3IH.mjs";
5
+ } from "../../chunk-ORHE7FYT.mjs";
6
6
  import "../../chunk-V7W6IM2V.mjs";
7
7
  import "../../chunk-OMTPWC7T.mjs";
8
8
  import "../../chunk-ZABXREBH.mjs";
@@ -15,7 +15,7 @@ import "../../chunk-OTPAZXVR.mjs";
15
15
  import "../../chunk-4LUMV4YO.mjs";
16
16
  import "../../chunk-YQFVRDNC.mjs";
17
17
  import "../../chunk-YQ3D5IQV.mjs";
18
- import "../../chunk-CPMIEVKK.mjs";
18
+ import "../../chunk-RKPANT3F.mjs";
19
19
  import "../../chunk-3XAXY2Z3.mjs";
20
20
  import "../../chunk-CBBFRI3Q.mjs";
21
21
  import "../../chunk-UPTB2MVO.mjs";
@@ -1,7 +1,12 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React__default from 'react';
2
3
  import { MessagesProps } from './props.js';
3
4
  import '@copilotkit/runtime-client-gql';
4
5
 
5
6
  declare const Messages: ({ messages, inProgress, children, RenderTextMessage, RenderActionExecutionMessage, RenderAgentStateMessage, RenderResultMessage, }: MessagesProps) => react_jsx_runtime.JSX.Element;
7
+ declare function useScrollToBottom(messages: any[]): {
8
+ messagesEndRef: React__default.RefObject<HTMLDivElement>;
9
+ messagesContainerRef: React__default.MutableRefObject<HTMLDivElement | null>;
10
+ };
6
11
 
7
- export { Messages };
12
+ export { Messages, useScrollToBottom };
@@ -30,10 +30,11 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/components/chat/Messages.tsx
31
31
  var Messages_exports = {};
32
32
  __export(Messages_exports, {
33
- Messages: () => Messages
33
+ Messages: () => Messages,
34
+ useScrollToBottom: () => useScrollToBottom
34
35
  });
35
36
  module.exports = __toCommonJS(Messages_exports);
36
- var import_react2 = __toESM(require("react"));
37
+ var import_react2 = require("react");
37
38
 
38
39
  // src/components/chat/ChatContext.tsx
39
40
  var import_react = __toESM(require("react"));
@@ -79,18 +80,8 @@ var Messages = ({
79
80
  }
80
81
  }
81
82
  }
82
- const messagesEndRef = import_react2.default.useRef(null);
83
- const scrollToBottom = () => {
84
- if (messagesEndRef.current) {
85
- messagesEndRef.current.scrollIntoView({
86
- behavior: "auto"
87
- });
88
- }
89
- };
90
- (0, import_react2.useEffect)(() => {
91
- scrollToBottom();
92
- }, [messages]);
93
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "copilotKitMessages", children: [
83
+ const { messagesEndRef, messagesContainerRef } = useScrollToBottom(messages);
84
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "copilotKitMessages", ref: messagesContainerRef, children: [
94
85
  messages.map((message, index) => {
95
86
  const isCurrentMessage = index === messages.length - 1;
96
87
  if (message.isTextMessage()) {
@@ -159,8 +150,68 @@ function makeInitialMessages(initial) {
159
150
  })
160
151
  );
161
152
  }
153
+ function useScrollToBottom(messages) {
154
+ const messagesEndRef = (0, import_react2.useRef)(null);
155
+ const messagesContainerRef = (0, import_react2.useRef)(null);
156
+ const isProgrammaticScrollRef = (0, import_react2.useRef)(false);
157
+ const isUserScrollUpRef = (0, import_react2.useRef)(false);
158
+ const scrollToBottom = () => {
159
+ if (messagesEndRef.current) {
160
+ isProgrammaticScrollRef.current = true;
161
+ messagesEndRef.current.scrollIntoView({
162
+ behavior: "auto"
163
+ });
164
+ }
165
+ };
166
+ const handleScroll = () => {
167
+ if (isProgrammaticScrollRef.current) {
168
+ isProgrammaticScrollRef.current = false;
169
+ return;
170
+ }
171
+ if (messagesContainerRef.current) {
172
+ const { scrollTop, scrollHeight, clientHeight } = messagesContainerRef.current;
173
+ isUserScrollUpRef.current = scrollTop + clientHeight < scrollHeight;
174
+ }
175
+ };
176
+ (0, import_react2.useEffect)(() => {
177
+ const container = messagesContainerRef.current;
178
+ if (container) {
179
+ container.addEventListener("scroll", handleScroll);
180
+ }
181
+ return () => {
182
+ if (container) {
183
+ container.removeEventListener("scroll", handleScroll);
184
+ }
185
+ };
186
+ }, []);
187
+ (0, import_react2.useEffect)(() => {
188
+ const container = messagesContainerRef.current;
189
+ if (!container) {
190
+ return;
191
+ }
192
+ const mutationObserver = new MutationObserver(() => {
193
+ if (!isUserScrollUpRef.current) {
194
+ scrollToBottom();
195
+ }
196
+ });
197
+ mutationObserver.observe(container, {
198
+ childList: true,
199
+ subtree: true,
200
+ characterData: true
201
+ });
202
+ return () => {
203
+ mutationObserver.disconnect();
204
+ };
205
+ }, []);
206
+ (0, import_react2.useEffect)(() => {
207
+ isUserScrollUpRef.current = false;
208
+ scrollToBottom();
209
+ }, [messages.filter((m) => m.isTextMessage() && m.role === import_runtime_client_gql.Role.User).length]);
210
+ return { messagesEndRef, messagesContainerRef };
211
+ }
162
212
  // Annotate the CommonJS export names for ESM import in node:
163
213
  0 && (module.exports = {
164
- Messages
214
+ Messages,
215
+ useScrollToBottom
165
216
  });
166
217
  //# sourceMappingURL=Messages.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/chat/Messages.tsx","../../../src/components/chat/ChatContext.tsx"],"sourcesContent":["import React, { useEffect, useMemo } from \"react\";\nimport { MessagesProps } from \"./props\";\nimport { useChatContext } from \"./ChatContext\";\nimport {\n ActionExecutionMessage,\n Message,\n ResultMessage,\n TextMessage,\n Role,\n AgentStateMessage,\n} from \"@copilotkit/runtime-client-gql\";\n\nexport const Messages = ({\n messages,\n inProgress,\n children,\n RenderTextMessage,\n RenderActionExecutionMessage,\n RenderAgentStateMessage,\n RenderResultMessage,\n}: MessagesProps) => {\n const context = useChatContext();\n const initialMessages = useMemo(\n () => makeInitialMessages(context.labels.initial),\n [context.labels.initial],\n );\n messages = [...initialMessages, ...messages];\n\n const actionResults: Record<string, string> = {};\n\n for (let i = 0; i < messages.length; i++) {\n if (messages[i].isActionExecutionMessage()) {\n const id = messages[i].id;\n const resultMessage: ResultMessage | undefined = messages.find(\n (message) => message.isResultMessage() && message.actionExecutionId === id,\n ) as ResultMessage | undefined;\n\n if (resultMessage) {\n actionResults[id] = ResultMessage.decodeResult(resultMessage.result || \"\");\n }\n }\n }\n\n const messagesEndRef = React.useRef<HTMLDivElement>(null);\n\n const scrollToBottom = () => {\n if (messagesEndRef.current) {\n messagesEndRef.current.scrollIntoView({\n behavior: \"auto\",\n });\n }\n };\n\n useEffect(() => {\n scrollToBottom();\n }, [messages]);\n\n return (\n <div className=\"copilotKitMessages\">\n {messages.map((message, index) => {\n const isCurrentMessage = index === messages.length - 1;\n\n if (message.isTextMessage()) {\n return (\n <RenderTextMessage\n key={index}\n message={message}\n inProgress={inProgress}\n index={index}\n isCurrentMessage={isCurrentMessage}\n />\n );\n } else if (message.isActionExecutionMessage()) {\n return (\n <RenderActionExecutionMessage\n key={index}\n message={message}\n inProgress={inProgress}\n index={index}\n isCurrentMessage={isCurrentMessage}\n actionResult={actionResults[message.id]}\n />\n );\n } else if (message.isAgentStateMessage()) {\n return (\n <RenderAgentStateMessage\n key={index}\n message={message}\n inProgress={inProgress}\n index={index}\n isCurrentMessage={isCurrentMessage}\n />\n );\n } else if (message.isResultMessage()) {\n return (\n <RenderResultMessage\n key={index}\n message={message}\n inProgress={inProgress}\n index={index}\n isCurrentMessage={isCurrentMessage}\n />\n );\n }\n })}\n <footer ref={messagesEndRef}>{children}</footer>\n </div>\n );\n};\n\nfunction makeInitialMessages(initial?: string | string[]): Message[] {\n let initialArray: string[] = [];\n if (initial) {\n if (Array.isArray(initial)) {\n initialArray.push(...initial);\n } else {\n initialArray.push(initial);\n }\n }\n\n return initialArray.map(\n (message) =>\n new TextMessage({\n role: Role.Assistant,\n content: message,\n }),\n );\n}\n","import React, { useMemo, useState } from \"react\";\nimport * as DefaultIcons from \"./Icons\";\n\n/**\n * Icons for CopilotChat component.\n */\nexport interface CopilotChatIcons {\n /**\n * The icon to use for the open chat button.\n * @default <OpenIcon />\n */\n openIcon?: React.ReactNode;\n\n /**\n * The icon to use for the close chat button.\n * @default <CloseIcon />\n */\n closeIcon?: React.ReactNode;\n\n /**\n * The icon to use for the close chat button in the header.\n * @default <HeaderCloseIcon />\n */\n headerCloseIcon?: React.ReactNode;\n\n /**\n * The icon to use for the send button.\n * @default <SendIcon />\n */\n sendIcon?: React.ReactNode;\n\n /**\n * The icon to use for the activity indicator.\n * @default <ActivityIcon />\n */\n activityIcon?: React.ReactNode;\n\n /**\n * The icon to use for the spinner.\n * @default <SpinnerIcon />\n */\n spinnerIcon?: React.ReactNode;\n\n /**\n * The icon to use for the stop button.\n * @default <StopIcon />\n */\n stopIcon?: React.ReactNode;\n\n /**\n * The icon to use for the regenerate button.\n * @default <RegenerateIcon />\n */\n regenerateIcon?: React.ReactNode;\n\n /**\n * The icons to use for push to talk.\n * @default <PushToTalkIcon />\n */\n\n pushToTalkIcon?: React.ReactNode;\n}\n\n/**\n * Labels for CopilotChat component.\n */\nexport interface CopilotChatLabels {\n /**\n * The initial message(s) to display in the chat window.\n */\n initial?: string | string[];\n\n /**\n * The title to display in the header.\n * @default \"CopilotKit\"\n */\n title?: string;\n\n /**\n * The placeholder to display in the input.\n * @default \"Type a message...\"\n */\n placeholder?: string;\n\n /**\n * The message to display when an error occurs.\n * @default \"❌ An error occurred. Please try again.\"\n */\n error?: string;\n\n /**\n * The label to display on the stop button.\n * @default \"Stop generating\"\n */\n stopGenerating?: string;\n\n /**\n * The label to display on the regenerate button.\n * @default \"Regenerate response\"\n */\n regenerateResponse?: string;\n}\n\ninterface ChatContext {\n labels: Required<CopilotChatLabels>;\n icons: Required<CopilotChatIcons>;\n open: boolean;\n setOpen: (open: boolean) => void;\n}\n\nexport const ChatContext = React.createContext<ChatContext | undefined>(undefined);\n\nexport function useChatContext(): ChatContext {\n const context = React.useContext(ChatContext);\n if (context === undefined) {\n throw new Error(\n \"Context not found. Did you forget to wrap your app in a <ChatContextProvider> component?\",\n );\n }\n return context;\n}\n\ninterface ChatContextProps {\n // temperature?: number;\n // instructions?: string;\n // maxFeedback?: number;\n labels?: CopilotChatLabels;\n icons?: CopilotChatIcons;\n children?: React.ReactNode;\n open: boolean;\n setOpen: (open: boolean) => void;\n}\n\nexport const ChatContextProvider = ({\n // temperature,\n // instructions,\n // maxFeedback,\n labels,\n icons,\n children,\n open,\n setOpen,\n}: ChatContextProps) => {\n const memoizedLabels = useMemo(\n () => ({\n ...{\n initial: \"\",\n title: \"CopilotKit\",\n placeholder: \"Type a message...\",\n error: \"❌ An error occurred. Please try again.\",\n stopGenerating: \"Stop generating\",\n regenerateResponse: \"Regenerate response\",\n },\n ...labels,\n }),\n [labels],\n );\n\n const memoizedIcons = useMemo(\n () => ({\n ...{\n openIcon: DefaultIcons.OpenIcon,\n closeIcon: DefaultIcons.CloseIcon,\n headerCloseIcon: DefaultIcons.HeaderCloseIcon,\n sendIcon: DefaultIcons.SendIcon,\n activityIcon: DefaultIcons.ActivityIcon,\n spinnerIcon: DefaultIcons.SpinnerIcon,\n stopIcon: DefaultIcons.StopIcon,\n regenerateIcon: DefaultIcons.RegenerateIcon,\n pushToTalkIcon: DefaultIcons.PushToTalkIcon,\n },\n ...icons,\n }),\n [icons],\n );\n\n const context = useMemo(\n () => ({\n labels: memoizedLabels,\n icons: memoizedIcons,\n open,\n setOpen,\n }),\n [memoizedLabels, memoizedIcons, open, setOpen],\n );\n\n return <ChatContext.Provider value={context}>{children}</ChatContext.Provider>;\n};\n"],"mappings":"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","names":["import_react","React","import_jsx_runtime","React"]}
1
+ {"version":3,"sources":["../../../src/components/chat/Messages.tsx","../../../src/components/chat/ChatContext.tsx"],"sourcesContent":["import React, { useEffect, useMemo, useRef } from \"react\";\nimport { MessagesProps } from \"./props\";\nimport { useChatContext } from \"./ChatContext\";\nimport {\n ActionExecutionMessage,\n Message,\n ResultMessage,\n TextMessage,\n Role,\n AgentStateMessage,\n} from \"@copilotkit/runtime-client-gql\";\n\nexport const Messages = ({\n messages,\n inProgress,\n children,\n RenderTextMessage,\n RenderActionExecutionMessage,\n RenderAgentStateMessage,\n RenderResultMessage,\n}: MessagesProps) => {\n const context = useChatContext();\n const initialMessages = useMemo(\n () => makeInitialMessages(context.labels.initial),\n [context.labels.initial],\n );\n messages = [...initialMessages, ...messages];\n\n const actionResults: Record<string, string> = {};\n\n for (let i = 0; i < messages.length; i++) {\n if (messages[i].isActionExecutionMessage()) {\n const id = messages[i].id;\n const resultMessage: ResultMessage | undefined = messages.find(\n (message) => message.isResultMessage() && message.actionExecutionId === id,\n ) as ResultMessage | undefined;\n\n if (resultMessage) {\n actionResults[id] = ResultMessage.decodeResult(resultMessage.result || \"\");\n }\n }\n }\n\n const { messagesEndRef, messagesContainerRef } = useScrollToBottom(messages);\n\n return (\n <div className=\"copilotKitMessages\" ref={messagesContainerRef}>\n {messages.map((message, index) => {\n const isCurrentMessage = index === messages.length - 1;\n\n if (message.isTextMessage()) {\n return (\n <RenderTextMessage\n key={index}\n message={message}\n inProgress={inProgress}\n index={index}\n isCurrentMessage={isCurrentMessage}\n />\n );\n } else if (message.isActionExecutionMessage()) {\n return (\n <RenderActionExecutionMessage\n key={index}\n message={message}\n inProgress={inProgress}\n index={index}\n isCurrentMessage={isCurrentMessage}\n actionResult={actionResults[message.id]}\n />\n );\n } else if (message.isAgentStateMessage()) {\n return (\n <RenderAgentStateMessage\n key={index}\n message={message}\n inProgress={inProgress}\n index={index}\n isCurrentMessage={isCurrentMessage}\n />\n );\n } else if (message.isResultMessage()) {\n return (\n <RenderResultMessage\n key={index}\n message={message}\n inProgress={inProgress}\n index={index}\n isCurrentMessage={isCurrentMessage}\n />\n );\n }\n })}\n <footer ref={messagesEndRef}>{children}</footer>\n </div>\n );\n};\n\nfunction makeInitialMessages(initial?: string | string[]): Message[] {\n let initialArray: string[] = [];\n if (initial) {\n if (Array.isArray(initial)) {\n initialArray.push(...initial);\n } else {\n initialArray.push(initial);\n }\n }\n\n return initialArray.map(\n (message) =>\n new TextMessage({\n role: Role.Assistant,\n content: message,\n }),\n );\n}\nexport function useScrollToBottom(messages: any[]) {\n const messagesEndRef = useRef<HTMLDivElement>(null);\n const messagesContainerRef = useRef<HTMLDivElement | null>(null);\n const isProgrammaticScrollRef = useRef(false);\n const isUserScrollUpRef = useRef(false);\n\n const scrollToBottom = () => {\n if (messagesEndRef.current) {\n isProgrammaticScrollRef.current = true;\n messagesEndRef.current.scrollIntoView({\n behavior: \"auto\",\n });\n }\n };\n\n const handleScroll = () => {\n if (isProgrammaticScrollRef.current) {\n isProgrammaticScrollRef.current = false;\n return;\n }\n\n if (messagesContainerRef.current) {\n const { scrollTop, scrollHeight, clientHeight } = messagesContainerRef.current;\n isUserScrollUpRef.current = scrollTop + clientHeight < scrollHeight;\n }\n };\n\n useEffect(() => {\n const container = messagesContainerRef.current;\n if (container) {\n container.addEventListener(\"scroll\", handleScroll);\n }\n return () => {\n if (container) {\n container.removeEventListener(\"scroll\", handleScroll);\n }\n };\n }, []);\n\n useEffect(() => {\n const container = messagesContainerRef.current;\n if (!container) {\n return;\n }\n\n const mutationObserver = new MutationObserver(() => {\n if (!isUserScrollUpRef.current) {\n scrollToBottom();\n }\n });\n\n mutationObserver.observe(container, {\n childList: true,\n subtree: true,\n characterData: true,\n });\n\n return () => {\n mutationObserver.disconnect();\n };\n }, []);\n\n useEffect(() => {\n isUserScrollUpRef.current = false;\n scrollToBottom();\n }, [messages.filter((m) => m.isTextMessage() && m.role === Role.User).length]);\n\n return { messagesEndRef, messagesContainerRef };\n}\n","import React, { useMemo, useState } from \"react\";\nimport * as DefaultIcons from \"./Icons\";\n\n/**\n * Icons for CopilotChat component.\n */\nexport interface CopilotChatIcons {\n /**\n * The icon to use for the open chat button.\n * @default <OpenIcon />\n */\n openIcon?: React.ReactNode;\n\n /**\n * The icon to use for the close chat button.\n * @default <CloseIcon />\n */\n closeIcon?: React.ReactNode;\n\n /**\n * The icon to use for the close chat button in the header.\n * @default <HeaderCloseIcon />\n */\n headerCloseIcon?: React.ReactNode;\n\n /**\n * The icon to use for the send button.\n * @default <SendIcon />\n */\n sendIcon?: React.ReactNode;\n\n /**\n * The icon to use for the activity indicator.\n * @default <ActivityIcon />\n */\n activityIcon?: React.ReactNode;\n\n /**\n * The icon to use for the spinner.\n * @default <SpinnerIcon />\n */\n spinnerIcon?: React.ReactNode;\n\n /**\n * The icon to use for the stop button.\n * @default <StopIcon />\n */\n stopIcon?: React.ReactNode;\n\n /**\n * The icon to use for the regenerate button.\n * @default <RegenerateIcon />\n */\n regenerateIcon?: React.ReactNode;\n\n /**\n * The icons to use for push to talk.\n * @default <PushToTalkIcon />\n */\n\n pushToTalkIcon?: React.ReactNode;\n}\n\n/**\n * Labels for CopilotChat component.\n */\nexport interface CopilotChatLabels {\n /**\n * The initial message(s) to display in the chat window.\n */\n initial?: string | string[];\n\n /**\n * The title to display in the header.\n * @default \"CopilotKit\"\n */\n title?: string;\n\n /**\n * The placeholder to display in the input.\n * @default \"Type a message...\"\n */\n placeholder?: string;\n\n /**\n * The message to display when an error occurs.\n * @default \"❌ An error occurred. Please try again.\"\n */\n error?: string;\n\n /**\n * The label to display on the stop button.\n * @default \"Stop generating\"\n */\n stopGenerating?: string;\n\n /**\n * The label to display on the regenerate button.\n * @default \"Regenerate response\"\n */\n regenerateResponse?: string;\n}\n\ninterface ChatContext {\n labels: Required<CopilotChatLabels>;\n icons: Required<CopilotChatIcons>;\n open: boolean;\n setOpen: (open: boolean) => void;\n}\n\nexport const ChatContext = React.createContext<ChatContext | undefined>(undefined);\n\nexport function useChatContext(): ChatContext {\n const context = React.useContext(ChatContext);\n if (context === undefined) {\n throw new Error(\n \"Context not found. Did you forget to wrap your app in a <ChatContextProvider> component?\",\n );\n }\n return context;\n}\n\ninterface ChatContextProps {\n // temperature?: number;\n // instructions?: string;\n // maxFeedback?: number;\n labels?: CopilotChatLabels;\n icons?: CopilotChatIcons;\n children?: React.ReactNode;\n open: boolean;\n setOpen: (open: boolean) => void;\n}\n\nexport const ChatContextProvider = ({\n // temperature,\n // instructions,\n // maxFeedback,\n labels,\n icons,\n children,\n open,\n setOpen,\n}: ChatContextProps) => {\n const memoizedLabels = useMemo(\n () => ({\n ...{\n initial: \"\",\n title: \"CopilotKit\",\n placeholder: \"Type a message...\",\n error: \"❌ An error occurred. Please try again.\",\n stopGenerating: \"Stop generating\",\n regenerateResponse: \"Regenerate response\",\n },\n ...labels,\n }),\n [labels],\n );\n\n const memoizedIcons = useMemo(\n () => ({\n ...{\n openIcon: DefaultIcons.OpenIcon,\n closeIcon: DefaultIcons.CloseIcon,\n headerCloseIcon: DefaultIcons.HeaderCloseIcon,\n sendIcon: DefaultIcons.SendIcon,\n activityIcon: DefaultIcons.ActivityIcon,\n spinnerIcon: DefaultIcons.SpinnerIcon,\n stopIcon: DefaultIcons.StopIcon,\n regenerateIcon: DefaultIcons.RegenerateIcon,\n pushToTalkIcon: DefaultIcons.PushToTalkIcon,\n },\n ...icons,\n }),\n [icons],\n );\n\n const context = useMemo(\n () => ({\n labels: memoizedLabels,\n icons: memoizedIcons,\n open,\n setOpen,\n }),\n [memoizedLabels, memoizedIcons, open, setOpen],\n );\n\n return <ChatContext.Provider value={context}>{children}</ChatContext.Provider>;\n};\n"],"mappings":"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","names":["import_react","React","import_jsx_runtime"]}
@@ -1,10 +1,12 @@
1
1
  import {
2
- Messages
3
- } from "../../chunk-CPMIEVKK.mjs";
2
+ Messages,
3
+ useScrollToBottom
4
+ } from "../../chunk-RKPANT3F.mjs";
4
5
  import "../../chunk-CBBFRI3Q.mjs";
5
6
  import "../../chunk-FZC7X5PK.mjs";
6
7
  import "../../chunk-MRXNTQOX.mjs";
7
8
  export {
8
- Messages
9
+ Messages,
10
+ useScrollToBottom
9
11
  };
10
12
  //# sourceMappingURL=Messages.mjs.map
@@ -524,7 +524,7 @@ var Header = ({}) => {
524
524
  };
525
525
 
526
526
  // src/components/chat/Messages.tsx
527
- var import_react3 = __toESM(require("react"));
527
+ var import_react3 = require("react");
528
528
  var import_runtime_client_gql = require("@copilotkit/runtime-client-gql");
529
529
  var import_jsx_runtime6 = require("react/jsx-runtime");
530
530
  var Messages = ({
@@ -554,18 +554,8 @@ var Messages = ({
554
554
  }
555
555
  }
556
556
  }
557
- const messagesEndRef = import_react3.default.useRef(null);
558
- const scrollToBottom = () => {
559
- if (messagesEndRef.current) {
560
- messagesEndRef.current.scrollIntoView({
561
- behavior: "auto"
562
- });
563
- }
564
- };
565
- (0, import_react3.useEffect)(() => {
566
- scrollToBottom();
567
- }, [messages]);
568
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "copilotKitMessages", children: [
557
+ const { messagesEndRef, messagesContainerRef } = useScrollToBottom(messages);
558
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "copilotKitMessages", ref: messagesContainerRef, children: [
569
559
  messages.map((message, index) => {
570
560
  const isCurrentMessage = index === messages.length - 1;
571
561
  if (message.isTextMessage()) {
@@ -634,6 +624,65 @@ function makeInitialMessages(initial) {
634
624
  })
635
625
  );
636
626
  }
627
+ function useScrollToBottom(messages) {
628
+ const messagesEndRef = (0, import_react3.useRef)(null);
629
+ const messagesContainerRef = (0, import_react3.useRef)(null);
630
+ const isProgrammaticScrollRef = (0, import_react3.useRef)(false);
631
+ const isUserScrollUpRef = (0, import_react3.useRef)(false);
632
+ const scrollToBottom = () => {
633
+ if (messagesEndRef.current) {
634
+ isProgrammaticScrollRef.current = true;
635
+ messagesEndRef.current.scrollIntoView({
636
+ behavior: "auto"
637
+ });
638
+ }
639
+ };
640
+ const handleScroll = () => {
641
+ if (isProgrammaticScrollRef.current) {
642
+ isProgrammaticScrollRef.current = false;
643
+ return;
644
+ }
645
+ if (messagesContainerRef.current) {
646
+ const { scrollTop, scrollHeight, clientHeight } = messagesContainerRef.current;
647
+ isUserScrollUpRef.current = scrollTop + clientHeight < scrollHeight;
648
+ }
649
+ };
650
+ (0, import_react3.useEffect)(() => {
651
+ const container = messagesContainerRef.current;
652
+ if (container) {
653
+ container.addEventListener("scroll", handleScroll);
654
+ }
655
+ return () => {
656
+ if (container) {
657
+ container.removeEventListener("scroll", handleScroll);
658
+ }
659
+ };
660
+ }, []);
661
+ (0, import_react3.useEffect)(() => {
662
+ const container = messagesContainerRef.current;
663
+ if (!container) {
664
+ return;
665
+ }
666
+ const mutationObserver = new MutationObserver(() => {
667
+ if (!isUserScrollUpRef.current) {
668
+ scrollToBottom();
669
+ }
670
+ });
671
+ mutationObserver.observe(container, {
672
+ childList: true,
673
+ subtree: true,
674
+ characterData: true
675
+ });
676
+ return () => {
677
+ mutationObserver.disconnect();
678
+ };
679
+ }, []);
680
+ (0, import_react3.useEffect)(() => {
681
+ isUserScrollUpRef.current = false;
682
+ scrollToBottom();
683
+ }, [messages.filter((m) => m.isTextMessage() && m.role === import_runtime_client_gql.Role.User).length]);
684
+ return { messagesEndRef, messagesContainerRef };
685
+ }
637
686
 
638
687
  // src/components/chat/Input.tsx
639
688
  var import_react6 = require("react");