@copilotz/chat-ui 0.9.20 → 0.9.23

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.d.cts CHANGED
@@ -163,6 +163,10 @@ interface ChatConfig {
163
163
  inputPlaceholder?: string;
164
164
  sendButton?: string;
165
165
  sendMessageTooltip?: string;
166
+ stageMessageTooltip?: string;
167
+ sendNowTooltip?: string;
168
+ stagedMessageLabel?: string;
169
+ discardStagedMessageTooltip?: string;
166
170
  newThread?: string;
167
171
  deleteThread?: string;
168
172
  copyMessage?: string;
@@ -357,6 +361,10 @@ interface ChatCallbacks {
357
361
  onThemeChange?: (theme: "light" | "dark" | "system") => void;
358
362
  onLogout?: () => void;
359
363
  }
364
+ interface ChatActivityNotice {
365
+ tone: "info" | "error";
366
+ message: string;
367
+ }
360
368
  interface ChatV2Props {
361
369
  messages?: ChatMessage[];
362
370
  threads?: ChatThread[];
@@ -370,6 +378,7 @@ interface ChatV2Props {
370
378
  isMessagesLoading?: boolean;
371
379
  isLoadingOlderMessages?: boolean;
372
380
  hasMoreMessagesBefore?: boolean;
381
+ activityNotice?: ChatActivityNotice | null;
373
382
  callbacks?: ChatCallbacks;
374
383
  onLoadOlderMessages?: () => void;
375
384
  user?: {
@@ -519,4 +528,4 @@ declare function mergeConfig(_baseConfig: ChatConfig, userConfig?: Partial<ChatC
519
528
  declare const getAttachmentKindFromMimeType: (mimeType?: string | null) => MediaAttachmentKind;
520
529
  declare const getMimeTypeFromDataUrl: (dataUrl: string) => string | null;
521
530
 
522
- export { type AgentOption, AssistantActivity, type AssistantActivityBlock, type AssistantActivityItem, type AssistantActivityKind, type AssistantActivityStatus, type AudioAttachment, type ChatCallbacks, type ChatConfig, type ChatHeaderMenuItem, type ChatMarkdownConfig, type ChatMessage, type ChatSender, type ChatState, type ChatThread, type ChatThreadTag, ChatUI, type ChatUserContext, ChatUserContextProvider, type ChatUserMenuItem, type ChatUserMenuSection, type ChatV2Props, type CreateVoiceProvider, type FileUploadProgress, type MediaAttachment, type MediaAttachmentKind, type MemoryItem, type MessageAction, type MessageActionEvent, MessageSenderAvatar, type StateCallback, type StreamingUpdate, type ToolCall, type UserCustomField, type VoiceComposerState, type VoiceProvider, type VoiceProviderHandlers, type VoiceProviderOptions, type VoiceReviewMode, type VoiceSegment, type VoiceTranscript, type VoiceTranscriptMode, defaultChatConfig, getAttachmentKindFromMimeType, getMimeTypeFromDataUrl, mergeConfig, resolveMessageSenderDisplay, useChatUserContext };
531
+ export { type AgentOption, AssistantActivity, type AssistantActivityBlock, type AssistantActivityItem, type AssistantActivityKind, type AssistantActivityStatus, type AudioAttachment, type ChatActivityNotice, type ChatCallbacks, type ChatConfig, type ChatHeaderMenuItem, type ChatMarkdownConfig, type ChatMessage, type ChatSender, type ChatState, type ChatThread, type ChatThreadTag, ChatUI, type ChatUserContext, ChatUserContextProvider, type ChatUserMenuItem, type ChatUserMenuSection, type ChatV2Props, type CreateVoiceProvider, type FileUploadProgress, type MediaAttachment, type MediaAttachmentKind, type MemoryItem, type MessageAction, type MessageActionEvent, MessageSenderAvatar, type StateCallback, type StreamingUpdate, type ToolCall, type UserCustomField, type VoiceComposerState, type VoiceProvider, type VoiceProviderHandlers, type VoiceProviderOptions, type VoiceReviewMode, type VoiceSegment, type VoiceTranscript, type VoiceTranscriptMode, defaultChatConfig, getAttachmentKindFromMimeType, getMimeTypeFromDataUrl, mergeConfig, resolveMessageSenderDisplay, useChatUserContext };
package/dist/index.d.ts CHANGED
@@ -163,6 +163,10 @@ interface ChatConfig {
163
163
  inputPlaceholder?: string;
164
164
  sendButton?: string;
165
165
  sendMessageTooltip?: string;
166
+ stageMessageTooltip?: string;
167
+ sendNowTooltip?: string;
168
+ stagedMessageLabel?: string;
169
+ discardStagedMessageTooltip?: string;
166
170
  newThread?: string;
167
171
  deleteThread?: string;
168
172
  copyMessage?: string;
@@ -357,6 +361,10 @@ interface ChatCallbacks {
357
361
  onThemeChange?: (theme: "light" | "dark" | "system") => void;
358
362
  onLogout?: () => void;
359
363
  }
364
+ interface ChatActivityNotice {
365
+ tone: "info" | "error";
366
+ message: string;
367
+ }
360
368
  interface ChatV2Props {
361
369
  messages?: ChatMessage[];
362
370
  threads?: ChatThread[];
@@ -370,6 +378,7 @@ interface ChatV2Props {
370
378
  isMessagesLoading?: boolean;
371
379
  isLoadingOlderMessages?: boolean;
372
380
  hasMoreMessagesBefore?: boolean;
381
+ activityNotice?: ChatActivityNotice | null;
373
382
  callbacks?: ChatCallbacks;
374
383
  onLoadOlderMessages?: () => void;
375
384
  user?: {
@@ -519,4 +528,4 @@ declare function mergeConfig(_baseConfig: ChatConfig, userConfig?: Partial<ChatC
519
528
  declare const getAttachmentKindFromMimeType: (mimeType?: string | null) => MediaAttachmentKind;
520
529
  declare const getMimeTypeFromDataUrl: (dataUrl: string) => string | null;
521
530
 
522
- export { type AgentOption, AssistantActivity, type AssistantActivityBlock, type AssistantActivityItem, type AssistantActivityKind, type AssistantActivityStatus, type AudioAttachment, type ChatCallbacks, type ChatConfig, type ChatHeaderMenuItem, type ChatMarkdownConfig, type ChatMessage, type ChatSender, type ChatState, type ChatThread, type ChatThreadTag, ChatUI, type ChatUserContext, ChatUserContextProvider, type ChatUserMenuItem, type ChatUserMenuSection, type ChatV2Props, type CreateVoiceProvider, type FileUploadProgress, type MediaAttachment, type MediaAttachmentKind, type MemoryItem, type MessageAction, type MessageActionEvent, MessageSenderAvatar, type StateCallback, type StreamingUpdate, type ToolCall, type UserCustomField, type VoiceComposerState, type VoiceProvider, type VoiceProviderHandlers, type VoiceProviderOptions, type VoiceReviewMode, type VoiceSegment, type VoiceTranscript, type VoiceTranscriptMode, defaultChatConfig, getAttachmentKindFromMimeType, getMimeTypeFromDataUrl, mergeConfig, resolveMessageSenderDisplay, useChatUserContext };
531
+ export { type AgentOption, AssistantActivity, type AssistantActivityBlock, type AssistantActivityItem, type AssistantActivityKind, type AssistantActivityStatus, type AudioAttachment, type ChatActivityNotice, type ChatCallbacks, type ChatConfig, type ChatHeaderMenuItem, type ChatMarkdownConfig, type ChatMessage, type ChatSender, type ChatState, type ChatThread, type ChatThreadTag, ChatUI, type ChatUserContext, ChatUserContextProvider, type ChatUserMenuItem, type ChatUserMenuSection, type ChatV2Props, type CreateVoiceProvider, type FileUploadProgress, type MediaAttachment, type MediaAttachmentKind, type MemoryItem, type MessageAction, type MessageActionEvent, MessageSenderAvatar, type StateCallback, type StreamingUpdate, type ToolCall, type UserCustomField, type VoiceComposerState, type VoiceProvider, type VoiceProviderHandlers, type VoiceProviderOptions, type VoiceReviewMode, type VoiceSegment, type VoiceTranscript, type VoiceTranscriptMode, defaultChatConfig, getAttachmentKindFromMimeType, getMimeTypeFromDataUrl, mergeConfig, resolveMessageSenderDisplay, useChatUserContext };
package/dist/index.js CHANGED
@@ -25,6 +25,10 @@ var defaultChatConfig = {
25
25
  inputPlaceholder: "Type your message...",
26
26
  sendButton: "Send",
27
27
  sendMessageTooltip: "Send message",
28
+ stageMessageTooltip: "Stage message",
29
+ sendNowTooltip: "Send now",
30
+ stagedMessageLabel: "Not sent yet",
31
+ discardStagedMessageTooltip: "Discard",
28
32
  newThread: "New Conversation",
29
33
  deleteThread: "Delete Conversation",
30
34
  copyMessage: "Copy",
@@ -4328,6 +4332,9 @@ import {
4328
4332
  UploadCloud
4329
4333
  } from "lucide-react";
4330
4334
  import { Fragment as Fragment6, jsx as jsx25, jsxs as jsxs15 } from "react/jsx-runtime";
4335
+ function createStagedSendId() {
4336
+ return typeof crypto !== "undefined" && typeof crypto.randomUUID === "function" ? crypto.randomUUID() : `${Date.now()}_${Math.random().toString(36).slice(2)}`;
4337
+ }
4331
4338
  function getActiveMentionMatch(value, caret) {
4332
4339
  const prefix = value.slice(0, caret);
4333
4340
  const match = /(^|\s)@([\w.-]*)$/.exec(prefix);
@@ -4613,6 +4620,7 @@ var ChatInput = memo4(function ChatInput2({
4613
4620
  const [activeMention, setActiveMention] = useState7(null);
4614
4621
  const [activeMentionIndex, setActiveMentionIndex] = useState7(0);
4615
4622
  const [isDraggingFiles, setIsDraggingFiles] = useState7(false);
4623
+ const [stagedSends, setStagedSends] = useState7([]);
4616
4624
  const textareaRef = useRef5(null);
4617
4625
  const fileInputRef = useRef5(null);
4618
4626
  const dragDepthRef = useRef5(0);
@@ -4705,18 +4713,48 @@ var ChatInput = memo4(function ChatInput2({
4705
4713
  textareaRef.current?.setSelectionRange(nextCaret, nextCaret);
4706
4714
  });
4707
4715
  }, [activeMention, draftValue, onTargetAgentChange, updateDraftValue]);
4708
- const handleSubmit = (e) => {
4709
- e.preventDefault();
4710
- if (!draftValue.trim() && attachments.length === 0 || disabled || isGenerating) return;
4711
- const mentionedAgent = resolveTargetFromMentions(draftValue, mentionAgents);
4712
- if (mentionedAgent) {
4713
- onTargetAgentChange?.(mentionedAgent.id);
4714
- }
4715
- onSubmit(draftValue.trim(), attachments);
4716
+ const clearComposer = useCallback3(() => {
4716
4717
  updateDraftValue("");
4717
4718
  onAttachmentsChange([]);
4718
4719
  setActiveMention(null);
4719
4720
  setActiveMentionIndex(0);
4721
+ }, [onAttachmentsChange, updateDraftValue]);
4722
+ const submitResolvedMessage = useCallback3((content, messageAttachments) => {
4723
+ const mentionedAgent = resolveTargetFromMentions(content, mentionAgents);
4724
+ if (mentionedAgent) {
4725
+ onTargetAgentChange?.(mentionedAgent.id);
4726
+ }
4727
+ onSubmit(content.trim(), messageAttachments);
4728
+ }, [mentionAgents, onSubmit, onTargetAgentChange]);
4729
+ const stageCurrentDraft = useCallback3(() => {
4730
+ const content = draftValue.trim();
4731
+ if (!content && attachments.length === 0) return;
4732
+ setStagedSends((prev) => [
4733
+ ...prev,
4734
+ {
4735
+ id: createStagedSendId(),
4736
+ content,
4737
+ attachments: [...attachments]
4738
+ }
4739
+ ]);
4740
+ clearComposer();
4741
+ }, [attachments, clearComposer, draftValue]);
4742
+ const sendStagedMessage = useCallback3((staged) => {
4743
+ setStagedSends((prev) => prev.filter((item) => item.id !== staged.id));
4744
+ submitResolvedMessage(staged.content, staged.attachments);
4745
+ }, [submitResolvedMessage]);
4746
+ const removeStagedMessage = useCallback3((id) => {
4747
+ setStagedSends((prev) => prev.filter((item) => item.id !== id));
4748
+ }, []);
4749
+ const handleSubmit = (e) => {
4750
+ e.preventDefault();
4751
+ if (!draftValue.trim() && attachments.length === 0 || disabled) return;
4752
+ if (isGenerating) {
4753
+ stageCurrentDraft();
4754
+ return;
4755
+ }
4756
+ submitResolvedMessage(draftValue.trim(), attachments);
4757
+ clearComposer();
4720
4758
  };
4721
4759
  const handleKeyDown = (e) => {
4722
4760
  if (isMentionMenuOpen) {
@@ -5240,6 +5278,51 @@ var ChatInput = memo4(function ChatInput2({
5240
5278
  { remaining: Math.max(0, maxAttachments - attachments.length) }
5241
5279
  ) })
5242
5280
  ] }) }),
5281
+ stagedSends.length > 0 && /* @__PURE__ */ jsx25("div", { className: "flex flex-col gap-1.5", children: stagedSends.map((staged) => /* @__PURE__ */ jsxs15(
5282
+ "div",
5283
+ {
5284
+ className: "flex min-h-10 items-center gap-2 rounded-2xl border border-border/80 bg-muted/45 px-2.5 py-1.5",
5285
+ children: [
5286
+ /* @__PURE__ */ jsxs15("div", { className: "min-w-0 flex-1", children: [
5287
+ /* @__PURE__ */ jsx25("div", { className: "truncate text-sm text-foreground", children: staged.content || staged.attachments[0]?.fileName || config?.labels?.attachmentsCount || "Attachment" }),
5288
+ staged.attachments.length > 0 && /* @__PURE__ */ jsx25("div", { className: "text-xs text-muted-foreground", children: formatLabel(
5289
+ config?.labels?.attachmentsCount,
5290
+ "{{count}}/{{max}} attachments",
5291
+ { count: staged.attachments.length, max: maxAttachments }
5292
+ ) }),
5293
+ /* @__PURE__ */ jsx25("div", { className: "text-xs text-muted-foreground", children: config?.labels?.stagedMessageLabel || "Not sent yet" })
5294
+ ] }),
5295
+ /* @__PURE__ */ jsxs15(Tooltip, { children: [
5296
+ /* @__PURE__ */ jsx25(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx25(
5297
+ Button,
5298
+ {
5299
+ type: "button",
5300
+ size: "icon",
5301
+ className: "h-8 w-8 rounded-full",
5302
+ onClick: () => sendStagedMessage(staged),
5303
+ children: /* @__PURE__ */ jsx25(Send2, { className: "h-4 w-4" })
5304
+ }
5305
+ ) }),
5306
+ /* @__PURE__ */ jsx25(TooltipContent, { children: config?.labels?.sendNowTooltip || config?.labels?.sendMessageTooltip })
5307
+ ] }),
5308
+ /* @__PURE__ */ jsxs15(Tooltip, { children: [
5309
+ /* @__PURE__ */ jsx25(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx25(
5310
+ Button,
5311
+ {
5312
+ type: "button",
5313
+ variant: "ghost",
5314
+ size: "icon",
5315
+ className: "h-8 w-8 rounded-full text-muted-foreground hover:text-foreground",
5316
+ onClick: () => removeStagedMessage(staged.id),
5317
+ children: /* @__PURE__ */ jsx25(X5, { className: "h-4 w-4" })
5318
+ }
5319
+ ) }),
5320
+ /* @__PURE__ */ jsx25(TooltipContent, { children: config?.labels?.discardStagedMessageTooltip || config?.labels?.voiceCancel })
5321
+ ] })
5322
+ ]
5323
+ },
5324
+ staged.id
5325
+ )) }),
5243
5326
  /* @__PURE__ */ jsxs15("div", { className: "relative min-w-0", children: [
5244
5327
  /* @__PURE__ */ jsx25(
5245
5328
  Textarea,
@@ -5347,19 +5430,34 @@ var ChatInput = memo4(function ChatInput2({
5347
5430
  ) }),
5348
5431
  /* @__PURE__ */ jsx25(TooltipContent, { children: config?.labels?.voiceEnter })
5349
5432
  ] }),
5350
- isGenerating ? /* @__PURE__ */ jsxs15(Tooltip, { children: [
5351
- /* @__PURE__ */ jsx25(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx25(
5352
- Button,
5353
- {
5354
- type: "button",
5355
- variant: "secondary",
5356
- size: "icon",
5357
- className: "h-9 w-9 rounded-full",
5358
- onClick: onStopGeneration,
5359
- children: /* @__PURE__ */ jsx25(Square2, { className: "h-4 w-4" })
5360
- }
5361
- ) }),
5362
- /* @__PURE__ */ jsx25(TooltipContent, { children: config?.labels?.stopGenerationTooltip })
5433
+ isGenerating ? /* @__PURE__ */ jsxs15(Fragment6, { children: [
5434
+ (draftValue.trim() || attachments.length > 0) && /* @__PURE__ */ jsxs15(Tooltip, { children: [
5435
+ /* @__PURE__ */ jsx25(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx25(
5436
+ Button,
5437
+ {
5438
+ type: "submit",
5439
+ size: "icon",
5440
+ className: "h-9 w-9 rounded-full",
5441
+ disabled,
5442
+ children: /* @__PURE__ */ jsx25(Send2, { className: "h-4 w-4" })
5443
+ }
5444
+ ) }),
5445
+ /* @__PURE__ */ jsx25(TooltipContent, { children: config?.labels?.stageMessageTooltip || config?.labels?.sendMessageTooltip })
5446
+ ] }),
5447
+ /* @__PURE__ */ jsxs15(Tooltip, { children: [
5448
+ /* @__PURE__ */ jsx25(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx25(
5449
+ Button,
5450
+ {
5451
+ type: "button",
5452
+ variant: "secondary",
5453
+ size: "icon",
5454
+ className: "h-9 w-9 rounded-full",
5455
+ onClick: onStopGeneration,
5456
+ children: /* @__PURE__ */ jsx25(Square2, { className: "h-4 w-4" })
5457
+ }
5458
+ ) }),
5459
+ /* @__PURE__ */ jsx25(TooltipContent, { children: config?.labels?.stopGenerationTooltip })
5460
+ ] })
5363
5461
  ] }) : /* @__PURE__ */ jsxs15(Tooltip, { children: [
5364
5462
  /* @__PURE__ */ jsx25(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx25(
5365
5463
  Button,
@@ -5976,6 +6074,7 @@ var ChatUI = ({
5976
6074
  isMessagesLoading = false,
5977
6075
  isLoadingOlderMessages = false,
5978
6076
  hasMoreMessagesBefore = false,
6077
+ activityNotice = null,
5979
6078
  callbacks = {},
5980
6079
  onLoadOlderMessages,
5981
6080
  user,
@@ -6624,41 +6723,50 @@ var ChatUI = ({
6624
6723
  ] })
6625
6724
  }
6626
6725
  ),
6627
- /* @__PURE__ */ jsx28("div", { className: "-mt-8 bg-gradient-to-t from-background via-background/95 to-transparent px-0 pb-[env(safe-area-inset-bottom)] pt-10", children: /* @__PURE__ */ jsx28(
6628
- ChatInput,
6629
- {
6630
- value: inputValue,
6631
- onChange: (value) => {
6632
- inputValueRef.current = value;
6633
- if (initialInputApplied.current && !initialInputConsumedRef.current) {
6634
- initialInputConsumedRef.current = true;
6635
- onInitialInputConsumed?.();
6636
- }
6637
- },
6638
- onSubmit: handleSendMessage,
6639
- attachments,
6640
- onAttachmentsChange: setAttachments,
6641
- placeholder: config.labels.inputPlaceholder,
6642
- disabled: false,
6643
- isGenerating,
6644
- onStopGeneration: callbacks.onStopGeneration,
6645
- enableFileUpload: config.features.enableFileUpload,
6646
- enableAudioRecording: config.features.enableAudioRecording,
6647
- maxAttachments: config.features.maxAttachments,
6648
- maxFileSize: config.features.maxFileSize,
6649
- acceptedFileTypes: config.features.acceptedFileTypes,
6650
- config,
6651
- mentionAgents: participantIds && participantIds.length > 0 ? agentOptions.filter(
6652
- (a) => participantIds.includes(a.id)
6653
- ) : agentOptions,
6654
- targetAgentId,
6655
- showTargetAgentSelector: Boolean(
6656
- isMultiAgentMode && shouldShowAgentSelector && onTargetAgentChange
6657
- ),
6658
- targetAgentSelectorPlaceholder: config.agentSelector?.label || "Select agent",
6659
- onTargetAgentChange
6660
- }
6661
- ) })
6726
+ /* @__PURE__ */ jsxs18("div", { className: "-mt-8 bg-gradient-to-t from-background via-background/95 to-transparent px-0 pb-[env(safe-area-inset-bottom)] pt-10", children: [
6727
+ activityNotice && /* @__PURE__ */ jsx28("div", { className: "mx-auto mb-2 w-full max-w-3xl px-3 md:px-2", children: /* @__PURE__ */ jsx28(
6728
+ "div",
6729
+ {
6730
+ className: activityNotice.tone === "error" ? "rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-sm text-destructive" : "rounded-md border border-border bg-muted/70 px-3 py-2 text-sm text-muted-foreground",
6731
+ children: activityNotice.message
6732
+ }
6733
+ ) }),
6734
+ /* @__PURE__ */ jsx28(
6735
+ ChatInput,
6736
+ {
6737
+ value: inputValue,
6738
+ onChange: (value) => {
6739
+ inputValueRef.current = value;
6740
+ if (initialInputApplied.current && !initialInputConsumedRef.current) {
6741
+ initialInputConsumedRef.current = true;
6742
+ onInitialInputConsumed?.();
6743
+ }
6744
+ },
6745
+ onSubmit: handleSendMessage,
6746
+ attachments,
6747
+ onAttachmentsChange: setAttachments,
6748
+ placeholder: config.labels.inputPlaceholder,
6749
+ disabled: false,
6750
+ isGenerating,
6751
+ onStopGeneration: callbacks.onStopGeneration,
6752
+ enableFileUpload: config.features.enableFileUpload,
6753
+ enableAudioRecording: config.features.enableAudioRecording,
6754
+ maxAttachments: config.features.maxAttachments,
6755
+ maxFileSize: config.features.maxFileSize,
6756
+ acceptedFileTypes: config.features.acceptedFileTypes,
6757
+ config,
6758
+ mentionAgents: participantIds && participantIds.length > 0 ? agentOptions.filter(
6759
+ (a) => participantIds.includes(a.id)
6760
+ ) : agentOptions,
6761
+ targetAgentId,
6762
+ showTargetAgentSelector: Boolean(
6763
+ isMultiAgentMode && shouldShowAgentSelector && onTargetAgentChange
6764
+ ),
6765
+ targetAgentSelectorPlaceholder: config.agentSelector?.label || "Select agent",
6766
+ onTargetAgentChange
6767
+ }
6768
+ )
6769
+ ] })
6662
6770
  ] }),
6663
6771
  config?.customComponent?.component && !isMobile && /* @__PURE__ */ jsx28(
6664
6772
  "div",