@stll/folio-core 0.52.0 → 0.53.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 (307) hide show
  1. package/README.md +23 -0
  2. package/dist/ai-edits/apply.d.ts +26 -1
  3. package/dist/ai-edits/apply.js +1519 -105
  4. package/dist/ai-edits/batch-claims.d.ts +130 -0
  5. package/dist/ai-edits/batch-claims.js +244 -0
  6. package/dist/ai-edits/blockRange.js +9 -3
  7. package/dist/ai-edits/character-boundaries.d.ts +43 -0
  8. package/dist/ai-edits/character-boundaries.js +95 -0
  9. package/dist/ai-edits/clean-text.d.ts +33 -3
  10. package/dist/ai-edits/clean-text.js +52 -6
  11. package/dist/ai-edits/comment-lifecycle.d.ts +18 -0
  12. package/dist/ai-edits/comment-lifecycle.js +52 -0
  13. package/dist/ai-edits/headless.d.ts +71 -7
  14. package/dist/ai-edits/headless.js +381 -41
  15. package/dist/ai-edits/index.d.ts +2 -1
  16. package/dist/ai-edits/index.js +2 -1
  17. package/dist/ai-edits/minimal-replacement.d.ts +21 -6
  18. package/dist/ai-edits/minimal-replacement.js +134 -15
  19. package/dist/ai-edits/newListNumbering.d.ts +23 -0
  20. package/dist/ai-edits/newListNumbering.js +94 -0
  21. package/dist/ai-edits/note-references.d.ts +96 -0
  22. package/dist/ai-edits/note-references.js +139 -0
  23. package/dist/ai-edits/pending-suggestions.d.ts +79 -0
  24. package/dist/ai-edits/pending-suggestions.js +306 -0
  25. package/dist/ai-edits/read.d.ts +1 -1
  26. package/dist/ai-edits/read.js +56 -43
  27. package/dist/ai-edits/result-validation.d.ts +29 -0
  28. package/dist/ai-edits/result-validation.js +164 -0
  29. package/dist/ai-edits/snapshot.d.ts +36 -3
  30. package/dist/ai-edits/snapshot.js +177 -23
  31. package/dist/ai-edits/table-cell-mutations.d.ts +1 -1
  32. package/dist/ai-edits/table-cell-mutations.js +4 -1
  33. package/dist/ai-edits/table-geometry.d.ts +1 -1
  34. package/dist/ai-edits/table-row-column-mutations.d.ts +38 -16
  35. package/dist/ai-edits/table-row-column-mutations.js +61 -26
  36. package/dist/ai-edits/types.d.ts +155 -16
  37. package/dist/compare/compare.d.ts +1 -1
  38. package/dist/compare/compare.js +65 -16
  39. package/dist/compare/content-alignment.js +13 -2
  40. package/dist/compare/content-types.d.ts +7 -0
  41. package/dist/compare/content.d.ts +4 -1
  42. package/dist/compare/content.js +6 -1
  43. package/dist/compare/formatting.js +2 -1
  44. package/dist/compare/inline-atoms.d.ts +21 -4
  45. package/dist/compare/inline-atoms.js +138 -16
  46. package/dist/compare/plan.js +10 -5
  47. package/dist/compare/scenario.js +14 -3
  48. package/dist/compare/section-boundary-properties.js +1 -1
  49. package/dist/compare/types.d.ts +4 -2
  50. package/dist/compare/types.js +2 -1
  51. package/dist/compare/verification.d.ts +1 -1
  52. package/dist/compare/verification.js +15 -3
  53. package/dist/controller/committedLayoutDiff.d.ts +25 -0
  54. package/dist/controller/committedLayoutDiff.js +71 -0
  55. package/dist/controller/contentControlWidgetController.d.ts +1 -1
  56. package/dist/controller/folioEditor.d.ts +1 -1
  57. package/dist/controller/fontReadiness.d.ts +70 -3
  58. package/dist/controller/fontReadiness.js +100 -10
  59. package/dist/controller/headerFooterEditorManager.js +6 -1
  60. package/dist/controller/layoutPipeline.d.ts +12 -10
  61. package/dist/controller/layoutPipeline.js +62 -9
  62. package/dist/controller/layoutRunOptions.d.ts +24 -0
  63. package/dist/controller/layoutRunOptions.js +17 -0
  64. package/dist/controller/layoutScheduler.d.ts +19 -14
  65. package/dist/controller/layoutScheduler.js +15 -12
  66. package/dist/controller/layoutSession.d.ts +26 -2
  67. package/dist/controller/layoutSession.js +1 -1
  68. package/dist/controller/noteEditorManager.js +8 -3
  69. package/dist/document-operations.d.ts +11 -2
  70. package/dist/document-operations.js +230 -21
  71. package/dist/docx/altChunk.d.ts +8 -0
  72. package/dist/docx/altChunk.js +17 -0
  73. package/dist/docx/attributeRemainder.d.ts +1 -1
  74. package/dist/docx/blockContentParser.d.ts +64 -1
  75. package/dist/docx/blockContentParser.js +17 -4
  76. package/dist/docx/blockCustomXmlShell.d.ts +7 -0
  77. package/dist/docx/blockCustomXmlShell.js +14 -0
  78. package/dist/docx/blockPlainText.js +7 -0
  79. package/dist/docx/commentAnchorIndex.js +1 -1
  80. package/dist/docx/commentRangeIntegrity.js +8 -3
  81. package/dist/docx/commentReferenceNormalization.js +1 -1
  82. package/dist/docx/commentReplyMarkers.js +20 -1
  83. package/dist/docx/compatibility.d.ts +1 -1
  84. package/dist/docx/compatibility.js +34 -13
  85. package/dist/docx/containerChildren.gen.d.ts +1 -1
  86. package/dist/docx/containerChildren.gen.js +1 -0
  87. package/dist/docx/documentParser.js +12 -12
  88. package/dist/docx/drawingIdNormalization.d.ts +3 -1
  89. package/dist/docx/drawingIdNormalization.js +6 -1
  90. package/dist/docx/ensureParaIds.js +119 -97
  91. package/dist/docx/footnoteParser.js +8 -4
  92. package/dist/docx/headerFooterParser.js +3 -3
  93. package/dist/docx/headerFooterReferenceNormalization.d.ts +20 -1
  94. package/dist/docx/headerFooterReferenceNormalization.js +52 -27
  95. package/dist/docx/hyperlinkParser.d.ts +1 -1
  96. package/dist/docx/index.d.ts +1 -1
  97. package/dist/docx/listNumberingInstances.d.ts +59 -0
  98. package/dist/docx/listNumberingInstances.js +249 -0
  99. package/dist/docx/normalizeBaseDirection.js +2 -1
  100. package/dist/docx/opaqueCarrier.d.ts +7 -0
  101. package/dist/docx/opaqueCarrier.js +38 -0
  102. package/dist/docx/packageParts.js +4 -1
  103. package/dist/docx/paragraphParser.js +91 -24
  104. package/dist/docx/paragraphPropertySource.d.ts +4 -2
  105. package/dist/docx/paragraphPropertySource.js +7 -1
  106. package/dist/docx/paragraphTraversal.js +1 -0
  107. package/dist/docx/parseWarningMessage.js +4 -1
  108. package/dist/docx/parser.js +173 -20
  109. package/dist/docx/rezip.js +27 -5
  110. package/dist/docx/sdtProperties.js +1 -1
  111. package/dist/docx/sdtPropertiesPatch.js +3 -0
  112. package/dist/docx/selectiveSave.js +16 -9
  113. package/dist/docx/selectiveXmlPatch.js +106 -37
  114. package/dist/docx/serializer/blockCustomXmlSerializer.d.ts +5 -0
  115. package/dist/docx/serializer/blockCustomXmlSerializer.js +4 -0
  116. package/dist/docx/serializer/documentSerializer.js +2 -0
  117. package/dist/docx/serializer/headerFooterSerializer.js +2 -0
  118. package/dist/docx/serializer/noteSerializer.js +3 -1
  119. package/dist/docx/serializer/paragraphSerializer.js +33 -9
  120. package/dist/docx/serializer/tableSerializer.js +25 -38
  121. package/dist/docx/server/createBilingualDocument.js +3 -3
  122. package/dist/docx/tableParser.d.ts +157 -1
  123. package/dist/docx/tableParser.js +89 -10
  124. package/dist/docx/textBoxParser.js +1 -1
  125. package/dist/docx/unzip.d.ts +2 -1
  126. package/dist/docx/unzip.js +1 -1
  127. package/dist/docx/wordprocessingPrefixes.d.ts +78 -0
  128. package/dist/docx/wordprocessingPrefixes.js +286 -0
  129. package/dist/i18n/messages/catalogs.gen.d.ts +136 -0
  130. package/dist/i18n/messages/catalogs.gen.js +153 -17
  131. package/dist/i18n/messages/messages.gen.d.ts +8 -0
  132. package/dist/internal/compare/inline-presentation.d.ts +2 -1
  133. package/dist/internal/compare/inline-presentation.js +11 -10
  134. package/dist/internal/headlessRevisionResolutionGuard.d.ts +2 -8
  135. package/dist/internal/headlessRevisionResolutionGuard.js +2 -11
  136. package/dist/internal/indexedPositionMap.d.ts +11 -0
  137. package/dist/internal/indexedPositionMap.js +42 -0
  138. package/dist/internal/pageBreakRunSourceDescendantIndex.js +2 -1
  139. package/dist/internal/revisionResolutionEdits.d.ts +13 -0
  140. package/dist/internal/revisionResolutionEdits.js +19 -0
  141. package/dist/internal/revisionResolutionInline.d.ts +24 -0
  142. package/dist/internal/{headlessRevisionResolution.js → revisionResolutionInline.js} +61 -43
  143. package/dist/internal/revisionResolutionStep.d.ts +34 -0
  144. package/dist/internal/revisionResolutionStep.js +282 -0
  145. package/dist/internal/revisionResolutionTracking.d.ts +11 -0
  146. package/dist/internal/revisionResolutionTracking.js +124 -0
  147. package/dist/internal/wholeStoryRevisionResolution.d.ts +56 -0
  148. package/dist/internal/wholeStoryRevisionResolution.js +530 -0
  149. package/dist/layout-bridge/convert/markupViewFlow.d.ts +20 -0
  150. package/dist/layout-bridge/convert/markupViewFlow.js +123 -0
  151. package/dist/layout-bridge/convert/tableConversion.js +1 -1
  152. package/dist/layout-bridge/convert/toFlowBlocks.js +10 -1
  153. package/dist/layout-engine/layoutInstrumentation.d.ts +9 -1
  154. package/dist/layout-engine/layoutInstrumentation.js +4 -1
  155. package/dist/layout-engine/measure/cache.d.ts +18 -1
  156. package/dist/layout-engine/measure/cache.js +31 -1
  157. package/dist/layout-engine/measure/font-metrics.worker.js +3 -7
  158. package/dist/layout-engine/measure/measureContainer.js +7 -47
  159. package/dist/layout-engine/measure/measureHelpers.d.ts +6 -1
  160. package/dist/layout-engine/measure/measureHelpers.js +22 -2
  161. package/dist/layout-engine/measure/measureWorker.js +2 -3
  162. package/dist/layout-engine/measure/measureWorkerProtocol.d.ts +6 -7
  163. package/dist/layout-engine/measure/measureWorkerProtocol.js +1 -2
  164. package/dist/layout-engine/types.d.ts +6 -0
  165. package/dist/layout-painter/renderPage.js +1 -0
  166. package/dist/layout-painter/renderParagraph.js +1 -1
  167. package/dist/managers/ContextMenuManager.js +5 -2
  168. package/dist/managers/types.d.ts +3 -0
  169. package/dist/markdown/fromMarkdown.js +2 -1
  170. package/dist/markdown/internals.d.ts +11 -1
  171. package/dist/markdown/internals.js +24 -3
  172. package/dist/markdown/renderBlock.js +39 -9
  173. package/dist/markdown/renderParagraph.d.ts +13 -1
  174. package/dist/markdown/renderParagraph.js +85 -38
  175. package/dist/markdown/renderRuns.js +3 -10
  176. package/dist/markdown/renderTable.js +24 -12
  177. package/dist/markdown/trailers.js +2 -2
  178. package/dist/markdown/types.d.ts +29 -7
  179. package/dist/paged-layout/incrementalMeasure.d.ts +1 -2
  180. package/dist/paged-layout/incrementalMeasure.js +1 -9
  181. package/dist/paged-layout/transactionDirtyRange.d.ts +1 -3
  182. package/dist/paged-layout/transactionDirtyRange.js +29 -41
  183. package/dist/panel-layout.d.ts +83 -0
  184. package/dist/panel-layout.js +96 -0
  185. package/dist/prosemirror/anchoredTextBoxes.d.ts +37 -0
  186. package/dist/prosemirror/anchoredTextBoxes.js +156 -0
  187. package/dist/prosemirror/attrs/index.d.ts +6 -2
  188. package/dist/prosemirror/attrs/index.js +172 -1
  189. package/dist/prosemirror/commands/comments.d.ts +7 -8
  190. package/dist/prosemirror/commands/comments.js +241 -207
  191. package/dist/prosemirror/commands/contentControls.d.ts +1 -1
  192. package/dist/prosemirror/commands/formatPainter.d.ts +1 -1
  193. package/dist/prosemirror/commands/formatting.d.ts +1 -1
  194. package/dist/prosemirror/commands/index.d.ts +2 -2
  195. package/dist/prosemirror/commands/index.js +2 -2
  196. package/dist/prosemirror/commands/paragraph.d.ts +7 -1
  197. package/dist/prosemirror/commands/paragraph.js +9 -1
  198. package/dist/prosemirror/commands/paragraphBookmarkJoin.d.ts +13 -0
  199. package/dist/prosemirror/commands/paragraphBookmarkJoin.js +22 -0
  200. package/dist/prosemirror/commands/pastePlainText.d.ts +1 -1
  201. package/dist/prosemirror/commands/resolveAllTableChanges.d.ts +40 -0
  202. package/dist/prosemirror/commands/resolveAllTableChanges.js +615 -0
  203. package/dist/prosemirror/commands/resolveNodePropertyChangeAttrs.d.ts +15 -0
  204. package/dist/prosemirror/commands/resolveNodePropertyChangeAttrs.js +46 -0
  205. package/dist/prosemirror/commands/resolveParagraphProperties.d.ts +16 -0
  206. package/dist/prosemirror/commands/resolveParagraphProperties.js +59 -0
  207. package/dist/prosemirror/commands/sectionBreak.js +2 -1
  208. package/dist/prosemirror/commands/tableCellMergeResolution.d.ts +8 -2
  209. package/dist/prosemirror/commands/tableCellMergeResolution.js +1 -1
  210. package/dist/prosemirror/contentControlRevisions.d.ts +1 -1
  211. package/dist/prosemirror/conversion/fromProseDoc.js +181 -31
  212. package/dist/prosemirror/conversion/toProseDoc.js +39 -4
  213. package/dist/prosemirror/emptyFieldResultRuns.d.ts +18 -0
  214. package/dist/prosemirror/emptyFieldResultRuns.js +33 -0
  215. package/dist/prosemirror/extensions/ExtensionManager.d.ts +1 -1
  216. package/dist/prosemirror/extensions/ExtensionManager.js +3 -1
  217. package/dist/prosemirror/extensions/StarterKit.js +3 -1
  218. package/dist/prosemirror/extensions/core/DocExtension.js +1 -1
  219. package/dist/prosemirror/extensions/core/ParagraphExtension.js +12 -0
  220. package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +3 -0
  221. package/dist/prosemirror/extensions/features/ListExtension.js +161 -123
  222. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +19 -2
  223. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +33 -20
  224. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +31 -2
  225. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +270 -99
  226. package/dist/prosemirror/extensions/features/PasteCleanupExtension.js +3 -2
  227. package/dist/prosemirror/extensions/features/pasteCleanup.js +2 -1
  228. package/dist/prosemirror/extensions/features/pastedHtmlLists.d.ts +12 -0
  229. package/dist/prosemirror/extensions/features/pastedHtmlLists.js +126 -0
  230. package/dist/prosemirror/extensions/marks/FootnoteRefExtension.js +21 -5
  231. package/dist/prosemirror/extensions/marks/RunIdentityExtension.d.ts +21 -18
  232. package/dist/prosemirror/extensions/marks/RunIdentityExtension.js +37 -17
  233. package/dist/prosemirror/extensions/marks/markUtils.d.ts +7 -2
  234. package/dist/prosemirror/extensions/marks/markUtils.js +8 -2
  235. package/dist/prosemirror/extensions/marks/noteReferenceDeletion.d.ts +10 -0
  236. package/dist/prosemirror/extensions/marks/noteReferenceDeletion.js +35 -0
  237. package/dist/prosemirror/extensions/nodes/BlockCustomXmlExtension.d.ts +6 -0
  238. package/dist/prosemirror/extensions/nodes/BlockCustomXmlExtension.js +52 -0
  239. package/dist/prosemirror/extensions/nodes/FieldExtension.d.ts +3 -3
  240. package/dist/prosemirror/extensions/nodes/FieldExtension.js +50 -15
  241. package/dist/prosemirror/extensions/nodes/PreservedBlockExtension.js +4 -1
  242. package/dist/prosemirror/extensions/nodes/TableExtension.d.ts +1 -1
  243. package/dist/prosemirror/extensions/nodes/TableExtension.js +19 -18
  244. package/dist/prosemirror/extensions/types.d.ts +4 -1
  245. package/dist/prosemirror/findReplaceSelection.js +1 -1
  246. package/dist/prosemirror/index.d.ts +3 -2
  247. package/dist/prosemirror/index.js +3 -2
  248. package/dist/prosemirror/indexedNodeLookup.d.ts +17 -0
  249. package/dist/prosemirror/indexedNodeLookup.js +103 -0
  250. package/dist/prosemirror/listAutoformatMarkers.d.ts +19 -0
  251. package/dist/prosemirror/listAutoformatMarkers.js +98 -0
  252. package/dist/prosemirror/listInstanceReferences.d.ts +12 -0
  253. package/dist/prosemirror/listInstanceReferences.js +72 -0
  254. package/dist/prosemirror/listLabels.d.ts +24 -0
  255. package/dist/prosemirror/listLabels.js +111 -0
  256. package/dist/prosemirror/listNumbering.d.ts +110 -0
  257. package/dist/prosemirror/listNumbering.js +345 -0
  258. package/dist/prosemirror/listRenderingAttrs.d.ts +11 -2
  259. package/dist/prosemirror/listRenderingAttrs.js +8 -1
  260. package/dist/prosemirror/markupViewProjection.d.ts +95 -0
  261. package/dist/prosemirror/markupViewProjection.js +83 -0
  262. package/dist/prosemirror/numberingAttr.d.ts +9 -1
  263. package/dist/prosemirror/numberingAttr.js +9 -1
  264. package/dist/prosemirror/outlineLevelAttr.js +1 -1
  265. package/dist/prosemirror/paragraphIndentation.d.ts +10 -1
  266. package/dist/prosemirror/paragraphIndentation.js +29 -7
  267. package/dist/prosemirror/paragraphMarkJoin.d.ts +19 -0
  268. package/dist/prosemirror/paragraphMarkJoin.js +24 -0
  269. package/dist/prosemirror/plugins/createDocScanPlugin.d.ts +1 -1
  270. package/dist/prosemirror/plugins/documentNumbering.d.ts +27 -1
  271. package/dist/prosemirror/plugins/documentNumbering.js +97 -11
  272. package/dist/prosemirror/plugins/documentStyles.d.ts +10 -1
  273. package/dist/prosemirror/plugins/documentStyles.js +14 -1
  274. package/dist/prosemirror/plugins/suggestionMode.d.ts +16 -2
  275. package/dist/prosemirror/plugins/suggestionMode.js +116 -52
  276. package/dist/prosemirror/plugins/templateDirectives.d.ts +1 -1
  277. package/dist/prosemirror/plugins/transactionInvariants.d.ts +32 -0
  278. package/dist/prosemirror/plugins/transactionInvariants.js +86 -0
  279. package/dist/prosemirror/positionSweep.d.ts +24 -0
  280. package/dist/prosemirror/positionSweep.js +222 -0
  281. package/dist/prosemirror/rebaseParagraphRunFormatting.d.ts +1 -1
  282. package/dist/prosemirror/rejoinRunCarriers.d.ts +1 -1
  283. package/dist/prosemirror/replacedAnnotations.d.ts +33 -1
  284. package/dist/prosemirror/replacedAnnotations.js +170 -1
  285. package/dist/prosemirror/runFormattingInlineCarriers.d.ts +1 -1
  286. package/dist/prosemirror/schema/index.d.ts +2 -2
  287. package/dist/prosemirror/schema/index.js +3 -0
  288. package/dist/prosemirror/schema/nodes.d.ts +42 -11
  289. package/dist/prosemirror/sectionMarkEdits.d.ts +20 -0
  290. package/dist/prosemirror/sectionMarkEdits.js +59 -0
  291. package/dist/prosemirror/storyListNumbering.d.ts +17 -0
  292. package/dist/prosemirror/storyListNumbering.js +102 -0
  293. package/dist/prosemirror/tableGridMutation.d.ts +48 -2
  294. package/dist/prosemirror/tableGridMutation.js +106 -1
  295. package/dist/prosemirror/validation.js +5 -1
  296. package/dist/redline.js +93 -9
  297. package/dist/render-dom/BodySelectionOverlay.d.ts +4 -1
  298. package/dist/render-dom/BodySelectionOverlay.js +3 -2
  299. package/dist/utils/findReplace.js +2 -2
  300. package/dist/utils/mergeDocumentContent.js +1 -1
  301. package/dist/utils/noteReferenceLabels.d.ts +36 -0
  302. package/dist/utils/noteReferenceLabels.js +32 -0
  303. package/dist/utils/replaceText.js +1 -1
  304. package/dist/version-comparison.d.ts +1 -0
  305. package/dist/version-comparison.js +1 -0
  306. package/package.json +3 -2
  307. package/dist/internal/headlessRevisionResolution.d.ts +0 -23
@@ -6,5 +6,17 @@ import { RenderContext } from "./types.js";
6
6
  * caller joins blocks.
7
7
  */
8
8
  declare function renderParagraph(ctx: RenderContext, pkg: document_d_exports.DocxPackage | undefined, para: document_d_exports.Paragraph): string;
9
+ /** A rendered paragraph, and whether it is a Markdown list item. */
10
+ type RenderedParagraph = {
11
+ markdown: string;
12
+ isListItem: boolean;
13
+ };
14
+ /**
15
+ * Render a paragraph. A list item is a paragraph that shows a marker, which is
16
+ * when the list counter gives it a label: a numbered heading renders as a
17
+ * heading, and a level that hides its marker (`w:vanish`) or that its list
18
+ * does not define as prose, as every other reader reads them.
19
+ */
20
+ declare function renderParagraphBlock(ctx: RenderContext, pkg: document_d_exports.DocxPackage | undefined, para: document_d_exports.Paragraph): RenderedParagraph;
9
21
  //#endregion
10
- export { renderParagraph };
22
+ export { RenderedParagraph, renderParagraph, renderParagraphBlock };
@@ -1,5 +1,5 @@
1
1
  import { isQuoteStyle, resolveHeadingLevel } from "../docx/builtInStyles.js";
2
- import { resolveListTemplate } from "../prosemirror/listMarker.js";
2
+ import { listLabelAttrsFromRendering } from "../prosemirror/listLabels.js";
3
3
  import { renderParagraphInline } from "./renderRuns.js";
4
4
  //#region src/markdown/renderParagraph.ts
5
5
  /**
@@ -9,6 +9,8 @@ import { renderParagraphInline } from "./renderRuns.js";
9
9
  * `IntenseQuote` styles become blockquotes. Ported from eigenpal/docx-editor
10
10
  * PR #595.
11
11
  *
12
+ * A numbered heading keeps its number after the hashes (`## 1. Scope`).
13
+ *
12
14
  * Which paragraphs those are is `builtInStyles`' decision, not this file's: the
13
15
  * id `Nadpis1` and the id `Heading1` are the same heading, and `ClauseHeading1`
14
16
  * is not one at all.
@@ -20,19 +22,59 @@ const MAX_MARKDOWN_HEADING_LEVEL = 6;
20
22
  * caller joins blocks.
21
23
  */
22
24
  function renderParagraph(ctx, pkg, para) {
25
+ return renderParagraphBlock(ctx, pkg, para).markdown;
26
+ }
27
+ /**
28
+ * Render a paragraph. A list item is a paragraph that shows a marker, which is
29
+ * when the list counter gives it a label: a numbered heading renders as a
30
+ * heading, and a level that hides its marker (`w:vanish`) or that its list
31
+ * does not define as prose, as every other reader reads them.
32
+ */
33
+ function renderParagraphBlock(ctx, pkg, para) {
34
+ const label = ctx.nextListLabel(listLabelAttrs(para));
23
35
  const inline = renderParagraphInline(ctx, pkg, para.content, para.paraId);
24
36
  const styleId = para.formatting?.styleId;
25
- const headingLevel = resolveHeadingLevel({
26
- outlineLevel: para.formatting?.outlineLevel,
27
- styleId
28
- }, ctx.builtInStyles);
37
+ const headingLevel = markdownHeadingLevel(ctx, para);
29
38
  if (headingLevel !== void 0) {
30
- if (!inline) return "";
31
- return `${"#".repeat(Math.min(MAX_MARKDOWN_HEADING_LEVEL, headingLevel + 1))} ${inline}`;
39
+ if (!inline) return {
40
+ markdown: "",
41
+ isListItem: false
42
+ };
43
+ const hashes = "#".repeat(Math.min(MAX_MARKDOWN_HEADING_LEVEL, headingLevel + 1));
44
+ return {
45
+ markdown: label ? `${hashes} ${label} ${inline}` : `${hashes} ${inline}`,
46
+ isListItem: false
47
+ };
32
48
  }
33
- if (para.listRendering && !para.listRendering.markerHidden) return renderListItem(ctx, para.listRendering, inline);
34
- if (isQuoteStyle(styleId, ctx.builtInStyles)) return inline.split("\n").map((line) => `> ${line}`).join("\n");
35
- return escapeLeadingBlockMarker(inline);
49
+ if (para.listRendering && label !== void 0) return {
50
+ markdown: renderListItem(ctx, para.listRendering, label, inline),
51
+ isListItem: true
52
+ };
53
+ if (isQuoteStyle(styleId, ctx.builtInStyles)) return {
54
+ markdown: inline.split("\n").map((line) => `> ${line}`).join("\n"),
55
+ isListItem: false
56
+ };
57
+ return {
58
+ markdown: escapeLeadingBlockMarker(inline),
59
+ isListItem: false
60
+ };
61
+ }
62
+ /** The paragraph's 0-based heading level, as `builtInStyles` classifies it. */
63
+ function markdownHeadingLevel(ctx, para) {
64
+ return resolveHeadingLevel({
65
+ outlineLevel: para.formatting?.outlineLevel,
66
+ styleId: para.formatting?.styleId
67
+ }, ctx.builtInStyles);
68
+ }
69
+ const UNNUMBERED = Object.freeze({});
70
+ /**
71
+ * The attrs the page's list counter reads, projected from the paragraph the
72
+ * way the editor projects them (`toProseDoc`). A paragraph without a list
73
+ * rendering counts as unnumbered.
74
+ */
75
+ function listLabelAttrs(para) {
76
+ const list = para.listRendering;
77
+ return list ? listLabelAttrsFromRendering(list, para.formatting?.numPrFromStyle) : UNNUMBERED;
36
78
  }
37
79
  /**
38
80
  * A plain paragraph whose visible text begins with markdown block syntax (e.g.
@@ -43,36 +85,41 @@ function renderParagraph(ctx, pkg, para) {
43
85
  function escapeLeadingBlockMarker(text) {
44
86
  return text.replace(/^(?<ws>[ \t]*)(?<marker>[#>])/gmu, "$<ws>\\$<marker>").replace(/^(?<ws>[ \t]*)(?<marker>[-+*])(?<after>[ \t])/gmu, "$<ws>\\$<marker>$<after>").replace(/^(?<ws>[ \t]*)(?<num>\d{1,9})(?<marker>[.)])(?<after>[ \t])/gmu, "$<ws>$<num>\\$<marker>$<after>");
45
87
  }
46
- function renderListItem(ctx, list, inline) {
47
- const indent = " ".repeat(list.level);
48
- if (list.isBullet) return `${indent}- ${inline}`.trimEnd();
49
- return `${indent}${list.marker.includes("%") ? resolveTemplateMarker(ctx, list) : list.marker.trim()} ${inline}`.trimEnd();
88
+ /**
89
+ * A markdown list marker's width when no ancestor at that level has rendered
90
+ * yet (e.g. a DOCX paragraph numbered at a level its list skipped over). Two
91
+ * spaces is the old fixed-indent behaviour, kept as a fallback rather than a
92
+ * guess of zero.
93
+ */
94
+ const DEFAULT_LIST_INDENT_WIDTH = 2;
95
+ /**
96
+ * The indent a level's item needs: the combined marker width of every
97
+ * shallower level's most recently rendered item (see
98
+ * `RenderContext.listIndentWidths`), so a child sits inside its parent's
99
+ * content column per CommonMark's list-nesting rule, not a fixed guess.
100
+ */
101
+ function listIndentWidth(ctx, level) {
102
+ let width = 0;
103
+ for (let ancestor = 0; ancestor < level; ancestor++) width += ctx.listIndentWidths[ancestor] ?? DEFAULT_LIST_INDENT_WIDTH;
104
+ return width;
50
105
  }
51
106
  /**
52
- * Resolve a `lvlText`-style marker template ("%1.") against live counters, the
53
- * same way the layout engine paints it. Editor-emitted documents carry
54
- * templates rather than baked numbers, so the serializer must count items in
55
- * document order; counters live on the context (`listCounters`) so they span
56
- * the whole render, including list items inside tables and block SDTs.
107
+ * A list item line with the label the page shows (`1.`, `a)`, `i.`), counted
108
+ * in document order across the whole render, list items inside tables and
109
+ * block SDTs included. A bullet is Markdown's `-`.
110
+ *
111
+ * The indent before the marker is not a fixed two spaces: CommonMark keeps a
112
+ * child nested under its parent only when it starts at or past the column
113
+ * where the parent item's content begins, which is the width of the parent's
114
+ * marker plus its one trailing space (`1. ` is 3 columns, `10. ` is 4, `- ` is
115
+ * 2). `ctx.listIndentWidths` is updated with this item's own marker width so
116
+ * a following, deeper item can indent correctly under it.
57
117
  */
58
- function resolveTemplateMarker(ctx, list) {
59
- const counters = ctx.listCounters.get(list.numId) ?? Array.from({ length: 9 }, () => 0);
60
- const level = list.level;
61
- const seenKey = `${list.numId}:${level}`;
62
- if (!ctx.listSeenLevels.has(seenKey)) {
63
- ctx.listSeenLevels.add(seenKey);
64
- if (list.startOverride !== void 0) counters[level] = list.startOverride - 1;
65
- }
66
- counters[level] = (counters[level] ?? 0) + 1;
67
- for (let i = level + 1; i < counters.length; i += 1) counters[i] = 0;
68
- ctx.listCounters.set(list.numId, counters);
69
- const levelFormats = list.levelNumFmts ?? (list.numFmt ? [list.numFmt] : void 0);
70
- return resolveListTemplate({
71
- template: list.marker,
72
- counters,
73
- levelFormats,
74
- forceDecimal: list.isLegal
75
- }).trim();
118
+ function renderListItem(ctx, list, label, inline) {
119
+ const indent = " ".repeat(listIndentWidth(ctx, list.level));
120
+ const marker = list.isBullet ? "- " : `${label} `;
121
+ ctx.listIndentWidths[list.level] = marker.length;
122
+ return `${indent}${marker}${inline}`.trimEnd();
76
123
  }
77
124
  //#endregion
78
- export { renderParagraph };
125
+ export { renderParagraph, renderParagraphBlock };
@@ -4,7 +4,7 @@ import { decodeOoxmlSymbolCharacter } from "../utils/ooxmlSymbol.js";
4
4
  import { wrapComment, wrapDeletion, wrapInsertion, wrapMoveFrom, wrapMoveTo } from "./annotations.js";
5
5
  import { escapeAltText, escapeInline, escapeLinkUrl } from "./escape.js";
6
6
  import { registerImage } from "./images.js";
7
- import { pushWarning } from "./internals.js";
7
+ import { numberNoteReference, pushWarning } from "./internals.js";
8
8
  //#region src/markdown/renderRuns.ts
9
9
  const MARK_DELIMS = {
10
10
  bold: "**",
@@ -81,17 +81,10 @@ function renderRunContent(ctx, pkg, content, paraId) {
81
81
  out += escapeInline(item.text);
82
82
  break;
83
83
  case "footnoteRef":
84
- case "endnoteRef": {
84
+ case "endnoteRef":
85
85
  if (ctx.opts.footnotes === "strip") break;
86
- const markerNumber = ctx.footnoteRefs.length + 1;
87
- ctx.footnoteRefs.push({
88
- refId: item.id,
89
- markerNumber,
90
- kind: item.type === "endnoteRef" ? "endnote" : "footnote"
91
- });
92
- out += `[^${markerNumber}]`;
86
+ out += numberNoteReference(ctx, item.type === "endnoteRef" ? "endnote" : "footnote", item.id).marker;
93
87
  break;
94
- }
95
88
  case "drawing": {
96
89
  const ref = resolveRelationshipIdOfType(pkg?.relationships, item.image.rId, RELATIONSHIP_TYPES.image);
97
90
  const media = ref.status === "resolved" ? pkg?.media?.get(ref.relationship.target) : void 0;
@@ -1,18 +1,25 @@
1
+ import { ALT_CHUNK_READER_DIAGNOSTIC, isAltChunkMarkup } from "../docx/altChunk.js";
1
2
  import { getHyperlinkRuns } from "../docx/hyperlinkParser.js";
3
+ import { OPAQUE_REVISION_CARRIER_READER_DIAGNOSTIC, isOpaqueNestedRowMarkup, opaqueRevisionCarrierName } from "../docx/opaqueCarrier.js";
2
4
  import { RELATIONSHIP_TYPES, resolveRelationshipIdOfType } from "../docx/relsParser.js";
3
5
  import { decodeOoxmlSymbolCharacter } from "../utils/ooxmlSymbol.js";
4
6
  import { escapeTableCell } from "./escape.js";
5
7
  import { registerImage } from "./images.js";
6
- import { pushWarning } from "./internals.js";
8
+ import { numberNoteReference, pushWarning } from "./internals.js";
7
9
  import { renderParagraph } from "./renderParagraph.js";
8
10
  //#region src/markdown/renderTable.ts
9
11
  /** Render a `Table` as markdown. Picks GFM vs HTML based on cell features. */
10
12
  function renderTable(ctx, pkg, table) {
11
13
  const { rows } = table;
12
- if (!rows.length) return "";
13
- if (needsHtmlFallback(rows)) return renderHtmlTable(ctx, pkg, rows, true);
14
- return renderGfmTable(ctx, pkg, rows, true);
14
+ const diagnostics = [...preservedCarrierDiagnostics(table.preserved?.children), ...rows.flatMap((row) => preservedCarrierDiagnostics(row.preserved?.children))];
15
+ if (!rows.length) return diagnostics.join("\n");
16
+ return [needsHtmlFallback(rows) ? renderHtmlTable(ctx, pkg, rows, true) : renderGfmTable(ctx, pkg, rows, true), ...diagnostics].filter(Boolean).join("\n\n");
15
17
  }
18
+ const preservedCarrierDiagnostics = (children) => (children ?? []).flatMap(({ xml }) => {
19
+ if (isAltChunkMarkup(xml)) return [ALT_CHUNK_READER_DIAGNOSTIC];
20
+ if (opaqueRevisionCarrierName(xml) !== void 0) return [OPAQUE_REVISION_CARRIER_READER_DIAGNOSTIC];
21
+ return isOpaqueNestedRowMarkup(xml) ? ["[Unsupported nested w:tr content]"] : [];
22
+ });
16
23
  function needsHtmlFallback(rows) {
17
24
  for (const row of rows) for (const cell of row.cells) {
18
25
  if ((cell.formatting?.gridSpan ?? 1) > 1) return true;
@@ -64,10 +71,15 @@ function renderGfmCell(ctx, pkg, cell) {
64
71
  break;
65
72
  }
66
73
  case "blockSdt":
74
+ case "blockCustomXml":
67
75
  renderBlocks(item.content);
68
76
  break;
69
- case "table":
77
+ case "table": break;
70
78
  case "preservedBlock":
79
+ if (isAltChunkMarkup(item.xml)) blocks.push(item.readerText === void 0 ? ALT_CHUNK_READER_DIAGNOSTIC : `${ALT_CHUNK_READER_DIAGNOSTIC}\n${item.readerText}`);
80
+ else if (opaqueRevisionCarrierName(item.xml) !== void 0) blocks.push(OPAQUE_REVISION_CARRIER_READER_DIAGNOSTIC);
81
+ else if (isOpaqueNestedRowMarkup(item.xml)) blocks.push("[Unsupported nested w:tr content]");
82
+ break;
71
83
  case "bookmarkStart":
72
84
  case "bookmarkEnd": break;
73
85
  default: return item;
@@ -139,9 +151,14 @@ function renderHtmlCell(ctx, pkg, cell) {
139
151
  break;
140
152
  }
141
153
  case "blockSdt":
154
+ case "blockCustomXml":
142
155
  renderBlocks(item.content);
143
156
  break;
144
157
  case "preservedBlock":
158
+ if (isAltChunkMarkup(item.xml)) parts.push(item.readerText === void 0 ? ALT_CHUNK_READER_DIAGNOSTIC : `${ALT_CHUNK_READER_DIAGNOSTIC} ${item.readerText}`);
159
+ else if (opaqueRevisionCarrierName(item.xml) !== void 0) parts.push(OPAQUE_REVISION_CARRIER_READER_DIAGNOSTIC);
160
+ else if (isOpaqueNestedRowMarkup(item.xml)) parts.push("[Unsupported nested w:tr content]");
161
+ break;
145
162
  case "bookmarkStart":
146
163
  case "bookmarkEnd": break;
147
164
  default: return item;
@@ -257,13 +274,8 @@ function renderHtmlRun(ctx, pkg, run, paraId) {
257
274
  case "footnoteRef":
258
275
  case "endnoteRef": {
259
276
  if (ctx.opts.footnotes === "strip") break;
260
- const markerNumber = ctx.footnoteRefs.length + 1;
261
- ctx.footnoteRefs.push({
262
- refId: item.id,
263
- markerNumber,
264
- kind: item.type === "endnoteRef" ? "endnote" : "footnote"
265
- });
266
- text += `<sup>[${markerNumber}]</sup>`;
277
+ const { token } = numberNoteReference(ctx, item.type === "endnoteRef" ? "endnote" : "footnote", item.id);
278
+ text += `<sup>[${token}]</sup>`;
267
279
  break;
268
280
  }
269
281
  default: break;
@@ -18,9 +18,9 @@ import { panic } from "better-result";
18
18
  function appendTrailers(ctx, doc, body) {
19
19
  const sections = body.trim() ? [body] : [];
20
20
  if (ctx.footnoteRefs.length > 0) {
21
- const refs = ctx.footnoteRefs.map(({ refId, markerNumber, kind }) => {
21
+ const refs = ctx.footnoteRefs.map(({ refId, marker, kind }) => {
22
22
  const note = kind === "endnote" ? doc.package.endnotes?.find((n) => n.id === refId) : doc.package.footnotes?.find((f) => f.id === refId);
23
- return `[^${markerNumber}]: ${note ? noteText(ctx, doc, note) : ""}`;
23
+ return `${marker}: ${note ? noteText(ctx, doc, note) : ""}`;
24
24
  });
25
25
  sections.push(refs.join("\n"));
26
26
  }
@@ -1,4 +1,6 @@
1
+ import { NoteReferenceKind, NoteReferenceNumbering } from "../utils/noteReferenceLabels.js";
1
2
  import { BuiltInStyleIndex } from "../docx/builtInStyles.js";
3
+ import { ListLabelCounter } from "../prosemirror/listLabels.js";
2
4
  //#region src/markdown/types.d.ts
3
5
  /**
4
6
  * Metadata describing a single image registration. Owned by the markdown
@@ -106,12 +108,18 @@ type RenderContext = {
106
108
  imagesByPath: Map<string, ImageRef>;
107
109
  /** Diagnostics accumulator. */
108
110
  warnings: string[];
109
- /** Footnote/endnote refs collected during this render, in document order. */
111
+ /**
112
+ * Footnote/endnote refs collected during this render, one per note in the
113
+ * order it is first referenced. `marker` is what the body line shows
114
+ * (`[^1]`, `[^e1]`) and what the definition trailer repeats.
115
+ */
110
116
  footnoteRefs: {
111
117
  refId: number;
112
- markerNumber: number;
113
- kind: "footnote" | "endnote";
118
+ marker: string;
119
+ kind: NoteReferenceKind;
114
120
  }[];
121
+ /** Reading-order note numbering, shared with the AI text view. */
122
+ noteNumbering: NoteReferenceNumbering;
115
123
  /** Comment refs collected during this render (sidecar mode only). */
116
124
  commentRefs: {
117
125
  commentId: number;
@@ -124,12 +132,26 @@ type RenderContext = {
124
132
  }[];
125
133
  /** 1-based counter for default virtual paths. */
126
134
  imageCounter: number;
127
- /** Live list counters per numId, for resolving `%N` marker templates. */
128
- listCounters: Map<number, number[]>;
129
- /** `numId:level` pairs already seen, so a start override applies once. */
130
- listSeenLevels: Set<string>;
135
+ /**
136
+ * Advances past one paragraph, in document order, and answers the list
137
+ * label it shows: the page's own counter, so the numbers follow the
138
+ * document as it stands rather than the markers resolved when it was read.
139
+ */
140
+ nextListLabel: ListLabelCounter;
131
141
  /** The document's styles indexed by the built-in they are; classifies headings and quotes. */
132
142
  builtInStyles: BuiltInStyleIndex;
143
+ /**
144
+ * The rendered width (marker text + one trailing space) of the most
145
+ * recently emitted list item at each level, indexed by `ListRendering.level`.
146
+ * A nested item's indent is the sum of every shallower level's width here,
147
+ * not a fixed two spaces: CommonMark only keeps a child nested under its
148
+ * parent when the child starts at or past the column where the parent's
149
+ * content begins, and a marker like `10. ` or `1. ` is wider than `- `.
150
+ * Document order visits a parent before its children, so by the time a
151
+ * level-N item renders, levels `0..N-1` already hold the current ancestor
152
+ * chain's widths.
153
+ */
154
+ listIndentWidths: number[];
133
155
  };
134
156
  //#endregion
135
157
  export { ImageMeta, ImageRef, MarkdownOptions, MarkdownResult, RenderContext, ResolvedOptions };
@@ -17,8 +17,7 @@ type IncrementalMeasureResult = {
17
17
  measures: Measure[];
18
18
  measuredBlockIndexes: number[];
19
19
  };
20
- declare function mergeDirtyRanges(first: DirtyRange | null, second: DirtyRange | null): DirtyRange | null;
21
20
  declare function findDirtyBlockIndexes(blocks: FlowBlock[], dirtyRange: DirtyRange): number[];
22
21
  declare function tryBuildIncrementalMeasures({ previousBlocks, previousMeasures, previousBlockWidths, nextBlocks, nextBlockWidths, dirtyRange, measureBlock }: IncrementalMeasureInput): IncrementalMeasureResult | null;
23
22
  //#endregion
24
- export { DirtyRange, IncrementalMeasureInput, IncrementalMeasureResult, findDirtyBlockIndexes, mergeDirtyRanges, tryBuildIncrementalMeasures };
23
+ export { DirtyRange, IncrementalMeasureInput, IncrementalMeasureResult, findDirtyBlockIndexes, tryBuildIncrementalMeasures };
@@ -1,12 +1,4 @@
1
1
  //#region src/paged-layout/incrementalMeasure.ts
2
- function mergeDirtyRanges(first, second) {
3
- if (!first) return second;
4
- if (!second) return first;
5
- return {
6
- from: Math.min(first.from, second.from),
7
- to: Math.max(first.to, second.to)
8
- };
9
- }
10
2
  function findDirtyBlockIndexes(blocks, dirtyRange) {
11
3
  const indexes = [];
12
4
  const dirtyFrom = Math.min(dirtyRange.from, dirtyRange.to);
@@ -53,4 +45,4 @@ function isIncrementalMeasureEligibleBlock(block) {
53
45
  });
54
46
  }
55
47
  //#endregion
56
- export { findDirtyBlockIndexes, mergeDirtyRanges, tryBuildIncrementalMeasures };
48
+ export { findDirtyBlockIndexes, tryBuildIncrementalMeasures };
@@ -2,7 +2,5 @@ import { DirtyRange } from "./incrementalMeasure.js";
2
2
  import { Transaction } from "prosemirror-state";
3
3
  //#region src/paged-layout/transactionDirtyRange.d.ts
4
4
  declare function getTransactionDirtyRange(transaction: Transaction): DirtyRange | null;
5
- /** Collect every transaction in an applied batch in the final document's coordinates. */
6
- declare function getTransactionsDirtyRange(transactions: readonly Transaction[]): DirtyRange | null;
7
5
  //#endregion
8
- export { getTransactionDirtyRange, getTransactionsDirtyRange };
6
+ export { getTransactionDirtyRange };
@@ -1,49 +1,37 @@
1
- import { mergeDirtyRanges } from "./incrementalMeasure.js";
1
+ import { sweepPositions } from "../prosemirror/positionSweep.js";
2
2
  import { AddMarkStep, RemoveMarkStep } from "prosemirror-transform";
3
3
  //#region src/paged-layout/transactionDirtyRange.ts
4
4
  function getTransactionDirtyRange(transaction) {
5
- const dirtyRange = {
6
- from: Number.POSITIVE_INFINITY,
7
- to: Number.NEGATIVE_INFINITY
8
- };
9
- for (let stepIndex = 0; stepIndex < transaction.mapping.maps.length; stepIndex += 1) includeStepDirtyRange(transaction, stepIndex, dirtyRange);
10
- if (!Number.isFinite(dirtyRange.from) || !Number.isFinite(dirtyRange.to)) return null;
11
- return dirtyRange;
12
- }
13
- /** Collect every transaction in an applied batch in the final document's coordinates. */
14
- function getTransactionsDirtyRange(transactions) {
15
- let combinedRange = null;
16
- for (let index = 0; index < transactions.length; index += 1) {
17
- const transaction = transactions[index];
18
- if (!transaction) continue;
19
- const range = getTransactionDirtyRange(transaction);
20
- if (!range) continue;
21
- let from = range.from;
22
- let to = range.to;
23
- for (const followingTransaction of transactions.slice(index + 1)) {
24
- from = followingTransaction.mapping.map(from, -1);
25
- to = followingTransaction.mapping.map(to, 1);
26
- }
27
- combinedRange = mergeDirtyRanges(combinedRange, {
28
- from,
29
- to
5
+ const queries = [];
6
+ const extend = (newStart, newEnd, from) => {
7
+ queries.push({
8
+ pos: newStart,
9
+ assoc: -1,
10
+ from
11
+ }, {
12
+ pos: newEnd,
13
+ assoc: 1,
14
+ from
30
15
  });
16
+ };
17
+ for (let stepIndex = 0; stepIndex < transaction.mapping.maps.length; stepIndex += 1) {
18
+ const map = transaction.mapping.maps[stepIndex];
19
+ if (!map) continue;
20
+ map.forEach((_oldStart, _oldEnd, newStart, newEnd) => extend(newStart, newEnd, stepIndex + 1));
21
+ const step = transaction.steps[stepIndex];
22
+ if (step instanceof AddMarkStep || step instanceof RemoveMarkStep) extend(step.from, step.to, stepIndex + 1);
31
23
  }
32
- return combinedRange;
33
- }
34
- function includeStepDirtyRange(transaction, stepIndex, dirtyRange) {
35
- const map = transaction.mapping.maps[stepIndex];
36
- if (!map) return;
37
- const followingMaps = transaction.mapping.slice(stepIndex + 1);
38
- const extend = (newStart, newEnd) => {
39
- const finalStart = followingMaps.map(newStart, -1);
40
- const finalEnd = followingMaps.map(newEnd, 1);
41
- dirtyRange.from = Math.min(dirtyRange.from, finalStart, finalEnd);
42
- dirtyRange.to = Math.max(dirtyRange.to, finalStart, finalEnd);
24
+ if (queries.length === 0) return null;
25
+ let from = Number.POSITIVE_INFINITY;
26
+ let to = Number.NEGATIVE_INFINITY;
27
+ for (const { pos } of sweepPositions([transaction.mapping], queries)) {
28
+ from = Math.min(from, pos);
29
+ to = Math.max(to, pos);
30
+ }
31
+ return {
32
+ from,
33
+ to
43
34
  };
44
- map.forEach((_oldStart, _oldEnd, newStart, newEnd) => extend(newStart, newEnd));
45
- const step = transaction.steps[stepIndex];
46
- if (step instanceof AddMarkStep || step instanceof RemoveMarkStep) extend(step.from, step.to);
47
35
  }
48
36
  //#endregion
49
- export { getTransactionDirtyRange, getTransactionsDirtyRange };
37
+ export { getTransactionDirtyRange };
@@ -0,0 +1,83 @@
1
+ //#region src/panel-layout.d.ts
2
+ /**
3
+ * One layout model for the editor's side panels: the page is centred between
4
+ * a start track (the document outline) and an end track (the comments).
5
+ *
6
+ * The editor measures the width it has once, and this module decides how
7
+ * each panel is presented. Every track the page shares the row with is
8
+ * counted here, so the page, the outline and the comments cannot overlap:
9
+ * a panel either gets a track of its own or becomes a drawer the user opens
10
+ * on purpose. A drawer takes no track.
11
+ *
12
+ * Space goes to the page first, then the outline rail, then the comments
13
+ * column, then the full outline column:
14
+ *
15
+ * - comments: a column when the page, the comments and the outline rail fit;
16
+ * otherwise a drawer.
17
+ * - outline: a column when it fits beside the page and the comments column;
18
+ * otherwise a rail of heading ticks when that fits; otherwise a drawer.
19
+ *
20
+ * The tier names the result: `wide` when every panel has its full column,
21
+ * `medium` when the outline is a rail, `narrow` when a panel is a drawer.
22
+ * The thresholds derive from the page width (at the current zoom) and the
23
+ * panel widths below, never from fixed breakpoints: a zoomed-out page or a
24
+ * landscape section moves them.
25
+ */
26
+ /** Widths, in CSS pixels, every tier is derived from. */
27
+ declare const PANEL_METRICS: {
28
+ /** The outline column in the `wide` tier, border included. */
29
+ readonly outlineColumnWidth: 256;
30
+ /** The outline rail in the `medium` tier, border included. */
31
+ readonly outlineRailWidth: 32;
32
+ /** A comment card column. */
33
+ readonly commentsWidth: 280;
34
+ /** Space between the page edge and the comment cards, and after them. */
35
+ readonly commentsGap: 12;
36
+ /** Canvas kept clear on either side of the page. */
37
+ readonly pageMargin: 20;
38
+ /** An outline or comments drawer, capped by the width it opens over. */
39
+ readonly drawerWidth: 304;
40
+ };
41
+ /** Width the comments take beside the page: gap, cards, gap. */
42
+ declare const COMMENTS_TRACK_WIDTH: number;
43
+ type PanelLayoutTier = "wide" | "medium" | "narrow";
44
+ /** How the outline is shown: a column, a rail of ticks, a drawer, or not at all. */
45
+ type OutlinePresentation = "none" | "column" | "rail" | "drawer";
46
+ /** How the comments are shown: a column beside the page, a drawer, or not at all. */
47
+ type CommentsPresentation = "hidden" | "column" | "drawer";
48
+ type PanelLayoutInput = {
49
+ /** Width of the row the outline track and the scroll viewport share, scrollbar excluded. */
50
+ availableWidth: number;
51
+ /** Width of the widest page at the current zoom. */
52
+ pageWidth: number;
53
+ /** Whether the document has an outline to show. */
54
+ outline: "absent" | "available";
55
+ /** Whether the user (or the auto-open) wants the comments shown. */
56
+ comments: "closed" | "open";
57
+ };
58
+ type PanelLayout = {
59
+ tier: PanelLayoutTier;
60
+ outline: OutlinePresentation;
61
+ comments: CommentsPresentation;
62
+ /** Width of the outline track at the page's start (outside the scroll viewport). */
63
+ outlineTrackWidth: number;
64
+ /** Width reserved after the page inside the scroll viewport for the comments. */
65
+ commentsGutter: number;
66
+ /** Smallest available width for each tier, for the same page and panels. */
67
+ thresholds: {
68
+ wide: number;
69
+ medium: number;
70
+ };
71
+ };
72
+ /**
73
+ * The smallest available width for each tier with the comments wanted as
74
+ * given: `wide` fits every column, `medium` fits the outline rail and the
75
+ * comments column.
76
+ */
77
+ declare const panelLayoutThresholds: ({ pageWidth, outline, comments }: Omit<PanelLayoutInput, "availableWidth">) => PanelLayout["thresholds"];
78
+ /** Decide each panel's presentation for the width the editor has. */
79
+ declare const computePanelLayout: (input: PanelLayoutInput) => PanelLayout;
80
+ /** Which drawer is open over the page: at most one at a time. */
81
+ type PanelOverlay = "none" | "outline" | "comments";
82
+ //#endregion
83
+ export { COMMENTS_TRACK_WIDTH, CommentsPresentation, OutlinePresentation, PANEL_METRICS, PanelLayout, PanelLayoutInput, PanelLayoutTier, PanelOverlay, computePanelLayout, panelLayoutThresholds };
@@ -0,0 +1,96 @@
1
+ //#region src/panel-layout.ts
2
+ /**
3
+ * One layout model for the editor's side panels: the page is centred between
4
+ * a start track (the document outline) and an end track (the comments).
5
+ *
6
+ * The editor measures the width it has once, and this module decides how
7
+ * each panel is presented. Every track the page shares the row with is
8
+ * counted here, so the page, the outline and the comments cannot overlap:
9
+ * a panel either gets a track of its own or becomes a drawer the user opens
10
+ * on purpose. A drawer takes no track.
11
+ *
12
+ * Space goes to the page first, then the outline rail, then the comments
13
+ * column, then the full outline column:
14
+ *
15
+ * - comments: a column when the page, the comments and the outline rail fit;
16
+ * otherwise a drawer.
17
+ * - outline: a column when it fits beside the page and the comments column;
18
+ * otherwise a rail of heading ticks when that fits; otherwise a drawer.
19
+ *
20
+ * The tier names the result: `wide` when every panel has its full column,
21
+ * `medium` when the outline is a rail, `narrow` when a panel is a drawer.
22
+ * The thresholds derive from the page width (at the current zoom) and the
23
+ * panel widths below, never from fixed breakpoints: a zoomed-out page or a
24
+ * landscape section moves them.
25
+ */
26
+ /** Widths, in CSS pixels, every tier is derived from. */
27
+ const PANEL_METRICS = {
28
+ /** The outline column in the `wide` tier, border included. */
29
+ outlineColumnWidth: 256,
30
+ /** The outline rail in the `medium` tier, border included. */
31
+ outlineRailWidth: 32,
32
+ /** A comment card column. */
33
+ commentsWidth: 280,
34
+ /** Space between the page edge and the comment cards, and after them. */
35
+ commentsGap: 12,
36
+ /** Canvas kept clear on either side of the page. */
37
+ pageMargin: 20,
38
+ /** An outline or comments drawer, capped by the width it opens over. */
39
+ drawerWidth: 304
40
+ };
41
+ /** Width the comments take beside the page: gap, cards, gap. */
42
+ const COMMENTS_TRACK_WIDTH = PANEL_METRICS.commentsWidth + 2 * PANEL_METRICS.commentsGap;
43
+ const pageTrackWidth = (pageWidth) => pageWidth + 2 * PANEL_METRICS.pageMargin;
44
+ /**
45
+ * The smallest available width for each tier with the comments wanted as
46
+ * given: `wide` fits every column, `medium` fits the outline rail and the
47
+ * comments column.
48
+ */
49
+ const panelLayoutThresholds = ({ pageWidth, outline, comments }) => {
50
+ const page = pageTrackWidth(pageWidth);
51
+ const commentsTrack = comments === "open" ? COMMENTS_TRACK_WIDTH : 0;
52
+ const hasOutline = outline === "available";
53
+ return {
54
+ wide: page + commentsTrack + (hasOutline ? PANEL_METRICS.outlineColumnWidth : 0),
55
+ medium: page + commentsTrack + (hasOutline ? PANEL_METRICS.outlineRailWidth : 0)
56
+ };
57
+ };
58
+ const OUTLINE_TRACK_WIDTH = {
59
+ none: 0,
60
+ column: PANEL_METRICS.outlineColumnWidth,
61
+ rail: PANEL_METRICS.outlineRailWidth,
62
+ drawer: 0
63
+ };
64
+ const tierFor = (outline, comments) => {
65
+ if (outline === "drawer" || comments === "drawer") return "narrow";
66
+ if (outline === "rail") return "medium";
67
+ return "wide";
68
+ };
69
+ /** Decide each panel's presentation for the width the editor has. */
70
+ const computePanelLayout = (input) => {
71
+ const { availableWidth } = input;
72
+ const thresholds = panelLayoutThresholds(input);
73
+ const page = pageTrackWidth(input.pageWidth);
74
+ const comments = (() => {
75
+ if (input.comments === "closed") return "hidden";
76
+ return availableWidth >= thresholds.medium ? "column" : "drawer";
77
+ })();
78
+ const commentsGutter = comments === "column" ? COMMENTS_TRACK_WIDTH : 0;
79
+ const outline = (() => {
80
+ if (input.outline === "absent") return "none";
81
+ const beside = page + commentsGutter;
82
+ if (availableWidth >= thresholds.wide) return "column";
83
+ if (availableWidth >= beside + PANEL_METRICS.outlineRailWidth) return "rail";
84
+ return "drawer";
85
+ })();
86
+ return {
87
+ tier: tierFor(outline, comments),
88
+ outline,
89
+ comments,
90
+ outlineTrackWidth: OUTLINE_TRACK_WIDTH[outline],
91
+ commentsGutter,
92
+ thresholds
93
+ };
94
+ };
95
+ //#endregion
96
+ export { COMMENTS_TRACK_WIDTH, PANEL_METRICS, computePanelLayout, panelLayoutThresholds };