@stll/folio-core 0.5.0 → 0.6.1
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/headless.d.ts +5 -1
- package/dist/ai-edits/headless.js +53 -3
- package/dist/ai-edits/index.d.ts +2 -2
- package/dist/compat/eigenpal.d.ts +2 -2
- package/dist/controller/layoutPipeline.js +17 -6
- package/dist/document-operations.d.ts +20 -3
- package/dist/document-operations.js +7 -4
- package/dist/docx/blockContentParser.js +2 -100
- package/dist/docx/paragraphTextBoxEnrichment.d.ts +9 -0
- package/dist/docx/paragraphTextBoxEnrichment.js +104 -0
- package/dist/docx/tableParser.js +2 -0
- package/dist/i18n/messages/catalogs.gen.d.ts +1054 -34
- package/dist/i18n/messages/catalogs.gen.js +1122 -68
- package/dist/i18n/messages/messages.gen.d.ts +62 -2
- package/dist/index.d.ts +2 -2
- package/dist/layout-bridge/convert/toFlowBlocks.js +15 -13
- package/dist/layout-bridge/sectionColumns.js +6 -1
- package/dist/layout-engine/index.js +63 -11
- package/dist/layout-engine/measure/measureBlocks.js +25 -2
- package/dist/layout-engine/paginator.d.ts +2 -0
- package/dist/layout-engine/paginator.js +17 -13
- package/dist/layout-engine/tableRowBreak.js +3 -0
- package/dist/layout-engine/types.d.ts +5 -2
- package/dist/layout-painter/index.js +1 -1
- package/dist/layout-painter/renderPage.js +7 -2
- package/dist/layout-painter/renderParagraph.js +5 -4
- package/dist/layout-painter/renderTable.js +88 -10
- package/dist/managers/TableSelectionManager.js +1 -1
- package/dist/paged-layout/sectionBlockWidths.js +11 -3
- package/dist/prosemirror/commands/index.js +1 -1
- package/dist/prosemirror/conversion/fromProseDoc.js +11 -2
- package/dist/prosemirror/conversion/toProseDoc.js +26 -20
- package/dist/prosemirror/extensions/nodes/TableExtension.js +2 -2
- package/dist/prosemirror/index.js +1 -1
- package/dist/prosemirror/insertOperations.js +1 -1
- package/dist/server.d.ts +2 -2
- package/package.json +1 -1
|
@@ -35,6 +35,7 @@ type Messages = {
|
|
|
35
35
|
"red": "Red";
|
|
36
36
|
"yellow": "Yellow";
|
|
37
37
|
};
|
|
38
|
+
"custom": "Custom";
|
|
38
39
|
"customColor": "Custom Color";
|
|
39
40
|
"noColor": "No color";
|
|
40
41
|
"standardColors": "Standard Colors";
|
|
@@ -59,6 +60,7 @@ type Messages = {
|
|
|
59
60
|
"closeDialog": "Close";
|
|
60
61
|
"insert": "Insert";
|
|
61
62
|
"px": "px";
|
|
63
|
+
"remove": "Remove";
|
|
62
64
|
"update": "Update";
|
|
63
65
|
};
|
|
64
66
|
"contentControlDateAriaLabel": "Pick a date";
|
|
@@ -122,13 +124,16 @@ type Messages = {
|
|
|
122
124
|
"title": "Footnote & Endnote Properties";
|
|
123
125
|
};
|
|
124
126
|
"hyperlink": {
|
|
127
|
+
"addressLabel": "Address";
|
|
125
128
|
"bookmarkLabel": "Bookmark";
|
|
126
129
|
"bookmarkPlaceholder": "Select a bookmark";
|
|
127
130
|
"displayTextHint": "Defaults to the selected text";
|
|
128
131
|
"displayTextLabel": "Display text";
|
|
129
132
|
"displayTextPlaceholder": "Text to display";
|
|
130
133
|
"invalidUrl": "Enter a valid URL";
|
|
134
|
+
"linkTo": "Link to";
|
|
131
135
|
"removeLink": "Remove link";
|
|
136
|
+
"screenTipLabel": "Screen tip";
|
|
132
137
|
"tabBookmark": "Bookmark";
|
|
133
138
|
"tabWebAddress": "Web address";
|
|
134
139
|
"titleEdit": "Edit hyperlink";
|
|
@@ -150,9 +155,11 @@ type Messages = {
|
|
|
150
155
|
"top": "Top";
|
|
151
156
|
};
|
|
152
157
|
"alignment": "Alignment";
|
|
158
|
+
"distanceFromText": "Distance from text (px)";
|
|
153
159
|
"horizontal": "Horizontal";
|
|
154
160
|
"offset": "Offset";
|
|
155
161
|
"offsetPx": "Offset (px)";
|
|
162
|
+
"position": "Position";
|
|
156
163
|
"relativeOptions": {
|
|
157
164
|
"character": "Character";
|
|
158
165
|
"column": "Column";
|
|
@@ -173,12 +180,17 @@ type Messages = {
|
|
|
173
180
|
"dashed": "Dashed";
|
|
174
181
|
"dotted": "Dotted";
|
|
175
182
|
"double": "Double";
|
|
183
|
+
"groove": "Groove";
|
|
184
|
+
"inset": "Inset";
|
|
185
|
+
"outset": "Outset";
|
|
186
|
+
"ridge": "Ridge";
|
|
176
187
|
"solid": "Solid";
|
|
177
188
|
};
|
|
178
189
|
"color": "Color";
|
|
179
190
|
"dimensions": "Dimensions";
|
|
180
191
|
"heightLabel": "Height";
|
|
181
192
|
"lockAspectRatio": "Lock aspect ratio";
|
|
193
|
+
"preview": "Preview";
|
|
182
194
|
"style": "Style";
|
|
183
195
|
"textWrapping": "Text wrapping";
|
|
184
196
|
"title": "Image Properties";
|
|
@@ -193,6 +205,11 @@ type Messages = {
|
|
|
193
205
|
"wrapRight": "Wrap right";
|
|
194
206
|
};
|
|
195
207
|
};
|
|
208
|
+
"insertImage": {
|
|
209
|
+
"altText": "Alt text";
|
|
210
|
+
"imageFile": "Image file";
|
|
211
|
+
"title": "Insert Image";
|
|
212
|
+
};
|
|
196
213
|
"insertSymbol": {
|
|
197
214
|
"categories": {
|
|
198
215
|
"arrows": "Arrows";
|
|
@@ -209,18 +226,19 @@ type Messages = {
|
|
|
209
226
|
"title": "Insert symbol";
|
|
210
227
|
};
|
|
211
228
|
"insertTable": {
|
|
212
|
-
"autofit": "Autofit";
|
|
229
|
+
"autofit": "Autofit to contents";
|
|
213
230
|
"columnWidthLabel": "Column width";
|
|
214
231
|
"columnsLabel": "Columns";
|
|
215
232
|
"fixedWidth": "Fixed width";
|
|
216
233
|
"hoverToSelect": "Hover to select table size";
|
|
217
234
|
"insertButton": "Insert";
|
|
218
235
|
"orSpecifySize": "Or specify size";
|
|
236
|
+
"plainTable": "Plain table";
|
|
219
237
|
"rowsLabel": "Rows";
|
|
220
238
|
"sizeSelector": "Table size selector";
|
|
221
239
|
"style": "Style";
|
|
222
240
|
"tableSize": "{cols} × {rows} table";
|
|
223
|
-
"title": "Insert
|
|
241
|
+
"title": "Insert Table";
|
|
224
242
|
"validationHint": "Rows: {minRows}–{maxRows}, columns: {minCols}–{maxCols}";
|
|
225
243
|
};
|
|
226
244
|
"pageSetup": {
|
|
@@ -245,6 +263,16 @@ type Messages = {
|
|
|
245
263
|
"sizeLabel": "Size";
|
|
246
264
|
"title": "Page Setup";
|
|
247
265
|
"top": "Top";
|
|
266
|
+
"unitInches": "in";
|
|
267
|
+
};
|
|
268
|
+
"pasteSpecial": {
|
|
269
|
+
"pasteMode": "Paste mode";
|
|
270
|
+
"title": "Paste Special";
|
|
271
|
+
};
|
|
272
|
+
"splitCell": {
|
|
273
|
+
"mergeBeforeSplit": "Merge selected cells before splitting";
|
|
274
|
+
"splitButton": "Split";
|
|
275
|
+
"title": "Split Cell";
|
|
248
276
|
};
|
|
249
277
|
"tableProperties": {
|
|
250
278
|
"alignOptions": {
|
|
@@ -266,6 +294,23 @@ type Messages = {
|
|
|
266
294
|
"percentage": "Percentage";
|
|
267
295
|
};
|
|
268
296
|
};
|
|
297
|
+
"watermark": {
|
|
298
|
+
"color": "Color";
|
|
299
|
+
"diagonal": "Diagonal";
|
|
300
|
+
"font": "Font";
|
|
301
|
+
"imageRelationshipId": "Header image relationship id";
|
|
302
|
+
"imageTarget": "Image target";
|
|
303
|
+
"noWatermark": "No watermark";
|
|
304
|
+
"opacity": "Opacity";
|
|
305
|
+
"pictureWatermark": "Picture watermark";
|
|
306
|
+
"scale": "Scale";
|
|
307
|
+
"targetIsExternalUrl": "Target is an external URL";
|
|
308
|
+
"text": "Text";
|
|
309
|
+
"textWatermark": "Text watermark";
|
|
310
|
+
"title": "Watermark";
|
|
311
|
+
"type": "Type";
|
|
312
|
+
"washout": "Washout";
|
|
313
|
+
};
|
|
269
314
|
};
|
|
270
315
|
"discardChanges": "Discard";
|
|
271
316
|
"dismiss": "Dismiss";
|
|
@@ -338,6 +383,17 @@ type Messages = {
|
|
|
338
383
|
"superscriptShortcut": "Superscript (Ctrl+Shift+=)";
|
|
339
384
|
};
|
|
340
385
|
"formattingToolbar": "Formatting toolbar";
|
|
386
|
+
"headerFooter": {
|
|
387
|
+
"closeFooterEditing": "Close footer editing";
|
|
388
|
+
"closeHeaderEditing": "Close header editing";
|
|
389
|
+
"footer": "Footer";
|
|
390
|
+
"header": "Header";
|
|
391
|
+
"insertPageCount": "Insert total page count";
|
|
392
|
+
"insertPageNumber": "Insert current page number";
|
|
393
|
+
"options": "Options";
|
|
394
|
+
"removeFooter": "Remove footer";
|
|
395
|
+
"removeHeader": "Remove header";
|
|
396
|
+
};
|
|
341
397
|
"hideDetails": "Hide details";
|
|
342
398
|
"historyGroup": "History";
|
|
343
399
|
"imageOverlay": {
|
|
@@ -399,6 +455,7 @@ type Messages = {
|
|
|
399
455
|
};
|
|
400
456
|
"listFormatting": "List formatting";
|
|
401
457
|
"listsGroup": "Lists";
|
|
458
|
+
"loadDocumentFailedTitle": "Failed to Load Document";
|
|
402
459
|
"loadingDocument": "Loading document...";
|
|
403
460
|
"loadingEditor": "Loading editor...";
|
|
404
461
|
"lockFile": "Lock file";
|
|
@@ -411,8 +468,10 @@ type Messages = {
|
|
|
411
468
|
"moreFormatting": "More formatting";
|
|
412
469
|
"networkError": "Network error. Please check your internet connection and try again.";
|
|
413
470
|
"nextChange": "Next Change";
|
|
471
|
+
"noDocumentLoaded": "No document loaded";
|
|
414
472
|
"numberedList": "Numbered List";
|
|
415
473
|
"parseError": "The document could not be parsed. It may be corrupted or in an unsupported format.";
|
|
474
|
+
"parseErrorTitle": "Unable to Parse Document";
|
|
416
475
|
"paste": "Paste";
|
|
417
476
|
"pasteUnformatted": "Paste without formatting";
|
|
418
477
|
"previousChange": "Previous Change";
|
|
@@ -572,6 +631,7 @@ type Messages = {
|
|
|
572
631
|
"viewGroup": "View";
|
|
573
632
|
"viewer": {
|
|
574
633
|
"pageIndicator": "Page {current} of {total}";
|
|
634
|
+
"pageOfTotal": "{current} of {total}";
|
|
575
635
|
};
|
|
576
636
|
"zoom": {
|
|
577
637
|
"zoomIn": "Zoom in";
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
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
|
+
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, FolioDocumentOperationUndoFailureReason, FolioDocumentOperationUndoHandle, FolioDocumentOperationUndoResult, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch } from "./document-operations.js";
|
|
5
5
|
import { createFolioAIEditSnapshot, hashFolioAIBlockText, normalizeFolioAIBlockText } from "./ai-edits/snapshot.js";
|
|
6
6
|
import { DeriveBlockIdInput, FolioBlockId, deriveBlockId, getFolioParaIdFromBlockId, isFolioBlockId, isSequentialFolioBlockId } from "./types/block-id.js";
|
|
7
7
|
import { WordDiffSegment, diffWordSegments } from "./ai-edits/word-diff.js";
|
|
@@ -27,4 +27,4 @@ import { toMarkdown, toMarkdownResult } from "./markdown/index.js";
|
|
|
27
27
|
import { EmbeddedFont, EmbeddedFontParts, extractEmbeddedFonts, getEmbeddedFontFaces } from "./fonts/embeddedFonts.js";
|
|
28
28
|
import { getGoogleFontsEnabled, setGoogleFontsEnabled } from "./utils/fontResolver.js";
|
|
29
29
|
type Document = document_d_exports.Document;
|
|
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 };
|
|
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 FolioDocumentOperationUndoFailureReason, type FolioDocumentOperationUndoHandle, type FolioDocumentOperationUndoResult, 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 };
|
|
@@ -6,8 +6,9 @@ import { resolveColor, resolveHighlightToCss } from "../../utils/colorResolver.j
|
|
|
6
6
|
import { resolveShadingFill } from "../../utils/formatToStyle.js";
|
|
7
7
|
import { convertBulletToUnicode } from "../../docx/bulletMarkers.js";
|
|
8
8
|
import { setTextBoxGroupId } from "../../layout-engine/textBoxGroup.js";
|
|
9
|
+
import { getColumns } from "../sectionColumns.js";
|
|
9
10
|
import { directionIsRtl } from "../../prosemirror/paragraphDirection.js";
|
|
10
|
-
import { expectBlockSdtAttrs, expectCharacterSpacingMarkAttrs, expectCommentMarkAttrs, expectEmphasisMarkAttrs, expectFieldAttrs, expectFontFamilyMarkAttrs, expectFontSizeMarkAttrs, expectFootnoteRefMarkAttrs, expectHighlightMarkAttrs, expectHyperlinkMarkAttrs, expectImageAttrs, expectMathAttrs, expectParagraphAttrs, expectRunFormattingOverrideMarkAttrs, expectRunShadingMarkAttrs, expectTableAttrs, expectTableCellAttrs, expectTableRowAttrs, expectTextBoxAttrs, expectTextColorMarkAttrs, expectTextEffectMarkAttrs, expectTrackedChangeMarkAttrs, expectUnderlineMarkAttrs } from "../../prosemirror/attrs/index.js";
|
|
11
|
+
import { expectBlockSdtAttrs, expectCharacterSpacingMarkAttrs, expectCommentMarkAttrs, expectEmphasisMarkAttrs, expectFieldAttrs, expectFontFamilyMarkAttrs, expectFontSizeMarkAttrs, expectFootnoteRefMarkAttrs, expectHardBreakAttrs, expectHighlightMarkAttrs, expectHyperlinkMarkAttrs, expectImageAttrs, expectMathAttrs, expectParagraphAttrs, expectRunFormattingOverrideMarkAttrs, expectRunShadingMarkAttrs, expectTableAttrs, expectTableCellAttrs, expectTableRowAttrs, expectTextBoxAttrs, expectTextColorMarkAttrs, expectTextEffectMarkAttrs, expectTrackedChangeMarkAttrs, expectUnderlineMarkAttrs } from "../../prosemirror/attrs/index.js";
|
|
11
12
|
import { autospacingMatchesBase } from "../../prosemirror/autospacingBase.js";
|
|
12
13
|
import { runShadingAttrsToShading } from "../../prosemirror/conversion/runShadingMark.js";
|
|
13
14
|
import { assertValidProseMirrorDocument } from "../../prosemirror/validation.js";
|
|
@@ -919,6 +920,7 @@ function convertTableCell(node, startPos, options, tableCellMargins) {
|
|
|
919
920
|
const block = convertParagraph(child, offset, options);
|
|
920
921
|
blocks.push(block);
|
|
921
922
|
} else if (child.type.name === "table") blocks.push(convertTable(child, offset, options));
|
|
923
|
+
else if (child.type.name === "textBox") blocks.push(convertTextBoxNode(child, offset, options));
|
|
922
924
|
offset += child.nodeSize;
|
|
923
925
|
});
|
|
924
926
|
const trailingBlock = blocks.at(-1);
|
|
@@ -1213,9 +1215,17 @@ function toFlowBlocks(doc, options = {}) {
|
|
|
1213
1215
|
}
|
|
1214
1216
|
switch (node.type.name) {
|
|
1215
1217
|
case "paragraph": {
|
|
1216
|
-
const block = convertParagraph(node, pos, opts);
|
|
1217
1218
|
const pmAttrs = expectParagraphAttrs(node);
|
|
1218
|
-
|
|
1219
|
+
const onlyChild = node.childCount === 1 ? node.firstChild : null;
|
|
1220
|
+
if (onlyChild?.type.name === "hardBreak" && expectHardBreakAttrs(onlyChild).breakType === "column") {
|
|
1221
|
+
const columnBreak = {
|
|
1222
|
+
kind: "columnBreak",
|
|
1223
|
+
id: nextBlockId(),
|
|
1224
|
+
pmStart: pos,
|
|
1225
|
+
pmEnd: pos + node.nodeSize
|
|
1226
|
+
};
|
|
1227
|
+
trackedPush(columnBreak);
|
|
1228
|
+
} else trackedPush(convertParagraph(node, pos, opts));
|
|
1219
1229
|
const secProps = pmAttrs._sectionProperties;
|
|
1220
1230
|
if (secProps || pmAttrs.sectionBreakType) {
|
|
1221
1231
|
const sectionBreak = {
|
|
@@ -1245,16 +1255,8 @@ function toFlowBlocks(doc, options = {}) {
|
|
|
1245
1255
|
if (secProps.headerDistance !== void 0) sectionBreak.margins.header = twipsToPixels(secProps.headerDistance);
|
|
1246
1256
|
if (secProps.footerDistance !== void 0) sectionBreak.margins.footer = twipsToPixels(secProps.footerDistance);
|
|
1247
1257
|
}
|
|
1248
|
-
const
|
|
1249
|
-
if (
|
|
1250
|
-
const cols = {
|
|
1251
|
-
count: colCount,
|
|
1252
|
-
gap: twipsToPixels(secProps.columnSpace ?? 720),
|
|
1253
|
-
equalWidth: secProps.equalWidth ?? true
|
|
1254
|
-
};
|
|
1255
|
-
if (secProps.separator !== void 0) cols.separator = secProps.separator;
|
|
1256
|
-
sectionBreak.columns = cols;
|
|
1257
|
-
}
|
|
1258
|
+
const columns = getColumns(secProps);
|
|
1259
|
+
if (columns) sectionBreak.columns = columns;
|
|
1258
1260
|
}
|
|
1259
1261
|
trackedPush(sectionBreak);
|
|
1260
1262
|
}
|
|
@@ -7,13 +7,18 @@ const DEFAULT_COLUMN_SPACE_TWIPS = 720;
|
|
|
7
7
|
* Returns undefined for single-column (default) to avoid unnecessary paginator overhead.
|
|
8
8
|
*/
|
|
9
9
|
function getColumns(sectionProps) {
|
|
10
|
-
const
|
|
10
|
+
const authoredColumns = sectionProps?.columns;
|
|
11
|
+
const count = sectionProps?.columnCount ?? authoredColumns?.length ?? 1;
|
|
11
12
|
if (count <= 1) return void 0;
|
|
12
13
|
const columns = {
|
|
13
14
|
count,
|
|
14
15
|
gap: twipsToPixels(sectionProps?.columnSpace ?? DEFAULT_COLUMN_SPACE_TWIPS),
|
|
15
16
|
equalWidth: sectionProps?.equalWidth ?? true
|
|
16
17
|
};
|
|
18
|
+
if (sectionProps?.equalWidth === false && authoredColumns?.length === count && authoredColumns.every(({ width }) => width !== void 0)) {
|
|
19
|
+
columns.widths = authoredColumns.map(({ width }) => twipsToPixels(width ?? 0));
|
|
20
|
+
columns.gaps = authoredColumns.slice(0, -1).map(({ space }) => twipsToPixels(space ?? sectionProps.columnSpace ?? DEFAULT_COLUMN_SPACE_TWIPS));
|
|
21
|
+
}
|
|
17
22
|
if (sectionProps?.separator !== void 0) columns.separator = sectionProps.separator;
|
|
18
23
|
return columns;
|
|
19
24
|
}
|
|
@@ -156,7 +156,8 @@ function layoutDocument(blocks, measures, options) {
|
|
|
156
156
|
pageSize: finalPageSize,
|
|
157
157
|
margins: finalMargins
|
|
158
158
|
};
|
|
159
|
-
|
|
159
|
+
const finalColumns = options.finalColumns ?? options.columns;
|
|
160
|
+
if (finalColumns !== void 0) finalConfig.columns = finalColumns;
|
|
160
161
|
const { configs: sectionConfigs, breakIndices } = collectSectionConfigs(blocks, bodyConfig, finalConfig);
|
|
161
162
|
const sectionBreakTypes = [...breakIndices.map((index) => blocks[index].type), options.bodyBreakType];
|
|
162
163
|
const initialConfig = sectionConfigs.at(0) ?? bodyConfig;
|
|
@@ -197,11 +198,11 @@ function layoutDocument(blocks, measures, options) {
|
|
|
197
198
|
const pageBeforeBlockLayout = paginator.getCurrentState().page.number;
|
|
198
199
|
switch (block.kind) {
|
|
199
200
|
case "paragraph":
|
|
200
|
-
layoutParagraph(block, measure, paginator, paginator.
|
|
201
|
+
layoutParagraph(block, measure, paginator, paginator.columnWidth, options.footnoteHeightById);
|
|
201
202
|
break;
|
|
202
203
|
case "table":
|
|
203
204
|
if (block.floating) layoutFloatingTable(block, measure, paginator, paginator.getContentWidth());
|
|
204
|
-
else layoutTable(block, measure, paginator);
|
|
205
|
+
else layoutTable(block, measure, paginator, options.footnoteHeightById);
|
|
205
206
|
break;
|
|
206
207
|
case "image":
|
|
207
208
|
layoutImage(block, measure, paginator);
|
|
@@ -416,9 +417,10 @@ function getHeaderRowsHeight(measure, headerRowCount) {
|
|
|
416
417
|
/**
|
|
417
418
|
* Layout a table block onto pages.
|
|
418
419
|
*/
|
|
419
|
-
function layoutTable(block, measure, paginator) {
|
|
420
|
+
function layoutTable(block, measure, paginator, footnoteHeightById) {
|
|
420
421
|
const rows = measure.rows;
|
|
421
422
|
if (rows.length === 0) return;
|
|
423
|
+
const rowFootnoteIds = block.rows.map((row) => collectTableRowFootnoteIds(row, footnoteHeightById));
|
|
422
424
|
const headerRowCount = countHeaderRows(block);
|
|
423
425
|
const headerRowsHeight = getHeaderRowsHeight(measure, headerRowCount);
|
|
424
426
|
let currentRowIndex = 0;
|
|
@@ -427,9 +429,9 @@ function layoutTable(block, measure, paginator) {
|
|
|
427
429
|
let x = paginator.getColumnX(columnIndex);
|
|
428
430
|
if (block.justification === "center") x += (paginator.columnWidth - measure.totalWidth) / 2;
|
|
429
431
|
else if (block.justification === "right") x = x + paginator.columnWidth - measure.totalWidth;
|
|
430
|
-
else
|
|
431
|
-
const leadingCellMargin = block.rows
|
|
432
|
-
x += block.indent - leadingCellMargin;
|
|
432
|
+
else {
|
|
433
|
+
const leadingCellMargin = block.rows.at(0)?.cells.at(0)?.padding?.left ?? 0;
|
|
434
|
+
x += (block.indent ?? 0) - leadingCellMargin;
|
|
433
435
|
}
|
|
434
436
|
return x;
|
|
435
437
|
};
|
|
@@ -507,13 +509,42 @@ function layoutTable(block, measure, paginator) {
|
|
|
507
509
|
const normalHeaderOverhead = repeatHeaderRowsForNormalFragment ? headerRowsHeight : 0;
|
|
508
510
|
let rowsHeight = 0;
|
|
509
511
|
let fittingRows = 0;
|
|
512
|
+
const pageFootnoteIds = new Set(state.page.footnoteIds ?? []);
|
|
513
|
+
const fragmentFootnoteIds = [];
|
|
514
|
+
let fragmentFootnoteHeight = 0;
|
|
515
|
+
let retryOnNextFlowRegion = false;
|
|
510
516
|
for (let j = currentRowIndex; j < rows.length; j++) {
|
|
511
517
|
const rowHeight = rows[j].height;
|
|
512
|
-
|
|
518
|
+
const currentRowFootnoteIds = rowFootnoteIds[j] ?? [];
|
|
519
|
+
const fragmentFootnoteCountBeforeRow = fragmentFootnoteIds.length;
|
|
520
|
+
let rowFootnoteHeight = 0;
|
|
521
|
+
for (const id of currentRowFootnoteIds) {
|
|
522
|
+
if (pageFootnoteIds.has(id) || fragmentFootnoteIds.includes(id)) continue;
|
|
523
|
+
fragmentFootnoteIds.push(id);
|
|
524
|
+
rowFootnoteHeight += footnoteHeightById?.get(id) ?? 0;
|
|
525
|
+
}
|
|
526
|
+
const separatorHeight = pageFootnoteIds.size === 0 && fragmentFootnoteHeight + rowFootnoteHeight > 0 ? 12 : 0;
|
|
527
|
+
if (rowsHeight + rowHeight + normalHeaderOverhead + fragmentFootnoteHeight + rowFootnoteHeight + separatorHeight <= availableHeight) {
|
|
513
528
|
rowsHeight += rowHeight;
|
|
529
|
+
fragmentFootnoteHeight += rowFootnoteHeight;
|
|
514
530
|
fittingRows++;
|
|
515
|
-
} else
|
|
531
|
+
} else if (fittingRows === 0) {
|
|
532
|
+
if (state.cursorY === state.topMargin && state.page.fragments.length === 0) {
|
|
533
|
+
rowsHeight += rowHeight;
|
|
534
|
+
fragmentFootnoteHeight += rowFootnoteHeight;
|
|
535
|
+
fittingRows++;
|
|
536
|
+
break;
|
|
537
|
+
}
|
|
538
|
+
fragmentFootnoteIds.splice(fragmentFootnoteCountBeforeRow);
|
|
539
|
+
paginator.forceColumnBreak();
|
|
540
|
+
retryOnNextFlowRegion = true;
|
|
541
|
+
break;
|
|
542
|
+
} else {
|
|
543
|
+
fragmentFootnoteIds.splice(fragmentFootnoteCountBeforeRow);
|
|
544
|
+
break;
|
|
545
|
+
}
|
|
516
546
|
}
|
|
547
|
+
if (retryOnNextFlowRegion) continue;
|
|
517
548
|
const fragmentHeight = rowsHeight + normalHeaderOverhead;
|
|
518
549
|
const isLastFragment = currentRowIndex + fittingRows >= rows.length;
|
|
519
550
|
const desiredX = computeTableX(state.columnIndex);
|
|
@@ -533,6 +564,7 @@ function layoutTable(block, measure, paginator) {
|
|
|
533
564
|
...repeatHeaderRowsForNormalFragment ? { headerRowCount } : {},
|
|
534
565
|
...block.sdtGroups ? { sdtGroups: block.sdtGroups } : {}
|
|
535
566
|
};
|
|
567
|
+
if (fragmentFootnoteHeight > 0) paginator.addFootnoteHeight(fragmentFootnoteHeight, fragmentFootnoteIds);
|
|
536
568
|
fragment.y = paginator.addFragment(fragment, fragmentHeight, bandSkip, 0).y;
|
|
537
569
|
fragment.x = desiredX;
|
|
538
570
|
currentRowIndex += fittingRows;
|
|
@@ -549,6 +581,25 @@ function layoutTable(block, measure, paginator) {
|
|
|
549
581
|
}
|
|
550
582
|
}
|
|
551
583
|
}
|
|
584
|
+
function collectTableRowFootnoteIds(row, footnoteHeightById) {
|
|
585
|
+
if (!row || !footnoteHeightById) return [];
|
|
586
|
+
const ids = [];
|
|
587
|
+
const walk = (blocks) => {
|
|
588
|
+
for (const block of blocks) {
|
|
589
|
+
if (block.kind === "paragraph") {
|
|
590
|
+
for (const run of block.runs) if (run.kind === "text" && run.footnoteRefId !== void 0 && footnoteHeightById.has(run.footnoteRefId) && !ids.includes(run.footnoteRefId)) ids.push(run.footnoteRefId);
|
|
591
|
+
continue;
|
|
592
|
+
}
|
|
593
|
+
if (block.kind === "table") {
|
|
594
|
+
for (const nestedRow of block.rows) for (const cell of nestedRow.cells) walk(cell.blocks);
|
|
595
|
+
continue;
|
|
596
|
+
}
|
|
597
|
+
if (block.kind === "textBox") walk(block.content);
|
|
598
|
+
}
|
|
599
|
+
};
|
|
600
|
+
for (const cell of row.cells) walk(cell.blocks);
|
|
601
|
+
return ids;
|
|
602
|
+
}
|
|
552
603
|
/**
|
|
553
604
|
* Layout a floating table (anchored) without advancing the cursor.
|
|
554
605
|
*/
|
|
@@ -587,8 +638,9 @@ function layoutFloatingTable(block, measure, paginator, contentWidth) {
|
|
|
587
638
|
else if (spec === "center") y = baseY + (contentHeight - tableHeight) / 2;
|
|
588
639
|
}
|
|
589
640
|
if (!usedExplicitY) y = paginator.ensureFits(tableHeight).cursorY;
|
|
590
|
-
const
|
|
591
|
-
const
|
|
641
|
+
const pageAnchored = floating?.horzAnchor === "page";
|
|
642
|
+
const minX = pageAnchored ? 0 : margins.left;
|
|
643
|
+
const maxX = pageAnchored ? page.size.w - tableWidth : margins.left + contentWidth - tableWidth;
|
|
592
644
|
if (Number.isFinite(maxX)) x = Math.max(minX, Math.min(x, maxX));
|
|
593
645
|
const fragment = {
|
|
594
646
|
kind: "table",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DEFAULT_TEXTBOX_MARGINS, floatingTextBoxReservesBand, tableColumnsArePinned } from "../types.js";
|
|
1
|
+
import { DEFAULT_TEXTBOX_MARGINS, floatingTextBoxReservesBand, isFloatingTextBoxBlock, tableColumnsArePinned } from "../types.js";
|
|
2
2
|
import { findClearLineY, measureParagraph } from "./measureParagraph.js";
|
|
3
3
|
import { getCachedParagraphMeasure, setCachedParagraphMeasure } from "./cache.js";
|
|
4
4
|
import { getTextBoxGroupId } from "../textBoxGroup.js";
|
|
@@ -56,6 +56,7 @@ function isInlineFlowImageRun(run) {
|
|
|
56
56
|
return true;
|
|
57
57
|
}
|
|
58
58
|
function measureTableCellBlockVisualHeight(block, blockMeasure) {
|
|
59
|
+
if (block.kind === "textBox" && isFloatingTextBoxBlock(block)) return 0;
|
|
59
60
|
if (block.kind !== "paragraph" || blockMeasure.kind !== "paragraph") {
|
|
60
61
|
if ("totalHeight" in blockMeasure) return blockMeasure.totalHeight;
|
|
61
62
|
if ("height" in blockMeasure) return blockMeasure.height;
|
|
@@ -95,7 +96,7 @@ function measureTableBlock(tableBlock, contentWidth, fieldValues) {
|
|
|
95
96
|
columnWidths = Array.from({ length: colCount }, () => equalWidth);
|
|
96
97
|
} else if (columnWidths.length > 0 && explicitWidthPx) {
|
|
97
98
|
const totalWidth = columnWidths.reduce((sum, w) => sum + w, 0);
|
|
98
|
-
if (totalWidth > 0 && Math.abs(totalWidth - explicitWidthPx) > 1) {
|
|
99
|
+
if (!(tableBlock.layout !== "fixed" && (tableBlock.widthType === void 0 || tableBlock.widthType === "dxa") && totalWidth - explicitWidthPx > 1) && totalWidth > 0 && Math.abs(totalWidth - explicitWidthPx) > 1) {
|
|
99
100
|
const scale = explicitWidthPx / totalWidth;
|
|
100
101
|
columnWidths = columnWidths.map((w) => w * scale);
|
|
101
102
|
}
|
|
@@ -176,6 +177,7 @@ function measureTableBlock(tableBlock, contentWidth, fieldValues) {
|
|
|
176
177
|
const padTop = sourceCell?.padding?.top ?? DEFAULT_CELL_PADDING_Y;
|
|
177
178
|
const padBottom = sourceCell?.padding?.bottom ?? DEFAULT_CELL_PADDING_Y;
|
|
178
179
|
cell.height += padTop + padBottom;
|
|
180
|
+
if ((sourceCell?.rowSpan ?? 1) > 1) continue;
|
|
179
181
|
const borderHeight = getTableCellVerticalBorderHeight(sourceCell, rowIdx === 0);
|
|
180
182
|
maxCellHeightWithBorders = Math.max(maxCellHeightWithBorders, cell.height + borderHeight);
|
|
181
183
|
maxBorderHeight = Math.max(maxBorderHeight, borderHeight);
|
|
@@ -186,6 +188,27 @@ function measureTableBlock(tableBlock, contentWidth, fieldValues) {
|
|
|
186
188
|
else if (explicitHeight) row.height = Math.max(maxCellHeightWithBorders, explicitHeight + maxBorderHeight);
|
|
187
189
|
else row.height = maxCellHeightWithBorders;
|
|
188
190
|
}
|
|
191
|
+
for (let rowIdx = 0; rowIdx < rows.length; rowIdx++) {
|
|
192
|
+
const sourceRow = tableBlock.rows[rowIdx];
|
|
193
|
+
const measuredRow = rows[rowIdx];
|
|
194
|
+
if (!sourceRow || !measuredRow) continue;
|
|
195
|
+
for (let cellIdx = 0; cellIdx < sourceRow.cells.length; cellIdx++) {
|
|
196
|
+
const sourceCell = sourceRow.cells[cellIdx];
|
|
197
|
+
const measuredCell = measuredRow.cells[cellIdx];
|
|
198
|
+
const rowSpan = sourceCell?.rowSpan ?? 1;
|
|
199
|
+
if (!sourceCell || !measuredCell || rowSpan <= 1) continue;
|
|
200
|
+
const spanEnd = Math.min(rows.length, rowIdx + rowSpan);
|
|
201
|
+
let combinedHeight = 0;
|
|
202
|
+
for (let spannedRowIdx = rowIdx; spannedRowIdx < spanEnd; spannedRowIdx++) combinedHeight += rows[spannedRowIdx]?.height ?? 0;
|
|
203
|
+
const deficit = measuredCell.height + getTableCellVerticalBorderHeight(sourceCell, rowIdx === 0) - combinedHeight;
|
|
204
|
+
if (deficit <= 0) continue;
|
|
205
|
+
for (let spannedRowIdx = spanEnd - 1; spannedRowIdx >= rowIdx; spannedRowIdx--) {
|
|
206
|
+
if (tableBlock.rows[spannedRowIdx]?.heightRule === "exact") continue;
|
|
207
|
+
rows[spannedRowIdx].height += deficit;
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
189
212
|
const totalHeight = rows.reduce((h, r) => h + r.height, 0);
|
|
190
213
|
const totalWidth = columnWidths.reduce((w, cw) => w + cw, 0) || explicitWidthPx || contentWidth;
|
|
191
214
|
return {
|
|
@@ -55,6 +55,8 @@ declare function createPaginator(options: PaginatorOptions): {
|
|
|
55
55
|
count: number;
|
|
56
56
|
gap: number;
|
|
57
57
|
equalWidth?: boolean;
|
|
58
|
+
widths?: number[];
|
|
59
|
+
gaps?: number[];
|
|
58
60
|
separator?: boolean;
|
|
59
61
|
}; /** Get current state. */
|
|
60
62
|
getCurrentState: () => PageState; /** Get available height in current column. */
|
|
@@ -7,12 +7,13 @@ import { panic } from "better-result";
|
|
|
7
7
|
* Tracks the current page, cursor position, and available space.
|
|
8
8
|
* Creates new pages when content doesn't fit.
|
|
9
9
|
*/
|
|
10
|
-
/**
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
return (
|
|
10
|
+
/** Calculate active column widths, preferring authored unequal widths. */
|
|
11
|
+
function calculateColumnWidths(pageWidth, leftMargin, rightMargin, columns) {
|
|
12
|
+
if (columns.widths?.length === columns.count && columns.widths.every((width) => Number.isFinite(width) && width > 0)) return [...columns.widths];
|
|
13
|
+
const equalWidth = (pageWidth - leftMargin - rightMargin - (columns.count - 1) * columns.gap) / columns.count;
|
|
14
|
+
return Array.from({ length: columns.count }, () => equalWidth);
|
|
15
15
|
}
|
|
16
|
+
const gapAfterColumn = (columns, columnIndex) => columns.gaps?.[columnIndex] ?? columns.gap;
|
|
16
17
|
function arePageSizesEqual(left, right) {
|
|
17
18
|
return left.w === right.w && left.h === right.h;
|
|
18
19
|
}
|
|
@@ -49,9 +50,9 @@ function createPaginator(options) {
|
|
|
49
50
|
return arePageSizesEqual(state.page.size, pageSize) && areMarginsEqual(state.page.margins, getPageMargins(state.page.number));
|
|
50
51
|
}
|
|
51
52
|
if (getContentHeight() <= 0) panic("Paginator: page size and margins yield no content area");
|
|
52
|
-
let
|
|
53
|
-
function
|
|
54
|
-
|
|
53
|
+
let columnWidths = calculateColumnWidths(pageSize.w, margins.left, margins.right, columns);
|
|
54
|
+
function recalculateColumnWidths() {
|
|
55
|
+
columnWidths = calculateColumnWidths(pageSize.w, margins.left, margins.right, columns);
|
|
55
56
|
}
|
|
56
57
|
function applyPendingLayout() {
|
|
57
58
|
if (pendingPageSize) pageSize = pendingPageSize;
|
|
@@ -59,7 +60,7 @@ function createPaginator(options) {
|
|
|
59
60
|
pendingPageSize = void 0;
|
|
60
61
|
pendingMargins = void 0;
|
|
61
62
|
if (getContentHeight() <= 0) panic("Paginator: section page size and margins yield no content area");
|
|
62
|
-
|
|
63
|
+
recalculateColumnWidths();
|
|
63
64
|
}
|
|
64
65
|
function getPageMargins(pageNumber) {
|
|
65
66
|
const pageMargins = pageNumber === 1 && options.firstPageMargins ? { ...options.firstPageMargins } : { ...margins };
|
|
@@ -75,7 +76,9 @@ function createPaginator(options) {
|
|
|
75
76
|
* Get X position for a given column index.
|
|
76
77
|
*/
|
|
77
78
|
function getColumnX(columnIndex) {
|
|
78
|
-
|
|
79
|
+
let x = states.at(-1)?.page.margins.left ?? getPageMargins(1).left;
|
|
80
|
+
for (let index = 0; index < columnIndex; index++) x += (columnWidths[index] ?? columnWidths[0] ?? 0) + gapAfterColumn(columns, index);
|
|
81
|
+
return x;
|
|
79
82
|
}
|
|
80
83
|
/**
|
|
81
84
|
* Create a new page and add it to the list.
|
|
@@ -274,7 +277,7 @@ function createPaginator(options) {
|
|
|
274
277
|
*/
|
|
275
278
|
function updateColumns(newColumns) {
|
|
276
279
|
columns = newColumns;
|
|
277
|
-
|
|
280
|
+
recalculateColumnWidths();
|
|
278
281
|
const state = getCurrentState();
|
|
279
282
|
if (columns.count > 1) state.page.columns = { ...columns };
|
|
280
283
|
else delete state.page.columns;
|
|
@@ -290,7 +293,7 @@ function createPaginator(options) {
|
|
|
290
293
|
if (newPageSize) pageSize = { ...newPageSize };
|
|
291
294
|
if (newMargins) margins = { ...newMargins };
|
|
292
295
|
if (getContentHeight() <= 0) panic("Paginator: section page size and margins yield no content area");
|
|
293
|
-
|
|
296
|
+
recalculateColumnWidths();
|
|
294
297
|
pendingPageSize = void 0;
|
|
295
298
|
pendingMargins = void 0;
|
|
296
299
|
}
|
|
@@ -312,7 +315,8 @@ function createPaginator(options) {
|
|
|
312
315
|
states,
|
|
313
316
|
/** Column width in pixels (use getColumnWidth() for current value after updates). */
|
|
314
317
|
get columnWidth() {
|
|
315
|
-
|
|
318
|
+
const columnIndex = states.at(-1)?.columnIndex ?? 0;
|
|
319
|
+
return columnWidths[columnIndex] ?? columnWidths[0] ?? getContentWidth();
|
|
316
320
|
},
|
|
317
321
|
/** Get current column layout (returns copy to prevent external mutation). */
|
|
318
322
|
get columns() {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isFloatingTextBoxBlock } from "./types.js";
|
|
1
2
|
import { measureParagraph } from "./measure/measureParagraph.js";
|
|
2
3
|
import { buildTableCellFloatingZones, getTableCellContentWidth, getTableCellFloatingImages } from "./measure/tableCellFloating.js";
|
|
3
4
|
//#region src/layout-engine/tableRowBreak.ts
|
|
@@ -74,6 +75,8 @@ function cellBreakGeometry(cell, measure) {
|
|
|
74
75
|
y = blockTop + blockMeasure.totalHeight;
|
|
75
76
|
paragraphY += blockMeasure.totalHeight;
|
|
76
77
|
} else if (blockMeasure) {
|
|
78
|
+
const block = cellBlocks?.[i];
|
|
79
|
+
if (block?.kind === "textBox" && isFloatingTextBoxBlock(block)) continue;
|
|
77
80
|
const blockHeight = getAtomicBlockHeight(blockMeasure);
|
|
78
81
|
if (blockHeight > 0) {
|
|
79
82
|
const top = y;
|
|
@@ -846,7 +846,9 @@ type Page = {
|
|
|
846
846
|
type ColumnLayout = {
|
|
847
847
|
count: number;
|
|
848
848
|
gap: number;
|
|
849
|
-
equalWidth?: boolean; /**
|
|
849
|
+
equalWidth?: boolean; /** Authored widths for unequal-width section columns. */
|
|
850
|
+
widths?: number[]; /** Authored space after each column except the last. */
|
|
851
|
+
gaps?: number[]; /** Draw vertical separator line between columns (w:sep). */
|
|
850
852
|
separator?: boolean;
|
|
851
853
|
};
|
|
852
854
|
/**
|
|
@@ -904,7 +906,8 @@ type LayoutOptions = {
|
|
|
904
906
|
w: number;
|
|
905
907
|
h: number;
|
|
906
908
|
}; /** Body-level final section margins. */
|
|
907
|
-
finalMargins?: PageMargins; /**
|
|
909
|
+
finalMargins?: PageMargins; /** Body-level final section column configuration. */
|
|
910
|
+
finalColumns?: ColumnLayout; /** Column configuration. */
|
|
908
911
|
columns?: ColumnLayout; /** Gap between rendered pages (for UI). */
|
|
909
912
|
pageGap?: number; /** Default line height multiplier. */
|
|
910
913
|
defaultLineHeight?: number; /** Header content heights by variant. */
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { FRAGMENT_CLASS_NAMES, renderFragment } from "./renderFragment.js";
|
|
2
2
|
import { IMAGE_CLASS_NAMES, renderImageFragment } from "./renderImage.js";
|
|
3
3
|
import { renderLine, renderParagraphFragment, sliceRunsForLine } from "./renderParagraph.js";
|
|
4
|
-
import { TABLE_CLASS_NAMES, renderTableFragment } from "./renderTable.js";
|
|
5
4
|
import { TEXTBOX_CLASS_NAMES, renderTextBoxFragment } from "./renderTextBox.js";
|
|
5
|
+
import { TABLE_CLASS_NAMES, renderTableFragment } from "./renderTable.js";
|
|
6
6
|
import { renderPage, renderPages } from "./renderPage.js";
|
|
7
7
|
import { prefersReducedMotionBehavior } from "../paged-layout/scrollNavigation.js";
|
|
8
8
|
import { createFeatureRegistry } from "./registry/registry.js";
|
|
@@ -8,8 +8,8 @@ import { renderFragment } from "./renderFragment.js";
|
|
|
8
8
|
import { applyImageVisualAttrs, hasImageVisualAttrs, renderImageFragment } from "./renderImage.js";
|
|
9
9
|
import { emuToPixels } from "./renderUtils.js";
|
|
10
10
|
import { renderParagraphFragment } from "./renderParagraph.js";
|
|
11
|
-
import { renderTableFragment } from "./renderTable.js";
|
|
12
11
|
import { renderTextBoxFragment } from "./renderTextBox.js";
|
|
12
|
+
import { renderTableFragment } from "./renderTable.js";
|
|
13
13
|
import { renderWatermarkLayer } from "./renderWatermark.js";
|
|
14
14
|
import { panic } from "better-result";
|
|
15
15
|
//#region src/layout-painter/renderPage.ts
|
|
@@ -560,7 +560,12 @@ function renderHeaderFooterContent(content, context, options, layout) {
|
|
|
560
560
|
...block.pmStart !== void 0 ? { pmStart: block.pmStart } : {},
|
|
561
561
|
...block.pmEnd !== void 0 ? { pmEnd: block.pmEnd } : {}
|
|
562
562
|
}, block, measure, hfContext, { document: doc });
|
|
563
|
-
|
|
563
|
+
const textBoxTop = block.position ? resolveHeaderFooterFloatTop({
|
|
564
|
+
height: measure.height,
|
|
565
|
+
paragraphY: cursorY,
|
|
566
|
+
position: block.position
|
|
567
|
+
}, layout) : cursorY;
|
|
568
|
+
fragEl.style.top = `${textBoxTop}px`;
|
|
564
569
|
fragEl.style.left = resolveHeaderFooterFloatLeft(measure.width, block.position?.horizontal, layout);
|
|
565
570
|
if (block.wrapType === "behind") fragEl.style.zIndex = "-1";
|
|
566
571
|
containerEl.append(fragEl);
|