ai-schadcn-chat 0.1.0
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/LICENSE +21 -0
- package/README.md +307 -0
- package/dist/ChatPanel-Cyq7boWQ.js +3468 -0
- package/dist/ChatPanel-Cyq7boWQ.js.map +1 -0
- package/dist/ChatPanel-D3VL5Vdq.cjs +10 -0
- package/dist/ChatPanel-D3VL5Vdq.cjs.map +1 -0
- package/dist/ChatProvider-DcrNbVMh.cjs +2 -0
- package/dist/ChatProvider-DcrNbVMh.cjs.map +1 -0
- package/dist/ChatProvider-DoD4jj4M.js +128 -0
- package/dist/ChatProvider-DoD4jj4M.js.map +1 -0
- package/dist/chat-engine-BaFdimfx.cjs +8 -0
- package/dist/chat-engine-BaFdimfx.cjs.map +1 -0
- package/dist/chat-engine-Cja0KtWE.js +520 -0
- package/dist/chat-engine-Cja0KtWE.js.map +1 -0
- package/dist/components/chat/AgentManager.d.ts +11 -0
- package/dist/components/chat/AgentManager.d.ts.map +1 -0
- package/dist/components/chat/AgentManager.js +110 -0
- package/dist/components/chat/Attachment.d.ts +34 -0
- package/dist/components/chat/Attachment.d.ts.map +1 -0
- package/dist/components/chat/Attachment.js +59 -0
- package/dist/components/chat/AttachmentPreview.d.ts +8 -0
- package/dist/components/chat/AttachmentPreview.d.ts.map +1 -0
- package/dist/components/chat/AttachmentPreview.js +43 -0
- package/dist/components/chat/ChatComposer.d.ts +11 -0
- package/dist/components/chat/ChatComposer.d.ts.map +1 -0
- package/dist/components/chat/ChatComposer.js +10 -0
- package/dist/components/chat/ChatHeader.d.ts +5 -0
- package/dist/components/chat/ChatHeader.d.ts.map +1 -0
- package/dist/components/chat/ChatHeader.js +132 -0
- package/dist/components/chat/ChatPanel.d.ts +36 -0
- package/dist/components/chat/ChatPanel.d.ts.map +1 -0
- package/dist/components/chat/ChatPanel.js +55 -0
- package/dist/components/chat/ChatProvider.d.ts +58 -0
- package/dist/components/chat/ChatProvider.d.ts.map +1 -0
- package/dist/components/chat/ChatProvider.js +145 -0
- package/dist/components/chat/Chatbubble.d.ts +30 -0
- package/dist/components/chat/Chatbubble.d.ts.map +1 -0
- package/dist/components/chat/Chatbubble.js +50 -0
- package/dist/components/chat/Markdown.d.ts +35 -0
- package/dist/components/chat/Markdown.d.ts.map +1 -0
- package/dist/components/chat/Markdown.js +130 -0
- package/dist/components/chat/Message.d.ts +22 -0
- package/dist/components/chat/Message.d.ts.map +1 -0
- package/dist/components/chat/Message.js +21 -0
- package/dist/components/chat/MessageInput.d.ts +24 -0
- package/dist/components/chat/MessageInput.d.ts.map +1 -0
- package/dist/components/chat/MessageInput.js +255 -0
- package/dist/components/chat/MessageList.d.ts +9 -0
- package/dist/components/chat/MessageList.d.ts.map +1 -0
- package/dist/components/chat/MessageList.js +249 -0
- package/dist/components/chat/MessageMarker.d.ts +25 -0
- package/dist/components/chat/MessageMarker.d.ts.map +1 -0
- package/dist/components/chat/MessageMarker.js +31 -0
- package/dist/components/chat/MessageScroller.d.ts +12 -0
- package/dist/components/chat/MessageScroller.d.ts.map +1 -0
- package/dist/components/chat/MessageScroller.js +48 -0
- package/dist/components/chat/MessageScrollerPrimitives.d.ts +76 -0
- package/dist/components/chat/MessageScrollerPrimitives.d.ts.map +1 -0
- package/dist/components/chat/MessageScrollerPrimitives.js +438 -0
- package/dist/components/chat/ProviderManager.d.ts +10 -0
- package/dist/components/chat/ProviderManager.d.ts.map +1 -0
- package/dist/components/chat/ProviderManager.js +110 -0
- package/dist/components/chat/ReasoningPanel.d.ts +15 -0
- package/dist/components/chat/ReasoningPanel.d.ts.map +1 -0
- package/dist/components/chat/ReasoningPanel.js +40 -0
- package/dist/components/chat/ThemeToggle.d.ts +4 -0
- package/dist/components/chat/ThemeToggle.d.ts.map +1 -0
- package/dist/components/chat/ThemeToggle.js +59 -0
- package/dist/components/index.d.ts +44 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +49 -0
- package/dist/components/ui/avatar.d.ts +11 -0
- package/dist/components/ui/avatar.d.ts.map +1 -0
- package/dist/components/ui/avatar.js +33 -0
- package/dist/components/ui/badge.d.ts +10 -0
- package/dist/components/ui/badge.d.ts.map +1 -0
- package/dist/components/ui/badge.js +19 -0
- package/dist/components/ui/button.d.ts +12 -0
- package/dist/components/ui/button.d.ts.map +1 -0
- package/dist/components/ui/button.js +34 -0
- package/dist/components/ui/card.d.ts +8 -0
- package/dist/components/ui/card.d.ts.map +1 -0
- package/dist/components/ui/card.js +15 -0
- package/dist/components/ui/checkbox.d.ts +5 -0
- package/dist/components/ui/checkbox.d.ts.map +1 -0
- package/dist/components/ui/checkbox.js +8 -0
- package/dist/components/ui/collapsible.d.ts +6 -0
- package/dist/components/ui/collapsible.d.ts.map +1 -0
- package/dist/components/ui/collapsible.js +5 -0
- package/dist/components/ui/dialog.d.ts +24 -0
- package/dist/components/ui/dialog.d.ts.map +1 -0
- package/dist/components/ui/dialog.js +30 -0
- package/dist/components/ui/dropdown-menu.d.ts +17 -0
- package/dist/components/ui/dropdown-menu.d.ts.map +1 -0
- package/dist/components/ui/dropdown-menu.js +20 -0
- package/dist/components/ui/input.d.ts +4 -0
- package/dist/components/ui/input.d.ts.map +1 -0
- package/dist/components/ui/input.js +7 -0
- package/dist/components/ui/label.d.ts +6 -0
- package/dist/components/ui/label.d.ts.map +1 -0
- package/dist/components/ui/label.js +10 -0
- package/dist/components/ui/popover.d.ts +6 -0
- package/dist/components/ui/popover.d.ts.map +1 -0
- package/dist/components/ui/popover.js +9 -0
- package/dist/components/ui/scroll-area.d.ts +3 -0
- package/dist/components/ui/scroll-area.d.ts.map +1 -0
- package/dist/components/ui/scroll-area.js +8 -0
- package/dist/components/ui/select.d.ts +14 -0
- package/dist/components/ui/select.d.ts.map +1 -0
- package/dist/components/ui/select.js +26 -0
- package/dist/components/ui/separator.d.ts +3 -0
- package/dist/components/ui/separator.d.ts.map +1 -0
- package/dist/components/ui/separator.js +6 -0
- package/dist/components/ui/switch.d.ts +3 -0
- package/dist/components/ui/switch.d.ts.map +1 -0
- package/dist/components/ui/switch.js +6 -0
- package/dist/components/ui/tabs.d.ts +6 -0
- package/dist/components/ui/tabs.d.ts.map +1 -0
- package/dist/components/ui/tabs.js +11 -0
- package/dist/components/ui/tooltip.d.ts +6 -0
- package/dist/components/ui/tooltip.d.ts.map +1 -0
- package/dist/components/ui/tooltip.js +9 -0
- package/dist/components.cjs +2 -0
- package/dist/components.cjs.map +1 -0
- package/dist/components.js +129 -0
- package/dist/components.js.map +1 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +3 -0
- package/dist/hooks/useChat.d.ts +6 -0
- package/dist/hooks/useChat.d.ts.map +1 -0
- package/dist/hooks/useChat.js +5 -0
- package/dist/hooks.cjs +2 -0
- package/dist/hooks.cjs.map +1 -0
- package/dist/hooks.js +8 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index-Ci4qkGOp.cjs +20 -0
- package/dist/index-Ci4qkGOp.cjs.map +1 -0
- package/dist/index-NhYr-cEJ.js +567 -0
- package/dist/index-NhYr-cEJ.js.map +1 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/agents.d.ts +29 -0
- package/dist/lib/agents.d.ts.map +1 -0
- package/dist/lib/agents.js +145 -0
- package/dist/lib/attachments.d.ts +40 -0
- package/dist/lib/attachments.d.ts.map +1 -0
- package/dist/lib/attachments.js +152 -0
- package/dist/lib/chat-engine.d.ts +109 -0
- package/dist/lib/chat-engine.d.ts.map +1 -0
- package/dist/lib/chat-engine.js +505 -0
- package/dist/lib/index.d.ts +8 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +7 -0
- package/dist/lib/persistence.d.ts +30 -0
- package/dist/lib/persistence.d.ts.map +1 -0
- package/dist/lib/persistence.js +104 -0
- package/dist/lib/providers.d.ts +40 -0
- package/dist/lib/providers.d.ts.map +1 -0
- package/dist/lib/providers.js +0 -0
- package/dist/lib/tw-merge.d.ts +9 -0
- package/dist/lib/tw-merge.d.ts.map +1 -0
- package/dist/lib/tw-merge.js +8 -0
- package/dist/lib/utils.d.ts +69 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +166 -0
- package/dist/lib/voice.d.ts +57 -0
- package/dist/lib/voice.d.ts.map +1 -0
- package/dist/lib/voice.js +103 -0
- package/dist/lib.cjs +2 -0
- package/dist/lib.cjs.map +1 -0
- package/dist/lib.js +59 -0
- package/dist/lib.js.map +1 -0
- package/dist/marker.css +68 -0
- package/dist/package.json +6 -0
- package/dist/presets-BxnbImSM.cjs +2 -0
- package/dist/presets-BxnbImSM.cjs.map +1 -0
- package/dist/presets-D8VQTD8n.js +193 -0
- package/dist/presets-D8VQTD8n.js.map +1 -0
- package/dist/providers/anthropic.d.ts +30 -0
- package/dist/providers/anthropic.d.ts.map +1 -0
- package/dist/providers/anthropic.js +251 -0
- package/dist/providers/base.d.ts +55 -0
- package/dist/providers/base.d.ts.map +1 -0
- package/dist/providers/base.js +272 -0
- package/dist/providers/index.d.ts +15 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +24 -0
- package/dist/providers/openai.d.ts +31 -0
- package/dist/providers/openai.d.ts.map +1 -0
- package/dist/providers/openai.js +192 -0
- package/dist/providers-BuaGy2tX.cjs +4 -0
- package/dist/providers-BuaGy2tX.cjs.map +1 -0
- package/dist/providers-kp-avTNl.js +324 -0
- package/dist/providers-kp-avTNl.js.map +1 -0
- package/dist/providers.cjs +2 -0
- package/dist/providers.cjs.map +1 -0
- package/dist/providers.js +14 -0
- package/dist/providers.js.map +1 -0
- package/dist/scroller.css +278 -0
- package/dist/style.css +1 -0
- package/dist/types/chat.d.ts +342 -0
- package/dist/types/chat.d.ts.map +1 -0
- package/dist/types/chat.js +4 -0
- package/dist/types/index.d.ts +9 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +14 -0
- package/dist/types/presets.d.ts +25 -0
- package/dist/types/presets.d.ts.map +1 -0
- package/dist/types/presets.js +207 -0
- package/dist/types.cjs +2 -0
- package/dist/types.cjs.map +1 -0
- package/dist/types.js +16 -0
- package/dist/types.js.map +1 -0
- package/dist/typeset-presets.css +56 -0
- package/dist/typeset.css +505 -0
- package/package.json +158 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, useCallback, useContext, useMemo, useRef, useSyncExternalStore, } from "react";
|
|
3
|
+
import { ChatEngine as ChatEngineImpl } from "../../lib/chat-engine.js";
|
|
4
|
+
import { buildDefaultMiniMaxConfig } from "../../types/presets.js";
|
|
5
|
+
const ChatContext = createContext(null);
|
|
6
|
+
/**
|
|
7
|
+
* Mount a chat engine for the lifetime of the React subtree. Multiple
|
|
8
|
+
* ChatProviders can coexist; each gets its own engine. The provider
|
|
9
|
+
* uses useSyncExternalStore for concurrent-mode-safe subscriptions.
|
|
10
|
+
*/
|
|
11
|
+
export function ChatProvider(props) {
|
|
12
|
+
const engineRef = useRef(null);
|
|
13
|
+
if (engineRef.current === null) {
|
|
14
|
+
engineRef.current = new ChatEngineImpl(props.config);
|
|
15
|
+
}
|
|
16
|
+
// Whenever the `config` prop changes, sync it into the engine.
|
|
17
|
+
// We compare by JSON to avoid spurious updates that would still
|
|
18
|
+
// trigger a re-render through the subscription.
|
|
19
|
+
const configRef = useRef(props.config);
|
|
20
|
+
if (!shallowEqual(configRef.current, props.config)) {
|
|
21
|
+
configRef.current = props.config;
|
|
22
|
+
engineRef.current.updateConfig(props.config);
|
|
23
|
+
}
|
|
24
|
+
// useSyncExternalStore requires the subscribe callback to be stable
|
|
25
|
+
// across renders — otherwise React tears down + recreates the
|
|
26
|
+
// subscription on every render and emits are lost. Memoize once
|
|
27
|
+
// against the engineRef, which itself is stable for the provider's
|
|
28
|
+
// lifetime.
|
|
29
|
+
const subscribe = useCallback((cb) => engineRef.current.subscribe(cb), []);
|
|
30
|
+
const getMessages = useCallback(() => engineRef.current.getMessagesSnapshot(), []);
|
|
31
|
+
const getConfigSnapshot = useCallback(() => engineRef.current.getConfig(), []);
|
|
32
|
+
const getActiveConversationId = useCallback(() => engineRef.current.getActiveConversationId(), []);
|
|
33
|
+
const getIsStreaming = useCallback(() => engineRef.current
|
|
34
|
+
.getMessagesSnapshot()
|
|
35
|
+
.some((m) => m.status === "streaming"), []);
|
|
36
|
+
const messages = useSyncExternalStore(subscribe, getMessages, getMessages);
|
|
37
|
+
const config = useSyncExternalStore(subscribe, getConfigSnapshot, getConfigSnapshot);
|
|
38
|
+
const conversationId = useSyncExternalStore(subscribe, getActiveConversationId, getActiveConversationId);
|
|
39
|
+
const isStreaming = useSyncExternalStore(subscribe, getIsStreaming, getIsStreaming);
|
|
40
|
+
const updateConfig = useCallback((arg) => {
|
|
41
|
+
engineRef.current.updateConfig(arg);
|
|
42
|
+
}, []);
|
|
43
|
+
const setConversationId = useCallback((id) => {
|
|
44
|
+
engineRef.current.setActiveConversationId(id);
|
|
45
|
+
}, []);
|
|
46
|
+
const send = useCallback(async (text, attachments) => {
|
|
47
|
+
await engineRef.current.sendUserMessage(text, attachments);
|
|
48
|
+
}, []);
|
|
49
|
+
const sendFiles = useCallback(async (text, files) => {
|
|
50
|
+
await engineRef.current.sendFiles(text, files);
|
|
51
|
+
}, []);
|
|
52
|
+
const abort = useCallback(() => engineRef.current.abort(), []);
|
|
53
|
+
const regenerate = useCallback(() => engineRef.current.regenerate(), []);
|
|
54
|
+
const editAndResend = useCallback((id, content) => engineRef.current.editAndResend(id, content), []);
|
|
55
|
+
const clear = useCallback(() => engineRef.current.clear(), []);
|
|
56
|
+
const newConversation = useCallback(() => engineRef.current.newConversation(), []);
|
|
57
|
+
const deleteMessage = useCallback((messageId) => {
|
|
58
|
+
engineRef.current.deleteMessage(messageId);
|
|
59
|
+
}, []);
|
|
60
|
+
const deleteConversation = useCallback((id) => {
|
|
61
|
+
engineRef.current.deleteConversation(id);
|
|
62
|
+
}, []);
|
|
63
|
+
const listConversations = useCallback(() => engineRef.current.listConversationIds(), []);
|
|
64
|
+
const listConversationsMeta = useCallback(() => engineRef.current.listConversationsMeta(), []);
|
|
65
|
+
const getActiveToolCallCount = useCallback(() => engineRef.current.getActiveToolCallCount(), []);
|
|
66
|
+
const value = useMemo(() => ({
|
|
67
|
+
engine: engineRef.current,
|
|
68
|
+
config,
|
|
69
|
+
updateConfig,
|
|
70
|
+
messages,
|
|
71
|
+
isStreaming,
|
|
72
|
+
conversationId,
|
|
73
|
+
setConversationId,
|
|
74
|
+
send,
|
|
75
|
+
sendFiles,
|
|
76
|
+
abort,
|
|
77
|
+
regenerate,
|
|
78
|
+
editAndResend,
|
|
79
|
+
clear,
|
|
80
|
+
newConversation,
|
|
81
|
+
deleteMessage,
|
|
82
|
+
deleteConversation,
|
|
83
|
+
listConversations,
|
|
84
|
+
listConversationsMeta,
|
|
85
|
+
getActiveToolCallCount,
|
|
86
|
+
}), [
|
|
87
|
+
config,
|
|
88
|
+
messages,
|
|
89
|
+
isStreaming,
|
|
90
|
+
conversationId,
|
|
91
|
+
updateConfig,
|
|
92
|
+
setConversationId,
|
|
93
|
+
send,
|
|
94
|
+
sendFiles,
|
|
95
|
+
abort,
|
|
96
|
+
regenerate,
|
|
97
|
+
editAndResend,
|
|
98
|
+
clear,
|
|
99
|
+
newConversation,
|
|
100
|
+
deleteMessage,
|
|
101
|
+
deleteConversation,
|
|
102
|
+
listConversations,
|
|
103
|
+
listConversationsMeta,
|
|
104
|
+
getActiveToolCallCount,
|
|
105
|
+
]);
|
|
106
|
+
return _jsx(ChatContext.Provider, { value: value, children: props.children });
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Hook to access the chat engine. Throws when used outside a ChatProvider.
|
|
110
|
+
*/
|
|
111
|
+
export function useChat() {
|
|
112
|
+
const value = useContext(ChatContext);
|
|
113
|
+
if (!value) {
|
|
114
|
+
throw new Error("useChat must be used inside <ChatProvider>");
|
|
115
|
+
}
|
|
116
|
+
return value;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Variant of useChat that returns null instead of throwing. Use in
|
|
120
|
+
* components that may render both inside and outside a provider.
|
|
121
|
+
*/
|
|
122
|
+
export function useOptionalChat() {
|
|
123
|
+
return useContext(ChatContext);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Default config helper for the MiniMax provider.
|
|
127
|
+
*/
|
|
128
|
+
export function defaultConfig(overrides = {}) {
|
|
129
|
+
return buildDefaultMiniMaxConfig(overrides);
|
|
130
|
+
}
|
|
131
|
+
function shallowEqual(a, b) {
|
|
132
|
+
if (a === b)
|
|
133
|
+
return true;
|
|
134
|
+
if (a.model.id !== b.model.id)
|
|
135
|
+
return false;
|
|
136
|
+
if (a.provider.baseUrl !== b.provider.baseUrl)
|
|
137
|
+
return false;
|
|
138
|
+
if (a.provider.credentials.apiKey !== b.provider.credentials.apiKey)
|
|
139
|
+
return false;
|
|
140
|
+
if (a.systemPrompt !== b.systemPrompt)
|
|
141
|
+
return false;
|
|
142
|
+
if (a.temperature !== b.temperature)
|
|
143
|
+
return false;
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chatbubble — sourced from `apps/v4/styles/radix-rhea/ui/bubble.tsx` in
|
|
3
|
+
* the official `shadcn-ui/ui` repo (https://github.com/shadcn-ui/ui).
|
|
4
|
+
*
|
|
5
|
+
* File renamed `bubble.tsx` → `Chatbubble.tsx` so the import paths in
|
|
6
|
+
* this package line up with the kebab-case file naming convention used
|
|
7
|
+
* throughout (`Message.tsx`, `MessageMarker.tsx`, etc.).
|
|
8
|
+
*
|
|
9
|
+
* Source paths in the original module were remapped:
|
|
10
|
+
* - `@/lib/utils` → `../../lib/utils.js`
|
|
11
|
+
* - `radix-ui` (Slot) → `@radix-ui/react-slot`
|
|
12
|
+
*/
|
|
13
|
+
import * as React from "react";
|
|
14
|
+
import { type VariantProps } from "class-variance-authority";
|
|
15
|
+
declare function BubbleGroup({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
16
|
+
declare const bubbleVariants: (props?: ({
|
|
17
|
+
variant?: "default" | "destructive" | "ghost" | "muted" | "outline" | "secondary" | "tinted" | null | undefined;
|
|
18
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
19
|
+
declare function Bubble({ variant, align, className, ...props }: React.ComponentProps<"div"> & VariantProps<typeof bubbleVariants> & {
|
|
20
|
+
align?: "start" | "end";
|
|
21
|
+
}): React.JSX.Element;
|
|
22
|
+
declare function BubbleContent({ asChild, className, ...props }: React.ComponentProps<"div"> & {
|
|
23
|
+
asChild?: boolean;
|
|
24
|
+
}): React.JSX.Element;
|
|
25
|
+
declare function BubbleReactions({ side, align, className, ...props }: React.ComponentProps<"div"> & {
|
|
26
|
+
align?: "start" | "end";
|
|
27
|
+
side?: "top" | "bottom";
|
|
28
|
+
}): React.JSX.Element;
|
|
29
|
+
export { BubbleGroup, Bubble, BubbleContent, BubbleReactions, type VariantProps as BubbleVariantProps, };
|
|
30
|
+
//# sourceMappingURL=Chatbubble.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Chatbubble.d.ts","sourceRoot":"","sources":["../../../src/components/chat/Chatbubble.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAKlE,iBAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQxE;AAED,QAAA,MAAM,cAAc;;8EAyBnB,CAAC;AAEF,iBAAS,MAAM,CAAC,EACd,OAAmB,EACnB,KAAe,EACf,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,GAC5B,YAAY,CAAC,OAAO,cAAc,CAAC,GAAG;IACpC,KAAK,CAAC,EAAE,OAAO,GAAG,KAAK,CAAC;CACzB,qBAUF;AAED,iBAAS,aAAa,CAAC,EACrB,OAAe,EACf,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,qBAaA;AAsBD,iBAAS,eAAe,CAAC,EACvB,IAAe,EACf,KAAa,EACb,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG;IAC/B,KAAK,CAAC,EAAE,OAAO,GAAG,KAAK,CAAC;IACxB,IAAI,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC;CACzB,qBAUA;AAED,OAAO,EACL,WAAW,EACX,MAAM,EACN,aAAa,EACb,eAAe,EACf,KAAK,YAAY,IAAI,kBAAkB,GACxC,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cva } from "class-variance-authority";
|
|
3
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
4
|
+
import { cn } from "../../lib/utils.js";
|
|
5
|
+
function BubbleGroup({ className, ...props }) {
|
|
6
|
+
return (_jsx("div", { "data-slot": "bubble-group", className: cn("flex min-w-0 flex-col gap-2", className), ...props }));
|
|
7
|
+
}
|
|
8
|
+
const bubbleVariants = cva("group/bubble relative flex w-fit max-w-[80%] min-w-0 flex-col gap-1 group-data-[align=end]/message:self-end data-[align=end]:self-end data-[variant=ghost]:max-w-full", {
|
|
9
|
+
variants: {
|
|
10
|
+
variant: {
|
|
11
|
+
default: "*:data-[slot=bubble-content]:bg-primary *:data-[slot=bubble-content]:text-primary-foreground [&>[data-slot=bubble-content]:is(button,a):hover]:bg-primary/80",
|
|
12
|
+
secondary: "*:data-[slot=bubble-content]:bg-secondary *:data-[slot=bubble-content]:text-secondary-foreground [&>[data-slot=bubble-content]:is(button,a):hover]:bg-[color-mix(in_oklch,var(--secondary),var(--foreground)_5%)]",
|
|
13
|
+
muted: "*:data-[slot=bubble-content]:bg-muted [&>[data-slot=bubble-content]:is(button,a):hover]:bg-[color-mix(in_oklch,var(--muted),var(--foreground)_5%)]",
|
|
14
|
+
tinted: "*:data-[slot=bubble-content]:bg-[oklch(from_var(--primary)_0.93_calc(c*0.4)_h)] *:data-[slot=bubble-content]:text-foreground dark:*:data-[slot=bubble-content]:bg-[oklch(from_var(--primary)_0.3_calc(c*0.4)_h)] [&>[data-slot=bubble-content]:is(button,a):hover]:bg-[oklch(from_var(--primary)_0.88_calc(c*0.5)_h)] dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-[oklch(from_var(--primary)_0.35_calc(c*0.5)_h)]",
|
|
15
|
+
outline: "*:data-[slot=bubble-content]:border-border *:data-[slot=bubble-content]:bg-background [&>[data-slot=bubble-content]:is(button,a):hover]:bg-muted [&>[data-slot=bubble-content]:is(button,a):hover]:text-foreground dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-input/30",
|
|
16
|
+
ghost: "border-none *:data-[slot=bubble-content]:rounded-none *:data-[slot=bubble-content]:bg-transparent *:data-[slot=bubble-content]:p-0 [&>[data-slot=bubble-content]:is(button,a):hover]:bg-muted [&>[data-slot=bubble-content]:is(button,a):hover]:text-foreground dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-muted/50",
|
|
17
|
+
destructive: "*:data-[slot=bubble-content]:bg-destructive/10 *:data-[slot=bubble-content]:text-destructive dark:*:data-[slot=bubble-content]:bg-destructive/20 [&>[data-slot=bubble-content]:is(button,a):hover]:bg-destructive/20 dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-destructive/30",
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
defaultVariants: {
|
|
21
|
+
variant: "default",
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
function Bubble({ variant = "default", align = "start", className, ...props }) {
|
|
25
|
+
return (_jsx("div", { "data-slot": "bubble", "data-variant": variant, "data-align": align, className: cn(bubbleVariants({ variant }), className), ...props }));
|
|
26
|
+
}
|
|
27
|
+
function BubbleContent({ asChild = false, className, ...props }) {
|
|
28
|
+
const Comp = asChild ? Slot : "div";
|
|
29
|
+
return (_jsx(Comp, { "data-slot": "bubble-content", className: cn("w-fit max-w-full min-w-0 overflow-hidden rounded-3xl border border-transparent px-3 py-2.5 text-sm leading-relaxed wrap-break-word group-data-[align=end]/bubble:self-end [button]:text-left [button,a]:transition-colors [button,a]:outline-none [button,a]:focus-visible:border-ring [button,a]:focus-visible:ring-3 [button,a]:focus-visible:ring-ring/30", className), ...props }));
|
|
30
|
+
}
|
|
31
|
+
const bubbleReactionsVariants = cva("absolute z-10 flex w-fit shrink-0 items-center justify-center gap-1 rounded-full bg-muted px-1.5 py-0.5 text-sm ring-3 ring-card has-[button]:p-0", {
|
|
32
|
+
variants: {
|
|
33
|
+
side: {
|
|
34
|
+
top: "top-0 -translate-y-3/4",
|
|
35
|
+
bottom: "bottom-0 translate-y-3/4",
|
|
36
|
+
},
|
|
37
|
+
align: {
|
|
38
|
+
start: "left-3",
|
|
39
|
+
end: "right-3",
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
defaultVariants: {
|
|
43
|
+
side: "bottom",
|
|
44
|
+
align: "end",
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
function BubbleReactions({ side = "bottom", align = "end", className, ...props }) {
|
|
48
|
+
return (_jsx("div", { "data-slot": "bubble-reactions", "data-align": align, "data-side": side, className: cn(bubbleReactionsVariants({ side, align }), className), ...props }));
|
|
49
|
+
}
|
|
50
|
+
export { BubbleGroup, Bubble, BubbleContent, BubbleReactions, };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type CSSProperties } from "react";
|
|
2
|
+
import type { TypesetConfig } from "../../types/chat.js";
|
|
3
|
+
export interface MarkdownProps {
|
|
4
|
+
children: string;
|
|
5
|
+
className?: string;
|
|
6
|
+
/**
|
|
7
|
+
* Optional typeset styling. When provided, the container becomes a
|
|
8
|
+
* `.typeset` element with the chosen preset + rhythm overrides. When
|
|
9
|
+
* undefined, the container falls back to the package's `ai-prose` class
|
|
10
|
+
* (the look every chat shipped with before this feature).
|
|
11
|
+
*
|
|
12
|
+
* The consumer app typically wires this from `config.ui.typeset` via the
|
|
13
|
+
* parent component. Passing it directly is supported for callers that
|
|
14
|
+
* want to bypass config plumbing (custom renderers, tests).
|
|
15
|
+
*/
|
|
16
|
+
typeset?: TypesetConfig;
|
|
17
|
+
/**
|
|
18
|
+
* When false, the syntax-highlight plugin is skipped. Defaults to true
|
|
19
|
+
* (highlights are on). Consumers wire this from `config.ui.enableCodeHighlight`.
|
|
20
|
+
*/
|
|
21
|
+
enableCodeHighlight?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* When false, the per-code-block Copy button is omitted. Defaults to
|
|
24
|
+
* true. Consumers wire this from `config.ui.enableCopyButtons`.
|
|
25
|
+
*/
|
|
26
|
+
enableCopyButtons?: boolean;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Resolves which CSS class + inline style the markdown container should use.
|
|
30
|
+
* Pure function, exported for unit tests.
|
|
31
|
+
*/
|
|
32
|
+
export declare function typesetClassName(typeset: TypesetConfig | undefined): string;
|
|
33
|
+
export declare function typesetInlineStyle(typeset: TypesetConfig | undefined): CSSProperties | undefined;
|
|
34
|
+
export declare const Markdown: import("react").MemoExoticComponent<({ children, className, typeset, enableCodeHighlight, enableCopyButtons, }: MarkdownProps) => import("react").JSX.Element>;
|
|
35
|
+
//# sourceMappingURL=Markdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Markdown.d.ts","sourceRoot":"","sources":["../../../src/components/chat/Markdown.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAAkB,KAAK,aAAa,EAAkB,MAAM,OAAO,CAAC;AAO3E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AA4CzD,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,aAAa,GAAG,SAAS,GAAG,MAAM,CAQ3E;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,aAAa,GAAG,SAAS,GAAG,aAAa,GAAG,SAAS,CAUhG;AAED,eAAO,MAAM,QAAQ,kHAMlB,aAAa,iCAoId,CAAC"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Markdown — renders assistant/tool message content as rich GitHub-flavored
|
|
4
|
+
* Markdown with syntax-highlighted code blocks (copy + language label),
|
|
5
|
+
* tables, links, and lists.
|
|
6
|
+
*
|
|
7
|
+
* Pipeline: react-markdown + remark-gfm (tables/strikethrough/autolinks) +
|
|
8
|
+
* rehype-raw (inline HTML) + rehype-highlight (highlight.js token classes,
|
|
9
|
+
* themed in globals.css). The renderer is memoized so re-renders during
|
|
10
|
+
* streaming only re-parse when the text actually changes.
|
|
11
|
+
*
|
|
12
|
+
* Styling: when `typeset` is set, the container gets `typeset` + the chosen
|
|
13
|
+
* preset class + CSS variables for any rhythm overrides. When omitted or
|
|
14
|
+
* `enabled === false`, we fall back to `ai-prose` so existing consumers see
|
|
15
|
+
* no change. Either way, the per-element classes in `components` below still
|
|
16
|
+
* apply — Tailwind utilities win specificity over typeset's `:where()` rules.
|
|
17
|
+
*/
|
|
18
|
+
import { Check, Copy } from "lucide-react";
|
|
19
|
+
import { memo, useState } from "react";
|
|
20
|
+
import ReactMarkdown from "react-markdown";
|
|
21
|
+
import rehypeHighlight from "rehype-highlight";
|
|
22
|
+
import rehypeRaw from "rehype-raw";
|
|
23
|
+
import remarkGfm from "remark-gfm";
|
|
24
|
+
import { Button } from "../ui/button.js";
|
|
25
|
+
import { cn } from "../../lib/utils.js";
|
|
26
|
+
function CopyButton({ getText }) {
|
|
27
|
+
const [copied, setCopied] = useState(false);
|
|
28
|
+
return (_jsx(Button, { type: "button", variant: "ghost", "aria-label": "Copy code", onClick: () => {
|
|
29
|
+
try {
|
|
30
|
+
void navigator.clipboard?.writeText(getText());
|
|
31
|
+
setCopied(true);
|
|
32
|
+
setTimeout(() => setCopied(false), 1600);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
/* ignore */
|
|
36
|
+
}
|
|
37
|
+
}, className: "h-7 gap-1.5 px-2 text-[11px] font-medium text-muted-foreground hover:bg-foreground/10 hover:text-foreground", children: copied ? (_jsxs(_Fragment, { children: [_jsx(Check, { className: "size-3 text-success" }), " Copied"] })) : (_jsxs(_Fragment, { children: [_jsx(Copy, { className: "size-3" }), " Copy"] })) }));
|
|
38
|
+
}
|
|
39
|
+
function nodeToText(node) {
|
|
40
|
+
if (node == null || typeof node === "boolean")
|
|
41
|
+
return "";
|
|
42
|
+
if (typeof node === "string" || typeof node === "number")
|
|
43
|
+
return String(node);
|
|
44
|
+
if (Array.isArray(node))
|
|
45
|
+
return node.map(nodeToText).join("");
|
|
46
|
+
if (typeof node === "object" && "props" in node) {
|
|
47
|
+
const props = node.props;
|
|
48
|
+
return nodeToText(props?.children);
|
|
49
|
+
}
|
|
50
|
+
return "";
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Resolves which CSS class + inline style the markdown container should use.
|
|
54
|
+
* Pure function, exported for unit tests.
|
|
55
|
+
*/
|
|
56
|
+
export function typesetClassName(typeset) {
|
|
57
|
+
if (!typeset || typeset.enabled === false) {
|
|
58
|
+
// Legacy look. Keep the same class so existing snapshots stay stable.
|
|
59
|
+
return cn("ai-prose", "text-[0.9375rem] leading-relaxed");
|
|
60
|
+
}
|
|
61
|
+
const presetClass = typeset.preset && typeset.preset !== "default" ? `typeset-${typeset.preset}` : "typeset";
|
|
62
|
+
return cn(presetClass, "text-[var(--typeset-size)]");
|
|
63
|
+
}
|
|
64
|
+
export function typesetInlineStyle(typeset) {
|
|
65
|
+
if (!typeset || typeset.enabled === false)
|
|
66
|
+
return undefined;
|
|
67
|
+
const vars = {};
|
|
68
|
+
if (typeset.size)
|
|
69
|
+
vars["--typeset-size"] = typeset.size;
|
|
70
|
+
if (typeof typeset.leading === "number")
|
|
71
|
+
vars["--typeset-leading"] = typeset.leading;
|
|
72
|
+
if (typeset.flow)
|
|
73
|
+
vars["--typeset-flow"] = typeset.flow;
|
|
74
|
+
if (typeset.fontBody)
|
|
75
|
+
vars["--typeset-font-body"] = typeset.fontBody;
|
|
76
|
+
if (typeset.fontHeading)
|
|
77
|
+
vars["--typeset-font-heading"] = typeset.fontHeading;
|
|
78
|
+
if (typeset.fontMono)
|
|
79
|
+
vars["--typeset-font-mono"] = typeset.fontMono;
|
|
80
|
+
return Object.keys(vars).length > 0 ? vars : undefined;
|
|
81
|
+
}
|
|
82
|
+
export const Markdown = memo(function Markdown({ children, className, typeset, enableCodeHighlight = true, enableCopyButtons = true, }) {
|
|
83
|
+
const containerClass = typesetClassName(typeset);
|
|
84
|
+
const containerStyle = typesetInlineStyle(typeset);
|
|
85
|
+
// rehypePlugins: omit `rehype-highlight` when `enableCodeHighlight` is off.
|
|
86
|
+
// react-markdown's Pluggable[] type is `[Plugin, ...params]`; we cast so we
|
|
87
|
+
// can branch at runtime without TypeScript narrowing the array shape.
|
|
88
|
+
const rehypePlugins = (enableCodeHighlight
|
|
89
|
+
? [rehypeRaw, [rehypeHighlight, { detect: true, ignoreMissing: true }]]
|
|
90
|
+
: [rehypeRaw]);
|
|
91
|
+
return (_jsx("div", { className: cn(containerClass, className), style: containerStyle, children: _jsx(ReactMarkdown, { remarkPlugins: [remarkGfm], rehypePlugins: rehypePlugins, components: {
|
|
92
|
+
p: ({ children }) => _jsx("p", { className: "my-2.5", children: children }),
|
|
93
|
+
a: ({ children, href }) => (_jsx("a", { href: href, target: "_blank", rel: "noreferrer noopener", className: "font-medium text-primary underline decoration-primary/30 underline-offset-2 transition-colors hover:decoration-primary", children: children })),
|
|
94
|
+
img: ({ src, alt }) => (_jsx("img", { src: typeof src === "string" ? src : undefined, alt: alt ?? "", loading: "lazy", className: "my-2 h-auto max-h-80 max-w-full rounded-xl border border-border object-contain" })),
|
|
95
|
+
ul: ({ children }) => (_jsx("ul", { className: "my-2.5 list-disc space-y-1 pl-5 marker:text-muted-foreground", children: children })),
|
|
96
|
+
ol: ({ children }) => (_jsx("ol", { className: "my-2.5 list-decimal space-y-1 pl-5 marker:text-muted-foreground", children: children })),
|
|
97
|
+
li: ({ children }) => _jsx("li", { className: "pl-1", children: children }),
|
|
98
|
+
h1: ({ children }) => (_jsx("h1", { className: "mb-2 mt-4 text-lg font-semibold tracking-tight", children: children })),
|
|
99
|
+
h2: ({ children }) => (_jsx("h2", { className: "mb-2 mt-4 text-base font-semibold tracking-tight", children: children })),
|
|
100
|
+
h3: ({ children }) => (_jsx("h3", { className: "mb-1.5 mt-3 text-sm font-semibold tracking-tight", children: children })),
|
|
101
|
+
blockquote: ({ children }) => (_jsx("blockquote", { className: "my-3 rounded-r-md border-l-2 border-primary/40 bg-primary/5 py-1 pl-3 text-muted-foreground", children: children })),
|
|
102
|
+
hr: () => _jsx("hr", { className: "my-4 border-border" }),
|
|
103
|
+
table: ({ children }) => (_jsx("div", { className: "my-3 overflow-x-auto rounded-lg border border-border", children: _jsx("table", { className: "w-full border-collapse text-sm", children: children }) })),
|
|
104
|
+
thead: ({ children }) => (_jsx("thead", { className: "bg-muted/60", children: children })),
|
|
105
|
+
th: ({ children }) => (_jsx("th", { className: "border-b border-border px-3 py-2 text-left font-semibold", children: children })),
|
|
106
|
+
td: ({ children }) => (_jsx("td", { className: "border-b border-border/60 px-3 py-2 align-top", children: children })),
|
|
107
|
+
code: ({ className: cls, children, ...props }) => {
|
|
108
|
+
const isBlock = /language-/.test(cls ?? "");
|
|
109
|
+
if (!isBlock) {
|
|
110
|
+
return (_jsx("code", { className: "rounded-md border border-border/70 bg-muted/70 px-1.5 py-0.5 font-mono text-[0.85em] text-foreground", ...props, children: children }));
|
|
111
|
+
}
|
|
112
|
+
return (_jsx("code", { className: cls, ...props, children: children }));
|
|
113
|
+
},
|
|
114
|
+
pre: ({ children }) => {
|
|
115
|
+
const lang = extractLang(children);
|
|
116
|
+
return (_jsxs("div", { className: "group/code my-3 overflow-hidden rounded-xl border border-border bg-[oklch(0.16_0.02_285)] shadow-sm", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-white/10 bg-white/[0.03] px-3 py-1.5", children: [_jsx("span", { className: "font-mono text-[11px] font-medium uppercase tracking-wide text-white/50", children: lang || "code" }), enableCopyButtons && (_jsx(CopyButton, { getText: () => nodeToText(children) }))] }), _jsx("pre", { className: "overflow-x-auto px-4 py-3 text-[0.8125rem] leading-relaxed text-white/90 [&_code]:bg-transparent [&_code]:p-0", children: children })] }));
|
|
117
|
+
},
|
|
118
|
+
}, children: children }) }));
|
|
119
|
+
});
|
|
120
|
+
function extractLang(children) {
|
|
121
|
+
// <pre><code class="hljs language-ts">…
|
|
122
|
+
const child = Array.isArray(children) ? children[0] : children;
|
|
123
|
+
const cls = (child &&
|
|
124
|
+
typeof child === "object" &&
|
|
125
|
+
"props" in child &&
|
|
126
|
+
child.props?.className) ||
|
|
127
|
+
"";
|
|
128
|
+
const m = /language-([\w-]+)/.exec(cls);
|
|
129
|
+
return m ? m[1] : "";
|
|
130
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Message — sourced from `apps/v4/styles/radix-rhea/ui/message.tsx` in
|
|
3
|
+
* the official `shadcn-ui/ui` repo (https://github.com/shadcn-ui/ui).
|
|
4
|
+
*
|
|
5
|
+
* Source paths in the original module were remapped:
|
|
6
|
+
* - `@/lib/utils` → `../../lib/utils.js`
|
|
7
|
+
*
|
|
8
|
+
* The component is a presentational frame that the consumer composes with
|
|
9
|
+
* `Bubble` (text), `Attachment` (files), `Marker` (tool calls, errors), and
|
|
10
|
+
* `MessageAvatar` (icon / image).
|
|
11
|
+
*/
|
|
12
|
+
import * as React from "react";
|
|
13
|
+
declare function MessageGroup({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
14
|
+
declare function Message({ className, align, ...props }: React.ComponentProps<"div"> & {
|
|
15
|
+
align?: "start" | "end";
|
|
16
|
+
}): React.JSX.Element;
|
|
17
|
+
declare function MessageAvatar({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
18
|
+
declare function MessageContent({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
19
|
+
declare function MessageHeader({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
20
|
+
declare function MessageFooter({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
21
|
+
export { MessageGroup, Message, MessageAvatar, MessageContent, MessageFooter, MessageHeader, };
|
|
22
|
+
//# sourceMappingURL=Message.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Message.d.ts","sourceRoot":"","sources":["../../../src/components/chat/Message.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,iBAAS,YAAY,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQzE;AAED,iBAAS,OAAO,CAAC,EACf,SAAS,EACT,KAAe,EACf,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG;IAAE,KAAK,CAAC,EAAE,OAAO,GAAG,KAAK,CAAA;CAAE,qBAY3D;AAED,iBAAS,aAAa,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAW1E;AAED,iBAAS,cAAc,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAW3E;AAED,iBAAS,aAAa,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAW1E;AAED,iBAAS,aAAa,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAW1E;AAED,OAAO,EACL,YAAY,EACZ,OAAO,EACP,aAAa,EACb,cAAc,EACd,aAAa,EACb,aAAa,GACd,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../../lib/utils.js";
|
|
3
|
+
function MessageGroup({ className, ...props }) {
|
|
4
|
+
return (_jsx("div", { "data-slot": "message-group", className: cn("flex min-w-0 flex-col gap-2", className), ...props }));
|
|
5
|
+
}
|
|
6
|
+
function Message({ className, align = "start", ...props }) {
|
|
7
|
+
return (_jsx("div", { "data-slot": "message", "data-align": align, className: cn("group/message relative flex w-full min-w-0 gap-2 text-sm data-[align=end]:flex-row-reverse", className), ...props }));
|
|
8
|
+
}
|
|
9
|
+
function MessageAvatar({ className, ...props }) {
|
|
10
|
+
return (_jsx("div", { "data-slot": "message-avatar", className: cn("flex w-fit min-w-8 shrink-0 items-center justify-center self-end overflow-hidden rounded-full bg-muted group-has-data-[slot=message-footer]/message:-translate-y-8", className), ...props }));
|
|
11
|
+
}
|
|
12
|
+
function MessageContent({ className, ...props }) {
|
|
13
|
+
return (_jsx("div", { "data-slot": "message-content", className: cn("flex w-full min-w-0 flex-col gap-2.5 wrap-break-word group-data-[align=end]/message:*:data-slot:self-end", className), ...props }));
|
|
14
|
+
}
|
|
15
|
+
function MessageHeader({ className, ...props }) {
|
|
16
|
+
return (_jsx("div", { "data-slot": "message-header", className: cn("flex max-w-full min-w-0 items-center px-3 text-xs font-medium text-muted-foreground group-has-data-[variant=ghost]/message:px-0", className), ...props }));
|
|
17
|
+
}
|
|
18
|
+
function MessageFooter({ className, ...props }) {
|
|
19
|
+
return (_jsx("div", { "data-slot": "message-footer", className: cn("flex max-w-full min-w-0 items-center px-3 text-xs font-medium text-muted-foreground group-has-data-[variant=ghost]/message:px-0 group-data-[align=end]/message:justify-end", className), ...props }));
|
|
20
|
+
}
|
|
21
|
+
export { MessageGroup, Message, MessageAvatar, MessageContent, MessageFooter, MessageHeader, };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import type { AttachmentMeta } from "../../types/chat.js";
|
|
3
|
+
export interface MessageInputProps {
|
|
4
|
+
/** Optional headless submit handler. When omitted, the input calls
|
|
5
|
+
* `useChat().send(text, attachments)`. */
|
|
6
|
+
onSend?: (content: string, attachments: AttachmentMeta[]) => void | Promise<void>;
|
|
7
|
+
/** Streaming state — toggles the trailing button between "send" and "stop". */
|
|
8
|
+
streaming?: boolean;
|
|
9
|
+
/** Disable the input entirely (e.g. while uploading). */
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
/** Override the trailing button render. */
|
|
12
|
+
renderSendButton?: (props: {
|
|
13
|
+
disabled: boolean;
|
|
14
|
+
onClick: () => void;
|
|
15
|
+
}) => ReactNode;
|
|
16
|
+
/** Extra className on the form. */
|
|
17
|
+
className?: string;
|
|
18
|
+
/** Extra className on the inner content wrapper (the composer card and hint
|
|
19
|
+
* text), merged over the default `max-w-3xl` via tailwind-merge. Use this
|
|
20
|
+
* to let the composer use more horizontal space in wide layouts. */
|
|
21
|
+
contentClassName?: string;
|
|
22
|
+
}
|
|
23
|
+
export declare function MessageInput(props: MessageInputProps): import("react").JSX.Element;
|
|
24
|
+
//# sourceMappingURL=MessageInput.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MessageInput.d.ts","sourceRoot":"","sources":["../../../src/components/chat/MessageInput.tsx"],"names":[],"mappings":"AA+BA,OAAO,EAUL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AA+Bf,OAAO,KAAK,EACV,cAAc,EAGf,MAAM,qBAAqB,CAAC;AAG7B,MAAM,WAAW,iBAAiB;IAChC;+CAC2C;IAC3C,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClF,+EAA+E;IAC/E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,yDAAyD;IACzD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,2CAA2C;IAC3C,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE;QACzB,QAAQ,EAAE,OAAO,CAAC;QAClB,OAAO,EAAE,MAAM,IAAI,CAAC;KACrB,KAAK,SAAS,CAAC;IAChB,mCAAmC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;yEAEqE;IACrE,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,+BA6ZpD"}
|