@stll/folio-core 0.56.0 → 0.57.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 (142) hide show
  1. package/dist/ai-edits/apply.js +45 -14
  2. package/dist/ai-edits/batch-claims.d.ts +3 -1
  3. package/dist/ai-edits/batch-claims.js +25 -1
  4. package/dist/ai-edits/table-row-column-mutations.js +17 -3
  5. package/dist/ai-suggestions/apply.js +20 -1
  6. package/dist/compare/inline-atoms.js +40 -16
  7. package/dist/compare/inline-provenance.js +12 -5
  8. package/dist/compat/eigenpal.d.ts +2 -1
  9. package/dist/compat/eigenpal.js +2 -1
  10. package/dist/controller/canonicalClipboard.js +7 -1
  11. package/dist/controller/canonicalComments.d.ts +41 -0
  12. package/dist/controller/canonicalComments.js +152 -0
  13. package/dist/controller/canonicalComposition.d.ts +4 -0
  14. package/dist/controller/canonicalComposition.js +43 -11
  15. package/dist/controller/canonicalInlineProjection.d.ts +6 -1
  16. package/dist/controller/canonicalInlineProjection.js +86 -3
  17. package/dist/controller/canonicalInput.js +10 -1
  18. package/dist/controller/canonicalInputTimer.d.ts +10 -1
  19. package/dist/controller/canonicalInputTimer.js +24 -1
  20. package/dist/controller/canonicalPublicOperations.d.ts +2 -2
  21. package/dist/controller/canonicalPublicOperations.js +107 -15
  22. package/dist/controller/canonicalSelection.d.ts +18 -0
  23. package/dist/controller/canonicalSelection.js +32 -0
  24. package/dist/controller/canonicalSession.d.ts +3 -0
  25. package/dist/controller/canonicalSession.js +58 -24
  26. package/dist/controller/canonicalStoryEditor.d.ts +2 -0
  27. package/dist/controller/canonicalStoryEditor.js +20 -0
  28. package/dist/controller/folioEditor.js +13 -0
  29. package/dist/controller/headerFooterEditorManager.d.ts +1 -1
  30. package/dist/controller/headerFooterEditorManager.js +25 -11
  31. package/dist/controller/hiddenEditorApi.d.ts +13 -2
  32. package/dist/controller/hiddenEditorApi.js +4 -0
  33. package/dist/controller/hiddenEditorManager.d.ts +3 -1
  34. package/dist/controller/hiddenEditorManager.js +166 -13
  35. package/dist/controller/noteEditorManager.d.ts +1 -1
  36. package/dist/controller/noteEditorManager.js +28 -13
  37. package/dist/docx/builtInStyles.js +13 -6
  38. package/dist/docx/containerChildren.gen.d.ts +3 -1
  39. package/dist/docx/containerChildren.gen.js +33 -1
  40. package/dist/docx/fieldParser.js +14 -2
  41. package/dist/docx/hyperlinkParser.d.ts +1 -1
  42. package/dist/docx/hyperlinkParser.js +20 -1
  43. package/dist/docx/inlineWrapperContent.d.ts +4 -4
  44. package/dist/docx/inlineWrapperContent.js +4 -4
  45. package/dist/docx/linkedSdtPreservation.d.ts +10 -0
  46. package/dist/docx/linkedSdtPreservation.js +37 -0
  47. package/dist/docx/paragraphParser.js +88 -67
  48. package/dist/docx/paragraphPropertySource.d.ts +22 -1
  49. package/dist/docx/paragraphPropertySource.js +107 -1
  50. package/dist/docx/preservedRunContent.js +2 -1
  51. package/dist/docx/relsParser.js +26 -2
  52. package/dist/docx/rezip.js +9 -6
  53. package/dist/docx/selectiveSave.js +10 -8
  54. package/dist/docx/serializer/commentSerializer.d.ts +4 -1
  55. package/dist/docx/serializer/commentSerializer.js +7 -3
  56. package/dist/docx/serializer/paragraphSerializer.js +207 -94
  57. package/dist/docx/server/materializeYjsDocx.js +14 -6
  58. package/dist/docx/server/migrateYjsAttrSchema.js +17 -5
  59. package/dist/i18n/messages/ar.gen.js +4 -0
  60. package/dist/i18n/messages/catalogs.gen.d.ts +68 -0
  61. package/dist/i18n/messages/catalogs.gen.js +68 -0
  62. package/dist/i18n/messages/cs.gen.js +4 -0
  63. package/dist/i18n/messages/de.gen.js +4 -0
  64. package/dist/i18n/messages/en.gen.js +4 -0
  65. package/dist/i18n/messages/es.gen.js +4 -0
  66. package/dist/i18n/messages/et.gen.js +4 -0
  67. package/dist/i18n/messages/fr.gen.js +4 -0
  68. package/dist/i18n/messages/he.gen.js +4 -0
  69. package/dist/i18n/messages/hi.gen.js +4 -0
  70. package/dist/i18n/messages/hu.gen.js +4 -0
  71. package/dist/i18n/messages/lt.gen.js +4 -0
  72. package/dist/i18n/messages/lv.gen.js +4 -0
  73. package/dist/i18n/messages/messages.gen.d.ts +4 -0
  74. package/dist/i18n/messages/pl.gen.js +4 -0
  75. package/dist/i18n/messages/pt-BR.gen.js +4 -0
  76. package/dist/i18n/messages/sk.gen.js +4 -0
  77. package/dist/i18n/messages/tr.gen.js +4 -0
  78. package/dist/i18n/messages/zh-CN.gen.js +4 -0
  79. package/dist/index.d.ts +2 -1
  80. package/dist/index.js +2 -1
  81. package/dist/internal/revisionResolutionInline.js +25 -3
  82. package/dist/markdown/renderRuns.js +1 -11
  83. package/dist/panel-layout.d.ts +11 -9
  84. package/dist/panel-layout.js +13 -9
  85. package/dist/prosemirror/addTrackedDeletionMark.d.ts +18 -0
  86. package/dist/prosemirror/addTrackedDeletionMark.js +87 -0
  87. package/dist/prosemirror/attrs/index.js +5 -0
  88. package/dist/prosemirror/commands/comments.js +60 -35
  89. package/dist/prosemirror/commands/propertyChangeScope.js +3 -6
  90. package/dist/prosemirror/commands/resolveParagraphProperties.js +22 -13
  91. package/dist/prosemirror/commentOps.js +15 -1
  92. package/dist/prosemirror/conversion/fromProseDoc.js +22 -3
  93. package/dist/prosemirror/conversion/toProseDoc.js +119 -18
  94. package/dist/prosemirror/extensions/core/ParagraphExtension.js +22 -5
  95. package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +74 -25
  96. package/dist/prosemirror/extensions/marks/FootnoteRefExtension.js +11 -0
  97. package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +22 -14
  98. package/dist/prosemirror/extensions/marks/markUtils.js +8 -7
  99. package/dist/prosemirror/extensions/marks/noteReferenceDeletion.js +5 -2
  100. package/dist/prosemirror/fieldRepresentation.d.ts +8 -0
  101. package/dist/prosemirror/fieldRepresentation.js +18 -0
  102. package/dist/prosemirror/hyperlinkRemoval.d.ts +13 -1
  103. package/dist/prosemirror/hyperlinkRemoval.js +28 -9
  104. package/dist/prosemirror/listNumbering.js +11 -5
  105. package/dist/prosemirror/noteReferenceOccurrenceId.d.ts +5 -0
  106. package/dist/prosemirror/noteReferenceOccurrenceId.js +5 -0
  107. package/dist/prosemirror/noteReferenceOccurrences.d.ts +21 -0
  108. package/dist/prosemirror/noteReferenceOccurrences.js +185 -0
  109. package/dist/prosemirror/noteReferenceReview.js +14 -1
  110. package/dist/prosemirror/plugins/documentStyles.d.ts +4 -1
  111. package/dist/prosemirror/plugins/documentStyles.js +17 -10
  112. package/dist/prosemirror/plugins/suggestionMode.js +47 -49
  113. package/dist/prosemirror/preservedXmlReview.d.ts +6 -0
  114. package/dist/prosemirror/preservedXmlReview.js +35 -0
  115. package/dist/prosemirror/runFormattingFromMarks.js +2 -2
  116. package/dist/prosemirror/runFormattingReconciliation.js +5 -4
  117. package/dist/prosemirror/runPropertyChangeResolution.d.ts +8 -1
  118. package/dist/prosemirror/runPropertyChangeResolution.js +24 -2
  119. package/dist/prosemirror/runStyleFormatting.d.ts +3 -1
  120. package/dist/prosemirror/runStyleFormatting.js +3 -1
  121. package/dist/prosemirror/schema/marks.d.ts +1 -0
  122. package/dist/prosemirror/schema/nodes.d.ts +2 -0
  123. package/dist/prosemirror/styles/paragraphStyleCascade.js +4 -1
  124. package/dist/prosemirror/styles/resolvedStyleAttrs.d.ts +15 -15
  125. package/dist/prosemirror/styles/resolvedStyleAttrs.js +69 -28
  126. package/dist/prosemirror/textInput.d.ts +5 -1
  127. package/dist/prosemirror/textInput.js +3 -3
  128. package/dist/prosemirror/trackedRevisionPath.d.ts +5 -1
  129. package/dist/prosemirror/trackedRevisionPath.js +39 -1
  130. package/dist/prosemirror/validation.js +3 -5
  131. package/dist/prosemirror/yjsDocumentMetadata.d.ts +9 -3
  132. package/dist/prosemirror/yjsDocumentMetadata.js +37 -8
  133. package/dist/types/canonicalCapabilities.d.ts +6 -20
  134. package/dist/types/canonicalCapabilities.js +6 -20
  135. package/dist/types/canonicalComments.d.ts +51 -0
  136. package/dist/types/canonicalComments.js +0 -0
  137. package/dist/types/canonicalSections.d.ts +12 -0
  138. package/dist/types/canonicalSections.js +0 -0
  139. package/dist/utils/headingCollector.js +45 -4
  140. package/dist/utils/outlineDepth.d.ts +9 -0
  141. package/dist/utils/outlineDepth.js +9 -0
  142. package/package.json +2 -2
@@ -1,3 +1,4 @@
1
+ import { addTrackedDeletionMark } from "../addTrackedDeletionMark.js";
1
2
  import { expectParagraphAttrs, expectTrackedChangeMarkAttrs } from "../attrs/index.js";
2
3
  import { clearIndentOnBackspace } from "../commands/clearParagraphIndent.js";
3
4
  import { paragraphPropertiesSnapshot } from "../commands/propertyChangeScope.js";
@@ -117,20 +118,13 @@ function findAdjacentRevisionForRange(doc, from, to, markTypeName, author) {
117
118
  * Retract the current author's own inserted text.
118
119
  * Processes in reverse order to maintain position validity.
119
120
  */
120
- function markRangeAsDeleted(tr, doc, from, to, insertionType, deletionType, pluginState, joinState) {
121
- const ranges = [];
121
+ function markRangeAsDeleted(tr, doc, from, to, deletionType, pluginState, joinState) {
122
+ let hasMarkableContent = false;
122
123
  doc.nodesBetween(from, to, (node, pos) => {
123
124
  if (!canCarryTrackedRunMark(node)) return;
124
- const start = Math.max(pos, from);
125
- const end = Math.min(pos + node.nodeSize, to);
126
- if (start >= end) return;
127
- const isOwnInsert = node.marks.some((m) => m.type === insertionType && m.attrs["author"] === pluginState.author);
125
+ if (Math.max(pos, from) >= Math.min(pos + node.nodeSize, to)) return;
128
126
  if (node.marks.some((m) => m.type === deletionType)) return;
129
- ranges.push({
130
- from: start,
131
- to: end,
132
- isOwnInsert
133
- });
127
+ hasMarkableContent = true;
134
128
  });
135
129
  const delAttrs = findAdjacentRevisionForRange(doc, from, to, "deletion", pluginState.author) || makeMarkAttrs(pluginState);
136
130
  let removedMark = false;
@@ -165,18 +159,20 @@ function markRangeAsDeleted(tr, doc, from, to, insertionType, deletionType, plug
165
159
  date: delAttrs.date
166
160
  });
167
161
  }
168
- if (ranges.length === 0) return;
162
+ if (!hasMarkableContent) return;
169
163
  encloseWholeControls({
170
164
  tr,
171
165
  from,
172
166
  to,
173
167
  revisionId: delAttrs.revisionId
174
168
  });
175
- for (let i = ranges.length - 1; i >= 0; i--) {
176
- const range = ranges[i];
177
- if (range.isOwnInsert) tr.delete(range.from, range.to);
178
- else tr.addMark(range.from, range.to, deletionType.create(delAttrs));
179
- }
169
+ addTrackedDeletionMark({
170
+ tr,
171
+ from,
172
+ to,
173
+ mark: deletionType.create(delAttrs),
174
+ insertionPolicy: "retract-own"
175
+ });
180
176
  }
181
177
  /** Preserve clipboard revisions inside the revision that inserted their content. */
182
178
  function enclosePastedRunRevisions({ tr, from, to, revision: insertion }) {
@@ -298,7 +294,7 @@ function handleSuggestionPaste(view, slice, pluginState) {
298
294
  const endsContainer = wholeBlocks && paragraphEndsItsContainer(doc.resolve($to.before()), $to.parent.type.name);
299
295
  const rotates = endsContainer && slice.content.firstChild?.type === $to.parent.type && slice.content.lastChild?.type === $to.parent.type;
300
296
  const tableFirst = endsContainer && !rotates;
301
- if (!tableFirst) markRangeAsDeleted(tr, doc, from, wholeBlocks && !endsContainer ? $to.after() : to, insertionType, deletionType, pluginState);
297
+ if (!tableFirst) markRangeAsDeleted(tr, doc, from, wholeBlocks && !endsContainer ? $to.after() : to, deletionType, pluginState);
302
298
  const carryAcross = () => {
303
299
  if (selectsAll || $from.parent.type.name !== "paragraph" || $from.parent === $to.parent || from <= $from.start()) return;
304
300
  const firstPos = tr.mapping.map($from.before());
@@ -332,7 +328,7 @@ function handleSuggestionPaste(view, slice, pluginState) {
332
328
  let insertTo = placed.length === 0 ? at : Math.max(...placed.map((range) => range.to));
333
329
  if (tableFirst) {
334
330
  const struck = tr.steps.length;
335
- markRangeAsDeleted(tr, tr.doc, tr.mapping.map(from), tr.mapping.map(to), insertionType, deletionType, pluginState);
331
+ markRangeAsDeleted(tr, tr.doc, tr.mapping.map(from), tr.mapping.map(to), deletionType, pluginState);
336
332
  const since = tr.mapping.slice(struck);
337
333
  insertFrom = since.map(insertFrom, -1);
338
334
  insertTo = since.map(insertTo, -1);
@@ -405,7 +401,7 @@ function handleSuggestionTableCellPaste(view, slice, pluginState) {
405
401
  if (!cell) return;
406
402
  const { from, to } = cellPasteRange(cell, cellPos, content);
407
403
  const mapFrom = tr.mapping.maps.length;
408
- markRangeAsDeleted(tr, tr.doc, from, to, insertionType, deletionType, pluginState);
404
+ markRangeAsDeleted(tr, tr.doc, from, to, deletionType, pluginState);
409
405
  const insertFrom = tr.mapping.slice(mapFrom).map(to);
410
406
  const sizeBefore = tr.doc.content.size;
411
407
  tr.replaceRange(insertFrom, insertFrom, content);
@@ -538,7 +534,7 @@ function applySuggestionInsert(view, from, to, text, pluginState) {
538
534
  const insertAttrs = findAdjacentRevision(view.state.doc, from, "insertion", pluginState.author) || makeMarkAttrs(pluginState);
539
535
  if (from !== to) {
540
536
  const deletionType = view.state.schema.marks["deletion"];
541
- if (deletionType) markRangeAsDeleted(tr, view.state.doc, from, to, insertionType, deletionType, pluginState, view.state);
537
+ if (deletionType) markRangeAsDeleted(tr, view.state.doc, from, to, deletionType, pluginState, view.state);
542
538
  }
543
539
  const insertAt = tr.mapping.map(to);
544
540
  tr.insertText(text, insertAt, insertAt);
@@ -597,7 +593,7 @@ function suggestRangeDeletion(state, tr, from, to) {
597
593
  const insertionType = state.schema.marks["insertion"];
598
594
  const deletionType = state.schema.marks["deletion"];
599
595
  if (!pluginState?.active || !insertionType || !deletionType) return false;
600
- markRangeAsDeleted(tr, tr.doc, from, to, insertionType, deletionType, pluginState);
596
+ markRangeAsDeleted(tr, tr.doc, from, to, deletionType, pluginState);
601
597
  return true;
602
598
  }
603
599
  /**
@@ -665,19 +661,19 @@ function handleSuggestionEnter(view, pluginState) {
665
661
  function caretDeleteTarget(state, direction) {
666
662
  const { $from } = state.selection;
667
663
  const backward = direction === "backward";
668
- let from = backward ? $from.pos - 1 : $from.pos;
669
- let to = backward ? $from.pos : $from.pos + 1;
670
- while (from >= $from.start() && to <= $from.end()) {
671
- const $adjacent = state.doc.resolve(from);
672
- const adjacent = $adjacent.nodeAfter;
673
- if (!adjacent || adjacent.type.name !== "bookmarkBoundary" && !adjacent.marks.some((mark) => mark.type === state.schema.marks["deletion"])) return {
674
- type: "inlineUnit",
675
- from,
676
- to
677
- };
678
- const skipped = backward && adjacent.isText ? $adjacent.textOffset + 1 : adjacent.nodeSize;
679
- from += backward ? -skipped : skipped;
680
- to += backward ? -skipped : skipped;
664
+ let cursor = $from.pos;
665
+ while (cursor >= $from.start() && cursor <= $from.end()) {
666
+ const adjacent = backward ? state.doc.resolve(cursor).nodeBefore : state.doc.resolve(cursor).nodeAfter;
667
+ if (!adjacent) return { type: "paragraphEdge" };
668
+ if (adjacent.type.name !== "bookmarkBoundary" && !adjacent.marks.some((mark) => mark.type === state.schema.marks["deletion"])) {
669
+ const size = adjacent.isAtom && !adjacent.isText ? adjacent.nodeSize : 1;
670
+ return {
671
+ type: "inlineUnit",
672
+ from: backward ? cursor - size : cursor,
673
+ to: backward ? cursor : cursor + size
674
+ };
675
+ }
676
+ cursor += backward ? -adjacent.nodeSize : adjacent.nodeSize;
681
677
  }
682
678
  return { type: "paragraphEdge" };
683
679
  }
@@ -795,7 +791,7 @@ function handleSuggestionDelete(state, dispatch, direction) {
795
791
  from: rangeFrom.pos,
796
792
  to: rangeTo.pos
797
793
  }).sort((a, b) => b.from - a.from);
798
- for (const { from, to } of ranges) markRangeAsDeleted(tr, state.doc, from, to, insertionType, deletionType, pluginState, state);
794
+ for (const { from, to } of ranges) markRangeAsDeleted(tr, state.doc, from, to, deletionType, pluginState, state);
799
795
  if (state.selection instanceof CellSelection) tr.setSelection(state.selection.map(tr.doc, tr.mapping));
800
796
  else {
801
797
  const cursorPos = tr.mapping.map($to.pos);
@@ -823,17 +819,20 @@ function handleSuggestionDelete(state, dispatch, direction) {
823
819
  const rangeTo = noteRange?.to ?? deleteEnd;
824
820
  const nodeAfter = state.doc.resolve(rangeFrom).nodeAfter;
825
821
  if (!nodeAfter || !canCarryTrackedRunMark(nodeAfter)) return false;
826
- const hasOwnInsertion = nodeAfter.marks.some((m) => m.type === insertionType && m.attrs["author"] === pluginState.author);
827
- if (nodeAfter.marks.some((m) => m.type === deletionType)) {
828
- const newPos = isBackward ? rangeFrom : rangeTo;
829
- tr.setSelection(TextSelection.near(tr.doc.resolve(newPos)));
830
- } else if (hasOwnInsertion) tr.delete(rangeFrom, rangeTo);
831
- else {
822
+ const mapFrom = tr.mapping.maps.length;
823
+ if (noteRange) markRangeAsDeleted(tr, state.doc, noteRange.from, noteRange.to, deletionType, pluginState);
824
+ else if (!nodeAfter.marks.some((m) => m.type === deletionType)) {
832
825
  const delAttrs = findAdjacentRevisionForRange(state.doc, rangeFrom, rangeTo, "deletion", pluginState.author) || makeMarkAttrs(pluginState);
833
- tr.addMark(rangeFrom, rangeTo, deletionType.create(delAttrs));
834
- const newPos = isBackward ? rangeFrom : rangeTo;
835
- tr.setSelection(TextSelection.near(tr.doc.resolve(newPos)));
826
+ addTrackedDeletionMark({
827
+ insertionPolicy: "retract-own",
828
+ tr,
829
+ from: rangeFrom,
830
+ to: rangeTo,
831
+ mark: deletionType.create(delAttrs)
832
+ });
836
833
  }
834
+ const newPos = tr.mapping.slice(mapFrom).map(isBackward ? rangeFrom : rangeTo);
835
+ tr.setSelection(TextSelection.near(tr.doc.resolve(newPos)));
837
836
  dispatch(tr.scrollIntoView());
838
837
  return true;
839
838
  }
@@ -850,7 +849,7 @@ function markComposedAsInsertion({ view, from, pluginState, replaced, compositio
850
849
  if (compositionId !== null) tr.setMeta("composition", compositionId);
851
850
  if (replaced) {
852
851
  tr.replaceRange(from, from, replaced);
853
- markRangeAsDeleted(tr, tr.doc, from, tr.mapping.map(from, 1), insertionType, deletionType, pluginState);
852
+ markRangeAsDeleted(tr, tr.doc, from, tr.mapping.map(from, 1), deletionType, pluginState);
854
853
  const restoredEnd = tr.doc.resolve(tr.mapping.map(from, 1));
855
854
  const restoredStart = tr.doc.resolve(from);
856
855
  if (restoredStart.parent.type.name === "paragraph" && restoredEnd.parent.type.name === "paragraph" && restoredStart.parent !== restoredEnd.parent) {
@@ -920,14 +919,14 @@ function replacedInline(before, step) {
920
919
  * rejecting restores it and accepting removes it. The author's own
921
920
  * insertions are retracted instead.
922
921
  */
923
- function restoreReplacedInline({ tr, replaced, insertionType, deletionType, pluginState }) {
922
+ function restoreReplacedInline({ tr, replaced, deletionType, pluginState }) {
924
923
  for (const { at, content } of replaced) {
925
924
  const pos = tr.mapping.map(at, -1);
926
925
  const $pos = tr.doc.resolve(pos);
927
926
  const index = $pos.index();
928
927
  if (!$pos.parent.canReplace(index, index, content)) continue;
929
928
  tr.insert(pos, content);
930
- markRangeAsDeleted(tr, tr.doc, pos, pos + content.size, insertionType, deletionType, pluginState);
929
+ markRangeAsDeleted(tr, tr.doc, pos, pos + content.size, deletionType, pluginState);
931
930
  }
932
931
  }
933
932
  /**
@@ -1103,7 +1102,6 @@ function createSuggestionModePlugin(initialActive = false, author = "User") {
1103
1102
  if (deletionType) restoreReplacedInline({
1104
1103
  tr,
1105
1104
  replaced,
1106
- insertionType,
1107
1105
  deletionType,
1108
1106
  pluginState
1109
1107
  });
@@ -0,0 +1,6 @@
1
+ import { Mark, Node } from "prosemirror-model";
2
+ //#region src/prosemirror/preservedXmlReview.d.ts
3
+ /** A retained opaque deleted result becomes ordinary text when its last deletion resolves. */
4
+ declare const resolvedPreservedXmlAttrs: (node: Node, marks: readonly Mark[]) => import("prosemirror-model").Attrs;
5
+ //#endregion
6
+ export { resolvedPreservedXmlAttrs };
@@ -0,0 +1,35 @@
1
+ import { captureVerbatimXml } from "../docx/verbatimCapture.js";
2
+ import { OOXML_NAMESPACE_SCOPE, WORDPROCESSINGML_NAMESPACE_URIS, cloneElement, getChildElements, getLocalName, parseXml } from "../docx/xmlParser.js";
3
+ import { expectPreservedXmlAttrs, expectTrackedChangeMarkAttrs } from "./attrs/index.js";
4
+ //#region src/prosemirror/preservedXmlReview.ts
5
+ const restoreDeletedText = (node) => {
6
+ if (node.type !== "element") return node;
7
+ const name = getLocalName(node.name);
8
+ let target;
9
+ if (name === "delText") target = "t";
10
+ if (name === "delInstrText") target = "instrText";
11
+ const renamed = target !== void 0 && WORDPROCESSINGML_NAMESPACE_URIS.has(node.namespaceUri ?? "") ? node.name?.replace(/[^:]+$/u, target) : node.name;
12
+ const elements = node.elements?.map(restoreDeletedText);
13
+ if (renamed === node.name && elements?.every((child, index) => child === node.elements?.[index]) !== false) return node;
14
+ return cloneElement(node, {
15
+ ...renamed !== void 0 && renamed !== node.name ? { name: renamed } : {},
16
+ ...elements ? { elements } : {}
17
+ });
18
+ };
19
+ const hasPendingDeletion = (marks) => marks.some((mark) => {
20
+ if (mark.type.name === "deletion") return true;
21
+ if (mark.type.name !== "insertion") return false;
22
+ return expectTrackedChangeMarkAttrs(mark)._docxRevisionAncestors?.some((ancestor) => ancestor.type === "deletion" || ancestor.type === "moveFrom") ?? false;
23
+ });
24
+ /** A retained opaque deleted result becomes ordinary text when its last deletion resolves. */
25
+ const resolvedPreservedXmlAttrs = (node, marks) => {
26
+ if (node.type.name !== "preservedXml" || !hasPendingDeletion(node.marks) || hasPendingDeletion(marks)) return node.attrs;
27
+ const attrs = expectPreservedXmlAttrs(node);
28
+ const xml = getChildElements(parseXml(attrs.xml, OOXML_NAMESPACE_SCOPE)).map((element) => captureVerbatimXml(restoreDeletedText(element))).join("");
29
+ return xml === attrs.xml ? node.attrs : {
30
+ ...node.attrs,
31
+ xml
32
+ };
33
+ };
34
+ //#endregion
35
+ export { resolvedPreservedXmlAttrs };
@@ -4,7 +4,7 @@ import { expectCharacterSpacingMarkAttrs, expectCharacterStyleMarkAttrs, expectE
4
4
  import { runShadingAttrsToShading, shadingToRunShadingAttrs } from "./conversion/runShadingMark.js";
5
5
  import { applyRunFormattingOverrideAttrs, buildRunFormattingOverrideAttrs } from "./extensions/marks/RunFormattingOverrideExtension.js";
6
6
  import { authoredRunFormattingFromAttrs, hasAuthoredRunFormattingProvenance } from "./runFormattingProvenance.js";
7
- import { paragraphFormattingForRun, resolveEffectiveRunStyleFormatting, suppressParagraphMarkFormatting } from "./runStyleFormatting.js";
7
+ import { isParagraphMarkSuppressionEligible, paragraphFormattingForRun, resolveEffectiveRunStyleFormatting, suppressParagraphMarkFormatting } from "./runStyleFormatting.js";
8
8
  //#region src/prosemirror/runFormattingFromMarks.ts
9
9
  const RUN_FORMATTING_VISUAL_GROUPS = {
10
10
  bold: "bold",
@@ -570,7 +570,7 @@ function marksToTextFormatting(marks, options) {
570
570
  inheritedFormatting: suppressedInheritedFormatting,
571
571
  observedFormatting: formatting
572
572
  });
573
- if (formattingAuthorshipCost(suppressed) < formattingAuthorshipCost(reconciled)) reconciled = suppressed;
573
+ if (isParagraphMarkSuppressionEligible(suppressed) && formattingAuthorshipCost(suppressed) < formattingAuthorshipCost(reconciled)) reconciled = suppressed;
574
574
  }
575
575
  return {
576
576
  ...reconciled,
@@ -3,7 +3,7 @@ import { expectCharacterStyleMarkAttrs } from "./attrs/index.js";
3
3
  import { textFormattingToMarks } from "./extensions/marks/markUtils.js";
4
4
  import { marksToTextFormatting } from "./runFormattingFromMarks.js";
5
5
  import { RUN_FORMATTING_MARK_NAMES } from "./runFormattingMarkNames.js";
6
- import { getParagraphMarkSuppressionOverrides, hasDirectRunFormatting, paragraphFormattingForRun, resolveEffectiveRunStyleFormatting } from "./runStyleFormatting.js";
6
+ import { getParagraphMarkSuppressionOverrides, hasDirectRunFormatting, isParagraphMarkSuppressionEligible, paragraphFormattingForRun, resolveEffectiveRunStyleFormatting } from "./runStyleFormatting.js";
7
7
  import { Mark } from "prosemirror-model";
8
8
  //#region src/prosemirror/runFormattingReconciliation.ts
9
9
  /** Read authored run properties without confusing inherited visuals for direct formatting. */
@@ -37,14 +37,15 @@ const reconcileRunFormattingMarks = ({ authoredFormatting, context, node, styleR
37
37
  paragraphFormatting,
38
38
  ...styleResolver !== void 0 ? { styleResolver } : {}
39
39
  }), authoredFormatting);
40
- const overrideFormatting = mergeTextFormatting(getParagraphMarkSuppressionOverrides({
40
+ const overrideFormatting = mergeTextFormatting(isParagraphMarkSuppressionEligible(authoredFormatting) ? getParagraphMarkSuppressionOverrides({
41
41
  directFormatting: authoredFormatting,
42
42
  paragraphMarkFormatting: context.paragraphMarkFormatting,
43
43
  suppressedFormatting: paragraphFormatting
44
- }), authoredFormatting);
44
+ }) : void 0, authoredFormatting);
45
45
  const formattingMarks = textFormattingToMarks(effectiveFormatting, node.type.schema, {
46
46
  overrideFormatting,
47
- directFormatting: authoredFormatting
47
+ directFormatting: authoredFormatting,
48
+ authoredCarrier: "preserve"
48
49
  });
49
50
  return Mark.setFrom([
50
51
  ...marks.filter(({ type }) => !RUN_FORMATTING_MARK_NAMES.has(type.name)),
@@ -14,5 +14,12 @@ type ReconstructRejectedRunFormattingMarksOptions = {
14
14
  * owner so their reject semantics cannot diverge at the bulk threshold.
15
15
  */
16
16
  declare const reconstructRejectedRunFormattingMarks: ({ node, paragraphContext, previousFormatting, styleResolver }: ReconstructRejectedRunFormattingMarksOptions) => readonly Mark[];
17
+ type RestoreHistoricalRunFormattingOptions = {
18
+ node: Node;
19
+ paragraphContext: ParagraphRunStyleContext;
20
+ styleResolver?: RunStyleResolver | null;
21
+ };
22
+ /** Restored deletions inherit the live paragraph cascade without authoring their historical visuals. */
23
+ declare const restoreHistoricalRunFormatting: ({ node, paragraphContext, styleResolver }: RestoreHistoricalRunFormattingOptions) => readonly Mark[];
17
24
  //#endregion
18
- export { reconstructRejectedRunFormattingMarks };
25
+ export { reconstructRejectedRunFormattingMarks, restoreHistoricalRunFormatting };
@@ -1,5 +1,6 @@
1
+ import { runFormattingInlineAtomDisposition } from "./runFormattingInlineCarriers.js";
1
2
  import { RUN_FORMATTING_MARK_NAMES } from "./runFormattingMarkNames.js";
2
- import { reconcileRunFormattingMarks } from "./runFormattingReconciliation.js";
3
+ import { readAuthoredRunFormatting, reconcileRunFormattingMarks } from "./runFormattingReconciliation.js";
3
4
  //#region src/prosemirror/runPropertyChangeResolution.ts
4
5
  /**
5
6
  * Rebuild the pre-change run marks against the paragraph's live style cascade.
@@ -14,5 +15,26 @@ const reconstructRejectedRunFormattingMarks = ({ node, paragraphContext, previou
14
15
  ...styleResolver !== void 0 ? { styleResolver } : {}
15
16
  }).filter(({ type }) => RUN_FORMATTING_MARK_NAMES.has(type.name));
16
17
  };
18
+ /** Restored deletions inherit the live paragraph cascade without authoring their historical visuals. */
19
+ const restoreHistoricalRunFormatting = ({ node, paragraphContext, styleResolver }) => {
20
+ const disposition = runFormattingInlineAtomDisposition(node);
21
+ if (disposition === null || disposition === "not-a-run") return node.marks;
22
+ if (paragraphContext.paragraphMarkFormatting === void 0) return node.marks;
23
+ return reconcileRunFormattingMarks({
24
+ authoredFormatting: readAuthoredRunFormatting({
25
+ context: {
26
+ baseParagraphFormatting: paragraphContext.baseParagraphFormatting,
27
+ paragraphFormatting: paragraphContext.baseParagraphFormatting,
28
+ paragraphMarkFormatting: void 0,
29
+ paragraphMarkPrecedesStyle: false
30
+ },
31
+ marks: node.marks,
32
+ ...styleResolver !== void 0 ? { styleResolver } : {}
33
+ }),
34
+ context: paragraphContext,
35
+ node,
36
+ ...styleResolver !== void 0 ? { styleResolver } : {}
37
+ });
38
+ };
17
39
  //#endregion
18
- export { reconstructRejectedRunFormattingMarks };
40
+ export { reconstructRejectedRunFormattingMarks, restoreHistoricalRunFormatting };
@@ -5,6 +5,8 @@ import { cascadeStyleTextFormatting } from "./styles/styleToggleCascade.js";
5
5
  import { Mark, Node } from "prosemirror-model";
6
6
  //#region src/prosemirror/runStyleFormatting.d.ts
7
7
  declare const hasDirectRunFormatting: (formatting: document_d_exports.TextFormatting | undefined) => boolean;
8
+ /** A stated run property or character style establishes paragraph-mark suppression. */
9
+ declare const isParagraphMarkSuppressionEligible: (formatting: document_d_exports.TextFormatting | undefined) => boolean;
8
10
  declare const stripParagraphMarkOnlyFormatting: (formatting: document_d_exports.TextFormatting) => document_d_exports.TextFormatting | undefined;
9
11
  declare const stripParagraphMarkFormattingForBodyRuns: (formatting: document_d_exports.TextFormatting) => document_d_exports.TextFormatting | undefined;
10
12
  type SuppressParagraphMarkFormattingOptions = {
@@ -66,4 +68,4 @@ type ResolveEffectiveRunStyleFormattingOptions = {
66
68
  /** Resolve the non-direct run cascade from shared document styles and the current paragraph. */
67
69
  declare const resolveEffectiveRunStyleFormatting: ({ marks, paragraphFormatting, styleResolver }: ResolveEffectiveRunStyleFormattingOptions) => document_d_exports.TextFormatting | undefined;
68
70
  //#endregion
69
- export { ParagraphRunStyleContext, RunStyleResolver, getParagraphMarkSuppressionOverrides, hasDirectRunFormatting, nearestParagraphRunStyleContext, paragraphFormattingForRun, paragraphRunStyleContext, paragraphRunStyleContextAt, resolveEffectiveRunStyleFormatting, resolveParagraphBodyRunFormatting, stripParagraphMarkFormattingForBodyRuns, stripParagraphMarkOnlyFormatting, suppressParagraphMarkFormatting };
71
+ export { ParagraphRunStyleContext, RunStyleResolver, getParagraphMarkSuppressionOverrides, hasDirectRunFormatting, isParagraphMarkSuppressionEligible, nearestParagraphRunStyleContext, paragraphFormattingForRun, paragraphRunStyleContext, paragraphRunStyleContextAt, resolveEffectiveRunStyleFormatting, resolveParagraphBodyRunFormatting, stripParagraphMarkFormattingForBodyRuns, stripParagraphMarkOnlyFormatting, suppressParagraphMarkFormatting };
@@ -20,6 +20,8 @@ const hasDirectRunFormatting = (formatting) => {
20
20
  if (!formatting) return false;
21
21
  return Object.entries(formatting).some(([property, value]) => property !== "styleId" && value !== void 0);
22
22
  };
23
+ /** A stated run property or character style establishes paragraph-mark suppression. */
24
+ const isParagraphMarkSuppressionEligible = (formatting) => hasDirectRunFormatting(formatting) || formatting?.styleId !== void 0;
23
25
  const stripParagraphMarkOnlyFormatting = (formatting) => {
24
26
  const { allCaps: _allCaps, highlight: _highlight, shading: _shading, smallCaps: _smallCaps, vertAlign: _vertAlign, preserved: _preserved, ...formattingForBody } = formatting;
25
27
  return Object.keys(formattingForBody).length > 0 ? formattingForBody : void 0;
@@ -182,4 +184,4 @@ const resolveEffectiveRunStyleFormatting = ({ marks, paragraphFormatting, styleR
182
184
  });
183
185
  };
184
186
  //#endregion
185
- export { getParagraphMarkSuppressionOverrides, hasDirectRunFormatting, nearestParagraphRunStyleContext, paragraphFormattingForRun, paragraphRunStyleContext, paragraphRunStyleContextAt, resolveEffectiveRunStyleFormatting, resolveParagraphBodyRunFormatting, stripParagraphMarkFormattingForBodyRuns, stripParagraphMarkOnlyFormatting, suppressParagraphMarkFormatting };
187
+ export { getParagraphMarkSuppressionOverrides, hasDirectRunFormatting, isParagraphMarkSuppressionEligible, nearestParagraphRunStyleContext, paragraphFormattingForRun, paragraphRunStyleContext, paragraphRunStyleContextAt, resolveEffectiveRunStyleFormatting, resolveParagraphBodyRunFormatting, stripParagraphMarkFormattingForBodyRuns, stripParagraphMarkOnlyFormatting, suppressParagraphMarkFormatting };
@@ -78,6 +78,7 @@ type TextEffectAttrs = {
78
78
  effect: Exclude<document_d_exports.TextEffect, "none">;
79
79
  };
80
80
  type FootnoteRefAttrs = {
81
+ occurrenceId: string;
81
82
  id: string | number;
82
83
  noteType?: "footnote" | "endnote";
83
84
  vertAlign?: "baseline" | "superscript";
@@ -272,6 +272,8 @@ type ParagraphAttrs = {
272
272
  * paragraph. `TableCellAttrs._resolvedBorders` is the same device.
273
273
  */
274
274
  _resolvedFormatting?: document_d_exports.ParagraphFormatting;
275
+ /** Style-only inheritance baseline, before numbering-level indentation. PM-only. */
276
+ _styleResolvedFormatting?: document_d_exports.ParagraphFormatting;
275
277
  /** Import-effective spacing baseline for HTML auto-spacing detection.
276
278
  * PM-only; never serialized back into DOCX formatting. */
277
279
  _autospacingBase?: {
@@ -59,7 +59,10 @@ function paragraphStyleCascadeAttrs({ styleId, formatting, styleResolver, tableP
59
59
  };
60
60
  const stylePpr = styleResolver.resolveParagraphStyleInTable(styleId, tableParagraphOverlay).paragraphFormatting;
61
61
  const resolvedFormatting = styleResolvedParagraphFormatting(stylePpr);
62
- if (resolvedFormatting) attrs._resolvedFormatting = resolvedFormatting;
62
+ if (resolvedFormatting) {
63
+ attrs._resolvedFormatting = resolvedFormatting;
64
+ attrs._styleResolvedFormatting = resolvedFormatting;
65
+ }
63
66
  set("alignment", formatting?.alignment ?? stylePpr?.alignment);
64
67
  set("alignmentFromStyle", stylePpr?.alignment);
65
68
  set("spaceBefore", formatting?.spaceBefore ?? stylePpr?.spaceBefore);
@@ -1,3 +1,4 @@
1
+ import { document_d_exports } from "../../types/document.js";
1
2
  import { ParagraphAttrs, ParagraphAttrsPatch } from "../schema/nodes.js";
2
3
  import { ResolvedParagraphStyle } from "./styleResolver.js";
3
4
  import { NumberingMap } from "../../docx/numberingParser.js";
@@ -38,17 +39,18 @@ declare function listAttrsFromNumbering(numPr: {
38
39
  numId: number;
39
40
  ilvl: number;
40
41
  }, numbering: NumberingMap | null | undefined): ParagraphAttrsPatch;
41
- /**
42
- * The numbering level's indentation a directly numbered paragraph reads as its
43
- * own where it states none: the load path folds the level's `w:ind` into the
44
- * paragraph (a direct `w:ind` wins per group, left vs first line/hanging), so
45
- * a paragraph a command numbers carries it too, and the save writes it where a
46
- * reopen reads it back.
47
- */
48
- declare function listLevelIndentAttrPatch(stated: DirectParagraphIndentation | undefined, numPr: {
49
- numId: number;
50
- ilvl: number;
51
- }, numbering: NumberingMap | null | undefined): ParagraphAttrsPatch;
42
+ type ListIndentationProvenanceOptions = {
43
+ direct: DirectParagraphIndentation | undefined;
44
+ styleFormatting: document_d_exports.ParagraphFormatting | undefined;
45
+ numberingSource: "style" | "paragraph";
46
+ numPr: {
47
+ numId: number;
48
+ ilvl: number;
49
+ } | undefined;
50
+ numbering: NumberingMap | null | undefined;
51
+ };
52
+ /** Project effective indentation and both inheritance layers together. */
53
+ declare function listIndentationProvenancePatch({ direct, styleFormatting, numberingSource, numPr, numbering }: ListIndentationProvenanceOptions): ParagraphAttrsPatch;
52
54
  /**
53
55
  * The indentation a paragraph leaving its list keeps: the level's indentation
54
56
  * it only read from its numbering goes with the numbering, back to what its
@@ -57,11 +59,9 @@ declare function listLevelIndentAttrPatch(stated: DirectParagraphIndentation | u
57
59
  */
58
60
  declare function listLevelIndentRemovalPatch(attrs: Readonly<ParagraphAttrs>, numbering: NumberingMap | null | undefined): ParagraphAttrsPatch;
59
61
  /** Recompute every level-dependent attr when a paragraph changes list level. */
60
- declare function listLevelAttrPatch(attrs: {
61
- listImplicitChildLevelAdvances?: number | null;
62
- }, numPr: {
62
+ declare function listLevelAttrPatch(attrs: Pick<ParagraphAttrs, "listImplicitChildLevelAdvances" | "_originalFormatting" | "_resolvedFormatting" | "_styleResolvedFormatting" | "numPr" | "numPrFromStyle" | "indentLeft" | "indentRight" | "indentFirstLine" | "hangingIndent">, numPr: {
63
63
  numId: number;
64
64
  ilvl: number;
65
65
  }, numbering: NumberingMap | null | undefined): ParagraphAttrsPatch;
66
66
  //#endregion
67
- export { listAttrsFromNumbering, listAttrsFromResolvedStyle, listLevelAttrPatch, listLevelIndentAttrPatch, listLevelIndentRemovalPatch, paragraphAttrsFromResolvedStyle };
67
+ export { listAttrsFromNumbering, listAttrsFromResolvedStyle, listIndentationProvenancePatch, listLevelAttrPatch, listLevelIndentRemovalPatch, paragraphAttrsFromResolvedStyle };
@@ -6,6 +6,7 @@ import { CLEARED_LIST_RENDERING_ATTRS } from "../listMarker.js";
6
6
  import { listRenderingAttrPatch } from "../listRenderingAttrs.js";
7
7
  import { paragraphNumberingAttr } from "../numberingAttr.js";
8
8
  import { styleResolvedParagraphFormatting } from "../paragraphFormattingProvenance.js";
9
+ import { directParagraphIndentation, paragraphIndentationAttrPatch, paragraphIndentationFromFormatting, withDirectParagraphIndentation } from "../paragraphIndentation.js";
9
10
  //#region src/prosemirror/styles/resolvedStyleAttrs.ts
10
11
  /**
11
12
  * Shared helper for projecting a resolved paragraph style onto ProseMirror
@@ -48,6 +49,7 @@ function paragraphAttrsFromResolvedStyle(resolved, identity) {
48
49
  borders: ppr?.borders ?? null,
49
50
  defaultTextFormatting: hasRunFormatting ? runFormatting : null,
50
51
  _resolvedFormatting: styleResolvedParagraphFormatting(ppr),
52
+ _styleResolvedFormatting: styleResolvedParagraphFormatting(ppr),
51
53
  _autospacingBase: autospacingBaseFromResolvedParagraphFormatting(ppr),
52
54
  _tableOfContentsLevel: tableOfContentsStyleLevel(identity) ?? null
53
55
  };
@@ -84,19 +86,26 @@ function listAttrsFromResolvedStyle(resolved, numbering) {
84
86
  numId,
85
87
  ilvl
86
88
  }, numbering);
87
- const level = numbering?.getLevel(numId, ilvl);
88
89
  attrs.numPrFromStyle = paragraphNumberingAttr(paragraphNumberingReference({
89
90
  numId,
90
91
  ilvl
91
92
  }));
92
- const ppr = resolved.paragraphFormatting;
93
- if (level?.pPr) {
94
- if (ppr?.indentLeft === void 0 && level.pPr.indentLeft !== void 0) attrs.indentLeft = level.pPr.indentLeft;
95
- if (!(ppr?.indentFirstLine !== void 0 || ppr?.hangingIndent !== void 0) && numberingLevelHasMarkerSlot(level)) {
96
- if (level.pPr.indentFirstLine !== void 0) attrs.indentFirstLine = level.pPr.indentFirstLine;
97
- if (level.pPr.hangingIndent !== void 0) attrs.hangingIndent = level.pPr.hangingIndent;
98
- }
99
- }
93
+ Object.assign(attrs, listIndentationProvenancePatch({
94
+ direct: void 0,
95
+ styleFormatting: resolved.paragraphFormatting,
96
+ numberingSource: "style",
97
+ numPr: {
98
+ numId,
99
+ ilvl
100
+ },
101
+ numbering
102
+ }));
103
+ for (const key of [
104
+ "indentLeft",
105
+ "indentRight",
106
+ "indentFirstLine"
107
+ ]) if (attrs[key] == null) Reflect.deleteProperty(attrs, key);
108
+ if (attrs.indentFirstLine === void 0 && resolved.paragraphFormatting?.hangingIndent === void 0) Reflect.deleteProperty(attrs, "hangingIndent");
100
109
  return attrs;
101
110
  }
102
111
  /** Project one resolved numbering level into the complete editor attr group. */
@@ -115,9 +124,9 @@ function listAttrsFromNumbering(numPr, numbering) {
115
124
  /**
116
125
  * The numbering level's indentation a directly numbered paragraph reads as its
117
126
  * own where it states none: the load path folds the level's `w:ind` into the
118
- * paragraph (a direct `w:ind` wins per group, left vs first line/hanging), so
119
- * a paragraph a command numbers carries it too, and the save writes it where a
120
- * reopen reads it back.
127
+ * paragraph (a direct `w:ind` wins per group, left vs first line/hanging).
128
+ * Keep this projection private: callers use the paired provenance helper so
129
+ * effective level values cannot be mistaken for authored indentation.
121
130
  */
122
131
  function listLevelIndentAttrPatch(stated, numPr, numbering) {
123
132
  const level = numbering?.getLevel(numPr.numId, numPr.ilvl);
@@ -130,6 +139,33 @@ function listLevelIndentAttrPatch(stated, numPr, numbering) {
130
139
  }
131
140
  return patch;
132
141
  }
142
+ /** Project effective indentation and both inheritance layers together. */
143
+ function listIndentationProvenancePatch({ direct, styleFormatting, numberingSource, numPr, numbering }) {
144
+ const style = {
145
+ ...styleResolvedParagraphFormatting(styleFormatting),
146
+ ...styleFormatting?.hangingIndent === void 0 ? {} : { hangingIndent: styleFormatting.hangingIndent }
147
+ };
148
+ const level = numPr === void 0 ? {} : listLevelIndentAttrPatch(numberingSource === "style" ? paragraphIndentationFromFormatting(style) : void 0, numPr, numbering);
149
+ if (level.indentLeft === 0 && style.indentLeft === void 0) Reflect.deleteProperty(level, "indentLeft");
150
+ if (level.indentFirstLine === 0 && style.indentFirstLine === void 0 && style.hangingIndent === void 0) {
151
+ Reflect.deleteProperty(level, "indentFirstLine");
152
+ Reflect.deleteProperty(level, "hangingIndent");
153
+ }
154
+ const resolved = {
155
+ ...style,
156
+ ...typeof level.indentLeft === "number" ? { indentLeft: level.indentLeft } : {},
157
+ ...typeof level.indentFirstLine === "number" ? { indentFirstLine: level.indentFirstLine } : {},
158
+ ...typeof level.hangingIndent === "boolean" ? { hangingIndent: level.hangingIndent } : {}
159
+ };
160
+ return {
161
+ ...paragraphIndentationAttrPatch({
162
+ direct,
163
+ inherited: paragraphIndentationFromFormatting(resolved)
164
+ }),
165
+ _resolvedFormatting: Object.keys(resolved).length === 0 ? null : resolved,
166
+ _styleResolvedFormatting: Object.keys(style).length === 0 ? null : style
167
+ };
168
+ }
133
169
  /**
134
170
  * The indentation a paragraph leaving its list keeps: the level's indentation
135
171
  * it only read from its numbering goes with the numbering, back to what its
@@ -138,28 +174,33 @@ function listLevelIndentAttrPatch(stated, numPr, numbering) {
138
174
  */
139
175
  function listLevelIndentRemovalPatch(attrs, numbering) {
140
176
  if (attrs.numPr?.kind !== "reference") return {};
141
- const level = numbering?.getLevel(attrs.numPr.numId, attrs.numPr.ilvl ?? 0);
142
- if (!level?.pPr) return {};
143
- const resolved = attrs.numPrFromStyle != null ? void 0 : attrs._resolvedFormatting;
144
- const patch = {};
145
- if (level.pPr.indentLeft !== void 0 && attrs.indentLeft === level.pPr.indentLeft) patch.indentLeft = resolved?.indentLeft ?? null;
146
- if (level.pPr.indentFirstLine !== void 0 && attrs.indentFirstLine === level.pPr.indentFirstLine && attrs.hangingIndent === (level.pPr.hangingIndent ?? false)) {
147
- patch.indentFirstLine = resolved?.indentFirstLine ?? null;
148
- patch.hangingIndent = resolved?.hangingIndent ?? false;
149
- }
150
- return patch;
177
+ const direct = directParagraphIndentation(attrs);
178
+ return {
179
+ ...listIndentationProvenancePatch({
180
+ direct,
181
+ styleFormatting: attrs._styleResolvedFormatting,
182
+ numberingSource: "paragraph",
183
+ numPr: void 0,
184
+ numbering
185
+ }),
186
+ _originalFormatting: withDirectParagraphIndentation(attrs._originalFormatting, direct) ?? null
187
+ };
151
188
  }
152
189
  /** Recompute every level-dependent attr when a paragraph changes list level. */
153
190
  function listLevelAttrPatch(attrs, numPr, numbering) {
154
- const level = numbering?.getLevel(numPr.numId, numPr.ilvl);
155
- const hasMarkerSlot = level ? numberingLevelHasMarkerSlot(level) : false;
191
+ const direct = directParagraphIndentation(attrs);
156
192
  return {
157
193
  ...listAttrsFromNumbering(numPr, numbering),
158
194
  listImplicitChildLevelAdvances: attrs.listImplicitChildLevelAdvances ?? null,
159
- indentLeft: level?.pPr?.indentLeft ?? null,
160
- indentFirstLine: hasMarkerSlot ? level?.pPr?.indentFirstLine ?? null : null,
161
- hangingIndent: hasMarkerSlot ? level?.pPr?.hangingIndent ?? null : null
195
+ ...listIndentationProvenancePatch({
196
+ direct,
197
+ styleFormatting: attrs._styleResolvedFormatting,
198
+ numberingSource: attrs.numPrFromStyle == null ? "paragraph" : "style",
199
+ numPr,
200
+ numbering
201
+ }),
202
+ _originalFormatting: withDirectParagraphIndentation(attrs._originalFormatting, direct) ?? null
162
203
  };
163
204
  }
164
205
  //#endregion
165
- export { listAttrsFromNumbering, listAttrsFromResolvedStyle, listLevelAttrPatch, listLevelIndentAttrPatch, listLevelIndentRemovalPatch, paragraphAttrsFromResolvedStyle };
206
+ export { listAttrsFromNumbering, listAttrsFromResolvedStyle, listIndentationProvenancePatch, listLevelAttrPatch, listLevelIndentRemovalPatch, paragraphAttrsFromResolvedStyle };
@@ -13,6 +13,10 @@ type TextInput = {
13
13
  to: number;
14
14
  };
15
15
  declare const dispatchEditorTextInput: <TView extends TextInputDispatchTarget<TView>>(view: TView, input: string | TextInput) => void;
16
+ declare const getEditorInputTargetRange: (view: EditorView, event: InputEvent) => {
17
+ from: number;
18
+ to: number;
19
+ } | null;
16
20
  /** Shared DOM boundary for editor runtimes and standalone suggestion views. */
17
21
  declare const handleEditorBeforeInput: (view: EditorView, event: InputEvent) => boolean;
18
22
  /**
@@ -23,4 +27,4 @@ declare const afterNativeCompositionFlush: (callback: () => void) => void;
23
27
  /** Route committed text through the model before the browser mutates mark spans. */
24
28
  declare const createTextInputPlugin: () => Plugin<any>;
25
29
  //#endregion
26
- export { afterNativeCompositionFlush, createTextInputPlugin, dispatchEditorTextInput, handleEditorBeforeInput };
30
+ export { afterNativeCompositionFlush, createTextInputPlugin, dispatchEditorTextInput, getEditorInputTargetRange, handleEditorBeforeInput };