@copilotz/chat-ui 0.1.7 → 0.1.8

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/dist/index.cjs CHANGED
@@ -55,6 +55,7 @@ module.exports = __toCommonJS(index_exports);
55
55
 
56
56
  // src/components/chat/ChatUI.tsx
57
57
  var import_react7 = require("react");
58
+ var import_react_virtual = require("@tanstack/react-virtual");
58
59
 
59
60
  // src/config/chatConfig.ts
60
61
  var defaultChatConfig = {
@@ -616,10 +617,11 @@ var rehypePluginsEmpty = [];
616
617
  var StreamingText = (0, import_react.memo)(function StreamingText2({
617
618
  content,
618
619
  isStreaming = false,
619
- thinkingLabel = "Thinking..."
620
+ thinkingLabel = "Thinking...",
621
+ className = ""
620
622
  }) {
621
623
  const hasContent = content.trim().length > 0;
622
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "prose prose-sm max-w-none dark:prose-invert", children: [
624
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: `prose prose-sm max-w-none dark:prose-invert break-words ${className}`, children: [
623
625
  hasContent ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
624
626
  import_react_markdown.default,
625
627
  {
@@ -861,7 +863,7 @@ var Message = (0, import_react.memo)(({
861
863
  minute: "2-digit"
862
864
  });
863
865
  };
864
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TooltipProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
866
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
865
867
  "div",
866
868
  {
867
869
  className: `flex w-full flex-col ${className} max-w-[800px] mx-auto`,
@@ -879,7 +881,7 @@ var Message = (0, import_react.memo)(({
879
881
  message.isEdited && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Badge, { variant: "outline", className: "text-xs", children: "editado" })
880
882
  ] })
881
883
  ] }),
882
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: `flex-1 min-w-0 ${messageIsUser ? "text-right" : "text-left"} ${isGrouped && showAvatar && !messageIsUser ? compactMode ? "ml-9" : "ml-11" : ""} ${isGrouped && showAvatar && messageIsUser ? compactMode ? "mr-9" : "mr-11" : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: `relative inline-flex flex-col ${messageIsUser ? "rounded-lg p-3 bg-primary text-primary-foreground ml-auto max-w-[85%]" : "max-w-[85%]"}`, children: [
884
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: `flex-1 min-w-0 ${messageIsUser ? "text-right" : "text-left"} ${isGrouped && showAvatar && !messageIsUser ? compactMode ? "ml-9" : "ml-11" : ""} ${isGrouped && showAvatar && messageIsUser ? compactMode ? "mr-9" : "mr-11" : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: `relative inline-flex flex-col overflow-hidden ${messageIsUser ? "rounded-lg p-3 bg-primary text-primary-foreground ml-auto max-w-[85%]" : "max-w-full"}`, children: [
883
885
  isEditing ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "space-y-2", children: [
884
886
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
885
887
  Textarea,
@@ -907,7 +909,8 @@ var Message = (0, import_react.memo)(({
907
909
  {
908
910
  content: message.content,
909
911
  isStreaming: message.isStreaming,
910
- thinkingLabel
912
+ thinkingLabel,
913
+ className: messageIsUser ? "[&_*]:text-right" : ""
911
914
  }
912
915
  ),
913
916
  message.attachments && message.attachments.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "mt-3 space-y-2", children: message.attachments.map((attachment, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MediaRenderer, { attachment }, index)) })
@@ -956,7 +959,7 @@ var Message = (0, import_react.memo)(({
956
959
  ] }) })
957
960
  ]
958
961
  }
959
- ) });
962
+ );
960
963
  }, arePropsEqual);
961
964
 
962
965
  // src/components/chat/Sidebar.tsx
@@ -3184,7 +3187,7 @@ var ChatInput = (0, import_react5.memo)(function ChatInput2({
3184
3187
  onChange: (e) => onChange(e.target.value),
3185
3188
  onKeyDown: handleKeyDown,
3186
3189
  placeholder,
3187
- disabled: disabled || isGenerating,
3190
+ disabled,
3188
3191
  className: "max-h-[120px] resize-none border-0 bg-transparent focus-visible:ring-0 focus-visible:ring-offset-0",
3189
3192
  rows: 1
3190
3193
  }
@@ -3757,7 +3760,6 @@ var ChatUI = ({
3757
3760
  initialInputApplied.current = true;
3758
3761
  }
3759
3762
  }, [initialInput]);
3760
- const messagesEndRef = (0, import_react7.useRef)(null);
3761
3763
  const scrollAreaRef = (0, import_react7.useRef)(null);
3762
3764
  const stateRef = (0, import_react7.useRef)(state);
3763
3765
  const inputValueRef = (0, import_react7.useRef)(inputValue);
@@ -3773,6 +3775,12 @@ var ChatUI = ({
3773
3775
  }, [attachments]);
3774
3776
  const [isCustomMounted, setIsCustomMounted] = (0, import_react7.useState)(false);
3775
3777
  const [isCustomVisible, setIsCustomVisible] = (0, import_react7.useState)(false);
3778
+ const virtualizer = (0, import_react_virtual.useVirtualizer)({
3779
+ count: messages.length,
3780
+ getScrollElement: () => scrollAreaRef.current,
3781
+ estimateSize: () => 100,
3782
+ overscan: 5
3783
+ });
3776
3784
  const createStateCallback = (0, import_react7.useCallback)(
3777
3785
  (setter) => ({
3778
3786
  setState: (newState) => setter?.(newState),
@@ -3805,20 +3813,24 @@ var ChatUI = ({
3805
3813
  }
3806
3814
  }, [state.showSidebar, isMobile, config.customComponent]);
3807
3815
  (0, import_react7.useEffect)(() => {
3808
- if (!state.isAtBottom) return;
3809
- const viewport = scrollAreaRef.current;
3810
- if (!viewport) return;
3811
- const target = viewport.scrollHeight;
3812
- try {
3813
- viewport.scrollTo({ top: target, behavior: "smooth" });
3814
- } catch {
3815
- viewport.scrollTop = target;
3816
- }
3816
+ if (!state.isAtBottom || messages.length === 0) return;
3817
+ requestAnimationFrame(() => {
3818
+ const viewport = scrollAreaRef.current;
3819
+ if (!viewport) return;
3820
+ try {
3821
+ viewport.scrollTo({ top: viewport.scrollHeight, behavior: "smooth" });
3822
+ } catch {
3823
+ viewport.scrollTop = viewport.scrollHeight;
3824
+ }
3825
+ });
3817
3826
  }, [messages, state.isAtBottom]);
3818
3827
  const handleScroll = (0, import_react7.useCallback)((e) => {
3819
3828
  const { scrollTop, scrollHeight, clientHeight } = e.currentTarget;
3820
3829
  const isAtBottom = scrollHeight - scrollTop - clientHeight < 50;
3821
- setState((prev) => ({ ...prev, isAtBottom }));
3830
+ setState((prev) => {
3831
+ if (prev.isAtBottom === isAtBottom) return prev;
3832
+ return { ...prev, isAtBottom };
3833
+ });
3822
3834
  }, []);
3823
3835
  const handleSendMessage = (0, import_react7.useCallback)((content, messageAttachments = []) => {
3824
3836
  if (!content.trim() && messageAttachments.length === 0) return;
@@ -3939,49 +3951,26 @@ var ChatUI = ({
3939
3951
  `message-skeleton-${index}`
3940
3952
  );
3941
3953
  }) });
3942
- const renderedMessageList = (0, import_react7.useMemo)(() => {
3943
- if (isMessagesLoading) return renderMessageLoadingSkeleton();
3944
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
3945
- renderSuggestions(),
3946
- messages.map((message, index) => {
3947
- const prevMessage = index > 0 ? messages[index - 1] : null;
3948
- const isGrouped = prevMessage !== null && prevMessage.role === message.role;
3949
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: isGrouped ? "space-y-1 -mt-2" : "space-y-2", children: [
3950
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
3951
- Message,
3952
- {
3953
- message,
3954
- userAvatar: user?.avatar,
3955
- userName: user?.name,
3956
- assistantAvatar: assistant?.avatar,
3957
- assistantName: assistant?.name,
3958
- showTimestamp: config.ui.showTimestamps,
3959
- showAvatar: config.ui.showAvatars,
3960
- enableCopy: config.features.enableMessageCopy,
3961
- enableEdit: config.features.enableMessageEditing,
3962
- enableRegenerate: config.features.enableRegeneration,
3963
- enableToolCallsDisplay: config.features.enableToolCallsDisplay,
3964
- compactMode: config.ui.compactMode,
3965
- onAction: handleMessageAction,
3966
- toolUsedLabel: config.labels.toolUsed,
3967
- thinkingLabel: config.labels.thinking,
3968
- isGrouped
3969
- }
3970
- ),
3971
- message.role === "assistant" && renderInlineSuggestions(message.id)
3972
- ] }, message.id);
3973
- })
3974
- ] });
3975
- }, [
3976
- isMessagesLoading,
3977
- messages,
3978
- handleSendMessage,
3954
+ const messageProps = (0, import_react7.useMemo)(() => ({
3955
+ userAvatar: user?.avatar,
3956
+ userName: user?.name,
3957
+ assistantAvatar: assistant?.avatar,
3958
+ assistantName: assistant?.name,
3959
+ showTimestamp: config.ui.showTimestamps,
3960
+ showAvatar: config.ui.showAvatars,
3961
+ enableCopy: config.features.enableMessageCopy,
3962
+ enableEdit: config.features.enableMessageEditing,
3963
+ enableRegenerate: config.features.enableRegeneration,
3964
+ enableToolCallsDisplay: config.features.enableToolCallsDisplay,
3965
+ compactMode: config.ui.compactMode,
3966
+ onAction: handleMessageAction,
3967
+ toolUsedLabel: config.labels.toolUsed,
3968
+ thinkingLabel: config.labels.thinking
3969
+ }), [
3979
3970
  user?.avatar,
3980
3971
  user?.name,
3981
3972
  assistant?.avatar,
3982
3973
  assistant?.name,
3983
- config.branding.title,
3984
- config.branding.subtitle,
3985
3974
  config.ui.showTimestamps,
3986
3975
  config.ui.showAvatars,
3987
3976
  config.ui.compactMode,
@@ -3991,9 +3980,7 @@ var ChatUI = ({
3991
3980
  config.features.enableToolCallsDisplay,
3992
3981
  config.labels.toolUsed,
3993
3982
  config.labels.thinking,
3994
- handleMessageAction,
3995
- messageSuggestions,
3996
- suggestions
3983
+ handleMessageAction
3997
3984
  ]);
3998
3985
  const shouldShowAgentSelector = Boolean(
3999
3986
  config.agentSelector?.enabled && onSelectAgent && agentOptions.length > 0 && (!config.agentSelector?.hideIfSingle || agentOptions.length > 1)
@@ -4054,10 +4041,48 @@ var ChatUI = ({
4054
4041
  className: "flex-1 min-h-0",
4055
4042
  viewportClassName: "p-4 overscroll-contain",
4056
4043
  onScrollCapture: handleScroll,
4057
- children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "max-w-4xl mx-auto space-y-4 pb-4", children: [
4058
- renderedMessageList,
4059
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { ref: messagesEndRef })
4060
- ] })
4044
+ style: { contain: "strict" },
4045
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "max-w-4xl mx-auto pb-4", children: isMessagesLoading ? renderMessageLoadingSkeleton() : messages.length === 0 ? renderSuggestions() : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4046
+ "div",
4047
+ {
4048
+ style: {
4049
+ height: `${virtualizer.getTotalSize()}px`,
4050
+ width: "100%",
4051
+ position: "relative"
4052
+ },
4053
+ children: virtualizer.getVirtualItems().map((virtualRow) => {
4054
+ const message = messages[virtualRow.index];
4055
+ const prevMessage = virtualRow.index > 0 ? messages[virtualRow.index - 1] : null;
4056
+ const isGrouped = prevMessage !== null && prevMessage.role === message.role;
4057
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4058
+ "div",
4059
+ {
4060
+ "data-index": virtualRow.index,
4061
+ ref: virtualizer.measureElement,
4062
+ style: {
4063
+ position: "absolute",
4064
+ top: 0,
4065
+ left: 0,
4066
+ width: "100%",
4067
+ transform: `translateY(${virtualRow.start}px)`
4068
+ },
4069
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: virtualRow.index === 0 ? "" : isGrouped ? "pt-2" : "pt-4", children: [
4070
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4071
+ Message,
4072
+ {
4073
+ message,
4074
+ ...messageProps,
4075
+ isGrouped
4076
+ }
4077
+ ),
4078
+ message.role === "assistant" && renderInlineSuggestions(message.id)
4079
+ ] })
4080
+ },
4081
+ message.id
4082
+ );
4083
+ })
4084
+ }
4085
+ ) })
4061
4086
  }
4062
4087
  ),
4063
4088
  /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "bg-background pb-[env(safe-area-inset-bottom)]", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(