@sybilion/uilib 1.3.81 → 1.3.83

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 (38) hide show
  1. package/dist/esm/components/ui/Chat/ChatChrome/ChatChrome.js +20 -5
  2. package/dist/esm/components/ui/Chat/ChatChrome/ChatChrome.styl.js +2 -2
  3. package/dist/esm/components/ui/Chat/ChatMessage/AgentMessageContent.js +3 -2
  4. package/dist/esm/components/ui/Chat/ChatMessage/ChatMessage.js +2 -2
  5. package/dist/esm/components/ui/Chat/ChatMessage/ChatMessage.styl.js +2 -2
  6. package/dist/esm/components/ui/Chat/ChatPresets/ChatPresets.js +2 -2
  7. package/dist/esm/components/ui/Chat/ChatPresets/ChatPresets.styl.js +2 -2
  8. package/dist/esm/components/ui/Chat/ChatSheet/useChatPanelChromeModel.js +2 -2
  9. package/dist/esm/types/src/components/ui/Chat/Chat.types.d.ts +14 -0
  10. package/dist/esm/types/src/components/ui/Chat/ChatChrome/ChatChrome.d.ts +1 -1
  11. package/dist/esm/types/src/components/ui/Chat/ChatChrome/ChatChrome.types.d.ts +11 -2
  12. package/dist/esm/types/src/components/ui/Chat/ChatChrome/index.d.ts +1 -1
  13. package/dist/esm/types/src/components/ui/Chat/ChatMessage/AgentMessageContent.d.ts +2 -1
  14. package/dist/esm/types/src/components/ui/Chat/ChatMessage/ChatMessage.d.ts +1 -1
  15. package/dist/esm/types/src/components/ui/Chat/ChatPresets/ChatPresets.d.ts +3 -1
  16. package/dist/esm/types/src/components/ui/Chat/index.d.ts +2 -2
  17. package/package.json +1 -1
  18. package/src/components/ui/Chat/Chat.types.ts +16 -0
  19. package/src/components/ui/Chat/ChatChrome/ChatChrome.styl +22 -4
  20. package/src/components/ui/Chat/ChatChrome/ChatChrome.styl.d.ts +4 -0
  21. package/src/components/ui/Chat/ChatChrome/ChatChrome.tsx +38 -9
  22. package/src/components/ui/Chat/ChatChrome/ChatChrome.types.ts +17 -1
  23. package/src/components/ui/Chat/ChatChrome/index.ts +1 -0
  24. package/src/components/ui/Chat/ChatMessage/AgentMessageContent.tsx +4 -1
  25. package/src/components/ui/Chat/ChatMessage/ChatMessage.styl +5 -3
  26. package/src/components/ui/Chat/ChatMessage/ChatMessage.styl.d.ts +1 -0
  27. package/src/components/ui/Chat/ChatMessage/ChatMessage.tsx +8 -3
  28. package/src/components/ui/Chat/ChatPresets/ChatPresets.styl +2 -1
  29. package/src/components/ui/Chat/ChatPresets/ChatPresets.styl.d.ts +1 -0
  30. package/src/components/ui/Chat/ChatPresets/ChatPresets.tsx +10 -1
  31. package/src/components/ui/Chat/ChatSheet/useChatPanelChromeModel.tsx +6 -2
  32. package/src/components/ui/Chat/index.ts +4 -0
  33. package/src/docs/pages/ChartAreaInteractivePage.tsx +7 -8
  34. package/src/docs/pages/ChatAttachmentsDropzonePage.tsx +1 -0
  35. package/src/docs/pages/ChatComposerPrefillPage.tsx +1 -0
  36. package/src/docs/pages/ChatPage.tsx +1 -1
  37. package/src/docs/pages/ChatSlashCommandsPage.tsx +1 -0
  38. package/src/docs/pages/ChatUserCsvAttachmentPage.tsx +1 -0
@@ -15,7 +15,7 @@ import { filterToTextAttachments, isAttachmentsDropzoneEnabled, buildAcceptAttr
15
15
  import { extractChatAttachmentItems } from '../chatAttachmentExtract.js';
16
16
  import S from './ChatChrome.styl.js';
17
17
 
18
- function ChatChrome({ showResizeHandle, resizeHandle, onClose, isEmpty, renderPresets, messages, onQuickReply, suppressedQuickReplyKeys, isLoading, loadingLabel, scriptContinueLabel, onScriptContinue, renderMessageChart, renderSystemMessage, showSyntheticBranchButtons, unusedBranchKeys, showInlinePresets, isLastMessageFromUser, scrollRef, effectiveScopeId, onPromptSubmit, onChatDeleted, onNewChat, promptPrefill, footerClassName, emptyState, allowedAttachments, allowPdfAttachments = false, onAttachmentsDropped, slashCommandItems, onSlashItemCommand, promptPlaceholder, hideChatSelector = false, }) {
18
+ function ChatChrome({ variant = 'default', showResizeHandle, resizeHandle, onClose, isEmpty, renderPresets, messages, onQuickReply, suppressedQuickReplyKeys, isLoading, loadingLabel, scriptContinueLabel, onScriptContinue, renderMessageChart, renderSystemMessage, showSyntheticBranchButtons, unusedBranchKeys, showInlinePresets, isLastMessageFromUser, scrollRef, effectiveScopeId, onPromptSubmit, onChatDeleted, onNewChat, promptPrefill, footerClassName, messageClassNames, messageTextClassNames, emptyState, allowedAttachments, allowPdfAttachments = false, onAttachmentsDropped, slashCommandItems, onSlashItemCommand, promptPlaceholder, hideChatSelector = false, }) {
19
19
  const filteredAllowedAttachments = useMemo(() => filterToTextAttachments(allowedAttachments), [allowedAttachments]);
20
20
  const attachmentsDropzoneEnabled = isAttachmentsDropzoneEnabled(allowedAttachments, allowPdfAttachments);
21
21
  const attachmentAccept = useMemo(() => buildAcceptAttr(filteredAllowedAttachments, allowPdfAttachments), [filteredAllowedAttachments, allowPdfAttachments]);
@@ -76,9 +76,24 @@ function ChatChrome({ showResizeHandle, resizeHandle, onClose, isEmpty, renderPr
76
76
  showInlinePresets,
77
77
  showSyntheticBranchButtons,
78
78
  ]);
79
- return (jsxs("div", { className: S.root, children: [showResizeHandle && resizeHandle ? (jsx(PanelResizeHandle, { edge: "leading", isActive: resizeHandle.isActive, startWidthPx: resizeHandle.startWidthPx, getShellWidth: resizeHandle.getShellWidth, onDragWidth: resizeHandle.onDragWidth, onDragComplete: resizeHandle.onDragComplete, className: cn(SidebarStem.sidebarResizeHandle, S.chatResizeHandle) })) : null, jsx("div", { className: S.panelHeader, children: onClose ? (jsx(Button, { type: "button", variant: "ghost", icon: true, className: S.panelClose, "aria-label": "Close chat", onClick: onClose, children: jsx(X, { className: "size-4" }) })) : null }), jsxs("div", { className: S.content, children: [attachmentsDropzoneEnabled ? (jsx(DropZone, { accept: attachmentAccept, label: "Drop text files to attach", multiple: true, ghost: true, overlayScope: "container", disabled: promptDisabled, className: S.attachmentDropzone, onFiles: handleAttachmentFiles })) : null, jsxs(Chat, { isEmpty: isEmpty, scopeId: effectiveScopeId, onChatDeleted: onChatDeleted, onNewChat: onNewChat, hideChatSelector: hideChatSelector, children: [isEmpty ? (jsx("div", { className: S.emptyBody, children: jsx(Chat.EmptyState, { ...emptyState }) })) : (jsx("div", { className: S.scrollWrapper, children: jsxs(Scroll, { y: true, yScrollbarClassName: S.scrollbar, className: S.scroll, innerClassName: S.scrollInner, offset: { y: { before: 56, after: 24 } }, fadeSize: "m", autoHide: true, ref: scrollRef, children: [messages.map((msg, index, arr) => {
79
+ const isClean = variant === 'clean';
80
+ return (jsxs("div", { className: cn(S.root, isClean && S.rootClean), children: [showResizeHandle && resizeHandle ? (jsx(PanelResizeHandle, { edge: "leading", isActive: resizeHandle.isActive, startWidthPx: resizeHandle.startWidthPx, getShellWidth: resizeHandle.getShellWidth, onDragWidth: resizeHandle.onDragWidth, onDragComplete: resizeHandle.onDragComplete, className: cn(SidebarStem.sidebarResizeHandle, S.chatResizeHandle) })) : null, jsx("div", { className: S.panelHeader, children: onClose ? (jsx(Button, { type: "button", variant: "ghost", icon: true, className: S.panelClose, "aria-label": "Close chat", onClick: onClose, children: jsx(X, { className: "size-4" }) })) : null }), jsxs("div", { className: S.content, children: [attachmentsDropzoneEnabled ? (jsx(DropZone, { accept: attachmentAccept, label: "Drop text files to attach", multiple: true, ghost: true, overlayScope: "container", disabled: promptDisabled, className: S.attachmentDropzone, onFiles: handleAttachmentFiles })) : null, jsxs(Chat, { className: isClean ? S.chatClean : undefined, isEmpty: isEmpty, scopeId: effectiveScopeId, onChatDeleted: onChatDeleted, onNewChat: onNewChat, hideChatSelector: hideChatSelector, children: [isEmpty ? (jsx("div", { className: S.emptyBody, children: jsx(Chat.EmptyState, { ...emptyState }) })) : (jsx("div", { className: S.scrollWrapper, children: jsxs(Scroll, { y: true, yScrollbarClassName: S.scrollbar, className: S.scroll, innerClassName: S.scrollInner, offset: { y: { before: 56, after: 24 } }, fadeSize: "m", autoHide: true, ref: scrollRef, children: [messages.map((msg, index, arr) => {
80
81
  const isLast = index === arr.length - 1;
81
- return (jsx(Chat.Message, { message: msg, role: msg.role, text: msg.text, inProgress: msg.inProgress, userTextFileAttachments: msg.userTextFileAttachments, onQuickReply: onQuickReply, suppressedQuickReplyKeys: suppressedQuickReplyKeys, quickReplyDisabled: isLoading, quickReplyHidden: Boolean(loadingLabel), isLastMessage: isLast, scriptContinue: isLast && scriptContinueLabel
82
+ const messageClassName = messageClassNames
83
+ ? {
84
+ [MessageRole.USER]: messageClassNames.user,
85
+ [MessageRole.ASSISTANT]: messageClassNames.assistant,
86
+ [MessageRole.SYSTEM]: messageClassNames.system,
87
+ }[msg.role]
88
+ : undefined;
89
+ const messageTextClassName = messageTextClassNames
90
+ ? {
91
+ [MessageRole.USER]: messageTextClassNames.user,
92
+ [MessageRole.ASSISTANT]: messageTextClassNames.assistant,
93
+ [MessageRole.SYSTEM]: messageTextClassNames.system,
94
+ }[msg.role]
95
+ : undefined;
96
+ return (jsx(Chat.Message, { message: msg, className: messageClassName, textClassName: messageTextClassName, role: msg.role, text: msg.text, inProgress: msg.inProgress, userTextFileAttachments: msg.userTextFileAttachments, onQuickReply: onQuickReply, suppressedQuickReplyKeys: suppressedQuickReplyKeys, quickReplyDisabled: isLoading, quickReplyHidden: Boolean(loadingLabel), isLastMessage: isLast, scriptContinue: isLast && scriptContinueLabel
82
97
  ? { label: scriptContinueLabel }
83
98
  : undefined, onScriptContinue: isLast && scriptContinueLabel
84
99
  ? onScriptContinue
@@ -87,9 +102,9 @@ function ChatChrome({ showResizeHandle, resizeHandle, onClose, isEmpty, renderPr
87
102
  const label = displayLabelForBranchKeyFromMessages(key, messages) ??
88
103
  humanizeBranchKey(key);
89
104
  return (jsx("span", { className: S.branchBtnWrap, children: jsxs(Button, { type: "button", variant: "outline", size: "sm", disabled: isLoading, onClick: () => onQuickReply(key, label), children: [jsx(PaperPlaneRightIcon, {}), label] }) }, key));
90
- }) })) : null, showInlinePresets && renderPresets('inline'), isLoading &&
105
+ }) })) : null, showInlinePresets && renderPresets('inline', { variant }), isLoading &&
91
106
  !hasInProgressSystemMessage &&
92
- (isLastMessageFromUser || loadingLabel) && (jsx(TextShimmer, { duration: 1, spread: 5, className: S.loader, children: loadingLabel ?? 'Thinking...' }))] }) })), isEmpty ? (jsx("div", { className: S.fixedPresets, children: renderPresets('fixed') })) : null, jsxs("div", { className: cn(S.footer, footerClassName), children: [isEmpty ? (jsx("div", { className: S.notice, children: "Forecast Assistant can make mistakes." })) : null, jsx(Chat.Prompt, { onSubmit: handlePromptSubmitWithAttachments, disabled: promptDisabled, attachments: pendingAttachments, onRemoveAttachment: handleRemoveAttachment, prefillMessage: promptPrefill ?? undefined, placeholder: promptPlaceholder, slashCommandItems: slashCommandItems, onSlashItemCommand: onSlashItemCommand, attachmentAccept: attachmentsDropzoneEnabled ? attachmentAccept : undefined, onAttachmentFiles: attachmentsDropzoneEnabled ? handleAttachmentFiles : undefined })] })] })] })] }));
107
+ (isLastMessageFromUser || loadingLabel) && (jsx(TextShimmer, { duration: 1, spread: 5, className: S.loader, children: loadingLabel ?? 'Thinking...' }))] }) })), isEmpty ? (jsx("div", { className: S.fixedPresets, children: renderPresets('fixed', { variant }) })) : null, isEmpty ? (jsx("div", { className: S.notice, children: "Forecast Assistant can make mistakes." })) : null, jsx("div", { className: cn(S.footer, isClean && S.footerClean, footerClassName), children: jsx(Chat.Prompt, { className: isClean ? S.promptClean : undefined, onSubmit: handlePromptSubmitWithAttachments, disabled: promptDisabled, attachments: pendingAttachments, onRemoveAttachment: handleRemoveAttachment, prefillMessage: promptPrefill ?? undefined, placeholder: promptPlaceholder, slashCommandItems: slashCommandItems, onSlashItemCommand: onSlashItemCommand, attachmentAccept: attachmentsDropzoneEnabled ? attachmentAccept : undefined, onAttachmentFiles: attachmentsDropzoneEnabled ? handleAttachmentFiles : undefined }) })] })] })] }));
93
108
  }
94
109
 
95
110
  export { ChatChrome };
@@ -1,7 +1,7 @@
1
1
  import styleInject from 'style-inject';
2
2
 
3
- var css_248z = "@media (max-width:768px){:root{--page-x-padding:var(--p-6);--page-y-padding:var(--p-6)}}.ChatChrome_root__oh4Ay{border-radius:var(--p-4);display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden;position:relative}.ChatChrome_chatResizeHandle__epfiT{background-color:var(--page-color);border-radius:2.5px;height:calc(100vh + 200px);left:0;opacity:0;position:absolute;right:auto;top:-200px;touch-action:none;transition:opacity .15s ease-out;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:5px;z-index:30}.ChatChrome_chatResizeHandle__epfiT:before{left:0;right:auto}.ChatChrome_panelHeader__Hkfit{align-items:center;display:flex;flex-shrink:0;justify-content:flex-end;min-height:70px;padding:var(--p-2) var(--p-3);position:absolute;width:100%;z-index:100}.ChatChrome_panelClose__DbKxz{flex-shrink:0}.ChatChrome_content__5qFEi{display:flex;flex:1;flex-direction:column;min-height:0;position:relative}.ChatChrome_attachmentDropzone__OC8UI{inset:0;position:absolute;z-index:200}.ChatChrome_scrollWrapper__m4HMu{flex:1;min-height:0;position:relative}.ChatChrome_scroll__oCxoJ{align-items:flex-end;height:100%;max-height:100%;max-width:100%;padding-bottom:var(--p-2);position:absolute;width:100%;z-index:3}.ChatChrome_scrollbar__Hu0aG{right:0!important}.ChatChrome_scrollInner__K9hIy{min-height:100%;padding-top:var(--p-10)}.ChatChrome_emptyBody__f2NE8{display:flex;flex:1;flex-direction:column;min-height:0;overflow:hidden}.ChatChrome_emptyBody__f2NE8>*{flex:1;min-height:0;overflow:auto}.ChatChrome_footer__a5Bpp{backdrop-filter:blur(30px);background-color:var(--background-alpha-800);border-top:1px solid var(--border);box-shadow:0 8px 24px 0 var(--background);display:flex;flex-direction:column;flex-shrink:0;position:relative;width:100%;z-index:50}.ChatChrome_fixedPresets__bONhR{flex-shrink:0;position:relative;width:100%;z-index:10}.ChatChrome_notice__JACIw{color:var(--muted-foreground);font-size:var(--text-xs);left:0;margin-bottom:var(--p-1);pointer-events:none;position:absolute;right:0;text-align:center;top:calc(var(--p-7)*-1)}@media (max-width:768px){.ChatChrome_notice__JACIw{font-size:10px}}.ChatChrome_loader__9-lnf{color:var(--muted-foreground);margin:var(--p-2) var(--p-6) var(--p-10)}.ChatChrome_branchRow__NMDNv{display:flex;flex-wrap:wrap;gap:8px;margin-top:var(--p-6);padding:0 var(--p-6);width:100%}.ChatChrome_branchBtnWrap__aOSVP{display:inline-flex;vertical-align:middle}";
4
- var S = {"root":"ChatChrome_root__oh4Ay","chatResizeHandle":"ChatChrome_chatResizeHandle__epfiT","panelHeader":"ChatChrome_panelHeader__Hkfit","panelClose":"ChatChrome_panelClose__DbKxz","content":"ChatChrome_content__5qFEi","attachmentDropzone":"ChatChrome_attachmentDropzone__OC8UI","scrollWrapper":"ChatChrome_scrollWrapper__m4HMu","scroll":"ChatChrome_scroll__oCxoJ","scrollbar":"ChatChrome_scrollbar__Hu0aG","scrollInner":"ChatChrome_scrollInner__K9hIy","emptyBody":"ChatChrome_emptyBody__f2NE8","footer":"ChatChrome_footer__a5Bpp","fixedPresets":"ChatChrome_fixedPresets__bONhR","notice":"ChatChrome_notice__JACIw","loader":"ChatChrome_loader__9-lnf","branchRow":"ChatChrome_branchRow__NMDNv","branchBtnWrap":"ChatChrome_branchBtnWrap__aOSVP"};
3
+ var css_248z = "@media (max-width:768px){:root{--page-x-padding:var(--p-6);--page-y-padding:var(--p-6)}}.ChatChrome_root__oh4Ay{border-radius:var(--p-4);display:flex;flex-direction:column;height:100%;min-height:0;overflow:hidden;position:relative}.ChatChrome_rootClean__WXM91{border-radius:0}.ChatChrome_chatResizeHandle__epfiT{background-color:var(--page-color);border-radius:2.5px;height:calc(100vh + 200px);left:0;opacity:0;position:absolute;right:auto;top:-200px;touch-action:none;transition:opacity .15s ease-out;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:5px;z-index:30}.ChatChrome_chatResizeHandle__epfiT:before{left:0;right:auto}.ChatChrome_panelHeader__Hkfit{align-items:center;display:flex;flex-shrink:0;justify-content:flex-end;min-height:70px;padding:var(--p-2) var(--p-3);position:absolute;width:100%;z-index:100}.ChatChrome_panelClose__DbKxz{flex-shrink:0}.ChatChrome_content__5qFEi{display:flex;flex:1;flex-direction:column;min-height:0;position:relative}.ChatChrome_chatClean__hM9yS{background-color:transparent}.ChatChrome_attachmentDropzone__OC8UI{inset:0;position:absolute;z-index:200}.ChatChrome_scrollWrapper__m4HMu{flex:1;min-height:0;position:relative}.ChatChrome_scroll__oCxoJ{align-items:flex-end;height:100%;max-height:100%;max-width:100%;padding-bottom:var(--p-2);position:absolute;width:100%;z-index:3}.ChatChrome_scrollbar__Hu0aG{right:0!important}.ChatChrome_scrollInner__K9hIy{min-height:100%;padding-top:var(--p-10)}.ChatChrome_emptyBody__f2NE8{display:flex;flex:1;flex-direction:column;min-height:0;overflow:hidden}.ChatChrome_emptyBody__f2NE8>*{flex:1;min-height:0;overflow:auto}.ChatChrome_footer__a5Bpp{backdrop-filter:blur(30px);background-color:var(--background-alpha-800);border-top:1px solid var(--border);box-shadow:0 8px 24px 0 var(--background);display:flex;flex-direction:column;flex-shrink:0;position:relative;width:100%;z-index:50}.ChatChrome_footerClean__xRDdB{backdrop-filter:none;background-color:transparent;border-top:none;border:1px solid var(--border);border-radius:var(--p-4);box-shadow:none}.ChatChrome_promptClean__Hv43Z{background-color:var(--background);border-radius:inherit}.ChatChrome_fixedPresets__bONhR,.ChatChrome_notice__JACIw{flex-shrink:0;position:relative;width:100%;z-index:10}.ChatChrome_notice__JACIw{color:var(--muted-foreground);font-size:var(--text-xs);margin-bottom:var(--p-1);pointer-events:none;text-align:center}@media (max-width:768px){.ChatChrome_notice__JACIw{font-size:10px}}.ChatChrome_loader__9-lnf{color:var(--muted-foreground);margin:var(--p-2) var(--p-6) var(--p-10)}.ChatChrome_branchRow__NMDNv{display:flex;flex-wrap:wrap;gap:8px;margin-top:var(--p-6);padding:0 var(--p-6);width:100%}.ChatChrome_branchBtnWrap__aOSVP{display:inline-flex;vertical-align:middle}";
4
+ var S = {"root":"ChatChrome_root__oh4Ay","rootClean":"ChatChrome_rootClean__WXM91","chatResizeHandle":"ChatChrome_chatResizeHandle__epfiT","panelHeader":"ChatChrome_panelHeader__Hkfit","panelClose":"ChatChrome_panelClose__DbKxz","content":"ChatChrome_content__5qFEi","chatClean":"ChatChrome_chatClean__hM9yS","attachmentDropzone":"ChatChrome_attachmentDropzone__OC8UI","scrollWrapper":"ChatChrome_scrollWrapper__m4HMu","scroll":"ChatChrome_scroll__oCxoJ","scrollbar":"ChatChrome_scrollbar__Hu0aG","scrollInner":"ChatChrome_scrollInner__K9hIy","emptyBody":"ChatChrome_emptyBody__f2NE8","footer":"ChatChrome_footer__a5Bpp","footerClean":"ChatChrome_footerClean__xRDdB","promptClean":"ChatChrome_promptClean__Hv43Z","fixedPresets":"ChatChrome_fixedPresets__bONhR","notice":"ChatChrome_notice__JACIw","loader":"ChatChrome_loader__9-lnf","branchRow":"ChatChrome_branchRow__NMDNv","branchBtnWrap":"ChatChrome_branchBtnWrap__aOSVP"};
5
5
  styleInject(css_248z);
6
6
 
7
7
  export { S as default };
@@ -1,4 +1,5 @@
1
1
  import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import cn from 'classnames';
2
3
  import { useState, useMemo } from 'react';
3
4
  import { Button } from '../../Button/Button.js';
4
5
  import { InteractiveContent } from '../../InteractiveContent/InteractiveContent.js';
@@ -13,7 +14,7 @@ import S from './ChatMessage.styl.js';
13
14
  import { DocIcon } from './icons/DocIcon.js';
14
15
  import { XlsIcon } from './icons/XlsIcon.js';
15
16
 
16
- function AgentMessageContent({ text, onQuickReply, suppressedQuickReplyKeys, quickReplyDisabled, quickReplyHidden, isLastMessage = true, scriptContinue, onScriptContinue, renderMessageChart, }) {
17
+ function AgentMessageContent({ text, textClassName, onQuickReply, suppressedQuickReplyKeys, quickReplyDisabled, quickReplyHidden, isLastMessage = true, scriptContinue, onScriptContinue, renderMessageChart, }) {
17
18
  const [showRaw, setShowRaw] = useState(false);
18
19
  const parts = useMemo(() => {
19
20
  // Convert markdown tables to HTML first
@@ -125,7 +126,7 @@ function AgentMessageContent({ text, onQuickReply, suppressedQuickReplyKeys, qui
125
126
  isLastMessage,
126
127
  renderMessageChart,
127
128
  ]);
128
- return (jsxs("div", { className: S.text, children: [showRaw ? text : parts, !showRaw &&
129
+ return (jsxs("div", { className: cn(S.text, textClassName), children: [showRaw ? text : parts, !showRaw &&
129
130
  !quickReplyHidden &&
130
131
  isLastMessage &&
131
132
  scriptContinue &&
@@ -10,13 +10,13 @@ import { AgentMessageContent } from './AgentMessageContent.js';
10
10
  import S from './ChatMessage.styl.js';
11
11
  import { UserTextFileAttachmentBubble } from './UserTextFileAttachmentBubble.js';
12
12
 
13
- function ChatMessage({ role, text, inProgress, userTextFileAttachments, onQuickReply, suppressedQuickReplyKeys, quickReplyDisabled, quickReplyHidden, isLastMessage = true, scriptContinue, onScriptContinue, renderMessageChart, message, renderSystemMessage, }) {
13
+ function ChatMessage({ role, text, inProgress, userTextFileAttachments, onQuickReply, suppressedQuickReplyKeys, quickReplyDisabled, quickReplyHidden, isLastMessage = true, scriptContinue, onScriptContinue, renderMessageChart, message, renderSystemMessage, className, textClassName, }) {
14
14
  const fileAttachments = userTextFileAttachmentsFromMessage({
15
15
  userTextFileAttachments,
16
16
  });
17
17
  const isAssistant = role === MessageRole.ASSISTANT;
18
18
  const isSystem = role === MessageRole.SYSTEM;
19
- return (jsx("div", { className: cn(S.root, S[`role-${role}`]), children: isSystem ? (jsx("div", { className: S.text, children: inProgress ? (jsx(TextShimmer, { as: "span", children: text })) : renderSystemMessage && message ? (renderSystemMessage(message)) : (text) })) : isAssistant ? (jsx(AgentMessageContent, { text: text, onQuickReply: onQuickReply, suppressedQuickReplyKeys: suppressedQuickReplyKeys, quickReplyDisabled: quickReplyDisabled, quickReplyHidden: quickReplyHidden, isLastMessage: isLastMessage, scriptContinue: scriptContinue, onScriptContinue: onScriptContinue, renderMessageChart: renderMessageChart })) : (jsxs("div", { className: S.userColumn, children: [jsx("div", { className: S.text, children: jsx(InteractiveContent, { text: text }) }), fileAttachments.map(attachment => (jsx(UserTextFileAttachmentBubble, { attachment: attachment }, `${attachment.displayName}:${attachment.filename}`)))] })) }));
19
+ return (jsx("div", { className: cn(S.root, S[`role-${role}`], className), children: isSystem ? (jsx("div", { className: cn(S.text, textClassName), children: inProgress ? (jsx(TextShimmer, { as: "span", children: text })) : renderSystemMessage && message ? (renderSystemMessage(message)) : (text) })) : isAssistant ? (jsx(AgentMessageContent, { text: text, textClassName: textClassName, onQuickReply: onQuickReply, suppressedQuickReplyKeys: suppressedQuickReplyKeys, quickReplyDisabled: quickReplyDisabled, quickReplyHidden: quickReplyHidden, isLastMessage: isLastMessage, scriptContinue: scriptContinue, onScriptContinue: onScriptContinue, renderMessageChart: renderMessageChart })) : (jsxs("div", { className: S.userColumn, children: [jsx("div", { className: cn(S.text, textClassName && S.textCustom, textClassName), children: jsx(InteractiveContent, { text: text }) }), fileAttachments.map(attachment => (jsx(UserTextFileAttachmentBubble, { attachment: attachment }, `${attachment.displayName}:${attachment.filename}`)))] })) }));
20
20
  }
21
21
 
22
22
  export { ChatMessage };
@@ -1,7 +1,7 @@
1
1
  import styleInject from 'style-inject';
2
2
 
3
- var css_248z = ".ChatMessage_root__6rnsF{background:var(--bg-secondary);display:flex;flex-direction:column;gap:var(--p-1);padding:var(--p-4);padding-bottom:var(--p-1)}.ChatMessage_text__Y1XNR{color:var(--text-secondary);font-size:var(--text-sm);max-width:100%;min-width:0;overflow-wrap:anywhere;-webkit-user-select:text;-moz-user-select:text;user-select:text;width:-moz-fit-content;width:fit-content;word-break:break-word}.ChatMessage_role-assistant__wketE+.ChatMessage_role-assistant__wketE,.ChatMessage_role-system__g13OP+.ChatMessage_role-system__g13OP,.ChatMessage_role-user__u4JPV+.ChatMessage_role-user__u4JPV{padding-top:var(--p-1)}.ChatMessage_role-user__u4JPV{align-items:flex-end;max-width:100%;min-width:0}.ChatMessage_role-user__u4JPV .ChatMessage_userColumn__cQM6-{align-items:flex-end;display:flex;flex-direction:column;gap:var(--p-2);max-width:100%;min-width:0}.ChatMessage_role-user__u4JPV .ChatMessage_text__Y1XNR{background-color:var(--sb-slate-100);border-radius:var(--p-4);border-bottom-right-radius:0;box-sizing:border-box;overflow:hidden;padding:var(--p-3) var(--p-4);white-space:pre-wrap}.dark .ChatMessage_role-user__u4JPV .ChatMessage_text__Y1XNR{background-color:var(--sb-gray-900)}.ChatMessage_role-system__g13OP{align-items:center}.ChatMessage_role-system__g13OP .ChatMessage_text__Y1XNR{color:var(--muted-foreground);width:100%}.ChatMessage_role-assistant__wketE .ChatMessage_text__Y1XNR{width:100%}.ChatMessage_role-assistant__wketE h3{line-height:2.4}.ChatMessage_role-assistant__wketE h4{font-size:1.1em;font-weight:600;line-height:2.2}.ChatMessage_role-assistant__wketE .ChatMessage_bullet__6vAhq{display:inline-block;margin-left:4px;margin-right:6px}.ChatMessage_role-assistant__wketE .ChatMessage_bullet__6vAhq:before{color:var(--text-secondary);content:\"•\";display:inline-block}.ChatMessage_role-assistant__wketE .ChatMessage_scrollHorizontal__Rms9n{max-width:100%}.ChatMessage_role-assistant__wketE table{border:1px solid var(--border);border-collapse:collapse;border-radius:var(--p-2);border-spacing:0;margin:var(--p-4) 0;overflow:hidden}.ChatMessage_role-assistant__wketE table td,.ChatMessage_role-assistant__wketE table th{border:1px solid var(--border);min-width:100px;padding:var(--p-1)}.ChatMessage_role-assistant__wketE table th{text-align:left}.ChatMessage_role-assistant__wketE ol,.ChatMessage_role-assistant__wketE ul{padding-left:var(--p-4)}.ChatMessage_role-assistant__wketE ul{list-style-type:disc}.ChatMessage_role-assistant__wketE ol{list-style-type:decimal}.ChatMessage_role-assistant__wketE .ChatMessage_datasetAppLink__Pxy-T{align-items:center;border:1px dashed var(--sb-slate-300);border-radius:8px;color:var(--foreground);display:inline-flex;font-size:var(--text-xs);gap:6px;margin:1px;max-width:100%;padding:2px 6px 2px 4px;text-decoration:none;vertical-align:middle}.ChatMessage_role-assistant__wketE .ChatMessage_datasetAppLink__Pxy-T:hover{background-color:var(--sb-slate-50);border-color:var(--sb-slate-400);border-style:solid}.dark .ChatMessage_role-assistant__wketE .ChatMessage_datasetAppLink__Pxy-T{border-color:var(--sb-gray-600)}.dark .ChatMessage_role-assistant__wketE .ChatMessage_datasetAppLink__Pxy-T:hover{background-color:var(--sb-gray-900)}.ChatMessage_role-assistant__wketE .ChatMessage_datasetAppLinkLabel__PMU7e{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ChatMessage_role-assistant__wketE .ChatMessage_quickReplyWrap__1UFyD{display:inline-block;margin:var(--p-1) var(--p-1) var(--p-1) 0;vertical-align:middle;width:100%}.ChatMessage_role-assistant__wketE .ChatMessage_downloadButtons__RygM-{display:flex;gap:var(--p-2);margin-top:var(--p-4)}.ChatMessage_role-assistant__wketE .ChatMessage_downloadCard__NsNRa{align-items:center;background-color:var(--background);border-radius:var(--p-3);box-shadow:0 0 0 1px var(--border);cursor:pointer;display:flex;gap:var(--p-4);margin-top:var(--p-3);padding:var(--p-3);padding-right:var(--p-4);transition:all .15s;width:-moz-fit-content;width:fit-content}.ChatMessage_role-assistant__wketE .ChatMessage_downloadCard__NsNRa:hover{background-color:var(--sb-gray-50);border-color:var(--border)}.dark .ChatMessage_role-assistant__wketE .ChatMessage_downloadCard__NsNRa{background-color:var(--sb-gray-900);border-color:var(--border)}.dark .ChatMessage_role-assistant__wketE .ChatMessage_downloadCard__NsNRa:hover{background-color:var(--sb-gray-800)}.ChatMessage_role-assistant__wketE .ChatMessage_downloadCardIcon__jkxDJ{align-items:center;border-radius:var(--p-2);display:flex;flex-shrink:0;height:32px;justify-content:center;width:32px}.ChatMessage_role-assistant__wketE .ChatMessage_downloadCardContent__PTPwz{display:flex;flex:1;flex-direction:column;min-width:0}.ChatMessage_role-assistant__wketE .ChatMessage_downloadCardTitle__K1wqr{font-size:var(--text-base);font-weight:600;line-height:1.4}.ChatMessage_role-assistant__wketE .ChatMessage_downloadCardSubtitle__fVeF2{color:var(--muted-foreground);font-size:var(--text-sm);line-height:1.4}";
4
- var S = {"root":"ChatMessage_root__6rnsF","text":"ChatMessage_text__Y1XNR","role-user":"ChatMessage_role-user__u4JPV","role-assistant":"ChatMessage_role-assistant__wketE","role-system":"ChatMessage_role-system__g13OP","userColumn":"ChatMessage_userColumn__cQM6-","bullet":"ChatMessage_bullet__6vAhq","scrollHorizontal":"ChatMessage_scrollHorizontal__Rms9n","datasetAppLink":"ChatMessage_datasetAppLink__Pxy-T","datasetAppLinkLabel":"ChatMessage_datasetAppLinkLabel__PMU7e","quickReplyWrap":"ChatMessage_quickReplyWrap__1UFyD","downloadButtons":"ChatMessage_downloadButtons__RygM-","downloadCard":"ChatMessage_downloadCard__NsNRa","downloadCardIcon":"ChatMessage_downloadCardIcon__jkxDJ","downloadCardContent":"ChatMessage_downloadCardContent__PTPwz","downloadCardTitle":"ChatMessage_downloadCardTitle__K1wqr","downloadCardSubtitle":"ChatMessage_downloadCardSubtitle__fVeF2"};
3
+ var css_248z = ".ChatMessage_root__6rnsF{background:var(--bg-secondary);display:flex;flex-direction:column;gap:var(--p-1);padding:var(--p-4);padding-bottom:var(--p-1)}.ChatMessage_text__Y1XNR{color:var(--text-secondary);font-size:var(--text-sm);max-width:100%;min-width:0;overflow-wrap:anywhere;-webkit-user-select:text;-moz-user-select:text;user-select:text;width:-moz-fit-content;width:fit-content;word-break:break-word}.ChatMessage_role-assistant__wketE+.ChatMessage_role-assistant__wketE,.ChatMessage_role-system__g13OP+.ChatMessage_role-system__g13OP,.ChatMessage_role-user__u4JPV+.ChatMessage_role-user__u4JPV{padding-top:var(--p-1)}.ChatMessage_role-user__u4JPV{align-items:flex-end;max-width:100%;min-width:0}.ChatMessage_role-user__u4JPV .ChatMessage_userColumn__cQM6-{align-items:flex-end;display:flex;flex-direction:column;gap:var(--p-2);max-width:100%;min-width:0}.ChatMessage_role-user__u4JPV .ChatMessage_text__Y1XNR{border-radius:var(--p-4);border-bottom-right-radius:0;box-sizing:border-box;overflow:hidden;padding:var(--p-3) var(--p-4);white-space:pre-wrap}.ChatMessage_role-user__u4JPV .ChatMessage_text__Y1XNR:not(.ChatMessage_textCustom__C8Tts){background-color:var(--sb-slate-100)}.dark .ChatMessage_role-user__u4JPV .ChatMessage_text__Y1XNR:not(.ChatMessage_textCustom__C8Tts){background-color:var(--sb-gray-900)}.ChatMessage_role-system__g13OP{align-items:center}.ChatMessage_role-system__g13OP .ChatMessage_text__Y1XNR{color:var(--muted-foreground);width:100%}.ChatMessage_role-assistant__wketE .ChatMessage_text__Y1XNR{width:100%}.ChatMessage_role-assistant__wketE h3{line-height:2.4}.ChatMessage_role-assistant__wketE h4{font-size:1.1em;font-weight:600;line-height:2.2}.ChatMessage_role-assistant__wketE .ChatMessage_bullet__6vAhq{display:inline-block;margin-left:4px;margin-right:6px}.ChatMessage_role-assistant__wketE .ChatMessage_bullet__6vAhq:before{color:var(--text-secondary);content:\"•\";display:inline-block}.ChatMessage_role-assistant__wketE .ChatMessage_scrollHorizontal__Rms9n{max-width:100%}.ChatMessage_role-assistant__wketE table{border:1px solid var(--border);border-collapse:collapse;border-radius:var(--p-2);border-spacing:0;margin:var(--p-4) 0;overflow:hidden}.ChatMessage_role-assistant__wketE table td,.ChatMessage_role-assistant__wketE table th{border:1px solid var(--border);min-width:100px;padding:var(--p-1)}.ChatMessage_role-assistant__wketE table th{text-align:left}.ChatMessage_role-assistant__wketE ol,.ChatMessage_role-assistant__wketE ul{padding-left:var(--p-4)}.ChatMessage_role-assistant__wketE ul{list-style-type:disc}.ChatMessage_role-assistant__wketE ol{list-style-type:decimal}.ChatMessage_role-assistant__wketE .ChatMessage_datasetAppLink__Pxy-T{align-items:center;border:1px dashed var(--sb-slate-300);border-radius:8px;color:var(--foreground);display:inline-flex;font-size:var(--text-xs);gap:6px;margin:1px;max-width:100%;padding:2px 6px 2px 4px;text-decoration:none;vertical-align:middle}.ChatMessage_role-assistant__wketE .ChatMessage_datasetAppLink__Pxy-T:hover{background-color:var(--sb-slate-50);border-color:var(--sb-slate-400);border-style:solid}.dark .ChatMessage_role-assistant__wketE .ChatMessage_datasetAppLink__Pxy-T{border-color:var(--sb-gray-600)}.dark .ChatMessage_role-assistant__wketE .ChatMessage_datasetAppLink__Pxy-T:hover{background-color:var(--sb-gray-900)}.ChatMessage_role-assistant__wketE .ChatMessage_datasetAppLinkLabel__PMU7e{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ChatMessage_role-assistant__wketE .ChatMessage_quickReplyWrap__1UFyD{display:inline-block;margin:var(--p-1) var(--p-1) var(--p-1) 0;vertical-align:middle;width:100%}.ChatMessage_role-assistant__wketE .ChatMessage_downloadButtons__RygM-{display:flex;gap:var(--p-2);margin-top:var(--p-4)}.ChatMessage_role-assistant__wketE .ChatMessage_downloadCard__NsNRa{align-items:center;background-color:var(--background);border-radius:var(--p-3);box-shadow:0 0 0 1px var(--border);cursor:pointer;display:flex;gap:var(--p-4);margin-top:var(--p-3);padding:var(--p-3);padding-right:var(--p-4);transition:all .15s;width:-moz-fit-content;width:fit-content}.ChatMessage_role-assistant__wketE .ChatMessage_downloadCard__NsNRa:hover{background-color:var(--sb-gray-50);border-color:var(--border)}.dark .ChatMessage_role-assistant__wketE .ChatMessage_downloadCard__NsNRa{background-color:var(--sb-gray-900);border-color:var(--border)}.dark .ChatMessage_role-assistant__wketE .ChatMessage_downloadCard__NsNRa:hover{background-color:var(--sb-gray-800)}.ChatMessage_role-assistant__wketE .ChatMessage_downloadCardIcon__jkxDJ{align-items:center;border-radius:var(--p-2);display:flex;flex-shrink:0;height:32px;justify-content:center;width:32px}.ChatMessage_role-assistant__wketE .ChatMessage_downloadCardContent__PTPwz{display:flex;flex:1;flex-direction:column;min-width:0}.ChatMessage_role-assistant__wketE .ChatMessage_downloadCardTitle__K1wqr{font-size:var(--text-base);font-weight:600;line-height:1.4}.ChatMessage_role-assistant__wketE .ChatMessage_downloadCardSubtitle__fVeF2{color:var(--muted-foreground);font-size:var(--text-sm);line-height:1.4}";
4
+ var S = {"root":"ChatMessage_root__6rnsF","text":"ChatMessage_text__Y1XNR","role-user":"ChatMessage_role-user__u4JPV","role-assistant":"ChatMessage_role-assistant__wketE","role-system":"ChatMessage_role-system__g13OP","userColumn":"ChatMessage_userColumn__cQM6-","textCustom":"ChatMessage_textCustom__C8Tts","bullet":"ChatMessage_bullet__6vAhq","scrollHorizontal":"ChatMessage_scrollHorizontal__Rms9n","datasetAppLink":"ChatMessage_datasetAppLink__Pxy-T","datasetAppLinkLabel":"ChatMessage_datasetAppLinkLabel__PMU7e","quickReplyWrap":"ChatMessage_quickReplyWrap__1UFyD","downloadButtons":"ChatMessage_downloadButtons__RygM-","downloadCard":"ChatMessage_downloadCard__NsNRa","downloadCardIcon":"ChatMessage_downloadCardIcon__jkxDJ","downloadCardContent":"ChatMessage_downloadCardContent__PTPwz","downloadCardTitle":"ChatMessage_downloadCardTitle__K1wqr","downloadCardSubtitle":"ChatMessage_downloadCardSubtitle__fVeF2"};
5
5
  styleInject(css_248z);
6
6
 
7
7
  export { S as default };
@@ -4,7 +4,7 @@ import { useState, useEffect } from 'react';
4
4
  import { Button } from '../../Button/Button.js';
5
5
  import S from './ChatPresets.styl.js';
6
6
 
7
- function ChatPresets({ chatId, items, usedItemIds = [], layout = 'fixed', onSelect, onItemUsed, }) {
7
+ function ChatPresets({ chatId, items, usedItemIds = [], layout = 'fixed', variant = 'default', onSelect, onItemUsed, }) {
8
8
  const [localUsedItems, setLocalUsedItems] = useState([]);
9
9
  useEffect(() => {
10
10
  setLocalUsedItems([]);
@@ -13,7 +13,7 @@ function ChatPresets({ chatId, items, usedItemIds = [], layout = 'fixed', onSele
13
13
  const availableItems = items.filter(item => !usedItems.includes(item.id));
14
14
  if (availableItems.length === 0)
15
15
  return null;
16
- return (jsx("div", { className: layout === 'inline' ? S.inlineRoot : S.root, children: jsx("div", { className: cn(S.inner, layout === 'inline' && S.innerInline), children: availableItems.map(preset => (jsx(Button, { type: "button", variant: "outline", size: "sm", className: cn(S.item), onClick: () => {
16
+ return (jsx("div", { className: layout === 'inline' ? S.inlineRoot : S.root, children: jsx("div", { className: cn(S.inner, layout === 'inline' && S.innerInline, variant === 'clean' && S.innerClean), children: availableItems.map(preset => (jsx(Button, { type: "button", variant: "outline", size: "sm", className: cn(S.item), onClick: () => {
17
17
  onSelect?.(preset);
18
18
  onItemUsed?.(preset.id);
19
19
  setLocalUsedItems(prev => [...prev, preset.id]);
@@ -1,7 +1,7 @@
1
1
  import styleInject from 'style-inject';
2
2
 
3
- var css_248z = ".ChatPresets_root__Cj42o{flex-shrink:0;position:relative;width:100%}.ChatPresets_inlineRoot__WXVnu{margin-top:var(--p-6);position:relative;width:100%}.ChatPresets_inner__h14-q{background-color:var(--background);display:flex;flex-wrap:wrap;gap:8px;min-width:0;padding:var(--p-2) var(--p-6) var(--p-3)}.ChatPresets_innerInline__iPM2b{background-color:transparent}.ChatPresets_item__LfX5b{flex:0 1 auto;font-size:var(--text-xs);height:auto;line-height:1.4;max-width:min(300px,100%);min-height:auto;min-width:0;overflow-wrap:anywhere;padding:var(--p-3);text-align:left;white-space:break-spaces!important}";
4
- var S = {"root":"ChatPresets_root__Cj42o","inlineRoot":"ChatPresets_inlineRoot__WXVnu","inner":"ChatPresets_inner__h14-q","innerInline":"ChatPresets_innerInline__iPM2b","item":"ChatPresets_item__LfX5b"};
3
+ var css_248z = ".ChatPresets_root__Cj42o{flex-shrink:0;position:relative;width:100%}.ChatPresets_inlineRoot__WXVnu{margin-top:var(--p-6);position:relative;width:100%}.ChatPresets_inner__h14-q{background-color:var(--background);display:flex;flex-wrap:wrap;gap:8px;min-width:0;padding:var(--p-2) var(--p-6) var(--p-3)}.ChatPresets_innerClean__U-sL0,.ChatPresets_innerInline__iPM2b{background-color:transparent}.ChatPresets_item__LfX5b{flex:0 1 auto;font-size:var(--text-xs);height:auto;line-height:1.4;max-width:min(300px,100%);min-height:auto;min-width:0;overflow-wrap:anywhere;padding:var(--p-3);text-align:left;white-space:break-spaces!important}";
4
+ var S = {"root":"ChatPresets_root__Cj42o","inlineRoot":"ChatPresets_inlineRoot__WXVnu","inner":"ChatPresets_inner__h14-q","innerInline":"ChatPresets_innerInline__iPM2b","innerClean":"ChatPresets_innerClean__U-sL0","item":"ChatPresets_item__LfX5b"};
5
5
  styleInject(css_248z);
6
6
 
7
7
  export { S as default };
@@ -813,10 +813,10 @@ function useChatPanelChromeModel({ embedAsPage, presets, scopeId, onMessage, onS
813
813
  sidebarWidthPx,
814
814
  chatWidthPx,
815
815
  ]);
816
- const renderPresets = (layout = 'fixed') => {
816
+ const renderPresets = (layout = 'fixed', options) => {
817
817
  if (!presetsWithFreeform?.length)
818
818
  return null;
819
- return (jsx(Chat.Presets, { chatId: currentChatId ?? '', items: presetsWithFreeform, layout: layout, usedItemIds: usedPresetIds, onSelect: preset => {
819
+ return (jsx(Chat.Presets, { chatId: currentChatId ?? '', items: presetsWithFreeform, layout: layout, variant: options?.variant, usedItemIds: usedPresetIds, onSelect: preset => {
820
820
  void submitPreset(preset);
821
821
  } }));
822
822
  };
@@ -97,9 +97,23 @@ export interface ChatPromptProps {
97
97
  /** Custom slash pick handler; return true to skip default mention insert and insert via composer API. */
98
98
  onSlashItemCommand?: SlashOnItemCommand;
99
99
  }
100
+ export type ChatMessageClassNames = {
101
+ user?: string;
102
+ assistant?: string;
103
+ system?: string;
104
+ };
105
+ export type ChatMessageTextClassNames = {
106
+ user?: string;
107
+ assistant?: string;
108
+ system?: string;
109
+ };
100
110
  export interface ChatMessageProps {
101
111
  role: MessageRole;
102
112
  text: string;
113
+ /** Extra class on the message root wrapper (role layout + defaults still apply). */
114
+ className?: string;
115
+ /** Extra class on the inner text bubble (merged with built-in `.text` styles). */
116
+ textClassName?: string;
103
117
  inProgress?: boolean;
104
118
  userTextFileAttachments?: UserTextFileAttachment[];
105
119
  onQuickReply?: (branchKey: string, displayLabel: string) => void;
@@ -1,2 +1,2 @@
1
1
  import type { ChatChromeProps } from './ChatChrome.types';
2
- export declare function ChatChrome({ showResizeHandle, resizeHandle, onClose, isEmpty, renderPresets, messages, onQuickReply, suppressedQuickReplyKeys, isLoading, loadingLabel, scriptContinueLabel, onScriptContinue, renderMessageChart, renderSystemMessage, showSyntheticBranchButtons, unusedBranchKeys, showInlinePresets, isLastMessageFromUser, scrollRef, effectiveScopeId, onPromptSubmit, onChatDeleted, onNewChat, promptPrefill, footerClassName, emptyState, allowedAttachments, allowPdfAttachments, onAttachmentsDropped, slashCommandItems, onSlashItemCommand, promptPlaceholder, hideChatSelector, }: ChatChromeProps): import("react/jsx-runtime").JSX.Element;
2
+ export declare function ChatChrome({ variant, showResizeHandle, resizeHandle, onClose, isEmpty, renderPresets, messages, onQuickReply, suppressedQuickReplyKeys, isLoading, loadingLabel, scriptContinueLabel, onScriptContinue, renderMessageChart, renderSystemMessage, showSyntheticBranchButtons, unusedBranchKeys, showInlinePresets, isLastMessageFromUser, scrollRef, effectiveScopeId, onPromptSubmit, onChatDeleted, onNewChat, promptPrefill, footerClassName, messageClassNames, messageTextClassNames, emptyState, allowedAttachments, allowPdfAttachments, onAttachmentsDropped, slashCommandItems, onSlashItemCommand, promptPlaceholder, hideChatSelector, }: ChatChromeProps): import("react/jsx-runtime").JSX.Element;
@@ -1,5 +1,5 @@
1
1
  import type { RefObject } from 'react';
2
- import type { ChatAttachmentDropItem, Message } from '#uilib/components/ui/Chat/Chat.types';
2
+ import type { ChatAttachmentDropItem, ChatMessageClassNames, ChatMessageTextClassNames, Message } from '#uilib/components/ui/Chat/Chat.types';
3
3
  import type { ChatEmptyStateProps } from '#uilib/components/ui/Chat/ChatEmptyState/ChatEmptyState.types';
4
4
  import type { ChatPresetsLayout } from '#uilib/components/ui/Chat/ChatPresets';
5
5
  import type { SlashCommandItem, SlashOnItemCommand } from '#uilib/tiptap/slash-mention/types';
@@ -12,12 +12,17 @@ export type ChatChromeResizeHandleConfig = {
12
12
  onDragComplete: (finalRawPx: number) => void;
13
13
  };
14
14
  export type { ChatAttachmentDropItem };
15
+ export type ChatChromeVariant = 'default' | 'clean';
16
+ export type ChatPresetsRenderOptions = {
17
+ variant?: ChatChromeVariant;
18
+ };
15
19
  export interface ChatChromeProps {
20
+ variant?: ChatChromeVariant;
16
21
  showResizeHandle: boolean;
17
22
  resizeHandle: ChatChromeResizeHandleConfig | undefined;
18
23
  onClose: (() => void) | undefined;
19
24
  isEmpty: boolean;
20
- renderPresets: (layout: ChatPresetsLayout) => React.ReactNode;
25
+ renderPresets: (layout: ChatPresetsLayout, options?: ChatPresetsRenderOptions) => React.ReactNode;
21
26
  /** Message list for the scroll area; use `[]` when empty. */
22
27
  messages: Message[];
23
28
  onQuickReply: (branchKey: string, displayLabel: string) => void;
@@ -43,6 +48,10 @@ export interface ChatChromeProps {
43
48
  /** `?prompt=` deep link text for one-shot composer pre-fill. */
44
49
  promptPrefill?: string | null;
45
50
  footerClassName?: string;
51
+ /** Per-role extra classes on message root wrappers (merged with built-in role styles). */
52
+ messageClassNames?: ChatMessageClassNames;
53
+ /** Per-role extra classes on inner text bubbles (merged with built-in `.text` styles). */
54
+ messageTextClassNames?: ChatMessageTextClassNames;
46
55
  emptyState?: ChatEmptyStateProps;
47
56
  /** MIME types / extensions (filtered to text-only allowlist). Enables dropzone when non-empty. */
48
57
  allowedAttachments?: readonly string[];
@@ -1,2 +1,2 @@
1
1
  export { ChatChrome } from './ChatChrome';
2
- export type { ChatAttachmentDropItem, ChatChromeProps, ChatChromeResizeHandleConfig, } from './ChatChrome.types';
2
+ export type { ChatAttachmentDropItem, ChatChromeProps, ChatChromeResizeHandleConfig, ChatChromeVariant, } from './ChatChrome.types';
@@ -1,6 +1,7 @@
1
1
  import { type ReactNode } from 'react';
2
- export declare function AgentMessageContent({ text, onQuickReply, suppressedQuickReplyKeys, quickReplyDisabled, quickReplyHidden, isLastMessage, scriptContinue, onScriptContinue, renderMessageChart, }: {
2
+ export declare function AgentMessageContent({ text, textClassName, onQuickReply, suppressedQuickReplyKeys, quickReplyDisabled, quickReplyHidden, isLastMessage, scriptContinue, onScriptContinue, renderMessageChart, }: {
3
3
  text: string;
4
+ textClassName?: string;
4
5
  onQuickReply?: (branchKey: string, displayLabel: string) => void;
5
6
  suppressedQuickReplyKeys?: ReadonlySet<string>;
6
7
  quickReplyDisabled?: boolean;
@@ -1,2 +1,2 @@
1
1
  import { type ChatMessageProps } from '../Chat.types';
2
- export declare function ChatMessage({ role, text, inProgress, userTextFileAttachments, onQuickReply, suppressedQuickReplyKeys, quickReplyDisabled, quickReplyHidden, isLastMessage, scriptContinue, onScriptContinue, renderMessageChart, message, renderSystemMessage, }: ChatMessageProps): import("react/jsx-runtime").JSX.Element;
2
+ export declare function ChatMessage({ role, text, inProgress, userTextFileAttachments, onQuickReply, suppressedQuickReplyKeys, quickReplyDisabled, quickReplyHidden, isLastMessage, scriptContinue, onScriptContinue, renderMessageChart, message, renderSystemMessage, className, textClassName, }: ChatMessageProps): import("react/jsx-runtime").JSX.Element;
@@ -1,3 +1,4 @@
1
+ import type { ChatChromeVariant } from '../ChatChrome/ChatChrome.types';
1
2
  import type { ChatPreset } from '../Chat.types';
2
3
  export type ChatPresetsLayout = 'fixed' | 'inline';
3
4
  export interface ChatPresetsProps {
@@ -5,7 +6,8 @@ export interface ChatPresetsProps {
5
6
  items: ChatPreset[];
6
7
  usedItemIds?: string[];
7
8
  layout?: ChatPresetsLayout;
9
+ variant?: ChatChromeVariant;
8
10
  onSelect?: (preset: ChatPreset) => void;
9
11
  onItemUsed?: (id: string) => void;
10
12
  }
11
- export declare function ChatPresets({ chatId, items, usedItemIds, layout, onSelect, onItemUsed, }: ChatPresetsProps): import("react/jsx-runtime").JSX.Element;
13
+ export declare function ChatPresets({ chatId, items, usedItemIds, layout, variant, onSelect, onItemUsed, }: ChatPresetsProps): import("react/jsx-runtime").JSX.Element;
@@ -1,7 +1,7 @@
1
1
  export { Chat } from './Chat';
2
2
  export { formatChatTranscript, usedPresetIdsFromMessages, } from './chat-preset-utils';
3
3
  export { ChatChrome } from './ChatChrome';
4
- export type { ChatChromeProps, ChatChromeResizeHandleConfig, } from './ChatChrome';
4
+ export type { ChatChromeProps, ChatChromeResizeHandleConfig, ChatChromeVariant, } from './ChatChrome';
5
5
  export { TEXT_ATTACHMENT_ACCEPT_PARTS, filterToTextAttachments, } from './chatAttachmentAccept';
6
6
  export { buildChatSendMessagePayload, displayTextFromSendPayload, normalizeUserTextFileAttachments, } from './buildChatSendMessagePayload';
7
7
  export { sanitizeAttachmentFilename } from './sanitizeAttachmentFilename';
@@ -18,7 +18,7 @@ export { CHAT_PROMPT_COMMAND_CHIP_CLASS, chatPromptChipHtml, createChatPromptCom
18
18
  export type { ChatPromptComposerInsertOptions } from './ChatPrompt/ChatPromptComposer.types';
19
19
  export { ChatPresets } from './ChatPresets';
20
20
  export type { ChatEmptyStateConfig, ChatEmptyStateContext, ChatEmptyStateProps, } from './ChatEmptyState/ChatEmptyState.types';
21
- export type { Chat as ChatType, ChatAttachmentDropItem, ChatMeta, ChatMetaValue, ChatSendMessagePayload, ChatProps, ChatPreset as ChatPresetType, Message, UserTextFileAttachment, } from './Chat.types';
21
+ export type { Chat as ChatType, ChatAttachmentDropItem, ChatMessageClassNames, ChatMessageTextClassNames, ChatMeta, ChatMetaValue, ChatSendMessagePayload, ChatMessageProps, ChatProps, ChatPreset as ChatPresetType, Message, UserTextFileAttachment, } from './Chat.types';
22
22
  export { MessageRole } from './Chat.types';
23
23
  export type { SlashCommandItem, SlashItemCommandContext, SlashOnItemCommand, } from '#uilib/tiptap/slash-mention/types';
24
24
  export { CsvIcon } from '../../icons/CsvIcon/CsvIcon';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sybilion/uilib",
3
- "version": "1.3.81",
3
+ "version": "1.3.83",
4
4
  "description": "Sybilion Design System — React UI components (Webpack + Stylus)",
5
5
  "publishConfig": {
6
6
  "access": "public",
@@ -114,9 +114,25 @@ export interface ChatPromptProps {
114
114
  onSlashItemCommand?: SlashOnItemCommand;
115
115
  }
116
116
 
117
+ export type ChatMessageClassNames = {
118
+ user?: string;
119
+ assistant?: string;
120
+ system?: string;
121
+ };
122
+
123
+ export type ChatMessageTextClassNames = {
124
+ user?: string;
125
+ assistant?: string;
126
+ system?: string;
127
+ };
128
+
117
129
  export interface ChatMessageProps {
118
130
  role: MessageRole;
119
131
  text: string;
132
+ /** Extra class on the message root wrapper (role layout + defaults still apply). */
133
+ className?: string;
134
+ /** Extra class on the inner text bubble (merged with built-in `.text` styles). */
135
+ textClassName?: string;
120
136
  inProgress?: boolean;
121
137
  userTextFileAttachments?: UserTextFileAttachment[];
122
138
  onQuickReply?: (branchKey: string, displayLabel: string) => void;
@@ -9,6 +9,9 @@
9
9
  overflow hidden
10
10
  border-radius var(--p-4)
11
11
 
12
+ .rootClean
13
+ border-radius 0
14
+
12
15
  .chatResizeHandle
13
16
  position: absolute;
14
17
  // top 0 !important
@@ -57,6 +60,9 @@
57
60
  flex-direction column
58
61
  position relative
59
62
 
63
+ .chatClean
64
+ background-color transparent
65
+
60
66
  .attachmentDropzone
61
67
  position absolute
62
68
  inset 0
@@ -111,6 +117,18 @@
111
117
  border-top 1px solid var(--border)
112
118
  box-shadow 0 8px 24px 0 var(--background)
113
119
 
120
+ .footerClean
121
+ backdrop-filter none
122
+ background-color transparent
123
+ border-top none
124
+ box-shadow none
125
+ border 1px solid var(--border)
126
+ border-radius var(--p-4)
127
+
128
+ .promptClean
129
+ background-color var(--background)
130
+ border-radius inherit
131
+
114
132
  .fixedPresets
115
133
  position relative
116
134
  z-index 10
@@ -118,10 +136,10 @@
118
136
  width 100%
119
137
 
120
138
  .notice
121
- position absolute
122
- top calc(-1 * var(--p-7))
123
- left 0
124
- right 0
139
+ position relative
140
+ z-index 10
141
+ flex-shrink 0
142
+ width 100%
125
143
  margin-bottom var(--p-1)
126
144
 
127
145
  font-size var(--text-xs)
@@ -4,16 +4,20 @@ interface CssExports {
4
4
  'attachmentDropzone': string;
5
5
  'branchBtnWrap': string;
6
6
  'branchRow': string;
7
+ 'chatClean': string;
7
8
  'chatResizeHandle': string;
8
9
  'content': string;
9
10
  'emptyBody': string;
10
11
  'fixedPresets': string;
11
12
  'footer': string;
13
+ 'footerClean': string;
12
14
  'loader': string;
13
15
  'notice': string;
14
16
  'panelClose': string;
15
17
  'panelHeader': string;
18
+ 'promptClean': string;
16
19
  'root': string;
20
+ 'rootClean': string;
17
21
  'scroll': string;
18
22
  'scrollInner': string;
19
23
  'scrollWrapper': string;
@@ -25,6 +25,7 @@ import S from './ChatChrome.styl';
25
25
  import type { ChatChromeProps } from './ChatChrome.types';
26
26
 
27
27
  export function ChatChrome({
28
+ variant = 'default',
28
29
  showResizeHandle,
29
30
  resizeHandle,
30
31
  onClose,
@@ -50,6 +51,8 @@ export function ChatChrome({
50
51
  onNewChat,
51
52
  promptPrefill,
52
53
  footerClassName,
54
+ messageClassNames,
55
+ messageTextClassNames,
53
56
  emptyState,
54
57
  allowedAttachments,
55
58
  allowPdfAttachments = false,
@@ -150,8 +153,10 @@ export function ChatChrome({
150
153
  showSyntheticBranchButtons,
151
154
  ]);
152
155
 
156
+ const isClean = variant === 'clean';
157
+
153
158
  return (
154
- <div className={S.root}>
159
+ <div className={cn(S.root, isClean && S.rootClean)}>
155
160
  {showResizeHandle && resizeHandle ? (
156
161
  <PanelResizeHandle
157
162
  edge="leading"
@@ -191,6 +196,7 @@ export function ChatChrome({
191
196
  />
192
197
  ) : null}
193
198
  <Chat
199
+ className={isClean ? S.chatClean : undefined}
194
200
  isEmpty={isEmpty}
195
201
  scopeId={effectiveScopeId}
196
202
  onChatDeleted={onChatDeleted}
@@ -215,10 +221,27 @@ export function ChatChrome({
215
221
  >
216
222
  {messages.map((msg, index, arr) => {
217
223
  const isLast = index === arr.length - 1;
224
+ const messageClassName = messageClassNames
225
+ ? {
226
+ [MessageRole.USER]: messageClassNames.user,
227
+ [MessageRole.ASSISTANT]: messageClassNames.assistant,
228
+ [MessageRole.SYSTEM]: messageClassNames.system,
229
+ }[msg.role]
230
+ : undefined;
231
+ const messageTextClassName = messageTextClassNames
232
+ ? {
233
+ [MessageRole.USER]: messageTextClassNames.user,
234
+ [MessageRole.ASSISTANT]:
235
+ messageTextClassNames.assistant,
236
+ [MessageRole.SYSTEM]: messageTextClassNames.system,
237
+ }[msg.role]
238
+ : undefined;
218
239
  return (
219
240
  <Chat.Message
220
241
  key={msg.id}
221
242
  message={msg}
243
+ className={messageClassName}
244
+ textClassName={messageTextClassName}
222
245
  role={msg.role}
223
246
  text={msg.text}
224
247
  inProgress={msg.inProgress}
@@ -268,7 +291,7 @@ export function ChatChrome({
268
291
  </div>
269
292
  ) : null}
270
293
 
271
- {showInlinePresets && renderPresets('inline')}
294
+ {showInlinePresets && renderPresets('inline', { variant })}
272
295
 
273
296
  {isLoading &&
274
297
  !hasInProgressSystemMessage &&
@@ -282,16 +305,22 @@ export function ChatChrome({
282
305
  )}
283
306
 
284
307
  {isEmpty ? (
285
- <div className={S.fixedPresets}>{renderPresets('fixed')}</div>
308
+ <div className={S.fixedPresets}>
309
+ {renderPresets('fixed', { variant })}
310
+ </div>
286
311
  ) : null}
287
312
 
288
- <div className={cn(S.footer, footerClassName)}>
289
- {isEmpty ? (
290
- <div className={S.notice}>
291
- Forecast Assistant can make mistakes.
292
- </div>
293
- ) : null}
313
+ {isEmpty ? (
314
+ <div className={S.notice}>
315
+ Forecast Assistant can make mistakes.
316
+ </div>
317
+ ) : null}
318
+
319
+ <div
320
+ className={cn(S.footer, isClean && S.footerClean, footerClassName)}
321
+ >
294
322
  <Chat.Prompt
323
+ className={isClean ? S.promptClean : undefined}
295
324
  onSubmit={handlePromptSubmitWithAttachments}
296
325
  disabled={promptDisabled}
297
326
  attachments={pendingAttachments}
@@ -2,6 +2,8 @@ import type { RefObject } from 'react';
2
2
 
3
3
  import type {
4
4
  ChatAttachmentDropItem,
5
+ ChatMessageClassNames,
6
+ ChatMessageTextClassNames,
5
7
  Message,
6
8
  } from '#uilib/components/ui/Chat/Chat.types';
7
9
  import type { ChatEmptyStateProps } from '#uilib/components/ui/Chat/ChatEmptyState/ChatEmptyState.types';
@@ -22,12 +24,22 @@ export type ChatChromeResizeHandleConfig = {
22
24
 
23
25
  export type { ChatAttachmentDropItem };
24
26
 
27
+ export type ChatChromeVariant = 'default' | 'clean';
28
+
29
+ export type ChatPresetsRenderOptions = {
30
+ variant?: ChatChromeVariant;
31
+ };
32
+
25
33
  export interface ChatChromeProps {
34
+ variant?: ChatChromeVariant;
26
35
  showResizeHandle: boolean;
27
36
  resizeHandle: ChatChromeResizeHandleConfig | undefined;
28
37
  onClose: (() => void) | undefined;
29
38
  isEmpty: boolean;
30
- renderPresets: (layout: ChatPresetsLayout) => React.ReactNode;
39
+ renderPresets: (
40
+ layout: ChatPresetsLayout,
41
+ options?: ChatPresetsRenderOptions,
42
+ ) => React.ReactNode;
31
43
  /** Message list for the scroll area; use `[]` when empty. */
32
44
  messages: Message[];
33
45
  onQuickReply: (branchKey: string, displayLabel: string) => void;
@@ -56,6 +68,10 @@ export interface ChatChromeProps {
56
68
  /** `?prompt=` deep link text for one-shot composer pre-fill. */
57
69
  promptPrefill?: string | null;
58
70
  footerClassName?: string;
71
+ /** Per-role extra classes on message root wrappers (merged with built-in role styles). */
72
+ messageClassNames?: ChatMessageClassNames;
73
+ /** Per-role extra classes on inner text bubbles (merged with built-in `.text` styles). */
74
+ messageTextClassNames?: ChatMessageTextClassNames;
59
75
  emptyState?: ChatEmptyStateProps;
60
76
  /** MIME types / extensions (filtered to text-only allowlist). Enables dropzone when non-empty. */
61
77
  allowedAttachments?: readonly string[];
@@ -3,4 +3,5 @@ export type {
3
3
  ChatAttachmentDropItem,
4
4
  ChatChromeProps,
5
5
  ChatChromeResizeHandleConfig,
6
+ ChatChromeVariant,
6
7
  } from './ChatChrome.types';
@@ -1,3 +1,4 @@
1
+ import cn from 'classnames';
1
2
  import { type ReactNode, useMemo, useState } from 'react';
2
3
 
3
4
  import { Button } from '#uilib/components/ui/Button';
@@ -15,6 +16,7 @@ import { XlsIcon } from './icons/XlsIcon';
15
16
 
16
17
  export function AgentMessageContent({
17
18
  text,
19
+ textClassName,
18
20
  onQuickReply,
19
21
  suppressedQuickReplyKeys,
20
22
  quickReplyDisabled,
@@ -25,6 +27,7 @@ export function AgentMessageContent({
25
27
  renderMessageChart,
26
28
  }: {
27
29
  text: string;
30
+ textClassName?: string;
28
31
  onQuickReply?: (branchKey: string, displayLabel: string) => void;
29
32
  suppressedQuickReplyKeys?: ReadonlySet<string>;
30
33
  quickReplyDisabled?: boolean;
@@ -211,7 +214,7 @@ export function AgentMessageContent({
211
214
 
212
215
  return (
213
216
  <div
214
- className={S.text}
217
+ className={cn(S.text, textClassName)}
215
218
  // onClick={() => setShowRaw(!showRaw)}
216
219
  >
217
220
  {showRaw ? text : parts}
@@ -39,7 +39,6 @@
39
39
  .text
40
40
  padding var(--p-3) var(--p-4)
41
41
 
42
- background-color var(--sb-slate-100)
43
42
  border-radius var(--p-4)
44
43
  border-bottom-right-radius 0
45
44
 
@@ -47,8 +46,11 @@
47
46
  overflow hidden
48
47
  box-sizing border-box
49
48
 
50
- :global(.dark) &
51
- background-color var(--sb-gray-900)
49
+ &:not(.textCustom)
50
+ background-color var(--sb-slate-100)
51
+
52
+ :global(.dark) &
53
+ background-color var(--sb-gray-900)
52
54
 
53
55
  .role-system
54
56
  align-items center
@@ -17,6 +17,7 @@ interface CssExports {
17
17
  'root': string;
18
18
  'scrollHorizontal': string;
19
19
  'text': string;
20
+ 'textCustom': string;
20
21
  'userColumn': string;
21
22
  }
22
23
  export const cssExports: CssExports;
@@ -24,6 +24,8 @@ export function ChatMessage({
24
24
  renderMessageChart,
25
25
  message,
26
26
  renderSystemMessage,
27
+ className,
28
+ textClassName,
27
29
  }: ChatMessageProps) {
28
30
  const fileAttachments = userTextFileAttachmentsFromMessage({
29
31
  userTextFileAttachments,
@@ -32,9 +34,9 @@ export function ChatMessage({
32
34
  const isSystem = role === MessageRole.SYSTEM;
33
35
 
34
36
  return (
35
- <div className={cn(S.root, S[`role-${role}`])}>
37
+ <div className={cn(S.root, S[`role-${role}`], className)}>
36
38
  {isSystem ? (
37
- <div className={S.text}>
39
+ <div className={cn(S.text, textClassName)}>
38
40
  {inProgress ? (
39
41
  <TextShimmer as="span">{text}</TextShimmer>
40
42
  ) : renderSystemMessage && message ? (
@@ -46,6 +48,7 @@ export function ChatMessage({
46
48
  ) : isAssistant ? (
47
49
  <AgentMessageContent
48
50
  text={text}
51
+ textClassName={textClassName}
49
52
  onQuickReply={onQuickReply}
50
53
  suppressedQuickReplyKeys={suppressedQuickReplyKeys}
51
54
  quickReplyDisabled={quickReplyDisabled}
@@ -57,7 +60,9 @@ export function ChatMessage({
57
60
  />
58
61
  ) : (
59
62
  <div className={S.userColumn}>
60
- <div className={S.text}>
63
+ <div
64
+ className={cn(S.text, textClassName && S.textCustom, textClassName)}
65
+ >
61
66
  <InteractiveContent text={text} />
62
67
  </div>
63
68
  {fileAttachments.map(attachment => (
@@ -16,7 +16,8 @@
16
16
  padding var(--p-2) var(--p-6) var(--p-3)
17
17
  background-color var(--background)
18
18
 
19
- .innerInline
19
+ .innerInline,
20
+ .innerClean
20
21
  background-color transparent
21
22
 
22
23
  .item
@@ -3,6 +3,7 @@
3
3
  interface CssExports {
4
4
  'inlineRoot': string;
5
5
  'inner': string;
6
+ 'innerClean': string;
6
7
  'innerInline': string;
7
8
  'item': string;
8
9
  'root': string;
@@ -3,6 +3,7 @@ import { useEffect, useState } from 'react';
3
3
 
4
4
  import { Button } from '#uilib/components/ui/Button';
5
5
 
6
+ import type { ChatChromeVariant } from '../ChatChrome/ChatChrome.types';
6
7
  import type { ChatPreset } from '../Chat.types';
7
8
  import S from './ChatPresets.styl';
8
9
 
@@ -13,6 +14,7 @@ export interface ChatPresetsProps {
13
14
  items: ChatPreset[];
14
15
  usedItemIds?: string[];
15
16
  layout?: ChatPresetsLayout;
17
+ variant?: ChatChromeVariant;
16
18
  onSelect?: (preset: ChatPreset) => void;
17
19
  onItemUsed?: (id: string) => void;
18
20
  }
@@ -22,6 +24,7 @@ export function ChatPresets({
22
24
  items,
23
25
  usedItemIds = [],
24
26
  layout = 'fixed',
27
+ variant = 'default',
25
28
  onSelect,
26
29
  onItemUsed,
27
30
  }: ChatPresetsProps) {
@@ -38,7 +41,13 @@ export function ChatPresets({
38
41
 
39
42
  return (
40
43
  <div className={layout === 'inline' ? S.inlineRoot : S.root}>
41
- <div className={cn(S.inner, layout === 'inline' && S.innerInline)}>
44
+ <div
45
+ className={cn(
46
+ S.inner,
47
+ layout === 'inline' && S.innerInline,
48
+ variant === 'clean' && S.innerClean,
49
+ )}
50
+ >
42
51
  {availableItems.map(preset => (
43
52
  <Button
44
53
  key={preset.id}
@@ -51,7 +51,7 @@ import {
51
51
  } from '../../Sidebar/Sidebar';
52
52
  import { Chat } from '../Chat';
53
53
  import type { ChatChromeProps } from '../ChatChrome';
54
- import type { ChatAttachmentDropItem } from '../ChatChrome/ChatChrome.types';
54
+ import type { ChatAttachmentDropItem, ChatPresetsRenderOptions } from '../ChatChrome/ChatChrome.types';
55
55
  import type { ChatEmptyStateConfig } from '../ChatEmptyState/ChatEmptyState.types';
56
56
  import type { ChatEmptyStateProps } from '../ChatEmptyState/ChatEmptyState.types';
57
57
  import {
@@ -1106,7 +1106,10 @@ export function useChatPanelChromeModel({
1106
1106
  chatWidthPx,
1107
1107
  ]);
1108
1108
 
1109
- const renderPresets = (layout: ChatPresetsLayout = 'fixed') => {
1109
+ const renderPresets = (
1110
+ layout: ChatPresetsLayout = 'fixed',
1111
+ options?: ChatPresetsRenderOptions,
1112
+ ) => {
1110
1113
  if (!presetsWithFreeform?.length) return null;
1111
1114
 
1112
1115
  return (
@@ -1114,6 +1117,7 @@ export function useChatPanelChromeModel({
1114
1117
  chatId={currentChatId ?? ''}
1115
1118
  items={presetsWithFreeform}
1116
1119
  layout={layout}
1120
+ variant={options?.variant}
1117
1121
  usedItemIds={usedPresetIds}
1118
1122
  onSelect={preset => {
1119
1123
  void submitPreset(preset);
@@ -7,6 +7,7 @@ export { ChatChrome } from './ChatChrome';
7
7
  export type {
8
8
  ChatChromeProps,
9
9
  ChatChromeResizeHandleConfig,
10
+ ChatChromeVariant,
10
11
  } from './ChatChrome';
11
12
  export {
12
13
  TEXT_ATTACHMENT_ACCEPT_PARTS,
@@ -47,9 +48,12 @@ export type {
47
48
  export type {
48
49
  Chat as ChatType,
49
50
  ChatAttachmentDropItem,
51
+ ChatMessageClassNames,
52
+ ChatMessageTextClassNames,
50
53
  ChatMeta,
51
54
  ChatMetaValue,
52
55
  ChatSendMessagePayload,
56
+ ChatMessageProps,
53
57
  ChatProps,
54
58
  ChatPreset as ChatPresetType,
55
59
  Message,
@@ -1,20 +1,19 @@
1
- import { useCallback, useMemo, useState } from 'react';
2
-
3
- import { ChartAreaInteractive } from '#uilib/components/ui/ChartAreaInteractive';
4
1
  import type {
5
2
  ChartDataPoint,
6
3
  OverlayMode,
7
4
  } from '#uilib/components/ui/ChartAreaInteractive/ChartAreaInteractive.types';
5
+ import { Tabs, TabsList, TabsTrigger } from '#uilib/components/ui/Tabs';
6
+ import { useCallback, useMemo, useState } from 'react';
7
+
8
+ import { AppPageHeader } from '../components/AppPageHeader/AppPageHeader';
9
+ import { ChartAreaInteractive } from '#uilib/components/ui/ChartAreaInteractive';
10
+ import { DocsHeaderActions } from '../docsHeaderActions';
11
+ import type { ForecastData } from '#uilib/types/forecast-data';
8
12
  import { ForecastItemData } from '#uilib/components/ui/ChartAreaInteractive/ChartLines';
9
13
  import { Label } from '#uilib/components/ui/Label';
10
14
  import { PageContentSection } from '#uilib/components/ui/Page';
11
15
  import { Switch } from '#uilib/components/ui/Switch';
12
- import { Tabs, TabsList, TabsTrigger } from '#uilib/components/ui/Tabs';
13
16
  import { useTheme } from '#uilib/contexts/theme-context';
14
- import type { ForecastData } from '#uilib/types/forecast-data';
15
-
16
- import { AppPageHeader } from '../components/AppPageHeader/AppPageHeader';
17
- import { DocsHeaderActions } from '../docsHeaderActions';
18
17
 
19
18
  const DEMO_FORECAST_ID = 1;
20
19
 
@@ -109,6 +109,7 @@ export default function ChatAttachmentsDropzonePage() {
109
109
  those types; PDF also requires <code>allowPdfAttachments</code>.
110
110
  </p>
111
111
  <ChatChrome
112
+ variant="clean"
112
113
  showResizeHandle={false}
113
114
  resizeHandle={undefined}
114
115
  onClose={undefined}
@@ -170,6 +170,7 @@ export default function ChatComposerPrefillPage() {
170
170
  </li>
171
171
  </ul>
172
172
  <ChatChrome
173
+ variant="clean"
173
174
  showResizeHandle={false}
174
175
  resizeHandle={undefined}
175
176
  onClose={undefined}
@@ -42,7 +42,7 @@ export default function ChatPage() {
42
42
  used chips hide for the session.
43
43
  </p>
44
44
  <div className={S.chatDemoHost}>
45
- <ChatChrome {...chromeProps} />
45
+ <ChatChrome {...chromeProps} variant="clean" />
46
46
  </div>
47
47
  </PageContentSection>
48
48
  </>
@@ -115,6 +115,7 @@ export default function ChatSlashCommandsPage() {
115
115
  }
116
116
  `}</style>
117
117
  <ChatChrome
118
+ variant="clean"
118
119
  showResizeHandle={false}
119
120
  resizeHandle={undefined}
120
121
  onClose={undefined}
@@ -137,6 +137,7 @@ export default function ChatUserCsvAttachmentPage() {
137
137
  </Button>
138
138
  </p>
139
139
  <ChatChrome
140
+ variant="clean"
140
141
  showResizeHandle={false}
141
142
  resizeHandle={undefined}
142
143
  onClose={undefined}