@stll/folio-core 0.4.0 → 0.5.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.
- package/dist/ai-edits/apply.d.ts +3 -9
- package/dist/ai-edits/apply.js +94 -14
- package/dist/ai-edits/blockRange.d.ts +33 -0
- package/dist/ai-edits/blockRange.js +58 -0
- package/dist/ai-edits/headless.d.ts +33 -4
- package/dist/ai-edits/headless.js +83 -15
- package/dist/ai-edits/index.d.ts +5 -3
- package/dist/ai-edits/index.js +3 -2
- package/dist/ai-edits/snapshot.d.ts +14 -2
- package/dist/ai-edits/snapshot.js +12 -1
- package/dist/ai-edits/types.d.ts +42 -3
- package/dist/compat/eigenpal.d.ts +3 -2
- package/dist/compat/eigenpal.js +6 -5
- package/dist/controller/layoutPipeline.d.ts +1 -0
- package/dist/controller/layoutPipeline.js +35 -137
- package/dist/controller/layoutScheduler.d.ts +2 -1
- package/dist/controller/layoutScheduler.js +6 -0
- package/dist/document-operations.d.ts +122 -0
- package/dist/document-operations.js +575 -0
- package/dist/docx/blockContentParser.js +17 -7
- package/dist/docx/encryption/agileDecryption.js +2 -1
- package/dist/docx/encryption/compoundFile.js +4 -2
- package/dist/docx/footnoteParser.d.ts +1 -17
- package/dist/docx/footnoteParser.js +1 -27
- package/dist/docx/groupDrawingParser.d.ts +8 -0
- package/dist/docx/groupDrawingParser.js +131 -0
- package/dist/docx/numberingParser.d.ts +3 -1
- package/dist/docx/numberingParser.js +8 -2
- package/dist/docx/paragraphParser.js +9 -3
- package/dist/docx/runParser.js +8 -1
- package/dist/docx/selectiveXmlPatch.js +4 -10
- package/dist/docx/serializer/numberingSerializer.js +3 -1
- package/dist/docx/settingsParser.d.ts +6 -3
- package/dist/docx/settingsParser.js +2 -0
- package/dist/docx/xmlParser.js +11 -4
- package/dist/index.d.ts +3 -2
- package/dist/index.js +6 -5
- package/dist/layout-bridge/convert/footnoteLayout.d.ts +37 -1
- package/dist/layout-bridge/convert/footnoteLayout.js +138 -14
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +5 -7
- package/dist/layout-bridge/convert/headerFooterLayout.js +5 -7
- package/dist/layout-bridge/convert/toFlowBlocks.js +56 -19
- package/dist/layout-engine/index.d.ts +6 -5
- package/dist/layout-engine/index.js +89 -26
- package/dist/layout-engine/keep-together.d.ts +13 -8
- package/dist/layout-engine/keep-together.js +40 -25
- package/dist/layout-engine/layoutInstrumentation.d.ts +11 -1
- package/dist/layout-engine/layoutInstrumentation.js +10 -1
- package/dist/layout-engine/measure/measureBlocks.js +28 -18
- package/dist/layout-engine/measure/measureParagraph.js +61 -15
- package/dist/layout-engine/paginator.d.ts +2 -1
- package/dist/layout-engine/paginator.js +9 -3
- package/dist/layout-engine/textBoxGroup.d.ts +7 -0
- package/dist/layout-engine/textBoxGroup.js +8 -0
- package/dist/layout-engine/types.d.ts +30 -9
- package/dist/layout-engine/types.js +20 -2
- package/dist/layout-painter/renderPage.d.ts +15 -1
- package/dist/layout-painter/renderPage.js +27 -11
- package/dist/layout-painter/renderParagraph.js +18 -8
- package/dist/layout-painter/renderTable.js +10 -7
- package/dist/managers/DocumentLoaderManager.js +12 -5
- package/dist/managers/TableSelectionManager.js +1 -1
- package/dist/model.js +1 -1
- package/dist/paged-layout/pageText.d.ts +14 -0
- package/dist/paged-layout/pageText.js +21 -0
- package/dist/prosemirror/attrs/index.js +2 -0
- package/dist/prosemirror/commands/comments.js +75 -5
- package/dist/prosemirror/commands/hyperlink.js +4 -2
- package/dist/prosemirror/commands/image.js +2 -1
- package/dist/prosemirror/commands/index.js +1 -1
- package/dist/prosemirror/commands/propertyChangeScope.d.ts +68 -0
- package/dist/prosemirror/commands/propertyChangeScope.js +242 -0
- package/dist/prosemirror/conversion/fromProseDoc.js +14 -3
- package/dist/prosemirror/conversion/toProseDoc.js +29 -8
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +2 -0
- package/dist/prosemirror/extensions/features/ListExtension.js +6 -0
- package/dist/prosemirror/extensions/nodes/TableExtension.js +10 -11
- package/dist/prosemirror/findReplaceSelection.js +2 -1
- package/dist/prosemirror/index.js +1 -1
- package/dist/prosemirror/insertOperations.js +1 -1
- package/dist/prosemirror/schema/nodes.d.ts +10 -5
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +1 -0
- package/dist/prosemirror/utils/tabCalculator.js +4 -2
- package/dist/redline.d.ts +20 -0
- package/dist/redline.js +127 -0
- package/dist/server.d.ts +7 -3
- package/dist/server.js +6 -2
- package/dist/symbols.d.ts +35 -0
- package/dist/symbols.js +512 -0
- package/dist/utils/clipboard.js +3 -3
- package/dist/utils/fontLoader.js +3 -0
- package/dist/utils/fontResolver.js +48 -1
- package/dist/utils/zoom.d.ts +21 -0
- package/dist/utils/zoom.js +21 -0
- package/dist/version-comparison.d.ts +92 -0
- package/dist/version-comparison.js +436 -0
- package/package.json +3 -3
- package/dist/paged-layout/headerFooterMargins.d.ts +0 -75
- package/dist/paged-layout/headerFooterMargins.js +0 -122
package/dist/ai-edits/types.d.ts
CHANGED
|
@@ -45,6 +45,27 @@ type FolioAIEditReviewMeta = {
|
|
|
45
45
|
severity?: FolioAIEditSeverity;
|
|
46
46
|
area?: string;
|
|
47
47
|
};
|
|
48
|
+
type FolioAIEditPrecondition = {
|
|
49
|
+
blockTextHash: string;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* A serializable range over the visible, post-tracked-changes text of one
|
|
53
|
+
* block. Offsets are zero-based UTF-16 boundaries, matching JavaScript string
|
|
54
|
+
* slicing; `selectedTextHash` makes a shifted or changed selection fail stale.
|
|
55
|
+
*/
|
|
56
|
+
type FolioAITextRangeHandle = {
|
|
57
|
+
type: "textRange";
|
|
58
|
+
story: "main";
|
|
59
|
+
blockId: string;
|
|
60
|
+
startOffset: number;
|
|
61
|
+
endOffset: number;
|
|
62
|
+
selectedTextHash: string;
|
|
63
|
+
};
|
|
64
|
+
type FolioAIInlineFormatting = {
|
|
65
|
+
bold?: boolean;
|
|
66
|
+
italic?: boolean;
|
|
67
|
+
underline?: boolean;
|
|
68
|
+
};
|
|
48
69
|
/**
|
|
49
70
|
* A party in an `insertSignatureTable` op. Mirrors the
|
|
50
71
|
* `signatureTable` helper in `docx-core/legal-source/compile.ts`:
|
|
@@ -56,13 +77,31 @@ type FolioAISignatureParty = {
|
|
|
56
77
|
signatory?: string;
|
|
57
78
|
title?: string;
|
|
58
79
|
};
|
|
59
|
-
type FolioAIEditOperation = FolioAIEditReviewMeta &
|
|
80
|
+
type FolioAIEditOperation = FolioAIEditReviewMeta & {
|
|
81
|
+
precondition?: FolioAIEditPrecondition;
|
|
82
|
+
} & ({
|
|
60
83
|
id: string;
|
|
61
84
|
type: "replaceInBlock";
|
|
62
85
|
blockId: string;
|
|
63
86
|
find: string;
|
|
64
87
|
replace: string;
|
|
65
88
|
comment?: FolioAIComment;
|
|
89
|
+
} | {
|
|
90
|
+
id: string;
|
|
91
|
+
type: "replaceRange";
|
|
92
|
+
range: FolioAITextRangeHandle;
|
|
93
|
+
replace: string;
|
|
94
|
+
comment?: FolioAIComment;
|
|
95
|
+
} | {
|
|
96
|
+
id: string;
|
|
97
|
+
type: "commentOnRange";
|
|
98
|
+
range: FolioAITextRangeHandle;
|
|
99
|
+
comment: FolioAIComment;
|
|
100
|
+
} | {
|
|
101
|
+
id: string;
|
|
102
|
+
type: "formatRange";
|
|
103
|
+
range: FolioAITextRangeHandle;
|
|
104
|
+
formatting: FolioAIInlineFormatting;
|
|
66
105
|
} | {
|
|
67
106
|
id: string;
|
|
68
107
|
type: "insertAfterBlock" | "insertBeforeBlock";
|
|
@@ -116,7 +155,7 @@ type FolioAIEditOperation = FolioAIEditReviewMeta & ({
|
|
|
116
155
|
comment?: FolioAIComment;
|
|
117
156
|
});
|
|
118
157
|
type FolioAIEditApplyMode = "direct" | "tracked-changes";
|
|
119
|
-
type FolioAIEditSkipReason = "missingBlock" | "changedBlock" | "ambiguousFind" | "missingFind" | "unsupportedBlock" | "emptyOperation"
|
|
158
|
+
type FolioAIEditSkipReason = "missingBlock" | "changedBlock" | "ambiguousFind" | "missingFind" | "unsupportedBlock" | "unsupportedMode" | "atomicBatchRejected" | "preconditionFailed" | "staleRange" | "emptyOperation"
|
|
120
159
|
/**
|
|
121
160
|
* The operation would not change the document — find equals
|
|
122
161
|
* replace, or replaceBlock's `text` matches the live block.
|
|
@@ -153,4 +192,4 @@ type FolioAIEditApplyResult = {
|
|
|
153
192
|
skipped: FolioAIEditSkippedOperation[];
|
|
154
193
|
};
|
|
155
194
|
//#endregion
|
|
156
|
-
export { FolioAIBlock, FolioAIBlockAnchor, FolioAIBlockKind, FolioAIBlockPreviewRun, FolioAIComment, FolioAIEditAppliedOperation, FolioAIEditApplyMode, FolioAIEditApplyResult, FolioAIEditOperation, FolioAIEditReviewMeta, FolioAIEditSeverity, FolioAIEditSkipReason, FolioAIEditSkippedOperation, FolioAIEditSnapshot, FolioAISignatureParty };
|
|
195
|
+
export { FolioAIBlock, FolioAIBlockAnchor, FolioAIBlockKind, FolioAIBlockPreviewRun, FolioAIComment, FolioAIEditAppliedOperation, FolioAIEditApplyMode, FolioAIEditApplyResult, FolioAIEditOperation, FolioAIEditPrecondition, FolioAIEditReviewMeta, FolioAIEditSeverity, FolioAIEditSkipReason, FolioAIEditSkippedOperation, FolioAIEditSnapshot, FolioAIInlineFormatting, FolioAISignatureParty, FolioAITextRangeHandle };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { FolioAIBlock, FolioAIBlockAnchor, FolioAIBlockKind, FolioAIBlockPreviewRun, FolioAIComment, FolioAIEditAppliedOperation, FolioAIEditApplyMode, FolioAIEditApplyResult, FolioAIEditOperation, FolioAIEditReviewMeta, FolioAIEditSeverity, FolioAIEditSkipReason, FolioAIEditSkippedOperation, FolioAIEditSnapshot, FolioAISignatureParty } from "../ai-edits/types.js";
|
|
1
|
+
import { FolioAIBlock, FolioAIBlockAnchor, FolioAIBlockKind, FolioAIBlockPreviewRun, FolioAIComment, FolioAIEditAppliedOperation, FolioAIEditApplyMode, FolioAIEditApplyResult, FolioAIEditOperation, FolioAIEditPrecondition, FolioAIEditReviewMeta, FolioAIEditSeverity, FolioAIEditSkipReason, FolioAIEditSkippedOperation, FolioAIEditSnapshot, FolioAISignatureParty } from "../ai-edits/types.js";
|
|
2
2
|
import { applyFolioAIEditOperations } from "../ai-edits/apply.js";
|
|
3
3
|
import { document_d_exports } from "../types/document.js";
|
|
4
|
+
import { ApplyFolioDocumentOperationsOptions, 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, FolioDocumentOperation, FolioDocumentOperationAffectedTarget, FolioDocumentOperationBatch, FolioDocumentOperationCapabilities, FolioDocumentOperationIssue, FolioDocumentOperationMode, FolioDocumentOperationPrecondition, FolioDocumentOperationReceipt, FolioDocumentOperationRecovery, FolioDocumentOperationResult, FolioDocumentOperationStatus, FolioDocumentOperationType, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch } from "../document-operations.js";
|
|
4
5
|
import { createFolioAIEditSnapshot, hashFolioAIBlockText, normalizeFolioAIBlockText } from "../ai-edits/snapshot.js";
|
|
5
6
|
import { DeriveBlockIdInput, FolioBlockId, deriveBlockId, getFolioParaIdFromBlockId, isFolioBlockId, isSequentialFolioBlockId } from "../types/block-id.js";
|
|
6
7
|
import { WordDiffSegment, diffWordSegments } from "../ai-edits/word-diff.js";
|
|
@@ -26,4 +27,4 @@ import { toMarkdown, toMarkdownResult } from "../markdown/index.js";
|
|
|
26
27
|
import { EmbeddedFont, EmbeddedFontParts, extractEmbeddedFonts, getEmbeddedFontFaces } from "../fonts/embeddedFonts.js";
|
|
27
28
|
import { getGoogleFontsEnabled, setGoogleFontsEnabled } from "../utils/fontResolver.js";
|
|
28
29
|
type Document = document_d_exports.Document;
|
|
29
|
-
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 ApplyResult, type AutocompleteSuggestionPluginOptions, type AutocompleteSuggestionState, type AutocompleteSuggestionStatus, type AutocompleteTriggerCheck, type AutocompleteTriggerOptions, type AutocompleteTriggerSkipReason, type CreateEmptyDocumentOptions, DEFAULT_AI_SUGGESTION_PRESETS, DEFAULT_AUTOCOMPLETE_DEAD_ZONE_NODES, type DeriveBlockIdInput, type DirectiveKind, type DirectiveRange, type Document, type DocxCompatibility, type EmbeddedFont, type EmbeddedFontParts, type FolioAIBlock, type FolioAIBlockAnchor, type FolioAIBlockKind, type FolioAIBlockPreviewRun, type FolioAIComment, type FolioAIEditAppliedOperation, type FolioAIEditApplyMode, type FolioAIEditApplyResult, type FolioAIEditOperation, type FolioAIEditReviewMeta, type FolioAIEditSeverity, type FolioAIEditSkipReason, type FolioAIEditSkippedOperation, type FolioAIEditSnapshot, type FolioAISignatureParty, type FolioBlockId, type ImageMeta, type ImageRef, type MarkdownOptions, type MarkdownResult, type PositionalText, type ResolvedAnchor, type TemplatePreviewSpan, type TemplatePreviewValue, type TemplatePreviewValues, type TemplateSlashMenuKeyAction, type TemplateSlashMenuState, type WordDiffSegment, acceptAutocompleteSuggestion, acceptAutocompleteWord, anonymizationDecorationsKey, appendAutocompleteToken, applyFolioAIEditOperations, applySuggestions, autocompleteSuggestionKey, autocompleteSuggestionPlugin, buildPositionalText, clearAutocompleteSuggestion, clearTemplateSlashMenu, consumeTemplateSlashQuery, createAICitationDecorationsPlugin, createDocx, createEmptyDocument, createFolioAIEditSnapshot, deriveBlockId, diffWordSegments, extractEmbeddedFonts, finishAutocompleteSuggestion, fromMarkdown, getAnonymizationMatches, getAutocompleteSuggestion, getEmbeddedFontFaces, getFolioCaretViewportRect, getFolioParaIdFromBlockId, getFolioSelectionViewportRect, getGoogleFontsEnabled, getTemplateDirectives, getTemplateSlashMenu, hashFolioAIBlockText, isFolioBlockId, isSequentialFolioBlockId, isSuggestionStale, normalizeFolioAIBlockText, resetTemplateSlashQuery, resolveSuggestionAnchor, scanDirectives, scrollFolioPositionIntoView, setAICitationsMeta, setAISuggestionsMeta, setActiveCitationMeta, setAnonymizationTermsMeta, setFocusedSuggestionMeta, setGoogleFontsEnabled, setTemplatePreviewValues, shouldTriggerAutocomplete, startAutocompleteSuggestion, templateSlashMenuKey, toMarkdown, toMarkdownResult };
|
|
30
|
+
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 CreateEmptyDocumentOptions, DEFAULT_AI_SUGGESTION_PRESETS, DEFAULT_AUTOCOMPLETE_DEAD_ZONE_NODES, type DeriveBlockIdInput, type DirectiveKind, type DirectiveRange, type Document, type DocxCompatibility, type EmbeddedFont, type EmbeddedFontParts, 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, type FolioAIBlock, type FolioAIBlockAnchor, type FolioAIBlockKind, type FolioAIBlockPreviewRun, type FolioAIComment, type FolioAIEditAppliedOperation, type FolioAIEditApplyMode, type FolioAIEditApplyResult, type FolioAIEditOperation, type FolioAIEditPrecondition, type FolioAIEditReviewMeta, type FolioAIEditSeverity, type FolioAIEditSkipReason, type FolioAIEditSkippedOperation, type FolioAIEditSnapshot, type FolioAISignatureParty, type FolioBlockId, type FolioDocumentOperation, type FolioDocumentOperationAffectedTarget, type FolioDocumentOperationBatch, type FolioDocumentOperationCapabilities, type FolioDocumentOperationIssue, type FolioDocumentOperationMode, type FolioDocumentOperationPrecondition, type FolioDocumentOperationReceipt, type FolioDocumentOperationRecovery, type FolioDocumentOperationResult, type FolioDocumentOperationStatus, type FolioDocumentOperationType, type ImageMeta, type ImageRef, InvalidFolioDocumentOperationBatchError, type MarkdownOptions, type MarkdownResult, type PositionalText, type ResolvedAnchor, type TemplatePreviewSpan, type TemplatePreviewValue, type TemplatePreviewValues, type TemplateSlashMenuKeyAction, type TemplateSlashMenuState, UnsupportedFolioDocumentOperationVersionError, type WordDiffSegment, acceptAutocompleteSuggestion, acceptAutocompleteWord, anonymizationDecorationsKey, appendAutocompleteToken, applyFolioAIEditOperations, applyFolioDocumentOperations, applySuggestions, assertSupportedFolioDocumentOperationVersion, autocompleteSuggestionKey, autocompleteSuggestionPlugin, buildPositionalText, clearAutocompleteSuggestion, clearTemplateSlashMenu, consumeTemplateSlashQuery, createAICitationDecorationsPlugin, createDocx, createEmptyDocument, createFolioAIEditSnapshot, deriveBlockId, diffWordSegments, extractEmbeddedFonts, finishAutocompleteSuggestion, fromMarkdown, getAnonymizationMatches, getAutocompleteSuggestion, getEmbeddedFontFaces, getFolioCaretViewportRect, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioParaIdFromBlockId, getFolioSelectionViewportRect, getGoogleFontsEnabled, getTemplateDirectives, getTemplateSlashMenu, hashFolioAIBlockText, isFolioBlockId, isFolioDocumentOperationModeSupported, isSequentialFolioBlockId, isSuggestionStale, isSupportedFolioDocumentOperationVersion, normalizeFolioAIBlockText, parseFolioDocumentOperationBatch, resetTemplateSlashQuery, resolveSuggestionAnchor, scanDirectives, scrollFolioPositionIntoView, setAICitationsMeta, setAISuggestionsMeta, setActiveCitationMeta, setAnonymizationTermsMeta, setFocusedSuggestionMeta, setGoogleFontsEnabled, setTemplatePreviewValues, shouldTriggerAutocomplete, startAutocompleteSuggestion, templateSlashMenuKey, toMarkdown, toMarkdownResult };
|
package/dist/compat/eigenpal.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
+
import { deriveBlockId, getFolioParaIdFromBlockId, isFolioBlockId, isSequentialFolioBlockId } from "../types/block-id.js";
|
|
2
|
+
import { createFolioAIEditSnapshot, hashFolioAIBlockText, normalizeFolioAIBlockText } from "../ai-edits/snapshot.js";
|
|
3
|
+
import { diffWordSegments } from "../ai-edits/word-diff.js";
|
|
4
|
+
import { applyFolioAIEditOperations } from "../ai-edits/apply.js";
|
|
5
|
+
import { 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, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch } from "../document-operations.js";
|
|
1
6
|
import { createEmptyDocument } from "../utils/createDocument.js";
|
|
2
7
|
import { createDocx } from "../docx/rezip.js";
|
|
3
|
-
import { deriveBlockId, getFolioParaIdFromBlockId, isFolioBlockId, isSequentialFolioBlockId } from "../types/block-id.js";
|
|
4
8
|
import { DEFAULT_AI_SUGGESTION_PRESETS } from "../ai-suggestions/types.js";
|
|
5
9
|
import { buildPositionalText } from "../ai-suggestions/text-positions.js";
|
|
6
10
|
import { isSuggestionStale, resolveSuggestionAnchor } from "../ai-suggestions/conflict.js";
|
|
7
11
|
import { applySuggestions } from "../ai-suggestions/apply.js";
|
|
8
|
-
import { createFolioAIEditSnapshot, hashFolioAIBlockText, normalizeFolioAIBlockText } from "../ai-edits/snapshot.js";
|
|
9
|
-
import { diffWordSegments } from "../ai-edits/word-diff.js";
|
|
10
|
-
import { applyFolioAIEditOperations } from "../ai-edits/apply.js";
|
|
11
12
|
import { setAISuggestionsMeta, setFocusedSuggestionMeta } from "../prosemirror/plugins/aiSuggestionDecorations.js";
|
|
12
13
|
import { getGoogleFontsEnabled, setGoogleFontsEnabled } from "../utils/fontResolver.js";
|
|
13
14
|
import { scrollFolioPositionIntoView } from "../paged-layout/scrollToPmPosition.js";
|
|
@@ -21,4 +22,4 @@ import { DEFAULT_AUTOCOMPLETE_DEAD_ZONE_NODES, acceptAutocompleteSuggestion, acc
|
|
|
21
22
|
import { fromMarkdown } from "../markdown/fromMarkdown.js";
|
|
22
23
|
import { toMarkdown, toMarkdownResult } from "../markdown/index.js";
|
|
23
24
|
import { extractEmbeddedFonts, getEmbeddedFontFaces } from "../fonts/embeddedFonts.js";
|
|
24
|
-
export { DEFAULT_AI_SUGGESTION_PRESETS, DEFAULT_AUTOCOMPLETE_DEAD_ZONE_NODES, acceptAutocompleteSuggestion, acceptAutocompleteWord, anonymizationDecorationsKey, appendAutocompleteToken, applyFolioAIEditOperations, applySuggestions, autocompleteSuggestionKey, autocompleteSuggestionPlugin, buildPositionalText, clearAutocompleteSuggestion, clearTemplateSlashMenu, consumeTemplateSlashQuery, createAICitationDecorationsPlugin, createDocx, createEmptyDocument, createFolioAIEditSnapshot, deriveBlockId, diffWordSegments, extractEmbeddedFonts, finishAutocompleteSuggestion, fromMarkdown, getAnonymizationMatches, getAutocompleteSuggestion, getEmbeddedFontFaces, getFolioCaretViewportRect, getFolioParaIdFromBlockId, getFolioSelectionViewportRect, getGoogleFontsEnabled, getTemplateDirectives, getTemplateSlashMenu, hashFolioAIBlockText, isFolioBlockId, isSequentialFolioBlockId, isSuggestionStale, normalizeFolioAIBlockText, resetTemplateSlashQuery, resolveSuggestionAnchor, scanDirectives, scrollFolioPositionIntoView, setAICitationsMeta, setAISuggestionsMeta, setActiveCitationMeta, setAnonymizationTermsMeta, setFocusedSuggestionMeta, setGoogleFontsEnabled, setTemplatePreviewValues, shouldTriggerAutocomplete, startAutocompleteSuggestion, templateSlashMenuKey, toMarkdown, toMarkdownResult };
|
|
25
|
+
export { DEFAULT_AI_SUGGESTION_PRESETS, DEFAULT_AUTOCOMPLETE_DEAD_ZONE_NODES, 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, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, acceptAutocompleteSuggestion, acceptAutocompleteWord, anonymizationDecorationsKey, appendAutocompleteToken, applyFolioAIEditOperations, applyFolioDocumentOperations, applySuggestions, assertSupportedFolioDocumentOperationVersion, autocompleteSuggestionKey, autocompleteSuggestionPlugin, buildPositionalText, clearAutocompleteSuggestion, clearTemplateSlashMenu, consumeTemplateSlashQuery, createAICitationDecorationsPlugin, createDocx, createEmptyDocument, createFolioAIEditSnapshot, deriveBlockId, diffWordSegments, extractEmbeddedFonts, finishAutocompleteSuggestion, fromMarkdown, getAnonymizationMatches, getAutocompleteSuggestion, getEmbeddedFontFaces, getFolioCaretViewportRect, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioParaIdFromBlockId, getFolioSelectionViewportRect, getGoogleFontsEnabled, getTemplateDirectives, getTemplateSlashMenu, hashFolioAIBlockText, isFolioBlockId, isFolioDocumentOperationModeSupported, isSequentialFolioBlockId, isSuggestionStale, isSupportedFolioDocumentOperationVersion, normalizeFolioAIBlockText, parseFolioDocumentOperationBatch, resetTemplateSlashQuery, resolveSuggestionAnchor, scanDirectives, scrollFolioPositionIntoView, setAICitationsMeta, setAISuggestionsMeta, setActiveCitationMeta, setAnonymizationTermsMeta, setFocusedSuggestionMeta, setGoogleFontsEnabled, setTemplatePreviewValues, shouldTriggerAutocomplete, startAutocompleteSuggestion, templateSlashMenuKey, toMarkdown, toMarkdownResult };
|
|
@@ -45,6 +45,7 @@ type LayoutPipelineDeps<THfPMs> = {
|
|
|
45
45
|
sectionProperties: document_d_exports.SectionProperties | null | undefined;
|
|
46
46
|
document: document_d_exports.Document | null;
|
|
47
47
|
defaultTabStop: number | undefined;
|
|
48
|
+
mirrorMargins: boolean;
|
|
48
49
|
styles: document_d_exports.StyleDefinitions | null | undefined;
|
|
49
50
|
layout: Layout | null;
|
|
50
51
|
hfPMs: THfPMs;
|
|
@@ -2,32 +2,24 @@ import "../layout-engine/types.js";
|
|
|
2
2
|
import { renderPages } from "../layout-painter/renderPage.js";
|
|
3
3
|
import { templatePreviewValuesKey } from "../prosemirror/plugins/templatePreviewValues.js";
|
|
4
4
|
import { toFlowBlocks } from "../layout-bridge/convert/toFlowBlocks.js";
|
|
5
|
-
import { recordLayoutComplete, recordLayoutError, recordLayoutPhase } from "../layout-engine/layoutInstrumentation.js";
|
|
5
|
+
import { recordLayoutComplete, recordLayoutError, recordLayoutPhase, recordLayoutStart } from "../layout-engine/layoutInstrumentation.js";
|
|
6
6
|
import { buildBookmarkPageMap } from "../fields/bookmarkPages.js";
|
|
7
7
|
import { buildBookmarkText } from "../fields/bookmarkText.js";
|
|
8
8
|
import { buildHeaderFooterFieldValues, fieldValuesEqual, resolveFieldValues } from "../fields/resolveFieldValues.js";
|
|
9
9
|
import { buildSectionPageCounts } from "../fields/sectionPageCounts.js";
|
|
10
10
|
import { buildSeqValues } from "../fields/seqValues.js";
|
|
11
11
|
import { installCanvasMeasureProvider } from "../layout-engine/measure/measureContainer.js";
|
|
12
|
-
import { buildFootnoteContentMap, collectFootnoteRefs } from "../layout-bridge/convert/footnoteLayout.js";
|
|
12
|
+
import { buildFootnoteContentMap, collectEndnoteRefs, collectFootnoteRefs, computeNoteDisplayNumbers, remapNoteMarkerText } from "../layout-bridge/convert/footnoteLayout.js";
|
|
13
13
|
import { applyTemplatePreviewToBlocks } from "../layout-bridge/convert/templatePreviewFlow.js";
|
|
14
14
|
import { layoutDocument } from "../layout-engine/index.js";
|
|
15
15
|
import { measureBlocks, measureSingleBlockWithoutFloatingZones } from "../layout-engine/measure/measureBlocks.js";
|
|
16
|
-
import { computeFirstPageHeaderFooterMarginExtender, computeHeaderFooterMarginExtender, extendSectionBreakMargins } from "../paged-layout/headerFooterMargins.js";
|
|
17
16
|
import { tryBuildIncrementalMeasures } from "../paged-layout/incrementalMeasure.js";
|
|
18
17
|
import { computePerBlockMeasureInputs } from "../paged-layout/sectionBlockWidths.js";
|
|
19
|
-
import { twipsToPixels } from "../paged-layout/sectionGeometry.js";
|
|
18
|
+
import { getMargins, getPageSize, twipsToPixels } from "../paged-layout/sectionGeometry.js";
|
|
20
19
|
import { getDocumentWatermark } from "../watermark/index.js";
|
|
21
20
|
//#region src/controller/layoutPipeline.ts
|
|
22
|
-
function pageMarginsEqual(left, right) {
|
|
23
|
-
return left.top === right.top && left.right === right.right && left.bottom === right.bottom && left.left === right.left && left.header === right.header && left.footer === right.footer;
|
|
24
|
-
}
|
|
25
|
-
function optionalPageMarginsEqual(left, right) {
|
|
26
|
-
if (left === void 0 || right === void 0) return left === right;
|
|
27
|
-
return pageMarginsEqual(left, right);
|
|
28
|
-
}
|
|
29
21
|
function runLayoutPipeline(deps, state, options = {}) {
|
|
30
|
-
const { contentWidth, columns, pageSize, margins, pageGap, syncCoordinator, headerContent, footerContent, firstPageHeaderContent, firstPageFooterContent, headerContentRId, footerContentRId, firstPageHeaderContentRId, firstPageFooterContentRId, sectionHeaderFooterRefs, theme: _theme, sectionProperties, document, defaultTabStop, styles, layout, hfPMs, painter, pagesContainer, session, renderHfFromContentOrPm, renderHeaderFooterContentByRId, documentFontsAreLoaded, buildFootnoteRenderItems, describeInvalidHighlightMarks, emptyTemplatePreviewEntries: EMPTY_TEMPLATE_PREVIEW_ENTRIES } = deps;
|
|
22
|
+
const { contentWidth, columns, pageSize, margins, pageGap, syncCoordinator, headerContent, footerContent, firstPageHeaderContent, firstPageFooterContent, headerContentRId, footerContentRId, firstPageHeaderContentRId, firstPageFooterContentRId, sectionHeaderFooterRefs, theme: _theme, sectionProperties, document, defaultTabStop, mirrorMargins, styles, layout, hfPMs, painter, pagesContainer, session, renderHfFromContentOrPm, renderHeaderFooterContentByRId, documentFontsAreLoaded, buildFootnoteRenderItems, describeInvalidHighlightMarks, emptyTemplatePreviewEntries: EMPTY_TEMPLATE_PREVIEW_ENTRIES } = deps;
|
|
31
23
|
let outcome = {};
|
|
32
24
|
let pendingArtifacts;
|
|
33
25
|
let pendingTemplatePreview;
|
|
@@ -37,6 +29,7 @@ function runLayoutPipeline(deps, state, options = {}) {
|
|
|
37
29
|
recordLayoutPhase(reason, phase, performance.now() - startedAt);
|
|
38
30
|
};
|
|
39
31
|
const currentEpoch = syncCoordinator.getStateSeq();
|
|
32
|
+
recordLayoutStart(reason);
|
|
40
33
|
syncCoordinator.onLayoutStart();
|
|
41
34
|
try {
|
|
42
35
|
let phaseStartedAt = performance.now();
|
|
@@ -61,6 +54,14 @@ function runLayoutPipeline(deps, state, options = {}) {
|
|
|
61
54
|
const footnoteRefs = collectFootnoteRefs(newBlocks);
|
|
62
55
|
const documentFootnotes = document?.package.footnotes;
|
|
63
56
|
const hasFootnotes = footnoteRefs.length > 0 && documentFootnotes !== void 0;
|
|
57
|
+
const footnoteDisplayNumbers = documentFootnotes ? computeNoteDisplayNumbers(documentFootnotes, footnoteRefs.map((ref) => ref.footnoteId)) : void 0;
|
|
58
|
+
const documentEndnotes = document?.package.endnotes;
|
|
59
|
+
const endnoteDisplayNumbers = documentEndnotes ? computeNoteDisplayNumbers(documentEndnotes, collectEndnoteRefs(newBlocks).map((ref) => ref.endnoteId)) : void 0;
|
|
60
|
+
newBlocks = remapNoteMarkerText(newBlocks, {
|
|
61
|
+
...footnoteDisplayNumbers ? { footnoteNumbers: footnoteDisplayNumbers } : {},
|
|
62
|
+
...endnoteDisplayNumbers ? { endnoteNumbers: endnoteDisplayNumbers } : {}
|
|
63
|
+
});
|
|
64
|
+
outcome.blocks = newBlocks;
|
|
64
65
|
const hfMetricsHeader = {
|
|
65
66
|
section: "header",
|
|
66
67
|
pageSize,
|
|
@@ -90,73 +91,19 @@ function runLayoutPipeline(deps, state, options = {}) {
|
|
|
90
91
|
let firstPageFooterForRender = hasTitlePg ? renderHfFromContentOrPm(firstPageFooterContent, firstPageFooterContentRId, hfPMs, contentWidth, hfMetricsFooter, hfOptions) : void 0;
|
|
91
92
|
let headerContentByRId = renderHeaderFooterContentByRId(document?.package.headers, hfPMs, contentWidth, hfMetricsHeader, hfOptions);
|
|
92
93
|
let footerContentByRId = renderHeaderFooterContentByRId(document?.package.footers, hfPMs, contentWidth, hfMetricsFooter, hfOptions);
|
|
93
|
-
const hfExtenderContent = {
|
|
94
|
-
headerContent: headerContentForRender,
|
|
95
|
-
footerContent: footerContentForRender,
|
|
96
|
-
firstPageHeaderContent: firstPageHeaderForRender,
|
|
97
|
-
firstPageFooterContent: firstPageFooterForRender
|
|
98
|
-
};
|
|
99
|
-
const buildSectionHfExtenderContent = () => {
|
|
100
|
-
if (!sectionHeaderFooterRefs) return;
|
|
101
|
-
return sectionHeaderFooterRefs.map((refs) => ({
|
|
102
|
-
headerContent: pickSectionHeaderFooterContent(headerContentByRId, refs.headerDefault, refs.evenAndOddHeaders === true ? refs.headerEven : void 0),
|
|
103
|
-
footerContent: pickSectionHeaderFooterContent(footerContentByRId, refs.footerDefault, refs.evenAndOddHeaders === true ? refs.footerEven : void 0),
|
|
104
|
-
firstPageHeaderContent: refs.titlePg === true ? headerContentByRId?.get(refs.headerFirst ?? "") : void 0,
|
|
105
|
-
firstPageFooterContent: refs.titlePg === true ? footerContentByRId?.get(refs.footerFirst ?? "") : void 0
|
|
106
|
-
}));
|
|
107
|
-
};
|
|
108
|
-
const hfWarn = (msg) => {
|
|
109
|
-
console.warn(`[PagedEditor] ${msg}`);
|
|
110
|
-
};
|
|
111
|
-
const extendForHfOverflow = computeHeaderFooterMarginExtender({
|
|
112
|
-
...hfExtenderContent,
|
|
113
|
-
pageSize,
|
|
114
|
-
warn: hfWarn
|
|
115
|
-
});
|
|
116
|
-
const extendForFirstPage = computeFirstPageHeaderFooterMarginExtender({
|
|
117
|
-
...hfExtenderContent,
|
|
118
|
-
pageSize,
|
|
119
|
-
warn: hfWarn
|
|
120
|
-
});
|
|
121
|
-
let effectiveMargins = extendForHfOverflow(margins);
|
|
122
|
-
let effectiveFirstPageMargins = hasTitlePg ? extendForFirstPage(margins) : void 0;
|
|
123
|
-
const sectionBreaks = newBlocks.filter((block) => block.kind === "sectionBreak");
|
|
124
|
-
const originalSectionBreakMargins = /* @__PURE__ */ new Map();
|
|
125
|
-
for (const sectionBreak of sectionBreaks) originalSectionBreakMargins.set(sectionBreak.id, sectionBreak.margins ? { ...sectionBreak.margins } : void 0);
|
|
126
|
-
const restoreSectionBreakMargins = () => {
|
|
127
|
-
for (const sectionBreak of sectionBreaks) {
|
|
128
|
-
const originalMargins = originalSectionBreakMargins.get(sectionBreak.id);
|
|
129
|
-
if (originalMargins === void 0) {
|
|
130
|
-
delete sectionBreak.margins;
|
|
131
|
-
continue;
|
|
132
|
-
}
|
|
133
|
-
sectionBreak.margins = { ...originalMargins };
|
|
134
|
-
}
|
|
135
|
-
};
|
|
136
|
-
const applySectionBreakMargins = (content, bodyMargins) => {
|
|
137
|
-
restoreSectionBreakMargins();
|
|
138
|
-
extendSectionBreakMargins(sectionBreaks, {
|
|
139
|
-
content,
|
|
140
|
-
sectionContent: buildSectionHfExtenderContent(),
|
|
141
|
-
bodyPageSize: pageSize,
|
|
142
|
-
bodyMargins,
|
|
143
|
-
warn: hfWarn
|
|
144
|
-
});
|
|
145
|
-
};
|
|
146
|
-
applySectionBreakMargins(hfExtenderContent, effectiveMargins);
|
|
147
94
|
recordPhaseDuration("header-footer", phaseStartedAt);
|
|
148
95
|
phaseStartedAt = performance.now();
|
|
149
|
-
|
|
96
|
+
const bodyLayoutConfig = {
|
|
150
97
|
pageSize,
|
|
151
|
-
margins
|
|
98
|
+
margins
|
|
152
99
|
};
|
|
153
100
|
if (columns !== void 0) bodyLayoutConfig.columns = columns;
|
|
154
|
-
|
|
101
|
+
const blockMeasureInputs = computePerBlockMeasureInputs({
|
|
155
102
|
blocks: newBlocks,
|
|
156
103
|
bodyConfig: bodyLayoutConfig,
|
|
157
104
|
finalConfig: bodyLayoutConfig
|
|
158
105
|
});
|
|
159
|
-
|
|
106
|
+
const blockWidths = blockMeasureInputs.widths;
|
|
160
107
|
const previousArtifacts = session.artifacts;
|
|
161
108
|
const incrementalResult = options.dirtyRange && !options.forceFull && previousArtifacts ? tryBuildIncrementalMeasures({
|
|
162
109
|
previousBlocks: previousArtifacts.blocks,
|
|
@@ -183,19 +130,31 @@ function runLayoutPipeline(deps, state, options = {}) {
|
|
|
183
130
|
let pageFootnoteMap = /* @__PURE__ */ new Map();
|
|
184
131
|
let footnoteContentMap = /* @__PURE__ */ new Map();
|
|
185
132
|
const bodyBreakType = sectionProperties?.sectionStart;
|
|
186
|
-
const buildLayoutOpts = (
|
|
133
|
+
const buildLayoutOpts = () => {
|
|
187
134
|
const nextLayoutOpts = {
|
|
188
135
|
pageSize,
|
|
189
|
-
margins
|
|
190
|
-
pageGap
|
|
136
|
+
margins,
|
|
137
|
+
pageGap,
|
|
138
|
+
mirrorMargins
|
|
191
139
|
};
|
|
192
|
-
if (
|
|
140
|
+
if (hasTitlePg && firstPageHeaderForRender) {
|
|
141
|
+
const headerBottom = (margins.header ?? 0) + (firstPageHeaderForRender.marginPushBottom ?? firstPageHeaderForRender.height);
|
|
142
|
+
if (headerBottom > margins.top) nextLayoutOpts.firstPageMargins = {
|
|
143
|
+
...margins,
|
|
144
|
+
top: headerBottom
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
const finalSection = document?.package.document.sections?.at(-1);
|
|
148
|
+
if (finalSection) {
|
|
149
|
+
nextLayoutOpts.finalPageSize = getPageSize(finalSection.properties);
|
|
150
|
+
nextLayoutOpts.finalMargins = getMargins(finalSection.properties);
|
|
151
|
+
}
|
|
193
152
|
if (columns !== void 0) nextLayoutOpts.columns = columns;
|
|
194
153
|
if (bodyBreakType !== void 0) nextLayoutOpts.bodyBreakType = bodyBreakType;
|
|
195
154
|
if (sectionHeaderFooterRefs !== void 0) nextLayoutOpts.sectionHeaderFooterRefs = sectionHeaderFooterRefs;
|
|
196
155
|
return nextLayoutOpts;
|
|
197
156
|
};
|
|
198
|
-
const layoutOpts = buildLayoutOpts(
|
|
157
|
+
const layoutOpts = buildLayoutOpts();
|
|
199
158
|
let layoutOptsUsed = layoutOpts;
|
|
200
159
|
if (hasFootnotes) {
|
|
201
160
|
footnoteContentMap = buildFootnoteContentMap(documentFootnotes, footnoteRefs, contentWidth, (() => {
|
|
@@ -292,57 +251,8 @@ function runLayoutPipeline(deps, state, options = {}) {
|
|
|
292
251
|
firstPageFooterForRender = hasTitlePg ? renderHfFromContentOrPm(firstPageFooterContent, firstPageFooterContentRId, hfPMs, contentWidth, hfMetricsFooter, finalHfOptions) : void 0;
|
|
293
252
|
headerContentByRId = renderHeaderFooterContentByRId(document?.package.headers, hfPMs, contentWidth, hfMetricsHeader, finalHfOptions);
|
|
294
253
|
footerContentByRId = renderHeaderFooterContentByRId(document?.package.footers, hfPMs, contentWidth, hfMetricsFooter, finalHfOptions);
|
|
295
|
-
return {
|
|
296
|
-
headerContent: headerContentForRender,
|
|
297
|
-
footerContent: footerContentForRender,
|
|
298
|
-
firstPageHeaderContent: firstPageHeaderForRender,
|
|
299
|
-
firstPageFooterContent: firstPageFooterForRender
|
|
300
|
-
};
|
|
301
254
|
};
|
|
302
|
-
|
|
303
|
-
for (let pass = 0; pass < MAX_HEADER_FOOTER_STABILIZATION_PASSES; pass++) {
|
|
304
|
-
const finalHfExtenderContent = rebuildHeaderFooterForLayout();
|
|
305
|
-
const finalEffectiveMargins = computeHeaderFooterMarginExtender({
|
|
306
|
-
...finalHfExtenderContent,
|
|
307
|
-
pageSize,
|
|
308
|
-
warn: hfWarn
|
|
309
|
-
})(margins);
|
|
310
|
-
const finalEffectiveFirstPageMargins = hasTitlePg ? computeFirstPageHeaderFooterMarginExtender({
|
|
311
|
-
...finalHfExtenderContent,
|
|
312
|
-
pageSize,
|
|
313
|
-
warn: hfWarn
|
|
314
|
-
})(margins) : void 0;
|
|
315
|
-
if (!pageMarginsEqual(effectiveMargins, finalEffectiveMargins) || !optionalPageMarginsEqual(effectiveFirstPageMargins, finalEffectiveFirstPageMargins)) {
|
|
316
|
-
effectiveMargins = finalEffectiveMargins;
|
|
317
|
-
effectiveFirstPageMargins = finalEffectiveFirstPageMargins;
|
|
318
|
-
applySectionBreakMargins(finalHfExtenderContent, effectiveMargins);
|
|
319
|
-
bodyLayoutConfig = {
|
|
320
|
-
pageSize,
|
|
321
|
-
margins: effectiveMargins
|
|
322
|
-
};
|
|
323
|
-
if (columns !== void 0) bodyLayoutConfig.columns = columns;
|
|
324
|
-
blockMeasureInputs = computePerBlockMeasureInputs({
|
|
325
|
-
blocks: newBlocks,
|
|
326
|
-
bodyConfig: bodyLayoutConfig,
|
|
327
|
-
finalConfig: bodyLayoutConfig
|
|
328
|
-
});
|
|
329
|
-
blockWidths = blockMeasureInputs.widths;
|
|
330
|
-
newMeasures = measureBlocks(newBlocks, blockWidths, blockMeasureInputs.marginTops, {
|
|
331
|
-
pageHeight: blockMeasureInputs.pageHeights,
|
|
332
|
-
marginBottom: blockMeasureInputs.marginBottoms
|
|
333
|
-
});
|
|
334
|
-
pendingArtifacts = {
|
|
335
|
-
blocks: newBlocks,
|
|
336
|
-
blockWidths,
|
|
337
|
-
measures: newMeasures
|
|
338
|
-
};
|
|
339
|
-
outcome.measures = newMeasures;
|
|
340
|
-
relayoutWithCurrentMeasures(buildLayoutOpts(effectiveMargins, effectiveFirstPageMargins));
|
|
341
|
-
stabilizeFieldWidths();
|
|
342
|
-
continue;
|
|
343
|
-
}
|
|
344
|
-
break;
|
|
345
|
-
}
|
|
255
|
+
rebuildHeaderFooterForLayout();
|
|
346
256
|
outcome.layout = newLayout;
|
|
347
257
|
recordPhaseDuration("layout-document", phaseStartedAt);
|
|
348
258
|
if (pagesContainer && painter) {
|
|
@@ -412,17 +322,5 @@ function runLayoutPipeline(deps, state, options = {}) {
|
|
|
412
322
|
syncCoordinator.onLayoutComplete(currentEpoch);
|
|
413
323
|
return outcome;
|
|
414
324
|
}
|
|
415
|
-
function pickSectionHeaderFooterContent(byRId, defaultRId, evenRId) {
|
|
416
|
-
const defaultContent = defaultRId ? byRId?.get(defaultRId) : void 0;
|
|
417
|
-
const evenContent = evenRId ? byRId?.get(evenRId) : void 0;
|
|
418
|
-
if (!defaultContent) return evenContent;
|
|
419
|
-
if (!evenContent) return defaultContent;
|
|
420
|
-
return headerFooterMarginPushHeight(evenContent) > headerFooterMarginPushHeight(defaultContent) ? evenContent : defaultContent;
|
|
421
|
-
}
|
|
422
|
-
function headerFooterMarginPushHeight(content) {
|
|
423
|
-
const bottom = content.marginPushBottom ?? content.visualBottom ?? content.height;
|
|
424
|
-
const top = content.marginPushTop ?? content.visualTop ?? 0;
|
|
425
|
-
return Math.max(bottom - top, content.height);
|
|
426
|
-
}
|
|
427
325
|
//#endregion
|
|
428
326
|
export { runLayoutPipeline };
|
|
@@ -18,7 +18,8 @@ type SchedulerClock = {
|
|
|
18
18
|
declare const browserClock: SchedulerClock;
|
|
19
19
|
type LayoutSchedulerConfig<TState> = {
|
|
20
20
|
runLayout: RunLayout<TState>; /** Quiet-window debounce before an interactive layout pass. */
|
|
21
|
-
debounceMs: number; /**
|
|
21
|
+
debounceMs: number; /** Run the first edit after a max-delay-sized idle period on the next frame. */
|
|
22
|
+
leadingFrame?: boolean; /** Hard cap on latency from the first edit in a burst. */
|
|
22
23
|
maxDelayMs: number;
|
|
23
24
|
/**
|
|
24
25
|
* Timing source. Pass `browserClock` in the browser; a host injects its own
|
|
@@ -9,6 +9,7 @@ const browserClock = {
|
|
|
9
9
|
};
|
|
10
10
|
const createLayoutScheduler = (config) => {
|
|
11
11
|
const clock = config.clock;
|
|
12
|
+
let lastRunAt = null;
|
|
12
13
|
let pending = null;
|
|
13
14
|
const flushPending = () => {
|
|
14
15
|
if (!pending || pending.rafId !== null) return;
|
|
@@ -17,6 +18,7 @@ const createLayoutScheduler = (config) => {
|
|
|
17
18
|
const latest = pending;
|
|
18
19
|
pending = null;
|
|
19
20
|
if (!latest) return;
|
|
21
|
+
lastRunAt = clock.now();
|
|
20
22
|
const options = { reason: "transaction" };
|
|
21
23
|
if (latest.dirtyRange) options.dirtyRange = latest.dirtyRange;
|
|
22
24
|
config.runLayout(latest.state, options);
|
|
@@ -45,6 +47,10 @@ const createLayoutScheduler = (config) => {
|
|
|
45
47
|
timerId: null
|
|
46
48
|
};
|
|
47
49
|
pending = next;
|
|
50
|
+
if (config.leadingFrame && (lastRunAt === null || clock.now() - lastRunAt >= config.maxDelayMs)) {
|
|
51
|
+
flushPending();
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
48
54
|
armTimer(next);
|
|
49
55
|
},
|
|
50
56
|
dispose() {
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { FolioAIEditAppliedOperation, FolioAIEditApplyMode, FolioAIEditOperation, FolioAIEditPrecondition, FolioAIEditSkippedOperation, FolioAIEditSnapshot, FolioAITextRangeHandle } from "./ai-edits/types.js";
|
|
2
|
+
import { FolioAIEditView } from "./ai-edits/apply.js";
|
|
3
|
+
|
|
4
|
+
//#region src/document-operations.d.ts
|
|
5
|
+
declare const FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION: 1;
|
|
6
|
+
declare const FOLIO_DOCUMENT_OPERATION_TYPES: readonly ["replaceInBlock", "replaceRange", "commentOnRange", "formatRange", "insertAfterBlock", "insertBeforeBlock", "replaceBlock", "deleteBlock", "commentOnBlock", "insertSignatureTable"];
|
|
7
|
+
declare const FOLIO_DOCUMENT_OPERATION_MODES: readonly ["direct", "tracked-changes"];
|
|
8
|
+
declare const FOLIO_DOCUMENT_OPERATION_STORIES: readonly ["main"];
|
|
9
|
+
declare const FOLIO_DOCUMENT_OPERATION_PRECONDITIONS: readonly ["blockTextHash"];
|
|
10
|
+
declare const FOLIO_DOCUMENT_OPERATION_BATCH_MODES: readonly ["best-effort", "atomic"];
|
|
11
|
+
type FolioDocumentOperation = FolioAIEditOperation;
|
|
12
|
+
type FolioDocumentOperationMode = FolioAIEditApplyMode;
|
|
13
|
+
type FolioDocumentOperationPrecondition = FolioAIEditPrecondition;
|
|
14
|
+
type FolioDocumentOperationType = FolioDocumentOperation["type"];
|
|
15
|
+
declare const FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE: Readonly<{
|
|
16
|
+
readonly replaceInBlock: readonly ["direct", "tracked-changes"];
|
|
17
|
+
readonly replaceRange: readonly ["direct", "tracked-changes"];
|
|
18
|
+
readonly commentOnRange: readonly ["direct", "tracked-changes"];
|
|
19
|
+
readonly formatRange: readonly ["direct"];
|
|
20
|
+
readonly insertAfterBlock: readonly ["direct", "tracked-changes"];
|
|
21
|
+
readonly insertBeforeBlock: readonly ["direct", "tracked-changes"];
|
|
22
|
+
readonly replaceBlock: readonly ["direct", "tracked-changes"];
|
|
23
|
+
readonly deleteBlock: readonly ["direct", "tracked-changes"];
|
|
24
|
+
readonly commentOnBlock: readonly ["direct", "tracked-changes"];
|
|
25
|
+
readonly insertSignatureTable: readonly ["direct"];
|
|
26
|
+
}>;
|
|
27
|
+
type FolioDocumentOperationCapabilities = {
|
|
28
|
+
readonly version: typeof FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION;
|
|
29
|
+
readonly operationTypes: typeof FOLIO_DOCUMENT_OPERATION_TYPES;
|
|
30
|
+
readonly modes: typeof FOLIO_DOCUMENT_OPERATION_MODES;
|
|
31
|
+
readonly modesByOperationType: typeof FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE;
|
|
32
|
+
readonly batchModes: typeof FOLIO_DOCUMENT_OPERATION_BATCH_MODES;
|
|
33
|
+
readonly dryRun: true;
|
|
34
|
+
readonly preconditions: typeof FOLIO_DOCUMENT_OPERATION_PRECONDITIONS;
|
|
35
|
+
readonly stories: typeof FOLIO_DOCUMENT_OPERATION_STORIES;
|
|
36
|
+
};
|
|
37
|
+
declare const getFolioDocumentOperationCapabilities: () => FolioDocumentOperationCapabilities;
|
|
38
|
+
declare const isFolioDocumentOperationModeSupported: (operationType: FolioDocumentOperationType, mode: FolioDocumentOperationMode) => boolean;
|
|
39
|
+
declare const isSupportedFolioDocumentOperationVersion: (value: unknown) => value is typeof FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION;
|
|
40
|
+
declare const UnsupportedFolioDocumentOperationVersionError_base: import("better-result").TaggedErrorClass<"UnsupportedFolioDocumentOperationVersionError", {
|
|
41
|
+
message: string;
|
|
42
|
+
receivedVersion: unknown;
|
|
43
|
+
}>;
|
|
44
|
+
declare class UnsupportedFolioDocumentOperationVersionError extends UnsupportedFolioDocumentOperationVersionError_base {}
|
|
45
|
+
declare const InvalidFolioDocumentOperationBatchError_base: import("better-result").TaggedErrorClass<"InvalidFolioDocumentOperationBatchError", {
|
|
46
|
+
message: string;
|
|
47
|
+
path: string;
|
|
48
|
+
reason: string;
|
|
49
|
+
}>;
|
|
50
|
+
declare class InvalidFolioDocumentOperationBatchError extends InvalidFolioDocumentOperationBatchError_base {}
|
|
51
|
+
declare const assertSupportedFolioDocumentOperationVersion: (value: unknown) => typeof FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION;
|
|
52
|
+
type FolioDocumentOperationBatch = {
|
|
53
|
+
readonly version: typeof FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION;
|
|
54
|
+
operations: FolioDocumentOperation[];
|
|
55
|
+
mode?: FolioDocumentOperationMode;
|
|
56
|
+
atomic?: boolean;
|
|
57
|
+
dryRun?: boolean;
|
|
58
|
+
};
|
|
59
|
+
declare const parseFolioDocumentOperationBatch: (value: unknown) => FolioDocumentOperationBatch;
|
|
60
|
+
type FolioDocumentOperationStatus = "committed" | "previewed" | "rejected";
|
|
61
|
+
type FolioDocumentOperationRecovery = "refreshDocument" | "narrowMatch" | "changeMode" | "changeTarget" | "removeOperation" | "inspectBatch";
|
|
62
|
+
type FolioDocumentOperationIssue = {
|
|
63
|
+
operationId: string;
|
|
64
|
+
operationIndex: number;
|
|
65
|
+
path: `$.operations[${number}]`;
|
|
66
|
+
code: FolioAIEditSkippedOperation["reason"];
|
|
67
|
+
retryable: boolean;
|
|
68
|
+
recovery: FolioDocumentOperationRecovery;
|
|
69
|
+
};
|
|
70
|
+
/** One typed target affected by a successfully applied document operation. */
|
|
71
|
+
type FolioDocumentOperationAffectedTarget = {
|
|
72
|
+
type: "block";
|
|
73
|
+
story: "main";
|
|
74
|
+
blockId: string;
|
|
75
|
+
effect: "updated" | "deleted" | "commented";
|
|
76
|
+
} | {
|
|
77
|
+
type: "textRange";
|
|
78
|
+
range: FolioAITextRangeHandle;
|
|
79
|
+
effect: "formatted" | "commented";
|
|
80
|
+
} | {
|
|
81
|
+
type: "insertion";
|
|
82
|
+
story: "main";
|
|
83
|
+
anchorBlockId: string;
|
|
84
|
+
position: "before" | "after";
|
|
85
|
+
content: "block" | "signatureTable";
|
|
86
|
+
} | {
|
|
87
|
+
type: "comment";
|
|
88
|
+
commentId: number;
|
|
89
|
+
};
|
|
90
|
+
/** Input-ordered effect receipt for one successfully applied operation. */
|
|
91
|
+
type FolioDocumentOperationReceipt = {
|
|
92
|
+
operationId: string;
|
|
93
|
+
operationIndex: number;
|
|
94
|
+
affected: FolioDocumentOperationAffectedTarget[];
|
|
95
|
+
};
|
|
96
|
+
type FolioDocumentOperationResult = {
|
|
97
|
+
version: typeof FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION;
|
|
98
|
+
status: FolioDocumentOperationStatus;
|
|
99
|
+
applied: FolioAIEditAppliedOperation[];
|
|
100
|
+
skipped: FolioAIEditSkippedOperation[];
|
|
101
|
+
issues: FolioDocumentOperationIssue[]; /** Successful effects in input-operation order; skipped operations are omitted. */
|
|
102
|
+
receipts: FolioDocumentOperationReceipt[];
|
|
103
|
+
};
|
|
104
|
+
declare const getFolioDocumentOperationIssues: (operations: readonly FolioDocumentOperation[], skipped: readonly FolioAIEditSkippedOperation[]) => FolioDocumentOperationIssue[];
|
|
105
|
+
/** Build deterministic affected-target receipts from operations and their applied entries. */
|
|
106
|
+
declare const getFolioDocumentOperationReceipts: (operations: readonly FolioDocumentOperation[], applied: readonly FolioAIEditAppliedOperation[]) => FolioDocumentOperationReceipt[];
|
|
107
|
+
type ApplyFolioDocumentOperationsOptions = {
|
|
108
|
+
view: FolioAIEditView;
|
|
109
|
+
snapshot: FolioAIEditSnapshot;
|
|
110
|
+
batch: FolioDocumentOperationBatch;
|
|
111
|
+
author?: string;
|
|
112
|
+
createCommentId?: (text: string) => number;
|
|
113
|
+
};
|
|
114
|
+
declare const applyFolioDocumentOperations: ({
|
|
115
|
+
view,
|
|
116
|
+
snapshot,
|
|
117
|
+
batch,
|
|
118
|
+
author,
|
|
119
|
+
createCommentId
|
|
120
|
+
}: ApplyFolioDocumentOperationsOptions) => FolioDocumentOperationResult;
|
|
121
|
+
//#endregion
|
|
122
|
+
export { ApplyFolioDocumentOperationsOptions, 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, FolioDocumentOperation, FolioDocumentOperationAffectedTarget, FolioDocumentOperationBatch, FolioDocumentOperationCapabilities, FolioDocumentOperationIssue, FolioDocumentOperationMode, FolioDocumentOperationPrecondition, FolioDocumentOperationReceipt, FolioDocumentOperationRecovery, FolioDocumentOperationResult, FolioDocumentOperationStatus, FolioDocumentOperationType, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch };
|