one-design-next 0.0.13 → 0.0.14

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.
@@ -34,7 +34,7 @@ import { createPortal } from 'react-dom';
34
34
  import { buildClipboardPayload, COMPOSER_CLIPBOARD_MIME, parseClipboardPayload, plainTextFromClipboardPayload, remapClipboardPayload } from "./clipboard";
35
35
  import { useChipManager } from "./hooks/useChipManager";
36
36
  import { useChipSelectionMarker } from "./hooks/useChipSelectionMarker";
37
- import { findChipHostBeforeCaret, getPlainText, isEditorEmpty, probeTrigger, resolveCaretJumpAroundChip, ZWSP } from "./utils";
37
+ import { findChipHostAfterCaret, findChipHostBeforeCaret, getPlainText, getVisibleTextBeforeHost, isEditorEmpty, moveCaretBeforeChip, normalizeEditorDom, probeTrigger, resolveCaretJumpAroundChip, stripInvisibleChars, ZWSP } from "./utils";
38
38
  import { ComposerInlineRef } from "./inline-ref";
39
39
  import ScrollArea from "../scroll-area";
40
40
 
@@ -176,6 +176,7 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
176
176
  var fireChange = useCallback(function () {
177
177
  var el = editorRef.current;
178
178
  if (!el) return;
179
+ normalizeEditorDom(el);
179
180
  setEmpty(isEditorEmpty(el));
180
181
  onChange === null || onChange === void 0 || onChange(getPlainText(el));
181
182
  // editor.height 锁定时 RO 不触发,主动同步一次,确保升格判定能拿到 scrollHeight
@@ -390,7 +391,10 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
390
391
  * ───────────────────────────────────── */
391
392
  var handleInput = useCallback(function () {
392
393
  var el = editorRef.current;
393
- if (el) setEmpty(isEditorEmpty(el));
394
+ if (el) {
395
+ normalizeEditorDom(el);
396
+ setEmpty(isEditorEmpty(el));
397
+ }
394
398
  requestScrollCaretIntoView();
395
399
  if (isComposingRef.current) return;
396
400
  fireChange();
@@ -442,17 +446,35 @@ export var ComposerEditor = /*#__PURE__*/forwardRef(function ComposerEditor(_ref
442
446
  if (onTriggerKeyDown(e) === true) return;
443
447
  }
444
448
 
445
- // Backspace:紧邻 chip 后方时整块删
449
+ // Backspace:chip 边界——空 text 在 chip 后先退回 chip 前;chip 前无正文再整块删
446
450
  if (e.key === 'Backspace') {
451
+ var el = editorRef.current;
447
452
  var sel = window.getSelection();
448
- if (sel && sel.rangeCount > 0) {
453
+ if (el && sel && sel.rangeCount > 0) {
449
454
  var range = sel.getRangeAt(0);
450
- if (range.collapsed) {
451
- var host = findChipHostBeforeCaret(range);
452
- var _id = host === null || host === void 0 ? void 0 : host.dataset.mentionId;
453
- if (_id) {
455
+ if (range.collapsed && el.contains(range.startContainer)) {
456
+ var hostBefore = findChipHostBeforeCaret(range);
457
+ if (hostBefore !== null && hostBefore !== void 0 && hostBefore.dataset.mentionId) {
458
+ var _node$textContent;
459
+ var node = range.startContainer,
460
+ offset = range.startOffset;
461
+ if (node.nodeType === Node.TEXT_NODE && offset === 0 && node.previousSibling === hostBefore && stripInvisibleChars((_node$textContent = node.textContent) !== null && _node$textContent !== void 0 ? _node$textContent : '') === '') {
462
+ e.preventDefault();
463
+ moveCaretBeforeChip(hostBefore, {
464
+ removeTrailingEmptyText: true,
465
+ trailingText: node
466
+ });
467
+ return;
468
+ }
469
+ e.preventDefault();
470
+ removeChip(hostBefore.dataset.mentionId);
471
+ return;
472
+ }
473
+ var hostAfter = findChipHostAfterCaret(range);
474
+ var idAfter = hostAfter === null || hostAfter === void 0 ? void 0 : hostAfter.dataset.mentionId;
475
+ if (idAfter && getVisibleTextBeforeHost(el, hostAfter).trim() === '') {
454
476
  e.preventDefault();
455
- removeChip(_id);
477
+ removeChip(idAfter);
456
478
  return;
457
479
  }
458
480
  }
@@ -86,6 +86,19 @@ export declare function resolveCaretJumpAroundChip(range: Range, direction: 'lef
86
86
  node: Node;
87
87
  offset: number;
88
88
  } | null;
89
+ export declare function childIndex(node: Node): number;
90
+ /** chip 之前的可见纯文本(不含 marker / 不可见字符)。 */
91
+ export declare function getVisibleTextBeforeHost(editor: HTMLElement, host: HTMLElement, chipIdAttr?: string): string;
92
+ /**
93
+ * 清理 contenteditable 删字后的幽灵节点:空 text、仅 chip 时的占位 <br>。
94
+ * 避免「文字 + invocation」删光文字后出现多余换行,以及 caret 卡在 chip 后误删 invocation。
95
+ */
96
+ export declare function normalizeEditorDom(editor: HTMLElement, _chipIdAttr?: string): void;
97
+ /** caret 落在 chip 后空 text 时,挪到 chip 前(不删 chip)。 */
98
+ export declare function moveCaretBeforeChip(host: HTMLElement, opts?: {
99
+ removeTrailingEmptyText?: boolean;
100
+ trailingText?: Text | null;
101
+ }): void;
89
102
  export interface TriggerProbe {
90
103
  /** 触发字符 */
91
104
  trigger: string;
@@ -328,7 +328,7 @@ export function resolveCaretJumpAroundChip(range, direction) {
328
328
  offset: childIndex(chip) + 1
329
329
  };
330
330
  }
331
- function childIndex(node) {
331
+ export function childIndex(node) {
332
332
  var i = 0;
333
333
  var cur = node.previousSibling;
334
334
  while (cur) {
@@ -338,6 +338,83 @@ function childIndex(node) {
338
338
  return i;
339
339
  }
340
340
 
341
+ /** chip 之前的可见纯文本(不含 marker / 不可见字符)。 */
342
+ export function getVisibleTextBeforeHost(editor, host) {
343
+ var chipIdAttr = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'mentionId';
344
+ var r = document.createRange();
345
+ r.selectNodeContents(editor);
346
+ r.setEndBefore(host);
347
+ var tmp = document.createElement('div');
348
+ tmp.appendChild(r.cloneContents());
349
+ return stripInvisibleChars(stripMarkers(getPlainText(tmp))).replace(/\n/g, '');
350
+ }
351
+
352
+ /**
353
+ * 清理 contenteditable 删字后的幽灵节点:空 text、仅 chip 时的占位 <br>。
354
+ * 避免「文字 + invocation」删光文字后出现多余换行,以及 caret 卡在 chip 后误删 invocation。
355
+ */
356
+ export function normalizeEditorDom(editor) {
357
+ var _chipIdAttr = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'mentionId';
358
+ var emptyTexts = [];
359
+ var walker = document.createTreeWalker(editor, NodeFilter.SHOW_TEXT);
360
+ var n;
361
+ while (n = walker.nextNode()) {
362
+ var _t$textContent;
363
+ var t = n;
364
+ if (stripInvisibleChars((_t$textContent = t.textContent) !== null && _t$textContent !== void 0 ? _t$textContent : '') === '') {
365
+ emptyTexts.push(t);
366
+ }
367
+ }
368
+ emptyTexts.forEach(function (t) {
369
+ return t.remove();
370
+ });
371
+ var plain = stripInvisibleChars(stripMarkers(getPlainText(editor))).replace(/\n/g, '');
372
+ var hasChip = !!editor.querySelector('[data-odn-composer-chip-host]');
373
+ if (hasChip && plain === '') {
374
+ editor.querySelectorAll('br').forEach(function (br) {
375
+ return br.remove();
376
+ });
377
+ }
378
+ editor.querySelectorAll('[data-odn-composer-chip-host]').forEach(function (hostEl) {
379
+ var host = hostEl;
380
+ var prev = host.previousSibling;
381
+ while (prev) {
382
+ if (prev.nodeType === Node.TEXT_NODE) {
383
+ var _prev$textContent;
384
+ var _t = stripInvisibleChars((_prev$textContent = prev.textContent) !== null && _prev$textContent !== void 0 ? _prev$textContent : '');
385
+ if (_t !== '') break;
386
+ var rm = prev;
387
+ prev = prev.previousSibling;
388
+ rm.remove();
389
+ continue;
390
+ }
391
+ if (prev.nodeType === Node.ELEMENT_NODE && prev.tagName === 'BR') {
392
+ var _rm = prev;
393
+ prev = prev.previousSibling;
394
+ _rm.remove();
395
+ continue;
396
+ }
397
+ break;
398
+ }
399
+ });
400
+ }
401
+
402
+ /** caret 落在 chip 后空 text 时,挪到 chip 前(不删 chip)。 */
403
+ export function moveCaretBeforeChip(host, opts) {
404
+ var parent = host.parentNode;
405
+ if (!parent) return;
406
+ var sel = window.getSelection();
407
+ if (!sel) return;
408
+ var r = document.createRange();
409
+ r.setStart(parent, childIndex(host));
410
+ r.collapse(true);
411
+ sel.removeAllRanges();
412
+ sel.addRange(r);
413
+ if (opts !== null && opts !== void 0 && opts.removeTrailingEmptyText && opts.trailingText) {
414
+ opts.trailingText.remove();
415
+ }
416
+ }
417
+
341
418
  /* ────────────────────────────────────────────────────────────────────
342
419
  * Trigger probe · @ / / 触发态判定
343
420
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "one-design-next",
3
- "version": "0.0.13",
3
+ "version": "0.0.14",
4
4
  "description": "One Design Next from TAD@tencent.com",
5
5
  "module": "dist/index.js",
6
6
  "types": "dist/index.d.ts",