@stll/folio-core 0.37.4 → 0.38.0

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.
Files changed (131) hide show
  1. package/dist/ai-edits/apply.js +275 -88
  2. package/dist/ai-edits/clean-text.js +12 -1
  3. package/dist/ai-edits/headless.d.ts +110 -0
  4. package/dist/ai-edits/headless.js +569 -40
  5. package/dist/ai-edits/index.d.ts +2 -1
  6. package/dist/ai-edits/snapshot.d.ts +24 -1
  7. package/dist/ai-edits/snapshot.js +206 -9
  8. package/dist/ai-edits/table-geometry.d.ts +7 -7
  9. package/dist/ai-edits/table-geometry.js +43 -27
  10. package/dist/ai-edits/table-template.d.ts +2 -1
  11. package/dist/ai-edits/table-template.js +9 -3
  12. package/dist/ai-edits/types.d.ts +38 -16
  13. package/dist/compare/__fixtures__/body-sequence.d.ts +4 -0
  14. package/dist/compare/__fixtures__/body-sequence.js +5 -3
  15. package/dist/compare/compare.d.ts +26 -2
  16. package/dist/compare/compare.js +444 -16
  17. package/dist/compare/content-alignment.js +216 -137
  18. package/dist/compare/content-types.d.ts +36 -2
  19. package/dist/compare/content.d.ts +13 -10
  20. package/dist/compare/content.js +69 -23
  21. package/dist/compare/formatting.d.ts +4 -22
  22. package/dist/compare/formatting.js +8 -112
  23. package/dist/compare/inline-atom-resources.d.ts +6 -0
  24. package/dist/compare/inline-atom-resources.js +26 -0
  25. package/dist/compare/inline-atoms.d.ts +35 -0
  26. package/dist/compare/inline-atoms.js +383 -0
  27. package/dist/compare/inline-provenance.d.ts +36 -0
  28. package/dist/compare/inline-provenance.js +334 -0
  29. package/dist/compare/plan.d.ts +4 -1
  30. package/dist/compare/plan.js +32 -4
  31. package/dist/compare/scenario.d.ts +4 -6
  32. package/dist/compare/section-boundary-properties.d.ts +63 -0
  33. package/dist/compare/section-boundary-properties.js +235 -0
  34. package/dist/compare/style-resources.d.ts +30 -0
  35. package/dist/compare/style-resources.js +404 -0
  36. package/dist/compare/types.d.ts +50 -11
  37. package/dist/compare/types.js +3 -1
  38. package/dist/compare/verification.d.ts +3 -5
  39. package/dist/compare/verification.js +8 -39
  40. package/dist/compat/eigenpal.d.ts +4 -4
  41. package/dist/compat/eigenpal.js +3 -3
  42. package/dist/document-operations.d.ts +5 -3
  43. package/dist/document-operations.js +112 -5
  44. package/dist/docx/blockContentParser.js +14 -2
  45. package/dist/docx/drawingIdNormalization.js +43 -2
  46. package/dist/docx/drawingRelationships.d.ts +10 -0
  47. package/dist/docx/drawingRelationships.js +28 -0
  48. package/dist/docx/fieldParser.js +1 -1
  49. package/dist/docx/hyperlinkParser.js +3 -5
  50. package/dist/docx/imageRawXml.d.ts +8 -0
  51. package/dist/docx/imageRawXml.js +13 -0
  52. package/dist/docx/newImage.d.ts +2 -2
  53. package/dist/docx/newImage.js +3 -3
  54. package/dist/docx/numberingParser.d.ts +1 -13
  55. package/dist/docx/numberingParser.js +31 -37
  56. package/dist/docx/paragraphParser.js +12 -9
  57. package/dist/docx/paragraphPropertySource.d.ts +8 -5
  58. package/dist/docx/paragraphPropertySource.js +16 -4
  59. package/dist/docx/removeHeaderFooterParts.d.ts +14 -0
  60. package/dist/docx/removeHeaderFooterParts.js +87 -0
  61. package/dist/docx/rezip.d.ts +3 -1
  62. package/dist/docx/rezip.js +143 -41
  63. package/dist/docx/runParser.js +16 -5
  64. package/dist/docx/sectionParser.js +3 -0
  65. package/dist/docx/sectionReferenceHistory.d.ts +17 -0
  66. package/dist/docx/sectionReferenceHistory.js +59 -0
  67. package/dist/docx/selectiveSave.js +11 -31
  68. package/dist/docx/selectiveXmlPatch.d.ts +8 -1
  69. package/dist/docx/selectiveXmlPatch.js +62 -2
  70. package/dist/docx/serializer/borderSerializer.d.ts +4 -1
  71. package/dist/docx/serializer/borderSerializer.js +20 -18
  72. package/dist/docx/serializer/commentSerializer.js +1 -1
  73. package/dist/docx/serializer/numberingSerializer.js +1 -1
  74. package/dist/docx/serializer/paragraphSerializer.js +13 -177
  75. package/dist/docx/serializer/partNamespaces.d.ts +1 -1
  76. package/dist/docx/serializer/partNamespaces.js +4 -0
  77. package/dist/docx/serializer/runSerializer.d.ts +1 -5
  78. package/dist/docx/serializer/runSerializer.js +4 -130
  79. package/dist/docx/serializer/sectionPropertiesSerializer.js +5 -2
  80. package/dist/docx/serializer/stylesSerializer.js +1 -1
  81. package/dist/docx/serializer/textFormattingSerializer.d.ts +17 -0
  82. package/dist/docx/serializer/textFormattingSerializer.js +144 -0
  83. package/dist/docx/tableParser.js +21 -11
  84. package/dist/docx/xmlParser.d.ts +10 -1
  85. package/dist/docx/xmlParser.js +23 -1
  86. package/dist/index.d.ts +4 -4
  87. package/dist/index.js +3 -3
  88. package/dist/internal/compare/inline-presentation.d.ts +20 -0
  89. package/dist/internal/compare/inline-presentation.js +222 -0
  90. package/dist/internal/paragraphFormattingSerialization.d.ts +25 -0
  91. package/dist/internal/paragraphFormattingSerialization.js +164 -0
  92. package/dist/internal/sectionReferenceResolution.d.ts +21 -0
  93. package/dist/internal/sectionReferenceResolution.js +72 -0
  94. package/dist/layout-bridge/convert/toFlowBlocks.js +1 -0
  95. package/dist/markdown/renderRuns.js +1 -0
  96. package/dist/markdown/renderTable.js +1 -0
  97. package/dist/prosemirror/attrs/index.js +20 -1
  98. package/dist/prosemirror/commands/comments.d.ts +11 -1
  99. package/dist/prosemirror/commands/comments.js +68 -6
  100. package/dist/prosemirror/commands/propertyChangeScope.d.ts +9 -3
  101. package/dist/prosemirror/commands/propertyChangeScope.js +4 -10
  102. package/dist/prosemirror/conversion/fromProseDoc.js +22 -22
  103. package/dist/prosemirror/conversion/toProseDoc.js +16 -57
  104. package/dist/prosemirror/extensions/core/ParagraphExtension.js +2 -0
  105. package/dist/prosemirror/extensions/marks/RunFormattingOverrideExtension.js +3 -0
  106. package/dist/prosemirror/imageCommit.js +7 -9
  107. package/dist/prosemirror/paragraphIndentation.d.ts +21 -0
  108. package/dist/prosemirror/paragraphIndentation.js +72 -0
  109. package/dist/prosemirror/plugins/documentNumbering.d.ts +3 -1
  110. package/dist/prosemirror/plugins/documentNumbering.js +7 -1
  111. package/dist/prosemirror/plugins/documentStyles.d.ts +3 -1
  112. package/dist/prosemirror/plugins/documentStyles.js +7 -1
  113. package/dist/prosemirror/rebaseParagraphRunFormatting.d.ts +3 -1
  114. package/dist/prosemirror/rebaseParagraphRunFormatting.js +2 -1
  115. package/dist/prosemirror/runFormattingInlineCarriers.d.ts +15 -2
  116. package/dist/prosemirror/runFormattingInlineCarriers.js +33 -3
  117. package/dist/prosemirror/runStyleFormatting.d.ts +15 -2
  118. package/dist/prosemirror/runStyleFormatting.js +76 -2
  119. package/dist/prosemirror/schema/marks.d.ts +3 -1
  120. package/dist/prosemirror/schema/marks.js +2 -0
  121. package/dist/prosemirror/schema/nodes.d.ts +3 -0
  122. package/dist/prosemirror/tableCellRevisionVisibility.d.ts +6 -0
  123. package/dist/prosemirror/tableCellRevisionVisibility.js +14 -0
  124. package/dist/prosemirror/trackedRunInlineAtoms.d.ts +1 -1
  125. package/dist/prosemirror/trackedRunInlineAtoms.js +1 -1
  126. package/dist/redline.js +15 -2
  127. package/dist/server.d.ts +3 -2
  128. package/dist/server.js +2 -2
  129. package/dist/version-comparison.d.ts +2 -0
  130. package/dist/version-comparison.js +30 -29
  131. package/package.json +2 -2
@@ -12,12 +12,14 @@ import { RUN_FORMATTING_MARK_NAMES } from "../runFormattingMarkNames.js";
12
12
  import { reconstructRejectedRunFormattingMarks } from "../runPropertyChangeResolution.js";
13
13
  import { paragraphRunStyleContextAt } from "../runStyleFormatting.js";
14
14
  import { getTableCellMergeChange } from "../tableCellMergeRevision.js";
15
+ import { isTableCellRetainedInReviewView } from "../tableCellRevisionVisibility.js";
15
16
  import { reconcileTableGridAfterColumnRemoval } from "../tableGridMutation.js";
16
17
  import { holdsNoContent } from "../zeroWidthAnchors.js";
17
18
  import { hasSerializableParagraphPropertyChange, paragraphPropertiesSnapshot, paragraphRejectAttrPatch, paragraphRejectOriginalFormatting, removeParagraphPropertyChanges, sectionRejectProperties, tableCellRejectAttrPatch, tableRejectAttrPatch, tableRowRejectAttrPatch } from "./propertyChangeScope.js";
18
19
  import { hasMatchingCollapsedTableCellMerge, resolveCollapsedTableCellMerge, resolveVisibleTableCellMerge } from "./tableCellMergeResolution.js";
19
20
  import { TableMap, removeRow } from "prosemirror-tables";
20
- import { PARAGRAPH_MARK_CHANGE_KINDS } from "@stll/docx-core/model";
21
+ import { Mapping } from "prosemirror-transform";
22
+ import { PARAGRAPH_MARK_CHANGE_KINDS, REVIEW_CARRIERS } from "@stll/docx-core/model";
21
23
  //#region src/prosemirror/commands/comments.ts
22
24
  /**
23
25
  * Add a comment mark to the current selection.
@@ -120,7 +122,11 @@ function resolveChange(from, to, mode, revisionIds, execution = "legacy") {
120
122
  if (matches.length > 0) {
121
123
  const remaining = sectionChanges.filter((c) => revisionSet !== null && (!c.info || !revisionSet.has(c.info.id)));
122
124
  let restored = { ...sectionProperties };
123
- if (mode === "reject") for (const change of matches.toReversed()) restored = sectionRejectProperties(restored, change.previousProperties);
125
+ if (mode === "reject") for (const change of matches.toReversed()) restored = sectionRejectProperties({
126
+ live: restored,
127
+ previousProperties: change.previousProperties,
128
+ previousReferences: change.previousReferences
129
+ });
124
130
  delete restored.propertyChanges;
125
131
  if (remaining.length > 0) restored.propertyChanges = remaining;
126
132
  nextAttrs = nextAttrs ?? { ...node.attrs };
@@ -132,7 +138,12 @@ function resolveChange(from, to, mode, revisionIds, execution = "legacy") {
132
138
  nextAttrs,
133
139
  paragraphPosition: pos,
134
140
  styleResolver,
135
- tr
141
+ tr,
142
+ ...mode === "reject" && { shouldRebase: (inline) => {
143
+ const deleted = inline.marks.some(({ type }) => type.name === "deletion");
144
+ const direct = inline.marks.some(({ type }) => type.name === "runFormattingOverride");
145
+ return !deleted || !direct;
146
+ } }
136
147
  });
137
148
  else tr.setNodeMarkup(pos, void 0, nextAttrs);
138
149
  return true;
@@ -309,11 +320,45 @@ function resolveChange(from, to, mode, revisionIds, execution = "legacy") {
309
320
  removedEndpointCount: removedSectionEndpointCount,
310
321
  removedReferences: removedSectionReferences
311
322
  });
323
+ if (!terminalTableDeletionIsPending(tr)) resolveTerminalTableReviewCarrier(tr, mode);
312
324
  if (tr.steps.length > 0) dispatch(tr);
313
325
  }
314
326
  return true;
315
327
  };
316
328
  }
329
+ /**
330
+ * The receiver belongs to the deleted terminal table, not every revision in
331
+ * the document. Keep it through independently resolved changes, then resolve
332
+ * it as soon as that table's deletion has been decided.
333
+ */
334
+ const terminalTableDeletionIsPending = (tr) => {
335
+ let terminalTable = null;
336
+ for (let index = tr.doc.childCount - 1; index >= 0; index--) {
337
+ const node = tr.doc.child(index);
338
+ if (node.type.name === "table") {
339
+ terminalTable = node;
340
+ break;
341
+ }
342
+ }
343
+ if (terminalTable === null) return false;
344
+ let pending = false;
345
+ terminalTable.descendants((node) => {
346
+ pending ||= node.type.name === "tableRow" && isTableRowRevisionAttr(node.attrs["trDel"]) || node.type.name !== "tableRow" && node.marks.some((mark) => mark.type.name === "deletion");
347
+ return !pending;
348
+ });
349
+ return pending;
350
+ };
351
+ /** Resolve the Folio-only receiver Word needs after a terminal deleted table. */
352
+ const resolveTerminalTableReviewCarrier = (tr, mode) => {
353
+ const carrier = tr.doc.lastChild;
354
+ if (carrier?.type.name !== "paragraph" || carrier.attrs["reviewCarrier"] !== REVIEW_CARRIERS.TERMINAL_TABLE) return;
355
+ const position = tr.doc.content.size - carrier.nodeSize;
356
+ if (mode === "accept") {
357
+ tr.setNodeAttribute(position, "reviewCarrier", void 0);
358
+ return;
359
+ }
360
+ tr.delete(position, position + carrier.nodeSize);
361
+ };
317
362
  const resolveRunPropertyChange = ({ tr, node, from, to, mark, mode, revisionSet, styleResolver }) => {
318
363
  const { changes } = expectRunPropertyChangeMarkAttrs(mark);
319
364
  const matches = changes.filter((change) => revisionSet === null || revisionSet.has(change.info.id));
@@ -401,11 +446,11 @@ function collectTableCellStructuralOps(node, cellPos, mode, revisionSet) {
401
446
  revisionSet
402
447
  });
403
448
  else {
404
- const keepsCell = marker.kind === "ins" === (mode === "accept");
449
+ const view = mode === "accept" ? "final" : "original";
405
450
  operations.push({
406
451
  type: "membership",
407
452
  cellPos,
408
- action: keepsCell ? "clear" : "remove"
453
+ action: isTableCellRetainedInReviewView(marker.kind, view) ? "clear" : "remove"
409
454
  });
410
455
  }
411
456
  if (hasMatchingCollapsedTableCellMerge(node, revisionSet)) operations.push({
@@ -671,6 +716,23 @@ function resolveAllChangesInHeadlessState(state, mode) {
671
716
  return resolvedState;
672
717
  }
673
718
  /**
719
+ * Resolve through the editor command path when a caller must map a position in
720
+ * the reviewed document back to the tracked source. The bulk resolver is
721
+ * faster, but deliberately replaces inline content without retaining mapping.
722
+ */
723
+ const resolveAllChangesInHeadlessStateWithMapping = (state, mode) => {
724
+ let resolvedState = state;
725
+ let mapping = new Mapping();
726
+ resolveChange(0, state.doc.content.size, mode)(state, (transaction) => {
727
+ resolvedState = state.apply(transaction);
728
+ mapping = transaction.mapping;
729
+ });
730
+ return {
731
+ state: resolvedState,
732
+ mapping
733
+ };
734
+ };
735
+ /**
674
736
  * Find the document range covered by all revision carriers with any of the
675
737
  * given ids. Returns null when none are present (already accepted/rejected, or
676
738
  * never existed). A replace operation typically passes two ids; standalone
@@ -1664,4 +1726,4 @@ function findPreviousChange(state, startPos) {
1664
1726
  return result.value;
1665
1727
  }
1666
1728
  //#endregion
1667
- export { acceptAIEditRevision, acceptAllChanges, acceptAllSuggestions, acceptChange, acceptSuggestion, addCommentMark, findAIEditRevisionRange, findChangeAtPosition, findNextChange, findParagraphBoundaryChangeAtPosition, findPreviousChange, findSuggestionRange, getSuggestions, rejectAIEditRevision, rejectAllChanges, rejectAllSuggestions, rejectChange, rejectSuggestion, removeCommentMark, resolveAllChangesInHeadlessState };
1729
+ export { acceptAIEditRevision, acceptAllChanges, acceptAllSuggestions, acceptChange, acceptSuggestion, addCommentMark, findAIEditRevisionRange, findChangeAtPosition, findNextChange, findParagraphBoundaryChangeAtPosition, findPreviousChange, findSuggestionRange, getSuggestions, rejectAIEditRevision, rejectAllChanges, rejectAllSuggestions, rejectChange, rejectSuggestion, removeCommentMark, resolveAllChangesInHeadlessState, resolveAllChangesInHeadlessStateWithMapping };
@@ -66,10 +66,16 @@ declare function paragraphRejectOriginalFormatting(previousFormatting: Paragraph
66
66
  * Rejected section properties: the stored old sectPr wholesale, preserving
67
67
  * the live header/footer references — `EG_HdrFtrReferences` is not part of
68
68
  * the `CT_SectPrBase` payload a `w:sectPrChange` stores (ECMA-376
69
- * §17.13.5.32), so those children survive a reject. The caller re-attaches
70
- * whatever `propertyChanges` remain unresolved.
69
+ * §17.13.5.32), so those children survive a native reject. An explicit Folio reference
70
+ * history replaces that selection, including restoring its absence. The
71
+ * caller re-attaches whatever `propertyChanges` remain unresolved.
71
72
  */
72
- declare function sectionRejectProperties(live: document_d_exports.SectionProperties, previousProperties: document_d_exports.SectionProperties | undefined): document_d_exports.SectionProperties;
73
+ type SectionRejectPropertiesOptions = {
74
+ live: document_d_exports.SectionProperties;
75
+ previousProperties: document_d_exports.SectionProperties | undefined;
76
+ previousReferences?: document_d_exports.SectionPropertyChange["previousReferences"];
77
+ };
78
+ declare function sectionRejectProperties({ live, previousProperties, previousReferences }: SectionRejectPropertiesOptions): document_d_exports.SectionProperties;
73
79
  /**
74
80
  * Attr patch for rejecting a `w:tblPrChange`: the stored old tblPr wholesale
75
81
  * (`w:tblPrChange` stores the complete previous tblPr, so every tblPr-derived
@@ -220,19 +220,13 @@ function paragraphRejectOriginalFormatting(previousFormatting, liveOriginal) {
220
220
  if (Object.keys(result).length === 0) return null;
221
221
  return result;
222
222
  }
223
- /**
224
- * Rejected section properties: the stored old sectPr wholesale, preserving
225
- * the live header/footer references — `EG_HdrFtrReferences` is not part of
226
- * the `CT_SectPrBase` payload a `w:sectPrChange` stores (ECMA-376
227
- * §17.13.5.32), so those children survive a reject. The caller re-attaches
228
- * whatever `propertyChanges` remain unresolved.
229
- */
230
- function sectionRejectProperties(live, previousProperties) {
223
+ function sectionRejectProperties({ live, previousProperties, previousReferences }) {
231
224
  const restored = { ...previousProperties };
232
225
  delete restored.propertyChanges;
233
- if (live.headerReferences) restored.headerReferences = live.headerReferences;
226
+ const references = previousReferences ?? live;
227
+ if (references.headerReferences) restored.headerReferences = references.headerReferences;
234
228
  else delete restored.headerReferences;
235
- if (live.footerReferences) restored.footerReferences = live.footerReferences;
229
+ if (references.footerReferences) restored.footerReferences = references.footerReferences;
236
230
  else delete restored.footerReferences;
237
231
  return restored;
238
232
  }
@@ -1,8 +1,9 @@
1
- import { numPrEqual } from "../../docx/numberingParser.js";
1
+ import { imageRawXmlFingerprint } from "../../docx/imageRawXml.js";
2
2
  import { PROSE_PARAGRAPH_SOURCE_CONTRACT_ATTR, ParagraphPropertySourceValidationError, copyDocumentParagraphPropertySourceContract, copyDocumentParagraphPropertySources, copyParagraphPropertyCapture, copyParagraphPropertySource, decodeTableCellParagraphSourcePayload, getDocumentParagraphPropertySourceContract, getParagraphPropertySource, getParagraphPropertySourceCandidate, getParagraphPropertySourceToken, getParagraphPropertySourceTransferId, getProseDocumentParagraphPropertySourceContract, getProseParagraphPropertySourceToken, isParagraphPropertySourceToken, linkParagraphPropertySourceCandidate, paragraphPropertySourceBelongsToDocument, paragraphPropertySourceTokenMatchesContract, recreateProseNodeWithParagraphPropertySource, restoreTableCellsWithParagraphPropertySources, visitDocumentStoryParagraphs, visitTableCellParagraphPropertySourceBindings } from "../../docx/paragraphPropertySource.js";
3
3
  import { visitDocxParagraphs } from "../../docx/paragraphTraversal.js";
4
4
  import { ShapeOutlineStyleSchema, narrowEnum } from "../../docx/parserEnums.js";
5
5
  import { DATE_UTC_ATTRIBUTE } from "../../docx/trackedChangeInfo.js";
6
+ import { isStyleSourcedParagraphNumbering, modelParagraphFormattingEmission, sameAuthoredParagraphNumberingReference } from "../../internal/paragraphFormattingSerialization.js";
6
7
  import { createStyleEngine } from "../../style-engine/styleEngine.js";
7
8
  import { OUTLINE_STYLE_CSS_ALIASES, normalizeShapeTextAnchor } from "../../types/documentEnumValues.js";
8
9
  import { canonicalJson } from "../../utils/canonicalJson.js";
@@ -106,9 +107,10 @@ const uniqueParagraphsById = (content, includeTransferIds = false) => {
106
107
  const restoreParagraphPropertySource = (paragraph, baseParagraph) => {
107
108
  copyParagraphPropertySource(paragraph, baseParagraph);
108
109
  const baseFormatting = baseParagraph.formatting;
109
- if (!baseFormatting?.numPr || !baseFormatting.numPrFromStyle || !numPrEqual(baseFormatting.numPr, baseFormatting.numPrFromStyle)) return;
110
- const { numPr, numPrFromStyle, ...authoredFormatting } = baseFormatting;
111
- if (canonicalJson(paragraph.formatting ?? {}) !== canonicalJson(authoredFormatting)) return;
110
+ if (!baseFormatting) return;
111
+ const { numPr, numPrFromStyle } = baseFormatting;
112
+ if (!numPr || !numPrFromStyle || !isStyleSourcedParagraphNumbering(numPr, numPrFromStyle)) return;
113
+ if (canonicalJson(modelParagraphFormattingEmission(paragraph.formatting)) !== canonicalJson(modelParagraphFormattingEmission(baseFormatting))) return;
112
114
  paragraph.formatting = {
113
115
  ...paragraph.formatting,
114
116
  numPr,
@@ -741,6 +743,7 @@ function convertPMParagraph(node, documentCounts, textBoxAnchorMarkers, styleRes
741
743
  };
742
744
  if (attrs.paraId) paragraph.paraId = attrs.paraId;
743
745
  if (attrs.textId) paragraph.textId = attrs.textId;
746
+ if (attrs.reviewCarrier) paragraph.reviewCarrier = attrs.reviewCarrier;
744
747
  const pFormatting = paragraphAttrsToFormatting(attrs);
745
748
  if (pFormatting) paragraph.formatting = pFormatting;
746
749
  const listRendering = listRenderingFromAttrs(attrs);
@@ -777,15 +780,6 @@ const propertyChangeFromAttrs = (change) => {
777
780
  ...currentFormatting !== void 0 && { currentFormatting }
778
781
  };
779
782
  };
780
- /**
781
- * Whether the paragraph's numbering still comes verbatim from its style —
782
- * serialize no direct `<w:numPr>` then. The moment a list command changes
783
- * `numPr` the values diverge and the numbering serializes as direct
784
- * formatting, so a stale provenance value can never swallow a user edit.
785
- */
786
- function isStyleSourcedNumPr(attrs) {
787
- return attrs.numPrFromStyle != null && attrs.numPr != null && numPrEqual(attrs.numPr, attrs.numPrFromStyle);
788
- }
789
783
  function assignBooleanToggle(result, attrs, orig, key) {
790
784
  const value = attrs[key] ?? void 0;
791
785
  if (value === (orig[key] ?? void 0)) return;
@@ -834,10 +828,10 @@ function paragraphAttrsToFormatting(attrs) {
834
828
  else Reflect.deleteProperty(result, "lineSpacingRule");
835
829
  if (directAlignment === void 0) Reflect.deleteProperty(result, "alignment");
836
830
  else result.alignment = directAlignment;
837
- if (isStyleSourcedNumPr(attrs)) {
831
+ if (isStyleSourcedParagraphNumbering(attrs.numPr, attrs.numPrFromStyle)) {
838
832
  delete result.numPr;
839
833
  delete result.numPrFromStyle;
840
- } else if (attrs.numPr !== orig.numPr && !numPrEqual(attrs.numPr, orig.numPr)) {
834
+ } else if (attrs.numPr !== orig.numPr && !sameAuthoredParagraphNumberingReference(attrs.numPr, orig.numPr)) {
841
835
  if (attrs.numPr) result.numPr = attrs.numPr;
842
836
  else delete result.numPr;
843
837
  delete result.numPrFromStyle;
@@ -874,7 +868,7 @@ function paragraphAttrsToFormatting(attrs) {
874
868
  if (attrs.indentRight) f.indentRight = attrs.indentRight;
875
869
  if (attrs.indentFirstLine) f.indentFirstLine = attrs.indentFirstLine;
876
870
  if (attrs.hangingIndent) f.hangingIndent = attrs.hangingIndent;
877
- if (attrs.numPr && !isStyleSourcedNumPr(attrs)) f.numPr = attrs.numPr;
871
+ if (attrs.numPr && !isStyleSourcedParagraphNumbering(attrs.numPr, attrs.numPrFromStyle)) f.numPr = attrs.numPr;
878
872
  if (attrs.styleId) f.styleId = attrs.styleId;
879
873
  if (attrs.borders) f.borders = attrs.borders;
880
874
  if (attrs.shading) f.shading = attrs.shading;
@@ -1145,6 +1139,10 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
1145
1139
  }));
1146
1140
  return;
1147
1141
  }
1142
+ if (node.type.name === "math") {
1143
+ currentTrackedChange.wrapper.content.push(createMathFromNode(node));
1144
+ return;
1145
+ }
1148
1146
  const run = createTrackedChangeRun({
1149
1147
  ...formattingContext,
1150
1148
  marks: otherMarks,
@@ -1718,9 +1716,6 @@ function createFieldFromNode(node, { baseParagraphFormatting, inheritedFormattin
1718
1716
  case "NUMPAGES":
1719
1717
  displayText = "1";
1720
1718
  break;
1721
- default:
1722
- displayText = " ";
1723
- break;
1724
1719
  }
1725
1720
  const displayRun = {
1726
1721
  type: "run",
@@ -1732,13 +1727,14 @@ function createFieldFromNode(node, { baseParagraphFormatting, inheritedFormattin
1732
1727
  };
1733
1728
  if (marks && node.type.name === "field") restoreRunPropertyChanges(displayRun, marks);
1734
1729
  const fieldContent = extractedContent.length > 0 ? synchronizeFieldDisplayText(extractedContent, displayText, displayRun) : [];
1730
+ const fallbackFieldContent = displayText ? [displayRun] : [];
1735
1731
  if (attrs.fieldKind === "complex") {
1736
1732
  const complex = {
1737
1733
  type: "complexField",
1738
1734
  instruction: attrs.instruction,
1739
1735
  fieldType: attrs.fieldType,
1740
1736
  fieldCode: [],
1741
- fieldResult: fieldContent.length > 0 ? fieldContent.filter((content) => content.type === "run") : [displayRun]
1737
+ fieldResult: fieldContent.length > 0 ? fieldContent.filter((content) => content.type === "run") : fallbackFieldContent
1742
1738
  };
1743
1739
  if (attrs.fldLock) complex.fldLock = true;
1744
1740
  if (attrs.dirty) complex.dirty = true;
@@ -1748,7 +1744,7 @@ function createFieldFromNode(node, { baseParagraphFormatting, inheritedFormattin
1748
1744
  type: "simpleField",
1749
1745
  instruction: attrs.instruction,
1750
1746
  fieldType: attrs.fieldType,
1751
- content: fieldContent.length > 0 ? fieldContent : [displayRun]
1747
+ content: fieldContent.length > 0 ? fieldContent : fallbackFieldContent
1752
1748
  };
1753
1749
  if (attrs.fldLock) simple.fldLock = true;
1754
1750
  if (attrs.dirty) simple.dirty = true;
@@ -1881,7 +1877,8 @@ function createImageRun(node) {
1881
1877
  } : {
1882
1878
  type: "drawing",
1883
1879
  image,
1884
- ...attrs._docxRawXml ? { rawXml: attrs._docxRawXml } : {}
1880
+ ...attrs._docxRawXml ? { rawXml: attrs._docxRawXml } : {},
1881
+ ...attrs._docxRawXml ? { rawImageFingerprint: imageRawXmlFingerprint(image) } : {}
1885
1882
  }]
1886
1883
  };
1887
1884
  }
@@ -1967,6 +1964,7 @@ const RUN_FORMATTING_VISUAL_GROUPS = {
1967
1964
  smallCaps: "smallCaps",
1968
1965
  allCaps: "allCaps",
1969
1966
  hidden: "hidden",
1967
+ noProof: null,
1970
1968
  color: "color",
1971
1969
  highlight: "highlight",
1972
1970
  shading: "shading",
@@ -2000,6 +1998,7 @@ const RUN_FORMATTING_FAST_PATH_DISPOSITION = {
2000
1998
  smallCaps: "visual",
2001
1999
  allCaps: "visual",
2002
2000
  hidden: "visual",
2001
+ noProof: "structural",
2003
2002
  color: "visual",
2004
2003
  highlight: "visual",
2005
2004
  shading: "visual",
@@ -2189,6 +2188,7 @@ const DIRECT_OVERRIDE_FORMATTING_PROPERTIES = [
2189
2188
  "emboss",
2190
2189
  "fontSizeCs",
2191
2190
  "hidden",
2191
+ "noProof",
2192
2192
  "imprint",
2193
2193
  "italic",
2194
2194
  "italicCs",
@@ -13,7 +13,7 @@ import { stampNumberedRefFieldBaselines } from "../numberedRefFields.js";
13
13
  import { pageBreakRunParagraphProjectionDispositionForFeatures } from "../pageBreakRunProjection.js";
14
14
  import { directionFromBidi } from "../paragraphDirection.js";
15
15
  import { lineSpacingProvenanceFromSpacing } from "../paragraphSpacing.js";
16
- import { getParagraphMarkSuppressionOverrides, hasDirectRunFormatting, stripParagraphMarkFormattingForBodyRuns, stripParagraphMarkOnlyFormatting, suppressParagraphMarkFormatting } from "../runStyleFormatting.js";
16
+ import { getParagraphMarkSuppressionOverrides, hasDirectRunFormatting, resolveParagraphBodyRunFormatting, stripParagraphMarkFormattingForBodyRuns, stripParagraphMarkOnlyFormatting, suppressParagraphMarkFormatting } from "../runStyleFormatting.js";
17
17
  import { schema } from "../schema/index.js";
18
18
  import { COMPLEX_SCRIPT_RUN_PROPERTY_KEYS } from "../schema/marks.js";
19
19
  import { cascadeStyleTextFormatting } from "../styles/styleToggleCascade.js";
@@ -202,45 +202,14 @@ function convertParagraph(paragraph, styleResolver, context, activeCommentIds, e
202
202
  if (!node) return;
203
203
  emitInlineNodes([node]);
204
204
  };
205
- let styleRunFormatting;
206
- let paragraphStyleRunFormatting;
207
- let paragraphStyleFontFamily;
208
- if (styleResolver) {
209
- const resolved = styleResolver.resolveParagraphStyle(paragraph.formatting?.styleId);
210
- styleRunFormatting = extraRunFormatting === void 0 ? resolved.runFormatting : withoutFontFamily(resolved.runFormatting);
211
- const paragraphStyle = paragraph.formatting?.styleId ? styleResolver.getStyle(paragraph.formatting.styleId) ?? styleResolver.getDefaultParagraphStyle() : styleResolver.getDefaultParagraphStyle();
212
- paragraphStyleRunFormatting = paragraphStyle?.type === "paragraph" ? paragraphStyle.rPr : void 0;
213
- paragraphStyleFontFamily = resolveParagraphStyleFontFamily(paragraph.formatting?.styleId, styleResolver);
214
- }
215
205
  const paragraphRunFormatting = resolveRunFormattingWithoutDefaults(paragraph.formatting?.runProperties, styleResolver);
216
206
  let inheritableParagraphRunFormatting;
217
207
  if (paragraphRunFormatting && !isTocParagraph && paragraph.formatting?.styleId === void 0) inheritableParagraphRunFormatting = stripParagraphMarkFormattingForBodyRuns(paragraphRunFormatting);
218
- const ordinaryStyleFormatting = paragraph.formatting?.styleId === void 0 ? mergeTextFormatting(styleRunFormatting, extraRunFormatting) : mergeTextFormatting(extraRunFormatting, styleRunFormatting);
219
- const orderedToggleFormatting = cascadeStyleTextFormatting([
220
- {
221
- formatting: styleResolver?.getDocDefaults()?.rPr,
222
- type: "defaults"
223
- },
224
- {
225
- formatting: extraRunFormatting,
226
- type: "style"
227
- },
228
- {
229
- formatting: paragraphStyleRunFormatting,
230
- type: "style"
231
- }
232
- ], { ordinaryFormatting: ordinaryStyleFormatting });
233
- let baseRunFormatting = orderedToggleFormatting.formatting;
234
- if (paragraphStyleFontFamily) baseRunFormatting = mergeTextFormatting(baseRunFormatting, { fontFamily: paragraphStyleFontFamily });
235
- const defaultCharacterFormatting = styleResolver?.getDefaultCharacterStyle()?.rPr;
236
- const ordinaryBaseWithDefaultCharacter = mergeTextFormatting(defaultCharacterFormatting, baseRunFormatting);
237
- const defaultCharacterStyleCascade = cascadeStyleTextFormatting([{
238
- cascade: orderedToggleFormatting,
239
- type: "carried"
240
- }, {
241
- formatting: defaultCharacterFormatting,
242
- type: "style"
243
- }], { ordinaryFormatting: ordinaryBaseWithDefaultCharacter });
208
+ const { baseFormatting: baseRunFormatting, baseToggleCascade: orderedToggleFormatting, defaultFormatting: ordinaryBaseWithDefaultCharacter, defaultToggleCascade: defaultCharacterStyleCascade } = resolveParagraphBodyRunFormatting({
209
+ styleId: paragraph.formatting?.styleId,
210
+ tableRunFormatting: extraRunFormatting,
211
+ styleResolver
212
+ });
244
213
  const ordinaryDefaultRunFormatting = mergeTextFormatting(ordinaryBaseWithDefaultCharacter, inheritableParagraphRunFormatting);
245
214
  const defaultToggleCascade = cascadeStyleTextFormatting([{
246
215
  cascade: defaultCharacterStyleCascade,
@@ -250,8 +219,11 @@ function convertParagraph(paragraph, styleResolver, context, activeCommentIds, e
250
219
  type: "direct"
251
220
  }], { ordinaryFormatting: ordinaryDefaultRunFormatting });
252
221
  const defaultRunFormatting = defaultToggleCascade.formatting;
253
- if (extraRunFormatting !== void 0) if (defaultRunFormatting) attrs.defaultTextFormatting = defaultRunFormatting;
254
- else delete attrs.defaultTextFormatting;
222
+ if (extraRunFormatting !== void 0) {
223
+ attrs._tableRunFormatting = extraRunFormatting;
224
+ if (defaultRunFormatting) attrs.defaultTextFormatting = defaultRunFormatting;
225
+ else delete attrs.defaultTextFormatting;
226
+ }
255
227
  const getInheritedRunFormatting = (formatting, fieldType) => {
256
228
  const hasCharacterStyle = formatting?.styleId !== void 0;
257
229
  const inheritedBaseFormatting = hasCharacterStyle ? baseRunFormatting : ordinaryBaseWithDefaultCharacter;
@@ -350,24 +322,6 @@ function convertParagraph(paragraph, styleResolver, context, activeCommentIds, e
350
322
  content: inlineNodes
351
323
  });
352
324
  }
353
- const withoutFontFamily = (formatting) => {
354
- if (!formatting?.fontFamily) return formatting;
355
- const { fontFamily: _fontFamily, ...withoutFont } = formatting;
356
- return Object.keys(withoutFont).length > 0 ? withoutFont : void 0;
357
- };
358
- const resolveParagraphStyleFontFamily = (styleId, styleResolver) => {
359
- let style = styleId ? styleResolver.getStyle(styleId) : styleResolver.getDefaultParagraphStyle();
360
- const visited = /* @__PURE__ */ new Set();
361
- const styleChain = [];
362
- while (style?.type === "paragraph" && !visited.has(style.styleId)) {
363
- visited.add(style.styleId);
364
- if (style.rPr?.fontFamily) styleChain.push({ fontFamily: style.rPr.fontFamily });
365
- style = style.basedOn ? styleResolver.getStyle(style.basedOn) : void 0;
366
- }
367
- let formatting;
368
- for (const styleFormatting of styleChain.toReversed()) formatting = mergeTextFormatting(formatting, styleFormatting);
369
- return formatting?.fontFamily;
370
- };
371
325
  /**
372
326
  * Apply comment marks to PM nodes within a comment range.
373
327
  */
@@ -418,6 +372,9 @@ function convertTrackedChange(change, markType, nextHyperlinkInstanceIndex, next
418
372
  textBoxAnchors
419
373
  });
420
374
  if (fieldNode) nodes.push(fieldNode);
375
+ } else if (item.type === "mathEquation") {
376
+ const mathNode = convertMathEquation(item);
377
+ if (mathNode) nodes.push(mathNode);
421
378
  } else if (item.type === "insertion" || item.type === "deletion" || item.type === "moveFrom" || item.type === "moveTo") {
422
379
  const nestedMarkType = item.type === "insertion" || item.type === "moveTo" ? "insertion" : "deletion";
423
380
  const nestedMoveKind = item.type === "moveFrom" || item.type === "moveTo" ? item.type : null;
@@ -460,6 +417,7 @@ function paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOver
460
417
  const attrs = {};
461
418
  if (paragraph.paraId) attrs.paraId = paragraph.paraId;
462
419
  if (paragraph.textId) attrs.textId = paragraph.textId;
420
+ if (paragraph.reviewCarrier) attrs.reviewCarrier = paragraph.reviewCarrier;
463
421
  if (styleId) attrs.styleId = styleId;
464
422
  if (tableOfContentsLevel !== void 0) attrs._tableOfContentsLevel = tableOfContentsLevel;
465
423
  if (formatting?.numPr) attrs.numPr = formatting.numPr;
@@ -1415,6 +1373,7 @@ const RUN_FORMATTING_INFERENCE = {
1415
1373
  smallCaps: "visible-boolean",
1416
1374
  allCaps: "visible-boolean",
1417
1375
  hidden: "visible-boolean",
1376
+ noProof: "structural",
1418
1377
  color: "color",
1419
1378
  highlight: "visible-value",
1420
1379
  shading: "preserve",
@@ -188,6 +188,7 @@ const paragraphNodeSpec = {
188
188
  [PROSE_PARAGRAPH_SOURCE_TOKEN_ATTR]: { default: null },
189
189
  idStability: { default: void 0 },
190
190
  textId: { default: null },
191
+ reviewCarrier: { default: void 0 },
191
192
  alignment: { default: null },
192
193
  alignmentFromStyle: { default: void 0 },
193
194
  kinsoku: { default: null },
@@ -240,6 +241,7 @@ const paragraphNodeSpec = {
240
241
  contextualSpacing: { default: null },
241
242
  runInWithNext: { default: null },
242
243
  defaultTextFormatting: { default: null },
244
+ _tableRunFormatting: { default: void 0 },
243
245
  sectionBreakType: { default: null },
244
246
  direction: { default: null },
245
247
  outlineLevel: { default: null },
@@ -19,6 +19,7 @@ function buildRunFormattingOverrideAttrs(formatting, options) {
19
19
  if (formatting?.allCaps !== void 0) attrs.allCaps = formatting.allCaps;
20
20
  if (formatting?.smallCaps !== void 0) attrs.smallCaps = formatting.smallCaps;
21
21
  if (formatting?.hidden !== void 0) attrs.hidden = formatting.hidden;
22
+ if (formatting?.noProof !== void 0) attrs.noProof = formatting.noProof;
22
23
  if (formatting?.emboss !== void 0) attrs.emboss = formatting.emboss;
23
24
  if (formatting?.imprint !== void 0) attrs.imprint = formatting.imprint;
24
25
  if (formatting?.shadow !== void 0) attrs.shadow = formatting.shadow;
@@ -58,6 +59,7 @@ function applyRunFormattingOverrideAttrs(formatting, attrs) {
58
59
  if (attrs.allCaps !== void 0) formatting.allCaps = attrs.allCaps;
59
60
  if (attrs.smallCaps !== void 0) formatting.smallCaps = attrs.smallCaps;
60
61
  if (attrs.hidden !== void 0) formatting.hidden = attrs.hidden;
62
+ if (attrs.noProof !== void 0) formatting.noProof = attrs.noProof;
61
63
  if (attrs.emboss !== void 0) formatting.emboss = attrs.emboss;
62
64
  if (attrs.imprint !== void 0) formatting.imprint = attrs.imprint;
63
65
  if (attrs.shadow !== void 0) formatting.shadow = attrs.shadow;
@@ -101,6 +103,7 @@ const RunFormattingOverrideExtension = createMarkExtension({
101
103
  allCaps: { default: null },
102
104
  smallCaps: { default: null },
103
105
  hidden: { default: null },
106
+ noProof: { default: null },
104
107
  emboss: { default: null },
105
108
  imprint: { default: null },
106
109
  shadow: { default: null },
@@ -1,3 +1,5 @@
1
+ import { expectImageAttrs, mergeImageAttrs } from "./attrs/index.js";
2
+ import { DRAWING_RAW_XML_MODES } from "@stll/docx-core/model";
1
3
  //#region src/prosemirror/imageCommit.ts
2
4
  const MIN_IMAGE_PX = 20;
3
5
  const MAX_IMAGE_PX = 2e3;
@@ -40,6 +42,7 @@ function isFloatingImage(node) {
40
42
  function imageNodeAt(view, pmPos) {
41
43
  const node = view.state.doc.nodeAt(pmPos);
42
44
  if (!node || node.type.name !== "image") return null;
45
+ if (expectImageAttrs(node)._docxRawXmlMode === DRAWING_RAW_XML_MODES.PRESERVE_ONLY) return null;
43
46
  return node;
44
47
  }
45
48
  /**
@@ -50,11 +53,10 @@ function commitImageResize(view, pmPos, newWidth, newHeight) {
50
53
  try {
51
54
  const node = imageNodeAt(view, pmPos);
52
55
  if (!node) return null;
53
- view.dispatch(view.state.tr.setNodeMarkup(pmPos, void 0, {
54
- ...node.attrs,
56
+ view.dispatch(view.state.tr.setNodeMarkup(pmPos, void 0, mergeImageAttrs(node, {
55
57
  width: newWidth,
56
58
  height: newHeight
57
- }));
59
+ })));
58
60
  return pmPos;
59
61
  } catch {
60
62
  return null;
@@ -69,7 +71,7 @@ function commitImageFloatMove(view, pmPos, hOffsetEmu, vOffsetEmu) {
69
71
  try {
70
72
  const node = imageNodeAt(view, pmPos);
71
73
  if (!node) return null;
72
- const newPosition = {
74
+ view.dispatch(view.state.tr.setNodeMarkup(pmPos, void 0, mergeImageAttrs(node, { position: {
73
75
  horizontal: {
74
76
  posOffset: hOffsetEmu,
75
77
  relativeTo: "margin"
@@ -78,11 +80,7 @@ function commitImageFloatMove(view, pmPos, hOffsetEmu, vOffsetEmu) {
78
80
  posOffset: vOffsetEmu,
79
81
  relativeTo: "margin"
80
82
  }
81
- };
82
- view.dispatch(view.state.tr.setNodeMarkup(pmPos, void 0, {
83
- ...node.attrs,
84
- position: newPosition
85
- }));
83
+ } })));
86
84
  return pmPos;
87
85
  } catch {
88
86
  return null;
@@ -0,0 +1,21 @@
1
+ import { document_d_exports } from "../types/document.js";
2
+ import { FolioContentParagraphIndentation } from "../compare/content-types.js";
3
+ import { ParagraphAttrs } from "./schema/nodes.js";
4
+ //#region src/prosemirror/paragraphIndentation.d.ts
5
+ /** The authored `w:ind` attribute cluster. */
6
+ type DirectParagraphIndentation = FolioContentParagraphIndentation;
7
+ /** Project only authored `w:ind` attributes, preserving zero and false. */
8
+ declare const paragraphIndentationFromFormatting: (formatting: document_d_exports.ParagraphFormatting | null | undefined) => DirectParagraphIndentation | undefined;
9
+ /** Read direct indentation without materializing values inherited from a style. */
10
+ declare const directParagraphIndentation: (attrs: ParagraphAttrs) => DirectParagraphIndentation | undefined;
11
+ declare const paragraphIndentationEqual: (left: DirectParagraphIndentation | null | undefined, right: DirectParagraphIndentation | null | undefined) => boolean;
12
+ /** Replace the complete direct `w:ind` cluster in canonical formatting. */
13
+ declare const withDirectParagraphIndentation: (formatting: document_d_exports.ParagraphFormatting | null | undefined, indentation: DirectParagraphIndentation | null | undefined) => document_d_exports.ParagraphFormatting | undefined;
14
+ type ParagraphIndentationAttrPatchOptions = {
15
+ direct: DirectParagraphIndentation | null | undefined;
16
+ inherited: DirectParagraphIndentation | null | undefined;
17
+ };
18
+ /** Project direct-over-inherited indentation into paragraph attrs. */
19
+ declare const paragraphIndentationAttrPatch: ({ direct, inherited }: ParagraphIndentationAttrPatchOptions) => Record<string, unknown>;
20
+ //#endregion
21
+ export { DirectParagraphIndentation, directParagraphIndentation, paragraphIndentationAttrPatch, paragraphIndentationEqual, paragraphIndentationFromFormatting, withDirectParagraphIndentation };
@@ -0,0 +1,72 @@
1
+ import { panic } from "better-result";
2
+ //#region src/prosemirror/paragraphIndentation.ts
3
+ const DIRECT_PARAGRAPH_INDENTATION_KEYS = [
4
+ "indentLeft",
5
+ "indentRight",
6
+ "indentFirstLine",
7
+ "hangingIndent"
8
+ ];
9
+ const copyIndentationValue = ({ target, key, value }) => {
10
+ switch (key) {
11
+ case "hangingIndent":
12
+ if (typeof value === "boolean") target.hangingIndent = value;
13
+ return;
14
+ case "indentLeft":
15
+ case "indentRight":
16
+ case "indentFirstLine":
17
+ if (typeof value === "number") target[key] = value;
18
+ return;
19
+ default: return panic("Unhandled paragraph indentation property", { key });
20
+ }
21
+ };
22
+ /** Project only authored `w:ind` attributes, preserving zero and false. */
23
+ const paragraphIndentationFromFormatting = (formatting) => {
24
+ if (!formatting) return;
25
+ const indentation = {};
26
+ for (const key of DIRECT_PARAGRAPH_INDENTATION_KEYS) copyIndentationValue({
27
+ target: indentation,
28
+ key,
29
+ value: formatting[key]
30
+ });
31
+ if (indentation.indentFirstLine !== void 0 && indentation.hangingIndent === void 0) indentation.hangingIndent = false;
32
+ return Object.keys(indentation).length > 0 ? indentation : void 0;
33
+ };
34
+ /** Read direct indentation without materializing values inherited from a style. */
35
+ const directParagraphIndentation = (attrs) => {
36
+ const original = paragraphIndentationFromFormatting(attrs._originalFormatting);
37
+ if (!original) return;
38
+ const indentation = {};
39
+ for (const key of DIRECT_PARAGRAPH_INDENTATION_KEYS) {
40
+ if (original[key] === void 0) continue;
41
+ copyIndentationValue({
42
+ target: indentation,
43
+ key,
44
+ value: attrs[key]
45
+ });
46
+ }
47
+ return Object.keys(indentation).length > 0 ? indentation : void 0;
48
+ };
49
+ const paragraphIndentationEqual = (left, right) => DIRECT_PARAGRAPH_INDENTATION_KEYS.every((key) => left?.[key] === right?.[key]);
50
+ /** Replace the complete direct `w:ind` cluster in canonical formatting. */
51
+ const withDirectParagraphIndentation = (formatting, indentation) => {
52
+ const result = { ...formatting };
53
+ for (const key of DIRECT_PARAGRAPH_INDENTATION_KEYS) Reflect.deleteProperty(result, key);
54
+ if (indentation) Object.assign(result, indentation);
55
+ return Object.keys(result).length > 0 ? result : void 0;
56
+ };
57
+ /** Project direct-over-inherited indentation into paragraph attrs. */
58
+ const paragraphIndentationAttrPatch = ({ direct, inherited }) => {
59
+ const effective = {
60
+ ...inherited,
61
+ ...direct
62
+ };
63
+ const hangingIndent = direct?.indentFirstLine === void 0 ? effective.hangingIndent ?? false : direct.hangingIndent === true;
64
+ return {
65
+ indentLeft: effective.indentLeft ?? null,
66
+ indentRight: effective.indentRight ?? null,
67
+ indentFirstLine: effective.indentFirstLine ?? null,
68
+ hangingIndent
69
+ };
70
+ };
71
+ //#endregion
72
+ export { directParagraphIndentation, paragraphIndentationAttrPatch, paragraphIndentationEqual, paragraphIndentationFromFormatting, withDirectParagraphIndentation };
@@ -4,5 +4,7 @@ import { EditorState, Plugin } from "prosemirror-state";
4
4
  //#region src/prosemirror/plugins/documentNumbering.d.ts
5
5
  declare const createDocumentNumberingPlugin: (definitions: document_d_exports.NumberingDefinitions | null | undefined) => Plugin;
6
6
  declare const getDocumentNumbering: (state: EditorState) => NumberingMap | null;
7
+ /** Replace numbering state while retaining every unrelated plugin state. */
8
+ declare const withDocumentNumbering: (state: EditorState, definitions: document_d_exports.NumberingDefinitions) => EditorState;
7
9
  //#endregion
8
- export { createDocumentNumberingPlugin, getDocumentNumbering };
10
+ export { createDocumentNumberingPlugin, getDocumentNumbering, withDocumentNumbering };