autumnnote 1.0.7 → 1.0.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.
@@ -293,8 +293,24 @@
293
293
  }
294
294
  /**
295
295
  * Strikethrough / removes strikethrough.
296
+ * Falls back to manual DOM manipulation inside nested formats where
297
+ * execCommand's state detection is unreliable (mirrors underline() logic).
296
298
  */
297
- var strikethrough = () => execCommand("strikeThrough");
299
+ function strikethrough() {
300
+ const sel = window.getSelection();
301
+ if (!sel || !sel.rangeCount) return;
302
+ let sc = sel.getRangeAt(0).startContainer;
303
+ if (sc.nodeType === 3) sc = sc.parentElement;
304
+ const sEl = sc && sc.closest && (sc.closest("s") || sc.closest("strike"));
305
+ const nativeState = document.queryCommandState("strikeThrough");
306
+ if (sEl && !nativeState) {
307
+ const parent = sEl.parentNode;
308
+ while (sEl.firstChild) parent.insertBefore(sEl.firstChild, sEl);
309
+ parent.removeChild(sEl);
310
+ return;
311
+ }
312
+ execCommand("strikeThrough");
313
+ }
298
314
  /**
299
315
  * Superscript toggle.
300
316
  */
@@ -327,6 +343,22 @@
327
343
  function fontSize(size, editable = document) {
328
344
  const sel = window.getSelection();
329
345
  const wasCollapsed = !sel || !sel.rangeCount || sel.getRangeAt(0).collapsed;
346
+ if (wasCollapsed && sel && sel.rangeCount > 0) {
347
+ try {
348
+ const range = sel.getRangeAt(0);
349
+ const span = document.createElement("span");
350
+ span.style.fontSize = size;
351
+ const zwsNode = document.createTextNode("​");
352
+ span.appendChild(zwsNode);
353
+ range.insertNode(span);
354
+ const nr = document.createRange();
355
+ nr.setStart(zwsNode, zwsNode.textContent.length);
356
+ nr.collapse(true);
357
+ sel.removeAllRanges();
358
+ sel.addRange(nr);
359
+ } catch (_) {}
360
+ return;
361
+ }
330
362
  execCommand("fontSize", "7");
331
363
  const scope = editable instanceof HTMLElement ? editable : document;
332
364
  const newSpans = [];
@@ -338,27 +370,17 @@
338
370
  el.parentNode.removeChild(el);
339
371
  newSpans.push(span);
340
372
  });
341
- if (sel && newSpans.length > 0) {
373
+ if (!wasCollapsed && sel && newSpans.length > 0) {
342
374
  const first = newSpans[0];
343
375
  const last = newSpans[newSpans.length - 1];
344
376
  try {
345
- if (wasCollapsed) {
346
- if (!first.firstChild) first.appendChild(document.createTextNode("​"));
347
- const nr = document.createRange();
348
- const anchor = first.firstChild;
349
- nr.setStart(anchor, anchor.textContent.length);
350
- nr.collapse(true);
351
- sel.removeAllRanges();
352
- sel.addRange(nr);
353
- } else {
354
- const nr = document.createRange();
355
- const startNode = first.firstChild || first;
356
- const endNode = last.lastChild || last;
357
- nr.setStart(startNode, 0);
358
- nr.setEnd(endNode, endNode.nodeType === Node.TEXT_NODE ? endNode.textContent.length : endNode.childNodes.length);
359
- sel.removeAllRanges();
360
- sel.addRange(nr);
361
- }
377
+ const nr = document.createRange();
378
+ const startNode = first.firstChild || first;
379
+ const endNode = last.lastChild || last;
380
+ nr.setStart(startNode, 0);
381
+ nr.setEnd(endNode, endNode.nodeType === Node.TEXT_NODE ? endNode.textContent.length : endNode.childNodes.length);
382
+ sel.removeAllRanges();
383
+ sel.addRange(nr);
362
384
  } catch (_) {}
363
385
  }
364
386
  }
@@ -389,8 +411,57 @@
389
411
  var indent = () => execCommand("indent");
390
412
  /**
391
413
  * Outdents the list or block.
414
+ * G.5: When cursor is inside a checklist item, "outdent" means converting
415
+ * that item back to a regular <p> element rather than calling execCommand
416
+ * (which would destroy the ul > li checklist structure).
392
417
  */
393
- var outdent = () => execCommand("outdent");
418
+ function outdent() {
419
+ const sel = window.getSelection();
420
+ if (sel && sel.rangeCount) {
421
+ let container = sel.getRangeAt(0).commonAncestorContainer;
422
+ if (container.nodeType === 3) container = container.parentElement;
423
+ const checkLi = container && container.closest && container.closest(".an-checklist li");
424
+ if (checkLi) {
425
+ _checklistItemToP(checkLi);
426
+ return;
427
+ }
428
+ }
429
+ execCommand("outdent");
430
+ }
431
+ /**
432
+ * G.5 helper: splits a checklist at checkLi, converts it to a <p>,
433
+ * and keeps items before/after as separate checklists.
434
+ * @param {HTMLElement} checkLi
435
+ */
436
+ function _checklistItemToP(checkLi) {
437
+ const checkUl = checkLi.closest(".an-checklist");
438
+ if (!checkUl) return;
439
+ const allLis = Array.from(checkUl.children);
440
+ const liIndex = allLis.indexOf(checkLi);
441
+ const afterLis = allLis.slice(liIndex + 1);
442
+ const p = document.createElement("p");
443
+ p.textContent = Array.from(checkLi.childNodes).filter((n) => !(n.nodeType === 1 && n.tagName === "INPUT")).map((n) => n.textContent).join("").replace(/\u200B/g, "").trim() || "\xA0";
444
+ if (afterLis.length > 0) {
445
+ const newUl = document.createElement("ul");
446
+ newUl.className = "an-checklist";
447
+ afterLis.forEach((li) => newUl.appendChild(li));
448
+ checkUl.parentNode.insertBefore(newUl, checkUl.nextSibling);
449
+ }
450
+ checkUl.parentNode.insertBefore(p, checkUl.nextSibling);
451
+ checkUl.removeChild(checkLi);
452
+ if (checkUl.children.length === 0) checkUl.parentNode.removeChild(checkUl);
453
+ try {
454
+ const nr = document.createRange();
455
+ const firstChild = p.firstChild;
456
+ nr.setStart(firstChild && firstChild.nodeType === 3 ? firstChild : p, 0);
457
+ nr.collapse(true);
458
+ const s = window.getSelection();
459
+ if (s) {
460
+ s.removeAllRanges();
461
+ s.addRange(nr);
462
+ }
463
+ } catch {}
464
+ }
394
465
  /**
395
466
  * Inserts an unordered list or converts selection.
396
467
  */
@@ -594,10 +665,60 @@
594
665
  sel.addRange(nr);
595
666
  return;
596
667
  }
597
- const lines = sel.toString().split(/\r?\n/).filter((l) => l.trim().length > 0);
598
- if (lines.length === 0) return;
599
- const items = lines.map((l) => `<li><input type="checkbox" contenteditable="false">${l || "​"}</li>`).join("");
600
- document.execCommand("insertHTML", false, `<ul class="an-checklist">${items}</ul>`);
668
+ if (!sel.toString().replace(/[\u00a0\u200B]/g, " ").trim()) return;
669
+ const BLOCK_TAGS_MULTI = new Set([
670
+ "P",
671
+ "DIV",
672
+ "H1",
673
+ "H2",
674
+ "H3",
675
+ "H4",
676
+ "H5",
677
+ "H6",
678
+ "BLOCKQUOTE",
679
+ "PRE",
680
+ "LI"
681
+ ]);
682
+ const blocks = [];
683
+ const seenBlocks = /* @__PURE__ */ new Set();
684
+ const commonAncestor = range.commonAncestorContainer;
685
+ const iter = document.createNodeIterator(commonAncestor.nodeType === Node.TEXT_NODE ? commonAncestor.parentNode : commonAncestor, NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT, null);
686
+ let node;
687
+ while (node = iter.nextNode()) {
688
+ if (!range.intersectsNode(node)) continue;
689
+ let block = node.nodeType === Node.TEXT_NODE ? node.parentElement : node;
690
+ while (block && !BLOCK_TAGS_MULTI.has(block.tagName)) block = block.parentElement;
691
+ if (block && !seenBlocks.has(block)) {
692
+ seenBlocks.add(block);
693
+ blocks.push(block);
694
+ }
695
+ }
696
+ if (blocks.length === 0) return;
697
+ const newUl = document.createElement("ul");
698
+ newUl.className = "an-checklist";
699
+ let lastTextNode = null;
700
+ blocks.forEach((block) => {
701
+ const li = document.createElement("li");
702
+ const cb = document.createElement("input");
703
+ cb.type = "checkbox";
704
+ cb.setAttribute("contenteditable", "false");
705
+ li.appendChild(cb);
706
+ const blockText = Array.from(block.childNodes).map((n) => n.textContent).join("").replace(/[\u00a0\u200B]/g, " ").trim();
707
+ const tn = document.createTextNode(blockText || "​");
708
+ li.appendChild(tn);
709
+ newUl.appendChild(li);
710
+ lastTextNode = tn;
711
+ });
712
+ const firstBlock = blocks[0];
713
+ firstBlock.parentNode.insertBefore(newUl, firstBlock);
714
+ blocks.forEach((block) => block.parentNode && block.parentNode.removeChild(block));
715
+ if (lastTextNode) {
716
+ const nr = document.createRange();
717
+ nr.setStart(lastTextNode, lastTextNode.textContent.length);
718
+ nr.collapse(true);
719
+ sel.removeAllRanges();
720
+ sel.addRange(nr);
721
+ }
601
722
  }
602
723
  /**
603
724
  * Returns true when the cursor is inside a checklist item.
@@ -1676,7 +1797,7 @@
1676
1797
  const para = closestPara(range.sc, editable);
1677
1798
  if (para && isLi(para)) {
1678
1799
  event.preventDefault();
1679
- if (event.shiftKey) execCommand("outdent");
1800
+ if (event.shiftKey) outdent();
1680
1801
  else execCommand("indent");
1681
1802
  return true;
1682
1803
  }
@@ -2097,7 +2218,12 @@
2097
2218
  };
2098
2219
  const isReadOnly = () => this.context.layoutInfo.container.classList.contains("an-disabled");
2099
2220
  this._disposers.push(on(editable, "keydown", onKeydown), on(editable, "beforeinput", onBeforeInput), on(editable, "input", onInput), on(document, "selectionchange", onSelChange), on(editable, "click", onCheckboxClick), on(editable, "mouseup", fixChecklistCursor), on(editable, "keyup", fixChecklistCursor), on(editable, "dragstart", (e) => {
2100
- if (isReadOnly()) e.preventDefault();
2221
+ if (isReadOnly()) {
2222
+ e.preventDefault();
2223
+ return;
2224
+ }
2225
+ const target = e.target;
2226
+ if (target && (target.nodeName === "IFRAME" || target.closest && target.closest(".an-video-wrapper"))) e.preventDefault();
2101
2227
  }), on(editable, "drop", (e) => {
2102
2228
  if (isReadOnly()) e.preventDefault();
2103
2229
  }));
@@ -2254,7 +2380,7 @@
2254
2380
  * @param {string} html - HTML string (will be sanitised)
2255
2381
  */
2256
2382
  setHTML(html) {
2257
- this.context.layoutInfo.editable.innerHTML = sanitiseHTML(html);
2383
+ this.context.layoutInfo.editable.innerHTML = sanitiseHTML(html, { allowIframes: true });
2258
2384
  if (this._history) this._history.reset();
2259
2385
  this.afterCommand();
2260
2386
  }
@@ -3629,7 +3755,7 @@
3629
3755
  _update() {
3630
3756
  const editable = this.context.layoutInfo.editable;
3631
3757
  const isFocused = document.activeElement === editable;
3632
- const isEmpty = !editable.textContent.trim() && !editable.querySelector("img, table, hr, .an-video-wrapper");
3758
+ const isEmpty = !(editable.textContent.replace(/\u200B/g, "").trim().length > 0) && !editable.querySelector("img, table, hr, .an-video-wrapper");
3633
3759
  editable.classList.toggle("an-placeholder", isEmpty && !isFocused);
3634
3760
  }
3635
3761
  };
@@ -4064,7 +4190,7 @@
4064
4190
  const fileInput = createElement("input", {
4065
4191
  type: "file",
4066
4192
  class: "an-input",
4067
- accept: "image/*"
4193
+ accept: "image/jpeg,image/png,image/gif,image/webp,image/svg+xml,image/avif"
4068
4194
  });
4069
4195
  this._fileInput = fileInput;
4070
4196
  const fileHint = createElement("p", { class: "an-dialog-hint" });
@@ -4111,14 +4237,15 @@
4111
4237
  _onFileChange() {
4112
4238
  const file = this._fileInput && this._fileInput.files && this._fileInput.files[0];
4113
4239
  if (!file || !file.type.startsWith("image/")) return;
4114
- if ([
4115
- "image/tiff",
4116
- "image/x-tiff",
4117
- "image/bmp",
4118
- "image/x-bmp",
4119
- "image/x-ms-bmp"
4120
- ].includes(file.type)) {
4121
- const message = `Format "${file.type}" is not supported for display in web browsers. Please convert to PNG, JPEG, or WebP first.`;
4240
+ if (!new Set([
4241
+ "image/jpeg",
4242
+ "image/png",
4243
+ "image/gif",
4244
+ "image/webp",
4245
+ "image/svg+xml",
4246
+ "image/avif"
4247
+ ]).has(file.type)) {
4248
+ const message = `Format "${file.type}" is not supported for display in web browsers. Please convert to JPEG, PNG, or WebP first.`;
4122
4249
  if (this._fileHint) this._fileHint.textContent = message;
4123
4250
  this.context.triggerEvent("imageError", {
4124
4251
  file,
@@ -5572,6 +5699,47 @@
5572
5699
  }
5573
5700
  return null;
5574
5701
  }
5702
+ /**
5703
+ * Build a 2D grid map of the table, accounting for both rowspan and colspan.
5704
+ *
5705
+ * gridMap[r][c] = the DOM cell occupying visual grid position (r, c).
5706
+ * cellPos = WeakMap: cell → { r, c, rs, cs } (top-left grid origin + span).
5707
+ *
5708
+ * Uses HTMLTableElement.rows which is scoped to the table itself and never
5709
+ * includes rows from nested tables.
5710
+ *
5711
+ * @param {HTMLTableElement} table
5712
+ * @returns {{ gridMap: Object, cellPos: WeakMap }}
5713
+ */
5714
+ function buildGridMap(table) {
5715
+ const rows = Array.from(table.rows);
5716
+ const gridMap = {};
5717
+ const cellPos = /* @__PURE__ */ new WeakMap();
5718
+ rows.forEach((row, r) => {
5719
+ if (!gridMap[r]) gridMap[r] = {};
5720
+ let c = 0;
5721
+ for (const cell of row.cells) {
5722
+ while (gridMap[r][c]) c++;
5723
+ const rs = cell.rowSpan || 1;
5724
+ const cs = cell.colSpan || 1;
5725
+ cellPos.set(cell, {
5726
+ r,
5727
+ c,
5728
+ rs,
5729
+ cs
5730
+ });
5731
+ for (let dr = 0; dr < rs; dr++) {
5732
+ if (!gridMap[r + dr]) gridMap[r + dr] = {};
5733
+ for (let dc = 0; dc < cs; dc++) gridMap[r + dr][c + dc] = cell;
5734
+ }
5735
+ c += cs;
5736
+ }
5737
+ });
5738
+ return {
5739
+ gridMap,
5740
+ cellPos
5741
+ };
5742
+ }
5575
5743
  var ICONS$2 = {
5576
5744
  rowAbove: `<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="1"/><line x1="3" y1="12" x2="21" y2="12"/><path d="M12 3v7"/><path d="M9 7l3-4 3 4"/></svg>`,
5577
5745
  rowBelow: `<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="1"/><line x1="3" y1="12" x2="21" y2="12"/><path d="M12 12v7"/><path d="M9 17l3 4 3-4"/></svg>`,
@@ -5580,10 +5748,12 @@
5580
5748
  colRight: `<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="1"/><line x1="12" y1="3" x2="12" y2="21"/><path d="M12 12h9"/><path d="M17 8l4 4-4 4"/></svg>`,
5581
5749
  deleteCol: `<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="1"/><line x1="12" y1="3" x2="12" y2="21"/><line x1="15" y1="6" x2="21" y2="12"/><line x1="21" y1="6" x2="15" y2="12"/></svg>`,
5582
5750
  mergeCells: `<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="7" width="8" height="10" rx="1"/><rect x="14" y="7" width="8" height="10" rx="1"/><path d="M10 12h4"/><path d="M12 10l2 2-2 2"/></svg>`,
5751
+ unmergeCells: `<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="5" width="20" height="14" rx="1"/><line x1="12" y1="5" x2="12" y2="19" stroke-dasharray="2.5 2"/><line x1="2" y1="12" x2="22" y2="12" stroke-dasharray="2.5 2"/><path d="M9 9 L6 12 L9 15"/><path d="M15 9 L18 12 L15 15"/></svg>`,
5583
5752
  colWidth: `<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="7" y1="4" x2="7" y2="20"/><line x1="17" y1="4" x2="17" y2="20"/><line x1="7" y1="12" x2="17" y2="12"/><path d="M10 9l-3 3 3 3"/><path d="M14 9l3 3-3 3"/></svg>`,
5584
5753
  rowHeight: `<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="4" y1="7" x2="20" y2="7"/><line x1="4" y1="17" x2="20" y2="17"/><line x1="12" y1="7" x2="12" y2="17"/><path d="M9 10l3-3 3 3"/><path d="M9 14l3 3 3-3"/></svg>`,
5585
5754
  tableBorder: `<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round"><line x1="3" y1="6" x2="21" y2="6" stroke-width="1"/><line x1="3" y1="13" x2="21" y2="13" stroke-width="2"/><line x1="3" y1="20" x2="21" y2="20" stroke-width="3"/></svg>`,
5586
- deleteTable: `<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="1"/><line x1="3" y1="9" x2="21" y2="9"/><line x1="3" y1="15" x2="21" y2="15"/><line x1="9" y1="3" x2="9" y2="21"/><line x1="15" y1="3" x2="15" y2="21"/><line x1="16" y1="16" x2="22" y2="22" stroke="#ef4444"/><line x1="22" y1="16" x2="16" y2="22" stroke="#ef4444"/></svg>`
5755
+ deleteTable: `<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="1"/><line x1="3" y1="9" x2="21" y2="9"/><line x1="3" y1="15" x2="21" y2="15"/><line x1="9" y1="3" x2="9" y2="21"/><line x1="15" y1="3" x2="15" y2="21"/><line x1="16" y1="16" x2="22" y2="22" stroke="#ef4444"/><line x1="22" y1="16" x2="16" y2="22" stroke="#ef4444"/></svg>`,
5756
+ selectCells: `<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4 L4 20 L9 15 L12 21 L14 20 L11 14 L17 14 Z" fill="currentColor" opacity="0.15"/><path d="M4 4 L4 20 L9 15 L12 21 L14 20 L11 14 L17 14 Z"/></svg>`
5587
5757
  };
5588
5758
  var TableTooltip = class {
5589
5759
  /** @param {import('../Context.js').Context} context */
@@ -5599,6 +5769,12 @@
5599
5769
  this._sizeApply = null;
5600
5770
  this._sizeTitleEl = null;
5601
5771
  this._sizeInputEl = null;
5772
+ this._selectMode = false;
5773
+ this._selectedCells = [];
5774
+ this._selectStart = null;
5775
+ this._selectDragging = false;
5776
+ this._selectBtn = null;
5777
+ this._editable = null;
5602
5778
  }
5603
5779
  initialize() {
5604
5780
  this._el = this._buildTooltip();
@@ -5606,6 +5782,29 @@
5606
5782
  this._sizePopover = this._buildSizePopover();
5607
5783
  document.body.appendChild(this._sizePopover);
5608
5784
  const editable = this.context.layoutInfo.editable;
5785
+ this._editable = editable;
5786
+ const onSelMousedown = (e) => {
5787
+ if (!this._selectMode) return;
5788
+ const cell = e.target.closest("td, th");
5789
+ if (!cell || !editable.contains(cell)) return;
5790
+ if (cell.style.cursor === "col-resize" || cell.style.cursor === "row-resize") return;
5791
+ e.preventDefault();
5792
+ this._activeTable = cell.closest("table");
5793
+ this._selectStart = cell;
5794
+ this._selectDragging = true;
5795
+ this._setSelection([cell]);
5796
+ };
5797
+ const onSelMousemove = (e) => {
5798
+ if (!this._selectMode || !this._selectDragging || !this._selectStart) return;
5799
+ const cell = e.target.closest("td, th");
5800
+ if (!cell || !editable.contains(cell)) return;
5801
+ if (cell.closest("table") !== this._activeTable) return;
5802
+ this._setSelection(this._getRectCells(this._selectStart, cell));
5803
+ };
5804
+ const onSelMouseup = () => {
5805
+ this._selectDragging = false;
5806
+ };
5807
+ this._disposers.push(on(editable, "mousedown", onSelMousedown), on(editable, "mousemove", onSelMousemove), on(document, "mouseup", onSelMouseup));
5609
5808
  this._disposers.push(on(editable, "mouseover", (e) => {
5610
5809
  if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
5611
5810
  const table = e.target.closest("table");
@@ -5615,9 +5814,11 @@
5615
5814
  this._scheduleShow(table);
5616
5815
  }
5617
5816
  }, { passive: true }), on(editable, "mouseout", (e) => {
5817
+ if (this._selectMode) return;
5618
5818
  const to = e.relatedTarget;
5619
5819
  if (!to || !editable.contains(to) && !this._el.contains(to) && !(this._sizePopover && this._sizePopover.contains(to))) this._scheduleHide();
5620
5820
  }, { passive: true }), on(document, "click", (e) => {
5821
+ if (this._selectMode && this._activeTable && this._activeTable.contains(e.target)) return;
5621
5822
  if (this._activeTable && !this._activeTable.contains(e.target) && !this._el.contains(e.target) && !(this._sizePopover && this._sizePopover.contains(e.target))) this._hide();
5622
5823
  }));
5623
5824
  this._initResize();
@@ -5690,7 +5891,7 @@
5690
5891
  if (_edge === "col") {
5691
5892
  _startW = _nearCell.offsetWidth;
5692
5893
  _colIdx = getVisualColIndex(_nearCell);
5693
- _colCells = _colIdx >= 0 ? Array.from(_table.querySelectorAll("tr")).map((r) => getCellAtVisualCol(r, _colIdx)).filter(Boolean) : [];
5894
+ _colCells = _colIdx >= 0 ? Array.from(_table.querySelectorAll("tr")).map((r) => getCellAtVisualCol(r, _colIdx)).filter(Boolean).filter((c) => (c.colSpan || 1) === 1) : [];
5694
5895
  document.body.style.cursor = "col-resize";
5695
5896
  } else {
5696
5897
  _row = _nearCell.closest("tr");
@@ -5761,6 +5962,9 @@
5761
5962
  this._label.textContent = "Table";
5762
5963
  el.appendChild(this._label);
5763
5964
  el.appendChild(this._sep());
5965
+ this._selectBtn = this._makeBtn(ICONS$2.selectCells, "Select Cells", () => this._toggleSelectMode());
5966
+ el.appendChild(this._selectBtn);
5967
+ el.appendChild(this._sep());
5764
5968
  el.appendChild(this._makeBtn(ICONS$2.rowAbove, "Add Row Above", () => this._addRow("above")));
5765
5969
  el.appendChild(this._makeBtn(ICONS$2.rowBelow, "Add Row Below", () => this._addRow("below")));
5766
5970
  el.appendChild(this._makeBtn(ICONS$2.deleteRow, "Delete Row", () => this._deleteRow()));
@@ -5770,6 +5974,7 @@
5770
5974
  el.appendChild(this._makeBtn(ICONS$2.deleteCol, "Delete Column", () => this._deleteColumn()));
5771
5975
  el.appendChild(this._sep());
5772
5976
  el.appendChild(this._makeBtn(ICONS$2.mergeCells, "Merge Cells", () => this._mergeCells()));
5977
+ el.appendChild(this._makeBtn(ICONS$2.unmergeCells, "Unmerge Cells", () => this._unmergeCells()));
5773
5978
  el.appendChild(this._sep());
5774
5979
  el.appendChild(this._makeBtn(ICONS$2.colWidth, "Column Width", () => this._openSizePopover("col")));
5775
5980
  el.appendChild(this._makeBtn(ICONS$2.rowHeight, "Row Height", () => this._openSizePopover("row")));
@@ -5777,6 +5982,7 @@
5777
5982
  el.appendChild(this._sep());
5778
5983
  el.appendChild(this._makeBtn(ICONS$2.deleteTable, "Delete Table", () => this._deleteTable(), true));
5779
5984
  this._disposers.push(on(el, "mouseenter", () => this._clearTimers()), on(el, "mouseleave", () => {
5985
+ if (this._selectMode) return;
5780
5986
  if (this._sizePopover && this._sizePopover.style.display !== "none") return;
5781
5987
  this._scheduleHide();
5782
5988
  }));
@@ -5832,6 +6038,12 @@
5832
6038
  this._el.style.display = "none";
5833
6039
  this._activeTable = null;
5834
6040
  this._activeCell = null;
6041
+ if (this._selectMode) {
6042
+ this._selectMode = false;
6043
+ if (this._selectBtn) this._selectBtn.classList.remove("an-link-tooltip-btn--active");
6044
+ if (this._editable) this._editable.classList.remove("an-table-select-mode");
6045
+ }
6046
+ this._clearSelection();
5835
6047
  this._clearTimers();
5836
6048
  this._hideSizePopover();
5837
6049
  }
@@ -5865,14 +6077,111 @@
5865
6077
  }
5866
6078
  return this._activeCell || this._activeTable && this._activeTable.querySelector("td, th");
5867
6079
  }
6080
+ _toggleSelectMode() {
6081
+ this._selectMode = !this._selectMode;
6082
+ if (this._selectBtn) this._selectBtn.classList.toggle("an-link-tooltip-btn--active", this._selectMode);
6083
+ if (this._editable) this._editable.classList.toggle("an-table-select-mode", this._selectMode);
6084
+ if (!this._selectMode) this._clearSelection();
6085
+ }
6086
+ _clearSelection() {
6087
+ this._selectedCells.forEach((c) => c.classList.remove("an-cell-selected"));
6088
+ this._selectedCells = [];
6089
+ this._selectStart = null;
6090
+ }
6091
+ _setSelection(cells) {
6092
+ this._selectedCells.forEach((c) => {
6093
+ if (!cells.includes(c)) c.classList.remove("an-cell-selected");
6094
+ });
6095
+ this._selectedCells = cells;
6096
+ cells.forEach((c) => c.classList.add("an-cell-selected"));
6097
+ }
6098
+ /**
6099
+ * Returns all cells in the rectangular area between startCell and endCell,
6100
+ * correctly handling rowspan/colspan by using the grid map.
6101
+ * The rect is expanded iteratively until it is stable — this ensures any
6102
+ * merged cell that starts outside the initial rect but spans into it is
6103
+ * fully included.
6104
+ */
6105
+ _getRectCells(startCell, endCell) {
6106
+ if (!startCell) return [];
6107
+ if (!endCell || startCell === endCell) return [startCell];
6108
+ const table = startCell.closest("table");
6109
+ if (!table || !table.contains(endCell)) return [startCell];
6110
+ const { gridMap, cellPos } = buildGridMap(table);
6111
+ const sp = cellPos.get(startCell);
6112
+ const ep = cellPos.get(endCell);
6113
+ if (!sp || !ep) return [startCell];
6114
+ let minR = Math.min(sp.r, ep.r);
6115
+ let maxR = Math.max(sp.r + sp.rs - 1, ep.r + ep.rs - 1);
6116
+ let minC = Math.min(sp.c, ep.c);
6117
+ let maxC = Math.max(sp.c + sp.cs - 1, ep.c + ep.cs - 1);
6118
+ let changed = true;
6119
+ while (changed) {
6120
+ changed = false;
6121
+ for (let r = minR; r <= maxR; r++) {
6122
+ const rowMap = gridMap[r];
6123
+ if (!rowMap) continue;
6124
+ for (let c = minC; c <= maxC; c++) {
6125
+ const cell = rowMap[c];
6126
+ if (!cell) continue;
6127
+ const pos = cellPos.get(cell);
6128
+ if (!pos) continue;
6129
+ if (pos.r < minR) {
6130
+ minR = pos.r;
6131
+ changed = true;
6132
+ }
6133
+ if (pos.r + pos.rs - 1 > maxR) {
6134
+ maxR = pos.r + pos.rs - 1;
6135
+ changed = true;
6136
+ }
6137
+ if (pos.c < minC) {
6138
+ minC = pos.c;
6139
+ changed = true;
6140
+ }
6141
+ if (pos.c + pos.cs - 1 > maxC) {
6142
+ maxC = pos.c + pos.cs - 1;
6143
+ changed = true;
6144
+ }
6145
+ }
6146
+ }
6147
+ }
6148
+ const seen = /* @__PURE__ */ new Set();
6149
+ const result = [];
6150
+ for (let r = minR; r <= maxR; r++) {
6151
+ const rowMap = gridMap[r];
6152
+ if (!rowMap) continue;
6153
+ for (let c = minC; c <= maxC; c++) {
6154
+ const cell = rowMap[c];
6155
+ if (cell && !seen.has(cell)) {
6156
+ seen.add(cell);
6157
+ result.push(cell);
6158
+ }
6159
+ }
6160
+ }
6161
+ return result.length > 0 ? result : [startCell];
6162
+ }
6163
+ /**
6164
+ * Returns the active cell set: user-selected cells when available,
6165
+ * otherwise the single active/cursor cell.
6166
+ * @returns {HTMLTableCellElement[]}
6167
+ */
6168
+ _getSelectedCells() {
6169
+ return this._selectedCells.length > 0 ? this._selectedCells : [this._getCell()].filter(Boolean);
6170
+ }
5868
6171
  _addRow(position) {
5869
- const cell = this._getCell();
5870
- if (!cell) return;
5871
- const row = cell.closest("tr");
5872
- if (!row) return;
5873
- const colCount = Array.from(row.cells).reduce((sum, c) => sum + (c.colSpan || 1), 0);
6172
+ const cells = this._getSelectedCells();
6173
+ if (!cells.length) return;
6174
+ const table = cells[0].closest("table");
6175
+ if (!table) return;
6176
+ const allRows = Array.from(table.querySelectorAll("tr"));
6177
+ const refRow = [...new Set(cells.map((c) => c.closest("tr")).filter(Boolean))].reduce((best, r) => {
6178
+ const bi = allRows.indexOf(best);
6179
+ const ri = allRows.indexOf(r);
6180
+ return position === "above" ? ri < bi ? r : best : ri > bi ? r : best;
6181
+ });
6182
+ const colCount = Array.from(refRow.cells).reduce((sum, c) => sum + (c.colSpan || 1), 0);
5874
6183
  const newRow = document.createElement("tr");
5875
- const refCells = Array.from(row.cells);
6184
+ const refCells = Array.from(refRow.cells);
5876
6185
  for (let i = 0; i < colCount; i++) {
5877
6186
  const td = createElement("td", {}, ["\xA0"]);
5878
6187
  const ref = refCells[i];
@@ -5880,19 +6189,20 @@
5880
6189
  if (ref && ref.style.minWidth) td.style.minWidth = ref.style.minWidth;
5881
6190
  newRow.appendChild(td);
5882
6191
  }
5883
- if (position === "above") row.parentElement?.insertBefore(newRow, row);
5884
- else row.insertAdjacentElement("afterend", newRow);
6192
+ if (position === "above") refRow.parentElement?.insertBefore(newRow, refRow);
6193
+ else refRow.insertAdjacentElement("afterend", newRow);
5885
6194
  requestAnimationFrame(() => this._positionNear(this._activeTable));
5886
6195
  this.context.invoke("editor.afterCommand");
5887
6196
  }
5888
6197
  _addColumn(position) {
5889
- const cell = this._getCell();
5890
- if (!cell) return;
5891
- const table = cell.closest("table");
6198
+ const cells = this._getSelectedCells();
6199
+ if (!cells.length) return;
6200
+ const table = cells[0].closest("table");
5892
6201
  if (!table) return;
5893
- const visualColIdx = getVisualColIndex(cell);
6202
+ const colIndices = cells.map((c) => getVisualColIndex(c));
6203
+ const targetColIdx = position === "left" ? Math.min(...colIndices) : Math.max(...colIndices);
5894
6204
  const rows = Array.from(table.querySelectorAll("tr"));
5895
- const refs = rows.map((r) => position === "left" ? getCellAtVisualCol(r, visualColIdx) : getCellAfterVisualCol(r, visualColIdx));
6205
+ const refs = rows.map((r) => position === "left" ? getCellAtVisualCol(r, targetColIdx) : getCellAfterVisualCol(r, targetColIdx));
5896
6206
  const isHeaders = rows.map((r) => r.closest("thead") !== null);
5897
6207
  rows.forEach((r, i) => {
5898
6208
  r.insertBefore(createElement(isHeaders[i] ? "th" : "td", {}, ["\xA0"]), refs[i]);
@@ -5901,68 +6211,93 @@
5901
6211
  this.context.invoke("editor.afterCommand");
5902
6212
  }
5903
6213
  _deleteRow() {
5904
- const cell = this._getCell();
5905
- if (!cell) return;
5906
- const row = cell.closest("tr");
5907
- const table = cell.closest("table");
5908
- if (!row || !table) return;
6214
+ const cells = this._getSelectedCells();
6215
+ if (!cells.length) return;
6216
+ const table = cells[0].closest("table");
6217
+ if (!table) return;
5909
6218
  const tbody = table.querySelector("tbody");
5910
- if ((tbody ? tbody.querySelectorAll("tr").length : table.querySelectorAll("tr").length) <= 1 && row.closest("tbody")) return;
6219
+ const totalBodyRows = tbody ? tbody.querySelectorAll("tr").length : table.querySelectorAll("tr").length;
6220
+ const selectedRows = [...new Set(cells.map((c) => c.closest("tr")).filter(Boolean))];
6221
+ if (selectedRows.filter((r) => r.closest("tbody")).length >= totalBodyRows) return;
5911
6222
  this._activeCell = null;
5912
- row.parentElement?.removeChild(row);
6223
+ this._clearSelection();
6224
+ selectedRows.forEach((r) => r.parentElement?.removeChild(r));
5913
6225
  requestAnimationFrame(() => this._positionNear(this._activeTable));
5914
6226
  this.context.invoke("editor.afterCommand");
5915
6227
  }
5916
6228
  _deleteColumn() {
5917
- const cell = this._getCell();
5918
- if (!cell) return;
5919
- const table = cell.closest("table");
6229
+ const cells = this._getSelectedCells();
6230
+ if (!cells.length) return;
6231
+ const table = cells[0].closest("table");
5920
6232
  if (!table) return;
5921
- const row = cell.closest("tr");
5922
- if (row && row.cells.length <= 1) return;
5923
- const visualColIdx = getVisualColIndex(cell);
5924
- this._activeCell = null;
5925
- const rows = Array.from(table.querySelectorAll("tr"));
5926
- rows.map((r) => getCellAtVisualCol(r, visualColIdx)).forEach((c, i) => {
5927
- if (c) rows[i].removeChild(c);
6233
+ const tableRows = Array.from(table.querySelectorAll("tr"));
6234
+ if (tableRows[0] && tableRows[0].cells.length <= 1) return;
6235
+ const colIndices = [...new Set(cells.map((c) => getVisualColIndex(c)))];
6236
+ if (colIndices.length >= (tableRows[0]?.cells.length ?? 1)) return;
6237
+ const cellsToDelete = [];
6238
+ colIndices.forEach((colIdx) => {
6239
+ tableRows.forEach((r) => {
6240
+ const c = getCellAtVisualCol(r, colIdx);
6241
+ if (c) cellsToDelete.push(c);
6242
+ });
5928
6243
  });
6244
+ this._activeCell = null;
6245
+ this._clearSelection();
6246
+ cellsToDelete.forEach((c) => c.parentElement?.removeChild(c));
5929
6247
  requestAnimationFrame(() => this._positionNear(this._activeTable));
5930
6248
  this.context.invoke("editor.afterCommand");
5931
6249
  }
5932
6250
  _mergeCells() {
5933
6251
  const cell = this._getCell();
5934
6252
  if (!cell) return;
5935
- const sel = window.getSelection();
5936
- if (!sel || sel.rangeCount === 0) return;
5937
- const range = sel.getRangeAt(0);
5938
6253
  const table = cell.closest("table");
5939
6254
  if (!table) return;
5940
- const selected = Array.from(table.querySelectorAll("td, th")).filter((c) => {
5941
- try {
5942
- return range.intersectsNode(c);
5943
- } catch {
5944
- return false;
5945
- }
5946
- });
5947
- if (selected.length < 2) return;
5948
- const rows = [...new Set(selected.map((c) => c.closest("tr")))];
5949
- if (rows.length === 1) {
5950
- const row = rows[0];
5951
- const rowSelected = Array.from(row.cells).filter((c) => selected.includes(c));
5952
- if (rowSelected.length < 2) return;
5953
- const first = rowSelected[0];
5954
- first.colSpan = rowSelected.reduce((sum, c) => sum + (c.colSpan || 1), 0);
5955
- first.innerHTML = rowSelected.map((c) => c.innerHTML).join("");
5956
- rowSelected.slice(1).forEach((c) => row.removeChild(c));
5957
- } else {
5958
- if ([...new Set(selected.map((c) => getVisualColIndex(c)))].length !== 1) return;
5959
- const first = selected[0];
5960
- first.rowSpan = selected.reduce((sum, c) => sum + (c.rowSpan || 1), 0);
5961
- first.innerHTML = selected.map((c) => c.innerHTML).join("");
5962
- selected.slice(1).forEach((c) => {
5963
- if (c.closest("tr")) c.closest("tr").removeChild(c);
6255
+ let selected = this._getSelectedCells().filter((c) => table.contains(c));
6256
+ if (selected.length < 2) {
6257
+ const sel = window.getSelection();
6258
+ if (!sel || sel.rangeCount === 0) return;
6259
+ const range = sel.getRangeAt(0);
6260
+ selected = Array.from(table.querySelectorAll("td, th")).filter((c) => {
6261
+ try {
6262
+ return range.intersectsNode(c);
6263
+ } catch {
6264
+ return false;
6265
+ }
5964
6266
  });
6267
+ if (selected.length < 2) return;
6268
+ }
6269
+ const { gridMap, cellPos } = buildGridMap(table);
6270
+ let minR = Infinity, maxR = -Infinity, minC = Infinity, maxC = -Infinity;
6271
+ selected.forEach((c) => {
6272
+ const pos = cellPos.get(c);
6273
+ if (!pos) return;
6274
+ if (pos.r < minR) minR = pos.r;
6275
+ if (pos.r + pos.rs - 1 > maxR) maxR = pos.r + pos.rs - 1;
6276
+ if (pos.c < minC) minC = pos.c;
6277
+ if (pos.c + pos.cs - 1 > maxC) maxC = pos.c + pos.cs - 1;
6278
+ });
6279
+ if (minR === Infinity) return;
6280
+ const seen = /* @__PURE__ */ new Set();
6281
+ const rectCells = [];
6282
+ for (let r = minR; r <= maxR; r++) {
6283
+ const rowMap = gridMap[r];
6284
+ if (!rowMap) continue;
6285
+ for (let c = minC; c <= maxC; c++) {
6286
+ const tc = rowMap[c];
6287
+ if (tc && !seen.has(tc)) {
6288
+ seen.add(tc);
6289
+ rectCells.push(tc);
6290
+ }
6291
+ }
5965
6292
  }
6293
+ if (rectCells.length < 2) return;
6294
+ const first = rectCells[0];
6295
+ first.colSpan = maxC - minC + 1;
6296
+ first.rowSpan = maxR - minR + 1;
6297
+ first.style.verticalAlign = "middle";
6298
+ first.innerHTML = rectCells.map((c) => c.innerHTML).join("");
6299
+ rectCells.slice(1).forEach((c) => c.parentElement?.removeChild(c));
6300
+ this._clearSelection();
5966
6301
  this.context.invoke("editor.afterCommand");
5967
6302
  }
5968
6303
  _deleteTable() {
@@ -5972,6 +6307,57 @@
5972
6307
  if (table.parentNode) table.parentNode.removeChild(table);
5973
6308
  this.context.invoke("editor.afterCommand");
5974
6309
  }
6310
+ _unmergeCells() {
6311
+ const cells = this._getSelectedCells();
6312
+ if (!cells.length) return;
6313
+ const table = cells[0].closest("table");
6314
+ if (!table) return;
6315
+ const mergedCells = cells.filter((c) => table.contains(c) && ((c.colSpan || 1) > 1 || (c.rowSpan || 1) > 1));
6316
+ if (!mergedCells.length) return;
6317
+ mergedCells.forEach((cell) => {
6318
+ if (table.contains(cell)) this._unmergeOne(cell, table);
6319
+ });
6320
+ this._clearSelection();
6321
+ requestAnimationFrame(() => this._positionNear(this._activeTable));
6322
+ this.context.invoke("editor.afterCommand");
6323
+ }
6324
+ /**
6325
+ * Split a single merged cell (colspan/rowspan > 1) back into individual cells.
6326
+ * New cells are empty (&nbsp;); the original cell retains its content.
6327
+ * @param {HTMLTableCellElement} cell
6328
+ * @param {HTMLTableElement} table
6329
+ */
6330
+ _unmergeOne(cell, table) {
6331
+ const cs = cell.colSpan || 1;
6332
+ const rs = cell.rowSpan || 1;
6333
+ if (cs === 1 && rs === 1) return;
6334
+ const { cellPos } = buildGridMap(table);
6335
+ const pos = cellPos.get(cell);
6336
+ if (!pos) return;
6337
+ const { r, c } = pos;
6338
+ const tableRows = Array.from(table.rows);
6339
+ const tag = cell.tagName.toLowerCase();
6340
+ cell.rowSpan = 1;
6341
+ cell.colSpan = 1;
6342
+ cell.style.verticalAlign = "";
6343
+ if (cs > 1) {
6344
+ const insertRef = cell.nextElementSibling;
6345
+ for (let dc = 1; dc < cs; dc++) tableRows[r].insertBefore(createElement(tag, {}, ["\xA0"]), insertRef);
6346
+ }
6347
+ for (let dr = 1; dr < rs; dr++) {
6348
+ const targetRow = tableRows[r + dr];
6349
+ if (!targetRow) continue;
6350
+ let ref = null;
6351
+ for (const tc of targetRow.cells) {
6352
+ const tp = cellPos.get(tc);
6353
+ if (tp && tp.c > c) {
6354
+ ref = tc;
6355
+ break;
6356
+ }
6357
+ }
6358
+ for (let dc = 0; dc < cs; dc++) targetRow.insertBefore(createElement(tag, {}, ["\xA0"]), ref);
6359
+ }
6360
+ }
5975
6361
  _buildSizePopover() {
5976
6362
  const popover = createElement("div", { class: "an-size-popover" });
5977
6363
  popover.style.display = "none";
@@ -6053,27 +6439,35 @@
6053
6439
  };
6054
6440
  } else {
6055
6441
  const isCol = type === "col";
6442
+ const activeCells = this._getSelectedCells().filter((c) => {
6443
+ const t = c.closest("table");
6444
+ return t && t === cell.closest("table");
6445
+ });
6056
6446
  this._sizeTitleEl.textContent = isCol ? "Column Width (px)" : "Row Height (px)";
6057
6447
  this._sizeInputEl.min = "1";
6058
6448
  this._sizeInputEl.max = "2000";
6059
6449
  this._sizeInputEl.value = isCol ? cell.offsetWidth || 120 : cell.closest("tr") ? cell.closest("tr").offsetHeight || 40 : 40;
6060
6450
  this._sizeApply = (val) => {
6451
+ const table = cell.closest("table");
6452
+ if (!table) return;
6061
6453
  if (isCol) {
6062
- const table = cell.closest("table");
6063
- const visualColIdx = getVisualColIndex(cell);
6064
- Array.from(table.querySelectorAll("tr")).map((r) => getCellAtVisualCol(r, visualColIdx)).forEach((c) => {
6065
- if (c) {
6066
- c.style.width = `${val}px`;
6067
- c.style.minWidth = `${val}px`;
6068
- }
6454
+ const colIndices = [...new Set(activeCells.map((c) => getVisualColIndex(c)))];
6455
+ const tableRows = Array.from(table.querySelectorAll("tr"));
6456
+ colIndices.forEach((colIdx) => {
6457
+ tableRows.forEach((r) => {
6458
+ const c = getCellAtVisualCol(r, colIdx);
6459
+ if (c && (c.colSpan || 1) === 1) {
6460
+ c.style.width = `${val}px`;
6461
+ c.style.minWidth = `${val}px`;
6462
+ }
6463
+ });
6069
6464
  });
6070
- } else {
6071
- const row = cell.closest("tr");
6072
- if (row) for (const c of row.cells) {
6465
+ } else [...new Set(activeCells.map((c) => c.closest("tr")).filter(Boolean))].forEach((row) => {
6466
+ for (const c of row.cells) {
6073
6467
  c.style.height = `${val}px`;
6074
6468
  c.style.minHeight = `${val}px`;
6075
6469
  }
6076
- }
6470
+ });
6077
6471
  this.context.invoke("editor.afterCommand");
6078
6472
  };
6079
6473
  }
@@ -8928,7 +9322,13 @@
8928
9322
  range.selectNodeContents(editable);
8929
9323
  range.collapse(false);
8930
9324
  }
9325
+ const _sc = range.startContainer;
9326
+ const _tdAnchor = (_sc.nodeType === 1 ? _sc : _sc.parentElement)?.closest?.("td, th");
8931
9327
  range.deleteContents();
9328
+ if (_tdAnchor && _tdAnchor.isConnected && !_tdAnchor.contains(range.startContainer)) {
9329
+ range.setStart(_tdAnchor, 0);
9330
+ range.collapse(true);
9331
+ }
8932
9332
  const textNode = document.createTextNode(char);
8933
9333
  range.insertNode(textNode);
8934
9334
  range.setStartAfter(textNode);
@@ -9497,7 +9897,13 @@
9497
9897
  range.selectNodeContents(editable);
9498
9898
  range.collapse(false);
9499
9899
  }
9900
+ const _sc = range.startContainer;
9901
+ const _tdAnchor = (_sc.nodeType === 1 ? _sc : _sc.parentElement)?.closest?.("td, th");
9500
9902
  range.deleteContents();
9903
+ if (_tdAnchor && _tdAnchor.isConnected && !_tdAnchor.contains(range.startContainer)) {
9904
+ range.setStart(_tdAnchor, 0);
9905
+ range.collapse(true);
9906
+ }
9501
9907
  range.insertNode(iconEl);
9502
9908
  let caretTextNode = iconEl.nextSibling;
9503
9909
  if (!caretTextNode || caretTextNode.nodeType !== Node.TEXT_NODE) {