@blocksdiy/react-common 1.27.1 → 1.28.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.
@@ -1,7 +1,8 @@
1
- import { type Message, type UserMessage } from "@ag-ui/client";
1
+ import { type Message, ToolMessage, type UserMessage } from "@ag-ui/client";
2
+ import { useRenderToolCall } from "@copilotkit/react-core/v2";
2
3
  import { ReactNode, SetStateAction } from "react";
3
- export { type Message, type AssistantMessage } from "@ag-ui/client";
4
- export { useRenderTool, useRenderToolCall, useDefaultRenderTool, useHumanInTheLoop, useFrontendTool, ToolCallStatus, } from "@copilotkit/react-core/v2";
4
+ export { type Message, type AssistantMessage, type UserMessage } from "@ag-ui/client";
5
+ export { useRenderTool, useDefaultRenderTool, useHumanInTheLoop, useFrontendTool, ToolCallStatus, } from "@copilotkit/react-core/v2";
5
6
  export interface Attachment {
6
7
  url: string;
7
8
  fileType: string;
@@ -10,10 +11,15 @@ export interface Attachment {
10
11
  export interface AgentChatComponent {
11
12
  id: string;
12
13
  name: string;
13
- toolName?: string;
14
- code?: string;
14
+ code: string;
15
15
  input?: Record<string, unknown>;
16
16
  description?: string;
17
+ /**
18
+ * When true, the chat_component tool pauses the agent run on the BE
19
+ * via `interrupt(...)` and the FE must call `respond(...)` (exposed
20
+ * to the rendered code) to resume it. Mirrors `block.data.userInterrupt`.
21
+ */
22
+ userInterrupt?: boolean;
17
23
  }
18
24
  export declare const getAgentChatComponentToolName: (name: string) => string;
19
25
  export interface AgentChat {
@@ -45,6 +51,14 @@ export interface AgentChatContextValue {
45
51
  agent: Agent | null;
46
52
  agentChat: AgentChat | null;
47
53
  components: AgentChatComponent[];
54
+ messageGroups: {
55
+ messageIds: string[];
56
+ role: "assistant" | "user";
57
+ }[];
58
+ messageById: Map<string, Message>;
59
+ toolMessages: ToolMessage[];
60
+ renderToolCall: ReturnType<typeof useRenderToolCall>;
61
+ hasSentMessageInSession: boolean;
48
62
  sendMessage: (message: Omit<UserMessage, "id" | "role">) => Promise<void>;
49
63
  sendFromInputs: () => Promise<void>;
50
64
  stopGeneration: () => void;
@@ -58,6 +72,11 @@ export interface AgentChatContextValue {
58
72
  }
59
73
  export declare const AgentChatContext: import("react").Context<AgentChatContextValue | null>;
60
74
  export declare const useAgentChat: () => AgentChatContextValue;
75
+ interface AgentChatScrollContextValue {
76
+ isAtBottom: boolean;
77
+ scrollToBottom: () => void;
78
+ }
79
+ export declare const useAgentChatScroll: () => AgentChatScrollContextValue;
61
80
  export interface AgentChatRootProps {
62
81
  appId: string;
63
82
  token?: string;
@@ -82,10 +101,22 @@ export interface AgentChatMessageProps {
82
101
  index: number;
83
102
  }
84
103
  export declare function AgentChatMessage({ message, index, ...props }: React.ComponentProps<"div"> & AgentChatMessageProps): import("react/jsx-runtime").JSX.Element | null;
104
+ export interface AgentChatMessageGroupProps {
105
+ messageGroup: {
106
+ messageIds: string[];
107
+ role: "assistant" | "user";
108
+ };
109
+ isLast?: boolean;
110
+ }
111
+ export declare function AgentChatMessageGroup({ messageGroup, isLast, style, ...props }: React.ComponentProps<"div"> & AgentChatMessageGroupProps): import("react/jsx-runtime").JSX.Element;
85
112
  export interface AgentChatMessagesProps {
86
113
  scrollAreaClassName?: string;
87
114
  }
88
- export declare function AgentChatMessages({ scrollAreaClassName, ...props }: React.ComponentProps<"div"> & AgentChatMessagesProps): import("react/jsx-runtime").JSX.Element;
115
+ export declare function AgentChatMessages({ scrollAreaClassName, children, ...props }: React.ComponentProps<"div"> & AgentChatMessagesProps): import("react/jsx-runtime").JSX.Element;
116
+ export interface AgentChatScrollToBottomProps {
117
+ asChild?: boolean;
118
+ }
119
+ export declare function AgentChatScrollToBottom({ asChild, onClick, ...props }: React.ComponentProps<"button"> & AgentChatScrollToBottomProps): import("react/jsx-runtime").JSX.Element | null;
89
120
  export interface AgentChatThinkingProps {
90
121
  asChild?: boolean;
91
122
  }
@@ -1 +1 @@
1
- {"version":3,"file":"new-agent-chat.d.ts","sourceRoot":"","sources":["../../src/components/new-agent-chat.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"new-agent-chat.d.ts","sourceRoot":"","sources":["../../src/components/new-agent-chat.tsx"],"names":[],"mappings":"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"}
@@ -2,11 +2,10 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
2
2
  import { AppVersionService, BlocksApiService, websocketsService } from "@blocksdiy/blocks-client-api";
3
3
  import { getApiHost } from "@blocksdiy/blocks-client-api/envService";
4
4
  import { CopilotKit, useCopilotChatInternal } from "@copilotkit/react-core";
5
- import { useCopilotKit } from "@copilotkit/react-core/v2";
5
+ import { useCopilotKit, useRenderToolCall } from "@copilotkit/react-core/v2";
6
6
  import { Slot } from "@radix-ui/react-slot";
7
7
  import { createContext, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState, } from "react";
8
- export { useRenderTool, useRenderToolCall, useDefaultRenderTool, useHumanInTheLoop, useFrontendTool, ToolCallStatus, } from "@copilotkit/react-core/v2";
9
- import { useStickToBottom } from "use-stick-to-bottom";
8
+ export { useRenderTool, useDefaultRenderTool, useHumanInTheLoop, useFrontendTool, ToolCallStatus, } from "@copilotkit/react-core/v2";
10
9
  // Client-only `useLayoutEffect`, falls back to `useEffect` during SSR.
11
10
  // Needed so the `agent.threadId` mirror commits before CopilotKit's
12
11
  // connect-on-mount effect reads it.
@@ -61,15 +60,82 @@ const validateAndConvertFiles = (files) => {
61
60
  }
62
61
  const hasOversizedFiles = files.some((file) => file.size > MAX_FILE_SIZE_BYTES);
63
62
  if (hasOversizedFiles) {
64
- console.error(`Upload failed because some files are bigger than ${MAX_FILE_SIZE_MB} MB.`);
65
63
  return null;
66
64
  }
67
65
  return files.map((file) => ({
68
- fileType: file.type,
66
+ fileType: file.type || "application/octet-stream",
69
67
  fileName: file.name,
70
68
  url: URL.createObjectURL(file),
71
69
  }));
72
70
  };
71
+ const fileFromAttachment = async (attachment) => {
72
+ const response = await fetch(attachment.url);
73
+ if (!response.ok) {
74
+ throw new Error("The blob URL is no longer valid");
75
+ }
76
+ const blob = await response.blob();
77
+ return new File([blob], attachment.fileName, {
78
+ type: attachment.fileType,
79
+ lastModified: Date.now(),
80
+ });
81
+ };
82
+ const getBrowserUploadUrl = (uploadUrl) => {
83
+ try {
84
+ const url = new URL(uploadUrl);
85
+ if (url.hostname === "localhost" && url.port === "4566") {
86
+ url.hostname = "blocks.localhost";
87
+ return url.toString();
88
+ }
89
+ }
90
+ catch {
91
+ return uploadUrl;
92
+ }
93
+ return uploadUrl;
94
+ };
95
+ const uploadFile = async ({ appId, blocksApiService, file, }) => {
96
+ const formData = new FormData();
97
+ const { uploadUrl, fields, protectedUrl } = await blocksApiService.getDataAssetUploadUrl({
98
+ productId: appId,
99
+ fileName: file.name,
100
+ fileType: file.type,
101
+ });
102
+ const request = new XMLHttpRequest();
103
+ if (uploadUrl && fields) {
104
+ for (const [key, value] of Object.entries(fields)) {
105
+ formData.append(key, value);
106
+ }
107
+ formData.append("file", file);
108
+ request.open("POST", getBrowserUploadUrl(uploadUrl));
109
+ }
110
+ return new Promise((resolve, reject) => {
111
+ request.onload = () => {
112
+ if (request.status >= 200 && request.status < 300) {
113
+ resolve(protectedUrl);
114
+ }
115
+ else {
116
+ reject(new Error("Error uploading file"));
117
+ }
118
+ };
119
+ request.onerror = () => {
120
+ reject(new Error("Error uploading file"));
121
+ };
122
+ request.send(formData);
123
+ });
124
+ };
125
+ const uploadAttachments = async ({ attachments, blocksApiService, appId, }) => {
126
+ if (!attachments?.length) {
127
+ return undefined;
128
+ }
129
+ return Promise.all(attachments.map(async (attachment) => {
130
+ const file = await fileFromAttachment(attachment);
131
+ const protectedUrl = await uploadFile({ appId, blocksApiService, file });
132
+ return {
133
+ url: protectedUrl,
134
+ fileName: attachment.fileName,
135
+ fileType: attachment.fileType,
136
+ };
137
+ }));
138
+ };
73
139
  const hasSendableInput = (prompt, attachments) => {
74
140
  return prompt.trim().length > 0 || attachments.length > 0;
75
141
  };
@@ -81,6 +147,55 @@ export const useAgentChat = () => {
81
147
  }
82
148
  return context;
83
149
  };
150
+ const NEW_MESSAGE_SCROLL_HIDE_MS = 500;
151
+ const AgentChatScrollContext = createContext(null);
152
+ export const useAgentChatScroll = () => {
153
+ const context = useContext(AgentChatScrollContext);
154
+ if (!context) {
155
+ throw new Error("useAgentChatScroll must be used within an AgentChatMessages provider");
156
+ }
157
+ return context;
158
+ };
159
+ const getMessageGroups = (scrollElement) => {
160
+ return Array.from(scrollElement.querySelectorAll('[data-slot="agent-chat-message-group"]'));
161
+ };
162
+ const SCROLL_BOTTOM_OFFSET_PX = 70;
163
+ const getTargetScrollTop = (scrollElement) => {
164
+ return Math.max(scrollElement.scrollHeight - 1 - scrollElement.clientHeight, 0);
165
+ };
166
+ const isScrollAtBottom = (scrollElement) => {
167
+ return getTargetScrollTop(scrollElement) - scrollElement.scrollTop <= SCROLL_BOTTOM_OFFSET_PX;
168
+ };
169
+ const setScrollTopInstantly = (scrollElement, scrollTop) => {
170
+ const { scrollBehavior } = getComputedStyle(scrollElement);
171
+ if (scrollBehavior !== "auto") {
172
+ scrollElement.style.scrollBehavior = "auto";
173
+ }
174
+ scrollElement.scrollTop = scrollTop;
175
+ if (scrollBehavior !== "auto") {
176
+ scrollElement.style.scrollBehavior = scrollBehavior;
177
+ }
178
+ };
179
+ const AGENT_CHAT_CONTAINER_HEIGHT_VAR = "--agent-chat-container-height";
180
+ const AGENT_CHAT_LATEST_USER_HEIGHT_VAR = "--agent-chat-latest-user-message-height";
181
+ const LAST_ASSISTANT_MESSAGE_GROUP_STYLE = {
182
+ minHeight: `max(calc(var(${AGENT_CHAT_CONTAINER_HEIGHT_VAR}, 0px) - var(${AGENT_CHAT_LATEST_USER_HEIGHT_VAR}, var(${AGENT_CHAT_CONTAINER_HEIGHT_VAR}, 0px))), 0px)`,
183
+ };
184
+ const updateScrollHeightVariables = (scrollElement) => {
185
+ const messageGroups = getMessageGroups(scrollElement);
186
+ const latestUserGroup = messageGroups.reverse().find((messageGroup) => messageGroup.dataset.messageGroup === "user");
187
+ scrollElement.style.setProperty(AGENT_CHAT_CONTAINER_HEIGHT_VAR, `${scrollElement.clientHeight}px`);
188
+ if (latestUserGroup) {
189
+ scrollElement.style.setProperty(AGENT_CHAT_LATEST_USER_HEIGHT_VAR, `${latestUserGroup.offsetHeight}px`);
190
+ }
191
+ else {
192
+ scrollElement.style.removeProperty(AGENT_CHAT_LATEST_USER_HEIGHT_VAR);
193
+ }
194
+ };
195
+ const clearScrollHeightVariables = (scrollElement) => {
196
+ scrollElement.style.removeProperty(AGENT_CHAT_CONTAINER_HEIGHT_VAR);
197
+ scrollElement.style.removeProperty(AGENT_CHAT_LATEST_USER_HEIGHT_VAR);
198
+ };
84
199
  const SessionReadables = () => {
85
200
  // const now = new Date();
86
201
  // useCopilotReadable({
@@ -105,6 +220,33 @@ const ChatInitializer = ({ agentId, agentChatId, chatId, token, appId, component
105
220
  const [isConfigLoaded, setIsConfigLoaded] = useState(false);
106
221
  const { messages: copilotMessages, sendMessage: copilotSendMessage, stopGeneration: copilotStopGeneration, isAvailable: isAgentReady, isLoading: isAgentRunning, agent: copilotAgent, } = useCopilotChatInternal();
107
222
  const { copilotkit } = useCopilotKit();
223
+ const renderToolCall = useRenderToolCall();
224
+ const messageById = useMemo(() => {
225
+ const messagesSet = new Map();
226
+ copilotMessages.forEach((message) => {
227
+ messagesSet.set(message.id, message);
228
+ });
229
+ return messagesSet;
230
+ }, [copilotMessages]);
231
+ const toolMessages = useMemo(() => {
232
+ return copilotMessages.filter((message) => message.role === "tool");
233
+ }, [copilotMessages]);
234
+ const messageGroups = useMemo(() => {
235
+ const groups = [];
236
+ copilotMessages.forEach((message) => {
237
+ if (message.role !== "assistant" && message.role !== "user") {
238
+ return;
239
+ }
240
+ const lastGroup = groups[groups.length - 1];
241
+ if (!lastGroup || lastGroup.role !== message.role) {
242
+ groups.push({ role: message.role, messageIds: [message.id] });
243
+ }
244
+ else {
245
+ lastGroup.messageIds.push(message.id);
246
+ }
247
+ });
248
+ return groups;
249
+ }, [copilotMessages]);
108
250
  // Mirror `currentThreadId` onto the agent instance — the `<CopilotKit>`
109
251
  // prop only feeds React context, but `agent.threadId` is what hits the
110
252
  // wire and the LangGraph checkpoint. `<CopilotChat>` does this for you;
@@ -120,6 +262,7 @@ const ChatInitializer = ({ agentId, agentChatId, chatId, token, appId, component
120
262
  const [prompt, setPrompt] = useState("");
121
263
  const [attachments, setAttachments] = useState([]);
122
264
  const [isDraggingFiles, setIsDraggingFiles] = useState(false);
265
+ const [hasSentMessageInSession, setHasSentMessageInSession] = useState(false);
123
266
  const blocksApiService = useMemo(() => new BlocksApiService({ token }), [token]);
124
267
  const attachmentsEnabled = agentChat ? agentChat.disableAttachments !== true : false;
125
268
  const canSendMessage = Boolean(agentChatId && agentChat && agent && isConfigLoaded && isAgentReady && !isAgentRunning);
@@ -131,6 +274,7 @@ const ChatInitializer = ({ agentId, agentChatId, chatId, token, appId, component
131
274
  if (!canSendMessage) {
132
275
  return Promise.resolve();
133
276
  }
277
+ setHasSentMessageInSession(true);
134
278
  return copilotSendMessage({ id: generateId(), role: "user", ...message });
135
279
  }, [canSendMessage, copilotSendMessage]);
136
280
  const stopGeneration = useCallback(() => {
@@ -151,7 +295,7 @@ const ChatInitializer = ({ agentId, agentChatId, chatId, token, appId, component
151
295
  if (!componentIds?.length) {
152
296
  return [];
153
297
  }
154
- const maybeComponentBlocks = await Promise.all(componentIds.map(async (componentId) => {
298
+ const chatComponentBlocks = await Promise.all(componentIds.map(async (componentId) => {
155
299
  try {
156
300
  const block = await blocksApiService.getBlock(componentId);
157
301
  const id = block?.id ?? componentId;
@@ -167,14 +311,14 @@ const ChatInitializer = ({ agentId, agentChatId, chatId, token, appId, component
167
311
  code,
168
312
  input: block?.data?.input,
169
313
  description,
170
- toolName: getAgentChatComponentToolName(name),
314
+ userInterrupt: Boolean(block?.data?.userInterrupt),
171
315
  };
172
316
  }
173
317
  catch {
174
318
  return null;
175
319
  }
176
320
  }));
177
- return maybeComponentBlocks.filter((component) => Boolean(component));
321
+ return chatComponentBlocks.filter((chatComponentBlock) => Boolean(chatComponentBlock));
178
322
  }, [blocksApiService, componentIds]);
179
323
  const componentIdsKey = componentIds?.join(",") ?? "";
180
324
  const initKeyRef = useRef(null);
@@ -197,6 +341,7 @@ const ChatInitializer = ({ agentId, agentChatId, chatId, token, appId, component
197
341
  }
198
342
  initKeyRef.current = initKey;
199
343
  initialPromptSentRef.current = false;
344
+ setHasSentMessageInSession(false);
200
345
  const ac = new AbortController();
201
346
  const initialize = async () => {
202
347
  setIsConfigLoaded(false);
@@ -301,12 +446,45 @@ const ChatInitializer = ({ agentId, agentChatId, chatId, token, appId, component
301
446
  });
302
447
  void copilotkit.runAgent({ agent: copilotAgent });
303
448
  }, [isAgentReady, isConfigLoaded, agentChat, copilotAgent, canSendMessage, copilotkit]);
449
+ const buildMessageContentFromInput = (currentPrompt = prompt, currentAttachments = attachments) => {
450
+ if (currentAttachments.length === 0) {
451
+ return currentPrompt;
452
+ }
453
+ const contentArray = [];
454
+ currentAttachments.forEach((attachment) => {
455
+ const source = { type: "url", value: attachment.url, mimeType: attachment.fileType };
456
+ const metadata = { filename: attachment.fileName };
457
+ switch (true) {
458
+ case attachment.fileType.startsWith("image/"):
459
+ contentArray.push({ type: "image", source, metadata });
460
+ break;
461
+ case attachment.fileType.startsWith("audio/"):
462
+ contentArray.push({ type: "audio", source, metadata });
463
+ break;
464
+ case attachment.fileType.startsWith("video/"):
465
+ contentArray.push({ type: "video", source, metadata });
466
+ break;
467
+ default:
468
+ contentArray.push({ type: "document", source, metadata });
469
+ }
470
+ });
471
+ if (currentPrompt) {
472
+ contentArray.push({ type: "text", text: currentPrompt });
473
+ }
474
+ return contentArray;
475
+ };
304
476
  const sendFromInputs = async () => {
305
477
  if (!canSendMessage || !hasSendableInput(prompt, attachments)) {
306
478
  return;
307
479
  }
308
480
  const currentPrompt = prompt;
309
- // const currentAttachments = attachments;
481
+ const currentAttachments = attachments;
482
+ const uploadedAttachments = await uploadAttachments({
483
+ attachments: currentAttachments,
484
+ appId,
485
+ blocksApiService,
486
+ });
487
+ const messageContent = buildMessageContentFromInput(currentPrompt, uploadedAttachments ?? []);
310
488
  setPrompt("");
311
489
  setAttachments([]);
312
490
  // Auto-skip any frontend user-choice tool call that's still waiting.
@@ -347,7 +525,9 @@ const ChatInitializer = ({ agentId, agentChatId, chatId, token, appId, component
347
525
  });
348
526
  }
349
527
  }
350
- await sendMessage({ content: currentPrompt });
528
+ await sendMessage({
529
+ content: messageContent,
530
+ });
351
531
  };
352
532
  const addAttachments = (attachments) => {
353
533
  if (!attachmentsEnabled) {
@@ -376,6 +556,11 @@ const ChatInitializer = ({ agentId, agentChatId, chatId, token, appId, component
376
556
  };
377
557
  return (_jsx(AgentChatContext.Provider, { value: {
378
558
  messages: copilotMessages,
559
+ messageGroups,
560
+ renderToolCall,
561
+ messageById,
562
+ toolMessages,
563
+ hasSentMessageInSession,
379
564
  prompt,
380
565
  attachments,
381
566
  sendMessage,
@@ -437,24 +622,139 @@ export function AgentChatMessage({ message, index, ...props }) {
437
622
  }
438
623
  return _jsx("div", { "data-message-index": index, "data-message-role": message.role, ...props });
439
624
  }
440
- export function AgentChatMessages({ scrollAreaClassName, ...props }) {
441
- const { messages } = useAgentChat();
442
- const userMessageCount = messages.filter((message) => message.role === "user" && message.name !== HIDDEN_INITIAL_PROMPT_MESSAGE_NAME).length;
443
- const previousUserMessageCountRef = useRef(userMessageCount);
444
- const { scrollRef, contentRef, scrollToBottom } = useStickToBottom({
445
- resize: "smooth",
446
- initial: { damping: 1, stiffness: 1 },
447
- });
625
+ export function AgentChatMessageGroup({ messageGroup, isLast, style, ...props }) {
626
+ const { hasSentMessageInSession, messageGroups } = useAgentChat();
627
+ const lastMessageGroup = messageGroups[messageGroups.length - 1];
628
+ const isLastMessageGroup = isLast ??
629
+ (lastMessageGroup?.role === messageGroup.role &&
630
+ lastMessageGroup.messageIds.length === messageGroup.messageIds.length &&
631
+ lastMessageGroup.messageIds.every((messageId, index) => messageId === messageGroup.messageIds[index]));
632
+ const mergedStyle = hasSentMessageInSession && isLastMessageGroup && messageGroup.role === "assistant"
633
+ ? {
634
+ ...style,
635
+ ...LAST_ASSISTANT_MESSAGE_GROUP_STYLE,
636
+ }
637
+ : style;
638
+ return (_jsx("div", { "data-slot": "agent-chat-message-group", "data-message-group": messageGroup.role, "data-message-group-role": messageGroup.role, style: mergedStyle, ...props }));
639
+ }
640
+ export function AgentChatMessages({ scrollAreaClassName, children, ...props }) {
641
+ const { isFetchingMessages, isThinking, messageGroups } = useAgentChat();
642
+ const messageGroupCount = messageGroups.length;
643
+ const scrollRef = useRef(null);
644
+ const previousMessageGroupCountRef = useRef(messageGroupCount);
645
+ const hasCompletedInitialScrollRef = useRef(false);
646
+ const previousIsThinkingRef = useRef(isThinking);
647
+ const newMessageScrollTimeoutRef = useRef(null);
648
+ const [isNewMessageScrollInProgress, setIsNewMessageScrollInProgress] = useState(false);
649
+ const [isAtBottom, setIsAtBottom] = useState(true);
650
+ const scrollToBottom = useCallback((behavior = "smooth") => {
651
+ const scrollElement = scrollRef.current;
652
+ if (!scrollElement) {
653
+ return;
654
+ }
655
+ const targetScrollTop = getTargetScrollTop(scrollElement);
656
+ if (behavior === "instant") {
657
+ setScrollTopInstantly(scrollElement, targetScrollTop);
658
+ }
659
+ else {
660
+ scrollElement.scrollTo({ top: targetScrollTop, behavior });
661
+ }
662
+ setIsAtBottom(true);
663
+ }, []);
664
+ const scrollContextValue = useMemo(() => ({
665
+ isAtBottom: isAtBottom || isNewMessageScrollInProgress,
666
+ scrollToBottom: () => {
667
+ void scrollToBottom();
668
+ },
669
+ }), [isAtBottom, isNewMessageScrollInProgress, scrollToBottom]);
670
+ useIsomorphicLayoutEffect(() => {
671
+ const scrollElement = scrollRef.current;
672
+ if (!scrollElement) {
673
+ return;
674
+ }
675
+ if (getComputedStyle(scrollElement).overflow === "visible") {
676
+ scrollElement.style.overflow = "auto";
677
+ }
678
+ const updateIsAtBottom = () => {
679
+ setIsAtBottom(isScrollAtBottom(scrollElement));
680
+ };
681
+ updateIsAtBottom();
682
+ scrollElement.addEventListener("scroll", updateIsAtBottom, { passive: true });
683
+ return () => {
684
+ scrollElement.removeEventListener("scroll", updateIsAtBottom);
685
+ };
686
+ }, []);
448
687
  useEffect(() => {
449
- if (userMessageCount > previousUserMessageCountRef.current) {
450
- void scrollToBottom({
451
- animation: "smooth",
452
- ignoreEscapes: true,
453
- });
454
- }
455
- previousUserMessageCountRef.current = userMessageCount;
456
- }, [scrollToBottom, userMessageCount]);
457
- return (_jsx("div", { ref: scrollRef, style: { overflow: "auto" }, className: scrollAreaClassName, children: _jsx("div", { ref: contentRef, "data-slot": "agent-chat-messages", ...props }) }));
688
+ return () => {
689
+ if (newMessageScrollTimeoutRef.current !== null) {
690
+ window.clearTimeout(newMessageScrollTimeoutRef.current);
691
+ }
692
+ };
693
+ }, []);
694
+ useEffect(() => {
695
+ const scrollElement = scrollRef.current;
696
+ const wasThinking = previousIsThinkingRef.current;
697
+ previousIsThinkingRef.current = isThinking;
698
+ if (!scrollElement || isThinking || !wasThinking) {
699
+ return;
700
+ }
701
+ setIsAtBottom(isScrollAtBottom(scrollElement));
702
+ }, [isThinking]);
703
+ useIsomorphicLayoutEffect(() => {
704
+ const scrollElement = scrollRef.current;
705
+ if (isFetchingMessages) {
706
+ previousMessageGroupCountRef.current = messageGroupCount;
707
+ return;
708
+ }
709
+ if (!scrollElement) {
710
+ previousMessageGroupCountRef.current = messageGroupCount;
711
+ return;
712
+ }
713
+ if (!hasCompletedInitialScrollRef.current) {
714
+ clearScrollHeightVariables(scrollElement);
715
+ scrollToBottom("instant");
716
+ previousMessageGroupCountRef.current = messageGroupCount;
717
+ hasCompletedInitialScrollRef.current = true;
718
+ return;
719
+ }
720
+ if (messageGroupCount < previousMessageGroupCountRef.current) {
721
+ previousMessageGroupCountRef.current = messageGroupCount;
722
+ clearScrollHeightVariables(scrollElement);
723
+ scrollToBottom("instant");
724
+ return;
725
+ }
726
+ if (messageGroupCount > previousMessageGroupCountRef.current) {
727
+ updateScrollHeightVariables(scrollElement);
728
+ setIsNewMessageScrollInProgress(true);
729
+ if (newMessageScrollTimeoutRef.current !== null) {
730
+ window.clearTimeout(newMessageScrollTimeoutRef.current);
731
+ }
732
+ newMessageScrollTimeoutRef.current = window.setTimeout(() => {
733
+ setIsNewMessageScrollInProgress(false);
734
+ newMessageScrollTimeoutRef.current = null;
735
+ }, NEW_MESSAGE_SCROLL_HIDE_MS);
736
+ scrollToBottom("smooth");
737
+ }
738
+ previousMessageGroupCountRef.current = messageGroupCount;
739
+ }, [isFetchingMessages, messageGroupCount, scrollToBottom]);
740
+ return (_jsx(AgentChatScrollContext.Provider, { value: scrollContextValue, children: _jsx("div", { ...props, children: _jsx("div", { ref: scrollRef, style: {
741
+ height: "100%",
742
+ width: "100%",
743
+ scrollbarGutter: "stable both-edges",
744
+ }, children: _jsx("div", { className: scrollAreaClassName, children: children }) }) }) }));
745
+ }
746
+ export function AgentChatScrollToBottom({ asChild = false, onClick, ...props }) {
747
+ const { isAtBottom, scrollToBottom } = useAgentChatScroll();
748
+ const Comp = asChild ? Slot : "button";
749
+ if (isAtBottom) {
750
+ return null;
751
+ }
752
+ return (_jsx(Comp, { "data-slot": "agent-chat-scroll-to-bottom", onClick: (event) => {
753
+ onClick?.(event);
754
+ if (!event.defaultPrevented) {
755
+ scrollToBottom();
756
+ }
757
+ }, ...props }));
458
758
  }
459
759
  export function AgentChatThinking({ asChild = false, ...props }) {
460
760
  const { isThinking } = useAgentChat();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blocksdiy/react-common",
3
- "version": "1.27.1",
3
+ "version": "1.28.1",
4
4
  "type": "module",
5
5
  "description": "React common",
6
6
  "keywords": [],
@@ -38,7 +38,7 @@
38
38
  "penpal": "^7.0.6",
39
39
  "react": "^19.2.4",
40
40
  "use-stick-to-bottom": "1.1.4",
41
- "@blocksdiy/blocks-client-api": "1.5.0"
41
+ "@blocksdiy/blocks-client-api": "1.10.1"
42
42
  },
43
43
  "devDependencies": {
44
44
  "@types/react": "^19.2.14",