@stll/folio-core 0.59.0 → 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 (116) hide show
  1. package/README.md +10 -1
  2. package/dist/compat/eigenpal.d.ts +2 -2
  3. package/dist/compat/eigenpal.js +2 -2
  4. package/dist/controller/canonicalSession.js +3 -2
  5. package/dist/controller/canonicalStructure.js +10 -7
  6. package/dist/controller/fontReadiness.js +1 -1
  7. package/dist/controller/layoutPipeline.js +7 -1
  8. package/dist/controller/layoutSession.d.ts +2 -0
  9. package/dist/display-list/build/fontTable.js +7 -5
  10. package/dist/display-list/build/furniture.d.ts +1 -0
  11. package/dist/display-list/build/furniture.js +1 -0
  12. package/dist/display-list/build/watermarkPrimitives.d.ts +2 -1
  13. package/dist/display-list/build/watermarkPrimitives.js +9 -3
  14. package/dist/display-list/editor/pageRenderer.js +1 -0
  15. package/dist/docx/bookmarkIdNormalization.d.ts +10 -0
  16. package/dist/docx/bookmarkIdNormalization.js +100 -0
  17. package/dist/docx/bookmarkParser.js +4 -2
  18. package/dist/docx/importedIdCollisions.d.ts +136 -0
  19. package/dist/docx/importedIdCollisions.js +215 -0
  20. package/dist/docx/numberingParser.js +2 -2
  21. package/dist/docx/paragraphPropertySource.js +1 -2
  22. package/dist/docx/parseContext.d.ts +2 -1
  23. package/dist/docx/parseContext.js +1 -0
  24. package/dist/docx/parseWarningMessage.js +1 -0
  25. package/dist/docx/parser.js +5 -1
  26. package/dist/docx/relsParser.js +1 -1
  27. package/dist/docx/rezip.js +2 -1
  28. package/dist/docx/selectedXmlIdentityScan.d.ts +10 -0
  29. package/dist/docx/selectedXmlIdentityScan.js +36 -0
  30. package/dist/docx/selectiveSave.js +5 -4
  31. package/dist/docx/selectiveXmlPatch.js +44 -52
  32. package/dist/docx/serializer/commentSerializer.d.ts +3 -1
  33. package/dist/docx/serializer/commentSerializer.js +11 -2
  34. package/dist/docx/serializer/runSerializer.js +2 -2
  35. package/dist/docx/serializer/trackedChangeAttributes.d.ts +1 -3
  36. package/dist/docx/serializer/trackedChangeAttributes.js +1 -11
  37. package/dist/fonts/embeddedFontFingerprint.d.ts +5 -0
  38. package/dist/fonts/embeddedFontFingerprint.js +18 -0
  39. package/dist/fonts/embeddedFonts.d.ts +1 -1
  40. package/dist/fonts/embeddedFonts.js +1 -1
  41. package/dist/fonts/headlessMeasure.js +0 -0
  42. package/dist/headless-layout.js +1 -0
  43. package/dist/index.d.ts +2 -2
  44. package/dist/index.js +2 -2
  45. package/dist/layout-bridge/convert/flowConversionShared.d.ts +2 -0
  46. package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -1
  47. package/dist/layout-bridge/convert/footnoteLayout.js +3 -0
  48. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
  49. package/dist/layout-bridge/convert/headerFooterLayout.js +2 -0
  50. package/dist/layout-bridge/convert/paragraphConversion.js +8 -1
  51. package/dist/layout-bridge/convert/toFlowBlocks.js +25 -1
  52. package/dist/layout-engine/measure/cache.js +39 -7
  53. package/dist/layout-engine/measure/lineTypography.js +1 -0
  54. package/dist/layout-engine/measure/listMarkerWidth.d.ts +1 -0
  55. package/dist/layout-engine/measure/listMarkerWidth.js +1 -0
  56. package/dist/layout-engine/measure/measureContainer.js +3 -4
  57. package/dist/layout-engine/measure/measureHelpers.d.ts +6 -9
  58. package/dist/layout-engine/measure/measureHelpers.js +21 -18
  59. package/dist/layout-engine/measure/measureParagraph.js +2 -0
  60. package/dist/layout-engine/measure/measureTypes.d.ts +2 -0
  61. package/dist/layout-engine/types.d.ts +4 -1
  62. package/dist/layout-painter/renderPage.d.ts +1 -0
  63. package/dist/layout-painter/renderPage.js +11 -3
  64. package/dist/layout-painter/renderParagraph.js +13 -3
  65. package/dist/layout-painter/renderWatermark.d.ts +1 -0
  66. package/dist/layout-painter/renderWatermark.js +7 -3
  67. package/dist/managers/editorShortcuts.d.ts +2 -1
  68. package/dist/managers/editorShortcuts.js +2 -1
  69. package/dist/prosemirror/canonicalSelectionRange.d.ts +4 -1
  70. package/dist/prosemirror/canonicalSelectionRange.js +9 -3
  71. package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.d.ts +8 -2
  72. package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.js +39 -3
  73. package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.d.ts +8 -2
  74. package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.js +4 -3
  75. package/dist/prosemirror/extensions/features/ImageDragExtension.js +4 -3
  76. package/dist/prosemirror/extensions/features/JoinedRunStyleExtension.js +4 -3
  77. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +9 -3
  78. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +6 -5
  79. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +8 -2
  80. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +11 -3
  81. package/dist/prosemirror/extensions/marks/RunIdentityExtension.js +4 -3
  82. package/dist/prosemirror/extensions/marks/markUtils.js +1 -1
  83. package/dist/prosemirror/pluginKeyOwner.d.ts +13 -0
  84. package/dist/prosemirror/pluginKeyOwner.js +35 -0
  85. package/dist/prosemirror/plugins/aiCitationDecorations.d.ts +11 -4
  86. package/dist/prosemirror/plugins/aiCitationDecorations.js +16 -3
  87. package/dist/prosemirror/plugins/aiSuggestionDecorations.d.ts +11 -4
  88. package/dist/prosemirror/plugins/aiSuggestionDecorations.js +18 -3
  89. package/dist/prosemirror/plugins/anonymizationDecorations.d.ts +11 -11
  90. package/dist/prosemirror/plugins/anonymizationDecorations.js +23 -13
  91. package/dist/prosemirror/plugins/autocompleteSuggestion.d.ts +8 -2
  92. package/dist/prosemirror/plugins/autocompleteSuggestion.js +27 -5
  93. package/dist/prosemirror/plugins/contentControlWidgets.d.ts +8 -2
  94. package/dist/prosemirror/plugins/contentControlWidgets.js +4 -3
  95. package/dist/prosemirror/plugins/createDocScanPlugin.d.ts +6 -5
  96. package/dist/prosemirror/plugins/createDocScanPlugin.js +1 -1
  97. package/dist/prosemirror/plugins/documentNumbering.js +5 -3
  98. package/dist/prosemirror/plugins/documentStyleState.d.ts +8 -2
  99. package/dist/prosemirror/plugins/documentStyleState.js +2 -2
  100. package/dist/prosemirror/plugins/documentStyles.js +1 -1
  101. package/dist/prosemirror/plugins/selectionTracker.d.ts +8 -2
  102. package/dist/prosemirror/plugins/selectionTracker.js +4 -3
  103. package/dist/prosemirror/plugins/suggestionMode.d.ts +8 -2
  104. package/dist/prosemirror/plugins/suggestionMode.js +4 -3
  105. package/dist/prosemirror/plugins/templateDirectives.d.ts +8 -2
  106. package/dist/prosemirror/plugins/templateDirectives.js +19 -4
  107. package/dist/prosemirror/plugins/templatePreviewValues.d.ts +8 -2
  108. package/dist/prosemirror/plugins/templatePreviewValues.js +27 -5
  109. package/dist/prosemirror/plugins/templateSlashMenu.d.ts +8 -2
  110. package/dist/prosemirror/plugins/templateSlashMenu.js +23 -5
  111. package/dist/prosemirror/plugins/transactionInvariants.js +23 -3
  112. package/dist/utils/fontLoader.d.ts +2 -2
  113. package/dist/utils/fontLoader.js +2 -7
  114. package/dist/utils/fontResolver.d.ts +7 -3
  115. package/dist/utils/fontResolver.js +6 -8
  116. package/package.json +24 -8
package/README.md CHANGED
@@ -20,9 +20,18 @@ Part of [stella](https://github.com/stella/stella), an open-source legal workspa
20
20
  ## Install
21
21
 
22
22
  ```sh
23
- bun add @stll/folio-core
23
+ bun add @stll/folio-core \
24
+ prosemirror-commands@^1.7.1 prosemirror-dropcursor@^1.8.2 prosemirror-gapcursor@^1.4.1 prosemirror-history@^1.5.0 \
25
+ prosemirror-inputrules@^1.5.0 prosemirror-keymap@^1.2.3 prosemirror-model@^1.25.9 prosemirror-state@^1.4.4 \
26
+ prosemirror-tables@^1.8.5 prosemirror-transform@^1.12.0 prosemirror-view@^1.42.6 y-prosemirror@^1.3.7 \
27
+ y-protocols@^1.0.6 yjs@^13.6.31
24
28
  ```
25
29
 
30
+ ProseMirror and Yjs packages are required peers, including the collaboration
31
+ packages `y-prosemirror` and `y-protocols`. Install one compatible copy of each in the host
32
+ application so schemas, plugins, editor states, and collaborative documents share
33
+ the same runtime. The command above includes the complete editor peer closure.
34
+
26
35
  ## Exports
27
36
 
28
37
  | Import | What it is |
@@ -37,9 +37,9 @@ import { ImageMeta, ImageRef, MarkdownOptions, MarkdownResult } from "../markdow
37
37
  import { fromMarkdown } from "../markdown/fromMarkdown.js";
38
38
  import { toMarkdown, toMarkdownResult } from "../markdown/index.js";
39
39
  import { EmbeddedFont, EmbeddedFontParts, buildEmbeddedFontFamilyMap, extractEmbeddedFonts, getEmbeddedFontFaces, scopeEmbeddedFontFamily } from "../fonts/embeddedFonts.js";
40
- import { getGoogleFontsEnabled, setEmbeddedFontFamilyMap, setGoogleFontsEnabled } from "../utils/fontResolver.js";
40
+ import { getGoogleFontsEnabled, setGoogleFontsEnabled } from "../utils/fontResolver.js";
41
41
  import { FOLIO_YJS_ATTR_SCHEMA_VERSION, FolioYjsAttrSchemaVersion, FolioYjsAttrSchemaVersionError } from "../prosemirror/yjsDocumentMetadata.js";
42
42
  import { DOCX_CONFORMANCE_CLASSES } from "../index.js";
43
43
  type Document = document_d_exports.Document;
44
44
  type DocxConformanceClass = document_d_exports.DocxConformanceClass;
45
- export { type AIBarStatus, type AIChatMode, type AICitation, type AICitationRange, type AICitationSource, type AIGenerateInput, type AISuggestion, type AISuggestionApplyMode, type AISuggestionPreset, type AISuggestionSeverity, type AISuggestionStatus, type AcceptAutocompleteResult, type AnonymizationMatch, type AnonymizationTerm, type ApplyFolioDocumentOperationsOptions, type ApplyResult, type AutocompleteSuggestionPluginOptions, type AutocompleteSuggestionState, type AutocompleteSuggestionStatus, type AutocompleteTriggerCheck, type AutocompleteTriggerOptions, type AutocompleteTriggerSkipReason, type BlockRect, COMPARE_REVISION_FORMATS, COMPARE_UNSUPPORTED_REASONS, COMPARE_VERIFICATION_CAUSES, COMPARE_VERIFICATION_INVARIANTS, type CompareChange, type CompareChangeLocation, type CompareCompatibility, type CompareContentOptions, CompareDocxApplyError, type CompareDocxError, CompareDocxFinalParagraphMarkError, CompareDocxOperationLimitError, type CompareDocxOptions, CompareDocxParseError, CompareDocxRoundTripError, CompareDocxSerializeError, type CompareFolioRequirement, type CompareResult, type CompareRevisionFormat, type CompareUnsupportedPart, type CompareUnsupportedReason, type CompareVerification, type CompareVerificationCause, type CompareVerificationFailure, type CompareVerificationInvariant, type CreateEmptyDocumentOptions, DEFAULT_AI_SUGGESTION_PRESETS, DEFAULT_AUTOCOMPLETE_DEAD_ZONE_NODES, DEFAULT_OUTLINE_DEPTH, DOCUMENT_PRESET_VERSION, DOCUMENT_STYLE_SET_VERSION, DOCX_CONFORMANCE_CLASSES, DRAWING_SAFETY_CLASSES, type DeriveBlockIdInput, type DirectiveKind, type DirectiveRange, type Document, type DocumentPreset, type DocumentPropertiesOptions, type DocumentStyleCatalog, type DocumentStyleCatalogEntry, type DocumentStyleSet, type DocxCompatibility, type DocxCompatibilityContext, type DocxCompatibilityIssue, type DocxCompatibilityLocation, type DocxCompatibilityPart, type DocxConformanceClass, type DocxDrawingClassification, type DrawingSafetyClass, type EmbeddedFont, type EmbeddedFontParts, type ExtractDocumentStyleSetOptions, FOLIO_CONTENT_COMPARISON_LIMITS, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FOLIO_LINE_SPACING_RULE_VALUES, FOLIO_PARAGRAPH_ALIGNMENT_VALUES, FOLIO_YJS_ATTR_SCHEMA_VERSION, type FinalParagraphMarkRevision, type FolioAIBlock, type FolioAIBlockAnchor, type FolioAIBlockKind, type FolioAIBlockPreviewRun, type FolioAIBlockStructuralBoundary, type FolioAIBlockTableLocation, type FolioAIComment, type FolioAIDiagnosticBlock, type FolioAIEditAppliedOperation, type FolioAIEditApplyMode, type FolioAIEditApplyOutcome, type FolioAIEditApplyResult, type FolioAIEditNormalization, type FolioAIEditNormalizationCode, type FolioAIEditOperation, type FolioAIEditPrecondition, type FolioAIEditReviewMeta, type FolioAIEditSeverity, type FolioAIEditSkipReason, type FolioAIEditSkippedOperation, type FolioAIEditSnapshot, type FolioAIInlineBooleanProperty, type FolioAIInlineFormatting, type FolioAIInlineFormattingPatch, type FolioAIParagraphBlock, type FolioAIParagraphSpacing, type FolioAISignatureParty, type FolioBlockId, type FolioContentBlock, type FolioContentBlockProperty, type FolioContentComparison, type FolioContentComparisonError, type FolioContentComparisonEvent, type FolioContentComparisonLimit, FolioContentComparisonLimitError, type FolioContentContainerPathEntry, type FolioContentFormatRange, type FolioContentFormattingChange, type FolioContentIdStability, type FolioContentInlineBooleanProperty, type FolioContentInlineComparisonResult, type FolioContentInlineFormatting, type FolioContentInlineFormattingPatch, FolioContentInlinePresentationProjectionError, type FolioContentLineSpacingRule, type FolioContentParagraphAlignment, type FolioContentParagraphFormattingPatch, type FolioContentParagraphKind, type FolioContentParagraphSpacing, type FolioContentRun, type FolioContentSnapshot, type FolioContentStatedNumbering, type FolioContentStructuralChange, type FolioContentTableLocation, type FolioContentTextSegment, type FolioDocumentOperation, type FolioDocumentOperationAffectedTarget, type FolioDocumentOperationBatch, type FolioDocumentOperationCapabilities, type FolioDocumentOperationIssue, type FolioDocumentOperationMode, type FolioDocumentOperationPrecondition, type FolioDocumentOperationReceipt, type FolioDocumentOperationRecovery, type FolioDocumentOperationResult, type FolioDocumentOperationResultBase, type FolioDocumentOperationStatus, type FolioDocumentOperationStory, type FolioDocumentOperationType, type FolioDocumentOperationUndoFailureReason, type FolioDocumentOperationUndoHandle, type FolioDocumentOperationUndoResult, type FolioDocxCompatibilityHost, type FolioDocxCompatibilityProfile, type FolioRevisionStamp, type FolioUndefinedReferencePolicy, type FolioWordDiffOptions, type FolioYjsAttrSchemaVersion, FolioYjsAttrSchemaVersionError, type ImageMeta, type ImageRef, type InspectDocxCompatibilityOptions, InvalidCompareDocxOptionsError, InvalidFolioContentComparisonError, InvalidFolioDocumentOperationBatchError, MAX_COMPARE_OPERATIONS, type MarkdownOptions, type MarkdownResult, type OutlineDepth, type PositionalText, type ResolvedAnchor, STELLA_STYLE_SET_NAME, type TemplatePreviewHiddenRange, type TemplatePreviewSpan, type TemplatePreviewValue, type TemplatePreviewValues, type TemplateSlashMenuKeyAction, type TemplateSlashMenuState, UnsupportedFolioDocumentOperationVersionError, WORD_DIFF_GRANULARITIES, type WordDiffGranularity, type WordDiffNormalization, type WordDiffOptions, type WordDiffSegment, acceptAutocompleteSuggestion, acceptAutocompleteWord, anonymizationDecorationsKey, appendAutocompleteToken, applyFolioAIEditOperations, applyFolioDocumentOperations, applySuggestions, assertSupportedFolioDocumentOperationVersion, autocompleteSuggestionKey, autocompleteSuggestionPlugin, buildEmbeddedFontFamilyMap, buildPositionalText, clearAutocompleteSuggestion, clearTemplateSlashMenu, compareContent, compareDocx, consumeTemplateSlashQuery, createAICitationDecorationsPlugin, createDocx, createEmptyDocument, createFolioAIEditSnapshot, createStellaStyleDocumentPreset, createStellaStyleSet, currentFolioBlockId, deriveBlockId, diffWordSegments, extractDocumentStyleSet, extractDocumentStyleSetFromDocx, extractEmbeddedFonts, filterHeadingsByDepth, finishAutocompleteSuggestion, fromMarkdown, getAnonymizationMatches, getAutocompleteSuggestion, getEmbeddedFontFaces, getFolioCaretViewportRect, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioParaIdFromBlockId, getFolioSelectionViewportRect, getGoogleFontsEnabled, getTemplateDirectives, getTemplateSlashMenu, hashFolioAIBlockText, inspectDocumentStyles, inspectDocumentStylesFromDocx, inspectDocxCompatibility, isFolioAIContentBlock, isFolioBlockId, isFolioDocumentOperationModeSupported, isSequentialFolioBlockId, isSuggestionStale, isSupportedFolioDocumentOperationVersion, mergeDocumentContent, normalizeFolioAIBlockText, parseFolioDocumentOperationBatch, resetTemplateSlashQuery, resolveSuggestionAnchor, scanDirectives, scopeEmbeddedFontFamily, scrollFolioPositionIntoView, setAICitationsMeta, setAISuggestionsMeta, setActiveCitationMeta, setAnonymizationTermsMeta, setEmbeddedFontFamilyMap, setFocusedSuggestionMeta, setGoogleFontsEnabled, setTemplatePreviewValues, shouldTriggerAutocomplete, startAutocompleteSuggestion, templateSlashMenuKey, toMarkdown, toMarkdownResult };
45
+ export { type AIBarStatus, type AIChatMode, type AICitation, type AICitationRange, type AICitationSource, type AIGenerateInput, type AISuggestion, type AISuggestionApplyMode, type AISuggestionPreset, type AISuggestionSeverity, type AISuggestionStatus, type AcceptAutocompleteResult, type AnonymizationMatch, type AnonymizationTerm, type ApplyFolioDocumentOperationsOptions, type ApplyResult, type AutocompleteSuggestionPluginOptions, type AutocompleteSuggestionState, type AutocompleteSuggestionStatus, type AutocompleteTriggerCheck, type AutocompleteTriggerOptions, type AutocompleteTriggerSkipReason, type BlockRect, COMPARE_REVISION_FORMATS, COMPARE_UNSUPPORTED_REASONS, COMPARE_VERIFICATION_CAUSES, COMPARE_VERIFICATION_INVARIANTS, type CompareChange, type CompareChangeLocation, type CompareCompatibility, type CompareContentOptions, CompareDocxApplyError, type CompareDocxError, CompareDocxFinalParagraphMarkError, CompareDocxOperationLimitError, type CompareDocxOptions, CompareDocxParseError, CompareDocxRoundTripError, CompareDocxSerializeError, type CompareFolioRequirement, type CompareResult, type CompareRevisionFormat, type CompareUnsupportedPart, type CompareUnsupportedReason, type CompareVerification, type CompareVerificationCause, type CompareVerificationFailure, type CompareVerificationInvariant, type CreateEmptyDocumentOptions, DEFAULT_AI_SUGGESTION_PRESETS, DEFAULT_AUTOCOMPLETE_DEAD_ZONE_NODES, DEFAULT_OUTLINE_DEPTH, DOCUMENT_PRESET_VERSION, DOCUMENT_STYLE_SET_VERSION, DOCX_CONFORMANCE_CLASSES, DRAWING_SAFETY_CLASSES, type DeriveBlockIdInput, type DirectiveKind, type DirectiveRange, type Document, type DocumentPreset, type DocumentPropertiesOptions, type DocumentStyleCatalog, type DocumentStyleCatalogEntry, type DocumentStyleSet, type DocxCompatibility, type DocxCompatibilityContext, type DocxCompatibilityIssue, type DocxCompatibilityLocation, type DocxCompatibilityPart, type DocxConformanceClass, type DocxDrawingClassification, type DrawingSafetyClass, type EmbeddedFont, type EmbeddedFontParts, type ExtractDocumentStyleSetOptions, FOLIO_CONTENT_COMPARISON_LIMITS, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FOLIO_LINE_SPACING_RULE_VALUES, FOLIO_PARAGRAPH_ALIGNMENT_VALUES, FOLIO_YJS_ATTR_SCHEMA_VERSION, type FinalParagraphMarkRevision, type FolioAIBlock, type FolioAIBlockAnchor, type FolioAIBlockKind, type FolioAIBlockPreviewRun, type FolioAIBlockStructuralBoundary, type FolioAIBlockTableLocation, type FolioAIComment, type FolioAIDiagnosticBlock, type FolioAIEditAppliedOperation, type FolioAIEditApplyMode, type FolioAIEditApplyOutcome, type FolioAIEditApplyResult, type FolioAIEditNormalization, type FolioAIEditNormalizationCode, type FolioAIEditOperation, type FolioAIEditPrecondition, type FolioAIEditReviewMeta, type FolioAIEditSeverity, type FolioAIEditSkipReason, type FolioAIEditSkippedOperation, type FolioAIEditSnapshot, type FolioAIInlineBooleanProperty, type FolioAIInlineFormatting, type FolioAIInlineFormattingPatch, type FolioAIParagraphBlock, type FolioAIParagraphSpacing, type FolioAISignatureParty, type FolioBlockId, type FolioContentBlock, type FolioContentBlockProperty, type FolioContentComparison, type FolioContentComparisonError, type FolioContentComparisonEvent, type FolioContentComparisonLimit, FolioContentComparisonLimitError, type FolioContentContainerPathEntry, type FolioContentFormatRange, type FolioContentFormattingChange, type FolioContentIdStability, type FolioContentInlineBooleanProperty, type FolioContentInlineComparisonResult, type FolioContentInlineFormatting, type FolioContentInlineFormattingPatch, FolioContentInlinePresentationProjectionError, type FolioContentLineSpacingRule, type FolioContentParagraphAlignment, type FolioContentParagraphFormattingPatch, type FolioContentParagraphKind, type FolioContentParagraphSpacing, type FolioContentRun, type FolioContentSnapshot, type FolioContentStatedNumbering, type FolioContentStructuralChange, type FolioContentTableLocation, type FolioContentTextSegment, type FolioDocumentOperation, type FolioDocumentOperationAffectedTarget, type FolioDocumentOperationBatch, type FolioDocumentOperationCapabilities, type FolioDocumentOperationIssue, type FolioDocumentOperationMode, type FolioDocumentOperationPrecondition, type FolioDocumentOperationReceipt, type FolioDocumentOperationRecovery, type FolioDocumentOperationResult, type FolioDocumentOperationResultBase, type FolioDocumentOperationStatus, type FolioDocumentOperationStory, type FolioDocumentOperationType, type FolioDocumentOperationUndoFailureReason, type FolioDocumentOperationUndoHandle, type FolioDocumentOperationUndoResult, type FolioDocxCompatibilityHost, type FolioDocxCompatibilityProfile, type FolioRevisionStamp, type FolioUndefinedReferencePolicy, type FolioWordDiffOptions, type FolioYjsAttrSchemaVersion, FolioYjsAttrSchemaVersionError, type ImageMeta, type ImageRef, type InspectDocxCompatibilityOptions, InvalidCompareDocxOptionsError, InvalidFolioContentComparisonError, InvalidFolioDocumentOperationBatchError, MAX_COMPARE_OPERATIONS, type MarkdownOptions, type MarkdownResult, type OutlineDepth, type PositionalText, type ResolvedAnchor, STELLA_STYLE_SET_NAME, type TemplatePreviewHiddenRange, type TemplatePreviewSpan, type TemplatePreviewValue, type TemplatePreviewValues, type TemplateSlashMenuKeyAction, type TemplateSlashMenuState, UnsupportedFolioDocumentOperationVersionError, WORD_DIFF_GRANULARITIES, type WordDiffGranularity, type WordDiffNormalization, type WordDiffOptions, type WordDiffSegment, acceptAutocompleteSuggestion, acceptAutocompleteWord, anonymizationDecorationsKey, appendAutocompleteToken, applyFolioAIEditOperations, applyFolioDocumentOperations, applySuggestions, assertSupportedFolioDocumentOperationVersion, autocompleteSuggestionKey, autocompleteSuggestionPlugin, buildEmbeddedFontFamilyMap, buildPositionalText, clearAutocompleteSuggestion, clearTemplateSlashMenu, compareContent, compareDocx, consumeTemplateSlashQuery, createAICitationDecorationsPlugin, createDocx, createEmptyDocument, createFolioAIEditSnapshot, createStellaStyleDocumentPreset, createStellaStyleSet, currentFolioBlockId, deriveBlockId, diffWordSegments, extractDocumentStyleSet, extractDocumentStyleSetFromDocx, extractEmbeddedFonts, filterHeadingsByDepth, finishAutocompleteSuggestion, fromMarkdown, getAnonymizationMatches, getAutocompleteSuggestion, getEmbeddedFontFaces, getFolioCaretViewportRect, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioParaIdFromBlockId, getFolioSelectionViewportRect, getGoogleFontsEnabled, getTemplateDirectives, getTemplateSlashMenu, hashFolioAIBlockText, inspectDocumentStyles, inspectDocumentStylesFromDocx, inspectDocxCompatibility, isFolioAIContentBlock, isFolioBlockId, isFolioDocumentOperationModeSupported, isSequentialFolioBlockId, isSuggestionStale, isSupportedFolioDocumentOperationVersion, mergeDocumentContent, normalizeFolioAIBlockText, parseFolioDocumentOperationBatch, resetTemplateSlashQuery, resolveSuggestionAnchor, scanDirectives, scopeEmbeddedFontFamily, scrollFolioPositionIntoView, setAICitationsMeta, setAISuggestionsMeta, setActiveCitationMeta, setAnonymizationTermsMeta, setFocusedSuggestionMeta, setGoogleFontsEnabled, setTemplatePreviewValues, shouldTriggerAutocomplete, startAutocompleteSuggestion, templateSlashMenuKey, toMarkdown, toMarkdownResult };
@@ -32,7 +32,7 @@ import { STELLA_STYLE_SET_NAME, createStellaStyleDocumentPreset, createStellaSty
32
32
  import { DOCUMENT_PRESET_VERSION, DOCUMENT_STYLE_SET_VERSION } from "../style-sets/types.js";
33
33
  import { currentFolioBlockId, deriveBlockId, getFolioParaIdFromBlockId, isFolioBlockId, isSequentialFolioBlockId } from "../types/block-id.js";
34
34
  import { createEmptyDocument } from "../utils/createDocument.js";
35
- import { getGoogleFontsEnabled, setEmbeddedFontFamilyMap, setGoogleFontsEnabled } from "../utils/fontResolver.js";
35
+ import { getGoogleFontsEnabled, setGoogleFontsEnabled } from "../utils/fontResolver.js";
36
36
  import { mergeDocumentContent } from "../utils/mergeDocumentContent.js";
37
37
  import { DEFAULT_OUTLINE_DEPTH, filterHeadingsByDepth } from "../utils/outlineDepth.js";
38
- export { COMPARE_REVISION_FORMATS, COMPARE_UNSUPPORTED_REASONS, COMPARE_VERIFICATION_CAUSES, COMPARE_VERIFICATION_INVARIANTS, CompareDocxApplyError, CompareDocxFinalParagraphMarkError, CompareDocxOperationLimitError, CompareDocxParseError, CompareDocxRoundTripError, CompareDocxSerializeError, DEFAULT_AI_SUGGESTION_PRESETS, DEFAULT_AUTOCOMPLETE_DEAD_ZONE_NODES, DEFAULT_OUTLINE_DEPTH, DOCUMENT_PRESET_VERSION, DOCUMENT_STYLE_SET_VERSION, DOCX_CONFORMANCE_CLASSES, DRAWING_SAFETY_CLASSES, FOLIO_CONTENT_COMPARISON_LIMITS, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FOLIO_LINE_SPACING_RULE_VALUES, FOLIO_PARAGRAPH_ALIGNMENT_VALUES, FOLIO_YJS_ATTR_SCHEMA_VERSION, FolioContentComparisonLimitError, FolioContentInlinePresentationProjectionError, FolioYjsAttrSchemaVersionError, InvalidCompareDocxOptionsError, InvalidFolioContentComparisonError, InvalidFolioDocumentOperationBatchError, MAX_COMPARE_OPERATIONS, STELLA_STYLE_SET_NAME, UnsupportedFolioDocumentOperationVersionError, WORD_DIFF_GRANULARITIES, acceptAutocompleteSuggestion, acceptAutocompleteWord, anonymizationDecorationsKey, appendAutocompleteToken, applyFolioAIEditOperations, applyFolioDocumentOperations, applySuggestions, assertSupportedFolioDocumentOperationVersion, autocompleteSuggestionKey, autocompleteSuggestionPlugin, buildEmbeddedFontFamilyMap, buildPositionalText, clearAutocompleteSuggestion, clearTemplateSlashMenu, compareContent, compareDocx, consumeTemplateSlashQuery, createAICitationDecorationsPlugin, createDocx, createEmptyDocument, createFolioAIEditSnapshot, createStellaStyleDocumentPreset, createStellaStyleSet, currentFolioBlockId, deriveBlockId, diffWordSegments, extractDocumentStyleSet, extractDocumentStyleSetFromDocx, extractEmbeddedFonts, filterHeadingsByDepth, finishAutocompleteSuggestion, fromMarkdown, getAnonymizationMatches, getAutocompleteSuggestion, getEmbeddedFontFaces, getFolioCaretViewportRect, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioParaIdFromBlockId, getFolioSelectionViewportRect, getGoogleFontsEnabled, getTemplateDirectives, getTemplateSlashMenu, hashFolioAIBlockText, inspectDocumentStyles, inspectDocumentStylesFromDocx, inspectDocxCompatibility, isFolioAIContentBlock, isFolioBlockId, isFolioDocumentOperationModeSupported, isSequentialFolioBlockId, isSuggestionStale, isSupportedFolioDocumentOperationVersion, mergeDocumentContent, normalizeFolioAIBlockText, parseFolioDocumentOperationBatch, resetTemplateSlashQuery, resolveSuggestionAnchor, scanDirectives, scopeEmbeddedFontFamily, scrollFolioPositionIntoView, setAICitationsMeta, setAISuggestionsMeta, setActiveCitationMeta, setAnonymizationTermsMeta, setEmbeddedFontFamilyMap, setFocusedSuggestionMeta, setGoogleFontsEnabled, setTemplatePreviewValues, shouldTriggerAutocomplete, startAutocompleteSuggestion, templateSlashMenuKey, toMarkdown, toMarkdownResult };
38
+ export { COMPARE_REVISION_FORMATS, COMPARE_UNSUPPORTED_REASONS, COMPARE_VERIFICATION_CAUSES, COMPARE_VERIFICATION_INVARIANTS, CompareDocxApplyError, CompareDocxFinalParagraphMarkError, CompareDocxOperationLimitError, CompareDocxParseError, CompareDocxRoundTripError, CompareDocxSerializeError, DEFAULT_AI_SUGGESTION_PRESETS, DEFAULT_AUTOCOMPLETE_DEAD_ZONE_NODES, DEFAULT_OUTLINE_DEPTH, DOCUMENT_PRESET_VERSION, DOCUMENT_STYLE_SET_VERSION, DOCX_CONFORMANCE_CLASSES, DRAWING_SAFETY_CLASSES, FOLIO_CONTENT_COMPARISON_LIMITS, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FOLIO_LINE_SPACING_RULE_VALUES, FOLIO_PARAGRAPH_ALIGNMENT_VALUES, FOLIO_YJS_ATTR_SCHEMA_VERSION, FolioContentComparisonLimitError, FolioContentInlinePresentationProjectionError, FolioYjsAttrSchemaVersionError, InvalidCompareDocxOptionsError, InvalidFolioContentComparisonError, InvalidFolioDocumentOperationBatchError, MAX_COMPARE_OPERATIONS, STELLA_STYLE_SET_NAME, UnsupportedFolioDocumentOperationVersionError, WORD_DIFF_GRANULARITIES, acceptAutocompleteSuggestion, acceptAutocompleteWord, anonymizationDecorationsKey, appendAutocompleteToken, applyFolioAIEditOperations, applyFolioDocumentOperations, applySuggestions, assertSupportedFolioDocumentOperationVersion, autocompleteSuggestionKey, autocompleteSuggestionPlugin, buildEmbeddedFontFamilyMap, buildPositionalText, clearAutocompleteSuggestion, clearTemplateSlashMenu, compareContent, compareDocx, consumeTemplateSlashQuery, createAICitationDecorationsPlugin, createDocx, createEmptyDocument, createFolioAIEditSnapshot, createStellaStyleDocumentPreset, createStellaStyleSet, currentFolioBlockId, deriveBlockId, diffWordSegments, extractDocumentStyleSet, extractDocumentStyleSetFromDocx, extractEmbeddedFonts, filterHeadingsByDepth, finishAutocompleteSuggestion, fromMarkdown, getAnonymizationMatches, getAutocompleteSuggestion, getEmbeddedFontFaces, getFolioCaretViewportRect, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioParaIdFromBlockId, getFolioSelectionViewportRect, getGoogleFontsEnabled, getTemplateDirectives, getTemplateSlashMenu, hashFolioAIBlockText, inspectDocumentStyles, inspectDocumentStylesFromDocx, inspectDocxCompatibility, isFolioAIContentBlock, isFolioBlockId, isFolioDocumentOperationModeSupported, isSequentialFolioBlockId, isSuggestionStale, isSupportedFolioDocumentOperationVersion, mergeDocumentContent, normalizeFolioAIBlockText, parseFolioDocumentOperationBatch, resetTemplateSlashQuery, resolveSuggestionAnchor, scanDirectives, scopeEmbeddedFontFamily, scrollFolioPositionIntoView, setAICitationsMeta, setAISuggestionsMeta, setActiveCitationMeta, setAnonymizationTermsMeta, setFocusedSuggestionMeta, setGoogleFontsEnabled, setTemplatePreviewValues, shouldTriggerAutocomplete, startAutocompleteSuggestion, templateSlashMenuKey, toMarkdown, toMarkdownResult };
@@ -1,7 +1,7 @@
1
1
  import { splitsGraphemeCluster, splitsSurrogatePair } from "../ai-edits/character-boundaries.js";
2
2
  import { rangedCommentIds, visitCommentMarkers } from "../docx/commentAnchorIndex.js";
3
3
  import { cloneDocumentWithParagraphPropertySources, copyDocumentParagraphPropertySourceContract, copyParagraphPropertySource, restoreParagraphIndentationProjection } from "../docx/paragraphPropertySource.js";
4
- import { canonicalSelectionRange } from "../prosemirror/canonicalSelectionRange.js";
4
+ import { canonicalContentPosition, canonicalSelectionRange } from "../prosemirror/canonicalSelectionRange.js";
5
5
  import { collectPairedBookmarkIds, footnoteToProseDoc, headerFooterToProseDoc, toProseDoc } from "../prosemirror/conversion/toProseDoc.js";
6
6
  import { markPackageChange } from "../prosemirror/extensions/features/ParagraphChangeTrackerExtension.js";
7
7
  import { runFormattingPatchFromMarks } from "../prosemirror/runFormattingFromMarks.js";
@@ -147,6 +147,7 @@ var CanonicalProjection = class {
147
147
  }
148
148
  addressAt(position) {
149
149
  if (!Number.isInteger(position)) return refuse("The input position is not an integer.");
150
+ position = canonicalContentPosition(this.doc, position);
150
151
  const paragraph = this.paragraphs.find(({ start, node }) => position >= start && position <= start + node.content.size);
151
152
  if (paragraph === void 0) return refuse("The input is outside a plain paragraph.");
152
153
  const relative = position - paragraph.start;
@@ -169,7 +170,7 @@ var CanonicalProjection = class {
169
170
  if (paragraph === void 0) panic("Input lost its paragraph.");
170
171
  let destination = position;
171
172
  paragraph.node.forEach((node, start) => {
172
- if (node.marks.some((mark) => mark.type.name === "deletion") && position > paragraph.start + start && position < paragraph.start + start + node.nodeSize) destination = paragraph.start + start + node.nodeSize;
173
+ if (node.marks.some((mark) => mark.type.name === "deletion") && destination >= paragraph.start + start && destination < paragraph.start + start + node.nodeSize) destination = paragraph.start + start + node.nodeSize;
173
174
  });
174
175
  return destination === position ? address : this.addressAt(destination);
175
176
  }
@@ -5,9 +5,9 @@ import { effectiveParagraphNumbering, paragraphNumberingSourcesFromBoundary } fr
5
5
  import { CANONICAL_GAP } from "../types/canonicalCapabilities.js";
6
6
  import { collectHeadings } from "../utils/headingCollector.js";
7
7
  import { CanonicalSessionError } from "./canonicalSession.js";
8
- import { Result } from "better-result";
8
+ import { Result, panic } from "better-result";
9
9
  import { headingOutlineLevel, paragraphNumberingReference } from "@stll/docx-core/model";
10
- import { OP_STORIES } from "@stll/docx-core/ops";
10
+ import { OP_STORIES, editorParagraphGroups, editorPositionAtPhysicalPosition, physicalPositionAtEditorOffset } from "@stll/docx-core/ops";
11
11
  //#region src/controller/canonicalStructure.ts
12
12
  const DEFAULT_TOC_PAGE_WIDTH_TWIPS = 12240;
13
13
  const DEFAULT_TOC_MARGIN_TWIPS = 1440;
@@ -322,17 +322,20 @@ const prepareCanonicalAutoformat = (session, state, { from, to, text }) => {
322
322
  if (text !== " " || from !== to) return void 0;
323
323
  const at = session.projection.addressAt(from);
324
324
  if (at.isErr()) return void 0;
325
- const address = session.projection.paragraph(at.value.blockId);
325
+ const logical = editorPositionAtPhysicalPosition(session.document, at.value);
326
+ const address = session.projection.paragraph(logical.blockId);
326
327
  if (address === void 0 || effectiveNumbering(address.source)?.kind === "reference") return void 0;
328
+ const group = editorParagraphGroups(session.document, logical.story).find(({ blockId }) => blockId === logical.blockId);
329
+ if (group === void 0) panic("Autoformat lost its logical paragraph");
327
330
  const source = address.source;
328
- const prefix = address.text.slice(0, at.value.offset) + text;
331
+ const prefix = group.text.slice(0, logical.offset) + text;
329
332
  const requests = listRequestsForMarker(prefix);
330
333
  const heading = /^(?<hashes>#{1,6}) $/u.exec(prefix)?.groups?.["hashes"];
331
334
  if (requests === null && heading === void 0) return void 0;
332
- const start = {
333
- ...at.value,
335
+ const start = physicalPositionAtEditorOffset(session.document, {
336
+ ...logical,
334
337
  offset: 0
335
- };
338
+ });
336
339
  const request = requests?.at(0);
337
340
  const styleId = `Heading${heading?.length ?? 1}`;
338
341
  if (request === void 0 && !session.hasStyle(styleId)) return void 0;
@@ -227,7 +227,7 @@ function addLayoutFontFamilyNameFace(faces, family, descriptor, fontAlternates)
227
227
  * the painter and the measurer put in `ctx.font` and `style.fontFamily`.
228
228
  */
229
229
  function resolvedStackFamilies(family, alternate) {
230
- const { cssFallback } = resolveFontFamily(family, alternate);
230
+ const { cssFallback } = resolveFontFamily(family, { alternateFontName: alternate });
231
231
  return parseFontFamilyList(cssFallback).filter((name) => !CSS_GENERIC_FONT_FAMILIES.has(name));
232
232
  }
233
233
  function addLayoutFontFace(faces, family, descriptor) {
@@ -42,7 +42,7 @@ const formatEndnoteTexts = (numbers, formatNumber) => {
42
42
  for (const [id, displayNumber] of numbers) texts.set(id, formatNumber(displayNumber));
43
43
  return texts;
44
44
  };
45
- const sameMeasureInputs = (left, right) => left.styles === right.styles && left.theme === right.theme && left.defaultTabStop === right.defaultTabStop && left.pageContentHeight === right.pageContentHeight && left.fontSet === right.fontSet && left.fontAlternates.size === right.fontAlternates.size && [...left.fontAlternates].every(([name, alternate]) => right.fontAlternates.get(name) === alternate) && left.markupView === right.markupView;
45
+ const sameMeasureInputs = (left, right) => left.embeddedFontFamilyMap === right.embeddedFontFamilyMap && left.styles === right.styles && left.theme === right.theme && left.defaultTabStop === right.defaultTabStop && left.pageContentHeight === right.pageContentHeight && left.fontSet === right.fontSet && left.fontAlternates.size === right.fontAlternates.size && [...left.fontAlternates].every(([name, alternate]) => right.fontAlternates.get(name) === alternate) && left.markupView === right.markupView;
46
46
  /**
47
47
  * The range an incremental pass re-measures, or `null` for a full measure: the
48
48
  * committed measures must come from the same measure inputs, and the range is
@@ -154,7 +154,9 @@ function runLayoutPipelineMeasured(deps, state, options) {
154
154
  let phaseStartedAt = performance.now();
155
155
  const pageContentHeight = pageSize.h - margins.top - margins.bottom;
156
156
  const fontAlternates = buildFontAlternates(document?.package.fontTable);
157
+ const embeddedFontFamilies = session.embeddedFontFamilyMap ? { embeddedFontFamilyMap: session.embeddedFontFamilyMap } : {};
157
158
  const measureInputs = {
159
+ ...embeddedFontFamilies,
158
160
  styles,
159
161
  theme: _theme,
160
162
  defaultTabStop,
@@ -164,6 +166,7 @@ function runLayoutPipelineMeasured(deps, state, options) {
164
166
  markupView
165
167
  };
166
168
  const flowOpts = {
169
+ ...embeddedFontFamilies,
167
170
  pageContentHeight,
168
171
  fontAlternates,
169
172
  ...styles ? { styles } : {},
@@ -248,6 +251,7 @@ function runLayoutPipelineMeasured(deps, state, options) {
248
251
  ...flowOpts.defaultSize === void 0 ? {} : { defaultSize: flowOpts.defaultSize },
249
252
  ..._theme !== void 0 ? { theme: _theme } : {},
250
253
  fontAlternates,
254
+ ...embeddedFontFamilies,
251
255
  measureBlocks: hfMeasureBlocks,
252
256
  ...defaultTabStop !== void 0 ? { defaultTabStopTwips: defaultTabStop } : {},
253
257
  ...flowOpts.lineBreakRules ? { lineBreakRules: flowOpts.lineBreakRules } : {},
@@ -380,6 +384,7 @@ function runLayoutPipelineMeasured(deps, state, options) {
380
384
  if (_theme !== void 0) noteOptions.theme = _theme;
381
385
  if (document?.package.numbering !== void 0) noteOptions.numbering = document.package.numbering;
382
386
  noteOptions.fontAlternates = fontAlternates;
387
+ if (session.embeddedFontFamilyMap) noteOptions.embeddedFontFamilyMap = session.embeddedFontFamilyMap;
383
388
  if (defaultTabStop !== void 0) noteOptions.defaultTabStopTwips = defaultTabStop;
384
389
  if (flowOpts.lineBreakRules) noteOptions.lineBreakRules = flowOpts.lineBreakRules;
385
390
  if (flowOpts.justificationCompatibility) noteOptions.justificationCompatibility = flowOpts.justificationCompatibility;
@@ -579,6 +584,7 @@ function runLayoutPipelineMeasured(deps, state, options) {
579
584
  outcome.blockLookup = blockLookup;
580
585
  const footnotesByPage = hasFootnotes ? buildFootnoteRenderItems(pageFootnoteMap, footnoteContentMap, document) : void 0;
581
586
  const renderOpts = {
587
+ ...embeddedFontFamilies,
582
588
  pageGap,
583
589
  showShadow: true,
584
590
  blockLookup,
@@ -23,6 +23,7 @@ type LayoutTemplatePreview = {
23
23
  * that changes how text measures brings new styles or font alternates.
24
24
  */
25
25
  type LayoutMeasureInputs = {
26
+ embeddedFontFamilyMap?: ReadonlyMap<string, string>;
26
27
  styles: document_d_exports.StyleDefinitions | null | undefined;
27
28
  theme: document_d_exports.Theme | null | undefined;
28
29
  defaultTabStop: number | undefined;
@@ -37,6 +38,7 @@ type LayoutMeasureInputs = {
37
38
  markupView: DisplayMode;
38
39
  };
39
40
  type LayoutSession = {
41
+ embeddedFontFamilyMap?: ReadonlyMap<string, string>;
40
42
  artifacts: LayoutArtifacts | null;
41
43
  lastEditorState: EditorState | null;
42
44
  lastPmDoc: EditorState["doc"] | null;
@@ -1,6 +1,6 @@
1
1
  import { ptToPx } from "../../layout-engine/measure/measureHelpers.js";
2
2
  import { getFontMetrics } from "../../layout-engine/measure/measureProvider.js";
3
- import { resolveFontFamily } from "../../utils/fontResolver.js";
3
+ import { parseFontFamilyList, resolveFontFamily } from "../../utils/fontResolver.js";
4
4
  //#region src/display-list/build/fontTable.ts
5
5
  const CSS_NORMAL_WEIGHT = 400;
6
6
  const CSS_BOLD_WEIGHT = 700;
@@ -12,7 +12,6 @@ const GENERIC_FAMILIES = {
12
12
  fantasy: "fantasy"
13
13
  };
14
14
  const DEFAULT_GENERIC = "sans-serif";
15
- const splitFallbackStack = (cssFallback) => cssFallback.split(",").map((entry) => entry.trim().replace(/^["']|["']$/gu, ""));
16
15
  /**
17
16
  * The category `resolveFontFamily` chose. It is the last CSS generic in the
18
17
  * stack it built, which is where `detectFontCategory` puts it; reading it back
@@ -30,8 +29,8 @@ const faceKey = (family, weight, italic) => `${family.toLowerCase()} ${weight} $
30
29
  * Package faces keyed by every family name a run can resolve to.
31
30
  *
32
31
  * `resolveFontFamily` substitutes the scoped `folio-embedded-{nonce}-{name}`
33
- * family only while the document's embedded-family map is installed; a build
34
- * that never installed it resolves the same run to the authored name. Both
32
+ * family when the run carries its document-owned embedded-family map; a build
33
+ * without that context resolves the same run to the authored name. Both
35
34
  * names therefore key the same face, and the bytes are interned by id so one
36
35
  * face's binary appears once however many names reach it.
37
36
  */
@@ -64,7 +63,10 @@ var FontTable = class {
64
63
  this.embeddedByKey = indexEmbeddedFonts(embeddedFonts);
65
64
  }
66
65
  intern({ fontFamily, alternateFontFamily, bold, italic, measureStyle }) {
67
- const stack = splitFallbackStack(resolveFontFamily(fontFamily, alternateFontFamily).cssFallback);
66
+ const stack = parseFontFamilyList(resolveFontFamily(fontFamily, {
67
+ alternateFontName: alternateFontFamily,
68
+ embeddedFontFamilyMap: measureStyle.embeddedFontFamilyMap
69
+ }).cssFallback);
68
70
  const family = stack.at(0) ?? fontFamily;
69
71
  const weight = bold ? CSS_BOLD_WEIGHT : CSS_NORMAL_WEIGHT;
70
72
  const isItalic = italic === true;
@@ -12,6 +12,7 @@ import { PageComposer } from "./regions.js";
12
12
  * caller's `documentFeatures` shows the document had one.
13
13
  */
14
14
  type PageFurnitureInputs = {
15
+ embeddedFontFamilyMap?: ReadonlyMap<string, string>;
15
16
  /**
16
17
  * `w:pgBorders` for the section. Absent: no border is painted, and the gap is
17
18
  * reported unless `documentFeatures` says the document has none.
@@ -61,6 +61,7 @@ const paintPageFurniture = ({ page, furniture, context }) => {
61
61
  const watermark = !suppliesWatermark(furniture) || selected.watermark === void 0 ? [] : paintWatermark({
62
62
  page,
63
63
  watermark: selected.watermark,
64
+ ...furniture.embeddedFontFamilyMap ? { embeddedFontFamilyMap: furniture.embeddedFontFamilyMap } : {},
64
65
  ...furniture.watermarkImageSrc === void 0 ? {} : { imageSrc: furniture.watermarkImageSrc },
65
66
  context
66
67
  });
@@ -4,12 +4,13 @@ import { DisplayPrimitive } from "../types.js";
4
4
  import { BuildContext } from "./buildContext.js";
5
5
  //#region src/display-list/build/watermarkPrimitives.d.ts
6
6
  type WatermarkPaintOptions = {
7
+ embeddedFontFamilyMap?: ReadonlyMap<string, string> | undefined;
7
8
  readonly page: Page;
8
9
  readonly watermark: document_d_exports.Watermark;
9
10
  /** Resolved `data:` source for a picture watermark; absent means unresolved. */
10
11
  readonly imageSrc?: string;
11
12
  readonly context: BuildContext;
12
13
  };
13
- declare const paintWatermark: ({ page, watermark, imageSrc, context }: WatermarkPaintOptions) => readonly DisplayPrimitive[];
14
+ declare const paintWatermark: ({ page, watermark, imageSrc, context, embeddedFontFamilyMap }: WatermarkPaintOptions) => readonly DisplayPrimitive[];
14
15
  //#endregion
15
16
  export { WatermarkPaintOptions, paintWatermark };
@@ -29,9 +29,10 @@ const TEXT_DEFAULT_OPACITY = .5;
29
29
  const TEXT_DIAGONAL_DEGREES = -45;
30
30
  const PICTURE_NATIVE_SCALE = 1;
31
31
  const PICTURE_WASHOUT_OPACITY = .18;
32
- const paintTextWatermark = (watermark, page, context) => {
32
+ const paintTextWatermark = ({ watermark, page, context, embeddedFontFamilyMap }) => {
33
33
  if (watermark.text.length === 0) return [];
34
34
  const style = {
35
+ ...embeddedFontFamilyMap ? { embeddedFontFamilyMap } : {},
35
36
  fontFamily: watermark.font ?? TEXT_DEFAULT_FONT,
36
37
  fontSize: pxToPt(TEXT_FONT_SIZE_PX),
37
38
  bold: true
@@ -129,9 +130,14 @@ const paintPictureWatermark = (watermark, page, imageSrc, context) => {
129
130
  opacity: watermark.washout === false ? 1 : PICTURE_WASHOUT_OPACITY
130
131
  }];
131
132
  };
132
- const paintWatermark = ({ page, watermark, imageSrc, context }) => {
133
+ const paintWatermark = ({ page, watermark, imageSrc, context, embeddedFontFamilyMap }) => {
133
134
  switch (watermark.kind) {
134
- case "text": return paintTextWatermark(watermark, page, context);
135
+ case "text": return paintTextWatermark({
136
+ watermark,
137
+ page,
138
+ context,
139
+ embeddedFontFamilyMap
140
+ });
135
141
  case "picture": return paintPictureWatermark(watermark, page, imageSrc, context);
136
142
  default: return [];
137
143
  }
@@ -17,6 +17,7 @@ const isPageRendererName = (value) => value === PAGE_RENDERER.legacy || value ==
17
17
  * which header a page carries.
18
18
  */
19
19
  const displayListFurnitureFrom = (options) => ({
20
+ ...options.embeddedFontFamilyMap ? { embeddedFontFamilyMap: options.embeddedFontFamilyMap } : {},
20
21
  ...options.pageBorders === void 0 ? {} : { pageBorders: options.pageBorders },
21
22
  ...options.theme === void 0 ? {} : { theme: options.theme },
22
23
  ...options.watermark === void 0 ? {} : { watermark: options.watermark },
@@ -0,0 +1,10 @@
1
+ //#region src/docx/bookmarkIdNormalization.d.ts
2
+ /**
3
+ * Give repeated bookmark ranges independent identities before editor pairing.
4
+ * The first range keeps its id. Ends close starts in encounter order, including
5
+ * overlapping ambiguous ranges. Only colliding ids are repaired: those require
6
+ * unique XML ids for a valid save. Every other source byte stays verbatim.
7
+ */
8
+ declare const normalizeBookmarkIdsInXmlParts: (parts: ReadonlyMap<string, string>) => ReadonlyMap<string, string>;
9
+ //#endregion
10
+ export { normalizeBookmarkIdsInXmlParts };
@@ -0,0 +1,100 @@
1
+ import { scanSelectedStreamingXmlElements } from "./selectedXmlIdentityScan.js";
2
+ import { WORDPROCESSINGML_NAMESPACE_URIS, findAttributeByNamespaceUri, getLocalName, getNamespaceUri } from "./xmlParser.js";
3
+ import { panic } from "better-result";
4
+ //#region src/docx/bookmarkIdNormalization.ts
5
+ const bookmarkIdentity = (element) => {
6
+ if (!WORDPROCESSINGML_NAMESPACE_URIS.has(getNamespaceUri(element) ?? "")) return null;
7
+ const name = getLocalName(element.name);
8
+ if (name !== "bookmarkStart" && name !== "bookmarkEnd") return null;
9
+ const attribute = findAttributeByNamespaceUri(element, WORDPROCESSINGML_NAMESPACE_URIS, "id");
10
+ if (!attribute) return null;
11
+ const id = Number(attribute.value);
12
+ if (!Number.isSafeInteger(id) || id < 0) return null;
13
+ return {
14
+ name,
15
+ attribute: attribute.name,
16
+ id
17
+ };
18
+ };
19
+ /**
20
+ * Give repeated bookmark ranges independent identities before editor pairing.
21
+ * The first range keeps its id. Ends close starts in encounter order, including
22
+ * overlapping ambiguous ranges. Only colliding ids are repaired: those require
23
+ * unique XML ids for a valid save. Every other source byte stays verbatim.
24
+ */
25
+ const normalizeBookmarkIdsInXmlParts = (parts) => {
26
+ const candidates = [...parts].filter(([, xml]) => /bookmark(?:Start|End)/u.test(xml));
27
+ const reserved = /* @__PURE__ */ new Set();
28
+ const repeated = /* @__PURE__ */ new Set();
29
+ const markersByPart = /* @__PURE__ */ new Map();
30
+ for (const [path, xml] of candidates) {
31
+ const starts = /* @__PURE__ */ new Set();
32
+ const markers = [];
33
+ if (scanSelectedStreamingXmlElements(xml, ({ element, attributeValueSpans }) => {
34
+ const marker = bookmarkIdentity(element);
35
+ if (!marker) return;
36
+ const span = attributeValueSpans.get(marker.attribute);
37
+ if (!span) panic("Missing bookmark identity source span");
38
+ markers.push({
39
+ marker,
40
+ ...span
41
+ });
42
+ reserved.add(marker.id);
43
+ if (marker.name === "bookmarkStart") {
44
+ if (starts.has(marker.id)) repeated.add(path);
45
+ starts.add(marker.id);
46
+ }
47
+ }).status === "unsupported") {
48
+ repeated.delete(path);
49
+ continue;
50
+ }
51
+ markersByPart.set(path, markers);
52
+ }
53
+ if (repeated.size === 0) return parts;
54
+ let next = 0;
55
+ const allocate = () => {
56
+ while (reserved.has(next)) next += 1;
57
+ const id = next++;
58
+ reserved.add(id);
59
+ return id;
60
+ };
61
+ const normalized = new Map(parts);
62
+ for (const [path, xml] of candidates) {
63
+ if (!repeated.has(path)) continue;
64
+ const seen = /* @__PURE__ */ new Set();
65
+ const open = /* @__PURE__ */ new Map();
66
+ const chunks = [];
67
+ let cursor = 0;
68
+ for (const { marker, start, end } of markersByPart.get(path) ?? []) {
69
+ let id = marker.id;
70
+ if (marker.name === "bookmarkStart") {
71
+ if (seen.has(id)) id = allocate();
72
+ seen.add(marker.id);
73
+ let queue = open.get(marker.id);
74
+ if (!queue) {
75
+ queue = {
76
+ ids: [],
77
+ cursor: 0
78
+ };
79
+ open.set(marker.id, queue);
80
+ }
81
+ queue.ids.push(id);
82
+ } else {
83
+ const queue = open.get(marker.id);
84
+ const paired = queue?.ids.at(queue.cursor);
85
+ if (paired !== void 0 && queue) {
86
+ id = paired;
87
+ queue.cursor += 1;
88
+ }
89
+ }
90
+ if (id === marker.id) continue;
91
+ chunks.push(xml.slice(cursor, start), String(id));
92
+ cursor = end;
93
+ }
94
+ chunks.push(xml.slice(cursor));
95
+ normalized.set(path, chunks.join(""));
96
+ }
97
+ return normalized;
98
+ };
99
+ //#endregion
100
+ export { normalizeBookmarkIdsInXmlParts };
@@ -31,8 +31,10 @@ function createBookmarkMap() {
31
31
  * @param bookmark - The bookmark start to add
32
32
  */
33
33
  function addBookmark(map, bookmark) {
34
- map.byId.set(bookmark.id, bookmark);
35
- if (bookmark.name) map.byName.set(bookmark.name, bookmark);
34
+ if (!map.byId.has(bookmark.id)) map.byId.set(bookmark.id, bookmark);
35
+ if (bookmark.name) {
36
+ if (!map.byName.has(bookmark.name)) map.byName.set(bookmark.name, bookmark);
37
+ }
36
38
  map.bookmarks.push(bookmark);
37
39
  }
38
40
  /**
@@ -0,0 +1,136 @@
1
+ import { ParseContext } from "./parseContext.js";
2
+ //#region src/docx/importedIdCollisions.d.ts
3
+ /** Definition sites only: paired markers and references never claim an identity. */
4
+ declare const IMPORTED_ID_COLLISION_REGISTRY: {
5
+ readonly bookmark: {
6
+ readonly kind: "bookmark";
7
+ readonly scope: "part";
8
+ readonly sites: readonly [{
9
+ readonly namespace: "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
10
+ readonly elements: Set<string>;
11
+ }];
12
+ readonly attribute: "id";
13
+ readonly attributeNamespace: "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
14
+ readonly encoding: "decimal";
15
+ };
16
+ readonly comment: {
17
+ readonly kind: "comment";
18
+ readonly scope: "part";
19
+ readonly sites: readonly [{
20
+ readonly namespace: "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
21
+ readonly elements: Set<string>;
22
+ }];
23
+ readonly attribute: "id";
24
+ readonly attributeNamespace: "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
25
+ readonly encoding: "decimal";
26
+ };
27
+ readonly footnote: {
28
+ readonly kind: "footnote";
29
+ readonly scope: "part";
30
+ readonly sites: readonly [{
31
+ readonly namespace: "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
32
+ readonly elements: Set<string>;
33
+ }];
34
+ readonly attribute: "id";
35
+ readonly attributeNamespace: "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
36
+ readonly encoding: "decimal";
37
+ };
38
+ readonly endnote: {
39
+ readonly kind: "endnote";
40
+ readonly scope: "part";
41
+ readonly sites: readonly [{
42
+ readonly namespace: "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
43
+ readonly elements: Set<string>;
44
+ }];
45
+ readonly attribute: "id";
46
+ readonly attributeNamespace: "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
47
+ readonly encoding: "decimal";
48
+ };
49
+ readonly revision: {
50
+ readonly kind: "revision";
51
+ readonly scope: "package";
52
+ readonly sites: readonly [{
53
+ readonly namespace: "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
54
+ readonly elements: Set<string>;
55
+ }];
56
+ readonly attribute: "id";
57
+ readonly attributeNamespace: "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
58
+ readonly encoding: "decimal";
59
+ };
60
+ readonly paraId: {
61
+ readonly kind: "paraId";
62
+ readonly scope: "part";
63
+ readonly sites: readonly [{
64
+ readonly namespace: "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
65
+ readonly elements: Set<string>;
66
+ }, {
67
+ readonly namespace: "http://schemas.microsoft.com/office/word/2012/wordml";
68
+ readonly elements: Set<string>;
69
+ }, {
70
+ readonly namespace: string;
71
+ readonly elements: Set<string>;
72
+ }];
73
+ readonly attribute: "paraId";
74
+ readonly attributeNamespace: "http://schemas.microsoft.com/office/word/2010/wordml";
75
+ readonly encoding: "hex";
76
+ };
77
+ readonly textId: {
78
+ readonly kind: "textId";
79
+ readonly scope: "part";
80
+ readonly sites: readonly [{
81
+ readonly namespace: "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
82
+ readonly elements: Set<string>;
83
+ }];
84
+ readonly attribute: "textId";
85
+ readonly attributeNamespace: "http://schemas.microsoft.com/office/word/2010/wordml";
86
+ readonly encoding: "hex";
87
+ };
88
+ readonly numId: {
89
+ readonly kind: "numId";
90
+ readonly scope: "part";
91
+ readonly sites: readonly [{
92
+ readonly namespace: "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
93
+ readonly elements: Set<string>;
94
+ }];
95
+ readonly attribute: "numId";
96
+ readonly attributeNamespace: "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
97
+ readonly encoding: "decimal";
98
+ };
99
+ readonly abstractNumId: {
100
+ readonly kind: "abstractNumId";
101
+ readonly scope: "part";
102
+ readonly sites: readonly [{
103
+ readonly namespace: "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
104
+ readonly elements: Set<string>;
105
+ }];
106
+ readonly attribute: "abstractNumId";
107
+ readonly attributeNamespace: "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
108
+ readonly encoding: "decimal";
109
+ };
110
+ readonly drawing: {
111
+ readonly kind: "drawing";
112
+ readonly scope: "package";
113
+ readonly sites: readonly [{
114
+ readonly namespace: "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing";
115
+ readonly elements: Set<string>;
116
+ }];
117
+ readonly attribute: "id";
118
+ readonly attributeNamespace: null;
119
+ readonly encoding: "decimal";
120
+ };
121
+ readonly relationship: {
122
+ readonly kind: "relationship";
123
+ readonly scope: "part";
124
+ readonly sites: readonly [{
125
+ readonly namespace: "http://schemas.openxmlformats.org/package/2006/relationships";
126
+ readonly elements: Set<string>;
127
+ }];
128
+ readonly attribute: "Id";
129
+ readonly attributeNamespace: null;
130
+ readonly encoding: "string";
131
+ };
132
+ };
133
+ /** Reports repeated source definitions without changing the package or choosing a winner. */
134
+ declare const diagnoseImportedIdCollisions: (parts: ReadonlyMap<string, string>, context: ParseContext) => void;
135
+ //#endregion
136
+ export { IMPORTED_ID_COLLISION_REGISTRY, diagnoseImportedIdCollisions };