@stll/folio-core 0.58.5 → 0.60.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 (208) hide show
  1. package/README.md +10 -1
  2. package/dist/ai-edits/apply.d.ts +11 -12
  3. package/dist/ai-edits/apply.js +179 -168
  4. package/dist/ai-edits/headless.d.ts +15 -13
  5. package/dist/ai-edits/headless.js +40 -13
  6. package/dist/ai-edits/index.d.ts +3 -3
  7. package/dist/ai-edits/newListNumbering.d.ts +3 -9
  8. package/dist/ai-edits/newListNumbering.js +36 -41
  9. package/dist/ai-edits/referenceClassification.d.ts +22 -0
  10. package/dist/ai-edits/referenceClassification.js +21 -0
  11. package/dist/ai-edits/snapshot.js +39 -40
  12. package/dist/ai-edits/types.d.ts +24 -32
  13. package/dist/compare/column-alignment.d.ts +4 -4
  14. package/dist/compare/compare.d.ts +3 -7
  15. package/dist/compare/compare.js +25 -27
  16. package/dist/compare/content-alignment.d.ts +9 -9
  17. package/dist/compare/content-types.d.ts +23 -10
  18. package/dist/compare/content-types.js +14 -0
  19. package/dist/compare/content.d.ts +16 -17
  20. package/dist/compare/content.js +30 -7
  21. package/dist/compare/formatting.d.ts +3 -3
  22. package/dist/compare/import-style-closure.d.ts +22 -0
  23. package/dist/compare/import-style-closure.js +33 -0
  24. package/dist/compare/inserted-resource-snapshot.d.ts +15 -0
  25. package/dist/compare/inserted-resource-snapshot.js +63 -0
  26. package/dist/compare/plan.js +20 -13
  27. package/dist/compare/scenario.js +12 -2
  28. package/dist/compare/style-resources.d.ts +8 -2
  29. package/dist/compare/style-resources.js +63 -14
  30. package/dist/compare/verification.d.ts +15 -3
  31. package/dist/compare/verification.js +47 -8
  32. package/dist/compat/eigenpal.d.ts +5 -5
  33. package/dist/compat/eigenpal.js +2 -2
  34. package/dist/controller/canonicalListRendering.js +13 -22
  35. package/dist/controller/canonicalPublicOperations.js +1 -1
  36. package/dist/controller/canonicalSession.js +3 -2
  37. package/dist/controller/canonicalStructure.js +55 -28
  38. package/dist/controller/fontReadiness.js +1 -1
  39. package/dist/controller/layoutPipeline.js +7 -1
  40. package/dist/controller/layoutSession.d.ts +2 -0
  41. package/dist/display-list/build/fontTable.js +7 -5
  42. package/dist/display-list/build/furniture.d.ts +1 -0
  43. package/dist/display-list/build/furniture.js +1 -0
  44. package/dist/display-list/build/watermarkPrimitives.d.ts +2 -1
  45. package/dist/display-list/build/watermarkPrimitives.js +9 -3
  46. package/dist/display-list/editor/pageRenderer.js +1 -0
  47. package/dist/document-operations.d.ts +4 -9
  48. package/dist/document-operations.js +45 -41
  49. package/dist/docx/attributeRemainder.d.ts +1 -1
  50. package/dist/docx/bookmarkIdNormalization.d.ts +10 -0
  51. package/dist/docx/bookmarkIdNormalization.js +100 -0
  52. package/dist/docx/bookmarkParser.js +4 -2
  53. package/dist/docx/importedIdCollisions.d.ts +136 -0
  54. package/dist/docx/importedIdCollisions.js +215 -0
  55. package/dist/docx/index.d.ts +1 -1
  56. package/dist/docx/listMarkerComputation.js +9 -14
  57. package/dist/docx/listTemplate.d.ts +22 -0
  58. package/dist/docx/listTemplate.js +40 -0
  59. package/dist/docx/numberingParser.js +4 -4
  60. package/dist/docx/numberingReferenceNormalization.js +3 -3
  61. package/dist/docx/paragraphParser.js +3 -4
  62. package/dist/docx/paragraphPropertySource.js +1 -2
  63. package/dist/docx/parseContext.d.ts +2 -1
  64. package/dist/docx/parseContext.js +1 -0
  65. package/dist/docx/parseWarningMessage.js +1 -0
  66. package/dist/docx/parser.js +5 -1
  67. package/dist/docx/relsParser.js +1 -1
  68. package/dist/docx/rezip.js +4 -3
  69. package/dist/docx/selectedXmlIdentityScan.d.ts +10 -0
  70. package/dist/docx/selectedXmlIdentityScan.js +36 -0
  71. package/dist/docx/selectiveSave.js +5 -4
  72. package/dist/docx/selectiveXmlPatch.js +44 -52
  73. package/dist/docx/serializer/commentSerializer.d.ts +3 -1
  74. package/dist/docx/serializer/commentSerializer.js +11 -2
  75. package/dist/docx/serializer/runSerializer.js +2 -2
  76. package/dist/docx/serializer/trackedChangeAttributes.d.ts +1 -3
  77. package/dist/docx/serializer/trackedChangeAttributes.js +1 -11
  78. package/dist/docx/server/materializeYjsDocx.js +2 -2
  79. package/dist/docx/server/migrateYjsAttrSchema.js +5 -5
  80. package/dist/fonts/embeddedFontFingerprint.d.ts +5 -0
  81. package/dist/fonts/embeddedFontFingerprint.js +18 -0
  82. package/dist/fonts/embeddedFonts.d.ts +1 -1
  83. package/dist/fonts/embeddedFonts.js +1 -1
  84. package/dist/fonts/headlessMeasure.js +0 -0
  85. package/dist/generated/text_shaper.js +8 -4
  86. package/dist/generated/text_shaper_bg.wasm +0 -0
  87. package/dist/headless-layout.js +1 -0
  88. package/dist/index.d.ts +5 -5
  89. package/dist/index.js +2 -2
  90. package/dist/internal/paragraphFormattingSerialization.d.ts +1 -8
  91. package/dist/internal/paragraphFormattingSerialization.js +6 -20
  92. package/dist/layout-bridge/convert/flowConversionShared.d.ts +3 -1
  93. package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -1
  94. package/dist/layout-bridge/convert/footnoteLayout.js +3 -0
  95. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
  96. package/dist/layout-bridge/convert/headerFooterLayout.js +2 -0
  97. package/dist/layout-bridge/convert/listMarkers.d.ts +1 -2
  98. package/dist/layout-bridge/convert/listMarkers.js +3 -11
  99. package/dist/layout-bridge/convert/paragraphAttrs.d.ts +1 -1
  100. package/dist/layout-bridge/convert/paragraphAttrs.js +8 -4
  101. package/dist/layout-bridge/convert/paragraphConversion.js +8 -1
  102. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +2 -1
  103. package/dist/layout-bridge/convert/toFlowBlocks.js +27 -2
  104. package/dist/layout-engine/measure/cache.js +39 -7
  105. package/dist/layout-engine/measure/lineTypography.js +1 -0
  106. package/dist/layout-engine/measure/listMarkerWidth.d.ts +1 -0
  107. package/dist/layout-engine/measure/listMarkerWidth.js +1 -0
  108. package/dist/layout-engine/measure/measureContainer.js +3 -4
  109. package/dist/layout-engine/measure/measureHelpers.d.ts +6 -9
  110. package/dist/layout-engine/measure/measureHelpers.js +21 -18
  111. package/dist/layout-engine/measure/measureParagraph.js +2 -0
  112. package/dist/layout-engine/measure/measureTypes.d.ts +2 -0
  113. package/dist/layout-engine/types.d.ts +4 -1
  114. package/dist/layout-painter/renderPage.d.ts +1 -0
  115. package/dist/layout-painter/renderPage.js +11 -3
  116. package/dist/layout-painter/renderParagraph.js +13 -3
  117. package/dist/layout-painter/renderWatermark.d.ts +1 -0
  118. package/dist/layout-painter/renderWatermark.js +7 -3
  119. package/dist/managers/editorShortcuts.d.ts +2 -1
  120. package/dist/managers/editorShortcuts.js +2 -1
  121. package/dist/markdown/renderParagraph.js +29 -3
  122. package/dist/prosemirror/canonicalSelectionRange.d.ts +4 -1
  123. package/dist/prosemirror/canonicalSelectionRange.js +9 -3
  124. package/dist/prosemirror/commands/comments.js +5 -32
  125. package/dist/prosemirror/commands/paragraphBookmarkJoin.d.ts +7 -1
  126. package/dist/prosemirror/commands/paragraphBookmarkJoin.js +35 -1
  127. package/dist/prosemirror/commands/propertyChangeScope.js +6 -0
  128. package/dist/prosemirror/commands/resolveParagraphProperties.js +10 -5
  129. package/dist/prosemirror/conversion/fromProseDoc.js +23 -9
  130. package/dist/prosemirror/conversion/toProseDoc.js +31 -7
  131. package/dist/prosemirror/extensions/core/ParagraphExtension.js +29 -14
  132. package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.d.ts +8 -2
  133. package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.js +39 -3
  134. package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.d.ts +8 -2
  135. package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.js +4 -3
  136. package/dist/prosemirror/extensions/features/ImageDragExtension.js +4 -3
  137. package/dist/prosemirror/extensions/features/JoinedRunStyleExtension.js +4 -3
  138. package/dist/prosemirror/extensions/features/ListExtension.js +51 -21
  139. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +9 -3
  140. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +6 -5
  141. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +8 -2
  142. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +11 -3
  143. package/dist/prosemirror/extensions/marks/RunIdentityExtension.js +4 -3
  144. package/dist/prosemirror/extensions/marks/markUtils.js +1 -1
  145. package/dist/prosemirror/listInstanceReferences.js +21 -15
  146. package/dist/prosemirror/listLabels.d.ts +4 -3
  147. package/dist/prosemirror/listLabels.js +18 -51
  148. package/dist/prosemirror/listMarker.d.ts +2 -19
  149. package/dist/prosemirror/listMarker.js +28 -57
  150. package/dist/prosemirror/listNumbering.js +16 -6
  151. package/dist/prosemirror/listRendering.d.ts +4 -3
  152. package/dist/prosemirror/listRendering.js +22 -3
  153. package/dist/prosemirror/listRenderingAttrs.d.ts +2 -1
  154. package/dist/prosemirror/listRenderingAttrs.js +6 -11
  155. package/dist/prosemirror/numberedRefFields.js +9 -5
  156. package/dist/prosemirror/numberingAttr.d.ts +19 -1
  157. package/dist/prosemirror/numberingAttr.js +16 -2
  158. package/dist/prosemirror/paragraphIndentation.js +5 -2
  159. package/dist/prosemirror/paragraphMarkJoin.js +17 -3
  160. package/dist/prosemirror/paragraphPropertyCarry.js +5 -6
  161. package/dist/prosemirror/pluginKeyOwner.d.ts +13 -0
  162. package/dist/prosemirror/pluginKeyOwner.js +35 -0
  163. package/dist/prosemirror/plugins/aiCitationDecorations.d.ts +11 -4
  164. package/dist/prosemirror/plugins/aiCitationDecorations.js +16 -3
  165. package/dist/prosemirror/plugins/aiSuggestionDecorations.d.ts +11 -4
  166. package/dist/prosemirror/plugins/aiSuggestionDecorations.js +18 -3
  167. package/dist/prosemirror/plugins/anonymizationDecorations.d.ts +11 -11
  168. package/dist/prosemirror/plugins/anonymizationDecorations.js +23 -13
  169. package/dist/prosemirror/plugins/autocompleteSuggestion.d.ts +8 -2
  170. package/dist/prosemirror/plugins/autocompleteSuggestion.js +27 -5
  171. package/dist/prosemirror/plugins/contentControlWidgets.d.ts +8 -2
  172. package/dist/prosemirror/plugins/contentControlWidgets.js +4 -3
  173. package/dist/prosemirror/plugins/createDocScanPlugin.d.ts +6 -5
  174. package/dist/prosemirror/plugins/createDocScanPlugin.js +1 -1
  175. package/dist/prosemirror/plugins/documentNumbering.js +5 -3
  176. package/dist/prosemirror/plugins/documentStyleState.d.ts +8 -2
  177. package/dist/prosemirror/plugins/documentStyleState.js +2 -2
  178. package/dist/prosemirror/plugins/documentStyles.js +1 -1
  179. package/dist/prosemirror/plugins/selectionTracker.d.ts +8 -2
  180. package/dist/prosemirror/plugins/selectionTracker.js +4 -3
  181. package/dist/prosemirror/plugins/suggestionMode.d.ts +8 -2
  182. package/dist/prosemirror/plugins/suggestionMode.js +4 -3
  183. package/dist/prosemirror/plugins/templateDirectives.d.ts +8 -2
  184. package/dist/prosemirror/plugins/templateDirectives.js +19 -4
  185. package/dist/prosemirror/plugins/templatePreviewValues.d.ts +8 -2
  186. package/dist/prosemirror/plugins/templatePreviewValues.js +27 -5
  187. package/dist/prosemirror/plugins/templateSlashMenu.d.ts +8 -2
  188. package/dist/prosemirror/plugins/templateSlashMenu.js +23 -5
  189. package/dist/prosemirror/plugins/transactionInvariants.js +29 -5
  190. package/dist/prosemirror/schema/nodes.d.ts +2 -1
  191. package/dist/prosemirror/selectionState.js +5 -1
  192. package/dist/prosemirror/storyListNumbering.js +11 -12
  193. package/dist/prosemirror/styles/paragraphStyleCascade.js +2 -6
  194. package/dist/prosemirror/styles/resolvedStyleAttrs.d.ts +11 -4
  195. package/dist/prosemirror/styles/resolvedStyleAttrs.js +28 -18
  196. package/dist/prosemirror/yjsDocumentMetadata.d.ts +9 -3
  197. package/dist/prosemirror/yjsDocumentMetadata.js +42 -10
  198. package/dist/redline.d.ts +17 -1
  199. package/dist/redline.js +118 -57
  200. package/dist/server.d.ts +3 -3
  201. package/dist/server.js +2 -2
  202. package/dist/utils/fontLoader.d.ts +2 -2
  203. package/dist/utils/fontLoader.js +2 -7
  204. package/dist/utils/fontResolver.d.ts +7 -3
  205. package/dist/utils/fontResolver.js +6 -8
  206. package/dist/version-comparison.d.ts +1 -2
  207. package/dist/version-comparison.js +1 -2
  208. package/package.json +26 -9
@@ -1,5 +1,5 @@
1
1
  import { sameStatedParagraphNumbering as sameStatedParagraphNumbering$1 } from "../../docx/numberingReference.js";
2
- import { getProseParagraphPropertySourceToken, markParagraphPropertySourceTransfers } from "../../docx/paragraphPropertySource.js";
2
+ import { markParagraphPropertySourceTransfers } from "../../docx/paragraphPropertySource.js";
3
3
  import { RevisionResolutionStep } from "../../internal/revisionResolutionStep.js";
4
4
  import { finalRevisionParagraphRanges } from "../../internal/revisionResolutionTracking.js";
5
5
  import { deleteTextBoxesAnchoredAt, droppedTextBoxAnchorIds, moveTextBoxesPastNextParagraph } from "../anchoredTextBoxes.js";
@@ -16,19 +16,18 @@ import { joinAtParagraphMark } from "../paragraphMarkJoin.js";
16
16
  import { getDocumentNumbering } from "../plugins/documentNumbering.js";
17
17
  import { getDocumentStyleResolver } from "../plugins/documentStyleState.js";
18
18
  import { resolvedPreservedXmlAttrs } from "../preservedXmlReview.js";
19
- import { rebaseParagraphRuns, setParagraphAttrsWithRebasedRunFormatting } from "../rebaseParagraphRunFormatting.js";
19
+ import { setParagraphAttrsWithRebasedRunFormatting } from "../rebaseParagraphRunFormatting.js";
20
20
  import { rejoinRunsAt } from "../rejoinRunCarriers.js";
21
21
  import { getFolioNodeRevisionCarriers, nodePropertyRevisionSites } from "../revisionCarriers.js";
22
22
  import { RUN_FORMATTING_MARK_NAMES } from "../runFormattingMarkNames.js";
23
23
  import { reconstructRejectedRunFormattingMarks, restoreHistoricalRunFormatting } from "../runPropertyChangeResolution.js";
24
- import { paragraphRunStyleContext, paragraphRunStyleContextAt } from "../runStyleFormatting.js";
24
+ import { paragraphRunStyleContextAt } from "../runStyleFormatting.js";
25
25
  import { getTableCellMergeChange } from "../tableCellMergeRevision.js";
26
26
  import { isTableCellRetainedInReviewView } from "../tableCellRevisionVisibility.js";
27
27
  import { markRowEmptiedInBatch, reconcileTableGridAfterColumnRemoval, removeRowsWithoutCellsAfterBatch, removeTableRow } from "../tableGridMutation.js";
28
28
  import { runInCellPending, runParagraphIntoTable } from "../tableRunIn.js";
29
29
  import { retainedTrackedRevisionMark, trackedRevisionPathOf } from "../trackedRevisionPath.js";
30
30
  import { holdsNoContent } from "../zeroWidthAnchors.js";
31
- import { inlineBookmarksForParagraphJoin } from "./paragraphBookmarkJoin.js";
32
31
  import { hasSerializableParagraphPropertyChange, paragraphPropertiesSnapshot } from "./propertyChangeScope.js";
33
32
  import { resolveNodePropertyChangeAttrs } from "./resolveNodePropertyChangeAttrs.js";
34
33
  import { resolveParagraphChangeAttrs } from "./resolveParagraphProperties.js";
@@ -338,8 +337,7 @@ function resolveChange(from, to, mode, revisionIds) {
338
337
  continue;
339
338
  }
340
339
  if (moveTextBoxesPastNextParagraph(tr, mappedPos)) markStructuralChange(tr);
341
- const joinPos = mappedPos + paragraph.nodeSize;
342
- let nextPos = joinPos;
340
+ let nextPos = mappedPos + paragraph.nodeSize;
343
341
  const boundaries = [];
344
342
  while (nextPos < tr.doc.content.size) {
345
343
  const boundary = tr.doc.nodeAt(nextPos);
@@ -375,32 +373,7 @@ function resolveChange(from, to, mode, revisionIds) {
375
373
  continue;
376
374
  }
377
375
  try {
378
- if (boundaries.length > 0) {
379
- const leftToken = getProseParagraphPropertySourceToken(paragraph);
380
- const rightToken = getProseParagraphPropertySourceToken(nextNode);
381
- const inlineBookmarks = inlineBookmarksForParagraphJoin({
382
- first: paragraph,
383
- boundaries,
384
- second: nextNode
385
- });
386
- if (!inlineBookmarks) continue;
387
- tr.replaceWith(joinPos - 1, nextPos + 1, inlineBookmarks);
388
- tr.setNodeMarkup(mappedPos, void 0, nextNode.attrs);
389
- markParagraphPropertySourceTransfers(tr, [{
390
- displacedToken: typeof leftToken === "string" ? leftToken : null,
391
- selectedToken: typeof rightToken === "string" ? rightToken : null
392
- }]);
393
- if (styleResolver && paragraph.content.size > 0) rebaseParagraphRuns({
394
- previousContext: paragraphRunStyleContext(paragraph, styleResolver),
395
- paragraphPosition: mappedPos,
396
- range: {
397
- from: 0,
398
- to: paragraph.content.size
399
- },
400
- styleResolver,
401
- tr
402
- });
403
- } else joinAtParagraphMark({
376
+ joinAtParagraphMark({
404
377
  tr,
405
378
  paragraphPos: mappedPos,
406
379
  paragraph,
@@ -9,5 +9,11 @@ type InlineBookmarksForParagraphJoinOptions = {
9
9
  declare const inlineBookmarksOf: (boundaries: readonly Node[]) => Node[] | null;
10
10
  /** Inline boundaries that can replace the paragraph break without replacing either paragraph's content. */
11
11
  declare const inlineBookmarksForParagraphJoin: ({ first, boundaries, second }: InlineBookmarksForParagraphJoinOptions) => Node[] | null;
12
+ /** Paragraph siblings separated only by typed bookmark boundaries. */
13
+ declare const paragraphJoinAfter: (doc: Node, position: number) => {
14
+ next: Node;
15
+ nextPosition: number;
16
+ inlineBookmarks: Node[];
17
+ } | null;
12
18
  //#endregion
13
- export { inlineBookmarksForParagraphJoin, inlineBookmarksOf };
19
+ export { inlineBookmarksForParagraphJoin, inlineBookmarksOf, paragraphJoinAfter };
@@ -1,4 +1,5 @@
1
1
  import { Fragment } from "prosemirror-model";
2
+ import { canJoin } from "prosemirror-transform";
2
3
  //#region src/prosemirror/commands/paragraphBookmarkJoin.ts
3
4
  /** The inline form of boundaries whose enclosing paragraph break was removed. */
4
5
  const inlineBookmarksOf = (boundaries) => {
@@ -18,5 +19,38 @@ const inlineBookmarksForParagraphJoin = ({ first, boundaries, second }) => {
18
19
  ]);
19
20
  return first.type.validContent(content) ? inline : null;
20
21
  };
22
+ /** Paragraph siblings separated only by typed bookmark boundaries. */
23
+ const paragraphJoinAfter = (doc, position) => {
24
+ const at = doc.resolve(position);
25
+ const first = at.nodeBefore;
26
+ if (first?.type.name !== "paragraph") return null;
27
+ const boundaries = [];
28
+ let nextPosition = position;
29
+ let index = at.index();
30
+ while (index < at.parent.childCount) {
31
+ const boundary = at.parent.child(index);
32
+ if (boundary.type.name !== "blockBookmarkBoundary") break;
33
+ boundaries.push(boundary);
34
+ nextPosition += boundary.nodeSize;
35
+ index++;
36
+ }
37
+ const next = index < at.parent.childCount ? at.parent.child(index) : null;
38
+ if (!next || next.type !== first.type) return null;
39
+ if (boundaries.length === 0) return canJoin(doc, position) ? {
40
+ next,
41
+ nextPosition,
42
+ inlineBookmarks: []
43
+ } : null;
44
+ const inlineBookmarks = inlineBookmarksForParagraphJoin({
45
+ first,
46
+ boundaries,
47
+ second: next
48
+ });
49
+ return inlineBookmarks ? {
50
+ next,
51
+ nextPosition,
52
+ inlineBookmarks
53
+ } : null;
54
+ };
21
55
  //#endregion
22
- export { inlineBookmarksForParagraphJoin, inlineBookmarksOf };
56
+ export { inlineBookmarksForParagraphJoin, inlineBookmarksOf, paragraphJoinAfter };
@@ -1,5 +1,6 @@
1
1
  import { isStyleSourcedParagraphNumbering } from "../../internal/paragraphFormattingSerialization.js";
2
2
  import { expectParagraphAttrs } from "../attrs/index.js";
3
+ import { LIST_RENDERING_ATTR_KEYS, hasListRendering } from "../listRenderingAttrs.js";
3
4
  import { readParagraphNumberingAttr } from "../numberingAttr.js";
4
5
  import { directParagraphAlignment } from "../paragraphAlignment.js";
5
6
  import { directionFromBidi } from "../paragraphDirection.js";
@@ -135,6 +136,11 @@ const paragraphPropertiesSnapshot = (node) => {
135
136
  }
136
137
  const directAlignment = directParagraphAlignment(attrs);
137
138
  if (directAlignment !== void 0) snapshot["alignment"] = directAlignment;
139
+ snapshot["numPrFromStyle"] = attrs.numPrFromStyle ?? null;
140
+ if (hasListRendering(attrs)) for (const key of LIST_RENDERING_ATTR_KEYS) {
141
+ const value = attrs[key];
142
+ if (value != null) snapshot[key] = value;
143
+ }
138
144
  Object.assign(snapshot, directParagraphSpacing(attrs), directParagraphIndentation(attrs));
139
145
  return snapshot;
140
146
  };
@@ -1,7 +1,7 @@
1
1
  import { resolveParagraphNumbering } from "../../docx/numberingReference.js";
2
2
  import { expectParagraphAttrs } from "../attrs/index.js";
3
3
  import { rejectedListRenderingPatch } from "../listRendering.js";
4
- import { paragraphNumberingAttr } from "../numberingAttr.js";
4
+ import { effectiveParagraphNumbering, paragraphNumberingAttr, paragraphNumberingSourcesFromBoundary } from "../numberingAttr.js";
5
5
  import { paragraphIndentationFromFormatting } from "../paragraphIndentation.js";
6
6
  import { resolveParagraphDefaultTextFormatting } from "../styles/paragraphStyleCascade.js";
7
7
  import { listIndentationProvenancePatch } from "../styles/resolvedStyleAttrs.js";
@@ -38,12 +38,17 @@ const resolveParagraphChangeAttrs = ({ node, boundaryCovered, mode, revisionSet,
38
38
  if (!styleResolver && sameStyle) styleNumbering = currentAttrs.numPrFromStyle ?? void 0;
39
39
  const inheritedNumbering = styleNumbering == null ? null : paragraphNumberingAttr(resolveParagraphNumbering(styleNumbering));
40
40
  const recordedNumbering = rejection.previousFormatting?.numPr;
41
- const restoredNumbering = recordedNumbering ?? inheritedNumbering;
41
+ const restoredNumPrFromStyle = recordedNumbering?.kind === "reference" || recordedNumbering?.kind === "none" ? null : inheritedNumbering;
42
+ const effectiveNumbering = effectiveParagraphNumbering(paragraphNumberingSourcesFromBoundary({
43
+ numPr: recordedNumbering,
44
+ numPrFromStyle: restoredNumPrFromStyle
45
+ }));
46
+ const restoredNumbering = effectiveNumbering === void 0 ? null : paragraphNumberingAttr(effectiveNumbering);
42
47
  const restoredFormatting = paragraphRejectOriginalFormatting(rejection.previousFormatting, node.attrs["_originalFormatting"]);
43
48
  const indentation = listIndentationProvenancePatch({
44
49
  direct: paragraphIndentationFromFormatting(restoredFormatting ?? void 0),
45
50
  styleFormatting: previousFormattingFromStyle,
46
- numberingSource: recordedNumbering == null ? "style" : "paragraph",
51
+ numberingSource: recordedNumbering?.kind === "reference" ? "paragraph" : "style",
47
52
  numPr: restoredNumbering?.kind === "reference" ? {
48
53
  numId: restoredNumbering.numId,
49
54
  ilvl: restoredNumbering.ilvl ?? 0
@@ -60,8 +65,8 @@ const resolveParagraphChangeAttrs = ({ node, boundaryCovered, mode, revisionSet,
60
65
  numbering,
61
66
  restoredNumbering
62
67
  }), {
63
- numPr: restoredNumbering,
64
- numPrFromStyle: recordedNumbering == null ? inheritedNumbering : null
68
+ numPr: recordedNumbering ?? null,
69
+ numPrFromStyle: restoredNumPrFromStyle
65
70
  });
66
71
  Object.assign(nextAttrs, indentation);
67
72
  nextAttrs["_originalFormatting"] = restoredFormatting;
@@ -4,7 +4,7 @@ import { normalizeFoldedListNumbers } from "../../docx/foldedListNumberFields.js
4
4
  import { getDocumentSourceStyles } from "../../docx/headerFooterVerbatim.js";
5
5
  import { EDITED_PREVIEW_FINGERPRINT, imageRawXmlFingerprint } from "../../docx/imageRawXml.js";
6
6
  import { isInlineSdtContent, isSimpleFieldContent } from "../../docx/inlineWrapperContent.js";
7
- import { paragraphNumberingReferenceId as paragraphNumberingReferenceId$1, sameStatedParagraphNumbering as sameStatedParagraphNumbering$1 } from "../../docx/numberingReference.js";
7
+ import { paragraphNumberingReferenceId, sameStatedParagraphNumbering as sameStatedParagraphNumbering$1 } from "../../docx/numberingReference.js";
8
8
  import { PROSE_PARAGRAPH_SOURCE_CONTRACT_ATTR, ParagraphPropertySourceValidationError, assignParagraphIndentationProjection, copyDocumentParagraphPropertySourceContract, copyDocumentParagraphPropertySources, copyParagraphPropertyCapture, copyParagraphPropertySource, decodeTableCellParagraphSourcePayload, getDocumentParagraphPropertySourceContract, getParagraphPropertySource, getParagraphPropertySourceCandidate, getParagraphPropertySourceToken, getParagraphPropertySourceTransferId, getProseDocumentParagraphPropertySourceContract, getProseParagraphPropertySourceToken, inspectParagraphSourceIdentity, isParagraphPropertySourceToken, linkParagraphPropertySourceCandidate, paragraphFormattingWithAuthoredIndentation, paragraphPropertySourceTokenMatchesContract, recreateProseNodeWithParagraphPropertySource, restoreTableCellsWithParagraphPropertySources, visitDocumentStoryParagraphs, visitTableCellParagraphPropertySourceBindings } from "../../docx/paragraphPropertySource.js";
9
9
  import { BLOCK_TREE_DESCENT, visitBlockTreeRecords, visitDocxParagraphs } from "../../docx/paragraphTraversal.js";
10
10
  import { refingerprintShapeAlternateContent } from "../../docx/shapeAlternateContent.js";
@@ -32,10 +32,11 @@ import "../extensions/nodes/MoveRangeBoundaryExtension.js";
32
32
  import "../extensions/nodes/RangeAnchorExtension.js";
33
33
  import { inlineWrapperMember, inlineWrapperStackKey } from "../inlineWrapperStack.js";
34
34
  import { completeNumberingForDoc } from "../listInstanceReferences.js";
35
- import { hasListRendering, listRenderingFromAttrs as listRenderingFromAttrs$1 } from "../listRenderingAttrs.js";
35
+ import { LIST_RENDERING_ATTR_KEYS, hasListRendering, listRenderingFromAttrs as listRenderingFromAttrs$1 } from "../listRenderingAttrs.js";
36
36
  import { expectMoveRangeBoundaryAttrs } from "../moveRangeBoundaryAttrs.js";
37
37
  import { assertNoteReferenceOccurrences, coalesceNoteReferenceOccurrences } from "../noteReferenceOccurrences.js";
38
38
  import { resolveNumberedRefFields } from "../numberedRefFields.js";
39
+ import { effectiveParagraphNumbering, paragraphNumberingSourcesFromBoundary } from "../numberingAttr.js";
39
40
  import { directParagraphAlignment } from "../paragraphAlignment.js";
40
41
  import { directionToAuthoredBidi } from "../paragraphDirection.js";
41
42
  import { paragraphIndentationFromFormatting } from "../paragraphIndentation.js";
@@ -172,11 +173,11 @@ const restoreParagraphPropertySource = (paragraph, baseParagraph) => {
172
173
  }
173
174
  }
174
175
  const { numPr, numPrFromStyle } = baseFormatting;
175
- if (!numPr || !numPrFromStyle || !isStyleSourcedParagraphNumbering(numPr, numPrFromStyle)) return;
176
+ if (numPrFromStyle == null || numPr != null && numPr.kind !== "levelOnly") return;
176
177
  if (canonicalJson(modelParagraphFormattingEmission(paragraph.formatting)) !== canonicalJson(modelParagraphFormattingEmission(baseFormatting))) return;
177
178
  paragraph.formatting = {
178
179
  ...paragraph.formatting,
179
- numPr,
180
+ ...numPr === void 0 ? {} : { numPr },
180
181
  numPrFromStyle
181
182
  };
182
183
  };
@@ -1024,7 +1025,10 @@ function removeTextBoxAnchorFromBlocks(blocks, marker) {
1024
1025
  * list markers on the way out of the editor.
1025
1026
  */
1026
1027
  function listRenderingFromAttrs(attrs) {
1027
- const numId = paragraphNumberingReferenceId$1(attrs.numPr);
1028
+ const numId = paragraphNumberingReferenceId(effectiveParagraphNumbering(paragraphNumberingSourcesFromBoundary({
1029
+ numPr: attrs.numPr,
1030
+ numPrFromStyle: attrs.numPrFromStyle
1031
+ })));
1028
1032
  if (numId === void 0) return;
1029
1033
  if (!hasListRendering(attrs)) return;
1030
1034
  return listRenderingFromAttrs$1({
@@ -1101,7 +1105,10 @@ function convertPMParagraph(node, documentCounts, textBoxAnchorMarkers, styleRes
1101
1105
  if (attrs.reviewCarrier) paragraph.reviewCarrier = attrs.reviewCarrier;
1102
1106
  const pFormatting = paragraphAttrsToFormatting(attrs);
1103
1107
  if (pFormatting) paragraph.formatting = pFormatting;
1104
- if (attrs.numPr?.kind === "reference") {
1108
+ if (effectiveParagraphNumbering(paragraphNumberingSourcesFromBoundary({
1109
+ numPr: attrs.numPr,
1110
+ numPrFromStyle: attrs.numPrFromStyle
1111
+ }))?.kind === "reference") {
1105
1112
  const inheritedIndentation = paragraphIndentationFromFormatting(attrs._resolvedFormatting);
1106
1113
  if (inheritedIndentation) assignParagraphIndentationProjection({
1107
1114
  paragraph,
@@ -1133,14 +1140,18 @@ const propertyChangeFromAttrs = (change) => {
1133
1140
  ...normalizedChangeInfo,
1134
1141
  currentFormatting
1135
1142
  };
1136
- const { numPr, ...previousWithoutNumPr } = previousFormatting;
1143
+ const { numPr, numPrFromStyle, ...previousWithoutNumPr } = previousFormatting;
1137
1144
  const normalizedPrevious = numPr == null ? previousWithoutNumPr : {
1138
1145
  ...previousWithoutNumPr,
1139
1146
  numPr
1140
1147
  };
1148
+ for (const key of LIST_RENDERING_ATTR_KEYS) if (normalizedPrevious[key] == null) Reflect.deleteProperty(normalizedPrevious, key);
1141
1149
  return {
1142
1150
  ...normalizedChangeInfo,
1143
- previousFormatting: normalizedPrevious,
1151
+ previousFormatting: {
1152
+ ...normalizedPrevious,
1153
+ ...numPrFromStyle == null ? {} : { numPrFromStyle }
1154
+ },
1144
1155
  ...currentFormatting !== void 0 && { currentFormatting }
1145
1156
  };
1146
1157
  };
@@ -1269,7 +1280,10 @@ function paragraphAttrsToFormatting(attrs) {
1269
1280
  const outlineLevel = authored("outlineLevel", Reflect.get(attrs, "outlineLevel"));
1270
1281
  const bidi = authored("bidi", directionToAuthoredBidi(attrs.direction));
1271
1282
  const snapToGrid = authored("snapToGrid", attrs.snapToGrid);
1272
- const numbered = paragraphNumberingReferenceId$1(attrs.numPr ?? void 0) !== void 0;
1283
+ const numbered = paragraphNumberingReferenceId(effectiveParagraphNumbering(paragraphNumberingSourcesFromBoundary({
1284
+ numPr: attrs.numPr,
1285
+ numPrFromStyle: attrs.numPrFromStyle
1286
+ }))) !== void 0;
1273
1287
  const statedIndent = (value) => value === 0 && !numbered ? void 0 : value;
1274
1288
  const indentLeft = statedIndent(authored("indentLeft", attrs.indentLeft));
1275
1289
  const indentRight = authored("indentRight", attrs.indentRight);
@@ -33,9 +33,10 @@ import "../extensions/nodes/SdtExtension.js";
33
33
  import { fieldRequiresStructuredContent } from "../fieldRepresentation.js";
34
34
  import { inlineWrapperLayer } from "../inlineWrapperStack.js";
35
35
  import { CLEARED_LIST_RENDERING_ATTRS } from "../listMarker.js";
36
+ import { listRenderingFor } from "../listRendering.js";
36
37
  import { listRenderingAttrPatch } from "../listRenderingAttrs.js";
37
38
  import { stampNumberedRefFieldBaselines } from "../numberedRefFields.js";
38
- import { paragraphNumberingAttr } from "../numberingAttr.js";
39
+ import { effectiveParagraphNumbering, paragraphNumberingAttr, paragraphNumberingSourcesFromBoundary } from "../numberingAttr.js";
39
40
  import { pageBreakRunParagraphProjectionDispositionForFeatures } from "../pageBreakRunProjection.js";
40
41
  import { directionFromBidi } from "../paragraphDirection.js";
41
42
  import { paragraphIndentationFromFormatting } from "../paragraphIndentation.js";
@@ -57,7 +58,7 @@ import { createMarkInterner } from "./markInterner.js";
57
58
  import { hasSinkChildren } from "./preservedSinkCarriers.js";
58
59
  import { sdtAttrsFromProperties } from "./sdtAttrs.js";
59
60
  import { panic } from "better-result";
60
- import { DRAWING_RAW_XML_MODES, PARSE_WARNING_CODES, mergeParagraphNumbering } from "@stll/docx-core/model";
61
+ import { DRAWING_RAW_XML_MODES, PARSE_WARNING_CODES } from "@stll/docx-core/model";
61
62
  //#region src/prosemirror/conversion/toProseDoc.ts
62
63
  /**
63
64
  * Document to ProseMirror Conversion
@@ -429,8 +430,11 @@ function convertParagraph(paragraph, styleResolver, context, extraRunFormatting,
429
430
  const { attrs, effectiveFrame } = paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOverlay);
430
431
  if (directFormatting === void 0) Reflect.deleteProperty(attrs, "_originalFormatting");
431
432
  else attrs._originalFormatting = directFormatting;
432
- const numPr = mergeParagraphNumbering(attrs.numPrFromStyle ?? void 0, attrs.numPr ?? void 0);
433
- if (numPr?.kind === "none" || paragraph.listRendering !== void 0 && context.numbering !== void 0 && numPr === void 0) Object.assign(attrs, CLEARED_LIST_RENDERING_ATTRS);
433
+ const numPr = effectiveParagraphNumbering(paragraphNumberingSourcesFromBoundary({
434
+ numPr: attrs.numPr,
435
+ numPrFromStyle: attrs.numPrFromStyle
436
+ }));
437
+ if (numPr.kind === "none" && (paragraph.formatting?.numPr?.kind === "none" || paragraph.listRendering !== void 0 && context.numbering !== void 0)) Object.assign(attrs, CLEARED_LIST_RENDERING_ATTRS);
434
438
  else if (context.numbering !== void 0 && numPr?.kind === "reference") {
435
439
  Object.assign(attrs, listIndentationProvenancePatch({
436
440
  direct: paragraphIndentationFromFormatting(directFormatting),
@@ -448,6 +452,25 @@ function convertParagraph(paragraph, styleResolver, context, extraRunFormatting,
448
452
  if (!(cached !== void 0 && listRenderingDefinitionsMatch(cached, rendering) && (cached.markerSecondSlotOffsetTwips === void 0 || cached.markerSecondSlotOffsetTwips === nextSlotOffset))) Object.assign(attrs, CLEARED_LIST_RENDERING_ATTRS, listRenderingAttrPatch(rendering));
449
453
  } else Object.assign(attrs, CLEARED_LIST_RENDERING_ATTRS);
450
454
  }
455
+ if (attrs._propertyChanges) attrs._propertyChanges = attrs._propertyChanges.map((change) => {
456
+ const previous = change.previousFormatting;
457
+ if (!previous) return change;
458
+ const inherited = styleResolver?.resolveParagraphStyle(previous.styleId ?? void 0).paragraphFormatting?.numPr;
459
+ const sources = paragraphNumberingSourcesFromBoundary({
460
+ numPr: previous.numPr,
461
+ numPrFromStyle: inherited ?? previous.numPrFromStyle
462
+ });
463
+ const originalNumbering = effectiveParagraphNumbering(sources);
464
+ const originalRendering = originalNumbering.kind === "reference" ? listRenderingFor(originalNumbering, context.numbering ?? null) : {};
465
+ return {
466
+ ...change,
467
+ previousFormatting: {
468
+ ...originalRendering,
469
+ ...previous,
470
+ numPrFromStyle: sources.numPrFromStyle === void 0 ? null : paragraphNumberingAttr(sources.numPrFromStyle)
471
+ }
472
+ };
473
+ });
451
474
  reportParagraphPageBreakProjection({
452
475
  paragraph,
453
476
  attrs,
@@ -813,12 +836,13 @@ function paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOver
813
836
  if (formatting) attrs._originalFormatting = formatting;
814
837
  if (paragraph.propertyChanges && paragraph.propertyChanges.length > 0) attrs._propertyChanges = paragraph.propertyChanges.map(({ previousFormatting, ...change }) => {
815
838
  if (previousFormatting === void 0) return change;
816
- const { numPr, ...rest } = previousFormatting;
839
+ const { numPr, numPrFromStyle, ...rest } = previousFormatting;
817
840
  return {
818
841
  ...change,
819
- previousFormatting: numPr === void 0 ? rest : {
842
+ previousFormatting: {
820
843
  ...rest,
821
- numPr: paragraphNumberingAttr(numPr)
844
+ ...numPr === void 0 ? {} : { numPr: paragraphNumberingAttr(numPr) },
845
+ ...numPrFromStyle === void 0 ? {} : { numPrFromStyle: paragraphNumberingAttr(numPrFromStyle) }
822
846
  }
823
847
  };
824
848
  });
@@ -11,6 +11,7 @@ import { autospacingMatchesBase } from "../../autospacingBase.js";
11
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
+ import { effectiveParagraphNumberingReference, paragraphNumberingSourcesFromBoundary } from "../../numberingAttr.js";
14
15
  import { directParagraphAlignment } from "../../paragraphAlignment.js";
15
16
  import { directionIsRtl } from "../../paragraphDirection.js";
16
17
  import { directParagraphIndentation } from "../../paragraphIndentation.js";
@@ -23,7 +24,7 @@ import { rebaseParagraphRuns } from "../../rebaseParagraphRuns.js";
23
24
  import { mintSectionProperties, parseSectionBreakType, sectionBreakTypeOf } from "../../sectionCarrier.js";
24
25
  import { listAttrsFromResolvedStyle, listIndentationProvenancePatch, paragraphAttrsFromResolvedStyle } from "../../styles/resolvedStyleAttrs.js";
25
26
  import { createNodeExtension } from "../create.js";
26
- import { headingOutlineLevel, paragraphNumberingLevel, paragraphNumberingReferenceId } from "@stll/docx-core/model";
27
+ import { headingOutlineLevel } from "@stll/docx-core/model";
27
28
  import { Fragment } from "prosemirror-model";
28
29
  //#region src/prosemirror/extensions/core/ParagraphExtension.ts
29
30
  /**
@@ -36,7 +37,11 @@ import { Fragment } from "prosemirror-model";
36
37
  function paragraphAttrsToDOMStyle(attrs) {
37
38
  const rawIndentLeft = Reflect.get(attrs, "indentLeft");
38
39
  let indentLeft = typeof rawIndentLeft === "number" ? rawIndentLeft : void 0;
39
- if (paragraphNumberingReferenceId(attrs.numPr) !== void 0 && (rawIndentLeft === null || rawIndentLeft === void 0)) indentLeft = ((paragraphNumberingLevel(attrs.numPr) ?? 0) + 1) * 720;
40
+ const numbering = effectiveParagraphNumberingReference(paragraphNumberingSourcesFromBoundary({
41
+ numPr: attrs.numPr,
42
+ numPrFromStyle: attrs.numPrFromStyle
43
+ }));
44
+ if (numbering !== void 0 && (rawIndentLeft === null || rawIndentLeft === void 0)) indentLeft = (numbering.ilvl + 1) * 720;
40
45
  const style = paragraphToStyle({
41
46
  ...attrs.alignment !== void 0 ? { alignment: attrs.alignment } : {},
42
47
  ...attrs.spaceBefore !== void 0 ? { spaceBefore: attrs.spaceBefore } : {},
@@ -71,11 +76,15 @@ function numFmtToClass(numFmt) {
71
76
  default: return "docx-list-decimal";
72
77
  }
73
78
  }
74
- function getListClass(numPr, listIsBullet, listNumFmt) {
75
- if (paragraphNumberingReferenceId(numPr) === void 0) return "";
76
- const level = paragraphNumberingLevel(numPr) ?? 0;
77
- if (listIsBullet) return `docx-list-bullet docx-list-level-${level}`;
78
- return `docx-list-numbered ${numFmtToClass(listNumFmt)} docx-list-level-${level}`;
79
+ function getListClass(attrs) {
80
+ const numbering = effectiveParagraphNumberingReference(paragraphNumberingSourcesFromBoundary({
81
+ numPr: attrs.numPr,
82
+ numPrFromStyle: attrs.numPrFromStyle
83
+ }));
84
+ if (numbering === void 0) return "";
85
+ const level = numbering.ilvl;
86
+ if (attrs.listIsBullet) return `docx-list-bullet docx-list-level-${level}`;
87
+ return `docx-list-numbered ${numFmtToClass(attrs.listNumFmt)} docx-list-level-${level}`;
79
88
  }
80
89
  /**
81
90
  * Parse a CSS length value to twips.
@@ -342,7 +351,7 @@ const paragraphNodeSpec = {
342
351
  toDOM(node) {
343
352
  const attrs = expectParagraphAttrs(node);
344
353
  const style = paragraphAttrsToDOMStyle(attrs);
345
- const listClass = getListClass(attrs.numPr, attrs.listIsBullet, attrs.listNumFmt);
354
+ const listClass = getListClass(attrs);
346
355
  const domAttrs = {};
347
356
  if (style) domAttrs["style"] = style;
348
357
  if (listClass) domAttrs["class"] = listClass;
@@ -535,7 +544,10 @@ function makeDecreaseIndent(amount = 720) {
535
544
  seen.add(pos);
536
545
  const currentIndent = node.attrs["indentLeft"] || 0;
537
546
  const newIndent = Math.max(0, currentIndent - amount);
538
- const numbered = paragraphNumberingReferenceId(expectParagraphAttrs(node).numPr ?? void 0) !== void 0;
547
+ const numbered = effectiveParagraphNumberingReference(paragraphNumberingSourcesFromBoundary({
548
+ numPr: expectParagraphAttrs(node).numPr,
549
+ numPrFromStyle: expectParagraphAttrs(node).numPrFromStyle
550
+ })) !== void 0;
539
551
  tr = tr.setNodeMarkup(pos, void 0, {
540
552
  ...node.attrs,
541
553
  indentLeft: newIndent > 0 || numbered ? newIndent : null
@@ -581,19 +593,19 @@ function makeApplyStyle() {
581
593
  } else Object.assign(newAttrs, directParagraphAttrs(current));
582
594
  newAttrs["_originalFormatting"] = restyledOriginal ?? null;
583
595
  const listAttrs = listAttrsFromResolvedStyle(resolvedAttrs, resolvedAttrs.numbering);
584
- const directNumId = current.numPrFromStyle == null ? paragraphNumberingReferenceId(current.numPr ?? void 0) : void 0;
596
+ const directNumbering = current.numPrFromStyle == null && current.numPr?.kind === "reference" ? current.numPr : void 0;
585
597
  if (listAttrs) Object.assign(newAttrs, listAttrs);
586
598
  else if (isStyleSourcedParagraphNumbering(current.numPr, current.numPrFromStyle)) Object.assign(newAttrs, CLEARED_LIST_RENDERING_ATTRS, {
587
599
  numPr: null,
588
600
  numPrFromStyle: null
589
601
  });
590
- else if (directNumId !== void 0) Object.assign(newAttrs, listIndentationProvenancePatch({
602
+ else if (directNumbering !== void 0) Object.assign(newAttrs, listIndentationProvenancePatch({
591
603
  direct: restyledIndentation(styleAttrs, restyledOriginal),
592
604
  styleFormatting: resolvedAttrs.paragraphFormatting,
593
605
  numberingSource: "paragraph",
594
606
  numPr: {
595
- numId: directNumId,
596
- ilvl: paragraphNumberingLevel(current.numPr ?? void 0) ?? 0
607
+ numId: directNumbering.numId,
608
+ ilvl: directNumbering.ilvl ?? 0
597
609
  },
598
610
  numbering: resolvedAttrs.numbering ?? getDocumentNumbering(state)
599
611
  }));
@@ -677,7 +689,10 @@ const ParagraphExtension = createNodeExtension({
677
689
  decreaseIndent: (amount) => withCanonicalParagraphFormatting(makeDecreaseIndent(amount), (node) => {
678
690
  const attrs = expectParagraphAttrs(node);
679
691
  const indentLeft = Math.max(0, (attrs.indentLeft ?? 0) - (amount ?? 720));
680
- return { indentLeft: indentLeft > 0 || paragraphNumberingReferenceId(attrs.numPr ?? void 0) !== void 0 ? indentLeft : null };
692
+ return { indentLeft: indentLeft > 0 || effectiveParagraphNumberingReference(paragraphNumberingSourcesFromBoundary({
693
+ numPr: attrs.numPr,
694
+ numPrFromStyle: attrs.numPrFromStyle
695
+ })) !== void 0 ? indentLeft : null };
681
696
  }),
682
697
  setIndentLeft: (twips) => withCanonicalParagraphFormatting(setParagraphAttr("indentLeft", twips > 0 ? twips : null), { indentLeft: twips > 0 ? twips : null }),
683
698
  setIndentRight: (twips) => withCanonicalParagraphFormatting(setParagraphAttr("indentRight", twips > 0 ? twips : null), { indentRight: twips > 0 ? twips : null }),
@@ -1,7 +1,13 @@
1
1
  import { Extension } from "../types.js";
2
- import { EditorState, PluginKey } from "prosemirror-state";
2
+ import { EditorState, Plugin } from "prosemirror-state";
3
3
  //#region src/prosemirror/extensions/features/AutoBidiDetectionExtension.d.ts
4
- declare const autoBidiDetectionKey: PluginKey<any>;
4
+ declare const autoBidiDetectionKey: Readonly<{
5
+ key: string;
6
+ createKey: () => import("prosemirror-state").PluginKey<unknown>;
7
+ owns: (plugin: Plugin<unknown>) => boolean;
8
+ get: (state: EditorState) => Plugin<unknown> | undefined;
9
+ getState: (state: EditorState) => unknown;
10
+ }>;
5
11
  /**
6
12
  * Imperatively apply auto-bidi detection to a freshly built state (initial
7
13
  * load: Markdown import, DOCX import, template). `appendTransaction` does not
@@ -2,11 +2,47 @@ import { setProseParagraphMarkupWithPropertySource } from "../../../docx/paragra
2
2
  import { getTransactionDirtyRange } from "../../../paged-layout/transactionDirtyRange.js";
3
3
  import { detectBaseDirection } from "../../../utils/baseDirection.js";
4
4
  import { directionIsAutoManaged } from "../../paragraphDirection.js";
5
+ import { createPluginKeyOwner } from "../../pluginKeyOwner.js";
5
6
  import { createExtension } from "../create.js";
6
7
  import { ignoreTrackedChanges } from "./ParagraphChangeTrackerExtension.js";
7
- import { Plugin, PluginKey } from "prosemirror-state";
8
+ import { Plugin } from "prosemirror-state";
8
9
  //#region src/prosemirror/extensions/features/AutoBidiDetectionExtension.ts
9
- const autoBidiDetectionKey = new PluginKey("autoBidiDetection");
10
+ /**
11
+ * AutoBidiDetection — sets the paragraph `direction` (to `{ source: "auto" }`)
12
+ * on RTL-led paragraphs that arrived without an explicit direction decision.
13
+ *
14
+ * Why: Folio only ever rendered/exported RTL when a paragraph already carried
15
+ * `w:bidi` (from a Word import) or the user toggled it by hand. Content that
16
+ * never had a flag — AI-generated text, Markdown/HTML/plain-text imports, paste,
17
+ * or just typing Arabic without the shortcut — stayed left-to-right both in the
18
+ * editor and in the exported `.docx`. The ProseMirror doc is the single source
19
+ * of truth for both the layout painter (`toFlowBlocks`) and the serializer
20
+ * (`fromProseDoc`), so writing the attribute here fixes the editor and the Word
21
+ * export from one place.
22
+ *
23
+ * Detection uses the first-strong-character rule (`detectBaseDirection`), the
24
+ * same logic the layout painter uses for base direction.
25
+ *
26
+ * Auto vs. explicit: only "auto-managed" paragraphs are (re-)evaluated — those
27
+ * whose `direction` is undecided (absent) or was set by this detector
28
+ * (`source: "auto"`). A manual user toggle or imported `w:bidi`
29
+ * (`source: "manual"`) is authoritative and never touched. Because the detector
30
+ * re-evaluates its own decisions, replacing an auto-RTL paragraph's text with
31
+ * Latin clears it again (no stale "sticky" RTL).
32
+ *
33
+ * The `direction` discriminated union is editor-runtime state. Its `"auto"`
34
+ * source is a *rendering* aid only — `directionToAuthoredBidi` maps it to
35
+ * `undefined`, so an auto-detected paragraph never serializes `w:bidi` on its
36
+ * own; only a manual decision (an explicit user toggle, or `w:bidi` the
37
+ * source document already carried) is authored content. This keeps a no-edit
38
+ * save byte-identical on direction, while the editor and layout painter still
39
+ * treat `"auto"` as RTL (`directionToBidi` / `directionIsRtl`) so detected
40
+ * text displays correctly before the user ever makes it explicit.
41
+ *
42
+ * Mirrors the appendTransaction + ensure-in-state pattern of
43
+ * `ParaIdAllocatorExtension`.
44
+ */
45
+ const autoBidiDetectionKey = createPluginKeyOwner("autoBidiDetection");
10
46
  const paragraphDirectionalText = (node) => {
11
47
  let text = "";
12
48
  node.descendants((child) => {
@@ -95,7 +131,7 @@ const ensureBaseDirectionInState = (state) => {
95
131
  return state.apply(applyBidiUpdates(state, updates));
96
132
  };
97
133
  const createAutoBidiDetectionPlugin = () => new Plugin({
98
- key: autoBidiDetectionKey,
134
+ key: autoBidiDetectionKey.createKey(),
99
135
  appendTransaction(transactions, _oldState, newState) {
100
136
  if (!transactions.some((t) => t.docChanged)) return null;
101
137
  const [first, ...rest] = transactions;
@@ -1,7 +1,13 @@
1
1
  import { Extension } from "../types.js";
2
- import { PluginKey } from "prosemirror-state";
2
+ import { Plugin } from "prosemirror-state";
3
3
  //#region src/prosemirror/extensions/features/EmptyParagraphFormatExtension.d.ts
4
- declare const emptyParagraphFormatKey: PluginKey<any>;
4
+ declare const emptyParagraphFormatKey: Readonly<{
5
+ key: string;
6
+ createKey: () => import("prosemirror-state").PluginKey<unknown>;
7
+ owns: (plugin: Plugin<unknown>) => boolean;
8
+ get: (state: import("prosemirror-state").EditorState) => Plugin<unknown> | undefined;
9
+ getState: (state: import("prosemirror-state").EditorState) => unknown;
10
+ }>;
5
11
  declare const EmptyParagraphFormatExtension: (options?: Partial<Record<string, unknown>> | undefined) => Extension;
6
12
  //#endregion
7
13
  export { EmptyParagraphFormatExtension, emptyParagraphFormatKey };
@@ -1,6 +1,7 @@
1
+ import { createPluginKeyOwner } from "../../pluginKeyOwner.js";
1
2
  import { createExtension } from "../create.js";
2
3
  import { textFormattingToMarks } from "../marks/markUtils.js";
3
- import { Plugin, PluginKey } from "prosemirror-state";
4
+ import { Plugin } from "prosemirror-state";
4
5
  //#region src/prosemirror/extensions/features/EmptyParagraphFormatExtension.ts
5
6
  /**
6
7
  * EmptyParagraphFormat — re-establishes stored marks for an empty styled
@@ -22,7 +23,7 @@ import { Plugin, PluginKey } from "prosemirror-state";
22
23
  * (bold/italic/color/…). Plain body paragraphs (font + size only) are left
23
24
  * untouched so ordinary typed text stays mark-free and serializes cleanly.
24
25
  */
25
- const emptyParagraphFormatKey = new PluginKey("emptyParagraphFormat");
26
+ const emptyParagraphFormatKey = createPluginKeyOwner("emptyParagraphFormat");
26
27
  /**
27
28
  * Run-formatting properties the painter does NOT reproduce from
28
29
  * `defaultTextFormatting` on its own (it forwards only font family + size).
@@ -37,7 +38,7 @@ function hasNonFontDefaults(dtf) {
37
38
  }
38
39
  function createEmptyParagraphFormatPlugin() {
39
40
  return new Plugin({
40
- key: emptyParagraphFormatKey,
41
+ key: emptyParagraphFormatKey.createKey(),
41
42
  appendTransaction(transactions, _oldState, newState) {
42
43
  if (!transactions.some((t) => t.selectionSet || t.docChanged)) return null;
43
44
  const { selection } = newState;
@@ -1,5 +1,6 @@
1
+ import { createPluginKeyOwner } from "../../pluginKeyOwner.js";
1
2
  import { createExtension } from "../create.js";
2
- import { NodeSelection, Plugin, PluginKey } from "prosemirror-state";
3
+ import { NodeSelection, Plugin } from "prosemirror-state";
3
4
  //#region src/prosemirror/extensions/features/ImageDragExtension.ts
4
5
  /**
5
6
  * Image Drag Extension — handles drag-to-reposition for images
@@ -10,12 +11,12 @@ import { NodeSelection, Plugin, PluginKey } from "prosemirror-state";
10
11
  * - Inline images: reorder within text flow via ProseMirror's default drag
11
12
  * - Custom drag initiation from mousedown on selected images
12
13
  */
13
- const imageDragKey = new PluginKey("imageDrag");
14
+ const imageDragKey = createPluginKeyOwner("imageDrag");
14
15
  const ImageDragExtension = createExtension({
15
16
  name: "imageDrag",
16
17
  onSchemaReady(_ctx) {
17
18
  return { plugins: [new Plugin({
18
- key: imageDragKey,
19
+ key: imageDragKey.createKey(),
19
20
  props: { handleDOMEvents: {
20
21
  dragstart(view, event) {
21
22
  const { selection } = view.state;
@@ -1,5 +1,6 @@
1
+ import { createPluginKeyOwner } from "../../pluginKeyOwner.js";
1
2
  import { createExtension } from "../create.js";
2
- import { Plugin, PluginKey } from "prosemirror-state";
3
+ import { Plugin } from "prosemirror-state";
3
4
  //#region src/prosemirror/extensions/features/JoinedRunStyleExtension.ts
4
5
  /**
5
6
  * Runs that a join moves into another paragraph take that paragraph's style.
@@ -16,7 +17,7 @@ import { Plugin, PluginKey } from "prosemirror-state";
16
17
  * {@link JOINED_RUNS_RESTYLED_META}, and is left as it is.
17
18
  */
18
19
  const JOINED_RUNS_RESTYLED_META = "joinedRunsRestyled";
19
- const pastedTableEndKey = new PluginKey("pastedTableEnd");
20
+ const pastedTableEndKey = createPluginKeyOwner("pastedTableEnd");
20
21
  /**
21
22
  * A table pasted over a story's last paragraph leaves that paragraph, emptied,
22
23
  * after it: a story ends with a paragraph, and the paste replaced the words,
@@ -24,7 +25,7 @@ const pastedTableEndKey = new PluginKey("pastedTableEnd");
24
25
  * paragraph, so the empty one is put back.
25
26
  */
26
27
  const createPastedTableEndPlugin = () => new Plugin({
27
- key: pastedTableEndKey,
28
+ key: pastedTableEndKey.createKey(),
28
29
  appendTransaction(transactions, oldState, newState) {
29
30
  if (!transactions.some((transaction) => transaction.docChanged && transaction.getMeta("uiEvent") === "paste")) return null;
30
31
  if (newState.doc.lastChild?.type.spec["tableRole"] !== "table" || oldState.doc.lastChild?.type.name !== "paragraph") return null;