dsh-quote-annotate-pro 0.2.7 → 0.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/lib/client.js +48 -6
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
本项目的所有重要变更都记在这里。版本号遵循 [SemVer](https://semver.org/lang/zh-CN/)。
|
|
4
4
|
|
|
5
|
+
## 0.2.8 — 修复"批注编辑框跑到窗口左上角 / 引用不了"
|
|
6
|
+
|
|
7
|
+
- **现象**:选中文字点「批注」后,编辑框出现在窗口左上角(压住侧边栏),看起来像引用功能坏了
|
|
8
|
+
- **根因**:装饰逻辑会替换消息里的文本节点;若用户**正在那条消息里划词**,替换会让选区失效,`getBoundingClientRect()` 随即返回全 0 —— 用这个矩形算出来的位置正好是 `left=12 / top=8`(窗口左上角)
|
|
9
|
+
- **修复**
|
|
10
|
+
- **不再动用户正在划词的那条消息**:`selectionTouches(row)` 守卫,等选区释放后再装饰
|
|
11
|
+
- **`safeRect()` 兜底**:矩形无效时先用当前选区重算,仍无效则退回视口底部居中 —— 编辑框不会再跑到左上角
|
|
12
|
+
- 文本与模型侧行为不变(位置行仍只对模型可见)
|
|
13
|
+
|
|
5
14
|
## 0.2.7 — 引用渲染定版:输入框与对话区都不再"先露原文"
|
|
6
15
|
|
|
7
16
|
- **输入框侧(本次)**:插入引用后**同一帧内**完成装饰 —— 不再走 `setTimeout`,改为在 `MutationObserver` 回调里同步执行(回调先于绘制),消除此前约 40ms 的"先露出完整引用块"窗口
|
package/lib/client.js
CHANGED
|
@@ -683,7 +683,7 @@ window.__ModuleLoader__.load({
|
|
|
683
683
|
anchorKey: sel.anchorKey,
|
|
684
684
|
turn: sel.turn,
|
|
685
685
|
kind: sel.kind,
|
|
686
|
-
}, sel.rect)
|
|
686
|
+
}, safeRect(sel.rect))
|
|
687
687
|
finish()
|
|
688
688
|
}
|
|
689
689
|
return React.createElement('div', { className: 'dshq-toolbar', style: { left, top } },
|
|
@@ -704,6 +704,31 @@ window.__ModuleLoader__.load({
|
|
|
704
704
|
}
|
|
705
705
|
|
|
706
706
|
// ============ 组件三:悬浮批注编辑框(评论输入框元素永久驻留,复用时输入法上下文不重建) ============
|
|
707
|
+
/**
|
|
708
|
+
* 选区矩形兜底。矩形失效(节点被装饰/重渲染替换后 getBoundingClientRect 会全 0)时,
|
|
709
|
+
* 直接用它会算出 left=12 / top=8 —— 编辑框就跑到窗口左上角(用户反馈的现象)。
|
|
710
|
+
* 处理:无效 → 用当前选区重算 → 仍无效 → 退回视口底部居中。
|
|
711
|
+
*/
|
|
712
|
+
function safeRect(rect) {
|
|
713
|
+
const ok = (r) => !!(r
|
|
714
|
+
&& Number.isFinite(r.left) && Number.isFinite(r.top)
|
|
715
|
+
&& Number.isFinite(r.right) && Number.isFinite(r.bottom)
|
|
716
|
+
&& ((r.right - r.left) > 0 || (r.bottom - r.top) > 0))
|
|
717
|
+
if (ok(rect)) return rect
|
|
718
|
+
try {
|
|
719
|
+
const s = typeof window !== 'undefined' ? window.getSelection() : null
|
|
720
|
+
if (s && s.rangeCount > 0) {
|
|
721
|
+
const r = s.getRangeAt(0).getBoundingClientRect()
|
|
722
|
+
if (ok(r)) return r
|
|
723
|
+
}
|
|
724
|
+
} catch (e) { /* ignore */ }
|
|
725
|
+
const vw = typeof window !== 'undefined' ? window.innerWidth : 1024
|
|
726
|
+
const vh = typeof window !== 'undefined' ? window.innerHeight : 768
|
|
727
|
+
const left = Math.max(12, Math.round(vw / 2 - 140))
|
|
728
|
+
const top = Math.max(12, Math.round(vh - 200))
|
|
729
|
+
return { left, right: left + 280, top, bottom: top + 24, width: 280, height: 24 }
|
|
730
|
+
}
|
|
731
|
+
|
|
707
732
|
const AnnotationEditor = () => {
|
|
708
733
|
const state = useEditor()
|
|
709
734
|
const inputRef = React.useRef(null)
|
|
@@ -721,18 +746,19 @@ window.__ModuleLoader__.load({
|
|
|
721
746
|
const vw = typeof window !== 'undefined' ? window.innerWidth : 1024
|
|
722
747
|
const vh = typeof window !== 'undefined' ? window.innerHeight : 768
|
|
723
748
|
const item = state.item
|
|
749
|
+
const rect = open ? safeRect(state.rect) : null
|
|
724
750
|
let left = -9999
|
|
725
751
|
let top = -9999
|
|
726
752
|
let w = 200
|
|
727
|
-
if (open) {
|
|
753
|
+
if (open && rect) {
|
|
728
754
|
// 宽度:默认约 10 字(120px),随评论输入变宽,封顶 340px
|
|
729
755
|
const quoteW = Math.min(220, item.text.length * 12 + 16)
|
|
730
756
|
const inputW = Math.min(300, Math.max(140, comment.length * 13 + 44))
|
|
731
757
|
w = Math.max(120, Math.min(340, Math.max(quoteW, inputW)))
|
|
732
|
-
const center =
|
|
758
|
+
const center = rect.left + (rect.right - rect.left) / 2
|
|
733
759
|
left = Math.max(12, Math.min(center - w / 2, vw - w - 12))
|
|
734
760
|
const estH = 200
|
|
735
|
-
top =
|
|
761
|
+
top = rect.bottom + 8 + estH <= vh - 8 ? rect.bottom + 8 : Math.max(8, rect.top - estH - 8)
|
|
736
762
|
}
|
|
737
763
|
const insert = () => {
|
|
738
764
|
if (!open || !item) return
|
|
@@ -1293,6 +1319,20 @@ window.__ModuleLoader__.load({
|
|
|
1293
1319
|
})
|
|
1294
1320
|
return wrap
|
|
1295
1321
|
}
|
|
1322
|
+
/** 用户当前选区是否落在这个行里(是则暂缓装饰,别动 DOM 把选区搞失效) */
|
|
1323
|
+
const selectionTouches = (row) => {
|
|
1324
|
+
try {
|
|
1325
|
+
const s = typeof window !== 'undefined' ? window.getSelection() : null
|
|
1326
|
+
if (!s || s.rangeCount === 0 || s.isCollapsed) return false
|
|
1327
|
+
for (let i = 0; i < s.rangeCount; i++) {
|
|
1328
|
+
const r = s.getRangeAt(i)
|
|
1329
|
+
const a = r.startContainer
|
|
1330
|
+
const b = r.endContainer
|
|
1331
|
+
if ((a && row.contains(a)) || (b && row.contains(b))) return true
|
|
1332
|
+
}
|
|
1333
|
+
} catch (e) { /* ignore */ }
|
|
1334
|
+
return false
|
|
1335
|
+
}
|
|
1296
1336
|
/** 把承载「【引用…】\n原文…」的文本节点拆成:隐藏头部 + 紧凑引用块 + 其余文本 */
|
|
1297
1337
|
const transformTextNode = (node) => {
|
|
1298
1338
|
const raw = node.nodeValue || ''
|
|
@@ -1326,10 +1366,12 @@ window.__ModuleLoader__.load({
|
|
|
1326
1366
|
}
|
|
1327
1367
|
const scan = () => {
|
|
1328
1368
|
timer = null
|
|
1329
|
-
try {
|
|
1330
|
-
for (const row of document.querySelectorAll(USER_ROW_SEL)) {
|
|
1369
|
+
try { for (const row of document.querySelectorAll(USER_ROW_SEL)) {
|
|
1331
1370
|
const kind = row.getAttribute('data-chat-flow-kind')
|
|
1332
1371
|
if (kind && kind !== 'user') continue
|
|
1372
|
+
// 用户正在这条消息里划词时**不要动它的 DOM**:替换文本节点会让选区失效,
|
|
1373
|
+
// 选区矩形随即变成全 0,批注气泡/编辑框就会定位到左上角(用户反馈过)。
|
|
1374
|
+
if (selectionTouches(row)) continue
|
|
1333
1375
|
let walker
|
|
1334
1376
|
try { walker = document.createTreeWalker(row, NodeFilter.SHOW_TEXT, null) } catch (e) { continue }
|
|
1335
1377
|
const targets = []
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-quote-annotate-pro",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.8",
|
|
4
4
|
"description": "选区引用与锚点批注(增强 fork):划词 → 批注 → 带精确锚点的引用;输入框上方只显示原文片段,点一下跳回原文;发送时把轮次/角色写入引用块,让模型精确知道你指的是哪一处。",
|
|
5
5
|
"keywords": ["dsh", "dsh-plugin", "deepseek-harness", "quote", "annotate", "selection", "reference", "anchor"],
|
|
6
6
|
"license": "MIT",
|