@harbour-enterprises/superdoc 1.3.0-next.3 → 1.3.0-next.5

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.
@@ -30890,8 +30890,9 @@ Please report this to https://github.com/markedjs/marked.`, e) {
30890
30890
  hash: attrs.hash
30891
30891
  };
30892
30892
  const annotationAttrsJson = JSON.stringify(annotationAttrs);
30893
+ const sanitizedDisplayLabel = attrs.displayLabel === "undefined" || attrs.displayLabel === void 0 ? "" : attrs.displayLabel;
30893
30894
  const sdtPrElements = [
30894
- { name: "w:alias", attributes: { "w:val": attrs.displayLabel } },
30895
+ { name: "w:alias", attributes: { "w:val": sanitizedDisplayLabel } },
30895
30896
  { name: "w:tag", attributes: { "w:val": annotationAttrsJson } },
30896
30897
  { name: "w:id", attributes: { "w:val": id } }
30897
30898
  ];
@@ -36365,7 +36366,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
36365
36366
  static getStoredSuperdocVersion(docx) {
36366
36367
  return SuperConverter.getStoredCustomProperty(docx, "SuperdocVersion");
36367
36368
  }
36368
- static setStoredSuperdocVersion(docx = this.convertedXml, version2 = "1.3.0-next.3") {
36369
+ static setStoredSuperdocVersion(docx = this.convertedXml, version2 = "1.3.0-next.5") {
36369
36370
  return SuperConverter.setStoredCustomProperty(docx, "SuperdocVersion", version2, false);
36370
36371
  }
36371
36372
  /**
@@ -49668,8 +49669,12 @@ Please report this to https://github.com/markedjs/marked.`, e) {
49668
49669
  const hasMatchingId = changeMarks.find((mark2) => mark2.attrs.id === id);
49669
49670
  if (hasMatchingId) nodesWithMark.push(node3);
49670
49671
  });
49672
+ const nodesToProcess = nodesWithMark.length ? nodesWithMark : node2 ? [node2] : [];
49673
+ if (!nodesToProcess.length) {
49674
+ return;
49675
+ }
49671
49676
  const { deletionText, trackedChangeText } = getTrackedChangeText({
49672
- nodes: nodesWithMark.length ? nodesWithMark : [node2],
49677
+ nodes: nodesToProcess,
49673
49678
  mark: trackedMark,
49674
49679
  trackedChangeType,
49675
49680
  isDeletionInsertion
@@ -52998,6 +53003,45 @@ Please report this to https://github.com/markedjs/marked.`, e) {
52998
53003
  console.warn("[collaboration] Failed to update Ydoc docx data", error);
52999
53004
  }
53000
53005
  };
53006
+ let isApplyingRemoteChanges = false;
53007
+ const isApplyingRemoteHeaderFooterChanges = () => isApplyingRemoteChanges;
53008
+ const pushHeaderFooterToYjs = (editor, type, sectionId, content2) => {
53009
+ if (isApplyingRemoteChanges) return;
53010
+ const ydoc = editor?.options?.ydoc;
53011
+ if (!ydoc) return;
53012
+ const headerFooterMap = ydoc.getMap("headerFooterJson");
53013
+ const key2 = `${type}:${sectionId}`;
53014
+ const existing = headerFooterMap.get(key2)?.content;
53015
+ if (existing && JSON.stringify(existing) === JSON.stringify(content2)) {
53016
+ return;
53017
+ }
53018
+ ydoc.transact(() => headerFooterMap.set(key2, { type, sectionId, content: content2 }), {
53019
+ event: "header-footer-update",
53020
+ user: editor.options.user
53021
+ });
53022
+ };
53023
+ const applyRemoteHeaderFooterChanges = (editor, key2, data) => {
53024
+ if (!editor || editor.isDestroyed || !editor.converter) return;
53025
+ const { type, sectionId, content: content2 } = data;
53026
+ if (!type || !sectionId || !content2) return;
53027
+ isApplyingRemoteChanges = true;
53028
+ try {
53029
+ const storage = editor.converter[`${type}s`];
53030
+ if (storage) storage[sectionId] = content2;
53031
+ editor.converter.headerFooterModified = true;
53032
+ const editors = editor.converter[`${type}Editors`];
53033
+ editors?.forEach((item) => {
53034
+ if (item.id === sectionId && item.editor) {
53035
+ item.editor.replaceContent(content2);
53036
+ }
53037
+ });
53038
+ editor.emit("remoteHeaderFooterChanged", { type, sectionId, content: content2 });
53039
+ } finally {
53040
+ setTimeout(() => {
53041
+ isApplyingRemoteChanges = false;
53042
+ }, 0);
53043
+ }
53044
+ };
53001
53045
  new PluginKey("collaboration");
53002
53046
  const Collaboration = Extension.create({
53003
53047
  name: "collaboration",
@@ -53026,6 +53070,18 @@ Please report this to https://github.com/markedjs/marked.`, e) {
53026
53070
  }
53027
53071
  });
53028
53072
  });
53073
+ const headerFooterMap = this.options.ydoc.getMap("headerFooterJson");
53074
+ headerFooterMap.observe((event) => {
53075
+ if (event.transaction.local) return;
53076
+ event.changes.keys.forEach((change, key2) => {
53077
+ if (change.action === "add" || change.action === "update") {
53078
+ const data = headerFooterMap.get(key2);
53079
+ if (data) {
53080
+ applyRemoteHeaderFooterChanges(this.editor, key2, data);
53081
+ }
53082
+ }
53083
+ });
53084
+ });
53029
53085
  return [syncPlugin];
53030
53086
  },
53031
53087
  addCommands() {
@@ -62020,7 +62076,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
62020
62076
  return false;
62021
62077
  }
62022
62078
  };
62023
- const summaryVersion = "1.3.0-next.3";
62079
+ const summaryVersion = "1.3.0-next.5";
62024
62080
  const nodeKeys = ["group", "content", "marks", "inline", "atom", "defining", "code", "tableRole", "summary"];
62025
62081
  const markKeys = ["group", "inclusive", "excludes", "spanning", "code"];
62026
62082
  function mapAttributes(attrs) {
@@ -64654,7 +64710,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
64654
64710
  * Process collaboration migrations
64655
64711
  */
64656
64712
  processCollaborationMigrations() {
64657
- console.debug("[checkVersionMigrations] Current editor version", "1.3.0-next.3");
64713
+ console.debug("[checkVersionMigrations] Current editor version", "1.3.0-next.5");
64658
64714
  if (!this.options.ydoc) return;
64659
64715
  const metaMap = this.options.ydoc.getMap("meta");
64660
64716
  let docVersion = metaMap.get("version");
@@ -74233,7 +74289,12 @@ ${l}
74233
74289
  const hanging = paraIndent?.hanging ?? 0;
74234
74290
  const isFirstLineOfPara = lineIndex === 0 || lineIndex === void 0;
74235
74291
  const firstLineOffsetForCumX = isFirstLineOfPara ? firstLine - hanging : 0;
74236
- const indentOffset = indentLeft + firstLineOffsetForCumX;
74292
+ const wordLayoutValue = block.attrs?.wordLayout;
74293
+ const wordLayout = isMinimalWordLayout(wordLayoutValue) ? wordLayoutValue : void 0;
74294
+ const isListParagraph = Boolean(wordLayout?.marker);
74295
+ const rawTextStartPx = typeof wordLayout?.marker?.textStartX === "number" && Number.isFinite(wordLayout.marker.textStartX) ? wordLayout.marker.textStartX : typeof wordLayout?.textStartPx === "number" && Number.isFinite(wordLayout.textStartPx) ? wordLayout.textStartPx : void 0;
74296
+ const listIndentOffset = isFirstLineOfPara ? rawTextStartPx ?? indentLeft : indentLeft;
74297
+ const indentOffset = isListParagraph ? listIndentOffset : indentLeft + firstLineOffsetForCumX;
74237
74298
  let cumulativeX = 0;
74238
74299
  const segmentsByRun = /* @__PURE__ */ new Map();
74239
74300
  line.segments.forEach((segment) => {
@@ -86780,6 +86841,15 @@ ${l}
86780
86841
  if (px == null || !Number.isFinite(px)) return void 0;
86781
86842
  return px / PX_PER_PT;
86782
86843
  };
86844
+ const convertIndentTwipsToPx$1 = (indent2) => {
86845
+ if (!indent2) return void 0;
86846
+ const result = {};
86847
+ if (isFiniteNumber(indent2.left)) result.left = twipsToPx$1(indent2.left);
86848
+ if (isFiniteNumber(indent2.right)) result.right = twipsToPx$1(indent2.right);
86849
+ if (isFiniteNumber(indent2.firstLine)) result.firstLine = twipsToPx$1(indent2.firstLine);
86850
+ if (isFiniteNumber(indent2.hanging)) result.hanging = twipsToPx$1(indent2.hanging);
86851
+ return Object.keys(result).length ? result : void 0;
86852
+ };
86783
86853
  const isFiniteNumber = (value) => typeof value === "number" && Number.isFinite(value);
86784
86854
  const isPlainObject$4 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
86785
86855
  const normalizePrefix = (value) => {
@@ -87850,6 +87920,19 @@ ${l}
87850
87920
  const effectiveMarks = nodeMarks.length > 0 ? nodeMarks : marksAsAttrs;
87851
87921
  const marks = [...effectiveMarks, ...inheritedMarks ?? []];
87852
87922
  applyMarksToRun(run2, marks, hyperlinkConfig, themeColors);
87923
+ if (marksAsAttrs.length > 0) {
87924
+ run2._explicitFont = true;
87925
+ }
87926
+ console.debug("[token-debug] tokenNodeToRun", {
87927
+ token,
87928
+ fontFamily: run2.fontFamily,
87929
+ fontSize: run2.fontSize,
87930
+ defaultFont,
87931
+ defaultSize,
87932
+ nodeMarksCount: nodeMarks.length,
87933
+ marksAsAttrsCount: marksAsAttrs.length,
87934
+ inheritedMarksCount: inheritedMarks?.length ?? 0
87935
+ });
87853
87936
  return run2;
87854
87937
  }
87855
87938
  const EIGHTHS_PER_POINT = 8;
@@ -89764,8 +89847,11 @@ ${l}
89764
89847
  const hydrated = hydrationOverride ?? hydrateParagraphStyleAttrs(para, converterContext);
89765
89848
  const mergedSpacing = mergeSpacingSources(hydrated?.spacing, paragraphProps.spacing, attrs.spacing);
89766
89849
  const normalizedSpacing = normalizeParagraphSpacing(mergedSpacing);
89767
- const indentSource = attrs.indent ?? paragraphProps.indent ?? hydrated?.indent;
89768
- const normalizedIndent = normalizePxIndent(indentSource) ?? normalizeParagraphIndent(indentSource ?? attrs.textIndent);
89850
+ const normalizeIndentObject = (value) => {
89851
+ if (!value || typeof value !== "object") return;
89852
+ return normalizePxIndent(value) ?? convertIndentTwipsToPx(value);
89853
+ };
89854
+ const normalizedIndent = normalizeIndentObject(attrs.indent) ?? convertIndentTwipsToPx(paragraphProps.indent) ?? convertIndentTwipsToPx(hydrated?.indent) ?? normalizeParagraphIndent(attrs.textIndent);
89769
89855
  const unwrapTabStops = (tabStops) => {
89770
89856
  if (!Array.isArray(tabStops)) {
89771
89857
  return void 0;
@@ -91335,9 +91421,12 @@ ${l}
91335
91421
  };
91336
91422
  } else {
91337
91423
  const spacingSource = para.attrs?.spacing !== void 0 ? para.attrs.spacing : paragraphProps.spacing !== void 0 ? paragraphProps.spacing : paragraphHydration?.spacing;
91338
- const indentSource = para.attrs?.indent ?? paragraphProps.indent ?? paragraphHydration?.indent;
91424
+ const normalizeIndentObject = (value) => {
91425
+ if (!value || typeof value !== "object") return;
91426
+ return normalizePxIndent(value) ?? convertIndentTwipsToPx$1(value);
91427
+ };
91339
91428
  const normalizedSpacing = normalizeParagraphSpacing(spacingSource);
91340
- const normalizedIndent = normalizePxIndent(indentSource) ?? normalizeParagraphIndent(indentSource ?? para.attrs?.textIndent);
91429
+ const normalizedIndent = normalizeIndentObject(para.attrs?.indent) ?? convertIndentTwipsToPx$1(paragraphProps.indent) ?? convertIndentTwipsToPx$1(paragraphHydration?.indent) ?? normalizeParagraphIndent(para.attrs?.textIndent);
91341
91430
  const styleNodeAttrs = paragraphHydration?.tabStops && !para.attrs?.tabStops && !para.attrs?.tabs ? { ...para.attrs ?? {}, tabStops: paragraphHydration.tabStops } : para.attrs ?? {};
91342
91431
  const styleNode = buildStyleNodeFromAttrs(styleNodeAttrs, normalizedSpacing, normalizedIndent);
91343
91432
  if (styleNodeAttrs.styleId == null && paragraphProps.styleId) {
@@ -91592,6 +91681,10 @@ ${l}
91592
91681
  if (TOKEN_INLINE_TYPES.has(node2.type)) {
91593
91682
  const tokenKind = TOKEN_INLINE_TYPES.get(node2.type);
91594
91683
  if (tokenKind) {
91684
+ const marksAsAttrs = Array.isArray(node2.attrs?.marksAsAttrs) ? node2.attrs.marksAsAttrs : [];
91685
+ const nodeMarks = node2.marks ?? [];
91686
+ const effectiveMarks = nodeMarks.length > 0 ? nodeMarks : marksAsAttrs;
91687
+ const mergedMarks = [...effectiveMarks, ...inheritedMarks ?? []];
91595
91688
  const tokenRun = tokenNodeToRun(
91596
91689
  node2,
91597
91690
  positions,
@@ -91608,6 +91701,23 @@ ${l}
91608
91701
  const inlineStyleId = getInlineStyleId(inheritedMarks);
91609
91702
  applyRunStyles2(tokenRun, inlineStyleId, activeRunStyleId);
91610
91703
  applyBaseRunDefaults(tokenRun, baseRunDefaults, defaultFont, defaultSize);
91704
+ if (mergedMarks.length > 0) {
91705
+ applyMarksToRun(
91706
+ tokenRun,
91707
+ mergedMarks,
91708
+ hyperlinkConfig,
91709
+ themeColors,
91710
+ converterContext?.backgroundColor
91711
+ );
91712
+ }
91713
+ console.debug("[token-debug] paragraph-token-run", {
91714
+ token: tokenRun.token,
91715
+ fontFamily: tokenRun.fontFamily,
91716
+ fontSize: tokenRun.fontSize,
91717
+ inlineStyleId,
91718
+ runStyleId: activeRunStyleId,
91719
+ mergedMarksCount: mergedMarks.length
91720
+ });
91611
91721
  currentRuns.push(tokenRun);
91612
91722
  }
91613
91723
  return;
@@ -93058,6 +93168,9 @@ ${l}
93058
93168
  };
93059
93169
  const onHeaderFooterDataUpdate = async ({ editor, transaction }, mainEditor, sectionId, type) => {
93060
93170
  if (!type || !sectionId) return;
93171
+ if (isApplyingRemoteHeaderFooterChanges()) {
93172
+ return;
93173
+ }
93061
93174
  const updatedData = editor.getUpdatedJson();
93062
93175
  const editorsList = mainEditor.converter[`${type}Editors`];
93063
93176
  if (Array.isArray(editorsList)) {
@@ -93081,6 +93194,7 @@ ${l}
93081
93194
  if (editor.docChanged && mainEditor.converter) {
93082
93195
  mainEditor.converter.headerFooterModified = true;
93083
93196
  }
93197
+ pushHeaderFooterToYjs(mainEditor, type, sectionId, updatedData);
93084
93198
  await updateYdocDocxData(mainEditor);
93085
93199
  };
93086
93200
  const setEditorToolbar = ({ editor }, mainEditor) => {
@@ -94588,6 +94702,77 @@ ${l}
94588
94702
  function isFieldAnnotationRun(run2) {
94589
94703
  return run2.kind === "fieldAnnotation";
94590
94704
  }
94705
+ function measureTabAlignmentGroup(startRunIndex, runs2, ctx2, decimalSeparator = ".") {
94706
+ const result = {
94707
+ totalWidth: 0,
94708
+ runs: [],
94709
+ endRunIndex: runs2.length
94710
+ };
94711
+ let foundDecimal = false;
94712
+ for (let i2 = startRunIndex; i2 < runs2.length; i2++) {
94713
+ const run2 = runs2[i2];
94714
+ if (isTabRun(run2)) {
94715
+ result.endRunIndex = i2;
94716
+ break;
94717
+ }
94718
+ if (isLineBreakRun(run2) || run2.kind === "break" && run2.breakType === "line") {
94719
+ result.endRunIndex = i2;
94720
+ break;
94721
+ }
94722
+ if (run2.kind === "text" || run2.kind === void 0) {
94723
+ const textRun = run2;
94724
+ const text2 = textRun.text || "";
94725
+ if (text2.length > 0) {
94726
+ const { font } = buildFontString(textRun);
94727
+ const width = measureRunWidth(text2, font, ctx2, textRun, 0);
94728
+ let beforeDecimalWidth;
94729
+ if (!foundDecimal) {
94730
+ const decimalIdx = text2.indexOf(decimalSeparator);
94731
+ if (decimalIdx >= 0) {
94732
+ foundDecimal = true;
94733
+ const beforeText = text2.slice(0, decimalIdx);
94734
+ beforeDecimalWidth = beforeText.length > 0 ? measureRunWidth(beforeText, font, ctx2, textRun, 0) : 0;
94735
+ result.beforeDecimalWidth = result.totalWidth + beforeDecimalWidth;
94736
+ }
94737
+ }
94738
+ result.runs.push({
94739
+ runIndex: i2,
94740
+ width,
94741
+ text: text2,
94742
+ beforeDecimalWidth
94743
+ });
94744
+ result.totalWidth += width;
94745
+ } else {
94746
+ result.runs.push({ runIndex: i2, width: 0, text: "" });
94747
+ }
94748
+ continue;
94749
+ }
94750
+ if (isImageRun(run2)) {
94751
+ const leftSpace = run2.distLeft ?? 0;
94752
+ const rightSpace = run2.distRight ?? 0;
94753
+ const imageWidth = run2.width + leftSpace + rightSpace;
94754
+ result.runs.push({ runIndex: i2, width: imageWidth });
94755
+ result.totalWidth += imageWidth;
94756
+ continue;
94757
+ }
94758
+ if (isFieldAnnotationRun(run2)) {
94759
+ const fontSize2 = run2.fontSize ?? DEFAULT_FIELD_ANNOTATION_FONT_SIZE;
94760
+ const { font } = buildFontString({
94761
+ fontFamily: run2.fontFamily ?? "Arial",
94762
+ fontSize: fontSize2,
94763
+ bold: run2.bold,
94764
+ italic: run2.italic
94765
+ });
94766
+ const textWidth = run2.displayLabel ? measureRunWidth(run2.displayLabel, font, ctx2, run2, 0) : 0;
94767
+ const pillWidth = textWidth + FIELD_ANNOTATION_PILL_PADDING;
94768
+ result.runs.push({ runIndex: i2, width: pillWidth });
94769
+ result.totalWidth += pillWidth;
94770
+ continue;
94771
+ }
94772
+ result.runs.push({ runIndex: i2, width: 0 });
94773
+ }
94774
+ return result;
94775
+ }
94591
94776
  async function measureBlock(block, constraints) {
94592
94777
  const normalized = normalizeConstraints(constraints);
94593
94778
  if (block.kind === "drawing") {
@@ -94711,6 +94896,7 @@ ${l}
94711
94896
  let pendingTabAlignment = null;
94712
94897
  let lastAppliedTabAlign = null;
94713
94898
  const warnedTabVals = /* @__PURE__ */ new Set();
94899
+ let activeTabGroup = null;
94714
94900
  const validateTabStopVal = (stop) => {
94715
94901
  if (!ALLOWED_TAB_VALS.has(stop.val) && !warnedTabVals.has(stop.val)) {
94716
94902
  warnedTabVals.add(stop.val);
@@ -94890,6 +95076,7 @@ ${l}
94890
95076
  continue;
94891
95077
  }
94892
95078
  if (isTabRun(run2)) {
95079
+ activeTabGroup = null;
94893
95080
  if (!currentLine) {
94894
95081
  currentLine = {
94895
95082
  fromRun: runIndex,
@@ -94914,12 +95101,6 @@ ${l}
94914
95101
  currentLine.maxFontSize = Math.max(currentLine.maxFontSize, 12);
94915
95102
  currentLine.toRun = runIndex;
94916
95103
  currentLine.toChar = 1;
94917
- if (stop) {
94918
- validateTabStopVal(stop);
94919
- pendingTabAlignment = { target: clampedTarget, val: stop.val };
94920
- } else {
94921
- pendingTabAlignment = null;
94922
- }
94923
95104
  if (stop && stop.leader && stop.leader !== "none") {
94924
95105
  const leaderStyle = stop.leader;
94925
95106
  const from2 = Math.min(originX, clampedTarget);
@@ -94927,6 +95108,36 @@ ${l}
94927
95108
  if (!currentLine.leaders) currentLine.leaders = [];
94928
95109
  currentLine.leaders.push({ from: from2, to, style: leaderStyle });
94929
95110
  }
95111
+ if (stop) {
95112
+ validateTabStopVal(stop);
95113
+ if (stop.val === "end" || stop.val === "center" || stop.val === "decimal") {
95114
+ const groupMeasure = measureTabAlignmentGroup(runIndex + 1, runsToProcess, ctx2, decimalSeparator);
95115
+ if (groupMeasure.totalWidth > 0) {
95116
+ let groupStartX;
95117
+ if (stop.val === "end") {
95118
+ groupStartX = Math.max(0, clampedTarget - groupMeasure.totalWidth);
95119
+ } else if (stop.val === "center") {
95120
+ groupStartX = Math.max(0, clampedTarget - groupMeasure.totalWidth / 2);
95121
+ } else {
95122
+ const beforeDecimal = groupMeasure.beforeDecimalWidth ?? groupMeasure.totalWidth;
95123
+ groupStartX = Math.max(0, clampedTarget - beforeDecimal);
95124
+ }
95125
+ activeTabGroup = {
95126
+ measure: groupMeasure,
95127
+ startX: groupStartX,
95128
+ currentX: groupStartX,
95129
+ target: clampedTarget,
95130
+ val: stop.val
95131
+ };
95132
+ currentLine.width = roundValue(groupStartX);
95133
+ }
95134
+ pendingTabAlignment = null;
95135
+ } else {
95136
+ pendingTabAlignment = { target: clampedTarget, val: stop.val };
95137
+ }
95138
+ } else {
95139
+ pendingTabAlignment = null;
95140
+ }
94930
95141
  continue;
94931
95142
  }
94932
95143
  if (isImageRun(run2)) {
@@ -94937,7 +95148,10 @@ ${l}
94937
95148
  const bottomSpace = run2.distBottom ?? 0;
94938
95149
  const imageHeight = run2.height + topSpace + bottomSpace;
94939
95150
  let imageStartX;
94940
- if (pendingTabAlignment && currentLine) {
95151
+ if (activeTabGroup && currentLine) {
95152
+ imageStartX = activeTabGroup.currentX;
95153
+ activeTabGroup.currentX = roundValue(activeTabGroup.currentX + imageWidth);
95154
+ } else if (pendingTabAlignment && currentLine) {
94941
95155
  imageStartX = alignPendingTabForWidth(imageWidth);
94942
95156
  }
94943
95157
  if (!currentLine) {
@@ -94962,10 +95176,14 @@ ${l}
94962
95176
  }
94963
95177
  ]
94964
95178
  };
95179
+ if (activeTabGroup && runIndex + 1 >= activeTabGroup.measure.endRunIndex) {
95180
+ activeTabGroup = null;
95181
+ }
94965
95182
  continue;
94966
95183
  }
94967
95184
  const appliedTabAlign = lastAppliedTabAlign;
94968
- if (currentLine.width + imageWidth > currentLine.maxWidth && currentLine.width > 0) {
95185
+ const skipFitCheck = activeTabGroup !== null;
95186
+ if (!skipFitCheck && currentLine.width + imageWidth > currentLine.maxWidth && currentLine.width > 0) {
94969
95187
  trimTrailingWrapSpaces(currentLine);
94970
95188
  const metrics = calculateTypographyMetrics(currentLine.maxFontSize, spacing, currentLine.maxFontInfo);
94971
95189
  const lineBase = currentLine;
@@ -94978,6 +95196,7 @@ ${l}
94978
95196
  tabStopCursor = 0;
94979
95197
  pendingTabAlignment = null;
94980
95198
  lastAppliedTabAlign = null;
95199
+ activeTabGroup = null;
94981
95200
  currentLine = {
94982
95201
  fromRun: runIndex,
94983
95202
  fromChar: 0,
@@ -95010,6 +95229,9 @@ ${l}
95010
95229
  ...imageStartX !== void 0 ? { x: imageStartX } : {}
95011
95230
  });
95012
95231
  }
95232
+ if (activeTabGroup && runIndex + 1 >= activeTabGroup.measure.endRunIndex) {
95233
+ activeTabGroup = null;
95234
+ }
95013
95235
  const tabAlign = appliedTabAlign;
95014
95236
  if (tabAlign && currentLine && tabAlign.val === "end") {
95015
95237
  currentLine.width = roundValue(tabAlign.target);
@@ -95185,7 +95407,11 @@ ${l}
95185
95407
  }
95186
95408
  }
95187
95409
  let segmentStartX;
95188
- if (currentLine && pendingTabAlignment) {
95410
+ let inActiveTabGroup = false;
95411
+ if (activeTabGroup && currentLine) {
95412
+ segmentStartX = activeTabGroup.currentX;
95413
+ inActiveTabGroup = true;
95414
+ } else if (currentLine && pendingTabAlignment) {
95189
95415
  segmentStartX = alignSegmentAtTab(segment, font, run2, charPosInRun);
95190
95416
  if (segmentStartX == null) {
95191
95417
  segmentStartX = currentLine.width;
@@ -95222,6 +95448,7 @@ ${l}
95222
95448
  tabStopCursor = 0;
95223
95449
  pendingTabAlignment = null;
95224
95450
  lastAppliedTabAlign = null;
95451
+ activeTabGroup = null;
95225
95452
  currentLine = {
95226
95453
  fromRun: runIndex,
95227
95454
  fromChar: spaceStartChar,
@@ -95240,7 +95467,19 @@ ${l}
95240
95467
  currentLine.width = roundValue(currentLine.width + boundarySpacing2 + singleSpaceWidth);
95241
95468
  currentLine.maxFontInfo = updateMaxFontInfo(currentLine.maxFontSize, currentLine.maxFontInfo, run2);
95242
95469
  currentLine.maxFontSize = Math.max(currentLine.maxFontSize, run2.fontSize);
95243
- appendSegment(currentLine.segments, runIndex, spaceStartChar, spaceEndChar, singleSpaceWidth);
95470
+ let spaceExplicitX;
95471
+ if (inActiveTabGroup && activeTabGroup) {
95472
+ spaceExplicitX = activeTabGroup.currentX;
95473
+ activeTabGroup.currentX = roundValue(activeTabGroup.currentX + singleSpaceWidth);
95474
+ }
95475
+ appendSegment(
95476
+ currentLine.segments,
95477
+ runIndex,
95478
+ spaceStartChar,
95479
+ spaceEndChar,
95480
+ singleSpaceWidth,
95481
+ spaceExplicitX
95482
+ );
95244
95483
  currentLine.spaceCount += 1;
95245
95484
  }
95246
95485
  }
@@ -95388,7 +95627,7 @@ ${l}
95388
95627
  const totalWidthWithWord = currentLine.width + boundarySpacing + wordCommitWidth + // Safe cast: only TextRuns produce word segments from split(), other run types are handled earlier
95389
95628
  (shouldIncludeDelimiterSpace ? run2.letterSpacing ?? 0 : 0);
95390
95629
  const availableWidth = currentLine.maxWidth - WIDTH_FUDGE_PX2;
95391
- let shouldBreak = currentLine.width + boundarySpacing + wordOnlyWidth > availableWidth && currentLine.width > 0 && !isTocEntry;
95630
+ let shouldBreak = !inActiveTabGroup && currentLine.width + boundarySpacing + wordOnlyWidth > availableWidth && currentLine.width > 0 && !isTocEntry;
95392
95631
  let compressedWidth = null;
95393
95632
  if (shouldBreak && justifyAlignment) {
95394
95633
  const isLastNonEmptyWordInSegment = wordIndex === lastNonEmptyWordIndex;
@@ -95453,15 +95692,14 @@ ${l}
95453
95692
  currentLine.width = roundValue(currentLine.width + boundarySpacing + wordOnlyWidth);
95454
95693
  currentLine.maxFontInfo = updateMaxFontInfo(currentLine.maxFontSize, currentLine.maxFontInfo, run2);
95455
95694
  currentLine.maxFontSize = Math.max(currentLine.maxFontSize, run2.fontSize);
95456
- const useExplicitXHere = wordIndex === 0 && segmentStartX !== void 0;
95457
- appendSegment(
95458
- currentLine.segments,
95459
- runIndex,
95460
- wordStartChar,
95461
- wordEndNoSpace,
95462
- wordOnlyWidth,
95463
- useExplicitXHere ? segmentStartX : void 0
95464
- );
95695
+ let explicitXHere;
95696
+ if (inActiveTabGroup && activeTabGroup) {
95697
+ explicitXHere = activeTabGroup.currentX;
95698
+ activeTabGroup.currentX = roundValue(activeTabGroup.currentX + wordOnlyWidth);
95699
+ } else if (wordIndex === 0 && segmentStartX !== void 0) {
95700
+ explicitXHere = segmentStartX;
95701
+ }
95702
+ appendSegment(currentLine.segments, runIndex, wordStartChar, wordEndNoSpace, wordOnlyWidth, explicitXHere);
95465
95703
  trimTrailingWrapSpaces(currentLine);
95466
95704
  const metrics = calculateTypographyMetrics(currentLine.maxFontSize, spacing, currentLine.maxFontInfo);
95467
95705
  const lineBase = currentLine;
@@ -95476,8 +95714,13 @@ ${l}
95476
95714
  }
95477
95715
  const newToChar = shouldIncludeDelimiterSpace ? wordEndWithSpace : wordEndNoSpace;
95478
95716
  currentLine.toChar = newToChar;
95479
- const useExplicitX = wordIndex === 0 && segmentStartX !== void 0;
95480
- const explicitX = useExplicitX ? segmentStartX : void 0;
95717
+ let explicitX;
95718
+ if (inActiveTabGroup && activeTabGroup) {
95719
+ explicitX = activeTabGroup.currentX;
95720
+ activeTabGroup.currentX = roundValue(activeTabGroup.currentX + wordCommitWidth);
95721
+ } else if (wordIndex === 0 && segmentStartX !== void 0) {
95722
+ explicitX = segmentStartX;
95723
+ }
95481
95724
  const targetWidth = compressedWidth != null ? compressedWidth : currentLine.width + boundarySpacing + wordCommitWidth + (shouldIncludeDelimiterSpace ? run2.letterSpacing ?? 0 : 0);
95482
95725
  if (compressedWidth != null) {
95483
95726
  currentLine.naturalWidth = roundValue(totalWidthWithWord);
@@ -95499,6 +95742,12 @@ ${l}
95499
95742
  }
95500
95743
  }
95501
95744
  lastAppliedTabAlign = null;
95745
+ if (activeTabGroup && runIndex + 1 >= activeTabGroup.measure.endRunIndex) {
95746
+ if (currentLine && activeTabGroup.val === "end") {
95747
+ currentLine.width = roundValue(activeTabGroup.target);
95748
+ }
95749
+ activeTabGroup = null;
95750
+ }
95502
95751
  if (!isLastSegment) {
95503
95752
  pendingTabAlignment = null;
95504
95753
  if (!currentLine) {
@@ -97929,6 +98178,17 @@ ${l}
97929
98178
  event: "collaborationReady",
97930
98179
  handler: handleCollaborationReady
97931
98180
  });
98181
+ const handleRemoteHeaderFooterChanged = (payload) => {
98182
+ this.#headerFooterAdapter?.invalidate(payload.sectionId);
98183
+ this.#headerFooterManager?.refresh();
98184
+ this.#pendingDocChange = true;
98185
+ this.#scheduleRerender();
98186
+ };
98187
+ this.#editor.on("remoteHeaderFooterChanged", handleRemoteHeaderFooterChanged);
98188
+ this.#editorListeners.push({
98189
+ event: "remoteHeaderFooterChanged",
98190
+ handler: handleRemoteHeaderFooterChanged
98191
+ });
97932
98192
  }
97933
98193
  /**
97934
98194
  * Setup awareness event subscriptions for remote cursor tracking.
@@ -143604,7 +143864,7 @@ ${reason}`);
143604
143864
  this.config.colors = shuffleArray(this.config.colors);
143605
143865
  this.userColorMap = /* @__PURE__ */ new Map();
143606
143866
  this.colorIndex = 0;
143607
- this.version = "1.3.0-next.3";
143867
+ this.version = "1.3.0-next.5";
143608
143868
  this.#log("🦋 [superdoc] Using SuperDoc version:", this.version);
143609
143869
  this.superdocId = config2.superdocId || v4();
143610
143870
  this.colors = this.config.colors;