@stll/folio-core 0.47.7 → 0.48.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/dist/controller/fontReadiness.js +3 -3
  2. package/dist/controller/hyphenationReadiness.d.ts +19 -0
  3. package/dist/controller/hyphenationReadiness.js +47 -0
  4. package/dist/controller/layoutPipeline.d.ts +3 -0
  5. package/dist/controller/layoutPipeline.js +59 -17
  6. package/dist/display-list/build/buildDisplayList.js +39 -12
  7. package/dist/display-list/build/pageFurniture.d.ts +7 -1
  8. package/dist/display-list/build/pageFurniture.js +21 -8
  9. package/dist/display-list/build/paragraphPrimitives.js +5 -4
  10. package/dist/display-list/build/tablePrimitives.js +10 -6
  11. package/dist/docx/attributeRemainder.js +10 -2
  12. package/dist/docx/blockContentParser.d.ts +2 -0
  13. package/dist/docx/blockContentParser.js +77 -62
  14. package/dist/docx/commentParser.d.ts +2 -1
  15. package/dist/docx/commentParser.js +57 -45
  16. package/dist/docx/containerChildren.d.ts +21 -8
  17. package/dist/docx/containerChildren.js +39 -9
  18. package/dist/docx/documentParser.d.ts +5 -1
  19. package/dist/docx/documentParser.js +8 -5
  20. package/dist/docx/documentSectionFacts.d.ts +22 -0
  21. package/dist/docx/documentSectionFacts.js +43 -0
  22. package/dist/docx/fieldParser.d.ts +8 -1
  23. package/dist/docx/fieldParser.js +47 -3
  24. package/dist/docx/fontTableParser.js +34 -27
  25. package/dist/docx/footnoteParser.d.ts +3 -2
  26. package/dist/docx/footnoteParser.js +15 -12
  27. package/dist/docx/groupDrawingParser.d.ts +2 -1
  28. package/dist/docx/groupDrawingParser.js +3 -6
  29. package/dist/docx/headerFooterParser.d.ts +7 -2
  30. package/dist/docx/headerFooterParser.js +15 -5
  31. package/dist/docx/hyperlinkParser.d.ts +48 -36
  32. package/dist/docx/hyperlinkParser.js +97 -82
  33. package/dist/docx/numberingParser.js +108 -84
  34. package/dist/docx/paragraphParser.d.ts +5 -1
  35. package/dist/docx/paragraphParser.js +381 -362
  36. package/dist/docx/paragraphProperties.js +123 -109
  37. package/dist/docx/paragraphPropertySource.d.ts +6 -1
  38. package/dist/docx/paragraphPropertySource.js +9 -1
  39. package/dist/docx/paragraphTextBoxEnrichment.d.ts +2 -1
  40. package/dist/docx/paragraphTextBoxEnrichment.js +17 -6
  41. package/dist/docx/parser.d.ts +7 -1
  42. package/dist/docx/parser.js +33 -16
  43. package/dist/docx/previewBudget.d.ts +55 -33
  44. package/dist/docx/previewBudget.js +59 -65
  45. package/dist/docx/rezip.js +41 -58
  46. package/dist/docx/runParser.d.ts +4 -1
  47. package/dist/docx/runParser.js +172 -184
  48. package/dist/docx/sdtProperties.js +87 -84
  49. package/dist/docx/sectionParser.js +169 -160
  50. package/dist/docx/serializer/paragraphSerializer.js +42 -38
  51. package/dist/docx/serializer/settingsSerializer.js +19 -1
  52. package/dist/docx/settingsParser.js +8 -0
  53. package/dist/docx/streamingXmlParser.d.ts +6 -2
  54. package/dist/docx/streamingXmlParser.js +12 -7
  55. package/dist/docx/styleParser.js +34 -8
  56. package/dist/docx/tableParser.d.ts +21 -12
  57. package/dist/docx/tableParser.js +518 -441
  58. package/dist/docx/textBoxParser.d.ts +8 -3
  59. package/dist/docx/textBoxParser.js +3 -3
  60. package/dist/docx/verbatimCapture.d.ts +10 -8
  61. package/dist/docx/verbatimCapture.js +45 -2
  62. package/dist/docx/vmlImageParser.d.ts +15 -13
  63. package/dist/docx/vmlImageParser.js +75 -60
  64. package/dist/docx/vmlPreview.d.ts +3 -3
  65. package/dist/docx/vmlPreview.js +3 -4
  66. package/dist/docx/xmlNamespaceContext.d.ts +9 -0
  67. package/dist/docx/xmlNamespaceContext.js +54 -0
  68. package/dist/docx/xmlParser.d.ts +6 -3
  69. package/dist/docx/xmlParser.js +11 -41
  70. package/dist/docx/xmlResourceLimits.d.ts +2 -1
  71. package/dist/docx/xmlResourceLimits.js +4 -1
  72. package/dist/fonts/headlessMeasure.js +0 -0
  73. package/dist/headless-layout.d.ts +11 -2
  74. package/dist/headless-layout.js +153 -107
  75. package/dist/internal/paragraphFormattingSerialization.js +3 -3
  76. package/dist/layout-bridge/convert/endnoteLayout.d.ts +65 -0
  77. package/dist/layout-bridge/convert/endnoteLayout.js +227 -0
  78. package/dist/layout-bridge/convert/footnoteLayout.d.ts +19 -3
  79. package/dist/layout-bridge/convert/footnoteLayout.js +40 -31
  80. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -7
  81. package/dist/layout-bridge/convert/headerFooterLayout.js +5 -20
  82. package/dist/layout-bridge/convert/paragraphMarkFormatting.d.ts +10 -0
  83. package/dist/layout-bridge/convert/paragraphMarkFormatting.js +59 -0
  84. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +29 -1
  85. package/dist/layout-bridge/convert/toFlowBlocks.js +258 -35
  86. package/dist/layout-bridge/engine/hitTest.js +5 -3
  87. package/dist/layout-bridge/engine/selectionRects.js +5 -3
  88. package/dist/layout-engine/anchorLayoutInCellCompatibility.d.ts +10 -0
  89. package/dist/layout-engine/anchorLayoutInCellCompatibility.js +22 -0
  90. package/dist/layout-engine/index.d.ts +2 -2
  91. package/dist/layout-engine/index.js +70 -11
  92. package/dist/layout-engine/justificationCompatibility.d.ts +1 -1
  93. package/dist/layout-engine/justificationCompatibility.js +9 -5
  94. package/dist/layout-engine/keep-together.d.ts +11 -5
  95. package/dist/layout-engine/keep-together.js +39 -16
  96. package/dist/layout-engine/layoutInstrumentation.d.ts +8 -2
  97. package/dist/layout-engine/layoutInstrumentation.js +8 -1
  98. package/dist/layout-engine/measure/advanceComposition.js +4 -7
  99. package/dist/layout-engine/measure/hyphenationDictionaries.d.ts +74 -0
  100. package/dist/layout-engine/measure/hyphenationDictionaries.js +138 -0
  101. package/dist/layout-engine/measure/hyphenationPreload.d.ts +11 -0
  102. package/dist/layout-engine/measure/hyphenationPreload.js +24 -0
  103. package/dist/layout-engine/measure/lineBreakProvider.d.ts +12 -2
  104. package/dist/layout-engine/measure/lineBreakProvider.js +30 -30
  105. package/dist/layout-engine/measure/lineBreaks.d.ts +6 -1
  106. package/dist/layout-engine/measure/lineBreaks.js +10 -3
  107. package/dist/layout-engine/measure/listMarkerWidth.d.ts +9 -6
  108. package/dist/layout-engine/measure/listMarkerWidth.js +20 -22
  109. package/dist/layout-engine/measure/measureBlocks.js +42 -8
  110. package/dist/layout-engine/measure/measureContainer.js +5 -5
  111. package/dist/layout-engine/measure/measureHelpers.d.ts +15 -3
  112. package/dist/layout-engine/measure/measureHelpers.js +21 -5
  113. package/dist/layout-engine/measure/measureParagraph.js +109 -30
  114. package/dist/layout-engine/measure/measureTypes.d.ts +5 -0
  115. package/dist/layout-engine/measure/tabCalculator.d.ts +2 -0
  116. package/dist/layout-engine/measure/tabCalculator.js +2 -1
  117. package/dist/layout-engine/measure/tableCellFloating.d.ts +2 -0
  118. package/dist/layout-engine/measure/tableCellFloating.js +51 -19
  119. package/dist/layout-engine/measure/tableCellGrid.d.ts +28 -3
  120. package/dist/layout-engine/measure/tableCellGrid.js +45 -5
  121. package/dist/layout-engine/measure/tableFragmentBorderGeometry.js +2 -1
  122. package/dist/layout-engine/noteAreaFlow.d.ts +19 -0
  123. package/dist/layout-engine/noteAreaFlow.js +83 -0
  124. package/dist/layout-engine/paginator.d.ts +10 -1
  125. package/dist/layout-engine/paginator.js +13 -1
  126. package/dist/layout-engine/tableRowBreak.js +3 -1
  127. package/dist/layout-engine/types.d.ts +89 -3
  128. package/dist/layout-engine/types.js +96 -1
  129. package/dist/layout-painter/index.d.ts +3 -0
  130. package/dist/layout-painter/renderPage.js +32 -83
  131. package/dist/layout-painter/renderParagraph.d.ts +6 -1
  132. package/dist/layout-painter/renderParagraph.js +34 -22
  133. package/dist/layout-painter/renderTable.js +26 -13
  134. package/dist/prosemirror/attrs/index.d.ts +9 -9
  135. package/dist/prosemirror/attrs/index.js +43 -11
  136. package/dist/prosemirror/conversion/fromProseDoc.js +8 -1
  137. package/dist/prosemirror/conversion/markInterner.d.ts +21 -0
  138. package/dist/prosemirror/conversion/markInterner.js +90 -0
  139. package/dist/prosemirror/conversion/toProseDoc.js +77 -41
  140. package/dist/prosemirror/extensions/core/DocExtension.js +2 -1
  141. package/dist/prosemirror/extensions/core/ParagraphExtension.js +1 -0
  142. package/dist/prosemirror/extensions/marks/markUtils.d.ts +6 -2
  143. package/dist/prosemirror/extensions/marks/markUtils.js +39 -51
  144. package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +2 -1
  145. package/dist/prosemirror/listMarker.d.ts +1 -0
  146. package/dist/prosemirror/listMarker.js +2 -0
  147. package/dist/prosemirror/listRenderingAttrs.d.ts +1 -0
  148. package/dist/prosemirror/listRenderingAttrs.js +3 -0
  149. package/dist/prosemirror/schema/nodes.d.ts +13 -1
  150. package/dist/prosemirror/textBoxHostParagraph.d.ts +13 -0
  151. package/dist/prosemirror/textBoxHostParagraph.js +21 -0
  152. package/dist/prosemirror/validation.js +91 -80
  153. package/dist/utils/createDocument.js +10 -1
  154. package/dist/utils/scriptSegments.d.ts +33 -4
  155. package/dist/utils/scriptSegments.js +39 -6
  156. package/dist/utils/textFormattingMerge.d.ts +17 -3
  157. package/dist/utils/textFormattingMerge.js +18 -12
  158. package/dist/utils/trailingText.d.ts +22 -0
  159. package/dist/utils/trailingText.js +32 -0
  160. package/package.json +2 -2
@@ -1,10 +1,11 @@
1
1
  import { NO_MODELLED_ATTRIBUTES, attributeRemainder } from "./attributeRemainder.js";
2
2
  import { parseBookmarkEnd, parseBookmarkStart } from "./bookmarkParser.js";
3
3
  import { parseBorderSpec } from "./borderParser.js";
4
- import { CAPTURE, dispatchChildren, keptUnless, ownedElsewhere, sequencePositions, withPreservedChildren } from "./containerChildren.js";
4
+ import { CAPTURE, dispatchChildrenWithContext, keptUnless, ownedElsewhere, sequencePositions, withPreservedChildren } from "./containerChildren.js";
5
5
  import { parseParagraph } from "./paragraphParser.js";
6
6
  import { enrichParagraphTextBoxes } from "./paragraphTextBoxEnrichment.js";
7
7
  import { FloatingTableXSpecSchema, FloatingTableYSpecSchema, TableAlignmentSchema, TextDirectionSchema, narrowEnum } from "./parserEnums.js";
8
+ import { standalonePreviewLedger } from "./previewBudget.js";
8
9
  import { captureSdtSiblingMarkers, parseSdtProperties } from "./sdtProperties.js";
9
10
  import { parseShading } from "./shadingParser.js";
10
11
  import { findChildAnySpelling } from "./strictNames.js";
@@ -216,38 +217,38 @@ const withSourceXml = (formatting, element) => ({
216
217
  * handler maps over the same names would be two answers to the same question,
217
218
  * and the one folio would notice is the day they stop agreeing.
218
219
  */
219
- const sharedTablePropertyHandlers = (formatting) => ({
220
- tblW: (child) => {
220
+ const SHARED_TABLE_PROPERTY_HANDLERS = {
221
+ tblW: (child, formatting) => {
221
222
  const width = parseWidth(child);
222
223
  if (width) formatting.width = width;
223
224
  return keptUnless(width !== void 0);
224
225
  },
225
- jc: (child) => {
226
+ jc: (child, formatting) => {
226
227
  const justification = narrowEnum(getAttribute(child, "w", "val"), TableAlignmentSchema);
227
228
  if (justification !== void 0) formatting.justification = justification;
228
229
  return keptUnless(justification !== void 0);
229
230
  },
230
- tblCellSpacing: (child) => {
231
+ tblCellSpacing: (child, formatting) => {
231
232
  const cellSpacing = parseWidth(child);
232
233
  if (cellSpacing) formatting.cellSpacing = cellSpacing;
233
234
  return keptUnless(cellSpacing !== void 0);
234
235
  },
235
- tblInd: (child) => {
236
+ tblInd: (child, formatting) => {
236
237
  const indent = parseWidth(child);
237
238
  if (indent) formatting.indent = indent;
238
239
  return keptUnless(indent !== void 0);
239
240
  },
240
- tblBorders: (child) => {
241
+ tblBorders: (child, formatting) => {
241
242
  const borders = parseTableBorders(child);
242
243
  if (borders) formatting.borders = borders;
243
244
  return keptUnless(borders !== void 0);
244
245
  },
245
- shd: (child) => {
246
+ shd: (child, formatting) => {
246
247
  const shading = parseShading(child);
247
248
  if (shading) formatting.shading = shading;
248
249
  return keptUnless(shading !== void 0);
249
250
  },
250
- tblLayout: (child) => {
251
+ tblLayout: (child, formatting) => {
251
252
  const layout = getAttribute(child, "w", "type");
252
253
  if (layout === "fixed" || layout === "autofit") {
253
254
  formatting.layout = layout;
@@ -255,17 +256,17 @@ const sharedTablePropertyHandlers = (formatting) => ({
255
256
  }
256
257
  return CAPTURE;
257
258
  },
258
- tblCellMar: (child) => {
259
+ tblCellMar: (child, formatting) => {
259
260
  const cellMargins = parseCellMargins(child);
260
261
  if (cellMargins) formatting.cellMargins = cellMargins;
261
262
  return keptUnless(cellMargins !== void 0);
262
263
  },
263
- tblLook: (child) => {
264
+ tblLook: (child, formatting) => {
264
265
  const look = parseTableLook(child);
265
266
  if (look) formatting.look = look;
266
267
  return keptUnless(look !== void 0);
267
268
  }
268
- });
269
+ };
269
270
  /**
270
271
  * The children the table walks skip, and the reader that takes each instead.
271
272
  *
@@ -358,58 +359,60 @@ const TABLE_CHILD_OWNERS = {
358
359
  reader: "tableParser#parseTableGrid"
359
360
  })
360
361
  };
362
+ const TABLE_PROPERTY_HANDLERS = {
363
+ ...SHARED_TABLE_PROPERTY_HANDLERS,
364
+ tblStyle: (child, formatting) => {
365
+ const styleId = getAttribute(child, "w", "val");
366
+ if (styleId) formatting.styleId = styleId;
367
+ return keptUnless(Boolean(styleId));
368
+ },
369
+ tblpPr: (child, formatting) => {
370
+ const floating = parseFloatingTableProperties(child);
371
+ if (floating) formatting.floating = floating;
372
+ return keptUnless(floating !== void 0);
373
+ },
374
+ tblOverlap: (child, formatting) => {
375
+ const overlap = getAttribute(child, "w", "val");
376
+ if (overlap === "never" || overlap === "overlap") {
377
+ formatting.overlap = overlap;
378
+ return;
379
+ }
380
+ return CAPTURE;
381
+ },
382
+ bidiVisual: (child, formatting) => {
383
+ formatting.bidi = parseBooleanElement(child);
384
+ },
385
+ tblStyleRowBandSize: (child, formatting) => {
386
+ const size = parseNumericAttribute(child, "w", "val");
387
+ if (size !== void 0) formatting.rowBandSize = size;
388
+ return keptUnless(size !== void 0);
389
+ },
390
+ tblStyleColBandSize: (child, formatting) => {
391
+ const size = parseNumericAttribute(child, "w", "val");
392
+ if (size !== void 0) formatting.columnBandSize = size;
393
+ return keptUnless(size !== void 0);
394
+ },
395
+ tblCaption: (child, formatting) => {
396
+ const caption = getAttribute(child, "w", "val");
397
+ if (caption !== null) formatting.caption = caption;
398
+ return keptUnless(caption !== null);
399
+ },
400
+ tblDescription: (child, formatting) => {
401
+ const description = getAttribute(child, "w", "val");
402
+ if (description !== null) formatting.description = description;
403
+ return keptUnless(description !== null);
404
+ },
405
+ tblPrChange: TABLE_PROPERTY_CHANGE_OWNER
406
+ };
361
407
  function parseTableProperties(tblPrElement) {
362
408
  if (!tblPrElement) return;
363
409
  const formatting = {};
364
- const preserved = dispatchChildren({
410
+ const preserved = dispatchChildrenWithContext({
365
411
  element: tblPrElement,
366
412
  container: "table-properties",
367
- handlers: {
368
- ...sharedTablePropertyHandlers(formatting),
369
- tblStyle: (child) => {
370
- const styleId = getAttribute(child, "w", "val");
371
- if (styleId) formatting.styleId = styleId;
372
- return keptUnless(Boolean(styleId));
373
- },
374
- tblpPr: (child) => {
375
- const floating = parseFloatingTableProperties(child);
376
- if (floating) formatting.floating = floating;
377
- return keptUnless(floating !== void 0);
378
- },
379
- tblOverlap: (child) => {
380
- const overlap = getAttribute(child, "w", "val");
381
- if (overlap === "never" || overlap === "overlap") {
382
- formatting.overlap = overlap;
383
- return;
384
- }
385
- return CAPTURE;
386
- },
387
- bidiVisual: (child) => {
388
- formatting.bidi = parseBooleanElement(child);
389
- },
390
- tblStyleRowBandSize: (child) => {
391
- const size = parseNumericAttribute(child, "w", "val");
392
- if (size !== void 0) formatting.rowBandSize = size;
393
- return keptUnless(size !== void 0);
394
- },
395
- tblStyleColBandSize: (child) => {
396
- const size = parseNumericAttribute(child, "w", "val");
397
- if (size !== void 0) formatting.columnBandSize = size;
398
- return keptUnless(size !== void 0);
399
- },
400
- tblCaption: (child) => {
401
- const caption = getAttribute(child, "w", "val");
402
- if (caption !== null) formatting.caption = caption;
403
- return keptUnless(caption !== null);
404
- },
405
- tblDescription: (child) => {
406
- const description = getAttribute(child, "w", "val");
407
- if (description !== null) formatting.description = description;
408
- return keptUnless(description !== null);
409
- },
410
- tblPrChange: TABLE_PROPERTY_CHANGE_OWNER
411
- },
412
- capturePosition: sequencePositions("table-properties", tblPrElement)
413
+ handlers: TABLE_PROPERTY_HANDLERS,
414
+ capturePosition: sequencePositions("table-properties", tblPrElement),
415
+ context: formatting
413
416
  });
414
417
  if (preserved) formatting.preserved = preserved;
415
418
  if (Object.keys(formatting).length === 0) return;
@@ -440,6 +443,10 @@ function parseTablePropertyChanges(tblPrElement, currentFormatting) {
440
443
  });
441
444
  return changes.length > 0 ? changes : void 0;
442
445
  }
446
+ const TABLE_PROPERTY_EXCEPTION_HANDLERS = {
447
+ ...SHARED_TABLE_PROPERTY_HANDLERS,
448
+ tblPrExChange: TABLE_PROPERTY_EXCEPTION_CHANGE_OWNER
449
+ };
443
450
  /**
444
451
  * Parse a row's table property exceptions (`w:tblPrEx`).
445
452
  *
@@ -451,14 +458,12 @@ function parseTablePropertyChanges(tblPrElement, currentFormatting) {
451
458
  function parseTablePropertyExceptions(tblPrExElement) {
452
459
  if (!tblPrExElement) return;
453
460
  const formatting = {};
454
- const preserved = dispatchChildren({
461
+ const preserved = dispatchChildrenWithContext({
455
462
  element: tblPrExElement,
456
463
  container: "table-property-exceptions",
457
- handlers: {
458
- ...sharedTablePropertyHandlers(formatting),
459
- tblPrExChange: TABLE_PROPERTY_EXCEPTION_CHANGE_OWNER
460
- },
461
- capturePosition: sequencePositions("table-property-exceptions", tblPrExElement)
464
+ handlers: TABLE_PROPERTY_EXCEPTION_HANDLERS,
465
+ capturePosition: sequencePositions("table-property-exceptions", tblPrExElement),
466
+ context: formatting
462
467
  });
463
468
  if (preserved) formatting.preserved = preserved;
464
469
  return withSourceXml(formatting, tblPrExElement);
@@ -551,6 +556,62 @@ function parseTableCellVerticalMergeRevisionValue(value) {
551
556
  if (value === "cont") return "continue";
552
557
  if (value === "rest") return "rest";
553
558
  }
559
+ const ROW_PROPERTY_HANDLERS = {
560
+ cnfStyle: (child, formatting) => {
561
+ const conditionalFormat = parseConditionalFormatStyle(child);
562
+ if (conditionalFormat) formatting.conditionalFormat = conditionalFormat;
563
+ return keptUnless(conditionalFormat !== void 0);
564
+ },
565
+ divId: CAPTURE,
566
+ gridBefore: (child, formatting) => {
567
+ const gridBefore = parseNumericAttribute(child, "w", "val");
568
+ if (gridBefore !== void 0 && gridBefore > 0) formatting.gridBefore = gridBefore;
569
+ return keptUnless(gridBefore !== void 0 && gridBefore > 0);
570
+ },
571
+ gridAfter: (child, formatting) => {
572
+ const gridAfter = parseNumericAttribute(child, "w", "val");
573
+ if (gridAfter !== void 0 && gridAfter > 0) formatting.gridAfter = gridAfter;
574
+ return keptUnless(gridAfter !== void 0 && gridAfter > 0);
575
+ },
576
+ wBefore: (child, formatting) => {
577
+ const widthBefore = parseTableMeasurement(child);
578
+ if (widthBefore) formatting.widthBefore = widthBefore;
579
+ return keptUnless(widthBefore !== void 0);
580
+ },
581
+ wAfter: (child, formatting) => {
582
+ const widthAfter = parseTableMeasurement(child);
583
+ if (widthAfter) formatting.widthAfter = widthAfter;
584
+ return keptUnless(widthAfter !== void 0);
585
+ },
586
+ cantSplit: (child, formatting) => {
587
+ formatting.cantSplit = parseBooleanElement(child);
588
+ },
589
+ trHeight: (child, formatting) => {
590
+ const heightVal = parseNumericAttribute(child, "w", "val");
591
+ if (heightVal === void 0 || heightVal <= 0) return CAPTURE;
592
+ formatting.height = {
593
+ value: heightVal,
594
+ type: "dxa"
595
+ };
596
+ const hRule = getAttribute(child, "w", "hRule");
597
+ if (hRule === "auto" || hRule === "atLeast" || hRule === "exact") formatting.heightRule = hRule;
598
+ },
599
+ tblHeader: (child, formatting) => {
600
+ formatting.header = parseBooleanElement(child);
601
+ },
602
+ tblCellSpacing: CAPTURE,
603
+ jc: (child, formatting) => {
604
+ const justification = narrowEnum(getAttribute(child, "w", "val"), TableAlignmentSchema);
605
+ if (justification !== void 0) formatting.justification = justification;
606
+ return keptUnless(justification !== void 0);
607
+ },
608
+ hidden: (child, formatting) => {
609
+ formatting.hidden = parseBooleanElement(child);
610
+ },
611
+ ins: ROW_INSERTION_OWNER,
612
+ del: ROW_DELETION_OWNER,
613
+ trPrChange: ROW_PROPERTY_CHANGE_OWNER
614
+ };
554
615
  /**
555
616
  * Parse table row properties (w:trPr)
556
617
  *
@@ -560,66 +621,12 @@ function parseTableCellVerticalMergeRevisionValue(value) {
560
621
  function parseTableRowProperties(trPrElement) {
561
622
  if (!trPrElement) return;
562
623
  const formatting = {};
563
- const preserved = dispatchChildren({
624
+ const preserved = dispatchChildrenWithContext({
564
625
  element: trPrElement,
565
626
  container: "row-properties",
566
- handlers: {
567
- cnfStyle: (child) => {
568
- const conditionalFormat = parseConditionalFormatStyle(child);
569
- if (conditionalFormat) formatting.conditionalFormat = conditionalFormat;
570
- return keptUnless(conditionalFormat !== void 0);
571
- },
572
- divId: CAPTURE,
573
- gridBefore: (child) => {
574
- const gridBefore = parseNumericAttribute(child, "w", "val");
575
- if (gridBefore !== void 0 && gridBefore > 0) formatting.gridBefore = gridBefore;
576
- return keptUnless(gridBefore !== void 0 && gridBefore > 0);
577
- },
578
- gridAfter: (child) => {
579
- const gridAfter = parseNumericAttribute(child, "w", "val");
580
- if (gridAfter !== void 0 && gridAfter > 0) formatting.gridAfter = gridAfter;
581
- return keptUnless(gridAfter !== void 0 && gridAfter > 0);
582
- },
583
- wBefore: (child) => {
584
- const widthBefore = parseTableMeasurement(child);
585
- if (widthBefore) formatting.widthBefore = widthBefore;
586
- return keptUnless(widthBefore !== void 0);
587
- },
588
- wAfter: (child) => {
589
- const widthAfter = parseTableMeasurement(child);
590
- if (widthAfter) formatting.widthAfter = widthAfter;
591
- return keptUnless(widthAfter !== void 0);
592
- },
593
- cantSplit: (child) => {
594
- formatting.cantSplit = parseBooleanElement(child);
595
- },
596
- trHeight: (child) => {
597
- const heightVal = parseNumericAttribute(child, "w", "val");
598
- if (heightVal === void 0 || heightVal <= 0) return CAPTURE;
599
- formatting.height = {
600
- value: heightVal,
601
- type: "dxa"
602
- };
603
- const hRule = getAttribute(child, "w", "hRule");
604
- if (hRule === "auto" || hRule === "atLeast" || hRule === "exact") formatting.heightRule = hRule;
605
- },
606
- tblHeader: (child) => {
607
- formatting.header = parseBooleanElement(child);
608
- },
609
- tblCellSpacing: CAPTURE,
610
- jc: (child) => {
611
- const justification = narrowEnum(getAttribute(child, "w", "val"), TableAlignmentSchema);
612
- if (justification !== void 0) formatting.justification = justification;
613
- return keptUnless(justification !== void 0);
614
- },
615
- hidden: (child) => {
616
- formatting.hidden = parseBooleanElement(child);
617
- },
618
- ins: ROW_INSERTION_OWNER,
619
- del: ROW_DELETION_OWNER,
620
- trPrChange: ROW_PROPERTY_CHANGE_OWNER
621
- },
622
- capturePosition: sequencePositions("row-properties", trPrElement)
627
+ handlers: ROW_PROPERTY_HANDLERS,
628
+ capturePosition: sequencePositions("row-properties", trPrElement),
629
+ context: formatting
623
630
  });
624
631
  if (preserved) formatting.preserved = preserved;
625
632
  return withSourceXml(formatting, trPrElement);
@@ -663,6 +670,72 @@ function parseConditionalFormatStyle(cnfElement) {
663
670
  if (Object.keys(style).length === 0) return;
664
671
  return style;
665
672
  }
673
+ const CELL_PROPERTY_HANDLERS = {
674
+ cnfStyle: (child, formatting) => {
675
+ const conditionalFormat = parseConditionalFormatStyle(child);
676
+ if (conditionalFormat) formatting.conditionalFormat = conditionalFormat;
677
+ return keptUnless(conditionalFormat !== void 0);
678
+ },
679
+ tcW: (child, formatting) => {
680
+ const width = parseWidth(child);
681
+ if (width) formatting.width = width;
682
+ return keptUnless(width !== void 0);
683
+ },
684
+ gridSpan: (child, formatting) => {
685
+ const gridSpan = parseNumericAttribute(child, "w", "val");
686
+ if (gridSpan !== void 0 && gridSpan > 1) {
687
+ formatting.gridSpan = Math.min(gridSpan, 63);
688
+ return;
689
+ }
690
+ return CAPTURE;
691
+ },
692
+ hMerge: CAPTURE,
693
+ vMerge: (child, formatting) => {
694
+ formatting.vMerge = getAttribute(child, "w", "val") === "restart" ? "restart" : "continue";
695
+ },
696
+ tcBorders: (child, formatting) => {
697
+ const borders = parseTableCellBorders(child);
698
+ if (borders) formatting.borders = borders;
699
+ return keptUnless(borders !== void 0);
700
+ },
701
+ shd: (child, formatting) => {
702
+ const shading = parseShading(child);
703
+ if (shading) formatting.shading = shading;
704
+ return keptUnless(shading !== void 0);
705
+ },
706
+ noWrap: (child, formatting) => {
707
+ formatting.noWrap = parseBooleanElement(child);
708
+ },
709
+ tcMar: (child, formatting) => {
710
+ const margins = parseCellMargins(child);
711
+ if (margins) formatting.margins = margins;
712
+ return keptUnless(margins !== void 0);
713
+ },
714
+ textDirection: (child, formatting) => {
715
+ const textDir = narrowEnum(getAttribute(child, "w", "val"), TextDirectionSchema);
716
+ if (textDir) formatting.textDirection = textDir;
717
+ return keptUnless(textDir !== void 0);
718
+ },
719
+ tcFitText: (child, formatting) => {
720
+ formatting.fitText = parseBooleanElement(child);
721
+ },
722
+ vAlign: (child, formatting) => {
723
+ const vAlign = getAttribute(child, "w", "val");
724
+ if (vAlign === "top" || vAlign === "center" || vAlign === "bottom") {
725
+ formatting.verticalAlign = vAlign;
726
+ return;
727
+ }
728
+ return CAPTURE;
729
+ },
730
+ hideMark: (child, formatting) => {
731
+ formatting.hideMark = parseBooleanElement(child);
732
+ },
733
+ headers: CAPTURE,
734
+ cellIns: CELL_INSERTION_OWNER,
735
+ cellDel: CELL_DELETION_OWNER,
736
+ cellMerge: CELL_MERGE_OWNER,
737
+ tcPrChange: CELL_PROPERTY_CHANGE_OWNER
738
+ };
666
739
  /**
667
740
  * Parse table cell properties (w:tcPr)
668
741
  *
@@ -672,76 +745,12 @@ function parseConditionalFormatStyle(cnfElement) {
672
745
  function parseTableCellProperties(tcPrElement) {
673
746
  if (!tcPrElement) return;
674
747
  const formatting = {};
675
- const preserved = dispatchChildren({
748
+ const preserved = dispatchChildrenWithContext({
676
749
  element: tcPrElement,
677
750
  container: "cell-properties",
678
- handlers: {
679
- cnfStyle: (child) => {
680
- const conditionalFormat = parseConditionalFormatStyle(child);
681
- if (conditionalFormat) formatting.conditionalFormat = conditionalFormat;
682
- return keptUnless(conditionalFormat !== void 0);
683
- },
684
- tcW: (child) => {
685
- const width = parseWidth(child);
686
- if (width) formatting.width = width;
687
- return keptUnless(width !== void 0);
688
- },
689
- gridSpan: (child) => {
690
- const gridSpan = parseNumericAttribute(child, "w", "val");
691
- if (gridSpan !== void 0 && gridSpan > 1) {
692
- formatting.gridSpan = Math.min(gridSpan, 63);
693
- return;
694
- }
695
- return CAPTURE;
696
- },
697
- hMerge: CAPTURE,
698
- vMerge: (child) => {
699
- formatting.vMerge = getAttribute(child, "w", "val") === "restart" ? "restart" : "continue";
700
- },
701
- tcBorders: (child) => {
702
- const borders = parseTableCellBorders(child);
703
- if (borders) formatting.borders = borders;
704
- return keptUnless(borders !== void 0);
705
- },
706
- shd: (child) => {
707
- const shading = parseShading(child);
708
- if (shading) formatting.shading = shading;
709
- return keptUnless(shading !== void 0);
710
- },
711
- noWrap: (child) => {
712
- formatting.noWrap = parseBooleanElement(child);
713
- },
714
- tcMar: (child) => {
715
- const margins = parseCellMargins(child);
716
- if (margins) formatting.margins = margins;
717
- return keptUnless(margins !== void 0);
718
- },
719
- textDirection: (child) => {
720
- const textDir = narrowEnum(getAttribute(child, "w", "val"), TextDirectionSchema);
721
- if (textDir) formatting.textDirection = textDir;
722
- return keptUnless(textDir !== void 0);
723
- },
724
- tcFitText: (child) => {
725
- formatting.fitText = parseBooleanElement(child);
726
- },
727
- vAlign: (child) => {
728
- const vAlign = getAttribute(child, "w", "val");
729
- if (vAlign === "top" || vAlign === "center" || vAlign === "bottom") {
730
- formatting.verticalAlign = vAlign;
731
- return;
732
- }
733
- return CAPTURE;
734
- },
735
- hideMark: (child) => {
736
- formatting.hideMark = parseBooleanElement(child);
737
- },
738
- headers: CAPTURE,
739
- cellIns: CELL_INSERTION_OWNER,
740
- cellDel: CELL_DELETION_OWNER,
741
- cellMerge: CELL_MERGE_OWNER,
742
- tcPrChange: CELL_PROPERTY_CHANGE_OWNER
743
- },
744
- capturePosition: sequencePositions("cell-properties", tcPrElement)
751
+ handlers: CELL_PROPERTY_HANDLERS,
752
+ capturePosition: sequencePositions("cell-properties", tcPrElement),
753
+ context: formatting
745
754
  });
746
755
  if (preserved) formatting.preserved = preserved;
747
756
  return withSourceXml(formatting, tcPrElement);
@@ -762,108 +771,141 @@ const recordContentControl = (wrapped, carriers, sdtElement) => {
762
771
  function withContainerXmlns(options, element) {
763
772
  return {
764
773
  ...options,
765
- rootXmlns: mergeXmlnsDeclarations(options?.rootXmlns ?? {}, element)
774
+ rootXmlns: mergeXmlnsDeclarations(options?.rootXmlns ?? {}, element),
775
+ previews: options?.previews ?? standalonePreviewLedger()
766
776
  };
767
777
  }
768
- function parseCellContent(tcElement, styles, theme, numbering, rels, media, options) {
769
- const findLastFlowBlock = (blocks) => {
770
- for (let index = blocks.length - 1; index >= 0; index -= 1) {
771
- const block = blocks[index];
772
- if (block?.type === "paragraph" || block?.type === "table") return block;
773
- if (block?.type === "blockSdt") {
774
- const nested = findLastFlowBlock(block.content);
775
- if (nested) return nested;
776
- }
778
+ const findLastFlowBlock = (blocks) => {
779
+ for (let index = blocks.length - 1; index >= 0; index -= 1) {
780
+ const block = blocks[index];
781
+ if (block?.type === "paragraph" || block?.type === "table") return block;
782
+ if (block?.type === "blockSdt") {
783
+ const nested = findLastFlowBlock(block.content);
784
+ if (nested) return nested;
777
785
  }
786
+ }
787
+ };
788
+ const CELL_CONTENT_UNDECLARED = { AlternateContent: (child, walk) => {
789
+ const selectedBranch = selectAlternateContentBranch(child);
790
+ if (!selectedBranch) return;
791
+ dispatchCellChildren(selectedBranch, {
792
+ ...walk,
793
+ options: withContainerXmlns(withContainerXmlns(walk.options, child), selectedBranch)
794
+ });
795
+ } };
796
+ const CELL_CONTENT_HANDLERS = {
797
+ p: (child, { resources: { styles, theme, numbering, rels, media }, options, modelled }) => {
798
+ const para = parseParagraph(child, styles, theme, numbering, rels, media, {
799
+ ...options,
800
+ runConsolidation: "deferred"
801
+ });
802
+ enrichParagraphTextBoxes(para, child, styles, theme, numbering, rels, media, parseTable, options.previews);
803
+ modelled.push(para);
804
+ },
805
+ tbl: (child, { resources: { styles, theme, numbering, rels, media }, options, modelled }) => {
806
+ const table = parseTable(child, styles, theme, numbering, rels, media, options);
807
+ if (!table) return;
808
+ modelled.push(table);
809
+ },
810
+ sdt: (child, { resources, options, modelled }) => {
811
+ const properties = parseSdtProperties(findWordprocessingChild(child, "sdtPr"), findWordprocessingChild(child, "sdtEndPr"));
812
+ const siblings = captureSdtSiblingMarkers(child);
813
+ if (siblings.before.length > 0) properties.rawSdtChildrenBeforeContent = siblings.before;
814
+ if (siblings.after.length > 0) properties.rawSdtChildrenAfterContent = siblings.after;
815
+ const sdtContent = findWordprocessingChild(child, "sdtContent");
816
+ if (!sdtContent) return CAPTURE;
817
+ modelled.push({
818
+ type: "blockSdt",
819
+ properties,
820
+ content: parseCellChildren({
821
+ element: sdtContent,
822
+ resources,
823
+ options: withContainerXmlns(withContainerXmlns(options, child), sdtContent),
824
+ requireTrailingParagraph: false
825
+ })
826
+ });
827
+ },
828
+ bookmarkStart: (child, { modelled }) => {
829
+ modelled.push(parseBookmarkStart(child));
830
+ },
831
+ bookmarkEnd: (child, { modelled }) => {
832
+ modelled.push(parseBookmarkEnd(child));
833
+ },
834
+ tcPr: CELL_PROPERTIES_OWNER,
835
+ sectPr: CAPTURE,
836
+ altChunk: CAPTURE,
837
+ commentRangeEnd: CAPTURE,
838
+ commentRangeStart: CAPTURE,
839
+ customXml: CAPTURE,
840
+ customXmlDelRangeEnd: CAPTURE,
841
+ customXmlDelRangeStart: CAPTURE,
842
+ customXmlInsRangeEnd: CAPTURE,
843
+ customXmlInsRangeStart: CAPTURE,
844
+ customXmlMoveFromRangeEnd: CAPTURE,
845
+ customXmlMoveFromRangeStart: CAPTURE,
846
+ customXmlMoveToRangeEnd: CAPTURE,
847
+ customXmlMoveToRangeStart: CAPTURE,
848
+ del: CAPTURE,
849
+ ins: CAPTURE,
850
+ moveFrom: CAPTURE,
851
+ moveFromRangeEnd: CAPTURE,
852
+ moveFromRangeStart: CAPTURE,
853
+ moveTo: CAPTURE,
854
+ moveToRangeEnd: CAPTURE,
855
+ moveToRangeStart: CAPTURE,
856
+ permEnd: CAPTURE,
857
+ permStart: CAPTURE,
858
+ proofErr: CAPTURE
859
+ };
860
+ /**
861
+ * AlternateContent is transparent to the cell's block sequence. An SDT is
862
+ * not: it owns a nested block sequence whose preservation positions must be
863
+ * counted independently from the surrounding cell.
864
+ */
865
+ const dispatchCellChildren = (childContainer, walk) => {
866
+ const preserved = dispatchChildrenWithContext({
867
+ element: childContainer,
868
+ container: "block-content",
869
+ capturePosition: () => walk.modelled.length,
870
+ undeclared: CELL_CONTENT_UNDECLARED,
871
+ handlers: CELL_CONTENT_HANDLERS,
872
+ context: walk
873
+ });
874
+ if (preserved?.children) walk.captured.push(...preserved.children);
875
+ };
876
+ const parseCellChildren = ({ element, resources, options, requireTrailingParagraph }) => {
877
+ const walk = {
878
+ resources,
879
+ options,
880
+ modelled: [],
881
+ captured: []
778
882
  };
779
- const parseCellChildren = (element, childOptions, requireTrailingParagraph) => {
780
- const modelled = [];
781
- const captured = [];
782
- const dispatchCellChildren = (childContainer, nestedOptions) => {
783
- const preserved = dispatchChildren({
784
- element: childContainer,
785
- container: "block-content",
786
- capturePosition: () => modelled.length,
787
- undeclared: { AlternateContent: (child) => {
788
- const selectedBranch = selectAlternateContentBranch(child);
789
- if (!selectedBranch) return;
790
- dispatchCellChildren(selectedBranch, withContainerXmlns(withContainerXmlns(nestedOptions, child), selectedBranch));
791
- } },
792
- handlers: {
793
- p: (child) => {
794
- const para = parseParagraph(child, styles, theme, numbering, rels, media, {
795
- ...nestedOptions,
796
- runConsolidation: "deferred"
797
- });
798
- enrichParagraphTextBoxes(para, child, styles, theme, numbering, rels, media, parseTable);
799
- modelled.push(para);
800
- },
801
- tbl: (child) => {
802
- const table = parseTable(child, styles, theme, numbering, rels, media, nestedOptions);
803
- if (!table) return;
804
- modelled.push(table);
805
- },
806
- sdt: (child) => {
807
- const properties = parseSdtProperties(findWordprocessingChild(child, "sdtPr"), findWordprocessingChild(child, "sdtEndPr"));
808
- const siblings = captureSdtSiblingMarkers(child);
809
- if (siblings.before.length > 0) properties.rawSdtChildrenBeforeContent = siblings.before;
810
- if (siblings.after.length > 0) properties.rawSdtChildrenAfterContent = siblings.after;
811
- const sdtContent = findWordprocessingChild(child, "sdtContent");
812
- if (!sdtContent) return CAPTURE;
813
- modelled.push({
814
- type: "blockSdt",
815
- properties,
816
- content: parseCellChildren(sdtContent, withContainerXmlns(withContainerXmlns(nestedOptions, child), sdtContent), false)
817
- });
818
- },
819
- bookmarkStart: (child) => {
820
- modelled.push(parseBookmarkStart(child));
821
- },
822
- bookmarkEnd: (child) => {
823
- modelled.push(parseBookmarkEnd(child));
824
- },
825
- tcPr: CELL_PROPERTIES_OWNER,
826
- sectPr: CAPTURE,
827
- altChunk: CAPTURE,
828
- commentRangeEnd: CAPTURE,
829
- commentRangeStart: CAPTURE,
830
- customXml: CAPTURE,
831
- customXmlDelRangeEnd: CAPTURE,
832
- customXmlDelRangeStart: CAPTURE,
833
- customXmlInsRangeEnd: CAPTURE,
834
- customXmlInsRangeStart: CAPTURE,
835
- customXmlMoveFromRangeEnd: CAPTURE,
836
- customXmlMoveFromRangeStart: CAPTURE,
837
- customXmlMoveToRangeEnd: CAPTURE,
838
- customXmlMoveToRangeStart: CAPTURE,
839
- del: CAPTURE,
840
- ins: CAPTURE,
841
- moveFrom: CAPTURE,
842
- moveFromRangeEnd: CAPTURE,
843
- moveFromRangeStart: CAPTURE,
844
- moveTo: CAPTURE,
845
- moveToRangeEnd: CAPTURE,
846
- moveToRangeStart: CAPTURE,
847
- permEnd: CAPTURE,
848
- permStart: CAPTURE,
849
- proofErr: CAPTURE
850
- }
851
- });
852
- if (preserved?.children) captured.push(...preserved.children);
853
- };
854
- dispatchCellChildren(element, childOptions);
855
- if (requireTrailingParagraph) {
856
- if (findLastFlowBlock(modelled)?.type !== "paragraph") modelled.push({
857
- type: "paragraph",
858
- content: []
859
- });
860
- }
861
- return withPreservedChildren(modelled, { children: captured }, (xml) => ({
862
- type: "preservedBlock",
863
- xml
864
- }));
865
- };
866
- return parseCellChildren(tcElement, options, true);
883
+ dispatchCellChildren(element, walk);
884
+ const { modelled, captured } = walk;
885
+ if (requireTrailingParagraph) {
886
+ if (findLastFlowBlock(modelled)?.type !== "paragraph") modelled.push({
887
+ type: "paragraph",
888
+ content: []
889
+ });
890
+ }
891
+ return withPreservedChildren(modelled, { children: captured }, (xml) => ({
892
+ type: "preservedBlock",
893
+ xml
894
+ }));
895
+ };
896
+ function parseCellContent(tcElement, styles, theme, numbering, rels, media, options) {
897
+ return parseCellChildren({
898
+ element: tcElement,
899
+ resources: {
900
+ styles,
901
+ theme,
902
+ numbering,
903
+ rels,
904
+ media
905
+ },
906
+ options,
907
+ requireTrailingParagraph: true
908
+ });
867
909
  }
868
910
  /**
869
911
  * Parse a table cell (w:tc)
@@ -893,6 +935,85 @@ function parseTableCell(tcElement, styles, theme, numbering, rels, media, option
893
935
  cell.content = parseCellContent(tcElement, styles, theme, numbering, rels, media, withContainerXmlns(options, tcElement));
894
936
  return cell;
895
937
  }
938
+ const ROW_CONTENT_HANDLERS = {
939
+ tc: (child, { resources: { styles, theme, numbering, rels, media }, options, row }) => {
940
+ row.cells.push(parseTableCell(child, styles, theme, numbering, rels, media, options));
941
+ },
942
+ sdt: (child, walk) => {
943
+ const { options, row, bookmarks, preservedChildren } = walk;
944
+ const sdtContent = findWordprocessingChild(child, "sdtContent");
945
+ if (!sdtContent) return CAPTURE;
946
+ const firstWrapped = row.cells.length;
947
+ const firstCaptured = preservedChildren.length;
948
+ const firstBookmark = bookmarks.length;
949
+ const sdtOptions = withContainerXmlns(options, child);
950
+ dispatchRowChildren(sdtContent, {
951
+ ...walk,
952
+ options: withContainerXmlns(sdtOptions, sdtContent)
953
+ });
954
+ const wrapped = row.cells.slice(firstWrapped);
955
+ if (wrapped.length === 0) {
956
+ preservedChildren.splice(firstCaptured);
957
+ bookmarks.splice(firstBookmark);
958
+ return CAPTURE;
959
+ }
960
+ recordContentControl(wrapped, [...preservedChildren.slice(firstCaptured), ...bookmarks.slice(firstBookmark)], child);
961
+ },
962
+ bookmarkStart: (child, { row, bookmarks }) => {
963
+ bookmarks.push({
964
+ index: row.cells.length,
965
+ marker: parseBookmarkStart(child)
966
+ });
967
+ },
968
+ bookmarkEnd: (child, { row, bookmarks }) => {
969
+ bookmarks.push({
970
+ index: row.cells.length,
971
+ marker: parseBookmarkEnd(child)
972
+ });
973
+ },
974
+ ...ROW_CHILD_OWNERS,
975
+ commentRangeEnd: CAPTURE,
976
+ commentRangeStart: CAPTURE,
977
+ customXml: CAPTURE,
978
+ customXmlDelRangeEnd: CAPTURE,
979
+ customXmlDelRangeStart: CAPTURE,
980
+ customXmlInsRangeEnd: CAPTURE,
981
+ customXmlInsRangeStart: CAPTURE,
982
+ customXmlMoveFromRangeEnd: CAPTURE,
983
+ customXmlMoveFromRangeStart: CAPTURE,
984
+ customXmlMoveToRangeEnd: CAPTURE,
985
+ customXmlMoveToRangeStart: CAPTURE,
986
+ del: CAPTURE,
987
+ ins: CAPTURE,
988
+ moveFrom: CAPTURE,
989
+ moveFromRangeEnd: CAPTURE,
990
+ moveFromRangeStart: CAPTURE,
991
+ moveTo: CAPTURE,
992
+ moveToRangeEnd: CAPTURE,
993
+ moveToRangeStart: CAPTURE,
994
+ permEnd: CAPTURE,
995
+ permStart: CAPTURE,
996
+ proofErr: CAPTURE,
997
+ tr: CAPTURE
998
+ };
999
+ /**
1000
+ * One row's children, or a cell-level content control's.
1001
+ *
1002
+ * folio keeps the cells `w:sdt` holds as the row's own and records the
1003
+ * control on each of them, so the recursion walks the control's content
1004
+ * with the same map; the sink is the row's either way, because the control
1005
+ * holds no capture of its own.
1006
+ */
1007
+ const dispatchRowChildren = (element, walk) => {
1008
+ const captured = dispatchChildrenWithContext({
1009
+ element,
1010
+ container: "row-content",
1011
+ capturePosition: () => walk.row.cells.length,
1012
+ handlers: ROW_CONTENT_HANDLERS,
1013
+ context: walk
1014
+ });
1015
+ if (captured?.children) walk.preservedChildren.push(...captured.children);
1016
+ };
896
1017
  /**
897
1018
  * Parse a table row (w:tr)
898
1019
  *
@@ -921,83 +1042,21 @@ function parseTableRow(trElement, styles, theme, numbering, rels, media, options
921
1042
  if (rowPropChanges !== void 0) row.propertyChanges = rowPropChanges;
922
1043
  const rowStructChange = parseTableRowStructuralChange(trPrElement);
923
1044
  if (rowStructChange !== void 0) row.structuralChange = rowStructChange;
924
- const rowOptions = withContainerXmlns(options, trElement);
925
1045
  const bookmarks = [];
926
1046
  const preservedChildren = [];
927
- /**
928
- * One row's children, or a cell-level content control's.
929
- *
930
- * folio keeps the cells `w:sdt` holds as the row's own and records the
931
- * control on each of them, so the recursion walks the control's content
932
- * with the same map; the sink is the row's either way, because the control
933
- * holds no capture of its own.
934
- */
935
- const dispatchRowChildren = (element, childOptions) => {
936
- const captured = dispatchChildren({
937
- element,
938
- container: "row-content",
939
- capturePosition: () => row.cells.length,
940
- handlers: {
941
- tc: (child) => {
942
- row.cells.push(parseTableCell(child, styles, theme, numbering, rels, media, childOptions));
943
- },
944
- sdt: (child) => {
945
- const sdtContent = findWordprocessingChild(child, "sdtContent");
946
- if (!sdtContent) return CAPTURE;
947
- const firstWrapped = row.cells.length;
948
- const firstCaptured = preservedChildren.length;
949
- const firstBookmark = bookmarks.length;
950
- const sdtOptions = withContainerXmlns(childOptions, child);
951
- dispatchRowChildren(sdtContent, withContainerXmlns(sdtOptions, sdtContent));
952
- const wrapped = row.cells.slice(firstWrapped);
953
- if (wrapped.length === 0) {
954
- preservedChildren.splice(firstCaptured);
955
- bookmarks.splice(firstBookmark);
956
- return CAPTURE;
957
- }
958
- recordContentControl(wrapped, [...preservedChildren.slice(firstCaptured), ...bookmarks.slice(firstBookmark)], child);
959
- },
960
- bookmarkStart: (child) => {
961
- bookmarks.push({
962
- index: row.cells.length,
963
- marker: parseBookmarkStart(child)
964
- });
965
- },
966
- bookmarkEnd: (child) => {
967
- bookmarks.push({
968
- index: row.cells.length,
969
- marker: parseBookmarkEnd(child)
970
- });
971
- },
972
- ...ROW_CHILD_OWNERS,
973
- commentRangeEnd: CAPTURE,
974
- commentRangeStart: CAPTURE,
975
- customXml: CAPTURE,
976
- customXmlDelRangeEnd: CAPTURE,
977
- customXmlDelRangeStart: CAPTURE,
978
- customXmlInsRangeEnd: CAPTURE,
979
- customXmlInsRangeStart: CAPTURE,
980
- customXmlMoveFromRangeEnd: CAPTURE,
981
- customXmlMoveFromRangeStart: CAPTURE,
982
- customXmlMoveToRangeEnd: CAPTURE,
983
- customXmlMoveToRangeStart: CAPTURE,
984
- del: CAPTURE,
985
- ins: CAPTURE,
986
- moveFrom: CAPTURE,
987
- moveFromRangeEnd: CAPTURE,
988
- moveFromRangeStart: CAPTURE,
989
- moveTo: CAPTURE,
990
- moveToRangeEnd: CAPTURE,
991
- moveToRangeStart: CAPTURE,
992
- permEnd: CAPTURE,
993
- permStart: CAPTURE,
994
- proofErr: CAPTURE,
995
- tr: CAPTURE
996
- }
997
- });
998
- if (captured?.children) preservedChildren.push(...captured.children);
999
- };
1000
- dispatchRowChildren(trElement, rowOptions);
1047
+ dispatchRowChildren(trElement, {
1048
+ resources: {
1049
+ styles,
1050
+ theme,
1051
+ numbering,
1052
+ rels,
1053
+ media
1054
+ },
1055
+ options: withContainerXmlns(options, trElement),
1056
+ row,
1057
+ bookmarks,
1058
+ preservedChildren
1059
+ });
1001
1060
  if (preservedChildren.length > 0) row.preserved = { children: preservedChildren };
1002
1061
  if (bookmarks.length > 0) row.bookmarks = bookmarks;
1003
1062
  const remainingAttributes = attributeRemainder({
@@ -1082,6 +1141,87 @@ function inferImplicitSingleCellRowSpans(table, rowsWithGridOffsets) {
1082
1141
  };
1083
1142
  }
1084
1143
  }
1144
+ const TABLE_CONTENT_HANDLERS = {
1145
+ tr: (child, { resources: { styles, theme, numbering, rels, media }, options, table, rowsWithGridOffsets }) => {
1146
+ const rowIndex = table.rows.length;
1147
+ table.rows.push(parseTableRow(child, styles, theme, numbering, rels, media, options));
1148
+ if (hasRowGridOffsets(child)) rowsWithGridOffsets.add(rowIndex);
1149
+ },
1150
+ sdt: (child, walk) => {
1151
+ const { options, table, bookmarks, preservedChildren } = walk;
1152
+ const sdtContent = findWordprocessingChild(child, "sdtContent");
1153
+ if (!sdtContent) return CAPTURE;
1154
+ const firstWrapped = table.rows.length;
1155
+ const firstCaptured = preservedChildren.length;
1156
+ const firstBookmark = bookmarks.length;
1157
+ const sdtOptions = withContainerXmlns(options, child);
1158
+ dispatchTableChildren(sdtContent, {
1159
+ ...walk,
1160
+ options: withContainerXmlns(sdtOptions, sdtContent)
1161
+ });
1162
+ const wrapped = table.rows.slice(firstWrapped);
1163
+ if (wrapped.length === 0) {
1164
+ preservedChildren.splice(firstCaptured);
1165
+ bookmarks.splice(firstBookmark);
1166
+ return CAPTURE;
1167
+ }
1168
+ recordContentControl(wrapped, [...preservedChildren.slice(firstCaptured), ...bookmarks.slice(firstBookmark)], child);
1169
+ },
1170
+ ...TABLE_CHILD_OWNERS,
1171
+ bookmarkStart: (child, { table, bookmarks }) => {
1172
+ bookmarks.push({
1173
+ index: table.rows.length,
1174
+ marker: parseBookmarkStart(child)
1175
+ });
1176
+ },
1177
+ bookmarkEnd: (child, { table, bookmarks }) => {
1178
+ bookmarks.push({
1179
+ index: table.rows.length,
1180
+ marker: parseBookmarkEnd(child)
1181
+ });
1182
+ },
1183
+ commentRangeEnd: CAPTURE,
1184
+ commentRangeStart: CAPTURE,
1185
+ customXml: CAPTURE,
1186
+ customXmlPr: CAPTURE,
1187
+ customXmlDelRangeEnd: CAPTURE,
1188
+ customXmlDelRangeStart: CAPTURE,
1189
+ customXmlInsRangeEnd: CAPTURE,
1190
+ customXmlInsRangeStart: CAPTURE,
1191
+ customXmlMoveFromRangeEnd: CAPTURE,
1192
+ customXmlMoveFromRangeStart: CAPTURE,
1193
+ customXmlMoveToRangeEnd: CAPTURE,
1194
+ customXmlMoveToRangeStart: CAPTURE,
1195
+ del: CAPTURE,
1196
+ ins: CAPTURE,
1197
+ moveFrom: CAPTURE,
1198
+ moveFromRangeEnd: CAPTURE,
1199
+ moveFromRangeStart: CAPTURE,
1200
+ moveTo: CAPTURE,
1201
+ moveToRangeEnd: CAPTURE,
1202
+ moveToRangeStart: CAPTURE,
1203
+ permEnd: CAPTURE,
1204
+ permStart: CAPTURE,
1205
+ proofErr: CAPTURE
1206
+ };
1207
+ /**
1208
+ * One table's children, or a row-level content control's.
1209
+ *
1210
+ * folio keeps the rows `w:sdt` holds as the table's own and records the
1211
+ * control on each of them, so the recursion walks the control's content
1212
+ * with the same map; the sink is the table's either way, because the
1213
+ * control holds no capture of its own.
1214
+ */
1215
+ const dispatchTableChildren = (element, walk) => {
1216
+ const captured = dispatchChildrenWithContext({
1217
+ element,
1218
+ container: "table-content",
1219
+ capturePosition: () => walk.table.rows.length,
1220
+ handlers: TABLE_CONTENT_HANDLERS,
1221
+ context: walk
1222
+ });
1223
+ if (captured?.children) walk.preservedChildren.push(...captured.children);
1224
+ };
1085
1225
  /**
1086
1226
  * Parse a table element (w:tbl)
1087
1227
  *
@@ -1114,86 +1254,23 @@ function parseTable(tblElement, styles, theme, numbering, rels, media, options)
1114
1254
  ...gridChange === void 0 ? {} : { gridChange }
1115
1255
  };
1116
1256
  }
1117
- const tableOptions = withContainerXmlns(options, tblElement);
1118
1257
  const rowsWithGridOffsets = /* @__PURE__ */ new Set();
1119
1258
  const preservedChildren = [];
1120
1259
  const bookmarks = [];
1121
- /**
1122
- * One table's children, or a row-level content control's.
1123
- *
1124
- * folio keeps the rows `w:sdt` holds as the table's own and records the
1125
- * control on each of them, so the recursion walks the control's content
1126
- * with the same map; the sink is the table's either way, because the
1127
- * control holds no capture of its own.
1128
- */
1129
- const dispatchTableChildren = (element, childOptions) => {
1130
- const captured = dispatchChildren({
1131
- element,
1132
- container: "table-content",
1133
- capturePosition: () => table.rows.length,
1134
- handlers: {
1135
- tr: (child) => {
1136
- const rowIndex = table.rows.length;
1137
- table.rows.push(parseTableRow(child, styles, theme, numbering, rels, media, childOptions));
1138
- if (hasRowGridOffsets(child)) rowsWithGridOffsets.add(rowIndex);
1139
- },
1140
- sdt: (child) => {
1141
- const sdtContent = findWordprocessingChild(child, "sdtContent");
1142
- if (!sdtContent) return CAPTURE;
1143
- const firstWrapped = table.rows.length;
1144
- const firstCaptured = preservedChildren.length;
1145
- const firstBookmark = bookmarks.length;
1146
- const sdtOptions = withContainerXmlns(childOptions, child);
1147
- dispatchTableChildren(sdtContent, withContainerXmlns(sdtOptions, sdtContent));
1148
- const wrapped = table.rows.slice(firstWrapped);
1149
- if (wrapped.length === 0) {
1150
- preservedChildren.splice(firstCaptured);
1151
- bookmarks.splice(firstBookmark);
1152
- return CAPTURE;
1153
- }
1154
- recordContentControl(wrapped, [...preservedChildren.slice(firstCaptured), ...bookmarks.slice(firstBookmark)], child);
1155
- },
1156
- ...TABLE_CHILD_OWNERS,
1157
- bookmarkStart: (child) => {
1158
- bookmarks.push({
1159
- index: table.rows.length,
1160
- marker: parseBookmarkStart(child)
1161
- });
1162
- },
1163
- bookmarkEnd: (child) => {
1164
- bookmarks.push({
1165
- index: table.rows.length,
1166
- marker: parseBookmarkEnd(child)
1167
- });
1168
- },
1169
- commentRangeEnd: CAPTURE,
1170
- commentRangeStart: CAPTURE,
1171
- customXml: CAPTURE,
1172
- customXmlPr: CAPTURE,
1173
- customXmlDelRangeEnd: CAPTURE,
1174
- customXmlDelRangeStart: CAPTURE,
1175
- customXmlInsRangeEnd: CAPTURE,
1176
- customXmlInsRangeStart: CAPTURE,
1177
- customXmlMoveFromRangeEnd: CAPTURE,
1178
- customXmlMoveFromRangeStart: CAPTURE,
1179
- customXmlMoveToRangeEnd: CAPTURE,
1180
- customXmlMoveToRangeStart: CAPTURE,
1181
- del: CAPTURE,
1182
- ins: CAPTURE,
1183
- moveFrom: CAPTURE,
1184
- moveFromRangeEnd: CAPTURE,
1185
- moveFromRangeStart: CAPTURE,
1186
- moveTo: CAPTURE,
1187
- moveToRangeEnd: CAPTURE,
1188
- moveToRangeStart: CAPTURE,
1189
- permEnd: CAPTURE,
1190
- permStart: CAPTURE,
1191
- proofErr: CAPTURE
1192
- }
1193
- });
1194
- if (captured?.children) preservedChildren.push(...captured.children);
1195
- };
1196
- dispatchTableChildren(tblElement, tableOptions);
1260
+ dispatchTableChildren(tblElement, {
1261
+ resources: {
1262
+ styles,
1263
+ theme,
1264
+ numbering,
1265
+ rels,
1266
+ media
1267
+ },
1268
+ options: withContainerXmlns(options, tblElement),
1269
+ table,
1270
+ rowsWithGridOffsets,
1271
+ bookmarks,
1272
+ preservedChildren
1273
+ });
1197
1274
  if (table.rows.length === 0) return;
1198
1275
  if (preservedChildren.length > 0) table.preserved = { children: preservedChildren };
1199
1276
  if (bookmarks.length > 0) table.bookmarks = bookmarks;