@stll/folio-core 0.58.5 → 0.60.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (208) hide show
  1. package/README.md +10 -1
  2. package/dist/ai-edits/apply.d.ts +11 -12
  3. package/dist/ai-edits/apply.js +179 -168
  4. package/dist/ai-edits/headless.d.ts +15 -13
  5. package/dist/ai-edits/headless.js +40 -13
  6. package/dist/ai-edits/index.d.ts +3 -3
  7. package/dist/ai-edits/newListNumbering.d.ts +3 -9
  8. package/dist/ai-edits/newListNumbering.js +36 -41
  9. package/dist/ai-edits/referenceClassification.d.ts +22 -0
  10. package/dist/ai-edits/referenceClassification.js +21 -0
  11. package/dist/ai-edits/snapshot.js +39 -40
  12. package/dist/ai-edits/types.d.ts +24 -32
  13. package/dist/compare/column-alignment.d.ts +4 -4
  14. package/dist/compare/compare.d.ts +3 -7
  15. package/dist/compare/compare.js +25 -27
  16. package/dist/compare/content-alignment.d.ts +9 -9
  17. package/dist/compare/content-types.d.ts +23 -10
  18. package/dist/compare/content-types.js +14 -0
  19. package/dist/compare/content.d.ts +16 -17
  20. package/dist/compare/content.js +30 -7
  21. package/dist/compare/formatting.d.ts +3 -3
  22. package/dist/compare/import-style-closure.d.ts +22 -0
  23. package/dist/compare/import-style-closure.js +33 -0
  24. package/dist/compare/inserted-resource-snapshot.d.ts +15 -0
  25. package/dist/compare/inserted-resource-snapshot.js +63 -0
  26. package/dist/compare/plan.js +20 -13
  27. package/dist/compare/scenario.js +12 -2
  28. package/dist/compare/style-resources.d.ts +8 -2
  29. package/dist/compare/style-resources.js +63 -14
  30. package/dist/compare/verification.d.ts +15 -3
  31. package/dist/compare/verification.js +47 -8
  32. package/dist/compat/eigenpal.d.ts +5 -5
  33. package/dist/compat/eigenpal.js +2 -2
  34. package/dist/controller/canonicalListRendering.js +13 -22
  35. package/dist/controller/canonicalPublicOperations.js +1 -1
  36. package/dist/controller/canonicalSession.js +3 -2
  37. package/dist/controller/canonicalStructure.js +55 -28
  38. package/dist/controller/fontReadiness.js +1 -1
  39. package/dist/controller/layoutPipeline.js +7 -1
  40. package/dist/controller/layoutSession.d.ts +2 -0
  41. package/dist/display-list/build/fontTable.js +7 -5
  42. package/dist/display-list/build/furniture.d.ts +1 -0
  43. package/dist/display-list/build/furniture.js +1 -0
  44. package/dist/display-list/build/watermarkPrimitives.d.ts +2 -1
  45. package/dist/display-list/build/watermarkPrimitives.js +9 -3
  46. package/dist/display-list/editor/pageRenderer.js +1 -0
  47. package/dist/document-operations.d.ts +4 -9
  48. package/dist/document-operations.js +45 -41
  49. package/dist/docx/attributeRemainder.d.ts +1 -1
  50. package/dist/docx/bookmarkIdNormalization.d.ts +10 -0
  51. package/dist/docx/bookmarkIdNormalization.js +100 -0
  52. package/dist/docx/bookmarkParser.js +4 -2
  53. package/dist/docx/importedIdCollisions.d.ts +136 -0
  54. package/dist/docx/importedIdCollisions.js +215 -0
  55. package/dist/docx/index.d.ts +1 -1
  56. package/dist/docx/listMarkerComputation.js +9 -14
  57. package/dist/docx/listTemplate.d.ts +22 -0
  58. package/dist/docx/listTemplate.js +40 -0
  59. package/dist/docx/numberingParser.js +4 -4
  60. package/dist/docx/numberingReferenceNormalization.js +3 -3
  61. package/dist/docx/paragraphParser.js +3 -4
  62. package/dist/docx/paragraphPropertySource.js +1 -2
  63. package/dist/docx/parseContext.d.ts +2 -1
  64. package/dist/docx/parseContext.js +1 -0
  65. package/dist/docx/parseWarningMessage.js +1 -0
  66. package/dist/docx/parser.js +5 -1
  67. package/dist/docx/relsParser.js +1 -1
  68. package/dist/docx/rezip.js +4 -3
  69. package/dist/docx/selectedXmlIdentityScan.d.ts +10 -0
  70. package/dist/docx/selectedXmlIdentityScan.js +36 -0
  71. package/dist/docx/selectiveSave.js +5 -4
  72. package/dist/docx/selectiveXmlPatch.js +44 -52
  73. package/dist/docx/serializer/commentSerializer.d.ts +3 -1
  74. package/dist/docx/serializer/commentSerializer.js +11 -2
  75. package/dist/docx/serializer/runSerializer.js +2 -2
  76. package/dist/docx/serializer/trackedChangeAttributes.d.ts +1 -3
  77. package/dist/docx/serializer/trackedChangeAttributes.js +1 -11
  78. package/dist/docx/server/materializeYjsDocx.js +2 -2
  79. package/dist/docx/server/migrateYjsAttrSchema.js +5 -5
  80. package/dist/fonts/embeddedFontFingerprint.d.ts +5 -0
  81. package/dist/fonts/embeddedFontFingerprint.js +18 -0
  82. package/dist/fonts/embeddedFonts.d.ts +1 -1
  83. package/dist/fonts/embeddedFonts.js +1 -1
  84. package/dist/fonts/headlessMeasure.js +0 -0
  85. package/dist/generated/text_shaper.js +8 -4
  86. package/dist/generated/text_shaper_bg.wasm +0 -0
  87. package/dist/headless-layout.js +1 -0
  88. package/dist/index.d.ts +5 -5
  89. package/dist/index.js +2 -2
  90. package/dist/internal/paragraphFormattingSerialization.d.ts +1 -8
  91. package/dist/internal/paragraphFormattingSerialization.js +6 -20
  92. package/dist/layout-bridge/convert/flowConversionShared.d.ts +3 -1
  93. package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -1
  94. package/dist/layout-bridge/convert/footnoteLayout.js +3 -0
  95. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
  96. package/dist/layout-bridge/convert/headerFooterLayout.js +2 -0
  97. package/dist/layout-bridge/convert/listMarkers.d.ts +1 -2
  98. package/dist/layout-bridge/convert/listMarkers.js +3 -11
  99. package/dist/layout-bridge/convert/paragraphAttrs.d.ts +1 -1
  100. package/dist/layout-bridge/convert/paragraphAttrs.js +8 -4
  101. package/dist/layout-bridge/convert/paragraphConversion.js +8 -1
  102. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +2 -1
  103. package/dist/layout-bridge/convert/toFlowBlocks.js +27 -2
  104. package/dist/layout-engine/measure/cache.js +39 -7
  105. package/dist/layout-engine/measure/lineTypography.js +1 -0
  106. package/dist/layout-engine/measure/listMarkerWidth.d.ts +1 -0
  107. package/dist/layout-engine/measure/listMarkerWidth.js +1 -0
  108. package/dist/layout-engine/measure/measureContainer.js +3 -4
  109. package/dist/layout-engine/measure/measureHelpers.d.ts +6 -9
  110. package/dist/layout-engine/measure/measureHelpers.js +21 -18
  111. package/dist/layout-engine/measure/measureParagraph.js +2 -0
  112. package/dist/layout-engine/measure/measureTypes.d.ts +2 -0
  113. package/dist/layout-engine/types.d.ts +4 -1
  114. package/dist/layout-painter/renderPage.d.ts +1 -0
  115. package/dist/layout-painter/renderPage.js +11 -3
  116. package/dist/layout-painter/renderParagraph.js +13 -3
  117. package/dist/layout-painter/renderWatermark.d.ts +1 -0
  118. package/dist/layout-painter/renderWatermark.js +7 -3
  119. package/dist/managers/editorShortcuts.d.ts +2 -1
  120. package/dist/managers/editorShortcuts.js +2 -1
  121. package/dist/markdown/renderParagraph.js +29 -3
  122. package/dist/prosemirror/canonicalSelectionRange.d.ts +4 -1
  123. package/dist/prosemirror/canonicalSelectionRange.js +9 -3
  124. package/dist/prosemirror/commands/comments.js +5 -32
  125. package/dist/prosemirror/commands/paragraphBookmarkJoin.d.ts +7 -1
  126. package/dist/prosemirror/commands/paragraphBookmarkJoin.js +35 -1
  127. package/dist/prosemirror/commands/propertyChangeScope.js +6 -0
  128. package/dist/prosemirror/commands/resolveParagraphProperties.js +10 -5
  129. package/dist/prosemirror/conversion/fromProseDoc.js +23 -9
  130. package/dist/prosemirror/conversion/toProseDoc.js +31 -7
  131. package/dist/prosemirror/extensions/core/ParagraphExtension.js +29 -14
  132. package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.d.ts +8 -2
  133. package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.js +39 -3
  134. package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.d.ts +8 -2
  135. package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.js +4 -3
  136. package/dist/prosemirror/extensions/features/ImageDragExtension.js +4 -3
  137. package/dist/prosemirror/extensions/features/JoinedRunStyleExtension.js +4 -3
  138. package/dist/prosemirror/extensions/features/ListExtension.js +51 -21
  139. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +9 -3
  140. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +6 -5
  141. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +8 -2
  142. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +11 -3
  143. package/dist/prosemirror/extensions/marks/RunIdentityExtension.js +4 -3
  144. package/dist/prosemirror/extensions/marks/markUtils.js +1 -1
  145. package/dist/prosemirror/listInstanceReferences.js +21 -15
  146. package/dist/prosemirror/listLabels.d.ts +4 -3
  147. package/dist/prosemirror/listLabels.js +18 -51
  148. package/dist/prosemirror/listMarker.d.ts +2 -19
  149. package/dist/prosemirror/listMarker.js +28 -57
  150. package/dist/prosemirror/listNumbering.js +16 -6
  151. package/dist/prosemirror/listRendering.d.ts +4 -3
  152. package/dist/prosemirror/listRendering.js +22 -3
  153. package/dist/prosemirror/listRenderingAttrs.d.ts +2 -1
  154. package/dist/prosemirror/listRenderingAttrs.js +6 -11
  155. package/dist/prosemirror/numberedRefFields.js +9 -5
  156. package/dist/prosemirror/numberingAttr.d.ts +19 -1
  157. package/dist/prosemirror/numberingAttr.js +16 -2
  158. package/dist/prosemirror/paragraphIndentation.js +5 -2
  159. package/dist/prosemirror/paragraphMarkJoin.js +17 -3
  160. package/dist/prosemirror/paragraphPropertyCarry.js +5 -6
  161. package/dist/prosemirror/pluginKeyOwner.d.ts +13 -0
  162. package/dist/prosemirror/pluginKeyOwner.js +35 -0
  163. package/dist/prosemirror/plugins/aiCitationDecorations.d.ts +11 -4
  164. package/dist/prosemirror/plugins/aiCitationDecorations.js +16 -3
  165. package/dist/prosemirror/plugins/aiSuggestionDecorations.d.ts +11 -4
  166. package/dist/prosemirror/plugins/aiSuggestionDecorations.js +18 -3
  167. package/dist/prosemirror/plugins/anonymizationDecorations.d.ts +11 -11
  168. package/dist/prosemirror/plugins/anonymizationDecorations.js +23 -13
  169. package/dist/prosemirror/plugins/autocompleteSuggestion.d.ts +8 -2
  170. package/dist/prosemirror/plugins/autocompleteSuggestion.js +27 -5
  171. package/dist/prosemirror/plugins/contentControlWidgets.d.ts +8 -2
  172. package/dist/prosemirror/plugins/contentControlWidgets.js +4 -3
  173. package/dist/prosemirror/plugins/createDocScanPlugin.d.ts +6 -5
  174. package/dist/prosemirror/plugins/createDocScanPlugin.js +1 -1
  175. package/dist/prosemirror/plugins/documentNumbering.js +5 -3
  176. package/dist/prosemirror/plugins/documentStyleState.d.ts +8 -2
  177. package/dist/prosemirror/plugins/documentStyleState.js +2 -2
  178. package/dist/prosemirror/plugins/documentStyles.js +1 -1
  179. package/dist/prosemirror/plugins/selectionTracker.d.ts +8 -2
  180. package/dist/prosemirror/plugins/selectionTracker.js +4 -3
  181. package/dist/prosemirror/plugins/suggestionMode.d.ts +8 -2
  182. package/dist/prosemirror/plugins/suggestionMode.js +4 -3
  183. package/dist/prosemirror/plugins/templateDirectives.d.ts +8 -2
  184. package/dist/prosemirror/plugins/templateDirectives.js +19 -4
  185. package/dist/prosemirror/plugins/templatePreviewValues.d.ts +8 -2
  186. package/dist/prosemirror/plugins/templatePreviewValues.js +27 -5
  187. package/dist/prosemirror/plugins/templateSlashMenu.d.ts +8 -2
  188. package/dist/prosemirror/plugins/templateSlashMenu.js +23 -5
  189. package/dist/prosemirror/plugins/transactionInvariants.js +29 -5
  190. package/dist/prosemirror/schema/nodes.d.ts +2 -1
  191. package/dist/prosemirror/selectionState.js +5 -1
  192. package/dist/prosemirror/storyListNumbering.js +11 -12
  193. package/dist/prosemirror/styles/paragraphStyleCascade.js +2 -6
  194. package/dist/prosemirror/styles/resolvedStyleAttrs.d.ts +11 -4
  195. package/dist/prosemirror/styles/resolvedStyleAttrs.js +28 -18
  196. package/dist/prosemirror/yjsDocumentMetadata.d.ts +9 -3
  197. package/dist/prosemirror/yjsDocumentMetadata.js +42 -10
  198. package/dist/redline.d.ts +17 -1
  199. package/dist/redline.js +118 -57
  200. package/dist/server.d.ts +3 -3
  201. package/dist/server.js +2 -2
  202. package/dist/utils/fontLoader.d.ts +2 -2
  203. package/dist/utils/fontLoader.js +2 -7
  204. package/dist/utils/fontResolver.d.ts +7 -3
  205. package/dist/utils/fontResolver.js +6 -8
  206. package/dist/version-comparison.d.ts +1 -2
  207. package/dist/version-comparison.js +1 -2
  208. package/package.json +26 -9
@@ -1,5 +1,6 @@
1
+ import { resolveListTemplate } from "../../docx/listTemplate.js";
2
+ import { formatCounter } from "../../prosemirror/listMarker.js";
1
3
  import { FlowBlock } from "../../layout-engine/types.js";
2
- import { formatCounter, resolveListTemplate } from "../../prosemirror/listMarker.js";
3
4
  import { ToFlowBlocksOptions, resetBlockIdCounter } from "./flowConversionShared.js";
4
5
  import { collectNoteRefs } from "./noteReferences.js";
5
6
  import { convertBorderSpecToLayout } from "./flowBorders.js";
@@ -1,8 +1,9 @@
1
1
  import { resolveDocumentGridLinePitch } from "../../docx/documentGrid.js";
2
+ import { resolveListTemplate } from "../../docx/listTemplate.js";
2
3
  import { buildPageBreakRunDescendantIndex } from "../../internal/pageBreakRunDescendantIndex.js";
3
4
  import { getPageNumbering } from "../../paged-layout/sectionGeometry.js";
4
5
  import { expectBlockSdtAttrs, expectHardBreakAttrs, expectParagraphAttrs, expectTextBoxAttrs } from "../../prosemirror/attrs/index.js";
5
- import { cloneListCounterState, formatCounter, resolveListTemplate } from "../../prosemirror/listMarker.js";
6
+ import { cloneListCounterState, formatCounter } from "../../prosemirror/listMarker.js";
6
7
  import { resolveNumberedRefFields } from "../../prosemirror/numberedRefFields.js";
7
8
  import { expectTextBoxAnchorAttrs } from "../../prosemirror/textBoxAnchorAttrs.js";
8
9
  import { assertValidProseMirrorDocument } from "../../prosemirror/validation.js";
@@ -411,10 +412,34 @@ function toFlowBlocks(doc, options = {}) {
411
412
  }
412
413
  const mergedBlocks = mergeRunInParagraphs(blocks);
413
414
  const tableCellLinePitch = doc.attrs["_adjustLineHeightInTable"] === true ? "sectionGrid" : void 0;
414
- return groupParagraphFrames(coalesceTrailingPageBreakBeforeContinuousSection(applySectionStartsToBoundaries(applySectionDocumentGrid(mergedBlocks, {
415
+ const result = groupParagraphFrames(coalesceTrailingPageBreakBeforeContinuousSection(applySectionStartsToBoundaries(applySectionDocumentGrid(mergedBlocks, {
415
416
  finalLinePitchTwips: opts.finalSectionDocumentGridLinePitchTwips,
416
417
  tableCellLinePitch
417
418
  }), readFinalSectionStart(doc)), options.splitPageBreakAndParagraphMark === true, sectionBreaksWithoutMarker), nextBlockId);
419
+ if (options.embeddedFontFamilyMap) attachEmbeddedFontFamilies(result, options.embeddedFontFamilyMap);
420
+ return result;
418
421
  }
422
+ /** Attach editor-owned resolution to freshly derived blocks without changing authored data. */
423
+ const attachEmbeddedFontFamilies = (blocks, familyMap) => {
424
+ for (const block of blocks) switch (block.kind) {
425
+ case "paragraph":
426
+ for (const run of block.runs) if (run.kind !== "image" && run.kind !== "lineBreak") run.embeddedFontFamilyMap = familyMap;
427
+ block.attrs ??= {};
428
+ block.attrs.embeddedFontFamilyMap = familyMap;
429
+ if (block.attrs.listMarkerFormatting) block.attrs.listMarkerFormatting.embeddedFontFamilyMap = familyMap;
430
+ break;
431
+ case "table":
432
+ for (const row of block.rows) for (const cell of row.cells) attachEmbeddedFontFamilies(cell.blocks, familyMap);
433
+ break;
434
+ case "textBox":
435
+ attachEmbeddedFontFamilies(block.content, familyMap);
436
+ break;
437
+ case "image":
438
+ case "sectionBreak":
439
+ case "pageBreak":
440
+ case "columnBreak": break;
441
+ default: return block;
442
+ }
443
+ };
419
444
  //#endregion
420
445
  export { WORD_UNSPECIFIED_FONT_SIZE, collectNoteRefs, convertBorderSpecToLayout, formatCounter, resetBlockIdCounter, resolveListTemplate, toFlowBlocks };
@@ -1,7 +1,14 @@
1
+ import { embeddedFontFingerprint } from "../../fonts/embeddedFontFingerprint.js";
1
2
  import { getLineBreakProviderGeneration } from "./lineBreakProvider.js";
2
3
  import { clearFontResolvedCache } from "./measureHelpers.js";
3
4
  //#region src/layout-engine/measure/cache.ts
4
5
  /**
6
+ * Measurement Cache
7
+ *
8
+ * LRU cache for text width measurements and paragraph layout results.
9
+ * Improves performance by avoiding repeated measurements of identical content.
10
+ */
11
+ /**
5
12
  * Default max entries for text width cache
6
13
  * Large documents (30+ pages) can generate 20,000+ unique text measurements.
7
14
  * A generous default avoids cache thrashing on big docs.
@@ -176,21 +183,31 @@ const imageMeasureCacheInput = (run) => ({
176
183
  exactLineHeight: run.exactLineHeight,
177
184
  positioned: run.position !== void 0
178
185
  });
179
- const runMeasureCacheInput = (run) => {
186
+ const runMeasureCacheInput = (run, fontContextRef) => {
180
187
  switch (run.kind) {
181
188
  case "text":
182
189
  case "tab":
183
- case "lineBreak":
184
190
  case "renderedPageBreak":
185
191
  case "field":
186
- case "math": return run;
192
+ case "math": {
193
+ const { embeddedFontFamilyMap, ...formatting } = run;
194
+ return {
195
+ ...formatting,
196
+ embeddedFontFamilies: fontContextRef(embeddedFontFamilyMap)
197
+ };
198
+ }
199
+ case "lineBreak": return run;
187
200
  case "image": return imageMeasureCacheInput(run);
188
201
  default: return run;
189
202
  }
190
203
  };
191
- const paragraphAttrsMeasureCacheInput = (attrs) => {
204
+ const paragraphAttrsMeasureCacheInput = (attrs, fontContextRef) => {
192
205
  if (attrs === void 0) return void 0;
193
- const { snapToGrid, ...measurementAttrs } = attrs;
206
+ const { snapToGrid, embeddedFontFamilyMap, ...rest } = attrs;
207
+ const measurementAttrs = {
208
+ ...rest,
209
+ embeddedFontFamilies: fontContextRef(embeddedFontFamilyMap)
210
+ };
194
211
  if (measurementAttrs.documentGridLinePitch === void 0) return measurementAttrs;
195
212
  return {
196
213
  ...measurementAttrs,
@@ -199,10 +216,25 @@ const paragraphAttrsMeasureCacheInput = (attrs) => {
199
216
  };
200
217
  /** Serialize the complete, semantically normalized paragraph measurement contract into a cache key. */
201
218
  function hashParagraphBlock(block) {
219
+ const fontContexts = [];
220
+ const contextRefs = /* @__PURE__ */ new Map();
221
+ const fontContextRef = (families) => {
222
+ if (!families) return void 0;
223
+ const fingerprint = embeddedFontFingerprint(families);
224
+ const existing = contextRefs.get(fingerprint);
225
+ if (existing !== void 0) return existing;
226
+ const index = fontContexts.length;
227
+ contextRefs.set(fingerprint, index);
228
+ fontContexts.push(fingerprint);
229
+ return index;
230
+ };
231
+ const attrs = paragraphAttrsMeasureCacheInput(block.attrs, fontContextRef);
232
+ const runs = block.runs.map((run) => runMeasureCacheInput(run, fontContextRef));
202
233
  return JSON.stringify({
203
234
  lineBreakProviderGeneration: getLineBreakProviderGeneration(),
204
- attrs: paragraphAttrsMeasureCacheInput(block.attrs),
205
- runs: block.runs.map(runMeasureCacheInput)
235
+ attrs,
236
+ runs,
237
+ fontContexts
206
238
  });
207
239
  }
208
240
  /**
@@ -96,6 +96,7 @@ const WORD_SINGLE_LINE_FLOOR = 1.15;
96
96
  */
97
97
  function calculateEmptyParagraphMetrics(fontSize, spacing, fontFamily, attrs) {
98
98
  const result = calculateTypographyMetrics(fontSize, spacing, getFontMetrics({
99
+ ...attrs?.embeddedFontFamilyMap ? { embeddedFontFamilyMap: attrs.embeddedFontFamilyMap } : {},
99
100
  fontSize,
100
101
  fontFamily: fontFamily ?? "Times New Roman",
101
102
  ...attrs?.defaultAlternateFontFamily !== void 0 ? { alternateFontFamily: attrs.defaultAlternateFontFamily } : {}
@@ -13,6 +13,7 @@ declare const DEFAULT_TAB_STOP_TWIPS = 720;
13
13
  * of the paragraph do not format its number.
14
14
  */
15
15
  declare function resolveListMarkerFont(block: ParagraphBlock): {
16
+ embeddedFontFamilyMap?: ReadonlyMap<string, string>;
16
17
  fontFamily: string;
17
18
  alternateFontFamily?: string;
18
19
  fontSize: number;
@@ -27,6 +27,7 @@ function resolveListMarkerFont(block) {
27
27
  alternateFontFamily = markerFormatting.alternateFontFamily;
28
28
  }
29
29
  const base = {
30
+ ...attrs?.embeddedFontFamilyMap ? { embeddedFontFamilyMap: attrs.embeddedFontFamilyMap } : {},
30
31
  fontFamily,
31
32
  ...alternateFontFamily !== void 0 ? { alternateFontFamily } : {},
32
33
  fontSize: markerFormatting?.fontSize ?? attrs?.defaultFontSize ?? DEFAULT_FONT_SIZE,
@@ -61,8 +61,7 @@ function canvasGetFontMetrics(style) {
61
61
  const bold = style.bold ?? false;
62
62
  const italic = style.italic ?? false;
63
63
  const fontVariant = style.fontVariant;
64
- const alternateFontFamily = style.alternateFontFamily;
65
- const fontCacheFamily = alternateFontFamily ? `${fontFamily}\u0000${alternateFontFamily}` : fontFamily;
64
+ const fontCacheFamily = getResolvedData(fontFamily, style).cssFallback;
66
65
  const cached = getCachedFontMetrics(fontCacheFamily, fontSize, bold, italic, fontVariant);
67
66
  if (cached !== void 0) return {
68
67
  fontSize,
@@ -98,7 +97,7 @@ function canvasGetFontMetrics(style) {
98
97
  }
99
98
  } catch {}
100
99
  lineHeight = Math.max(lineHeight, ascent + descent);
101
- const singleLineRatio = getResolvedData(fontFamily, alternateFontFamily).singleLineRatio;
100
+ const singleLineRatio = getResolvedData(fontFamily, style).singleLineRatio;
102
101
  const result = {
103
102
  fontSize,
104
103
  ascent,
@@ -165,7 +164,7 @@ function canvasMeasureTextWidth(text, sourceStyle) {
165
164
  * takes the single-font path (no double-counting, no recursion).
166
165
  */
167
166
  function glyphAdvanceStyle(style) {
168
- const result = {};
167
+ const result = { ...style.embeddedFontFamilyMap ? { embeddedFontFamilyMap: style.embeddedFontFamilyMap } : {} };
169
168
  if (style.fontFamily !== void 0) result.fontFamily = style.fontFamily;
170
169
  if (style.alternateFontFamily !== void 0) result.alternateFontFamily = style.alternateFontFamily;
171
170
  if (style.fontSize !== void 0) result.fontSize = style.fontSize;
@@ -33,20 +33,17 @@ type ResolvedFontCache = {
33
33
  /**
34
34
  * Get the resolved font data for a font family, with caching.
35
35
  */
36
- declare function getResolvedData(fontFamily: string, alternateFontFamily?: string): ResolvedFontCache;
36
+ type ResolvedDataOptions = {
37
+ alternateFontFamily?: string | undefined;
38
+ embeddedFontFamilyMap?: ReadonlyMap<string, string> | undefined;
39
+ };
40
+ declare function getResolvedData(fontFamily: string, options?: ResolvedDataOptions): ResolvedFontCache;
37
41
  /**
38
42
  * Whether a face of `family` (a `FontFace.family`, possibly quoted) can change
39
43
  * a width this page has measured.
40
44
  */
41
45
  declare function isLayoutFontFamily(family: string): boolean;
42
- /**
43
- * Clear the resolved-font-family cache. `resolveFontFamily`'s output for a
44
- * given key can change even when the raw font names don't — e.g. when the
45
- * active document's embedded-font family map changes (see
46
- * `utils/fontResolver.ts`'s `setEmbeddedFontFamilyMap`) — so this must be
47
- * cleared whenever that happens, not just on font-name changes. Folded into
48
- * `clearAllCaches` (`./cache.ts`) so callers get it for free.
49
- */
46
+ /** Clear cached resolution after a browser font-set or font-policy change. */
50
47
  declare function clearFontResolvedCache(): void;
51
48
  /**
52
49
  * Build a CSS font string from styling properties
@@ -59,6 +59,7 @@ function buildRunFontStyle(run, fallbackFontFamily, fallbackFontSize) {
59
59
  const horizontalScale = normalizeHorizontalScalePercent(run.horizontalScale);
60
60
  return {
61
61
  fontFamily: run.fontFamily ?? fallbackFontFamily,
62
+ ...run.embeddedFontFamilyMap ? { embeddedFontFamilyMap: run.embeddedFontFamilyMap } : {},
62
63
  ...run.alternateFontFamily !== void 0 ? { alternateFontFamily: run.alternateFontFamily } : {},
63
64
  ...run.eastAsiaFontFamily !== void 0 ? { eastAsiaFontFamily: run.eastAsiaFontFamily } : {},
64
65
  ...run.eastAsiaAlternateFontFamily !== void 0 ? { eastAsiaAlternateFontFamily: run.eastAsiaAlternateFontFamily } : {},
@@ -80,19 +81,27 @@ function buildRunFontStyle(run, fallbackFontFamily, fallbackFontSize) {
80
81
  }
81
82
  /** Cache for resolved font data */
82
83
  const fontResolvedCache = /* @__PURE__ */ new Map();
83
- /**
84
- * Get the resolved font data for a font family, with caching.
85
- */
86
- function getResolvedData(fontFamily, alternateFontFamily) {
84
+ let embeddedFontResolvedCaches = /* @__PURE__ */ new WeakMap();
85
+ function getResolvedData(fontFamily, options = {}) {
86
+ const { alternateFontFamily, embeddedFontFamilyMap } = options;
87
+ let cache = fontResolvedCache;
88
+ if (embeddedFontFamilyMap) {
89
+ const owned = embeddedFontResolvedCaches.get(embeddedFontFamilyMap);
90
+ cache = owned ?? /* @__PURE__ */ new Map();
91
+ if (!owned) embeddedFontResolvedCaches.set(embeddedFontFamilyMap, cache);
92
+ }
87
93
  const cacheKey = `${fontFamily}\u0000${alternateFontFamily ?? ""}`;
88
- let cached = fontResolvedCache.get(cacheKey);
94
+ let cached = cache.get(cacheKey);
89
95
  if (cached === void 0) {
90
- const resolved = resolveFontFamily(fontFamily, alternateFontFamily);
96
+ const resolved = resolveFontFamily(fontFamily, {
97
+ alternateFontName: alternateFontFamily,
98
+ embeddedFontFamilyMap
99
+ });
91
100
  cached = {
92
101
  cssFallback: resolved.cssFallback,
93
102
  singleLineRatio: resolved.singleLineRatio
94
103
  };
95
- fontResolvedCache.set(cacheKey, cached);
104
+ cache.set(cacheKey, cached);
96
105
  for (const family of parseFontFamilyList(resolved.cssFallback)) layoutFontFamilies.add(normalizeFontFamilyName(family));
97
106
  }
98
107
  return cached;
@@ -119,19 +128,13 @@ function isLayoutFontFamily(family) {
119
128
  /**
120
129
  * Get the CSS fallback string for a font family, with caching.
121
130
  */
122
- function getResolvedFallback(fontFamily, alternateFontFamily) {
123
- return getResolvedData(fontFamily, alternateFontFamily).cssFallback;
131
+ function getResolvedFallback(fontFamily, style) {
132
+ return getResolvedData(fontFamily, style).cssFallback;
124
133
  }
125
- /**
126
- * Clear the resolved-font-family cache. `resolveFontFamily`'s output for a
127
- * given key can change even when the raw font names don't — e.g. when the
128
- * active document's embedded-font family map changes (see
129
- * `utils/fontResolver.ts`'s `setEmbeddedFontFamilyMap`) — so this must be
130
- * cleared whenever that happens, not just on font-name changes. Folded into
131
- * `clearAllCaches` (`./cache.ts`) so callers get it for free.
132
- */
134
+ /** Clear cached resolution after a browser font-set or font-policy change. */
133
135
  function clearFontResolvedCache() {
134
136
  fontResolvedCache.clear();
137
+ embeddedFontResolvedCaches = /* @__PURE__ */ new WeakMap();
135
138
  }
136
139
  /**
137
140
  * Build a CSS font string from styling properties
@@ -154,7 +157,7 @@ function buildFontString(style) {
154
157
  const fontSizePx = ptToPx(style.fontSize ?? 11);
155
158
  parts.push(`${fontSizePx}px`);
156
159
  const fontFamily = style.fontFamily ?? "Times New Roman";
157
- parts.push(getResolvedFallback(fontFamily, style.alternateFontFamily));
160
+ parts.push(getResolvedFallback(fontFamily, style));
158
161
  return parts.join(" ");
159
162
  }
160
163
  /**
@@ -169,6 +169,7 @@ function measureParagraph(block, maxWidth, options) {
169
169
  const metrics = lineFontMetrics ?? getFontMetrics({
170
170
  fontSize: paragraphFontSize,
171
171
  fontFamily: paragraphFontFamily,
172
+ ...attrs?.embeddedFontFamilyMap ? { embeddedFontFamilyMap: attrs.embeddedFontFamilyMap } : {},
172
173
  ...attrs?.defaultAlternateFontFamily !== void 0 ? { alternateFontFamily: attrs.defaultAlternateFontFamily } : {}
173
174
  });
174
175
  const finalTypography = { ...calculateTypographyMetrics(fontSize, spacing, metrics) };
@@ -402,6 +403,7 @@ function measureParagraph(block, maxWidth, options) {
402
403
  if (isMathRun(run)) {
403
404
  const style = {
404
405
  fontFamily: run.fontFamily ?? "Cambria Math",
406
+ ...run.embeddedFontFamilyMap ? { embeddedFontFamilyMap: run.embeddedFontFamilyMap } : {},
405
407
  fontSize: run.fontSize ?? 11,
406
408
  ...run.bold !== void 0 ? { bold: run.bold } : {},
407
409
  ...run.italic !== void 0 ? { italic: run.italic } : {}
@@ -13,6 +13,8 @@ declare namespace measureTypes_d_exports {
13
13
  * Font styling properties for measurement
14
14
  */
15
15
  type FontStyle = {
16
+ /** Embedded families owned by this editor, never ambient process state. */
17
+ embeddedFontFamilyMap?: ReadonlyMap<string, string>;
16
18
  fontFamily?: string;
17
19
  alternateFontFamily?: string;
18
20
  /**
@@ -13,6 +13,8 @@ type BlockId = string | number;
13
13
  * Common run formatting properties applied to text runs.
14
14
  */
15
15
  type RunFormatting = {
16
+ /** Embedded families owned by this editor, never ambient process state. */
17
+ embeddedFontFamilyMap?: ReadonlyMap<string, string>;
16
18
  bold?: boolean;
17
19
  italic?: boolean;
18
20
  /**
@@ -160,7 +162,7 @@ type RunFormatting = {
160
162
  /** Groups a suggestion's runs for accept/reject and scroll-to. */
161
163
  suggestionId?: string;
162
164
  };
163
- type ListMarkerFormatting = Pick<RunFormatting, "fontFamily" | "alternateFontFamily" | "eastAsiaFontFamily" | "eastAsiaAlternateFontFamily" | "complexScriptFontFamily" | "complexScriptAlternateFontFamily" | "fontSize" | "complexScriptFontSize" | "bold" | "complexScriptBold" | "italic" | "complexScriptItalic" | "rtl" | "forceComplexScript" | "color">;
165
+ type ListMarkerFormatting = Pick<RunFormatting, "embeddedFontFamilyMap" | "fontFamily" | "alternateFontFamily" | "eastAsiaFontFamily" | "eastAsiaAlternateFontFamily" | "complexScriptFontFamily" | "complexScriptAlternateFontFamily" | "fontSize" | "complexScriptFontSize" | "bold" | "complexScriptBold" | "italic" | "complexScriptItalic" | "rtl" | "forceComplexScript" | "color">;
164
166
  /**
165
167
  * Hyperlink information for a run.
166
168
  */
@@ -416,6 +418,7 @@ declare const isListNumPr: (value: ParagraphNumberingOverride | null | undefined
416
418
  * Paragraph block attributes.
417
419
  */
418
420
  type ParagraphAttrs = {
421
+ embeddedFontFamilyMap?: ReadonlyMap<string, string>;
419
422
  alignment?: "left" | "center" | "right" | "justify";
420
423
  /** Document-generation policy for justified line fitting. */
421
424
  justificationCompatibility?: {
@@ -93,6 +93,7 @@ type PaintPageRequest = {
93
93
  readonly options: RenderPageOptions;
94
94
  };
95
95
  type RenderPageOptions = {
96
+ embeddedFontFamilyMap?: ReadonlyMap<string, string>;
96
97
  /** Document to create elements in (default: window.document) */
97
98
  document?: Document;
98
99
  /** Bookmark name -> 1-indexed page, for resolving PAGEREF fields at paint. */
@@ -1,3 +1,4 @@
1
+ import { embeddedFontFingerprint } from "../fonts/embeddedFontFingerprint.js";
1
2
  import "../layout-engine/measure/floatingLineClearance.js";
2
3
  import { resolveFloatingTableX } from "../layout-engine/measure/floatingTablePosition.js";
3
4
  import { rectsToFloatingZones } from "../layout-engine/measure/floatingZones.js";
@@ -59,7 +60,7 @@ function applyPageStyles(element, width, height, options) {
59
60
  element.style.border = "none";
60
61
  element.style.boxShadow = "none";
61
62
  element.style.outline = "none";
62
- element.style.fontFamily = getDefaultPageFontFamily();
63
+ element.style.fontFamily = resolveFontFamily(DEFAULT_FONT_FAMILY, options).cssFallback;
63
64
  element.style.fontSize = `${1056 / 72}px`;
64
65
  element.style.color = "var(--doc-canvas-text, #000)";
65
66
  }
@@ -179,7 +180,10 @@ function syncPageWatermarkOverlay(pageEl, page, options, doc) {
179
180
  for (const stale of Array.from(pageEl.querySelectorAll(":scope > .layout-page-watermark"))) stale.remove();
180
181
  const watermark = options.watermark;
181
182
  if (!watermark) return;
182
- const overlay = renderWatermarkLayer(watermark, page, doc, options.watermarkImageSrc !== void 0 ? { imageSrc: options.watermarkImageSrc } : {});
183
+ const overlay = renderWatermarkLayer(watermark, page, doc, {
184
+ ...options.watermarkImageSrc !== void 0 ? { imageSrc: options.watermarkImageSrc } : {},
185
+ ...options.embeddedFontFamilyMap ? { embeddedFontFamilyMap: options.embeddedFontFamilyMap } : {}
186
+ });
183
187
  if (!overlay) return;
184
188
  const contentEl = pageEl.querySelector(`:scope > .${PAGE_CLASS_NAMES.content}`);
185
189
  if (contentEl) {
@@ -785,7 +789,10 @@ function renderPage(page, context, options = {}) {
785
789
  const pageBorderEl = renderPageBorderOverlay(page, options, doc);
786
790
  if (pageBorderEl && options.pageBorders?.zOrder === "back") pageEl.append(pageBorderEl);
787
791
  if (options.watermark) {
788
- const watermarkEl = renderWatermarkLayer(options.watermark, page, doc, options.watermarkImageSrc !== void 0 ? { imageSrc: options.watermarkImageSrc } : {});
792
+ const watermarkEl = renderWatermarkLayer(options.watermark, page, doc, {
793
+ ...options.watermarkImageSrc !== void 0 ? { imageSrc: options.watermarkImageSrc } : {},
794
+ ...options.embeddedFontFamilyMap ? { embeddedFontFamilyMap: options.embeddedFontFamilyMap } : {}
795
+ });
789
796
  if (watermarkEl) pageEl.append(watermarkEl);
790
797
  }
791
798
  const contentEl = doc.createElement("div");
@@ -1403,6 +1410,7 @@ function headerFooterContentFingerprint(prefix, entries) {
1403
1410
  */
1404
1411
  function computeOptionsHash(options) {
1405
1412
  const parts = [];
1413
+ if (options.embeddedFontFamilyMap) parts.push(`embedded-fonts:${embeddedFontFingerprint(options.embeddedFontFamilyMap)}`);
1406
1414
  if (options.headerContent) parts.push(`hdr:${options.headerContent.blocks.length},${options.headerContent.height},${options.headerContent.visualTop ?? 0},${options.headerContent.visualBottom ?? options.headerContent.height},${options.headerContent.rId ?? ""},${options.headerContent.textSig ?? ""}`);
1407
1415
  if (options.footerContent) parts.push(`ftr:${options.footerContent.blocks.length},${options.footerContent.height},${options.footerContent.visualTop ?? 0},${options.footerContent.visualBottom ?? options.footerContent.height},${options.footerContent.rId ?? ""},${options.footerContent.textSig ?? ""}`);
1408
1416
  parts.push(...headerFooterContentFingerprint("hdr-map", options.headerContentByRId));
@@ -190,7 +190,10 @@ const UNICODE_BIDI_BY_WRAPPER_CONTROL = {
190
190
  * Apply text run styles to an element
191
191
  */
192
192
  function applyRunStyles(element, run) {
193
- if (run.fontFamily) element.style.fontFamily = resolveFontFamily(run.fontFamily, run.alternateFontFamily).cssFallback;
193
+ if (run.fontFamily) element.style.fontFamily = resolveFontFamily(run.fontFamily, {
194
+ alternateFontName: run.alternateFontFamily,
195
+ embeddedFontFamilyMap: run.embeddedFontFamilyMap
196
+ }).cssFallback;
194
197
  if (run.fontSize) element.style.fontSize = `${fontSizePtToPx(run.fontSize)}px`;
195
198
  if (run.bold) element.style.fontWeight = "700";
196
199
  if (run.italic) element.style.fontStyle = "italic";
@@ -1043,6 +1046,7 @@ function runVisualSpaceContraction({ text, horizontalScale, visualSpaceContracti
1043
1046
  */
1044
1047
  function runMeasureStyle(run) {
1045
1048
  return {
1049
+ ...run.embeddedFontFamilyMap ? { embeddedFontFamilyMap: run.embeddedFontFamilyMap } : {},
1046
1050
  ...run.bold !== void 0 ? { bold: run.bold } : {},
1047
1051
  ...run.italic !== void 0 ? { italic: run.italic } : {},
1048
1052
  ...run.letterSpacing !== void 0 ? { letterSpacing: run.letterSpacing } : {},
@@ -1168,7 +1172,10 @@ function createTextMeasurer(doc) {
1168
1172
  if (style.smallCaps) fontPrefixParts.push("small-caps");
1169
1173
  if (bold) fontPrefixParts.push("700");
1170
1174
  fontPrefixParts.push(`${size * 96 / 72}px`);
1171
- return `${fontPrefixParts.join(" ")} ${resolveFontFamily(family, alternateFamily).cssFallback}`;
1175
+ return `${fontPrefixParts.join(" ")} ${resolveFontFamily(family, {
1176
+ alternateFontName: alternateFamily,
1177
+ embeddedFontFamilyMap: style.embeddedFontFamilyMap
1178
+ }).cssFallback}`;
1172
1179
  };
1173
1180
  const baseFont = fontString(fontFamily, fontSize, style.bold, style.italic, style.alternateFontFamily);
1174
1181
  const complex = resolveComplexScriptFormatting(style);
@@ -1670,7 +1677,10 @@ function renderListMarker({ marker, inlineWidth, visualOffset, doc, formatting,
1670
1677
  const span = doc.createElement("span");
1671
1678
  span.className = "layout-list-marker";
1672
1679
  span.style.display = "inline-block";
1673
- span.style.fontFamily = resolveFontFamily(formatting.fontFamily, formatting.alternateFontFamily).cssFallback;
1680
+ span.style.fontFamily = resolveFontFamily(formatting.fontFamily, {
1681
+ alternateFontName: formatting.alternateFontFamily,
1682
+ embeddedFontFamilyMap: formatting.embeddedFontFamilyMap
1683
+ }).cssFallback;
1674
1684
  if (formatting.fontSize) span.style.fontSize = `${formatting.fontSize * 96 / 72}px`;
1675
1685
  if (formatting.bold !== void 0) span.style.fontWeight = formatting.bold ? "700" : "normal";
1676
1686
  if (formatting.italic !== void 0) span.style.fontStyle = formatting.italic ? "italic" : "normal";
@@ -2,6 +2,7 @@ import { document_d_exports } from "../types/document.js";
2
2
  import { Page } from "../layout-engine/types.js";
3
3
  //#region src/layout-painter/renderWatermark.d.ts
4
4
  type RenderWatermarkOptions = {
5
+ embeddedFontFamilyMap?: ReadonlyMap<string, string>;
5
6
  /** Resolved image src for picture watermarks (`data:` / `blob:` only). */
6
7
  imageSrc?: string;
7
8
  };
@@ -25,7 +25,11 @@ function renderWatermarkLayer(watermark, page, doc, options = {}) {
25
25
  layer.style.display = "flex";
26
26
  layer.style.alignItems = "center";
27
27
  layer.style.justifyContent = "center";
28
- if (watermark.kind === "text") layer.append(renderTextWatermark(watermark, doc));
28
+ if (watermark.kind === "text") layer.append(renderTextWatermark({
29
+ watermark,
30
+ doc,
31
+ options
32
+ }));
29
33
  else {
30
34
  const imageSrc = options.imageSrc;
31
35
  if (!imageSrc) return null;
@@ -33,10 +37,10 @@ function renderWatermarkLayer(watermark, page, doc, options = {}) {
33
37
  }
34
38
  return layer;
35
39
  }
36
- function renderTextWatermark(watermark, doc) {
40
+ function renderTextWatermark({ watermark, doc, options }) {
37
41
  const el = doc.createElement("div");
38
42
  el.textContent = watermark.text;
39
- el.style.fontFamily = resolveFontFamily(watermark.font ?? "Calibri").cssFallback;
43
+ el.style.fontFamily = resolveFontFamily(watermark.font ?? "Calibri", options).cssFallback;
40
44
  el.style.fontSize = "144px";
41
45
  el.style.fontWeight = "bold";
42
46
  el.style.whiteSpace = "nowrap";
@@ -1,6 +1,7 @@
1
1
  import { HistoryShortcutOwner } from "../prosemirror/extensions/core/HistoryExtension.js";
2
2
  import { EditorState, Transaction } from "prosemirror-state";
3
3
  //#region src/managers/editorShortcuts.d.ts
4
+ declare const DEFAULT_KEYBOARD_SHORTCUT_SCOPE = "editor";
4
5
  declare function isMacPlatform(): boolean;
5
6
  /**
6
7
  * `target` is an input-like element that the user is typing into. We must
@@ -82,4 +83,4 @@ declare function isKeydownInShortcutScope(event: {
82
83
  */
83
84
  declare function deleteSelectedTable(state: EditorState, dispatch: (tr: Transaction) => void): boolean;
84
85
  //#endregion
85
- export { ClassifyEditorKeydownOptions, EditorKeydownIntent, HostShortcut, IsKeydownInShortcutScopeOptions, KeyboardShortcutScope, ShortcutScopeRoot, classifyEditorKeydown, deleteSelectedTable, historyShortcutOwner, isFocusInInputLike, isKeydownInShortcutScope, isMacPlatform };
86
+ export { ClassifyEditorKeydownOptions, DEFAULT_KEYBOARD_SHORTCUT_SCOPE, EditorKeydownIntent, HostShortcut, IsKeydownInShortcutScopeOptions, KeyboardShortcutScope, ShortcutScopeRoot, classifyEditorKeydown, deleteSelectedTable, historyShortcutOwner, isFocusInInputLike, isKeydownInShortcutScope, isMacPlatform };
@@ -1,6 +1,7 @@
1
1
  import { deleteTable } from "../prosemirror/commands/table.js";
2
2
  import { getTableContext } from "../prosemirror/extensions/nodes/TableExtension.js";
3
3
  //#region src/managers/editorShortcuts.ts
4
+ const DEFAULT_KEYBOARD_SHORTCUT_SCOPE = "editor";
4
5
  function isMacPlatform() {
5
6
  if (typeof navigator === "undefined") return false;
6
7
  return /Mac|iPod|iPhone|iPad/u.test(navigator.platform);
@@ -78,4 +79,4 @@ function deleteSelectedTable(state, dispatch) {
78
79
  return false;
79
80
  }
80
81
  //#endregion
81
- export { classifyEditorKeydown, deleteSelectedTable, historyShortcutOwner, isFocusInInputLike, isKeydownInShortcutScope, isMacPlatform };
82
+ export { DEFAULT_KEYBOARD_SHORTCUT_SCOPE, classifyEditorKeydown, deleteSelectedTable, historyShortcutOwner, isFocusInInputLike, isKeydownInShortcutScope, isMacPlatform };
@@ -40,7 +40,33 @@ function renderParagraphBlock(ctx, pkg, para) {
40
40
  let list = para.listRendering;
41
41
  if (numPr?.kind === "none" || pkg?.numbering !== void 0 && numPr === void 0) list = void 0;
42
42
  else if (pkg?.numbering !== void 0 && numPr?.kind === "reference") list = resolveCachedListRendering(para.listRendering, resolveListRenderingDefinition(numPr, getCachedNumberingMap(pkg.numbering))) ?? void 0;
43
- const label = ctx.nextListLabel(list ? listLabelAttrsFromRendering(list, numPrFromStyle) : UNNUMBERED);
43
+ const counterAttrs = listLabelAttrsFromRendering(list, {
44
+ numPr: para.formatting?.numPr,
45
+ numPrFromStyle
46
+ });
47
+ if (para.pPrMark) counterAttrs.pPrMark = para.pPrMark;
48
+ let originalList;
49
+ if (para.propertyChanges) counterAttrs._propertyChanges = para.propertyChanges.map(({ previousFormatting, ...change }) => {
50
+ if (!previousFormatting) return change;
51
+ const previousInherited = ctx.paragraphNumbering(previousFormatting.styleId) ?? previousFormatting.numPrFromStyle;
52
+ const previousNumbering = mergeParagraphNumbering(previousInherited, previousFormatting.numPr);
53
+ const previousRendering = pkg?.numbering !== void 0 && previousNumbering?.kind === "reference" ? resolveListRenderingDefinition(previousNumbering, getCachedNumberingMap(pkg.numbering)).rendering ?? void 0 : void 0;
54
+ originalList ??= previousRendering;
55
+ const previousAttrs = listLabelAttrsFromRendering(previousRendering, {
56
+ numPr: previousFormatting.numPr,
57
+ numPrFromStyle: previousInherited
58
+ });
59
+ return {
60
+ ...change,
61
+ previousFormatting: {
62
+ ...previousFormatting,
63
+ ...previousAttrs,
64
+ ...previousAttrs.numPr === void 0 ? { numPr: null } : { numPr: previousAttrs.numPr },
65
+ ...previousAttrs.numPrFromStyle === void 0 ? { numPrFromStyle: null } : { numPrFromStyle: previousAttrs.numPrFromStyle }
66
+ }
67
+ };
68
+ });
69
+ const label = ctx.nextListLabel(counterAttrs);
44
70
  const inline = renderParagraphInline(ctx, pkg, para.content, para.paraId);
45
71
  const styleId = para.formatting?.styleId;
46
72
  const headingLevel = markdownHeadingLevel(ctx, para);
@@ -57,7 +83,8 @@ function renderParagraphBlock(ctx, pkg, para) {
57
83
  type: "paragraph"
58
84
  };
59
85
  }
60
- if (list && label !== void 0) return renderListItem(ctx, list, label, inline);
86
+ const visibleList = list ?? originalList;
87
+ if (visibleList && label !== void 0) return renderListItem(ctx, visibleList, label, inline);
61
88
  ctx.listIndentWidths = [];
62
89
  if (isQuoteStyle(styleId, ctx.builtInStyles)) return {
63
90
  markdown: inline.split("\n").map((line) => `> ${line}`).join("\n"),
@@ -75,7 +102,6 @@ function markdownHeadingLevel(ctx, para) {
75
102
  styleId: para.formatting?.styleId
76
103
  }, ctx.builtInStyles);
77
104
  }
78
- const UNNUMBERED = Object.freeze({});
79
105
  /**
80
106
  * A plain paragraph whose visible text begins with markdown block syntax (e.g.
81
107
  * `# Not a heading`, `- value`, `1. value`, `> quote`) would be reclassified as
@@ -1,9 +1,12 @@
1
+ import { Node } from "prosemirror-model";
1
2
  import { EditorState } from "prosemirror-state";
2
3
  //#region src/prosemirror/canonicalSelectionRange.d.ts
4
+ /** Document edges denote the first and last editable content gaps. */
5
+ declare const canonicalContentPosition: (doc: Node, position: number) => number;
3
6
  /** Whole-document selection addresses paragraph content rather than document edges. */
4
7
  declare const canonicalSelectionRange: ({ doc, selection }: EditorState) => {
5
8
  from: number;
6
9
  to: number;
7
10
  };
8
11
  //#endregion
9
- export { canonicalSelectionRange };
12
+ export { canonicalContentPosition, canonicalSelectionRange };
@@ -1,10 +1,16 @@
1
1
  import { AllSelection, Selection } from "prosemirror-state";
2
2
  //#region src/prosemirror/canonicalSelectionRange.ts
3
+ /** Document edges denote the first and last editable content gaps. */
4
+ const canonicalContentPosition = (doc, position) => {
5
+ if (position === 0) return Selection.atStart(doc).from;
6
+ if (position === doc.content.size) return Selection.atEnd(doc).to;
7
+ return position;
8
+ };
3
9
  /** Whole-document selection addresses paragraph content rather than document edges. */
4
10
  const canonicalSelectionRange = ({ doc, selection }) => {
5
11
  if (selection instanceof AllSelection) return {
6
- from: Selection.atStart(doc).from,
7
- to: Selection.atEnd(doc).to
12
+ from: canonicalContentPosition(doc, selection.from),
13
+ to: canonicalContentPosition(doc, selection.to)
8
14
  };
9
15
  return {
10
16
  from: selection.from,
@@ -12,4 +18,4 @@ const canonicalSelectionRange = ({ doc, selection }) => {
12
18
  };
13
19
  };
14
20
  //#endregion
15
- export { canonicalSelectionRange };
21
+ export { canonicalContentPosition, canonicalSelectionRange };