@harbour-enterprises/superdoc 1.3.0 → 1.3.1-next.1

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.
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  const jszip = require("./jszip-C8_CqJxM.cjs");
3
3
  const helpers$1 = require("./helpers-nOdwpmwb.cjs");
4
- const superEditor_converter = require("./SuperConverter-BJ-tba6U.cjs");
4
+ const superEditor_converter = require("./SuperConverter-rwP6nlvC.cjs");
5
5
  const vue = require("./vue-De9wkgLl.cjs");
6
6
  require("./jszip.min-BPh2MMAa.cjs");
7
7
  const eventemitter3 = require("./eventemitter3-BQuRcMPI.cjs");
@@ -15451,7 +15451,7 @@ const canUseDOM = () => {
15451
15451
  return false;
15452
15452
  }
15453
15453
  };
15454
- const summaryVersion = "1.3.0";
15454
+ const summaryVersion = "1.3.1-next.1";
15455
15455
  const nodeKeys = ["group", "content", "marks", "inline", "atom", "defining", "code", "tableRole", "summary"];
15456
15456
  const markKeys = ["group", "inclusive", "excludes", "spanning", "code"];
15457
15457
  function mapAttributes(attrs) {
@@ -18083,7 +18083,7 @@ class Editor extends EventEmitter {
18083
18083
  * Process collaboration migrations
18084
18084
  */
18085
18085
  processCollaborationMigrations() {
18086
- console.debug("[checkVersionMigrations] Current editor version", "1.3.0");
18086
+ console.debug("[checkVersionMigrations] Current editor version", "1.3.1-next.1");
18087
18087
  if (!this.options.ydoc) return;
18088
18088
  const metaMap = this.options.ydoc.getMap("meta");
18089
18089
  let docVersion = metaMap.get("version");
@@ -24946,7 +24946,7 @@ function isMinimalWordLayout(value) {
24946
24946
  return true;
24947
24947
  }
24948
24948
  const LIST_MARKER_GAP$2 = 8;
24949
- const DEFAULT_TAB_INTERVAL_PX$2 = 48;
24949
+ const DEFAULT_TAB_INTERVAL_PX$1 = 48;
24950
24950
  const DEFAULT_PAGE_HEIGHT_PX = 1056;
24951
24951
  const DEFAULT_VIRTUALIZED_PAGE_GAP$1 = 72;
24952
24952
  const COMMENT_EXTERNAL_COLOR = "#B1124B";
@@ -25980,7 +25980,7 @@ class DomPainter {
25980
25980
  const textStart = paraIndentLeft + firstLine;
25981
25981
  tabWidth = textStart - currentPos;
25982
25982
  if (tabWidth <= 0) {
25983
- tabWidth = DEFAULT_TAB_INTERVAL_PX$2 - currentPos % DEFAULT_TAB_INTERVAL_PX$2;
25983
+ tabWidth = DEFAULT_TAB_INTERVAL_PX$1 - currentPos % DEFAULT_TAB_INTERVAL_PX$1;
25984
25984
  } else if (tabWidth < LIST_MARKER_GAP$2) {
25985
25985
  tabWidth = LIST_MARKER_GAP$2;
25986
25986
  }
@@ -26132,7 +26132,7 @@ class DomPainter {
26132
26132
  const textStart = paraIndentLeft + firstLine;
26133
26133
  tabWidth = textStart - currentPos;
26134
26134
  if (tabWidth <= 0) {
26135
- tabWidth = DEFAULT_TAB_INTERVAL_PX$2 - currentPos % DEFAULT_TAB_INTERVAL_PX$2;
26135
+ tabWidth = DEFAULT_TAB_INTERVAL_PX$1 - currentPos % DEFAULT_TAB_INTERVAL_PX$1;
26136
26136
  } else if (tabWidth < LIST_MARKER_GAP$2) {
26137
26137
  tabWidth = LIST_MARKER_GAP$2;
26138
26138
  }
@@ -27480,6 +27480,13 @@ class DomPainter {
27480
27480
  const trackedConfig = this.resolveTrackedChangesConfig(block);
27481
27481
  if (runsForLine.length === 0) {
27482
27482
  const span = this.doc.createElement("span");
27483
+ span.classList.add("superdoc-empty-run");
27484
+ if (lineRange.pmStart != null) {
27485
+ span.dataset.pmStart = String(lineRange.pmStart);
27486
+ }
27487
+ if (lineRange.pmEnd != null) {
27488
+ span.dataset.pmEnd = String(lineRange.pmEnd);
27489
+ }
27483
27490
  span.innerHTML = "&nbsp;";
27484
27491
  el.appendChild(span);
27485
27492
  }
@@ -30726,7 +30733,6 @@ const DEFAULT_LIST_INDENT_BASE_PX = 24;
30726
30733
  const DEFAULT_LIST_INDENT_STEP_PX = 24;
30727
30734
  const DEFAULT_LIST_HANGING_PX$1 = 18;
30728
30735
  const SPACE_SUFFIX_GAP_PX = 4;
30729
- const DEFAULT_TAB_INTERVAL_PX$1 = 48;
30730
30736
  function resolveListTextStartPx(wordLayout, indentLeft, firstLine, hanging, measureMarkerText) {
30731
30737
  const marker = wordLayout?.marker;
30732
30738
  if (!marker) {
@@ -30760,9 +30766,13 @@ function resolveListTextStartPx(wordLayout, indentLeft, firstLine, hanging, meas
30760
30766
  return markerStartPos + finalMarkerTextWidth;
30761
30767
  }
30762
30768
  const markerJustification = marker.justification ?? "left";
30769
+ const markerWidthEffective = Math.max(
30770
+ typeof marker.markerBoxWidthPx === "number" && Number.isFinite(marker.markerBoxWidthPx) ? marker.markerBoxWidthPx : 0,
30771
+ finalMarkerTextWidth
30772
+ );
30763
30773
  if (markerJustification !== "left") {
30764
- const gutterWidth = typeof marker.gutterWidthPx === "number" && Number.isFinite(marker.gutterWidthPx) && marker.gutterWidthPx > 0 ? marker.gutterWidthPx : LIST_MARKER_GAP$1;
30765
- return markerStartPos + finalMarkerTextWidth + Math.max(gutterWidth, LIST_MARKER_GAP$1);
30774
+ const gutterWidth2 = typeof marker.gutterWidthPx === "number" && Number.isFinite(marker.gutterWidthPx) && marker.gutterWidthPx > 0 ? marker.gutterWidthPx : LIST_MARKER_GAP$1;
30775
+ return markerStartPos + finalMarkerTextWidth + Math.max(gutterWidth2, LIST_MARKER_GAP$1);
30766
30776
  }
30767
30777
  if (wordLayout?.firstLineIndentMode === true) {
30768
30778
  let targetTabStop;
@@ -30774,12 +30784,12 @@ function resolveListTextStartPx(wordLayout, indentLeft, firstLine, hanging, meas
30774
30784
  }
30775
30785
  }
30776
30786
  }
30777
- const textStartTarget = typeof marker.textStartX === "number" && Number.isFinite(marker.textStartX) ? marker.textStartX : wordLayout.textStartPx;
30787
+ const textStartTarget2 = typeof marker.textStartX === "number" && Number.isFinite(marker.textStartX) ? marker.textStartX : wordLayout.textStartPx;
30778
30788
  let tabWidth2;
30779
30789
  if (targetTabStop !== void 0) {
30780
30790
  tabWidth2 = targetTabStop - currentPos;
30781
- } else if (textStartTarget !== void 0 && Number.isFinite(textStartTarget) && textStartTarget > currentPos) {
30782
- tabWidth2 = textStartTarget - currentPos;
30791
+ } else if (textStartTarget2 !== void 0 && Number.isFinite(textStartTarget2) && textStartTarget2 > currentPos) {
30792
+ tabWidth2 = textStartTarget2 - currentPos;
30783
30793
  } else {
30784
30794
  tabWidth2 = LIST_MARKER_GAP$1;
30785
30795
  }
@@ -30788,14 +30798,21 @@ function resolveListTextStartPx(wordLayout, indentLeft, firstLine, hanging, meas
30788
30798
  }
30789
30799
  return markerStartPos + finalMarkerTextWidth + tabWidth2;
30790
30800
  }
30801
+ const textStartTarget = typeof wordLayout?.textStartPx === "number" && Number.isFinite(wordLayout.textStartPx) ? wordLayout.textStartPx : void 0;
30802
+ const gutterWidth = typeof marker.gutterWidthPx === "number" && Number.isFinite(marker.gutterWidthPx) && marker.gutterWidthPx > 0 ? marker.gutterWidthPx : LIST_MARKER_GAP$1;
30803
+ const currentPosStandard = markerStartPos + markerWidthEffective;
30804
+ if (textStartTarget !== void 0) {
30805
+ const gap = Math.max(textStartTarget - currentPosStandard, gutterWidth);
30806
+ return currentPosStandard + gap;
30807
+ }
30791
30808
  const textStart = indentLeft + firstLine;
30792
- let tabWidth = textStart - currentPos;
30809
+ let tabWidth = textStart - currentPosStandard;
30793
30810
  if (tabWidth <= 0) {
30794
- tabWidth = DEFAULT_TAB_INTERVAL_PX$1 - currentPos % DEFAULT_TAB_INTERVAL_PX$1;
30811
+ tabWidth = gutterWidth;
30795
30812
  } else if (tabWidth < LIST_MARKER_GAP$1) {
30796
- tabWidth = LIST_MARKER_GAP$1;
30813
+ tabWidth = Math.max(tabWidth, gutterWidth);
30797
30814
  }
30798
- return markerStartPos + finalMarkerTextWidth + tabWidth;
30815
+ return currentPosStandard + tabWidth;
30799
30816
  }
30800
30817
  function getWordLayoutConfig(block) {
30801
30818
  if (!block || block.kind !== "paragraph") {
@@ -30824,21 +30841,45 @@ function isListItem(markerWidth, block) {
30824
30841
  return hasHangingIndentPattern;
30825
30842
  }
30826
30843
  function calculateTextStartIndent(params2) {
30827
- const { isFirstLine, isListItem: isListItem2, markerWidth, paraIndentLeft, firstLineIndent, hangingIndent, wordLayout } = params2;
30844
+ const {
30845
+ isFirstLine,
30846
+ isListItem: isListItem2,
30847
+ markerWidth,
30848
+ markerTextWidth,
30849
+ paraIndentLeft,
30850
+ firstLineIndent,
30851
+ hangingIndent,
30852
+ wordLayout
30853
+ } = params2;
30828
30854
  const firstLineOffset = firstLineIndent - hangingIndent;
30829
- const isFirstLineIndentMode = wordLayout?.firstLineIndentMode === true;
30855
+ const effectiveMarkerTextWidth = typeof markerTextWidth === "number" && Number.isFinite(markerTextWidth) && markerTextWidth > 0 ? markerTextWidth : markerWidth;
30830
30856
  let indentAdjust = paraIndentLeft;
30831
- if (isListItem2 && isFirstLine && isFirstLineIndentMode) {
30857
+ if (isListItem2 && isFirstLine) {
30832
30858
  const resolvedTextStart = resolveListTextStartPx(
30833
30859
  wordLayout,
30834
30860
  paraIndentLeft,
30835
30861
  Math.max(firstLineIndent, 0),
30836
30862
  Math.max(hangingIndent, 0),
30837
- () => markerWidth
30838
- // Use provided markerWidth since we don't have canvas access here
30863
+ () => effectiveMarkerTextWidth
30864
+ // Use measured marker text width when available
30839
30865
  );
30840
- const textStartFallback = paraIndentLeft + Math.max(firstLineIndent, 0) + markerWidth;
30841
- indentAdjust = typeof resolvedTextStart === "number" && Number.isFinite(resolvedTextStart) ? resolvedTextStart : textStartFallback;
30866
+ if (typeof resolvedTextStart === "number" && Number.isFinite(resolvedTextStart)) {
30867
+ indentAdjust = resolvedTextStart;
30868
+ } else {
30869
+ const explicitTextStart = wordLayout?.marker?.textStartX ?? wordLayout?.textStartPx;
30870
+ const isStandardHangingList = hangingIndent > 0 && wordLayout?.firstLineIndentMode !== true;
30871
+ const textStartLooksValid = typeof explicitTextStart === "number" && Number.isFinite(explicitTextStart) && (!isStandardHangingList || explicitTextStart > paraIndentLeft);
30872
+ if (textStartLooksValid) {
30873
+ indentAdjust = explicitTextStart;
30874
+ } else if (wordLayout?.firstLineIndentMode === true) {
30875
+ indentAdjust = paraIndentLeft + Math.max(firstLineIndent, 0) + markerWidth;
30876
+ } else if (isStandardHangingList && effectiveMarkerTextWidth > 0) {
30877
+ const markerStartPos = Math.max(0, paraIndentLeft - hangingIndent + firstLineIndent);
30878
+ const gutterWidthCandidate = wordLayout?.gutterWidthPx;
30879
+ const gutterWidth = typeof gutterWidthCandidate === "number" && Number.isFinite(gutterWidthCandidate) ? gutterWidthCandidate : wordLayout?.marker?.gutterWidthPx ?? LIST_MARKER_GAP$1;
30880
+ indentAdjust = markerStartPos + effectiveMarkerTextWidth + gutterWidth;
30881
+ }
30882
+ }
30842
30883
  } else if (isFirstLine && !isListItem2) {
30843
30884
  indentAdjust += firstLineOffset;
30844
30885
  }
@@ -31689,12 +31730,16 @@ function layoutParagraphBlock(ctx2, anchors) {
31689
31730
  const negativeRightIndent = indentRight < 0 ? indentRight : 0;
31690
31731
  const remeasureWidth = Math.max(1, columnWidth - indentLeft - indentRight);
31691
31732
  let didRemeasureForColumnWidth = false;
31733
+ let remeasuredMarkerInfo;
31692
31734
  if (typeof remeasureParagraph2 === "function" && typeof measurementWidth === "number" && measurementWidth > remeasureWidth) {
31693
31735
  const firstLineIndent = calculateFirstLineIndent(block, measure);
31694
31736
  const newMeasure = remeasureParagraph2(block, columnWidth, firstLineIndent);
31695
31737
  const newLines = normalizeLines(newMeasure);
31696
31738
  lines = newLines;
31697
31739
  didRemeasureForColumnWidth = true;
31740
+ if (newMeasure.marker) {
31741
+ remeasuredMarkerInfo = newMeasure.marker;
31742
+ }
31698
31743
  }
31699
31744
  let fromLine = 0;
31700
31745
  const attrs = getParagraphAttrs(block);
@@ -31733,10 +31778,12 @@ function layoutParagraphBlock(ctx2, anchors) {
31733
31778
  width: fragmentWidth,
31734
31779
  ...computeFragmentPmRange(block, lines, 0, lines.length)
31735
31780
  };
31736
- if (measure.marker) {
31737
- fragment.markerWidth = measure.marker.markerWidth;
31738
- if (measure.marker.markerTextWidth != null) {
31739
- fragment.markerTextWidth = measure.marker.markerTextWidth;
31781
+ if (measure.marker || remeasuredMarkerInfo) {
31782
+ const effectiveMarkerInfo = remeasuredMarkerInfo ?? measure.marker;
31783
+ fragment.markerWidth = effectiveMarkerInfo?.markerWidth ?? measure.marker?.markerWidth ?? 0;
31784
+ const markerTextWidth = remeasuredMarkerInfo?.markerTextWidth ?? measure.marker?.markerTextWidth;
31785
+ if (markerTextWidth != null) {
31786
+ fragment.markerTextWidth = markerTextWidth;
31740
31787
  }
31741
31788
  }
31742
31789
  state.page.fragments.push(fragment);
@@ -31778,6 +31825,9 @@ function layoutParagraphBlock(ctx2, anchors) {
31778
31825
  const newLines = normalizeLines(newMeasure);
31779
31826
  lines = newLines;
31780
31827
  didRemeasureForFloats = true;
31828
+ if (newMeasure.marker) {
31829
+ remeasuredMarkerInfo = newMeasure.marker;
31830
+ }
31781
31831
  }
31782
31832
  }
31783
31833
  while (fromLine < lines.length) {
@@ -31849,13 +31899,16 @@ function layoutParagraphBlock(ctx2, anchors) {
31849
31899
  if (didRemeasureForColumnWidth) {
31850
31900
  fragment.lines = lines.slice(fromLine, slice2.toLine);
31851
31901
  }
31852
- if (measure.marker && fromLine === 0) {
31853
- fragment.markerWidth = measure.marker.markerWidth;
31854
- if (measure.marker.markerTextWidth != null) {
31855
- fragment.markerTextWidth = measure.marker.markerTextWidth;
31902
+ if ((measure.marker || remeasuredMarkerInfo) && fromLine === 0) {
31903
+ const effectiveMarkerInfo = remeasuredMarkerInfo ?? measure.marker;
31904
+ fragment.markerWidth = effectiveMarkerInfo?.markerWidth ?? measure.marker?.markerWidth ?? 0;
31905
+ const markerTextWidth = remeasuredMarkerInfo?.markerTextWidth ?? measure.marker?.markerTextWidth;
31906
+ if (markerTextWidth != null) {
31907
+ fragment.markerTextWidth = markerTextWidth;
31856
31908
  }
31857
- if (measure.kind === "paragraph" && measure.marker?.gutterWidth != null) {
31858
- fragment.markerGutter = measure.marker.gutterWidth;
31909
+ const gutterWidth = remeasuredMarkerInfo?.gutterWidth ?? measure.marker?.gutterWidth;
31910
+ if (gutterWidth != null) {
31911
+ fragment.markerGutter = gutterWidth;
31859
31912
  }
31860
31913
  }
31861
31914
  if (fromLine > 0) fragment.continuesFromPrev = true;
@@ -35296,16 +35349,19 @@ function remeasureParagraph(block, maxWidth, firstLineIndent = 0) {
35296
35349
  const contentWidth = Math.max(1, maxWidth - indentLeft - indentRight);
35297
35350
  const markerTextStartX = wordLayout?.marker?.textStartX;
35298
35351
  const textStartPx = typeof markerTextStartX === "number" && Number.isFinite(markerTextStartX) ? markerTextStartX : typeof wordLayout?.textStartPx === "number" && Number.isFinite(wordLayout.textStartPx) ? wordLayout.textStartPx : void 0;
35352
+ let measuredMarkerTextWidth;
35299
35353
  const resolvedTextStartPx = resolveListTextStartPx(
35300
35354
  wordLayout,
35301
35355
  indentLeft,
35302
35356
  indentFirstLine,
35303
35357
  indentHanging,
35304
- (markerText, marker) => {
35358
+ (markerText, marker2) => {
35305
35359
  const context = getCtx();
35306
35360
  if (!context) return 0;
35307
- context.font = markerFontString(marker.run);
35308
- return context.measureText(markerText).width;
35361
+ context.font = markerFontString(marker2.run);
35362
+ const width = context.measureText(markerText).width;
35363
+ measuredMarkerTextWidth = width;
35364
+ return width;
35309
35365
  }
35310
35366
  );
35311
35367
  const effectiveTextStartPx = resolvedTextStartPx ?? textStartPx;
@@ -35396,7 +35452,14 @@ function remeasureParagraph(block, maxWidth, firstLineIndent = 0) {
35396
35452
  }
35397
35453
  }
35398
35454
  const totalHeight = lines.reduce((s2, l) => s2 + l.lineHeight, 0);
35399
- return { kind: "paragraph", lines, totalHeight };
35455
+ const marker = wordLayout?.marker;
35456
+ const markerInfo = marker ? {
35457
+ markerWidth: marker.markerBoxWidthPx ?? indentHanging ?? 0,
35458
+ markerTextWidth: measuredMarkerTextWidth ?? 0,
35459
+ indentLeft,
35460
+ gutterWidth: marker.gutterWidthPx
35461
+ } : void 0;
35462
+ return { kind: "paragraph", lines, totalHeight, marker: markerInfo };
35400
35463
  }
35401
35464
  function hasComments(run) {
35402
35465
  return "comments" in run && Array.isArray(run.comments) && run.comments.length > 0;
@@ -37447,6 +37510,7 @@ function selectionToRects(layout, blocks, measures, from3, to, geometryHelper) {
37447
37510
  isFirstLine,
37448
37511
  isListItem: isListItemFlag,
37449
37512
  markerWidth,
37513
+ markerTextWidth: fragment.markerTextWidth ?? measure.marker?.markerTextWidth ?? void 0,
37450
37514
  paraIndentLeft: indent.left,
37451
37515
  firstLineIndent: indent.firstLine,
37452
37516
  hangingIndent: indent.hanging,
@@ -37584,6 +37648,7 @@ function selectionToRects(layout, blocks, measures, from3, to, geometryHelper) {
37584
37648
  isFirstLine,
37585
37649
  isListItem: cellIsListItem,
37586
37650
  markerWidth: paragraphMarkerWidth,
37651
+ markerTextWidth: info.measure?.marker?.markerTextWidth ?? void 0,
37587
37652
  paraIndentLeft: cellIndent.left,
37588
37653
  firstLineIndent: cellIndent.firstLine,
37589
37654
  hangingIndent: cellIndent.hanging,
@@ -37835,25 +37900,36 @@ const mapPointToPm = (block, line, x, isRTL, availableWidthOverride, alignmentOv
37835
37900
  const range = computeLinePmRange(block, line);
37836
37901
  if (range.pmStart == null || range.pmEnd == null) return null;
37837
37902
  const result = findCharacterAtX(block, line, x, range.pmStart, availableWidthOverride, alignmentOverride);
37903
+ let pmPosition = result.pmPosition;
37838
37904
  if (isRTL) {
37839
37905
  const charOffset = result.charOffset;
37840
37906
  const charsInLine = Math.max(1, line.toChar - line.fromChar);
37841
37907
  const reversedOffset = Math.max(0, Math.min(charsInLine, charsInLine - charOffset));
37842
- return charOffsetToPm(block, line, reversedOffset, range.pmStart);
37908
+ pmPosition = charOffsetToPm(block, line, reversedOffset, range.pmStart);
37843
37909
  }
37844
- return result.pmPosition;
37910
+ return pmPosition;
37845
37911
  };
37846
37912
  const mapPmToX = (block, line, offset2, fragmentWidth, alignmentOverride) => {
37847
37913
  if (fragmentWidth <= 0 || line.width <= 0) return 0;
37848
37914
  let paraIndentLeft = 0;
37849
37915
  let paraIndentRight = 0;
37916
+ let effectiveLeft = 0;
37850
37917
  if (block.kind === "paragraph") {
37851
37918
  const indentLeft = typeof block.attrs?.indent?.left === "number" ? block.attrs.indent.left : 0;
37852
37919
  const indentRight = typeof block.attrs?.indent?.right === "number" ? block.attrs.indent.right : 0;
37853
37920
  paraIndentLeft = Number.isFinite(indentLeft) ? indentLeft : 0;
37854
37921
  paraIndentRight = Number.isFinite(indentRight) ? indentRight : 0;
37922
+ effectiveLeft = paraIndentLeft;
37923
+ const wl = getWordLayoutConfig(block);
37924
+ const isListParagraph = Boolean(block.attrs?.numberingProperties) || Boolean(wl?.marker);
37925
+ if (isListParagraph) {
37926
+ 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;
37927
+ if (typeof explicitTextStart === "number" && explicitTextStart > paraIndentLeft) {
37928
+ effectiveLeft = explicitTextStart;
37929
+ }
37930
+ }
37855
37931
  }
37856
- const totalIndent = paraIndentLeft + paraIndentRight;
37932
+ const totalIndent = effectiveLeft + paraIndentRight;
37857
37933
  const availableWidth = Math.max(0, fragmentWidth - totalIndent);
37858
37934
  if (totalIndent > fragmentWidth) {
37859
37935
  console.warn(
@@ -39191,16 +39267,26 @@ function lineHeightBeforeIndex(lines, fromLine, targetIndex) {
39191
39267
  }
39192
39268
  function computeCaretLayoutRectGeometry({ layout, blocks, measures, painterHost, viewportHost, visibleHost, zoom }, pos, includeDomFallback = true) {
39193
39269
  if (!layout) return null;
39194
- const hit = getFragmentAtPosition(layout, blocks, measures, pos);
39270
+ let effectivePos = pos;
39271
+ let hit = getFragmentAtPosition(layout, blocks, measures, pos);
39195
39272
  if (!hit) {
39196
- return null;
39273
+ const fallbackCandidates = [pos - 1, pos + 1, pos - 2, pos + 2].filter((candidate) => candidate >= 0);
39274
+ for (const candidate of fallbackCandidates) {
39275
+ const fallbackHit = getFragmentAtPosition(layout, blocks, measures, candidate);
39276
+ if (fallbackHit) {
39277
+ hit = fallbackHit;
39278
+ effectivePos = candidate;
39279
+ break;
39280
+ }
39281
+ }
39282
+ if (!hit) return null;
39197
39283
  }
39198
39284
  const block = hit.block;
39199
39285
  const measure = hit.measure;
39200
39286
  if (hit.fragment.kind === "table" && block?.kind === "table" && measure?.kind === "table") {
39201
39287
  return computeTableCaretLayoutRectFromDom(
39202
39288
  { viewportHost, visibleHost, zoom },
39203
- pos,
39289
+ effectivePos,
39204
39290
  hit.fragment,
39205
39291
  block,
39206
39292
  measure,
@@ -39208,92 +39294,32 @@ function computeCaretLayoutRectGeometry({ layout, blocks, measures, painterHost,
39208
39294
  );
39209
39295
  }
39210
39296
  if (!block || block.kind !== "paragraph" || measure?.kind !== "paragraph") return null;
39211
- if (hit.fragment.kind !== "para") {
39212
- return null;
39213
- }
39297
+ if (hit.fragment.kind !== "para") return null;
39214
39298
  const fragment = hit.fragment;
39215
- const lineInfo = findLineContainingPos(block, measure, fragment.fromLine, fragment.toLine, pos);
39216
- if (!lineInfo) {
39217
- return null;
39218
- }
39299
+ const lineInfo = findLineContainingPos(block, measure, fragment.fromLine, fragment.toLine, effectivePos);
39300
+ if (!lineInfo) return null;
39219
39301
  const { line, index: index2 } = lineInfo;
39220
39302
  const range = computeLinePmRange(block, line);
39221
39303
  if (range.pmStart == null || range.pmEnd == null) return null;
39222
- const pmOffset = pmPosToCharOffset(block, line, pos);
39304
+ const pmOffset = pmPosToCharOffset(block, line, effectivePos);
39223
39305
  const markerWidth = fragment.markerWidth ?? measure.marker?.markerWidth ?? 0;
39224
- const indent = extractParagraphIndent(block.attrs?.indent);
39225
- const availableWidth = Math.max(0, fragment.width - (indent.left + indent.right));
39226
- const charX = measureCharacterX(block, line, pmOffset, availableWidth);
39306
+ const markerTextWidth = fragment.markerTextWidth ?? measure.marker?.markerTextWidth ?? void 0;
39227
39307
  const isFirstLine = index2 === fragment.fromLine;
39228
39308
  const isListItemFlag = isListItem(markerWidth, block);
39229
- const isListFirstLine = isFirstLine && !fragment.continuesFromPrev && isListItemFlag;
39230
39309
  const wordLayout = getWordLayoutConfig(block);
39231
- const isFirstLineIndentMode = wordLayout?.firstLineIndentMode === true;
39232
- if (isListFirstLine && isFirstLineIndentMode) {
39233
- const textStartPx = calculateTextStartIndent({
39234
- isFirstLine,
39235
- isListItem: isListItemFlag,
39236
- markerWidth,
39237
- paraIndentLeft: indent.left,
39238
- firstLineIndent: indent.firstLine,
39239
- hangingIndent: indent.hanging,
39240
- wordLayout
39241
- });
39242
- const localX2 = fragment.x + textStartPx + charX;
39243
- const lineOffset2 = lineHeightBeforeIndex(measure.lines, fragment.fromLine, index2);
39244
- const localY2 = fragment.y + lineOffset2;
39245
- const result2 = {
39246
- pageIndex: hit.pageIndex,
39247
- x: localX2,
39248
- y: localY2,
39249
- height: line.lineHeight
39250
- };
39251
- const pageEl2 = painterHost?.querySelector(
39252
- `.superdoc-page[data-page-index="${hit.pageIndex}"]`
39253
- );
39254
- const pageRect2 = pageEl2?.getBoundingClientRect();
39255
- let domCaretX2 = null;
39256
- let domCaretY2 = null;
39257
- const spanEls2 = pageEl2?.querySelectorAll("span[data-pm-start][data-pm-end]");
39258
- for (const spanEl of Array.from(spanEls2 ?? [])) {
39259
- const pmStart = Number(spanEl.dataset.pmStart);
39260
- const pmEnd = Number(spanEl.dataset.pmEnd);
39261
- if (pos >= pmStart && pos <= pmEnd && spanEl.firstChild?.nodeType === Node.TEXT_NODE) {
39262
- const textNode = spanEl.firstChild;
39263
- const charIndex = Math.min(pos - pmStart, textNode.length);
39264
- const rangeObj = document.createRange();
39265
- rangeObj.setStart(textNode, charIndex);
39266
- rangeObj.setEnd(textNode, charIndex);
39267
- if (typeof rangeObj.getBoundingClientRect !== "function") {
39268
- break;
39269
- }
39270
- const rangeRect = rangeObj.getBoundingClientRect();
39271
- if (pageRect2) {
39272
- domCaretX2 = (rangeRect.left - pageRect2.left) / zoom;
39273
- domCaretY2 = (rangeRect.top - pageRect2.top) / zoom;
39274
- }
39275
- break;
39276
- }
39277
- }
39278
- if (includeDomFallback && domCaretX2 != null && domCaretY2 != null) {
39279
- return {
39280
- pageIndex: hit.pageIndex,
39281
- x: domCaretX2,
39282
- y: domCaretY2,
39283
- height: line.lineHeight
39284
- };
39285
- }
39286
- return result2;
39287
- }
39310
+ const indent = extractParagraphIndent(block.attrs?.indent);
39288
39311
  const indentAdjust = calculateTextStartIndent({
39289
39312
  isFirstLine,
39290
39313
  isListItem: isListItemFlag,
39291
39314
  markerWidth,
39315
+ markerTextWidth,
39292
39316
  paraIndentLeft: indent.left,
39293
39317
  firstLineIndent: indent.firstLine,
39294
39318
  hangingIndent: indent.hanging,
39295
39319
  wordLayout
39296
39320
  });
39321
+ const availableWidth = Math.max(0, fragment.width - (indentAdjust + indent.right));
39322
+ const charX = measureCharacterX(block, line, pmOffset, availableWidth);
39297
39323
  const localX = fragment.x + indentAdjust + charX;
39298
39324
  const lineOffset = lineHeightBeforeIndex(measure.lines, fragment.fromLine, index2);
39299
39325
  const localY = fragment.y + lineOffset;
@@ -39311,9 +39337,9 @@ function computeCaretLayoutRectGeometry({ layout, blocks, measures, painterHost,
39311
39337
  for (const spanEl of Array.from(spanEls ?? [])) {
39312
39338
  const pmStart = Number(spanEl.dataset.pmStart);
39313
39339
  const pmEnd = Number(spanEl.dataset.pmEnd);
39314
- if (pos >= pmStart && pos <= pmEnd && spanEl.firstChild?.nodeType === Node.TEXT_NODE) {
39340
+ if (effectivePos >= pmStart && effectivePos <= pmEnd && spanEl.firstChild?.nodeType === Node.TEXT_NODE) {
39315
39341
  const textNode = spanEl.firstChild;
39316
- const charIndex = Math.min(pos - pmStart, textNode.length);
39342
+ const charIndex = Math.min(effectivePos - pmStart, textNode.length);
39317
39343
  const rangeObj = document.createRange();
39318
39344
  rangeObj.setStart(textNode, charIndex);
39319
39345
  rangeObj.setEnd(textNode, charIndex);
@@ -52537,7 +52563,12 @@ class PresentationEditor extends EventEmitter {
52537
52563
  }
52538
52564
  if (!handledByDepth) {
52539
52565
  try {
52540
- const tr = this.#editor.state.tr.setSelection(superEditor_converter.TextSelection.create(this.#editor.state.doc, hit.pos));
52566
+ const doc22 = this.#editor.state.doc;
52567
+ let nextSelection = superEditor_converter.TextSelection.create(doc22, hit.pos);
52568
+ if (!nextSelection.$from.parent.inlineContent) {
52569
+ nextSelection = superEditor_converter.Selection.near(doc22.resolve(hit.pos), 1);
52570
+ }
52571
+ const tr = this.#editor.state.tr.setSelection(nextSelection);
52541
52572
  this.#editor.view?.dispatch(tr);
52542
52573
  } catch {
52543
52574
  }
@@ -53527,6 +53558,7 @@ class PresentationEditor extends EventEmitter {
53527
53558
  if (!layout) {
53528
53559
  return;
53529
53560
  }
53561
+ const { from: from3, to } = selection;
53530
53562
  const docEpoch = this.#epochMapper.getCurrentEpoch();
53531
53563
  if (this.#layoutEpoch < docEpoch) {
53532
53564
  return;
@@ -53541,7 +53573,6 @@ class PresentationEditor extends EventEmitter {
53541
53573
  }
53542
53574
  return;
53543
53575
  }
53544
- const { from: from3, to } = selection;
53545
53576
  if (from3 === to) {
53546
53577
  const caretLayout = this.#computeCaretLayoutRect(from3);
53547
53578
  if (!caretLayout) {
@@ -58140,6 +58171,28 @@ const createMarkDefsFromStyleRunProps = (styleRunProps) => {
58140
58171
  }
58141
58172
  return markDefs;
58142
58173
  };
58174
+ const normalizeSelectionIntoRun = (tr, runType) => {
58175
+ const selection = tr.selection;
58176
+ if (!(selection instanceof superEditor_converter.TextSelection)) return;
58177
+ if (selection.from !== selection.to) return;
58178
+ const $pos = tr.doc.resolve(selection.from);
58179
+ if ($pos.parent.type === runType) return;
58180
+ const nodeAfter = $pos.nodeAfter;
58181
+ if (nodeAfter?.type === runType && nodeAfter.content.size > 0) {
58182
+ const nextPos = selection.from + 1;
58183
+ if (nextPos <= tr.doc.content.size) {
58184
+ tr.setSelection(superEditor_converter.TextSelection.create(tr.doc, nextPos));
58185
+ }
58186
+ return;
58187
+ }
58188
+ const nodeBefore = $pos.nodeBefore;
58189
+ if (nodeBefore?.type === runType && nodeBefore.content.size > 0) {
58190
+ const prevPos = selection.from - 1;
58191
+ if (prevPos >= 0) {
58192
+ tr.setSelection(superEditor_converter.TextSelection.create(tr.doc, prevPos));
58193
+ }
58194
+ }
58195
+ };
58143
58196
  const buildWrapTransaction = (state, ranges, runType, editor, markDefsFromMeta = []) => {
58144
58197
  if (!ranges.length) return null;
58145
58198
  const replacements = [];
@@ -58173,6 +58226,7 @@ const buildWrapTransaction = (state, ranges, runType, editor, markDefsFromMeta =
58173
58226
  if (!replacements.length) return null;
58174
58227
  const tr = state.tr;
58175
58228
  replacements.sort((a, b) => b.from - a.from).forEach(({ from: from3, to, runNode }) => tr.replaceWith(from3, to, runNode));
58229
+ normalizeSelectionIntoRun(tr, runType);
58176
58230
  return tr.docChanged ? tr : null;
58177
58231
  };
58178
58232
  const wrapTextInRunsPlugin = (editor) => {
@@ -73080,6 +73134,7 @@ const useToolbarItem = (options) => {
73080
73134
  const parentItem = vue.ref(null);
73081
73135
  const iconColor = vue.ref(options.iconColor);
73082
73136
  const hasCaret = vue.ref(options.hasCaret);
73137
+ const restoreEditorFocus = Boolean(options.restoreEditorFocus);
73083
73138
  const dropdownStyles = vue.ref(options.dropdownStyles);
73084
73139
  const tooltip = vue.ref(options.tooltip);
73085
73140
  const tooltipVisible = vue.ref(options.tooltipVisible);
@@ -73155,6 +73210,7 @@ const useToolbarItem = (options) => {
73155
73210
  hideLabel,
73156
73211
  inlineTextInputVisible,
73157
73212
  hasInlineTextInput,
73213
+ restoreEditorFocus,
73158
73214
  markName,
73159
73215
  labelAttr,
73160
73216
  childItem,
@@ -75468,6 +75524,7 @@ const makeDefaultItems = ({
75468
75524
  command: "toggleBulletList",
75469
75525
  icon: toolbarIcons2.bulletList,
75470
75526
  tooltip: toolbarTexts2.bulletList,
75527
+ restoreEditorFocus: true,
75471
75528
  attributes: {
75472
75529
  ariaLabel: "Bullet list"
75473
75530
  }
@@ -75478,6 +75535,7 @@ const makeDefaultItems = ({
75478
75535
  command: "toggleOrderedList",
75479
75536
  icon: toolbarIcons2.numberedList,
75480
75537
  tooltip: toolbarTexts2.numberedList,
75538
+ restoreEditorFocus: true,
75481
75539
  attributes: {
75482
75540
  ariaLabel: "Numbered list"
75483
75541
  }
@@ -86348,6 +86406,7 @@ class SuperToolbar extends eventemitter3.EventEmitter {
86348
86406
  selectionUpdate: null,
86349
86407
  focus: null
86350
86408
  };
86409
+ this._restoreFocusTimeoutId = null;
86351
86410
  if (!this.config.selector && this.config.element) {
86352
86411
  this.config.selector = this.config.element;
86353
86412
  }
@@ -87013,6 +87072,7 @@ class SuperToolbar extends eventemitter3.EventEmitter {
87013
87072
  const wasFocused = Boolean(typeof hasFocusFn === "function" && hasFocusFn.call(this.activeEditor.view));
87014
87073
  const { command: command2 } = item;
87015
87074
  const isMarkToggle = this.isMarkToggle(item);
87075
+ const shouldRestoreFocus = Boolean(item?.restoreEditorFocus);
87016
87076
  if (!wasFocused && isMarkToggle) {
87017
87077
  this.pendingMarkCommands.push({ command: command2, argument, item });
87018
87078
  item?.activate?.();
@@ -87043,6 +87103,13 @@ class SuperToolbar extends eventemitter3.EventEmitter {
87043
87103
  }
87044
87104
  if (isMarkToggle) this.#syncStickyMarksFromState();
87045
87105
  this.updateToolbarState();
87106
+ if (shouldRestoreFocus && this.activeEditor && !this.activeEditor.options.isHeaderOrFooter) {
87107
+ this._restoreFocusTimeoutId = setTimeout(() => {
87108
+ this._restoreFocusTimeoutId = null;
87109
+ if (!this.activeEditor || this.activeEditor.options.isHeaderOrFooter) return;
87110
+ this.activeEditor.focus();
87111
+ }, 0);
87112
+ }
87046
87113
  }
87047
87114
  /**
87048
87115
  * Processes and executes pending mark commands when editor selection updates.
@@ -87185,6 +87252,17 @@ class SuperToolbar extends eventemitter3.EventEmitter {
87185
87252
  const tr = state.tr.setStoredMarks([mark]);
87186
87253
  view.dispatch(tr);
87187
87254
  }
87255
+ /**
87256
+ * Cleans up resources when the toolbar is destroyed.
87257
+ * Clears any pending timeouts to prevent callbacks firing after unmount.
87258
+ * @returns {void}
87259
+ */
87260
+ destroy() {
87261
+ if (this._restoreFocusTimeoutId !== null) {
87262
+ clearTimeout(this._restoreFocusTimeoutId);
87263
+ this._restoreFocusTimeoutId = null;
87264
+ }
87265
+ }
87188
87266
  }
87189
87267
  const onMarginClickCursorChange = (event, editor) => {
87190
87268
  const y = event.clientY;