@windoc/core 0.3.27 → 0.3.29

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.
package/dist/index.js CHANGED
@@ -78,7 +78,7 @@ __export(index_exports, {
78
78
  module.exports = __toCommonJS(index_exports);
79
79
 
80
80
  // src/version.ts
81
- var version = "0.3.27";
81
+ var version = "0.3.29";
82
82
 
83
83
  // src/dataset/enum/Common.ts
84
84
  var MaxHeightRatio = /* @__PURE__ */ ((MaxHeightRatio2) => {
@@ -19074,10 +19074,11 @@ var ListParticle = class {
19074
19074
  const curIndex = isSetCursor ? endIndex : startIndex;
19075
19075
  this.draw.render({ curIndex, isSetCursor });
19076
19076
  }
19077
- getListIndentWidth(element) {
19078
- const { scale } = this.options;
19077
+ // Each level indents by the list's marker column, so a nested marker starts
19078
+ // exactly where its parent's text starts
19079
+ getListIndentWidth(element, markerWidth) {
19079
19080
  const level = element.listLevel ?? 0;
19080
- return level * INDENT_PER_LEVEL * scale;
19081
+ return level * markerWidth;
19081
19082
  }
19082
19083
  _getListMarkerStyleElement(elementList, startIndex = 0) {
19083
19084
  const startElement = elementList[startIndex];
@@ -19207,8 +19208,9 @@ var ListParticle = class {
19207
19208
  leftTop: [startX]
19208
19209
  }
19209
19210
  } = position;
19210
- const indentWidth = this.getListIndentWidth(startElement);
19211
- return startX - offsetX + tabWidth + indentWidth;
19211
+ const level = startElement.listLevel ?? 0;
19212
+ const markerWidth = offsetX / (level + 1);
19213
+ return startX - markerWidth + tabWidth;
19212
19214
  }
19213
19215
  getListMarker(row) {
19214
19216
  const startElement = row.elementList[0];
@@ -22491,8 +22493,9 @@ var Draw = class {
22491
22493
  boundingBoxAscent: 0,
22492
22494
  boundingBoxDescent: 0
22493
22495
  };
22494
- const listIndentWidth = element.listId ? this.listParticle.getListIndentWidth(element) : 0;
22495
- const offsetX = curRow.offsetX || (element.listId && listStyleMap.get(element.listId) || 0) + listIndentWidth || 0;
22496
+ const listMarkerWidth = element.listId && listStyleMap.get(element.listId) || 0;
22497
+ const listIndentWidth = element.listId ? this.listParticle.getListIndentWidth(element, listMarkerWidth) : 0;
22498
+ const offsetX = curRow.offsetX || listMarkerWidth + listIndentWidth || 0;
22496
22499
  const availableWidth = innerWidth - offsetX;
22497
22500
  const isStartElement = curRow.elementList.length === 1;
22498
22501
  x += isStartElement ? offsetX : 0;
@@ -23240,7 +23243,10 @@ var Draw = class {
23240
23243
  if (element.listId) {
23241
23244
  row.isList = true;
23242
23245
  const baseListOffset = listStyleMap.get(element.listId) || 0;
23243
- const rowListIndent = this.listParticle.getListIndentWidth(element);
23246
+ const rowListIndent = this.listParticle.getListIndentWidth(
23247
+ element,
23248
+ baseListOffset
23249
+ );
23244
23250
  row.offsetX = baseListOffset + rowListIndent;
23245
23251
  row.listIndex = listState.listIndex;
23246
23252
  }
@@ -24681,7 +24687,8 @@ async function exportDrawToDocx(draw, options = {}) {
24681
24687
  const ctx = {
24682
24688
  draw,
24683
24689
  scale: draw.getOptions().scale,
24684
- measureCtx
24690
+ measureCtx,
24691
+ lists: /* @__PURE__ */ new Map()
24685
24692
  };
24686
24693
  const file = await createDocument(ctx);
24687
24694
  const blob = await import_docx2.Packer.toBlob(file);
@@ -24699,16 +24706,21 @@ async function createDocument(ctx) {
24699
24706
  const headerExtra = header.getExtraHeight() / scale;
24700
24707
  const footerExtra = footer.getExtraHeight() / scale;
24701
24708
  const layoutMargins = draw.getMargins();
24709
+ planLists(ctx);
24702
24710
  const body = await serializeMain(ctx, layoutMargins[3]);
24703
24711
  const headerChildren = opts.header.disabled ? [] : await serializeRows(ctx, header.getRowList(), {
24704
24712
  startX: layoutMargins[3],
24705
24713
  width: draw.getInnerWidth(),
24706
24714
  positionList: header.getPositionList()
24707
24715
  });
24708
- const footerChildren = opts.footer.disabled ? [] : await serializeFooter(ctx, width, height, margins);
24716
+ const footerResult = opts.footer.disabled ? { children: [], distance: footer.getFooterBottom() / scale } : await serializeFooter(ctx, width, height, margins);
24717
+ const footerChildren = footerResult.children;
24709
24718
  const { pageNumber } = draw.getOptions();
24719
+ endWithParagraph(headerChildren);
24720
+ endWithParagraph(footerChildren);
24710
24721
  return new import_docx2.Document({
24711
24722
  compatabilityModeVersion: 15,
24723
+ numbering: { config: createNumberingConfig(ctx) },
24712
24724
  // LibreOffice formats PAGE/NUMPAGES results from the paragraph style
24713
24725
  styles: {
24714
24726
  paragraphStyles: [
@@ -24735,7 +24747,7 @@ async function createDocument(ctx) {
24735
24747
  bottom: pxTw(margins[2] + footerExtra),
24736
24748
  left: pxTw(margins[3]),
24737
24749
  header: pxTw(headerTop),
24738
- footer: pxTw(footer.getFooterBottom() / scale),
24750
+ footer: pxTw(footerResult.distance),
24739
24751
  gutter: 0
24740
24752
  }
24741
24753
  }
@@ -24767,13 +24779,14 @@ async function serializeMain(ctx, startX) {
24767
24779
  }
24768
24780
  async function serializeRows(ctx, rowList, zone, options = {}) {
24769
24781
  const { pageBreakBefore = false, padTop = 0, padBottom = 0 } = options;
24782
+ const units = groupUnits(ctx, rowList, zone);
24770
24783
  const children = [];
24771
- for (let r = 0; r < rowList.length; r++) {
24772
- const row = rowList[r];
24773
- const isFirst = r === 0;
24774
- const isLast = r === rowList.length - 1;
24775
- const table = row.elementList.find((el) => el.type === "table" /* TABLE */);
24776
- if (table) {
24784
+ for (let u = 0; u < units.length; u++) {
24785
+ const unit = units[u];
24786
+ const isFirst = u === 0;
24787
+ const isLast = u === units.length - 1;
24788
+ if (unit.kind === "table") {
24789
+ const { row, table } = unit;
24777
24790
  if (isFirst && (pageBreakBefore || padTop) || row.offsetY) {
24778
24791
  children.push(
24779
24792
  createSpacerParagraph(
@@ -24790,72 +24803,92 @@ async function serializeRows(ctx, rowList, zone, options = {}) {
24790
24803
  }
24791
24804
  continue;
24792
24805
  }
24806
+ const first = unitFirstRow(unit);
24793
24807
  const rowOptions = {
24794
24808
  pageBreakBefore: isFirst && pageBreakBefore,
24795
24809
  padTop: isFirst ? padTop : 0,
24796
- padBottom: isLast ? padBottom : 0
24810
+ padBottom: isLast ? padBottom : 0,
24811
+ rowY: rowY(zone, first)
24797
24812
  };
24798
- if (!isFirst && isTextRow(rowList[r - 1])) rowOptions.skipLead = true;
24799
- rowOptions.rowY = rowY(zone, row);
24800
- if (!isLast && isTextRow(rowList[r + 1])) {
24801
- rowOptions.extraAfter = rowLead(ctx, rowList[r + 1], {
24802
- rowY: rowY(zone, rowList[r + 1])
24803
- });
24813
+ if (!isFirst && units[u - 1].kind !== "table") rowOptions.skipLead = true;
24814
+ const next = units[u + 1];
24815
+ if (next && next.kind !== "table") {
24816
+ rowOptions.extraAfter = unitLead(ctx, next, zone, {});
24804
24817
  }
24805
- const lead = rowOptions.pageBreakBefore ? rowLead(ctx, row, rowOptions) : 0;
24818
+ const lead = rowOptions.pageBreakBefore ? unitLead(ctx, unit, zone, rowOptions) : 0;
24806
24819
  if (lead) {
24807
24820
  children.push(createSpacerParagraph(true, lead / PX_TO_TWIP));
24808
24821
  rowOptions.pageBreakBefore = false;
24809
24822
  rowOptions.skipLead = true;
24810
24823
  }
24811
- children.push(await serializeRow(ctx, row, zone, rowOptions));
24824
+ children.push(
24825
+ unit.kind === "list" ? await serializeListItem(ctx, unit.rows, zone, rowOptions) : await serializeRow(ctx, unit.row, zone, rowOptions)
24826
+ );
24812
24827
  }
24813
24828
  return children;
24814
24829
  }
24830
+ function unitFirstRow(unit) {
24831
+ return unit.kind === "list" ? unit.rows[0] : unit.row;
24832
+ }
24833
+ function unitLead(ctx, unit, zone, options) {
24834
+ if (unit.kind === "list") return listLead(ctx, unit.rows[0], options);
24835
+ const row = unitFirstRow(unit);
24836
+ return rowLead(ctx, row, { ...options, rowY: rowY(zone, row) });
24837
+ }
24838
+ function groupUnits(ctx, rowList, zone) {
24839
+ const units = [];
24840
+ for (let r = 0; r < rowList.length; r++) {
24841
+ const row = rowList[r];
24842
+ const table = row.elementList.find((el) => el.type === "table" /* TABLE */);
24843
+ if (table) {
24844
+ units.push({ kind: "table", row, table });
24845
+ continue;
24846
+ }
24847
+ if (isNativeListStart(ctx, row, zone)) {
24848
+ const rows = [row];
24849
+ while (r + 1 < rowList.length && isListContinuation(row, rowList[r + 1])) {
24850
+ rows.push(rowList[++r]);
24851
+ }
24852
+ units.push({ kind: "list", rows });
24853
+ continue;
24854
+ }
24855
+ units.push({ kind: "row", row });
24856
+ }
24857
+ return units;
24858
+ }
24815
24859
  function rowY(zone, row) {
24816
24860
  return zone.positionList[row.startIndex]?.coordinate.leftTop[1];
24817
24861
  }
24818
- function isTextRow(row) {
24819
- return !row.elementList.some((el) => el.type === "table" /* TABLE */);
24820
- }
24821
- async function serializeRow(ctx, row, zone, options, suffix) {
24822
- const { pageBreakBefore = false } = options;
24862
+ async function appendRowRuns(ctx, row, zone, line) {
24823
24863
  const { draw, scale } = ctx;
24824
24864
  const positions = zone.positionList;
24825
- const children = [];
24826
- const tabStops = [];
24827
- const firstPosition = positions[row.startIndex];
24828
- let pen = 0;
24829
- let indent = firstPosition ? (firstPosition.coordinate.leftTop[0] - zone.startX) / scale : 0;
24830
- let started = false;
24831
24865
  const anchorTo = (layoutX) => {
24832
24866
  const target = (layoutX - zone.startX) / scale;
24833
- if (!started) {
24834
- indent = target;
24835
- pen = target;
24836
- started = true;
24867
+ if (!line.started) {
24868
+ line.indent = target;
24869
+ line.pen = target;
24870
+ line.started = true;
24837
24871
  return;
24838
24872
  }
24839
- if (target - pen > ANCHOR_EPS) {
24840
- tabStops.push(pxTw(target));
24841
- children.push(new import_docx2.TextRun({ children: [new import_docx2.Tab()] }));
24842
- pen = target;
24873
+ if (target - line.pen > ANCHOR_EPS) {
24874
+ line.tabStops.push(pxTw(target));
24875
+ line.children.push(new import_docx2.TextRun({ children: [new import_docx2.Tab()] }));
24876
+ line.pen = target;
24843
24877
  }
24844
24878
  };
24845
- if (row.isList && firstPosition) {
24846
- const listParticle = draw.getListParticle();
24847
- const markerX = listParticle.getListMarkerX(row, firstPosition);
24848
- const marker = markerX === null ? null : listParticle.getListMarker(row);
24849
- if (markerX !== null && marker) {
24850
- anchorTo(markerX);
24851
- children.push(createTextRun(ctx, marker.text, marker.styleElement));
24852
- pen += measure(ctx, marker.text, marker.styleElement);
24853
- }
24854
- }
24855
24879
  let run = null;
24856
24880
  const flush = () => {
24857
24881
  if (!run) return;
24858
- children.push(createTextRun(ctx, run.text, run.element));
24882
+ line.children.push(
24883
+ createTextRun(
24884
+ ctx,
24885
+ run.text,
24886
+ run.element,
24887
+ void 0,
24888
+ void 0,
24889
+ line.position
24890
+ )
24891
+ );
24859
24892
  run = null;
24860
24893
  };
24861
24894
  for (let j = 0; j < row.elementList.length; j++) {
@@ -24863,19 +24896,7 @@ async function serializeRow(ctx, row, zone, options, suffix) {
24863
24896
  const position = positions[row.startIndex + j];
24864
24897
  if (!position) continue;
24865
24898
  if (element.hide || element.control?.hide || element.area?.hide) continue;
24866
- if (element.type === "separator" /* SEPARATOR */) {
24867
- flush();
24868
- return createSeparatorParagraph(
24869
- ctx,
24870
- row,
24871
- element,
24872
- position.coordinate.leftTop[0],
24873
- position.coordinate.leftTop[1],
24874
- zone,
24875
- options
24876
- );
24877
- }
24878
- if (element.value === ZERO || element.type === "tab" /* TAB */ || element.type === "pageBreak" /* PAGE_BREAK */ || element.type === "columnBreak" /* COLUMN_BREAK */) {
24899
+ if (element.value === ZERO || element.type === "tab" /* TAB */ || element.type === "pageBreak" /* PAGE_BREAK */ || element.type === "columnBreak" /* COLUMN_BREAK */ || element.type === "separator" /* SEPARATOR */) {
24879
24900
  continue;
24880
24901
  }
24881
24902
  const x = position.coordinate.leftTop[0];
@@ -24884,25 +24905,32 @@ async function serializeRow(ctx, row, zone, options, suffix) {
24884
24905
  flush();
24885
24906
  anchorTo(x);
24886
24907
  const image = await createImageRun(element);
24887
- if (image) children.push(image);
24888
- pen += layoutWidth;
24908
+ if (image) line.children.push(image);
24909
+ line.pen += layoutWidth;
24889
24910
  continue;
24890
24911
  }
24891
24912
  if (element.type === "label" /* LABEL */) {
24892
24913
  flush();
24893
24914
  const padding = element.label?.padding || draw.getOptions().label.defaultPadding;
24894
24915
  anchorTo(x + padding[3] * scale);
24895
- children.push(
24896
- createTextRun(ctx, element.value, element, labelShading(ctx, element))
24916
+ line.children.push(
24917
+ createTextRun(
24918
+ ctx,
24919
+ element.value,
24920
+ element,
24921
+ labelShading(ctx, element),
24922
+ void 0,
24923
+ line.position
24924
+ )
24897
24925
  );
24898
- pen += measure(ctx, element.value, element);
24926
+ line.pen += measure(ctx, element.value, element);
24899
24927
  continue;
24900
24928
  }
24901
24929
  const text = getElementText(element);
24902
24930
  if (!text) continue;
24903
24931
  const natural = measure(ctx, text, element);
24904
24932
  const target = (x - zone.startX) / scale;
24905
- const isDrift = !started || target - pen > ANCHOR_EPS;
24933
+ const isDrift = !line.started || target - line.pen > ANCHOR_EPS;
24906
24934
  const extra = layoutWidth - natural;
24907
24935
  const needsSpacing = Math.abs(extra) * PX_TO_TWIP >= 1;
24908
24936
  const canJoin = run && !isDrift && !needsSpacing && isSameRunStyle(run.element, element);
@@ -24912,39 +24940,286 @@ async function serializeRow(ctx, row, zone, options, suffix) {
24912
24940
  flush();
24913
24941
  anchorTo(x);
24914
24942
  if (needsSpacing) {
24915
- children.push(
24916
- createTextRun(ctx, text, element, void 0, pxTw(extra))
24943
+ line.children.push(
24944
+ createTextRun(
24945
+ ctx,
24946
+ text,
24947
+ element,
24948
+ void 0,
24949
+ pxTw(extra),
24950
+ line.position
24951
+ )
24917
24952
  );
24918
24953
  } else {
24919
24954
  run = { text, element };
24920
24955
  }
24921
24956
  }
24922
- pen = target + layoutWidth;
24957
+ line.pen = target + layoutWidth;
24923
24958
  }
24924
24959
  flush();
24925
- if (!children.length && !suffix) {
24960
+ }
24961
+ async function serializeRow(ctx, row, zone, options, suffix, anchor) {
24962
+ const { pageBreakBefore = false } = options;
24963
+ const { draw, scale } = ctx;
24964
+ const firstPosition = zone.positionList[row.startIndex];
24965
+ const separatorIndex = row.elementList.findIndex(
24966
+ (el) => el.type === "separator" /* SEPARATOR */
24967
+ );
24968
+ if (separatorIndex >= 0) {
24969
+ const position = zone.positionList[row.startIndex + separatorIndex];
24970
+ if (position) {
24971
+ return createSeparatorParagraph(
24972
+ ctx,
24973
+ row,
24974
+ row.elementList[separatorIndex],
24975
+ position.coordinate.leftTop[0],
24976
+ position.coordinate.leftTop[1],
24977
+ zone,
24978
+ options
24979
+ );
24980
+ }
24981
+ }
24982
+ const line = {
24983
+ children: [],
24984
+ tabStops: [],
24985
+ pen: 0,
24986
+ started: false,
24987
+ indent: firstPosition ? (firstPosition.coordinate.leftTop[0] - zone.startX) / scale : 0
24988
+ };
24989
+ if (row.isList && firstPosition) {
24990
+ const listParticle = draw.getListParticle();
24991
+ const markerX = listParticle.getListMarkerX(row, firstPosition);
24992
+ const marker = markerX === null ? null : listParticle.getListMarker(row);
24993
+ if (markerX !== null && marker) {
24994
+ line.indent = (markerX - zone.startX) / scale;
24995
+ line.pen = line.indent;
24996
+ line.started = true;
24997
+ line.children.push(createTextRun(ctx, marker.text, marker.styleElement));
24998
+ line.pen += measure(ctx, marker.text, marker.styleElement);
24999
+ }
25000
+ }
25001
+ await appendRowRuns(ctx, row, zone, line);
25002
+ const { children } = line;
25003
+ if (anchor) children.unshift(anchor);
25004
+ if (!line.started && !suffix) {
24926
25005
  const total = (options.skipLead ? 0 : rowLead(ctx, row, options)) + rowLine(ctx, row).lineTw + rowSpacing(ctx, row, options).after;
24927
- return createSpacerParagraph(pageBreakBefore, total / PX_TO_TWIP);
25006
+ return createSpacerParagraph(pageBreakBefore, total / PX_TO_TWIP, anchor);
24928
25007
  }
24929
- const stops = tabStops.map((position) => ({ type: import_docx2.TabStopType.LEFT, position }));
25008
+ const stops = line.tabStops.map((position) => ({ type: import_docx2.TabStopType.LEFT, position }));
24930
25009
  if (suffix) {
24931
25010
  stops.push({ type: suffix.tabType, position: suffix.tabStop });
24932
25011
  children.push(new import_docx2.TextRun({ children: [new import_docx2.Tab()] }), ...suffix.children);
24933
25012
  }
24934
25013
  return new import_docx2.Paragraph({
24935
25014
  children,
25015
+ run: hasInlineImage(row) ? { size: IMAGE_MARK_HALF_POINTS } : void 0,
24936
25016
  style: suffix?.style,
24937
25017
  pageBreakBefore,
24938
25018
  widowControl: false,
24939
25019
  tabStops: stops,
24940
- indent: { left: pxTw(indent), right: RIGHT_SLACK_TWIP },
25020
+ indent: { left: pxTw(line.indent), right: RIGHT_SLACK_TWIP },
24941
25021
  spacing: rowSpacing(ctx, row, options)
24942
25022
  });
24943
25023
  }
25024
+ var olStyleFormat = {
25025
+ decimal: { format: import_docx2.LevelFormat.DECIMAL, suffix: "." },
25026
+ decimalParen: { format: import_docx2.LevelFormat.DECIMAL, suffix: ")" },
25027
+ decimalZero: { format: import_docx2.LevelFormat.DECIMAL_ZERO, suffix: "." },
25028
+ lowerAlpha: { format: import_docx2.LevelFormat.LOWER_LETTER, suffix: "." },
25029
+ lowerAlphaParen: { format: import_docx2.LevelFormat.LOWER_LETTER, suffix: ")" },
25030
+ upperAlpha: { format: import_docx2.LevelFormat.UPPER_LETTER, suffix: "." },
25031
+ lowerRoman: { format: import_docx2.LevelFormat.LOWER_ROMAN, suffix: "." },
25032
+ lowerRomanParen: { format: import_docx2.LevelFormat.LOWER_ROMAN, suffix: ")" },
25033
+ upperRoman: { format: import_docx2.LevelFormat.UPPER_ROMAN, suffix: "." },
25034
+ outline: { format: import_docx2.LevelFormat.DECIMAL, suffix: "." }
25035
+ };
25036
+ function isListItemStart(row) {
25037
+ const first = row.elementList[0];
25038
+ return !!row.isList && first?.value === ZERO && !first.listWrap;
25039
+ }
25040
+ function rowListId(row) {
25041
+ return row.elementList.find((el) => el.listId)?.listId;
25042
+ }
25043
+ function levelSpec(element, markerText) {
25044
+ const level = Math.min(element.listLevel ?? 0, 8);
25045
+ if (element.listType === "ul" /* UL */) {
25046
+ return { level, format: import_docx2.LevelFormat.BULLET, text: markerText };
25047
+ }
25048
+ const cycle = element.listPreset ? olPresetCycles[element.listPreset] : void 0;
25049
+ const style = cycle ? cycle[level % cycle.length] : "decimal";
25050
+ const spec = olStyleFormat[style] || olStyleFormat.decimal;
25051
+ return { level, format: spec.format, text: `%${level + 1}${spec.suffix}` };
25052
+ }
25053
+ function planLists(ctx) {
25054
+ const listParticle = ctx.draw.getListParticle();
25055
+ const counters = /* @__PURE__ */ new Map();
25056
+ const visit = (rowList) => {
25057
+ for (const row of rowList) {
25058
+ const table = row.elementList.find((el) => el.type === "table" /* TABLE */);
25059
+ if (table) {
25060
+ for (const tr of table.trList || []) {
25061
+ for (const td of tr.tdList) visit(td.rowList || []);
25062
+ }
25063
+ continue;
25064
+ }
25065
+ if (!isListItemStart(row)) continue;
25066
+ const listId = rowListId(row);
25067
+ if (!listId) continue;
25068
+ let plan2 = ctx.lists.get(listId);
25069
+ if (!plan2) {
25070
+ plan2 = {
25071
+ reference: `windoc-list-${ctx.lists.size + 1}`,
25072
+ native: true,
25073
+ levels: /* @__PURE__ */ new Map()
25074
+ };
25075
+ ctx.lists.set(listId, plan2);
25076
+ }
25077
+ const marker = listParticle.getListMarker(row);
25078
+ if (!marker || hasInlineImage(row)) {
25079
+ plan2.native = false;
25080
+ continue;
25081
+ }
25082
+ const spec = levelSpec(row.elementList[0], marker.text);
25083
+ const known = plan2.levels.get(spec.level);
25084
+ if (known && (known.format !== spec.format || known.text !== spec.text)) {
25085
+ plan2.native = false;
25086
+ }
25087
+ plan2.levels.set(spec.level, spec);
25088
+ const count = counters.get(listId) || [];
25089
+ counters.set(listId, count);
25090
+ count[spec.level] = (count[spec.level] || 0) + 1;
25091
+ count.length = spec.level + 1;
25092
+ if (spec.format !== import_docx2.LevelFormat.BULLET && count[spec.level] !== (row.listIndex ?? 0) + 1) {
25093
+ plan2.native = false;
25094
+ }
25095
+ }
25096
+ };
25097
+ ctx.draw.getPageRowList().forEach(visit);
25098
+ }
25099
+ function createNumberingConfig(ctx) {
25100
+ return [...ctx.lists.values()].filter((plan2) => plan2.native).map((plan2) => ({
25101
+ reference: plan2.reference,
25102
+ levels: Array.from({ length: 9 }, (_, level) => {
25103
+ const spec = plan2.levels.get(level) || {
25104
+ format: import_docx2.LevelFormat.DECIMAL,
25105
+ text: `%${level + 1}.`
25106
+ };
25107
+ return {
25108
+ level,
25109
+ format: spec.format,
25110
+ text: spec.text,
25111
+ alignment: import_docx2.AlignmentType.LEFT
25112
+ };
25113
+ })
25114
+ }));
25115
+ }
25116
+ function listMarkerGeometry(ctx, row, zone) {
25117
+ const listParticle = ctx.draw.getListParticle();
25118
+ const firstPosition = zone.positionList[row.startIndex];
25119
+ if (!firstPosition) return null;
25120
+ const markerX = listParticle.getListMarkerX(row, firstPosition);
25121
+ const marker = listParticle.getListMarker(row);
25122
+ if (markerX === null || !marker) return null;
25123
+ const textIndex = row.elementList.findIndex(
25124
+ (el) => el.value !== ZERO && el.type !== "tab" /* TAB */
25125
+ );
25126
+ const textPosition = textIndex >= 0 ? zone.positionList[row.startIndex + textIndex] : firstPosition;
25127
+ const textX = textPosition.coordinate.leftTop[0];
25128
+ if (textX - markerX <= 0) return null;
25129
+ return {
25130
+ marker,
25131
+ indent: (textX - zone.startX) / ctx.scale,
25132
+ hanging: (textX - markerX) / ctx.scale
25133
+ };
25134
+ }
25135
+ function isNativeListStart(ctx, row, zone) {
25136
+ if (!isListItemStart(row) || hasInlineImage(row)) return false;
25137
+ const listId = rowListId(row);
25138
+ if (!listId || !ctx.lists.get(listId)?.native) return false;
25139
+ if (row.elementList.some((el) => el.type === "separator" /* SEPARATOR */)) {
25140
+ return false;
25141
+ }
25142
+ return !!listMarkerGeometry(ctx, row, zone);
25143
+ }
25144
+ function isListContinuation(start, row) {
25145
+ return !!row.isList && !isListItemStart(row) && rowListId(row) === rowListId(start) && row.height === start.height && row.ascent === start.ascent && !row.offsetY && !row.spaceAbove && !hasInlineImage(row) && !row.elementList.some(
25146
+ (el) => el.type === "table" /* TABLE */ || el.type === "separator" /* SEPARATOR */
25147
+ );
25148
+ }
25149
+ function listLead(ctx, row, options) {
25150
+ return tw(ctx, (row.offsetY || 0) + (row.spaceAbove || 0)) + pxTw(options.padTop || 0);
25151
+ }
25152
+ async function serializeListItem(ctx, rows, zone, options) {
25153
+ const { scale } = ctx;
25154
+ const first = rows[0];
25155
+ const last = rows[rows.length - 1];
25156
+ const geometry = listMarkerGeometry(ctx, first, zone);
25157
+ const plan2 = ctx.lists.get(rowListId(first));
25158
+ const height = first.height / scale;
25159
+ const raise = Math.round(
25160
+ (EXACT_BASELINE_RATIO * height - first.ascent / scale) * 1.5
25161
+ );
25162
+ const position = raise ? `${raise}` : void 0;
25163
+ const line = {
25164
+ children: [],
25165
+ tabStops: [],
25166
+ pen: geometry.indent,
25167
+ started: true,
25168
+ indent: geometry.indent,
25169
+ position
25170
+ };
25171
+ for (let i = 0; i < rows.length; i++) {
25172
+ if (i > 0) {
25173
+ line.children.push(new import_docx2.TextRun({ break: 1 }));
25174
+ line.pen = geometry.indent;
25175
+ }
25176
+ await appendRowRuns(ctx, rows[i], zone, line);
25177
+ }
25178
+ return new import_docx2.Paragraph({
25179
+ children: line.children,
25180
+ numbering: {
25181
+ reference: plan2.reference,
25182
+ level: Math.min(first.elementList[0].listLevel ?? 0, 8)
25183
+ },
25184
+ // the number is drawn with the paragraph mark's formatting
25185
+ run: { ...runStyle(ctx, geometry.marker.styleElement), position },
25186
+ pageBreakBefore: options.pageBreakBefore,
25187
+ widowControl: false,
25188
+ tabStops: [...new Set(line.tabStops)].map((tabPosition) => ({
25189
+ type: import_docx2.TabStopType.LEFT,
25190
+ position: tabPosition
25191
+ })),
25192
+ indent: {
25193
+ left: pxTw(geometry.indent),
25194
+ hanging: pxTw(geometry.hanging),
25195
+ right: RIGHT_SLACK_TWIP
25196
+ },
25197
+ spacing: {
25198
+ before: options.skipLead ? 0 : listLead(ctx, first, options),
25199
+ after: tw(ctx, last.spaceBelow || 0) + pxTw(options.padBottom || 0) + (options.extraAfter || 0),
25200
+ line: pxTw(height),
25201
+ lineRule: import_docx2.LineRuleType.EXACT
25202
+ }
25203
+ });
25204
+ }
24944
25205
  var EXACT_BASELINE_RATIO = 0.8;
25206
+ var IMAGE_MARK_HALF_POINTS = 2;
25207
+ var IMAGE_MARK_DESCENT_PX = 0.3;
25208
+ function hasInlineImage(row) {
25209
+ return row.elementList.some((el) => el.type === "image" /* IMAGE */);
25210
+ }
24945
25211
  function rowLine(ctx, row, baseline = row.ascent / ctx.scale) {
24946
25212
  const { scale } = ctx;
24947
25213
  const height = row.height / scale;
25214
+ if (hasInlineImage(row)) {
25215
+ const lineTw2 = pxTw(Math.min(baseline, height) + IMAGE_MARK_DESCENT_PX);
25216
+ return {
25217
+ lineTw: lineTw2,
25218
+ beforeTw: 0,
25219
+ afterTw: Math.max(0, pxTw(height) - lineTw2),
25220
+ atLeast: true
25221
+ };
25222
+ }
24948
25223
  const ascent = Math.min(baseline, height);
24949
25224
  const line = Math.min(
24950
25225
  ascent / EXACT_BASELINE_RATIO,
@@ -24956,7 +25231,7 @@ function rowLine(ctx, row, baseline = row.ascent / ctx.scale) {
24956
25231
  pxTw(ascent) - Math.round(lineTw * EXACT_BASELINE_RATIO)
24957
25232
  );
24958
25233
  const afterTw = Math.max(0, pxTw(height) - lineTw - beforeTw);
24959
- return { lineTw, beforeTw, afterTw };
25234
+ return { lineTw, beforeTw, afterTw, atLeast: false };
24960
25235
  }
24961
25236
  function rowLead(ctx, row, options) {
24962
25237
  const separator = row.elementList.find(
@@ -24971,12 +25246,12 @@ function rowLead(ctx, row, options) {
24971
25246
  return rowLine(ctx, row, baseline).beforeTw + tw(ctx, (row.offsetY || 0) + (row.spaceAbove || 0)) + pxTw(options.padTop || 0);
24972
25247
  }
24973
25248
  function rowSpacing(ctx, row, options) {
24974
- const { lineTw, afterTw } = rowLine(ctx, row);
25249
+ const { lineTw, afterTw, atLeast } = rowLine(ctx, row);
24975
25250
  return {
24976
25251
  before: options.skipLead ? 0 : rowLead(ctx, row, options),
24977
25252
  after: afterTw + tw(ctx, row.spaceBelow || 0) + pxTw(options.padBottom || 0) + (options.extraAfter || 0),
24978
25253
  line: lineTw,
24979
- lineRule: import_docx2.LineRuleType.EXACT
25254
+ lineRule: atLeast ? import_docx2.LineRuleType.AT_LEAST : import_docx2.LineRuleType.EXACT
24980
25255
  };
24981
25256
  }
24982
25257
  function createSeparatorParagraph(ctx, row, element, x, rowY2, zone, options) {
@@ -25023,16 +25298,20 @@ function createLineImage(width, height, color, dashArray) {
25023
25298
  ctx.moveTo(0, canvas.height / 2);
25024
25299
  ctx.lineTo(canvas.width, canvas.height / 2);
25025
25300
  ctx.stroke();
25026
- const binary = atob(canvas.toDataURL("image/png").split(",")[1]);
25027
- const bytes = new Uint8Array(binary.length);
25028
- for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
25029
- return bytes;
25301
+ return canvasToPng(canvas);
25030
25302
  }
25031
- function createSpacerParagraph(pageBreakBefore, height = 0) {
25303
+ function endWithParagraph(children) {
25304
+ if (children[children.length - 1] instanceof import_docx2.Table) {
25305
+ children.push(createSpacerParagraph(false));
25306
+ }
25307
+ return children;
25308
+ }
25309
+ function createSpacerParagraph(pageBreakBefore, height = 0, anchor) {
25032
25310
  return new import_docx2.Paragraph({
25033
25311
  pageBreakBefore,
25034
25312
  widowControl: false,
25035
- children: [new import_docx2.TextRun({ text: "", size: 2 })],
25313
+ run: { size: 2 },
25314
+ children: anchor ? [anchor, new import_docx2.TextRun({ text: "", size: 2 })] : [new import_docx2.TextRun({ text: "", size: 2 })],
25036
25315
  spacing: {
25037
25316
  before: 0,
25038
25317
  after: 0,
@@ -25070,7 +25349,7 @@ async function serializeTable(ctx, element, position, zone) {
25070
25349
  );
25071
25350
  cells.push(
25072
25351
  new import_docx2.TableCell({
25073
- children: cellChildren.length ? cellChildren : [createSpacerParagraph(false)],
25352
+ children: cellChildren.length ? endWithParagraph(cellChildren) : [createSpacerParagraph(false)],
25074
25353
  columnSpan: td.colspan > 1 ? td.colspan : void 0,
25075
25354
  rowSpan: td.rowspan > 1 ? td.rowspan : void 0,
25076
25355
  width: { size: pxTw(td.width), type: import_docx2.WidthType.DXA },
@@ -25191,6 +25470,7 @@ async function serializeFooter(ctx, pageWidth, pageHeight, margins) {
25191
25470
  const footer = draw.getFooter();
25192
25471
  const opts = draw.getOptions();
25193
25472
  const barHeight = footer.getHeight() / scale;
25473
+ const footerBottom = footer.getFooterBottom() / scale;
25194
25474
  const contentHeight = footer.getRowHeight() / scale;
25195
25475
  const paddingTop = Math.floor(Math.max(0, (barHeight - contentHeight) / 2) * scale) / scale;
25196
25476
  const zone = {
@@ -25212,56 +25492,73 @@ async function serializeFooter(ctx, pageWidth, pageHeight, margins) {
25212
25492
  }
25213
25493
  }
25214
25494
  }
25495
+ const band = opts.footer.backgroundColor ? createBandImage(
25496
+ pageWidth,
25497
+ pageHeight - footerBottom - barHeight,
25498
+ barHeight,
25499
+ opts.footer.backgroundColor
25500
+ ) : void 0;
25215
25501
  const children = [];
25216
25502
  for (let r = 0; r < rowList.length; r++) {
25217
25503
  const row = rowList[r];
25218
- const rowOptions = { padTop: r === 0 ? paddingTop : 0 };
25219
- if (r !== pageNumberRow) {
25220
- children.push(...await serializeRows(ctx, [row], zone, rowOptions));
25221
- continue;
25222
- }
25223
- const top = zone.positionList[row.startIndex].coordinate.leftTop[1] / scale;
25224
- const shift = pageNumber.baseline - (top + row.ascent / scale);
25225
- children.push(
25226
- await serializeRow(ctx, row, zone, rowOptions, {
25504
+ let suffix;
25505
+ if (r === pageNumberRow) {
25506
+ const top = zone.positionList[row.startIndex].coordinate.leftTop[1] / scale;
25507
+ suffix = {
25227
25508
  tabStop: pageNumber.tabStop,
25228
25509
  tabType: pageNumber.tabType,
25229
- children: pageNumber.runs(shift),
25510
+ children: pageNumber.runs(
25511
+ pageNumber.baseline - (top + row.ascent / scale)
25512
+ ),
25230
25513
  style: PAGE_NUMBER_STYLE
25231
- })
25514
+ };
25515
+ }
25516
+ children.push(
25517
+ await serializeRow(ctx, row, zone, {}, suffix, r === 0 ? band : void 0)
25232
25518
  );
25233
25519
  }
25234
- const fill = opts.footer.backgroundColor ? normalizeHexColor(opts.footer.backgroundColor, "FFFFFF") : void 0;
25235
- const none = { style: import_docx2.BorderStyle.NONE, size: 0, color: "auto" };
25236
- const band = new import_docx2.Table({
25237
- layout: import_docx2.TableLayoutType.FIXED,
25238
- width: { size: pxTw(pageWidth), type: import_docx2.WidthType.DXA },
25239
- columnWidths: [pxTw(pageWidth)],
25240
- indent: { size: -pxTw(margins[3]), type: import_docx2.WidthType.DXA },
25241
- borders: noTableBorders(),
25242
- rows: [
25243
- new import_docx2.TableRow({
25244
- cantSplit: true,
25245
- height: { value: pxTw(barHeight), rule: import_docx2.HeightRule.EXACT },
25246
- children: [
25247
- new import_docx2.TableCell({
25248
- width: { size: pxTw(pageWidth), type: import_docx2.WidthType.DXA },
25249
- margins: {
25250
- top: 0,
25251
- bottom: 0,
25252
- left: pxTw(margins[3]),
25253
- right: pxTw(margins[1]),
25254
- marginUnitType: import_docx2.WidthType.DXA
25255
- },
25256
- shading: fill ? { fill, type: import_docx2.ShadingType.CLEAR, color: "auto" } : void 0,
25257
- borders: { top: none, right: none, bottom: none, left: none },
25258
- children: children.length ? children : [createSpacerParagraph(false)]
25259
- })
25260
- ]
25261
- })
25262
- ]
25520
+ if (!children.length && band) {
25521
+ children.push(createSpacerParagraph(false, 0, band));
25522
+ }
25523
+ const contentTop = pageHeight - footerBottom - barHeight + paddingTop;
25524
+ const distance = Math.max(0, pageHeight - contentTop - contentHeight);
25525
+ return { children, distance };
25526
+ }
25527
+ var EMU_PER_PX = 9525;
25528
+ function createBandImage(width, top, height, color) {
25529
+ return new import_docx2.ImageRun({
25530
+ type: "png",
25531
+ data: createFillImage(color),
25532
+ transformation: { width, height },
25533
+ floating: {
25534
+ horizontalPosition: {
25535
+ relative: import_docx2.HorizontalPositionRelativeFrom.PAGE,
25536
+ offset: 0
25537
+ },
25538
+ verticalPosition: {
25539
+ relative: import_docx2.VerticalPositionRelativeFrom.PAGE,
25540
+ offset: Math.round(top * EMU_PER_PX)
25541
+ },
25542
+ behindDocument: true,
25543
+ allowOverlap: true,
25544
+ wrap: { type: import_docx2.TextWrappingType.NONE }
25545
+ }
25263
25546
  });
25264
- return [band];
25547
+ }
25548
+ function createFillImage(color) {
25549
+ const canvas = document.createElement("canvas");
25550
+ canvas.width = 4;
25551
+ canvas.height = 4;
25552
+ const ctx = canvas.getContext("2d");
25553
+ ctx.fillStyle = color;
25554
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
25555
+ return canvasToPng(canvas);
25556
+ }
25557
+ function canvasToPng(canvas) {
25558
+ const binary = atob(canvas.toDataURL("image/png").split(",")[1]);
25559
+ const bytes = new Uint8Array(binary.length);
25560
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
25561
+ return bytes;
25265
25562
  }
25266
25563
  var PAGE_NUMBER_STYLE = "WindocPageNumber";
25267
25564
  var FieldCharAttributes = class extends import_docx2.XmlAttributeComponent {
@@ -25335,7 +25632,17 @@ function createPageNumberRuns(ctx, pageHeight, textWidth) {
25335
25632
  }).flat()
25336
25633
  };
25337
25634
  }
25338
- function createTextRun(ctx, text, element, shading, characterSpacing) {
25635
+ function runStyle(ctx, element) {
25636
+ const opts = ctx.draw.getOptions();
25637
+ return {
25638
+ font: mapFont(element.font || opts.defaultFont),
25639
+ size: Math.round(getSize(ctx, element) * 2),
25640
+ bold: !!element.bold,
25641
+ italics: !!element.italic,
25642
+ color: normalizeHexColor(element.color || opts.defaultColor, "000000")
25643
+ };
25644
+ }
25645
+ function createTextRun(ctx, text, element, shading, characterSpacing, position) {
25339
25646
  const opts = ctx.draw.getOptions();
25340
25647
  const isLink = element.type === "hyperlink" /* HYPERLINK */;
25341
25648
  const color = normalizeHexColor(
@@ -25355,7 +25662,8 @@ function createTextRun(ctx, text, element, shading, characterSpacing) {
25355
25662
  underline: element.underline || isLink ? { type: mapUnderlineType(element.textDecoration?.style) } : void 0,
25356
25663
  color,
25357
25664
  shading: shading || (highlight ? { fill: highlight, type: import_docx2.ShadingType.CLEAR, color: "auto" } : void 0),
25358
- characterSpacing
25665
+ characterSpacing,
25666
+ position
25359
25667
  });
25360
25668
  if (isLink && element.url) {
25361
25669
  return new import_docx2.ExternalHyperlink({ link: element.url, children: [textRun] });