@stll/folio-core 0.55.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 (225) hide show
  1. package/dist/ai-edits/apply.js +214 -52
  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/headless.js +2 -2
  5. package/dist/ai-edits/table-row-column-mutations.js +17 -3
  6. package/dist/ai-edits/types.d.ts +7 -1
  7. package/dist/ai-suggestions/apply.js +20 -1
  8. package/dist/compare/compare.js +1 -0
  9. package/dist/compare/inline-atoms.js +40 -16
  10. package/dist/compare/inline-provenance.js +12 -5
  11. package/dist/compare/reproducible-package.d.ts +0 -17
  12. package/dist/compare/reproducible-package.js +12 -18
  13. package/dist/compat/eigenpal.d.ts +2 -1
  14. package/dist/compat/eigenpal.js +2 -1
  15. package/dist/controller/canonicalClipboard.d.ts +23 -0
  16. package/dist/controller/canonicalClipboard.js +482 -0
  17. package/dist/controller/canonicalClipboardResources.d.ts +21 -0
  18. package/dist/controller/canonicalClipboardResources.js +382 -0
  19. package/dist/controller/canonicalComments.d.ts +41 -0
  20. package/dist/controller/canonicalComments.js +152 -0
  21. package/dist/controller/canonicalComposition.d.ts +24 -3
  22. package/dist/controller/canonicalComposition.js +208 -48
  23. package/dist/controller/canonicalInlineProjection.d.ts +118 -0
  24. package/dist/controller/canonicalInlineProjection.js +476 -0
  25. package/dist/controller/canonicalInput.d.ts +13 -4
  26. package/dist/controller/canonicalInput.js +62 -14
  27. package/dist/controller/canonicalInputTimer.d.ts +16 -0
  28. package/dist/controller/canonicalInputTimer.js +34 -0
  29. package/dist/controller/canonicalPublicOperations.d.ts +48 -0
  30. package/dist/controller/canonicalPublicOperations.js +648 -0
  31. package/dist/controller/canonicalSelection.d.ts +18 -0
  32. package/dist/controller/canonicalSelection.js +32 -0
  33. package/dist/controller/canonicalSession.d.ts +27 -6
  34. package/dist/controller/canonicalSession.js +298 -116
  35. package/dist/controller/canonicalStoryEditor.d.ts +7 -3
  36. package/dist/controller/canonicalStoryEditor.js +27 -2
  37. package/dist/controller/canonicalStructure.js +57 -4
  38. package/dist/controller/canonicalTocSelection.d.ts +11 -0
  39. package/dist/controller/canonicalTocSelection.js +43 -0
  40. package/dist/controller/folioEditor.d.ts +2 -9
  41. package/dist/controller/folioEditor.js +18 -4
  42. package/dist/controller/headerFooterEditorManager.d.ts +2 -1
  43. package/dist/controller/headerFooterEditorManager.js +26 -11
  44. package/dist/controller/hiddenEditorApi.d.ts +24 -3
  45. package/dist/controller/hiddenEditorApi.js +8 -0
  46. package/dist/controller/hiddenEditorManager.d.ts +5 -1
  47. package/dist/controller/hiddenEditorManager.js +378 -43
  48. package/dist/controller/noteEditorManager.d.ts +2 -1
  49. package/dist/controller/noteEditorManager.js +29 -13
  50. package/dist/document-operations.d.ts +8 -1
  51. package/dist/document-operations.js +6 -4
  52. package/dist/docx/blockPlainText.d.ts +1 -1
  53. package/dist/docx/blockPlainText.js +11 -3
  54. package/dist/docx/builtInStyles.js +13 -6
  55. package/dist/docx/canonicalResourceSave.d.ts +16 -0
  56. package/dist/docx/canonicalResourceSave.js +27 -0
  57. package/dist/docx/canonicalSave.d.ts +29 -0
  58. package/dist/docx/canonicalSave.js +101 -0
  59. package/dist/docx/canonicalStoryRepack.d.ts +1 -1
  60. package/dist/docx/canonicalStoryRepack.js +38 -5
  61. package/dist/docx/containerChildren.gen.d.ts +3 -1
  62. package/dist/docx/containerChildren.gen.js +33 -1
  63. package/dist/docx/documentParser.d.ts +1 -13
  64. package/dist/docx/documentParser.js +1 -47
  65. package/dist/docx/ensureParaIds.js +10 -4
  66. package/dist/docx/fieldParser.js +14 -2
  67. package/dist/docx/footnoteParser.d.ts +1 -11
  68. package/dist/docx/footnoteParser.js +1 -16
  69. package/dist/docx/headerFooterParser.d.ts +1 -9
  70. package/dist/docx/headerFooterParser.js +1 -12
  71. package/dist/docx/headerFooterVerbatim.d.ts +26 -1
  72. package/dist/docx/headerFooterVerbatim.js +81 -3
  73. package/dist/docx/hyperlinkParser.d.ts +1 -1
  74. package/dist/docx/hyperlinkParser.js +20 -1
  75. package/dist/docx/imageParser.d.ts +13 -1
  76. package/dist/docx/imageParser.js +20 -11
  77. package/dist/docx/inlineWrapperContent.d.ts +4 -4
  78. package/dist/docx/inlineWrapperContent.js +4 -4
  79. package/dist/docx/linkedSdtPreservation.d.ts +10 -0
  80. package/dist/docx/linkedSdtPreservation.js +37 -0
  81. package/dist/docx/metadataPrivacy.js +6 -1
  82. package/dist/docx/packageParts.js +9 -3
  83. package/dist/docx/paragraphParser.js +88 -67
  84. package/dist/docx/paragraphPropertySource.d.ts +22 -1
  85. package/dist/docx/paragraphPropertySource.js +109 -2
  86. package/dist/docx/parser.js +2 -1
  87. package/dist/docx/preservedRunContent.js +2 -1
  88. package/dist/docx/relsParser.js +26 -2
  89. package/dist/docx/removeHeaderFooterParts.js +17 -6
  90. package/dist/docx/rezip.d.ts +49 -5
  91. package/dist/docx/rezip.js +754 -235
  92. package/dist/docx/saveDiagnostics.d.ts +11 -0
  93. package/dist/docx/selectiveSave.d.ts +2 -1
  94. package/dist/docx/selectiveSave.js +42 -11
  95. package/dist/docx/selectiveXmlPatch.js +7 -5
  96. package/dist/docx/serializer/commentSerializer.d.ts +4 -1
  97. package/dist/docx/serializer/commentSerializer.js +7 -3
  98. package/dist/docx/serializer/documentSerializer.d.ts +9 -2
  99. package/dist/docx/serializer/documentSerializer.js +29 -10
  100. package/dist/docx/serializer/paragraphSerializer.js +207 -94
  101. package/dist/docx/server/applyDocxXmlPatchProposal.js +14 -9
  102. package/dist/docx/server/materializeYjsDocx.js +14 -6
  103. package/dist/docx/server/migrateYjsAttrSchema.js +17 -5
  104. package/dist/docx/storyBlockReplay.d.ts +21 -1
  105. package/dist/docx/storyBlockReplay.js +113 -9
  106. package/dist/docx/storyPlainText.d.ts +20 -0
  107. package/dist/docx/storyPlainText.js +23 -0
  108. package/dist/docx/structuralXmlPatch.js +10 -22
  109. package/dist/docx/styleParser.d.ts +5 -1
  110. package/dist/docx/styleParser.js +1 -1
  111. package/dist/docx/tableParser.d.ts +1 -8
  112. package/dist/docx/tableParser.js +1 -28
  113. package/dist/docx/textBoxParser.d.ts +1 -5
  114. package/dist/docx/textBoxParser.js +1 -20
  115. package/dist/docx/unzip.js +6 -1
  116. package/dist/i18n/messages/ar.gen.js +4 -0
  117. package/dist/i18n/messages/catalogs.gen.d.ts +68 -0
  118. package/dist/i18n/messages/catalogs.gen.js +68 -0
  119. package/dist/i18n/messages/cs.gen.js +4 -0
  120. package/dist/i18n/messages/de.gen.js +4 -0
  121. package/dist/i18n/messages/en.gen.js +4 -0
  122. package/dist/i18n/messages/es.gen.js +4 -0
  123. package/dist/i18n/messages/et.gen.js +4 -0
  124. package/dist/i18n/messages/fr.gen.js +4 -0
  125. package/dist/i18n/messages/he.gen.js +4 -0
  126. package/dist/i18n/messages/hi.gen.js +4 -0
  127. package/dist/i18n/messages/hu.gen.js +4 -0
  128. package/dist/i18n/messages/lt.gen.js +4 -0
  129. package/dist/i18n/messages/lv.gen.js +4 -0
  130. package/dist/i18n/messages/messages.gen.d.ts +4 -0
  131. package/dist/i18n/messages/pl.gen.js +4 -0
  132. package/dist/i18n/messages/pt-BR.gen.js +4 -0
  133. package/dist/i18n/messages/sk.gen.js +4 -0
  134. package/dist/i18n/messages/tr.gen.js +4 -0
  135. package/dist/i18n/messages/zh-CN.gen.js +4 -0
  136. package/dist/index.d.ts +2 -1
  137. package/dist/index.js +2 -1
  138. package/dist/internal/acceptedBlockProjection.d.ts +12 -0
  139. package/dist/internal/acceptedBlockProjection.js +45 -0
  140. package/dist/internal/revisionResolutionInline.js +25 -3
  141. package/dist/managers/DocumentLoaderManager.js +2 -1
  142. package/dist/markdown/escape.d.ts +3 -1
  143. package/dist/markdown/escape.js +9 -2
  144. package/dist/markdown/renderBlock.js +5 -120
  145. package/dist/markdown/renderParagraph.js +4 -2
  146. package/dist/markdown/renderRuns.d.ts +7 -1
  147. package/dist/markdown/renderRuns.js +33 -24
  148. package/dist/panel-layout.d.ts +11 -9
  149. package/dist/panel-layout.js +13 -9
  150. package/dist/prosemirror/addTrackedDeletionMark.d.ts +18 -0
  151. package/dist/prosemirror/addTrackedDeletionMark.js +87 -0
  152. package/dist/prosemirror/attrs/index.js +5 -0
  153. package/dist/prosemirror/canonicalCommands.d.ts +28 -4
  154. package/dist/prosemirror/canonicalCommands.js +11 -4
  155. package/dist/prosemirror/canonicalSelectionRange.d.ts +9 -0
  156. package/dist/prosemirror/canonicalSelectionRange.js +15 -0
  157. package/dist/prosemirror/clipboardIntent.d.ts +7 -0
  158. package/dist/prosemirror/clipboardIntent.js +9 -0
  159. package/dist/prosemirror/commands/comments.js +60 -35
  160. package/dist/prosemirror/commands/pageBreak.js +2 -2
  161. package/dist/prosemirror/commands/pastePlainText.js +2 -1
  162. package/dist/prosemirror/commands/propertyChangeScope.js +3 -6
  163. package/dist/prosemirror/commands/resolveParagraphProperties.js +22 -13
  164. package/dist/prosemirror/commentOps.js +15 -1
  165. package/dist/prosemirror/conversion/fromProseDoc.js +22 -3
  166. package/dist/prosemirror/conversion/hyphenTextCarriers.d.ts +8 -0
  167. package/dist/prosemirror/conversion/hyphenTextCarriers.js +8 -0
  168. package/dist/prosemirror/conversion/toProseDoc.d.ts +7 -1
  169. package/dist/prosemirror/conversion/toProseDoc.js +124 -22
  170. package/dist/prosemirror/extensions/core/ParagraphExtension.js +61 -35
  171. package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +74 -25
  172. package/dist/prosemirror/extensions/marks/FootnoteRefExtension.js +11 -0
  173. package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +65 -29
  174. package/dist/prosemirror/extensions/marks/markUtils.js +11 -8
  175. package/dist/prosemirror/extensions/marks/noteReferenceDeletion.js +5 -2
  176. package/dist/prosemirror/fieldRepresentation.d.ts +8 -0
  177. package/dist/prosemirror/fieldRepresentation.js +18 -0
  178. package/dist/prosemirror/hyperlinkRemoval.d.ts +13 -1
  179. package/dist/prosemirror/hyperlinkRemoval.js +28 -9
  180. package/dist/prosemirror/insertOperations.js +2 -1
  181. package/dist/prosemirror/listNumbering.js +11 -5
  182. package/dist/prosemirror/noteReferenceOccurrenceId.d.ts +5 -0
  183. package/dist/prosemirror/noteReferenceOccurrenceId.js +5 -0
  184. package/dist/prosemirror/noteReferenceOccurrences.d.ts +21 -0
  185. package/dist/prosemirror/noteReferenceOccurrences.js +185 -0
  186. package/dist/prosemirror/noteReferenceReview.js +14 -1
  187. package/dist/prosemirror/paragraphPropertyCarry.d.ts +7 -1
  188. package/dist/prosemirror/paragraphPropertyCarry.js +8 -3
  189. package/dist/prosemirror/plugins/documentStyles.d.ts +4 -1
  190. package/dist/prosemirror/plugins/documentStyles.js +17 -10
  191. package/dist/prosemirror/plugins/suggestionMode.js +48 -48
  192. package/dist/prosemirror/preservedXmlReview.d.ts +6 -0
  193. package/dist/prosemirror/preservedXmlReview.js +35 -0
  194. package/dist/prosemirror/runFormattingFromMarks.js +2 -2
  195. package/dist/prosemirror/runFormattingReconciliation.js +5 -4
  196. package/dist/prosemirror/runPropertyChangeResolution.d.ts +8 -1
  197. package/dist/prosemirror/runPropertyChangeResolution.js +24 -2
  198. package/dist/prosemirror/runStyleFormatting.d.ts +3 -1
  199. package/dist/prosemirror/runStyleFormatting.js +3 -1
  200. package/dist/prosemirror/schema/marks.d.ts +1 -0
  201. package/dist/prosemirror/schema/nodes.d.ts +2 -0
  202. package/dist/prosemirror/styles/paragraphStyleCascade.js +4 -1
  203. package/dist/prosemirror/styles/resolvedStyleAttrs.d.ts +15 -15
  204. package/dist/prosemirror/styles/resolvedStyleAttrs.js +69 -28
  205. package/dist/prosemirror/textInput.d.ts +5 -1
  206. package/dist/prosemirror/textInput.js +3 -3
  207. package/dist/prosemirror/trackedRevisionPath.d.ts +5 -1
  208. package/dist/prosemirror/trackedRevisionPath.js +39 -1
  209. package/dist/prosemirror/validation.js +3 -5
  210. package/dist/prosemirror/yjsDocumentMetadata.d.ts +9 -3
  211. package/dist/prosemirror/yjsDocumentMetadata.js +37 -8
  212. package/dist/types/canonicalCapabilities.d.ts +201 -0
  213. package/dist/types/canonicalCapabilities.js +198 -0
  214. package/dist/types/canonicalComments.d.ts +51 -0
  215. package/dist/types/canonicalComments.js +0 -0
  216. package/dist/types/canonicalSave.d.ts +11 -0
  217. package/dist/types/canonicalSave.js +0 -0
  218. package/dist/types/canonicalSections.d.ts +12 -0
  219. package/dist/types/canonicalSections.js +0 -0
  220. package/dist/types/docxSerialization.d.ts +14 -0
  221. package/dist/types/docxSerialization.js +7 -0
  222. package/dist/utils/headingCollector.js +45 -4
  223. package/dist/utils/outlineDepth.d.ts +9 -0
  224. package/dist/utils/outlineDepth.js +9 -0
  225. package/package.json +4 -4
@@ -2,7 +2,7 @@ import { rangedCommentIds } from "../../docx/commentAnchorIndex.js";
2
2
  import { resolveColorValueToHex } from "../../docx/drawingUtils.js";
3
3
  import { isInlineSdtContent, isTrackedChangeWrapperChild } from "../../docx/inlineWrapperContent.js";
4
4
  import { computeListRendering, getCachedNumberingMap } from "../../docx/numberingParser.js";
5
- import { PROSE_PARAGRAPH_SOURCE_CONTRACT_ATTR, createProseParagraphWithPropertySource, getDocumentParagraphPropertySourceContract, proseParagraphAttrsWithoutPropertySource, recreateProseNodeWithParagraphPropertySource, transportTableCellsWithParagraphPropertySources } from "../../docx/paragraphPropertySource.js";
5
+ import { PROSE_PARAGRAPH_SOURCE_CONTRACT_ATTR, createProseParagraphWithPropertySource, getDocumentParagraphPropertySourceContract, paragraphFormattingWithAuthoredIndentation, proseParagraphAttrsWithoutPropertySource, recreateProseNodeWithParagraphPropertySource, transportTableCellsWithParagraphPropertySources } from "../../docx/paragraphPropertySource.js";
6
6
  import { isBaselineVertAlign } from "../../docx/runParser.js";
7
7
  import { replayableShapeAlternateContent } from "../../docx/shapeAlternateContent.js";
8
8
  import { resolveTableLook } from "../../docx/tableLook.js";
@@ -25,11 +25,11 @@ import { setAutospacingBaseValue } from "../autospacingBase.js";
25
25
  import { withEnclosingRevision } from "../contentControlRevisions.js";
26
26
  import { emptyFieldRunPropertyChanges } from "../emptyFieldResultRuns.js";
27
27
  import { planEmptyRanges } from "../emptyRangeAnchor.js";
28
- import { INLINE_WRAPPER_MARK_NAME } from "../extensions/marks/InlineWrapperExtension.js";
29
28
  import { textFormattingToMarks } from "../extensions/marks/markUtils.js";
30
29
  import { MOVE_RANGE_BOUNDARY_NODE_NAME } from "../extensions/nodes/MoveRangeBoundaryExtension.js";
31
30
  import { RANGE_ANCHOR_NODE_NAME } from "../extensions/nodes/RangeAnchorExtension.js";
32
31
  import "../extensions/nodes/SdtExtension.js";
32
+ import { fieldRequiresStructuredContent } from "../fieldRepresentation.js";
33
33
  import { inlineWrapperLayer } from "../inlineWrapperStack.js";
34
34
  import { CLEARED_LIST_RENDERING_ATTRS } from "../listMarker.js";
35
35
  import { listRenderingAttrPatch } from "../listRenderingAttrs.js";
@@ -37,18 +37,21 @@ import { stampNumberedRefFieldBaselines } from "../numberedRefFields.js";
37
37
  import { paragraphNumberingAttr } from "../numberingAttr.js";
38
38
  import { pageBreakRunParagraphProjectionDispositionForFeatures } from "../pageBreakRunProjection.js";
39
39
  import { directionFromBidi } from "../paragraphDirection.js";
40
+ import { paragraphIndentationFromFormatting } from "../paragraphIndentation.js";
40
41
  import { lineSpacingProvenanceFromSpacing } from "../paragraphSpacing.js";
41
42
  import { RUN_IDENTITY_MARK_NAME, hasRunIdentityPayload, runIdentityAttrs } from "../runIdentity.js";
42
43
  import { continueRunIdentitiesAcrossRevisions } from "../runIdentityAcrossRevisions.js";
43
- import { getParagraphMarkSuppressionOverrides, hasDirectRunFormatting, resolveParagraphBodyRunFormatting, stripParagraphMarkFormattingForBodyRuns, stripParagraphMarkOnlyFormatting, suppressParagraphMarkFormatting } from "../runStyleFormatting.js";
44
+ import { getParagraphMarkSuppressionOverrides, hasDirectRunFormatting, isParagraphMarkSuppressionEligible, resolveParagraphBodyRunFormatting, stripParagraphMarkFormattingForBodyRuns, stripParagraphMarkOnlyFormatting, suppressParagraphMarkFormatting } from "../runStyleFormatting.js";
44
45
  import { schema } from "../schema/index.js";
45
46
  import { PRESERVED_XML_LEVELS } from "../schema/nodes.js";
46
47
  import { extractTableParagraphOverlay, paragraphStyleCascadeAttrs, resolveRunFormattingWithoutDefaults } from "../styles/paragraphStyleCascade.js";
48
+ import { listIndentationProvenancePatch } from "../styles/resolvedStyleAttrs.js";
47
49
  import { cascadeStyleTextFormatting } from "../styles/styleToggleCascade.js";
48
50
  import { tableCellStyleRegions, tableRowBand } from "../styles/tableStyleRegions.js";
49
51
  import { canCarryTrackedRunMark, trackedRunInlineAtomDisposition } from "../trackedRunInlineAtoms.js";
50
52
  import { assertValidProseMirrorDocument } from "../validation.js";
51
53
  import { resolveEffectiveTableCellFormatting } from "./effectiveTableCellFormatting.js";
54
+ import { HYPHEN_TEXT_CARRIERS } from "./hyphenTextCarriers.js";
52
55
  import { listRenderingDefinitionsMatch } from "./listRenderingDefinition.js";
53
56
  import { createMarkInterner } from "./markInterner.js";
54
57
  import { hasSinkChildren } from "./preservedSinkCarriers.js";
@@ -56,6 +59,19 @@ import { sdtAttrsFromProperties } from "./sdtAttrs.js";
56
59
  import { panic } from "better-result";
57
60
  import { DRAWING_RAW_XML_MODES, PARSE_WARNING_CODES, mergeParagraphNumbering } from "@stll/docx-core/model";
58
61
  //#region src/prosemirror/conversion/toProseDoc.ts
62
+ /**
63
+ * Document to ProseMirror Conversion
64
+ *
65
+ * Converts our Document type (from DOCX parsing) to a ProseMirror document.
66
+ * Preserves all formatting attributes for round-trip fidelity.
67
+ *
68
+ * Style Resolution:
69
+ * When styles are provided, paragraph properties are resolved from the style chain:
70
+ * - Document defaults (docDefaults)
71
+ * - Normal style (if no explicit styleId)
72
+ * - Style chain (basedOn inheritance)
73
+ * - Inline properties (highest priority)
74
+ */
59
75
  const DETACHED_WATERMARK_HOST = Symbol.for("stll.detachedWatermarkHost");
60
76
  const noPageBreakProjectionWarning = () => {};
61
77
  const pageBreakProjectionWarn = (warn) => warn === void 0 ? noPageBreakProjectionWarning : (detail) => {
@@ -105,6 +121,11 @@ const createHyperlinkInstanceIndexAllocator = () => {
105
121
  let index = 0;
106
122
  return () => index++;
107
123
  };
124
+ /** Imported occurrences belong to the projection walk, not to the referenced note. */
125
+ const createNoteReferenceOccurrenceAllocator = () => {
126
+ let index = 0;
127
+ return () => `source-note:${index++}`;
128
+ };
108
129
  /**
109
130
  * Find bookmark pairs across every editable inline wrapper in a document story.
110
131
  * Each endpoint is converted at its own structural position, so a range may
@@ -231,6 +252,7 @@ function toProseDoc(document, options) {
231
252
  const theme = options?.theme ?? document.package.theme ?? null;
232
253
  const nextTextBoxGroupId = createTextBoxGroupIdFactory();
233
254
  const nextHyperlinkInstanceIndex = createHyperlinkInstanceIndexAllocator();
255
+ const nextNoteReferenceOccurrenceId = createNoteReferenceOccurrenceAllocator();
234
256
  const pairedBookmarkIds = collectPairedBookmarkIds(paragraphs);
235
257
  const conversionContext = {
236
258
  listRenderings: /* @__PURE__ */ new Map(),
@@ -238,6 +260,7 @@ function toProseDoc(document, options) {
238
260
  theme,
239
261
  nextTextBoxGroupId,
240
262
  nextHyperlinkInstanceIndex,
263
+ nextNoteReferenceOccurrenceId,
241
264
  pairedBookmarkIds,
242
265
  pageBreakRunSourceDescendants: buildPageBreakRunSourceDescendantIndex(paragraphs),
243
266
  storyRangedCommentIds: rangedCommentIds(paragraphs),
@@ -405,12 +428,26 @@ function convertParagraph(paragraph, styleResolver, context, extraRunFormatting,
405
428
  let runIdentityId = 0;
406
429
  const runScope = {
407
430
  nextRunIdentityId: () => runIdentityId++,
431
+ nextNoteReferenceOccurrenceId: context.nextNoteReferenceOccurrenceId,
408
432
  createMark: context.createMark
409
433
  };
434
+ const directFormatting = paragraphFormattingWithAuthoredIndentation(paragraph);
410
435
  const { attrs, effectiveFrame } = paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOverlay);
436
+ if (directFormatting === void 0) Reflect.deleteProperty(attrs, "_originalFormatting");
437
+ else attrs._originalFormatting = directFormatting;
411
438
  const numPr = mergeParagraphNumbering(attrs.numPrFromStyle ?? void 0, attrs.numPr ?? void 0);
412
439
  if (numPr?.kind === "none") Object.assign(attrs, CLEARED_LIST_RENDERING_ATTRS);
413
440
  else if (context.numbering !== void 0 && numPr?.kind === "reference") {
441
+ Object.assign(attrs, listIndentationProvenancePatch({
442
+ direct: paragraphIndentationFromFormatting(directFormatting),
443
+ styleFormatting: attrs._styleResolvedFormatting,
444
+ numberingSource: attrs.numPrFromStyle == null ? "paragraph" : "style",
445
+ numPr: {
446
+ numId: numPr.numId,
447
+ ilvl: numPr.ilvl ?? 0
448
+ },
449
+ numbering: context.numbering
450
+ }));
414
451
  const { rendering, nextSlotOffset } = resolveListRendering(numPr, context);
415
452
  if (rendering !== null) {
416
453
  const cached = paragraph.listRendering;
@@ -475,7 +512,7 @@ function convertParagraph(paragraph, styleResolver, context, extraRunFormatting,
475
512
  ...!hasCharacterStyle ? { implicitCharacterStyleApplied: true } : {},
476
513
  toggleCascade: inheritedToggleCascade
477
514
  };
478
- if (!(hasDirectRunFormatting(formatting) || formatting?.styleId !== void 0)) return {
515
+ if (!isParagraphMarkSuppressionEligible(formatting)) return {
479
516
  formatting: defaultRunFormatting,
480
517
  implicitCharacterStyleApplied: true,
481
518
  toggleCascade: defaultToggleCascade
@@ -642,7 +679,7 @@ function applyCommentMarks(nodes, commentIds) {
642
679
  if (!commentMarkType) return nodes;
643
680
  const commentMarks = [...commentIds].toSorted((left, right) => left - right).map((commentId) => commentMarkType.create({ commentId }));
644
681
  return nodes.map((node) => {
645
- if (!node.isText && (!node.isInline || !node.type.allowsMarkType(commentMarkType))) return node;
682
+ if (!node.isInline) return node;
646
683
  let marks = node.marks;
647
684
  for (const commentMark of commentMarks) marks = commentMark.addToSet(marks);
648
685
  return node.mark(marks);
@@ -786,7 +823,7 @@ function paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOver
786
823
  if (tableOfContentsLevel !== void 0) attrs._tableOfContentsLevel = tableOfContentsLevel;
787
824
  if (formatting?.numPr) attrs.numPr = paragraphNumberingAttr(formatting.numPr);
788
825
  if (formatting?.numPrFromStyle) attrs.numPrFromStyle = paragraphNumberingAttr(formatting.numPrFromStyle);
789
- if (paragraph.listRendering && formatting?.numPr?.kind !== "none") Object.assign(attrs, listRenderingAttrPatch(paragraph.listRendering));
826
+ if (paragraph.listRendering && formatting?.numPr?.kind !== "none") Object.assign(attrs, CLEARED_LIST_RENDERING_ATTRS, listRenderingAttrPatch(paragraph.listRendering));
790
827
  if (formatting) attrs._originalFormatting = formatting;
791
828
  if (paragraph.propertyChanges && paragraph.propertyChanges.length > 0) attrs._propertyChanges = paragraph.propertyChanges.map(({ previousFormatting, ...change }) => {
792
829
  if (previousFormatting === void 0) return change;
@@ -1289,6 +1326,7 @@ function convertTableCell({ cell, styleResolver, context, isHeader, gridWidthPer
1289
1326
  function standaloneTableCellToProseMirror(cell, nodeType) {
1290
1327
  const nextTextBoxGroupId = createTextBoxGroupIdFactory();
1291
1328
  const nextHyperlinkInstanceIndex = createHyperlinkInstanceIndexAllocator();
1329
+ const nextNoteReferenceOccurrenceId = createNoteReferenceOccurrenceAllocator();
1292
1330
  const pageBreakRunSourceDescendants = buildPageBreakRunSourceDescendantIndex(cell.content);
1293
1331
  reportSourceContainerPageBreakRun(cell.content, "table-cell", pageBreakRunSourceDescendants, noPageBreakProjectionWarning);
1294
1332
  return convertTableCell({
@@ -1300,6 +1338,7 @@ function standaloneTableCellToProseMirror(cell, nodeType) {
1300
1338
  numbering: void 0,
1301
1339
  nextTextBoxGroupId,
1302
1340
  nextHyperlinkInstanceIndex,
1341
+ nextNoteReferenceOccurrenceId,
1303
1342
  pairedBookmarkIds: collectPairedBookmarkIds(cell.content),
1304
1343
  pageBreakRunSourceDescendants,
1305
1344
  storyRangedCommentIds: rangedCommentIds(cell.content),
@@ -1323,14 +1362,56 @@ function convertField(field, { getInheritedRunFormatting, styleResolver, nextHyp
1323
1362
  let fieldFormatting;
1324
1363
  let fieldPropertyChanges;
1325
1364
  const inlineNodes = [];
1326
- const hasStructuredSourceContent = fieldResultHasPageBreakContent(field) || field.type === "simpleField" && field.content.some((content) => content.type === "hyperlink" || content.type === "preservedInline" || content.type === "inlineWrapper");
1365
+ const hasStructuredSourceContent = fieldResultHasPageBreakContent(field) || field.type === "simpleField" && field.content.some((content) => content.type === "hyperlink" || content.type === "preservedInline" || content.type === "inlineWrapper" || content.type === "insertion" || content.type === "deletion" || content.type === "moveFrom" || content.type === "moveTo");
1327
1366
  const appendRun = (run, into) => {
1328
1367
  for (const content of run.content) if (content.type === "text") displayText += content.text;
1329
1368
  fieldFormatting ??= run.formatting;
1330
1369
  fieldPropertyChanges ??= run.propertyChanges;
1331
- if (!hasStructuredSourceContent) return;
1370
+ if (field.type !== "simpleField" && !hasStructuredSourceContent) return;
1332
1371
  into.push(...convertRun(run, getInheritedRunFormatting(run.formatting, field.fieldType), runScope, styleResolver, textBoxAnchors));
1333
1372
  };
1373
+ const collectDisplay = (items) => {
1374
+ for (const item of items) switch (item.type) {
1375
+ case "run":
1376
+ for (const child of item.content) if (child.type === "text") displayText += child.text;
1377
+ fieldFormatting ??= item.formatting;
1378
+ fieldPropertyChanges ??= item.propertyChanges;
1379
+ break;
1380
+ case "hyperlink":
1381
+ collectDisplay(item.children);
1382
+ break;
1383
+ case "inlineWrapper":
1384
+ case "inlineSdt":
1385
+ case "insertion":
1386
+ case "deletion":
1387
+ case "moveFrom":
1388
+ case "moveTo":
1389
+ collectDisplay(item.content);
1390
+ break;
1391
+ case "simpleField":
1392
+ collectDisplay(item.content);
1393
+ break;
1394
+ case "complexField":
1395
+ collectDisplay(item.fieldResult);
1396
+ break;
1397
+ case "preservedInline":
1398
+ displayText += item.text;
1399
+ break;
1400
+ case "mathEquation":
1401
+ displayText += item.plainText ?? "";
1402
+ break;
1403
+ case "bookmarkStart":
1404
+ case "bookmarkEnd":
1405
+ case "commentRangeStart":
1406
+ case "commentRangeEnd":
1407
+ case "commentReference":
1408
+ case "moveFromRangeStart":
1409
+ case "moveFromRangeEnd":
1410
+ case "moveToRangeStart":
1411
+ case "moveToRangeEnd": break;
1412
+ default: panic(`Unsupported field display content: ${JSON.stringify(item)}`);
1413
+ }
1414
+ };
1334
1415
  if (field.type === "simpleField") for (const { content, stack } of withInlineWrapperStacks(field.content)) {
1335
1416
  const itemNodes = [];
1336
1417
  switch (content.type) {
@@ -1354,6 +1435,16 @@ function convertField(field, { getInheritedRunFormatting, styleResolver, nextHyp
1354
1435
  runScope
1355
1436
  }));
1356
1437
  break;
1438
+ case "insertion":
1439
+ case "deletion":
1440
+ case "moveFrom":
1441
+ case "moveTo":
1442
+ collectDisplay(content.content);
1443
+ itemNodes.push(...convertTrackedChange(content, content.type === "insertion" || content.type === "moveTo" ? "insertion" : "deletion", nextHyperlinkInstanceIndex, runScope, {
1444
+ current: getInheritedRunFormatting,
1445
+ historical: getInheritedRunFormatting
1446
+ }, styleResolver, content.type === "moveFrom" || content.type === "moveTo" ? content.type : null, textBoxAnchors));
1447
+ break;
1357
1448
  default: break;
1358
1449
  }
1359
1450
  inlineNodes.push(...withInlineWrapperMark(itemNodes, stack));
@@ -1367,11 +1458,7 @@ function convertField(field, { getInheritedRunFormatting, styleResolver, nextHyp
1367
1458
  styleResolver,
1368
1459
  createMark: runScope.createMark
1369
1460
  });
1370
- const hasConvertedHyperlinkContent = inlineNodes.some((node) => node.marks.some((mark) => mark.type.name === "hyperlink"));
1371
- const hasConvertedPageBreakContent = inlineNodes.some((node) => node.type.name === "pageBreakRun");
1372
- const hasConvertedPreservedContent = inlineNodes.some((node) => node.type.name === "preservedXml");
1373
- const hasConvertedWrapperContent = inlineNodes.some((node) => node.marks.some((mark) => mark.type.name === INLINE_WRAPPER_MARK_NAME));
1374
- const createStructuredField = hasConvertedPageBreakContent || hasConvertedPreservedContent || hasStructuredSourceContent && (hasConvertedHyperlinkContent || hasConvertedWrapperContent);
1461
+ const createStructuredField = fieldRequiresStructuredContent(inlineNodes);
1375
1462
  const resultRuns = field.type === "simpleField" ? field.content.flatMap((content) => content.type === "run" ? [content] : []) : field.fieldResult;
1376
1463
  const emptyResultRuns = displayText === "" && resultRuns.length > 0 && (field.type === "complexField" || field.content.length === resultRuns.length) && resultRuns.every((run) => run.content.every((item) => item.type === "text" && item.text === "")) ? resultRuns : void 0;
1377
1464
  const resultPropertyChanges = emptyResultRuns ? emptyFieldRunPropertyChanges(emptyResultRuns) : fieldPropertyChanges;
@@ -1563,7 +1650,14 @@ function convertRun(run, resolvedStyleFormatting, runScope, styleResolver, textB
1563
1650
  const identity = runIdentityMark(run, runScope.nextRunIdentityId);
1564
1651
  if (identity) marks.push(identity);
1565
1652
  for (const content of run.content) {
1566
- const contentNodes = convertRunContent(content, marks, mergedFormatting, textBoxAnchors, run.formatting);
1653
+ const contentNodes = convertRunContent({
1654
+ content,
1655
+ marks,
1656
+ formatting: mergedFormatting,
1657
+ textBoxAnchors,
1658
+ authoredFormatting: run.formatting,
1659
+ nextNoteReferenceOccurrenceId: runScope.nextNoteReferenceOccurrenceId
1660
+ });
1567
1661
  nodes.push(...contentNodes);
1568
1662
  }
1569
1663
  return nodes;
@@ -1969,10 +2063,7 @@ const noteReferenceVertAlign = (vertAlign) => {
1969
2063
  * run was authored with.
1970
2064
  */
1971
2065
  const carriedRunFormatting = (formatting) => formatting && Object.keys(formatting).length > 0 ? formatting : void 0;
1972
- /**
1973
- * Convert RunContent to ProseMirror nodes
1974
- */
1975
- function convertRunContent(content, marks, formatting, textBoxAnchors, authoredFormatting) {
2066
+ function convertRunContent({ content, marks, formatting, textBoxAnchors, authoredFormatting, nextNoteReferenceOccurrenceId }) {
1976
2067
  switch (content.type) {
1977
2068
  case "noteMarker": return [schema.node("noteMarker", { kind: content.kind }).mark(marks)];
1978
2069
  case "text":
@@ -2012,6 +2103,7 @@ function convertRunContent(content, marks, formatting, textBoxAnchors, authoredF
2012
2103
  case "footnoteRef": {
2013
2104
  const footnoteMark = schema.mark("footnoteRef", {
2014
2105
  id: content.id.toString(),
2106
+ occurrenceId: nextNoteReferenceOccurrenceId(),
2015
2107
  noteType: "footnote",
2016
2108
  vertAlign: noteReferenceVertAlign(formatting?.vertAlign),
2017
2109
  customMarkFollows: content.customMarkFollows
@@ -2021,6 +2113,7 @@ function convertRunContent(content, marks, formatting, textBoxAnchors, authoredF
2021
2113
  case "endnoteRef": {
2022
2114
  const endnoteMark = schema.mark("footnoteRef", {
2023
2115
  id: content.id.toString(),
2116
+ occurrenceId: nextNoteReferenceOccurrenceId(),
2024
2117
  noteType: "endnote",
2025
2118
  vertAlign: noteReferenceVertAlign(formatting?.vertAlign),
2026
2119
  customMarkFollows: content.customMarkFollows
@@ -2034,8 +2127,8 @@ function convertRunContent(content, marks, formatting, textBoxAnchors, authoredF
2034
2127
  text: content.text,
2035
2128
  level: PRESERVED_XML_LEVELS.run
2036
2129
  }).mark(marks)];
2037
- case "noBreakHyphen": return [schema.text("‑", marks)];
2038
- case "softHyphen": return [schema.text("­", marks)];
2130
+ case "noBreakHyphen": return [schema.text(HYPHEN_TEXT_CARRIERS.noBreakHyphen, marks)];
2131
+ case "softHyphen": return [schema.text(HYPHEN_TEXT_CARRIERS.softHyphen, marks)];
2039
2132
  case "symbol": return [schema.node("symbol", {
2040
2133
  font: content.font,
2041
2134
  char: content.char
@@ -2250,7 +2343,14 @@ function convertHyperlink(hyperlink, { getInheritedRunFormatting, styleResolver,
2250
2343
  const identity = runIdentityMark(child, runScope.nextRunIdentityId);
2251
2344
  if (identity) runMarks.push(identity);
2252
2345
  const allMarks = [...runMarks, linkMark];
2253
- for (const content of child.content) childNodes.push(...convertRunContent(content, allMarks, mergedFormatting, textBoxAnchors, child.formatting));
2346
+ for (const content of child.content) childNodes.push(...convertRunContent({
2347
+ content,
2348
+ marks: allMarks,
2349
+ formatting: mergedFormatting,
2350
+ textBoxAnchors,
2351
+ authoredFormatting: child.formatting,
2352
+ nextNoteReferenceOccurrenceId: runScope.nextNoteReferenceOccurrenceId
2353
+ }));
2254
2354
  break;
2255
2355
  }
2256
2356
  default: break;
@@ -2694,6 +2794,7 @@ function headerFooterToProseDoc(content, options) {
2694
2794
  const theme = options?.theme ?? null;
2695
2795
  const nextTextBoxGroupId = createTextBoxGroupIdFactory();
2696
2796
  const nextHyperlinkInstanceIndex = createHyperlinkInstanceIndexAllocator();
2797
+ const nextNoteReferenceOccurrenceId = createNoteReferenceOccurrenceAllocator();
2697
2798
  const pairedBookmarkIds = collectPairedBookmarkIds(content);
2698
2799
  const conversionContext = {
2699
2800
  listRenderings: /* @__PURE__ */ new Map(),
@@ -2701,6 +2802,7 @@ function headerFooterToProseDoc(content, options) {
2701
2802
  numbering: options?.numbering === void 0 ? void 0 : getCachedNumberingMap(options.numbering),
2702
2803
  nextTextBoxGroupId,
2703
2804
  nextHyperlinkInstanceIndex,
2805
+ nextNoteReferenceOccurrenceId,
2704
2806
  pairedBookmarkIds,
2705
2807
  pageBreakRunSourceDescendants: buildPageBreakRunSourceDescendantIndex(content),
2706
2808
  storyRangedCommentIds: rangedCommentIds(content),
@@ -2765,4 +2867,4 @@ function createEmptyDoc() {
2765
2867
  return schema.node("doc", null, [schema.node("paragraph", {}, [])]);
2766
2868
  }
2767
2869
  //#endregion
2768
- export { createEmptyDoc, footnoteToProseDoc, headerFooterToProseDoc, standaloneTableCellToProseMirror, toProseDoc };
2870
+ export { collectPairedBookmarkIds, createEmptyDoc, footnoteToProseDoc, headerFooterToProseDoc, standaloneTableCellToProseMirror, toProseDoc };
@@ -8,18 +8,20 @@ import { collectHeadings } from "../../../utils/headingCollector.js";
8
8
  import { tableOfContentsStyleLevel } from "../../../utils/tableOfContentsStyle.js";
9
9
  import { expectParagraphAttrs } from "../../attrs/index.js";
10
10
  import { autospacingMatchesBase } from "../../autospacingBase.js";
11
- import { withCanonicalParagraphFormatting } from "../../canonicalCommands.js";
11
+ import { withCanonicalCommand, withCanonicalParagraphFormatting, withCanonicalStartParagraphFormatting } from "../../canonicalCommands.js";
12
12
  import { removeSectionBreakAtSelection, setSectionBreakType } from "../../commands/sectionBreak.js";
13
13
  import { CLEARED_LIST_RENDERING_ATTRS } from "../../listMarker.js";
14
14
  import { directParagraphAlignment } from "../../paragraphAlignment.js";
15
15
  import { directionIsRtl } from "../../paragraphDirection.js";
16
16
  import { directParagraphIndentation } from "../../paragraphIndentation.js";
17
+ import { recordReplacedParagraphProperties } from "../../paragraphPropertyCarry.js";
17
18
  import { directParagraphSpacing, withDirectParagraphSpacing } from "../../paragraphSpacing.js";
18
19
  import { getDocumentNumbering } from "../../plugins/documentNumbering.js";
19
20
  import { getDocumentBuiltInStyles, getDocumentStyleResolver } from "../../plugins/documentStyleState.js";
21
+ import { SUGGESTION_META, makeRevisionInfo } from "../../plugins/suggestionMode.js";
20
22
  import { rebaseParagraphRuns } from "../../rebaseParagraphRuns.js";
21
23
  import { mintSectionProperties, parseSectionBreakType, sectionBreakTypeOf } from "../../sectionCarrier.js";
22
- import { listAttrsFromResolvedStyle, listLevelIndentAttrPatch, paragraphAttrsFromResolvedStyle } from "../../styles/resolvedStyleAttrs.js";
24
+ import { listAttrsFromResolvedStyle, listIndentationProvenancePatch, paragraphAttrsFromResolvedStyle } from "../../styles/resolvedStyleAttrs.js";
23
25
  import { createNodeExtension } from "../create.js";
24
26
  import { headingOutlineLevel, paragraphNumberingLevel, paragraphNumberingReferenceId } from "@stll/docx-core/model";
25
27
  import { Fragment } from "prosemirror-model";
@@ -263,6 +265,7 @@ const paragraphNodeSpec = {
263
265
  _emptyHyperlinks: { default: null },
264
266
  _originalFormatting: { default: null },
265
267
  _resolvedFormatting: { default: void 0 },
268
+ _styleResolvedFormatting: { default: void 0 },
266
269
  _autospacingBase: { default: null },
267
270
  _sectionProperties: { default: null },
268
271
  _propertyChanges: { default: null },
@@ -548,6 +551,7 @@ function makeApplyStyle() {
548
551
  const { $from, $to } = state.selection;
549
552
  if (!dispatch) return true;
550
553
  let tr = state.tr;
554
+ const revision = makeRevisionInfo(state);
551
555
  const seen = /* @__PURE__ */ new Set();
552
556
  state.doc.nodesBetween($from.pos, $to.pos, (node, pos) => {
553
557
  if (node.type.name === "paragraph" && !seen.has(pos)) {
@@ -583,12 +587,24 @@ function makeApplyStyle() {
583
587
  numPr: null,
584
588
  numPrFromStyle: null
585
589
  });
586
- else if (directNumId !== void 0) Object.assign(newAttrs, listLevelIndentAttrPatch(restyledIndentation(styleAttrs, restyledOriginal), {
587
- numId: directNumId,
588
- ilvl: paragraphNumberingLevel(current.numPr ?? void 0) ?? 0
589
- }, resolvedAttrs.numbering ?? getDocumentNumbering(state)));
590
+ else if (directNumId !== void 0) Object.assign(newAttrs, listIndentationProvenancePatch({
591
+ direct: restyledIndentation(styleAttrs, restyledOriginal),
592
+ styleFormatting: resolvedAttrs.paragraphFormatting,
593
+ numberingSource: "paragraph",
594
+ numPr: {
595
+ numId: directNumId,
596
+ ilvl: paragraphNumberingLevel(current.numPr ?? void 0) ?? 0
597
+ },
598
+ numbering: resolvedAttrs.numbering ?? getDocumentNumbering(state)
599
+ }));
590
600
  }
591
601
  tr = tr.setNodeMarkup(pos, void 0, newAttrs);
602
+ if (revision) recordReplacedParagraphProperties({
603
+ tr,
604
+ position: pos,
605
+ replaced: node,
606
+ revision
607
+ });
592
608
  rebaseParagraphRuns({
593
609
  tr,
594
610
  position: pos,
@@ -598,6 +614,7 @@ function makeApplyStyle() {
598
614
  });
599
615
  }
600
616
  });
617
+ if (revision) tr.setMeta(SUGGESTION_META, true);
601
618
  dispatch(tr.scrollIntoView());
602
619
  return true;
603
620
  };
@@ -696,7 +713,7 @@ const ParagraphExtension = createNodeExtension({
696
713
  }, { styleId: null }),
697
714
  insertSectionBreak: (breakType) => setSectionBreakType(breakType),
698
715
  removeSectionBreak: () => removeSectionBreakAtSelection,
699
- generateTOC: ({ title }) => (state, dispatch) => {
716
+ generateTOC: ({ title }) => withCanonicalCommand((state, dispatch) => {
700
717
  const builtInStyles = getDocumentBuiltInStyles(state);
701
718
  const headings = collectHeadings(state.doc, builtInStyles);
702
719
  if (headings.length === 0) return false;
@@ -773,44 +790,53 @@ const ParagraphExtension = createNodeExtension({
773
790
  tr.insert(insertPos, Fragment.from(tocNodes));
774
791
  dispatch(tr.scrollIntoView());
775
792
  return true;
776
- },
777
- toggleBidi: () => (state, dispatch) => {
778
- const { $from } = state.selection;
779
- const paragraph = $from.parent;
780
- if (paragraph.type.name !== "paragraph") return false;
781
- return setParagraphAttr("direction", directionIsRtl(paragraph.attrs["direction"]) ? {
782
- source: "manual",
783
- value: "ltr"
784
- } : {
793
+ }, (state) => [{
794
+ type: "generateTOC",
795
+ at: state.selection.from,
796
+ title
797
+ }]),
798
+ toggleBidi: () => {
799
+ const directionFor = (paragraph) => ({
785
800
  source: "manual",
786
- value: "rtl"
787
- })(state, dispatch);
801
+ value: directionIsRtl(expectParagraphAttrs(paragraph).direction) ? "ltr" : "rtl"
802
+ });
803
+ return withCanonicalStartParagraphFormatting((state, dispatch) => {
804
+ const paragraph = state.selection.$from.parent;
805
+ if (paragraph.type.name !== "paragraph") return false;
806
+ return setParagraphAttr("direction", directionFor(paragraph))(state, dispatch);
807
+ }, (paragraph) => ({ bidi: directionIsRtl(directionFor(paragraph)) }));
788
808
  },
789
- setRtl: () => setParagraphAttr("direction", {
809
+ setRtl: () => withCanonicalParagraphFormatting(setParagraphAttr("direction", {
790
810
  source: "manual",
791
811
  value: "rtl"
792
- }),
793
- setLtr: () => setParagraphAttr("direction", {
812
+ }), { bidi: true }),
813
+ setLtr: () => withCanonicalParagraphFormatting(setParagraphAttr("direction", {
794
814
  source: "manual",
795
815
  value: "ltr"
796
- }),
797
- setTabs: (tabs) => setParagraphAttr("tabs", tabs.length > 0 ? tabs : null),
798
- addTabStop: (position, alignment = "left", leader = "none") => (state, dispatch) => {
799
- const { $from } = state.selection;
800
- const paragraph = $from.parent;
801
- if (paragraph.type.name !== "paragraph") return false;
802
- return setParagraphAttr("tabs", [...(paragraph.attrs["tabs"] || []).filter((t) => t.position !== position), {
816
+ }), { bidi: false }),
817
+ setTabs: (tabs) => withCanonicalParagraphFormatting(setParagraphAttr("tabs", tabs.length > 0 ? tabs : null), { tabs: tabs.length > 0 ? tabs : null }),
818
+ addTabStop: (position, alignment = "left", leader = "none") => {
819
+ const tabsFor = (paragraph) => [...(expectParagraphAttrs(paragraph).tabs ?? []).filter((tab) => tab.position !== position), {
803
820
  position,
804
821
  alignment,
805
822
  leader
806
- }].toSorted((a, b) => a.position - b.position))(state, dispatch);
823
+ }].toSorted((a, b) => a.position - b.position);
824
+ return withCanonicalStartParagraphFormatting((state, dispatch) => {
825
+ const paragraph = state.selection.$from.parent;
826
+ if (paragraph.type.name !== "paragraph") return false;
827
+ return setParagraphAttr("tabs", tabsFor(paragraph))(state, dispatch);
828
+ }, (paragraph) => ({ tabs: tabsFor(paragraph) }));
807
829
  },
808
- removeTabStop: (position) => (state, dispatch) => {
809
- const { $from } = state.selection;
810
- const paragraph = $from.parent;
811
- if (paragraph.type.name !== "paragraph") return false;
812
- const newTabs = (paragraph.attrs["tabs"] || []).filter((t) => t.position !== position);
813
- return setParagraphAttr("tabs", newTabs.length > 0 ? newTabs : null)(state, dispatch);
830
+ removeTabStop: (position) => {
831
+ const tabsFor = (paragraph) => {
832
+ const tabs = (expectParagraphAttrs(paragraph).tabs ?? []).filter((tab) => tab.position !== position);
833
+ return tabs.length > 0 ? tabs : null;
834
+ };
835
+ return withCanonicalStartParagraphFormatting((state, dispatch) => {
836
+ const paragraph = state.selection.$from.parent;
837
+ if (paragraph.type.name !== "paragraph") return false;
838
+ return setParagraphAttr("tabs", tabsFor(paragraph))(state, dispatch);
839
+ }, (paragraph) => ({ tabs: tabsFor(paragraph) }));
814
840
  }
815
841
  } };
816
842
  }
@@ -1,5 +1,5 @@
1
1
  import { mergeTextFormatting } from "../../../utils/textFormattingMerge.js";
2
- import { expectCharacterStyleMarkAttrs, expectRunFormattingOverrideMarkAttrs } from "../../attrs/index.js";
2
+ import { expectCharacterStyleMarkAttrs, expectParagraphAttrs, expectRunFormattingOverrideMarkAttrs } from "../../attrs/index.js";
3
3
  import { clearIndentOnBackspace } from "../../commands/clearParagraphIndent.js";
4
4
  import { keepSectionBreaksOnSurvivingMarks } from "../../commands/sectionBreak.js";
5
5
  import { getDocumentStyleResolver } from "../../plugins/documentStyleState.js";
@@ -23,27 +23,55 @@ function chainCommands(...commands) {
23
23
  return false;
24
24
  };
25
25
  }
26
- /**
27
- * Custom Enter handler: splits the block, inherits style-related attrs,
28
- * clears paragraph borders, and preserves run formatting on the new paragraph.
29
- *
30
- * splitBlock creates a new paragraph with default attrs (all null),
31
- * so we must manually copy style-related attrs from the source paragraph.
32
- * Word does NOT propagate paragraph borders (w:pBdr) on Enter.
33
- */
34
26
  const INHERITED_PARA_ATTRS = [
35
- "defaultTextFormatting",
36
- "styleId",
37
- "_tableOfContentsLevel",
38
- "lineSpacing",
39
- "lineSpacingRule",
40
- "snapToGrid",
41
- "spaceAfter",
42
- "spaceBefore",
43
- "spacingExplicit",
44
- "spacingFromDocDefaults",
45
- "spacingFromImplicitDefaultStyle",
46
- "contextualSpacing"
27
+ {
28
+ attr: "defaultTextFormatting",
29
+ formattingFields: ["runProperties"]
30
+ },
31
+ {
32
+ attr: "styleId",
33
+ formattingFields: ["styleId"]
34
+ },
35
+ {
36
+ attr: "_tableOfContentsLevel",
37
+ formattingFields: []
38
+ },
39
+ {
40
+ attr: "lineSpacing",
41
+ formattingFields: ["lineSpacing", "spacingPreservedAttributes"]
42
+ },
43
+ {
44
+ attr: "lineSpacingRule",
45
+ formattingFields: ["lineSpacingRule", "spacingPreservedAttributes"]
46
+ },
47
+ {
48
+ attr: "snapToGrid",
49
+ formattingFields: ["snapToGrid"]
50
+ },
51
+ {
52
+ attr: "spaceAfter",
53
+ formattingFields: ["spaceAfter", "spacingPreservedAttributes"]
54
+ },
55
+ {
56
+ attr: "spaceBefore",
57
+ formattingFields: ["spaceBefore", "spacingPreservedAttributes"]
58
+ },
59
+ {
60
+ attr: "spacingExplicit",
61
+ formattingFields: ["spacingExplicit"]
62
+ },
63
+ {
64
+ attr: "spacingFromDocDefaults",
65
+ formattingFields: []
66
+ },
67
+ {
68
+ attr: "spacingFromImplicitDefaultStyle",
69
+ formattingFields: []
70
+ },
71
+ {
72
+ attr: "contextualSpacing",
73
+ formattingFields: ["contextualSpacing"]
74
+ }
47
75
  ];
48
76
  /** Style formatting needed when the caret has no marks of its own. */
49
77
  const STYLE_MARK_NAMES = /* @__PURE__ */ new Set([
@@ -142,10 +170,31 @@ const splitBlockClearBorders = (state, dispatch, view) => {
142
170
  }
143
171
  const newAttrs = { ...newPara.attrs };
144
172
  let attrsChanged = false;
145
- if (sourcePara) for (const key of INHERITED_PARA_ATTRS) {
146
- const srcVal = sourcePara.attrs[key];
147
- if (srcVal !== null && newAttrs[key] === null) {
148
- newAttrs[key] = srcVal;
173
+ if (sourcePara) {
174
+ const sourceAttrs = expectParagraphAttrs(sourcePara);
175
+ const addedAttrs = expectParagraphAttrs(newPara);
176
+ const originalFormatting = { ...addedAttrs._originalFormatting };
177
+ const resolvedFormatting = { ...addedAttrs._resolvedFormatting };
178
+ for (const { attr, formattingFields } of INHERITED_PARA_ATTRS) {
179
+ const srcVal = sourceAttrs[attr];
180
+ if (srcVal !== null && newAttrs[attr] === null) {
181
+ newAttrs[attr] = srcVal;
182
+ attrsChanged = true;
183
+ }
184
+ if (newAttrs[attr] !== srcVal) continue;
185
+ for (const field of formattingFields) {
186
+ const original = sourceAttrs._originalFormatting?.[field];
187
+ if (original !== void 0) Reflect.set(originalFormatting, field, original);
188
+ const resolved = sourceAttrs._resolvedFormatting?.[field];
189
+ if (resolved !== void 0) Reflect.set(resolvedFormatting, field, resolved);
190
+ }
191
+ }
192
+ if (Object.keys(originalFormatting).length > 0) {
193
+ newAttrs["_originalFormatting"] = originalFormatting;
194
+ attrsChanged = true;
195
+ }
196
+ if (Object.keys(resolvedFormatting).length > 0) {
197
+ newAttrs["_resolvedFormatting"] = resolvedFormatting;
149
198
  attrsChanged = true;
150
199
  }
151
200
  }