dsh-sidenote 0.7.0 → 0.7.2
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/README.md +3 -3
- package/lib/client.js +1131 -606
- package/lib/types/client/annotations/NativeComposer.d.ts +10 -0
- package/lib/types/client/annotations/NativeUserContext.d.ts +33 -2
- package/lib/types/client/annotations/chip.d.ts +2 -12
- package/lib/types/client/host/chat.d.ts +34 -0
- package/lib/types/client/host/contracts.d.ts +14 -1
- package/lib/types/client/host/dom.d.ts +5 -0
- package/lib/types/client/locales.d.ts +13 -0
- package/lib/types/client/sidechat/NativeConversation.d.ts +7 -0
- package/lib/types/client/sidechat/identity.d.ts +1 -1
- package/lib/types/client/sidechat/snapshot.d.ts +2 -0
- package/package.json +9 -4
- package/src/client/annotate/index.tsx +7 -16
- package/src/client/annotations/NativeComposer.tsx +110 -0
- package/src/client/annotations/NativeUserContext.tsx +168 -36
- package/src/client/annotations/annotations.module.css +60 -157
- package/src/client/annotations/chip.tsx +122 -118
- package/src/client/host/chat.ts +23 -19
- package/src/client/host/contracts.ts +5 -0
- package/src/client/host/dom.ts +13 -1
- package/src/client/locales.ts +30 -4
- package/src/client/reflow.ts +1 -1
- package/src/client/sidechat/NativeConversation.tsx +33 -16
- package/src/client/sidechat/SideChatPanel.tsx +8 -3
- package/src/client/sidechat/identity.ts +5 -1
- package/src/client/sidechat/sidechat.module.css +15 -1
- package/src/client/sidechat/snapshot.ts +7 -0
- package/lib/types/client/annotate/chip.d.ts +0 -10
- package/lib/types/client/annotate/send.d.ts +0 -8
- package/src/client/annotate/chip.tsx +0 -94
- package/src/client/annotate/send.ts +0 -155
package/lib/client.js
CHANGED
|
@@ -31,6 +31,7 @@ window.__ModuleLoader__.load({
|
|
|
31
31
|
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
32
32
|
_deepseek_ai_dsh_client_ui_primitives = __toESM(_deepseek_ai_dsh_client_ui_primitives, 1);
|
|
33
33
|
let react_dom_client = require("react-dom/client");
|
|
34
|
+
let react_dom = require("react-dom");
|
|
34
35
|
//#region src/client/host/currentSession.ts
|
|
35
36
|
/**
|
|
36
37
|
* 当前(在屏)会话 id 的双版本探测:0.1.5 的 SessionListState 带 `current`
|
|
@@ -176,6 +177,20 @@ window.__ModuleLoader__.load({
|
|
|
176
177
|
function sessionStatusSource(ctx) {
|
|
177
178
|
return ctx.get("uiSession")?.sessionStatus;
|
|
178
179
|
}
|
|
180
|
+
function completedReplySeqsOf(state) {
|
|
181
|
+
const result = [];
|
|
182
|
+
for (const turn of state.timeline.turnOrder) {
|
|
183
|
+
if (state.timeline.turns.get(turn)?.end?.data.reason.kind !== "completed") continue;
|
|
184
|
+
for (const key of [...state.locations.getTurn(turn)].reverse()) {
|
|
185
|
+
const node = state.nodes.get(key);
|
|
186
|
+
if (node?.kind !== "assistant-step") continue;
|
|
187
|
+
const data = node.data;
|
|
188
|
+
if (data.status === "settled" && data.finalNode && data.blocks?.some((block) => block.kind === "text" && block.text?.trim()) && !data.blocks.some((block) => block.kind === "tool-call")) result.push(data.finalNode.seq);
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return result;
|
|
193
|
+
}
|
|
179
194
|
function chatSourceOf(ctx, binding) {
|
|
180
195
|
const session = binding?.session;
|
|
181
196
|
if (session === void 0) return void 0;
|
|
@@ -184,21 +199,7 @@ window.__ModuleLoader__.load({
|
|
|
184
199
|
if (typeof target?.getSnapshot === "function" && typeof target.subscribe === "function") return {
|
|
185
200
|
subscribe: (fn) => target.subscribe(fn),
|
|
186
201
|
getLegacy: () => target.getSnapshot()?.legacy ?? null,
|
|
187
|
-
getCompletedReplySeqs: () =>
|
|
188
|
-
const state = target.getSnapshot();
|
|
189
|
-
const result = [];
|
|
190
|
-
for (const turn of state.timeline.turnOrder) {
|
|
191
|
-
if (state.timeline.turns.get(turn)?.end?.data.reason.kind !== "completed") continue;
|
|
192
|
-
for (const key of [...state.locations.getTurn(turn)].reverse()) {
|
|
193
|
-
const node = state.nodes.get(key);
|
|
194
|
-
if (node?.kind !== "assistant-step") continue;
|
|
195
|
-
const data = node.data;
|
|
196
|
-
if (data.status === "settled" && data.finalNode && data.blocks?.some((block) => block.kind === "text" && block.text?.trim()) && !data.blocks.some((block) => block.kind === "tool-call")) result.push(data.finalNode.seq);
|
|
197
|
-
break;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
return result;
|
|
201
|
-
},
|
|
202
|
+
getCompletedReplySeqs: () => completedReplySeqsOf(target.getSnapshot()),
|
|
202
203
|
getLastTurnEnd: () => {
|
|
203
204
|
const timeline = target.getSnapshot().timeline;
|
|
204
205
|
if (!timeline) return void 0;
|
|
@@ -284,9 +285,6 @@ window.__ModuleLoader__.load({
|
|
|
284
285
|
if (composer !== void 0 && composer.width > 0 && composer.left < clip.right && composer.right > clip.left) clip.bottom = Math.min(clip.bottom, composer.top);
|
|
285
286
|
return clip;
|
|
286
287
|
}
|
|
287
|
-
function mainComposerOf(node) {
|
|
288
|
-
return node.closest("[data-composer-seat]");
|
|
289
|
-
}
|
|
290
288
|
function focusMainComposer(view) {
|
|
291
289
|
[...view.querySelectorAll("[data-composer-seat] [data-composer-input], [data-composer-seat] textarea")].find((input) => input.closest("[data-sidenote-chat-session]") === null)?.focus();
|
|
292
290
|
}
|
|
@@ -302,22 +300,25 @@ window.__ModuleLoader__.load({
|
|
|
302
300
|
function findSendButtonInCard(root = document) {
|
|
303
301
|
const card = root.querySelector("[data-composer-card]");
|
|
304
302
|
if (card === null) return null;
|
|
305
|
-
const buttons = card.querySelectorAll("button");
|
|
303
|
+
const buttons = card.querySelectorAll("button:not([data-sidenote-submit])");
|
|
306
304
|
const last = buttons[buttons.length - 1];
|
|
307
305
|
return last instanceof HTMLButtonElement ? last : null;
|
|
308
306
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
function isMainComposerInput(target) {
|
|
313
|
-
return target instanceof HTMLElement && (target.closest("[data-composer-input]") !== null || target instanceof HTMLTextAreaElement) && mainComposerOf(target) !== null;
|
|
314
|
-
}
|
|
315
|
-
function composerHasMenu(seat) {
|
|
316
|
-
return seat.querySelector("[role=\"listbox\"], [role=\"menu\"], [aria-haspopup][aria-expanded=\"true\"]") !== null;
|
|
307
|
+
/** Bound message hover details to their native conversation pane. */
|
|
308
|
+
function conversationViewOf(node) {
|
|
309
|
+
return node.closest("[data-conversation-session], [data-sidenote-chat-session]") ?? document.body;
|
|
317
310
|
}
|
|
318
311
|
function hasConversationMessages() {
|
|
319
312
|
return document.querySelector("[data-chat-flow-kind]") !== null;
|
|
320
313
|
}
|
|
314
|
+
/** 0.2.0 has no UserText extension. Only add our own portal seat; never move
|
|
315
|
+
* or replace host-owned children. The CSS-module suffix is checked by E2E. */
|
|
316
|
+
function mountUserBubbleAddon(root, addon) {
|
|
317
|
+
root.querySelector("[class$=\"_bubble\"]")?.prepend(addon);
|
|
318
|
+
return () => {
|
|
319
|
+
addon.remove();
|
|
320
|
+
};
|
|
321
|
+
}
|
|
321
322
|
//#endregion
|
|
322
323
|
//#region src/client/host/sidebar.ts
|
|
323
324
|
/** better-sidebar version that moved the right column to DSH's native sidebar. */
|
|
@@ -610,7 +611,7 @@ window.__ModuleLoader__.load({
|
|
|
610
611
|
let dockRegistered = false;
|
|
611
612
|
let report = {
|
|
612
613
|
versions: {
|
|
613
|
-
sidenote: "0.7.
|
|
614
|
+
sidenote: "0.7.2",
|
|
614
615
|
dsh: "unknown",
|
|
615
616
|
betterSidebar: null
|
|
616
617
|
},
|
|
@@ -787,6 +788,14 @@ window.__ModuleLoader__.load({
|
|
|
787
788
|
diagSideAcceptance: "Side message acceptance",
|
|
788
789
|
inputUnavailable: "Cannot send right now. Body, attachments and quotes have been retained.",
|
|
789
790
|
snapshotContext: "Main conversation progress at first send",
|
|
791
|
+
mainContext: "Main conversation context",
|
|
792
|
+
contextAtSend: "Updates on first send",
|
|
793
|
+
contextAsOf: "As of {time}",
|
|
794
|
+
contextInherited: "Inherited history",
|
|
795
|
+
contextrequest: "Request",
|
|
796
|
+
contextreply: "Reply",
|
|
797
|
+
contextthinking: "Reasoning",
|
|
798
|
+
contextstreaming: "In progress",
|
|
790
799
|
inputWaiting: "The input is not ready. Body, attachments and quotes have been retained. Please try again shortly.",
|
|
791
800
|
draftRecoveryConflict: "The host has another draft. Your local body is retained; review this session in the main view before retrying.",
|
|
792
801
|
quoteWorkflowWaiting: "Annotations are not ready yet. Please try again shortly.",
|
|
@@ -877,6 +886,9 @@ window.__ModuleLoader__.load({
|
|
|
877
886
|
notePlaceholder: "Add a note (optional)…",
|
|
878
887
|
confirmTitle: "Confirm",
|
|
879
888
|
saveNoteAria: "Save note",
|
|
889
|
+
editNoteAria: "Edit note",
|
|
890
|
+
selectedText: "Selected text",
|
|
891
|
+
userComment: "Your comment",
|
|
880
892
|
sideNotePlaceholder: "Add a note for the side chat (optional)…",
|
|
881
893
|
sideNoteAria: "Side chat note",
|
|
882
894
|
confirmAskAria: "Confirm and ask",
|
|
@@ -897,15 +909,17 @@ window.__ModuleLoader__.load({
|
|
|
897
909
|
sentBadgeTitle: "Sent annotation {n} (view only)",
|
|
898
910
|
sentCardTitle: "Annotation {n} (sent)",
|
|
899
911
|
clearAll: "Clear all",
|
|
912
|
+
clearAnnotations: "Clear annotations",
|
|
913
|
+
clearReflows: "Clear side-chat reflows",
|
|
900
914
|
chipNote: " ({note})",
|
|
901
915
|
headerSide: "Side",
|
|
902
916
|
headerSideTitle: "Open a side chat (forked from the current session)",
|
|
903
917
|
hintText: "Tip: select any text in a reply to annotate it or ask in a side chat",
|
|
904
918
|
hintClose: "Got it",
|
|
905
|
-
reflowToMain: "
|
|
919
|
+
reflowToMain: "Bring back to main conversation",
|
|
906
920
|
sendAnnotations: "Send annotations",
|
|
907
921
|
reflowFrom: "From side chat ({title}):",
|
|
908
|
-
reflowDone: "Added
|
|
922
|
+
reflowDone: "Added to main conversation, not sent yet",
|
|
909
923
|
reflowFailed: "Couldn't reach the main session",
|
|
910
924
|
reflowChipOne: "1 side-chat reflow",
|
|
911
925
|
reflowChipMany: "{n} side-chat reflows",
|
|
@@ -988,6 +1002,14 @@ window.__ModuleLoader__.load({
|
|
|
988
1002
|
diagSideAcceptance: "侧聊消息接受",
|
|
989
1003
|
inputUnavailable: "暂时无法发送,正文、附件和注释已保留。",
|
|
990
1004
|
snapshotContext: "首次发送时的主线进展",
|
|
1005
|
+
mainContext: "主线上下文",
|
|
1006
|
+
contextAtSend: "发送时更新",
|
|
1007
|
+
contextAsOf: "截至 {time}",
|
|
1008
|
+
contextInherited: "已继承主线历史",
|
|
1009
|
+
contextrequest: "请求",
|
|
1010
|
+
contextreply: "回答",
|
|
1011
|
+
contextthinking: "思考",
|
|
1012
|
+
contextstreaming: "正在输出",
|
|
991
1013
|
inputWaiting: "输入尚未就绪,正文、附件和注释已保留,请稍后重试。",
|
|
992
1014
|
draftRecoveryConflict: "宿主另有草稿,本地正文已保留;请在主视图核对该会话草稿后再试。",
|
|
993
1015
|
quoteWorkflowWaiting: "注释功能暂未就绪,请稍后重试。",
|
|
@@ -1078,6 +1100,9 @@ window.__ModuleLoader__.load({
|
|
|
1078
1100
|
notePlaceholder: "这里可以写自己的注解…",
|
|
1079
1101
|
confirmTitle: "确认",
|
|
1080
1102
|
saveNoteAria: "确认注解",
|
|
1103
|
+
editNoteAria: "编辑批注",
|
|
1104
|
+
selectedText: "所选文本",
|
|
1105
|
+
userComment: "用户评论",
|
|
1081
1106
|
sideNotePlaceholder: "给侧边聊天写个注解(可空)…",
|
|
1082
1107
|
sideNoteAria: "侧边聊天注解",
|
|
1083
1108
|
confirmAskAria: "确认并提问",
|
|
@@ -1098,15 +1123,17 @@ window.__ModuleLoader__.load({
|
|
|
1098
1123
|
sentBadgeTitle: "已发送的注释 {n}(只读回看)",
|
|
1099
1124
|
sentCardTitle: "注释 {n}(已发送)",
|
|
1100
1125
|
clearAll: "清空全部",
|
|
1126
|
+
clearAnnotations: "清空注释",
|
|
1127
|
+
clearReflows: "清空侧边回流",
|
|
1101
1128
|
chipNote: "({note})",
|
|
1102
1129
|
headerSide: "侧边",
|
|
1103
1130
|
headerSideTitle: "打开侧边聊天(从当前会话 fork)",
|
|
1104
1131
|
hintText: "小技巧:划选回复里的文字,可以加注解或在侧边提问",
|
|
1105
1132
|
hintClose: "知道了",
|
|
1106
|
-
reflowToMain: "
|
|
1133
|
+
reflowToMain: "带回主对话",
|
|
1107
1134
|
sendAnnotations: "发送注释",
|
|
1108
1135
|
reflowFrom: "来自侧边聊天({title}):",
|
|
1109
|
-
reflowDone: "
|
|
1136
|
+
reflowDone: "已加入主对话,尚未发送",
|
|
1110
1137
|
reflowFailed: "主会话不可达",
|
|
1111
1138
|
reflowChipOne: "1 条侧边回流",
|
|
1112
1139
|
reflowChipMany: "{n} 条侧边回流",
|
|
@@ -1235,15 +1262,15 @@ window.__ModuleLoader__.load({
|
|
|
1235
1262
|
document.head.appendChild(tag);
|
|
1236
1263
|
}
|
|
1237
1264
|
var diagnostics_module_css_default = {
|
|
1265
|
+
"versions": "tGe0LW_versions",
|
|
1238
1266
|
"trigger": "tGe0LW_trigger",
|
|
1239
|
-
"
|
|
1267
|
+
"actions": "tGe0LW_actions",
|
|
1240
1268
|
"panel": "tGe0LW_panel",
|
|
1241
|
-
"list": "tGe0LW_list",
|
|
1242
|
-
"header": "tGe0LW_header",
|
|
1243
1269
|
"settingTitle": "tGe0LW_settingTitle",
|
|
1244
|
-
"
|
|
1245
|
-
"
|
|
1246
|
-
"description": "tGe0LW_description"
|
|
1270
|
+
"setting": "tGe0LW_setting",
|
|
1271
|
+
"header": "tGe0LW_header",
|
|
1272
|
+
"description": "tGe0LW_description",
|
|
1273
|
+
"list": "tGe0LW_list"
|
|
1247
1274
|
};
|
|
1248
1275
|
//#endregion
|
|
1249
1276
|
//#region src/client/diagnostics/index.tsx
|
|
@@ -1462,7 +1489,7 @@ window.__ModuleLoader__.load({
|
|
|
1462
1489
|
/**
|
|
1463
1490
|
* 回流通道的受控对象层(Delivery_02 Workitem_04 v2):侧边聊天的结论以
|
|
1464
1491
|
* 「待回流对象」进入主会话——主 composer 上方的 chip(可预览/可移除),
|
|
1465
|
-
* 发送瞬间由
|
|
1492
|
+
* 发送瞬间由 annotations/NativeComposer.tsx 原生提交入口与注释协议块一起序列化进消息。
|
|
1466
1493
|
* 不经草稿文本流(用户裁定:直接进草稿「很脏」)。
|
|
1467
1494
|
*
|
|
1468
1495
|
* 气泡留痕:序列化形态是 XML 协议块(见 buildReflowBlock),随注释协议块
|
|
@@ -2053,6 +2080,38 @@ window.__ModuleLoader__.load({
|
|
|
2053
2080
|
};
|
|
2054
2081
|
}
|
|
2055
2082
|
//#endregion
|
|
2083
|
+
//#region src/client/host/icons.ts
|
|
2084
|
+
const EmptyIcon = () => null;
|
|
2085
|
+
const iconExports = _deepseek_ai_dsh_client_ui_primitives;
|
|
2086
|
+
/** Prefer the weight-named 0.1.7 export, then fall back to the legacy size-named export. */
|
|
2087
|
+
function resolveIcon(exports, modernName, legacyName) {
|
|
2088
|
+
return exports[modernName] ?? exports[legacyName] ?? EmptyIcon;
|
|
2089
|
+
}
|
|
2090
|
+
const icon = (modernName, legacyName) => resolveIcon(iconExports, modernName, legacyName);
|
|
2091
|
+
const IconNewChatOutline16 = icon("IconNewChatOutlineRegular", "IconNewChatOutline16");
|
|
2092
|
+
const IconCheckOutline16 = icon("IconCheckOutlineRegular", "IconCheckOutline16");
|
|
2093
|
+
const IconListPenOutline16 = icon("IconListPenOutlineRegular", "IconListPenOutline16");
|
|
2094
|
+
const IconEditOutline16 = icon("IconEditOutlineRegular", "IconEditOutline16");
|
|
2095
|
+
const IconTrashOutline16 = icon("IconTrashOutlineRegular", "IconTrashOutline16");
|
|
2096
|
+
icon("IconPlayOutlineRegular", "IconPlayOutline16");
|
|
2097
|
+
icon("IconCordisPluginOutlineRegular", "IconCordisPluginOutline14");
|
|
2098
|
+
icon("IconBranchOutlineRegular", "IconBranchOutline16");
|
|
2099
|
+
const IconShareOutline16 = icon("IconShareOutlineRegular", "IconShareOutline16");
|
|
2100
|
+
const IconChevronDownOutline14 = icon("IconChevronDownOutlineRegular", "IconChevronDownOutline14");
|
|
2101
|
+
const IconCloseOutline16 = icon("IconCloseOutlineRegular", "IconCloseOutline16");
|
|
2102
|
+
icon("IconRightUpOutlineRegular", "IconRightUpOutline16");
|
|
2103
|
+
icon("IconSearchOutlineRegular", "IconSearchOutline16");
|
|
2104
|
+
icon("IconGlobeOutlineRegular", "IconGlobeOutline14");
|
|
2105
|
+
icon("IconCodeOutlineRegular", "IconCodeOutline16");
|
|
2106
|
+
icon("IconChecklistOutlineRegular", "IconChecklistOutline14");
|
|
2107
|
+
icon("IconThinkOutlineRegular", "IconThinkOutline16");
|
|
2108
|
+
icon("IconInspectOutlineRegular", "IconInspectOutline12");
|
|
2109
|
+
icon("IconPaperclipOutlineRegular", "IconPaperclipOutline16");
|
|
2110
|
+
icon("IconStopFillRegular", "IconStopFill16");
|
|
2111
|
+
icon("IconSendOutlineRegular", "IconSendOutline16");
|
|
2112
|
+
icon("IconWarningOutlineRegular", "IconWarningOutline16");
|
|
2113
|
+
icon("IconQuestionOutlineRegular", "IconQuestionOutline14");
|
|
2114
|
+
//#endregion
|
|
2056
2115
|
//#region src/client/annotations/format.ts
|
|
2057
2116
|
/** 协议头(双语):zh「我批注了以下 2 处内容:」/ en 见 locales。 */
|
|
2058
2117
|
function protocolHeader(n) {
|
|
@@ -2262,7 +2321,7 @@ window.__ModuleLoader__.load({
|
|
|
2262
2321
|
}
|
|
2263
2322
|
//#endregion
|
|
2264
2323
|
//#region \0dsh-css:/home/runner/work/dsh-sidenote/dsh-sidenote/src/client/sidechat/sidechat.module.css.mjs
|
|
2265
|
-
const css$2 = "._5KEEsG_nativeHost,._5KEEsG_root,._5KEEsG_nativeConversation{flex-direction:column;min-height:0;display:flex}._5KEEsG_nativeHost,._5KEEsG_root{height:100%}._5KEEsG_root{color:var(--dsw-alias-label-primary)}._5KEEsG_nativeConversation{flex:1}._5KEEsG_nativeToolbar{border-bottom:1px solid var(--dsw-alias-border-l1);justify-content:space-between;align-items:center;gap:8px;padding:8px 12px;display:flex}._5KEEsG_nativeToolbarActions{flex-wrap:wrap;align-items:center;gap:8px;display:flex}._5KEEsG_nativeAction,._5KEEsG_historyToggle{color:var(--dsw-alias-label-secondary);font:inherit;cursor:pointer;background:0 0;border:0;border-radius:6px;padding:4px 6px;font-size:13px}._5KEEsG_nativeAction:hover,._5KEEsG_nativeAction:focus-visible,._5KEEsG_historyToggle:hover,._5KEEsG_historyToggle:focus-visible{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}._5KEEsG_nativeAction:disabled{opacity:.5;cursor:default}._5KEEsG_historyToggle{text-align:left;margin:
|
|
2324
|
+
const css$2 = "._5KEEsG_nativeHost,._5KEEsG_root,._5KEEsG_nativeConversation{flex-direction:column;min-height:0;display:flex}._5KEEsG_nativeHost,._5KEEsG_root{height:100%}._5KEEsG_root{color:var(--dsw-alias-label-primary)}._5KEEsG_nativeConversation{flex:1}._5KEEsG_chatView{flex-direction:column;flex:1 0 auto;min-width:0;display:flex}._5KEEsG_mainContext{flex:none;padding:12px 24px 4px}._5KEEsG_historyToggle{align-items:center;gap:6px;display:flex}._5KEEsG_contextHint{color:var(--dsw-alias-label-tertiary);font-size:12px}._5KEEsG_contextChevron{transform:rotate(-90deg)}._5KEEsG_contextChevron,._5KEEsG_contextChevronOpen{flex:none}._5KEEsG_progressEntries{max-height:240px;margin:8px 6px;overflow:auto}._5KEEsG_progressEntry{white-space:pre-wrap;overflow-wrap:anywhere;margin:10px 0;font-size:13px;line-height:1.6}._5KEEsG_root [data-sidenote-progress-snapshot],._5KEEsG_root[data-sidenote-context-pending] [data-submission-echo]{display:none}._5KEEsG_reflowAction{width:32px;height:32px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:8px;flex:none;order:1;justify-content:center;align-items:center;margin-left:auto;padding:0;display:inline-flex}._5KEEsG_reflowAction:hover{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-interactive-bg-hover)}._5KEEsG_reflowAction:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}._5KEEsG_reflowAction:disabled{cursor:default;color:var(--dsw-alias-state-business-primary);background:0 0}._5KEEsG_nativeToolbar{border-bottom:1px solid var(--dsw-alias-border-l1);justify-content:space-between;align-items:center;gap:8px;padding:8px 12px;display:flex}._5KEEsG_nativeToolbarActions{flex-wrap:wrap;align-items:center;gap:8px;display:flex}._5KEEsG_nativeAction,._5KEEsG_historyToggle{color:var(--dsw-alias-label-secondary);font:inherit;cursor:pointer;background:0 0;border:0;border-radius:6px;padding:4px 6px;font-size:13px}._5KEEsG_nativeAction:hover,._5KEEsG_nativeAction:focus-visible,._5KEEsG_historyToggle:hover,._5KEEsG_historyToggle:focus-visible{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}._5KEEsG_nativeAction:disabled{opacity:.5;cursor:default}._5KEEsG_historyToggle{text-align:left;margin:0}._5KEEsG_stateScreen{text-align:center;flex-direction:column;flex:1;justify-content:center;align-items:center;gap:8px;padding:24px 16px;display:flex}._5KEEsG_emptyIcon{color:var(--dsw-alias-label-tertiary)}._5KEEsG_emptyTitle{font-size:14px;font-weight:600}._5KEEsG_emptyText{color:var(--dsw-alias-label-secondary);max-width:280px;font-size:13px;line-height:1.6}._5KEEsG_stateDetail,._5KEEsG_errorRow{color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere;font-size:13px;line-height:1.6}._5KEEsG_errorRow{padding:8px 12px}._5KEEsG_headerSide{color:var(--dsw-alias-label-secondary);cursor:pointer;font:inherit;background:0 0;border:0;border-radius:6px;align-items:center;gap:4px;padding:4px 8px;display:inline-flex}._5KEEsG_headerSide:hover,._5KEEsG_headerSide:focus-visible{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}._5KEEsG_headerSide:disabled{opacity:.4;cursor:default}._5KEEsG_visibilitySetting{justify-content:space-between;align-items:center;gap:16px;padding:8px 0;display:flex}._5KEEsG_visibilitySetting p{color:var(--dsw-alias-label-secondary);margin:4px 0 0;font-size:13px}";
|
|
2266
2325
|
const tagId$2 = "dsh-sidenote/sidechat.module.css";
|
|
2267
2326
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
|
|
2268
2327
|
const tag = document.createElement("style");
|
|
@@ -2272,21 +2331,29 @@ window.__ModuleLoader__.load({
|
|
|
2272
2331
|
document.head.appendChild(tag);
|
|
2273
2332
|
}
|
|
2274
2333
|
var sidechat_module_css_default = {
|
|
2275
|
-
"stateScreen": "_5KEEsG_stateScreen",
|
|
2276
|
-
"root": "_5KEEsG_root",
|
|
2277
2334
|
"emptyText": "_5KEEsG_emptyText",
|
|
2278
|
-
"
|
|
2335
|
+
"headerSide": "_5KEEsG_headerSide",
|
|
2279
2336
|
"nativeConversation": "_5KEEsG_nativeConversation",
|
|
2280
|
-
"emptyIcon": "_5KEEsG_emptyIcon",
|
|
2281
|
-
"visibilitySetting": "_5KEEsG_visibilitySetting",
|
|
2282
2337
|
"errorRow": "_5KEEsG_errorRow",
|
|
2338
|
+
"nativeAction": "_5KEEsG_nativeAction",
|
|
2339
|
+
"stateDetail": "_5KEEsG_stateDetail",
|
|
2340
|
+
"progressEntries": "_5KEEsG_progressEntries",
|
|
2341
|
+
"contextChevron": "_5KEEsG_contextChevron",
|
|
2283
2342
|
"nativeToolbar": "_5KEEsG_nativeToolbar",
|
|
2343
|
+
"mainContext": "_5KEEsG_mainContext",
|
|
2344
|
+
"root": "_5KEEsG_root",
|
|
2345
|
+
"nativeHost": "_5KEEsG_nativeHost",
|
|
2346
|
+
"contextHint": "_5KEEsG_contextHint",
|
|
2347
|
+
"visibilitySetting": "_5KEEsG_visibilitySetting",
|
|
2348
|
+
"progressEntry": "_5KEEsG_progressEntry",
|
|
2349
|
+
"reflowAction": "_5KEEsG_reflowAction",
|
|
2350
|
+
"emptyIcon": "_5KEEsG_emptyIcon",
|
|
2351
|
+
"nativeToolbarActions": "_5KEEsG_nativeToolbarActions",
|
|
2352
|
+
"contextChevronOpen": "_5KEEsG_contextChevronOpen",
|
|
2353
|
+
"stateScreen": "_5KEEsG_stateScreen",
|
|
2284
2354
|
"emptyTitle": "_5KEEsG_emptyTitle",
|
|
2285
2355
|
"historyToggle": "_5KEEsG_historyToggle",
|
|
2286
|
-
"
|
|
2287
|
-
"nativeHost": "_5KEEsG_nativeHost",
|
|
2288
|
-
"nativeAction": "_5KEEsG_nativeAction",
|
|
2289
|
-
"headerSide": "_5KEEsG_headerSide"
|
|
2356
|
+
"chatView": "_5KEEsG_chatView"
|
|
2290
2357
|
};
|
|
2291
2358
|
//#endregion
|
|
2292
2359
|
//#region src/client/sidechat/NativeConversation.tsx
|
|
@@ -2301,7 +2368,51 @@ window.__ModuleLoader__.load({
|
|
|
2301
2368
|
});
|
|
2302
2369
|
}
|
|
2303
2370
|
function ChatView(props) {
|
|
2304
|
-
|
|
2371
|
+
const side = (0, react.useContext)(SideContext);
|
|
2372
|
+
const fold = (0, react.useMemo)(() => createFoldStore(`dsh-sidenote:fold:v1:${side.sessionId}`), [side.sessionId]);
|
|
2373
|
+
(0, react.useSyncExternalStore)(fold.subscribe, fold.getSnapshot);
|
|
2374
|
+
const expanded = fold.isOpen("inherited");
|
|
2375
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2376
|
+
className: sidechat_module_css_default.chatView,
|
|
2377
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2378
|
+
className: sidechat_module_css_default.mainContext,
|
|
2379
|
+
"data-sidenote-main-context": true,
|
|
2380
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
2381
|
+
type: "button",
|
|
2382
|
+
className: sidechat_module_css_default.historyToggle,
|
|
2383
|
+
"aria-expanded": expanded,
|
|
2384
|
+
onClick: () => {
|
|
2385
|
+
fold.toggle("inherited");
|
|
2386
|
+
},
|
|
2387
|
+
children: [
|
|
2388
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconChevronDownOutline14, {
|
|
2389
|
+
size: 12,
|
|
2390
|
+
className: expanded ? sidechat_module_css_default.contextChevronOpen : sidechat_module_css_default.contextChevron
|
|
2391
|
+
}),
|
|
2392
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("mainContext") }),
|
|
2393
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2394
|
+
className: sidechat_module_css_default.contextHint,
|
|
2395
|
+
children: side.contextPending ? t("contextAtSend") : side.progress?.takenAt ? t("contextAsOf", { time: side.progress.takenAt }) : t("contextInherited")
|
|
2396
|
+
})
|
|
2397
|
+
]
|
|
2398
|
+
}), expanded && side.progress && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2399
|
+
className: sidechat_module_css_default.progressEntries,
|
|
2400
|
+
children: side.progress.entries.map((entry, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2401
|
+
className: sidechat_module_css_default.progressEntry,
|
|
2402
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2403
|
+
className: sidechat_module_css_default.contextHint,
|
|
2404
|
+
children: entry.kind === "tool" ? entry.toolName : t(`context${entry.kind}`)
|
|
2405
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: entry.text })]
|
|
2406
|
+
}, index))
|
|
2407
|
+
})]
|
|
2408
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SideContext.Provider, {
|
|
2409
|
+
value: {
|
|
2410
|
+
...side,
|
|
2411
|
+
contextExpanded: expanded
|
|
2412
|
+
},
|
|
2413
|
+
children: props.renderSlot("conversation.session", { view: "chat" })
|
|
2414
|
+
})]
|
|
2415
|
+
});
|
|
2305
2416
|
}
|
|
2306
2417
|
function Content(props) {
|
|
2307
2418
|
return props.renderFactorySlot("conversation.content", {
|
|
@@ -2337,12 +2448,13 @@ window.__ModuleLoader__.load({
|
|
|
2337
2448
|
}
|
|
2338
2449
|
function ReflowAction(props) {
|
|
2339
2450
|
const side = (0, react.useContext)(SideContext);
|
|
2340
|
-
const
|
|
2341
|
-
|
|
2451
|
+
const state = props.useChat((state) => state);
|
|
2452
|
+
const node = state.legacy?.nodes.find((node) => node.messageId === props.messageId);
|
|
2453
|
+
if (side === null || !node || !completedReplySeqsOf(state).includes(node.seq)) return null;
|
|
2342
2454
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReplyAction, {
|
|
2343
2455
|
side,
|
|
2344
|
-
messages: transcriptOf(legacy ?? null),
|
|
2345
|
-
seq:
|
|
2456
|
+
messages: transcriptOf(state.legacy ?? null),
|
|
2457
|
+
seq: node.seq
|
|
2346
2458
|
});
|
|
2347
2459
|
}
|
|
2348
2460
|
function ReplyAction({ side, messages, seq }) {
|
|
@@ -2351,20 +2463,35 @@ window.__ModuleLoader__.load({
|
|
|
2351
2463
|
if (!reply) return null;
|
|
2352
2464
|
const question = pairQuestions(messages).get(reply.key);
|
|
2353
2465
|
const added = isReplyAdded(side, reply, question);
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
"
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2466
|
+
const label = t(added ? "reflowDone" : "reflowToMain");
|
|
2467
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
2468
|
+
label,
|
|
2469
|
+
side: "top",
|
|
2470
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2471
|
+
type: "button",
|
|
2472
|
+
className: sidechat_module_css_default.reflowAction,
|
|
2473
|
+
"aria-label": label,
|
|
2474
|
+
"aria-pressed": added,
|
|
2475
|
+
disabled: added,
|
|
2476
|
+
onClick: () => {
|
|
2477
|
+
addReply(side, reply, question);
|
|
2478
|
+
},
|
|
2479
|
+
children: added ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconCheckOutline16, { size: 18 }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
2480
|
+
width: "18",
|
|
2481
|
+
height: "18",
|
|
2482
|
+
viewBox: "0 0 24 24",
|
|
2483
|
+
fill: "none",
|
|
2484
|
+
stroke: "currentColor",
|
|
2485
|
+
strokeWidth: "1.6",
|
|
2486
|
+
strokeLinecap: "round",
|
|
2487
|
+
strokeLinejoin: "round",
|
|
2488
|
+
"aria-hidden": "true",
|
|
2489
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M4 4v16M20 12H8m5-5-5 5 5 5" })
|
|
2490
|
+
})
|
|
2491
|
+
})
|
|
2363
2492
|
});
|
|
2364
2493
|
}
|
|
2365
2494
|
function HistoryView({ Original, props, side }) {
|
|
2366
|
-
const fold = (0, react.useMemo)(() => createFoldStore(`dsh-sidenote:fold:v1:${side.sessionId}`), [side.sessionId]);
|
|
2367
|
-
(0, react.useSyncExternalStore)(fold.subscribe, fold.getSnapshot);
|
|
2368
2495
|
const nodes = props.useChat((state) => state.nodes);
|
|
2369
2496
|
const snapshot = props.useConversation((state) => state);
|
|
2370
2497
|
const groups = snapshot.views.grouped("chat");
|
|
@@ -2378,9 +2505,7 @@ window.__ModuleLoader__.load({
|
|
|
2378
2505
|
const members = groups?.groupSource(entry.key).getSnapshot()?.members ?? [];
|
|
2379
2506
|
return members.length > 0 && members.every(isInherited);
|
|
2380
2507
|
};
|
|
2381
|
-
const
|
|
2382
|
-
const expanded = fold.isOpen("inherited");
|
|
2383
|
-
const visible = expanded ? entries : entries.filter((entry) => !isInherited(entry));
|
|
2508
|
+
const visible = side.contextExpanded ? entries : entries.filter((entry) => !isInherited(entry));
|
|
2384
2509
|
const projected = {
|
|
2385
2510
|
...snapshot,
|
|
2386
2511
|
views: {
|
|
@@ -2392,18 +2517,10 @@ window.__ModuleLoader__.load({
|
|
|
2392
2517
|
}
|
|
2393
2518
|
};
|
|
2394
2519
|
const useProjected = (0, react.useCallback)((selector) => selector(projected), [projected]);
|
|
2395
|
-
return
|
|
2396
|
-
type: "button",
|
|
2397
|
-
className: sidechat_module_css_default.historyToggle,
|
|
2398
|
-
"aria-expanded": expanded,
|
|
2399
|
-
onClick: () => {
|
|
2400
|
-
fold.toggle("inherited");
|
|
2401
|
-
},
|
|
2402
|
-
children: t("inheritedLabel", { n: inherited.length })
|
|
2403
|
-
}), (0, react.createElement)(Original, {
|
|
2520
|
+
return (0, react.createElement)(Original, {
|
|
2404
2521
|
...props,
|
|
2405
2522
|
useConversation: useProjected
|
|
2406
|
-
})
|
|
2523
|
+
});
|
|
2407
2524
|
}
|
|
2408
2525
|
/** Both admitted hosts publish the native chat View; only 0.2.1 adds a Flow slot. */
|
|
2409
2526
|
function registerInheritedHistory(ctx) {
|
|
@@ -2484,47 +2601,15 @@ window.__ModuleLoader__.load({
|
|
|
2484
2601
|
}
|
|
2485
2602
|
function registerNativeConversation(ctx) {
|
|
2486
2603
|
ctx.slots.inject("sidenote.conversation", () => ctx.slots.register({ name: "sidenote.conversation" }, Content));
|
|
2487
|
-
ctx.slots.inject("conversation.chat.
|
|
2488
|
-
name: "conversation.chat.
|
|
2604
|
+
ctx.slots.inject("conversation.chat.assistant-actions", () => ctx.slots.register({
|
|
2605
|
+
name: "conversation.chat.assistant-actions",
|
|
2489
2606
|
id: "dsh-sidenote-reflow",
|
|
2490
|
-
order:
|
|
2607
|
+
order: 100
|
|
2491
2608
|
}, ReflowAction));
|
|
2492
2609
|
registerInheritedHistory(ctx);
|
|
2493
2610
|
registerAssistantAnchors(ctx);
|
|
2494
2611
|
}
|
|
2495
2612
|
//#endregion
|
|
2496
|
-
//#region src/client/host/icons.ts
|
|
2497
|
-
const EmptyIcon = () => null;
|
|
2498
|
-
const iconExports = _deepseek_ai_dsh_client_ui_primitives;
|
|
2499
|
-
/** Prefer the weight-named 0.1.7 export, then fall back to the legacy size-named export. */
|
|
2500
|
-
function resolveIcon(exports, modernName, legacyName) {
|
|
2501
|
-
return exports[modernName] ?? exports[legacyName] ?? EmptyIcon;
|
|
2502
|
-
}
|
|
2503
|
-
const icon = (modernName, legacyName) => resolveIcon(iconExports, modernName, legacyName);
|
|
2504
|
-
const IconNewChatOutline16 = icon("IconNewChatOutlineRegular", "IconNewChatOutline16");
|
|
2505
|
-
const IconCheckOutline16 = icon("IconCheckOutlineRegular", "IconCheckOutline16");
|
|
2506
|
-
const IconListPenOutline16 = icon("IconListPenOutlineRegular", "IconListPenOutline16");
|
|
2507
|
-
icon("IconEditOutlineRegular", "IconEditOutline16");
|
|
2508
|
-
const IconTrashOutline16 = icon("IconTrashOutlineRegular", "IconTrashOutline16");
|
|
2509
|
-
icon("IconPlayOutlineRegular", "IconPlayOutline16");
|
|
2510
|
-
icon("IconCordisPluginOutlineRegular", "IconCordisPluginOutline14");
|
|
2511
|
-
icon("IconBranchOutlineRegular", "IconBranchOutline16");
|
|
2512
|
-
const IconShareOutline16 = icon("IconShareOutlineRegular", "IconShareOutline16");
|
|
2513
|
-
icon("IconChevronDownOutlineRegular", "IconChevronDownOutline14");
|
|
2514
|
-
const IconCloseOutline16 = icon("IconCloseOutlineRegular", "IconCloseOutline16");
|
|
2515
|
-
icon("IconRightUpOutlineRegular", "IconRightUpOutline16");
|
|
2516
|
-
icon("IconSearchOutlineRegular", "IconSearchOutline16");
|
|
2517
|
-
icon("IconGlobeOutlineRegular", "IconGlobeOutline14");
|
|
2518
|
-
icon("IconCodeOutlineRegular", "IconCodeOutline16");
|
|
2519
|
-
icon("IconChecklistOutlineRegular", "IconChecklistOutline14");
|
|
2520
|
-
icon("IconThinkOutlineRegular", "IconThinkOutline16");
|
|
2521
|
-
icon("IconInspectOutlineRegular", "IconInspectOutline12");
|
|
2522
|
-
icon("IconPaperclipOutlineRegular", "IconPaperclipOutline16");
|
|
2523
|
-
icon("IconStopFillRegular", "IconStopFill16");
|
|
2524
|
-
icon("IconSendOutlineRegular", "IconSendOutline16");
|
|
2525
|
-
icon("IconWarningOutlineRegular", "IconWarningOutline16");
|
|
2526
|
-
icon("IconQuestionOutlineRegular", "IconQuestionOutline14");
|
|
2527
|
-
//#endregion
|
|
2528
2613
|
//#region src/client/sidechat/composer.ts
|
|
2529
2614
|
/** Programmatic draft handoff only. The embedded native composer owns editing and submission. */
|
|
2530
2615
|
function resolveSessionInput(ctx, sessionId) {
|
|
@@ -2864,12 +2949,15 @@ window.__ModuleLoader__.load({
|
|
|
2864
2949
|
/**
|
|
2865
2950
|
* 首条用户消息 → topic。折叠全部空白(含换行)为单空格,截 20 码点,
|
|
2866
2951
|
* 超长加省略号;清洗后为空返回 undefined(调用方回退编号标题)。
|
|
2867
|
-
*
|
|
2952
|
+
* 已落盘消息也会用于恢复主题;先剥离快照及批注/回流协议。
|
|
2868
2953
|
* 划选提问的种子草稿是「> 引用行 + note 行」(buildSideChatQuote):
|
|
2869
2954
|
* 引用行剥除(用户自己的话才是主题),机械占位行(noNote)丢弃;
|
|
2870
2955
|
* 剥完为空(未补充直接发送)时退回引用内容——引用即主题。
|
|
2871
2956
|
*/
|
|
2872
2957
|
function topicOf(text) {
|
|
2958
|
+
text = splitSnapshotPrefix(text)?.rest ?? text;
|
|
2959
|
+
const protocol = splitProtocolPrefix(text);
|
|
2960
|
+
if (protocol) text = text.slice(protocol.length).trim() || protocol.annotations.map((item) => item.note || item.quote).join(" ") || protocol.reflows.map((item) => item.source).join(" ");
|
|
2873
2961
|
const lines = text.split("\n");
|
|
2874
2962
|
const clean = lines.filter((l) => !l.startsWith(">")).filter((l) => l.trim() !== t("noNote")).join(" ").replaceAll(/\s+/gu, " ").trim();
|
|
2875
2963
|
if (clean !== "") return truncate(clean);
|
|
@@ -3153,6 +3241,21 @@ window.__ModuleLoader__.load({
|
|
|
3153
3241
|
}
|
|
3154
3242
|
//#endregion
|
|
3155
3243
|
//#region src/client/sidechat/snapshot.ts
|
|
3244
|
+
/** Read the plugin's persisted progress block as plain, expandable content. */
|
|
3245
|
+
function snapshotEntriesFromText(text) {
|
|
3246
|
+
const kinds = {
|
|
3247
|
+
"user-request": "request",
|
|
3248
|
+
reply: "reply",
|
|
3249
|
+
thinking: "thinking",
|
|
3250
|
+
"tool-call": "tool",
|
|
3251
|
+
streaming: "streaming"
|
|
3252
|
+
};
|
|
3253
|
+
return [...text.matchAll(/<(user-request|reply|thinking|tool-call|streaming)(?: name="([^"]*)")?>([\s\S]*?)<\/\1>/g)].map((match) => ({
|
|
3254
|
+
kind: kinds[match[1]],
|
|
3255
|
+
text: match[3].trim(),
|
|
3256
|
+
...match[2] ? { toolName: match[2] } : {}
|
|
3257
|
+
}));
|
|
3258
|
+
}
|
|
3156
3259
|
function blocksText(blocks, kinds) {
|
|
3157
3260
|
if (!Array.isArray(blocks)) return "";
|
|
3158
3261
|
const parts = [];
|
|
@@ -4262,6 +4365,22 @@ ${entries.map((entry) => {
|
|
|
4262
4365
|
}, [visible]);
|
|
4263
4366
|
const parent = meta.parentSessionId ? ctx.sessions.binding(meta.parentSessionId)?.session : void 0;
|
|
4264
4367
|
const parentSnapshot = (0, react.useSyncExternalStore)((0, react.useCallback)((notify) => parent?.subscribe(notify) ?? NOOP_UNSUBSCRIBE, [parent]), () => parent?.getSnapshot() ?? null);
|
|
4368
|
+
const parentChat = (0, react.useMemo)(() => chatSourceOf(ctx, ctx.sessions.binding(meta.parentSessionId ?? scope.sessionId)), [
|
|
4369
|
+
ctx,
|
|
4370
|
+
parent,
|
|
4371
|
+
meta.parentSessionId,
|
|
4372
|
+
scope.sessionId
|
|
4373
|
+
]);
|
|
4374
|
+
const parentLegacy = (0, react.useSyncExternalStore)((0, react.useCallback)((notify) => parentChat?.subscribe(notify) ?? NOOP_UNSUBSCRIBE, [parentChat]), () => parentChat?.getLegacy() ?? null);
|
|
4375
|
+
const savedProgress = (0, react.useMemo)(() => messages.filter((message) => message.role === "user" && (message.seq ?? -1) > (meta.boundarySeq ?? -1)).map((message) => splitSnapshotPrefix(message.text)).find(Boolean), [messages, meta.boundarySeq]);
|
|
4376
|
+
const progress = (0, react.useMemo)(() => savedProgress ? {
|
|
4377
|
+
entries: snapshotEntriesFromText(savedProgress.snapshot),
|
|
4378
|
+
takenAt: savedProgress.takenAt
|
|
4379
|
+
} : meta.forkedMidTurn ? { entries: snapshotEntriesOf(parentLegacy?.nodes ?? [], parentLegacy?.partial) } : void 0, [
|
|
4380
|
+
savedProgress,
|
|
4381
|
+
meta.forkedMidTurn,
|
|
4382
|
+
parentLegacy
|
|
4383
|
+
]);
|
|
4265
4384
|
const status = sessionStatusSource(ctx);
|
|
4266
4385
|
const parentPending = (0, react.useSyncExternalStore)((0, react.useCallback)((notify) => status?.subscribe(notify) ?? NOOP_UNSUBSCRIBE, [status]), () => status?.getSnapshot().get(meta.parentSessionId ?? scope.sessionId)?.pendingInteraction != null);
|
|
4267
4386
|
const [saving, setSaving] = (0, react.useState)(false);
|
|
@@ -4297,7 +4416,9 @@ ${entries.map((entry) => {
|
|
|
4297
4416
|
parentSessionId: meta.parentSessionId ?? scope.sessionId,
|
|
4298
4417
|
title: tab.title,
|
|
4299
4418
|
boundarySeq: meta.boundarySeq,
|
|
4300
|
-
reflow: props.reflow
|
|
4419
|
+
reflow: props.reflow,
|
|
4420
|
+
progress,
|
|
4421
|
+
contextPending: meta.forkedMidTurn && !savedProgress
|
|
4301
4422
|
};
|
|
4302
4423
|
const replies = finalReplies(messages, meta.boundarySeq, new Set(chat?.getCompletedReplySeqs?.() ?? []));
|
|
4303
4424
|
const questions = pairQuestions(messages);
|
|
@@ -4309,6 +4430,7 @@ ${entries.map((entry) => {
|
|
|
4309
4430
|
className: sidechat_module_css_default.root,
|
|
4310
4431
|
"data-sidenote-chat-session": childId,
|
|
4311
4432
|
"data-sidenote-view-title": tab.title,
|
|
4433
|
+
"data-sidenote-context-pending": side.contextPending || void 0,
|
|
4312
4434
|
children: [
|
|
4313
4435
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4314
4436
|
className: sidechat_module_css_default.nativeToolbar,
|
|
@@ -5431,34 +5553,34 @@ ${entries.map((entry) => {
|
|
|
5431
5553
|
document.head.appendChild(tag);
|
|
5432
5554
|
}
|
|
5433
5555
|
var annotate_module_css_default = {
|
|
5434
|
-
"
|
|
5435
|
-
"
|
|
5436
|
-
"
|
|
5556
|
+
"dshSidenoteHintIn": "_SVViG_dshSidenoteHintIn",
|
|
5557
|
+
"deleteButton": "_SVViG_deleteButton",
|
|
5558
|
+
"editorEdit": "_SVViG_editorEdit",
|
|
5437
5559
|
"hintClose": "_SVViG_hintClose",
|
|
5438
|
-
"sentChipRow": "_SVViG_sentChipRow",
|
|
5439
5560
|
"editorTarget": "_SVViG_editorTarget",
|
|
5440
|
-
"
|
|
5561
|
+
"sentChipRow": "_SVViG_sentChipRow",
|
|
5562
|
+
"editorInput": "_SVViG_editorInput",
|
|
5563
|
+
"toolbarButton": "_SVViG_toolbarButton",
|
|
5441
5564
|
"highlight": "_SVViG_highlight",
|
|
5442
|
-
"
|
|
5443
|
-
"
|
|
5444
|
-
"
|
|
5445
|
-
"saveButton": "_SVViG_saveButton",
|
|
5565
|
+
"sentChip": "_SVViG_sentChip",
|
|
5566
|
+
"editorTextarea": "_SVViG_editorTextarea",
|
|
5567
|
+
"editorNew": "_SVViG_editorNew",
|
|
5446
5568
|
"toolbarBelow": "_SVViG_toolbarBelow",
|
|
5447
|
-
"
|
|
5448
|
-
"toolbarButton": "_SVViG_toolbarButton",
|
|
5569
|
+
"badgeSent": "_SVViG_badgeSent",
|
|
5449
5570
|
"toolbar": "_SVViG_toolbar",
|
|
5571
|
+
"editorFooter": "_SVViG_editorFooter",
|
|
5450
5572
|
"editorAsk": "_SVViG_editorAsk",
|
|
5451
5573
|
"confirmButton": "_SVViG_confirmButton",
|
|
5452
|
-
"
|
|
5453
|
-
"editorSpacer": "_SVViG_editorSpacer",
|
|
5454
|
-
"deleteButton": "_SVViG_deleteButton",
|
|
5574
|
+
"hint": "_SVViG_hint",
|
|
5455
5575
|
"badge": "_SVViG_badge",
|
|
5456
|
-
"
|
|
5457
|
-
"
|
|
5458
|
-
"editorInput": "_SVViG_editorInput",
|
|
5576
|
+
"saveButton": "_SVViG_saveButton",
|
|
5577
|
+
"sentCardNote": "_SVViG_sentCardNote",
|
|
5459
5578
|
"cancelButton": "_SVViG_cancelButton",
|
|
5460
|
-
"
|
|
5461
|
-
"
|
|
5579
|
+
"editorAskRow": "_SVViG_editorAskRow",
|
|
5580
|
+
"editorSpacer": "_SVViG_editorSpacer",
|
|
5581
|
+
"editorError": "_SVViG_editorError",
|
|
5582
|
+
"sentCardTitle": "_SVViG_sentCardTitle",
|
|
5583
|
+
"sentCardQuote": "_SVViG_sentCardQuote"
|
|
5462
5584
|
};
|
|
5463
5585
|
//#endregion
|
|
5464
5586
|
//#region src/client/annotate/hint.tsx
|
|
@@ -6260,527 +6382,624 @@ ${entries.map((entry) => {
|
|
|
6260
6382
|
});
|
|
6261
6383
|
}
|
|
6262
6384
|
//#endregion
|
|
6263
|
-
//#region src/client/annotations/
|
|
6264
|
-
|
|
6265
|
-
|
|
6266
|
-
|
|
6267
|
-
|
|
6268
|
-
|
|
6269
|
-
|
|
6270
|
-
|
|
6271
|
-
|
|
6272
|
-
const draftBeforeWait = input.state.getSnapshot();
|
|
6273
|
-
let prefix = "";
|
|
6274
|
-
let receipt;
|
|
6275
|
-
try {
|
|
6276
|
-
receipt = await prepareSubmission(ctx, sessionId, input, block);
|
|
6277
|
-
const draft = input.state.getSnapshot();
|
|
6278
|
-
if (draft.draft !== draftBeforeWait.draft || draft.draftRev !== draftBeforeWait.draftRev) throw new Error("等待会话就绪期间草稿已改变;正文和注释已保留,请重新发送");
|
|
6279
|
-
prefix = block + (draft.draft === "" ? "" : "\n\n");
|
|
6280
|
-
if (!prependInputText(input, prefix)) throw new Error("宿主输入尚未就绪,无法安全加入引用;内容已保留");
|
|
6281
|
-
receipt.submit(options.mode);
|
|
6282
|
-
await receipt.outcome;
|
|
6283
|
-
store.markSent(annotations.filter((annotation) => store.get(annotation.id) === annotation).map((annotation) => annotation.id));
|
|
6284
|
-
return true;
|
|
6285
|
-
} catch (error) {
|
|
6286
|
-
rollbackInputPrefix(input, prefix);
|
|
6287
|
-
const text = error instanceof Error ? error.message : String(error);
|
|
6288
|
-
store.setSubmission(sessionId, {
|
|
6289
|
-
pending: false,
|
|
6290
|
-
error: text
|
|
6291
|
-
});
|
|
6292
|
-
try {
|
|
6293
|
-
if (typeof input.notify === "function") input.notify("error", text);
|
|
6294
|
-
} catch {}
|
|
6295
|
-
return false;
|
|
6296
|
-
} finally {
|
|
6297
|
-
receipt?.dispose();
|
|
6298
|
-
}
|
|
6299
|
-
}
|
|
6300
|
-
/** Shared by native input gestures and the explicit annotation/reflow actions. */
|
|
6301
|
-
async function submitControlledInput(ctx, store, reflow, sessionId, mode) {
|
|
6302
|
-
if (store.getSubmission(sessionId).pending) return false;
|
|
6303
|
-
const input = resolveInput(ctx, sessionId);
|
|
6304
|
-
if (!input) {
|
|
6305
|
-
store.setSubmission(sessionId, {
|
|
6306
|
-
pending: false,
|
|
6307
|
-
error: t("inputUnavailable")
|
|
6308
|
-
});
|
|
6309
|
-
return false;
|
|
6310
|
-
}
|
|
6311
|
-
const draft = input.state.getSnapshot();
|
|
6312
|
-
if (draft.phase !== "plain" || draft.draft.trimStart().startsWith("/")) return false;
|
|
6313
|
-
const active = store.listActive(sessionId);
|
|
6314
|
-
const reflows = reflow.list(sessionId);
|
|
6315
|
-
if (draft.draft.trim() === "" && inputAttachmentIds(input).length === 0 && active.length === 0 && reflows.length === 0) return false;
|
|
6316
|
-
const extras = submissionExtrasOf(sessionId);
|
|
6317
|
-
const prefix = extras?.firstSendPrefix();
|
|
6318
|
-
store.setSubmission(sessionId, { pending: true });
|
|
6319
|
-
try {
|
|
6320
|
-
const { injectedIds } = await tryInjectReflows(sessionId, reflows);
|
|
6321
|
-
for (const id of injectedIds) reflow.remove(id);
|
|
6322
|
-
const hitchhikers = reflows.filter((item) => !injectedIds.has(item.id));
|
|
6323
|
-
if (active.length === 0 && hitchhikers.length === 0 && !prefix) {
|
|
6324
|
-
if (input.state.getSnapshot().draft.trim() !== "" || inputAttachmentIds(input).length > 0) input.submit(mode);
|
|
6325
|
-
return true;
|
|
6326
|
-
}
|
|
6327
|
-
const accepted = await submitAnnotations({
|
|
6328
|
-
ctx,
|
|
6329
|
-
store,
|
|
6330
|
-
sessionId,
|
|
6331
|
-
input,
|
|
6332
|
-
annotations: active,
|
|
6333
|
-
leadingBlocks: [...prefix ? [prefix] : [], ...hitchhikers.map(buildReflowBlock)],
|
|
6334
|
-
mode
|
|
6335
|
-
});
|
|
6336
|
-
if (accepted) {
|
|
6337
|
-
for (const item of hitchhikers) reflow.remove(item.id);
|
|
6338
|
-
extras?.onSubmitText(draft.draft);
|
|
6339
|
-
extras?.onAccepted();
|
|
6340
|
-
}
|
|
6341
|
-
return accepted;
|
|
6342
|
-
} catch (error) {
|
|
6343
|
-
store.setSubmission(sessionId, {
|
|
6344
|
-
pending: false,
|
|
6345
|
-
error: error instanceof Error ? error.message : String(error)
|
|
6346
|
-
});
|
|
6347
|
-
return false;
|
|
6348
|
-
} finally {
|
|
6349
|
-
store.setSubmission(sessionId, {
|
|
6350
|
-
...store.getSubmission(sessionId),
|
|
6351
|
-
pending: false
|
|
6352
|
-
});
|
|
6353
|
-
}
|
|
6354
|
-
}
|
|
6355
|
-
//#endregion
|
|
6356
|
-
//#region \0dsh-css:/home/runner/work/dsh-sidenote/dsh-sidenote/src/client/annotations/annotations.module.css.mjs
|
|
6357
|
-
const css = ".SVnebq_chipWrap{box-sizing:border-box;width:calc(100% - var(--dsh-composer-side-clearance,16px) - var(--dsh-composer-side-clearance,16px));max-width:var(--dsh-composer-card-max-width,780px);flex-direction:column;align-items:flex-start;gap:4px;margin:0 auto;display:flex;position:relative}.SVnebq_chip{border:1px solid var(--dsw-alias-border-l1,#0000001a);background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-primary,#1f2329);cursor:pointer;user-select:none;border-radius:999px;align-items:center;gap:5px;padding:2px 10px;font-size:12px;line-height:18px;display:inline-flex}.SVnebq_chip:hover{background:var(--dsw-alias-interactive-bg-hover,#0000000d)}.SVnebq_chipPanel{z-index:50;border:1px solid var(--dsw-alias-border-l1,#00000014);background:var(--dsw-alias-bg-layer-1,#fff);border-radius:12px;min-width:220px;max-width:420px;margin:0;padding:4px;list-style:none;position:absolute;bottom:calc(100% + 4px);left:0;box-shadow:0 6px 20px #0000001a}.SVnebq_chipRow{border-radius:8px;align-items:center;gap:8px;padding:4px 6px;display:flex}.SVnebq_chipRow:hover{background:var(--dsw-alias-interactive-bg-hover,#0000000a)}.SVnebq_chipNumber{color:#fff;text-align:center;background:#2f88ff;border-radius:999px;flex:none;width:16px;height:16px;font-size:10px;font-weight:600;line-height:16px}.SVnebq_chipText{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-primary,#1f2329);flex:auto;font-size:12px;overflow:hidden}.SVnebq_chipNote{color:var(--dsw-alias-label-tertiary,#8f959e)}.SVnebq_chipRemove{width:20px;height:20px;color:var(--dsw-alias-label-tertiary,#8f959e);cursor:pointer;background:0 0;border:none;border-radius:999px;flex:none;place-items:center;padding:0;display:grid}.SVnebq_chipRemove:hover{background:var(--dsw-alias-interactive-bg-hover,#00000014);color:var(--dsw-alias-state-error-primary,#d53f3f)}.SVnebq_chipClearAll{color:var(--dsw-alias-label-tertiary,#8f959e);cursor:pointer;background:0 0;border:none;border-radius:6px;padding:2px 6px;font-size:12px;line-height:18px}.SVnebq_chipClearAll:hover{color:var(--dsw-alias-state-error-primary,#d53f3f);background:var(--dsw-alias-interactive-bg-hover,#0000000a)}.SVnebq_chipWrap{background:var(--dsw-alias-bg-base,#fff);padding:2px 0}.SVnebq_chipPanel:after{content:\"\";background:var(--dsw-alias-bg-layer-1,#fff);border-right:1px solid var(--dsw-alias-border-l1,#00000014);border-bottom:1px solid var(--dsw-alias-border-l1,#00000014);width:10px;height:10px;position:absolute;bottom:-5px;left:18px;transform:rotate(45deg)}.SVnebq_side{width:100%;max-width:none;margin:0}.SVnebq_storageNotice{color:var(--dsw-alias-label-secondary,#646a73);font-size:12px}.SVnebq_sentContext{color:var(--dsw-alias-label-secondary);margin:8px 0;font-size:13px}.SVnebq_sentContext summary{cursor:pointer}.SVnebq_sentContext pre,.SVnebq_sentContext blockquote{white-space:pre-wrap;overflow-wrap:anywhere;font:inherit}";
|
|
6358
|
-
const tagId = "dsh-sidenote/annotations.module.css";
|
|
6359
|
-
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
6360
|
-
const tag = document.createElement("style");
|
|
6361
|
-
tag.dataset.plugin = "dsh-sidenote";
|
|
6362
|
-
tag.dataset.pluginCss = tagId;
|
|
6363
|
-
tag.textContent = css;
|
|
6364
|
-
document.head.appendChild(tag);
|
|
6385
|
+
//#region \0dsh-css:/home/runner/work/dsh-sidenote/dsh-sidenote/src/client/annotations/annotations.module.css.mjs
|
|
6386
|
+
const css = ".SVnebq_chipWrap{box-sizing:border-box;width:calc(100% - 2 * var(--dsh-composer-side-clearance,16px));max-width:var(--dsh-composer-card-max-width,780px);background:var(--dsw-alias-bg-base);flex-wrap:wrap;align-items:center;gap:6px;margin:0 auto;padding:2px 0;display:flex}.SVnebq_chip{--chip-surface:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);background:var(--chip-surface);color:var(--dsw-alias-label-secondary);border-radius:10px;align-items:center;transition:background .12s,color .12s;display:inline-flex;position:relative}.SVnebq_chip:hover,.SVnebq_chip:focus-within,.SVnebq_chip[data-open]{--chip-surface:var(--dsw-alias-interactive-bg-hover-solid);color:var(--dsw-alias-label-primary)}.SVnebq_chipMain{border-radius:inherit;min-height:28px;color:inherit;font:inherit;cursor:pointer;background:0 0;border:0;align-items:center;gap:5px;padding:3px 9px;font-size:12px;line-height:18px;display:inline-flex}.SVnebq_chipDismissShade{border-radius:inherit;background:linear-gradient(to right, transparent, var(--chip-surface) 45%);opacity:0;pointer-events:none;justify-content:flex-end;align-items:center;width:38px;transition:opacity .16s ease-out;display:flex;position:absolute;inset:0 3px 0 auto}.SVnebq_chipDismiss{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);width:24px;height:24px;color:var(--dsw-alias-label-secondary);cursor:pointer;border-radius:50%;flex:none;justify-content:center;align-items:center;padding:0;transition:transform .16s ease-out,background .12s,color .12s;display:inline-flex;transform:translate(2px)scale(.94)}.SVnebq_chip:hover .SVnebq_chipDismissShade,.SVnebq_chip:focus-within .SVnebq_chipDismissShade{opacity:1}.SVnebq_chip:hover .SVnebq_chipDismiss,.SVnebq_chip:focus-within .SVnebq_chipDismiss{pointer-events:auto;transform:none}.SVnebq_chipDismiss:hover{background:var(--dsw-alias-interactive-bg-hover-solid);color:var(--dsw-alias-label-primary)}.SVnebq_chipDismiss:disabled{opacity:.45;cursor:default}.SVnebq_contextPanel{box-sizing:border-box;z-index:1000;overscroll-behavior:contain;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border-radius:14px;padding:4px;animation:.12s ease-out SVnebq_contextAppear;position:fixed;overflow:auto;box-shadow:0 8px 28px #0000001f}.SVnebq_contextList{margin:0;padding:0;list-style:none}.SVnebq_contextItem{border-radius:10px;align-items:flex-start;gap:10px;margin:0;padding:8px 10px;transition:background .12s;display:flex}.SVnebq_contextItem+.SVnebq_contextItem{border-top:1px solid var(--dsw-alias-border-l1)}.SVnebq_contextItem:hover,.SVnebq_contextItem:focus-within{background:var(--dsw-alias-interactive-bg-hover)}.SVnebq_contextNumber{min-width:16px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;font-size:12px;line-height:21px}.SVnebq_contextContent{flex:1;min-width:0}.SVnebq_contextLabel{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.SVnebq_contextLabel:not(:first-child){margin-top:6px}.SVnebq_contextSource{color:var(--dsw-alias-label-secondary);margin-bottom:8px;font-size:12px}.SVnebq_contextText{white-space:pre-wrap;overflow-wrap:anywhere;user-select:text;font-size:13px;line-height:1.6}.SVnebq_contextActions{flex:none;gap:2px;display:flex}.SVnebq_contextAction{width:26px;height:26px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:8px;justify-content:center;align-items:center;padding:0;transition:color .12s,background .12s;display:inline-flex}.SVnebq_contextAction:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}.SVnebq_contextAction:disabled,.SVnebq_chipClearAll:disabled{opacity:.45;cursor:default}.SVnebq_contextEditor{box-sizing:border-box;resize:vertical;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);width:100%;min-height:64px;color:inherit;font:inherit;border-radius:6px;margin-top:4px;padding:6px 8px;font-size:13px;line-height:1.6;display:block}.SVnebq_contextFooter{padding:2px 10px 4px}.SVnebq_chipClearAll{color:var(--dsw-alias-label-tertiary);cursor:pointer;font:inherit;background:0 0;border:0;border-radius:6px;padding:4px 6px;font-size:12px}.SVnebq_chipClearAll:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-state-error-primary)}.SVnebq_chipMain:focus-visible,.SVnebq_chipDismiss:focus-visible,.SVnebq_contextAction:focus-visible,.SVnebq_chipClearAll:focus-visible,.SVnebq_contextEditor:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}.SVnebq_storageNotice{color:var(--dsw-alias-label-secondary);flex-basis:100%;font-size:12px}@keyframes SVnebq_contextAppear{0%{opacity:0;transform:translateY(3px)}to{opacity:1;transform:translateY(0)}}@media (hover:none){.SVnebq_chipMain{padding-right:32px}.SVnebq_chipDismissShade{opacity:1}.SVnebq_chipDismiss{pointer-events:auto;transform:none}}@media (prefers-reduced-motion:reduce){.SVnebq_contextPanel{animation:none}.SVnebq_chip,.SVnebq_chipDismissShade,.SVnebq_chipDismiss,.SVnebq_contextItem,.SVnebq_contextAction{transition:none}}.SVnebq_sentContext{color:var(--dsw-alias-label-secondary);margin:8px 0;font-size:13px}.SVnebq_sentContext summary{cursor:pointer}.SVnebq_sentContext pre,.SVnebq_sentContext blockquote{white-space:pre-wrap;overflow-wrap:anywhere;font:inherit}.SVnebq_userContextHost{display:contents}[data-sidenote-context-replaced]{display:none!important}.SVnebq_sentChips{white-space:normal;display:inline}.SVnebq_sentChipGroup{display:inline}.SVnebq_sentChip{vertical-align:middle;background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary);font:inherit;border:0;border-radius:6px;align-items:center;gap:4px;margin:0 6px 2px 0;padding:2px 6px;font-size:12px;line-height:18px;transition:background .14s,color .14s;display:inline-flex}button.SVnebq_sentChip{cursor:pointer}button.SVnebq_sentChip:hover,button.SVnebq_sentChip[aria-expanded=true]{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover-solid)}button.SVnebq_sentChip:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}.SVnebq_sentChevron,.SVnebq_sentChevronOpen{opacity:.65;flex:none;transition:transform .14s}.SVnebq_sentChevronOpen{transform:rotate(180deg)}.SVnebq_sentPreview{text-align:left;white-space:normal}@media (prefers-reduced-motion:reduce){.SVnebq_sentChip,.SVnebq_sentChevron,.SVnebq_sentChevronOpen{transition:none}}";
|
|
6387
|
+
const tagId = "dsh-sidenote/annotations.module.css";
|
|
6388
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
6389
|
+
const tag = document.createElement("style");
|
|
6390
|
+
tag.dataset.plugin = "dsh-sidenote";
|
|
6391
|
+
tag.dataset.pluginCss = tagId;
|
|
6392
|
+
tag.textContent = css;
|
|
6393
|
+
document.head.appendChild(tag);
|
|
6365
6394
|
}
|
|
6366
6395
|
var annotations_module_css_default = {
|
|
6396
|
+
"storageNotice": "SVnebq_storageNotice",
|
|
6397
|
+
"contextAction": "SVnebq_contextAction",
|
|
6398
|
+
"userContextHost": "SVnebq_userContextHost",
|
|
6399
|
+
"chipDismissShade": "SVnebq_chipDismissShade",
|
|
6400
|
+
"sentChipGroup": "SVnebq_sentChipGroup",
|
|
6401
|
+
"sentChip": "SVnebq_sentChip",
|
|
6402
|
+
"contextFooter": "SVnebq_contextFooter",
|
|
6403
|
+
"sentContext": "SVnebq_sentContext",
|
|
6404
|
+
"sentChevronOpen": "SVnebq_sentChevronOpen",
|
|
6405
|
+
"contextPanel": "SVnebq_contextPanel",
|
|
6406
|
+
"contextAppear": "SVnebq_contextAppear",
|
|
6407
|
+
"sentChevron": "SVnebq_sentChevron",
|
|
6408
|
+
"contextEditor": "SVnebq_contextEditor",
|
|
6409
|
+
"contextNumber": "SVnebq_contextNumber",
|
|
6410
|
+
"contextText": "SVnebq_contextText",
|
|
6411
|
+
"sentChips": "SVnebq_sentChips",
|
|
6412
|
+
"contextContent": "SVnebq_contextContent",
|
|
6413
|
+
"sentPreview": "SVnebq_sentPreview",
|
|
6414
|
+
"chipMain": "SVnebq_chipMain",
|
|
6415
|
+
"contextItem": "SVnebq_contextItem",
|
|
6416
|
+
"contextLabel": "SVnebq_contextLabel",
|
|
6367
6417
|
"chipWrap": "SVnebq_chipWrap",
|
|
6418
|
+
"contextActions": "SVnebq_contextActions",
|
|
6419
|
+
"contextSource": "SVnebq_contextSource",
|
|
6368
6420
|
"chipClearAll": "SVnebq_chipClearAll",
|
|
6369
|
-
"sentContext": "SVnebq_sentContext",
|
|
6370
|
-
"chipNumber": "SVnebq_chipNumber",
|
|
6371
|
-
"chipRow": "SVnebq_chipRow",
|
|
6372
|
-
"chipPanel": "SVnebq_chipPanel",
|
|
6373
|
-
"chipRemove": "SVnebq_chipRemove",
|
|
6374
|
-
"side": "SVnebq_side",
|
|
6375
|
-
"storageNotice": "SVnebq_storageNotice",
|
|
6376
|
-
"chipNote": "SVnebq_chipNote",
|
|
6377
6421
|
"chip": "SVnebq_chip",
|
|
6378
|
-
"
|
|
6422
|
+
"chipDismiss": "SVnebq_chipDismiss",
|
|
6423
|
+
"contextList": "SVnebq_contextList"
|
|
6379
6424
|
};
|
|
6380
6425
|
//#endregion
|
|
6381
6426
|
//#region src/client/annotations/chip.tsx
|
|
6382
|
-
/**
|
|
6383
|
-
|
|
6384
|
-
|
|
6385
|
-
|
|
6386
|
-
|
|
6387
|
-
|
|
6388
|
-
|
|
6389
|
-
|
|
6390
|
-
|
|
6391
|
-
|
|
6392
|
-
|
|
6427
|
+
/** Shared, compact context dock for both native composers. */
|
|
6428
|
+
function AnnotationDetail({ item, store, pending, onEdit }) {
|
|
6429
|
+
const [editing, setEditing] = (0, react.useState)(false);
|
|
6430
|
+
const [note, setNote] = (0, react.useState)(item.note);
|
|
6431
|
+
const cancelled = (0, react.useRef)(false);
|
|
6432
|
+
const save = () => {
|
|
6433
|
+
if (!cancelled.current) store.setNote(item.id, note);
|
|
6434
|
+
setEditing(false);
|
|
6435
|
+
};
|
|
6436
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
6437
|
+
className: annotations_module_css_default.contextItem,
|
|
6438
|
+
children: [
|
|
6439
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
6440
|
+
className: annotations_module_css_default.contextNumber,
|
|
6441
|
+
children: [item.number, "."]
|
|
6442
|
+
}),
|
|
6443
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6444
|
+
className: annotations_module_css_default.contextContent,
|
|
6445
|
+
children: [
|
|
6446
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6447
|
+
className: annotations_module_css_default.contextLabel,
|
|
6448
|
+
children: t("selectedText")
|
|
6449
|
+
}),
|
|
6450
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6451
|
+
className: annotations_module_css_default.contextText,
|
|
6452
|
+
children: item.text
|
|
6453
|
+
}),
|
|
6454
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6455
|
+
className: annotations_module_css_default.contextLabel,
|
|
6456
|
+
children: t("userComment")
|
|
6457
|
+
}),
|
|
6458
|
+
editing ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
|
|
6459
|
+
autoFocus: true,
|
|
6460
|
+
rows: 3,
|
|
6461
|
+
className: annotations_module_css_default.contextEditor,
|
|
6462
|
+
"aria-label": t("userComment"),
|
|
6463
|
+
value: note,
|
|
6464
|
+
onChange: (event) => {
|
|
6465
|
+
setNote(event.target.value);
|
|
6466
|
+
},
|
|
6467
|
+
onBlur: save,
|
|
6468
|
+
onKeyDown: (event) => {
|
|
6469
|
+
if (event.key === "Escape") {
|
|
6470
|
+
event.preventDefault();
|
|
6471
|
+
event.stopPropagation();
|
|
6472
|
+
cancelled.current = true;
|
|
6473
|
+
setEditing(false);
|
|
6474
|
+
}
|
|
6475
|
+
if (event.key === "Enter" && (event.metaKey || event.ctrlKey)) {
|
|
6476
|
+
event.preventDefault();
|
|
6477
|
+
save();
|
|
6478
|
+
}
|
|
6479
|
+
}
|
|
6480
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6481
|
+
className: annotations_module_css_default.contextText,
|
|
6482
|
+
children: item.note || /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6483
|
+
className: annotations_module_css_default.contextLabel,
|
|
6484
|
+
children: t("noNote")
|
|
6485
|
+
})
|
|
6486
|
+
})
|
|
6487
|
+
]
|
|
6488
|
+
}),
|
|
6489
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6490
|
+
className: annotations_module_css_default.contextActions,
|
|
6491
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
6492
|
+
type: "button",
|
|
6493
|
+
className: annotations_module_css_default.contextAction,
|
|
6494
|
+
disabled: pending,
|
|
6495
|
+
"aria-label": t(editing ? "saveNoteAria" : "editNoteAria"),
|
|
6496
|
+
title: t(editing ? "saveNoteAria" : "editNoteAria"),
|
|
6497
|
+
onMouseDown: (event) => {
|
|
6498
|
+
if (editing) event.preventDefault();
|
|
6499
|
+
},
|
|
6500
|
+
onClick: () => {
|
|
6501
|
+
if (editing) save();
|
|
6502
|
+
else {
|
|
6503
|
+
cancelled.current = false;
|
|
6504
|
+
setNote(item.note);
|
|
6505
|
+
setEditing(true);
|
|
6506
|
+
onEdit();
|
|
6507
|
+
}
|
|
6508
|
+
},
|
|
6509
|
+
children: editing ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconCheckOutline16, { size: 16 }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconEditOutline16, { size: 16 })
|
|
6510
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
6511
|
+
type: "button",
|
|
6512
|
+
className: annotations_module_css_default.contextAction,
|
|
6513
|
+
disabled: pending,
|
|
6514
|
+
"aria-label": t("removeAria", { n: item.number }),
|
|
6515
|
+
title: t("removeTitle"),
|
|
6516
|
+
onClick: () => {
|
|
6517
|
+
store.remove(item.id);
|
|
6518
|
+
},
|
|
6519
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconTrashOutline16, { size: 16 })
|
|
6520
|
+
})]
|
|
6521
|
+
})
|
|
6522
|
+
]
|
|
6523
|
+
});
|
|
6524
|
+
}
|
|
6525
|
+
function ContextChips({ ctx, store, reflow, sessionId }) {
|
|
6393
6526
|
useLocaleTick();
|
|
6394
|
-
|
|
6395
|
-
(0, react.useSyncExternalStore)(
|
|
6396
|
-
const
|
|
6397
|
-
const
|
|
6527
|
+
(0, react.useSyncExternalStore)(store.subscribe, store.getSnapshot);
|
|
6528
|
+
(0, react.useSyncExternalStore)(reflow.subscribe, reflow.getSnapshot);
|
|
6529
|
+
const diagnostics = hostDiagnostics(ctx);
|
|
6530
|
+
const capabilities = (0, react.useSyncExternalStore)(diagnostics.subscribe, diagnostics.getSnapshot);
|
|
6531
|
+
const [open, setOpen] = (0, react.useState)(null);
|
|
6532
|
+
const [position, setPosition] = (0, react.useState)({ visibility: "hidden" });
|
|
6533
|
+
const root = (0, react.useRef)(null);
|
|
6534
|
+
const panel = (0, react.useRef)(null);
|
|
6535
|
+
const timer = (0, react.useRef)(void 0);
|
|
6536
|
+
const id = (0, react.useId)();
|
|
6537
|
+
const clearTimer = () => {
|
|
6538
|
+
clearTimeout(timer.current);
|
|
6539
|
+
timer.current = void 0;
|
|
6540
|
+
};
|
|
6541
|
+
const active = store.listActive(sessionId);
|
|
6542
|
+
const reflows = reflow.list(sessionId);
|
|
6543
|
+
const submission = store.getSubmission(sessionId);
|
|
6544
|
+
const hasItems = open?.kind === "annotations" ? active.length > 0 : reflows.length > 0;
|
|
6545
|
+
const shown = open !== null && hasItems;
|
|
6546
|
+
const label = (kind) => kind === "annotations" ? t(active.length === 1 ? "chipOne" : "chipMany", { n: active.length }) : t(reflows.length === 1 ? "reflowChipOne" : "reflowChipMany", { n: reflows.length });
|
|
6398
6547
|
(0, react.useEffect)(() => {
|
|
6399
|
-
|
|
6400
|
-
|
|
6401
|
-
|
|
6402
|
-
|
|
6403
|
-
|
|
6548
|
+
setOpen(null);
|
|
6549
|
+
return clearTimer;
|
|
6550
|
+
}, [sessionId]);
|
|
6551
|
+
(0, react.useEffect)(() => {
|
|
6552
|
+
if (!submission.pending && submission.error === t("inputUnavailable") && resolveInput(ctx, sessionId)) store.setSubmission(sessionId, { pending: false });
|
|
6553
|
+
}, [capabilities, sessionId]);
|
|
6554
|
+
(0, react.useEffect)(() => {
|
|
6555
|
+
if (!hasItems) setOpen(null);
|
|
6556
|
+
}, [hasItems]);
|
|
6557
|
+
(0, react.useLayoutEffect)(() => {
|
|
6558
|
+
if (!shown) return;
|
|
6559
|
+
const place = () => {
|
|
6560
|
+
const rect = root.current.getBoundingClientRect();
|
|
6561
|
+
const width = Math.min(480, rect.width, window.innerWidth - 24);
|
|
6562
|
+
setPosition({
|
|
6563
|
+
width,
|
|
6564
|
+
left: Math.max(12, Math.min(rect.left, window.innerWidth - width - 12)),
|
|
6565
|
+
bottom: window.innerHeight - rect.top + 8,
|
|
6566
|
+
maxHeight: Math.min(280, window.innerHeight / 3, rect.top - 16)
|
|
6567
|
+
});
|
|
6568
|
+
};
|
|
6569
|
+
place();
|
|
6570
|
+
window.addEventListener("resize", place);
|
|
6571
|
+
window.addEventListener("scroll", place, true);
|
|
6572
|
+
return () => {
|
|
6573
|
+
window.removeEventListener("resize", place);
|
|
6574
|
+
window.removeEventListener("scroll", place, true);
|
|
6575
|
+
};
|
|
6576
|
+
}, [shown, open?.kind]);
|
|
6577
|
+
(0, react.useLayoutEffect)(() => {
|
|
6578
|
+
if (shown && open.pinned && root.current?.contains(document.activeElement)) panel.current?.focus();
|
|
6579
|
+
}, [
|
|
6580
|
+
shown,
|
|
6581
|
+
open?.kind,
|
|
6582
|
+
open?.pinned
|
|
6583
|
+
]);
|
|
6584
|
+
(0, react.useEffect)(() => {
|
|
6585
|
+
if (!shown) return;
|
|
6586
|
+
const outside = (event) => {
|
|
6587
|
+
if (!root.current?.contains(event.target) && !panel.current?.contains(event.target)) {
|
|
6588
|
+
clearTimer();
|
|
6589
|
+
setOpen(null);
|
|
6404
6590
|
}
|
|
6405
6591
|
};
|
|
6406
|
-
const
|
|
6407
|
-
|
|
6408
|
-
|
|
6409
|
-
|
|
6592
|
+
const escape = (event) => {
|
|
6593
|
+
if (event.key !== "Escape") return;
|
|
6594
|
+
event.preventDefault();
|
|
6595
|
+
clearTimer();
|
|
6596
|
+
setOpen(null);
|
|
6597
|
+
root.current?.querySelector(`[data-context-kind="${open?.kind}"]`)?.focus();
|
|
6410
6598
|
};
|
|
6411
|
-
document.addEventListener("
|
|
6412
|
-
document.addEventListener("
|
|
6599
|
+
document.addEventListener("pointerdown", outside);
|
|
6600
|
+
document.addEventListener("keydown", escape);
|
|
6413
6601
|
return () => {
|
|
6414
|
-
document.removeEventListener("
|
|
6415
|
-
document.removeEventListener("
|
|
6602
|
+
document.removeEventListener("pointerdown", outside);
|
|
6603
|
+
document.removeEventListener("keydown", escape);
|
|
6416
6604
|
};
|
|
6417
|
-
}, [
|
|
6418
|
-
|
|
6419
|
-
|
|
6420
|
-
|
|
6421
|
-
|
|
6422
|
-
|
|
6423
|
-
|
|
6605
|
+
}, [shown, open?.kind]);
|
|
6606
|
+
const leave = () => {
|
|
6607
|
+
clearTimer();
|
|
6608
|
+
if (!open?.pinned) timer.current = setTimeout(() => {
|
|
6609
|
+
if (!panel.current?.contains(document.activeElement)) setOpen(null);
|
|
6610
|
+
}, 220);
|
|
6611
|
+
};
|
|
6612
|
+
const clear = (kind) => {
|
|
6613
|
+
clearTimer();
|
|
6614
|
+
if (kind === "annotations") for (const item of active) store.remove(item.id);
|
|
6615
|
+
else reflow.clearSession(sessionId);
|
|
6616
|
+
if (open?.kind === kind) setOpen(null);
|
|
6617
|
+
};
|
|
6618
|
+
const chip = (kind) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
6619
|
+
className: annotations_module_css_default.chip,
|
|
6620
|
+
"data-open": shown && open.kind === kind || void 0,
|
|
6621
|
+
onPointerEnter: (event) => {
|
|
6622
|
+
if (event.pointerType === "touch") return;
|
|
6623
|
+
clearTimer();
|
|
6624
|
+
if (!open?.pinned) timer.current = setTimeout(() => {
|
|
6625
|
+
setOpen({
|
|
6626
|
+
kind,
|
|
6627
|
+
pinned: false
|
|
6628
|
+
});
|
|
6629
|
+
}, 160);
|
|
6630
|
+
},
|
|
6631
|
+
onPointerLeave: leave,
|
|
6632
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
6633
|
+
type: "button",
|
|
6634
|
+
className: annotations_module_css_default.chipMain,
|
|
6635
|
+
"data-context-kind": kind,
|
|
6636
|
+
"aria-haspopup": "dialog",
|
|
6637
|
+
"aria-expanded": shown && open.kind === kind,
|
|
6638
|
+
"aria-controls": id,
|
|
6639
|
+
onClick: () => {
|
|
6640
|
+
clearTimer();
|
|
6641
|
+
setOpen(open?.kind === kind && open.pinned ? null : {
|
|
6642
|
+
kind,
|
|
6643
|
+
pinned: true
|
|
6644
|
+
});
|
|
6645
|
+
},
|
|
6646
|
+
children: [kind === "annotations" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconListPenOutline16, { size: 14 }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconShareOutline16, { size: 14 }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: label(kind) })]
|
|
6647
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6648
|
+
className: annotations_module_css_default.chipDismissShade,
|
|
6649
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
6650
|
+
type: "button",
|
|
6651
|
+
className: annotations_module_css_default.chipDismiss,
|
|
6652
|
+
disabled: submission.pending,
|
|
6653
|
+
"aria-label": t(kind === "annotations" ? "clearAnnotations" : "clearReflows"),
|
|
6654
|
+
title: t(kind === "annotations" ? "clearAnnotations" : "clearReflows"),
|
|
6655
|
+
onClick: () => {
|
|
6656
|
+
clear(kind);
|
|
6657
|
+
},
|
|
6658
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconCloseOutline16, { size: 14 })
|
|
6659
|
+
})
|
|
6660
|
+
})]
|
|
6661
|
+
});
|
|
6662
|
+
if (!active.length && !reflows.length && !submission.error) return null;
|
|
6424
6663
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6425
|
-
ref:
|
|
6426
|
-
className:
|
|
6427
|
-
"data-sidenote-
|
|
6664
|
+
ref: root,
|
|
6665
|
+
className: annotations_module_css_default.chipWrap,
|
|
6666
|
+
"data-sidenote-context-dock": true,
|
|
6667
|
+
"data-sidenote-annotation-ui": true,
|
|
6428
6668
|
children: [
|
|
6669
|
+
active.length > 0 && chip("annotations"),
|
|
6670
|
+
reflows.length > 0 && chip("reflows"),
|
|
6429
6671
|
store.getStorageStatus(sessionId) === "memory" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6430
6672
|
className: annotations_module_css_default.storageNotice,
|
|
6431
6673
|
role: "status",
|
|
6432
6674
|
children: t("annotationStorageMemory")
|
|
6433
6675
|
}),
|
|
6434
|
-
submission.error
|
|
6676
|
+
submission.error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6435
6677
|
className: annotations_module_css_default.storageNotice,
|
|
6436
6678
|
role: "alert",
|
|
6437
6679
|
children: submission.error
|
|
6438
6680
|
}),
|
|
6439
|
-
|
|
6440
|
-
|
|
6441
|
-
|
|
6442
|
-
"
|
|
6443
|
-
|
|
6444
|
-
|
|
6445
|
-
|
|
6446
|
-
|
|
6447
|
-
|
|
6448
|
-
|
|
6449
|
-
|
|
6450
|
-
|
|
6451
|
-
|
|
6452
|
-
|
|
6453
|
-
|
|
6454
|
-
|
|
6455
|
-
|
|
6456
|
-
|
|
6457
|
-
|
|
6458
|
-
|
|
6459
|
-
|
|
6460
|
-
|
|
6461
|
-
|
|
6462
|
-
|
|
6463
|
-
|
|
6464
|
-
|
|
6465
|
-
|
|
6466
|
-
|
|
6467
|
-
|
|
6468
|
-
|
|
6469
|
-
|
|
6470
|
-
|
|
6471
|
-
|
|
6472
|
-
|
|
6473
|
-
|
|
6474
|
-
|
|
6475
|
-
|
|
6476
|
-
|
|
6477
|
-
|
|
6478
|
-
|
|
6479
|
-
|
|
6480
|
-
|
|
6481
|
-
|
|
6482
|
-
|
|
6483
|
-
|
|
6484
|
-
|
|
6485
|
-
|
|
6681
|
+
shown && (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6682
|
+
ref: panel,
|
|
6683
|
+
id,
|
|
6684
|
+
role: "dialog",
|
|
6685
|
+
tabIndex: -1,
|
|
6686
|
+
"aria-label": label(open.kind),
|
|
6687
|
+
className: annotations_module_css_default.contextPanel,
|
|
6688
|
+
style: position,
|
|
6689
|
+
"data-sidenote-context-preview": true,
|
|
6690
|
+
"data-sidenote-no-quote": true,
|
|
6691
|
+
onPointerEnter: clearTimer,
|
|
6692
|
+
onPointerLeave: leave,
|
|
6693
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
6694
|
+
className: annotations_module_css_default.contextList,
|
|
6695
|
+
children: open.kind === "annotations" ? active.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AnnotationDetail, {
|
|
6696
|
+
item,
|
|
6697
|
+
store,
|
|
6698
|
+
pending: submission.pending,
|
|
6699
|
+
onEdit: () => {
|
|
6700
|
+
setOpen({
|
|
6701
|
+
kind: "annotations",
|
|
6702
|
+
pinned: true
|
|
6703
|
+
});
|
|
6704
|
+
}
|
|
6705
|
+
}, item.id)) : reflows.map((item, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
6706
|
+
className: annotations_module_css_default.contextItem,
|
|
6707
|
+
children: [
|
|
6708
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
6709
|
+
className: annotations_module_css_default.contextNumber,
|
|
6710
|
+
children: [index + 1, "."]
|
|
6711
|
+
}),
|
|
6712
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6713
|
+
className: annotations_module_css_default.contextContent,
|
|
6714
|
+
children: [
|
|
6715
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6716
|
+
className: annotations_module_css_default.contextSource,
|
|
6717
|
+
children: item.sideTitle
|
|
6718
|
+
}),
|
|
6719
|
+
item.question && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6720
|
+
className: annotations_module_css_default.contextLabel,
|
|
6721
|
+
children: t("contextrequest")
|
|
6722
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6723
|
+
className: annotations_module_css_default.contextText,
|
|
6724
|
+
children: item.question
|
|
6725
|
+
})] }),
|
|
6726
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6727
|
+
className: annotations_module_css_default.contextLabel,
|
|
6728
|
+
children: t("contextreply")
|
|
6729
|
+
}),
|
|
6730
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6731
|
+
className: annotations_module_css_default.contextText,
|
|
6732
|
+
children: item.text
|
|
6733
|
+
})
|
|
6734
|
+
]
|
|
6735
|
+
}),
|
|
6736
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6737
|
+
className: annotations_module_css_default.contextActions,
|
|
6738
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
6739
|
+
type: "button",
|
|
6740
|
+
className: annotations_module_css_default.contextAction,
|
|
6741
|
+
disabled: submission.pending,
|
|
6742
|
+
"aria-label": t("reflowRemoveTitle"),
|
|
6743
|
+
title: t("reflowRemoveTitle"),
|
|
6744
|
+
onClick: () => {
|
|
6745
|
+
reflow.remove(item.id);
|
|
6746
|
+
},
|
|
6747
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconTrashOutline16, { size: 16 })
|
|
6748
|
+
})
|
|
6749
|
+
})
|
|
6750
|
+
]
|
|
6751
|
+
}, item.id))
|
|
6752
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6753
|
+
className: annotations_module_css_default.contextFooter,
|
|
6486
6754
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
6487
6755
|
type: "button",
|
|
6488
6756
|
className: annotations_module_css_default.chipClearAll,
|
|
6489
6757
|
disabled: submission.pending,
|
|
6490
6758
|
onClick: () => {
|
|
6491
|
-
|
|
6759
|
+
clear(open.kind);
|
|
6492
6760
|
},
|
|
6493
6761
|
children: t("clearAll")
|
|
6494
6762
|
})
|
|
6495
6763
|
})]
|
|
6496
|
-
})
|
|
6764
|
+
}), document.body)
|
|
6497
6765
|
]
|
|
6498
6766
|
});
|
|
6499
6767
|
}
|
|
6500
|
-
function
|
|
6501
|
-
return
|
|
6502
|
-
|
|
6503
|
-
|
|
6504
|
-
function createAnnotationChip(ctx, store, reflow) {
|
|
6505
|
-
return function AnnotationChipEntry(props) {
|
|
6506
|
-
const diagnostics = hostDiagnostics(ctx);
|
|
6507
|
-
const capabilities = (0, react.useSyncExternalStore)(diagnostics.subscribe, diagnostics.getSnapshot);
|
|
6508
|
-
(0, react.useEffect)(() => {
|
|
6509
|
-
const state = store.getSubmission(props.session.sessionId);
|
|
6510
|
-
if (!state.pending && state.error === t("inputUnavailable") && resolveInput(ctx, props.session.sessionId)) store.setSubmission(props.session.sessionId, { pending: false });
|
|
6511
|
-
}, [capabilities, props.session.sessionId]);
|
|
6512
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AnnotationChip, {
|
|
6768
|
+
function createContextChips(ctx, store, reflow) {
|
|
6769
|
+
return function ContextChipsEntry(props) {
|
|
6770
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AnnotationBoundary, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ContextChips, {
|
|
6771
|
+
ctx,
|
|
6513
6772
|
store,
|
|
6514
|
-
|
|
6515
|
-
|
|
6516
|
-
|
|
6517
|
-
submitControlledInput(ctx, store, reflow, props.session.sessionId);
|
|
6518
|
-
}
|
|
6519
|
-
});
|
|
6773
|
+
reflow,
|
|
6774
|
+
sessionId: props.session.sessionId
|
|
6775
|
+
}, props.session.sessionId) });
|
|
6520
6776
|
};
|
|
6521
6777
|
}
|
|
6522
6778
|
//#endregion
|
|
6523
|
-
//#region src/client/
|
|
6524
|
-
/**
|
|
6525
|
-
function
|
|
6526
|
-
|
|
6527
|
-
|
|
6528
|
-
|
|
6529
|
-
|
|
6530
|
-
|
|
6531
|
-
|
|
6532
|
-
|
|
6533
|
-
|
|
6534
|
-
|
|
6535
|
-
|
|
6536
|
-
|
|
6537
|
-
|
|
6538
|
-
|
|
6539
|
-
|
|
6540
|
-
|
|
6541
|
-
|
|
6542
|
-
|
|
6543
|
-
|
|
6544
|
-
|
|
6545
|
-
|
|
6546
|
-
|
|
6547
|
-
|
|
6548
|
-
|
|
6549
|
-
|
|
6550
|
-
|
|
6551
|
-
}, [expanded]);
|
|
6552
|
-
(0, react.useEffect)(() => {
|
|
6553
|
-
setExpanded(false);
|
|
6554
|
-
}, [sessionId]);
|
|
6555
|
-
const items = reflow.list(sessionId);
|
|
6556
|
-
if (items.length === 0) return null;
|
|
6557
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6558
|
-
ref: rootRef,
|
|
6559
|
-
className: annotations_module_css_default.chipWrap,
|
|
6560
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
6561
|
-
type: "button",
|
|
6562
|
-
className: annotations_module_css_default.chip,
|
|
6563
|
-
"aria-expanded": expanded,
|
|
6564
|
-
onClick: () => {
|
|
6565
|
-
setExpanded((open) => !open);
|
|
6566
|
-
},
|
|
6567
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconShareOutline16, { size: 12 }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t(items.length === 1 ? "reflowChipOne" : "reflowChipMany", { n: items.length }) })]
|
|
6568
|
-
}), expanded && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
6569
|
-
className: annotations_module_css_default.chipPanel,
|
|
6570
|
-
children: items.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
6571
|
-
className: annotations_module_css_default.chipRow,
|
|
6572
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
6573
|
-
className: annotations_module_css_default.chipText,
|
|
6574
|
-
title: item.text,
|
|
6575
|
-
children: [
|
|
6576
|
-
t("reflowFrom", { title: item.sideTitle }),
|
|
6577
|
-
" ",
|
|
6578
|
-
item.text.replace(/[*_`#>[\]]/g, "").replace(/\s+/g, " ")
|
|
6579
|
-
]
|
|
6580
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
6581
|
-
type: "button",
|
|
6582
|
-
className: annotations_module_css_default.chipRemove,
|
|
6583
|
-
title: t("reflowRemoveTitle"),
|
|
6584
|
-
"aria-label": t("reflowRemoveTitle"),
|
|
6585
|
-
onClick: () => {
|
|
6586
|
-
reflow.remove(item.id);
|
|
6587
|
-
},
|
|
6588
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconCloseOutline16, { size: 12 })
|
|
6589
|
-
})]
|
|
6590
|
-
}, item.id))
|
|
6591
|
-
})]
|
|
6779
|
+
//#region src/client/annotations/send.ts
|
|
6780
|
+
/** Main and side composers use this same native transaction and acceptance boundary. */
|
|
6781
|
+
async function submitAnnotations(options) {
|
|
6782
|
+
const { ctx, store, sessionId, input, annotations } = options;
|
|
6783
|
+
cancelInputRollback(input);
|
|
6784
|
+
const parts = [...options.leadingBlocks ?? []];
|
|
6785
|
+
if (annotations.length > 0) parts.push(buildProtocolBlock(annotations));
|
|
6786
|
+
const block = parts.join("\n\n");
|
|
6787
|
+
if (block === "") return false;
|
|
6788
|
+
const draftBeforeWait = input.state.getSnapshot();
|
|
6789
|
+
let prefix = "";
|
|
6790
|
+
let receipt;
|
|
6791
|
+
try {
|
|
6792
|
+
receipt = await prepareSubmission(ctx, sessionId, input, block);
|
|
6793
|
+
const draft = input.state.getSnapshot();
|
|
6794
|
+
if (draft.draft !== draftBeforeWait.draft || draft.draftRev !== draftBeforeWait.draftRev) throw new Error("等待会话就绪期间草稿已改变;正文和注释已保留,请重新发送");
|
|
6795
|
+
prefix = block + (draft.draft === "" ? "" : "\n\n");
|
|
6796
|
+
if (!prependInputText(input, prefix)) throw new Error("宿主输入尚未就绪,无法安全加入引用;内容已保留");
|
|
6797
|
+
receipt.submit(options.mode);
|
|
6798
|
+
await receipt.outcome;
|
|
6799
|
+
store.markSent(annotations.filter((annotation) => store.get(annotation.id) === annotation).map((annotation) => annotation.id));
|
|
6800
|
+
return true;
|
|
6801
|
+
} catch (error) {
|
|
6802
|
+
rollbackInputPrefix(input, prefix);
|
|
6803
|
+
const text = error instanceof Error ? error.message : String(error);
|
|
6804
|
+
store.setSubmission(sessionId, {
|
|
6805
|
+
pending: false,
|
|
6806
|
+
error: text
|
|
6592
6807
|
});
|
|
6808
|
+
try {
|
|
6809
|
+
if (typeof input.notify === "function") input.notify("error", text);
|
|
6810
|
+
} catch {}
|
|
6811
|
+
return false;
|
|
6812
|
+
} finally {
|
|
6813
|
+
receipt?.dispose();
|
|
6593
6814
|
}
|
|
6594
|
-
return function ReflowChipEntry(props) {
|
|
6595
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AnnotationBoundary, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReflowChip, { ...props }) });
|
|
6596
|
-
};
|
|
6597
6815
|
}
|
|
6598
|
-
|
|
6599
|
-
|
|
6600
|
-
|
|
6601
|
-
|
|
6602
|
-
|
|
6603
|
-
|
|
6604
|
-
|
|
6605
|
-
|
|
6606
|
-
|
|
6607
|
-
|
|
6608
|
-
|
|
6609
|
-
|
|
6610
|
-
|
|
6611
|
-
const
|
|
6612
|
-
|
|
6613
|
-
|
|
6614
|
-
|
|
6615
|
-
const
|
|
6616
|
-
|
|
6617
|
-
|
|
6618
|
-
|
|
6619
|
-
|
|
6620
|
-
|
|
6621
|
-
|
|
6622
|
-
|
|
6623
|
-
if (sessionId === "") return false;
|
|
6624
|
-
const active = store.listActive(sessionId);
|
|
6625
|
-
const reflows = reflow.list(sessionId);
|
|
6626
|
-
const prefix = submissionExtrasOf(sessionId)?.firstSendPrefix();
|
|
6627
|
-
if (active.length === 0 && reflows.length === 0 && !prefix) return false;
|
|
6628
|
-
const input = resolveInput(ctx, sessionId);
|
|
6629
|
-
if (input === void 0) {
|
|
6630
|
-
store.setSubmission(sessionId, {
|
|
6631
|
-
pending: false,
|
|
6632
|
-
error: t("inputUnavailable")
|
|
6633
|
-
});
|
|
6816
|
+
/** Shared by native input gestures and the explicit annotation/reflow actions. */
|
|
6817
|
+
async function submitControlledInput(ctx, store, reflow, sessionId, mode) {
|
|
6818
|
+
if (store.getSubmission(sessionId).pending) return false;
|
|
6819
|
+
const input = resolveInput(ctx, sessionId);
|
|
6820
|
+
if (!input) {
|
|
6821
|
+
store.setSubmission(sessionId, {
|
|
6822
|
+
pending: false,
|
|
6823
|
+
error: t("inputUnavailable")
|
|
6824
|
+
});
|
|
6825
|
+
return false;
|
|
6826
|
+
}
|
|
6827
|
+
const draft = input.state.getSnapshot();
|
|
6828
|
+
if (draft.phase !== "plain" || draft.draft.trimStart().startsWith("/")) return false;
|
|
6829
|
+
const active = store.listActive(sessionId);
|
|
6830
|
+
const reflows = reflow.list(sessionId);
|
|
6831
|
+
if (draft.draft.trim() === "" && inputAttachmentIds(input).length === 0 && active.length === 0 && reflows.length === 0) return false;
|
|
6832
|
+
const extras = submissionExtrasOf(sessionId);
|
|
6833
|
+
const prefix = extras?.firstSendPrefix();
|
|
6834
|
+
store.setSubmission(sessionId, { pending: true });
|
|
6835
|
+
try {
|
|
6836
|
+
const { injectedIds } = await tryInjectReflows(sessionId, reflows);
|
|
6837
|
+
for (const id of injectedIds) reflow.remove(id);
|
|
6838
|
+
const hitchhikers = reflows.filter((item) => !injectedIds.has(item.id));
|
|
6839
|
+
if (active.length === 0 && hitchhikers.length === 0 && !prefix) {
|
|
6840
|
+
if (input.state.getSnapshot().draft.trim() !== "" || inputAttachmentIds(input).length > 0) input.submit(mode);
|
|
6634
6841
|
return true;
|
|
6635
6842
|
}
|
|
6636
|
-
const
|
|
6637
|
-
|
|
6638
|
-
|
|
6639
|
-
|
|
6640
|
-
|
|
6641
|
-
|
|
6642
|
-
|
|
6643
|
-
|
|
6644
|
-
committingSessions.delete(sessionId);
|
|
6843
|
+
const accepted = await submitAnnotations({
|
|
6844
|
+
ctx,
|
|
6845
|
+
store,
|
|
6846
|
+
sessionId,
|
|
6847
|
+
input,
|
|
6848
|
+
annotations: active,
|
|
6849
|
+
leadingBlocks: [...prefix ? [prefix] : [], ...hitchhikers.map(buildReflowBlock)],
|
|
6850
|
+
mode
|
|
6645
6851
|
});
|
|
6646
|
-
|
|
6647
|
-
|
|
6648
|
-
|
|
6649
|
-
|
|
6650
|
-
if (!isMainComposerInput(target)) return;
|
|
6651
|
-
const seat = mainComposerOf(target);
|
|
6652
|
-
if (event.isComposing || event.keyCode === 229) return;
|
|
6653
|
-
if (committingSessions.has(currentSessionId(seat)) || store.getSubmission(currentSessionId(seat)).pending) {
|
|
6654
|
-
if (event.key === "Enter") {
|
|
6655
|
-
event.preventDefault();
|
|
6656
|
-
event.stopImmediatePropagation();
|
|
6657
|
-
}
|
|
6658
|
-
return;
|
|
6659
|
-
}
|
|
6660
|
-
if (event.key !== "Enter" || event.shiftKey) return;
|
|
6661
|
-
if (!hijack(seat, event.metaKey || event.ctrlKey ? "steer" : void 0)) return;
|
|
6662
|
-
event.preventDefault();
|
|
6663
|
-
event.stopImmediatePropagation();
|
|
6664
|
-
};
|
|
6665
|
-
const onClick = (event) => {
|
|
6666
|
-
const target = event.target;
|
|
6667
|
-
if (!(target instanceof Element)) return;
|
|
6668
|
-
const seat = mainComposerOf(target);
|
|
6669
|
-
if (seat === null) return;
|
|
6670
|
-
const button = target.closest("button");
|
|
6671
|
-
if (swallowNextClick && button === findSendButtonInCard(seat)) {
|
|
6672
|
-
clearSwallow();
|
|
6673
|
-
event.preventDefault();
|
|
6674
|
-
event.stopImmediatePropagation();
|
|
6675
|
-
return;
|
|
6676
|
-
}
|
|
6677
|
-
if (button === null) return;
|
|
6678
|
-
if (button !== findSendButtonInCard(seat)) return;
|
|
6679
|
-
if (ctx.sessions.binding(currentSessionId(seat))?.session.getSnapshot().running === true && resolveInput(ctx, currentSessionId(seat))?.state.getSnapshot().draft.trim() === "") return;
|
|
6680
|
-
if (committingSessions.has(currentSessionId(seat))) {
|
|
6681
|
-
event.preventDefault();
|
|
6682
|
-
event.stopImmediatePropagation();
|
|
6683
|
-
return;
|
|
6852
|
+
if (accepted) {
|
|
6853
|
+
for (const item of hitchhikers) reflow.remove(item.id);
|
|
6854
|
+
extras?.onSubmitText(draft.draft);
|
|
6855
|
+
extras?.onAccepted();
|
|
6684
6856
|
}
|
|
6685
|
-
|
|
6686
|
-
|
|
6687
|
-
|
|
6688
|
-
|
|
6689
|
-
|
|
6690
|
-
|
|
6691
|
-
|
|
6692
|
-
|
|
6693
|
-
|
|
6694
|
-
|
|
6695
|
-
|
|
6696
|
-
|
|
6697
|
-
|
|
6698
|
-
if (seat === null) return;
|
|
6699
|
-
const button = target.closest("button");
|
|
6700
|
-
if (!(button instanceof HTMLButtonElement)) return;
|
|
6701
|
-
if (!button.disabled) return;
|
|
6702
|
-
if (button !== findSendButtonInCard(seat)) return;
|
|
6703
|
-
if (committingSessions.has(currentSessionId(seat))) return;
|
|
6704
|
-
const sessionId = currentSessionId(seat);
|
|
6705
|
-
if (sessionId === "") return;
|
|
6706
|
-
const input = resolveInput(ctx, sessionId);
|
|
6707
|
-
if (input === void 0 || input.state.getSnapshot().draft.trim() !== "") return;
|
|
6708
|
-
if (!hijack(seat)) return;
|
|
6709
|
-
armSwallow();
|
|
6710
|
-
event.preventDefault();
|
|
6711
|
-
event.stopImmediatePropagation();
|
|
6712
|
-
};
|
|
6713
|
-
document.addEventListener("keydown", onKeyDown, true);
|
|
6714
|
-
document.addEventListener("click", onClick, true);
|
|
6715
|
-
document.addEventListener("pointerdown", onPointerDown, true);
|
|
6716
|
-
return () => {
|
|
6717
|
-
clearSwallow();
|
|
6718
|
-
document.removeEventListener("keydown", onKeyDown, true);
|
|
6719
|
-
document.removeEventListener("click", onClick, true);
|
|
6720
|
-
document.removeEventListener("pointerdown", onPointerDown, true);
|
|
6721
|
-
};
|
|
6857
|
+
return accepted;
|
|
6858
|
+
} catch (error) {
|
|
6859
|
+
store.setSubmission(sessionId, {
|
|
6860
|
+
pending: false,
|
|
6861
|
+
error: error instanceof Error ? error.message : String(error)
|
|
6862
|
+
});
|
|
6863
|
+
return false;
|
|
6864
|
+
} finally {
|
|
6865
|
+
store.setSubmission(sessionId, {
|
|
6866
|
+
...store.getSubmission(sessionId),
|
|
6867
|
+
pending: false
|
|
6868
|
+
});
|
|
6869
|
+
}
|
|
6722
6870
|
}
|
|
6723
6871
|
//#endregion
|
|
6724
|
-
//#region src/client/annotations/
|
|
6725
|
-
/**
|
|
6726
|
-
|
|
6727
|
-
|
|
6872
|
+
//#region src/client/annotations/NativeComposer.tsx
|
|
6873
|
+
/** The host has already resolved Enter/click, menus, IME and busy delivery mode. */
|
|
6874
|
+
function submitNativeWithContext(ctx, annotations, reflow, sessionId, native, mode, source) {
|
|
6875
|
+
if (annotations.getSubmission(sessionId).pending) return;
|
|
6876
|
+
const hasContext = annotations.countActive(sessionId) > 0 || reflow.list(sessionId).length > 0;
|
|
6877
|
+
const input = resolveInput(ctx, sessionId);
|
|
6878
|
+
if (!input) {
|
|
6879
|
+
if (hasContext || submissionExtrasOf(sessionId)?.firstSendPrefix()) annotations.setSubmission(sessionId, {
|
|
6880
|
+
pending: false,
|
|
6881
|
+
error: t("inputUnavailable")
|
|
6882
|
+
});
|
|
6883
|
+
else native(mode, source);
|
|
6884
|
+
return;
|
|
6885
|
+
}
|
|
6886
|
+
const draft = input.state.getSnapshot();
|
|
6887
|
+
if (draft.phase !== "plain" || draft.draft.trimStart().startsWith("/")) {
|
|
6888
|
+
native(mode, source);
|
|
6889
|
+
return;
|
|
6890
|
+
}
|
|
6891
|
+
const hasMessage = draft.draft.trim() !== "" || inputAttachmentIds(input).length > 0;
|
|
6892
|
+
if (hasContext || hasMessage && submissionExtrasOf(sessionId)?.firstSendPrefix()) submitControlledInput(ctx, annotations, reflow, sessionId, mode);
|
|
6893
|
+
else native(mode, source);
|
|
6894
|
+
}
|
|
6895
|
+
function ContextComposer({ Original, props, ctx, annotations, reflow }) {
|
|
6896
|
+
(0, react.useSyncExternalStore)(annotations.subscribe, annotations.getSnapshot);
|
|
6897
|
+
(0, react.useSyncExternalStore)(reflow.subscribe, reflow.getSnapshot);
|
|
6898
|
+
const input = props.useInput((state) => state);
|
|
6899
|
+
const session = props.useSession((state) => state);
|
|
6900
|
+
const busyMode = props.useBusyEnter((mode) => mode);
|
|
6901
|
+
const sessionId = props.sessionId ?? "";
|
|
6902
|
+
const pending = annotations.getSubmission(sessionId).pending;
|
|
6903
|
+
const contextOnly = (annotations.countActive(sessionId) > 0 || reflow.list(sessionId).length > 0) && input?.draft.trim() === "" && (input.attachmentIds ?? input.imageIds ?? []).length === 0;
|
|
6904
|
+
const root = (0, react.useRef)(null);
|
|
6905
|
+
const [seat] = (0, react.useState)(() => document.createElement("span"));
|
|
6906
|
+
const [nativeButton, setNativeButton] = (0, react.useState)(null);
|
|
6907
|
+
const keyboard = (0, react.useMemo)(() => props.keyboard && new Proxy(props.keyboard, { get(target, property) {
|
|
6908
|
+
if (property === "submit") return (mode, source) => submitNativeWithContext(ctx, annotations, reflow, sessionId, target.submit.bind(target), mode, source);
|
|
6909
|
+
const value = Reflect.get(target, property, target);
|
|
6910
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
6911
|
+
} }), [
|
|
6912
|
+
props.keyboard,
|
|
6913
|
+
ctx,
|
|
6914
|
+
annotations,
|
|
6915
|
+
reflow,
|
|
6916
|
+
sessionId
|
|
6917
|
+
]);
|
|
6918
|
+
const useInput = (0, react.useCallback)((select) => props.useInput((state) => select(pending && state?.phase === "plain" ? {
|
|
6919
|
+
...state,
|
|
6920
|
+
phase: "submitting"
|
|
6921
|
+
} : state)), [props.useInput, pending]);
|
|
6922
|
+
(0, react.useLayoutEffect)(() => {
|
|
6923
|
+
if (!contextOnly || !root.current) return;
|
|
6924
|
+
const button = findSendButtonInCard(root.current);
|
|
6925
|
+
if (!button) return;
|
|
6926
|
+
setNativeButton(button);
|
|
6927
|
+
seat.style.display = "contents";
|
|
6928
|
+
button.parentElement.append(seat);
|
|
6929
|
+
if (!session?.running) button.dataset.sidenoteContextReplaced = "";
|
|
6930
|
+
return () => {
|
|
6931
|
+
delete button.dataset.sidenoteContextReplaced;
|
|
6932
|
+
seat.remove();
|
|
6933
|
+
};
|
|
6934
|
+
}, [
|
|
6935
|
+
contextOnly,
|
|
6936
|
+
session?.running,
|
|
6937
|
+
sessionId,
|
|
6938
|
+
props.variant,
|
|
6939
|
+
seat
|
|
6940
|
+
]);
|
|
6941
|
+
const offline = session?.subagent?.address.mode === "continuable" && session.subagent.parentAvailable !== true;
|
|
6942
|
+
const disabled = pending || input?.phase !== "plain" || props.disabled || props.blocked !== void 0 || session?.removed || offline || !keyboard || !props.inputActions;
|
|
6943
|
+
const mode = session?.running ? busyMode : void 0;
|
|
6944
|
+
const label = props.t(session?.running ? mode === "steer" ? "input.send.steer" : "input.send.queue" : "input.send");
|
|
6945
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6946
|
+
className: annotations_module_css_default.userContextHost,
|
|
6947
|
+
ref: root,
|
|
6948
|
+
children: [(0, react.createElement)(Original, {
|
|
6949
|
+
...props,
|
|
6950
|
+
keyboard,
|
|
6951
|
+
useInput
|
|
6952
|
+
}), contextOnly && nativeButton && (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
6953
|
+
type: "button",
|
|
6954
|
+
"data-sidenote-submit": true,
|
|
6955
|
+
className: nativeButton.className,
|
|
6956
|
+
disabled,
|
|
6957
|
+
"aria-label": label,
|
|
6958
|
+
title: label,
|
|
6959
|
+
onClick: () => {
|
|
6960
|
+
keyboard?.submit(mode, "click");
|
|
6961
|
+
},
|
|
6962
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
6963
|
+
width: "20",
|
|
6964
|
+
height: "20",
|
|
6965
|
+
viewBox: "0 0 24 24",
|
|
6966
|
+
fill: "none",
|
|
6967
|
+
stroke: "currentColor",
|
|
6968
|
+
strokeWidth: "2",
|
|
6969
|
+
strokeLinecap: "round",
|
|
6970
|
+
strokeLinejoin: "round",
|
|
6971
|
+
"aria-hidden": "true",
|
|
6972
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M12 19V5m-6 6 6-6 6 6" })
|
|
6973
|
+
})
|
|
6974
|
+
}), seat)]
|
|
6975
|
+
});
|
|
6976
|
+
}
|
|
6977
|
+
/** Keep the native editor and controls; replace only its empty submit seat
|
|
6978
|
+
* while plugin-owned context exists, and retain a separate native Stop. */
|
|
6979
|
+
function registerNativeComposer(ctx, annotations, reflow) {
|
|
6728
6980
|
const slots = ctx.slots;
|
|
6729
|
-
ctx.slots.inject("conversation.
|
|
6981
|
+
ctx.slots.inject("conversation.composer.bar", () => {
|
|
6730
6982
|
const patched = /* @__PURE__ */ new Map();
|
|
6731
6983
|
const patch = () => {
|
|
6732
|
-
for (const entry of slots.entries("conversation.
|
|
6733
|
-
if (
|
|
6984
|
+
for (const entry of slots.entries("conversation.composer.bar")) {
|
|
6985
|
+
if (patched.has(entry)) continue;
|
|
6734
6986
|
const Original = entry.component;
|
|
6735
|
-
|
|
6736
|
-
|
|
6737
|
-
|
|
6738
|
-
|
|
6739
|
-
|
|
6740
|
-
|
|
6741
|
-
|
|
6742
|
-
|
|
6743
|
-
const content = blocks.map((block, index) => index === at ? {
|
|
6744
|
-
...block,
|
|
6745
|
-
text: afterSnapshot.slice(protocol?.length ?? 0).trimStart()
|
|
6746
|
-
} : block);
|
|
6747
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
6748
|
-
snapshot && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
|
|
6749
|
-
className: annotations_module_css_default.sentContext,
|
|
6750
|
-
"data-sidenote-progress-snapshot": true,
|
|
6751
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", { children: t("snapshotContext") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", { children: snapshot.snapshot })]
|
|
6752
|
-
}),
|
|
6753
|
-
protocol && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6754
|
-
"data-dsh-sidenote-bubble": true,
|
|
6755
|
-
children: [protocol.annotations.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
|
|
6756
|
-
className: annotations_module_css_default.sentContext,
|
|
6757
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", { children: t("sentChipLabel", { n: protocol.annotations.length }) }), protocol.annotations.map((annotation) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("blockquote", { children: [annotation.quote, annotation.note && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: annotation.note })] }, annotation.id))]
|
|
6758
|
-
}), protocol.reflows.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
|
|
6759
|
-
className: annotations_module_css_default.sentContext,
|
|
6760
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", { children: t("reflowBubbleLabel") }), protocol.reflows.map((reflow, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("blockquote", { children: [reflow.source, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", { children: flattenReflowContent(reflow.content) })] }, index))]
|
|
6761
|
-
})]
|
|
6762
|
-
}),
|
|
6763
|
-
(0, react.createElement)(Original, {
|
|
6764
|
-
...props,
|
|
6765
|
-
node: {
|
|
6766
|
-
...props.node,
|
|
6767
|
-
data: {
|
|
6768
|
-
...props.node.data,
|
|
6769
|
-
content
|
|
6770
|
-
}
|
|
6771
|
-
}
|
|
6772
|
-
})
|
|
6773
|
-
] });
|
|
6774
|
-
}
|
|
6775
|
-
entry.component = ContextUser;
|
|
6987
|
+
const Wrapped = (props) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ContextComposer, {
|
|
6988
|
+
Original,
|
|
6989
|
+
props,
|
|
6990
|
+
ctx,
|
|
6991
|
+
annotations,
|
|
6992
|
+
reflow
|
|
6993
|
+
});
|
|
6994
|
+
entry.component = Wrapped;
|
|
6776
6995
|
patched.set(entry, {
|
|
6777
6996
|
original: Original,
|
|
6778
|
-
wrapped:
|
|
6997
|
+
wrapped: Wrapped
|
|
6779
6998
|
});
|
|
6780
6999
|
}
|
|
6781
7000
|
};
|
|
6782
7001
|
patch();
|
|
6783
|
-
const off = slots.subscribe("conversation.
|
|
7002
|
+
const off = slots.subscribe("conversation.composer.bar", patch);
|
|
6784
7003
|
return () => {
|
|
6785
7004
|
off();
|
|
6786
7005
|
for (const [entry, value] of patched) if (entry.component === value.wrapped) entry.component = value.original;
|
|
@@ -6788,6 +7007,320 @@ ${entries.map((entry) => {
|
|
|
6788
7007
|
});
|
|
6789
7008
|
}
|
|
6790
7009
|
//#endregion
|
|
7010
|
+
//#region src/client/annotations/NativeUserContext.tsx
|
|
7011
|
+
const CONTEXT_NODE = "dsh-sidenote-context";
|
|
7012
|
+
/** Injected notices and their following human input are one admitted batch.
|
|
7013
|
+
* Project its reflows into that bubble without changing or resending history. */
|
|
7014
|
+
function injectedReflowPrefix(nodes, seq) {
|
|
7015
|
+
const prefixes = [];
|
|
7016
|
+
for (let i = nodes.findIndex((node) => node.seq === seq) - 1; i >= 0; i--) {
|
|
7017
|
+
const node = nodes[i];
|
|
7018
|
+
if (node.kind !== "context") break;
|
|
7019
|
+
if (node.source?.kind !== "dsh-sidenote") continue;
|
|
7020
|
+
const text = (node.content ?? []).filter((block) => block.type === "text").map((block) => block.text ?? "").join("\n");
|
|
7021
|
+
const start = text.indexOf("<reflow ");
|
|
7022
|
+
if (start < 0) continue;
|
|
7023
|
+
const prefix = splitProtocolPrefix(text.slice(start));
|
|
7024
|
+
if (prefix?.reflows.length) prefixes.unshift(text.slice(start, start + prefix.length));
|
|
7025
|
+
}
|
|
7026
|
+
return prefixes.join("\n\n");
|
|
7027
|
+
}
|
|
7028
|
+
/** One prefix node leaves the body, @ references and attachments to the host. */
|
|
7029
|
+
const sentContextRule = {
|
|
7030
|
+
id: CONTEXT_NODE,
|
|
7031
|
+
order: 0,
|
|
7032
|
+
match(text, from) {
|
|
7033
|
+
const snapshot = splitSnapshotPrefix(text);
|
|
7034
|
+
const start = snapshot ? text.length - snapshot.rest.length : 0;
|
|
7035
|
+
if (from > start) return void 0;
|
|
7036
|
+
const protocol = splitProtocolPrefix(text.slice(start));
|
|
7037
|
+
return protocol ? {
|
|
7038
|
+
id: CONTEXT_NODE,
|
|
7039
|
+
start,
|
|
7040
|
+
end: start + protocol.length,
|
|
7041
|
+
data: protocol
|
|
7042
|
+
} : void 0;
|
|
7043
|
+
}
|
|
7044
|
+
};
|
|
7045
|
+
function ContextChip({ label, icon, children, interactive }) {
|
|
7046
|
+
const [open, setOpen] = (0, react.useState)(null);
|
|
7047
|
+
const [position, setPosition] = (0, react.useState)({ visibility: "hidden" });
|
|
7048
|
+
const anchor = (0, react.useRef)(null);
|
|
7049
|
+
const panel = (0, react.useRef)(null);
|
|
7050
|
+
const timer = (0, react.useRef)(void 0);
|
|
7051
|
+
const clearTimer = () => {
|
|
7052
|
+
clearTimeout(timer.current);
|
|
7053
|
+
timer.current = void 0;
|
|
7054
|
+
};
|
|
7055
|
+
const leave = () => {
|
|
7056
|
+
clearTimer();
|
|
7057
|
+
if (!open?.pinned) timer.current = setTimeout(() => {
|
|
7058
|
+
if (!panel.current?.contains(document.activeElement)) setOpen(null);
|
|
7059
|
+
}, 160);
|
|
7060
|
+
};
|
|
7061
|
+
const id = (0, react.useId)();
|
|
7062
|
+
const expanded = open !== null;
|
|
7063
|
+
(0, react.useEffect)(() => clearTimer, []);
|
|
7064
|
+
(0, react.useLayoutEffect)(() => {
|
|
7065
|
+
if (!expanded) return;
|
|
7066
|
+
const place = () => {
|
|
7067
|
+
const rect = anchor.current.getBoundingClientRect();
|
|
7068
|
+
const view = conversationViewOf(anchor.current).getBoundingClientRect();
|
|
7069
|
+
const left = Math.max(12, view.left + 12), right = Math.min(window.innerWidth - 12, view.right - 12);
|
|
7070
|
+
const top = Math.max(12, view.top + 12), bottom = Math.min(window.innerHeight - 12, view.bottom - 12);
|
|
7071
|
+
if (rect.bottom < top || rect.top > bottom) {
|
|
7072
|
+
setOpen(null);
|
|
7073
|
+
return;
|
|
7074
|
+
}
|
|
7075
|
+
const width = Math.min(420, right - left);
|
|
7076
|
+
const above = rect.top - top - 8, below = bottom - rect.bottom - 8;
|
|
7077
|
+
const preferAbove = above >= Math.min(280, window.innerHeight / 3) || above >= below;
|
|
7078
|
+
setPosition({
|
|
7079
|
+
width,
|
|
7080
|
+
left: Math.max(left, Math.min(rect.left, right - width)),
|
|
7081
|
+
maxHeight: Math.min(280, window.innerHeight / 3, preferAbove ? above : below),
|
|
7082
|
+
...preferAbove ? { bottom: window.innerHeight - rect.top + 8 } : { top: rect.bottom + 8 }
|
|
7083
|
+
});
|
|
7084
|
+
};
|
|
7085
|
+
place();
|
|
7086
|
+
window.addEventListener("scroll", place, true);
|
|
7087
|
+
window.addEventListener("resize", place);
|
|
7088
|
+
return () => {
|
|
7089
|
+
window.removeEventListener("scroll", place, true);
|
|
7090
|
+
window.removeEventListener("resize", place);
|
|
7091
|
+
};
|
|
7092
|
+
}, [expanded]);
|
|
7093
|
+
(0, react.useEffect)(() => {
|
|
7094
|
+
if (!expanded) return;
|
|
7095
|
+
const outside = (event) => {
|
|
7096
|
+
if (!anchor.current?.contains(event.target) && !panel.current?.contains(event.target)) {
|
|
7097
|
+
clearTimer();
|
|
7098
|
+
setOpen(null);
|
|
7099
|
+
}
|
|
7100
|
+
};
|
|
7101
|
+
const escape = (event) => {
|
|
7102
|
+
if (event.key === "Escape") {
|
|
7103
|
+
event.preventDefault();
|
|
7104
|
+
clearTimer();
|
|
7105
|
+
setOpen(null);
|
|
7106
|
+
anchor.current?.focus();
|
|
7107
|
+
}
|
|
7108
|
+
};
|
|
7109
|
+
document.addEventListener("pointerdown", outside);
|
|
7110
|
+
document.addEventListener("keydown", escape);
|
|
7111
|
+
return () => {
|
|
7112
|
+
document.removeEventListener("pointerdown", outside);
|
|
7113
|
+
document.removeEventListener("keydown", escape);
|
|
7114
|
+
};
|
|
7115
|
+
}, [expanded]);
|
|
7116
|
+
(0, react.useLayoutEffect)(() => {
|
|
7117
|
+
if (open?.pinned && document.activeElement === anchor.current) panel.current?.focus();
|
|
7118
|
+
}, [open?.pinned]);
|
|
7119
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
7120
|
+
className: annotations_module_css_default.sentChipGroup,
|
|
7121
|
+
children: [interactive ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
7122
|
+
ref: anchor,
|
|
7123
|
+
type: "button",
|
|
7124
|
+
className: annotations_module_css_default.sentChip,
|
|
7125
|
+
"aria-haspopup": "dialog",
|
|
7126
|
+
"aria-expanded": expanded,
|
|
7127
|
+
"aria-controls": id,
|
|
7128
|
+
onPointerEnter: (event) => {
|
|
7129
|
+
if (event.pointerType === "touch") return;
|
|
7130
|
+
clearTimer();
|
|
7131
|
+
if (!open && !document.querySelector("[data-sidenote-sent-preview][data-pinned]")) timer.current = setTimeout(() => {
|
|
7132
|
+
setOpen({ pinned: false });
|
|
7133
|
+
}, 180);
|
|
7134
|
+
},
|
|
7135
|
+
onPointerLeave: leave,
|
|
7136
|
+
onClick: () => {
|
|
7137
|
+
clearTimer();
|
|
7138
|
+
setOpen(open?.pinned ? null : { pinned: true });
|
|
7139
|
+
},
|
|
7140
|
+
children: [
|
|
7141
|
+
icon,
|
|
7142
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: label }),
|
|
7143
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconChevronDownOutline14, {
|
|
7144
|
+
size: 12,
|
|
7145
|
+
className: expanded ? annotations_module_css_default.sentChevronOpen : annotations_module_css_default.sentChevron
|
|
7146
|
+
})
|
|
7147
|
+
]
|
|
7148
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
7149
|
+
className: annotations_module_css_default.sentChip,
|
|
7150
|
+
children: [icon, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: label })]
|
|
7151
|
+
}), interactive && expanded && (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7152
|
+
ref: panel,
|
|
7153
|
+
id,
|
|
7154
|
+
role: "dialog",
|
|
7155
|
+
tabIndex: -1,
|
|
7156
|
+
"aria-label": label,
|
|
7157
|
+
className: `${annotations_module_css_default.contextPanel} ${annotations_module_css_default.sentPreview}`,
|
|
7158
|
+
style: position,
|
|
7159
|
+
"data-sidenote-sent-preview": true,
|
|
7160
|
+
"data-pinned": open.pinned || void 0,
|
|
7161
|
+
"data-sidenote-no-quote": true,
|
|
7162
|
+
onPointerEnter: clearTimer,
|
|
7163
|
+
onPointerLeave: leave,
|
|
7164
|
+
children
|
|
7165
|
+
}), document.body)]
|
|
7166
|
+
});
|
|
7167
|
+
}
|
|
7168
|
+
function SentContext({ protocol, interactive = true }) {
|
|
7169
|
+
useLocaleTick();
|
|
7170
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
7171
|
+
className: annotations_module_css_default.sentChips,
|
|
7172
|
+
"data-dsh-sidenote-bubble": true,
|
|
7173
|
+
"data-sidenote-no-quote": true,
|
|
7174
|
+
children: [protocol.annotations.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ContextChip, {
|
|
7175
|
+
label: t("sentChipLabel", { n: protocol.annotations.length }),
|
|
7176
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconListPenOutline16, { size: 12 }),
|
|
7177
|
+
interactive,
|
|
7178
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
7179
|
+
className: annotations_module_css_default.contextList,
|
|
7180
|
+
children: protocol.annotations.map((annotation) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
7181
|
+
className: annotations_module_css_default.contextItem,
|
|
7182
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
7183
|
+
className: annotations_module_css_default.contextNumber,
|
|
7184
|
+
children: [annotation.id, "."]
|
|
7185
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7186
|
+
className: annotations_module_css_default.contextContent,
|
|
7187
|
+
children: [
|
|
7188
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7189
|
+
className: annotations_module_css_default.contextLabel,
|
|
7190
|
+
children: t("selectedText")
|
|
7191
|
+
}),
|
|
7192
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7193
|
+
className: annotations_module_css_default.contextText,
|
|
7194
|
+
children: annotation.quote
|
|
7195
|
+
}),
|
|
7196
|
+
annotation.note && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7197
|
+
className: annotations_module_css_default.contextLabel,
|
|
7198
|
+
children: t("userComment")
|
|
7199
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7200
|
+
className: annotations_module_css_default.contextText,
|
|
7201
|
+
children: annotation.note
|
|
7202
|
+
})] })
|
|
7203
|
+
]
|
|
7204
|
+
})]
|
|
7205
|
+
}, annotation.id))
|
|
7206
|
+
})
|
|
7207
|
+
}), protocol.reflows.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ContextChip, {
|
|
7208
|
+
label: t("reflowBubbleLabel"),
|
|
7209
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconShareOutline16, { size: 12 }),
|
|
7210
|
+
interactive,
|
|
7211
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
7212
|
+
className: annotations_module_css_default.contextList,
|
|
7213
|
+
children: protocol.reflows.map((reflow, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
7214
|
+
className: annotations_module_css_default.contextItem,
|
|
7215
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
7216
|
+
className: annotations_module_css_default.contextNumber,
|
|
7217
|
+
children: [index + 1, "."]
|
|
7218
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7219
|
+
className: annotations_module_css_default.contextContent,
|
|
7220
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7221
|
+
className: annotations_module_css_default.contextSource,
|
|
7222
|
+
children: reflow.source
|
|
7223
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7224
|
+
className: annotations_module_css_default.contextText,
|
|
7225
|
+
children: flattenReflowContent(reflow.content)
|
|
7226
|
+
})]
|
|
7227
|
+
})]
|
|
7228
|
+
}, index))
|
|
7229
|
+
})
|
|
7230
|
+
})]
|
|
7231
|
+
});
|
|
7232
|
+
}
|
|
7233
|
+
function LegacyContext({ Original, props, protocol }) {
|
|
7234
|
+
const root = (0, react.useRef)(null);
|
|
7235
|
+
const [seat] = (0, react.useState)(() => document.createElement("span"));
|
|
7236
|
+
(0, react.useLayoutEffect)(() => root.current ? mountUserBubbleAddon(root.current, seat) : void 0, [seat, props.node]);
|
|
7237
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7238
|
+
ref: root,
|
|
7239
|
+
className: annotations_module_css_default.userContextHost,
|
|
7240
|
+
children: [(0, react.createElement)(Original, props), (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SentContext, { protocol }), seat)]
|
|
7241
|
+
});
|
|
7242
|
+
}
|
|
7243
|
+
/** Keep contextual chips inside the native bubble on both main and side chat.
|
|
7244
|
+
* Only the progress snapshot remains outside its owning user message. */
|
|
7245
|
+
function registerUserContext(ctx) {
|
|
7246
|
+
ctx.inject(["uiConversation"], () => {
|
|
7247
|
+
const ui = ctx.get("uiConversation");
|
|
7248
|
+
const nativeText = ui.userText !== void 0;
|
|
7249
|
+
if (nativeText) ctx.slots.inject("conversation.user.text.node", () => {
|
|
7250
|
+
const offRenderer = ctx.slots.register({
|
|
7251
|
+
name: "conversation.user.text.node",
|
|
7252
|
+
key: CONTEXT_NODE
|
|
7253
|
+
}, (props) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SentContext, {
|
|
7254
|
+
protocol: props.node.data,
|
|
7255
|
+
interactive: props.interactive
|
|
7256
|
+
}));
|
|
7257
|
+
const offRule = ui.userText.register(sentContextRule);
|
|
7258
|
+
return () => {
|
|
7259
|
+
offRule();
|
|
7260
|
+
offRenderer();
|
|
7261
|
+
};
|
|
7262
|
+
});
|
|
7263
|
+
const slots = ctx.slots;
|
|
7264
|
+
ctx.slots.inject("conversation.chat.node", () => {
|
|
7265
|
+
const patched = /* @__PURE__ */ new Map();
|
|
7266
|
+
const patch = () => {
|
|
7267
|
+
for (const entry of slots.entries("conversation.chat.node")) {
|
|
7268
|
+
if (!["user", "steering"].includes(entry.options.key ?? "") || patched.has(entry)) continue;
|
|
7269
|
+
const Original = entry.component;
|
|
7270
|
+
function ContextUser(props) {
|
|
7271
|
+
const injected = injectedReflowPrefix(props.useChat((state) => state.legacy.nodes), props.node.data.seq);
|
|
7272
|
+
const blocks = props.node.data.content;
|
|
7273
|
+
const at = blocks.findIndex((block) => block.type === "text");
|
|
7274
|
+
const text = blocks[at]?.text ?? "";
|
|
7275
|
+
const snapshot = splitSnapshotPrefix(text);
|
|
7276
|
+
const afterSnapshot = (injected ? injected + "\n\n" : "") + (snapshot?.rest ?? text);
|
|
7277
|
+
const protocol = nativeText ? null : splitProtocolPrefix(afterSnapshot);
|
|
7278
|
+
if (!snapshot && !protocol && !injected) return (0, react.createElement)(Original, props);
|
|
7279
|
+
const displayText = (protocol ? afterSnapshot.slice(protocol.length).trimStart() : afterSnapshot) || (protocol ? "" : "");
|
|
7280
|
+
const content = at < 0 ? [...blocks, {
|
|
7281
|
+
type: "text",
|
|
7282
|
+
text: displayText
|
|
7283
|
+
}] : blocks.map((block, index) => index === at ? {
|
|
7284
|
+
...block,
|
|
7285
|
+
text: displayText
|
|
7286
|
+
} : block);
|
|
7287
|
+
const projected = {
|
|
7288
|
+
...props,
|
|
7289
|
+
node: {
|
|
7290
|
+
...props.node,
|
|
7291
|
+
data: {
|
|
7292
|
+
...props.node.data,
|
|
7293
|
+
content
|
|
7294
|
+
}
|
|
7295
|
+
}
|
|
7296
|
+
};
|
|
7297
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [snapshot && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
|
|
7298
|
+
className: annotations_module_css_default.sentContext,
|
|
7299
|
+
"data-sidenote-progress-snapshot": true,
|
|
7300
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", { children: t("snapshotContext") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", { children: snapshot.snapshot })]
|
|
7301
|
+
}), protocol ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LegacyContext, {
|
|
7302
|
+
Original,
|
|
7303
|
+
props: projected,
|
|
7304
|
+
protocol
|
|
7305
|
+
}) : (0, react.createElement)(Original, projected)] });
|
|
7306
|
+
}
|
|
7307
|
+
entry.component = ContextUser;
|
|
7308
|
+
patched.set(entry, {
|
|
7309
|
+
original: Original,
|
|
7310
|
+
wrapped: ContextUser
|
|
7311
|
+
});
|
|
7312
|
+
}
|
|
7313
|
+
};
|
|
7314
|
+
patch();
|
|
7315
|
+
const off = slots.subscribe("conversation.chat.node", patch);
|
|
7316
|
+
return () => {
|
|
7317
|
+
off();
|
|
7318
|
+
for (const [entry, value] of patched) if (entry.component === value.wrapped) entry.component = value.original;
|
|
7319
|
+
};
|
|
7320
|
+
});
|
|
7321
|
+
});
|
|
7322
|
+
}
|
|
7323
|
+
//#endregion
|
|
6791
7324
|
//#region src/client/annotate/index.tsx
|
|
6792
7325
|
/**
|
|
6793
7326
|
* 划选注释(Delivery_02 重构后):selection listener + numbered badges +
|
|
@@ -6816,29 +7349,21 @@ ${entries.map((entry) => {
|
|
|
6816
7349
|
store,
|
|
6817
7350
|
controller
|
|
6818
7351
|
}));
|
|
6819
|
-
|
|
7352
|
+
registerNativeComposer(ctx, store, reflow);
|
|
6820
7353
|
registerUserContext(ctx);
|
|
6821
7354
|
ctx.slots.inject("conversation.input.dock", () => {
|
|
6822
|
-
const
|
|
7355
|
+
const offContext = ctx.slots.register({
|
|
6823
7356
|
name: "conversation.input.dock",
|
|
6824
7357
|
id: "dsh-sidenote-annotations",
|
|
6825
7358
|
order: 10,
|
|
6826
7359
|
registrant: "dsh-sidenote"
|
|
6827
|
-
},
|
|
6828
|
-
const offReflow = ctx.slots.register({
|
|
6829
|
-
name: "conversation.input.dock",
|
|
6830
|
-
id: "dsh-sidenote-reflow",
|
|
6831
|
-
order: 11,
|
|
6832
|
-
registrant: "dsh-sidenote"
|
|
6833
|
-
}, createReflowChip(reflow));
|
|
7360
|
+
}, createContextChips(ctx, store, reflow));
|
|
6834
7361
|
hostDiagnostics(ctx).dockRegistered();
|
|
6835
7362
|
return () => {
|
|
6836
|
-
|
|
6837
|
-
offReflow();
|
|
7363
|
+
offContext();
|
|
6838
7364
|
};
|
|
6839
7365
|
});
|
|
6840
7366
|
return () => {
|
|
6841
|
-
offInterceptor();
|
|
6842
7367
|
controller.dispose();
|
|
6843
7368
|
setTimeout(() => {
|
|
6844
7369
|
root.unmount();
|