diff --git a/packages/client/ui-chat/src/client/chat/ChatView.tsx b/packages/client/ui-chat/src/client/chat/ChatView.tsx index bf58d4c0c7..7374af1293 100644 --- a/packages/client/ui-chat/src/client/chat/ChatView.tsx +++ b/packages/client/ui-chat/src/client/chat/ChatView.tsx @@ -1,7 +1,7 @@ // An enclosing `[data-conversation-scroll]` owns scrolling when present; // otherwise this view owns it. Each row subscribes to one stable node key. -import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react' +import { memo, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, type ComponentProps } from 'react' import type { ConversationTimelineSnapshot, RenderMessageImages, } from '@deepseek-ai/dsh-client-ui-conversation/client' @@ -199,6 +199,16 @@ function TurnStatus({ startTime, t }: { ) } +type ChatNodeListProps = Omit, 'nodeKey'> & { + readonly order: readonly string[] +} + +const ChatNodeList = memo(function ChatNodeList({ order, ...seatProps }: ChatNodeListProps) { + return order.map(nodeKey => ( + + )) +}) + /** * The chat view slot entry: pure component over the composed props; each * ordered business Node crosses the keyed renderer seat. @@ -743,27 +753,24 @@ export function ChatView({ )} - {order.map(nodeKey => ( - - ))} + {/* No pending placeholders: questions (ui-user-questions) and approvals (ApprovalPanel) both take over the composer, so a flow card would double-render the same wait. */}