@coffer-org/plugin-webchat 5.0.0 → 6.0.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.
|
@@ -23959,42 +23959,35 @@ function AgentPicker({ agents, defaultAgentId, selection, onChange }) {
|
|
|
23959
23959
|
if (ladder) {
|
|
23960
23960
|
const level = ladder.indexOf(current) + 1;
|
|
23961
23961
|
const shown = preview ?? level;
|
|
23962
|
-
const previewRow = preview === null ? void 0 : ladder[preview - 1];
|
|
23963
23962
|
const levelName = (row, n) => `${row.label} · ${t("webchat.level", {
|
|
23964
23963
|
value: n,
|
|
23965
23964
|
max: ladder.length
|
|
23966
23965
|
})}`;
|
|
23967
|
-
return /* @__PURE__ */
|
|
23968
|
-
|
|
23969
|
-
|
|
23970
|
-
|
|
23971
|
-
|
|
23972
|
-
|
|
23973
|
-
children:
|
|
23974
|
-
|
|
23975
|
-
|
|
23976
|
-
|
|
23977
|
-
|
|
23978
|
-
|
|
23979
|
-
|
|
23980
|
-
|
|
23981
|
-
|
|
23982
|
-
|
|
23983
|
-
|
|
23984
|
-
|
|
23985
|
-
|
|
23986
|
-
|
|
23987
|
-
|
|
23988
|
-
|
|
23989
|
-
|
|
23990
|
-
|
|
23991
|
-
|
|
23992
|
-
}) }, `${r.agentId}/${r.presetId}`);
|
|
23993
|
-
})
|
|
23994
|
-
}), previewRow && /* @__PURE__ */ jsx("span", {
|
|
23995
|
-
className: "min-w-0 truncate text-xs text-muted",
|
|
23996
|
-
children: previewRow.hint || previewRow.label
|
|
23997
|
-
})]
|
|
23966
|
+
return /* @__PURE__ */ jsx("ul", {
|
|
23967
|
+
"aria-label": t("webchat.agentPicker"),
|
|
23968
|
+
className: "flex shrink-0 items-center",
|
|
23969
|
+
onPointerLeave: () => setPreview(null),
|
|
23970
|
+
children: ladder.map((r, i) => {
|
|
23971
|
+
const n = i + 1;
|
|
23972
|
+
return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("button", {
|
|
23973
|
+
type: "button",
|
|
23974
|
+
...r === current ? { "aria-current": true } : {},
|
|
23975
|
+
"aria-label": levelName(r, n),
|
|
23976
|
+
className: "flex rounded p-1 focus-visible:outline-2 focus-visible:outline-accent",
|
|
23977
|
+
onPointerEnter: () => setPreview(n),
|
|
23978
|
+
onFocus: () => setPreview(n),
|
|
23979
|
+
onBlur: () => setPreview(null),
|
|
23980
|
+
onClick: () => onChange({
|
|
23981
|
+
agentId: r.agentId,
|
|
23982
|
+
presetId: r.presetId
|
|
23983
|
+
}),
|
|
23984
|
+
children: /* @__PURE__ */ jsx(Star, {
|
|
23985
|
+
size: 16,
|
|
23986
|
+
"aria-hidden": true,
|
|
23987
|
+
className: n <= shown ? "fill-yellow-400 text-yellow-400" : "text-border"
|
|
23988
|
+
})
|
|
23989
|
+
}) }, `${r.agentId}/${r.presetId}`);
|
|
23990
|
+
})
|
|
23998
23991
|
});
|
|
23999
23992
|
}
|
|
24000
23993
|
return /* @__PURE__ */ jsxs("div", {
|
|
@@ -24294,12 +24287,31 @@ function ChatDropSurface({ children, onFiles, className }) {
|
|
|
24294
24287
|
})]
|
|
24295
24288
|
});
|
|
24296
24289
|
}
|
|
24297
|
-
/**
|
|
24298
|
-
*
|
|
24299
|
-
*
|
|
24300
|
-
*
|
|
24301
|
-
function
|
|
24302
|
-
return
|
|
24290
|
+
/** The states the VIEWPORT offers, ordered from least to most expanded. `panel` — the 380px
|
|
24291
|
+
* floating window — exists only where it does not obstruct the page: on a narrow screen the
|
|
24292
|
+
* widget has exactly two states, the bubble and the full sheet. Every mode transition is a
|
|
24293
|
+
* move along this ladder, so no call site can put the widget into a mode its screen lacks. */
|
|
24294
|
+
function chatModes(wide) {
|
|
24295
|
+
return wide ? [
|
|
24296
|
+
"bubble",
|
|
24297
|
+
"panel",
|
|
24298
|
+
"modal"
|
|
24299
|
+
] : ["bubble", "modal"];
|
|
24300
|
+
}
|
|
24301
|
+
/** Where the widget rests once it is opened — expanded, but as little as the viewport allows.
|
|
24302
|
+
* Also where it returns after following a link from a response: on a wide screen the panel
|
|
24303
|
+
* does not obstruct the page the user just navigated to, while on a narrow one the sheet is
|
|
24304
|
+
* the only visible state, so the active conversation survives the navigation either way. */
|
|
24305
|
+
function restingMode(wide) {
|
|
24306
|
+
return chatModes(wide)[1];
|
|
24307
|
+
}
|
|
24308
|
+
/** One step along the ladder, clamped at both ends: `-1` is what collapse, Esc and a dialog
|
|
24309
|
+
* dismiss do, `+1` is expand. A mode this viewport no longer offers is re-homed by the effect
|
|
24310
|
+
* in the widget, not by stepping — the step always returns a mode from the current ladder. */
|
|
24311
|
+
function stepMode(mode, wide, delta) {
|
|
24312
|
+
const ladder = chatModes(wide);
|
|
24313
|
+
const next = ladder.indexOf(mode) + delta;
|
|
24314
|
+
return ladder[Math.min(ladder.length - 1, Math.max(0, next))];
|
|
24303
24315
|
}
|
|
24304
24316
|
function ChatWidget() {
|
|
24305
24317
|
const { t } = useTranslation();
|
|
@@ -24313,20 +24325,22 @@ function ChatWidget() {
|
|
|
24313
24325
|
const [uploadError, setUploadError] = useState(null);
|
|
24314
24326
|
const [retryFiles, setRetryFiles] = useState([]);
|
|
24315
24327
|
const wide = useMinWidth("sm", 640);
|
|
24316
|
-
const wideNav = useMinWidth("nav", 768);
|
|
24317
24328
|
const onChatNavigate = useCallback(() => {
|
|
24318
|
-
setMode(
|
|
24319
|
-
}, [
|
|
24329
|
+
setMode(restingMode(wide));
|
|
24330
|
+
}, [wide]);
|
|
24320
24331
|
const expandBtnRef = useRef(null);
|
|
24321
24332
|
const prevModeRef = useRef("bubble");
|
|
24322
24333
|
useEffect(() => {
|
|
24323
24334
|
if (mode !== "modal") return;
|
|
24324
24335
|
const onKey = (e) => {
|
|
24325
|
-
if (e.key === "Escape") setMode("
|
|
24336
|
+
if (e.key === "Escape") setMode(stepMode("modal", wide, -1));
|
|
24326
24337
|
};
|
|
24327
24338
|
window.addEventListener("keydown", onKey);
|
|
24328
24339
|
return () => window.removeEventListener("keydown", onKey);
|
|
24329
|
-
}, [mode]);
|
|
24340
|
+
}, [mode, wide]);
|
|
24341
|
+
useEffect(() => {
|
|
24342
|
+
if (!chatModes(wide).includes(mode)) setMode(restingMode(wide));
|
|
24343
|
+
}, [mode, wide]);
|
|
24330
24344
|
useEffect(() => {
|
|
24331
24345
|
if (mode === "panel" && prevModeRef.current === "modal") expandBtnRef.current?.focus();
|
|
24332
24346
|
if (mode !== "modal") setThreadsOpen(false);
|
|
@@ -24429,11 +24443,11 @@ function ChatWidget() {
|
|
|
24429
24443
|
onClick: startNew,
|
|
24430
24444
|
children: /* @__PURE__ */ jsx(Plus, { size: 16 })
|
|
24431
24445
|
}),
|
|
24432
|
-
/* @__PURE__ */ jsx("button", {
|
|
24446
|
+
chatModes(wide).includes("panel") && /* @__PURE__ */ jsx("button", {
|
|
24433
24447
|
ref: expandBtnRef,
|
|
24434
24448
|
"aria-label": mode === "modal" ? t("webchat.collapse") : t("webchat.expand"),
|
|
24435
24449
|
className: "rounded p-1 hover:bg-elevated",
|
|
24436
|
-
onClick: () => setMode(mode === "modal" ?
|
|
24450
|
+
onClick: () => setMode(stepMode(mode, wide, mode === "modal" ? -1 : 1)),
|
|
24437
24451
|
children: mode === "modal" ? /* @__PURE__ */ jsx(Minimize2, { size: 16 }) : /* @__PURE__ */ jsx(Maximize2, { size: 16 })
|
|
24438
24452
|
}),
|
|
24439
24453
|
/* @__PURE__ */ jsx("button", {
|
|
@@ -24489,7 +24503,7 @@ function ChatWidget() {
|
|
|
24489
24503
|
});
|
|
24490
24504
|
if (mode === "bubble") return /* @__PURE__ */ jsx("button", {
|
|
24491
24505
|
"aria-label": t("webchat.open"),
|
|
24492
|
-
onClick: () => setMode(wide
|
|
24506
|
+
onClick: () => setMode(restingMode(wide)),
|
|
24493
24507
|
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",
|
|
24494
24508
|
children: /* @__PURE__ */ jsx(MessageCircle, { size: 24 })
|
|
24495
24509
|
});
|
|
@@ -24501,7 +24515,7 @@ function ChatWidget() {
|
|
|
24501
24515
|
return /* @__PURE__ */ jsxs(Dialog, {
|
|
24502
24516
|
open: true,
|
|
24503
24517
|
modal: false,
|
|
24504
|
-
onOpenChange: (open) => !open && setMode("
|
|
24518
|
+
onOpenChange: (open) => !open && setMode(stepMode("modal", wide, -1)),
|
|
24505
24519
|
children: [/* @__PURE__ */ jsx("div", {
|
|
24506
24520
|
"data-chat-backdrop": true,
|
|
24507
24521
|
"aria-hidden": "true",
|
|
@@ -24536,4 +24550,4 @@ function ChatWidget() {
|
|
|
24536
24550
|
});
|
|
24537
24551
|
}
|
|
24538
24552
|
//#endregion
|
|
24539
|
-
export { ChatWidget, ChatWidget as default,
|
|
24553
|
+
export { ChatWidget, ChatWidget as default, chatModes, restingMode, stepMode };
|
package/dist/schema.js
CHANGED
|
@@ -4354,6 +4354,13 @@ function wrapKey(key, opts, meta) {
|
|
|
4354
4354
|
editor: opts.editor
|
|
4355
4355
|
}
|
|
4356
4356
|
};
|
|
4357
|
+
if (opts.activate) m = {
|
|
4358
|
+
...m,
|
|
4359
|
+
hints: {
|
|
4360
|
+
...m.hints,
|
|
4361
|
+
activate: opts.activate
|
|
4362
|
+
}
|
|
4363
|
+
};
|
|
4357
4364
|
if (opts.span !== void 0) m = {
|
|
4358
4365
|
...m,
|
|
4359
4366
|
hints: {
|
|
@@ -4754,6 +4761,7 @@ function resolveUnits(u) {
|
|
|
4754
4761
|
function normalizeOpts(rawIn) {
|
|
4755
4762
|
const raw = rawIn;
|
|
4756
4763
|
if (raw["view"] !== void 0) throw new Error("[normalizeOpts] `view` is gone — presentational options live in `ui: {}` (see CLAUDE.md § field author options and the field-types skill).");
|
|
4764
|
+
if (raw.ui?.["agent"] !== void 0) throw new Error("[normalizeOpts] `agent` is not presentation — declare it at the top level of the field call, not in `ui: {}`.");
|
|
4757
4765
|
const r = raw.rules ?? {};
|
|
4758
4766
|
const v = raw.ui ?? {};
|
|
4759
4767
|
const config = {};
|
|
@@ -4790,7 +4798,8 @@ function normalizeOpts(rawIn) {
|
|
|
4790
4798
|
emphasis: v.emphasis,
|
|
4791
4799
|
noLabel: v.noLabel,
|
|
4792
4800
|
role: v.role,
|
|
4793
|
-
editor: v.editor
|
|
4801
|
+
editor: v.editor,
|
|
4802
|
+
activate: v.activate
|
|
4794
4803
|
};
|
|
4795
4804
|
return Object.fromEntries(Object.entries(result).filter(([, val]) => val !== void 0));
|
|
4796
4805
|
}
|
|
@@ -9542,10 +9551,11 @@ var field = new Proxy({}, {
|
|
|
9542
9551
|
has: (_t, k) => k in composedField()
|
|
9543
9552
|
});
|
|
9544
9553
|
function toClient(field) {
|
|
9545
|
-
const { kind, label, required, prim, hints, options, strict, relation, json, hidden, derived, parts, cache } = field;
|
|
9554
|
+
const { kind, label, agent, required, prim, hints, options, strict, relation, json, hidden, derived, parts, cache } = field;
|
|
9546
9555
|
return {
|
|
9547
9556
|
kind,
|
|
9548
9557
|
label,
|
|
9558
|
+
...agent !== void 0 && { agent },
|
|
9549
9559
|
required,
|
|
9550
9560
|
prim,
|
|
9551
9561
|
hints,
|
|
@@ -9952,6 +9962,7 @@ function materialize(decl, name) {
|
|
|
9952
9962
|
const base = {
|
|
9953
9963
|
kind: type.kind,
|
|
9954
9964
|
label: opts.label ?? "",
|
|
9965
|
+
...opts.agent !== void 0 && { agent: opts.agent },
|
|
9955
9966
|
required,
|
|
9956
9967
|
prim: type.prim,
|
|
9957
9968
|
column: built.column,
|
|
@@ -9995,6 +10006,7 @@ function collectionGroup(key, opts, parts, collectionView) {
|
|
|
9995
10006
|
multiple: true,
|
|
9996
10007
|
required: opts.required ?? false,
|
|
9997
10008
|
label: opts.label ?? key,
|
|
10009
|
+
...opts.agent !== void 0 && { agent: opts.agent },
|
|
9998
10010
|
display: "wrap",
|
|
9999
10011
|
kind: collectionView,
|
|
10000
10012
|
fields: rowFields
|
package/dist/web.js
CHANGED
|
@@ -11,7 +11,7 @@ import { definePluginUI } from "@coffer-org/web-ui";
|
|
|
11
11
|
var ui_default = definePluginUI({ slots: [{
|
|
12
12
|
slot: "overlay",
|
|
13
13
|
id: "webchat",
|
|
14
|
-
load: () => import("./ChatWidget-
|
|
14
|
+
load: () => import("./ChatWidget-DFVDexpD.js")
|
|
15
15
|
}] });
|
|
16
16
|
//#endregion
|
|
17
17
|
export { ui_default as default };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coffer-org/plugin-webchat",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=24"
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"test:ui": "vitest run --root ."
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@coffer-org/sdk": "^
|
|
31
|
-
"@coffer-org/server": "^
|
|
30
|
+
"@coffer-org/sdk": "^6.0.0",
|
|
31
|
+
"@coffer-org/server": "^6.0.0",
|
|
32
32
|
"lucide-react": "^1.17.0",
|
|
33
33
|
"react-markdown": "^10.1.0",
|
|
34
34
|
"remark-gfm": "^4.0.1"
|