@stll/folio-core 0.8.0 → 0.9.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 (152) hide show
  1. package/README.md +39 -0
  2. package/dist/ai-edits/apply.js +18 -4
  3. package/dist/ai-edits/headless.d.ts +31 -4
  4. package/dist/ai-edits/headless.js +148 -35
  5. package/dist/ai-edits/index.d.ts +3 -3
  6. package/dist/ai-edits/index.js +2 -1
  7. package/dist/ai-edits/snapshot.js +40 -3
  8. package/dist/ai-edits/types.d.ts +2 -1
  9. package/dist/compat/eigenpal.d.ts +6 -4
  10. package/dist/compat/eigenpal.js +5 -3
  11. package/dist/controller/latestRequestGate.d.ts +13 -0
  12. package/dist/controller/latestRequestGate.js +16 -0
  13. package/dist/controller/layoutPipeline.js +12 -1
  14. package/dist/document-operations.d.ts +10 -3
  15. package/dist/document-operations.js +29 -14
  16. package/dist/docx/blockContentParser.js +2 -2
  17. package/dist/docx/commentParser.js +1 -1
  18. package/dist/docx/compatibility.d.ts +3 -7
  19. package/dist/docx/compatibility.js +0 -11
  20. package/dist/docx/encryption/agileDecryption.js +1 -1
  21. package/dist/docx/encryption/encryptionInfo.js +1 -1
  22. package/dist/docx/encryption/openEncryptedDocx.js +1 -1
  23. package/dist/docx/fontTableParser.d.ts +6 -0
  24. package/dist/docx/fontTableParser.js +72 -0
  25. package/dist/docx/groupDrawingParser.js +7 -2
  26. package/dist/docx/headerFooterParser.js +1 -1
  27. package/dist/docx/normalizeBaseDirection.js +1 -1
  28. package/dist/docx/numberingParser.js +1 -0
  29. package/dist/docx/paragraphParser.js +12 -1
  30. package/dist/docx/parser.d.ts +1 -1
  31. package/dist/docx/parser.js +12 -9
  32. package/dist/docx/rezip.js +70 -5
  33. package/dist/docx/runConsolidator.js +4 -0
  34. package/dist/docx/runParser.js +19 -1
  35. package/dist/docx/selectiveSave.js +3 -3
  36. package/dist/docx/serializer/fontTableSerializer.d.ts +6 -0
  37. package/dist/docx/serializer/fontTableSerializer.js +26 -0
  38. package/dist/docx/serializer/headerFooterSerializer.js +1 -1
  39. package/dist/docx/serializer/paragraphSerializer.js +4 -0
  40. package/dist/docx/serializer/runSerializer.js +7 -0
  41. package/dist/docx/serializer/settingsSerializer.d.ts +6 -0
  42. package/dist/docx/serializer/settingsSerializer.js +16 -0
  43. package/dist/docx/serializer/stylesSerializer.d.ts +6 -0
  44. package/dist/docx/serializer/stylesSerializer.js +56 -0
  45. package/dist/docx/serializer/tableSerializer.js +25 -26
  46. package/dist/docx/serializer/themeSerializer.d.ts +6 -0
  47. package/dist/docx/serializer/themeSerializer.js +36 -0
  48. package/dist/docx/settingsParser.js +46 -0
  49. package/dist/docx/styleParser.js +26 -1
  50. package/dist/docx/tableParser.js +11 -1
  51. package/dist/docx/vmlImageParser.js +1 -0
  52. package/dist/i18n/messages/catalogs.gen.d.ts +5916 -5916
  53. package/dist/i18n/messages/catalogs.gen.js +5910 -5910
  54. package/dist/index.d.ts +6 -4
  55. package/dist/index.js +5 -3
  56. package/dist/layout-bridge/convert/footnoteLayout.d.ts +3 -0
  57. package/dist/layout-bridge/convert/footnoteLayout.js +3 -1
  58. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +3 -0
  59. package/dist/layout-bridge/convert/headerFooterLayout.js +6 -1
  60. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +14 -2
  61. package/dist/layout-bridge/convert/toFlowBlocks.js +51 -14
  62. package/dist/layout-bridge/engine/measuring/index.d.ts +2 -1
  63. package/dist/layout-bridge/engine/measuring/index.js +2 -1
  64. package/dist/layout-engine/index.js +36 -28
  65. package/dist/layout-engine/measure/cache.js +11 -3
  66. package/dist/layout-engine/measure/font-metrics.worker.js +1 -0
  67. package/dist/layout-engine/measure/index.d.ts +2 -1
  68. package/dist/layout-engine/measure/index.js +2 -1
  69. package/dist/layout-engine/measure/lineBreakProvider.d.ts +33 -0
  70. package/dist/layout-engine/measure/lineBreakProvider.js +252 -0
  71. package/dist/layout-engine/measure/lineBreaks.d.ts +7 -2
  72. package/dist/layout-engine/measure/lineBreaks.js +11 -18
  73. package/dist/layout-engine/measure/listMarkerWidth.d.ts +1 -0
  74. package/dist/layout-engine/measure/listMarkerWidth.js +12 -6
  75. package/dist/layout-engine/measure/measureBlocks.d.ts +1 -2
  76. package/dist/layout-engine/measure/measureBlocks.js +6 -36
  77. package/dist/layout-engine/measure/measureContainer.js +32 -9
  78. package/dist/layout-engine/measure/measureHelpers.js +5 -2
  79. package/dist/layout-engine/measure/measureParagraph.js +335 -72
  80. package/dist/layout-engine/measure/measureTypes.d.ts +2 -1
  81. package/dist/layout-engine/measure/measureWorker.d.ts +2 -2
  82. package/dist/layout-engine/measure/measureWorker.js +8 -19
  83. package/dist/layout-engine/measure/measureWorkerProtocol.d.ts +3 -14
  84. package/dist/layout-engine/measure/tableCellFloating.d.ts +10 -3
  85. package/dist/layout-engine/measure/tableCellFloating.js +37 -29
  86. package/dist/layout-engine/measure/tableCellFlow.d.ts +27 -0
  87. package/dist/layout-engine/measure/tableCellFlow.js +73 -0
  88. package/dist/layout-engine/measure/tableCellGrid.js +1 -1
  89. package/dist/layout-engine/measure/textMeasurementPolicy.d.ts +18 -0
  90. package/dist/layout-engine/measure/textMeasurementPolicy.js +24 -0
  91. package/dist/layout-engine/renderedBreakReconciliation.d.ts +6 -1
  92. package/dist/layout-engine/renderedBreakReconciliation.js +34 -11
  93. package/dist/layout-engine/tableRowBreak.d.ts +5 -2
  94. package/dist/layout-engine/tableRowBreak.js +62 -29
  95. package/dist/layout-engine/types.d.ts +40 -7
  96. package/dist/layout-painter/anchoredImagePosition.d.ts +23 -0
  97. package/dist/layout-painter/anchoredImagePosition.js +95 -0
  98. package/dist/layout-painter/borderStroke.d.ts +23 -0
  99. package/dist/layout-painter/borderStroke.js +39 -0
  100. package/dist/layout-painter/renderImage.d.ts +5 -4
  101. package/dist/layout-painter/renderImage.js +18 -4
  102. package/dist/layout-painter/renderPage.d.ts +2 -27
  103. package/dist/layout-painter/renderPage.js +13 -99
  104. package/dist/layout-painter/renderParagraph.js +41 -23
  105. package/dist/layout-painter/renderTable.d.ts +2 -0
  106. package/dist/layout-painter/renderTable.js +223 -43
  107. package/dist/managers/DocumentLoaderManager.d.ts +1 -1
  108. package/dist/managers/DocumentLoaderManager.js +2 -2
  109. package/dist/prosemirror/attrs/index.d.ts +4 -2
  110. package/dist/prosemirror/attrs/index.js +21 -2
  111. package/dist/prosemirror/commands/propertyChangeScope.js +1 -1
  112. package/dist/prosemirror/conversion/fromProseDoc.js +33 -18
  113. package/dist/prosemirror/conversion/toProseDoc.js +50 -18
  114. package/dist/prosemirror/extensions/StarterKit.js +2 -0
  115. package/dist/prosemirror/extensions/core/ParagraphExtension.js +7 -2
  116. package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.js +1 -1
  117. package/dist/prosemirror/extensions/features/ListExtension.js +1 -0
  118. package/dist/prosemirror/extensions/marks/FootnoteRefExtension.js +1 -0
  119. package/dist/prosemirror/extensions/marks/HighlightExtension.js +1 -1
  120. package/dist/prosemirror/extensions/marks/LanguageExtension.d.ts +7 -0
  121. package/dist/prosemirror/extensions/marks/LanguageExtension.js +30 -0
  122. package/dist/prosemirror/extensions/marks/RunShadingExtension.js +1 -1
  123. package/dist/prosemirror/extensions/marks/TextColorExtension.js +1 -1
  124. package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +1 -1
  125. package/dist/prosemirror/extensions/marks/markUtils.js +12 -0
  126. package/dist/prosemirror/extensions/nodes/ImageExtension.js +2 -1
  127. package/dist/prosemirror/extensions/nodes/TableExtension.js +4 -2
  128. package/dist/prosemirror/schema/index.d.ts +2 -2
  129. package/dist/prosemirror/schema/marks.d.ts +6 -1
  130. package/dist/prosemirror/schema/nodes.d.ts +13 -11
  131. package/dist/prosemirror/styles/resolvedStyleAttrs.js +1 -0
  132. package/dist/prosemirror/utils/tabCalculator.d.ts +3 -1
  133. package/dist/prosemirror/utils/tabCalculator.js +12 -10
  134. package/dist/prosemirror/validation.js +4 -1
  135. package/dist/redline.js +13 -3
  136. package/dist/server.d.ts +6 -3
  137. package/dist/server.js +5 -2
  138. package/dist/style-sets/extract.d.ts +35 -0
  139. package/dist/style-sets/extract.js +123 -0
  140. package/dist/style-sets/stellaStyle.d.ts +13 -0
  141. package/dist/style-sets/stellaStyle.js +516 -0
  142. package/dist/style-sets/types.d.ts +31 -0
  143. package/dist/style-sets/types.js +5 -0
  144. package/dist/utils/createDocument.d.ts +12 -2
  145. package/dist/utils/createDocument.js +42 -31
  146. package/dist/utils/fontResolver.js +6 -6
  147. package/dist/utils/formatToStyle.js +1 -1
  148. package/dist/utils/paragraphFormattingMerge.d.ts +14 -3
  149. package/dist/utils/paragraphFormattingMerge.js +14 -4
  150. package/package.json +5 -1
  151. package/dist/docx/capabilities.d.ts +0 -41
  152. package/dist/docx/capabilities.js +0 -322
@@ -1,12 +1,13 @@
1
1
  import { eighthsToPixels, pointsToPixels } from "../utils/units.js";
2
2
  import { resolveFontFamily } from "../utils/fontResolver.js";
3
+ import { borderToStyle } from "../utils/formatToStyle.js";
3
4
  import { floatingTextBoxReservesBand, floatingTextBoxWrapsText, isFloatingImageRun, isFloatingTextBoxBlock, isTextWrappingFloatingImageRun } from "../layout-engine/types.js";
4
5
  import { rectsToFloatingZones } from "../layout-engine/measure/floatingZones.js";
5
6
  import { measureParagraph } from "../layout-engine/measure/measureParagraph.js";
6
- import { borderToStyle } from "../utils/formatToStyle.js";
7
+ import { emuToPixels } from "./renderUtils.js";
8
+ import { resolveAnchoredImagePosition as resolveAnchoredImagePosition$1 } from "./anchoredImagePosition.js";
7
9
  import { renderFragment } from "./renderFragment.js";
8
10
  import { applyImageVisualAttrs, hasImageVisualAttrs, renderImageFragment } from "./renderImage.js";
9
- import { emuToPixels } from "./renderUtils.js";
10
11
  import { renderParagraphFragment } from "./renderParagraph.js";
11
12
  import { renderTextBoxFragment } from "./renderTextBox.js";
12
13
  import { renderTableFragment } from "./renderTable.js";
@@ -33,6 +34,7 @@ const PAGE_CLASS_NAMES = {
33
34
  header: "layout-page-header",
34
35
  footer: "layout-page-footer"
35
36
  };
37
+ const HEADER_FOOTER_RULE_CLIP_MARGIN = pointsToPixels(1.5);
36
38
  const getDefaultPageFontFamily = () => resolveFontFamily("Calibri").cssFallback;
37
39
  /**
38
40
  * Apply page styles to an element
@@ -271,57 +273,6 @@ function applyFragmentStyles(element, fragment, margins) {
271
273
  element.style.width = `${fragment.width}px`;
272
274
  if ("height" in fragment) element.style.height = `${fragment.height}px`;
273
275
  }
274
- function resolveHorizontalBand(relativeTo, geometry) {
275
- switch (relativeTo) {
276
- case "page": return {
277
- baseX: -geometry.marginLeft,
278
- bandWidth: geometry.pageWidth
279
- };
280
- case "leftMargin":
281
- case "insideMargin": return {
282
- baseX: -geometry.marginLeft,
283
- bandWidth: geometry.marginLeft
284
- };
285
- case "rightMargin":
286
- case "outsideMargin": return {
287
- baseX: geometry.contentWidth,
288
- bandWidth: geometry.marginRight
289
- };
290
- case "character": return {
291
- baseX: 0,
292
- bandWidth: 0
293
- };
294
- default: return {
295
- baseX: 0,
296
- bandWidth: geometry.contentWidth
297
- };
298
- }
299
- }
300
- function resolveVerticalBand(relativeTo, fragmentY, geometry) {
301
- switch (relativeTo) {
302
- case "page": return {
303
- baseY: -geometry.marginTop,
304
- bandHeight: geometry.pageHeight
305
- };
306
- case "topMargin": return {
307
- baseY: -geometry.marginTop,
308
- bandHeight: geometry.marginTop
309
- };
310
- case "bottomMargin": return {
311
- baseY: geometry.contentHeight,
312
- bandHeight: geometry.marginBottom
313
- };
314
- case "paragraph":
315
- case "line": return {
316
- baseY: fragmentY,
317
- bandHeight: 0
318
- };
319
- default: return {
320
- baseY: 0,
321
- bandHeight: geometry.contentHeight
322
- };
323
- }
324
- }
325
276
  /**
326
277
  * Resolve the on-page coordinates of an anchored floating image.
327
278
  *
@@ -337,47 +288,7 @@ function resolveVerticalBand(relativeTo, fragmentY, geometry) {
337
288
  * picked by `relativeFrom`.
338
289
  */
339
290
  function resolveAnchoredImagePosition(imgRun, fragmentY, geometry) {
340
- const position = imgRun.position;
341
- const contentWidth = geometry.contentWidth;
342
- let side = "left";
343
- let x = 0;
344
- if (position?.horizontal) {
345
- const h = position.horizontal;
346
- const { baseX, bandWidth } = resolveHorizontalBand(h.relativeTo, geometry);
347
- const horizontalHasBand = h.relativeTo !== "character";
348
- if (h.align === "right" || h.align === "outside") {
349
- side = "right";
350
- x = horizontalHasBand ? baseX + bandWidth - imgRun.width : 0;
351
- } else if (h.align === "left" || h.align === "inside") {
352
- side = "left";
353
- x = baseX;
354
- } else if (h.align === "center") {
355
- side = "left";
356
- x = horizontalHasBand ? baseX + (bandWidth - imgRun.width) / 2 : 0;
357
- } else if (h.posOffset !== void 0) {
358
- x = baseX + emuToPixels(h.posOffset);
359
- side = x > contentWidth / 2 ? "right" : "left";
360
- } else x = baseX;
361
- } else if (imgRun.cssFloat === "right") {
362
- side = "right";
363
- x = contentWidth - imgRun.width;
364
- }
365
- let y;
366
- if (position?.vertical) {
367
- const v = position.vertical;
368
- const { baseY, bandHeight } = resolveVerticalBand(v.relativeTo, fragmentY, geometry);
369
- const verticalHasBand = v.relativeTo !== "paragraph" && v.relativeTo !== "line";
370
- if (v.align === "top" || v.align === "inside") y = baseY;
371
- else if (v.align === "center") y = verticalHasBand ? baseY + (bandHeight - imgRun.height) / 2 : fragmentY;
372
- else if (v.align === "bottom" || v.align === "outside") y = verticalHasBand ? baseY + bandHeight - imgRun.height : fragmentY;
373
- else if (v.posOffset !== void 0) y = baseY + emuToPixels(v.posOffset);
374
- else y = verticalHasBand ? baseY : fragmentY;
375
- } else y = fragmentY;
376
- return {
377
- x,
378
- y,
379
- side
380
- };
291
+ return resolveAnchoredImagePosition$1(imgRun, fragmentY, geometry);
381
292
  }
382
293
  /**
383
294
  * Extract floating images from a paragraph block and determine their page-level positions.
@@ -1011,7 +922,10 @@ function renderPage(page, context, options = {}) {
1011
922
  });
1012
923
  prevParagraphBorders = paragraphBlock.attrs?.borders;
1013
924
  } else if (fragment.kind === "table" && blockData?.block.kind === "table" && blockData.measure.kind === "table") {
1014
- fragmentEl = renderTableFragment(fragment, blockData.block, blockData.measure, fragmentContext, { document: doc });
925
+ fragmentEl = renderTableFragment(fragment, blockData.block, blockData.measure, fragmentContext, {
926
+ document: doc,
927
+ pageGeometry
928
+ });
1015
929
  prevParagraphBorders = void 0;
1016
930
  } else if (fragment.kind === "image" && blockData?.block.kind === "image" && blockData.measure.kind === "image") {
1017
931
  fragmentEl = renderImageFragment(fragment, blockData.block, blockData.measure, fragmentContext, { document: doc });
@@ -1086,7 +1000,6 @@ function renderPage(page, context, options = {}) {
1086
1000
  headerEl.style.width = `${headerContentWidth}px`;
1087
1001
  headerEl.style.height = `${interactiveHeaderHeight}px`;
1088
1002
  headerEl.style.minHeight = `${interactiveHeaderHeight}px`;
1089
- headerEl.style.opacity = "0.62";
1090
1003
  let shouldClipHeader = !headerOverflows && headerContentFitsBox;
1091
1004
  if (options.headerContent && options.headerContent.blocks.length > 0) {
1092
1005
  const headerContentEl = renderHeaderFooterContent(options.headerContent, {
@@ -1107,7 +1020,8 @@ function renderPage(page, context, options = {}) {
1107
1020
  }
1108
1021
  if (shouldClipHeader) {
1109
1022
  headerEl.style.maxHeight = `${availableHeaderHeight}px`;
1110
- headerEl.style.overflow = "hidden";
1023
+ headerEl.style.overflow = "clip";
1024
+ headerEl.style.overflowClipMargin = `${HEADER_FOOTER_RULE_CLIP_MARGIN}px`;
1111
1025
  }
1112
1026
  pageEl.append(headerEl);
1113
1027
  moveBehindHeaderFooterElementsToPage(headerEl, pageEl, headerDistance, page.margins.left);
@@ -1132,7 +1046,6 @@ function renderPage(page, context, options = {}) {
1132
1046
  footerEl.style.width = `${footerContentWidth}px`;
1133
1047
  footerEl.style.height = `${interactiveFooterHeight}px`;
1134
1048
  footerEl.style.minHeight = `${interactiveFooterHeight}px`;
1135
- footerEl.style.opacity = "0.62";
1136
1049
  const footerContentFitsBox = footerVisualBottom - footerVisualTop <= interactiveFooterHeight;
1137
1050
  let shouldClipFooter = !footerOverflows && footerContentFitsBox;
1138
1051
  if (options.footerContent && options.footerContent.blocks.length > 0) {
@@ -1154,7 +1067,8 @@ function renderPage(page, context, options = {}) {
1154
1067
  }
1155
1068
  if (shouldClipFooter) {
1156
1069
  footerEl.style.maxHeight = `${availableFooterHeight}px`;
1157
- footerEl.style.overflow = "hidden";
1070
+ footerEl.style.overflow = "clip";
1071
+ footerEl.style.overflowClipMargin = `${HEADER_FOOTER_RULE_CLIP_MARGIN}px`;
1158
1072
  }
1159
1073
  pageEl.append(footerEl);
1160
1074
  moveBehindHeaderFooterElementsToPage(footerEl, pageEl, footerNaturalTop, page.margins.left);
@@ -1,19 +1,22 @@
1
1
  import { parseXmlDocument } from "../docx/xmlParser.js";
2
2
  import { resolveFontFamily } from "../utils/fontResolver.js";
3
+ import { detectBaseDirection } from "../utils/baseDirection.js";
4
+ import { AUTHOR_COLORS, getAuthorColorIdx } from "../utils/authorColors.js";
3
5
  import "../utils/fontWeights.js";
6
+ import { FONT_KERNING_MODE, countCompressibleSpaces, getFontKerningMode, getRunFontKerningMode } from "../layout-engine/measure/textMeasurementPolicy.js";
7
+ import "../layout-engine/measure/measureHelpers.js";
4
8
  import { calculateTabWidth } from "../prosemirror/utils/tabCalculator.js";
5
9
  import { inlineImageBoundingBox, parseRotationDegrees, rotatedBoundingBox } from "../utils/rotationBoundingBox.js";
6
10
  import { hasCjk, segmentByScript } from "../utils/scriptSegments.js";
7
11
  import { isFloatingImageRun } from "../layout-engine/types.js";
8
12
  import { getListMarkerInlineWidth, getListMarkerVisualOffset } from "../layout-engine/measure/listMarkerWidth.js";
13
+ import { resolveImageLineAlign } from "./renderUtils.js";
9
14
  import { applySdtDataAttrs } from "./sdtBoundary.js";
10
15
  import { applyImageVisualAttrs, hasImageVisualAttrs, wrapImageWithCrop } from "./renderImage.js";
11
16
  import { ommlToMathml } from "../docx/mathToMathml.js";
12
17
  import { evaluateFieldInstruction } from "../fields/evaluateField.js";
13
- import { AUTHOR_COLORS, getAuthorColorIdx } from "../utils/authorColors.js";
14
- import { detectBaseDirection } from "../utils/baseDirection.js";
18
+ import { borderStrokeToCss, resolveParagraphBorderHorizontalOutsets } from "./borderStroke.js";
15
19
  import { getAutomaticTextColorForBackground } from "./documentColors.js";
16
- import { resolveImageLineAlign } from "./renderUtils.js";
17
20
  //#region src/layout-painter/renderParagraph.ts
18
21
  /**
19
22
  * Paragraph Fragment Renderer
@@ -128,9 +131,7 @@ function applyRunStyles(element, run) {
128
131
  element.style.transform = `scaleX(${run.horizontalScale / 100})`;
129
132
  element.style.transformOrigin = "left center";
130
133
  }
131
- if (run.kerningMinPt && run.kerningMinPt > 0) {
132
- if ((run.fontSize ?? 11) >= run.kerningMinPt) element.style.fontKerning = "normal";
133
- }
134
+ element.style.fontKerning = getRunFontKerningMode(run, 11);
134
135
  if (run.emboss) element.style.textShadow = "1px 1px 1px rgba(255,255,255,0.5), -1px -1px 1px rgba(0,0,0,0.3)";
135
136
  if (run.imprint) element.style.textShadow = "-1px -1px 1px rgba(255,255,255,0.5), 1px 1px 1px rgba(0,0,0,0.3)";
136
137
  if (run.textShadow && !run.emboss && !run.imprint) element.style.textShadow = "1px 1px 2px rgba(0,0,0,0.3)";
@@ -785,19 +786,14 @@ const startsAfterSoftWrap = (block, line) => {
785
786
  * must trigger within this slack.
786
787
  */
787
788
  const RIGHT_EDGE_EPSILON_PX = .5;
788
- function countShrinkableSpaces(runs) {
789
+ function countShrinkableSpaces(runs, context) {
789
790
  let count = 0;
790
- for (const run of runs) if (isTextRun(run)) {
791
- for (const char of run.text ?? "") if (char === " ") count++;
792
- } else if (isFieldRun(run)) {
793
- for (const char of run.fallback ?? "") if (char === " ") count++;
794
- } else if (isMathRun(run)) {
795
- for (const char of run.plainText ?? "") if (char === " ") count++;
796
- }
791
+ for (const run of runs) if (isTextRun(run)) count += countCompressibleSpaces(run.text ?? "");
792
+ else if (isFieldRun(run)) count += countCompressibleSpaces(resolveFieldText(run, context));
797
793
  return count;
798
794
  }
799
795
  /**
800
- * Build a TextMeasureStyle from a TextRun or FieldRun's relevant fields.
796
+ * Build the shared measurement style from a paintable text run.
801
797
  */
802
798
  function runMeasureStyle(run) {
803
799
  return {
@@ -805,7 +801,8 @@ function runMeasureStyle(run) {
805
801
  ...run.italic !== void 0 ? { italic: run.italic } : {},
806
802
  ...run.letterSpacing !== void 0 ? { letterSpacing: run.letterSpacing } : {},
807
803
  ...run.smallCaps !== void 0 ? { smallCaps: run.smallCaps } : {},
808
- ...run.eastAsiaFontFamily !== void 0 ? { eastAsiaFontFamily: run.eastAsiaFontFamily } : {}
804
+ ...run.eastAsiaFontFamily !== void 0 ? { eastAsiaFontFamily: run.eastAsiaFontFamily } : {},
805
+ kerning: getRunFontKerningMode(run, 11) === FONT_KERNING_MODE.enabled
809
806
  };
810
807
  }
811
808
  /**
@@ -910,6 +907,7 @@ function createTextMeasurer(doc) {
910
907
  const ctx = doc.createElement("canvas").getContext("2d");
911
908
  return (text, fontSize = 11, fontFamily = "Calibri", style = {}) => {
912
909
  if (!ctx) return applyLetterSpacingToMeasuredWidth(text.length * 7, text, style.letterSpacing);
910
+ ctx.fontKerning = getFontKerningMode(style);
913
911
  const cssFallback = resolveFontFamily(fontFamily).cssFallback;
914
912
  const fontSizePx = fontSize * 96 / 72;
915
913
  const fontPrefixParts = [];
@@ -996,7 +994,7 @@ function renderLine(block, line, alignment, doc, options) {
996
994
  const firstLineHangingExpansionPx = hasVisibleListMarker ? Math.min(firstLineHangingPx, Math.max(0, options.leftIndentPx ?? 0)) : firstLineHangingPx;
997
995
  const justifyCapacityPx = options.availableWidth + firstLineHangingExpansionPx;
998
996
  const overfullPx = line.width - justifyCapacityPx;
999
- const shrinkableSpaces = countShrinkableSpaces(runsForLine.filter((run) => !isTextRun(run) || !isCollapsedLineEdgeSpaceRun(run)));
997
+ const shrinkableSpaces = countShrinkableSpaces(runsForLine.filter((run) => !isTextRun(run) || !isCollapsedLineEdgeSpaceRun(run)), options.context);
1000
998
  if (overfullPx > RIGHT_EDGE_EPSILON_PX && shrinkableSpaces > 0) {
1001
999
  lineEl.style.textAlign = "left";
1002
1000
  lineEl.style.textAlignLast = "auto";
@@ -1134,6 +1132,20 @@ function renderLine(block, line, alignment, doc, options) {
1134
1132
  lineEl.append(runEl);
1135
1133
  }
1136
1134
  }
1135
+ if (line.discretionaryHyphen) {
1136
+ const sourceRun = block.runs[line.discretionaryHyphen.runIndex];
1137
+ if (sourceRun && isTextRun(sourceRun)) {
1138
+ const hyphenRun = {
1139
+ ...sourceRun,
1140
+ text: "-"
1141
+ };
1142
+ Reflect.deleteProperty(hyphenRun, "pmStart");
1143
+ Reflect.deleteProperty(hyphenRun, "pmEnd");
1144
+ const hyphenEl = renderTextRun(hyphenRun, doc);
1145
+ hyphenEl.dataset["discretionaryHyphen"] = "true";
1146
+ lineEl.append(hyphenEl);
1147
+ }
1148
+ }
1137
1149
  const inFlowRuns = runsForLine.filter((run) => !(isImageRun(run) && isFloatingImageRun(run)));
1138
1150
  const blankBreakRun = inFlowRuns.length > 0 && inFlowRuns.every(isLineBreakRun) ? inFlowRuns.find(isLineBreakRun) : void 0;
1139
1151
  if (blankBreakRun?.pmStart !== void 0) {
@@ -1239,7 +1251,10 @@ function renderParagraphFragment(fragment, block, measure, context, options = {}
1239
1251
  }
1240
1252
  };
1241
1253
  fragmentEl.style.boxSizing = "border-box";
1242
- const borderToCss = (b) => `${b.width}px ${borderStyleToCss(b.style)} ${b.color}`;
1254
+ const borderToCss = (border) => borderStrokeToCss({
1255
+ ...border,
1256
+ style: borderStyleToCss(border.style)
1257
+ });
1243
1258
  const groupedWithPrev = bordersFormGroup(options.prevBorders, borders);
1244
1259
  const groupedWithNext = bordersFormGroup(borders, options.nextBorders);
1245
1260
  const renderedTopBorder = groupedWithPrev ? borders.between : borders.top;
@@ -1249,8 +1264,9 @@ function renderParagraphFragment(fragment, block, measure, context, options = {}
1249
1264
  borderBox.style.position = "absolute";
1250
1265
  borderBox.style.pointerEvents = "none";
1251
1266
  borderBox.style.boxSizing = "border-box";
1252
- borderBox.style.left = `${indentLeft - (borders.left?.space ?? 0) - (borders.left?.width ?? 0)}px`;
1253
- borderBox.style.right = `${indentRight - (borders.right?.space ?? 0) - (borders.right?.width ?? 0)}px`;
1267
+ const horizontalOutsets = resolveParagraphBorderHorizontalOutsets(borders, renderedTopBorder !== void 0 || renderedBottomBorder !== void 0);
1268
+ borderBox.style.left = `${indentLeft - horizontalOutsets.left}px`;
1269
+ borderBox.style.right = `${indentRight - horizontalOutsets.right}px`;
1254
1270
  borderBox.style.top = `${-(renderedTopBorder?.space ?? 0) - (renderedTopBorder?.width ?? 0)}px`;
1255
1271
  borderBox.style.bottom = `${-(renderedBottomBorder?.space ?? 0) - (renderedBottomBorder?.width ?? 0)}px`;
1256
1272
  if (renderedTopBorder) borderBox.style.borderTop = borderToCss(renderedTopBorder);
@@ -1342,7 +1358,7 @@ function renderParagraphFragment(fragment, block, measure, context, options = {}
1342
1358
  lineEl.style.paddingLeft = `${Math.max(0, markerStart)}px`;
1343
1359
  lineEl.style.textIndent = "0";
1344
1360
  let firstTextRun;
1345
- if (!block.attrs.listMarkerFontFamily || !block.attrs.listMarkerFontSize) for (let ri = line.fromRun; ri <= line.toRun; ri++) {
1361
+ if (!block.attrs.listMarkerFontFamily || !block.attrs.listMarkerFontSize || block.attrs.listMarkerBold === void 0) for (let ri = line.fromRun; ri <= line.toRun; ri++) {
1346
1362
  const r = block.runs[ri];
1347
1363
  if (r && r.kind === "text") {
1348
1364
  firstTextRun = r;
@@ -1351,7 +1367,8 @@ function renderParagraphFragment(fragment, block, measure, context, options = {}
1351
1367
  }
1352
1368
  const markerFontFamily = block.attrs.listMarkerFontFamily ?? firstTextRun?.fontFamily ?? block.attrs.defaultFontFamily;
1353
1369
  const markerFontSize = block.attrs.listMarkerFontSize ?? firstTextRun?.fontSize ?? block.attrs.defaultFontSize;
1354
- const marker = renderListMarker(block.attrs.listMarker, getListMarkerInlineWidth(block), getListMarkerVisualOffset(block), doc, markerFontFamily, markerFontSize, block.attrs.listMarkerRevision, block.attrs.listMarkerSecondSlotOffsetTwips);
1370
+ const markerBold = block.attrs.listMarkerBold ?? firstTextRun?.bold;
1371
+ const marker = renderListMarker(block.attrs.listMarker, getListMarkerInlineWidth(block), getListMarkerVisualOffset(block), doc, markerFontFamily, markerFontSize, markerBold, block.attrs.listMarkerRevision, block.attrs.listMarkerSecondSlotOffsetTwips);
1355
1372
  const markerMarginLeft = markerStart - Math.min(indentLeft, 0);
1356
1373
  if (markerMarginLeft < 0) marker.style.marginLeft = `${markerMarginLeft}px`;
1357
1374
  lineEl.prepend(marker);
@@ -1368,12 +1385,13 @@ function renderParagraphFragment(fragment, block, measure, context, options = {}
1368
1385
  * tab grid. Long markers like "1.1.1." therefore grow to the next stop
1369
1386
  * instead of butting against the body text.
1370
1387
  */
1371
- function renderListMarker(marker, inlineWidth, visualOffset, doc, fontFamily, fontSize, revision, secondSlotOffsetTwips) {
1388
+ function renderListMarker(marker, inlineWidth, visualOffset, doc, fontFamily, fontSize, bold, revision, secondSlotOffsetTwips) {
1372
1389
  const span = doc.createElement("span");
1373
1390
  span.className = "layout-list-marker";
1374
1391
  span.style.display = "inline-block";
1375
1392
  if (fontFamily) span.style.fontFamily = resolveFontFamily(fontFamily).cssFallback;
1376
1393
  if (fontSize) span.style.fontSize = `${fontSize * 96 / 72}px`;
1394
+ if (bold !== void 0) span.style.fontWeight = bold ? "800" : "normal";
1377
1395
  span.style.textAlign = "left";
1378
1396
  span.style.textAlignLast = "left";
1379
1397
  span.style.boxSizing = "border-box";
@@ -1,5 +1,6 @@
1
1
  import { TableBlock, TableFragment, TableMeasure } from "../layout-engine/types.js";
2
2
  import { RenderContext } from "./renderUtils.js";
3
+ import { PageGeometry } from "./anchoredImagePosition.js";
3
4
 
4
5
  //#region src/layout-painter/renderTable.d.ts
5
6
  /**
@@ -20,6 +21,7 @@ declare const TABLE_CLASS_NAMES: {
20
21
  */
21
22
  type RenderTableFragmentOptions = {
22
23
  document?: Document;
24
+ pageGeometry?: PageGeometry;
23
25
  };
24
26
  /**
25
27
  * Render a table fragment to DOM