@aipanel/dsh-client 1.2.7 → 1.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.
Files changed (2) hide show
  1. package/lib/client.js +80 -11
  2. package/package.json +8 -5
package/lib/client.js CHANGED
@@ -285,7 +285,7 @@ function registerDiagnosticsView(ctx) {
285
285
 
286
286
  // dsh-client/src/client/index.ts
287
287
  var SELECTION_STORAGE_KEY = "dsh.bridge.selection";
288
- var inject = ["slots"];
288
+ var inject = ["slots", "sessions", "inputTriggers", "conversation"];
289
289
  var SESSION_READY_EVENT = "aipanel:session-ready";
290
290
  var INSERT_ELEMENT_EVENT = "aipanel:insert-element";
291
291
  var SESSION_SETTLE_MS = 400;
@@ -447,12 +447,46 @@ function apply(ctx) {
447
447
  let start = snapshot.draft.length;
448
448
  let end = snapshot.draft.length;
449
449
  try {
450
- const el = document.querySelector("textarea[data-phase]");
451
- if (el && el.value === snapshot.draft) {
452
- const s = el.selectionStart ?? 0;
453
- const e = el.selectionEnd ?? s;
454
- start = Math.min(s, snapshot.draft.length);
455
- end = Math.min(e, snapshot.draft.length);
450
+ const composer = document.querySelector(
451
+ '[role="textbox"][contenteditable="true"], textarea[data-phase]'
452
+ );
453
+ if (composer) {
454
+ if (composer.isContentEditable) {
455
+ const draftInComposer = (composer.innerText ?? "").replace(/\n$/, "");
456
+ if (draftInComposer === snapshot.draft) {
457
+ const sel = window.getSelection();
458
+ if (sel && sel.rangeCount > 0 && sel.anchorNode && sel.focusNode && composer.contains(sel.anchorNode) && composer.contains(sel.focusNode)) {
459
+ const textNodes = [];
460
+ const walker = document.createTreeWalker(composer, NodeFilter.SHOW_TEXT);
461
+ let n = walker.nextNode();
462
+ while (n) {
463
+ textNodes.push(n);
464
+ n = walker.nextNode();
465
+ }
466
+ const posOf = (node, off) => {
467
+ const idx = textNodes.indexOf(node);
468
+ if (idx < 0) return null;
469
+ let acc = 0;
470
+ for (let i = 0; i < idx; i++) acc += textNodes[i].data.length;
471
+ return acc + Math.min(off, textNodes[idx].data.length);
472
+ };
473
+ const s = posOf(sel.anchorNode, sel.anchorOffset);
474
+ const e = posOf(sel.focusNode, sel.focusOffset);
475
+ if (s !== null && e !== null) {
476
+ start = Math.min(Math.max(s, 0), snapshot.draft.length);
477
+ end = Math.min(Math.max(e, start), snapshot.draft.length);
478
+ }
479
+ }
480
+ }
481
+ } else {
482
+ const ta = composer;
483
+ if (ta.value === snapshot.draft) {
484
+ const s = ta.selectionStart ?? snapshot.draft.length;
485
+ const e = ta.selectionEnd ?? s;
486
+ start = Math.min(s, snapshot.draft.length);
487
+ end = Math.min(e, snapshot.draft.length);
488
+ }
489
+ }
456
490
  }
457
491
  } catch {
458
492
  }
@@ -479,11 +513,46 @@ function apply(ctx) {
479
513
  input.insertReference(reference, { start, end, draftRev: rev });
480
514
  requestAnimationFrame(() => {
481
515
  try {
482
- const el = document.querySelector("textarea[data-phase]");
516
+ const el = document.querySelector(
517
+ '[role="textbox"][contenteditable="true"], textarea[data-phase]'
518
+ );
483
519
  if (!el) return;
484
- const caret = Math.min(start + insertedLen + leadingSpace, el.value.length);
485
- el.focus();
486
- el.setSelectionRange(caret, caret);
520
+ const caret = start + insertedLen + leadingSpace;
521
+ if (el.isContentEditable) {
522
+ const textNodes = [];
523
+ const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);
524
+ let n = walker.nextNode();
525
+ while (n) {
526
+ textNodes.push(n);
527
+ n = walker.nextNode();
528
+ }
529
+ let target = textNodes[textNodes.length - 1] ?? null;
530
+ let off = target ? target.data.length : 0;
531
+ let remaining = Math.max(0, caret);
532
+ if (target) {
533
+ for (const t of textNodes) {
534
+ if (remaining <= t.data.length) {
535
+ target = t;
536
+ off = remaining;
537
+ break;
538
+ }
539
+ remaining -= t.data.length;
540
+ }
541
+ }
542
+ if (target) {
543
+ const range = document.createRange();
544
+ range.setStart(target, Math.min(off, target.data.length));
545
+ range.collapse(true);
546
+ const sel = window.getSelection();
547
+ sel?.removeAllRanges();
548
+ sel?.addRange(range);
549
+ }
550
+ el.focus();
551
+ } else {
552
+ const ta = el;
553
+ ta.focus();
554
+ ta.setSelectionRange(Math.min(caret, ta.value.length), Math.min(caret, ta.value.length));
555
+ }
487
556
  } catch {
488
557
  }
489
558
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aipanel/dsh-client",
3
- "version": "1.2.7",
3
+ "version": "1.2.8",
4
4
  "type": "module",
5
5
  "description": "AIPanel 浏览器侧插件(dsh web Web Client):注册 @aipanel 文件引用 source,选中元素以 file chip 高亮插入并可供模型解析。",
6
6
  "publishConfig": {
@@ -11,9 +11,9 @@
11
11
  "lib"
12
12
  ],
13
13
  "devDependencies": {
14
- "@deepseek-ai/cordis": "^4.0.1",
15
- "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.1-rc.2",
16
- "@deepseek-ai/dsh-client-ui-primitives": "^0.0.1-rc.1",
14
+ "@deepseek-ai/cordis": "^4.0.2",
15
+ "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.2-rc.1",
16
+ "@deepseek-ai/dsh-client-ui-primitives": "^0.1.2-rc.1",
17
17
  "@types/react": "^18.3.0",
18
18
  "esbuild": "^0.25.0",
19
19
  "react": "^18.3.0"
@@ -27,7 +27,10 @@
27
27
  "client": {
28
28
  "platform": "web",
29
29
  "inject": [
30
- "slots"
30
+ "slots",
31
+ "sessions",
32
+ "inputTriggers",
33
+ "conversation"
31
34
  ]
32
35
  }
33
36
  },