dsh-per-message-model 0.1.4 → 0.1.6
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/lib/client.js +55 -29
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -118,26 +118,37 @@ window.__ModuleLoader__.load({
|
|
|
118
118
|
* existing chip behavior (color change + title); a single click rolls the
|
|
119
119
|
* model name out from left to right like a scroll (icon rotates by a random
|
|
120
120
|
* angle); clicking again rolls it back (icon rotates back).
|
|
121
|
+
*
|
|
122
|
+
* Implemented WITHOUT React state on purpose: the DSH slot renderer mounts
|
|
123
|
+
* registrants through an error boundary and some hosts do not tolerate
|
|
124
|
+
* hook-based state in dock seats; the unfold/collapse is a pure DOM class
|
|
125
|
+
* toggle plus an inline transform on the icon, so it works in any host.
|
|
121
126
|
*/
|
|
122
127
|
function FooterModelBadge({ useProjection, t }) {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
const
|
|
126
|
-
const current =
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
128
|
+
let value = null;
|
|
129
|
+
try { value = useProjection("perMessageModel"); } catch (err) { value = null; }
|
|
130
|
+
const hasValue = value !== null && value !== void 0 && typeof value === "object";
|
|
131
|
+
const current = hasValue && typeof value.current === "object" && value.current !== null ? value.current : null;
|
|
132
|
+
const provider = current !== null && typeof current.provider === "string" ? current.provider : null;
|
|
133
|
+
const model = current !== null && typeof current.model === "string" ? current.model : null;
|
|
134
|
+
let label;
|
|
135
|
+
try { label = provider !== null && model !== null ? provider + " / " + model : (typeof t === "function" ? t("badge.unknown") : "model unknown"); }
|
|
136
|
+
catch (err) { label = provider !== null && model !== null ? provider + " / " + model : "model unknown"; }
|
|
137
|
+
const toggle = (event) => {
|
|
138
|
+
const btn = event && event.currentTarget ? event.currentTarget : null;
|
|
139
|
+
if (btn === null) return;
|
|
140
|
+
const labelEl = btn.querySelector('[class*="footer-label"]');
|
|
141
|
+
const iconEl = btn.querySelector('[class*="footer-icon"]');
|
|
142
|
+
const isOpen = btn.getAttribute("aria-expanded") === "true";
|
|
143
|
+
if (isOpen) {
|
|
144
|
+
btn.setAttribute("aria-expanded", "false");
|
|
145
|
+
if (labelEl !== null) labelEl.setAttribute("data-open", "false");
|
|
146
|
+
if (iconEl !== null) iconEl.style.transform = "rotate(0deg)";
|
|
138
147
|
} else {
|
|
139
|
-
|
|
140
|
-
|
|
148
|
+
const deg = Math.round(90 + Math.random() * 180);
|
|
149
|
+
btn.setAttribute("aria-expanded", "true");
|
|
150
|
+
if (labelEl !== null) labelEl.setAttribute("data-open", "true");
|
|
151
|
+
if (iconEl !== null) iconEl.style.transform = "rotate(" + deg + "deg)";
|
|
141
152
|
}
|
|
142
153
|
};
|
|
143
154
|
return createElement("button", {
|
|
@@ -146,22 +157,22 @@ window.__ModuleLoader__.load({
|
|
|
146
157
|
"data-dsh-per-message-model-footer": "true",
|
|
147
158
|
"aria-label": label,
|
|
148
159
|
title: label,
|
|
149
|
-
"aria-expanded":
|
|
160
|
+
"aria-expanded": "false",
|
|
150
161
|
onClick: toggle
|
|
151
162
|
}, [
|
|
152
163
|
createElement("span", {
|
|
153
164
|
key: "icon",
|
|
154
165
|
className: BADGE_PREFIX + "footer-icon",
|
|
155
|
-
style: { transform:
|
|
166
|
+
style: { transform: "rotate(0deg)" }
|
|
156
167
|
}, chipIcon()),
|
|
157
168
|
createElement("span", {
|
|
158
169
|
key: "label",
|
|
159
170
|
className: BADGE_PREFIX + "footer-label",
|
|
160
|
-
"data-open":
|
|
171
|
+
"data-open": "false"
|
|
161
172
|
}, label)
|
|
162
173
|
]);
|
|
163
174
|
}
|
|
164
|
-
//#endregion
|
|
175
|
+
//#endregion //#endregion
|
|
165
176
|
//#region client divider
|
|
166
177
|
/** Fixed Chinese copy for the model-switch divider (user-required). */
|
|
167
178
|
const SWITCH_COPY = "模型切换:";
|
|
@@ -231,7 +242,9 @@ window.__ModuleLoader__.load({
|
|
|
231
242
|
React.useEffect(() => {
|
|
232
243
|
if (typeof document === "undefined" || typeof MutationObserver === "undefined") return;
|
|
233
244
|
let observer = null;
|
|
245
|
+
let timer = 0;
|
|
234
246
|
const tryInsert = () => {
|
|
247
|
+
let remaining = 0;
|
|
235
248
|
for (const sw of switches) {
|
|
236
249
|
if (sw.to === null || typeof sw.to !== "object" ||
|
|
237
250
|
typeof sw.to.provider !== "string" || typeof sw.to.model !== "string") continue;
|
|
@@ -247,22 +260,35 @@ window.__ModuleLoader__.load({
|
|
|
247
260
|
const fromAnchor = document.querySelector('[data-chat-anchor-key="' + fromKey + '"]');
|
|
248
261
|
const toAnchor = toKey !== null ? document.querySelector('[data-chat-anchor-key="' + toKey + '"]') : null;
|
|
249
262
|
const anchor = fromAnchor !== null ? fromAnchor : toAnchor;
|
|
250
|
-
if (anchor === null) continue;
|
|
263
|
+
if (anchor === null) { remaining += 1; continue; }
|
|
251
264
|
const node = buildDividerNode(sw);
|
|
252
265
|
node.setAttribute("data-from-seq", String(seqKey));
|
|
253
266
|
if (fromAnchor !== null) fromAnchor.insertAdjacentElement("afterend", node);
|
|
254
267
|
else toAnchor.insertAdjacentElement("beforebegin", node);
|
|
255
268
|
}
|
|
269
|
+
return remaining;
|
|
256
270
|
};
|
|
257
|
-
|
|
258
|
-
//
|
|
259
|
-
//
|
|
260
|
-
//
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
271
|
+
// Insert what is already rendered; watch (debounced) only while some
|
|
272
|
+
// anchors are still missing (windowed history loads them on scroll),
|
|
273
|
+
// and disconnect the moment everything is in place so a live
|
|
274
|
+
// session's continuous DOM churn can never re-trigger work.
|
|
275
|
+
const schedule = () => {
|
|
276
|
+
if (timer !== 0) return;
|
|
277
|
+
timer = setTimeout(() => {
|
|
278
|
+
timer = 0;
|
|
279
|
+
if (tryInsert() === 0 && observer !== null) {
|
|
280
|
+
observer.disconnect();
|
|
281
|
+
observer = null;
|
|
282
|
+
}
|
|
283
|
+
}, 150);
|
|
284
|
+
};
|
|
285
|
+
if (tryInsert() > 0) {
|
|
286
|
+
observer = new MutationObserver(schedule);
|
|
287
|
+
observer.observe(document.body, { childList: true, subtree: true });
|
|
288
|
+
}
|
|
264
289
|
return () => {
|
|
265
290
|
if (observer !== null) observer.disconnect();
|
|
291
|
+
if (timer !== 0) clearTimeout(timer);
|
|
266
292
|
};
|
|
267
293
|
}, [switches]);
|
|
268
294
|
return null;
|