@stll/folio-core 0.35.1 → 0.37.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 (236) hide show
  1. package/README.md +59 -1
  2. package/dist/ai-edits/apply.js +878 -377
  3. package/dist/ai-edits/block-identity.d.ts +4 -1
  4. package/dist/ai-edits/block-identity.js +4 -1
  5. package/dist/ai-edits/blockRange.js +14 -14
  6. package/dist/ai-edits/clean-text.d.ts +40 -1
  7. package/dist/ai-edits/clean-text.js +52 -2
  8. package/dist/ai-edits/headless.d.ts +3 -1
  9. package/dist/ai-edits/headless.js +141 -73
  10. package/dist/ai-edits/index.d.ts +3 -3
  11. package/dist/ai-edits/index.js +2 -2
  12. package/dist/ai-edits/read.js +38 -20
  13. package/dist/ai-edits/snapshot.d.ts +14 -6
  14. package/dist/ai-edits/snapshot.js +105 -20
  15. package/dist/ai-edits/table-cell-mutations.js +1 -1
  16. package/dist/ai-edits/table-row-column-mutations.js +7 -0
  17. package/dist/ai-edits/table-template.d.ts +11 -1
  18. package/dist/ai-edits/table-template.js +49 -17
  19. package/dist/ai-edits/types.d.ts +62 -61
  20. package/dist/ai-edits/word-diff.d.ts +18 -3
  21. package/dist/ai-edits/word-diff.js +556 -67
  22. package/dist/ai-suggestions/conflict.js +1 -4
  23. package/dist/ai-suggestions/text-positions.d.ts +8 -0
  24. package/dist/ai-suggestions/text-positions.js +27 -5
  25. package/dist/compare/__fixtures__/body-sequence.js +3 -4
  26. package/dist/compare/column-alignment.d.ts +13 -13
  27. package/dist/compare/column-alignment.js +78 -39
  28. package/dist/compare/compare.d.ts +4 -3
  29. package/dist/compare/compare.js +48 -21
  30. package/dist/compare/content-alignment.d.ts +95 -0
  31. package/dist/compare/content-alignment.js +1450 -0
  32. package/dist/compare/content-types.d.ts +100 -0
  33. package/dist/compare/content-types.js +0 -0
  34. package/dist/compare/content.d.ts +209 -0
  35. package/dist/compare/content.js +885 -0
  36. package/dist/compare/formatting.d.ts +5 -5
  37. package/dist/compare/formatting.js +6 -4
  38. package/dist/compare/plan.d.ts +6 -1
  39. package/dist/compare/plan.js +171 -566
  40. package/dist/compare/scenario.d.ts +2 -2
  41. package/dist/compare/types.d.ts +3 -3
  42. package/dist/compare/verification.d.ts +8 -9
  43. package/dist/compare/verification.js +72 -50
  44. package/dist/compat/eigenpal.d.ts +5 -3
  45. package/dist/compat/eigenpal.js +3 -2
  46. package/dist/controller/headerFooterEditorManager.js +18 -10
  47. package/dist/controller/hiddenEditorApi.js +1 -1
  48. package/dist/controller/hiddenEditorManager.d.ts +7 -2
  49. package/dist/controller/hiddenEditorManager.js +15 -6
  50. package/dist/controller/layoutPipeline.js +5 -3
  51. package/dist/controller/noteEditorManager.js +12 -7
  52. package/dist/display-list/build/headerFooterPrimitives.js +1 -0
  53. package/dist/display-list/build/storyPrimitives.d.ts +5 -2
  54. package/dist/display-list/build/storyPrimitives.js +60 -3
  55. package/dist/display-list/build/tablePrimitives.js +30 -0
  56. package/dist/display-list/primitives.d.ts +1 -1
  57. package/dist/document-operations.d.ts +8 -4
  58. package/dist/document-operations.js +104 -12
  59. package/dist/docx/blockContentParser.js +6 -27
  60. package/dist/docx/commentParser.js +2 -4
  61. package/dist/docx/commentRangeIntegrity.js +2 -4
  62. package/dist/docx/documentClone.d.ts +2 -0
  63. package/dist/docx/documentClone.js +2 -0
  64. package/dist/docx/ensureParaIds.js +9 -4
  65. package/dist/docx/headerFooterParser.js +2 -4
  66. package/dist/docx/normalizeBaseDirection.js +5 -7
  67. package/dist/docx/numberingParser.d.ts +3 -1
  68. package/dist/docx/numberingParser.js +4 -1
  69. package/dist/docx/paragraphParser.js +34 -35
  70. package/dist/docx/paragraphPropertySource.d.ts +49 -0
  71. package/dist/docx/paragraphPropertySource.js +113 -0
  72. package/dist/docx/paragraphTraversal.js +30 -34
  73. package/dist/docx/rezip.d.ts +0 -8
  74. package/dist/docx/rezip.js +41 -16
  75. package/dist/docx/runConsolidator.js +2 -4
  76. package/dist/docx/runParser.js +6 -17
  77. package/dist/docx/sectionParser.js +1 -15
  78. package/dist/docx/serializer/paragraphSerializer.js +289 -30
  79. package/dist/docx/serializer/runSerializer.js +6 -12
  80. package/dist/docx/serializer/sectionPropertiesSerializer.js +2 -10
  81. package/dist/docx/serializer/tableSerializer.js +4 -23
  82. package/dist/docx/serializer/trackedChangeAttributes.d.ts +11 -0
  83. package/dist/docx/serializer/trackedChangeAttributes.js +31 -0
  84. package/dist/docx/server/build.d.ts +1 -1
  85. package/dist/docx/server/createBilingualDocument.js +8 -10
  86. package/dist/docx/server/evaluateDocxXmlPatchProposal.js +22 -13
  87. package/dist/docx/server/validateDocxConformance.js +17 -13
  88. package/dist/docx/tableParser.js +1 -37
  89. package/dist/docx/trackedChangeInfo.d.ts +11 -0
  90. package/dist/docx/trackedChangeInfo.js +38 -0
  91. package/dist/docx/verbatimCapture.d.ts +20 -9
  92. package/dist/docx/verbatimCapture.js +208 -8
  93. package/dist/docx/xmlParser.d.ts +3 -1
  94. package/dist/docx/xmlParser.js +6 -1
  95. package/dist/docx/xmlSafety.d.ts +1 -1
  96. package/dist/docx/xmlSafety.js +157 -0
  97. package/dist/headless-layout.js +5 -4
  98. package/dist/index.d.ts +5 -3
  99. package/dist/index.js +3 -2
  100. package/dist/internal/headlessRevisionResolution.d.ts +23 -0
  101. package/dist/internal/headlessRevisionResolution.js +155 -0
  102. package/dist/internal/headlessRevisionResolutionGuard.d.ts +12 -0
  103. package/dist/internal/headlessRevisionResolutionGuard.js +28 -0
  104. package/dist/internal/pageBreakRunDescendantIndex.d.ts +9 -0
  105. package/dist/internal/pageBreakRunDescendantIndex.js +27 -0
  106. package/dist/internal/pageBreakRunPartition.d.ts +26 -0
  107. package/dist/internal/pageBreakRunPartition.js +35 -0
  108. package/dist/internal/pageBreakRunSourceDescendantIndex.d.ts +15 -0
  109. package/dist/internal/pageBreakRunSourceDescendantIndex.js +126 -0
  110. package/dist/internal/sectionEndpointResolution.d.ts +32 -0
  111. package/dist/internal/sectionEndpointResolution.js +38 -0
  112. package/dist/layout-bridge/convert/footnoteLayout.js +1 -0
  113. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +16 -4
  114. package/dist/layout-bridge/convert/headerFooterLayout.js +52 -9
  115. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +4 -0
  116. package/dist/layout-bridge/convert/toFlowBlocks.js +391 -82
  117. package/dist/layout-bridge/dom/clickToPositionDom.d.ts +8 -1
  118. package/dist/layout-bridge/dom/clickToPositionDom.js +114 -40
  119. package/dist/layout-bridge/dom/textStreamDom.d.ts +24 -0
  120. package/dist/layout-bridge/dom/textStreamDom.js +75 -0
  121. package/dist/layout-bridge/headerFooterLayout.js +16 -30
  122. package/dist/layout-engine/index.js +12 -3
  123. package/dist/layout-engine/measure/tableFragmentBorderGeometry.d.ts +17 -0
  124. package/dist/layout-engine/measure/tableFragmentBorderGeometry.js +24 -0
  125. package/dist/layout-engine/renderedBreakReconciliation.js +1 -1
  126. package/dist/layout-engine/types.d.ts +7 -0
  127. package/dist/layout-painter/imageLayout.d.ts +1 -1
  128. package/dist/layout-painter/renderTable.js +20 -0
  129. package/dist/markdown/renderBlock.js +7 -10
  130. package/dist/model.d.ts +1 -1
  131. package/dist/paged-layout/rangeProjection.js +6 -9
  132. package/dist/paged-layout/transactionDirtyRange.d.ts +3 -1
  133. package/dist/paged-layout/transactionDirtyRange.js +23 -1
  134. package/dist/prosemirror/attrs/index.d.ts +7 -3
  135. package/dist/prosemirror/attrs/index.js +128 -7
  136. package/dist/prosemirror/bookmarkBoundaryIntegrity.d.ts +9 -0
  137. package/dist/prosemirror/bookmarkBoundaryIntegrity.js +22 -0
  138. package/dist/prosemirror/commands/comments.d.ts +10 -1
  139. package/dist/prosemirror/commands/comments.js +551 -87
  140. package/dist/prosemirror/commands/formatPainter.d.ts +45 -10
  141. package/dist/prosemirror/commands/formatPainter.js +319 -63
  142. package/dist/prosemirror/commands/index.d.ts +2 -2
  143. package/dist/prosemirror/commands/pageBreak.d.ts +5 -2
  144. package/dist/prosemirror/commands/pageBreak.js +18 -36
  145. package/dist/prosemirror/commands/propertyChangeScope.d.ts +27 -3
  146. package/dist/prosemirror/commands/propertyChangeScope.js +85 -14
  147. package/dist/prosemirror/conversion/fromProseDoc.d.ts +8 -5
  148. package/dist/prosemirror/conversion/fromProseDoc.js +935 -223
  149. package/dist/prosemirror/conversion/runShadingMark.js +2 -2
  150. package/dist/prosemirror/conversion/toProseDoc.d.ts +26 -1
  151. package/dist/prosemirror/conversion/toProseDoc.js +439 -291
  152. package/dist/prosemirror/extensions/StarterKit.js +4 -0
  153. package/dist/prosemirror/extensions/core/ParagraphExtension.js +54 -6
  154. package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.js +7 -1
  155. package/dist/prosemirror/extensions/features/ListExtension.js +95 -123
  156. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +19 -6
  157. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +27 -1
  158. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +134 -30
  159. package/dist/prosemirror/extensions/features/pasteCleanup.js +9 -15
  160. package/dist/prosemirror/extensions/marks/BoldExtension.js +4 -3
  161. package/dist/prosemirror/extensions/marks/CharacterStyleExtension.d.ts +4 -7
  162. package/dist/prosemirror/extensions/marks/CharacterStyleExtension.js +5 -11
  163. package/dist/prosemirror/extensions/marks/FontSizeExtension.js +3 -3
  164. package/dist/prosemirror/extensions/marks/ItalicExtension.js +4 -3
  165. package/dist/prosemirror/extensions/marks/PageBreakRunOwnerExtension.d.ts +13 -0
  166. package/dist/prosemirror/extensions/marks/PageBreakRunOwnerExtension.js +39 -0
  167. package/dist/prosemirror/extensions/marks/RunFormattingOverrideExtension.d.ts +7 -1
  168. package/dist/prosemirror/extensions/marks/RunFormattingOverrideExtension.js +67 -21
  169. package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +2 -0
  170. package/dist/prosemirror/extensions/marks/markUtils.d.ts +8 -1
  171. package/dist/prosemirror/extensions/marks/markUtils.js +88 -2
  172. package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.js +44 -3
  173. package/dist/prosemirror/extensions/nodes/FieldExtension.js +1 -1
  174. package/dist/prosemirror/extensions/nodes/HardBreakExtension.js +15 -4
  175. package/dist/prosemirror/extensions/nodes/PageBreakExtension.d.ts +6 -0
  176. package/dist/prosemirror/extensions/nodes/PageBreakExtension.js +6 -0
  177. package/dist/prosemirror/extensions/nodes/PageBreakRunExtension.d.ts +6 -0
  178. package/dist/prosemirror/extensions/nodes/PageBreakRunExtension.js +36 -0
  179. package/dist/prosemirror/findReplaceSelection.js +8 -3
  180. package/dist/prosemirror/index.d.ts +3 -3
  181. package/dist/prosemirror/listMarker.d.ts +26 -1
  182. package/dist/prosemirror/listMarker.js +108 -14
  183. package/dist/prosemirror/pageBreakRunProjection.d.ts +28 -0
  184. package/dist/prosemirror/pageBreakRunProjection.js +47 -0
  185. package/dist/prosemirror/paraText.js +6 -0
  186. package/dist/prosemirror/paragraphAlignment.d.ts +12 -0
  187. package/dist/prosemirror/paragraphAlignment.js +13 -0
  188. package/dist/prosemirror/paragraphSpacing.d.ts +29 -0
  189. package/dist/prosemirror/paragraphSpacing.js +125 -0
  190. package/dist/prosemirror/plugins/documentNumbering.d.ts +8 -0
  191. package/dist/prosemirror/plugins/documentNumbering.js +18 -0
  192. package/dist/prosemirror/plugins/pmTextScan.d.ts +3 -2
  193. package/dist/prosemirror/plugins/pmTextScan.js +14 -4
  194. package/dist/prosemirror/plugins/suggestionMode.js +9 -11
  195. package/dist/prosemirror/rebaseParagraphRunFormatting.d.ts +16 -0
  196. package/dist/prosemirror/rebaseParagraphRunFormatting.js +61 -0
  197. package/dist/prosemirror/runFormattingInlineCarriers.d.ts +64 -0
  198. package/dist/prosemirror/runFormattingInlineCarriers.js +121 -0
  199. package/dist/prosemirror/runFormattingProvenance.d.ts +12 -0
  200. package/dist/prosemirror/runFormattingProvenance.js +48 -0
  201. package/dist/prosemirror/runFormattingReconciliation.d.ts +25 -0
  202. package/dist/prosemirror/runFormattingReconciliation.js +54 -0
  203. package/dist/prosemirror/runPropertyChangeResolution.d.ts +18 -0
  204. package/dist/prosemirror/runPropertyChangeResolution.js +18 -0
  205. package/dist/prosemirror/runStyleFormatting.d.ts +50 -0
  206. package/dist/prosemirror/runStyleFormatting.js +105 -0
  207. package/dist/prosemirror/schema/index.d.ts +3 -3
  208. package/dist/prosemirror/schema/marks.d.ts +84 -9
  209. package/dist/prosemirror/schema/marks.js +73 -1
  210. package/dist/prosemirror/schema/nodes.d.ts +30 -6
  211. package/dist/prosemirror/styles/resolvedStyleAttrs.d.ts +14 -2
  212. package/dist/prosemirror/styles/resolvedStyleAttrs.js +45 -23
  213. package/dist/prosemirror/styles/styleResolver.d.ts +10 -13
  214. package/dist/prosemirror/styles/styleResolver.js +3 -3
  215. package/dist/prosemirror/styles/styleToggleCascade.d.ts +8 -1
  216. package/dist/prosemirror/styles/styleToggleCascade.js +24 -1
  217. package/dist/prosemirror/tableGridMutation.d.ts +20 -0
  218. package/dist/prosemirror/tableGridMutation.js +30 -0
  219. package/dist/prosemirror/trackedRunInlineAtoms.d.ts +31 -0
  220. package/dist/prosemirror/trackedRunInlineAtoms.js +39 -0
  221. package/dist/prosemirror/utils/visualLineNavigation.js +27 -31
  222. package/dist/prosemirror/validation.js +23 -4
  223. package/dist/redline.js +4 -1
  224. package/dist/render-dom/HeaderFooterSelectionOverlay.js +20 -20
  225. package/dist/render-dom/RenderedDomContext.js +17 -34
  226. package/dist/server.d.ts +4 -4
  227. package/dist/server.js +2 -2
  228. package/dist/style-engine/styleEngine.d.ts +1 -1
  229. package/dist/utils/clipboard.js +1 -1
  230. package/dist/utils/findReplace.js +38 -21
  231. package/dist/utils/mergeDocumentContent.js +3 -3
  232. package/dist/utils/replaceText.js +2 -1
  233. package/dist/version-comparison.d.ts +38 -44
  234. package/dist/version-comparison.js +270 -399
  235. package/dist/watermark/index.js +2 -4
  236. package/package.json +8 -2
@@ -5,6 +5,7 @@ import { ExtensionManager } from "../prosemirror/extensions/ExtensionManager.js"
5
5
  import { createStarterKit } from "../prosemirror/extensions/StarterKit.js";
6
6
  import { ensureBaseDirectionInState } from "../prosemirror/extensions/features/AutoBidiDetectionExtension.js";
7
7
  import { ensureParaIdsInState } from "../prosemirror/extensions/features/ParaIdAllocatorExtension.js";
8
+ import { createDocumentNumberingPlugin } from "../prosemirror/plugins/documentNumbering.js";
8
9
  import { createDocumentStylesPlugin } from "../prosemirror/plugins/documentStyles.js";
9
10
  import { schema } from "../prosemirror/schema/index.js";
10
11
  import { EditorState } from "prosemirror-state";
@@ -31,14 +32,15 @@ const noteToProseDocument = (note, styles, theme) => {
31
32
  if (theme !== void 0) options.theme = theme;
32
33
  return footnoteToProseDoc(note.content, options);
33
34
  };
34
- const buildInitialState = (document, styles, manager, externalPlugins) => {
35
+ const buildInitialState = (document, styles, numbering, manager, externalPlugins) => {
35
36
  return ensureBaseDirectionInState(ensureParaIdsInState(EditorState.create({
36
37
  doc: document,
37
38
  schema,
38
39
  plugins: [
39
40
  ...manager.getPlugins(),
40
41
  ...externalPlugins,
41
- createDocumentStylesPlugin(styles)
42
+ createDocumentStylesPlugin(styles),
43
+ createDocumentNumberingPlugin(numbering)
42
44
  ]
43
45
  })));
44
46
  };
@@ -65,6 +67,7 @@ const createNoteEditorManager = (deps) => {
65
67
  const document = deps.getDocument();
66
68
  const styles = deps.getStyles();
67
69
  const theme = deps.getTheme();
70
+ const numbering = document?.package.numbering;
68
71
  const externalPlugins = deps.getPlugins?.() ?? EMPTY_PLUGINS;
69
72
  const wanted = new Map(enumerateDocumentNoteStories(document).map((story) => [storyMapKey(story), story]));
70
73
  const activeKey = active ? storyMapKey(active) : null;
@@ -81,18 +84,19 @@ const createNoteEditorManager = (deps) => {
81
84
  if (existing) {
82
85
  if (existing.mountNode.parentElement !== host) host.append(existing.mountNode);
83
86
  const nextProseDocument = noteToProseDocument(note, styles, theme);
84
- const contextIsCurrent = existing.appliedStyles === styles && existing.appliedTheme === theme && existing.appliedPlugins === externalPlugins;
87
+ const contextIsCurrent = existing.appliedStyles === styles && existing.appliedTheme === theme && existing.appliedNumbering === numbering && existing.appliedPlugins === externalPlugins;
85
88
  if ((existing.appliedNote === note && existing.appliedContent === note.content || existing.appliedProseDocument.eq(nextProseDocument)) && contextIsCurrent) {
86
89
  existing.appliedNote = note;
87
90
  existing.appliedContent = note.content;
88
91
  existing.appliedProseDocument = nextProseDocument;
89
92
  continue;
90
93
  }
91
- existing.view.updateState(buildInitialState(nextProseDocument, styles, existing.manager, externalPlugins));
94
+ existing.view.updateState(buildInitialState(nextProseDocument, styles, numbering, existing.manager, externalPlugins));
92
95
  existing.appliedNote = note;
93
96
  existing.appliedContent = note.content;
94
97
  existing.appliedStyles = styles;
95
98
  existing.appliedTheme = theme;
99
+ existing.appliedNumbering = numbering;
96
100
  existing.appliedPlugins = externalPlugins;
97
101
  existing.appliedProseDocument = nextProseDocument;
98
102
  existing.dirty = false;
@@ -107,7 +111,7 @@ const createNoteEditorManager = (deps) => {
107
111
  host.append(mountNode);
108
112
  const proseDocument = noteToProseDocument(note, styles, theme);
109
113
  const view = new EditorView(mountNode, {
110
- state: buildInitialState(proseDocument, styles, manager, externalPlugins),
114
+ state: buildInitialState(proseDocument, styles, numbering, manager, externalPlugins),
111
115
  dispatchTransaction(transaction) {
112
116
  view.updateState(view.state.apply(transaction));
113
117
  const mountedStory = mounted.get(key);
@@ -123,6 +127,7 @@ const createNoteEditorManager = (deps) => {
123
127
  mounted.set(key, {
124
128
  appliedContent: note.content,
125
129
  appliedNote: note,
130
+ appliedNumbering: numbering,
126
131
  appliedPlugins: externalPlugins,
127
132
  appliedProseDocument: proseDocument,
128
133
  appliedStyles: styles,
@@ -169,7 +174,7 @@ const createNoteEditorManager = (deps) => {
169
174
  }
170
175
  const updated = {
171
176
  ...current,
172
- content: proseDocToBlocks(story.view.state.doc)
177
+ content: proseDocToBlocks(story.view.state.doc, current.content, document.package.styles)
173
178
  };
174
179
  footnotes[index] = updated;
175
180
  story.appliedNote = updated;
@@ -186,7 +191,7 @@ const createNoteEditorManager = (deps) => {
186
191
  }
187
192
  const updated = {
188
193
  ...current,
189
- content: proseDocToBlocks(story.view.state.doc)
194
+ content: proseDocToBlocks(story.view.state.doc, current.content, document.package.styles)
190
195
  };
191
196
  endnotes[index] = updated;
192
197
  story.appliedNote = updated;
@@ -28,6 +28,7 @@ const paintHeaderFooter = ({ composer, page, section, content, distancePx, conte
28
28
  xPx: page.margins.left,
29
29
  yPx: originYPx,
30
30
  widthPx: page.size.w - page.margins.left - page.margins.right,
31
+ page,
31
32
  context: {
32
33
  ...context,
33
34
  story
@@ -1,4 +1,4 @@
1
- import { FlowBlock, Measure } from "../../layout-engine/types.js";
1
+ import { FlowBlock, Measure, Page } from "../../layout-engine/types.js";
2
2
  import { BuildContext } from "./buildContext.js";
3
3
  import { PageComposer } from "./regions.js";
4
4
  //#region src/display-list/build/storyPrimitives.d.ts
@@ -13,6 +13,9 @@ type PaintStoryOptions = {
13
13
  readonly context: BuildContext;
14
14
  readonly label: string;
15
15
  };
16
+ type PaintHeaderFooterStoryOptions = PaintStoryOptions & {
17
+ readonly page: Page;
18
+ };
16
19
  /**
17
20
  * A footnote body: every block stacks by its measured height, which is the
18
21
  * height the paginator reserved the band from.
@@ -24,6 +27,6 @@ declare const paintFootnoteBlocks: ({ composer, blocks, measures, xPx, yPx, widt
24
27
  * they are reported rather than painted: their position resolves against page
25
28
  * and margin anchors the display list producer does not carry.
26
29
  */
27
- declare const paintHeaderFooterBlocks: ({ composer, blocks, measures, xPx, yPx, widthPx, context, label }: PaintStoryOptions) => void;
30
+ declare const paintHeaderFooterBlocks: ({ composer, blocks, measures, xPx, yPx, widthPx, page, context, label }: PaintHeaderFooterStoryOptions) => void;
28
31
  //#endregion
29
32
  export { PaintStoryOptions, paintFootnoteBlocks, paintHeaderFooterBlocks };
@@ -1,6 +1,7 @@
1
1
  import { isFloatingImageRun, isFloatingTextBoxBlock } from "../../layout-engine/types.js";
2
+ import { resolveAnchoredImagePosition } from "../../layout-painter/anchoredImagePosition.js";
2
3
  import { HIT_REGION_KINDS } from "../primitives.js";
3
- import { paintImageFragment } from "./imagePrimitives.js";
4
+ import { paintImage, paintImageFragment } from "./imagePrimitives.js";
4
5
  import { paintParagraphFragment } from "./paragraphPrimitives.js";
5
6
  import { blockRegion } from "./regions.js";
6
7
  import { paintTableFragment } from "./tablePrimitives.js";
@@ -150,6 +151,47 @@ const measuredHeightPx = (measure) => {
150
151
  default: return 0;
151
152
  }
152
153
  };
154
+ const paintHeaderFooterFloatingImage = ({ composer, run, block, paragraphYPx, page, context, label }) => {
155
+ const contentWidth = page.size.w - page.margins.left - page.margins.right;
156
+ const geometry = {
157
+ pageWidth: page.size.w,
158
+ pageHeight: page.size.h,
159
+ marginLeft: page.margins.left,
160
+ marginTop: page.margins.top,
161
+ marginRight: page.margins.right,
162
+ marginBottom: page.margins.bottom,
163
+ ...page.authoredMargins === void 0 ? {} : { authoredMargins: page.authoredMargins },
164
+ contentWidth,
165
+ contentHeight: page.size.h - page.margins.top - page.margins.bottom
166
+ };
167
+ const position = resolveAnchoredImagePosition(run, paragraphYPx - page.margins.top, geometry);
168
+ const fragment = {
169
+ blockId: block.id,
170
+ x: page.margins.left + position.x,
171
+ y: page.margins.top + position.y,
172
+ width: run.width,
173
+ height: run.height,
174
+ ...run.pmStart === void 0 ? {} : { pmStart: run.pmStart },
175
+ ...run.pmEnd === void 0 ? {} : { pmEnd: run.pmEnd }
176
+ };
177
+ composer.region(blockRegion({
178
+ fragment,
179
+ kind: HIT_REGION_KINDS.image,
180
+ context
181
+ }), () => {
182
+ composer.push(paintImage({
183
+ source: run,
184
+ rect: {
185
+ xPx: fragment.x,
186
+ yPx: fragment.y,
187
+ widthPx: fragment.width,
188
+ heightPx: fragment.height
189
+ },
190
+ context,
191
+ label: `${label} floating image`
192
+ }));
193
+ });
194
+ };
153
195
  /**
154
196
  * A footnote body: every block stacks by its measured height, which is the
155
197
  * height the paginator reserved the band from.
@@ -182,7 +224,7 @@ const paintFootnoteBlocks = ({ composer, blocks, measures, xPx, yPx, widthPx, co
182
224
  * they are reported rather than painted: their position resolves against page
183
225
  * and margin anchors the display list producer does not carry.
184
226
  */
185
- const paintHeaderFooterBlocks = ({ composer, blocks, measures, xPx, yPx, widthPx, context, label }) => {
227
+ const paintHeaderFooterBlocks = ({ composer, blocks, measures, xPx, yPx, widthPx, page, context, label }) => {
186
228
  let cursorYPx = yPx;
187
229
  const reportOutOfFlow = (detail) => {
188
230
  context.unsupported.report(UNSUPPORTED_CONSTRUCT.headerFooterContent, context.pageIndex, `${label}: ${detail}`);
@@ -196,7 +238,6 @@ const paintHeaderFooterBlocks = ({ composer, blocks, measures, xPx, yPx, widthPx
196
238
  switch (block.kind) {
197
239
  case "paragraph":
198
240
  if (measure.kind !== "paragraph") break;
199
- if (block.runs.some((run) => run.kind === "image" && (isFloatingImageRun(run) || run.position !== void 0))) reportOutOfFlow(`paragraph ${String(block.id)} anchors a floating picture, which resolves against page and margin anchors the display list does not carry`);
200
241
  paintStoryBlock({
201
242
  composer,
202
243
  block,
@@ -208,6 +249,22 @@ const paintHeaderFooterBlocks = ({ composer, blocks, measures, xPx, yPx, widthPx
208
249
  label,
209
250
  construct: UNSUPPORTED_CONSTRUCT.headerFooterContent
210
251
  });
252
+ for (const run of block.runs) {
253
+ if (run.kind !== "image" || !isFloatingImageRun(run) && run.position === void 0) continue;
254
+ if (run.wrapType === "behind") {
255
+ reportOutOfFlow(`paragraph ${String(block.id)} anchors a behind-text picture that requires the page-underlay paint phase`);
256
+ continue;
257
+ }
258
+ paintHeaderFooterFloatingImage({
259
+ composer,
260
+ run,
261
+ block,
262
+ paragraphYPx: cursorYPx,
263
+ page,
264
+ context,
265
+ label
266
+ });
267
+ }
211
268
  cursorYPx += measure.totalHeight;
212
269
  continue;
213
270
  case "table":
@@ -1,5 +1,6 @@
1
1
  import { createTableCellFlowState, placeTableCellBlock } from "../../layout-engine/measure/tableCellFlow.js";
2
2
  import { buildTableCellGrid, buildTableCellPlacements, getSourceCellAt } from "../../layout-engine/measure/tableCellGrid.js";
3
+ import { tableFragmentBottomBorders } from "../../layout-engine/measure/tableFragmentBorderGeometry.js";
3
4
  import { resolveTableCellPadding } from "../../layout-engine/types.js";
4
5
  import { HIT_REGION_KINDS } from "../primitives.js";
5
6
  import { parseDisplayColor } from "./colors.js";
@@ -332,6 +333,28 @@ const paintTableBody = ({ composer, block, measure, xPx, yPx, fromRow, toRow, he
332
333
  cursorYPx += rowMeasure.height;
333
334
  }
334
335
  };
336
+ const paintFragmentBottomBorders = ({ composer, fragment, block, measure, context }) => {
337
+ if (fragment.continuesOnNext !== true || fragment.bottomClip === void 0) return;
338
+ const primitives = [];
339
+ for (const { left, width, border } of tableFragmentBottomBorders({
340
+ fragment,
341
+ block,
342
+ measure
343
+ })) {
344
+ const stroke = strokeFor(border, context, "table fragment bottom border");
345
+ if (!stroke) continue;
346
+ const yPx = fragment.y + fragment.height - stroke.thicknessPx / 2;
347
+ primitives.push({
348
+ kind: "line",
349
+ x1Px: fragment.x + left,
350
+ y1Px: yPx,
351
+ x2Px: fragment.x + left + width,
352
+ y2Px: yPx,
353
+ stroke
354
+ });
355
+ }
356
+ composer.push(primitives);
357
+ };
335
358
  /** A whole, unpaginated table: what a nested table inside a cell or box is. */
336
359
  const paintTableBlock = ({ composer, block, measure, xPx, yPx, context, paintTextBox }) => paintTableBody({
337
360
  composer,
@@ -404,6 +427,13 @@ const paintTableFragment = ({ composer, fragment, block, measure, context, paint
404
427
  children: [...clipped.primitives()],
405
428
  regions: [...clipped.regions()]
406
429
  }]);
430
+ paintFragmentBottomBorders({
431
+ composer,
432
+ fragment,
433
+ block,
434
+ measure,
435
+ context
436
+ });
407
437
  };
408
438
  //#endregion
409
439
  export { paintTableBlock, paintTableFragment };
@@ -15,7 +15,7 @@ import { hasComplexScript, isComplexScriptCodePoint } from "../utils/scriptSegme
15
15
  * advances rightward from its origin whatever the paragraph does.
16
16
  */
17
17
  declare const glyphCellOffsetsPx: (run: DisplayGlyphRun) => readonly number[];
18
- declare const DISPLAY_PRIMITIVE_KINDS: ("glyphRun" | "rect" | "line" | "image" | "clipGroup" | "rotateGroup" | "opacityGroup")[];
18
+ declare const DISPLAY_PRIMITIVE_KINDS: ("image" | "line" | "rect" | "glyphRun" | "clipGroup" | "rotateGroup" | "opacityGroup")[];
19
19
  /**
20
20
  * Dash geometry of each stroke pattern, as multiples of the stroke thickness.
21
21
  *
@@ -3,6 +3,10 @@ import { FolioAIEditAppliedOperation, FolioAIEditApplyMode, FolioAIEditNormaliza
3
3
  import { FolioAIEditView, FolioRevisionStamp, FolioWordDiffOptions } from "./ai-edits/apply.js";
4
4
  //#region src/document-operations.d.ts
5
5
  declare const FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION: 1;
6
+ /** Direct paragraph-alignment values accepted by the operation contract. */
7
+ declare const FOLIO_PARAGRAPH_ALIGNMENT_VALUES: readonly ("left" | "center" | "right" | "both" | "distribute" | "mediumKashida" | "highKashida" | "lowKashida" | "thaiDistribute")[];
8
+ /** `w:spacing/@w:lineRule` values accepted by the operation contract. */
9
+ declare const FOLIO_LINE_SPACING_RULE_VALUES: readonly ("auto" | "exact" | "atLeast")[];
6
10
  declare const FOLIO_DOCUMENT_OPERATION_TYPES: readonly ["replaceInBlock", "replaceRange", "commentOnRange", "formatRange", "insertAfterBlock", "insertBeforeBlock", "replaceBlock", "deleteBlock", "splitBlock", "mergeBlockWithNext", "setBlockParagraphProperties", "insertTable", "deleteTable", "commentOnBlock", "insertSignatureTable", "insertTableRow", "deleteTableRow", "insertTableColumn", "deleteTableColumn", "mergeTableCells", "splitTableCell"];
7
11
  declare const FOLIO_DOCUMENT_OPERATION_MODES: readonly ["direct", "tracked-changes", "suggested"];
8
12
  declare const FOLIO_DOCUMENT_OPERATION_STORIES: readonly ["main", "header", "footer", "footnote", "endnote"];
@@ -93,8 +97,8 @@ declare const FOLIO_DOCUMENT_OPERATION_KEYS_BY_TYPE: Readonly<{
93
97
  readonly replaceRange: readonly ["id", "type", "range", "severity", "area", "precondition", "suggestionId", "replace", "comment"];
94
98
  readonly commentOnRange: readonly ["id", "type", "range", "severity", "area", "precondition", "comment"];
95
99
  readonly formatRange: readonly ["id", "type", "range", "severity", "area", "precondition", "suggestionId", "formatting"];
96
- readonly insertAfterBlock: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "text", "inheritFormatting", "listLevel", "moveId", "pageBreakBefore", "styleId", "comment"];
97
- readonly insertBeforeBlock: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "text", "inheritFormatting", "listLevel", "moveId", "pageBreakBefore", "styleId", "comment"];
100
+ readonly insertAfterBlock: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "text", "inheritFormatting", "alignment", "spacing", "listLevel", "moveId", "pageBreakBefore", "styleId", "comment"];
101
+ readonly insertBeforeBlock: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "text", "inheritFormatting", "alignment", "spacing", "listLevel", "moveId", "pageBreakBefore", "styleId", "comment"];
98
102
  readonly replaceBlock: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "text", "preserveFormatting", "styleId", "comment"];
99
103
  readonly deleteBlock: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "moveId", "comment"];
100
104
  readonly splitBlock: readonly ["id", "type", "blockId", "severity", "area", "precondition", "suggestionId", "offset", "separator"];
@@ -117,7 +121,7 @@ declare const parseFolioDocumentOperationBatch: (value: unknown) => FolioDocumen
117
121
  * review queue instead of applying it; the core apply path never produces it.
118
122
  */
119
123
  type FolioDocumentOperationStatus = "committed" | "previewed" | "rejected" | "queued";
120
- type FolioDocumentOperationRecovery = "refreshDocument" | "narrowMatch" | "changeMode" | "changeTarget" | "removeOperation" | "inspectBatch" | "retryLater";
124
+ type FolioDocumentOperationRecovery = "refreshDocument" | "narrowMatch" | "changeMode" | "changeTarget" | "removeOperation" | "inspectBatch" | "resolveTrackedChange" | "retryLater";
121
125
  type FolioDocumentOperationIssue = {
122
126
  operationId: string;
123
127
  operationIndex: number;
@@ -278,4 +282,4 @@ type ApplyFolioDocumentOperationsOptions = {
278
282
  };
279
283
  declare const applyFolioDocumentOperations: ({ view, snapshot, batch, story, author, createCommentId, createUndoHandle, revisionStamp, wordDiff, tableTemplates }: ApplyFolioDocumentOperationsOptions) => FolioDocumentOperationResult;
280
284
  //#endregion
281
- export { ApplyFolioDocumentOperationsOptions, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_BATCH_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_KEYS_BY_TYPE, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FolioDocumentOperation, FolioDocumentOperationAffectedTarget, FolioDocumentOperationBatch, FolioDocumentOperationBatchPrecondition, FolioDocumentOperationCapabilities, FolioDocumentOperationIssue, FolioDocumentOperationMode, FolioDocumentOperationPrecondition, FolioDocumentOperationQueuedOperation, FolioDocumentOperationReceipt, FolioDocumentOperationRecovery, FolioDocumentOperationResult, FolioDocumentOperationResultBase, FolioDocumentOperationStatus, FolioDocumentOperationStory, FolioDocumentOperationType, FolioDocumentOperationUndoFailureReason, FolioDocumentOperationUndoHandle, FolioDocumentOperationUndoResult, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch };
285
+ export { ApplyFolioDocumentOperationsOptions, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_BATCH_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_KEYS_BY_TYPE, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FOLIO_LINE_SPACING_RULE_VALUES, FOLIO_PARAGRAPH_ALIGNMENT_VALUES, FolioDocumentOperation, FolioDocumentOperationAffectedTarget, FolioDocumentOperationBatch, FolioDocumentOperationBatchPrecondition, FolioDocumentOperationCapabilities, FolioDocumentOperationIssue, FolioDocumentOperationMode, FolioDocumentOperationPrecondition, FolioDocumentOperationQueuedOperation, FolioDocumentOperationReceipt, FolioDocumentOperationRecovery, FolioDocumentOperationResult, FolioDocumentOperationResultBase, FolioDocumentOperationStatus, FolioDocumentOperationStory, FolioDocumentOperationType, FolioDocumentOperationUndoFailureReason, FolioDocumentOperationUndoHandle, FolioDocumentOperationUndoResult, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch };
@@ -1,7 +1,12 @@
1
1
  import { applyFolioAIEditOperations, previewFolioAIEditOperations } from "./ai-edits/apply.js";
2
+ import { LINE_SPACING_RULE_VALUES, PARAGRAPH_ALIGNMENT_VALUES } from "./types/documentEnumValues.js";
2
3
  import { TaggedError } from "better-result";
3
4
  //#region src/document-operations.ts
4
5
  const FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION = 1;
6
+ /** Direct paragraph-alignment values accepted by the operation contract. */
7
+ const FOLIO_PARAGRAPH_ALIGNMENT_VALUES = Object.freeze([...PARAGRAPH_ALIGNMENT_VALUES]);
8
+ /** `w:spacing/@w:lineRule` values accepted by the operation contract. */
9
+ const FOLIO_LINE_SPACING_RULE_VALUES = Object.freeze([...LINE_SPACING_RULE_VALUES]);
5
10
  const FOLIO_DOCUMENT_OPERATION_TYPES = Object.freeze([
6
11
  "replaceInBlock",
7
12
  "replaceRange",
@@ -143,6 +148,12 @@ const readOptionalBoolean = (value, key, path) => {
143
148
  if (typeof candidate === "boolean") return candidate;
144
149
  return invalidBatch(`${path}.${key}`, "expected a boolean when provided");
145
150
  };
151
+ const readClearableBoolean = (value, key, path) => {
152
+ const candidate = value[key];
153
+ if (candidate === void 0 || candidate === null) return candidate;
154
+ if (typeof candidate === "boolean") return candidate;
155
+ return invalidBatch(`${path}.${key}`, "expected a boolean or null when provided");
156
+ };
146
157
  const readClearableNonEmptyString = (value, key, path) => {
147
158
  const candidate = value[key];
148
159
  if (candidate === void 0 || candidate === null) return candidate;
@@ -172,8 +183,8 @@ const readOptionalStringArray = (value, key, path) => {
172
183
  };
173
184
  const readNonNegativeInteger = (value, key, path) => {
174
185
  const candidate = value[key];
175
- if (typeof candidate === "number" && Number.isInteger(candidate) && candidate >= 0) return candidate;
176
- return invalidBatch(`${path}.${key}`, "expected a non-negative integer");
186
+ if (typeof candidate === "number" && Number.isSafeInteger(candidate) && candidate >= 0) return candidate;
187
+ return invalidBatch(`${path}.${key}`, "expected a non-negative safe integer");
177
188
  };
178
189
  /**
179
190
  * A non-negative integer that may also be cleared. `undefined` is "say
@@ -185,6 +196,52 @@ const readClearableNonNegativeInteger = (value, key, path) => {
185
196
  if (candidate === void 0) return;
186
197
  return candidate === null ? null : readNonNegativeInteger(value, key, path);
187
198
  };
199
+ const readClearableParagraphAlignment = ({ value, key, path }) => {
200
+ const candidate = value[key];
201
+ if (candidate === void 0 || candidate === null) return candidate;
202
+ for (const alignment of FOLIO_PARAGRAPH_ALIGNMENT_VALUES) if (candidate === alignment) return alignment;
203
+ return invalidBatch(`${path}.${key}`, `expected one of ${FOLIO_PARAGRAPH_ALIGNMENT_VALUES.join(", ")} or null when provided`);
204
+ };
205
+ const PARAGRAPH_SPACING_KEYS = [
206
+ "spaceBefore",
207
+ "spaceAfter",
208
+ "lineSpacing",
209
+ "lineSpacingRule",
210
+ "beforeAutospacing",
211
+ "afterAutospacing"
212
+ ];
213
+ const isLineSpacingRule = (value) => FOLIO_LINE_SPACING_RULE_VALUES.some((rule) => value === rule);
214
+ /**
215
+ * Read one complete direct `w:spacing` cluster. Individual fields are
216
+ * optional so explicit zero and false survive; null removes the child.
217
+ */
218
+ const readClearableParagraphSpacing = ({ value, key, path }) => {
219
+ const candidate = value[key];
220
+ if (candidate === void 0 || candidate === null) return candidate;
221
+ const spacingPath = `${path}.${key}`;
222
+ if (!isPlainObject(candidate)) return invalidBatch(spacingPath, "expected an object or null when provided");
223
+ assertAllowedKeys(candidate, spacingPath, PARAGRAPH_SPACING_KEYS);
224
+ if (Object.keys(candidate).length === 0) return invalidBatch(spacingPath, "expected at least one spacing property");
225
+ const spacing = {};
226
+ for (const unsignedKey of ["spaceBefore", "spaceAfter"]) if (candidate[unsignedKey] !== void 0) spacing[unsignedKey] = readNonNegativeInteger(candidate, unsignedKey, spacingPath);
227
+ const lineSpacing = candidate["lineSpacing"];
228
+ if (lineSpacing !== void 0) {
229
+ if (typeof lineSpacing !== "number" || !Number.isSafeInteger(lineSpacing)) return invalidBatch(`${spacingPath}.lineSpacing`, "expected a safe signed integer when provided");
230
+ spacing.lineSpacing = lineSpacing;
231
+ }
232
+ const lineSpacingRule = candidate["lineSpacingRule"];
233
+ if (lineSpacingRule !== void 0) {
234
+ if (!isLineSpacingRule(lineSpacingRule)) return invalidBatch(`${spacingPath}.lineSpacingRule`, `expected one of ${FOLIO_LINE_SPACING_RULE_VALUES.join(", ")} when provided`);
235
+ spacing.lineSpacingRule = lineSpacingRule;
236
+ }
237
+ for (const booleanKey of ["beforeAutospacing", "afterAutospacing"]) {
238
+ const booleanValue = candidate[booleanKey];
239
+ if (booleanValue === void 0) continue;
240
+ if (typeof booleanValue !== "boolean") return invalidBatch(`${spacingPath}.${booleanKey}`, "expected a boolean when provided");
241
+ spacing[booleanKey] = booleanValue;
242
+ }
243
+ return spacing;
244
+ };
188
245
  /**
189
246
  * A rectangular grid of cell texts. Rectangular because a table whose rows
190
247
  * hold different cell counts is not a table any consumer can lay out, and the
@@ -209,13 +266,30 @@ const readParagraphProperties = (value, path) => {
209
266
  const candidate = value["properties"];
210
267
  const propertiesPath = `${path}.properties`;
211
268
  if (!isPlainObject(candidate)) return invalidBatch(propertiesPath, "expected an object");
212
- assertAllowedKeys(candidate, propertiesPath, ["styleId", "listLevel"]);
269
+ assertAllowedKeys(candidate, propertiesPath, [
270
+ "styleId",
271
+ "listLevel",
272
+ "alignment",
273
+ "spacing"
274
+ ]);
213
275
  const styleId = candidate["styleId"] === null ? null : readOptionalString(candidate, "styleId", propertiesPath);
214
276
  const listLevel = readClearableNonNegativeInteger(candidate, "listLevel", propertiesPath);
215
- if (styleId === void 0 && listLevel === void 0) return invalidBatch(propertiesPath, "expected at least one property to set");
277
+ const alignment = readClearableParagraphAlignment({
278
+ value: candidate,
279
+ key: "alignment",
280
+ path: propertiesPath
281
+ });
282
+ const spacing = readClearableParagraphSpacing({
283
+ value: candidate,
284
+ key: "spacing",
285
+ path: propertiesPath
286
+ });
287
+ if (styleId === void 0 && listLevel === void 0 && alignment === void 0 && spacing === void 0) return invalidBatch(propertiesPath, "expected at least one property to set");
216
288
  return {
217
289
  ...styleId !== void 0 && { styleId },
218
- ...listLevel !== void 0 && { listLevel }
290
+ ...listLevel !== void 0 && { listLevel },
291
+ ...alignment !== void 0 && { alignment },
292
+ ...spacing !== void 0 && { spacing }
219
293
  };
220
294
  };
221
295
  const readTextRange = (value, path) => {
@@ -261,10 +335,10 @@ const readInlineFormatting = (value, path) => {
261
335
  "fontSizePt",
262
336
  "color"
263
337
  ]);
264
- const bold = readOptionalBoolean(candidate, "bold", formattingPath);
265
- const italic = readOptionalBoolean(candidate, "italic", formattingPath);
266
- const underline = readOptionalBoolean(candidate, "underline", formattingPath);
267
- const strike = readOptionalBoolean(candidate, "strike", formattingPath);
338
+ const bold = readClearableBoolean(candidate, "bold", formattingPath);
339
+ const italic = readClearableBoolean(candidate, "italic", formattingPath);
340
+ const underline = readClearableBoolean(candidate, "underline", formattingPath);
341
+ const strike = readClearableBoolean(candidate, "strike", formattingPath);
268
342
  const fontFamily = readClearableNonEmptyString(candidate, "fontFamily", formattingPath);
269
343
  const fontSizePt = readClearableFontSize(candidate, "fontSizePt", formattingPath);
270
344
  const color = readClearableRgbColor(candidate, "color", formattingPath);
@@ -354,6 +428,8 @@ const FOLIO_DOCUMENT_OPERATION_KEYS_BY_TYPE = Object.freeze({
354
428
  ...COMMON_OPERATION_KEYS,
355
429
  "text",
356
430
  "inheritFormatting",
431
+ "alignment",
432
+ "spacing",
357
433
  "listLevel",
358
434
  "moveId",
359
435
  "pageBreakBefore",
@@ -364,6 +440,8 @@ const FOLIO_DOCUMENT_OPERATION_KEYS_BY_TYPE = Object.freeze({
364
440
  ...COMMON_OPERATION_KEYS,
365
441
  "text",
366
442
  "inheritFormatting",
443
+ "alignment",
444
+ "spacing",
367
445
  "listLevel",
368
446
  "moveId",
369
447
  "pageBreakBefore",
@@ -545,6 +623,16 @@ const parseDocumentOperation = (value, index) => {
545
623
  const styleId = value["styleId"] === null ? null : readOptionalString(value, "styleId", path);
546
624
  const moveId = readOptionalString(value, "moveId", path);
547
625
  const listLevel = readClearableNonNegativeInteger(value, "listLevel", path);
626
+ const alignment = readClearableParagraphAlignment({
627
+ value,
628
+ key: "alignment",
629
+ path
630
+ });
631
+ const spacing = readClearableParagraphSpacing({
632
+ value,
633
+ key: "spacing",
634
+ path
635
+ });
548
636
  return {
549
637
  ...operationMeta,
550
638
  id,
@@ -552,6 +640,8 @@ const parseDocumentOperation = (value, index) => {
552
640
  blockId,
553
641
  text: readString(value, "text", path),
554
642
  ...inheritFormatting !== void 0 && { inheritFormatting },
643
+ ...alignment !== void 0 && { alignment },
644
+ ...spacing !== void 0 && { spacing },
555
645
  ...listLevel !== void 0 && { listLevel },
556
646
  ...moveId !== void 0 && { moveId },
557
647
  ...pageBreakBefore !== void 0 && { pageBreakBefore },
@@ -561,7 +651,7 @@ const parseDocumentOperation = (value, index) => {
561
651
  }
562
652
  if (type === "replaceBlock") {
563
653
  const preserveFormatting = readOptionalBoolean(value, "preserveFormatting", path);
564
- const styleId = readOptionalString(value, "styleId", path);
654
+ const styleId = value["styleId"] === null ? null : readOptionalString(value, "styleId", path);
565
655
  return {
566
656
  ...operationMeta,
567
657
  id,
@@ -735,6 +825,8 @@ const recoveryByReason = {
735
825
  preconditionFailed: "refreshDocument",
736
826
  staleRange: "refreshDocument",
737
827
  emptyOperation: "removeOperation",
828
+ pendingParagraphPropertyChange: "resolveTrackedChange",
829
+ pendingRunPropertyChange: "resolveTrackedChange",
738
830
  noopOperation: "removeOperation",
739
831
  documentVersionMismatch: "refreshDocument",
740
832
  documentNotEditable: "retryLater"
@@ -751,7 +843,7 @@ const getFolioDocumentOperationIssues = (operations, skipped) => {
751
843
  operationIndex,
752
844
  path: `$.operations[${operationIndex}]`,
753
845
  code: reason,
754
- retryable: reason !== "emptyOperation" && reason !== "noopOperation",
846
+ retryable: reason !== "emptyOperation" && reason !== "noopOperation" && reason !== "pendingParagraphPropertyChange" && reason !== "pendingRunPropertyChange",
755
847
  recovery: recoveryByReason[reason]
756
848
  };
757
849
  });
@@ -981,4 +1073,4 @@ const applyFolioDocumentOperations = ({ view, snapshot, batch, story = "main", a
981
1073
  };
982
1074
  };
983
1075
  //#endregion
984
- export { FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_BATCH_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_KEYS_BY_TYPE, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch };
1076
+ export { FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_BATCH_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_KEYS_BY_TYPE, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FOLIO_LINE_SPACING_RULE_VALUES, FOLIO_PARAGRAPH_ALIGNMENT_VALUES, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch };
@@ -9,7 +9,7 @@ import { parseTable } from "./tableParser.js";
9
9
  import { captureVerbatimXml } from "./verbatimCapture.js";
10
10
  import { findChild, getChildElements, getLocalName, mergeXmlnsDeclarations } from "./xmlParser.js";
11
11
  //#region src/docx/blockContentParser.ts
12
- const computeListMarker = (paragraph, { numbering, listCounters, abstractCounters, restartedNumIds, previousList, siblingNumIdsByAbstractNumId }) => {
12
+ const computeListMarker = (paragraph, { numbering, listCounters, abstractCounters, restartedNumIds, previousList }) => {
13
13
  const listRendering = paragraph.listRendering;
14
14
  if (!listRendering || !numbering) {
15
15
  previousList.abstractNumId = null;
@@ -26,26 +26,17 @@ const computeListMarker = (paragraph, { numbering, listCounters, abstractCounter
26
26
  }
27
27
  const firstEncounter = !listCounters.has(numId);
28
28
  if (firstEncounter) listCounters.set(numId, Array.from({ length: 9 }).fill(NaN));
29
- const counters = listCounters.get(numId);
29
+ let counters = listCounters.get(numId);
30
30
  if (!counters) return;
31
31
  const abstractNumId = numbering.getAbstractNumId(numId);
32
- if (firstEncounter && abstractNumId !== null) {
33
- let siblingNumIds = siblingNumIdsByAbstractNumId.get(abstractNumId);
34
- if (!siblingNumIds) {
35
- siblingNumIds = /* @__PURE__ */ new Set();
36
- siblingNumIdsByAbstractNumId.set(abstractNumId, siblingNumIds);
37
- }
38
- siblingNumIds.add(numId);
39
- }
40
32
  const styleNumbering = paragraph.formatting?.numPrFromStyle;
41
- let resumedAbstractCounters;
42
33
  const resumesRestartedInstance = firstEncounter && listRendering.startOverride === void 0 && abstractNumId !== null && previousList.abstractNumId === abstractNumId && previousList.numId !== null && previousList.numId !== numId && restartedNumIds.has(previousList.numId);
43
34
  const resumesStyleInstance = firstEncounter && !styleNumbering && listRendering.startOverride === void 0 && abstractNumId !== null && previousList.abstractNumId === abstractNumId && previousList.fromStyle === true;
44
35
  if (abstractNumId !== null && (styleNumbering || resumesRestartedInstance || resumesStyleInstance)) {
45
36
  const latestAbstractCounters = abstractCounters.get(abstractNumId);
46
37
  if (latestAbstractCounters) {
47
- for (let i = 0; i < counters.length; i += 1) counters[i] = latestAbstractCounters[i] ?? NaN;
48
- resumedAbstractCounters = latestAbstractCounters;
38
+ counters = latestAbstractCounters;
39
+ listCounters.set(numId, counters);
49
40
  }
50
41
  }
51
42
  if (listRendering.startOverride !== void 0 || resumesRestartedInstance || previousList.numId === numId && restartedNumIds.has(numId)) restartedNumIds.add(numId);
@@ -64,17 +55,7 @@ const computeListMarker = (paragraph, { numbering, listCounters, abstractCounter
64
55
  const childCounter = counters[level + 1];
65
56
  counters[level + 1] = (childCounter === void 0 || Number.isNaN(childCounter) ? 0 : childCounter) + childAdvances;
66
57
  }
67
- if (abstractNumId !== null) {
68
- if (resumedAbstractCounters) {
69
- const siblingNumIds = siblingNumIdsByAbstractNumId.get(abstractNumId);
70
- for (const otherNumId of siblingNumIds ?? []) {
71
- const otherCounters = listCounters.get(otherNumId);
72
- if (otherNumId === numId || !otherCounters || !otherCounters.every((value, index) => Object.is(value, resumedAbstractCounters[index]))) continue;
73
- for (let i = 0; i < otherCounters.length; i += 1) otherCounters[i] = counters[i] ?? NaN;
74
- }
75
- }
76
- abstractCounters.set(abstractNumId, [...counters]);
77
- }
58
+ if (abstractNumId !== null) abstractCounters.set(abstractNumId, counters);
78
59
  previousList.abstractNumId = abstractNumId;
79
60
  previousList.fromStyle = Boolean(styleNumbering);
80
61
  previousList.numId = numId;
@@ -108,7 +89,6 @@ const parseBlockContent = (parent, styles, theme, numbering, rels, media, option
108
89
  fromStyle: false,
109
90
  numId: null
110
91
  },
111
- siblingNumIdsByAbstractNumId: /* @__PURE__ */ new Map(),
112
92
  options: {
113
93
  ...options,
114
94
  rootXmlns: mergeXmlnsDeclarations(options?.rootXmlns ?? {}, parent)
@@ -129,8 +109,7 @@ const parseBlockContentWithState = (parent, styles, theme, numbering, rels, medi
129
109
  listCounters: state.listCounters,
130
110
  abstractCounters: state.abstractCounters,
131
111
  restartedNumIds: state.restartedNumIds,
132
- previousList: state.previousList,
133
- siblingNumIdsByAbstractNumId: state.siblingNumIdsByAbstractNumId
112
+ previousList: state.previousList
134
113
  });
135
114
  content.push(paragraph);
136
115
  continue;
@@ -1,4 +1,5 @@
1
1
  import { parseParagraph } from "./paragraphParser.js";
2
+ import { cloneParagraphWithPropertySource } from "./paragraphPropertySource.js";
2
3
  import { parseRunProperties } from "./runParser.js";
3
4
  import { findChild, getAttribute, getChildElements, getLocalName, parseXml } from "./xmlParser.js";
4
5
  //#region src/docx/commentParser.ts
@@ -14,10 +15,7 @@ const normalizeFirstCommentParagraph = (paragraphElement, paragraph, theme) => {
14
15
  const annotationReferenceFormatting = normalizeAnnotationReferenceFormatting(runProperties ? parseRunProperties(runProperties, theme) : void 0);
15
16
  const firstParsedContent = paragraph.content.at(0);
16
17
  return {
17
- paragraph: firstParsedContent?.type === "run" && firstParsedContent.content.length === 0 ? {
18
- ...paragraph,
19
- content: paragraph.content.slice(1)
20
- } : paragraph,
18
+ paragraph: firstParsedContent?.type === "run" && firstParsedContent.content.length === 0 ? cloneParagraphWithPropertySource(paragraph, { content: paragraph.content.slice(1) }) : paragraph,
21
19
  ...annotationReferenceFormatting !== void 0 ? { annotationReferenceFormatting } : {}
22
20
  };
23
21
  };
@@ -1,3 +1,4 @@
1
+ import { cloneParagraphWithPropertySource } from "./paragraphPropertySource.js";
1
2
  //#region src/docx/commentRangeIntegrity.ts
2
3
  const withoutOrphanCommentRanges = (doc) => {
3
4
  const validCommentIds = new Set((doc.package.document.comments ?? []).map((comment) => comment.id));
@@ -176,10 +177,7 @@ const withoutOrphanParagraphMarkers = (paragraph, validCommentIds) => {
176
177
  content.push(item);
177
178
  }
178
179
  if (!changed) return paragraph;
179
- return {
180
- ...paragraph,
181
- content
182
- };
180
+ return cloneParagraphWithPropertySource(paragraph, { content });
183
181
  };
184
182
  const isCommentMarker = (content) => content.type === "commentRangeStart" || content.type === "commentRangeEnd" || content.type === "commentReference";
185
183
  //#endregion
@@ -0,0 +1,2 @@
1
+ import { cloneDocumentWithParagraphPropertySources } from "./paragraphPropertySource.js";
2
+ export { cloneDocumentWithParagraphPropertySources };