@stll/folio-core 0.11.0 → 0.13.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 (263) hide show
  1. package/dist/ai-edits/apply.d.ts +2 -1
  2. package/dist/ai-edits/apply.js +693 -63
  3. package/dist/ai-edits/block-identity.d.ts +4 -0
  4. package/dist/ai-edits/block-identity.js +9 -0
  5. package/dist/ai-edits/blockRange.d.ts +28 -1
  6. package/dist/ai-edits/blockRange.js +68 -2
  7. package/dist/ai-edits/clean-text.js +2 -1
  8. package/dist/ai-edits/headless.d.ts +4 -4
  9. package/dist/ai-edits/headless.js +9 -9
  10. package/dist/ai-edits/index.d.ts +2 -2
  11. package/dist/ai-edits/index.js +2 -2
  12. package/dist/ai-edits/read.d.ts +7 -7
  13. package/dist/ai-edits/read.js +110 -3
  14. package/dist/ai-edits/snapshot.js +21 -3
  15. package/dist/ai-edits/table-cell-mutations.d.ts +48 -0
  16. package/dist/ai-edits/table-cell-mutations.js +238 -0
  17. package/dist/ai-edits/table-mutation-plan.d.ts +38 -0
  18. package/dist/ai-edits/table-mutation-plan.js +90 -0
  19. package/dist/ai-edits/table-row-column-mutations.d.ts +108 -0
  20. package/dist/ai-edits/table-row-column-mutations.js +300 -0
  21. package/dist/ai-edits/table-targets.d.ts +32 -0
  22. package/dist/ai-edits/table-targets.js +70 -0
  23. package/dist/ai-edits/types.d.ts +62 -1
  24. package/dist/ai-edits/word-diff.js +21 -0
  25. package/dist/compat/eigenpal.d.ts +3 -3
  26. package/dist/compat/eigenpal.js +3 -3
  27. package/dist/content-controls/mutateContentControls.js +1 -1
  28. package/dist/controller/activeEditorStory.d.ts +36 -0
  29. package/dist/controller/activeEditorStory.js +30 -0
  30. package/dist/controller/contentControlWidgetController.d.ts +55 -0
  31. package/dist/controller/contentControlWidgetController.js +141 -0
  32. package/dist/controller/fontReadiness.js +2 -0
  33. package/dist/controller/headerFooterEditorManager.js +2 -2
  34. package/dist/controller/hiddenEditorApi.js +2 -2
  35. package/dist/controller/hiddenEditorManager.d.ts +12 -1
  36. package/dist/controller/hiddenEditorManager.js +44 -12
  37. package/dist/controller/layoutPipeline.d.ts +2 -0
  38. package/dist/controller/layoutPipeline.js +17 -2
  39. package/dist/controller/noteEditorManager.d.ts +36 -0
  40. package/dist/controller/noteEditorManager.js +210 -0
  41. package/dist/document-operations.d.ts +43 -11
  42. package/dist/document-operations.js +186 -18
  43. package/dist/docx/blockContentParser.js +21 -7
  44. package/dist/docx/commentParser.js +6 -1
  45. package/dist/docx/commentRangeIntegrity.d.ts +6 -0
  46. package/dist/docx/commentRangeIntegrity.js +186 -0
  47. package/dist/docx/conformance.js +62 -1
  48. package/dist/docx/documentGrid.d.ts +8 -0
  49. package/dist/docx/documentGrid.js +8 -0
  50. package/dist/docx/drawingUtils.js +1 -1
  51. package/dist/docx/encryption/agileDecryption.js +12 -2
  52. package/dist/docx/encryption/compoundFile.js +6 -1
  53. package/dist/docx/encryption/encryptionInfo.d.ts +9 -1
  54. package/dist/docx/encryption/encryptionInfo.js +18 -2
  55. package/dist/docx/encryption/openEncryptedDocx.js +1 -1
  56. package/dist/docx/ensureParaIds.js +8 -7
  57. package/dist/docx/fieldParser.js +1 -1
  58. package/dist/docx/groupDrawingParser.js +10 -5
  59. package/dist/docx/hyperlinkParser.js +1 -1
  60. package/dist/docx/imageParser.js +10 -6
  61. package/dist/docx/metadataPrivacy.js +17 -3
  62. package/dist/docx/notePropertiesParser.js +1 -1
  63. package/dist/docx/numberingParser.js +1 -1
  64. package/dist/docx/paragraphParser.js +70 -61
  65. package/dist/docx/paragraphTextBoxEnrichment.d.ts +2 -1
  66. package/dist/docx/paragraphTextBoxEnrichment.js +67 -13
  67. package/dist/docx/paragraphTraversal.js +1 -1
  68. package/dist/docx/parser.js +3 -3
  69. package/dist/docx/rezip.js +20 -9
  70. package/dist/docx/runParser.js +17 -6
  71. package/dist/docx/sdtProperties.js +1 -1
  72. package/dist/docx/sectionParser.js +18 -5
  73. package/dist/docx/selectiveSave.js +5 -1
  74. package/dist/docx/selectiveXmlPatch.d.ts +22 -1
  75. package/dist/docx/selectiveXmlPatch.js +61 -1
  76. package/dist/docx/serializer/blockSdtSerializer.js +3 -2
  77. package/dist/docx/serializer/commentSerializer.js +5 -6
  78. package/dist/docx/serializer/documentSerializer.js +2 -2
  79. package/dist/docx/serializer/headerFooterSerializer.js +2 -2
  80. package/dist/docx/serializer/noteSerializer.js +2 -2
  81. package/dist/docx/serializer/paragraphSerializer.js +23 -15
  82. package/dist/docx/serializer/runSerializer.js +25 -21
  83. package/dist/docx/serializer/sectionPropertiesSerializer.js +2 -1
  84. package/dist/docx/serializer/stylesSerializer.js +1 -1
  85. package/dist/docx/serializer/tableSerializer.d.ts +5 -4
  86. package/dist/docx/serializer/tableSerializer.js +26 -20
  87. package/dist/docx/serializer/xmlUtils.d.ts +13 -1
  88. package/dist/docx/serializer/xmlUtils.js +27 -1
  89. package/dist/docx/server/applyDocxXmlPatchProposal.d.ts +87 -0
  90. package/dist/docx/server/applyDocxXmlPatchProposal.js +204 -0
  91. package/dist/docx/server/boundedArchive.d.ts +14 -3
  92. package/dist/docx/server/boundedArchive.js +56 -11
  93. package/dist/docx/server/evaluateDocxXmlPatchProposal.d.ts +85 -0
  94. package/dist/docx/server/evaluateDocxXmlPatchProposal.js +361 -0
  95. package/dist/docx/server/extractDocxText.js +55 -8
  96. package/dist/docx/server/inspectDocxPackage.d.ts +70 -0
  97. package/dist/docx/server/inspectDocxPackage.js +217 -0
  98. package/dist/docx/server/validateDocxConformance.d.ts +41 -0
  99. package/dist/docx/server/validateDocxConformance.js +336 -0
  100. package/dist/docx/settingsParser.js +26 -3
  101. package/dist/docx/shapeParser.js +1 -1
  102. package/dist/docx/styleParser.js +4 -2
  103. package/dist/docx/tableParser.d.ts +8 -1
  104. package/dist/docx/tableParser.js +31 -10
  105. package/dist/docx/textBoxParser.d.ts +3 -3
  106. package/dist/docx/textBoxParser.js +16 -12
  107. package/dist/docx/unzip.js +1 -0
  108. package/dist/docx/vmlImageParser.js +11 -3
  109. package/dist/docx/xmlParser.js +11 -1
  110. package/dist/docx/xmlSafety.d.ts +5 -0
  111. package/dist/docx/xmlSafety.js +9 -0
  112. package/dist/fields/resolveFieldValues.js +1 -3
  113. package/dist/fonts/embeddedFonts.d.ts +33 -5
  114. package/dist/fonts/embeddedFonts.js +37 -8
  115. package/dist/i18n/messages/catalogs.gen.d.ts +17 -0
  116. package/dist/i18n/messages/catalogs.gen.js +17 -0
  117. package/dist/i18n/messages/messages.gen.d.ts +1 -0
  118. package/dist/index.d.ts +3 -3
  119. package/dist/index.js +3 -3
  120. package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -0
  121. package/dist/layout-bridge/convert/footnoteLayout.js +47 -40
  122. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
  123. package/dist/layout-bridge/convert/headerFooterLayout.js +3 -0
  124. package/dist/layout-bridge/convert/templatePreviewFlow.js +3 -3
  125. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +4 -2
  126. package/dist/layout-bridge/convert/toFlowBlocks.js +151 -20
  127. package/dist/layout-bridge/dom/noteStoryDom.d.ts +6 -0
  128. package/dist/layout-bridge/dom/noteStoryDom.js +17 -0
  129. package/dist/layout-bridge/engine/clickToPosition.js +2 -2
  130. package/dist/layout-engine/index.d.ts +2 -2
  131. package/dist/layout-engine/index.js +58 -30
  132. package/dist/layout-engine/justificationCompatibility.d.ts +6 -0
  133. package/dist/layout-engine/justificationCompatibility.js +8 -0
  134. package/dist/layout-engine/keep-together.js +11 -1
  135. package/dist/layout-engine/measure/cache.js +23 -5
  136. package/dist/layout-engine/measure/effectiveLineBreakPolicy.js +8 -2
  137. package/dist/layout-engine/measure/lineBreakProvider.d.ts +2 -2
  138. package/dist/layout-engine/measure/lineBreakProvider.js +56 -37
  139. package/dist/layout-engine/measure/measureBlocks.js +15 -4
  140. package/dist/layout-engine/measure/measureContainer.js +1 -1
  141. package/dist/layout-engine/measure/measureHelpers.d.ts +11 -2
  142. package/dist/layout-engine/measure/measureHelpers.js +15 -4
  143. package/dist/layout-engine/measure/measureParagraph.js +85 -25
  144. package/dist/layout-engine/measure/measureProvider.js +4 -3
  145. package/dist/layout-engine/measure/tableCellFlow.js +5 -2
  146. package/dist/layout-engine/measure/textBoxParagraphLayout.d.ts +9 -7
  147. package/dist/layout-engine/measure/textBoxParagraphLayout.js +22 -6
  148. package/dist/layout-engine/measure/textMeasurementPolicy.d.ts +3 -1
  149. package/dist/layout-engine/measure/textMeasurementPolicy.js +7 -1
  150. package/dist/layout-engine/paginator.js +5 -1
  151. package/dist/layout-engine/paragraphSpacing.d.ts +28 -4
  152. package/dist/layout-engine/paragraphSpacing.js +107 -13
  153. package/dist/layout-engine/renderedBreakReconciliation.js +1 -1
  154. package/dist/layout-engine/types.d.ts +48 -15
  155. package/dist/layout-painter/registry/modules/textBox.js +5 -1
  156. package/dist/layout-painter/renderImage.d.ts +12 -1
  157. package/dist/layout-painter/renderImage.js +21 -4
  158. package/dist/layout-painter/renderPage.d.ts +5 -2
  159. package/dist/layout-painter/renderPage.js +59 -14
  160. package/dist/layout-painter/renderParagraph.js +55 -15
  161. package/dist/layout-painter/renderTable.d.ts +5 -1
  162. package/dist/layout-painter/renderTable.js +7 -3
  163. package/dist/layout-painter/renderTextBox.d.ts +2 -1
  164. package/dist/layout-painter/renderTextBox.js +25 -14
  165. package/dist/layout-painter/renderWatermark.d.ts +1 -1
  166. package/dist/layout-painter/renderWatermark.js +2 -1
  167. package/dist/managers/DocumentLoaderManager.js +1 -1
  168. package/dist/markdown/fromMarkdown.js +1 -1
  169. package/dist/model.js +1 -1
  170. package/dist/prosemirror/attrs/index.d.ts +4 -2
  171. package/dist/prosemirror/attrs/index.js +175 -18
  172. package/dist/prosemirror/commands/comments.d.ts +79 -4
  173. package/dist/prosemirror/commands/comments.js +622 -13
  174. package/dist/prosemirror/commands/contentControls.js +1 -1
  175. package/dist/prosemirror/commands/hyperlink.js +15 -1
  176. package/dist/prosemirror/commands/image.js +7 -1
  177. package/dist/prosemirror/commands/index.d.ts +2 -2
  178. package/dist/prosemirror/commands/index.js +2 -2
  179. package/dist/prosemirror/commands/pageBreak.js +1 -1
  180. package/dist/prosemirror/commands/propertyChangeScope.d.ts +2 -2
  181. package/dist/prosemirror/commands/propertyChangeScope.js +3 -2
  182. package/dist/prosemirror/commands/tableCellMergeResolution.d.ts +9 -0
  183. package/dist/prosemirror/commands/tableCellMergeResolution.js +181 -0
  184. package/dist/prosemirror/commentIdAllocator.js +13 -3
  185. package/dist/prosemirror/conversion/fromProseDoc.d.ts +2 -1
  186. package/dist/prosemirror/conversion/fromProseDoc.js +404 -62
  187. package/dist/prosemirror/conversion/index.js +1 -1
  188. package/dist/prosemirror/conversion/sdtAttrs.d.ts +9 -0
  189. package/dist/prosemirror/conversion/sdtAttrs.js +49 -0
  190. package/dist/prosemirror/conversion/toProseDoc.d.ts +2 -1
  191. package/dist/prosemirror/conversion/toProseDoc.js +364 -103
  192. package/dist/prosemirror/extensions/ExtensionManager.js +1 -1
  193. package/dist/prosemirror/extensions/StarterKit.js +6 -1
  194. package/dist/prosemirror/extensions/core/ParagraphExtension.js +6 -2
  195. package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +1 -0
  196. package/dist/prosemirror/extensions/features/ImagePasteExtension.js +10 -2
  197. package/dist/prosemirror/extensions/features/ListExtension.js +1 -1
  198. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +10 -1
  199. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +93 -2
  200. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +2 -1
  201. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +6 -2
  202. package/dist/prosemirror/extensions/features/pasteCleanup.js +15 -2
  203. package/dist/prosemirror/extensions/marks/CharacterSpacingExtension.js +1 -1
  204. package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +30 -4
  205. package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.d.ts +9 -1
  206. package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +70 -11
  207. package/dist/prosemirror/extensions/nodes/FieldExtension.js +1 -1
  208. package/dist/prosemirror/extensions/nodes/RenderedPageBreakExtension.d.ts +7 -0
  209. package/dist/prosemirror/extensions/nodes/RenderedPageBreakExtension.js +22 -0
  210. package/dist/prosemirror/extensions/nodes/TableExtension.d.ts +1 -1
  211. package/dist/prosemirror/extensions/nodes/TableExtension.js +14 -6
  212. package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.d.ts +13 -0
  213. package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.js +41 -0
  214. package/dist/prosemirror/extensions/nodes/TextBoxExtension.d.ts +5 -2
  215. package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +4 -1
  216. package/dist/prosemirror/index.d.ts +1 -1
  217. package/dist/prosemirror/index.js +1 -1
  218. package/dist/prosemirror/plugins/contentControlWidgets.d.ts +36 -10
  219. package/dist/prosemirror/plugins/contentControlWidgets.js +128 -94
  220. package/dist/prosemirror/plugins/revisionIds.d.ts +23 -0
  221. package/dist/prosemirror/plugins/revisionIds.js +57 -0
  222. package/dist/prosemirror/plugins/selectionTracker.js +1 -0
  223. package/dist/prosemirror/plugins/suggestionMode.js +5 -4
  224. package/dist/prosemirror/runFormattingMarkNames.d.ts +14 -0
  225. package/dist/prosemirror/runFormattingMarkNames.js +40 -0
  226. package/dist/prosemirror/schema/index.d.ts +2 -2
  227. package/dist/prosemirror/schema/marks.d.ts +30 -3
  228. package/dist/prosemirror/schema/marks.js +15 -0
  229. package/dist/prosemirror/schema/nodes.d.ts +111 -6
  230. package/dist/prosemirror/selectionState.js +1 -0
  231. package/dist/prosemirror/styles/resolvedStyleAttrs.js +1 -0
  232. package/dist/prosemirror/tableCellMergeRevision.d.ts +9 -0
  233. package/dist/prosemirror/tableCellMergeRevision.js +22 -0
  234. package/dist/prosemirror/textBoxAnchorAttrs.d.ts +9 -0
  235. package/dist/prosemirror/textBoxAnchorAttrs.js +33 -0
  236. package/dist/prosemirror/utils/extractTrackedChanges.d.ts +1 -1
  237. package/dist/prosemirror/utils/extractTrackedChanges.js +62 -14
  238. package/dist/prosemirror/validation.js +9 -1
  239. package/dist/render-dom/RemoteSelectionOverlay.js +2 -2
  240. package/dist/server.d.ts +7 -3
  241. package/dist/server.js +7 -3
  242. package/dist/utils/clipboard.d.ts +10 -1
  243. package/dist/utils/clipboard.js +33 -6
  244. package/dist/utils/colorResolver.d.ts +8 -1
  245. package/dist/utils/colorResolver.js +35 -5
  246. package/dist/utils/fontFamilyMerge.js +9 -11
  247. package/dist/utils/fontLoader.js +3 -2
  248. package/dist/utils/fontResolver.d.ts +2 -1
  249. package/dist/utils/fontResolver.js +31 -7
  250. package/dist/utils/fontWeights.d.ts +1 -1
  251. package/dist/utils/fontWeights.js +1 -1
  252. package/dist/utils/hexId.d.ts +11 -1
  253. package/dist/utils/hexId.js +11 -1
  254. package/dist/utils/paragraphFormattingMerge.js +1 -0
  255. package/dist/utils/sanitizeImageSrc.d.ts +21 -0
  256. package/dist/utils/sanitizeImageSrc.js +30 -0
  257. package/dist/utils/stripXmlDeclarations.d.ts +11 -0
  258. package/dist/utils/stripXmlDeclarations.js +35 -0
  259. package/dist/version-comparison.d.ts +22 -2
  260. package/dist/version-comparison.js +41 -12
  261. package/dist/watermark/index.d.ts +11 -1
  262. package/dist/watermark/index.js +22 -1
  263. package/package.json +3 -2
@@ -1,10 +1,10 @@
1
1
  import { TABLE_CELL_TEXT_DIRECTION_VALUES, TABLE_WIDTH_TYPE_VALUES } from "../../../types/documentEnumValues.js";
2
2
  import { expectTableAttrs, expectTableCellAttrs, expectTableRowAttrs, mergeTableAttrs, mergeTableCellAttrs, mergeTableRowAttrs } from "../../attrs/index.js";
3
3
  import { createExtension, createNodeExtension } from "../create.js";
4
- import { resolveColor } from "../../../utils/colorResolver.js";
4
+ import { isValidHexColor, resolveColor } from "../../../utils/colorResolver.js";
5
5
  import { panic } from "better-result";
6
- import { Plugin, PluginKey, Selection, TextSelection } from "prosemirror-state";
7
6
  import { CellSelection, TableMap, columnResizing, mergeCells, removeRow, selectedRect, splitCell, tableEditing } from "prosemirror-tables";
7
+ import { Plugin, PluginKey, Selection, TextSelection } from "prosemirror-state";
8
8
  import { Decoration, DecorationSet } from "prosemirror-view";
9
9
  //#region src/prosemirror/extensions/nodes/TableExtension.ts
10
10
  /**
@@ -127,7 +127,8 @@ function parseCellAttrsFromDOM(element) {
127
127
  const margins = extractCellMarginsFromCSS(style);
128
128
  const rawValign = element.dataset["valign"];
129
129
  const verticalAlign = (rawValign === "top" || rawValign === "center" || rawValign === "bottom" ? rawValign : void 0) ?? mapCssVerticalAlign(style.verticalAlign) ?? void 0;
130
- const backgroundColor = element.dataset["bgcolor"] || parseCssColorToHex(style.backgroundColor) || void 0;
130
+ const rawBgColor = element.dataset["bgcolor"];
131
+ const backgroundColor = (isValidHexColor(rawBgColor) ? rawBgColor : void 0) || parseCssColorToHex(style.backgroundColor) || void 0;
131
132
  return {
132
133
  colspan: Number(element.getAttribute("colspan") ?? "1") || 1,
133
134
  rowspan: Number(element.getAttribute("rowspan") ?? "1") || 1,
@@ -154,7 +155,8 @@ const tableSpec = {
154
155
  borders: { default: null },
155
156
  _resolvedIndent: { default: null },
156
157
  _originalFormatting: { default: null },
157
- tblPrChange: { default: null }
158
+ tblPrChange: { default: null },
159
+ _suggestedInsert: { default: null }
158
160
  },
159
161
  parseDOM: [{
160
162
  tag: "table",
@@ -190,7 +192,7 @@ const tableSpec = {
190
192
  }
191
193
  };
192
194
  const tableRowSpec = {
193
- content: "(tableCell | tableHeader)+",
195
+ content: "(tableCell | tableHeader)*",
194
196
  tableRole: "row",
195
197
  attrs: {
196
198
  height: { default: null },
@@ -198,7 +200,9 @@ const tableRowSpec = {
198
200
  isHeader: { default: false },
199
201
  hidden: { default: false },
200
202
  _originalFormatting: { default: null },
201
- trPrChange: { default: null }
203
+ trPrChange: { default: null },
204
+ trIns: { default: null },
205
+ trDel: { default: null }
202
206
  },
203
207
  parseDOM: [{ tag: "tr" }],
204
208
  toDOM(node) {
@@ -315,8 +319,10 @@ const tableCellSpec = {
315
319
  margins: { default: null },
316
320
  textDirection: { default: null },
317
321
  noWrap: { default: false },
322
+ hideMark: { default: false },
318
323
  _originalFormatting: { default: null },
319
324
  tcPrChange: { default: null },
325
+ cellMarker: { default: null },
320
326
  _preserveVMergeRestart: { default: null },
321
327
  _docxVMergeContinuationCells: { default: null }
322
328
  },
@@ -369,8 +375,10 @@ const tableHeaderSpec = {
369
375
  margins: { default: null },
370
376
  textDirection: { default: null },
371
377
  noWrap: { default: false },
378
+ hideMark: { default: false },
372
379
  _originalFormatting: { default: null },
373
380
  tcPrChange: { default: null },
381
+ cellMarker: { default: null },
374
382
  _preserveVMergeRestart: { default: null },
375
383
  _docxVMergeContinuationCells: { default: null }
376
384
  },
@@ -0,0 +1,13 @@
1
+ import { NodeExtension } from "../types.js";
2
+
3
+ //#region src/prosemirror/extensions/nodes/TextBoxAnchorExtension.d.ts
4
+ /**
5
+ * Zero-width inline anchor for a text box extracted to a sibling PM block.
6
+ *
7
+ * Keeping the anchor in the paragraph lets ordinary ProseMirror transactions
8
+ * map its position as surrounding text is edited. The save conversion consumes
9
+ * it when the sibling text box is restored to the DOCX run stream.
10
+ */
11
+ declare const TextBoxAnchorExtension: (options?: Partial<Record<string, unknown>> | undefined) => NodeExtension;
12
+ //#endregion
13
+ export { TextBoxAnchorExtension };
@@ -0,0 +1,41 @@
1
+ import { expectTextBoxAnchorAttrs } from "../../textBoxAnchorAttrs.js";
2
+ import { createNodeExtension } from "../create.js";
3
+ //#region src/prosemirror/extensions/nodes/TextBoxAnchorExtension.ts
4
+ /**
5
+ * Zero-width inline anchor for a text box extracted to a sibling PM block.
6
+ *
7
+ * Keeping the anchor in the paragraph lets ordinary ProseMirror transactions
8
+ * map its position as surrounding text is edited. The save conversion consumes
9
+ * it when the sibling text box is restored to the DOCX run stream.
10
+ */
11
+ const TextBoxAnchorExtension = createNodeExtension({
12
+ name: "textBoxAnchor",
13
+ schemaNodeName: "textBoxAnchor",
14
+ nodeSpec: {
15
+ inline: true,
16
+ group: "inline",
17
+ marks: "_",
18
+ atom: true,
19
+ selectable: false,
20
+ attrs: { anchorId: {} },
21
+ parseDOM: [{
22
+ tag: "span[data-docx-textbox-anchor]",
23
+ getAttrs(dom) {
24
+ if (!(dom instanceof HTMLElement)) return false;
25
+ const anchorId = dom.dataset["docxTextboxAnchor"];
26
+ return anchorId ? { anchorId } : false;
27
+ }
28
+ }],
29
+ toDOM(node) {
30
+ const { anchorId } = expectTextBoxAnchorAttrs(node);
31
+ return ["span", {
32
+ "data-docx-textbox-anchor": anchorId,
33
+ "aria-hidden": "true",
34
+ contenteditable: "false",
35
+ style: "display: inline-block; width: 0; height: 0; overflow: hidden; pointer-events: none;"
36
+ }];
37
+ }
38
+ }
39
+ });
40
+ //#endregion
41
+ export { TextBoxAnchorExtension };
@@ -1,7 +1,7 @@
1
1
  import { document_d_exports } from "../../../types/document.js";
2
2
  import { OutlineStyleAttr } from "../../../types/documentEnumValues.js";
3
3
  import { NodeExtension } from "../types.js";
4
- import { ImagePositionAttrs } from "../../schema/nodes.js";
4
+ import { ImagePositionAttrs, TextBoxAttrs as TextBoxAttrs$1 } from "../../schema/nodes.js";
5
5
 
6
6
  //#region src/prosemirror/extensions/nodes/TextBoxExtension.d.ts
7
7
  type TextBoxAttrs = {
@@ -28,7 +28,10 @@ type TextBoxAttrs = {
28
28
  distRight?: number; /** Position for floating/anchored text boxes. */
29
29
  position?: ImagePositionAttrs; /** Original DOCX placement hint for save-path reconstruction. */
30
30
  _docxPlacement?: "standalone" | "inlineWithPrevious"; /** Original DOCX paragraph group for standalone text-box reconstruction. */
31
- _docxGroupId?: string;
31
+ _docxGroupId?: string; /** Inline anchor linking this block node to its source run position. */
32
+ _docxAnchorId?: string; /** Original run-level revision wrapper for save-path reconstruction. */
33
+ _docxTrackedChange?: TextBoxAttrs$1["_docxTrackedChange"]; /** Original inline content-control ancestry for save-path reconstruction. */
34
+ _docxInlineSdts?: TextBoxAttrs$1["_docxInlineSdts"];
32
35
  };
33
36
  declare const TextBoxExtension: (options?: Partial<Record<string, unknown>> | undefined) => NodeExtension;
34
37
  //#endregion
@@ -50,7 +50,10 @@ const TextBoxExtension = createNodeExtension({
50
50
  distRight: { default: null },
51
51
  position: { default: null },
52
52
  _docxPlacement: { default: null },
53
- _docxGroupId: { default: null }
53
+ _docxGroupId: { default: null },
54
+ _docxAnchorId: { default: null },
55
+ _docxTrackedChange: { default: null },
56
+ _docxInlineSdts: { default: null }
54
57
  },
55
58
  parseDOM: [{
56
59
  tag: "div.docx-textbox",
@@ -1,5 +1,5 @@
1
- import { ImageAttrs, ParagraphAttrs } from "./schema/nodes.js";
2
1
  import { FontFamilyAttrs, FontSizeAttrs, HyperlinkAttrs, TextColorAttrs, UnderlineAttrs } from "./schema/marks.js";
2
+ import { ImageAttrs, ParagraphAttrs } from "./schema/nodes.js";
3
3
  import { schema, singletonManager } from "./schema/index.js";
4
4
  import { PAINTABLE_MARK_NAMES, applyFormatMarks, captureFormatMarks } from "./commands/formatPainter.js";
5
5
  import { clearFormatting, getMarkAttr, isMarkActive } from "./extensions/marks/markUtils.js";
@@ -1,5 +1,4 @@
1
1
  import { assertValidProseMirrorDocument, formatProseMirrorDocumentIssues, validateProseMirrorDocument } from "./validation.js";
2
- import { fromProseDoc, updateDocumentContent } from "./conversion/fromProseDoc.js";
3
2
  import { StyleResolver, createStyleResolver } from "./styles/styleResolver.js";
4
3
  import { getParagraphAlignment, getParagraphBidi, getStyleId } from "./extensions/core/ParagraphExtension.js";
5
4
  import { createDocumentStylesPlugin, documentStylesKey, getDocumentStyleResolver } from "./plugins/documentStyles.js";
@@ -11,6 +10,7 @@ import { createSelectionTrackerPlugin, extractSelectionContext, getSelectionCont
11
10
  import { getHyperlinkAttrs, getSelectedText, isHyperlinkActive } from "./extensions/marks/HyperlinkExtension.js";
12
11
  import { schema, singletonManager } from "./schema/index.js";
13
12
  import { createEmptyDoc, toProseDoc } from "./conversion/toProseDoc.js";
13
+ import { fromProseDoc, updateDocumentContent } from "./conversion/fromProseDoc.js";
14
14
  import { addColumnLeft, addColumnRight, addRowAbove, addRowBelow, applyTableStyle, autoFitContents, deleteColumn, deleteRow, deleteTable, distributeColumns, insertTable, mergeCells, removeTableBorders, selectColumn, selectRow, selectTable, setAllTableBorders, setCellBorder, setCellFillColor, setCellMargins, setCellTextDirection, setCellVerticalAlign, setInsideTableBorders, setOutsideTableBorders, setRowHeight, setTableBorderColor, setTableBorderPreset, setTableBorderWidth, setTableBorders, setTableProperties, splitCell, toggleHeaderRow, toggleNoWrap } from "./commands/table.js";
15
15
  import { extractSelectionState } from "./selectionState.js";
16
16
  import { clearFontFamily, clearFontSize, clearHighlight, clearTextColor, insertHyperlink, removeHyperlink, setFontFamily, setFontSize, setHighlight, setHyperlink, setTextColor, toggleBold, toggleItalic, toggleStrike, toggleSubscript, toggleSuperscript, toggleUnderline } from "./commands/formatting.js";
@@ -1,20 +1,26 @@
1
- import { ContentControlLockedError, ContentControlTypeError } from "../../content-controls/errors.js";
1
+ import { ContentControlBoundError, ContentControlLockedError, ContentControlTypeError } from "../../content-controls/errors.js";
2
2
  import { Plugin, PluginKey } from "prosemirror-state";
3
3
  import { EditorView } from "prosemirror-view";
4
4
 
5
5
  //#region src/prosemirror/plugins/contentControlWidgets.d.ts
6
+ type ContentControlWidgetAnchor = {
7
+ getBoundingClientRect: () => {
8
+ bottom: number;
9
+ left: number;
10
+ };
11
+ };
6
12
  type ContentControlWidgetEvent = {
7
13
  kind: "dropdownOpen";
8
14
  tag: string; /** PM position of the clicked SDT instance — disambiguates duplicates. */
9
15
  pmPos: number;
10
16
  sdtType: "dropdown" | "comboBox";
11
- anchor: HTMLElement;
17
+ anchor: ContentControlWidgetAnchor;
12
18
  listItemsJson: string | undefined;
13
19
  } | {
14
20
  kind: "datePick";
15
21
  tag: string;
16
22
  pmPos: number;
17
- anchor: HTMLElement;
23
+ anchor: ContentControlWidgetAnchor;
18
24
  currentValue: string | undefined;
19
25
  } | {
20
26
  /**
@@ -26,21 +32,41 @@ type ContentControlWidgetEvent = {
26
32
  tag: string;
27
33
  pmPos: number;
28
34
  sdtType: string;
29
- anchor: HTMLElement;
30
- error: ContentControlLockedError | ContentControlTypeError;
35
+ anchor: ContentControlWidgetAnchor;
36
+ error: ContentControlLockedError | ContentControlTypeError | ContentControlBoundError;
31
37
  };
32
38
  type ContentControlWidgetCallback = (event: ContentControlWidgetEvent) => void;
39
+ type ContentControlWidgetClickEvent = {
40
+ preventDefault: () => void;
41
+ target: unknown;
42
+ };
43
+ type ContentControlWidgetView = Pick<EditorView, "dispatch" | "state">;
44
+ type HandleContentControlWidgetClickOptions = {
45
+ event: ContentControlWidgetClickEvent;
46
+ onEvent: ContentControlWidgetCallback;
47
+ view: ContentControlWidgetView;
48
+ };
33
49
  declare const contentControlWidgetsPluginKey: PluginKey<unknown>;
34
50
  /**
35
51
  * CustomEvent name dispatched on the editor view DOM whenever the plugin
36
- * needs to surface a `ContentControlWidgetEvent` to the React shell. The
37
- * shell subscribes via `addEventListener` and renders the matching chrome.
52
+ * needs to surface a `ContentControlWidgetEvent` to an adapter shell. The
53
+ * adapter subscribes via `addEventListener` and renders the matching chrome.
38
54
  *
39
- * Using a CustomEvent keeps the plugin from owning a React reference and
40
- * makes the host's responsibility explicit: receive event → render UI →
55
+ * Using a CustomEvent keeps the plugin framework-neutral and makes the
56
+ * adapter's responsibility explicit: receive event → render UI →
41
57
  * call dispatchDropdownPick / dispatchDatePick.
42
58
  */
43
59
  declare const CONTENT_CONTROL_WIDGET_EVENT_NAME = "folio:content-control-widget";
60
+ /**
61
+ * Interpret one click from either the live ProseMirror DOM or the painted page
62
+ * tree. Both surfaces carry the same `data-sdt-*` projection, so adapters only
63
+ * need to forward the click and render the resulting typed event.
64
+ */
65
+ declare const handleContentControlWidgetClick: ({
66
+ event,
67
+ onEvent,
68
+ view
69
+ }: HandleContentControlWidgetClickOptions) => boolean;
44
70
  declare function createContentControlWidgetsPlugin(onEvent?: ContentControlWidgetCallback): Plugin;
45
71
  /**
46
72
  * Stable resolver helpers exposed for the UI shell so a popover menu or
@@ -53,4 +79,4 @@ declare function createContentControlWidgetsPlugin(onEvent?: ContentControlWidge
53
79
  declare function dispatchDropdownPick(view: EditorView, pmPos: number, value: string): boolean;
54
80
  declare function dispatchDatePick(view: EditorView, pmPos: number, date: string): boolean;
55
81
  //#endregion
56
- export { CONTENT_CONTROL_WIDGET_EVENT_NAME, ContentControlWidgetCallback, ContentControlWidgetEvent, contentControlWidgetsPluginKey, createContentControlWidgetsPlugin, dispatchDatePick, dispatchDropdownPick };
82
+ export { CONTENT_CONTROL_WIDGET_EVENT_NAME, ContentControlWidgetAnchor, ContentControlWidgetCallback, ContentControlWidgetEvent, contentControlWidgetsPluginKey, createContentControlWidgetsPlugin, dispatchDatePick, dispatchDropdownPick, handleContentControlWidgetClick };
@@ -1,4 +1,4 @@
1
- import { ContentControlLockedError, ContentControlTypeError } from "../../content-controls/errors.js";
1
+ import { ContentControlBoundError, ContentControlLockedError, ContentControlTypeError } from "../../content-controls/errors.js";
2
2
  import { findBlockSdtMatch, setContentControlValueTr } from "../commands/contentControls.js";
3
3
  import { Plugin, PluginKey } from "prosemirror-state";
4
4
  //#region src/prosemirror/plugins/contentControlWidgets.ts
@@ -19,18 +19,129 @@ import { Plugin, PluginKey } from "prosemirror-state";
19
19
  const contentControlWidgetsPluginKey = new PluginKey("contentControlWidgets");
20
20
  /**
21
21
  * CustomEvent name dispatched on the editor view DOM whenever the plugin
22
- * needs to surface a `ContentControlWidgetEvent` to the React shell. The
23
- * shell subscribes via `addEventListener` and renders the matching chrome.
22
+ * needs to surface a `ContentControlWidgetEvent` to an adapter shell. The
23
+ * adapter subscribes via `addEventListener` and renders the matching chrome.
24
24
  *
25
- * Using a CustomEvent keeps the plugin from owning a React reference and
26
- * makes the host's responsibility explicit: receive event → render UI →
25
+ * Using a CustomEvent keeps the plugin framework-neutral and makes the
26
+ * adapter's responsibility explicit: receive event → render UI →
27
27
  * call dispatchDropdownPick / dispatchDatePick.
28
28
  */
29
29
  const CONTENT_CONTROL_WIDGET_EVENT_NAME = "folio:content-control-widget";
30
- function findSdtAncestor(target) {
31
- if (!(target instanceof Element)) return null;
32
- return target.closest("[data-sdt-type]");
33
- }
30
+ const SDT_DATASET_KEY = {
31
+ checked: "sdtChecked",
32
+ listItems: "sdtListItems",
33
+ pmPos: "sdtPmPos",
34
+ tag: "sdtTag",
35
+ type: "sdtType"
36
+ };
37
+ const SDT_TYPE = {
38
+ checkbox: "checkbox",
39
+ comboBox: "comboBox",
40
+ date: "date",
41
+ dropdown: "dropdown"
42
+ };
43
+ const SDT_TYPE_SELECTOR = "[data-sdt-type]";
44
+ const findClosest = (target, selector) => {
45
+ if (typeof target !== "object" || target === null || !("closest" in target) || typeof target.closest !== "function") return null;
46
+ return target.closest(selector);
47
+ };
48
+ const isContentControlWidgetElement = (value) => {
49
+ if (typeof value !== "object" || value === null || !("dataset" in value) || typeof value.dataset !== "object" || value.dataset === null || !("getBoundingClientRect" in value) || typeof value.getBoundingClientRect !== "function") return false;
50
+ return true;
51
+ };
52
+ const findSdtAncestor = (target) => {
53
+ const candidate = findClosest(target, SDT_TYPE_SELECTOR);
54
+ return isContentControlWidgetElement(candidate) ? candidate : null;
55
+ };
56
+ /**
57
+ * Interpret one click from either the live ProseMirror DOM or the painted page
58
+ * tree. Both surfaces carry the same `data-sdt-*` projection, so adapters only
59
+ * need to forward the click and render the resulting typed event.
60
+ */
61
+ const handleContentControlWidgetClick = ({ event, onEvent, view }) => {
62
+ const anchor = findSdtAncestor(event.target);
63
+ if (!anchor) return false;
64
+ const tag = anchor.dataset[SDT_DATASET_KEY.tag] ?? "";
65
+ const sdtType = anchor.dataset[SDT_DATASET_KEY.type];
66
+ const pmPosRaw = anchor.dataset[SDT_DATASET_KEY.pmPos];
67
+ const pmPos = pmPosRaw ? Number.parseInt(pmPosRaw, 10) : NaN;
68
+ if (!sdtType || Number.isNaN(pmPos)) return false;
69
+ try {
70
+ if (sdtType === SDT_TYPE.checkbox) {
71
+ const current = anchor.dataset[SDT_DATASET_KEY.checked] === "true";
72
+ const tr = setContentControlValueTr(view.state, { pmPos }, {
73
+ kind: SDT_TYPE.checkbox,
74
+ checked: !current
75
+ });
76
+ if (tr) {
77
+ view.dispatch(tr);
78
+ event.preventDefault();
79
+ return true;
80
+ }
81
+ } else if (sdtType === SDT_TYPE.dropdown || sdtType === SDT_TYPE.comboBox) {
82
+ const refusal = lockRefusalFor(view, pmPos);
83
+ if (refusal) {
84
+ onEvent({
85
+ kind: "refused",
86
+ tag,
87
+ pmPos,
88
+ sdtType,
89
+ anchor,
90
+ error: refusal
91
+ });
92
+ event.preventDefault();
93
+ return true;
94
+ }
95
+ onEvent({
96
+ kind: "dropdownOpen",
97
+ tag,
98
+ pmPos,
99
+ sdtType,
100
+ anchor,
101
+ listItemsJson: anchor.dataset[SDT_DATASET_KEY.listItems]
102
+ });
103
+ event.preventDefault();
104
+ return true;
105
+ } else if (sdtType === SDT_TYPE.date) {
106
+ const refusal = lockRefusalFor(view, pmPos);
107
+ if (refusal) {
108
+ onEvent({
109
+ kind: "refused",
110
+ tag,
111
+ pmPos,
112
+ sdtType,
113
+ anchor,
114
+ error: refusal
115
+ });
116
+ event.preventDefault();
117
+ return true;
118
+ }
119
+ onEvent({
120
+ kind: "datePick",
121
+ tag,
122
+ pmPos,
123
+ anchor,
124
+ currentValue: findBlockSdtMatch(view.state.doc, { pmPos })?.node.textContent
125
+ });
126
+ event.preventDefault();
127
+ return true;
128
+ }
129
+ } catch (error) {
130
+ if (error instanceof ContentControlLockedError || error instanceof ContentControlTypeError || error instanceof ContentControlBoundError) {
131
+ onEvent({
132
+ kind: "refused",
133
+ tag,
134
+ pmPos,
135
+ sdtType,
136
+ anchor,
137
+ error
138
+ });
139
+ return true;
140
+ }
141
+ throw error;
142
+ }
143
+ return false;
144
+ };
34
145
  function createContentControlWidgetsPlugin(onEvent = () => void 0) {
35
146
  const emit = (view, payload) => {
36
147
  onEvent(payload);
@@ -42,88 +153,11 @@ function createContentControlWidgetsPlugin(onEvent = () => void 0) {
42
153
  return new Plugin({
43
154
  key: contentControlWidgetsPluginKey,
44
155
  props: { handleDOMEvents: { click(view, event) {
45
- const anchor = findSdtAncestor(event.target);
46
- if (!anchor) return false;
47
- const tag = anchor.dataset["sdtTag"] ?? "";
48
- const sdtType = anchor.dataset["sdtType"];
49
- const pmPosRaw = anchor.dataset["sdtPmPos"];
50
- const pmPos = pmPosRaw ? Number.parseInt(pmPosRaw, 10) : NaN;
51
- if (!sdtType || Number.isNaN(pmPos)) return false;
52
- try {
53
- if (sdtType === "checkbox") {
54
- const current = anchor.dataset["sdtChecked"] === "true";
55
- const tr = setContentControlValueTr(view.state, { pmPos }, {
56
- kind: "checkbox",
57
- checked: !current
58
- });
59
- if (tr) {
60
- view.dispatch(tr);
61
- event.preventDefault();
62
- return true;
63
- }
64
- } else if (sdtType === "dropdown" || sdtType === "comboBox") {
65
- const refusal = lockRefusalFor(view, pmPos);
66
- if (refusal) {
67
- emit(view, {
68
- kind: "refused",
69
- tag,
70
- pmPos,
71
- sdtType,
72
- anchor,
73
- error: refusal
74
- });
75
- event.preventDefault();
76
- return true;
77
- }
78
- emit(view, {
79
- kind: "dropdownOpen",
80
- tag,
81
- pmPos,
82
- sdtType,
83
- anchor,
84
- listItemsJson: anchor.dataset["sdtListItems"]
85
- });
86
- event.preventDefault();
87
- return true;
88
- } else if (sdtType === "date") {
89
- const refusal = lockRefusalFor(view, pmPos);
90
- if (refusal) {
91
- emit(view, {
92
- kind: "refused",
93
- tag,
94
- pmPos,
95
- sdtType,
96
- anchor,
97
- error: refusal
98
- });
99
- event.preventDefault();
100
- return true;
101
- }
102
- emit(view, {
103
- kind: "datePick",
104
- tag,
105
- pmPos,
106
- anchor,
107
- currentValue: void 0
108
- });
109
- event.preventDefault();
110
- return true;
111
- }
112
- } catch (error) {
113
- if (error instanceof ContentControlLockedError || error instanceof ContentControlTypeError) {
114
- emit(view, {
115
- kind: "refused",
116
- tag,
117
- pmPos,
118
- sdtType,
119
- anchor,
120
- error
121
- });
122
- return true;
123
- }
124
- throw error;
125
- }
126
- return false;
156
+ return handleContentControlWidgetClick({
157
+ view,
158
+ event,
159
+ onEvent: (payload) => emit(view, payload)
160
+ });
127
161
  } } },
128
162
  view() {
129
163
  return {};
@@ -149,7 +183,7 @@ function dispatchDropdownPick(view, pmPos, value) {
149
183
  view.dispatch(tr);
150
184
  return true;
151
185
  } catch (error) {
152
- if (error instanceof ContentControlLockedError || error instanceof ContentControlTypeError) return false;
186
+ if (error instanceof ContentControlLockedError || error instanceof ContentControlTypeError || error instanceof ContentControlBoundError) return false;
153
187
  throw error;
154
188
  }
155
189
  }
@@ -163,7 +197,7 @@ function dispatchDatePick(view, pmPos, date) {
163
197
  view.dispatch(tr);
164
198
  return true;
165
199
  } catch (error) {
166
- if (error instanceof ContentControlLockedError || error instanceof ContentControlTypeError) return false;
200
+ if (error instanceof ContentControlLockedError || error instanceof ContentControlTypeError || error instanceof ContentControlBoundError) return false;
167
201
  throw error;
168
202
  }
169
203
  }
@@ -189,4 +223,4 @@ function lockRefusalFor(view, pmPos) {
189
223
  });
190
224
  }
191
225
  //#endregion
192
- export { CONTENT_CONTROL_WIDGET_EVENT_NAME, contentControlWidgetsPluginKey, createContentControlWidgetsPlugin, dispatchDatePick, dispatchDropdownPick };
226
+ export { CONTENT_CONTROL_WIDGET_EVENT_NAME, contentControlWidgetsPluginKey, createContentControlWidgetsPlugin, dispatchDatePick, dispatchDropdownPick, handleContentControlWidgetClick };
@@ -0,0 +1,23 @@
1
+ import { Node } from "prosemirror-model";
2
+
3
+ //#region src/prosemirror/plugins/revisionIds.d.ts
4
+ /**
5
+ * Mint the next tracked-revision id (`w:id`). Strictly monotonic per realm,
6
+ * and always inside the range serialized `w:id` may occupy.
7
+ */
8
+ declare function mintRevisionId(): number;
9
+ /**
10
+ * Raise the counter above `maxId` so freshly minted ids cannot collide with
11
+ * ids already present in a loaded document. Only ever raises.
12
+ *
13
+ * `maxId` is derived from file content, so it is untrusted: a malformed or
14
+ * out-of-range value is ignored outright rather than folded into range.
15
+ */
16
+ declare function seedRevisionIdsAbove(maxId: number): void;
17
+ /**
18
+ * Raise the counter above every revision id already present in `doc`.
19
+ * Called from the suggestion-mode plugin's `state.init`.
20
+ */
21
+ declare function seedRevisionIdsFromDoc(doc: Node): void;
22
+ //#endregion
23
+ export { mintRevisionId, seedRevisionIdsAbove, seedRevisionIdsFromDoc };
@@ -0,0 +1,57 @@
1
+ import { MAX_REVISION_ID } from "@stll/docx-core/model";
2
+ //#region src/prosemirror/plugins/revisionIds.ts
3
+ /**
4
+ * Next id to hand out. Starts at 1 (0 is the serializer's "unusable metadata"
5
+ * fallback) and is raised past a loaded document's existing ids by
6
+ * `seedRevisionIdsAbove`.
7
+ *
8
+ * NOT seeded from a clock. `Date.now()` (~1.8e12) overflows the signed 32-bit
9
+ * int consumers read `w:id` into.
10
+ */
11
+ let counter = 1;
12
+ /**
13
+ * Mint the next tracked-revision id (`w:id`). Strictly monotonic per realm,
14
+ * and always inside the range serialized `w:id` may occupy.
15
+ */
16
+ function mintRevisionId() {
17
+ if (counter > MAX_REVISION_ID) counter = 1;
18
+ return counter++;
19
+ }
20
+ /**
21
+ * Raise the counter above `maxId` so freshly minted ids cannot collide with
22
+ * ids already present in a loaded document. Only ever raises.
23
+ *
24
+ * `maxId` is derived from file content, so it is untrusted: a malformed or
25
+ * out-of-range value is ignored outright rather than folded into range.
26
+ */
27
+ function seedRevisionIdsAbove(maxId) {
28
+ if (!Number.isInteger(maxId) || maxId < 0 || maxId >= MAX_REVISION_ID) return;
29
+ if (maxId >= counter) counter = maxId + 1;
30
+ }
31
+ /** Node attrs that carry a revision id directly (`revisionId` field). */
32
+ const DIRECT_REVISION_ATTR_KEYS = ["trIns", "trDel"];
33
+ /**
34
+ * Raise the counter above every revision id already present in `doc`.
35
+ * Called from the suggestion-mode plugin's `state.init`.
36
+ */
37
+ function seedRevisionIdsFromDoc(doc) {
38
+ let max = 0;
39
+ const consider = (id) => {
40
+ if (typeof id === "number" && Number.isInteger(id) && id > max && id <= MAX_REVISION_ID) max = id;
41
+ };
42
+ doc.descendants((node) => {
43
+ for (const mark of node.marks) consider(mark.attrs["revisionId"]);
44
+ const attrs = node.attrs;
45
+ const pPrMark = attrs["pPrMark"];
46
+ if (pPrMark?.info) consider(pPrMark.info.id);
47
+ for (const key of DIRECT_REVISION_ATTR_KEYS) {
48
+ const value = attrs[key];
49
+ if (value) consider(value.revisionId);
50
+ }
51
+ const cellMarker = attrs["cellMarker"];
52
+ if (cellMarker?.info) consider(cellMarker.info.revisionId);
53
+ });
54
+ seedRevisionIdsAbove(max);
55
+ }
56
+ //#endregion
57
+ export { mintRevisionId, seedRevisionIdsAbove, seedRevisionIdsFromDoc };
@@ -36,6 +36,7 @@ function extractSelectionContext(state) {
36
36
  paragraphFormatting.lineSpacing = paragraph.attrs["lineSpacing"];
37
37
  paragraphFormatting.lineSpacingRule = paragraph.attrs["lineSpacingRule"];
38
38
  }
39
+ if (typeof paragraph.attrs["snapToGrid"] === "boolean") paragraphFormatting.snapToGrid = paragraph.attrs["snapToGrid"];
39
40
  if (paragraph.attrs["indentLeft"]) paragraphFormatting.indentLeft = paragraph.attrs["indentLeft"];
40
41
  if (paragraph.attrs["indentRight"]) paragraphFormatting.indentRight = paragraph.attrs["indentRight"];
41
42
  if (paragraph.attrs["indentFirstLine"]) paragraphFormatting.indentFirstLine = paragraph.attrs["indentFirstLine"];
@@ -1,6 +1,7 @@
1
1
  import { splitBlockClearBorders } from "../extensions/features/BaseKeymapExtension.js";
2
- import { Plugin, PluginKey, TextSelection } from "prosemirror-state";
2
+ import { mintRevisionId, seedRevisionIdsFromDoc } from "./revisionIds.js";
3
3
  import { isHistoryTransaction } from "prosemirror-history";
4
+ import { Plugin, PluginKey, TextSelection } from "prosemirror-state";
4
5
  //#region src/prosemirror/plugins/suggestionMode.ts
5
6
  /**
6
7
  * Suggestion Mode Plugin
@@ -17,10 +18,9 @@ import { isHistoryTransaction } from "prosemirror-history";
17
18
  const suggestionModeKey = new PluginKey("suggestionMode");
18
19
  const SUGGESTION_META = "suggestionModeApplied";
19
20
  const SUGGESTION_BYPASS_META = "suggestionModeBypass";
20
- let nextRevisionId = Date.now();
21
21
  function makeMarkAttrs(pluginState) {
22
22
  return {
23
- revisionId: nextRevisionId++,
23
+ revisionId: mintRevisionId(),
24
24
  author: pluginState.author,
25
25
  date: (/* @__PURE__ */ new Date()).toISOString()
26
26
  };
@@ -340,7 +340,8 @@ function createSuggestionModePlugin(initialActive = false, author = "User") {
340
340
  return new Plugin({
341
341
  key: suggestionModeKey,
342
342
  state: {
343
- init() {
343
+ init(_config, instance) {
344
+ seedRevisionIdsFromDoc(instance.doc);
344
345
  return {
345
346
  active: initialActive,
346
347
  author
@@ -0,0 +1,14 @@
1
+ //#region src/prosemirror/runFormattingMarkNames.d.ts
2
+ /**
3
+ * Names of the marks that carry run-level (character) formatting.
4
+ *
5
+ * Single source of truth shared by every place that must swap a run's live
6
+ * formatting back to a previously recorded set: rejecting a `runPropertyChange`
7
+ * (commands/comments.ts) and stripping a *suggested* `runPropertyChange` at the
8
+ * serialization boundary (conversion/fromProseDoc.ts). Keeping one list makes
9
+ * it structurally impossible for the two paths to drift and let a formatting
10
+ * mark survive a revert.
11
+ */
12
+ declare const RUN_FORMATTING_MARK_NAMES: Set<string>;
13
+ //#endregion
14
+ export { RUN_FORMATTING_MARK_NAMES };