@stll/folio-core 0.29.0 → 0.31.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 (103) hide show
  1. package/dist/controller/folioEditor.d.ts +28 -1
  2. package/dist/controller/folioEditor.js +37 -26
  3. package/dist/controller/fontReadiness.js +28 -24
  4. package/dist/controller/hiddenEditorManager.d.ts +2 -7
  5. package/dist/controller/layoutPipeline.js +33 -3
  6. package/dist/controller/noteEditorManager.d.ts +3 -6
  7. package/dist/docx/metafileSvg.d.ts +12 -0
  8. package/dist/docx/metafileSvg.js +462 -0
  9. package/dist/docx/paragraphTextBoxEnrichment.js +55 -4
  10. package/dist/docx/parser.d.ts +2 -2
  11. package/dist/docx/parser.js +26 -0
  12. package/dist/docx/runParser.js +2 -1
  13. package/dist/docx/serializer/runSerializer.js +14 -2
  14. package/dist/docx/server/createBilingualDocument.d.ts +20 -3
  15. package/dist/docx/server/createBilingualDocument.js +153 -22
  16. package/dist/docx/styleParser.js +2 -1
  17. package/dist/docx/textBoxParser.js +14 -0
  18. package/dist/docx/vmlImageParser.js +72 -152
  19. package/dist/docx/vmlPreview.d.ts +31 -0
  20. package/dist/docx/vmlPreview.js +535 -0
  21. package/dist/docx/wrapTypes.d.ts +2 -36
  22. package/dist/docx/wrapTypes.js +1 -39
  23. package/dist/fonts/fontAlternates.d.ts +8 -0
  24. package/dist/fonts/fontAlternates.js +16 -0
  25. package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -0
  26. package/dist/layout-bridge/convert/footnoteLayout.js +34 -3
  27. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
  28. package/dist/layout-bridge/convert/headerFooterLayout.js +5 -0
  29. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +3 -0
  30. package/dist/layout-bridge/convert/toFlowBlocks.js +78 -28
  31. package/dist/layout-bridge/dom/noteStoryDom.d.ts +1 -1
  32. package/dist/layout-bridge/engine/selectionRects.js +3 -1
  33. package/dist/layout-engine/index.js +65 -32
  34. package/dist/layout-engine/justifiedLineFit.d.ts +7 -0
  35. package/dist/layout-engine/justifiedLineFit.js +6 -0
  36. package/dist/layout-engine/keep-together.js +15 -10
  37. package/dist/layout-engine/measure/complexScriptFormatting.d.ts +6 -1
  38. package/dist/layout-engine/measure/complexScriptFormatting.js +11 -2
  39. package/dist/layout-engine/measure/floatingTablePosition.d.ts +16 -1
  40. package/dist/layout-engine/measure/floatingTablePosition.js +29 -6
  41. package/dist/layout-engine/measure/lineBreakProvider.js +67 -8
  42. package/dist/layout-engine/measure/listMarkerWidth.d.ts +1 -0
  43. package/dist/layout-engine/measure/listMarkerWidth.js +23 -10
  44. package/dist/layout-engine/measure/measureBlocks.d.ts +15 -0
  45. package/dist/layout-engine/measure/measureBlocks.js +197 -30
  46. package/dist/layout-engine/measure/measureContainer.js +20 -24
  47. package/dist/layout-engine/measure/measureHelpers.d.ts +1 -1
  48. package/dist/layout-engine/measure/measureHelpers.js +14 -8
  49. package/dist/layout-engine/measure/measureParagraph.js +111 -37
  50. package/dist/layout-engine/measure/measureTypes.d.ts +3 -0
  51. package/dist/layout-engine/measure/tabCalculator.d.ts +123 -0
  52. package/dist/layout-engine/measure/tabCalculator.js +144 -0
  53. package/dist/layout-engine/measure/tableCellFlow.d.ts +21 -1
  54. package/dist/layout-engine/measure/tableCellFlow.js +45 -8
  55. package/dist/layout-engine/measure/tableInlinePlacement.d.ts +10 -2
  56. package/dist/layout-engine/measure/tableInlinePlacement.js +17 -15
  57. package/dist/layout-engine/paginator.d.ts +26 -2
  58. package/dist/layout-engine/paginator.js +76 -14
  59. package/dist/layout-engine/paragraphSpacing.d.ts +3 -1
  60. package/dist/layout-engine/paragraphSpacing.js +4 -3
  61. package/dist/layout-engine/renderedBreakReconciliation.d.ts +14 -3
  62. package/dist/layout-engine/renderedBreakReconciliation.js +45 -14
  63. package/dist/layout-engine/section-breaks.d.ts +3 -1
  64. package/dist/layout-engine/section-breaks.js +6 -2
  65. package/dist/layout-engine/types.d.ts +18 -1
  66. package/dist/layout-engine/types.js +1 -1
  67. package/dist/layout-painter/imageLayout.d.ts +1 -1
  68. package/dist/layout-painter/renderPage.js +6 -1
  69. package/dist/layout-painter/renderParagraph.js +169 -82
  70. package/dist/layout-painter/renderTable.d.ts +1 -1
  71. package/dist/layout-painter/renderTable.js +18 -7
  72. package/dist/layout-painter/renderTextBox.d.ts +1 -1
  73. package/dist/layout-painter/renderTextBox.js +6 -1
  74. package/dist/model.d.ts +3 -3
  75. package/dist/model.js +2 -2
  76. package/dist/paged-layout/sectionBlockWidths.d.ts +14 -0
  77. package/dist/paged-layout/sectionBlockWidths.js +103 -14
  78. package/dist/prosemirror/attrs/index.js +12 -1
  79. package/dist/prosemirror/conversion/fromProseDoc.js +6 -2
  80. package/dist/prosemirror/conversion/toProseDoc.js +10 -3
  81. package/dist/prosemirror/extensions/marks/CharacterSpacingExtension.js +9 -5
  82. package/dist/prosemirror/extensions/nodes/TableExtension.js +2 -0
  83. package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +6 -2
  84. package/dist/prosemirror/schema/nodes.d.ts +4 -0
  85. package/dist/prosemirror/utils/tabCalculator.d.ts +2 -123
  86. package/dist/prosemirror/utils/tabCalculator.js +1 -140
  87. package/dist/render-dom/RemoteSelectionOverlay.d.ts +4 -4
  88. package/dist/server.d.ts +2 -2
  89. package/dist/server.js +2 -2
  90. package/dist/types/documentEnumValues.d.ts +4 -1
  91. package/dist/types/documentEnumValues.js +12 -1
  92. package/dist/types/editor-story.d.ts +8 -0
  93. package/dist/types/editor-story.js +0 -0
  94. package/dist/types/remote-selection.d.ts +11 -0
  95. package/dist/types/remote-selection.js +0 -0
  96. package/dist/types/wrap.d.ts +36 -0
  97. package/dist/types/wrap.js +40 -0
  98. package/dist/utils/fontResolver.d.ts +1 -1
  99. package/dist/utils/fontResolver.js +42 -2
  100. package/dist/utils/formatToStyle.js +4 -2
  101. package/dist/utils/horizontalScale.d.ts +28 -0
  102. package/dist/utils/horizontalScale.js +42 -0
  103. package/package.json +2 -2
@@ -2,7 +2,7 @@ import { measureParagraph } from "../layout-engine/measure/measureParagraph.js";
2
2
  import { buildTableCellFloatingZones, getTableCellContentWidth, getTableCellFloatingImages } from "../layout-engine/measure/tableCellFloating.js";
3
3
  import { createTableCellFlowState, finishTableCellFlow, placeTableCellBlock } from "../layout-engine/measure/tableCellFlow.js";
4
4
  import { buildTableCellGrid, buildTableCellPlacements, getSourceCellAt } from "../layout-engine/measure/tableCellGrid.js";
5
- import { resolveTableInlinePlacement } from "../layout-engine/measure/tableInlinePlacement.js";
5
+ import { resolveTableInlineOffset, resolveTableInlinePlacement } from "../layout-engine/measure/tableInlinePlacement.js";
6
6
  import { isFloatingImageRun, isFloatingTextBoxBlock, resolveTableCellPadding, tableColumnsArePinned } from "../layout-engine/types.js";
7
7
  import { applySanitizedImageSrc } from "../utils/sanitizeImageSrc.js";
8
8
  import { emuToPixels } from "../utils/units.js";
@@ -134,7 +134,7 @@ function renderCellContent({ cell, cellMeasure, context, doc, contentWidthOverri
134
134
  } else if (block?.kind === "table" && measure?.kind === "table") {
135
135
  const tableBlock = block;
136
136
  const tableMeasure = measure;
137
- const nestedTableEl = renderNestedTable(tableBlock, tableMeasure, context, doc);
137
+ const nestedTableEl = renderNestedTable(tableBlock, tableMeasure, context, doc, contentWidth);
138
138
  nestedTableEl.style.position = "relative";
139
139
  const placement = placeTableCellBlock(flowState, tableBlock, tableMeasure);
140
140
  if (placement.leadingSpacing > 0) {
@@ -224,13 +224,18 @@ function tableHasFloatingCellContent(block) {
224
224
  /**
225
225
  * Render a nested table (within a cell)
226
226
  */
227
- function renderNestedTable(block, measure, context, doc) {
227
+ function renderNestedTable(block, measure, context, doc, frameWidth = context.contentWidth ?? measure.totalWidth) {
228
228
  const tableEl = doc.createElement("div");
229
229
  tableEl.className = `${TABLE_CLASS_NAMES.table} layout-nested-table`;
230
230
  tableEl.style.position = "relative";
231
231
  tableEl.style.width = `${measure.totalWidth}px`;
232
232
  tableEl.style.display = "block";
233
233
  const placement = resolveTableInlinePlacement(block);
234
+ const tableInlineOffset = resolveTableInlineOffset({
235
+ table: block,
236
+ frameWidth,
237
+ tableWidth: measure.totalWidth
238
+ });
234
239
  if (placement.alignment === "center") {
235
240
  tableEl.style.marginLeft = "auto";
236
241
  tableEl.style.marginRight = "auto";
@@ -277,7 +282,13 @@ function renderNestedTable(block, measure, context, doc) {
277
282
  bidi: block.bidi === true,
278
283
  columnsPinned,
279
284
  cellGrid,
280
- cellPlacements
285
+ cellPlacements,
286
+ inlineOffset: resolveTableInlineOffset({
287
+ table: block,
288
+ rowJustification: row.justification,
289
+ frameWidth,
290
+ tableWidth: measure.totalWidth
291
+ }) - tableInlineOffset
281
292
  });
282
293
  tableEl.append(rowEl);
283
294
  y += rowMeasure.height;
@@ -433,11 +444,11 @@ function renderTableCell({ cell, cellMeasure, x, width, rowHeight, borderFlags,
433
444
  return cellEl;
434
445
  }
435
446
  const hasVisibleBorder = (border) => border !== void 0 && border.style !== "none" && border.style !== "nil";
436
- function renderTableRow({ row, rowMeasure, rowIndex, y, columnWidths, totalRows, context, doc, rowYPositions, isFirstRowInFragment, bidi = false, columnsPinned = false, cellGrid, cellPlacements, contentClip, pageContentPosition }) {
447
+ function renderTableRow({ row, rowMeasure, rowIndex, y, columnWidths, totalRows, context, doc, rowYPositions, isFirstRowInFragment, bidi = false, columnsPinned = false, cellGrid, cellPlacements, contentClip, pageContentPosition, inlineOffset = 0 }) {
437
448
  const rowEl = doc.createElement("div");
438
449
  rowEl.className = TABLE_CLASS_NAMES.row;
439
450
  rowEl.style.position = "absolute";
440
- rowEl.style.left = "0";
451
+ rowEl.style.left = `${inlineOffset}px`;
441
452
  rowEl.style.top = `${y}px`;
442
453
  rowEl.style.width = "100%";
443
454
  rowEl.style.height = `${rowMeasure.height}px`;
@@ -484,7 +495,7 @@ function renderTableRow({ row, rowMeasure, rowIndex, y, columnWidths, totalRows,
484
495
  ...contentClip ? { contentClip } : {},
485
496
  ...pageContentPosition ? { pageContentPosition: {
486
497
  geometry: pageContentPosition.geometry,
487
- x: pageContentPosition.x + cellLeft,
498
+ x: pageContentPosition.x + inlineOffset + cellLeft,
488
499
  y: pageContentPosition.y
489
500
  } } : {}
490
501
  });
@@ -12,7 +12,7 @@ declare const TEXTBOX_CLASS_NAMES: {
12
12
  */
13
13
  type RenderTextBoxFragmentOptions = {
14
14
  document?: Document;
15
- renderTable?: (block: TableBlock, measure: TableMeasure, context: RenderContext, document: Document) => HTMLElement;
15
+ renderTable?: (block: TableBlock, measure: TableMeasure, context: RenderContext, document: Document, frameWidth?: number) => HTMLElement;
16
16
  };
17
17
  /**
18
18
  * Render a text box fragment to DOM
@@ -36,6 +36,11 @@ function renderTextBoxFragment(fragment, block, measure, context, options = {})
36
36
  }
37
37
  const margins = block.margins ?? DEFAULT_TEXTBOX_MARGINS;
38
38
  containerEl.style.padding = `${margins.top}px ${margins.right}px ${margins.bottom}px ${margins.left}px`;
39
+ if (block.verticalAlign === "middle" || block.verticalAlign === "bottom") {
40
+ containerEl.style.display = "flex";
41
+ containerEl.style.flexDirection = "column";
42
+ containerEl.style.justifyContent = block.verticalAlign === "middle" ? "center" : "flex-end";
43
+ }
39
44
  containerEl.dataset["blockId"] = String(fragment.blockId);
40
45
  if (fragment.pmStart !== void 0) containerEl.dataset["pmStart"] = String(fragment.pmStart);
41
46
  if (fragment.pmEnd !== void 0) containerEl.dataset["pmEnd"] = String(fragment.pmEnd);
@@ -48,7 +53,7 @@ function renderTextBoxFragment(fragment, block, measure, context, options = {})
48
53
  if (!contentBlock || !contentMeasure || !placement) continue;
49
54
  if (contentBlock.kind === "table" && contentMeasure.kind === "table") {
50
55
  if (!options.renderTable) panic("renderTextBoxFragment: a nested table renderer is required for table content");
51
- const tableEl = options.renderTable(contentBlock, contentMeasure, context, doc);
56
+ const tableEl = options.renderTable(contentBlock, contentMeasure, context, doc, innerWidth);
52
57
  tableEl.style.marginTop = `${placement.leadingSpacing}px`;
53
58
  containerEl.append(tableEl);
54
59
  continue;
package/dist/model.d.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  import { document_d_exports } from "./types/document.js";
2
2
  import { DeriveBlockIdInput, FolioBlockId, deriveBlockId, getFolioParaIdFromBlockId, getSequentialFolioBlockIdIndex, isFolioBlockId, isSequentialFolioBlockId } from "./types/block-id.js";
3
- import { BORDER_STYLE_VALUES, CONDITIONAL_STYLE_TYPE_VALUES, EMPHASIS_MARK_VALUES, FIELD_TYPE_VALUES, FLOATING_TABLE_X_SPEC_VALUES, FLOATING_TABLE_Y_SPEC_VALUES, FONT_HINT_VALUES, FONT_THEME_VALUES, FRAME_WRAP_VALUES, FRAME_X_ALIGN_VALUES, FRAME_Y_ALIGN_VALUES, HIGHLIGHT_COLOR_VALUES, IMAGE_HORIZONTAL_ALIGNMENT_VALUES, IMAGE_HORIZONTAL_RELATIVE_TO_VALUES, IMAGE_VERTICAL_ALIGNMENT_VALUES, IMAGE_VERTICAL_RELATIVE_TO_VALUES, IMAGE_WRAP_TEXT_VALUES, IMAGE_WRAP_TYPE_VALUES, LEVEL_SUFFIX_VALUES, LINE_SPACING_RULE_VALUES, NUMBER_FORMAT_VALUES, OUTLINE_STYLE_ATTR_VALUES, OUTLINE_STYLE_CSS_ALIASES, OUTLINE_STYLE_CSS_ALIAS_VALUES, OutlineStyleAttr, OutlineStyleCssAlias, PARAGRAPH_ALIGNMENT_VALUES, POSITIONAL_TAB_ALIGNMENT_VALUES, POSITIONAL_TAB_LEADER_VALUES, POSITIONAL_TAB_RELATIVE_TO_VALUES, SDT_LOCK_VALUES, SDT_TYPE_VALUES, SHADING_PATTERN_VALUES, SHAPE_OUTLINE_STYLE_VALUES, SHAPE_TYPE_VALUES, STYLE_TYPE_VALUES, TABLE_CELL_TEXT_DIRECTION_VALUES, TABLE_CELL_VERTICAL_ALIGNMENT_VALUES, TABLE_JUSTIFICATION_VALUES, TABLE_ROW_HEIGHT_RULE_VALUES, TABLE_WIDTH_TYPE_VALUES, TAB_LEADER_VALUES, TAB_STOP_ALIGNMENT_VALUES, TEXT_EFFECT_VALUES, THEME_COLOR_SLOT_VALUES, UNDERLINE_STYLE_VALUES } from "./types/documentEnumValues.js";
3
+ import { BORDER_STYLE_VALUES, CONDITIONAL_STYLE_TYPE_VALUES, EMPHASIS_MARK_VALUES, FIELD_TYPE_VALUES, FLOATING_TABLE_X_SPEC_VALUES, FLOATING_TABLE_Y_SPEC_VALUES, FONT_HINT_VALUES, FONT_THEME_VALUES, FRAME_WRAP_VALUES, FRAME_X_ALIGN_VALUES, FRAME_Y_ALIGN_VALUES, HIGHLIGHT_COLOR_VALUES, IMAGE_HORIZONTAL_ALIGNMENT_VALUES, IMAGE_HORIZONTAL_RELATIVE_TO_VALUES, IMAGE_VERTICAL_ALIGNMENT_VALUES, IMAGE_VERTICAL_RELATIVE_TO_VALUES, IMAGE_WRAP_TEXT_VALUES, IMAGE_WRAP_TYPE_VALUES, LEVEL_SUFFIX_VALUES, LINE_SPACING_RULE_VALUES, NUMBER_FORMAT_VALUES, OUTLINE_STYLE_ATTR_VALUES, OUTLINE_STYLE_CSS_ALIASES, OUTLINE_STYLE_CSS_ALIAS_VALUES, OutlineStyleAttr, OutlineStyleCssAlias, PARAGRAPH_ALIGNMENT_VALUES, POSITIONAL_TAB_ALIGNMENT_VALUES, POSITIONAL_TAB_LEADER_VALUES, POSITIONAL_TAB_RELATIVE_TO_VALUES, SDT_LOCK_VALUES, SDT_TYPE_VALUES, SHADING_PATTERN_VALUES, SHAPE_OUTLINE_STYLE_VALUES, SHAPE_TEXT_ANCHOR_VALUES, SHAPE_TYPE_VALUES, STYLE_TYPE_VALUES, TABLE_CELL_TEXT_DIRECTION_VALUES, TABLE_CELL_VERTICAL_ALIGNMENT_VALUES, TABLE_JUSTIFICATION_VALUES, TABLE_ROW_HEIGHT_RULE_VALUES, TABLE_WIDTH_TYPE_VALUES, TAB_LEADER_VALUES, TAB_STOP_ALIGNMENT_VALUES, TEXT_EFFECT_VALUES, THEME_COLOR_SLOT_VALUES, UNDERLINE_STYLE_VALUES, normalizeShapeTextAnchor } from "./types/documentEnumValues.js";
4
4
  import { types_d_exports } from "./layout-engine/types.js";
5
5
  import { measureTypes_d_exports } from "./layout-engine/measure/measureTypes.js";
6
6
  export * from "@stll/docx-core/model";
7
7
  declare namespace model_d_exports {
8
- export { BORDER_STYLE_VALUES, CONDITIONAL_STYLE_TYPE_VALUES, DeriveBlockIdInput, EMPHASIS_MARK_VALUES, FIELD_TYPE_VALUES, FLOATING_TABLE_X_SPEC_VALUES, FLOATING_TABLE_Y_SPEC_VALUES, FONT_HINT_VALUES, FONT_THEME_VALUES, FRAME_WRAP_VALUES, FRAME_X_ALIGN_VALUES, FRAME_Y_ALIGN_VALUES, FolioBlockId, HIGHLIGHT_COLOR_VALUES, IMAGE_HORIZONTAL_ALIGNMENT_VALUES, IMAGE_HORIZONTAL_RELATIVE_TO_VALUES, IMAGE_VERTICAL_ALIGNMENT_VALUES, IMAGE_VERTICAL_RELATIVE_TO_VALUES, IMAGE_WRAP_TEXT_VALUES, IMAGE_WRAP_TYPE_VALUES, LEVEL_SUFFIX_VALUES, LINE_SPACING_RULE_VALUES, types_d_exports as Layout, measureTypes_d_exports as Measure, NUMBER_FORMAT_VALUES, OUTLINE_STYLE_ATTR_VALUES, OUTLINE_STYLE_CSS_ALIASES, OUTLINE_STYLE_CSS_ALIAS_VALUES, OutlineStyleAttr, OutlineStyleCssAlias, PARAGRAPH_ALIGNMENT_VALUES, POSITIONAL_TAB_ALIGNMENT_VALUES, POSITIONAL_TAB_LEADER_VALUES, POSITIONAL_TAB_RELATIVE_TO_VALUES, SDT_LOCK_VALUES, SDT_TYPE_VALUES, SHADING_PATTERN_VALUES, SHAPE_OUTLINE_STYLE_VALUES, SHAPE_TYPE_VALUES, STYLE_TYPE_VALUES, TABLE_CELL_TEXT_DIRECTION_VALUES, TABLE_CELL_VERTICAL_ALIGNMENT_VALUES, TABLE_JUSTIFICATION_VALUES, TABLE_ROW_HEIGHT_RULE_VALUES, TABLE_WIDTH_TYPE_VALUES, TAB_LEADER_VALUES, TAB_STOP_ALIGNMENT_VALUES, TEXT_EFFECT_VALUES, THEME_COLOR_SLOT_VALUES, UNDERLINE_STYLE_VALUES, deriveBlockId, getFolioParaIdFromBlockId, getSequentialFolioBlockIdIndex, isFolioBlockId, isSequentialFolioBlockId };
8
+ export { BORDER_STYLE_VALUES, CONDITIONAL_STYLE_TYPE_VALUES, DeriveBlockIdInput, EMPHASIS_MARK_VALUES, FIELD_TYPE_VALUES, FLOATING_TABLE_X_SPEC_VALUES, FLOATING_TABLE_Y_SPEC_VALUES, FONT_HINT_VALUES, FONT_THEME_VALUES, FRAME_WRAP_VALUES, FRAME_X_ALIGN_VALUES, FRAME_Y_ALIGN_VALUES, FolioBlockId, HIGHLIGHT_COLOR_VALUES, IMAGE_HORIZONTAL_ALIGNMENT_VALUES, IMAGE_HORIZONTAL_RELATIVE_TO_VALUES, IMAGE_VERTICAL_ALIGNMENT_VALUES, IMAGE_VERTICAL_RELATIVE_TO_VALUES, IMAGE_WRAP_TEXT_VALUES, IMAGE_WRAP_TYPE_VALUES, LEVEL_SUFFIX_VALUES, LINE_SPACING_RULE_VALUES, types_d_exports as Layout, measureTypes_d_exports as Measure, NUMBER_FORMAT_VALUES, OUTLINE_STYLE_ATTR_VALUES, OUTLINE_STYLE_CSS_ALIASES, OUTLINE_STYLE_CSS_ALIAS_VALUES, OutlineStyleAttr, OutlineStyleCssAlias, PARAGRAPH_ALIGNMENT_VALUES, POSITIONAL_TAB_ALIGNMENT_VALUES, POSITIONAL_TAB_LEADER_VALUES, POSITIONAL_TAB_RELATIVE_TO_VALUES, SDT_LOCK_VALUES, SDT_TYPE_VALUES, SHADING_PATTERN_VALUES, SHAPE_OUTLINE_STYLE_VALUES, SHAPE_TEXT_ANCHOR_VALUES, SHAPE_TYPE_VALUES, STYLE_TYPE_VALUES, TABLE_CELL_TEXT_DIRECTION_VALUES, TABLE_CELL_VERTICAL_ALIGNMENT_VALUES, TABLE_JUSTIFICATION_VALUES, TABLE_ROW_HEIGHT_RULE_VALUES, TABLE_WIDTH_TYPE_VALUES, TAB_LEADER_VALUES, TAB_STOP_ALIGNMENT_VALUES, TEXT_EFFECT_VALUES, THEME_COLOR_SLOT_VALUES, UNDERLINE_STYLE_VALUES, deriveBlockId, getFolioParaIdFromBlockId, getSequentialFolioBlockIdIndex, isFolioBlockId, isSequentialFolioBlockId, normalizeShapeTextAnchor };
9
9
  }
10
10
  //#endregion
11
- export { BORDER_STYLE_VALUES, CONDITIONAL_STYLE_TYPE_VALUES, DeriveBlockIdInput, EMPHASIS_MARK_VALUES, FIELD_TYPE_VALUES, FLOATING_TABLE_X_SPEC_VALUES, FLOATING_TABLE_Y_SPEC_VALUES, FONT_HINT_VALUES, FONT_THEME_VALUES, FRAME_WRAP_VALUES, FRAME_X_ALIGN_VALUES, FRAME_Y_ALIGN_VALUES, FolioBlockId, HIGHLIGHT_COLOR_VALUES, IMAGE_HORIZONTAL_ALIGNMENT_VALUES, IMAGE_HORIZONTAL_RELATIVE_TO_VALUES, IMAGE_VERTICAL_ALIGNMENT_VALUES, IMAGE_VERTICAL_RELATIVE_TO_VALUES, IMAGE_WRAP_TEXT_VALUES, IMAGE_WRAP_TYPE_VALUES, LEVEL_SUFFIX_VALUES, LINE_SPACING_RULE_VALUES, types_d_exports as Layout, type measureTypes_d_exports as Measure, NUMBER_FORMAT_VALUES, OUTLINE_STYLE_ATTR_VALUES, OUTLINE_STYLE_CSS_ALIASES, OUTLINE_STYLE_CSS_ALIAS_VALUES, OutlineStyleAttr, OutlineStyleCssAlias, PARAGRAPH_ALIGNMENT_VALUES, POSITIONAL_TAB_ALIGNMENT_VALUES, POSITIONAL_TAB_LEADER_VALUES, POSITIONAL_TAB_RELATIVE_TO_VALUES, SDT_LOCK_VALUES, SDT_TYPE_VALUES, SHADING_PATTERN_VALUES, SHAPE_OUTLINE_STYLE_VALUES, SHAPE_TYPE_VALUES, STYLE_TYPE_VALUES, TABLE_CELL_TEXT_DIRECTION_VALUES, TABLE_CELL_VERTICAL_ALIGNMENT_VALUES, TABLE_JUSTIFICATION_VALUES, TABLE_ROW_HEIGHT_RULE_VALUES, TABLE_WIDTH_TYPE_VALUES, TAB_LEADER_VALUES, TAB_STOP_ALIGNMENT_VALUES, TEXT_EFFECT_VALUES, THEME_COLOR_SLOT_VALUES, UNDERLINE_STYLE_VALUES, deriveBlockId, getFolioParaIdFromBlockId, getSequentialFolioBlockIdIndex, isFolioBlockId, isSequentialFolioBlockId };
11
+ export { BORDER_STYLE_VALUES, CONDITIONAL_STYLE_TYPE_VALUES, DeriveBlockIdInput, EMPHASIS_MARK_VALUES, FIELD_TYPE_VALUES, FLOATING_TABLE_X_SPEC_VALUES, FLOATING_TABLE_Y_SPEC_VALUES, FONT_HINT_VALUES, FONT_THEME_VALUES, FRAME_WRAP_VALUES, FRAME_X_ALIGN_VALUES, FRAME_Y_ALIGN_VALUES, FolioBlockId, HIGHLIGHT_COLOR_VALUES, IMAGE_HORIZONTAL_ALIGNMENT_VALUES, IMAGE_HORIZONTAL_RELATIVE_TO_VALUES, IMAGE_VERTICAL_ALIGNMENT_VALUES, IMAGE_VERTICAL_RELATIVE_TO_VALUES, IMAGE_WRAP_TEXT_VALUES, IMAGE_WRAP_TYPE_VALUES, LEVEL_SUFFIX_VALUES, LINE_SPACING_RULE_VALUES, types_d_exports as Layout, type measureTypes_d_exports as Measure, NUMBER_FORMAT_VALUES, OUTLINE_STYLE_ATTR_VALUES, OUTLINE_STYLE_CSS_ALIASES, OUTLINE_STYLE_CSS_ALIAS_VALUES, OutlineStyleAttr, OutlineStyleCssAlias, PARAGRAPH_ALIGNMENT_VALUES, POSITIONAL_TAB_ALIGNMENT_VALUES, POSITIONAL_TAB_LEADER_VALUES, POSITIONAL_TAB_RELATIVE_TO_VALUES, SDT_LOCK_VALUES, SDT_TYPE_VALUES, SHADING_PATTERN_VALUES, SHAPE_OUTLINE_STYLE_VALUES, SHAPE_TEXT_ANCHOR_VALUES, SHAPE_TYPE_VALUES, STYLE_TYPE_VALUES, TABLE_CELL_TEXT_DIRECTION_VALUES, TABLE_CELL_VERTICAL_ALIGNMENT_VALUES, TABLE_JUSTIFICATION_VALUES, TABLE_ROW_HEIGHT_RULE_VALUES, TABLE_WIDTH_TYPE_VALUES, TAB_LEADER_VALUES, TAB_STOP_ALIGNMENT_VALUES, TEXT_EFFECT_VALUES, THEME_COLOR_SLOT_VALUES, UNDERLINE_STYLE_VALUES, deriveBlockId, getFolioParaIdFromBlockId, getSequentialFolioBlockIdIndex, isFolioBlockId, isSequentialFolioBlockId, normalizeShapeTextAnchor };
package/dist/model.js CHANGED
@@ -1,4 +1,4 @@
1
1
  import { types_exports } from "./layout-engine/types.js";
2
2
  import { deriveBlockId, getFolioParaIdFromBlockId, getSequentialFolioBlockIdIndex, isFolioBlockId, isSequentialFolioBlockId } from "./types/block-id.js";
3
- import { BORDER_STYLE_VALUES, CONDITIONAL_STYLE_TYPE_VALUES, EMPHASIS_MARK_VALUES, FIELD_TYPE_VALUES, FLOATING_TABLE_X_SPEC_VALUES, FLOATING_TABLE_Y_SPEC_VALUES, FONT_HINT_VALUES, FONT_THEME_VALUES, FRAME_WRAP_VALUES, FRAME_X_ALIGN_VALUES, FRAME_Y_ALIGN_VALUES, HIGHLIGHT_COLOR_VALUES, IMAGE_HORIZONTAL_ALIGNMENT_VALUES, IMAGE_HORIZONTAL_RELATIVE_TO_VALUES, IMAGE_VERTICAL_ALIGNMENT_VALUES, IMAGE_VERTICAL_RELATIVE_TO_VALUES, IMAGE_WRAP_TEXT_VALUES, IMAGE_WRAP_TYPE_VALUES, LEVEL_SUFFIX_VALUES, LINE_SPACING_RULE_VALUES, NUMBER_FORMAT_VALUES, OUTLINE_STYLE_ATTR_VALUES, OUTLINE_STYLE_CSS_ALIASES, OUTLINE_STYLE_CSS_ALIAS_VALUES, PARAGRAPH_ALIGNMENT_VALUES, POSITIONAL_TAB_ALIGNMENT_VALUES, POSITIONAL_TAB_LEADER_VALUES, POSITIONAL_TAB_RELATIVE_TO_VALUES, SDT_LOCK_VALUES, SDT_TYPE_VALUES, SHADING_PATTERN_VALUES, SHAPE_OUTLINE_STYLE_VALUES, SHAPE_TYPE_VALUES, STYLE_TYPE_VALUES, TABLE_CELL_TEXT_DIRECTION_VALUES, TABLE_CELL_VERTICAL_ALIGNMENT_VALUES, TABLE_JUSTIFICATION_VALUES, TABLE_ROW_HEIGHT_RULE_VALUES, TABLE_WIDTH_TYPE_VALUES, TAB_LEADER_VALUES, TAB_STOP_ALIGNMENT_VALUES, TEXT_EFFECT_VALUES, THEME_COLOR_SLOT_VALUES, UNDERLINE_STYLE_VALUES } from "./types/documentEnumValues.js";
4
- export { BORDER_STYLE_VALUES, CONDITIONAL_STYLE_TYPE_VALUES, EMPHASIS_MARK_VALUES, FIELD_TYPE_VALUES, FLOATING_TABLE_X_SPEC_VALUES, FLOATING_TABLE_Y_SPEC_VALUES, FONT_HINT_VALUES, FONT_THEME_VALUES, FRAME_WRAP_VALUES, FRAME_X_ALIGN_VALUES, FRAME_Y_ALIGN_VALUES, HIGHLIGHT_COLOR_VALUES, IMAGE_HORIZONTAL_ALIGNMENT_VALUES, IMAGE_HORIZONTAL_RELATIVE_TO_VALUES, IMAGE_VERTICAL_ALIGNMENT_VALUES, IMAGE_VERTICAL_RELATIVE_TO_VALUES, IMAGE_WRAP_TEXT_VALUES, IMAGE_WRAP_TYPE_VALUES, LEVEL_SUFFIX_VALUES, LINE_SPACING_RULE_VALUES, types_exports as Layout, NUMBER_FORMAT_VALUES, OUTLINE_STYLE_ATTR_VALUES, OUTLINE_STYLE_CSS_ALIASES, OUTLINE_STYLE_CSS_ALIAS_VALUES, PARAGRAPH_ALIGNMENT_VALUES, POSITIONAL_TAB_ALIGNMENT_VALUES, POSITIONAL_TAB_LEADER_VALUES, POSITIONAL_TAB_RELATIVE_TO_VALUES, SDT_LOCK_VALUES, SDT_TYPE_VALUES, SHADING_PATTERN_VALUES, SHAPE_OUTLINE_STYLE_VALUES, SHAPE_TYPE_VALUES, STYLE_TYPE_VALUES, TABLE_CELL_TEXT_DIRECTION_VALUES, TABLE_CELL_VERTICAL_ALIGNMENT_VALUES, TABLE_JUSTIFICATION_VALUES, TABLE_ROW_HEIGHT_RULE_VALUES, TABLE_WIDTH_TYPE_VALUES, TAB_LEADER_VALUES, TAB_STOP_ALIGNMENT_VALUES, TEXT_EFFECT_VALUES, THEME_COLOR_SLOT_VALUES, UNDERLINE_STYLE_VALUES, deriveBlockId, getFolioParaIdFromBlockId, getSequentialFolioBlockIdIndex, isFolioBlockId, isSequentialFolioBlockId };
3
+ import { BORDER_STYLE_VALUES, CONDITIONAL_STYLE_TYPE_VALUES, EMPHASIS_MARK_VALUES, FIELD_TYPE_VALUES, FLOATING_TABLE_X_SPEC_VALUES, FLOATING_TABLE_Y_SPEC_VALUES, FONT_HINT_VALUES, FONT_THEME_VALUES, FRAME_WRAP_VALUES, FRAME_X_ALIGN_VALUES, FRAME_Y_ALIGN_VALUES, HIGHLIGHT_COLOR_VALUES, IMAGE_HORIZONTAL_ALIGNMENT_VALUES, IMAGE_HORIZONTAL_RELATIVE_TO_VALUES, IMAGE_VERTICAL_ALIGNMENT_VALUES, IMAGE_VERTICAL_RELATIVE_TO_VALUES, IMAGE_WRAP_TEXT_VALUES, IMAGE_WRAP_TYPE_VALUES, LEVEL_SUFFIX_VALUES, LINE_SPACING_RULE_VALUES, NUMBER_FORMAT_VALUES, OUTLINE_STYLE_ATTR_VALUES, OUTLINE_STYLE_CSS_ALIASES, OUTLINE_STYLE_CSS_ALIAS_VALUES, PARAGRAPH_ALIGNMENT_VALUES, POSITIONAL_TAB_ALIGNMENT_VALUES, POSITIONAL_TAB_LEADER_VALUES, POSITIONAL_TAB_RELATIVE_TO_VALUES, SDT_LOCK_VALUES, SDT_TYPE_VALUES, SHADING_PATTERN_VALUES, SHAPE_OUTLINE_STYLE_VALUES, SHAPE_TEXT_ANCHOR_VALUES, SHAPE_TYPE_VALUES, STYLE_TYPE_VALUES, TABLE_CELL_TEXT_DIRECTION_VALUES, TABLE_CELL_VERTICAL_ALIGNMENT_VALUES, TABLE_JUSTIFICATION_VALUES, TABLE_ROW_HEIGHT_RULE_VALUES, TABLE_WIDTH_TYPE_VALUES, TAB_LEADER_VALUES, TAB_STOP_ALIGNMENT_VALUES, TEXT_EFFECT_VALUES, THEME_COLOR_SLOT_VALUES, UNDERLINE_STYLE_VALUES, normalizeShapeTextAnchor } from "./types/documentEnumValues.js";
4
+ export { BORDER_STYLE_VALUES, CONDITIONAL_STYLE_TYPE_VALUES, EMPHASIS_MARK_VALUES, FIELD_TYPE_VALUES, FLOATING_TABLE_X_SPEC_VALUES, FLOATING_TABLE_Y_SPEC_VALUES, FONT_HINT_VALUES, FONT_THEME_VALUES, FRAME_WRAP_VALUES, FRAME_X_ALIGN_VALUES, FRAME_Y_ALIGN_VALUES, HIGHLIGHT_COLOR_VALUES, IMAGE_HORIZONTAL_ALIGNMENT_VALUES, IMAGE_HORIZONTAL_RELATIVE_TO_VALUES, IMAGE_VERTICAL_ALIGNMENT_VALUES, IMAGE_VERTICAL_RELATIVE_TO_VALUES, IMAGE_WRAP_TEXT_VALUES, IMAGE_WRAP_TYPE_VALUES, LEVEL_SUFFIX_VALUES, LINE_SPACING_RULE_VALUES, types_exports as Layout, NUMBER_FORMAT_VALUES, OUTLINE_STYLE_ATTR_VALUES, OUTLINE_STYLE_CSS_ALIASES, OUTLINE_STYLE_CSS_ALIAS_VALUES, PARAGRAPH_ALIGNMENT_VALUES, POSITIONAL_TAB_ALIGNMENT_VALUES, POSITIONAL_TAB_LEADER_VALUES, POSITIONAL_TAB_RELATIVE_TO_VALUES, SDT_LOCK_VALUES, SDT_TYPE_VALUES, SHADING_PATTERN_VALUES, SHAPE_OUTLINE_STYLE_VALUES, SHAPE_TEXT_ANCHOR_VALUES, SHAPE_TYPE_VALUES, STYLE_TYPE_VALUES, TABLE_CELL_TEXT_DIRECTION_VALUES, TABLE_CELL_VERTICAL_ALIGNMENT_VALUES, TABLE_JUSTIFICATION_VALUES, TABLE_ROW_HEIGHT_RULE_VALUES, TABLE_WIDTH_TYPE_VALUES, TAB_LEADER_VALUES, TAB_STOP_ALIGNMENT_VALUES, TEXT_EFFECT_VALUES, THEME_COLOR_SLOT_VALUES, UNDERLINE_STYLE_VALUES, deriveBlockId, getFolioParaIdFromBlockId, getSequentialFolioBlockIdIndex, isFolioBlockId, isSequentialFolioBlockId, normalizeShapeTextAnchor };
@@ -6,14 +6,28 @@ type ComputePerBlockMeasureInput = {
6
6
  bodyConfig: SectionLayoutConfig;
7
7
  finalConfig: SectionLayoutConfig;
8
8
  };
9
+ type PerBlockPhysicalPageGeometry = {
10
+ pageHeights: number[];
11
+ pageWidths: number[];
12
+ marginTops: number[];
13
+ marginLefts: number[];
14
+ marginRights: number[];
15
+ marginBottoms: number[];
16
+ };
9
17
  type PerBlockMeasureInputs = {
10
18
  widths: number[];
19
+ /** Authored section top, retained for section-relative text-box semantics. */
11
20
  marginTops: number[];
12
21
  pageHeights: number[];
13
22
  pageWidths: number[];
14
23
  marginLefts: number[];
15
24
  marginRights: number[];
16
25
  marginBottoms: number[];
26
+ /** Absolute page X of the active column's content origin. */
27
+ contentLefts: number[];
28
+ columnIndices: number[];
29
+ columnCounts: number[];
30
+ physicalPageGeometry: PerBlockPhysicalPageGeometry;
17
31
  };
18
32
  /**
19
33
  * Compute per-block measurement widths by scanning for section breaks.
@@ -1,5 +1,18 @@
1
1
  import { collectSectionConfigs } from "../layout-engine/index.js";
2
+ import { hasPageBreakBefore } from "../layout-engine/keep-together.js";
3
+ import { calculateColumnLefts, calculateColumnWidths } from "../layout-engine/paginator.js";
4
+ import { normalizeSectionBreakType } from "../layout-engine/section-breaks.js";
2
5
  //#region src/paged-layout/sectionBlockWidths.ts
6
+ function resolvePreBlockPageTransition(block, config) {
7
+ if (!hasPageBreakBefore(block)) return { type: "none" };
8
+ return {
9
+ type: "physicalPage",
10
+ geometry: {
11
+ pageSize: config.pageSize,
12
+ margins: config.margins
13
+ }
14
+ };
15
+ }
3
16
  const SINGLE_COLUMN_LAYOUT = {
4
17
  count: 1,
5
18
  gap: 0
@@ -20,40 +33,105 @@ function computePerBlockWidths({ blocks, bodyConfig, finalConfig }) {
20
33
  }).widths;
21
34
  }
22
35
  function computePerBlockMeasureInputs({ blocks, bodyConfig, finalConfig }) {
23
- function colWidth(cw, cols, columnIndex) {
24
- if (cols.count <= 1) return cw;
25
- const authoredWidth = cols.widths?.[columnIndex];
26
- if (authoredWidth !== void 0) return authoredWidth;
27
- return Math.floor((cw - (cols.count - 1) * cols.gap) / cols.count);
28
- }
29
- function contentWidth(config) {
30
- return config.pageSize.w - config.margins.left - config.margins.right;
31
- }
32
36
  const { configs: sectionConfigs, breakIndices } = collectSectionConfigs(blocks, bodyConfig, finalConfig);
33
37
  let sectionIdx = 0;
34
38
  let columnIndex = 0;
39
+ let measuredSectionIdx = -1;
40
+ let activeColumns = SINGLE_COLUMN_LAYOUT;
41
+ let activeColumnWidths = [];
42
+ let activeContentLefts = [];
43
+ let columnGeometryDirty = true;
35
44
  const widths = [];
36
45
  const marginTops = [];
46
+ const physicalMarginTops = [];
37
47
  const pageHeights = [];
38
48
  const pageWidths = [];
39
49
  const marginLefts = [];
40
50
  const marginRights = [];
41
51
  const marginBottoms = [];
52
+ const physicalPageHeights = [];
53
+ const physicalPageWidths = [];
54
+ const physicalMarginLefts = [];
55
+ const physicalMarginRights = [];
56
+ const physicalMarginBottoms = [];
57
+ const contentLefts = [];
58
+ const columnIndices = [];
59
+ const columnCounts = [];
60
+ const initialConfig = sectionConfigs[0] ?? finalConfig;
61
+ let physicalPageGeometry = {
62
+ pageSize: initialConfig.pageSize,
63
+ margins: initialConfig.margins
64
+ };
65
+ let hasPhysicalPageContent = false;
42
66
  for (let i = 0; i < blocks.length; i++) {
43
67
  const config = sectionConfigs[sectionIdx] ?? finalConfig;
44
- const columns = config.columns ?? SINGLE_COLUMN_LAYOUT;
45
- widths.push(colWidth(contentWidth(config), columns, columnIndex));
68
+ const block = blocks[i];
69
+ const preBlockTransition = resolvePreBlockPageTransition(block, config);
70
+ switch (preBlockTransition.type) {
71
+ case "physicalPage":
72
+ physicalPageGeometry = preBlockTransition.geometry;
73
+ hasPhysicalPageContent = false;
74
+ columnGeometryDirty = true;
75
+ columnIndex = 0;
76
+ break;
77
+ case "none": break;
78
+ default:
79
+ }
80
+ if (measuredSectionIdx !== sectionIdx || columnGeometryDirty) {
81
+ activeColumns = config.columns ?? SINGLE_COLUMN_LAYOUT;
82
+ activeColumnWidths = calculateColumnWidths(physicalPageGeometry.pageSize.w, physicalPageGeometry.margins.left, physicalPageGeometry.margins.right, activeColumns);
83
+ activeContentLefts = calculateColumnLefts(physicalPageGeometry.margins.left, activeColumnWidths, activeColumns);
84
+ measuredSectionIdx = sectionIdx;
85
+ columnGeometryDirty = false;
86
+ }
87
+ widths.push(activeColumnWidths[columnIndex] ?? activeColumnWidths[0] ?? 0);
88
+ contentLefts.push(activeContentLefts[columnIndex] ?? physicalPageGeometry.margins.left);
89
+ columnIndices.push(columnIndex);
90
+ columnCounts.push(activeColumns.count);
46
91
  marginTops.push(config.margins.top);
92
+ physicalMarginTops.push(physicalPageGeometry.margins.top);
47
93
  pageHeights.push(config.pageSize.h);
48
94
  pageWidths.push(config.pageSize.w);
49
95
  marginLefts.push(config.margins.left);
50
96
  marginRights.push(config.margins.right);
51
97
  marginBottoms.push(config.margins.bottom);
98
+ physicalPageHeights.push(physicalPageGeometry.pageSize.h);
99
+ physicalPageWidths.push(physicalPageGeometry.pageSize.w);
100
+ physicalMarginLefts.push(physicalPageGeometry.margins.left);
101
+ physicalMarginRights.push(physicalPageGeometry.margins.right);
102
+ physicalMarginBottoms.push(physicalPageGeometry.margins.bottom);
52
103
  if (sectionIdx < breakIndices.length && i === breakIndices[sectionIdx]) {
104
+ const sectionBreak = block;
105
+ const nextConfig = sectionConfigs[sectionIdx + 1] ?? finalConfig;
106
+ if (!(sectionBreak?.kind === "sectionBreak" && normalizeSectionBreakType(sectionBreak.type) === "continuous" && hasPhysicalPageContent && Math.round(nextConfig.pageSize.w) === Math.round(physicalPageGeometry.pageSize.w) && Math.round(nextConfig.pageSize.h) === Math.round(physicalPageGeometry.pageSize.h))) {
107
+ physicalPageGeometry = {
108
+ pageSize: nextConfig.pageSize,
109
+ margins: nextConfig.margins
110
+ };
111
+ hasPhysicalPageContent = false;
112
+ }
113
+ columnGeometryDirty = true;
53
114
  sectionIdx++;
54
115
  columnIndex = 0;
55
- } else if (blocks[i]?.kind === "pageBreak") columnIndex = 0;
56
- else if (blocks[i]?.kind === "columnBreak") columnIndex = (columnIndex + 1) % columns.count;
116
+ } else if (block.kind === "pageBreak") {
117
+ physicalPageGeometry = {
118
+ pageSize: config.pageSize,
119
+ margins: config.margins
120
+ };
121
+ hasPhysicalPageContent = false;
122
+ columnGeometryDirty = true;
123
+ columnIndex = 0;
124
+ } else if (block.kind === "columnBreak") {
125
+ if (columnIndex + 1 >= activeColumns.count) {
126
+ physicalPageGeometry = {
127
+ pageSize: config.pageSize,
128
+ margins: config.margins
129
+ };
130
+ hasPhysicalPageContent = false;
131
+ columnGeometryDirty = true;
132
+ }
133
+ columnIndex = (columnIndex + 1) % activeColumns.count;
134
+ } else hasPhysicalPageContent = true;
57
135
  }
58
136
  return {
59
137
  widths,
@@ -62,7 +140,18 @@ function computePerBlockMeasureInputs({ blocks, bodyConfig, finalConfig }) {
62
140
  pageWidths,
63
141
  marginLefts,
64
142
  marginRights,
65
- marginBottoms
143
+ marginBottoms,
144
+ contentLefts,
145
+ columnIndices,
146
+ columnCounts,
147
+ physicalPageGeometry: {
148
+ pageHeights: physicalPageHeights,
149
+ pageWidths: physicalPageWidths,
150
+ marginTops: physicalMarginTops,
151
+ marginLefts: physicalMarginLefts,
152
+ marginRights: physicalMarginRights,
153
+ marginBottoms: physicalMarginBottoms
154
+ }
66
155
  };
67
156
  }
68
157
  //#endregion
@@ -1,4 +1,5 @@
1
1
  import { EMPHASIS_MARK_VALUES, FIELD_TYPE_VALUES, FONT_HINT_VALUES, FONT_THEME_VALUES, HIGHLIGHT_COLOR_VALUES, IMAGE_HORIZONTAL_ALIGNMENT_VALUES, IMAGE_HORIZONTAL_RELATIVE_TO_VALUES, IMAGE_VERTICAL_ALIGNMENT_VALUES, IMAGE_VERTICAL_RELATIVE_TO_VALUES, IMAGE_WRAP_TEXT_VALUES, IMAGE_WRAP_TYPE_VALUES, LINE_SPACING_RULE_VALUES, NUMBER_FORMAT_VALUES, OUTLINE_STYLE_ATTR_VALUES, PARAGRAPH_ALIGNMENT_VALUES, POSITIONAL_TAB_ALIGNMENT_VALUES, POSITIONAL_TAB_LEADER_VALUES, POSITIONAL_TAB_RELATIVE_TO_VALUES, SDT_LOCK_VALUES, SDT_TYPE_VALUES, SHADING_PATTERN_VALUES, TABLE_CELL_TEXT_DIRECTION_VALUES, TABLE_CELL_VERTICAL_ALIGNMENT_VALUES, TABLE_JUSTIFICATION_VALUES, TABLE_ROW_HEIGHT_RULE_VALUES, TABLE_WIDTH_TYPE_VALUES, TAB_LEADER_VALUES, TAB_STOP_ALIGNMENT_VALUES, TEXT_EFFECT_VALUES, THEME_COLOR_SLOT_VALUES, UNDERLINE_STYLE_VALUES } from "../../types/documentEnumValues.js";
2
+ import { normalizeHorizontalScalePercent } from "../../utils/horizontalScale.js";
2
3
  import { isParagraphDirection } from "../paragraphDirection.js";
3
4
  import { TRACKED_CHANGE_PROVENANCE_VALUES } from "../schema/marks.js";
4
5
  import { panic } from "better-result";
@@ -276,6 +277,7 @@ const readTableAttrs = (node) => {
276
277
  "insideH",
277
278
  "insideV"
278
279
  ]);
280
+ optionalOneOf(attrs, "_resolvedJustification", "table.attrs._resolvedJustification", issues, TABLE_JUSTIFICATION_VALUES);
279
281
  optionalBoolean(attrs, "_resolvedBidi", "table.attrs._resolvedBidi", issues);
280
282
  optionalRecord(attrs, "_originalFormatting", "table.attrs._originalFormatting", issues);
281
283
  return attrsResult(attrs, issues);
@@ -289,6 +291,7 @@ const readTableRowAttrs = (node) => {
289
291
  optionalOneOf(attrs, "heightRule", "tableRow.attrs.heightRule", issues, TABLE_ROW_HEIGHT_RULE_VALUES);
290
292
  optionalBoolean(attrs, "isHeader", "tableRow.attrs.isHeader", issues);
291
293
  optionalBoolean(attrs, "hidden", "tableRow.attrs.hidden", issues);
294
+ optionalOneOf(attrs, "_resolvedJustification", "tableRow.attrs._resolvedJustification", issues, TABLE_JUSTIFICATION_VALUES);
292
295
  optionalRecord(attrs, "_originalFormatting", "tableRow.attrs._originalFormatting", issues);
293
296
  optionalTableRowRevision(attrs, "trIns", issues);
294
297
  optionalTableRowRevision(attrs, "trDel", issues);
@@ -595,7 +598,15 @@ const readCharacterSpacingMarkAttrs = (mark) => {
595
598
  optionalNumber(attrs, "position", "characterSpacing.attrs.position", issues);
596
599
  optionalNumber(attrs, "scale", "characterSpacing.attrs.scale", issues);
597
600
  optionalNumber(attrs, "kerning", "characterSpacing.attrs.kerning", issues);
598
- return attrsResult(attrs, issues);
601
+ const result = attrsResult(attrs, issues);
602
+ if (!result.ok) return result;
603
+ const { scale, ...rest } = result.value;
604
+ const horizontalScale = normalizeHorizontalScalePercent(scale);
605
+ result.value = {
606
+ ...rest,
607
+ ...horizontalScale !== void 0 ? { scale: horizontalScale } : {}
608
+ };
609
+ return result;
599
610
  };
600
611
  const expectCharacterSpacingMarkAttrs = (mark) => expectCachedMarkAttrs(mark, characterSpacingAttrsCache, readCharacterSpacingMarkAttrs, "character spacing attrs");
601
612
  const readEmphasisMarkAttrs = (mark) => {
@@ -1,6 +1,7 @@
1
1
  import { numPrEqual } from "../../docx/numberingParser.js";
2
2
  import { ShapeOutlineStyleSchema, narrowEnum } from "../../docx/parserEnums.js";
3
- import { OUTLINE_STYLE_CSS_ALIASES } from "../../types/documentEnumValues.js";
3
+ import { OUTLINE_STYLE_CSS_ALIASES, normalizeShapeTextAnchor } from "../../types/documentEnumValues.js";
4
+ import { normalizeHorizontalScalePercent } from "../../utils/horizontalScale.js";
4
5
  import { pixelsToEmu } from "../../utils/units.js";
5
6
  import { expectBlockSdtAttrs, expectCharacterSpacingMarkAttrs, expectCharacterStyleMarkAttrs, expectCommentMarkAttrs, expectEmphasisMarkAttrs, expectFieldAttrs, expectFontFamilyMarkAttrs, expectFontSizeMarkAttrs, expectFootnoteRefMarkAttrs, expectHardBreakAttrs, expectHighlightMarkAttrs, expectHyperlinkMarkAttrs, expectImageAttrs, expectLanguageMarkAttrs, expectMathAttrs, expectParagraphAttrs, expectRunFormattingOverrideMarkAttrs, expectRunPropertyChangeMarkAttrs, expectRunShadingMarkAttrs, expectSdtAttrs, expectShapeAttrs, expectStrikeMarkAttrs, expectSymbolAttrs, expectTabAttrs, expectTableAttrs, expectTableCellAttrs, expectTableRowAttrs, expectTextBoxAttrs, expectTextColorMarkAttrs, expectTextEffectMarkAttrs, expectTrackedChangeMarkAttrs, expectUnderlineMarkAttrs } from "../attrs/index.js";
6
7
  import { autospacingMatchesBase, hasAutospacingBaseSide } from "../autospacingBase.js";
@@ -1573,7 +1574,8 @@ function marksToTextFormatting(marks, options) {
1573
1574
  const attrs = expectCharacterSpacingMarkAttrs(mark);
1574
1575
  if (attrs.spacing !== void 0) formatting.spacing = attrs.spacing;
1575
1576
  if (attrs.position !== void 0) formatting.position = attrs.position;
1576
- if (attrs.scale !== void 0) formatting.scale = attrs.scale;
1577
+ const horizontalScale = normalizeHorizontalScalePercent(attrs.scale);
1578
+ if (horizontalScale !== void 0) formatting.scale = horizontalScale;
1577
1579
  if (attrs.kerning !== void 0) formatting.kerning = attrs.kerning;
1578
1580
  break;
1579
1581
  }
@@ -2014,6 +2016,7 @@ function tableCellAttrsToFormatting(attrs) {
2014
2016
  */
2015
2017
  function convertPMTextBox(node) {
2016
2018
  const attrs = expectTextBoxAttrs(node);
2019
+ const verticalAlign = normalizeShapeTextAnchor(attrs.verticalAlign);
2017
2020
  const childBlocks = [];
2018
2021
  node.forEach((child) => {
2019
2022
  if (child.type.name === "paragraph") childBlocks.push(convertPMParagraph(child));
@@ -2033,6 +2036,7 @@ function convertPMTextBox(node) {
2033
2036
  }],
2034
2037
  ...attrs.autoFit !== void 0 ? { autoFit: attrs.autoFit } : {},
2035
2038
  ...attrs.textWrap !== void 0 ? { textWrap: attrs.textWrap } : {},
2039
+ ...verticalAlign !== void 0 ? { anchor: verticalAlign } : {},
2036
2040
  margins: (() => {
2037
2041
  const m = {};
2038
2042
  if (typeof attrs.marginTop === "number") m.top = pixelsToEmu(attrs.marginTop);
@@ -1,5 +1,6 @@
1
1
  import { resolveColorValueToHex } from "../../docx/drawingUtils.js";
2
2
  import { createStyleEngine } from "../../style-engine/styleEngine.js";
3
+ import { normalizeHorizontalScalePercent } from "../../utils/horizontalScale.js";
3
4
  import { mergeParagraphFormatting, mergeParagraphTabStops } from "../../utils/paragraphFormattingMerge.js";
4
5
  import { tableOfContentsStyleLevel } from "../../utils/tableOfContentsStyle.js";
5
6
  import { mergeTextFormatting } from "../../utils/textFormattingMerge.js";
@@ -802,6 +803,7 @@ function convertTable(table, styleResolver, context) {
802
803
  const resolvedTableBorders = table.formatting?.borders ?? tableStyle?.tblPr?.borders ?? fallbackTableStyle?.tblPr?.borders;
803
804
  const fallbackTableIndent = fallbackTableStyle?.tblPr?.indent;
804
805
  const resolvedTableIndent = table.formatting?.indent ?? tableStyle?.tblPr?.indent ?? (fallbackTableIndent?.value === 0 ? void 0 : fallbackTableIndent);
806
+ const resolvedTableJustification = tableStyle?.tblPr?.justification ?? fallbackTableStyle?.tblPr?.justification;
805
807
  const resolvedTableBidi = table.formatting?.bidi ?? tableStyle?.tblPr?.bidi ?? fallbackTableStyle?.tblPr?.bidi;
806
808
  const tableCellMargins = table.formatting?.cellMargins ?? tableStyle?.tblPr?.cellMargins ?? fallbackTableStyle?.tblPr?.cellMargins;
807
809
  let cellMarginsAttr;
@@ -824,6 +826,7 @@ function convertTable(table, styleResolver, context) {
824
826
  if (table.formatting?.look) attrs.look = table.formatting.look;
825
827
  if (table.formatting?.borders) attrs.borders = table.formatting.borders;
826
828
  if (resolvedTableIndent) attrs._resolvedIndent = resolvedTableIndent;
829
+ if (resolvedTableJustification) attrs._resolvedJustification = resolvedTableJustification;
827
830
  if (resolvedTableBidi !== void 0) attrs._resolvedBidi = resolvedTableBidi;
828
831
  if (table.formatting) attrs._originalFormatting = table.formatting;
829
832
  if (table.propertyChanges && table.propertyChanges.length > 0) attrs.tblPrChange = [...table.propertyChanges];
@@ -863,7 +866,8 @@ function convertTable(table, styleResolver, context) {
863
866
  })();
864
867
  })();
865
868
  if (bandingEnabledH && !isFirstRowStyled && !isLastRow) dataRowIndex++;
866
- return convertTableRow(row, styleResolver, context, isFirstRowStyled, columnWidths, totalWidth, conditionalStyles, rowBandStyle, bandingEnabledV, look, resolvedTableBorders, rowIndex, totalRows, totalColumns, rowSpanMap, cellMarginsAttr);
869
+ const resolvedRowJustification = tableStyle?.trPr?.justification ?? fallbackTableStyle?.trPr?.justification;
870
+ return convertTableRow(row, styleResolver, context, isFirstRowStyled, columnWidths, totalWidth, conditionalStyles, rowBandStyle, bandingEnabledV, look, resolvedTableBorders, rowIndex, totalRows, totalColumns, rowSpanMap, cellMarginsAttr, resolvedRowJustification);
867
871
  });
868
872
  return schema.node("table", attrs, rows);
869
873
  }
@@ -880,11 +884,12 @@ function countTableColumns(rows) {
880
884
  /**
881
885
  * Convert a TableRow to a ProseMirror table row node
882
886
  */
883
- function convertTableRow(row, styleResolver, context, isHeaderRow, columnWidths, totalWidth, conditionalStyles, rowBandStyle, bandingEnabledV, tableLook, tableBorders, rowIndex, totalRows, totalColumns, rowSpanMap, defaultCellMargins) {
887
+ function convertTableRow(row, styleResolver, context, isHeaderRow, columnWidths, totalWidth, conditionalStyles, rowBandStyle, bandingEnabledV, tableLook, tableBorders, rowIndex, totalRows, totalColumns, rowSpanMap, defaultCellMargins, resolvedJustification) {
884
888
  const attrsWithoutStructuralChange = { isHeader: !!row.formatting?.header };
885
889
  if (row.formatting?.height?.value !== void 0) attrsWithoutStructuralChange.height = row.formatting.height.value;
886
890
  if (row.formatting?.heightRule) attrsWithoutStructuralChange.heightRule = row.formatting.heightRule;
887
891
  if (row.formatting?.hidden) attrsWithoutStructuralChange.hidden = true;
892
+ if (resolvedJustification) attrsWithoutStructuralChange._resolvedJustification = resolvedJustification;
888
893
  if (row.formatting) attrsWithoutStructuralChange._originalFormatting = row.formatting;
889
894
  if (row.propertyChanges && row.propertyChanges.length > 0) attrsWithoutStructuralChange.trPrChange = [...row.propertyChanges];
890
895
  let attrs = attrsWithoutStructuralChange;
@@ -1493,7 +1498,7 @@ function textFormattingToMarks(formatting, options) {
1493
1498
  if (formatting.smallCaps) marks.push(schema.mark("smallCaps"));
1494
1499
  const spacing = typeof formatting.spacing === "number" ? formatting.spacing : null;
1495
1500
  const position = typeof formatting.position === "number" ? formatting.position : null;
1496
- const scale = typeof formatting.scale === "number" ? formatting.scale : null;
1501
+ const scale = normalizeHorizontalScalePercent(formatting.scale) ?? null;
1497
1502
  const kerning = typeof formatting.kerning === "number" ? formatting.kerning : null;
1498
1503
  if (spacing !== null || position !== null || scale !== null || kerning !== null) marks.push(schema.mark("characterSpacing", {
1499
1504
  spacing,
@@ -1764,6 +1769,7 @@ function textBoxFromShape(shape, textBody) {
1764
1769
  if (textBody.margins) textBox.margins = textBody.margins;
1765
1770
  if (textBody.autoFit) textBox.autoFit = textBody.autoFit;
1766
1771
  if (textBody.textWrap) textBox.textWrap = textBody.textWrap;
1772
+ if (textBody.anchor) textBox.verticalAlign = textBody.anchor;
1767
1773
  return textBox;
1768
1774
  }
1769
1775
  /**
@@ -1839,6 +1845,7 @@ function convertTextBox(textBox, styleResolver, options) {
1839
1845
  height: heightPx,
1840
1846
  autoFit: textBox.autoFit,
1841
1847
  textWrap: textBox.textWrap,
1848
+ verticalAlign: textBox.verticalAlign,
1842
1849
  textBoxId: textBox.id,
1843
1850
  fillColor,
1844
1851
  outlineWidth,
@@ -1,3 +1,4 @@
1
+ import { getHorizontalScaleFactor, normalizeHorizontalScalePercent, parseHorizontalScalePercent } from "../../../utils/horizontalScale.js";
1
2
  import { formatPx, twipsToPixels } from "../../../utils/units.js";
2
3
  import { expectCharacterSpacingMarkAttrs } from "../../attrs/index.js";
3
4
  import { createMarkExtension } from "../create.js";
@@ -28,12 +29,13 @@ const CharacterSpacingExtension = createMarkExtension({
28
29
  getAttrs: (dom) => ({
29
30
  spacing: dom.dataset["spacing"] ? Number(dom.dataset["spacing"]) : null,
30
31
  position: dom.dataset["position"] ? Number(dom.dataset["position"]) : null,
31
- scale: dom.dataset["scale"] ? Number(dom.dataset["scale"]) : null,
32
+ scale: parseHorizontalScalePercent(dom.dataset["scale"]),
32
33
  kerning: dom.dataset["kerning"] ? Number(dom.dataset["kerning"]) : null
33
34
  })
34
35
  }],
35
36
  toDOM(mark) {
36
- const { spacing, position, scale, kerning } = expectCharacterSpacingMarkAttrs(mark);
37
+ const { spacing, position, scale: authoredScale, kerning } = expectCharacterSpacingMarkAttrs(mark);
38
+ const scale = normalizeHorizontalScalePercent(authoredScale);
37
39
  const styles = [];
38
40
  const dataAttrs = { class: "docx-char-spacing" };
39
41
  if (spacing !== void 0 && spacing !== 0) {
@@ -45,10 +47,12 @@ const CharacterSpacingExtension = createMarkExtension({
45
47
  styles.push(`vertical-align: ${formatPx(px)}`);
46
48
  dataAttrs["data-position"] = String(position);
47
49
  }
48
- if (scale !== void 0 && scale !== 100) {
49
- styles.push(`transform: scaleX(${scale / 100})`);
50
- styles.push("display: inline-block");
50
+ if (scale !== void 0) {
51
51
  dataAttrs["data-scale"] = String(scale);
52
+ if (scale !== 100) {
53
+ styles.push(`transform: scaleX(${getHorizontalScaleFactor(scale)})`);
54
+ styles.push("display: inline-block");
55
+ }
52
56
  }
53
57
  if (kerning !== void 0) dataAttrs["data-kerning"] = String(kerning);
54
58
  if (styles.length > 0) dataAttrs["style"] = styles.join("; ");
@@ -154,6 +154,7 @@ const tableSpec = {
154
154
  look: { default: null },
155
155
  borders: { default: null },
156
156
  _resolvedIndent: { default: null },
157
+ _resolvedJustification: { default: null },
157
158
  _resolvedBidi: { default: null },
158
159
  _originalFormatting: { default: null },
159
160
  tblPrChange: { default: null },
@@ -200,6 +201,7 @@ const tableRowSpec = {
200
201
  heightRule: { default: null },
201
202
  isHeader: { default: false },
202
203
  hidden: { default: false },
204
+ _resolvedJustification: { default: null },
203
205
  _originalFormatting: { default: null },
204
206
  trPrChange: { default: null },
205
207
  trIns: { default: null },
@@ -1,4 +1,4 @@
1
- import { IMAGE_WRAP_TYPE_VALUES } from "../../../types/documentEnumValues.js";
1
+ import { IMAGE_WRAP_TYPE_VALUES, normalizeShapeTextAnchor } from "../../../types/documentEnumValues.js";
2
2
  import { expectTextBoxAttrs } from "../../attrs/index.js";
3
3
  import { createNodeExtension } from "../create.js";
4
4
  //#region src/prosemirror/extensions/nodes/TextBoxExtension.ts
@@ -21,6 +21,9 @@ function parseTextBoxAutoFit(raw) {
21
21
  function parseTextBoxTextWrap(raw) {
22
22
  if (raw === "none" || raw === "square") return raw;
23
23
  }
24
+ function parseTextBoxVerticalAlign(raw) {
25
+ return normalizeShapeTextAnchor(raw);
26
+ }
24
27
  const TextBoxExtension = createNodeExtension({
25
28
  name: "textBox",
26
29
  schemaNodeName: "textBox",
@@ -68,6 +71,7 @@ const TextBoxExtension = createNodeExtension({
68
71
  const wrapType = parseTextBoxWrapType(d["wrapType"]);
69
72
  const autoFit = parseTextBoxAutoFit(d["autoFit"]);
70
73
  const textWrap = parseTextBoxTextWrap(d["textWrap"]);
74
+ const verticalAlign = parseTextBoxVerticalAlign(d["verticalAlign"]);
71
75
  return {
72
76
  ...d["width"] ? { width: Number(d["width"]) } : {},
73
77
  ...d["height"] ? { height: Number(d["height"]) } : {},
@@ -82,7 +86,7 @@ const TextBoxExtension = createNodeExtension({
82
86
  ...d["marginBottom"] ? { marginBottom: Number(d["marginBottom"]) } : {},
83
87
  ...d["marginLeft"] ? { marginLeft: Number(d["marginLeft"]) } : {},
84
88
  ...d["marginRight"] ? { marginRight: Number(d["marginRight"]) } : {},
85
- ...d["verticalAlign"] ? { verticalAlign: d["verticalAlign"] } : {},
89
+ ...verticalAlign ? { verticalAlign } : {},
86
90
  ...d["displayMode"] ? { displayMode: d["displayMode"] } : {},
87
91
  ...d["cssFloat"] ? { cssFloat: d["cssFloat"] } : {},
88
92
  ...wrapType ? { wrapType } : {},
@@ -571,6 +571,8 @@ type TableAttrs = {
571
571
  borders?: document_d_exports.TableBorders;
572
572
  /** Effective table indent after style resolution. PM-only; never serialized. */
573
573
  _resolvedIndent?: NonNullable<document_d_exports.TableFormatting["indent"]>;
574
+ /** Style-derived table justification fallback. PM-only; never serialized. */
575
+ _resolvedJustification?: NonNullable<document_d_exports.TableFormatting["justification"]>;
574
576
  /** Effective table direction after style resolution. PM-only; never serialized. */
575
577
  _resolvedBidi?: boolean;
576
578
  /** Original table formatting from DOCX for lossless round-trip serialization */
@@ -596,6 +598,8 @@ type TableRowAttrs = {
596
598
  isHeader?: boolean;
597
599
  /** Whether the row is hidden (`w:hidden`) */
598
600
  hidden?: boolean;
601
+ /** Style-derived row justification fallback. PM-only; never serialized. */
602
+ _resolvedJustification?: NonNullable<document_d_exports.TableRowFormatting["justification"]>;
599
603
  /** Original row formatting from DOCX for lossless round-trip serialization */
600
604
  _originalFormatting?: document_d_exports.TableRowFormatting;
601
605
  /** Tracked row property changes (w:trPrChange) for round-trip + accept/reject */