@meshagent/meshagent-tailwind 0.38.2 → 0.38.3
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/CHANGELOG.md +9 -0
- package/dist/cjs/Chat.d.ts +11 -3
- package/dist/cjs/Chat.js +376 -29
- package/dist/cjs/ChatBotView.d.ts +29 -0
- package/dist/cjs/ChatBotView.js +491 -0
- package/dist/cjs/ChatInput.d.ts +12 -3
- package/dist/cjs/ChatInput.js +143 -44
- package/dist/cjs/ChatThread.d.ts +17 -3
- package/dist/cjs/ChatThread.js +646 -90
- package/dist/cjs/ChatTypingIndicator.d.ts +12 -5
- package/dist/cjs/ChatTypingIndicator.js +104 -13
- package/dist/cjs/FileUploader.d.ts +3 -2
- package/dist/cjs/FileUploader.js +35 -11
- package/dist/cjs/UploadPill.d.ts +2 -2
- package/dist/cjs/UploadPill.js +70 -32
- package/dist/cjs/chat-hooks.d.ts +38 -0
- package/dist/cjs/chat-hooks.js +390 -0
- package/dist/cjs/chat-message.d.ts +11 -0
- package/dist/cjs/chat-message.js +33 -0
- package/dist/cjs/components/ui/button.d.ts +1 -1
- package/dist/cjs/conversation-descriptor.d.ts +59 -0
- package/dist/cjs/conversation-descriptor.js +300 -0
- package/dist/cjs/file-attachment.d.ts +45 -0
- package/dist/cjs/file-attachment.js +171 -0
- package/dist/cjs/index.d.ts +5 -0
- package/dist/cjs/index.js +5 -0
- package/dist/cjs/multi-thread-view.d.ts +18 -0
- package/dist/cjs/multi-thread-view.js +88 -0
- package/dist/cjs/tools/ui-toolkit.d.ts +1 -1
- package/dist/cjs/tools/ui-toolkit.js +2 -1
- package/dist/esm/Chat.d.ts +11 -3
- package/dist/esm/Chat.js +378 -31
- package/dist/esm/ChatBotView.d.ts +29 -0
- package/dist/esm/ChatBotView.js +486 -0
- package/dist/esm/ChatInput.d.ts +12 -3
- package/dist/esm/ChatInput.js +143 -34
- package/dist/esm/ChatThread.d.ts +17 -3
- package/dist/esm/ChatThread.js +648 -92
- package/dist/esm/ChatTypingIndicator.d.ts +12 -5
- package/dist/esm/ChatTypingIndicator.js +94 -13
- package/dist/esm/FileUploader.d.ts +3 -2
- package/dist/esm/FileUploader.js +26 -12
- package/dist/esm/UploadPill.d.ts +2 -2
- package/dist/esm/UploadPill.js +60 -32
- package/dist/esm/chat-hooks.d.ts +38 -0
- package/dist/esm/chat-hooks.js +372 -0
- package/dist/esm/chat-message.d.ts +11 -0
- package/dist/esm/chat-message.js +13 -0
- package/dist/esm/components/ui/button.d.ts +1 -1
- package/dist/esm/conversation-descriptor.d.ts +59 -0
- package/dist/esm/conversation-descriptor.js +280 -0
- package/dist/esm/file-attachment.d.ts +45 -0
- package/dist/esm/file-attachment.js +151 -0
- package/dist/esm/index.d.ts +5 -0
- package/dist/esm/index.js +5 -0
- package/dist/esm/multi-thread-view.d.ts +18 -0
- package/dist/esm/multi-thread-view.js +68 -0
- package/dist/esm/tools/ui-toolkit.d.ts +1 -1
- package/dist/esm/tools/ui-toolkit.js +2 -1
- package/dist/index.css +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,486 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
3
|
+
import { useDocumentChanged } from "@meshagent/meshagent-react";
|
|
4
|
+
import {
|
|
5
|
+
AlertTriangle,
|
|
6
|
+
Check,
|
|
7
|
+
MessageSquare,
|
|
8
|
+
MessageSquarePlus,
|
|
9
|
+
Pencil
|
|
10
|
+
} from "lucide-react";
|
|
11
|
+
import { useThreadStatus } from "./chat-hooks";
|
|
12
|
+
import { Chat } from "./Chat";
|
|
13
|
+
import { Button } from "./components/ui/button";
|
|
14
|
+
import { Spinner } from "./components/ui/spinner";
|
|
15
|
+
import {
|
|
16
|
+
ChatThreadDisplayMode,
|
|
17
|
+
chatDocumentPath,
|
|
18
|
+
defaultThreadDisplayNameFromPath,
|
|
19
|
+
resolvedThreadListPath
|
|
20
|
+
} from "./conversation-descriptor";
|
|
21
|
+
import { cn } from "./lib/utils";
|
|
22
|
+
import { MultiThreadView } from "./multi-thread-view";
|
|
23
|
+
const multiThreadLayoutBreakpointPx = 920;
|
|
24
|
+
import {
|
|
25
|
+
ChatThreadDisplayMode as ChatThreadDisplayMode2,
|
|
26
|
+
chatDocumentPath as chatDocumentPath2,
|
|
27
|
+
resolvedThreadListPath as resolvedThreadListPath2
|
|
28
|
+
} from "./conversation-descriptor";
|
|
29
|
+
function normalizePath(path) {
|
|
30
|
+
const normalized = path?.trim();
|
|
31
|
+
return normalized ? normalized : null;
|
|
32
|
+
}
|
|
33
|
+
function parseDate(value) {
|
|
34
|
+
const parsed = new Date(value);
|
|
35
|
+
return Number.isNaN(parsed.getTime()) ? /* @__PURE__ */ new Date(0) : parsed;
|
|
36
|
+
}
|
|
37
|
+
function compareThreadEntries(left, right) {
|
|
38
|
+
const leftSortDate = left.modifiedAt.trim() ? parseDate(left.modifiedAt) : parseDate(left.createdAt);
|
|
39
|
+
const rightSortDate = right.modifiedAt.trim() ? parseDate(right.modifiedAt) : parseDate(right.createdAt);
|
|
40
|
+
const dateComparison = rightSortDate.getTime() - leftSortDate.getTime();
|
|
41
|
+
if (dateComparison !== 0) {
|
|
42
|
+
return dateComparison;
|
|
43
|
+
}
|
|
44
|
+
const leftCreatedAt = parseDate(left.createdAt);
|
|
45
|
+
const rightCreatedAt = parseDate(right.createdAt);
|
|
46
|
+
const createdDateComparison = rightCreatedAt.getTime() - leftCreatedAt.getTime();
|
|
47
|
+
if (createdDateComparison !== 0) {
|
|
48
|
+
return createdDateComparison;
|
|
49
|
+
}
|
|
50
|
+
return left.path.localeCompare(right.path);
|
|
51
|
+
}
|
|
52
|
+
function parseThreadListEntries(document) {
|
|
53
|
+
const entries = [];
|
|
54
|
+
for (const child of document.root.getChildren()) {
|
|
55
|
+
if (child.tagName !== "thread") {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
const rawPath = child.getAttribute("path");
|
|
59
|
+
if (typeof rawPath !== "string" || rawPath.trim() === "") {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
const path = rawPath.trim();
|
|
63
|
+
const rawName = child.getAttribute("name");
|
|
64
|
+
const rawCreatedAt = child.getAttribute("created_at");
|
|
65
|
+
const rawModifiedAt = child.getAttribute("modified_at");
|
|
66
|
+
entries.push({
|
|
67
|
+
element: child,
|
|
68
|
+
path,
|
|
69
|
+
name: typeof rawName === "string" && rawName.trim() !== "" ? rawName.trim() : defaultThreadDisplayNameFromPath(path),
|
|
70
|
+
createdAt: typeof rawCreatedAt === "string" ? rawCreatedAt : "",
|
|
71
|
+
modifiedAt: typeof rawModifiedAt === "string" ? rawModifiedAt : ""
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
entries.sort(compareThreadEntries);
|
|
75
|
+
return entries;
|
|
76
|
+
}
|
|
77
|
+
function threadEntriesEqual(left, right) {
|
|
78
|
+
return left.length === right.length && left.every((entry, index) => {
|
|
79
|
+
const other = right[index];
|
|
80
|
+
return entry.path === other?.path && entry.name === other.name && entry.createdAt === other.createdAt && entry.modifiedAt === other.modifiedAt;
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
function describeError(error) {
|
|
84
|
+
if (error instanceof Error && error.message.trim() !== "") {
|
|
85
|
+
return error.message;
|
|
86
|
+
}
|
|
87
|
+
return `${error}`;
|
|
88
|
+
}
|
|
89
|
+
async function closeDocument(room, path) {
|
|
90
|
+
try {
|
|
91
|
+
await room.sync.close(path);
|
|
92
|
+
} catch {
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function useIsWideLayout(minWidth) {
|
|
96
|
+
const [matches, setMatches] = useState(false);
|
|
97
|
+
useEffect(() => {
|
|
98
|
+
if (typeof window === "undefined") {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const mediaQuery = window.matchMedia(`(min-width: ${minWidth}px)`);
|
|
102
|
+
const updateMatches = (event) => {
|
|
103
|
+
setMatches(event?.matches ?? mediaQuery.matches);
|
|
104
|
+
};
|
|
105
|
+
updateMatches();
|
|
106
|
+
mediaQuery.addEventListener("change", updateMatches);
|
|
107
|
+
return () => {
|
|
108
|
+
mediaQuery.removeEventListener("change", updateMatches);
|
|
109
|
+
};
|
|
110
|
+
}, [minWidth]);
|
|
111
|
+
return matches;
|
|
112
|
+
}
|
|
113
|
+
function useThreadListDocument({
|
|
114
|
+
room,
|
|
115
|
+
path
|
|
116
|
+
}) {
|
|
117
|
+
const [document, setDocument] = useState(null);
|
|
118
|
+
const [entries, setEntries] = useState([]);
|
|
119
|
+
const [loading, setLoading] = useState(path !== null);
|
|
120
|
+
const [error, setError] = useState(null);
|
|
121
|
+
const syncDocumentState = useCallback((nextDocument) => {
|
|
122
|
+
const nextEntries = parseThreadListEntries(nextDocument);
|
|
123
|
+
setEntries((currentEntries) => threadEntriesEqual(currentEntries, nextEntries) ? currentEntries : nextEntries);
|
|
124
|
+
}, []);
|
|
125
|
+
useEffect(() => {
|
|
126
|
+
let cancelled = false;
|
|
127
|
+
let opened = false;
|
|
128
|
+
if (path === null) {
|
|
129
|
+
setDocument(null);
|
|
130
|
+
setEntries([]);
|
|
131
|
+
setLoading(false);
|
|
132
|
+
setError(null);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
setDocument(null);
|
|
136
|
+
setEntries([]);
|
|
137
|
+
setLoading(true);
|
|
138
|
+
setError(null);
|
|
139
|
+
void room.sync.open(path).then((nextDocument) => {
|
|
140
|
+
if (cancelled) {
|
|
141
|
+
void closeDocument(room, path);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
opened = true;
|
|
145
|
+
setDocument(nextDocument);
|
|
146
|
+
syncDocumentState(nextDocument);
|
|
147
|
+
setLoading(false);
|
|
148
|
+
setError(null);
|
|
149
|
+
}).catch((nextError) => {
|
|
150
|
+
if (cancelled) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
setDocument(null);
|
|
154
|
+
setEntries([]);
|
|
155
|
+
setLoading(false);
|
|
156
|
+
setError(nextError);
|
|
157
|
+
});
|
|
158
|
+
return () => {
|
|
159
|
+
cancelled = true;
|
|
160
|
+
if (opened) {
|
|
161
|
+
void closeDocument(room, path);
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
}, [path, room, syncDocumentState]);
|
|
165
|
+
useDocumentChanged({
|
|
166
|
+
document,
|
|
167
|
+
onChanged: syncDocumentState
|
|
168
|
+
});
|
|
169
|
+
return {
|
|
170
|
+
document,
|
|
171
|
+
entries,
|
|
172
|
+
loading,
|
|
173
|
+
error
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
function ThreadListRow({
|
|
177
|
+
title,
|
|
178
|
+
selected,
|
|
179
|
+
onClick,
|
|
180
|
+
icon,
|
|
181
|
+
trailing
|
|
182
|
+
}) {
|
|
183
|
+
return /* @__PURE__ */ jsx("div", { className: "px-2 py-1", children: /* @__PURE__ */ jsxs(
|
|
184
|
+
"div",
|
|
185
|
+
{
|
|
186
|
+
className: cn(
|
|
187
|
+
"flex min-w-0 items-center rounded-lg border border-transparent transition-colors",
|
|
188
|
+
selected ? "bg-accent text-accent-foreground" : "text-muted-foreground hover:bg-accent/50 hover:text-foreground"
|
|
189
|
+
),
|
|
190
|
+
children: [
|
|
191
|
+
/* @__PURE__ */ jsxs(
|
|
192
|
+
"button",
|
|
193
|
+
{
|
|
194
|
+
type: "button",
|
|
195
|
+
className: "flex min-w-0 flex-1 items-center gap-3 px-3 py-2 text-left",
|
|
196
|
+
onClick,
|
|
197
|
+
children: [
|
|
198
|
+
/* @__PURE__ */ jsx("span", { className: "flex h-4 w-4 shrink-0 items-center justify-center", children: icon }),
|
|
199
|
+
/* @__PURE__ */ jsx(
|
|
200
|
+
"span",
|
|
201
|
+
{
|
|
202
|
+
className: cn(
|
|
203
|
+
"truncate text-sm font-medium",
|
|
204
|
+
selected ? "text-accent-foreground" : "text-foreground"
|
|
205
|
+
),
|
|
206
|
+
children: title
|
|
207
|
+
}
|
|
208
|
+
)
|
|
209
|
+
]
|
|
210
|
+
}
|
|
211
|
+
),
|
|
212
|
+
/* @__PURE__ */ jsx("div", { className: "shrink-0 pr-1", children: trailing ?? /* @__PURE__ */ jsx("div", { className: "h-8 w-8" }) })
|
|
213
|
+
]
|
|
214
|
+
}
|
|
215
|
+
) });
|
|
216
|
+
}
|
|
217
|
+
function ThreadListEntryRow({
|
|
218
|
+
room,
|
|
219
|
+
entry,
|
|
220
|
+
agentName,
|
|
221
|
+
selected,
|
|
222
|
+
onSelect,
|
|
223
|
+
onRename
|
|
224
|
+
}) {
|
|
225
|
+
const status = useThreadStatus({ room, path: entry.path, agentName });
|
|
226
|
+
const iconClassName = selected ? "text-accent-foreground" : "text-muted-foreground";
|
|
227
|
+
const hasStatus = status.text?.trim() !== "";
|
|
228
|
+
return /* @__PURE__ */ jsx(
|
|
229
|
+
ThreadListRow,
|
|
230
|
+
{
|
|
231
|
+
title: entry.name,
|
|
232
|
+
selected,
|
|
233
|
+
onClick: () => onSelect(entry),
|
|
234
|
+
icon: hasStatus ? /* @__PURE__ */ jsx(Spinner, { size: "sm", className: iconClassName }) : selected ? /* @__PURE__ */ jsx(Check, { className: cn("h-4 w-4", iconClassName) }) : /* @__PURE__ */ jsx(MessageSquare, { className: cn("h-4 w-4", iconClassName) }),
|
|
235
|
+
trailing: /* @__PURE__ */ jsx(
|
|
236
|
+
Button,
|
|
237
|
+
{
|
|
238
|
+
type: "button",
|
|
239
|
+
variant: "ghost",
|
|
240
|
+
size: "icon",
|
|
241
|
+
className: "h-8 w-8 rounded-md",
|
|
242
|
+
"aria-label": `Rename ${entry.name}`,
|
|
243
|
+
onClick: () => onRename(entry),
|
|
244
|
+
children: /* @__PURE__ */ jsx(Pencil, { className: "h-4 w-4" })
|
|
245
|
+
}
|
|
246
|
+
)
|
|
247
|
+
}
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
function ThreadListPanel({
|
|
251
|
+
room,
|
|
252
|
+
threadList,
|
|
253
|
+
selectedThreadPath,
|
|
254
|
+
agentName,
|
|
255
|
+
onSelectThread,
|
|
256
|
+
onClearSelection,
|
|
257
|
+
onRenameThread
|
|
258
|
+
}) {
|
|
259
|
+
const { entries, error, loading } = threadList;
|
|
260
|
+
const hasSelectedEntry = selectedThreadPath !== null && entries.some((entry) => entry.path === selectedThreadPath);
|
|
261
|
+
const showPendingNewThreadSelection = selectedThreadPath === null || !hasSelectedEntry;
|
|
262
|
+
return /* @__PURE__ */ jsx("div", { className: "flex h-full min-h-0 flex-col overflow-hidden rounded-2xl border bg-background", children: loading ? /* @__PURE__ */ jsx("div", { className: "flex min-h-0 flex-1 items-center justify-center p-6", children: /* @__PURE__ */ jsx(Spinner, { size: "lg", className: "text-muted-foreground" }) }) : error ? /* @__PURE__ */ jsx("div", { className: "flex min-h-0 flex-1 items-center justify-center p-6 text-center text-sm text-muted-foreground", children: `Unable to load threads: ${describeError(error)}` }) : /* @__PURE__ */ jsxs("div", { className: "flex min-h-0 flex-1 flex-col overflow-y-auto py-1", children: [
|
|
263
|
+
/* @__PURE__ */ jsx(
|
|
264
|
+
ThreadListRow,
|
|
265
|
+
{
|
|
266
|
+
title: "New thread",
|
|
267
|
+
selected: showPendingNewThreadSelection,
|
|
268
|
+
onClick: onClearSelection,
|
|
269
|
+
icon: showPendingNewThreadSelection ? /* @__PURE__ */ jsx(Check, { className: "h-4 w-4 text-accent-foreground" }) : /* @__PURE__ */ jsx(MessageSquarePlus, { className: "h-4 w-4 text-muted-foreground" })
|
|
270
|
+
}
|
|
271
|
+
),
|
|
272
|
+
entries.length === 0 && showPendingNewThreadSelection ? /* @__PURE__ */ jsx("div", { className: "flex min-h-0 flex-1 items-center justify-center px-4 py-6 text-center text-sm text-muted-foreground", children: "No threads yet" }) : null,
|
|
273
|
+
entries.map((entry) => /* @__PURE__ */ jsx(
|
|
274
|
+
ThreadListEntryRow,
|
|
275
|
+
{
|
|
276
|
+
room,
|
|
277
|
+
entry,
|
|
278
|
+
agentName,
|
|
279
|
+
selected: entry.path === selectedThreadPath,
|
|
280
|
+
onSelect: onSelectThread,
|
|
281
|
+
onRename: onRenameThread
|
|
282
|
+
},
|
|
283
|
+
entry.path
|
|
284
|
+
))
|
|
285
|
+
] }) });
|
|
286
|
+
}
|
|
287
|
+
function MultiThreadUnavailable() {
|
|
288
|
+
return /* @__PURE__ */ jsx("div", { className: "flex min-h-0 flex-1 items-center justify-center px-4 py-8", children: /* @__PURE__ */ jsx("div", { className: "w-full max-w-[912px] rounded-3xl border border-destructive/30 bg-destructive/5 p-6 text-destructive", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
|
|
289
|
+
/* @__PURE__ */ jsx(AlertTriangle, { className: "mt-0.5 h-5 w-5 shrink-0" }),
|
|
290
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
291
|
+
/* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold", children: "Unable to start a new thread" }),
|
|
292
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-destructive/80", children: "No chat agent is selected." })
|
|
293
|
+
] })
|
|
294
|
+
] }) }) });
|
|
295
|
+
}
|
|
296
|
+
function ChatBotView({
|
|
297
|
+
room,
|
|
298
|
+
path,
|
|
299
|
+
documentPath,
|
|
300
|
+
participants,
|
|
301
|
+
agentName,
|
|
302
|
+
threadDisplayMode = ChatThreadDisplayMode.SingleThread,
|
|
303
|
+
threadDir,
|
|
304
|
+
threadListPath,
|
|
305
|
+
toolkit,
|
|
306
|
+
tool,
|
|
307
|
+
centerComposer = false,
|
|
308
|
+
emptyStateTitle = "No threads yet",
|
|
309
|
+
emptyStateDescription = "Start a new conversation to see it here.",
|
|
310
|
+
selectedThreadPath,
|
|
311
|
+
onSelectedThreadPathChanged,
|
|
312
|
+
onSelectedThreadResolved,
|
|
313
|
+
onThreadResolved,
|
|
314
|
+
newThreadResetVersion = 0,
|
|
315
|
+
showThreadList = true,
|
|
316
|
+
threadListWidth = 280,
|
|
317
|
+
threadListCollapsedHeight = 220
|
|
318
|
+
}) {
|
|
319
|
+
const isWideLayout = useIsWideLayout(multiThreadLayoutBreakpointPx);
|
|
320
|
+
const resolvedDocumentPath = useMemo(
|
|
321
|
+
() => normalizePath(documentPath ?? path),
|
|
322
|
+
[documentPath, path]
|
|
323
|
+
);
|
|
324
|
+
const resolvedSingleThreadPath = useMemo(
|
|
325
|
+
() => resolvedDocumentPath ?? chatDocumentPath(agentName, { threadDir }),
|
|
326
|
+
[agentName, resolvedDocumentPath, threadDir]
|
|
327
|
+
);
|
|
328
|
+
const explicitSelectedThreadPath = selectedThreadPath !== void 0 ? normalizePath(selectedThreadPath) : void 0;
|
|
329
|
+
const legacySelectedThreadPath = threadDisplayMode === ChatThreadDisplayMode.MultiThreadComposer ? resolvedDocumentPath : null;
|
|
330
|
+
const [internalSelectedThreadPath, setInternalSelectedThreadPath] = useState(() => explicitSelectedThreadPath ?? legacySelectedThreadPath ?? null);
|
|
331
|
+
const previousLegacySelectedThreadPathRef = useRef(legacySelectedThreadPath);
|
|
332
|
+
const previousNewThreadResetVersionRef = useRef(newThreadResetVersion);
|
|
333
|
+
const activeSelectedThreadPath = explicitSelectedThreadPath ?? internalSelectedThreadPath;
|
|
334
|
+
const resolvedThreadListDocumentPath = useMemo(
|
|
335
|
+
() => resolvedThreadListPath(threadListPath, { threadDir, agentName }),
|
|
336
|
+
[agentName, threadDir, threadListPath]
|
|
337
|
+
);
|
|
338
|
+
const threadList = useThreadListDocument({
|
|
339
|
+
room,
|
|
340
|
+
path: threadDisplayMode === ChatThreadDisplayMode.MultiThreadComposer && showThreadList && resolvedThreadListDocumentPath !== null ? resolvedThreadListDocumentPath : null
|
|
341
|
+
});
|
|
342
|
+
useEffect(() => {
|
|
343
|
+
if (explicitSelectedThreadPath === void 0) {
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
setInternalSelectedThreadPath(explicitSelectedThreadPath);
|
|
347
|
+
}, [explicitSelectedThreadPath]);
|
|
348
|
+
useEffect(() => {
|
|
349
|
+
if (explicitSelectedThreadPath !== void 0) {
|
|
350
|
+
previousLegacySelectedThreadPathRef.current = legacySelectedThreadPath;
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
if (legacySelectedThreadPath !== previousLegacySelectedThreadPathRef.current) {
|
|
354
|
+
setInternalSelectedThreadPath(legacySelectedThreadPath);
|
|
355
|
+
}
|
|
356
|
+
previousLegacySelectedThreadPathRef.current = legacySelectedThreadPath;
|
|
357
|
+
}, [explicitSelectedThreadPath, legacySelectedThreadPath]);
|
|
358
|
+
const emitResolvedThread = useCallback((nextPath, displayName) => {
|
|
359
|
+
onSelectedThreadResolved?.(nextPath, displayName);
|
|
360
|
+
onThreadResolved?.(nextPath, displayName);
|
|
361
|
+
}, [onSelectedThreadResolved, onThreadResolved]);
|
|
362
|
+
const handleSelectedThreadPathChanged = useCallback((nextPath) => {
|
|
363
|
+
const normalizedNextPath = normalizePath(nextPath);
|
|
364
|
+
if (explicitSelectedThreadPath === void 0) {
|
|
365
|
+
setInternalSelectedThreadPath(normalizedNextPath);
|
|
366
|
+
}
|
|
367
|
+
onSelectedThreadPathChanged?.(normalizedNextPath);
|
|
368
|
+
}, [explicitSelectedThreadPath, onSelectedThreadPathChanged]);
|
|
369
|
+
const setSelectedThread = useCallback((nextPath, displayName) => {
|
|
370
|
+
const normalizedNextPath = normalizePath(nextPath);
|
|
371
|
+
handleSelectedThreadPathChanged(normalizedNextPath);
|
|
372
|
+
emitResolvedThread(normalizedNextPath, displayName);
|
|
373
|
+
}, [emitResolvedThread, handleSelectedThreadPathChanged]);
|
|
374
|
+
useEffect(() => {
|
|
375
|
+
if (threadDisplayMode !== ChatThreadDisplayMode.MultiThreadComposer) {
|
|
376
|
+
previousNewThreadResetVersionRef.current = newThreadResetVersion;
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
if (previousNewThreadResetVersionRef.current !== newThreadResetVersion && activeSelectedThreadPath !== null) {
|
|
380
|
+
setSelectedThread(null, null);
|
|
381
|
+
}
|
|
382
|
+
previousNewThreadResetVersionRef.current = newThreadResetVersion;
|
|
383
|
+
}, [activeSelectedThreadPath, newThreadResetVersion, setSelectedThread, threadDisplayMode]);
|
|
384
|
+
const handleRenameThread = useCallback((entry) => {
|
|
385
|
+
if (typeof window === "undefined") {
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
const nextName = window.prompt("Rename thread", entry.name);
|
|
389
|
+
if (nextName === null) {
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
const trimmedName = nextName.trim();
|
|
393
|
+
if (trimmedName === "" || trimmedName === entry.name) {
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
entry.element.setAttribute("name", trimmedName);
|
|
397
|
+
if (entry.path === activeSelectedThreadPath) {
|
|
398
|
+
emitResolvedThread(entry.path, trimmedName);
|
|
399
|
+
}
|
|
400
|
+
}, [activeSelectedThreadPath, emitResolvedThread]);
|
|
401
|
+
if (threadDisplayMode !== ChatThreadDisplayMode.MultiThreadComposer) {
|
|
402
|
+
return /* @__PURE__ */ jsx(
|
|
403
|
+
Chat,
|
|
404
|
+
{
|
|
405
|
+
room,
|
|
406
|
+
path: resolvedSingleThreadPath,
|
|
407
|
+
participants,
|
|
408
|
+
agentName,
|
|
409
|
+
toolkit,
|
|
410
|
+
tool,
|
|
411
|
+
centerComposer,
|
|
412
|
+
emptyStateTitle,
|
|
413
|
+
emptyStateDescription,
|
|
414
|
+
onThreadResolved
|
|
415
|
+
}
|
|
416
|
+
);
|
|
417
|
+
}
|
|
418
|
+
if (!agentName?.trim()) {
|
|
419
|
+
return /* @__PURE__ */ jsx(MultiThreadUnavailable, {});
|
|
420
|
+
}
|
|
421
|
+
const content = /* @__PURE__ */ jsx(
|
|
422
|
+
MultiThreadView,
|
|
423
|
+
{
|
|
424
|
+
room,
|
|
425
|
+
agentName,
|
|
426
|
+
toolkit,
|
|
427
|
+
tool,
|
|
428
|
+
selectedThreadPath: activeSelectedThreadPath,
|
|
429
|
+
onSelectedThreadPathChanged: handleSelectedThreadPathChanged,
|
|
430
|
+
onSelectedThreadResolved: emitResolvedThread,
|
|
431
|
+
newThreadResetVersion,
|
|
432
|
+
centerComposer,
|
|
433
|
+
emptyStateTitle,
|
|
434
|
+
emptyStateDescription,
|
|
435
|
+
builder: (threadPath) => /* @__PURE__ */ jsx(
|
|
436
|
+
Chat,
|
|
437
|
+
{
|
|
438
|
+
room,
|
|
439
|
+
path: threadPath,
|
|
440
|
+
participants,
|
|
441
|
+
agentName,
|
|
442
|
+
toolkit,
|
|
443
|
+
tool,
|
|
444
|
+
centerComposer,
|
|
445
|
+
emptyStateTitle,
|
|
446
|
+
emptyStateDescription
|
|
447
|
+
}
|
|
448
|
+
)
|
|
449
|
+
}
|
|
450
|
+
);
|
|
451
|
+
if (!showThreadList || resolvedThreadListDocumentPath === null) {
|
|
452
|
+
return content;
|
|
453
|
+
}
|
|
454
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-1 h-full", isWideLayout ? "flex-row items-stretch" : "flex-col"), children: [
|
|
455
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-col h-full min-h-0 min-w-0 flex-1", children: content }),
|
|
456
|
+
/* @__PURE__ */ jsx(
|
|
457
|
+
"div",
|
|
458
|
+
{
|
|
459
|
+
className: cn("shrink-0 mr-4", isWideLayout ? "ml-3" : "mt-3"),
|
|
460
|
+
style: isWideLayout ? { width: threadListWidth } : { height: threadListCollapsedHeight },
|
|
461
|
+
children: /* @__PURE__ */ jsx(
|
|
462
|
+
ThreadListPanel,
|
|
463
|
+
{
|
|
464
|
+
room,
|
|
465
|
+
threadList,
|
|
466
|
+
selectedThreadPath: activeSelectedThreadPath,
|
|
467
|
+
agentName,
|
|
468
|
+
onSelectThread: (entry) => {
|
|
469
|
+
setSelectedThread(entry.path, entry.name);
|
|
470
|
+
},
|
|
471
|
+
onClearSelection: () => {
|
|
472
|
+
setSelectedThread(null, null);
|
|
473
|
+
},
|
|
474
|
+
onRenameThread: handleRenameThread
|
|
475
|
+
}
|
|
476
|
+
)
|
|
477
|
+
}
|
|
478
|
+
)
|
|
479
|
+
] });
|
|
480
|
+
}
|
|
481
|
+
export {
|
|
482
|
+
ChatBotView,
|
|
483
|
+
ChatThreadDisplayMode2 as ChatThreadDisplayMode,
|
|
484
|
+
chatDocumentPath2 as chatDocumentPath,
|
|
485
|
+
resolvedThreadListPath2 as resolvedThreadListPath
|
|
486
|
+
};
|
package/dist/esm/ChatInput.d.ts
CHANGED
|
@@ -1,12 +1,21 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { ReactElement } from "react";
|
|
2
|
+
import { ChatMessage } from "./chat-message";
|
|
3
|
+
import { type FileUpload } from "./file-attachment";
|
|
2
4
|
interface ChatInputProps {
|
|
3
|
-
onSubmit: (message: ChatMessage) => void
|
|
5
|
+
onSubmit: (message: ChatMessage) => void | Promise<void>;
|
|
4
6
|
onFilesSelected: (files: File[]) => void;
|
|
5
7
|
attachments: FileUpload[];
|
|
6
8
|
setAttachments: (attachments: FileUpload[]) => void;
|
|
7
9
|
onTextChange?: (text: string) => void;
|
|
8
10
|
onCancelRequest?: () => void;
|
|
9
11
|
showCancelButton?: boolean;
|
|
12
|
+
placeholder?: string;
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
clearOnSubmit?: boolean;
|
|
15
|
+
autoFocus?: boolean;
|
|
16
|
+
value?: string;
|
|
17
|
+
defaultValue?: string;
|
|
18
|
+
onValueChange?: (value: string) => void;
|
|
10
19
|
}
|
|
11
|
-
export declare function ChatInput({ onSubmit, onFilesSelected, attachments, setAttachments, onTextChange, onCancelRequest, showCancelButton }: ChatInputProps):
|
|
20
|
+
export declare function ChatInput({ onSubmit, onFilesSelected, attachments, setAttachments, onTextChange, onCancelRequest, showCancelButton, placeholder, disabled, clearOnSubmit, autoFocus, value: controlledValue, defaultValue, onValueChange, }: ChatInputProps): ReactElement;
|
|
12
21
|
export {};
|