@stll/folio-core 0.5.0 → 0.6.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.
@@ -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 table";
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 };
@@ -201,7 +201,7 @@ function layoutDocument(blocks, measures, options) {
201
201
  break;
202
202
  case "table":
203
203
  if (block.floating) layoutFloatingTable(block, measure, paginator, paginator.getContentWidth());
204
- else layoutTable(block, measure, paginator);
204
+ else layoutTable(block, measure, paginator, options.footnoteHeightById);
205
205
  break;
206
206
  case "image":
207
207
  layoutImage(block, measure, paginator);
@@ -416,9 +416,10 @@ function getHeaderRowsHeight(measure, headerRowCount) {
416
416
  /**
417
417
  * Layout a table block onto pages.
418
418
  */
419
- function layoutTable(block, measure, paginator) {
419
+ function layoutTable(block, measure, paginator, footnoteHeightById) {
420
420
  const rows = measure.rows;
421
421
  if (rows.length === 0) return;
422
+ const rowFootnoteIds = block.rows.map((row) => collectTableRowFootnoteIds(row, footnoteHeightById));
422
423
  const headerRowCount = countHeaderRows(block);
423
424
  const headerRowsHeight = getHeaderRowsHeight(measure, headerRowCount);
424
425
  let currentRowIndex = 0;
@@ -507,13 +508,42 @@ function layoutTable(block, measure, paginator) {
507
508
  const normalHeaderOverhead = repeatHeaderRowsForNormalFragment ? headerRowsHeight : 0;
508
509
  let rowsHeight = 0;
509
510
  let fittingRows = 0;
511
+ const pageFootnoteIds = new Set(state.page.footnoteIds ?? []);
512
+ const fragmentFootnoteIds = [];
513
+ let fragmentFootnoteHeight = 0;
514
+ let retryOnNextFlowRegion = false;
510
515
  for (let j = currentRowIndex; j < rows.length; j++) {
511
516
  const rowHeight = rows[j].height;
512
- if (rowsHeight + rowHeight + normalHeaderOverhead <= availableHeight || fittingRows === 0) {
517
+ const currentRowFootnoteIds = rowFootnoteIds[j] ?? [];
518
+ const fragmentFootnoteCountBeforeRow = fragmentFootnoteIds.length;
519
+ let rowFootnoteHeight = 0;
520
+ for (const id of currentRowFootnoteIds) {
521
+ if (pageFootnoteIds.has(id) || fragmentFootnoteIds.includes(id)) continue;
522
+ fragmentFootnoteIds.push(id);
523
+ rowFootnoteHeight += footnoteHeightById?.get(id) ?? 0;
524
+ }
525
+ const separatorHeight = pageFootnoteIds.size === 0 && fragmentFootnoteHeight + rowFootnoteHeight > 0 ? 12 : 0;
526
+ if (rowsHeight + rowHeight + normalHeaderOverhead + fragmentFootnoteHeight + rowFootnoteHeight + separatorHeight <= availableHeight) {
513
527
  rowsHeight += rowHeight;
528
+ fragmentFootnoteHeight += rowFootnoteHeight;
514
529
  fittingRows++;
515
- } else break;
530
+ } else if (fittingRows === 0) {
531
+ if (state.cursorY === state.topMargin && state.page.fragments.length === 0) {
532
+ rowsHeight += rowHeight;
533
+ fragmentFootnoteHeight += rowFootnoteHeight;
534
+ fittingRows++;
535
+ break;
536
+ }
537
+ fragmentFootnoteIds.splice(fragmentFootnoteCountBeforeRow);
538
+ paginator.forceColumnBreak();
539
+ retryOnNextFlowRegion = true;
540
+ break;
541
+ } else {
542
+ fragmentFootnoteIds.splice(fragmentFootnoteCountBeforeRow);
543
+ break;
544
+ }
516
545
  }
546
+ if (retryOnNextFlowRegion) continue;
517
547
  const fragmentHeight = rowsHeight + normalHeaderOverhead;
518
548
  const isLastFragment = currentRowIndex + fittingRows >= rows.length;
519
549
  const desiredX = computeTableX(state.columnIndex);
@@ -533,6 +563,7 @@ function layoutTable(block, measure, paginator) {
533
563
  ...repeatHeaderRowsForNormalFragment ? { headerRowCount } : {},
534
564
  ...block.sdtGroups ? { sdtGroups: block.sdtGroups } : {}
535
565
  };
566
+ if (fragmentFootnoteHeight > 0) paginator.addFootnoteHeight(fragmentFootnoteHeight, fragmentFootnoteIds);
536
567
  fragment.y = paginator.addFragment(fragment, fragmentHeight, bandSkip, 0).y;
537
568
  fragment.x = desiredX;
538
569
  currentRowIndex += fittingRows;
@@ -549,6 +580,25 @@ function layoutTable(block, measure, paginator) {
549
580
  }
550
581
  }
551
582
  }
583
+ function collectTableRowFootnoteIds(row, footnoteHeightById) {
584
+ if (!row || !footnoteHeightById) return [];
585
+ const ids = [];
586
+ const walk = (blocks) => {
587
+ for (const block of blocks) {
588
+ if (block.kind === "paragraph") {
589
+ 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);
590
+ continue;
591
+ }
592
+ if (block.kind === "table") {
593
+ for (const nestedRow of block.rows) for (const cell of nestedRow.cells) walk(cell.blocks);
594
+ continue;
595
+ }
596
+ if (block.kind === "textBox") walk(block.content);
597
+ }
598
+ };
599
+ for (const cell of row.cells) walk(cell.blocks);
600
+ return ids;
601
+ }
552
602
  /**
553
603
  * Layout a floating table (anchored) without advancing the cursor.
554
604
  */
@@ -176,6 +176,7 @@ function measureTableBlock(tableBlock, contentWidth, fieldValues) {
176
176
  const padTop = sourceCell?.padding?.top ?? DEFAULT_CELL_PADDING_Y;
177
177
  const padBottom = sourceCell?.padding?.bottom ?? DEFAULT_CELL_PADDING_Y;
178
178
  cell.height += padTop + padBottom;
179
+ if ((sourceCell?.rowSpan ?? 1) > 1) continue;
179
180
  const borderHeight = getTableCellVerticalBorderHeight(sourceCell, rowIdx === 0);
180
181
  maxCellHeightWithBorders = Math.max(maxCellHeightWithBorders, cell.height + borderHeight);
181
182
  maxBorderHeight = Math.max(maxBorderHeight, borderHeight);
@@ -186,6 +187,27 @@ function measureTableBlock(tableBlock, contentWidth, fieldValues) {
186
187
  else if (explicitHeight) row.height = Math.max(maxCellHeightWithBorders, explicitHeight + maxBorderHeight);
187
188
  else row.height = maxCellHeightWithBorders;
188
189
  }
190
+ for (let rowIdx = 0; rowIdx < rows.length; rowIdx++) {
191
+ const sourceRow = tableBlock.rows[rowIdx];
192
+ const measuredRow = rows[rowIdx];
193
+ if (!sourceRow || !measuredRow) continue;
194
+ for (let cellIdx = 0; cellIdx < sourceRow.cells.length; cellIdx++) {
195
+ const sourceCell = sourceRow.cells[cellIdx];
196
+ const measuredCell = measuredRow.cells[cellIdx];
197
+ const rowSpan = sourceCell?.rowSpan ?? 1;
198
+ if (!sourceCell || !measuredCell || rowSpan <= 1) continue;
199
+ const spanEnd = Math.min(rows.length, rowIdx + rowSpan);
200
+ let combinedHeight = 0;
201
+ for (let spannedRowIdx = rowIdx; spannedRowIdx < spanEnd; spannedRowIdx++) combinedHeight += rows[spannedRowIdx]?.height ?? 0;
202
+ const deficit = measuredCell.height + getTableCellVerticalBorderHeight(sourceCell, rowIdx === 0) - combinedHeight;
203
+ if (deficit <= 0) continue;
204
+ for (let spannedRowIdx = spanEnd - 1; spannedRowIdx >= rowIdx; spannedRowIdx--) {
205
+ if (tableBlock.rows[spannedRowIdx]?.heightRule === "exact") continue;
206
+ rows[spannedRowIdx].height += deficit;
207
+ break;
208
+ }
209
+ }
210
+ }
189
211
  const totalHeight = rows.reduce((h, r) => h + r.height, 0);
190
212
  const totalWidth = columnWidths.reduce((w, cw) => w + cw, 0) || explicitWidthPx || contentWidth;
191
213
  return {
@@ -1,5 +1,5 @@
1
- import { addColumn, addRow, createTableContext, deleteColumn, deleteRow, getColumnCount, mergeCells, splitCell } from "../utils/tableOperations.js";
2
1
  import { Subscribable } from "./Subscribable.js";
2
+ import { addColumn, addRow, createTableContext, deleteColumn, deleteRow, getColumnCount, mergeCells, splitCell } from "../utils/tableOperations.js";
3
3
  //#region src/managers/TableSelectionManager.ts
4
4
  /** Data attributes for table elements in the rendered DOM */
5
5
  const TABLE_DATA_ATTRIBUTES = {
@@ -5,9 +5,9 @@ import { getTableContext, isInTable as isInTableCell } from "../extensions/nodes
5
5
  import { getListInfo, isInList } from "../extensions/features/ListExtension.js";
6
6
  import { CLIPBOARD_READ_ERROR_EVENT, buildPlainTextSlice, pasteWithoutFormatting } from "./pastePlainText.js";
7
7
  import { getHyperlinkAttrs, getSelectedText, isHyperlinkActive } from "../extensions/marks/HyperlinkExtension.js";
8
+ import { addColumnLeft, addColumnRight, addRowAbove, addRowBelow, applyTableStyle, autoFitContents, deleteColumn, deleteRow, deleteTable, distributeColumns, insertTable, mergeCells, removeTableBorders, selectColumn, selectRow, selectTable, setAllTableBorders, setCellBorder, setCellFillColor, setCellMargins, setCellTextDirection, setCellVerticalAlign, setInsideTableBorders, setOutsideTableBorders, setRowHeight, setTableBorderColor, setTableBorderPreset, setTableBorderWidth, setTableBorders, setTableProperties, splitCell, toggleHeaderRow, toggleNoWrap } from "./table.js";
8
9
  import { clearFontFamily, clearFontSize, clearHighlight, clearTextColor, insertHyperlink, removeHyperlink, setFontFamily, setFontSize, setHighlight, setHyperlink, setTextColor, setUnderlineStyle, toggleBold, toggleItalic, toggleStrike, toggleSubscript, toggleSuperscript, toggleUnderline } from "./formatting.js";
9
10
  import { addTabStop, alignCenter, alignJustify, alignLeft, alignRight, applyStyle, clearStyle, decreaseIndent, decreaseListLevel, doubleSpacing, generateTOC, increaseIndent, increaseListLevel, oneAndHalfSpacing, removeList, removeTabStop, setAlignment, setIndentFirstLine, setIndentLeft, setIndentRight, setLineSpacing, setLtr, setRtl, setSpaceAfter, setSpaceBefore, singleSpacing, toggleBidi, toggleBulletList, toggleNumberedList } from "./paragraph.js";
10
- import { addColumnLeft, addColumnRight, addRowAbove, addRowBelow, applyTableStyle, autoFitContents, deleteColumn, deleteRow, deleteTable, distributeColumns, insertTable, mergeCells, removeTableBorders, selectColumn, selectRow, selectTable, setAllTableBorders, setCellBorder, setCellFillColor, setCellMargins, setCellTextDirection, setCellVerticalAlign, setInsideTableBorders, setOutsideTableBorders, setRowHeight, setTableBorderColor, setTableBorderPreset, setTableBorderWidth, setTableBorders, setTableProperties, splitCell, toggleHeaderRow, toggleNoWrap } from "./table.js";
11
11
  import { PAINTABLE_MARK_NAMES, applyFormatMarks, captureFormatMarks } from "./formatPainter.js";
12
12
  import { insertPageBreak } from "./pageBreak.js";
13
13
  export { CLIPBOARD_READ_ERROR_EVENT, PAINTABLE_MARK_NAMES, acceptAIEditRevision, acceptAllChanges, acceptChange, addColumnLeft, addColumnRight, addCommentMark, addRowAbove, addRowBelow, addTabStop, alignCenter, alignJustify, alignLeft, alignRight, applyFormatMarks, applyStyle, applyTableStyle, autoFitContents, buildPlainTextSlice, captureFormatMarks, clearFontFamily, clearFontSize, clearFormatting, clearHighlight, clearStyle, clearTextColor, createRemoveMarkCommand, createSetMarkCommand, decreaseIndent, decreaseListLevel, deleteColumn, deleteRow, deleteTable, distributeColumns, doubleSpacing, findAIEditRevisionRange, findNextChange, findPreviousChange, generateTOC, getHyperlinkAttrs, getListInfo, getMarkAttr, getParagraphAlignment, getParagraphBidi, getSelectedText, getStyleId, getTableContext, increaseIndent, increaseListLevel, insertHyperlink, insertPageBreak, insertTable, isHyperlinkActive, isInList, isInTableCell as isInTable, isMarkActive, mergeCells, oneAndHalfSpacing, pasteWithoutFormatting, rejectAIEditRevision, rejectAllChanges, rejectChange, removeCommentMark, removeHyperlink, removeList, removeTabStop, removeTableBorders, selectColumn, selectRow, selectTable, setAlignment, setAllTableBorders, setCellBorder, setCellFillColor, setCellMargins, setCellTextDirection, setCellVerticalAlign, setFontFamily, setFontSize, setHighlight, setHyperlink, setIndentFirstLine, setIndentLeft, setIndentRight, setInsideTableBorders, setLineSpacing, setLtr, setOutsideTableBorders, setRowHeight, setRtl, setSpaceAfter, setSpaceBefore, setTableBorderColor, setTableBorderPreset, setTableBorderWidth, setTableBorders, setTableProperties, setTextColor, setUnderlineStyle, singleSpacing, splitCell, toggleBidi, toggleBold, toggleBulletList, toggleHeaderRow, toggleItalic, toggleNoWrap, toggleNumberedList, toggleStrike, toggleSubscript, toggleSuperscript, toggleUnderline };
@@ -11,10 +11,10 @@ import { createSelectionTrackerPlugin, extractSelectionContext, getSelectionCont
11
11
  import { getHyperlinkAttrs, getSelectedText, isHyperlinkActive } from "./extensions/marks/HyperlinkExtension.js";
12
12
  import { schema, singletonManager } from "./schema/index.js";
13
13
  import { createEmptyDoc, toProseDoc } from "./conversion/toProseDoc.js";
14
+ import { addColumnLeft, addColumnRight, addRowAbove, addRowBelow, applyTableStyle, autoFitContents, deleteColumn, deleteRow, deleteTable, distributeColumns, insertTable, mergeCells, removeTableBorders, selectColumn, selectRow, selectTable, setAllTableBorders, setCellBorder, setCellFillColor, setCellMargins, setCellTextDirection, setCellVerticalAlign, setInsideTableBorders, setOutsideTableBorders, setRowHeight, setTableBorderColor, setTableBorderPreset, setTableBorderWidth, setTableBorders, setTableProperties, splitCell, toggleHeaderRow, toggleNoWrap } from "./commands/table.js";
14
15
  import { extractSelectionState } from "./selectionState.js";
15
16
  import { clearFontFamily, clearFontSize, clearHighlight, clearTextColor, insertHyperlink, removeHyperlink, setFontFamily, setFontSize, setHighlight, setHyperlink, setTextColor, toggleBold, toggleItalic, toggleStrike, toggleSubscript, toggleSuperscript, toggleUnderline } from "./commands/formatting.js";
16
17
  import { addTabStop, alignCenter, alignJustify, alignLeft, alignRight, applyStyle, clearStyle, decreaseIndent, decreaseListLevel, generateTOC, increaseIndent, increaseListLevel, removeList, removeTabStop, setAlignment, setIndentFirstLine, setIndentLeft, setIndentRight, setLineSpacing, setLtr, setRtl, toggleBidi, toggleBulletList, toggleNumberedList } from "./commands/paragraph.js";
17
- import { addColumnLeft, addColumnRight, addRowAbove, addRowBelow, applyTableStyle, autoFitContents, deleteColumn, deleteRow, deleteTable, distributeColumns, insertTable, mergeCells, removeTableBorders, selectColumn, selectRow, selectTable, setAllTableBorders, setCellBorder, setCellFillColor, setCellMargins, setCellTextDirection, setCellVerticalAlign, setInsideTableBorders, setOutsideTableBorders, setRowHeight, setTableBorderColor, setTableBorderPreset, setTableBorderWidth, setTableBorders, setTableProperties, splitCell, toggleHeaderRow, toggleNoWrap } from "./commands/table.js";
18
18
  import { PAINTABLE_MARK_NAMES, applyFormatMarks, captureFormatMarks } from "./commands/formatPainter.js";
19
19
  import { insertPageBreak } from "./commands/pageBreak.js";
20
20
  import { insertImageFromFile } from "./commands/image.js";
@@ -1,5 +1,5 @@
1
- import { generateTOC } from "./commands/paragraph.js";
2
1
  import { insertTable } from "./commands/table.js";
2
+ import { generateTOC } from "./commands/paragraph.js";
3
3
  import { insertPageBreak } from "./commands/pageBreak.js";
4
4
  import { insertImageFromFile } from "./commands/image.js";
5
5
  //#region src/prosemirror/insertOperations.ts
package/dist/server.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { FolioAIBlock, FolioAIBlockAnchor, FolioAIBlockKind, FolioAIBlockPreviewRun, FolioAIComment, FolioAIEditApplyMode, FolioAIEditApplyResult, FolioAIEditOperation, FolioAIEditPrecondition, FolioAIEditSnapshot, FolioAIInlineFormatting, FolioAITextRangeHandle } from "./ai-edits/types.js";
2
- 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, FolioDocumentOperation, FolioDocumentOperationAffectedTarget, FolioDocumentOperationBatch, FolioDocumentOperationCapabilities, FolioDocumentOperationIssue, FolioDocumentOperationMode, FolioDocumentOperationPrecondition, FolioDocumentOperationReceipt, FolioDocumentOperationRecovery, FolioDocumentOperationResult, FolioDocumentOperationStatus, FolioDocumentOperationType, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch } from "./document-operations.js";
2
+ 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, FolioDocumentOperation, FolioDocumentOperationAffectedTarget, FolioDocumentOperationBatch, FolioDocumentOperationCapabilities, FolioDocumentOperationIssue, FolioDocumentOperationMode, FolioDocumentOperationPrecondition, FolioDocumentOperationReceipt, FolioDocumentOperationRecovery, FolioDocumentOperationResult, FolioDocumentOperationStatus, FolioDocumentOperationType, FolioDocumentOperationUndoFailureReason, FolioDocumentOperationUndoHandle, FolioDocumentOperationUndoResult, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch } from "./document-operations.js";
3
3
  import { FolioReviewChange, FolioReviewChangeKind } from "./ai-edits/read.js";
4
4
  import { ApplyFolioAIEditsToBufferOptions, ApplyFolioAIEditsToBufferResult, FolioApplyDocumentOperationsOptions, FolioApplyOperationsOptions, FolioDocumentStory, FolioDocumentStoryHandle, FolioDocxReviewer, FolioDocxReviewerOptions, FolioReviewChangeFilter, FolioReviewComment, FolioReviewCommentFilter, FolioReviewCommentReply, FolioReviewReplyInput, applyFolioAIEditsToBuffer } from "./ai-edits/headless.js";
5
5
  import { createFolioAITextRangeHandle } from "./ai-edits/snapshot.js";
@@ -9,4 +9,4 @@ import { createDocx } from "./docx/rezip.js";
9
9
  import { CreateCommentReplyInput, replyToComment } from "./docx/replyToComment.js";
10
10
  import { GenerateRedlineDocxOptions, GenerateRedlineDocxResult, generateRedlineDocx } from "./redline.js";
11
11
  import { FolioBlockDiff, FolioFormatProperty, FolioVersionDiff, FolioVersionDiffSegment, compareDocxVersions } from "./version-comparison.js";
12
- export { type ApplyFolioAIEditsToBufferOptions, type ApplyFolioAIEditsToBufferResult, type CreateCommentReplyInput, type CreateEmptyDocumentOptions, type DeriveBlockIdInput, 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 FolioAIEditApplyMode, type FolioAIEditApplyResult, type FolioAIEditOperation, type FolioAIEditPrecondition, type FolioAIEditSnapshot, type FolioAIInlineFormatting, type FolioAITextRangeHandle, type FolioApplyDocumentOperationsOptions, type FolioApplyOperationsOptions, type FolioBlockDiff, 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 FolioDocumentStory, type FolioDocumentStoryHandle, FolioDocxReviewer, type FolioDocxReviewerOptions, type FolioFormatProperty, type FolioReviewChange, type FolioReviewChangeFilter, type FolioReviewChangeKind, type FolioReviewComment, type FolioReviewCommentFilter, type FolioReviewCommentReply, type FolioReviewReplyInput, type FolioVersionDiff, type FolioVersionDiffSegment, type GenerateRedlineDocxOptions, type GenerateRedlineDocxResult, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioAIEditsToBuffer, assertSupportedFolioDocumentOperationVersion, compareDocxVersions, createDocx, createEmptyDocument, createFolioAITextRangeHandle, deriveBlockId, generateRedlineDocx, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioParaIdFromBlockId, isFolioBlockId, isFolioDocumentOperationModeSupported, isSequentialFolioBlockId, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch, replyToComment };
12
+ export { type ApplyFolioAIEditsToBufferOptions, type ApplyFolioAIEditsToBufferResult, type CreateCommentReplyInput, type CreateEmptyDocumentOptions, type DeriveBlockIdInput, 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 FolioAIEditApplyMode, type FolioAIEditApplyResult, type FolioAIEditOperation, type FolioAIEditPrecondition, type FolioAIEditSnapshot, type FolioAIInlineFormatting, type FolioAITextRangeHandle, type FolioApplyDocumentOperationsOptions, type FolioApplyOperationsOptions, type FolioBlockDiff, 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 FolioDocumentStory, type FolioDocumentStoryHandle, FolioDocxReviewer, type FolioDocxReviewerOptions, type FolioFormatProperty, type FolioReviewChange, type FolioReviewChangeFilter, type FolioReviewChangeKind, type FolioReviewComment, type FolioReviewCommentFilter, type FolioReviewCommentReply, type FolioReviewReplyInput, type FolioVersionDiff, type FolioVersionDiffSegment, type GenerateRedlineDocxOptions, type GenerateRedlineDocxResult, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioAIEditsToBuffer, assertSupportedFolioDocumentOperationVersion, compareDocxVersions, createDocx, createEmptyDocument, createFolioAITextRangeHandle, deriveBlockId, generateRedlineDocx, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioParaIdFromBlockId, isFolioBlockId, isFolioDocumentOperationModeSupported, isSequentialFolioBlockId, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch, replyToComment };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stll/folio-core",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Headless, framework-neutral core of folio: the OOXML (.docx) parser, document model, ProseMirror integration, and page-layout engine. No React.",
5
5
  "keywords": [
6
6
  "document-model",