@harbour-enterprises/superdoc 1.3.0 → 1.3.1-next.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.
@@ -36435,7 +36435,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
36435
36435
  static getStoredSuperdocVersion(docx) {
36436
36436
  return SuperConverter.getStoredCustomProperty(docx, "SuperdocVersion");
36437
36437
  }
36438
- static setStoredSuperdocVersion(docx = this.convertedXml, version2 = "1.3.0") {
36438
+ static setStoredSuperdocVersion(docx = this.convertedXml, version2 = "1.3.1-next.2") {
36439
36439
  return SuperConverter.setStoredCustomProperty(docx, "SuperdocVersion", version2, false);
36440
36440
  }
36441
36441
  /**
@@ -62245,7 +62245,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
62245
62245
  return false;
62246
62246
  }
62247
62247
  };
62248
- const summaryVersion = "1.3.0";
62248
+ const summaryVersion = "1.3.1-next.2";
62249
62249
  const nodeKeys = ["group", "content", "marks", "inline", "atom", "defining", "code", "tableRole", "summary"];
62250
62250
  const markKeys = ["group", "inclusive", "excludes", "spanning", "code"];
62251
62251
  function mapAttributes(attrs) {
@@ -64878,7 +64878,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
64878
64878
  * Process collaboration migrations
64879
64879
  */
64880
64880
  processCollaborationMigrations() {
64881
- console.debug("[checkVersionMigrations] Current editor version", "1.3.0");
64881
+ console.debug("[checkVersionMigrations] Current editor version", "1.3.1-next.2");
64882
64882
  if (!this.options.ydoc) return;
64883
64883
  const metaMap = this.options.ydoc.getMap("meta");
64884
64884
  let docVersion = metaMap.get("version");
@@ -71743,7 +71743,7 @@ ${l}
71743
71743
  return true;
71744
71744
  }
71745
71745
  const LIST_MARKER_GAP$2 = 8;
71746
- const DEFAULT_TAB_INTERVAL_PX$2 = 48;
71746
+ const DEFAULT_TAB_INTERVAL_PX$1 = 48;
71747
71747
  const DEFAULT_PAGE_HEIGHT_PX = 1056;
71748
71748
  const DEFAULT_VIRTUALIZED_PAGE_GAP$1 = 72;
71749
71749
  const COMMENT_EXTERNAL_COLOR = "#B1124B";
@@ -71894,6 +71894,7 @@ ${l}
71894
71894
  this.layoutVersion = 0;
71895
71895
  this.layoutEpoch = 0;
71896
71896
  this.processedLayoutVersion = -1;
71897
+ this.currentMapping = null;
71897
71898
  this.onScrollHandler = null;
71898
71899
  this.onWindowScrollHandler = null;
71899
71900
  this.onResizeHandler = null;
@@ -71999,7 +72000,7 @@ ${l}
71999
72000
  this.blockLookup = nextLookup;
72000
72001
  this.changedBlocks = changed;
72001
72002
  }
72002
- paint(layout, mount2) {
72003
+ paint(layout, mount2, mapping) {
72003
72004
  if (!(mount2 instanceof HTMLElement)) {
72004
72005
  throw new Error("DomPainter.paint requires a valid HTMLElement mount");
72005
72006
  }
@@ -72008,6 +72009,13 @@ ${l}
72008
72009
  throw new Error("DomPainter.paint requires a DOM-like document");
72009
72010
  }
72010
72011
  this.doc = doc2;
72012
+ const isSimpleTransaction = mapping && mapping.maps.length === 1;
72013
+ if (mapping && !isSimpleTransaction) {
72014
+ this.blockLookup.forEach((_2, id) => this.changedBlocks.add(id));
72015
+ this.currentMapping = null;
72016
+ } else {
72017
+ this.currentMapping = mapping ?? null;
72018
+ }
72011
72019
  ensurePrintStyles(doc2);
72012
72020
  ensureLinkStyles(doc2);
72013
72021
  ensureTrackChangeStyles(doc2);
@@ -72034,6 +72042,7 @@ ${l}
72034
72042
  this.currentLayout = layout;
72035
72043
  this.pageStates = [];
72036
72044
  this.changedBlocks.clear();
72045
+ this.currentMapping = null;
72037
72046
  return;
72038
72047
  }
72039
72048
  if (mode === "book") {
@@ -72042,6 +72051,7 @@ ${l}
72042
72051
  this.currentLayout = layout;
72043
72052
  this.pageStates = [];
72044
72053
  this.changedBlocks.clear();
72054
+ this.currentMapping = null;
72045
72055
  return;
72046
72056
  }
72047
72057
  applyStyles$2(mount2, containerStyles);
@@ -72050,6 +72060,7 @@ ${l}
72050
72060
  this.renderVirtualized(layout, mount2);
72051
72061
  this.currentLayout = layout;
72052
72062
  this.changedBlocks.clear();
72063
+ this.currentMapping = null;
72053
72064
  return;
72054
72065
  }
72055
72066
  mount2.style.gap = `${this.pageGap}px`;
@@ -72060,6 +72071,7 @@ ${l}
72060
72071
  }
72061
72072
  this.currentLayout = layout;
72062
72073
  this.changedBlocks.clear();
72074
+ this.currentMapping = null;
72063
72075
  }
72064
72076
  // ----------------
72065
72077
  // Virtualized path
@@ -72591,6 +72603,8 @@ ${l}
72591
72603
  pageEl.replaceChild(replacement, current.element);
72592
72604
  current.element = replacement;
72593
72605
  current.signature = fragmentSignature(fragment, this.blockLookup);
72606
+ } else if (this.currentMapping) {
72607
+ this.updatePositionAttributes(current.element, this.currentMapping);
72594
72608
  }
72595
72609
  this.updateFragmentElement(current.element, fragment, contextBase.section);
72596
72610
  current.fragment = fragment;
@@ -72619,6 +72633,45 @@ ${l}
72619
72633
  state.fragments = nextFragments;
72620
72634
  this.renderDecorationsForPage(pageEl, page);
72621
72635
  }
72636
+ /**
72637
+ * Updates data-pm-start/data-pm-end attributes on all elements within a fragment
72638
+ * using the transaction's mapping. Skips header/footer content (separate PM coordinate space).
72639
+ * Also skips fragments that end before the edit point (their positions don't change).
72640
+ */
72641
+ updatePositionAttributes(fragmentEl, mapping) {
72642
+ if (fragmentEl.closest(".superdoc-page-header, .superdoc-page-footer")) {
72643
+ return;
72644
+ }
72645
+ try {
72646
+ const fragEnd = fragmentEl.dataset.pmEnd;
72647
+ if (fragEnd !== void 0 && fragEnd !== "") {
72648
+ const endNum = Number(fragEnd);
72649
+ if (Number.isFinite(endNum) && mapping.map(endNum, -1) === endNum) {
72650
+ return;
72651
+ }
72652
+ }
72653
+ const elements = fragmentEl.querySelectorAll("[data-pm-start], [data-pm-end]");
72654
+ const allElements = [fragmentEl, ...Array.from(elements)];
72655
+ for (const el of allElements) {
72656
+ const oldStart = el.dataset.pmStart;
72657
+ const oldEnd = el.dataset.pmEnd;
72658
+ if (oldStart !== void 0 && oldStart !== "") {
72659
+ const num = Number(oldStart);
72660
+ if (Number.isFinite(num)) {
72661
+ el.dataset.pmStart = String(mapping.map(num));
72662
+ }
72663
+ }
72664
+ if (oldEnd !== void 0 && oldEnd !== "") {
72665
+ const num = Number(oldEnd);
72666
+ if (Number.isFinite(num)) {
72667
+ el.dataset.pmEnd = String(mapping.map(num, -1));
72668
+ }
72669
+ }
72670
+ }
72671
+ } catch (error) {
72672
+ console.error("Error updating position attributes with mapping:", error);
72673
+ }
72674
+ }
72622
72675
  createPageState(page, pageSize) {
72623
72676
  if (!this.doc) {
72624
72677
  throw new Error("DomPainter.createPageState requires a document");
@@ -72777,7 +72830,7 @@ ${l}
72777
72830
  const textStart = paraIndentLeft + firstLine;
72778
72831
  tabWidth = textStart - currentPos;
72779
72832
  if (tabWidth <= 0) {
72780
- tabWidth = DEFAULT_TAB_INTERVAL_PX$2 - currentPos % DEFAULT_TAB_INTERVAL_PX$2;
72833
+ tabWidth = DEFAULT_TAB_INTERVAL_PX$1 - currentPos % DEFAULT_TAB_INTERVAL_PX$1;
72781
72834
  } else if (tabWidth < LIST_MARKER_GAP$2) {
72782
72835
  tabWidth = LIST_MARKER_GAP$2;
72783
72836
  }
@@ -72929,7 +72982,7 @@ ${l}
72929
72982
  const textStart = paraIndentLeft + firstLine;
72930
72983
  tabWidth = textStart - currentPos;
72931
72984
  if (tabWidth <= 0) {
72932
- tabWidth = DEFAULT_TAB_INTERVAL_PX$2 - currentPos % DEFAULT_TAB_INTERVAL_PX$2;
72985
+ tabWidth = DEFAULT_TAB_INTERVAL_PX$1 - currentPos % DEFAULT_TAB_INTERVAL_PX$1;
72933
72986
  } else if (tabWidth < LIST_MARKER_GAP$2) {
72934
72987
  tabWidth = LIST_MARKER_GAP$2;
72935
72988
  }
@@ -74277,6 +74330,13 @@ ${l}
74277
74330
  const trackedConfig = this.resolveTrackedChangesConfig(block);
74278
74331
  if (runsForLine.length === 0) {
74279
74332
  const span = this.doc.createElement("span");
74333
+ span.classList.add("superdoc-empty-run");
74334
+ if (lineRange.pmStart != null) {
74335
+ span.dataset.pmStart = String(lineRange.pmStart);
74336
+ }
74337
+ if (lineRange.pmEnd != null) {
74338
+ span.dataset.pmEnd = String(lineRange.pmEnd);
74339
+ }
74280
74340
  span.innerHTML = "&nbsp;";
74281
74341
  el.appendChild(span);
74282
74342
  }
@@ -74989,8 +75049,6 @@ ${l}
74989
75049
  base2,
74990
75050
  fragment.fromLine,
74991
75051
  fragment.toLine,
74992
- fragment.pmStart ?? "",
74993
- fragment.pmEnd ?? "",
74994
75052
  fragment.continuesFromPrev ? 1 : 0,
74995
75053
  fragment.continuesOnNext ? 1 : 0,
74996
75054
  fragment.markerWidth ?? ""
@@ -75082,16 +75140,15 @@ ${l}
75082
75140
  imgRun.distTop ?? "",
75083
75141
  imgRun.distBottom ?? "",
75084
75142
  imgRun.distLeft ?? "",
75085
- imgRun.distRight ?? "",
75086
- imgRun.pmStart ?? "",
75087
- imgRun.pmEnd ?? ""
75143
+ imgRun.distRight ?? ""
75144
+ // Note: pmStart/pmEnd intentionally excluded to prevent O(n) change detection
75088
75145
  ].join(",");
75089
75146
  }
75090
75147
  if (run2.kind === "lineBreak") {
75091
- return ["linebreak", run2.pmStart ?? "", run2.pmEnd ?? ""].join(",");
75148
+ return "linebreak";
75092
75149
  }
75093
75150
  if (run2.kind === "tab") {
75094
- return [run2.text ?? "", "tab", run2.pmStart ?? "", run2.pmEnd ?? ""].join(",");
75151
+ return [run2.text ?? "", "tab"].join(",");
75095
75152
  }
75096
75153
  const textRun = run2;
75097
75154
  return [
@@ -75107,8 +75164,7 @@ ${l}
75107
75164
  textRun.strike ? 1 : 0,
75108
75165
  textRun.highlight ?? "",
75109
75166
  textRun.letterSpacing != null ? textRun.letterSpacing : "",
75110
- textRun.pmStart ?? "",
75111
- textRun.pmEnd ?? "",
75167
+ // Note: pmStart/pmEnd intentionally excluded to prevent O(n) change detection
75112
75168
  textRun.token ?? "",
75113
75169
  // Tracked changes - force re-render when added or removed tracked change
75114
75170
  textRun.trackedChange ? 1 : 0,
@@ -75564,8 +75620,8 @@ ${l}
75564
75620
  ruler: options.ruler
75565
75621
  });
75566
75622
  return {
75567
- paint(layout, mount2) {
75568
- painter.paint(layout, mount2);
75623
+ paint(layout, mount2, mapping) {
75624
+ painter.paint(layout, mount2, mapping);
75569
75625
  },
75570
75626
  setData(blocks2, measures, headerBlocks, headerMeasures, footerBlocks, footerMeasures) {
75571
75627
  painter.setData(blocks2, measures, headerBlocks, headerMeasures, footerBlocks, footerMeasures);
@@ -77521,7 +77577,6 @@ ${l}
77521
77577
  const DEFAULT_LIST_INDENT_STEP_PX = 24;
77522
77578
  const DEFAULT_LIST_HANGING_PX$1 = 18;
77523
77579
  const SPACE_SUFFIX_GAP_PX = 4;
77524
- const DEFAULT_TAB_INTERVAL_PX$1 = 48;
77525
77580
  function resolveListTextStartPx(wordLayout, indentLeft, firstLine, hanging, measureMarkerText) {
77526
77581
  const marker = wordLayout?.marker;
77527
77582
  if (!marker) {
@@ -77555,9 +77610,13 @@ ${l}
77555
77610
  return markerStartPos + finalMarkerTextWidth;
77556
77611
  }
77557
77612
  const markerJustification = marker.justification ?? "left";
77613
+ const markerWidthEffective = Math.max(
77614
+ typeof marker.markerBoxWidthPx === "number" && Number.isFinite(marker.markerBoxWidthPx) ? marker.markerBoxWidthPx : 0,
77615
+ finalMarkerTextWidth
77616
+ );
77558
77617
  if (markerJustification !== "left") {
77559
- const gutterWidth = typeof marker.gutterWidthPx === "number" && Number.isFinite(marker.gutterWidthPx) && marker.gutterWidthPx > 0 ? marker.gutterWidthPx : LIST_MARKER_GAP$1;
77560
- return markerStartPos + finalMarkerTextWidth + Math.max(gutterWidth, LIST_MARKER_GAP$1);
77618
+ const gutterWidth2 = typeof marker.gutterWidthPx === "number" && Number.isFinite(marker.gutterWidthPx) && marker.gutterWidthPx > 0 ? marker.gutterWidthPx : LIST_MARKER_GAP$1;
77619
+ return markerStartPos + finalMarkerTextWidth + Math.max(gutterWidth2, LIST_MARKER_GAP$1);
77561
77620
  }
77562
77621
  if (wordLayout?.firstLineIndentMode === true) {
77563
77622
  let targetTabStop;
@@ -77569,12 +77628,12 @@ ${l}
77569
77628
  }
77570
77629
  }
77571
77630
  }
77572
- const textStartTarget = typeof marker.textStartX === "number" && Number.isFinite(marker.textStartX) ? marker.textStartX : wordLayout.textStartPx;
77631
+ const textStartTarget2 = typeof marker.textStartX === "number" && Number.isFinite(marker.textStartX) ? marker.textStartX : wordLayout.textStartPx;
77573
77632
  let tabWidth2;
77574
77633
  if (targetTabStop !== void 0) {
77575
77634
  tabWidth2 = targetTabStop - currentPos;
77576
- } else if (textStartTarget !== void 0 && Number.isFinite(textStartTarget) && textStartTarget > currentPos) {
77577
- tabWidth2 = textStartTarget - currentPos;
77635
+ } else if (textStartTarget2 !== void 0 && Number.isFinite(textStartTarget2) && textStartTarget2 > currentPos) {
77636
+ tabWidth2 = textStartTarget2 - currentPos;
77578
77637
  } else {
77579
77638
  tabWidth2 = LIST_MARKER_GAP$1;
77580
77639
  }
@@ -77583,14 +77642,21 @@ ${l}
77583
77642
  }
77584
77643
  return markerStartPos + finalMarkerTextWidth + tabWidth2;
77585
77644
  }
77645
+ const textStartTarget = typeof wordLayout?.textStartPx === "number" && Number.isFinite(wordLayout.textStartPx) ? wordLayout.textStartPx : void 0;
77646
+ const gutterWidth = typeof marker.gutterWidthPx === "number" && Number.isFinite(marker.gutterWidthPx) && marker.gutterWidthPx > 0 ? marker.gutterWidthPx : LIST_MARKER_GAP$1;
77647
+ const currentPosStandard = markerStartPos + markerWidthEffective;
77648
+ if (textStartTarget !== void 0) {
77649
+ const gap = Math.max(textStartTarget - currentPosStandard, gutterWidth);
77650
+ return currentPosStandard + gap;
77651
+ }
77586
77652
  const textStart = indentLeft + firstLine;
77587
- let tabWidth = textStart - currentPos;
77653
+ let tabWidth = textStart - currentPosStandard;
77588
77654
  if (tabWidth <= 0) {
77589
- tabWidth = DEFAULT_TAB_INTERVAL_PX$1 - currentPos % DEFAULT_TAB_INTERVAL_PX$1;
77655
+ tabWidth = gutterWidth;
77590
77656
  } else if (tabWidth < LIST_MARKER_GAP$1) {
77591
- tabWidth = LIST_MARKER_GAP$1;
77657
+ tabWidth = Math.max(tabWidth, gutterWidth);
77592
77658
  }
77593
- return markerStartPos + finalMarkerTextWidth + tabWidth;
77659
+ return currentPosStandard + tabWidth;
77594
77660
  }
77595
77661
  function getWordLayoutConfig(block) {
77596
77662
  if (!block || block.kind !== "paragraph") {
@@ -77619,21 +77685,45 @@ ${l}
77619
77685
  return hasHangingIndentPattern;
77620
77686
  }
77621
77687
  function calculateTextStartIndent(params2) {
77622
- const { isFirstLine, isListItem: isListItem2, markerWidth, paraIndentLeft, firstLineIndent, hangingIndent, wordLayout } = params2;
77688
+ const {
77689
+ isFirstLine,
77690
+ isListItem: isListItem2,
77691
+ markerWidth,
77692
+ markerTextWidth,
77693
+ paraIndentLeft,
77694
+ firstLineIndent,
77695
+ hangingIndent,
77696
+ wordLayout
77697
+ } = params2;
77623
77698
  const firstLineOffset = firstLineIndent - hangingIndent;
77624
- const isFirstLineIndentMode = wordLayout?.firstLineIndentMode === true;
77699
+ const effectiveMarkerTextWidth = typeof markerTextWidth === "number" && Number.isFinite(markerTextWidth) && markerTextWidth > 0 ? markerTextWidth : markerWidth;
77625
77700
  let indentAdjust = paraIndentLeft;
77626
- if (isListItem2 && isFirstLine && isFirstLineIndentMode) {
77701
+ if (isListItem2 && isFirstLine) {
77627
77702
  const resolvedTextStart = resolveListTextStartPx(
77628
77703
  wordLayout,
77629
77704
  paraIndentLeft,
77630
77705
  Math.max(firstLineIndent, 0),
77631
77706
  Math.max(hangingIndent, 0),
77632
- () => markerWidth
77633
- // Use provided markerWidth since we don't have canvas access here
77707
+ () => effectiveMarkerTextWidth
77708
+ // Use measured marker text width when available
77634
77709
  );
77635
- const textStartFallback = paraIndentLeft + Math.max(firstLineIndent, 0) + markerWidth;
77636
- indentAdjust = typeof resolvedTextStart === "number" && Number.isFinite(resolvedTextStart) ? resolvedTextStart : textStartFallback;
77710
+ if (typeof resolvedTextStart === "number" && Number.isFinite(resolvedTextStart)) {
77711
+ indentAdjust = resolvedTextStart;
77712
+ } else {
77713
+ const explicitTextStart = wordLayout?.marker?.textStartX ?? wordLayout?.textStartPx;
77714
+ const isStandardHangingList = hangingIndent > 0 && wordLayout?.firstLineIndentMode !== true;
77715
+ const textStartLooksValid = typeof explicitTextStart === "number" && Number.isFinite(explicitTextStart) && (!isStandardHangingList || explicitTextStart > paraIndentLeft);
77716
+ if (textStartLooksValid) {
77717
+ indentAdjust = explicitTextStart;
77718
+ } else if (wordLayout?.firstLineIndentMode === true) {
77719
+ indentAdjust = paraIndentLeft + Math.max(firstLineIndent, 0) + markerWidth;
77720
+ } else if (isStandardHangingList && effectiveMarkerTextWidth > 0) {
77721
+ const markerStartPos = Math.max(0, paraIndentLeft - hangingIndent + firstLineIndent);
77722
+ const gutterWidthCandidate = wordLayout?.gutterWidthPx;
77723
+ const gutterWidth = typeof gutterWidthCandidate === "number" && Number.isFinite(gutterWidthCandidate) ? gutterWidthCandidate : wordLayout?.marker?.gutterWidthPx ?? LIST_MARKER_GAP$1;
77724
+ indentAdjust = markerStartPos + effectiveMarkerTextWidth + gutterWidth;
77725
+ }
77726
+ }
77637
77727
  } else if (isFirstLine && !isListItem2) {
77638
77728
  indentAdjust += firstLineOffset;
77639
77729
  }
@@ -78484,12 +78574,16 @@ ${l}
78484
78574
  const negativeRightIndent = indentRight < 0 ? indentRight : 0;
78485
78575
  const remeasureWidth = Math.max(1, columnWidth - indentLeft - indentRight);
78486
78576
  let didRemeasureForColumnWidth = false;
78577
+ let remeasuredMarkerInfo;
78487
78578
  if (typeof remeasureParagraph2 === "function" && typeof measurementWidth === "number" && measurementWidth > remeasureWidth) {
78488
78579
  const firstLineIndent = calculateFirstLineIndent(block, measure);
78489
78580
  const newMeasure = remeasureParagraph2(block, columnWidth, firstLineIndent);
78490
78581
  const newLines = normalizeLines(newMeasure);
78491
78582
  lines = newLines;
78492
78583
  didRemeasureForColumnWidth = true;
78584
+ if (newMeasure.marker) {
78585
+ remeasuredMarkerInfo = newMeasure.marker;
78586
+ }
78493
78587
  }
78494
78588
  let fromLine = 0;
78495
78589
  const attrs = getParagraphAttrs(block);
@@ -78528,10 +78622,12 @@ ${l}
78528
78622
  width: fragmentWidth,
78529
78623
  ...computeFragmentPmRange(block, lines, 0, lines.length)
78530
78624
  };
78531
- if (measure.marker) {
78532
- fragment.markerWidth = measure.marker.markerWidth;
78533
- if (measure.marker.markerTextWidth != null) {
78534
- fragment.markerTextWidth = measure.marker.markerTextWidth;
78625
+ if (measure.marker || remeasuredMarkerInfo) {
78626
+ const effectiveMarkerInfo = remeasuredMarkerInfo ?? measure.marker;
78627
+ fragment.markerWidth = effectiveMarkerInfo?.markerWidth ?? measure.marker?.markerWidth ?? 0;
78628
+ const markerTextWidth = remeasuredMarkerInfo?.markerTextWidth ?? measure.marker?.markerTextWidth;
78629
+ if (markerTextWidth != null) {
78630
+ fragment.markerTextWidth = markerTextWidth;
78535
78631
  }
78536
78632
  }
78537
78633
  state.page.fragments.push(fragment);
@@ -78573,6 +78669,9 @@ ${l}
78573
78669
  const newLines = normalizeLines(newMeasure);
78574
78670
  lines = newLines;
78575
78671
  didRemeasureForFloats = true;
78672
+ if (newMeasure.marker) {
78673
+ remeasuredMarkerInfo = newMeasure.marker;
78674
+ }
78576
78675
  }
78577
78676
  }
78578
78677
  while (fromLine < lines.length) {
@@ -78644,13 +78743,16 @@ ${l}
78644
78743
  if (didRemeasureForColumnWidth) {
78645
78744
  fragment.lines = lines.slice(fromLine, slice.toLine);
78646
78745
  }
78647
- if (measure.marker && fromLine === 0) {
78648
- fragment.markerWidth = measure.marker.markerWidth;
78649
- if (measure.marker.markerTextWidth != null) {
78650
- fragment.markerTextWidth = measure.marker.markerTextWidth;
78746
+ if ((measure.marker || remeasuredMarkerInfo) && fromLine === 0) {
78747
+ const effectiveMarkerInfo = remeasuredMarkerInfo ?? measure.marker;
78748
+ fragment.markerWidth = effectiveMarkerInfo?.markerWidth ?? measure.marker?.markerWidth ?? 0;
78749
+ const markerTextWidth = remeasuredMarkerInfo?.markerTextWidth ?? measure.marker?.markerTextWidth;
78750
+ if (markerTextWidth != null) {
78751
+ fragment.markerTextWidth = markerTextWidth;
78651
78752
  }
78652
- if (measure.kind === "paragraph" && measure.marker?.gutterWidth != null) {
78653
- fragment.markerGutter = measure.marker.gutterWidth;
78753
+ const gutterWidth = remeasuredMarkerInfo?.gutterWidth ?? measure.marker?.gutterWidth;
78754
+ if (gutterWidth != null) {
78755
+ fragment.markerGutter = gutterWidth;
78654
78756
  }
78655
78757
  }
78656
78758
  if (fromLine > 0) fragment.continuesFromPrev = true;
@@ -82093,16 +82195,19 @@ ${l}
82093
82195
  const contentWidth = Math.max(1, maxWidth - indentLeft - indentRight);
82094
82196
  const markerTextStartX = wordLayout?.marker?.textStartX;
82095
82197
  const textStartPx = typeof markerTextStartX === "number" && Number.isFinite(markerTextStartX) ? markerTextStartX : typeof wordLayout?.textStartPx === "number" && Number.isFinite(wordLayout.textStartPx) ? wordLayout.textStartPx : void 0;
82198
+ let measuredMarkerTextWidth;
82096
82199
  const resolvedTextStartPx = resolveListTextStartPx(
82097
82200
  wordLayout,
82098
82201
  indentLeft,
82099
82202
  indentFirstLine,
82100
82203
  indentHanging,
82101
- (markerText, marker) => {
82204
+ (markerText, marker2) => {
82102
82205
  const context = getCtx();
82103
82206
  if (!context) return 0;
82104
- context.font = markerFontString(marker.run);
82105
- return context.measureText(markerText).width;
82207
+ context.font = markerFontString(marker2.run);
82208
+ const width = context.measureText(markerText).width;
82209
+ measuredMarkerTextWidth = width;
82210
+ return width;
82106
82211
  }
82107
82212
  );
82108
82213
  const effectiveTextStartPx = resolvedTextStartPx ?? textStartPx;
@@ -82193,7 +82298,14 @@ ${l}
82193
82298
  }
82194
82299
  }
82195
82300
  const totalHeight = lines.reduce((s2, l) => s2 + l.lineHeight, 0);
82196
- return { kind: "paragraph", lines, totalHeight };
82301
+ const marker = wordLayout?.marker;
82302
+ const markerInfo = marker ? {
82303
+ markerWidth: marker.markerBoxWidthPx ?? indentHanging ?? 0,
82304
+ markerTextWidth: measuredMarkerTextWidth ?? 0,
82305
+ indentLeft,
82306
+ gutterWidth: marker.gutterWidthPx
82307
+ } : void 0;
82308
+ return { kind: "paragraph", lines, totalHeight, marker: markerInfo };
82197
82309
  }
82198
82310
  function hasComments(run2) {
82199
82311
  return "comments" in run2 && Array.isArray(run2.comments) && run2.comments.length > 0;
@@ -84245,6 +84357,7 @@ ${l}
84245
84357
  isFirstLine,
84246
84358
  isListItem: isListItemFlag,
84247
84359
  markerWidth,
84360
+ markerTextWidth: fragment.markerTextWidth ?? measure.marker?.markerTextWidth ?? void 0,
84248
84361
  paraIndentLeft: indent2.left,
84249
84362
  firstLineIndent: indent2.firstLine,
84250
84363
  hangingIndent: indent2.hanging,
@@ -84382,6 +84495,7 @@ ${l}
84382
84495
  isFirstLine,
84383
84496
  isListItem: cellIsListItem,
84384
84497
  markerWidth: paragraphMarkerWidth,
84498
+ markerTextWidth: info.measure?.marker?.markerTextWidth ?? void 0,
84385
84499
  paraIndentLeft: cellIndent.left,
84386
84500
  firstLineIndent: cellIndent.firstLine,
84387
84501
  hangingIndent: cellIndent.hanging,
@@ -84633,25 +84747,36 @@ ${l}
84633
84747
  const range2 = computeLinePmRange(block, line);
84634
84748
  if (range2.pmStart == null || range2.pmEnd == null) return null;
84635
84749
  const result = findCharacterAtX(block, line, x2, range2.pmStart, availableWidthOverride, alignmentOverride);
84750
+ let pmPosition = result.pmPosition;
84636
84751
  if (isRTL) {
84637
84752
  const charOffset = result.charOffset;
84638
84753
  const charsInLine = Math.max(1, line.toChar - line.fromChar);
84639
84754
  const reversedOffset = Math.max(0, Math.min(charsInLine, charsInLine - charOffset));
84640
- return charOffsetToPm(block, line, reversedOffset, range2.pmStart);
84755
+ pmPosition = charOffsetToPm(block, line, reversedOffset, range2.pmStart);
84641
84756
  }
84642
- return result.pmPosition;
84757
+ return pmPosition;
84643
84758
  };
84644
84759
  const mapPmToX = (block, line, offset2, fragmentWidth, alignmentOverride) => {
84645
84760
  if (fragmentWidth <= 0 || line.width <= 0) return 0;
84646
84761
  let paraIndentLeft = 0;
84647
84762
  let paraIndentRight = 0;
84763
+ let effectiveLeft = 0;
84648
84764
  if (block.kind === "paragraph") {
84649
84765
  const indentLeft = typeof block.attrs?.indent?.left === "number" ? block.attrs.indent.left : 0;
84650
84766
  const indentRight = typeof block.attrs?.indent?.right === "number" ? block.attrs.indent.right : 0;
84651
84767
  paraIndentLeft = Number.isFinite(indentLeft) ? indentLeft : 0;
84652
84768
  paraIndentRight = Number.isFinite(indentRight) ? indentRight : 0;
84769
+ effectiveLeft = paraIndentLeft;
84770
+ const wl = getWordLayoutConfig(block);
84771
+ const isListParagraph = Boolean(block.attrs?.numberingProperties) || Boolean(wl?.marker);
84772
+ if (isListParagraph) {
84773
+ const explicitTextStart = typeof wl?.marker?.textStartX === "number" && Number.isFinite(wl.marker.textStartX) ? wl.marker.textStartX : typeof wl?.textStartPx === "number" && Number.isFinite(wl.textStartPx) ? wl.textStartPx : void 0;
84774
+ if (typeof explicitTextStart === "number" && explicitTextStart > paraIndentLeft) {
84775
+ effectiveLeft = explicitTextStart;
84776
+ }
84777
+ }
84653
84778
  }
84654
- const totalIndent = paraIndentLeft + paraIndentRight;
84779
+ const totalIndent = effectiveLeft + paraIndentRight;
84655
84780
  const availableWidth = Math.max(0, fragmentWidth - totalIndent);
84656
84781
  if (totalIndent > fragmentWidth) {
84657
84782
  console.warn(
@@ -85983,16 +86108,26 @@ ${l}
85983
86108
  }
85984
86109
  function computeCaretLayoutRectGeometry({ layout, blocks: blocks2, measures, painterHost, viewportHost, visibleHost, zoom }, pos, includeDomFallback = true) {
85985
86110
  if (!layout) return null;
85986
- const hit = getFragmentAtPosition(layout, blocks2, measures, pos);
86111
+ let effectivePos = pos;
86112
+ let hit = getFragmentAtPosition(layout, blocks2, measures, pos);
85987
86113
  if (!hit) {
85988
- return null;
86114
+ const fallbackCandidates = [pos - 1, pos + 1, pos - 2, pos + 2].filter((candidate) => candidate >= 0);
86115
+ for (const candidate of fallbackCandidates) {
86116
+ const fallbackHit = getFragmentAtPosition(layout, blocks2, measures, candidate);
86117
+ if (fallbackHit) {
86118
+ hit = fallbackHit;
86119
+ effectivePos = candidate;
86120
+ break;
86121
+ }
86122
+ }
86123
+ if (!hit) return null;
85989
86124
  }
85990
86125
  const block = hit.block;
85991
86126
  const measure = hit.measure;
85992
86127
  if (hit.fragment.kind === "table" && block?.kind === "table" && measure?.kind === "table") {
85993
86128
  return computeTableCaretLayoutRectFromDom(
85994
86129
  { viewportHost, visibleHost, zoom },
85995
- pos,
86130
+ effectivePos,
85996
86131
  hit.fragment,
85997
86132
  block,
85998
86133
  measure,
@@ -86000,92 +86135,32 @@ ${l}
86000
86135
  );
86001
86136
  }
86002
86137
  if (!block || block.kind !== "paragraph" || measure?.kind !== "paragraph") return null;
86003
- if (hit.fragment.kind !== "para") {
86004
- return null;
86005
- }
86138
+ if (hit.fragment.kind !== "para") return null;
86006
86139
  const fragment = hit.fragment;
86007
- const lineInfo = findLineContainingPos(block, measure, fragment.fromLine, fragment.toLine, pos);
86008
- if (!lineInfo) {
86009
- return null;
86010
- }
86140
+ const lineInfo = findLineContainingPos(block, measure, fragment.fromLine, fragment.toLine, effectivePos);
86141
+ if (!lineInfo) return null;
86011
86142
  const { line, index: index2 } = lineInfo;
86012
86143
  const range2 = computeLinePmRange(block, line);
86013
86144
  if (range2.pmStart == null || range2.pmEnd == null) return null;
86014
- const pmOffset = pmPosToCharOffset(block, line, pos);
86145
+ const pmOffset = pmPosToCharOffset(block, line, effectivePos);
86015
86146
  const markerWidth = fragment.markerWidth ?? measure.marker?.markerWidth ?? 0;
86016
- const indent2 = extractParagraphIndent(block.attrs?.indent);
86017
- const availableWidth = Math.max(0, fragment.width - (indent2.left + indent2.right));
86018
- const charX = measureCharacterX(block, line, pmOffset, availableWidth);
86147
+ const markerTextWidth = fragment.markerTextWidth ?? measure.marker?.markerTextWidth ?? void 0;
86019
86148
  const isFirstLine = index2 === fragment.fromLine;
86020
86149
  const isListItemFlag = isListItem(markerWidth, block);
86021
- const isListFirstLine = isFirstLine && !fragment.continuesFromPrev && isListItemFlag;
86022
86150
  const wordLayout = getWordLayoutConfig(block);
86023
- const isFirstLineIndentMode = wordLayout?.firstLineIndentMode === true;
86024
- if (isListFirstLine && isFirstLineIndentMode) {
86025
- const textStartPx = calculateTextStartIndent({
86026
- isFirstLine,
86027
- isListItem: isListItemFlag,
86028
- markerWidth,
86029
- paraIndentLeft: indent2.left,
86030
- firstLineIndent: indent2.firstLine,
86031
- hangingIndent: indent2.hanging,
86032
- wordLayout
86033
- });
86034
- const localX2 = fragment.x + textStartPx + charX;
86035
- const lineOffset2 = lineHeightBeforeIndex(measure.lines, fragment.fromLine, index2);
86036
- const localY2 = fragment.y + lineOffset2;
86037
- const result2 = {
86038
- pageIndex: hit.pageIndex,
86039
- x: localX2,
86040
- y: localY2,
86041
- height: line.lineHeight
86042
- };
86043
- const pageEl2 = painterHost?.querySelector(
86044
- `.superdoc-page[data-page-index="${hit.pageIndex}"]`
86045
- );
86046
- const pageRect2 = pageEl2?.getBoundingClientRect();
86047
- let domCaretX2 = null;
86048
- let domCaretY2 = null;
86049
- const spanEls2 = pageEl2?.querySelectorAll("span[data-pm-start][data-pm-end]");
86050
- for (const spanEl of Array.from(spanEls2 ?? [])) {
86051
- const pmStart = Number(spanEl.dataset.pmStart);
86052
- const pmEnd = Number(spanEl.dataset.pmEnd);
86053
- if (pos >= pmStart && pos <= pmEnd && spanEl.firstChild?.nodeType === Node.TEXT_NODE) {
86054
- const textNode = spanEl.firstChild;
86055
- const charIndex = Math.min(pos - pmStart, textNode.length);
86056
- const rangeObj = document.createRange();
86057
- rangeObj.setStart(textNode, charIndex);
86058
- rangeObj.setEnd(textNode, charIndex);
86059
- if (typeof rangeObj.getBoundingClientRect !== "function") {
86060
- break;
86061
- }
86062
- const rangeRect = rangeObj.getBoundingClientRect();
86063
- if (pageRect2) {
86064
- domCaretX2 = (rangeRect.left - pageRect2.left) / zoom;
86065
- domCaretY2 = (rangeRect.top - pageRect2.top) / zoom;
86066
- }
86067
- break;
86068
- }
86069
- }
86070
- if (includeDomFallback && domCaretX2 != null && domCaretY2 != null) {
86071
- return {
86072
- pageIndex: hit.pageIndex,
86073
- x: domCaretX2,
86074
- y: domCaretY2,
86075
- height: line.lineHeight
86076
- };
86077
- }
86078
- return result2;
86079
- }
86151
+ const indent2 = extractParagraphIndent(block.attrs?.indent);
86080
86152
  const indentAdjust = calculateTextStartIndent({
86081
86153
  isFirstLine,
86082
86154
  isListItem: isListItemFlag,
86083
86155
  markerWidth,
86156
+ markerTextWidth,
86084
86157
  paraIndentLeft: indent2.left,
86085
86158
  firstLineIndent: indent2.firstLine,
86086
86159
  hangingIndent: indent2.hanging,
86087
86160
  wordLayout
86088
86161
  });
86162
+ const availableWidth = Math.max(0, fragment.width - (indentAdjust + indent2.right));
86163
+ const charX = measureCharacterX(block, line, pmOffset, availableWidth);
86089
86164
  const localX = fragment.x + indentAdjust + charX;
86090
86165
  const lineOffset = lineHeightBeforeIndex(measure.lines, fragment.fromLine, index2);
86091
86166
  const localY = fragment.y + lineOffset;
@@ -86103,9 +86178,9 @@ ${l}
86103
86178
  for (const spanEl of Array.from(spanEls ?? [])) {
86104
86179
  const pmStart = Number(spanEl.dataset.pmStart);
86105
86180
  const pmEnd = Number(spanEl.dataset.pmEnd);
86106
- if (pos >= pmStart && pos <= pmEnd && spanEl.firstChild?.nodeType === Node.TEXT_NODE) {
86181
+ if (effectivePos >= pmStart && effectivePos <= pmEnd && spanEl.firstChild?.nodeType === Node.TEXT_NODE) {
86107
86182
  const textNode = spanEl.firstChild;
86108
- const charIndex = Math.min(pos - pmStart, textNode.length);
86183
+ const charIndex = Math.min(effectivePos - pmStart, textNode.length);
86109
86184
  const rangeObj = document.createRange();
86110
86185
  rangeObj.setStart(textNode, charIndex);
86111
86186
  rangeObj.setEnd(textNode, charIndex);
@@ -96955,6 +97030,7 @@ ${l}
96955
97030
  #telemetryEmitter = null;
96956
97031
  #renderScheduled = false;
96957
97032
  #pendingDocChange = false;
97033
+ #pendingMapping = null;
96958
97034
  #isRerendering = false;
96959
97035
  #selectionSync = new SelectionSyncCoordinator();
96960
97036
  #remoteCursorUpdateScheduled = false;
@@ -98559,6 +98635,15 @@ ${l}
98559
98635
  }
98560
98636
  if (trackedChangesChanged || transaction?.docChanged) {
98561
98637
  this.#pendingDocChange = true;
98638
+ if (transaction?.docChanged) {
98639
+ if (this.#pendingMapping !== null) {
98640
+ const combined = this.#pendingMapping.slice();
98641
+ combined.appendMapping(transaction.mapping);
98642
+ this.#pendingMapping = combined;
98643
+ } else {
98644
+ this.#pendingMapping = transaction.mapping;
98645
+ }
98646
+ }
98562
98647
  this.#selectionSync.onLayoutStart();
98563
98648
  this.#scheduleRerender();
98564
98649
  }
@@ -99257,7 +99342,12 @@ ${l}
99257
99342
  }
99258
99343
  if (!handledByDepth) {
99259
99344
  try {
99260
- const tr = this.#editor.state.tr.setSelection(TextSelection$1.create(this.#editor.state.doc, hit.pos));
99345
+ const doc22 = this.#editor.state.doc;
99346
+ let nextSelection = TextSelection$1.create(doc22, hit.pos);
99347
+ if (!nextSelection.$from.parent.inlineContent) {
99348
+ nextSelection = Selection.near(doc22.resolve(hit.pos), 1);
99349
+ }
99350
+ const tr = this.#editor.state.tr.setSelection(nextSelection);
99261
99351
  this.#editor.view?.dispatch(tr);
99262
99352
  } catch {
99263
99353
  }
@@ -100120,7 +100210,9 @@ ${l}
100120
100210
  footerMeasures.length > 0 ? footerMeasures : void 0
100121
100211
  );
100122
100212
  this.#domIndexObserverManager?.pause();
100123
- painter.paint(layout, this.#painterHost);
100213
+ const mapping = this.#pendingMapping;
100214
+ this.#pendingMapping = null;
100215
+ painter.paint(layout, this.#painterHost, mapping ?? void 0);
100124
100216
  this.#applyVertAlignToLayout();
100125
100217
  this.#rebuildDomPositionIndex();
100126
100218
  this.#domIndexObserverManager?.resume();
@@ -100235,6 +100327,7 @@ ${l}
100235
100327
  if (!layout) {
100236
100328
  return;
100237
100329
  }
100330
+ const { from: from2, to } = selection;
100238
100331
  const docEpoch = this.#epochMapper.getCurrentEpoch();
100239
100332
  if (this.#layoutEpoch < docEpoch) {
100240
100333
  return;
@@ -100249,7 +100342,6 @@ ${l}
100249
100342
  }
100250
100343
  return;
100251
100344
  }
100252
- const { from: from2, to } = selection;
100253
100345
  if (from2 === to) {
100254
100346
  const caretLayout = this.#computeCaretLayoutRect(from2);
100255
100347
  if (!caretLayout) {
@@ -104836,6 +104928,28 @@ ${l}
104836
104928
  }
104837
104929
  return markDefs;
104838
104930
  };
104931
+ const normalizeSelectionIntoRun = (tr, runType) => {
104932
+ const selection = tr.selection;
104933
+ if (!(selection instanceof TextSelection$1)) return;
104934
+ if (selection.from !== selection.to) return;
104935
+ const $pos = tr.doc.resolve(selection.from);
104936
+ if ($pos.parent.type === runType) return;
104937
+ const nodeAfter = $pos.nodeAfter;
104938
+ if (nodeAfter?.type === runType && nodeAfter.content.size > 0) {
104939
+ const nextPos = selection.from + 1;
104940
+ if (nextPos <= tr.doc.content.size) {
104941
+ tr.setSelection(TextSelection$1.create(tr.doc, nextPos));
104942
+ }
104943
+ return;
104944
+ }
104945
+ const nodeBefore = $pos.nodeBefore;
104946
+ if (nodeBefore?.type === runType && nodeBefore.content.size > 0) {
104947
+ const prevPos = selection.from - 1;
104948
+ if (prevPos >= 0) {
104949
+ tr.setSelection(TextSelection$1.create(tr.doc, prevPos));
104950
+ }
104951
+ }
104952
+ };
104839
104953
  const buildWrapTransaction = (state, ranges, runType, editor, markDefsFromMeta = []) => {
104840
104954
  if (!ranges.length) return null;
104841
104955
  const replacements = [];
@@ -104869,6 +104983,7 @@ ${l}
104869
104983
  if (!replacements.length) return null;
104870
104984
  const tr = state.tr;
104871
104985
  replacements.sort((a2, b2) => b2.from - a2.from).forEach(({ from: from2, to, runNode }) => tr.replaceWith(from2, to, runNode));
104986
+ normalizeSelectionIntoRun(tr, runType);
104872
104987
  return tr.docChanged ? tr : null;
104873
104988
  };
104874
104989
  const wrapTextInRunsPlugin = (editor) => {
@@ -119817,6 +119932,7 @@ ${l}
119817
119932
  const parentItem = ref(null);
119818
119933
  const iconColor = ref(options.iconColor);
119819
119934
  const hasCaret = ref(options.hasCaret);
119935
+ const restoreEditorFocus = Boolean(options.restoreEditorFocus);
119820
119936
  const dropdownStyles = ref(options.dropdownStyles);
119821
119937
  const tooltip = ref(options.tooltip);
119822
119938
  const tooltipVisible = ref(options.tooltipVisible);
@@ -119892,6 +120008,7 @@ ${l}
119892
120008
  hideLabel,
119893
120009
  inlineTextInputVisible,
119894
120010
  hasInlineTextInput,
120011
+ restoreEditorFocus,
119895
120012
  markName,
119896
120013
  labelAttr,
119897
120014
  childItem,
@@ -122205,6 +122322,7 @@ ${l}
122205
122322
  command: "toggleBulletList",
122206
122323
  icon: toolbarIcons2.bulletList,
122207
122324
  tooltip: toolbarTexts2.bulletList,
122325
+ restoreEditorFocus: true,
122208
122326
  attributes: {
122209
122327
  ariaLabel: "Bullet list"
122210
122328
  }
@@ -122215,6 +122333,7 @@ ${l}
122215
122333
  command: "toggleOrderedList",
122216
122334
  icon: toolbarIcons2.numberedList,
122217
122335
  tooltip: toolbarTexts2.numberedList,
122336
+ restoreEditorFocus: true,
122218
122337
  attributes: {
122219
122338
  ariaLabel: "Numbered list"
122220
122339
  }
@@ -135114,6 +135233,7 @@ ${style2}
135114
135233
  selectionUpdate: null,
135115
135234
  focus: null
135116
135235
  };
135236
+ this._restoreFocusTimeoutId = null;
135117
135237
  if (!this.config.selector && this.config.element) {
135118
135238
  this.config.selector = this.config.element;
135119
135239
  }
@@ -135779,6 +135899,7 @@ ${style2}
135779
135899
  const wasFocused = Boolean(typeof hasFocusFn === "function" && hasFocusFn.call(this.activeEditor.view));
135780
135900
  const { command: command2 } = item;
135781
135901
  const isMarkToggle = this.isMarkToggle(item);
135902
+ const shouldRestoreFocus = Boolean(item?.restoreEditorFocus);
135782
135903
  if (!wasFocused && isMarkToggle) {
135783
135904
  this.pendingMarkCommands.push({ command: command2, argument, item });
135784
135905
  item?.activate?.();
@@ -135809,6 +135930,13 @@ ${style2}
135809
135930
  }
135810
135931
  if (isMarkToggle) this.#syncStickyMarksFromState();
135811
135932
  this.updateToolbarState();
135933
+ if (shouldRestoreFocus && this.activeEditor && !this.activeEditor.options.isHeaderOrFooter) {
135934
+ this._restoreFocusTimeoutId = setTimeout(() => {
135935
+ this._restoreFocusTimeoutId = null;
135936
+ if (!this.activeEditor || this.activeEditor.options.isHeaderOrFooter) return;
135937
+ this.activeEditor.focus();
135938
+ }, 0);
135939
+ }
135812
135940
  }
135813
135941
  /**
135814
135942
  * Processes and executes pending mark commands when editor selection updates.
@@ -135951,6 +136079,17 @@ ${style2}
135951
136079
  const tr = state.tr.setStoredMarks([mark2]);
135952
136080
  view.dispatch(tr);
135953
136081
  }
136082
+ /**
136083
+ * Cleans up resources when the toolbar is destroyed.
136084
+ * Clears any pending timeouts to prevent callbacks firing after unmount.
136085
+ * @returns {void}
136086
+ */
136087
+ destroy() {
136088
+ if (this._restoreFocusTimeoutId !== null) {
136089
+ clearTimeout(this._restoreFocusTimeoutId);
136090
+ this._restoreFocusTimeoutId = null;
136091
+ }
136092
+ }
135954
136093
  }
135955
136094
  async function createZip(blobs, fileNames) {
135956
136095
  const zip = new JSZip();
@@ -144479,7 +144618,7 @@ ${reason}`);
144479
144618
  this.config.colors = shuffleArray(this.config.colors);
144480
144619
  this.userColorMap = /* @__PURE__ */ new Map();
144481
144620
  this.colorIndex = 0;
144482
- this.version = "1.3.0";
144621
+ this.version = "1.3.1-next.2";
144483
144622
  this.#log("🦋 [superdoc] Using SuperDoc version:", this.version);
144484
144623
  this.superdocId = config2.superdocId || v4();
144485
144624
  this.colors = this.config.colors;