superdoc 1.0.0-beta.15 → 1.0.0-beta.16

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 (27) hide show
  1. package/dist/chunks/{PdfViewer-DltPlBWC.cjs → PdfViewer-93eWvs8z.cjs} +1 -1
  2. package/dist/chunks/{PdfViewer-CjlHzt9e.es.js → PdfViewer-ODeuH1gb.es.js} +1 -1
  3. package/dist/chunks/{index-qg0AxQJC.es.js → index-DW5_UKLM.es.js} +3 -3
  4. package/dist/chunks/{index-Bds7gW4r-Pk_xAuWe.es.js → index-DexFffM7-Cbdy0Zy6.es.js} +1 -1
  5. package/dist/chunks/{index-Bds7gW4r-JPDW6c39.cjs → index-DexFffM7-XZD_g6eY.cjs} +1 -1
  6. package/dist/chunks/{index-BZnlco_f.cjs → index-RquHXtgI.cjs} +3 -3
  7. package/dist/chunks/{super-editor.es-CuAhqbzW.cjs → super-editor.es-BLKWkx5G.cjs} +1223 -131
  8. package/dist/chunks/{super-editor.es-CQTkj_nb.es.js → super-editor.es-Dg5uoFkw.es.js} +1223 -131
  9. package/dist/super-editor/ai-writer.es.js +2 -2
  10. package/dist/super-editor/chunks/{converter-qMoZOGGn.js → converter-C_R_BK8X.js} +1 -1
  11. package/dist/super-editor/chunks/{docx-zipper-QKiyORxV.js → docx-zipper-BvQAYmi1.js} +1 -1
  12. package/dist/super-editor/chunks/{editor-D8ZdjC2V.js → editor-DFFvalb1.js} +1224 -132
  13. package/dist/super-editor/chunks/{index-Bds7gW4r.js → index-DexFffM7.js} +1 -1
  14. package/dist/super-editor/chunks/{toolbar-Spi7vpev.js → toolbar-DLPfegtw.js} +2 -2
  15. package/dist/super-editor/converter.es.js +1 -1
  16. package/dist/super-editor/docx-zipper.es.js +2 -2
  17. package/dist/super-editor/editor.es.js +3 -3
  18. package/dist/super-editor/file-zipper.es.js +1 -1
  19. package/dist/super-editor/super-editor.es.js +6 -6
  20. package/dist/super-editor/toolbar.es.js +2 -2
  21. package/dist/super-editor.cjs +1 -1
  22. package/dist/super-editor.es.js +1 -1
  23. package/dist/superdoc.cjs +2 -2
  24. package/dist/superdoc.es.js +2 -2
  25. package/dist/superdoc.umd.js +1225 -133
  26. package/dist/superdoc.umd.js.map +1 -1
  27. package/package.json +1 -1
@@ -36249,7 +36249,7 @@ const _SuperConverter = class _SuperConverter2 {
36249
36249
  static getStoredSuperdocVersion(docx) {
36250
36250
  return _SuperConverter2.getStoredCustomProperty(docx, "SuperdocVersion");
36251
36251
  }
36252
- static setStoredSuperdocVersion(docx = this.convertedXml, version2 = "1.0.0-beta.15") {
36252
+ static setStoredSuperdocVersion(docx = this.convertedXml, version2 = "1.0.0-beta.16") {
36253
36253
  return _SuperConverter2.setStoredCustomProperty(docx, "SuperdocVersion", version2, false);
36254
36254
  }
36255
36255
  /**
@@ -52977,7 +52977,7 @@ const isHeadless = (editor) => {
52977
52977
  const shouldSkipNodeView = (editor) => {
52978
52978
  return isHeadless(editor);
52979
52979
  };
52980
- const summaryVersion = "1.0.0-beta.15";
52980
+ const summaryVersion = "1.0.0-beta.16";
52981
52981
  const nodeKeys = ["group", "content", "marks", "inline", "atom", "defining", "code", "tableRole", "summary"];
52982
52982
  const markKeys = ["group", "inclusive", "excludes", "spanning", "code"];
52983
52983
  function mapAttributes(attrs) {
@@ -53756,7 +53756,7 @@ const _Editor = class _Editor2 extends EventEmitter$1 {
53756
53756
  { default: remarkStringify },
53757
53757
  { default: remarkGfm }
53758
53758
  ] = await Promise.all([
53759
- import("./index-Bds7gW4r-Pk_xAuWe.es.js"),
53759
+ import("./index-DexFffM7-Cbdy0Zy6.es.js"),
53760
53760
  import("./index-DRCvimau-Cw339678.es.js"),
53761
53761
  import("./index-C_x_N6Uh-DJn8hIEt.es.js"),
53762
53762
  import("./index-D_sWOSiG-DE96TaT5.es.js"),
@@ -53961,7 +53961,7 @@ const _Editor = class _Editor2 extends EventEmitter$1 {
53961
53961
  * Process collaboration migrations
53962
53962
  */
53963
53963
  processCollaborationMigrations() {
53964
- console.debug("[checkVersionMigrations] Current editor version", "1.0.0-beta.15");
53964
+ console.debug("[checkVersionMigrations] Current editor version", "1.0.0-beta.16");
53965
53965
  if (!this.options.ydoc) return;
53966
53966
  const metaMap = this.options.ydoc.getMap("meta");
53967
53967
  let docVersion = metaMap.get("version");
@@ -55036,7 +55036,7 @@ const pickLang = (value) => {
55036
55036
  const normalized = value.trim().toLowerCase();
55037
55037
  return normalized || void 0;
55038
55038
  };
55039
- const normalizeColor = (value) => {
55039
+ const normalizeColor$1 = (value) => {
55040
55040
  if (typeof value !== "string") return void 0;
55041
55041
  const trimmed = value.trim();
55042
55042
  if (!trimmed || trimmed === "auto" || trimmed === "none") return void 0;
@@ -55676,14 +55676,14 @@ const resolveThemeColor = (attrs, themeColors) => {
55676
55676
  const resolveColorFromAttributes = (attrs, themeColors) => {
55677
55677
  if (!attrs) return void 0;
55678
55678
  if (typeof attrs.color === "string") {
55679
- const normalized = normalizeColor(attrs.color);
55679
+ const normalized = normalizeColor$1(attrs.color);
55680
55680
  if (normalized) {
55681
55681
  return normalized;
55682
55682
  }
55683
55683
  }
55684
55684
  const theme = resolveThemeColor(attrs, themeColors);
55685
55685
  if (theme) {
55686
- return normalizeColor(theme);
55686
+ return normalizeColor$1(theme);
55687
55687
  }
55688
55688
  return void 0;
55689
55689
  };
@@ -56118,13 +56118,8 @@ const MAX_BORDER_SIZE_PX = 100;
56118
56118
  const borderSizeToPx = (size2) => {
56119
56119
  if (!isFiniteNumber(size2)) return void 0;
56120
56120
  if (size2 <= 0) return 0;
56121
- let pixelValue;
56122
- if (size2 < EIGHTHS_PER_POINT) {
56123
- pixelValue = size2;
56124
- } else {
56125
- const points = size2 / EIGHTHS_PER_POINT;
56126
- pixelValue = points * PX_PER_PT;
56127
- }
56121
+ const points = size2 / EIGHTHS_PER_POINT;
56122
+ const pixelValue = points * PX_PER_PT;
56128
56123
  return Math.min(MAX_BORDER_SIZE_PX, Math.max(MIN_BORDER_SIZE_PX, pixelValue));
56129
56124
  };
56130
56125
  const normalizeColorWithDefault = (color) => {
@@ -56263,7 +56258,7 @@ const normalizeBorderSide = (value) => {
56263
56258
  if (style2 === "none") return void 0;
56264
56259
  const width = pickNumber(raw.size);
56265
56260
  const widthPx = borderSizeToPx(width);
56266
- const color = normalizeColor(raw.color);
56261
+ const color = normalizeColor$1(raw.color);
56267
56262
  const space = pickNumber(raw.space);
56268
56263
  if (!style2 && widthPx == null && space == null && !color) {
56269
56264
  return void 0;
@@ -56319,7 +56314,7 @@ const normalizeParagraphShading = (value) => {
56319
56314
  return Object.keys(shading).length > 0 ? shading : void 0;
56320
56315
  };
56321
56316
  const normalizeShadingColor = (value) => {
56322
- const normalized = normalizeColor(value);
56317
+ const normalized = normalizeColor$1(value);
56323
56318
  if (!normalized) return void 0;
56324
56319
  if (normalized.toLowerCase() === "#auto") {
56325
56320
  return void 0;
@@ -57482,11 +57477,11 @@ const buildMarkerLayout = ({
57482
57477
  baselineOffsetPx: markerRun.baselineShift ?? 0,
57483
57478
  gutterWidthPx: markerBoxWidthPx,
57484
57479
  justification: numbering.lvlJc ?? "left",
57485
- suffix: normalizeSuffix(numbering.suffix) ?? "tab",
57480
+ suffix: normalizeSuffix$1(numbering.suffix) ?? "tab",
57486
57481
  run: markerRun,
57487
57482
  path: numbering.path
57488
57483
  });
57489
- const normalizeSuffix = (suffix2) => {
57484
+ const normalizeSuffix$1 = (suffix2) => {
57490
57485
  if (suffix2 === "tab" || suffix2 === "space" || suffix2 === "nothing") {
57491
57486
  return suffix2;
57492
57487
  }
@@ -57940,6 +57935,154 @@ const cloneIfObject = (value) => {
57940
57935
  };
57941
57936
  const { resolveSpacingIndent } = Engines;
57942
57937
  const DEFAULT_DECIMAL_SEPARATOR$2 = ".";
57938
+ const asOoxmlElement = (value) => {
57939
+ if (!value || typeof value !== "object") return void 0;
57940
+ const element = value;
57941
+ if (element.name == null && element.attributes == null && element.elements == null) return void 0;
57942
+ return element;
57943
+ };
57944
+ const findChild = (parent, name) => {
57945
+ return parent?.elements?.find((child) => child?.name === name);
57946
+ };
57947
+ const getAttribute = (element, key2) => {
57948
+ if (!element?.attributes) return void 0;
57949
+ const attrs = element.attributes;
57950
+ return attrs[key2] ?? attrs[key2.startsWith("w:") ? key2.slice(2) : `w:${key2}`];
57951
+ };
57952
+ const parseNumberAttr = (value) => {
57953
+ if (value == null) return void 0;
57954
+ const num = typeof value === "number" ? value : Number.parseInt(String(value), 10);
57955
+ return Number.isFinite(num) ? num : void 0;
57956
+ };
57957
+ const normalizeNumFmt = (value) => {
57958
+ if (typeof value !== "string") return void 0;
57959
+ switch (value) {
57960
+ case "decimal":
57961
+ return "decimal";
57962
+ case "lowerLetter":
57963
+ return "lowerLetter";
57964
+ case "upperLetter":
57965
+ return "upperLetter";
57966
+ case "lowerRoman":
57967
+ return "lowerRoman";
57968
+ case "upperRoman":
57969
+ return "upperRoman";
57970
+ case "bullet":
57971
+ return "bullet";
57972
+ default:
57973
+ return void 0;
57974
+ }
57975
+ };
57976
+ const normalizeSuffix = (value) => {
57977
+ if (typeof value !== "string") return void 0;
57978
+ if (value === "tab" || value === "space" || value === "nothing") {
57979
+ return value;
57980
+ }
57981
+ return void 0;
57982
+ };
57983
+ const normalizeJustification = (value) => {
57984
+ if (typeof value !== "string") return void 0;
57985
+ if (value === "start") return "left";
57986
+ if (value === "end") return "right";
57987
+ if (value === "left" || value === "center" || value === "right") return value;
57988
+ return void 0;
57989
+ };
57990
+ const extractIndentFromLevel = (lvl) => {
57991
+ const pPr = findChild(lvl, "w:pPr");
57992
+ const ind = findChild(pPr, "w:ind");
57993
+ if (!ind) return void 0;
57994
+ const left2 = parseNumberAttr(getAttribute(ind, "w:left"));
57995
+ const right2 = parseNumberAttr(getAttribute(ind, "w:right"));
57996
+ const firstLine = parseNumberAttr(getAttribute(ind, "w:firstLine"));
57997
+ const hanging = parseNumberAttr(getAttribute(ind, "w:hanging"));
57998
+ const indent = {};
57999
+ if (left2 != null) indent.left = left2;
58000
+ if (right2 != null) indent.right = right2;
58001
+ if (firstLine != null) indent.firstLine = firstLine;
58002
+ if (hanging != null) indent.hanging = hanging;
58003
+ return Object.keys(indent).length ? indent : void 0;
58004
+ };
58005
+ const normalizeColor = (value) => {
58006
+ if (typeof value !== "string") return void 0;
58007
+ const trimmed = value.trim();
58008
+ if (!trimmed || trimmed.toLowerCase() === "auto") return void 0;
58009
+ const upper = trimmed.startsWith("#") ? trimmed.slice(1) : trimmed;
58010
+ return `#${upper.toUpperCase()}`;
58011
+ };
58012
+ const extractMarkerRun = (lvl) => {
58013
+ const rPr = findChild(lvl, "w:rPr");
58014
+ if (!rPr) return void 0;
58015
+ const run2 = {};
58016
+ const rFonts = findChild(rPr, "w:rFonts");
58017
+ const font = getAttribute(rFonts, "w:ascii") ?? getAttribute(rFonts, "w:hAnsi") ?? getAttribute(rFonts, "w:eastAsia");
58018
+ if (typeof font === "string" && font.trim()) {
58019
+ run2.fontFamily = font;
58020
+ }
58021
+ const sz = parseNumberAttr(getAttribute(findChild(rPr, "w:sz"), "w:val")) ?? parseNumberAttr(getAttribute(findChild(rPr, "w:szCs"), "w:val"));
58022
+ if (sz != null) {
58023
+ run2.fontSize = sz / 2;
58024
+ }
58025
+ const color = normalizeColor(getAttribute(findChild(rPr, "w:color"), "w:val"));
58026
+ if (color) run2.color = color;
58027
+ if (findChild(rPr, "w:b")) run2.bold = true;
58028
+ if (findChild(rPr, "w:i")) run2.italic = true;
58029
+ const spacingTwips = parseNumberAttr(getAttribute(findChild(rPr, "w:spacing"), "w:val"));
58030
+ if (spacingTwips != null && Number.isFinite(spacingTwips)) {
58031
+ run2.letterSpacing = twipsToPx$1(spacingTwips);
58032
+ }
58033
+ return Object.keys(run2).length ? run2 : void 0;
58034
+ };
58035
+ const findNumFmtElement = (lvl) => {
58036
+ if (!lvl) return void 0;
58037
+ const direct = findChild(lvl, "w:numFmt");
58038
+ if (direct) return direct;
58039
+ const alternate = findChild(lvl, "mc:AlternateContent");
58040
+ const choice = findChild(alternate, "mc:Choice");
58041
+ if (choice) {
58042
+ return findChild(choice, "w:numFmt");
58043
+ }
58044
+ return void 0;
58045
+ };
58046
+ const resolveNumberingFromContext = (numId, ilvl, numbering) => {
58047
+ const definitions = numbering?.definitions;
58048
+ const abstracts = numbering?.abstracts;
58049
+ if (!definitions || !abstracts) return void 0;
58050
+ const numDef = asOoxmlElement(definitions[String(numId)]);
58051
+ if (!numDef) return void 0;
58052
+ const abstractId = getAttribute(findChild(numDef, "w:abstractNumId"), "w:val");
58053
+ if (abstractId == null) return void 0;
58054
+ const abstract = asOoxmlElement(abstracts[String(abstractId)]);
58055
+ if (!abstract) return void 0;
58056
+ let levelDef = abstract.elements?.find(
58057
+ (el) => el?.name === "w:lvl" && parseNumberAttr(el.attributes?.["w:ilvl"]) === ilvl
58058
+ );
58059
+ const override = numDef.elements?.find(
58060
+ (el) => el?.name === "w:lvlOverride" && parseNumberAttr(el.attributes?.["w:ilvl"]) === ilvl
58061
+ );
58062
+ const overrideLvl = findChild(override, "w:lvl");
58063
+ if (overrideLvl) {
58064
+ levelDef = overrideLvl;
58065
+ }
58066
+ const startOverride = parseNumberAttr(getAttribute(findChild(override, "w:startOverride"), "w:val"));
58067
+ if (!levelDef) return void 0;
58068
+ const numFmtEl = findNumFmtElement(levelDef);
58069
+ const lvlText = getAttribute(findChild(levelDef, "w:lvlText"), "w:val");
58070
+ const start2 = startOverride ?? parseNumberAttr(getAttribute(findChild(levelDef, "w:start"), "w:val"));
58071
+ const suffix2 = normalizeSuffix(getAttribute(findChild(levelDef, "w:suff"), "w:val"));
58072
+ const lvlJc = normalizeJustification(getAttribute(findChild(levelDef, "w:lvlJc"), "w:val"));
58073
+ const indent = extractIndentFromLevel(levelDef);
58074
+ const markerRun = extractMarkerRun(levelDef);
58075
+ const numFmt = normalizeNumFmt(getAttribute(numFmtEl, "w:val"));
58076
+ return {
58077
+ format: numFmt,
58078
+ lvlText,
58079
+ start: start2,
58080
+ suffix: suffix2,
58081
+ lvlJc,
58082
+ resolvedLevelIndent: indent,
58083
+ resolvedMarkerRpr: markerRun
58084
+ };
58085
+ };
57943
58086
  const isTruthy = (value) => {
57944
58087
  if (value === true || value === 1) return true;
57945
58088
  if (typeof value === "string") {
@@ -58572,6 +58715,30 @@ const computeParagraphAttrs = (para, styleContext, listCounterContext, converter
58572
58715
  const ilvl = Number.isFinite(numberingProps.ilvl) ? Math.max(0, Math.floor(Number(numberingProps.ilvl))) : 0;
58573
58716
  const listRendering = normalizeListRenderingAttrs(attrs.listRendering);
58574
58717
  const numericNumId = typeof numId === "number" ? numId : void 0;
58718
+ const resolvedLevel = resolveNumberingFromContext(numId, ilvl, converterContext?.numbering);
58719
+ if (resolvedLevel) {
58720
+ if (resolvedLevel.format && numberingProps.format == null) {
58721
+ numberingProps.format = resolvedLevel.format;
58722
+ }
58723
+ if (resolvedLevel.lvlText && numberingProps.lvlText == null) {
58724
+ numberingProps.lvlText = resolvedLevel.lvlText;
58725
+ }
58726
+ if (resolvedLevel.start != null && numberingProps.start == null) {
58727
+ numberingProps.start = resolvedLevel.start;
58728
+ }
58729
+ if (resolvedLevel.suffix && numberingProps.suffix == null) {
58730
+ numberingProps.suffix = resolvedLevel.suffix;
58731
+ }
58732
+ if (resolvedLevel.lvlJc && numberingProps.lvlJc == null) {
58733
+ numberingProps.lvlJc = resolvedLevel.lvlJc;
58734
+ }
58735
+ if (resolvedLevel.resolvedLevelIndent && !numberingProps.resolvedLevelIndent) {
58736
+ numberingProps.resolvedLevelIndent = resolvedLevel.resolvedLevelIndent;
58737
+ }
58738
+ if (resolvedLevel.resolvedMarkerRpr && !numberingProps.resolvedMarkerRpr) {
58739
+ numberingProps.resolvedMarkerRpr = resolvedLevel.resolvedMarkerRpr;
58740
+ }
58741
+ }
58575
58742
  let counterValue = 1;
58576
58743
  if (listCounterContext && typeof numericNumId === "number") {
58577
58744
  counterValue = listCounterContext.incrementListCounter(numericNumId, ilvl);
@@ -59797,41 +59964,45 @@ function paragraphToFlowBlocks$1(para, nextBlockId, positions, defaultFont, defa
59797
59964
  }
59798
59965
  return;
59799
59966
  }
59800
- if (node.type === "hardBreak") {
59801
- flushParagraph();
59802
- blocks.push({
59803
- kind: "pageBreak",
59804
- id: nextId(),
59805
- attrs: node.attrs || {}
59806
- });
59807
- return;
59808
- }
59809
- if (node.type === "lineBreak") {
59967
+ if (node.type === "hardBreak" || node.type === "lineBreak") {
59810
59968
  const attrs = node.attrs ?? {};
59811
- if (attrs.lineBreakType === "column") {
59969
+ const breakType = attrs.pageBreakType ?? attrs.lineBreakType ?? "line";
59970
+ if (breakType === "page") {
59971
+ flushParagraph();
59972
+ blocks.push({
59973
+ kind: "pageBreak",
59974
+ id: nextId(),
59975
+ attrs: node.attrs || {}
59976
+ });
59977
+ return;
59978
+ }
59979
+ if (breakType === "column") {
59812
59980
  flushParagraph();
59813
59981
  blocks.push({
59814
59982
  kind: "columnBreak",
59815
59983
  id: nextId(),
59816
59984
  attrs: node.attrs || {}
59817
59985
  });
59986
+ return;
59987
+ }
59988
+ const lineBreakRun = { kind: "lineBreak", attrs: {} };
59989
+ const lbAttrs = {};
59990
+ if (attrs.lineBreakType) lbAttrs.lineBreakType = String(attrs.lineBreakType);
59991
+ if (attrs.clear) lbAttrs.clear = String(attrs.clear);
59992
+ if (Object.keys(lbAttrs).length > 0) {
59993
+ lineBreakRun.attrs = lbAttrs;
59818
59994
  } else {
59819
- const lineBreakRun = { kind: "lineBreak", attrs: {} };
59820
- const lbAttrs = {};
59821
- if (attrs.lineBreakType) lbAttrs.lineBreakType = String(attrs.lineBreakType);
59822
- if (attrs.clear) lbAttrs.clear = String(attrs.clear);
59823
- if (Object.keys(lbAttrs).length > 0) {
59824
- lineBreakRun.attrs = lbAttrs;
59825
- } else {
59826
- delete lineBreakRun.attrs;
59827
- }
59828
- const pos = positions.get(node);
59829
- if (pos) {
59830
- lineBreakRun.pmStart = pos.start;
59831
- lineBreakRun.pmEnd = pos.end;
59832
- }
59833
- currentRuns.push(lineBreakRun);
59995
+ delete lineBreakRun.attrs;
59996
+ }
59997
+ const pos = positions.get(node);
59998
+ if (pos) {
59999
+ lineBreakRun.pmStart = pos.start;
60000
+ lineBreakRun.pmEnd = pos.end;
59834
60001
  }
60002
+ if (activeSdt) {
60003
+ lineBreakRun.sdt = activeSdt;
60004
+ }
60005
+ currentRuns.push(lineBreakRun);
59835
60006
  return;
59836
60007
  }
59837
60008
  };
@@ -60424,6 +60595,22 @@ const normalizeTableWidth = (value) => {
60424
60595
  };
60425
60596
  const isTableRowNode = (node) => node.type === "tableRow" || node.type === "table_row";
60426
60597
  const isTableCellNode = (node) => node.type === "tableCell" || node.type === "table_cell" || node.type === "tableHeader" || node.type === "table_header";
60598
+ const normalizeRowHeight = (rowProps) => {
60599
+ if (!rowProps || typeof rowProps !== "object") return void 0;
60600
+ const rawRowHeight = rowProps.rowHeight;
60601
+ if (!rawRowHeight || typeof rawRowHeight !== "object") return void 0;
60602
+ const heightObj = rawRowHeight;
60603
+ const rawValue = pickNumber(heightObj.value ?? heightObj.val);
60604
+ if (rawValue == null) return void 0;
60605
+ const rawRule = heightObj.rule ?? heightObj.hRule;
60606
+ const rule = rawRule === "exact" || rawRule === "atLeast" || rawRule === "auto" ? rawRule : "atLeast";
60607
+ const isLikelyTwips = rawValue >= 300 || Math.abs(rawValue % 15) < 1e-6;
60608
+ const valuePx = isLikelyTwips ? twipsToPx$1(rawValue) : rawValue;
60609
+ return {
60610
+ value: valuePx,
60611
+ rule
60612
+ };
60613
+ };
60427
60614
  const parseTableCell = (args) => {
60428
60615
  const { cellNode, rowIndex, cellIndex, context, defaultCellPadding } = args;
60429
60616
  if (!isTableCellNode(cellNode) || !Array.isArray(cellNode.content)) {
@@ -60461,8 +60648,9 @@ const parseTableCell = (args) => {
60461
60648
  const padding = extractCellPadding(cellNode.attrs ?? {}) ?? (defaultCellPadding ? { ...defaultCellPadding } : void 0);
60462
60649
  if (padding) cellAttrs.padding = padding;
60463
60650
  const verticalAlign = cellNode.attrs?.verticalAlign;
60464
- if (verticalAlign === "top" || verticalAlign === "middle" || verticalAlign === "bottom") {
60465
- cellAttrs.verticalAlign = verticalAlign;
60651
+ const normalizedVerticalAlign = verticalAlign === "middle" ? "center" : verticalAlign === "center" ? "center" : verticalAlign;
60652
+ if (normalizedVerticalAlign === "top" || normalizedVerticalAlign === "center" || normalizedVerticalAlign === "bottom") {
60653
+ cellAttrs.verticalAlign = normalizedVerticalAlign;
60466
60654
  }
60467
60655
  const background = cellNode.attrs?.background;
60468
60656
  if (background && typeof background.color === "string") {
@@ -60505,15 +60693,89 @@ const parseTableRow = (args) => {
60505
60693
  });
60506
60694
  if (cells.length === 0) return null;
60507
60695
  const rowProps = rowNode.attrs?.tableRowProperties;
60696
+ const rowHeight = normalizeRowHeight(rowProps);
60508
60697
  const attrs = rowProps && typeof rowProps === "object" ? {
60509
- tableRowProperties: rowProps
60510
- } : void 0;
60698
+ tableRowProperties: rowProps,
60699
+ ...rowHeight ? { rowHeight } : {}
60700
+ } : rowHeight ? { rowHeight } : void 0;
60511
60701
  return {
60512
60702
  id: context.nextBlockId(`row-${rowIndex}`),
60513
60703
  cells,
60514
60704
  attrs
60515
60705
  };
60516
60706
  };
60707
+ function extractFloatingTableAnchorWrap(node) {
60708
+ const tableProperties = node.attrs?.tableProperties;
60709
+ const floatingProps = tableProperties?.floatingTableProperties;
60710
+ if (!floatingProps) {
60711
+ return {};
60712
+ }
60713
+ const hasPositioning = floatingProps.tblpX !== void 0 || floatingProps.tblpY !== void 0 || floatingProps.tblpXSpec !== void 0 || floatingProps.tblpYSpec !== void 0 || floatingProps.horzAnchor !== void 0 || floatingProps.vertAnchor !== void 0;
60714
+ if (!hasPositioning) {
60715
+ return {};
60716
+ }
60717
+ const mapHorzAnchor = (val) => {
60718
+ switch (val) {
60719
+ case "page":
60720
+ return "page";
60721
+ case "margin":
60722
+ return "margin";
60723
+ case "text":
60724
+ default:
60725
+ return "column";
60726
+ }
60727
+ };
60728
+ const mapVertAnchor = (val) => {
60729
+ switch (val) {
60730
+ case "page":
60731
+ return "page";
60732
+ case "margin":
60733
+ return "margin";
60734
+ case "text":
60735
+ default:
60736
+ return "paragraph";
60737
+ }
60738
+ };
60739
+ const anchor = {
60740
+ isAnchored: true,
60741
+ hRelativeFrom: mapHorzAnchor(floatingProps.horzAnchor),
60742
+ vRelativeFrom: mapVertAnchor(floatingProps.vertAnchor)
60743
+ };
60744
+ if (floatingProps.tblpXSpec) {
60745
+ anchor.alignH = floatingProps.tblpXSpec;
60746
+ }
60747
+ if (floatingProps.tblpYSpec) {
60748
+ anchor.alignV = floatingProps.tblpYSpec;
60749
+ }
60750
+ if (floatingProps.tblpX !== void 0) {
60751
+ anchor.offsetH = twipsToPx$1(floatingProps.tblpX);
60752
+ }
60753
+ if (floatingProps.tblpY !== void 0) {
60754
+ anchor.offsetV = twipsToPx$1(floatingProps.tblpY);
60755
+ }
60756
+ const hasDistances = floatingProps.leftFromText !== void 0 || floatingProps.rightFromText !== void 0 || floatingProps.topFromText !== void 0 || floatingProps.bottomFromText !== void 0;
60757
+ const wrap2 = {
60758
+ type: "Square",
60759
+ // Floating tables with text distances use square wrapping
60760
+ wrapText: "bothSides"
60761
+ // Default to text on both sides
60762
+ };
60763
+ if (hasDistances) {
60764
+ if (floatingProps.topFromText !== void 0) {
60765
+ wrap2.distTop = twipsToPx$1(floatingProps.topFromText);
60766
+ }
60767
+ if (floatingProps.bottomFromText !== void 0) {
60768
+ wrap2.distBottom = twipsToPx$1(floatingProps.bottomFromText);
60769
+ }
60770
+ if (floatingProps.leftFromText !== void 0) {
60771
+ wrap2.distLeft = twipsToPx$1(floatingProps.leftFromText);
60772
+ }
60773
+ if (floatingProps.rightFromText !== void 0) {
60774
+ wrap2.distRight = twipsToPx$1(floatingProps.rightFromText);
60775
+ }
60776
+ }
60777
+ return { anchor, wrap: wrap2 };
60778
+ }
60517
60779
  function tableNodeToBlock$1(node, nextBlockId, positions, defaultFont, defaultSize, _styleContext, trackedChanges, bookmarks, hyperlinkConfig, themeColors, paragraphToFlowBlocks2, converterContext) {
60518
60780
  if (!Array.isArray(node.content) || node.content.length === 0) return null;
60519
60781
  if (!paragraphToFlowBlocks2) return null;
@@ -60578,6 +60840,10 @@ function tableNodeToBlock$1(node, nextBlockId, positions, defaultFont, defaultSi
60578
60840
  if (tableLayout) {
60579
60841
  tableAttrs.tableLayout = tableLayout;
60580
60842
  }
60843
+ const tableProperties = node.attrs?.tableProperties;
60844
+ if (tableProperties && typeof tableProperties === "object") {
60845
+ tableAttrs.tableProperties = tableProperties;
60846
+ }
60581
60847
  let columnWidths = void 0;
60582
60848
  const twipsToPixels2 = (twips) => {
60583
60849
  const PIXELS_PER_INCH2 = 96;
@@ -60621,12 +60887,15 @@ function tableNodeToBlock$1(node, nextBlockId, positions, defaultFont, defaultSi
60621
60887
  columnWidths = void 0;
60622
60888
  }
60623
60889
  }
60890
+ const { anchor, wrap: wrap2 } = extractFloatingTableAnchorWrap(node);
60624
60891
  const tableBlock = {
60625
60892
  kind: "table",
60626
60893
  id: nextBlockId("table"),
60627
60894
  rows,
60628
60895
  attrs: Object.keys(tableAttrs).length > 0 ? tableAttrs : void 0,
60629
- columnWidths
60896
+ columnWidths,
60897
+ ...anchor ? { anchor } : {},
60898
+ ...wrap2 ? { wrap: wrap2 } : {}
60630
60899
  };
60631
60900
  return tableBlock;
60632
60901
  }
@@ -60962,7 +61231,7 @@ function getMeasurementContext() {
60962
61231
  return measurementCtx;
60963
61232
  }
60964
61233
  function getRunFontString(run2) {
60965
- if (run2.kind === "tab" || run2.kind === "lineBreak" || "src" in run2) {
61234
+ if (run2.kind === "tab" || run2.kind === "lineBreak" || run2.kind === "break" || "src" in run2) {
60966
61235
  return "normal normal 16px Arial";
60967
61236
  }
60968
61237
  const style2 = run2.italic ? "italic" : "normal";
@@ -60989,6 +61258,10 @@ function sliceRunsForLine$1(block, line) {
60989
61258
  result.push(run2);
60990
61259
  continue;
60991
61260
  }
61261
+ if (run2.kind === "break") {
61262
+ result.push(run2);
61263
+ continue;
61264
+ }
60992
61265
  const text = run2.text ?? "";
60993
61266
  const isFirstRun = runIndex === line.fromRun;
60994
61267
  const isLastRun = runIndex === line.toRun;
@@ -61022,7 +61295,7 @@ function measureCharacterX(block, line, charOffset) {
61022
61295
  1,
61023
61296
  runs2.reduce((sum, run2) => {
61024
61297
  if (isTabRun$1(run2)) return sum + TAB_CHAR_LENGTH;
61025
- if ("src" in run2 || run2.kind === "lineBreak") return sum;
61298
+ if ("src" in run2 || run2.kind === "lineBreak" || run2.kind === "break") return sum;
61026
61299
  return sum + (run2.text ?? "").length;
61027
61300
  }, 0)
61028
61301
  );
@@ -61043,7 +61316,7 @@ function measureCharacterX(block, line, charOffset) {
61043
61316
  currentCharOffset += runLength2;
61044
61317
  continue;
61045
61318
  }
61046
- const text = "src" in run2 || run2.kind === "lineBreak" ? "" : run2.text ?? "";
61319
+ const text = "src" in run2 || run2.kind === "lineBreak" || run2.kind === "break" ? "" : run2.text ?? "";
61047
61320
  const runLength = text.length;
61048
61321
  if (currentCharOffset + runLength >= charOffset) {
61049
61322
  const offsetInRun = charOffset - currentCharOffset;
@@ -61086,7 +61359,7 @@ function measureCharacterXSegmentBased(block, line, charOffset, ctx2) {
61086
61359
  if (isTabRun$1(run2)) {
61087
61360
  return segmentBaseX + (offsetInSegment > 0 ? segment.width ?? 0 : 0);
61088
61361
  }
61089
- if ("src" in run2 || run2.kind === "lineBreak") {
61362
+ if ("src" in run2 || run2.kind === "lineBreak" || run2.kind === "break") {
61090
61363
  return segmentBaseX + (offsetInSegment >= segmentChars ? segment.width ?? 0 : 0);
61091
61364
  }
61092
61365
  const text = run2.text ?? "";
@@ -61109,7 +61382,7 @@ function findCharacterAtX(block, line, x2, pmStart) {
61109
61382
  1,
61110
61383
  runs2.reduce((sum, run2) => {
61111
61384
  if (isTabRun$1(run2)) return sum + TAB_CHAR_LENGTH;
61112
- if ("src" in run2 || run2.kind === "lineBreak") return sum;
61385
+ if ("src" in run2 || run2.kind === "lineBreak" || run2.kind === "break") return sum;
61113
61386
  return sum + (run2.text ?? "").length;
61114
61387
  }, 0)
61115
61388
  );
@@ -61144,7 +61417,7 @@ function findCharacterAtX(block, line, x2, pmStart) {
61144
61417
  currentCharOffset += TAB_CHAR_LENGTH;
61145
61418
  continue;
61146
61419
  }
61147
- const text = "src" in run2 || run2.kind === "lineBreak" ? "" : run2.text ?? "";
61420
+ const text = "src" in run2 || run2.kind === "lineBreak" || run2.kind === "break" ? "" : run2.text ?? "";
61148
61421
  const runLength = text.length;
61149
61422
  if (runLength === 0) continue;
61150
61423
  ctx2.font = getRunFontString(run2);
@@ -61577,6 +61850,40 @@ function createFloatingObjectManager(columns, margins, pageWidth) {
61577
61850
  };
61578
61851
  zones.push(zone);
61579
61852
  },
61853
+ registerTable(tableBlock, measure, anchorY, columnIndex, pageNumber) {
61854
+ if (!tableBlock.anchor?.isAnchored) {
61855
+ return;
61856
+ }
61857
+ const { wrap: wrap2, anchor } = tableBlock;
61858
+ const wrapType = wrap2?.type ?? "None";
61859
+ if (wrapType === "None") {
61860
+ return;
61861
+ }
61862
+ const tableWidth = measure.totalWidth ?? 0;
61863
+ const tableHeight = measure.totalHeight ?? 0;
61864
+ const x2 = computeTableAnchorX(anchor, columnIndex, columns, tableWidth, margins, pageWidth);
61865
+ const y2 = anchorY + (anchor.offsetV ?? 0);
61866
+ const zone = {
61867
+ imageBlockId: tableBlock.id,
61868
+ // Reusing imageBlockId field for table id
61869
+ pageNumber,
61870
+ columnIndex,
61871
+ bounds: {
61872
+ x: x2,
61873
+ y: y2,
61874
+ width: tableWidth,
61875
+ height: tableHeight
61876
+ },
61877
+ distances: {
61878
+ top: wrap2?.distTop ?? 0,
61879
+ bottom: wrap2?.distBottom ?? 0,
61880
+ left: wrap2?.distLeft ?? 0,
61881
+ right: wrap2?.distRight ?? 0
61882
+ },
61883
+ wrapMode: computeTableWrapMode(wrap2)
61884
+ };
61885
+ zones.push(zone);
61886
+ },
61580
61887
  getExclusionsForLine(lineY, lineHeight2, columnIndex, pageNumber) {
61581
61888
  const result = zones.filter((zone) => {
61582
61889
  if (zone.pageNumber !== pageNumber || zone.columnIndex !== columnIndex) {
@@ -61684,6 +61991,49 @@ function computeWrapMode(wrap2, _anchor) {
61684
61991
  if (wrapText === "largest") return "largest";
61685
61992
  return "both";
61686
61993
  }
61994
+ function computeTableAnchorX(anchor, columnIndex, columns, tableWidth, margins, pageWidth) {
61995
+ const alignH = anchor.alignH ?? "left";
61996
+ const offsetH = anchor.offsetH ?? 0;
61997
+ const marginLeft = Math.max(0, margins?.left ?? 0);
61998
+ const marginRight = Math.max(0, margins?.right ?? 0);
61999
+ const contentWidth = pageWidth != null ? Math.max(1, pageWidth - (marginLeft + marginRight)) : columns.width;
62000
+ const contentLeft = marginLeft;
62001
+ const columnLeft = contentLeft + columnIndex * (columns.width + columns.gap);
62002
+ const relativeFrom = anchor.hRelativeFrom ?? "column";
62003
+ let baseX;
62004
+ let availableWidth;
62005
+ if (relativeFrom === "page") {
62006
+ if (columns.count === 1) {
62007
+ baseX = contentLeft;
62008
+ availableWidth = contentWidth;
62009
+ } else {
62010
+ baseX = 0;
62011
+ availableWidth = pageWidth != null ? pageWidth : contentWidth;
62012
+ }
62013
+ } else if (relativeFrom === "margin") {
62014
+ baseX = contentLeft;
62015
+ availableWidth = contentWidth;
62016
+ } else {
62017
+ baseX = columnLeft;
62018
+ availableWidth = columns.width;
62019
+ }
62020
+ let effectiveAlignH = alignH;
62021
+ if (alignH === "inside") effectiveAlignH = "left";
62022
+ if (alignH === "outside") effectiveAlignH = "right";
62023
+ const result = effectiveAlignH === "left" ? baseX + offsetH : effectiveAlignH === "right" ? baseX + availableWidth - tableWidth - offsetH : effectiveAlignH === "center" ? baseX + (availableWidth - tableWidth) / 2 + offsetH : baseX;
62024
+ return result;
62025
+ }
62026
+ function computeTableWrapMode(wrap2) {
62027
+ if (!wrap2) return "none";
62028
+ if (wrap2.type === "None") {
62029
+ return "none";
62030
+ }
62031
+ const wrapText = wrap2.wrapText ?? "bothSides";
62032
+ if (wrapText === "left") return "right";
62033
+ if (wrapText === "right") return "left";
62034
+ if (wrapText === "largest") return "largest";
62035
+ return "both";
62036
+ }
61687
62037
  function computeNextSectionPropsAtBreak(blocks) {
61688
62038
  const nextSectionPropsAtBreak = /* @__PURE__ */ new Map();
61689
62039
  const docxBreakIndexes = [];
@@ -62380,6 +62730,206 @@ function generateColumnBoundaries(measure) {
62380
62730
  }
62381
62731
  return boundaries;
62382
62732
  }
62733
+ function countHeaderRows(block) {
62734
+ let count = 0;
62735
+ for (let i = 0; i < block.rows.length; i++) {
62736
+ const row = block.rows[i];
62737
+ const repeatHeader = row.attrs?.tableRowProperties?.repeatHeader;
62738
+ if (repeatHeader === true) {
62739
+ count++;
62740
+ } else {
62741
+ break;
62742
+ }
62743
+ }
62744
+ return count;
62745
+ }
62746
+ function sumRowHeights(rows, fromRow, toRow) {
62747
+ let total = 0;
62748
+ for (let i = fromRow; i < toRow && i < rows.length; i++) {
62749
+ total += rows[i].height;
62750
+ }
62751
+ return total;
62752
+ }
62753
+ function calculateFragmentHeight(fragment, measure, _headerCount) {
62754
+ let height = 0;
62755
+ if (fragment.repeatHeaderCount && fragment.repeatHeaderCount > 0) {
62756
+ height += sumRowHeights(measure.rows, 0, fragment.repeatHeaderCount);
62757
+ }
62758
+ height += sumRowHeights(measure.rows, fragment.fromRow, fragment.toRow);
62759
+ return height;
62760
+ }
62761
+ const MIN_PARTIAL_ROW_HEIGHT = 20;
62762
+ function getCellLines(cell) {
62763
+ if (cell.blocks && cell.blocks.length > 0) {
62764
+ const allLines = [];
62765
+ for (const block of cell.blocks) {
62766
+ if (block.kind === "paragraph") {
62767
+ if (block.kind === "paragraph" && "lines" in block) {
62768
+ const paraBlock = block;
62769
+ if (paraBlock.lines) {
62770
+ allLines.push(...paraBlock.lines);
62771
+ }
62772
+ }
62773
+ }
62774
+ }
62775
+ return allLines;
62776
+ }
62777
+ if (cell.paragraph?.lines) {
62778
+ return cell.paragraph.lines;
62779
+ }
62780
+ return [];
62781
+ }
62782
+ function getCellPadding(cellIdx, blockRow) {
62783
+ const padding = blockRow?.cells?.[cellIdx]?.attrs?.padding ?? {};
62784
+ return {
62785
+ top: padding.top ?? 2,
62786
+ bottom: padding.bottom ?? 2,
62787
+ left: padding.left ?? 4,
62788
+ right: padding.right ?? 4
62789
+ };
62790
+ }
62791
+ function getCellTotalLines(cell) {
62792
+ return getCellLines(cell).length;
62793
+ }
62794
+ function computePartialRow(rowIndex, blockRow, measure, availableHeight, fromLineByCell) {
62795
+ const row = measure.rows[rowIndex];
62796
+ if (!row) {
62797
+ throw new Error(`Invalid rowIndex ${rowIndex}: measure.rows has ${measure.rows.length} rows`);
62798
+ }
62799
+ const cellCount = row.cells.length;
62800
+ const startLines = fromLineByCell || new Array(cellCount).fill(0);
62801
+ const toLineByCell = [];
62802
+ const heightByCell = [];
62803
+ const cellPaddings = row.cells.map((_2, idx) => getCellPadding(idx, blockRow));
62804
+ for (let cellIdx = 0; cellIdx < cellCount; cellIdx++) {
62805
+ const cell = row.cells[cellIdx];
62806
+ const startLine = startLines[cellIdx] || 0;
62807
+ const cellPadding = cellPaddings[cellIdx];
62808
+ const availableForLines = Math.max(0, availableHeight - (cellPadding.top + cellPadding.bottom));
62809
+ const lines = getCellLines(cell);
62810
+ let cumulativeHeight = 0;
62811
+ let cutLine = startLine;
62812
+ for (let i = startLine; i < lines.length; i++) {
62813
+ const lineHeight2 = lines[i].lineHeight || 0;
62814
+ if (cumulativeHeight + lineHeight2 > availableForLines) {
62815
+ break;
62816
+ }
62817
+ cumulativeHeight += lineHeight2;
62818
+ cutLine = i + 1;
62819
+ }
62820
+ toLineByCell.push(cutLine);
62821
+ heightByCell.push(cumulativeHeight);
62822
+ }
62823
+ const positiveHeights = heightByCell.filter((h2) => h2 > 0);
62824
+ const minHeight = positiveHeights.length > 0 ? Math.min(...positiveHeights) : 0;
62825
+ let actualPartialHeight = 0;
62826
+ let maxPaddingTotal = 0;
62827
+ for (let cellIdx = 0; cellIdx < cellCount; cellIdx++) {
62828
+ const cell = row.cells[cellIdx];
62829
+ const startLine = startLines[cellIdx] || 0;
62830
+ const lines = getCellLines(cell);
62831
+ const cellPadding = cellPaddings[cellIdx];
62832
+ const paddingTotal = cellPadding.top + cellPadding.bottom;
62833
+ maxPaddingTotal = Math.max(maxPaddingTotal, paddingTotal);
62834
+ let cumulativeHeight = 0;
62835
+ let cutLine = startLine;
62836
+ for (let i = startLine; i < lines.length; i++) {
62837
+ const lineHeight2 = lines[i].lineHeight || 0;
62838
+ if (cumulativeHeight + lineHeight2 > minHeight) {
62839
+ break;
62840
+ }
62841
+ cumulativeHeight += lineHeight2;
62842
+ cutLine = i + 1;
62843
+ }
62844
+ toLineByCell[cellIdx] = cutLine;
62845
+ actualPartialHeight = Math.max(actualPartialHeight, cumulativeHeight + paddingTotal);
62846
+ }
62847
+ const madeProgress = toLineByCell.some((cutLine, idx) => cutLine > (startLines[idx] || 0));
62848
+ const isFirstPart = startLines.every((l3) => l3 === 0);
62849
+ const allCellsExhausted = toLineByCell.every((cutLine, idx) => {
62850
+ const totalLines = getCellTotalLines(row.cells[idx]);
62851
+ return cutLine >= totalLines;
62852
+ });
62853
+ const isLastPart = allCellsExhausted || !madeProgress;
62854
+ if (actualPartialHeight === 0 && isFirstPart) {
62855
+ actualPartialHeight = maxPaddingTotal;
62856
+ }
62857
+ return {
62858
+ rowIndex,
62859
+ fromLineByCell: startLines,
62860
+ toLineByCell,
62861
+ isFirstPart,
62862
+ isLastPart,
62863
+ partialHeight: actualPartialHeight
62864
+ };
62865
+ }
62866
+ function findSplitPoint(block, measure, startRow, availableHeight, fullPageHeight, _pendingPartialRow) {
62867
+ let accumulatedHeight = 0;
62868
+ let lastFitRow = startRow;
62869
+ for (let i = startRow; i < block.rows.length; i++) {
62870
+ const row = block.rows[i];
62871
+ const rowHeight = measure.rows[i]?.height || 0;
62872
+ const cantSplit = row.attrs?.tableRowProperties?.cantSplit === true;
62873
+ if (accumulatedHeight + rowHeight <= availableHeight) {
62874
+ accumulatedHeight += rowHeight;
62875
+ lastFitRow = i + 1;
62876
+ } else {
62877
+ const remainingHeight = availableHeight - accumulatedHeight;
62878
+ if (fullPageHeight && rowHeight > fullPageHeight) {
62879
+ const partialRow = computePartialRow(i, block.rows[i], measure, remainingHeight);
62880
+ return { endRow: i + 1, partialRow };
62881
+ }
62882
+ if (cantSplit) {
62883
+ if (lastFitRow === startRow) {
62884
+ return { endRow: startRow, partialRow: null };
62885
+ }
62886
+ return { endRow: lastFitRow, partialRow: null };
62887
+ }
62888
+ if (remainingHeight >= MIN_PARTIAL_ROW_HEIGHT) {
62889
+ const partialRow = computePartialRow(i, block.rows[i], measure, remainingHeight);
62890
+ const hasContent = partialRow.toLineByCell.some(
62891
+ (cutLine, idx) => cutLine > (partialRow.fromLineByCell[idx] || 0)
62892
+ );
62893
+ if (hasContent) {
62894
+ return { endRow: i + 1, partialRow };
62895
+ }
62896
+ }
62897
+ return { endRow: lastFitRow, partialRow: null };
62898
+ }
62899
+ }
62900
+ return { endRow: block.rows.length, partialRow: null };
62901
+ }
62902
+ function generateFragmentMetadata(measure, _fromRow, _toRow, _repeatHeaderCount) {
62903
+ return {
62904
+ columnBoundaries: generateColumnBoundaries(measure),
62905
+ coordinateSystem: "fragment"
62906
+ };
62907
+ }
62908
+ function layoutMonolithicTable(context) {
62909
+ let state2 = context.ensurePage();
62910
+ if (state2.cursorY + context.measure.totalHeight > state2.contentBottom && state2.page.fragments.length > 0) {
62911
+ state2 = context.advanceColumn(state2);
62912
+ }
62913
+ state2 = context.ensurePage();
62914
+ const height = Math.min(context.measure.totalHeight, state2.contentBottom - state2.cursorY);
62915
+ const metadata = {
62916
+ columnBoundaries: generateColumnBoundaries(context.measure),
62917
+ coordinateSystem: "fragment"
62918
+ };
62919
+ const fragment = {
62920
+ kind: "table",
62921
+ blockId: context.block.id,
62922
+ fromRow: 0,
62923
+ toRow: context.block.rows.length,
62924
+ x: context.columnX(state2.columnIndex),
62925
+ y: state2.cursorY,
62926
+ width: Math.min(context.columnWidth, context.measure.totalWidth || context.columnWidth),
62927
+ height,
62928
+ metadata
62929
+ };
62930
+ state2.page.fragments.push(fragment);
62931
+ state2.cursorY += height;
62932
+ }
62383
62933
  function layoutTableBlock({
62384
62934
  block,
62385
62935
  measure,
@@ -62388,30 +62938,176 @@ function layoutTableBlock({
62388
62938
  advanceColumn,
62389
62939
  columnX
62390
62940
  }) {
62941
+ if (block.anchor?.isAnchored) {
62942
+ return;
62943
+ }
62944
+ const tableProps = block.attrs?.tableProperties;
62945
+ const floatingProps = tableProps?.floatingTableProperties;
62946
+ if (floatingProps && Object.keys(floatingProps).length > 0) {
62947
+ layoutMonolithicTable({ block, measure, columnWidth, ensurePage, advanceColumn, columnX });
62948
+ return;
62949
+ }
62950
+ const headerCount = countHeaderRows(block);
62951
+ const headerHeight = headerCount > 0 ? sumRowHeights(measure.rows, 0, headerCount) : 0;
62391
62952
  let state2 = ensurePage();
62392
- if (state2.cursorY + measure.totalHeight > state2.contentBottom && state2.page.fragments.length > 0) {
62393
- state2 = advanceColumn(state2);
62953
+ let currentRow = 0;
62954
+ let isTableContinuation = false;
62955
+ let pendingPartialRow = null;
62956
+ while (currentRow < block.rows.length || pendingPartialRow !== null) {
62957
+ state2 = ensurePage();
62958
+ const availableHeight = state2.contentBottom - state2.cursorY;
62959
+ let repeatHeaderCount = 0;
62960
+ if (currentRow === 0 && !pendingPartialRow) {
62961
+ repeatHeaderCount = 0;
62962
+ } else {
62963
+ if (headerCount > 0 && headerHeight <= availableHeight) {
62964
+ repeatHeaderCount = headerCount;
62965
+ } else if (headerCount > 0 && headerHeight > availableHeight) {
62966
+ repeatHeaderCount = 0;
62967
+ }
62968
+ }
62969
+ const availableForBody = repeatHeaderCount > 0 ? availableHeight - headerHeight : availableHeight;
62970
+ const fullPageHeight = state2.contentBottom;
62971
+ if (pendingPartialRow !== null) {
62972
+ const rowIndex = pendingPartialRow.rowIndex;
62973
+ const fromLineByCell = pendingPartialRow.toLineByCell;
62974
+ const continuationPartialRow = computePartialRow(
62975
+ rowIndex,
62976
+ block.rows[rowIndex],
62977
+ measure,
62978
+ availableForBody,
62979
+ fromLineByCell
62980
+ );
62981
+ const madeProgress = continuationPartialRow.toLineByCell.some(
62982
+ (toLine, idx) => toLine > (fromLineByCell[idx] || 0)
62983
+ );
62984
+ const hasRemainingLinesAfterContinuation = continuationPartialRow.toLineByCell.some(
62985
+ (toLine, idx) => {
62986
+ const totalLines = getCellTotalLines(measure.rows[rowIndex].cells[idx]);
62987
+ return toLine < totalLines;
62988
+ }
62989
+ );
62990
+ const hadRemainingLinesBefore = fromLineByCell.some((fromLine, idx) => {
62991
+ const totalLines = getCellTotalLines(measure.rows[rowIndex].cells[idx]);
62992
+ return fromLine < totalLines;
62993
+ });
62994
+ const fragmentHeight2 = continuationPartialRow.partialHeight + (repeatHeaderCount > 0 ? headerHeight : 0);
62995
+ if (fragmentHeight2 > 0) {
62996
+ const fragment2 = {
62997
+ kind: "table",
62998
+ blockId: block.id,
62999
+ fromRow: rowIndex,
63000
+ toRow: rowIndex + 1,
63001
+ x: columnX(state2.columnIndex),
63002
+ y: state2.cursorY,
63003
+ width: Math.min(columnWidth, measure.totalWidth || columnWidth),
63004
+ height: fragmentHeight2,
63005
+ continuesFromPrev: true,
63006
+ continuesOnNext: hasRemainingLinesAfterContinuation || rowIndex + 1 < block.rows.length,
63007
+ repeatHeaderCount,
63008
+ partialRow: continuationPartialRow,
63009
+ metadata: generateFragmentMetadata(measure)
63010
+ };
63011
+ state2.page.fragments.push(fragment2);
63012
+ state2.cursorY += fragmentHeight2;
63013
+ }
63014
+ const rowComplete = !hasRemainingLinesAfterContinuation;
63015
+ if (rowComplete) {
63016
+ currentRow = rowIndex + 1;
63017
+ pendingPartialRow = null;
63018
+ } else if (!madeProgress && hadRemainingLinesBefore) {
63019
+ state2 = advanceColumn(state2);
63020
+ } else {
63021
+ state2 = advanceColumn(state2);
63022
+ pendingPartialRow = continuationPartialRow;
63023
+ }
63024
+ isTableContinuation = true;
63025
+ continue;
63026
+ }
63027
+ const bodyStartRow = currentRow;
63028
+ const { endRow, partialRow } = findSplitPoint(block, measure, bodyStartRow, availableForBody, fullPageHeight);
63029
+ if (endRow === bodyStartRow && partialRow === null && state2.page.fragments.length > 0) {
63030
+ state2 = advanceColumn(state2);
63031
+ continue;
63032
+ }
63033
+ if (endRow === bodyStartRow && partialRow === null) {
63034
+ const forcedPartialRow = computePartialRow(bodyStartRow, block.rows[bodyStartRow], measure, availableForBody);
63035
+ const forcedEndRow = bodyStartRow + 1;
63036
+ const fragmentHeight2 = forcedPartialRow.partialHeight + (repeatHeaderCount > 0 ? headerHeight : 0);
63037
+ const fragment2 = {
63038
+ kind: "table",
63039
+ blockId: block.id,
63040
+ fromRow: bodyStartRow,
63041
+ toRow: forcedEndRow,
63042
+ x: columnX(state2.columnIndex),
63043
+ y: state2.cursorY,
63044
+ width: Math.min(columnWidth, measure.totalWidth || columnWidth),
63045
+ height: fragmentHeight2,
63046
+ continuesFromPrev: isTableContinuation,
63047
+ continuesOnNext: !forcedPartialRow.isLastPart || forcedEndRow < block.rows.length,
63048
+ repeatHeaderCount,
63049
+ partialRow: forcedPartialRow,
63050
+ metadata: generateFragmentMetadata(measure)
63051
+ };
63052
+ state2.page.fragments.push(fragment2);
63053
+ state2.cursorY += fragmentHeight2;
63054
+ pendingPartialRow = forcedPartialRow;
63055
+ isTableContinuation = true;
63056
+ continue;
63057
+ }
63058
+ let fragmentHeight;
63059
+ if (partialRow) {
63060
+ const fullRowsHeight = sumRowHeights(measure.rows, bodyStartRow, endRow - 1);
63061
+ fragmentHeight = fullRowsHeight + partialRow.partialHeight + (repeatHeaderCount > 0 ? headerHeight : 0);
63062
+ } else {
63063
+ fragmentHeight = calculateFragmentHeight(
63064
+ { fromRow: bodyStartRow, toRow: endRow, repeatHeaderCount },
63065
+ measure
63066
+ );
63067
+ }
63068
+ const fragment = {
63069
+ kind: "table",
63070
+ blockId: block.id,
63071
+ fromRow: bodyStartRow,
63072
+ toRow: endRow,
63073
+ x: columnX(state2.columnIndex),
63074
+ y: state2.cursorY,
63075
+ width: Math.min(columnWidth, measure.totalWidth || columnWidth),
63076
+ height: fragmentHeight,
63077
+ continuesFromPrev: isTableContinuation,
63078
+ continuesOnNext: endRow < block.rows.length || (partialRow ? !partialRow.isLastPart : false),
63079
+ repeatHeaderCount,
63080
+ partialRow: partialRow || void 0,
63081
+ metadata: generateFragmentMetadata(measure)
63082
+ };
63083
+ state2.page.fragments.push(fragment);
63084
+ state2.cursorY += fragmentHeight;
63085
+ if (partialRow && !partialRow.isLastPart) {
63086
+ pendingPartialRow = partialRow;
63087
+ currentRow = partialRow.rowIndex;
63088
+ } else {
63089
+ currentRow = endRow;
63090
+ pendingPartialRow = null;
63091
+ }
63092
+ isTableContinuation = true;
62394
63093
  }
62395
- state2 = ensurePage();
62396
- const height = Math.min(measure.totalHeight, state2.contentBottom - state2.cursorY);
63094
+ }
63095
+ function createAnchoredTableFragment(block, measure, x2, y2) {
62397
63096
  const metadata = {
62398
63097
  columnBoundaries: generateColumnBoundaries(measure),
62399
63098
  coordinateSystem: "fragment"
62400
- // rowBoundaries omitted - not needed for column resize, reduces DOM overhead
62401
63099
  };
62402
- const fragment = {
63100
+ return {
62403
63101
  kind: "table",
62404
63102
  blockId: block.id,
62405
63103
  fromRow: 0,
62406
63104
  toRow: block.rows.length,
62407
- x: columnX(state2.columnIndex),
62408
- y: state2.cursorY,
62409
- width: Math.min(columnWidth, measure.totalWidth || columnWidth),
62410
- height,
63105
+ x: x2,
63106
+ y: y2,
63107
+ width: measure.totalWidth ?? 0,
63108
+ height: measure.totalHeight ?? 0,
62411
63109
  metadata
62412
63110
  };
62413
- state2.page.fragments.push(fragment);
62414
- state2.cursorY += height;
62415
63111
  }
62416
63112
  function isPageRelativeAnchor(block) {
62417
63113
  const vRelativeFrom = block.anchor?.vRelativeFrom;
@@ -62438,9 +63134,6 @@ function collectPreRegisteredAnchors(blocks, measures) {
62438
63134
  function collectAnchoredDrawings(blocks, measures) {
62439
63135
  const map22 = /* @__PURE__ */ new Map();
62440
63136
  const len = Math.min(blocks.length, measures.length);
62441
- for (let i = 0; i < len; i += 1) {
62442
- if (blocks[i].kind === "paragraph") ;
62443
- }
62444
63137
  const nearestPrevParagraph = (fromIndex) => {
62445
63138
  for (let i = fromIndex - 1; i >= 0; i -= 1) {
62446
63139
  if (blocks[i].kind === "paragraph") return i;
@@ -62476,6 +63169,36 @@ function collectAnchoredDrawings(blocks, measures) {
62476
63169
  }
62477
63170
  return map22;
62478
63171
  }
63172
+ function collectAnchoredTables(blocks, measures) {
63173
+ const map22 = /* @__PURE__ */ new Map();
63174
+ const nearestPrevParagraph = (fromIndex) => {
63175
+ for (let i = fromIndex - 1; i >= 0; i -= 1) {
63176
+ if (blocks[i].kind === "paragraph") return i;
63177
+ }
63178
+ return null;
63179
+ };
63180
+ const nearestNextParagraph = (fromIndex) => {
63181
+ for (let i = fromIndex + 1; i < blocks.length; i += 1) {
63182
+ if (blocks[i].kind === "paragraph") return i;
63183
+ }
63184
+ return null;
63185
+ };
63186
+ for (let i = 0; i < blocks.length; i += 1) {
63187
+ const block = blocks[i];
63188
+ const measure = measures[i];
63189
+ if (block.kind !== "table" || measure?.kind !== "table") continue;
63190
+ const tableBlock = block;
63191
+ const tableMeasure = measure;
63192
+ if (!tableBlock.anchor?.isAnchored) continue;
63193
+ let anchorParaIndex = nearestPrevParagraph(i);
63194
+ if (anchorParaIndex == null) anchorParaIndex = nearestNextParagraph(i);
63195
+ if (anchorParaIndex == null) continue;
63196
+ const list = map22.get(anchorParaIndex) ?? [];
63197
+ list.push({ block: tableBlock, measure: tableMeasure });
63198
+ map22.set(anchorParaIndex, list);
63199
+ }
63200
+ return map22;
63201
+ }
62479
63202
  function createPaginator(opts) {
62480
63203
  const states = [];
62481
63204
  const pages = [];
@@ -63061,7 +63784,9 @@ function layoutDocument(blocks, measures, options = {}) {
63061
63784
  cachedColumnsState.state = null;
63062
63785
  };
63063
63786
  const anchoredByParagraph = collectAnchoredDrawings(blocks, measures);
63787
+ const anchoredTablesByParagraph = collectAnchoredTables(blocks, measures);
63064
63788
  const placedAnchoredIds = /* @__PURE__ */ new Set();
63789
+ const placedAnchoredTableIds = /* @__PURE__ */ new Set();
63065
63790
  const preRegisteredAnchors = collectPreRegisteredAnchors(blocks, measures);
63066
63791
  const preRegisteredPositions = /* @__PURE__ */ new Map();
63067
63792
  for (const entry of preRegisteredAnchors) {
@@ -63239,6 +63964,19 @@ function layoutDocument(blocks, measures, options = {}) {
63239
63964
  }
63240
63965
  }
63241
63966
  const anchorsForPara = anchoredByParagraph.get(index2);
63967
+ const tablesForPara = anchoredTablesByParagraph.get(index2);
63968
+ if (tablesForPara) {
63969
+ const state2 = paginator.ensurePage();
63970
+ for (const { block: tableBlock, measure: tableMeasure } of tablesForPara) {
63971
+ if (placedAnchoredTableIds.has(tableBlock.id)) continue;
63972
+ floatManager.registerTable(tableBlock, tableMeasure, state2.cursorY, state2.columnIndex, state2.page.number);
63973
+ const anchorX = tableBlock.anchor?.offsetH ?? columnX(state2.columnIndex);
63974
+ const anchorY = state2.cursorY + (tableBlock.anchor?.offsetV ?? 0);
63975
+ const tableFragment = createAnchoredTableFragment(tableBlock, tableMeasure, anchorX, anchorY);
63976
+ state2.page.fragments.push(tableFragment);
63977
+ placedAnchoredTableIds.add(tableBlock.id);
63978
+ }
63979
+ }
63242
63980
  layoutParagraphBlock(
63243
63981
  {
63244
63982
  block,
@@ -63510,7 +64248,9 @@ const hashRuns = (block) => {
63510
64248
  const trackedMode = block.attrs && "trackedChangesMode" in block.attrs && block.attrs.trackedChangesMode || "review";
63511
64249
  const trackedEnabled = resolveTrackedChangesEnabled(block.attrs, true);
63512
64250
  const runsHash = block.runs.map((run2) => {
63513
- const text = normalizeText("src" in run2 || run2.kind === "lineBreak" ? "" : run2.text ?? "");
64251
+ const text = normalizeText(
64252
+ "src" in run2 || run2.kind === "lineBreak" || run2.kind === "break" ? "" : run2.text ?? ""
64253
+ );
63514
64254
  const bold = "bold" in run2 ? run2.bold : false;
63515
64255
  const italic = "italic" in run2 ? run2.italic : false;
63516
64256
  const color = "color" in run2 ? run2.color : void 0;
@@ -64170,7 +64910,7 @@ function fontString(run2) {
64170
64910
  return `${italic}${bold}${size2}px ${family}`.trim();
64171
64911
  }
64172
64912
  function runText(run2) {
64173
- return "src" in run2 || run2.kind === "lineBreak" ? "" : run2.text ?? "";
64913
+ return "src" in run2 || run2.kind === "lineBreak" || run2.kind === "break" ? "" : run2.text ?? "";
64174
64914
  }
64175
64915
  function measureRunSliceWidth(run2, fromChar, toChar) {
64176
64916
  const context = getCtx();
@@ -64332,7 +65072,7 @@ const paragraphBlocksEqual = (a, b2) => {
64332
65072
  for (let i = 0; i < a.runs.length; i += 1) {
64333
65073
  const runA = a.runs[i];
64334
65074
  const runB = b2.runs[i];
64335
- if (("src" in runA || runA.kind === "lineBreak" ? "" : runA.text) !== ("src" in runB || runB.kind === "lineBreak" ? "" : runB.text) || ("bold" in runA ? runA.bold : false) !== ("bold" in runB ? runB.bold : false) || ("italic" in runA ? runA.italic : false) !== ("italic" in runB ? runB.italic : false) || ("color" in runA ? runA.color : void 0) !== ("color" in runB ? runB.color : void 0) || getTrackedChangeKey(runA) !== getTrackedChangeKey(runB)) {
65075
+ if (("src" in runA || runA.kind === "lineBreak" || runA.kind === "break" ? "" : runA.text) !== ("src" in runB || runB.kind === "lineBreak" || runB.kind === "break" ? "" : runB.text) || ("bold" in runA ? runA.bold : false) !== ("bold" in runB ? runB.bold : false) || ("italic" in runA ? runA.italic : false) !== ("italic" in runB ? runB.italic : false) || ("color" in runA ? runA.color : void 0) !== ("color" in runB ? runB.color : void 0) || getTrackedChangeKey(runA) !== getTrackedChangeKey(runB)) {
64336
65076
  return false;
64337
65077
  }
64338
65078
  }
@@ -64452,7 +65192,7 @@ function computeHeaderFooterContentHash(blocks) {
64452
65192
  parts.push(block.id);
64453
65193
  if (block.kind === "paragraph") {
64454
65194
  for (const run2 of block.runs) {
64455
- if (!("src" in run2) && run2.kind !== "lineBreak") {
65195
+ if (!("src" in run2) && run2.kind !== "lineBreak" && run2.kind !== "break") {
64456
65196
  parts.push(run2.text ?? "");
64457
65197
  }
64458
65198
  if ("bold" in run2 && run2.bold) parts.push("b");
@@ -65423,7 +66163,7 @@ function computeLinePmRange$1(block, line) {
65423
66163
  for (let runIndex = line.fromRun; runIndex <= line.toRun; runIndex += 1) {
65424
66164
  const run2 = block.runs[runIndex];
65425
66165
  if (!run2) continue;
65426
- const text = "src" in run2 || run2.kind === "lineBreak" ? "" : run2.text ?? "";
66166
+ const text = "src" in run2 || run2.kind === "lineBreak" || run2.kind === "break" ? "" : run2.text ?? "";
65427
66167
  const runLength = text.length;
65428
66168
  const runPmStart = run2.pmStart ?? null;
65429
66169
  const runPmEnd = run2.pmEnd ?? (runPmStart != null ? runPmStart + runLength : null);
@@ -68031,7 +68771,20 @@ const resolveTableCellBorders = (tableBorders, rowIndex, colIndex, totalRows, to
68031
68771
  };
68032
68772
  };
68033
68773
  const renderTableCell = (deps) => {
68034
- const { doc: doc2, x: x2, y: y2, rowHeight, cellMeasure, cell, borders, renderLine, context, applySdtDataset } = deps;
68774
+ const {
68775
+ doc: doc2,
68776
+ x: x2,
68777
+ y: y2,
68778
+ rowHeight,
68779
+ cellMeasure,
68780
+ cell,
68781
+ borders,
68782
+ renderLine,
68783
+ context,
68784
+ applySdtDataset,
68785
+ fromLine,
68786
+ toLine
68787
+ } = deps;
68035
68788
  const cellEl = doc2.createElement("div");
68036
68789
  cellEl.style.position = "absolute";
68037
68790
  cellEl.style.left = `${x2}px`;
@@ -68039,6 +68792,7 @@ const renderTableCell = (deps) => {
68039
68792
  cellEl.style.width = `${cellMeasure.width}px`;
68040
68793
  cellEl.style.height = `${rowHeight}px`;
68041
68794
  cellEl.style.boxSizing = "border-box";
68795
+ cellEl.style.overflow = "hidden";
68042
68796
  if (borders) {
68043
68797
  applyCellBorders(cellEl, borders);
68044
68798
  }
@@ -68052,36 +68806,87 @@ const renderTableCell = (deps) => {
68052
68806
  }
68053
68807
  let contentElement;
68054
68808
  const attrs = cell?.attrs;
68055
- const padding = attrs?.padding || { top: 2, left: 4, right: 4 };
68809
+ const padding = attrs?.padding || { top: 2, left: 4, right: 4, bottom: 2 };
68056
68810
  const paddingLeft = padding.left ?? 4;
68057
68811
  const paddingTop = padding.top ?? 2;
68058
68812
  const paddingRight = padding.right ?? 4;
68813
+ const paddingBottom = padding.bottom ?? 2;
68059
68814
  const cellBlocks = cell?.blocks ?? (cell?.paragraph ? [cell.paragraph] : []);
68060
- const blockMeasures = cellMeasure.blocks ?? (cellMeasure.paragraph ? [cellMeasure.paragraph] : []);
68815
+ const blockMeasures = cellMeasure?.blocks ?? (cellMeasure?.paragraph ? [cellMeasure.paragraph] : []);
68061
68816
  if (cellBlocks.length > 0 && blockMeasures.length > 0) {
68062
68817
  const content = doc2.createElement("div");
68063
68818
  content.style.position = "absolute";
68064
68819
  content.style.left = `${x2 + paddingLeft}px`;
68065
68820
  content.style.top = `${y2 + paddingTop}px`;
68066
- content.style.width = `${Math.max(0, cellMeasure.width - paddingLeft - paddingRight)}px`;
68067
- let blockY = 0;
68821
+ const contentWidth = Math.max(0, cellMeasure.width - paddingLeft - paddingRight);
68822
+ const contentHeight = Math.max(0, rowHeight - paddingTop - paddingBottom);
68823
+ content.style.width = `${contentWidth + 1}px`;
68824
+ content.style.height = `${contentHeight}px`;
68825
+ content.style.display = "flex";
68826
+ content.style.flexDirection = "column";
68827
+ content.style.overflowX = "visible";
68828
+ content.style.overflowY = "hidden";
68829
+ if (cell?.attrs?.verticalAlign === "center") {
68830
+ content.style.justifyContent = "center";
68831
+ } else if (cell?.attrs?.verticalAlign === "bottom") {
68832
+ content.style.justifyContent = "flex-end";
68833
+ } else {
68834
+ content.style.justifyContent = "flex-start";
68835
+ }
68836
+ const blockLineCounts = [];
68837
+ for (let i = 0; i < Math.min(blockMeasures.length, cellBlocks.length); i++) {
68838
+ const bm = blockMeasures[i];
68839
+ if (bm.kind === "paragraph") {
68840
+ blockLineCounts.push(bm.lines?.length || 0);
68841
+ } else {
68842
+ blockLineCounts.push(0);
68843
+ }
68844
+ }
68845
+ const totalLines = blockLineCounts.reduce((a, b2) => a + b2, 0);
68846
+ const globalFromLine = fromLine ?? 0;
68847
+ const globalToLine = toLine === -1 || toLine === void 0 ? totalLines : toLine;
68848
+ let cumulativeLineCount = 0;
68068
68849
  for (let i = 0; i < Math.min(blockMeasures.length, cellBlocks.length); i++) {
68069
68850
  const blockMeasure = blockMeasures[i];
68070
68851
  const block = cellBlocks[i];
68071
68852
  if (blockMeasure.kind === "paragraph" && block?.kind === "paragraph") {
68853
+ const lines = blockMeasure.lines;
68854
+ const blockLineCount = lines?.length || 0;
68855
+ const blockStartGlobal = cumulativeLineCount;
68856
+ const blockEndGlobal = cumulativeLineCount + blockLineCount;
68857
+ if (blockEndGlobal <= globalFromLine) {
68858
+ cumulativeLineCount += blockLineCount;
68859
+ continue;
68860
+ }
68861
+ if (blockStartGlobal >= globalToLine) {
68862
+ cumulativeLineCount += blockLineCount;
68863
+ continue;
68864
+ }
68865
+ const localStartLine = Math.max(0, globalFromLine - blockStartGlobal);
68866
+ const localEndLine = Math.min(blockLineCount, globalToLine - blockStartGlobal);
68072
68867
  const paraWrapper = doc2.createElement("div");
68073
- paraWrapper.style.position = "absolute";
68074
- paraWrapper.style.top = `${blockY}px`;
68868
+ paraWrapper.style.position = "relative";
68075
68869
  paraWrapper.style.left = "0";
68076
68870
  paraWrapper.style.width = "100%";
68077
68871
  applySdtDataset(paraWrapper, block.attrs?.sdt);
68078
- const lines = blockMeasure.lines;
68079
- lines.forEach((line) => {
68872
+ let renderedHeight = 0;
68873
+ for (let lineIdx = localStartLine; lineIdx < localEndLine && lineIdx < lines.length; lineIdx++) {
68874
+ const line = lines[lineIdx];
68080
68875
  const lineEl = renderLine(block, line, { ...context, section: "body" });
68081
68876
  paraWrapper.appendChild(lineEl);
68082
- });
68877
+ renderedHeight += line.lineHeight;
68878
+ }
68879
+ const renderedEntireBlock = localStartLine === 0 && localEndLine >= blockLineCount;
68880
+ if (renderedEntireBlock && blockMeasure.totalHeight && blockMeasure.totalHeight > renderedHeight) {
68881
+ renderedHeight = blockMeasure.totalHeight;
68882
+ }
68083
68883
  content.appendChild(paraWrapper);
68084
- blockY += blockMeasure.totalHeight;
68884
+ if (renderedHeight > 0) {
68885
+ paraWrapper.style.height = `${renderedHeight}px`;
68886
+ }
68887
+ cumulativeLineCount += blockLineCount;
68888
+ } else {
68889
+ cumulativeLineCount += 0;
68085
68890
  }
68086
68891
  }
68087
68892
  contentElement = content;
@@ -68102,7 +68907,10 @@ const renderTableRow = (deps) => {
68102
68907
  allRowHeights,
68103
68908
  context,
68104
68909
  renderLine,
68105
- applySdtDataset
68910
+ applySdtDataset,
68911
+ continuesFromPrev,
68912
+ continuesOnNext,
68913
+ partialRow
68106
68914
  } = deps;
68107
68915
  const calculateXPosition = (gridColumnStart) => {
68108
68916
  let x2 = 0;
@@ -68135,25 +68943,57 @@ const renderTableRow = (deps) => {
68135
68943
  const isLastRow = rowIndex === totalRows - 1;
68136
68944
  const isFirstCol = gridColIndex === 0;
68137
68945
  const isLastCol = gridColIndex === totalCols - 1;
68946
+ const treatAsFirstRow = isFirstRow || continuesFromPrev;
68947
+ const treatAsLastRow = isLastRow || continuesOnNext;
68138
68948
  resolvedBorders = {
68139
- // For top: use cell's if defined, otherwise use table's top for first row
68140
- top: cellBordersAttr.top ?? borderValueToSpec(isFirstRow ? tableBorders.top : tableBorders.insideH),
68141
- // For bottom: use cell's if defined, otherwise use table's bottom for last row only
68142
- bottom: cellBordersAttr.bottom ?? borderValueToSpec(isLastRow ? tableBorders.bottom : void 0),
68949
+ // For top: use cell's if defined, otherwise use table's top border for first row OR continuation
68950
+ top: cellBordersAttr.top ?? borderValueToSpec(treatAsFirstRow ? tableBorders.top : tableBorders.insideH),
68951
+ // For bottom: use cell's if defined, otherwise use table's bottom border for last row OR before continuation
68952
+ bottom: cellBordersAttr.bottom ?? borderValueToSpec(treatAsLastRow ? tableBorders.bottom : void 0),
68143
68953
  // For left: use cell's if defined, otherwise use table's left for first col
68144
68954
  left: cellBordersAttr.left ?? borderValueToSpec(isFirstCol ? tableBorders.left : tableBorders.insideV),
68145
68955
  // For right: use cell's if defined, otherwise use table's right for last col only
68146
68956
  right: cellBordersAttr.right ?? borderValueToSpec(isLastCol ? tableBorders.right : void 0)
68147
68957
  };
68148
68958
  } else if (hasExplicitBorders) {
68149
- resolvedBorders = cellBordersAttr;
68959
+ resolvedBorders = {
68960
+ top: cellBordersAttr.top,
68961
+ bottom: cellBordersAttr.bottom,
68962
+ left: cellBordersAttr.left,
68963
+ right: cellBordersAttr.right
68964
+ };
68150
68965
  } else if (tableBorders) {
68151
- resolvedBorders = resolveTableCellBorders(tableBorders, rowIndex, gridColIndex, totalRows, totalCols);
68966
+ const isFirstRow = rowIndex === 0;
68967
+ const isLastRow = rowIndex === totalRows - 1;
68968
+ const treatAsFirstRow = isFirstRow || continuesFromPrev;
68969
+ const treatAsLastRow = isLastRow || continuesOnNext;
68970
+ const baseBorders = resolveTableCellBorders(tableBorders, rowIndex, gridColIndex, totalRows, totalCols);
68971
+ if (baseBorders) {
68972
+ resolvedBorders = {
68973
+ // If this is a continuation (continuesFromPrev), use table's top border
68974
+ top: treatAsFirstRow ? borderValueToSpec(tableBorders.top) : baseBorders.top,
68975
+ // If this continues on next (continuesOnNext), use table's bottom border
68976
+ bottom: treatAsLastRow ? borderValueToSpec(tableBorders.bottom) : baseBorders.bottom,
68977
+ left: baseBorders.left,
68978
+ right: baseBorders.right
68979
+ };
68980
+ } else {
68981
+ resolvedBorders = void 0;
68982
+ }
68152
68983
  } else {
68153
68984
  resolvedBorders = void 0;
68154
68985
  }
68155
68986
  const rowSpan = cellMeasure.rowSpan ?? 1;
68156
- const cellHeight = rowSpan > 1 ? calculateRowspanHeight(rowIndex, rowSpan) : rowMeasure.height;
68987
+ let cellHeight;
68988
+ if (partialRow) {
68989
+ cellHeight = partialRow.partialHeight;
68990
+ } else if (rowSpan > 1) {
68991
+ cellHeight = calculateRowspanHeight(rowIndex, rowSpan);
68992
+ } else {
68993
+ cellHeight = rowMeasure.height;
68994
+ }
68995
+ const fromLine = partialRow?.fromLineByCell?.[cellIndex];
68996
+ const toLine = partialRow?.toLineByCell?.[cellIndex];
68157
68997
  const { cellElement, contentElement } = renderTableCell({
68158
68998
  doc: doc2,
68159
68999
  x: x2,
@@ -68164,7 +69004,9 @@ const renderTableRow = (deps) => {
68164
69004
  borders: resolvedBorders,
68165
69005
  renderLine,
68166
69006
  context,
68167
- applySdtDataset
69007
+ applySdtDataset,
69008
+ fromLine,
69009
+ toLine
68168
69010
  });
68169
69011
  container.appendChild(cellElement);
68170
69012
  if (contentElement) {
@@ -68278,11 +69120,46 @@ const renderTableFragment = (deps) => {
68278
69120
  if (borderCollapse === "separate" && block.attrs?.cellSpacing) {
68279
69121
  container.style.borderSpacing = `${block.attrs.cellSpacing}px`;
68280
69122
  }
68281
- const allRowHeights = measure.rows.map((r2) => r2.height);
69123
+ const allRowHeights = measure.rows.map((r2, idx) => {
69124
+ if (fragment.partialRow && fragment.partialRow.rowIndex === idx) {
69125
+ return fragment.partialRow.partialHeight;
69126
+ }
69127
+ return r2?.height ?? 0;
69128
+ });
68282
69129
  let y2 = 0;
69130
+ if (fragment.repeatHeaderCount && fragment.repeatHeaderCount > 0) {
69131
+ for (let r2 = 0; r2 < fragment.repeatHeaderCount; r2 += 1) {
69132
+ const rowMeasure = measure.rows[r2];
69133
+ if (!rowMeasure) break;
69134
+ renderTableRow({
69135
+ doc: doc2,
69136
+ container,
69137
+ rowIndex: r2,
69138
+ y: y2,
69139
+ rowMeasure,
69140
+ row: block.rows[r2],
69141
+ totalRows: block.rows.length,
69142
+ tableBorders,
69143
+ columnWidths: measure.columnWidths,
69144
+ allRowHeights,
69145
+ context,
69146
+ renderLine,
69147
+ applySdtDataset,
69148
+ // Headers are always rendered as-is (no border suppression)
69149
+ continuesFromPrev: false,
69150
+ continuesOnNext: false
69151
+ });
69152
+ y2 += rowMeasure.height;
69153
+ }
69154
+ }
68283
69155
  for (let r2 = fragment.fromRow; r2 < fragment.toRow; r2 += 1) {
68284
69156
  const rowMeasure = measure.rows[r2];
68285
69157
  if (!rowMeasure) break;
69158
+ const isFirstRenderedBodyRow = r2 === fragment.fromRow;
69159
+ const isLastRenderedBodyRow = r2 === fragment.toRow - 1;
69160
+ const isPartialRow = fragment.partialRow && fragment.partialRow.rowIndex === r2;
69161
+ const partialRowData = isPartialRow ? fragment.partialRow : void 0;
69162
+ const actualRowHeight = partialRowData ? partialRowData.partialHeight : rowMeasure.height;
68286
69163
  renderTableRow({
68287
69164
  doc: doc2,
68288
69165
  container,
@@ -68296,9 +69173,15 @@ const renderTableFragment = (deps) => {
68296
69173
  allRowHeights,
68297
69174
  context,
68298
69175
  renderLine,
68299
- applySdtDataset
69176
+ applySdtDataset,
69177
+ // Draw top border if table continues from previous fragment (MS Word behavior)
69178
+ continuesFromPrev: isFirstRenderedBodyRow && fragment.continuesFromPrev === true,
69179
+ // Draw bottom border if table continues on next fragment (MS Word behavior)
69180
+ continuesOnNext: isLastRenderedBodyRow && fragment.continuesOnNext === true,
69181
+ // Pass partial row data for mid-row splits
69182
+ partialRow: partialRowData
68300
69183
  });
68301
- y2 += rowMeasure.height;
69184
+ y2 += actualRowHeight;
68302
69185
  }
68303
69186
  return container;
68304
69187
  };
@@ -70086,6 +70969,12 @@ const _DomPainter = class _DomPainter2 {
70086
70969
  isLineBreakRun(run2) {
70087
70970
  return run2.kind === "lineBreak";
70088
70971
  }
70972
+ /**
70973
+ * Type guard to check if a run is a break run.
70974
+ */
70975
+ isBreakRun(run2) {
70976
+ return run2.kind === "break";
70977
+ }
70089
70978
  renderRun(run2, context, trackedConfig) {
70090
70979
  if (this.isImageRun(run2)) {
70091
70980
  return this.renderImageRun(run2);
@@ -70093,7 +70982,10 @@ const _DomPainter = class _DomPainter2 {
70093
70982
  if (this.isLineBreakRun(run2)) {
70094
70983
  return null;
70095
70984
  }
70096
- if (!run2.text || !this.doc) {
70985
+ if (this.isBreakRun(run2)) {
70986
+ return null;
70987
+ }
70988
+ if (!("text" in run2) || !run2.text || !this.doc) {
70097
70989
  return null;
70098
70990
  }
70099
70991
  const linkData = this.extractLinkData(run2);
@@ -70234,6 +71126,12 @@ const _DomPainter = class _DomPainter2 {
70234
71126
  if (styleId) {
70235
71127
  el.setAttribute("styleid", styleId);
70236
71128
  }
71129
+ const alignment2 = block.attrs?.alignment;
71130
+ if (alignment2 === "center" || alignment2 === "right" || alignment2 === "justify") {
71131
+ el.style.textAlign = alignment2 === "justify" ? "justify" : alignment2;
71132
+ } else {
71133
+ el.style.textAlign = "left";
71134
+ }
70237
71135
  const lineRange = computeLinePmRange(block, line);
70238
71136
  if (lineRange.pmStart != null) {
70239
71137
  el.dataset.pmStart = String(lineRange.pmStart);
@@ -70351,10 +71249,16 @@ const _DomPainter = class _DomPainter2 {
70351
71249
  if (this.isLineBreakRun(baseRun)) {
70352
71250
  continue;
70353
71251
  }
71252
+ if (this.isBreakRun(baseRun)) {
71253
+ continue;
71254
+ }
70354
71255
  const runSegments = segmentsByRun.get(runIndex);
70355
71256
  if (!runSegments || runSegments.length === 0) {
70356
71257
  continue;
70357
71258
  }
71259
+ if (!("text" in baseRun)) {
71260
+ continue;
71261
+ }
70358
71262
  const baseText = baseRun.text ?? "";
70359
71263
  const runPmStart = baseRun.pmStart ?? null;
70360
71264
  const fallbackPmEnd = runPmStart != null && baseRun.pmEnd == null ? runPmStart + baseText.length : baseRun.pmEnd ?? null;
@@ -70673,7 +71577,12 @@ const fragmentKey = (fragment) => {
70673
71577
  if (fragment.kind === "drawing") {
70674
71578
  return `drawing:${fragment.blockId}:${fragment.x}:${fragment.y}`;
70675
71579
  }
70676
- return `${fragment.kind}:${fragment.blockId}`;
71580
+ if (fragment.kind === "table") {
71581
+ const partialKey = fragment.partialRow ? `:${fragment.partialRow.fromLineByCell.join(",")}-${fragment.partialRow.toLineByCell.join(",")}` : "";
71582
+ return `table:${fragment.blockId}:${fragment.fromRow}:${fragment.toRow}${partialKey}`;
71583
+ }
71584
+ const _exhaustiveCheck = fragment;
71585
+ return _exhaustiveCheck;
70677
71586
  };
70678
71587
  const fragmentSignature = (fragment, lookup2) => {
70679
71588
  const base2 = lookup2.get(fragment.blockId)?.version ?? "missing";
@@ -70715,6 +71624,20 @@ const fragmentSignature = (fragment, lookup2) => {
70715
71624
  fragment.zIndex ?? ""
70716
71625
  ].join("|");
70717
71626
  }
71627
+ if (fragment.kind === "table") {
71628
+ const partialSig = fragment.partialRow ? `${fragment.partialRow.fromLineByCell.join(",")}-${fragment.partialRow.toLineByCell.join(",")}-${fragment.partialRow.partialHeight}` : "";
71629
+ return [
71630
+ base2,
71631
+ fragment.fromRow,
71632
+ fragment.toRow,
71633
+ fragment.width,
71634
+ fragment.height,
71635
+ fragment.continuesFromPrev ? 1 : 0,
71636
+ fragment.continuesOnNext ? 1 : 0,
71637
+ fragment.repeatHeaderCount ?? 0,
71638
+ partialSig
71639
+ ].join("|");
71640
+ }
70718
71641
  return base2;
70719
71642
  };
70720
71643
  const deriveBlockVersion = (block) => {
@@ -70860,7 +71783,7 @@ const deriveBlockVersion = (block) => {
70860
71783
  return block.id;
70861
71784
  };
70862
71785
  const applyRunStyles = (element, run2, isLink = false) => {
70863
- if (run2.kind === "tab" || run2.kind === "image" || run2.kind === "lineBreak") {
71786
+ if (run2.kind === "tab" || run2.kind === "image" || run2.kind === "lineBreak" || run2.kind === "break") {
70864
71787
  return;
70865
71788
  }
70866
71789
  element.style.fontFamily = run2.fontFamily;
@@ -70994,6 +71917,17 @@ const sliceRunsForLine = (block, line) => {
70994
71917
  result.push(run2);
70995
71918
  continue;
70996
71919
  }
71920
+ if (run2.kind === "break") {
71921
+ result.push(run2);
71922
+ continue;
71923
+ }
71924
+ if (run2.kind === "tab") {
71925
+ result.push(run2);
71926
+ continue;
71927
+ }
71928
+ if (!("text" in run2)) {
71929
+ continue;
71930
+ }
70997
71931
  const text = run2.text ?? "";
70998
71932
  const isFirstRun = runIndex === line.fromRun;
70999
71933
  const isLastRun = runIndex === line.toRun;
@@ -71007,20 +71941,14 @@ const sliceRunsForLine = (block, line) => {
71007
71941
  if (!slice2) continue;
71008
71942
  const pmSliceStart = runPmStart != null ? runPmStart + start2 : void 0;
71009
71943
  const pmSliceEnd = runPmStart != null ? runPmStart + end2 : fallbackPmEnd ?? void 0;
71010
- if (run2.kind === "tab") {
71011
- if (slice2.includes(" ")) {
71012
- result.push(run2);
71013
- }
71014
- } else {
71015
- const sliced = {
71016
- ...run2,
71017
- text: slice2,
71018
- pmStart: pmSliceStart,
71019
- pmEnd: pmSliceEnd,
71020
- comments: run2.comments ? [...run2.comments] : void 0
71021
- };
71022
- result.push(sliced);
71023
- }
71944
+ const sliced = {
71945
+ ...run2,
71946
+ text: slice2,
71947
+ pmStart: pmSliceStart,
71948
+ pmEnd: pmSliceEnd,
71949
+ comments: run2.comments ? [...run2.comments] : void 0
71950
+ };
71951
+ result.push(sliced);
71024
71952
  } else {
71025
71953
  result.push(run2);
71026
71954
  }
@@ -71063,6 +71991,39 @@ const computeLinePmRange = (block, line) => {
71063
71991
  }
71064
71992
  continue;
71065
71993
  }
71994
+ if (run2.kind === "break") {
71995
+ const runPmStart2 = run2.pmStart ?? null;
71996
+ const runPmEnd = run2.pmEnd ?? null;
71997
+ if (runPmStart2 == null || runPmEnd == null) {
71998
+ continue;
71999
+ }
72000
+ if (pmStart == null) {
72001
+ pmStart = runPmStart2;
72002
+ }
72003
+ pmEnd = runPmEnd;
72004
+ if (runIndex === line.toRun) {
72005
+ break;
72006
+ }
72007
+ continue;
72008
+ }
72009
+ if (run2.kind === "tab") {
72010
+ const runPmStart2 = run2.pmStart ?? null;
72011
+ const runPmEnd = run2.pmEnd ?? null;
72012
+ if (runPmStart2 == null || runPmEnd == null) {
72013
+ continue;
72014
+ }
72015
+ if (pmStart == null) {
72016
+ pmStart = runPmStart2;
72017
+ }
72018
+ pmEnd = runPmEnd;
72019
+ if (runIndex === line.toRun) {
72020
+ break;
72021
+ }
72022
+ continue;
72023
+ }
72024
+ if (!("text" in run2)) {
72025
+ continue;
72026
+ }
71066
72027
  const text = run2.text ?? "";
71067
72028
  const runLength = text.length;
71068
72029
  const runPmStart = run2.pmStart ?? null;
@@ -71104,6 +72065,12 @@ const resolveRunText = (run2, context) => {
71104
72065
  if (run2.kind === "lineBreak") {
71105
72066
  return "";
71106
72067
  }
72068
+ if (run2.kind === "break") {
72069
+ return "";
72070
+ }
72071
+ if (!("text" in run2)) {
72072
+ return "";
72073
+ }
71107
72074
  if (!runToken) {
71108
72075
  return run2.text ?? "";
71109
72076
  }
@@ -71301,6 +72268,7 @@ async function measureBlock(block, constraints) {
71301
72268
  async function measureParagraphBlock(block, maxWidth) {
71302
72269
  const ctx2 = getCanvasContext();
71303
72270
  const wordLayout = block.attrs?.wordLayout;
72271
+ const WIDTH_FUDGE_PX = 0.5;
71304
72272
  const lines = [];
71305
72273
  const indent = block.attrs?.indent;
71306
72274
  const spacing = block.attrs?.spacing;
@@ -71395,8 +72363,67 @@ async function measureParagraphBlock(block, maxWidth) {
71395
72363
  lastAppliedTabAlign = { target, val };
71396
72364
  pendingTabAlignment = null;
71397
72365
  };
71398
- for (let runIndex = 0; runIndex < block.runs.length; runIndex++) {
71399
- const run2 = block.runs[runIndex];
72366
+ const runsToProcess = [];
72367
+ for (const run2 of block.runs) {
72368
+ if (run2.text && typeof run2.text === "string" && run2.text.includes("\n")) {
72369
+ const textRun = run2;
72370
+ const segments = textRun.text.split("\n");
72371
+ let cursor = textRun.pmStart ?? 0;
72372
+ segments.forEach((seg, idx) => {
72373
+ runsToProcess.push({
72374
+ ...textRun,
72375
+ text: seg,
72376
+ pmStart: cursor,
72377
+ pmEnd: cursor + seg.length
72378
+ });
72379
+ cursor += seg.length;
72380
+ if (idx !== segments.length - 1) {
72381
+ runsToProcess.push({
72382
+ kind: "break",
72383
+ breakType: "line",
72384
+ pmStart: cursor,
72385
+ pmEnd: cursor + 1,
72386
+ sdt: run2.sdt
72387
+ });
72388
+ cursor += 1;
72389
+ }
72390
+ });
72391
+ } else {
72392
+ runsToProcess.push(run2);
72393
+ }
72394
+ }
72395
+ for (let runIndex = 0; runIndex < runsToProcess.length; runIndex++) {
72396
+ const run2 = runsToProcess[runIndex];
72397
+ if (run2.kind === "break") {
72398
+ if (currentLine) {
72399
+ const metrics = calculateTypographyMetrics(currentLine.maxFontSize, spacing);
72400
+ const completedLine = { ...currentLine, ...metrics };
72401
+ addBarTabsToLine(completedLine);
72402
+ lines.push(completedLine);
72403
+ currentLine = null;
72404
+ } else {
72405
+ const textRunWithSize = block.runs.find(
72406
+ (r2) => r2.kind !== "tab" && r2.kind !== "lineBreak" && r2.kind !== "break" && !("src" in r2) && "fontSize" in r2
72407
+ );
72408
+ const fallbackSize = textRunWithSize?.fontSize ?? 12;
72409
+ const metrics = calculateTypographyMetrics(fallbackSize, spacing);
72410
+ const emptyLine = {
72411
+ fromRun: runIndex,
72412
+ fromChar: 0,
72413
+ toRun: runIndex,
72414
+ toChar: 0,
72415
+ width: 0,
72416
+ segments: [],
72417
+ ...metrics
72418
+ };
72419
+ addBarTabsToLine(emptyLine);
72420
+ lines.push(emptyLine);
72421
+ }
72422
+ tabStopCursor = 0;
72423
+ pendingTabAlignment = null;
72424
+ lastAppliedTabAlign = null;
72425
+ continue;
72426
+ }
71400
72427
  if (isLineBreakRun(run2)) {
71401
72428
  if (currentLine) {
71402
72429
  const metrics = calculateTypographyMetrics(currentLine.maxFontSize, spacing);
@@ -71547,6 +72574,9 @@ async function measureParagraphBlock(block, maxWidth) {
71547
72574
  }
71548
72575
  continue;
71549
72576
  }
72577
+ if (!("text" in run2) || !("fontSize" in run2)) {
72578
+ continue;
72579
+ }
71550
72580
  lastFontSize = run2.fontSize;
71551
72581
  const { font } = buildFontString(run2);
71552
72582
  const tabSegments = run2.text.split(" ");
@@ -71586,18 +72616,18 @@ async function measureParagraphBlock(block, maxWidth) {
71586
72616
  segments: [{ runIndex, fromChar: wordStartChar, toChar: wordEndNoSpace, width: wordOnlyWidth }]
71587
72617
  };
71588
72618
  const ls = run2.letterSpacing ?? 0;
71589
- if (!isLastWord && currentLine.width + spaceWidth <= currentLine.maxWidth) {
72619
+ if (!isLastWord && currentLine.width + spaceWidth <= currentLine.maxWidth - WIDTH_FUDGE_PX) {
71590
72620
  currentLine.toChar = wordEndWithSpace;
71591
72621
  currentLine.width = roundValue(currentLine.width + spaceWidth + ls);
71592
72622
  charPosInRun = wordEndWithSpace;
71593
72623
  } else {
71594
- charPosInRun = wordEndNoSpace;
72624
+ charPosInRun = wordEndWithSpace;
71595
72625
  }
71596
72626
  continue;
71597
72627
  }
71598
72628
  const isTocEntry = block.attrs?.isTocEntry;
71599
72629
  const boundarySpacing = currentLine.width > 0 ? run2.letterSpacing ?? 0 : 0;
71600
- if (currentLine.width + boundarySpacing + wordOnlyWidth > currentLine.maxWidth && currentLine.width > 0 && !isTocEntry) {
72630
+ if (currentLine.width + boundarySpacing + wordOnlyWidth > currentLine.maxWidth - WIDTH_FUDGE_PX && currentLine.width > 0 && !isTocEntry) {
71601
72631
  const metrics = calculateTypographyMetrics(currentLine.maxFontSize, spacing);
71602
72632
  const completedLine = {
71603
72633
  ...currentLine,
@@ -71617,16 +72647,16 @@ async function measureParagraphBlock(block, maxWidth) {
71617
72647
  maxWidth: getEffectiveWidth(contentWidth),
71618
72648
  segments: [{ runIndex, fromChar: wordStartChar, toChar: wordEndNoSpace, width: wordOnlyWidth }]
71619
72649
  };
71620
- if (!isLastWord && currentLine.width + spaceWidth <= currentLine.maxWidth) {
72650
+ if (!isLastWord && currentLine.width + spaceWidth <= currentLine.maxWidth - WIDTH_FUDGE_PX) {
71621
72651
  currentLine.toChar = wordEndWithSpace;
71622
72652
  currentLine.width = roundValue(currentLine.width + spaceWidth + (run2.letterSpacing ?? 0));
71623
72653
  charPosInRun = wordEndWithSpace;
71624
72654
  } else {
71625
- charPosInRun = wordEndNoSpace;
72655
+ charPosInRun = wordEndWithSpace;
71626
72656
  }
71627
72657
  } else {
71628
72658
  currentLine.toRun = runIndex;
71629
- if (!isLastWord && currentLine.width + boundarySpacing + wordOnlyWidth + spaceWidth > currentLine.maxWidth) {
72659
+ if (!isLastWord && currentLine.width + boundarySpacing + wordOnlyWidth + spaceWidth > currentLine.maxWidth - WIDTH_FUDGE_PX) {
71630
72660
  currentLine.toChar = wordEndNoSpace;
71631
72661
  currentLine.width = roundValue(currentLine.width + boundarySpacing + wordOnlyWidth);
71632
72662
  currentLine.maxFontSize = Math.max(currentLine.maxFontSize, run2.fontSize);
@@ -71752,6 +72782,34 @@ async function measureParagraphBlock(block, maxWidth) {
71752
72782
  async function measureTableBlock(block, constraints) {
71753
72783
  const maxWidth = typeof constraints === "number" ? constraints : constraints.maxWidth;
71754
72784
  let columnWidths;
72785
+ const scaleColumnWidths = (widths, targetWidth) => {
72786
+ const totalWidth2 = widths.reduce((a, b2) => a + b2, 0);
72787
+ if (totalWidth2 <= targetWidth || widths.length === 0) return widths;
72788
+ const scale = targetWidth / totalWidth2;
72789
+ const scaled = widths.map((w2) => Math.max(1, Math.round(w2 * scale)));
72790
+ const sum = scaled.reduce((a, b2) => a + b2, 0);
72791
+ if (sum !== targetWidth) {
72792
+ const adjust = (delta) => {
72793
+ let idx = 0;
72794
+ const direction = delta > 0 ? 1 : -1;
72795
+ delta = Math.abs(delta);
72796
+ while (delta > 0 && scaled.length > 0) {
72797
+ const i = idx % scaled.length;
72798
+ if (direction > 0) {
72799
+ scaled[i] += 1;
72800
+ delta -= 1;
72801
+ } else if (scaled[i] > 1) {
72802
+ scaled[i] -= 1;
72803
+ delta -= 1;
72804
+ }
72805
+ idx += 1;
72806
+ if (idx > scaled.length * 2 && delta > 0) break;
72807
+ }
72808
+ };
72809
+ adjust(targetWidth - sum);
72810
+ }
72811
+ return scaled;
72812
+ };
71755
72813
  const maxCellCount = Math.max(1, Math.max(...block.rows.map((r2) => r2.cells.length)));
71756
72814
  if (block.columnWidths && block.columnWidths.length > 0) {
71757
72815
  columnWidths = [...block.columnWidths];
@@ -71760,8 +72818,7 @@ async function measureTableBlock(block, constraints) {
71760
72818
  if (hasExplicitWidth || hasFixedLayout) {
71761
72819
  const totalWidth2 = columnWidths.reduce((a, b2) => a + b2, 0);
71762
72820
  if (totalWidth2 > maxWidth) {
71763
- const scale = maxWidth / totalWidth2;
71764
- columnWidths = columnWidths.map((w2) => Math.max(1, Math.floor(w2 * scale)));
72821
+ columnWidths = scaleColumnWidths(columnWidths, maxWidth);
71765
72822
  }
71766
72823
  } else {
71767
72824
  if (columnWidths.length < maxCellCount) {
@@ -71775,8 +72832,7 @@ async function measureTableBlock(block, constraints) {
71775
72832
  }
71776
72833
  const totalWidth2 = columnWidths.reduce((a, b2) => a + b2, 0);
71777
72834
  if (totalWidth2 > maxWidth) {
71778
- const scale = maxWidth / totalWidth2;
71779
- columnWidths = columnWidths.map((w2) => Math.max(1, Math.floor(w2 * scale)));
72835
+ columnWidths = scaleColumnWidths(columnWidths, maxWidth);
71780
72836
  }
71781
72837
  }
71782
72838
  } else {
@@ -71793,6 +72849,8 @@ async function measureTableBlock(block, constraints) {
71793
72849
  };
71794
72850
  const rowspanTracker = new Array(gridColumnCount).fill(0);
71795
72851
  const rows = [];
72852
+ const rowBaseHeights = new Array(block.rows.length).fill(0);
72853
+ const spanConstraints = [];
71796
72854
  for (let rowIndex = 0; rowIndex < block.rows.length; rowIndex++) {
71797
72855
  const row = block.rows[rowIndex];
71798
72856
  const cellMeasures = [];
@@ -71839,6 +72897,11 @@ async function measureTableBlock(block, constraints) {
71839
72897
  colSpan: colspan,
71840
72898
  rowSpan: rowspan
71841
72899
  });
72900
+ if (rowspan === 1) {
72901
+ rowBaseHeights[rowIndex] = Math.max(rowBaseHeights[rowIndex], totalCellHeight);
72902
+ } else {
72903
+ spanConstraints.push({ startRow: rowIndex, rowSpan: rowspan, requiredHeight: totalCellHeight });
72904
+ }
71842
72905
  gridColIndex += colspan;
71843
72906
  }
71844
72907
  for (let col = gridColIndex; col < gridColumnCount; col++) {
@@ -71846,10 +72909,39 @@ async function measureTableBlock(block, constraints) {
71846
72909
  rowspanTracker[col]--;
71847
72910
  }
71848
72911
  }
71849
- const rowHeight = Math.max(0, ...cellMeasures.map((c2) => c2.height));
71850
- rows.push({ cells: cellMeasures, height: rowHeight });
72912
+ rows.push({ cells: cellMeasures, height: 0 });
72913
+ }
72914
+ const rowHeights = [...rowBaseHeights];
72915
+ for (const constraint of spanConstraints) {
72916
+ const { startRow, rowSpan, requiredHeight } = constraint;
72917
+ if (rowSpan <= 0) continue;
72918
+ let currentHeight = 0;
72919
+ for (let i = 0; i < rowSpan && startRow + i < rowHeights.length; i++) {
72920
+ currentHeight += rowHeights[startRow + i];
72921
+ }
72922
+ if (currentHeight < requiredHeight) {
72923
+ const spanLength = Math.min(rowSpan, rowHeights.length - startRow);
72924
+ const increment = spanLength > 0 ? (requiredHeight - currentHeight) / spanLength : 0;
72925
+ for (let i = 0; i < spanLength; i++) {
72926
+ rowHeights[startRow + i] += increment;
72927
+ }
72928
+ }
72929
+ }
72930
+ block.rows.forEach((row, index2) => {
72931
+ const spec = row.attrs?.rowHeight;
72932
+ if (spec?.value != null && Number.isFinite(spec.value)) {
72933
+ const rule = spec.rule ?? "atLeast";
72934
+ if (rule === "exact") {
72935
+ rowHeights[index2] = spec.value;
72936
+ } else {
72937
+ rowHeights[index2] = Math.max(rowHeights[index2], spec.value);
72938
+ }
72939
+ }
72940
+ });
72941
+ for (let i = 0; i < rows.length; i++) {
72942
+ rows[i].height = Math.max(0, rowHeights[i]);
71851
72943
  }
71852
- const totalHeight = rows.reduce((sum, r2) => sum + r2.height, 0);
72944
+ const totalHeight = rowHeights.reduce((sum, h2) => sum + h2, 0);
71853
72945
  const totalWidth = columnWidths.reduce((a, b2) => a + b2, 0);
71854
72946
  return {
71855
72947
  kind: "table",
@@ -72055,7 +73147,7 @@ const resolveLineHeight = (spacing, baseLineHeight) => {
72055
73147
  if (spacing.lineRule === "atLeast") {
72056
73148
  return Math.max(baseLineHeight, raw);
72057
73149
  }
72058
- return raw;
73150
+ return Math.max(baseLineHeight, raw);
72059
73151
  };
72060
73152
  const sanitizePositive = (value) => typeof value === "number" && Number.isFinite(value) ? Math.max(0, value) : 0;
72061
73153
  const sanitizeDecimalSeparator = (value) => {