@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.
@@ -1,6 +1,6 @@
1
1
  import { B as Buffer$2 } from "./jszip-B1fkPkPJ.es.js";
2
2
  import { t as twipsToInches, i as inchesToTwips, p as ptToTwips, l as linesToTwips, a as twipsToLines, b as pixelsToTwips, h as halfPointToPoints, c as twipsToPixels$2, d as convertSizeToCSS, e as inchesToPixels } from "./helpers-C8e9wR5l.es.js";
3
- import { g as generateDocxRandomId, T as TextSelection$1, o as objectIncludes, w as wrapTextsInRuns, D as DOMParser$1, c as createDocFromMarkdown, a as createDocFromHTML, b as chainableEditorState, d as convertMarkdownToHTML, f as findParentNode, e as findParentNodeClosestToPos, h as generateRandom32BitHex, i as generateRandomSigned32BitIntStrId, P as PluginKey, j as Plugin, M as Mapping, N as NodeSelection, k as Selection, l as Slice, m as DOMSerializer, F as Fragment, n as Mark$1, p as dropPoint, A as AllSelection, q as Schema$1, s as canSplit, t as resolveRunProperties, u as encodeMarksFromRPr, v as liftTarget, x as canJoin, y as joinPoint, z as replaceStep$1, R as ReplaceAroundStep$1, B as htmlHandler, C as ReplaceStep, E as getResolvedParagraphProperties, G as changeListLevel, H as isList$1, I as updateNumberingProperties, L as ListHelpers, J as inputRulesPlugin, K as TrackDeleteMarkName$1, O as TrackInsertMarkName$1, Q as TrackFormatMarkName$1, U as AddMarkStep, V as RemoveMarkStep, W as CommandService, S as SuperConverter, X as EditorState, Y as unflattenListsInHtml, Z as SelectionRange, _ as Transform, $ as createOoxmlResolver, a0 as translator, a1 as translator$1, a2 as resolveDocxFontFamily, a3 as combineIndentProperties, a4 as _getReferencedTableStyles, a5 as decodeRPrFromMarks, a6 as calculateResolvedParagraphProperties, a7 as encodeCSSFromPPr, a8 as encodeCSSFromRPr, a9 as generateOrderedListIndex, aa as docxNumberingHelpers, ab as InputRule, ac as insertNewRelationship, ad as kebabCase$1, ae as getUnderlineCssString } from "./SuperConverter-z20LprsX.es.js";
3
+ import { g as generateDocxRandomId, T as TextSelection$1, o as objectIncludes, w as wrapTextsInRuns, D as DOMParser$1, c as createDocFromMarkdown, a as createDocFromHTML, b as chainableEditorState, d as convertMarkdownToHTML, f as findParentNode, e as findParentNodeClosestToPos, h as generateRandom32BitHex, i as generateRandomSigned32BitIntStrId, P as PluginKey, j as Plugin, M as Mapping, N as NodeSelection, k as Selection, l as Slice, m as DOMSerializer, F as Fragment, n as Mark$1, p as dropPoint, A as AllSelection, q as Schema$1, s as canSplit, t as resolveRunProperties, u as encodeMarksFromRPr, v as liftTarget, x as canJoin, y as joinPoint, z as replaceStep$1, R as ReplaceAroundStep$1, B as htmlHandler, C as ReplaceStep, E as getResolvedParagraphProperties, G as changeListLevel, H as isList$1, I as updateNumberingProperties, L as ListHelpers, J as inputRulesPlugin, K as TrackDeleteMarkName$1, O as TrackInsertMarkName$1, Q as TrackFormatMarkName$1, U as AddMarkStep, V as RemoveMarkStep, W as CommandService, S as SuperConverter, X as EditorState, Y as unflattenListsInHtml, Z as SelectionRange, _ as Transform, $ as createOoxmlResolver, a0 as translator, a1 as translator$1, a2 as resolveDocxFontFamily, a3 as combineIndentProperties, a4 as _getReferencedTableStyles, a5 as decodeRPrFromMarks, a6 as calculateResolvedParagraphProperties, a7 as encodeCSSFromPPr, a8 as encodeCSSFromRPr, a9 as generateOrderedListIndex, aa as docxNumberingHelpers, ab as InputRule, ac as insertNewRelationship, ad as kebabCase$1, ae as getUnderlineCssString } from "./SuperConverter-BE5tNyQz.es.js";
4
4
  import { p as process$1, r as ref, C as global$1, c as computed, E as createElementBlock, F as Fragment$1, S as renderList, O as withModifiers, G as openBlock, P as normalizeClass, M as createCommentVNode, H as toDisplayString, K as createBaseVNode, U as createApp, f as onMounted, X as onUnmounted, R as withDirectives, v as unref, Y as vModelText, y as nextTick, L as normalizeStyle, u as watch, Z as withKeys, _ as createTextVNode, I as createVNode, h, $ as readonly, s as getCurrentInstance, o as onBeforeUnmount, j as reactive, b as onBeforeMount, i as inject, a0 as onActivated, a1 as onDeactivated, a2 as Comment, d as defineComponent, a as provide, g as Teleport, t as toRef, a3 as renderSlot, a4 as isVNode, D as shallowRef, w as watchEffect, T as Transition, a5 as mergeProps, a6 as vShow, a7 as cloneVNode, a8 as Text$2, m as markRaw, N as createBlock, J as withCtx, a9 as useCssVars, V as resolveDynamicComponent, aa as normalizeProps, ab as guardReactiveProps } from "./vue-BnBKJwCW.es.js";
5
5
  import "./jszip.min-DCl8qkFO.es.js";
6
6
  import { E as EventEmitter$1 } from "./eventemitter3-CwrdEv8r.es.js";
@@ -15434,7 +15434,7 @@ const canUseDOM = () => {
15434
15434
  return false;
15435
15435
  }
15436
15436
  };
15437
- const summaryVersion = "1.3.0";
15437
+ const summaryVersion = "1.3.1-next.2";
15438
15438
  const nodeKeys = ["group", "content", "marks", "inline", "atom", "defining", "code", "tableRole", "summary"];
15439
15439
  const markKeys = ["group", "inclusive", "excludes", "spanning", "code"];
15440
15440
  function mapAttributes(attrs) {
@@ -18066,7 +18066,7 @@ class Editor extends EventEmitter {
18066
18066
  * Process collaboration migrations
18067
18067
  */
18068
18068
  processCollaborationMigrations() {
18069
- console.debug("[checkVersionMigrations] Current editor version", "1.3.0");
18069
+ console.debug("[checkVersionMigrations] Current editor version", "1.3.1-next.2");
18070
18070
  if (!this.options.ydoc) return;
18071
18071
  const metaMap = this.options.ydoc.getMap("meta");
18072
18072
  let docVersion = metaMap.get("version");
@@ -24929,7 +24929,7 @@ function isMinimalWordLayout(value) {
24929
24929
  return true;
24930
24930
  }
24931
24931
  const LIST_MARKER_GAP$2 = 8;
24932
- const DEFAULT_TAB_INTERVAL_PX$2 = 48;
24932
+ const DEFAULT_TAB_INTERVAL_PX$1 = 48;
24933
24933
  const DEFAULT_PAGE_HEIGHT_PX = 1056;
24934
24934
  const DEFAULT_VIRTUALIZED_PAGE_GAP$1 = 72;
24935
24935
  const COMMENT_EXTERNAL_COLOR = "#B1124B";
@@ -25080,6 +25080,7 @@ class DomPainter {
25080
25080
  this.layoutVersion = 0;
25081
25081
  this.layoutEpoch = 0;
25082
25082
  this.processedLayoutVersion = -1;
25083
+ this.currentMapping = null;
25083
25084
  this.onScrollHandler = null;
25084
25085
  this.onWindowScrollHandler = null;
25085
25086
  this.onResizeHandler = null;
@@ -25185,7 +25186,7 @@ class DomPainter {
25185
25186
  this.blockLookup = nextLookup;
25186
25187
  this.changedBlocks = changed;
25187
25188
  }
25188
- paint(layout, mount2) {
25189
+ paint(layout, mount2, mapping) {
25189
25190
  if (!(mount2 instanceof HTMLElement)) {
25190
25191
  throw new Error("DomPainter.paint requires a valid HTMLElement mount");
25191
25192
  }
@@ -25194,6 +25195,13 @@ class DomPainter {
25194
25195
  throw new Error("DomPainter.paint requires a DOM-like document");
25195
25196
  }
25196
25197
  this.doc = doc2;
25198
+ const isSimpleTransaction = mapping && mapping.maps.length === 1;
25199
+ if (mapping && !isSimpleTransaction) {
25200
+ this.blockLookup.forEach((_, id) => this.changedBlocks.add(id));
25201
+ this.currentMapping = null;
25202
+ } else {
25203
+ this.currentMapping = mapping ?? null;
25204
+ }
25197
25205
  ensurePrintStyles(doc2);
25198
25206
  ensureLinkStyles(doc2);
25199
25207
  ensureTrackChangeStyles(doc2);
@@ -25220,6 +25228,7 @@ class DomPainter {
25220
25228
  this.currentLayout = layout;
25221
25229
  this.pageStates = [];
25222
25230
  this.changedBlocks.clear();
25231
+ this.currentMapping = null;
25223
25232
  return;
25224
25233
  }
25225
25234
  if (mode === "book") {
@@ -25228,6 +25237,7 @@ class DomPainter {
25228
25237
  this.currentLayout = layout;
25229
25238
  this.pageStates = [];
25230
25239
  this.changedBlocks.clear();
25240
+ this.currentMapping = null;
25231
25241
  return;
25232
25242
  }
25233
25243
  applyStyles$2(mount2, containerStyles);
@@ -25236,6 +25246,7 @@ class DomPainter {
25236
25246
  this.renderVirtualized(layout, mount2);
25237
25247
  this.currentLayout = layout;
25238
25248
  this.changedBlocks.clear();
25249
+ this.currentMapping = null;
25239
25250
  return;
25240
25251
  }
25241
25252
  mount2.style.gap = `${this.pageGap}px`;
@@ -25246,6 +25257,7 @@ class DomPainter {
25246
25257
  }
25247
25258
  this.currentLayout = layout;
25248
25259
  this.changedBlocks.clear();
25260
+ this.currentMapping = null;
25249
25261
  }
25250
25262
  // ----------------
25251
25263
  // Virtualized path
@@ -25777,6 +25789,8 @@ class DomPainter {
25777
25789
  pageEl.replaceChild(replacement, current.element);
25778
25790
  current.element = replacement;
25779
25791
  current.signature = fragmentSignature(fragment, this.blockLookup);
25792
+ } else if (this.currentMapping) {
25793
+ this.updatePositionAttributes(current.element, this.currentMapping);
25780
25794
  }
25781
25795
  this.updateFragmentElement(current.element, fragment, contextBase.section);
25782
25796
  current.fragment = fragment;
@@ -25805,6 +25819,45 @@ class DomPainter {
25805
25819
  state.fragments = nextFragments;
25806
25820
  this.renderDecorationsForPage(pageEl, page);
25807
25821
  }
25822
+ /**
25823
+ * Updates data-pm-start/data-pm-end attributes on all elements within a fragment
25824
+ * using the transaction's mapping. Skips header/footer content (separate PM coordinate space).
25825
+ * Also skips fragments that end before the edit point (their positions don't change).
25826
+ */
25827
+ updatePositionAttributes(fragmentEl, mapping) {
25828
+ if (fragmentEl.closest(".superdoc-page-header, .superdoc-page-footer")) {
25829
+ return;
25830
+ }
25831
+ try {
25832
+ const fragEnd = fragmentEl.dataset.pmEnd;
25833
+ if (fragEnd !== void 0 && fragEnd !== "") {
25834
+ const endNum = Number(fragEnd);
25835
+ if (Number.isFinite(endNum) && mapping.map(endNum, -1) === endNum) {
25836
+ return;
25837
+ }
25838
+ }
25839
+ const elements = fragmentEl.querySelectorAll("[data-pm-start], [data-pm-end]");
25840
+ const allElements = [fragmentEl, ...Array.from(elements)];
25841
+ for (const el of allElements) {
25842
+ const oldStart = el.dataset.pmStart;
25843
+ const oldEnd = el.dataset.pmEnd;
25844
+ if (oldStart !== void 0 && oldStart !== "") {
25845
+ const num = Number(oldStart);
25846
+ if (Number.isFinite(num)) {
25847
+ el.dataset.pmStart = String(mapping.map(num));
25848
+ }
25849
+ }
25850
+ if (oldEnd !== void 0 && oldEnd !== "") {
25851
+ const num = Number(oldEnd);
25852
+ if (Number.isFinite(num)) {
25853
+ el.dataset.pmEnd = String(mapping.map(num, -1));
25854
+ }
25855
+ }
25856
+ }
25857
+ } catch (error) {
25858
+ console.error("Error updating position attributes with mapping:", error);
25859
+ }
25860
+ }
25808
25861
  createPageState(page, pageSize) {
25809
25862
  if (!this.doc) {
25810
25863
  throw new Error("DomPainter.createPageState requires a document");
@@ -25963,7 +26016,7 @@ class DomPainter {
25963
26016
  const textStart = paraIndentLeft + firstLine;
25964
26017
  tabWidth = textStart - currentPos;
25965
26018
  if (tabWidth <= 0) {
25966
- tabWidth = DEFAULT_TAB_INTERVAL_PX$2 - currentPos % DEFAULT_TAB_INTERVAL_PX$2;
26019
+ tabWidth = DEFAULT_TAB_INTERVAL_PX$1 - currentPos % DEFAULT_TAB_INTERVAL_PX$1;
25967
26020
  } else if (tabWidth < LIST_MARKER_GAP$2) {
25968
26021
  tabWidth = LIST_MARKER_GAP$2;
25969
26022
  }
@@ -26115,7 +26168,7 @@ class DomPainter {
26115
26168
  const textStart = paraIndentLeft + firstLine;
26116
26169
  tabWidth = textStart - currentPos;
26117
26170
  if (tabWidth <= 0) {
26118
- tabWidth = DEFAULT_TAB_INTERVAL_PX$2 - currentPos % DEFAULT_TAB_INTERVAL_PX$2;
26171
+ tabWidth = DEFAULT_TAB_INTERVAL_PX$1 - currentPos % DEFAULT_TAB_INTERVAL_PX$1;
26119
26172
  } else if (tabWidth < LIST_MARKER_GAP$2) {
26120
26173
  tabWidth = LIST_MARKER_GAP$2;
26121
26174
  }
@@ -27463,6 +27516,13 @@ class DomPainter {
27463
27516
  const trackedConfig = this.resolveTrackedChangesConfig(block);
27464
27517
  if (runsForLine.length === 0) {
27465
27518
  const span = this.doc.createElement("span");
27519
+ span.classList.add("superdoc-empty-run");
27520
+ if (lineRange.pmStart != null) {
27521
+ span.dataset.pmStart = String(lineRange.pmStart);
27522
+ }
27523
+ if (lineRange.pmEnd != null) {
27524
+ span.dataset.pmEnd = String(lineRange.pmEnd);
27525
+ }
27466
27526
  span.innerHTML = "&nbsp;";
27467
27527
  el.appendChild(span);
27468
27528
  }
@@ -28175,8 +28235,6 @@ const fragmentSignature = (fragment, lookup) => {
28175
28235
  base2,
28176
28236
  fragment.fromLine,
28177
28237
  fragment.toLine,
28178
- fragment.pmStart ?? "",
28179
- fragment.pmEnd ?? "",
28180
28238
  fragment.continuesFromPrev ? 1 : 0,
28181
28239
  fragment.continuesOnNext ? 1 : 0,
28182
28240
  fragment.markerWidth ?? ""
@@ -28268,16 +28326,15 @@ const deriveBlockVersion = (block) => {
28268
28326
  imgRun.distTop ?? "",
28269
28327
  imgRun.distBottom ?? "",
28270
28328
  imgRun.distLeft ?? "",
28271
- imgRun.distRight ?? "",
28272
- imgRun.pmStart ?? "",
28273
- imgRun.pmEnd ?? ""
28329
+ imgRun.distRight ?? ""
28330
+ // Note: pmStart/pmEnd intentionally excluded to prevent O(n) change detection
28274
28331
  ].join(",");
28275
28332
  }
28276
28333
  if (run.kind === "lineBreak") {
28277
- return ["linebreak", run.pmStart ?? "", run.pmEnd ?? ""].join(",");
28334
+ return "linebreak";
28278
28335
  }
28279
28336
  if (run.kind === "tab") {
28280
- return [run.text ?? "", "tab", run.pmStart ?? "", run.pmEnd ?? ""].join(",");
28337
+ return [run.text ?? "", "tab"].join(",");
28281
28338
  }
28282
28339
  const textRun = run;
28283
28340
  return [
@@ -28293,8 +28350,7 @@ const deriveBlockVersion = (block) => {
28293
28350
  textRun.strike ? 1 : 0,
28294
28351
  textRun.highlight ?? "",
28295
28352
  textRun.letterSpacing != null ? textRun.letterSpacing : "",
28296
- textRun.pmStart ?? "",
28297
- textRun.pmEnd ?? "",
28353
+ // Note: pmStart/pmEnd intentionally excluded to prevent O(n) change detection
28298
28354
  textRun.token ?? "",
28299
28355
  // Tracked changes - force re-render when added or removed tracked change
28300
28356
  textRun.trackedChange ? 1 : 0,
@@ -28753,8 +28809,8 @@ const createDomPainter = (options) => {
28753
28809
  ruler: options.ruler
28754
28810
  });
28755
28811
  return {
28756
- paint(layout, mount2) {
28757
- painter.paint(layout, mount2);
28812
+ paint(layout, mount2, mapping) {
28813
+ painter.paint(layout, mount2, mapping);
28758
28814
  },
28759
28815
  setData(blocks, measures, headerBlocks, headerMeasures, footerBlocks, footerMeasures) {
28760
28816
  painter.setData(blocks, measures, headerBlocks, headerMeasures, footerBlocks, footerMeasures);
@@ -30709,7 +30765,6 @@ const DEFAULT_LIST_INDENT_BASE_PX = 24;
30709
30765
  const DEFAULT_LIST_INDENT_STEP_PX = 24;
30710
30766
  const DEFAULT_LIST_HANGING_PX$1 = 18;
30711
30767
  const SPACE_SUFFIX_GAP_PX = 4;
30712
- const DEFAULT_TAB_INTERVAL_PX$1 = 48;
30713
30768
  function resolveListTextStartPx(wordLayout, indentLeft, firstLine, hanging, measureMarkerText) {
30714
30769
  const marker = wordLayout?.marker;
30715
30770
  if (!marker) {
@@ -30743,9 +30798,13 @@ function resolveListTextStartPx(wordLayout, indentLeft, firstLine, hanging, meas
30743
30798
  return markerStartPos + finalMarkerTextWidth;
30744
30799
  }
30745
30800
  const markerJustification = marker.justification ?? "left";
30801
+ const markerWidthEffective = Math.max(
30802
+ typeof marker.markerBoxWidthPx === "number" && Number.isFinite(marker.markerBoxWidthPx) ? marker.markerBoxWidthPx : 0,
30803
+ finalMarkerTextWidth
30804
+ );
30746
30805
  if (markerJustification !== "left") {
30747
- const gutterWidth = typeof marker.gutterWidthPx === "number" && Number.isFinite(marker.gutterWidthPx) && marker.gutterWidthPx > 0 ? marker.gutterWidthPx : LIST_MARKER_GAP$1;
30748
- return markerStartPos + finalMarkerTextWidth + Math.max(gutterWidth, LIST_MARKER_GAP$1);
30806
+ const gutterWidth2 = typeof marker.gutterWidthPx === "number" && Number.isFinite(marker.gutterWidthPx) && marker.gutterWidthPx > 0 ? marker.gutterWidthPx : LIST_MARKER_GAP$1;
30807
+ return markerStartPos + finalMarkerTextWidth + Math.max(gutterWidth2, LIST_MARKER_GAP$1);
30749
30808
  }
30750
30809
  if (wordLayout?.firstLineIndentMode === true) {
30751
30810
  let targetTabStop;
@@ -30757,12 +30816,12 @@ function resolveListTextStartPx(wordLayout, indentLeft, firstLine, hanging, meas
30757
30816
  }
30758
30817
  }
30759
30818
  }
30760
- const textStartTarget = typeof marker.textStartX === "number" && Number.isFinite(marker.textStartX) ? marker.textStartX : wordLayout.textStartPx;
30819
+ const textStartTarget2 = typeof marker.textStartX === "number" && Number.isFinite(marker.textStartX) ? marker.textStartX : wordLayout.textStartPx;
30761
30820
  let tabWidth2;
30762
30821
  if (targetTabStop !== void 0) {
30763
30822
  tabWidth2 = targetTabStop - currentPos;
30764
- } else if (textStartTarget !== void 0 && Number.isFinite(textStartTarget) && textStartTarget > currentPos) {
30765
- tabWidth2 = textStartTarget - currentPos;
30823
+ } else if (textStartTarget2 !== void 0 && Number.isFinite(textStartTarget2) && textStartTarget2 > currentPos) {
30824
+ tabWidth2 = textStartTarget2 - currentPos;
30766
30825
  } else {
30767
30826
  tabWidth2 = LIST_MARKER_GAP$1;
30768
30827
  }
@@ -30771,14 +30830,21 @@ function resolveListTextStartPx(wordLayout, indentLeft, firstLine, hanging, meas
30771
30830
  }
30772
30831
  return markerStartPos + finalMarkerTextWidth + tabWidth2;
30773
30832
  }
30833
+ const textStartTarget = typeof wordLayout?.textStartPx === "number" && Number.isFinite(wordLayout.textStartPx) ? wordLayout.textStartPx : void 0;
30834
+ const gutterWidth = typeof marker.gutterWidthPx === "number" && Number.isFinite(marker.gutterWidthPx) && marker.gutterWidthPx > 0 ? marker.gutterWidthPx : LIST_MARKER_GAP$1;
30835
+ const currentPosStandard = markerStartPos + markerWidthEffective;
30836
+ if (textStartTarget !== void 0) {
30837
+ const gap = Math.max(textStartTarget - currentPosStandard, gutterWidth);
30838
+ return currentPosStandard + gap;
30839
+ }
30774
30840
  const textStart = indentLeft + firstLine;
30775
- let tabWidth = textStart - currentPos;
30841
+ let tabWidth = textStart - currentPosStandard;
30776
30842
  if (tabWidth <= 0) {
30777
- tabWidth = DEFAULT_TAB_INTERVAL_PX$1 - currentPos % DEFAULT_TAB_INTERVAL_PX$1;
30843
+ tabWidth = gutterWidth;
30778
30844
  } else if (tabWidth < LIST_MARKER_GAP$1) {
30779
- tabWidth = LIST_MARKER_GAP$1;
30845
+ tabWidth = Math.max(tabWidth, gutterWidth);
30780
30846
  }
30781
- return markerStartPos + finalMarkerTextWidth + tabWidth;
30847
+ return currentPosStandard + tabWidth;
30782
30848
  }
30783
30849
  function getWordLayoutConfig(block) {
30784
30850
  if (!block || block.kind !== "paragraph") {
@@ -30807,21 +30873,45 @@ function isListItem(markerWidth, block) {
30807
30873
  return hasHangingIndentPattern;
30808
30874
  }
30809
30875
  function calculateTextStartIndent(params2) {
30810
- const { isFirstLine, isListItem: isListItem2, markerWidth, paraIndentLeft, firstLineIndent, hangingIndent, wordLayout } = params2;
30876
+ const {
30877
+ isFirstLine,
30878
+ isListItem: isListItem2,
30879
+ markerWidth,
30880
+ markerTextWidth,
30881
+ paraIndentLeft,
30882
+ firstLineIndent,
30883
+ hangingIndent,
30884
+ wordLayout
30885
+ } = params2;
30811
30886
  const firstLineOffset = firstLineIndent - hangingIndent;
30812
- const isFirstLineIndentMode = wordLayout?.firstLineIndentMode === true;
30887
+ const effectiveMarkerTextWidth = typeof markerTextWidth === "number" && Number.isFinite(markerTextWidth) && markerTextWidth > 0 ? markerTextWidth : markerWidth;
30813
30888
  let indentAdjust = paraIndentLeft;
30814
- if (isListItem2 && isFirstLine && isFirstLineIndentMode) {
30889
+ if (isListItem2 && isFirstLine) {
30815
30890
  const resolvedTextStart = resolveListTextStartPx(
30816
30891
  wordLayout,
30817
30892
  paraIndentLeft,
30818
30893
  Math.max(firstLineIndent, 0),
30819
30894
  Math.max(hangingIndent, 0),
30820
- () => markerWidth
30821
- // Use provided markerWidth since we don't have canvas access here
30895
+ () => effectiveMarkerTextWidth
30896
+ // Use measured marker text width when available
30822
30897
  );
30823
- const textStartFallback = paraIndentLeft + Math.max(firstLineIndent, 0) + markerWidth;
30824
- indentAdjust = typeof resolvedTextStart === "number" && Number.isFinite(resolvedTextStart) ? resolvedTextStart : textStartFallback;
30898
+ if (typeof resolvedTextStart === "number" && Number.isFinite(resolvedTextStart)) {
30899
+ indentAdjust = resolvedTextStart;
30900
+ } else {
30901
+ const explicitTextStart = wordLayout?.marker?.textStartX ?? wordLayout?.textStartPx;
30902
+ const isStandardHangingList = hangingIndent > 0 && wordLayout?.firstLineIndentMode !== true;
30903
+ const textStartLooksValid = typeof explicitTextStart === "number" && Number.isFinite(explicitTextStart) && (!isStandardHangingList || explicitTextStart > paraIndentLeft);
30904
+ if (textStartLooksValid) {
30905
+ indentAdjust = explicitTextStart;
30906
+ } else if (wordLayout?.firstLineIndentMode === true) {
30907
+ indentAdjust = paraIndentLeft + Math.max(firstLineIndent, 0) + markerWidth;
30908
+ } else if (isStandardHangingList && effectiveMarkerTextWidth > 0) {
30909
+ const markerStartPos = Math.max(0, paraIndentLeft - hangingIndent + firstLineIndent);
30910
+ const gutterWidthCandidate = wordLayout?.gutterWidthPx;
30911
+ const gutterWidth = typeof gutterWidthCandidate === "number" && Number.isFinite(gutterWidthCandidate) ? gutterWidthCandidate : wordLayout?.marker?.gutterWidthPx ?? LIST_MARKER_GAP$1;
30912
+ indentAdjust = markerStartPos + effectiveMarkerTextWidth + gutterWidth;
30913
+ }
30914
+ }
30825
30915
  } else if (isFirstLine && !isListItem2) {
30826
30916
  indentAdjust += firstLineOffset;
30827
30917
  }
@@ -31672,12 +31762,16 @@ function layoutParagraphBlock(ctx2, anchors) {
31672
31762
  const negativeRightIndent = indentRight < 0 ? indentRight : 0;
31673
31763
  const remeasureWidth = Math.max(1, columnWidth - indentLeft - indentRight);
31674
31764
  let didRemeasureForColumnWidth = false;
31765
+ let remeasuredMarkerInfo;
31675
31766
  if (typeof remeasureParagraph2 === "function" && typeof measurementWidth === "number" && measurementWidth > remeasureWidth) {
31676
31767
  const firstLineIndent = calculateFirstLineIndent(block, measure);
31677
31768
  const newMeasure = remeasureParagraph2(block, columnWidth, firstLineIndent);
31678
31769
  const newLines = normalizeLines(newMeasure);
31679
31770
  lines = newLines;
31680
31771
  didRemeasureForColumnWidth = true;
31772
+ if (newMeasure.marker) {
31773
+ remeasuredMarkerInfo = newMeasure.marker;
31774
+ }
31681
31775
  }
31682
31776
  let fromLine = 0;
31683
31777
  const attrs = getParagraphAttrs(block);
@@ -31716,10 +31810,12 @@ function layoutParagraphBlock(ctx2, anchors) {
31716
31810
  width: fragmentWidth,
31717
31811
  ...computeFragmentPmRange(block, lines, 0, lines.length)
31718
31812
  };
31719
- if (measure.marker) {
31720
- fragment.markerWidth = measure.marker.markerWidth;
31721
- if (measure.marker.markerTextWidth != null) {
31722
- fragment.markerTextWidth = measure.marker.markerTextWidth;
31813
+ if (measure.marker || remeasuredMarkerInfo) {
31814
+ const effectiveMarkerInfo = remeasuredMarkerInfo ?? measure.marker;
31815
+ fragment.markerWidth = effectiveMarkerInfo?.markerWidth ?? measure.marker?.markerWidth ?? 0;
31816
+ const markerTextWidth = remeasuredMarkerInfo?.markerTextWidth ?? measure.marker?.markerTextWidth;
31817
+ if (markerTextWidth != null) {
31818
+ fragment.markerTextWidth = markerTextWidth;
31723
31819
  }
31724
31820
  }
31725
31821
  state.page.fragments.push(fragment);
@@ -31761,6 +31857,9 @@ function layoutParagraphBlock(ctx2, anchors) {
31761
31857
  const newLines = normalizeLines(newMeasure);
31762
31858
  lines = newLines;
31763
31859
  didRemeasureForFloats = true;
31860
+ if (newMeasure.marker) {
31861
+ remeasuredMarkerInfo = newMeasure.marker;
31862
+ }
31764
31863
  }
31765
31864
  }
31766
31865
  while (fromLine < lines.length) {
@@ -31832,13 +31931,16 @@ function layoutParagraphBlock(ctx2, anchors) {
31832
31931
  if (didRemeasureForColumnWidth) {
31833
31932
  fragment.lines = lines.slice(fromLine, slice2.toLine);
31834
31933
  }
31835
- if (measure.marker && fromLine === 0) {
31836
- fragment.markerWidth = measure.marker.markerWidth;
31837
- if (measure.marker.markerTextWidth != null) {
31838
- fragment.markerTextWidth = measure.marker.markerTextWidth;
31934
+ if ((measure.marker || remeasuredMarkerInfo) && fromLine === 0) {
31935
+ const effectiveMarkerInfo = remeasuredMarkerInfo ?? measure.marker;
31936
+ fragment.markerWidth = effectiveMarkerInfo?.markerWidth ?? measure.marker?.markerWidth ?? 0;
31937
+ const markerTextWidth = remeasuredMarkerInfo?.markerTextWidth ?? measure.marker?.markerTextWidth;
31938
+ if (markerTextWidth != null) {
31939
+ fragment.markerTextWidth = markerTextWidth;
31839
31940
  }
31840
- if (measure.kind === "paragraph" && measure.marker?.gutterWidth != null) {
31841
- fragment.markerGutter = measure.marker.gutterWidth;
31941
+ const gutterWidth = remeasuredMarkerInfo?.gutterWidth ?? measure.marker?.gutterWidth;
31942
+ if (gutterWidth != null) {
31943
+ fragment.markerGutter = gutterWidth;
31842
31944
  }
31843
31945
  }
31844
31946
  if (fromLine > 0) fragment.continuesFromPrev = true;
@@ -35279,16 +35381,19 @@ function remeasureParagraph(block, maxWidth, firstLineIndent = 0) {
35279
35381
  const contentWidth = Math.max(1, maxWidth - indentLeft - indentRight);
35280
35382
  const markerTextStartX = wordLayout?.marker?.textStartX;
35281
35383
  const textStartPx = typeof markerTextStartX === "number" && Number.isFinite(markerTextStartX) ? markerTextStartX : typeof wordLayout?.textStartPx === "number" && Number.isFinite(wordLayout.textStartPx) ? wordLayout.textStartPx : void 0;
35384
+ let measuredMarkerTextWidth;
35282
35385
  const resolvedTextStartPx = resolveListTextStartPx(
35283
35386
  wordLayout,
35284
35387
  indentLeft,
35285
35388
  indentFirstLine,
35286
35389
  indentHanging,
35287
- (markerText, marker) => {
35390
+ (markerText, marker2) => {
35288
35391
  const context = getCtx();
35289
35392
  if (!context) return 0;
35290
- context.font = markerFontString(marker.run);
35291
- return context.measureText(markerText).width;
35393
+ context.font = markerFontString(marker2.run);
35394
+ const width = context.measureText(markerText).width;
35395
+ measuredMarkerTextWidth = width;
35396
+ return width;
35292
35397
  }
35293
35398
  );
35294
35399
  const effectiveTextStartPx = resolvedTextStartPx ?? textStartPx;
@@ -35379,7 +35484,14 @@ function remeasureParagraph(block, maxWidth, firstLineIndent = 0) {
35379
35484
  }
35380
35485
  }
35381
35486
  const totalHeight = lines.reduce((s2, l) => s2 + l.lineHeight, 0);
35382
- return { kind: "paragraph", lines, totalHeight };
35487
+ const marker = wordLayout?.marker;
35488
+ const markerInfo = marker ? {
35489
+ markerWidth: marker.markerBoxWidthPx ?? indentHanging ?? 0,
35490
+ markerTextWidth: measuredMarkerTextWidth ?? 0,
35491
+ indentLeft,
35492
+ gutterWidth: marker.gutterWidthPx
35493
+ } : void 0;
35494
+ return { kind: "paragraph", lines, totalHeight, marker: markerInfo };
35383
35495
  }
35384
35496
  function hasComments(run) {
35385
35497
  return "comments" in run && Array.isArray(run.comments) && run.comments.length > 0;
@@ -37430,6 +37542,7 @@ function selectionToRects(layout, blocks, measures, from3, to, geometryHelper) {
37430
37542
  isFirstLine,
37431
37543
  isListItem: isListItemFlag,
37432
37544
  markerWidth,
37545
+ markerTextWidth: fragment.markerTextWidth ?? measure.marker?.markerTextWidth ?? void 0,
37433
37546
  paraIndentLeft: indent.left,
37434
37547
  firstLineIndent: indent.firstLine,
37435
37548
  hangingIndent: indent.hanging,
@@ -37567,6 +37680,7 @@ function selectionToRects(layout, blocks, measures, from3, to, geometryHelper) {
37567
37680
  isFirstLine,
37568
37681
  isListItem: cellIsListItem,
37569
37682
  markerWidth: paragraphMarkerWidth,
37683
+ markerTextWidth: info.measure?.marker?.markerTextWidth ?? void 0,
37570
37684
  paraIndentLeft: cellIndent.left,
37571
37685
  firstLineIndent: cellIndent.firstLine,
37572
37686
  hangingIndent: cellIndent.hanging,
@@ -37818,25 +37932,36 @@ const mapPointToPm = (block, line, x, isRTL, availableWidthOverride, alignmentOv
37818
37932
  const range = computeLinePmRange(block, line);
37819
37933
  if (range.pmStart == null || range.pmEnd == null) return null;
37820
37934
  const result = findCharacterAtX(block, line, x, range.pmStart, availableWidthOverride, alignmentOverride);
37935
+ let pmPosition = result.pmPosition;
37821
37936
  if (isRTL) {
37822
37937
  const charOffset = result.charOffset;
37823
37938
  const charsInLine = Math.max(1, line.toChar - line.fromChar);
37824
37939
  const reversedOffset = Math.max(0, Math.min(charsInLine, charsInLine - charOffset));
37825
- return charOffsetToPm(block, line, reversedOffset, range.pmStart);
37940
+ pmPosition = charOffsetToPm(block, line, reversedOffset, range.pmStart);
37826
37941
  }
37827
- return result.pmPosition;
37942
+ return pmPosition;
37828
37943
  };
37829
37944
  const mapPmToX = (block, line, offset2, fragmentWidth, alignmentOverride) => {
37830
37945
  if (fragmentWidth <= 0 || line.width <= 0) return 0;
37831
37946
  let paraIndentLeft = 0;
37832
37947
  let paraIndentRight = 0;
37948
+ let effectiveLeft = 0;
37833
37949
  if (block.kind === "paragraph") {
37834
37950
  const indentLeft = typeof block.attrs?.indent?.left === "number" ? block.attrs.indent.left : 0;
37835
37951
  const indentRight = typeof block.attrs?.indent?.right === "number" ? block.attrs.indent.right : 0;
37836
37952
  paraIndentLeft = Number.isFinite(indentLeft) ? indentLeft : 0;
37837
37953
  paraIndentRight = Number.isFinite(indentRight) ? indentRight : 0;
37954
+ effectiveLeft = paraIndentLeft;
37955
+ const wl = getWordLayoutConfig(block);
37956
+ const isListParagraph = Boolean(block.attrs?.numberingProperties) || Boolean(wl?.marker);
37957
+ if (isListParagraph) {
37958
+ 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;
37959
+ if (typeof explicitTextStart === "number" && explicitTextStart > paraIndentLeft) {
37960
+ effectiveLeft = explicitTextStart;
37961
+ }
37962
+ }
37838
37963
  }
37839
- const totalIndent = paraIndentLeft + paraIndentRight;
37964
+ const totalIndent = effectiveLeft + paraIndentRight;
37840
37965
  const availableWidth = Math.max(0, fragmentWidth - totalIndent);
37841
37966
  if (totalIndent > fragmentWidth) {
37842
37967
  console.warn(
@@ -39174,16 +39299,26 @@ function lineHeightBeforeIndex(lines, fromLine, targetIndex) {
39174
39299
  }
39175
39300
  function computeCaretLayoutRectGeometry({ layout, blocks, measures, painterHost, viewportHost, visibleHost, zoom }, pos, includeDomFallback = true) {
39176
39301
  if (!layout) return null;
39177
- const hit = getFragmentAtPosition(layout, blocks, measures, pos);
39302
+ let effectivePos = pos;
39303
+ let hit = getFragmentAtPosition(layout, blocks, measures, pos);
39178
39304
  if (!hit) {
39179
- return null;
39305
+ const fallbackCandidates = [pos - 1, pos + 1, pos - 2, pos + 2].filter((candidate) => candidate >= 0);
39306
+ for (const candidate of fallbackCandidates) {
39307
+ const fallbackHit = getFragmentAtPosition(layout, blocks, measures, candidate);
39308
+ if (fallbackHit) {
39309
+ hit = fallbackHit;
39310
+ effectivePos = candidate;
39311
+ break;
39312
+ }
39313
+ }
39314
+ if (!hit) return null;
39180
39315
  }
39181
39316
  const block = hit.block;
39182
39317
  const measure = hit.measure;
39183
39318
  if (hit.fragment.kind === "table" && block?.kind === "table" && measure?.kind === "table") {
39184
39319
  return computeTableCaretLayoutRectFromDom(
39185
39320
  { viewportHost, visibleHost, zoom },
39186
- pos,
39321
+ effectivePos,
39187
39322
  hit.fragment,
39188
39323
  block,
39189
39324
  measure,
@@ -39191,92 +39326,32 @@ function computeCaretLayoutRectGeometry({ layout, blocks, measures, painterHost,
39191
39326
  );
39192
39327
  }
39193
39328
  if (!block || block.kind !== "paragraph" || measure?.kind !== "paragraph") return null;
39194
- if (hit.fragment.kind !== "para") {
39195
- return null;
39196
- }
39329
+ if (hit.fragment.kind !== "para") return null;
39197
39330
  const fragment = hit.fragment;
39198
- const lineInfo = findLineContainingPos(block, measure, fragment.fromLine, fragment.toLine, pos);
39199
- if (!lineInfo) {
39200
- return null;
39201
- }
39331
+ const lineInfo = findLineContainingPos(block, measure, fragment.fromLine, fragment.toLine, effectivePos);
39332
+ if (!lineInfo) return null;
39202
39333
  const { line, index: index2 } = lineInfo;
39203
39334
  const range = computeLinePmRange(block, line);
39204
39335
  if (range.pmStart == null || range.pmEnd == null) return null;
39205
- const pmOffset = pmPosToCharOffset(block, line, pos);
39336
+ const pmOffset = pmPosToCharOffset(block, line, effectivePos);
39206
39337
  const markerWidth = fragment.markerWidth ?? measure.marker?.markerWidth ?? 0;
39207
- const indent = extractParagraphIndent(block.attrs?.indent);
39208
- const availableWidth = Math.max(0, fragment.width - (indent.left + indent.right));
39209
- const charX = measureCharacterX(block, line, pmOffset, availableWidth);
39338
+ const markerTextWidth = fragment.markerTextWidth ?? measure.marker?.markerTextWidth ?? void 0;
39210
39339
  const isFirstLine = index2 === fragment.fromLine;
39211
39340
  const isListItemFlag = isListItem(markerWidth, block);
39212
- const isListFirstLine = isFirstLine && !fragment.continuesFromPrev && isListItemFlag;
39213
39341
  const wordLayout = getWordLayoutConfig(block);
39214
- const isFirstLineIndentMode = wordLayout?.firstLineIndentMode === true;
39215
- if (isListFirstLine && isFirstLineIndentMode) {
39216
- const textStartPx = calculateTextStartIndent({
39217
- isFirstLine,
39218
- isListItem: isListItemFlag,
39219
- markerWidth,
39220
- paraIndentLeft: indent.left,
39221
- firstLineIndent: indent.firstLine,
39222
- hangingIndent: indent.hanging,
39223
- wordLayout
39224
- });
39225
- const localX2 = fragment.x + textStartPx + charX;
39226
- const lineOffset2 = lineHeightBeforeIndex(measure.lines, fragment.fromLine, index2);
39227
- const localY2 = fragment.y + lineOffset2;
39228
- const result2 = {
39229
- pageIndex: hit.pageIndex,
39230
- x: localX2,
39231
- y: localY2,
39232
- height: line.lineHeight
39233
- };
39234
- const pageEl2 = painterHost?.querySelector(
39235
- `.superdoc-page[data-page-index="${hit.pageIndex}"]`
39236
- );
39237
- const pageRect2 = pageEl2?.getBoundingClientRect();
39238
- let domCaretX2 = null;
39239
- let domCaretY2 = null;
39240
- const spanEls2 = pageEl2?.querySelectorAll("span[data-pm-start][data-pm-end]");
39241
- for (const spanEl of Array.from(spanEls2 ?? [])) {
39242
- const pmStart = Number(spanEl.dataset.pmStart);
39243
- const pmEnd = Number(spanEl.dataset.pmEnd);
39244
- if (pos >= pmStart && pos <= pmEnd && spanEl.firstChild?.nodeType === Node.TEXT_NODE) {
39245
- const textNode = spanEl.firstChild;
39246
- const charIndex = Math.min(pos - pmStart, textNode.length);
39247
- const rangeObj = document.createRange();
39248
- rangeObj.setStart(textNode, charIndex);
39249
- rangeObj.setEnd(textNode, charIndex);
39250
- if (typeof rangeObj.getBoundingClientRect !== "function") {
39251
- break;
39252
- }
39253
- const rangeRect = rangeObj.getBoundingClientRect();
39254
- if (pageRect2) {
39255
- domCaretX2 = (rangeRect.left - pageRect2.left) / zoom;
39256
- domCaretY2 = (rangeRect.top - pageRect2.top) / zoom;
39257
- }
39258
- break;
39259
- }
39260
- }
39261
- if (includeDomFallback && domCaretX2 != null && domCaretY2 != null) {
39262
- return {
39263
- pageIndex: hit.pageIndex,
39264
- x: domCaretX2,
39265
- y: domCaretY2,
39266
- height: line.lineHeight
39267
- };
39268
- }
39269
- return result2;
39270
- }
39342
+ const indent = extractParagraphIndent(block.attrs?.indent);
39271
39343
  const indentAdjust = calculateTextStartIndent({
39272
39344
  isFirstLine,
39273
39345
  isListItem: isListItemFlag,
39274
39346
  markerWidth,
39347
+ markerTextWidth,
39275
39348
  paraIndentLeft: indent.left,
39276
39349
  firstLineIndent: indent.firstLine,
39277
39350
  hangingIndent: indent.hanging,
39278
39351
  wordLayout
39279
39352
  });
39353
+ const availableWidth = Math.max(0, fragment.width - (indentAdjust + indent.right));
39354
+ const charX = measureCharacterX(block, line, pmOffset, availableWidth);
39280
39355
  const localX = fragment.x + indentAdjust + charX;
39281
39356
  const lineOffset = lineHeightBeforeIndex(measure.lines, fragment.fromLine, index2);
39282
39357
  const localY = fragment.y + lineOffset;
@@ -39294,9 +39369,9 @@ function computeCaretLayoutRectGeometry({ layout, blocks, measures, painterHost,
39294
39369
  for (const spanEl of Array.from(spanEls ?? [])) {
39295
39370
  const pmStart = Number(spanEl.dataset.pmStart);
39296
39371
  const pmEnd = Number(spanEl.dataset.pmEnd);
39297
- if (pos >= pmStart && pos <= pmEnd && spanEl.firstChild?.nodeType === Node.TEXT_NODE) {
39372
+ if (effectivePos >= pmStart && effectivePos <= pmEnd && spanEl.firstChild?.nodeType === Node.TEXT_NODE) {
39298
39373
  const textNode = spanEl.firstChild;
39299
- const charIndex = Math.min(pos - pmStart, textNode.length);
39374
+ const charIndex = Math.min(effectivePos - pmStart, textNode.length);
39300
39375
  const rangeObj = document.createRange();
39301
39376
  rangeObj.setStart(textNode, charIndex);
39302
39377
  rangeObj.setEnd(textNode, charIndex);
@@ -50195,6 +50270,7 @@ class PresentationEditor extends EventEmitter {
50195
50270
  #telemetryEmitter = null;
50196
50271
  #renderScheduled = false;
50197
50272
  #pendingDocChange = false;
50273
+ #pendingMapping = null;
50198
50274
  #isRerendering = false;
50199
50275
  #selectionSync = new SelectionSyncCoordinator();
50200
50276
  #remoteCursorUpdateScheduled = false;
@@ -51802,6 +51878,15 @@ class PresentationEditor extends EventEmitter {
51802
51878
  }
51803
51879
  if (trackedChangesChanged || transaction?.docChanged) {
51804
51880
  this.#pendingDocChange = true;
51881
+ if (transaction?.docChanged) {
51882
+ if (this.#pendingMapping !== null) {
51883
+ const combined = this.#pendingMapping.slice();
51884
+ combined.appendMapping(transaction.mapping);
51885
+ this.#pendingMapping = combined;
51886
+ } else {
51887
+ this.#pendingMapping = transaction.mapping;
51888
+ }
51889
+ }
51805
51890
  this.#selectionSync.onLayoutStart();
51806
51891
  this.#scheduleRerender();
51807
51892
  }
@@ -52520,7 +52605,12 @@ class PresentationEditor extends EventEmitter {
52520
52605
  }
52521
52606
  if (!handledByDepth) {
52522
52607
  try {
52523
- const tr = this.#editor.state.tr.setSelection(TextSelection$1.create(this.#editor.state.doc, hit.pos));
52608
+ const doc22 = this.#editor.state.doc;
52609
+ let nextSelection = TextSelection$1.create(doc22, hit.pos);
52610
+ if (!nextSelection.$from.parent.inlineContent) {
52611
+ nextSelection = Selection.near(doc22.resolve(hit.pos), 1);
52612
+ }
52613
+ const tr = this.#editor.state.tr.setSelection(nextSelection);
52524
52614
  this.#editor.view?.dispatch(tr);
52525
52615
  } catch {
52526
52616
  }
@@ -53389,7 +53479,9 @@ class PresentationEditor extends EventEmitter {
53389
53479
  footerMeasures.length > 0 ? footerMeasures : void 0
53390
53480
  );
53391
53481
  this.#domIndexObserverManager?.pause();
53392
- painter.paint(layout, this.#painterHost);
53482
+ const mapping = this.#pendingMapping;
53483
+ this.#pendingMapping = null;
53484
+ painter.paint(layout, this.#painterHost, mapping ?? void 0);
53393
53485
  this.#applyVertAlignToLayout();
53394
53486
  this.#rebuildDomPositionIndex();
53395
53487
  this.#domIndexObserverManager?.resume();
@@ -53510,6 +53602,7 @@ class PresentationEditor extends EventEmitter {
53510
53602
  if (!layout) {
53511
53603
  return;
53512
53604
  }
53605
+ const { from: from3, to } = selection;
53513
53606
  const docEpoch = this.#epochMapper.getCurrentEpoch();
53514
53607
  if (this.#layoutEpoch < docEpoch) {
53515
53608
  return;
@@ -53524,7 +53617,6 @@ class PresentationEditor extends EventEmitter {
53524
53617
  }
53525
53618
  return;
53526
53619
  }
53527
- const { from: from3, to } = selection;
53528
53620
  if (from3 === to) {
53529
53621
  const caretLayout = this.#computeCaretLayoutRect(from3);
53530
53622
  if (!caretLayout) {
@@ -58123,6 +58215,28 @@ const createMarkDefsFromStyleRunProps = (styleRunProps) => {
58123
58215
  }
58124
58216
  return markDefs;
58125
58217
  };
58218
+ const normalizeSelectionIntoRun = (tr, runType) => {
58219
+ const selection = tr.selection;
58220
+ if (!(selection instanceof TextSelection$1)) return;
58221
+ if (selection.from !== selection.to) return;
58222
+ const $pos = tr.doc.resolve(selection.from);
58223
+ if ($pos.parent.type === runType) return;
58224
+ const nodeAfter = $pos.nodeAfter;
58225
+ if (nodeAfter?.type === runType && nodeAfter.content.size > 0) {
58226
+ const nextPos = selection.from + 1;
58227
+ if (nextPos <= tr.doc.content.size) {
58228
+ tr.setSelection(TextSelection$1.create(tr.doc, nextPos));
58229
+ }
58230
+ return;
58231
+ }
58232
+ const nodeBefore = $pos.nodeBefore;
58233
+ if (nodeBefore?.type === runType && nodeBefore.content.size > 0) {
58234
+ const prevPos = selection.from - 1;
58235
+ if (prevPos >= 0) {
58236
+ tr.setSelection(TextSelection$1.create(tr.doc, prevPos));
58237
+ }
58238
+ }
58239
+ };
58126
58240
  const buildWrapTransaction = (state, ranges, runType, editor, markDefsFromMeta = []) => {
58127
58241
  if (!ranges.length) return null;
58128
58242
  const replacements = [];
@@ -58156,6 +58270,7 @@ const buildWrapTransaction = (state, ranges, runType, editor, markDefsFromMeta =
58156
58270
  if (!replacements.length) return null;
58157
58271
  const tr = state.tr;
58158
58272
  replacements.sort((a, b) => b.from - a.from).forEach(({ from: from3, to, runNode }) => tr.replaceWith(from3, to, runNode));
58273
+ normalizeSelectionIntoRun(tr, runType);
58159
58274
  return tr.docChanged ? tr : null;
58160
58275
  };
58161
58276
  const wrapTextInRunsPlugin = (editor) => {
@@ -73063,6 +73178,7 @@ const useToolbarItem = (options) => {
73063
73178
  const parentItem = ref(null);
73064
73179
  const iconColor = ref(options.iconColor);
73065
73180
  const hasCaret = ref(options.hasCaret);
73181
+ const restoreEditorFocus = Boolean(options.restoreEditorFocus);
73066
73182
  const dropdownStyles = ref(options.dropdownStyles);
73067
73183
  const tooltip = ref(options.tooltip);
73068
73184
  const tooltipVisible = ref(options.tooltipVisible);
@@ -73138,6 +73254,7 @@ const useToolbarItem = (options) => {
73138
73254
  hideLabel,
73139
73255
  inlineTextInputVisible,
73140
73256
  hasInlineTextInput,
73257
+ restoreEditorFocus,
73141
73258
  markName,
73142
73259
  labelAttr,
73143
73260
  childItem,
@@ -75451,6 +75568,7 @@ const makeDefaultItems = ({
75451
75568
  command: "toggleBulletList",
75452
75569
  icon: toolbarIcons2.bulletList,
75453
75570
  tooltip: toolbarTexts2.bulletList,
75571
+ restoreEditorFocus: true,
75454
75572
  attributes: {
75455
75573
  ariaLabel: "Bullet list"
75456
75574
  }
@@ -75461,6 +75579,7 @@ const makeDefaultItems = ({
75461
75579
  command: "toggleOrderedList",
75462
75580
  icon: toolbarIcons2.numberedList,
75463
75581
  tooltip: toolbarTexts2.numberedList,
75582
+ restoreEditorFocus: true,
75464
75583
  attributes: {
75465
75584
  ariaLabel: "Numbered list"
75466
75585
  }
@@ -86331,6 +86450,7 @@ class SuperToolbar extends EventEmitter$1 {
86331
86450
  selectionUpdate: null,
86332
86451
  focus: null
86333
86452
  };
86453
+ this._restoreFocusTimeoutId = null;
86334
86454
  if (!this.config.selector && this.config.element) {
86335
86455
  this.config.selector = this.config.element;
86336
86456
  }
@@ -86996,6 +87116,7 @@ class SuperToolbar extends EventEmitter$1 {
86996
87116
  const wasFocused = Boolean(typeof hasFocusFn === "function" && hasFocusFn.call(this.activeEditor.view));
86997
87117
  const { command: command2 } = item;
86998
87118
  const isMarkToggle = this.isMarkToggle(item);
87119
+ const shouldRestoreFocus = Boolean(item?.restoreEditorFocus);
86999
87120
  if (!wasFocused && isMarkToggle) {
87000
87121
  this.pendingMarkCommands.push({ command: command2, argument, item });
87001
87122
  item?.activate?.();
@@ -87026,6 +87147,13 @@ class SuperToolbar extends EventEmitter$1 {
87026
87147
  }
87027
87148
  if (isMarkToggle) this.#syncStickyMarksFromState();
87028
87149
  this.updateToolbarState();
87150
+ if (shouldRestoreFocus && this.activeEditor && !this.activeEditor.options.isHeaderOrFooter) {
87151
+ this._restoreFocusTimeoutId = setTimeout(() => {
87152
+ this._restoreFocusTimeoutId = null;
87153
+ if (!this.activeEditor || this.activeEditor.options.isHeaderOrFooter) return;
87154
+ this.activeEditor.focus();
87155
+ }, 0);
87156
+ }
87029
87157
  }
87030
87158
  /**
87031
87159
  * Processes and executes pending mark commands when editor selection updates.
@@ -87168,6 +87296,17 @@ class SuperToolbar extends EventEmitter$1 {
87168
87296
  const tr = state.tr.setStoredMarks([mark]);
87169
87297
  view.dispatch(tr);
87170
87298
  }
87299
+ /**
87300
+ * Cleans up resources when the toolbar is destroyed.
87301
+ * Clears any pending timeouts to prevent callbacks firing after unmount.
87302
+ * @returns {void}
87303
+ */
87304
+ destroy() {
87305
+ if (this._restoreFocusTimeoutId !== null) {
87306
+ clearTimeout(this._restoreFocusTimeoutId);
87307
+ this._restoreFocusTimeoutId = null;
87308
+ }
87309
+ }
87171
87310
  }
87172
87311
  const onMarginClickCursorChange = (event, editor) => {
87173
87312
  const y = event.clientY;