@nextclaw/agent-chat-ui 0.2.10 → 0.2.12

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 (2) hide show
  1. package/dist/index.js +56 -20
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1945,6 +1945,9 @@ function ChatMessageAvatar({ role }) {
1945
1945
  );
1946
1946
  }
1947
1947
 
1948
+ // src/components/chat/ui/chat-message-list/chat-message.tsx
1949
+ import { memo } from "react";
1950
+
1948
1951
  // src/components/chat/ui/chat-message-list/chat-message-markdown.tsx
1949
1952
  import { useMemo as useMemo5 } from "react";
1950
1953
  import ReactMarkdown from "react-markdown";
@@ -2543,7 +2546,7 @@ function ToolCardRoot({ children, className }) {
2543
2546
  );
2544
2547
  }
2545
2548
  function ToolCardContent({ children, className }) {
2546
- return /* @__PURE__ */ jsx17("div", { className: cn("border-t border-amber-200/15 bg-amber-50/50 p-3 w-full overflow-hidden", className), children });
2549
+ return /* @__PURE__ */ jsx17("div", { className: cn("border-t border-amber-200/15 bg-amber-50/50 px-3 pt-1 pb-2 w-full overflow-hidden", className), children });
2547
2550
  }
2548
2551
 
2549
2552
  // src/components/chat/ui/chat-message-list/tool-card/tool-card-header.tsx
@@ -2645,11 +2648,14 @@ function TerminalExecutionView({ card }) {
2645
2648
  }
2646
2649
  ),
2647
2650
  expanded && /* @__PURE__ */ jsxs12(Fragment3, { children: [
2648
- /* @__PURE__ */ jsx20("div", { className: "px-3 pb-0.5 font-mono w-full max-h-48 overflow-y-auto custom-scrollbar-amber min-h-0 text-[12px]", children: /* @__PURE__ */ jsxs12("div", { className: "flex items-start gap-2 leading-relaxed", children: [
2651
+ /* @__PURE__ */ jsx20("div", { className: "px-3 pb-2 font-mono w-full max-h-48 overflow-y-auto custom-scrollbar-amber min-h-0 text-[12px]", children: /* @__PURE__ */ jsxs12("div", { className: "flex items-start gap-2 leading-relaxed", children: [
2649
2652
  /* @__PURE__ */ jsx20("span", { className: "text-amber-500/50 font-medium shrink-0 select-none mt-[1px]", children: "$" }),
2650
- /* @__PURE__ */ jsx20("div", { className: "flex-1 min-w-0", children: commandPart ? /* @__PURE__ */ jsx20("span", { className: "text-amber-950/80 break-words whitespace-pre-wrap tracking-tight font-medium", children: commandPart }) : /* @__PURE__ */ jsx20("div", { className: "h-3 w-32 bg-amber-200/30 rounded animate-pulse mt-2" }) })
2653
+ /* @__PURE__ */ jsx20("div", { className: "flex-1 min-w-0", children: commandPart ? /* @__PURE__ */ jsxs12("div", { className: "text-amber-950/80 break-words whitespace-pre-wrap tracking-tight font-medium inline-block", children: [
2654
+ commandPart,
2655
+ isRunning && !output && /* @__PURE__ */ jsx20("span", { className: "inline-block w-1.5 h-3 ml-1 bg-amber-500/60 animate-pulse align-middle" })
2656
+ ] }) : /* @__PURE__ */ jsx20("div", { className: "h-3 w-32 bg-amber-200/30 rounded animate-pulse mt-2" }) })
2651
2657
  ] }) }),
2652
- (output || isRunning && hasContent) && /* @__PURE__ */ jsx20(ToolCardContent, { className: "mt-2", children: /* @__PURE__ */ jsxs12("pre", { className: "font-mono text-[12px] text-amber-950/70 whitespace-pre-wrap break-all w-full max-w-full max-h-64 overflow-y-auto overflow-x-hidden min-w-0 custom-scrollbar-amber leading-relaxed", children: [
2658
+ output && /* @__PURE__ */ jsx20(ToolCardContent, { children: /* @__PURE__ */ jsxs12("pre", { className: "font-mono text-[12px] text-amber-950/70 whitespace-pre-wrap break-all w-full max-w-full max-h-64 overflow-y-auto overflow-x-hidden min-w-0 custom-scrollbar-amber leading-relaxed px-0", children: [
2653
2659
  output,
2654
2660
  isRunning && /* @__PURE__ */ jsx20("span", { className: "inline-block w-1.5 h-3 ml-1 bg-amber-500/60 animate-pulse align-middle" })
2655
2661
  ] }) })
@@ -2689,10 +2695,7 @@ function FileOperationView({ card }) {
2689
2695
  ] }, idx);
2690
2696
  }
2691
2697
  }
2692
- return /* @__PURE__ */ jsxs12("div", { className: "px-2 py-0.5 text-amber-950/80 w-full break-all whitespace-pre-wrap", children: [
2693
- /* @__PURE__ */ jsx20("span", { className: "select-none opacity-0 mr-2 w-3 inline-block shrink-0", children: " " }),
2694
- /* @__PURE__ */ jsx20("span", { children: line })
2695
- ] }, idx);
2698
+ return /* @__PURE__ */ jsx20("div", { className: "py-0.5 text-amber-950/80 w-full break-all whitespace-pre-wrap", children: /* @__PURE__ */ jsx20("span", { children: line }) }, idx);
2696
2699
  };
2697
2700
  const lines = output.split("\n");
2698
2701
  const maxLines = 15;
@@ -2709,7 +2712,7 @@ function FileOperationView({ card }) {
2709
2712
  onToggle
2710
2713
  }
2711
2714
  ),
2712
- expanded && output && /* @__PURE__ */ jsx20(ToolCardContent, { children: /* @__PURE__ */ jsx20("div", { className: "font-mono text-[12px] leading-relaxed py-2 max-h-48 overflow-y-auto overflow-x-hidden min-w-0 custom-scrollbar-amber text-amber-950/80 w-full px-1", children: displayLines.map(renderLine) }) })
2715
+ expanded && output && /* @__PURE__ */ jsx20(ToolCardContent, { children: /* @__PURE__ */ jsx20("div", { className: "font-mono text-[12px] leading-relaxed max-h-48 overflow-y-auto overflow-x-hidden min-w-0 custom-scrollbar-amber text-amber-950/80 w-full", children: displayLines.map(renderLine) }) })
2713
2716
  ] });
2714
2717
  }
2715
2718
  function SearchSnippetView({ card }) {
@@ -2740,7 +2743,7 @@ function SearchSnippetView({ card }) {
2740
2743
  onToggle
2741
2744
  }
2742
2745
  ),
2743
- expanded && output && /* @__PURE__ */ jsx20(ToolCardContent, { children: /* @__PURE__ */ jsx20("pre", { className: "font-mono text-[12px] text-amber-950/70 whitespace-pre-wrap break-all w-full max-w-full max-h-64 overflow-y-auto overflow-x-hidden min-w-0 custom-scrollbar-amber py-2 leading-relaxed", children: output }) })
2746
+ expanded && output && /* @__PURE__ */ jsx20(ToolCardContent, { children: /* @__PURE__ */ jsx20("pre", { className: "font-mono text-[12px] text-amber-950/70 whitespace-pre-wrap break-all w-full max-w-full max-h-64 overflow-y-auto overflow-x-hidden min-w-0 custom-scrollbar-amber leading-relaxed", children: output }) })
2744
2747
  ] });
2745
2748
  }
2746
2749
  function GenericToolCard({ card }) {
@@ -2772,7 +2775,7 @@ function GenericToolCard({ card }) {
2772
2775
  onToggle
2773
2776
  }
2774
2777
  ),
2775
- expanded && output && /* @__PURE__ */ jsx20(ToolCardContent, { children: /* @__PURE__ */ jsx20("pre", { className: "mt-1 text-amber-950/80 whitespace-pre-wrap break-all overflow-y-auto overflow-x-hidden max-h-64 custom-scrollbar-amber py-1 w-full min-w-0 max-w-full leading-relaxed", children: output }) })
2778
+ expanded && output && /* @__PURE__ */ jsx20(ToolCardContent, { children: /* @__PURE__ */ jsx20("pre", { className: "text-amber-950/80 whitespace-pre-wrap break-all overflow-y-auto overflow-x-hidden max-h-64 custom-scrollbar-amber w-full min-w-0 max-w-full leading-relaxed", children: output }) })
2776
2779
  ] });
2777
2780
  }
2778
2781
 
@@ -2818,7 +2821,7 @@ function ChatUnknownPart(props) {
2818
2821
 
2819
2822
  // src/components/chat/ui/chat-message-list/chat-message.tsx
2820
2823
  import { jsx as jsx23 } from "react/jsx-runtime";
2821
- function ChatMessage(props) {
2824
+ var ChatMessage = memo(function ChatMessage2(props) {
2822
2825
  const { message, texts } = props;
2823
2826
  const { role } = message;
2824
2827
  const isUser = role === "user";
@@ -2880,7 +2883,7 @@ function ChatMessage(props) {
2880
2883
  }) })
2881
2884
  }
2882
2885
  );
2883
- }
2886
+ });
2884
2887
 
2885
2888
  // src/components/chat/ui/chat-message-list/chat-message-meta.tsx
2886
2889
  import { jsxs as jsxs14 } from "react/jsx-runtime";
@@ -2944,17 +2947,36 @@ function ChatMessageList(props) {
2944
2947
  }
2945
2948
 
2946
2949
  // src/components/chat/hooks/use-sticky-bottom-scroll.ts
2947
- import { useCallback as useCallback2, useEffect as useEffect7, useLayoutEffect as useLayoutEffect2, useRef as useRef6 } from "react";
2950
+ import { useEffect as useEffect7, useLayoutEffect as useLayoutEffect2, useRef as useRef6 } from "react";
2948
2951
  var DEFAULT_STICKY_THRESHOLD_PX = 10;
2949
2952
  function scrollElementToBottom(element) {
2950
2953
  element.scrollTop = element.scrollHeight;
2951
2954
  }
2955
+ function queueScrollToBottom(params) {
2956
+ const element = params.scrollRef.current;
2957
+ if (!element) {
2958
+ return;
2959
+ }
2960
+ if (params.scheduledScrollFrameRef.current !== null) {
2961
+ cancelAnimationFrame(params.scheduledScrollFrameRef.current);
2962
+ }
2963
+ params.scheduledScrollFrameRef.current = requestAnimationFrame(() => {
2964
+ params.scheduledScrollFrameRef.current = null;
2965
+ const currentElement = params.scrollRef.current;
2966
+ if (!currentElement) {
2967
+ return;
2968
+ }
2969
+ params.isProgrammaticScrollRef.current = true;
2970
+ scrollElementToBottom(currentElement);
2971
+ });
2972
+ }
2952
2973
  function useStickyBottomScroll(params) {
2953
2974
  const isStickyRef = useRef6(true);
2954
2975
  const isProgrammaticScrollRef = useRef6(false);
2955
2976
  const previousResetKeyRef = useRef6(null);
2956
2977
  const pendingInitialScrollRef = useRef6(false);
2957
- const onScroll = useCallback2(() => {
2978
+ const scheduledScrollFrameRef = useRef6(null);
2979
+ const onScroll = () => {
2958
2980
  if (isProgrammaticScrollRef.current) {
2959
2981
  isProgrammaticScrollRef.current = false;
2960
2982
  return;
@@ -2965,7 +2987,7 @@ function useStickyBottomScroll(params) {
2965
2987
  }
2966
2988
  const distanceFromBottom = element.scrollHeight - element.scrollTop - element.clientHeight;
2967
2989
  isStickyRef.current = distanceFromBottom <= (params.stickyThresholdPx ?? DEFAULT_STICKY_THRESHOLD_PX);
2968
- }, [params.scrollRef, params.stickyThresholdPx]);
2990
+ };
2969
2991
  useEffect7(() => {
2970
2992
  if (previousResetKeyRef.current === params.resetKey) {
2971
2993
  return;
@@ -2974,6 +2996,14 @@ function useStickyBottomScroll(params) {
2974
2996
  isStickyRef.current = true;
2975
2997
  pendingInitialScrollRef.current = true;
2976
2998
  }, [params.resetKey]);
2999
+ useEffect7(() => {
3000
+ const scheduledScrollFrame = scheduledScrollFrameRef.current;
3001
+ return () => {
3002
+ if (scheduledScrollFrame !== null) {
3003
+ cancelAnimationFrame(scheduledScrollFrame);
3004
+ }
3005
+ };
3006
+ }, []);
2977
3007
  useLayoutEffect2(() => {
2978
3008
  if (!pendingInitialScrollRef.current || params.isLoading || !params.hasContent) {
2979
3009
  return;
@@ -2983,8 +3013,11 @@ function useStickyBottomScroll(params) {
2983
3013
  return;
2984
3014
  }
2985
3015
  pendingInitialScrollRef.current = false;
2986
- isProgrammaticScrollRef.current = true;
2987
- scrollElementToBottom(element);
3016
+ queueScrollToBottom({
3017
+ scrollRef: params.scrollRef,
3018
+ scheduledScrollFrameRef,
3019
+ isProgrammaticScrollRef
3020
+ });
2988
3021
  }, [params.hasContent, params.isLoading, params.scrollRef]);
2989
3022
  useLayoutEffect2(() => {
2990
3023
  if (!isStickyRef.current || !params.hasContent) {
@@ -2994,8 +3027,11 @@ function useStickyBottomScroll(params) {
2994
3027
  if (!element) {
2995
3028
  return;
2996
3029
  }
2997
- isProgrammaticScrollRef.current = true;
2998
- scrollElementToBottom(element);
3030
+ queueScrollToBottom({
3031
+ scrollRef: params.scrollRef,
3032
+ scheduledScrollFrameRef,
3033
+ isProgrammaticScrollRef
3034
+ });
2999
3035
  }, [params.contentVersion, params.hasContent, params.scrollRef]);
3000
3036
  return { onScroll };
3001
3037
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextclaw/agent-chat-ui",
3
- "version": "0.2.10",
3
+ "version": "0.2.12",
4
4
  "private": false,
5
5
  "description": "Reusable Nextclaw agent chat UI primitives and default skin.",
6
6
  "type": "module",