@coffer-org/plugin-webchat 2.2.1 → 2.2.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.
|
@@ -6186,12 +6186,49 @@ function useMinWidth(name, fallback) {
|
|
|
6186
6186
|
}
|
|
6187
6187
|
//#endregion
|
|
6188
6188
|
//#region ../web/api.ts
|
|
6189
|
+
function uploadFileWithProgress(file, onProgress) {
|
|
6190
|
+
return new Promise((resolve) => {
|
|
6191
|
+
const xhr = new XMLHttpRequest();
|
|
6192
|
+
xhr.open("POST", "/api/upload");
|
|
6193
|
+
xhr.upload.addEventListener("progress", (event) => {
|
|
6194
|
+
if (event.lengthComputable) onProgress(Math.min(100, Math.round(event.loaded / event.total * 100)));
|
|
6195
|
+
});
|
|
6196
|
+
xhr.addEventListener("load", () => {
|
|
6197
|
+
if (xhr.status < 200 || xhr.status >= 300) {
|
|
6198
|
+
resolve(null);
|
|
6199
|
+
return;
|
|
6200
|
+
}
|
|
6201
|
+
try {
|
|
6202
|
+
const j = JSON.parse(xhr.responseText);
|
|
6203
|
+
const name = j.name ?? j.filename;
|
|
6204
|
+
if (!name) {
|
|
6205
|
+
resolve(null);
|
|
6206
|
+
return;
|
|
6207
|
+
}
|
|
6208
|
+
onProgress(100);
|
|
6209
|
+
resolve({
|
|
6210
|
+
name,
|
|
6211
|
+
...j.mime ? { mime: j.mime } : {},
|
|
6212
|
+
...j.size != null ? { size: j.size } : {}
|
|
6213
|
+
});
|
|
6214
|
+
} catch {
|
|
6215
|
+
resolve(null);
|
|
6216
|
+
}
|
|
6217
|
+
});
|
|
6218
|
+
xhr.addEventListener("error", () => resolve(null));
|
|
6219
|
+
xhr.addEventListener("abort", () => resolve(null));
|
|
6220
|
+
const fd = new FormData();
|
|
6221
|
+
fd.append("file", file);
|
|
6222
|
+
xhr.send(fd);
|
|
6223
|
+
});
|
|
6224
|
+
}
|
|
6189
6225
|
/**
|
|
6190
6226
|
* Upload a file → descriptor from the server (or null).
|
|
6191
6227
|
* Take mime/size from the response, not the browser File: the server overwrites
|
|
6192
6228
|
* them from disk anyway, so client values would only be noise.
|
|
6193
6229
|
*/
|
|
6194
|
-
async function uploadFile(file) {
|
|
6230
|
+
async function uploadFile(file, onProgress) {
|
|
6231
|
+
if (onProgress) return uploadFileWithProgress(file, onProgress);
|
|
6195
6232
|
const fd = new FormData();
|
|
6196
6233
|
fd.append("file", file);
|
|
6197
6234
|
const r = await fetch("/api/upload", {
|
|
@@ -29254,7 +29291,7 @@ var Bubble = memo(function Bubble({ role, text, reasoning, attachments }) {
|
|
|
29254
29291
|
});
|
|
29255
29292
|
//#endregion
|
|
29256
29293
|
//#region src/ui/ChatComposer.tsx
|
|
29257
|
-
function ChatComposer({ streaming, onSend, onStop, attachments, uploading, uploadError, onPickFiles, onRemoveAttachment }) {
|
|
29294
|
+
function ChatComposer({ streaming, onSend, onStop, attachments, uploading, uploadError, uploadProgress, onPickFiles, onRemoveAttachment }) {
|
|
29258
29295
|
const { t } = useTranslation();
|
|
29259
29296
|
const [text, setText] = useState("");
|
|
29260
29297
|
function submit() {
|
|
@@ -29263,7 +29300,7 @@ function ChatComposer({ streaming, onSend, onStop, attachments, uploading, uploa
|
|
|
29263
29300
|
}
|
|
29264
29301
|
return /* @__PURE__ */ jsxs("div", {
|
|
29265
29302
|
className: "flex shrink-0 flex-col gap-2 border-t border-border p-2",
|
|
29266
|
-
children: [(attachments.length > 0 || uploadError) && /* @__PURE__ */ jsxs("div", {
|
|
29303
|
+
children: [(attachments.length > 0 || uploading || uploadError) && /* @__PURE__ */ jsxs("div", {
|
|
29267
29304
|
className: "flex flex-wrap items-center gap-1.5 px-1",
|
|
29268
29305
|
"data-chat-attachments": true,
|
|
29269
29306
|
children: [
|
|
@@ -29287,10 +29324,31 @@ function ChatComposer({ streaming, onSend, onStop, attachments, uploading, uploa
|
|
|
29287
29324
|
})
|
|
29288
29325
|
]
|
|
29289
29326
|
}, `${a.name}-${i}`)),
|
|
29290
|
-
uploading && /* @__PURE__ */
|
|
29291
|
-
|
|
29292
|
-
|
|
29293
|
-
|
|
29327
|
+
uploading && /* @__PURE__ */ jsxs("div", {
|
|
29328
|
+
className: "flex min-w-32 flex-1 items-center gap-2",
|
|
29329
|
+
"aria-label": t("webchat.uploading"),
|
|
29330
|
+
children: [
|
|
29331
|
+
/* @__PURE__ */ jsx(LoaderCircle, {
|
|
29332
|
+
size: 14,
|
|
29333
|
+
className: "shrink-0 animate-spin text-muted"
|
|
29334
|
+
}),
|
|
29335
|
+
/* @__PURE__ */ jsx("div", {
|
|
29336
|
+
role: "progressbar",
|
|
29337
|
+
"aria-label": t("webchat.uploadProgress"),
|
|
29338
|
+
"aria-valuemin": 0,
|
|
29339
|
+
"aria-valuemax": 100,
|
|
29340
|
+
"aria-valuenow": uploadProgress,
|
|
29341
|
+
className: "h-1.5 min-w-0 flex-1 overflow-hidden rounded-full bg-border",
|
|
29342
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
29343
|
+
className: "h-full rounded-full bg-accent transition-[width]",
|
|
29344
|
+
style: { width: `${uploadProgress}%` }
|
|
29345
|
+
})
|
|
29346
|
+
}),
|
|
29347
|
+
/* @__PURE__ */ jsxs("span", {
|
|
29348
|
+
className: "text-xs tabular-nums text-muted",
|
|
29349
|
+
children: [uploadProgress, "%"]
|
|
29350
|
+
})
|
|
29351
|
+
]
|
|
29294
29352
|
}),
|
|
29295
29353
|
uploadError && /* @__PURE__ */ jsx("span", {
|
|
29296
29354
|
className: "text-xs text-danger",
|
|
@@ -29443,6 +29501,7 @@ function ChatWidget() {
|
|
|
29443
29501
|
const [threadsOpen, setThreadsOpen] = useState(false);
|
|
29444
29502
|
const [attachments, setAttachments] = useState([]);
|
|
29445
29503
|
const [uploading, setUploading] = useState(false);
|
|
29504
|
+
const [uploadProgress, setUploadProgress] = useState(0);
|
|
29446
29505
|
const [uploadError, setUploadError] = useState(null);
|
|
29447
29506
|
const wide = useMinWidth("sm", 640);
|
|
29448
29507
|
const wideNav = useMinWidth("nav", 768);
|
|
@@ -29486,6 +29545,7 @@ function ChatWidget() {
|
|
|
29486
29545
|
if (!files.length) return;
|
|
29487
29546
|
setUploadError(null);
|
|
29488
29547
|
setUploading(true);
|
|
29548
|
+
setUploadProgress(0);
|
|
29489
29549
|
const added = [];
|
|
29490
29550
|
let error = null;
|
|
29491
29551
|
for (const file of files) {
|
|
@@ -29494,7 +29554,8 @@ function ChatWidget() {
|
|
|
29494
29554
|
continue;
|
|
29495
29555
|
}
|
|
29496
29556
|
try {
|
|
29497
|
-
|
|
29557
|
+
setUploadProgress(0);
|
|
29558
|
+
const rec = await uploadFile(file, setUploadProgress);
|
|
29498
29559
|
if (rec) added.push({
|
|
29499
29560
|
...rec,
|
|
29500
29561
|
label: file.name
|
|
@@ -29506,6 +29567,7 @@ function ChatWidget() {
|
|
|
29506
29567
|
}
|
|
29507
29568
|
if (added.length) setAttachments((prev) => [...prev, ...added]);
|
|
29508
29569
|
setUploading(false);
|
|
29570
|
+
setUploadProgress(0);
|
|
29509
29571
|
if (error) setUploadError(error);
|
|
29510
29572
|
}, []);
|
|
29511
29573
|
const hasConversation = chat.messages.length > 0 || chat.pending !== null;
|
|
@@ -29564,6 +29626,7 @@ function ChatWidget() {
|
|
|
29564
29626
|
streaming: chat.pending !== null,
|
|
29565
29627
|
attachments,
|
|
29566
29628
|
uploading,
|
|
29629
|
+
uploadProgress,
|
|
29567
29630
|
uploadError,
|
|
29568
29631
|
onPickFiles: (files) => void pickFiles(Array.from(files)),
|
|
29569
29632
|
onRemoveAttachment: (index) => setAttachments((prev) => prev.filter((_, i) => i !== index)),
|
|
@@ -29582,7 +29645,7 @@ function ChatWidget() {
|
|
|
29582
29645
|
});
|
|
29583
29646
|
if (mode === "bubble") return /* @__PURE__ */ jsx("button", {
|
|
29584
29647
|
"aria-label": t("webchat.open"),
|
|
29585
|
-
onClick: () => setMode("panel"),
|
|
29648
|
+
onClick: () => setMode(wide ? "panel" : "modal"),
|
|
29586
29649
|
className: "fixed bottom-20 right-4 z-40 grid h-14 w-14 place-items-center rounded-full bg-accent text-white shadow-lg nav:bottom-4",
|
|
29587
29650
|
children: /* @__PURE__ */ jsx(MessageCircle, { size: 24 })
|
|
29588
29651
|
});
|
package/dist/web.js
CHANGED
|
@@ -11,7 +11,7 @@ import { definePluginUI } from "@coffer-org/web-sdk";
|
|
|
11
11
|
var ui_default = definePluginUI({ slots: [{
|
|
12
12
|
slot: "overlay",
|
|
13
13
|
id: "webchat",
|
|
14
|
-
load: () => import("./ChatWidget-
|
|
14
|
+
load: () => import("./ChatWidget-1G0ZxQH2.js")
|
|
15
15
|
}] });
|
|
16
16
|
//#endregion
|
|
17
17
|
export { ui_default as default };
|