import * as React from 'react'; import { SxProps } from '@mui/system'; import { Theme } from '@mui/material/styles'; import { SlotComponentProps } from '@mui/utils/types'; import { type ChatRootProps, type ChatFeatures, type MessageListRootAutoScrollConfig, type ChatSuggestion, type ChatVariant, type ChatDensity, type ChatAttachmentsConfig, type MessageGroupSlotProps } from '@mui/x-chat-headless'; import type { ChatConversationProps } from "../ChatConversation/ChatConversation.js"; import type { ChatConversationListProps } from "../ChatConversationList/ChatConversationList.js"; import type { ChatConversationHeaderProps } from "../ChatConversation/ChatConversationHeader.js"; import type { ChatConversationTitleProps } from "../ChatConversation/ChatConversationTitle.js"; import type { ChatConversationSubtitleProps } from "../ChatConversation/ChatConversationSubtitle.js"; import type { ChatConversationHeaderInfoProps } from "../ChatConversation/ChatConversationHeaderInfo.js"; import type { ChatConversationHeaderActionsProps } from "../ChatConversation/ChatConversationHeaderActions.js"; import type { ChatMessageListProps } from "../ChatMessageList/ChatMessageList.js"; import type { ChatMessageProps, ChatMessageActionsResolveContext } from "../ChatMessage/ChatMessage.js"; import type { ChatMessageAvatarProps } from "../ChatMessage/ChatMessageAvatar.js"; import type { ChatMessageContentProps } from "../ChatMessage/ChatMessageContent.js"; import type { ChatMessageInlineMetaProps } from "../ChatMessage/ChatMessageInlineMeta.js"; import type { ChatMessageMetaProps } from "../ChatMessage/ChatMessageMeta.js"; import type { ChatMessageActionsProps } from "../ChatMessage/ChatMessageActions.js"; import type { ChatMessageGroupProps } from "../ChatMessage/ChatMessageGroup.js"; import type { ChatMessageErrorProps } from "../ChatMessageError/ChatMessageError.js"; import type { ChatDateDividerProps } from "../ChatMessage/ChatDateDivider.js"; import type { ChatComposerProps } from "../ChatComposer/ChatComposer.js"; import type { ChatComposerTextAreaProps } from "../ChatComposer/ChatComposerTextArea.js"; import type { ChatComposerSendButtonProps } from "../ChatComposer/ChatComposerSendButton.js"; import type { ChatComposerAttachButtonProps } from "../ChatComposer/ChatComposerAttachButton.js"; import type { ChatComposerAttachmentListProps } from "../ChatComposer/ChatComposerAttachmentList.js"; import type { ChatComposerToolbarProps } from "../ChatComposer/ChatComposerToolbar.js"; import type { ChatComposerHelperTextProps } from "../ChatComposer/ChatComposerHelperText.js"; import type { ChatStreamingIndicatorProps } from "../ChatIndicators/ChatStreamingIndicator.js"; import type { ChatTypingIndicatorProps } from "../ChatIndicators/ChatTypingIndicator.js"; import type { ChatUnreadMarkerProps } from "../ChatIndicators/ChatUnreadMarker.js"; import type { ChatScrollToBottomAffordanceProps } from "../ChatIndicators/ChatScrollToBottomAffordance.js"; import type { ChatSuggestionsProps } from "../ChatSuggestions/ChatSuggestions.js"; import { type ChatBoxClasses } from "./chatBoxClasses.js"; /** Outer layout singletons. */ interface ChatBoxLayoutSlots { /** The outermost `ChatBox` container element. */ root?: React.ElementType; /** Wrapper that arranges the conversations pane and the thread pane. */ layout?: React.ElementType; /** Container for the conversation-list sidebar (or drawer on narrow widths). */ conversationsPane?: React.ElementType; /** Container for the active thread — the message list plus the composer. */ threadPane?: React.ElementType; } interface ChatBoxLayoutSlotProps { root?: SlotComponentProps<'div', { sx?: SxProps; }, {}>; layout?: SlotComponentProps<'div', { sx?: SxProps; }, {}>; conversationsPane?: SlotComponentProps<'div', { sx?: SxProps; }, {}>; threadPane?: SlotComponentProps<'div', { sx?: SxProps; }, {}>; } /** * Conversation family. `conversationRoot` swaps the styled element of * `` (wrapper-only); the default child layout (header + * message list + composer) continues to render inside it. */ interface ChatBoxConversationSlots { /** * Styled root of `` (wrapper-only); the default header, * message list and composer continue to render inside it. */ conversationRoot?: React.ElementType; /** The conversation-list sidebar component. */ conversationList?: React.ElementType; /** The header bar rendered above the message list. */ conversationHeader?: React.ElementType; /** The title + subtitle group inside the header. */ conversationHeaderInfo?: React.ElementType; /** The conversation title element. */ conversationTitle?: React.ElementType; /** The conversation subtitle element (participants, status, etc.). */ conversationSubtitle?: React.ElementType; /** The actions area on the trailing side of the header. */ conversationHeaderActions?: React.ElementType; } interface ChatBoxConversationSlotProps { conversationRoot?: Partial; conversationList?: Partial; conversationHeader?: Partial; conversationHeaderInfo?: Partial; conversationTitle?: Partial; conversationSubtitle?: Partial; conversationHeaderActions?: Partial; } /** * Message-list chrome. `messageList` swaps the scrollable root *element* of * `` (wrapper-only — the default rows still render inside); * `messageGroup` swaps the per-author group wrapper. */ interface ChatBoxMessageListSlots { /** * Styled scrollable root element of `` (wrapper-only). The * default message rows render inside it, so a plain element such as `'section'` * wraps the list rather than replacing it. */ messageList?: React.ElementType; /** The per-author group wrapper around consecutive messages. */ messageGroup?: React.ElementType; /** * The date separator rendered between message groups. Only rendered when * `features.dateDivider` is enabled. Pass `null` to hide it. */ dateDivider?: React.ElementType | null; /** * The "new messages" marker. Only rendered when `features.unreadMarker` is * enabled. Pass `null` to hide it. */ unreadMarker?: React.ElementType | null; /** * The animated dots shown while an assistant response is in flight: as a * trailing row while waiting for the response to start, then inside the * assistant bubble while it streams. Controlled by * `features.streamingIndicator` (`'auto'` by default). Pass `null` to hide it. */ streamingIndicator?: React.ElementType | null; } interface ChatBoxMessageListSlotProps { messageList?: Partial; messageGroup?: Partial; dateDivider?: Partial; unreadMarker?: Partial; streamingIndicator?: Partial; } /** * Per-row message parts. `messageRoot` swaps the styled element of * `` (wrapper-only). Presentational slots accept `null` to hide the * piece and collapse the surrounding layout (avatar grid track, etc.). */ interface ChatBoxMessageSlots { /** * Styled root of `` (wrapper-only); the default avatar/content/meta * tree still renders inside it. */ messageRoot?: React.ElementType; /** * Avatar component. Pass `null` to hide the avatar entirely and drop the * reserved avatar grid track. */ messageAvatar?: React.ElementType | null; /** The message bubble component. */ messageContent?: React.ElementType; /** External meta (compact variant). Pass `null` to hide. */ messageMeta?: React.ElementType | null; /** Inline meta rendered inside the bubble (default variant). Pass `null` to hide. */ messageInlineMeta?: React.ElementType | null; /** * Error card shown under the bubble when the message status is `error`. * Pass `null` to hide the error surface entirely (no component is mounted). */ messageError?: React.ElementType | null; /** * Actions row component (receives `{ messageId }`). Pass `null` to hide * actions entirely; omit to render only the declarative `extraActions` from * `slotProps.messageActions` if provided. */ messageActions?: React.ElementType | null; /** * Author name label rendered by the group wrapper (default variant: above the * bubble; compact variant: inside the message grid). Pass `null` to hide. */ messageAuthorName?: React.ElementType | null; } interface ChatBoxMessageSlotProps { messageRoot?: Partial; messageAvatar?: Partial; messageContent?: Partial; messageMeta?: Partial; messageInlineMeta?: Partial; messageError?: Partial; /** * Props for the message actions row. Pass a function of the message context * to vary props per message — most commonly returning `extraActions` * (declarative action buttons) only for assistant rows. */ messageActions?: Partial | ((context: ChatMessageActionsResolveContext) => Partial); messageAuthorName?: MessageGroupSlotProps['authorName']; } /** * Composer family. `composerRoot` swaps the styled element of `` * (wrapper-only); the default attach/input/send/toolbar render inside it. */ interface ChatBoxComposerSlots { /** * Styled root of `` (wrapper-only); the default attach/input/send/ * toolbar render inside it. */ composerRoot?: React.ElementType; /** The auto-resizing text input. */ composerInput?: React.ElementType; /** Send button. Pass `null` to hide it; the form still submits on Enter. */ composerSendButton?: React.ElementType | null; /** * Attach button. Pass `null` to hide just the button while keeping the rest of * the attachment pipeline (drag/drop, paste). Use `features.attachments: false` * to disable attachments entirely. */ composerAttachButton?: React.ElementType | null; /** The pending-attachment preview list. */ composerAttachmentList?: React.ElementType; /** The composer toolbar (button row). */ composerToolbar?: React.ElementType; /** The helper / disclaimer text below the input. */ composerHelperText?: React.ElementType; } interface ChatBoxComposerSlotProps { composerRoot?: Partial; composerInput?: Partial; composerSendButton?: Partial; composerAttachButton?: Partial; composerAttachmentList?: Partial; composerToolbar?: Partial; composerHelperText?: Partial; } /** Standalone widgets. */ interface ChatBoxWidgetSlots { /** The animated typing indicator shown while the assistant responds. */ typingIndicator?: React.ElementType; /** The floating scroll-to-bottom button. */ scrollToBottom?: React.ElementType; /** The prompt-suggestion chips. */ suggestions?: React.ElementType; /** Custom content rendered when the thread has no messages. */ emptyState?: React.ElementType; } interface ChatBoxWidgetSlotProps { typingIndicator?: Partial; scrollToBottom?: Partial; suggestions?: Partial; emptyState?: SlotComponentProps; }, {}>; } export interface ChatBoxSlots extends ChatBoxLayoutSlots, ChatBoxConversationSlots, ChatBoxMessageListSlots, ChatBoxMessageSlots, ChatBoxComposerSlots, ChatBoxWidgetSlots {} export interface ChatBoxSlotProps extends ChatBoxLayoutSlotProps, ChatBoxConversationSlotProps, ChatBoxMessageListSlotProps, ChatBoxMessageSlotProps, ChatBoxComposerSlotProps, ChatBoxWidgetSlotProps {} export interface ChatBoxFeatures extends ChatFeatures { /** * Whether the runtime sends outbound typing signals through `adapter.setTyping()` * automatically as the user composes a message. * * When enabled and the adapter implements `setTyping()`, the runtime calls it * for the active conversation: `{ isTyping: true }` when the composer value * changes from empty (`''`) to non-empty, and `{ isTyping: false }` when it * changes back to empty — including when a message is sent (sending clears the * composer). Switching conversations clears typing on the previous one and * re-signals on the new one if a draft is present; mounting with an initial * draft signals `true`; unmounting signals a final `false`. Keystrokes that * keep the composer non-empty produce no additional calls, there is no * built-in idle timeout, and failures are swallowed with a dev-only warning. * * When disabled (the default), the runtime never calls `setTyping()`; wire it * up manually (e.g. on composer `onChange`) instead. If you enable this flag, * remove any manual wiring to avoid double-firing. * @default false */ typingSignal?: boolean; /** * Whether to render the built-in conversation list sidebar / drawer. * When disabled, `ChatBox` renders only the active thread surface even if * conversations are present or loaded through `adapter.listConversations()`. * This flag controls only the built-in sidebar / drawer UI. * @default false */ conversationList?: boolean; /** * Whether to render a date divider between messages whose `createdAt` values * fall on different calendar days. Use the `dateDivider` slot to customize the * rendered component once enabled. * @default false */ dateDivider?: boolean; /** * Whether to render the unread "new messages" marker above the first unread * message (derived from the active conversation's `unreadCount` / `readState`). * Use the `unreadMarker` slot to customize the rendered component once enabled. * @default false */ unreadMarker?: boolean; /** * Whether to show the scroll-to-bottom affordance button when the user has scrolled up. * @default true */ scrollToBottom?: boolean; /** * Whether to show the conversation header (title, subtitle, and actions bar). * @default true */ conversationHeader?: boolean; /** * Whether to enable attachment functionality (attach button and attachment preview list), * and optionally configure attachment validation constraints. * * - `true` – enable with no restrictions (default). * - `false` – disable attachment functionality entirely. * - `{ acceptedMimeTypes, maxFileCount, maxFileSize, onAttachmentReject }` – enable * with the specified validation rules. * @default true */ attachments?: boolean | ChatAttachmentsConfig; /** * Whether to show the helper text below the composer input. * @default true */ helperText?: boolean; /** * Controls automatic scrolling to the bottom when new messages arrive or streaming * content grows, as long as the user is within `buffer` pixels of the bottom. * * - `true` – enable with the default buffer (150 px). * - `{ buffer: number }` – enable with a custom threshold. * - `false` – disable all automatic scrolling (the user can still use the * scroll-to-bottom affordance button manually). * * Note: scrolling to the bottom when the *user* sends a message is always * active regardless of this setting. * @default true */ autoScroll?: boolean | MessageListRootAutoScrollConfig; /** * Whether to show prompt suggestions in the empty state. * @default true */ suggestions?: boolean; /** * Whether to show the animated streaming indicator while waiting for / * receiving an assistant response. * - `'auto'` – shown only in assistant-backed conversations (an assistant * member/participant is configured, or an assistant message exists). * - `true` – always shown while a response is in flight. * - `false` – never shown. * Use the `streamingIndicator` slot to customize the rendered component. * @default 'auto' */ streamingIndicator?: boolean | 'auto'; } export type ChatBoxLayoutMode = 'standard' | 'overlay' | 'split'; export interface ChatBoxLayoutModeBreakpoints { /** * Container width below which ChatBox switches from the standard side-by-side layout * to the overlay conversations panel. * @default 600 */ overlay: number; /** * Container width below which ChatBox switches from overlay mode to the split list/thread flow. * This value is clamped so it never exceeds `overlay`. * @default 450 */ split: number; } export interface ChatBoxProps extends Omit, 'slots' | 'slotProps'> { className?: string; sx?: SxProps; /** * Override or extend the styles applied to the component. */ classes?: Partial; /** * The visual layout variant of the chat. * - `'default'` – Standard layout with avatars, individual timestamps, and full spacing. * - `'compact'` – Messenger-style layout: no avatars, author + timestamp in group header, tighter spacing. * @default 'default' */ variant?: ChatVariant; /** * The vertical spacing density of chat messages. * - `'compact'` – Reduced vertical spacing between messages. * - `'standard'` – Default spacing. * - `'comfortable'` – Increased vertical spacing between messages. * @default 'standard' */ density?: ChatDensity; /** * The components used for each slot inside the ChatBox. Keys are flat and * prefixed by area: * * - Layout — `root`, `layout`, `conversationsPane`, `threadPane`. * - Conversation — `conversationRoot`, `conversationList`, `conversationHeader`, * `conversationHeaderInfo`, `conversationTitle`, `conversationSubtitle`, * `conversationHeaderActions`. * - Message list — `messageList`, `messageGroup`, `dateDivider`, `unreadMarker`, * `streamingIndicator`. The divider slots render only when the matching * `features.dateDivider` / `features.unreadMarker` flag is enabled; the * streaming indicator renders by default (`features.streamingIndicator: 'auto'`) * and accepts `null` to hide it. * - Message — `messageRoot`, `messageAvatar`, `messageContent`, `messageMeta`, * `messageInlineMeta`, `messageError`, `messageActions`, `messageAuthorName`. * Pass `null` to a presentational slot (`messageAvatar`, `messageMeta`, * `messageInlineMeta`, `messageActions`, `messageAuthorName`) to hide it and * collapse the surrounding layout. * - Composer — `composerRoot`, `composerInput`, `composerSendButton`, * `composerAttachButton`, `composerAttachmentList`, `composerToolbar`, * `composerHelperText`. Pass `null` to `composerSendButton` / * `composerAttachButton` to hide the button. * - Widgets — `typingIndicator`, `scrollToBottom`, `suggestions`, `emptyState`. * * `*Root` slots (`conversationRoot`, `messageRoot`, `composerRoot`) are * wrapper-only: they swap the styled element while the default children still * render inside. */ slots?: ChatBoxSlots; /** * Props forwarded to each slot. Mirrors the flat keys of `slots`. */ slotProps?: ChatBoxSlotProps; /** * Feature flags to enable or disable built-in ChatBox behaviours. */ features?: ChatBoxFeatures; /** * Forces the responsive layout mode instead of deriving it from the container width. * When omitted, ChatBox chooses the mode automatically using `layoutModeBreakpoints`. */ layoutMode?: ChatBoxLayoutMode; /** * Container-width breakpoints used when `layoutMode` is not provided. */ layoutModeBreakpoints?: Partial; /** * Prompt suggestions displayed in the empty state. * Clicking a suggestion pre-fills the composer. */ suggestions?: Array; /** * Whether clicking a suggestion automatically submits the message. * @default false */ suggestionsAutoSubmit?: boolean; } export {};