@windoc/core 0.3.28 → 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.28";
81
+ var version = "0.3.29";
82
82
 
83
83
  // src/dataset/enum/Common.ts
84
84
  var MaxHeightRatio = /* @__PURE__ */ ((MaxHeightRatio2) => {
@@ -24687,7 +24687,8 @@ async function exportDrawToDocx(draw, options = {}) {
24687
24687
  const ctx = {
24688
24688
  draw,
24689
24689
  scale: draw.getOptions().scale,
24690
- measureCtx
24690
+ measureCtx,
24691
+ lists: /* @__PURE__ */ new Map()
24691
24692
  };
24692
24693
  const file = await createDocument(ctx);
24693
24694
  const blob = await import_docx2.Packer.toBlob(file);
@@ -24705,18 +24706,21 @@ async function createDocument(ctx) {
24705
24706
  const headerExtra = header.getExtraHeight() / scale;
24706
24707
  const footerExtra = footer.getExtraHeight() / scale;
24707
24708
  const layoutMargins = draw.getMargins();
24709
+ planLists(ctx);
24708
24710
  const body = await serializeMain(ctx, layoutMargins[3]);
24709
24711
  const headerChildren = opts.header.disabled ? [] : await serializeRows(ctx, header.getRowList(), {
24710
24712
  startX: layoutMargins[3],
24711
24713
  width: draw.getInnerWidth(),
24712
24714
  positionList: header.getPositionList()
24713
24715
  });
24714
- 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;
24715
24718
  const { pageNumber } = draw.getOptions();
24716
24719
  endWithParagraph(headerChildren);
24717
24720
  endWithParagraph(footerChildren);
24718
24721
  return new import_docx2.Document({
24719
24722
  compatabilityModeVersion: 15,
24723
+ numbering: { config: createNumberingConfig(ctx) },
24720
24724
  // LibreOffice formats PAGE/NUMPAGES results from the paragraph style
24721
24725
  styles: {
24722
24726
  paragraphStyles: [
@@ -24743,7 +24747,7 @@ async function createDocument(ctx) {
24743
24747
  bottom: pxTw(margins[2] + footerExtra),
24744
24748
  left: pxTw(margins[3]),
24745
24749
  header: pxTw(headerTop),
24746
- footer: pxTw(footer.getFooterBottom() / scale),
24750
+ footer: pxTw(footerResult.distance),
24747
24751
  gutter: 0
24748
24752
  }
24749
24753
  }
@@ -24775,13 +24779,14 @@ async function serializeMain(ctx, startX) {
24775
24779
  }
24776
24780
  async function serializeRows(ctx, rowList, zone, options = {}) {
24777
24781
  const { pageBreakBefore = false, padTop = 0, padBottom = 0 } = options;
24782
+ const units = groupUnits(ctx, rowList, zone);
24778
24783
  const children = [];
24779
- for (let r = 0; r < rowList.length; r++) {
24780
- const row = rowList[r];
24781
- const isFirst = r === 0;
24782
- const isLast = r === rowList.length - 1;
24783
- const table = row.elementList.find((el) => el.type === "table" /* TABLE */);
24784
- 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;
24785
24790
  if (isFirst && (pageBreakBefore || padTop) || row.offsetY) {
24786
24791
  children.push(
24787
24792
  createSpacerParagraph(
@@ -24798,72 +24803,92 @@ async function serializeRows(ctx, rowList, zone, options = {}) {
24798
24803
  }
24799
24804
  continue;
24800
24805
  }
24806
+ const first = unitFirstRow(unit);
24801
24807
  const rowOptions = {
24802
24808
  pageBreakBefore: isFirst && pageBreakBefore,
24803
24809
  padTop: isFirst ? padTop : 0,
24804
- padBottom: isLast ? padBottom : 0
24810
+ padBottom: isLast ? padBottom : 0,
24811
+ rowY: rowY(zone, first)
24805
24812
  };
24806
- if (!isFirst && isTextRow(rowList[r - 1])) rowOptions.skipLead = true;
24807
- rowOptions.rowY = rowY(zone, row);
24808
- if (!isLast && isTextRow(rowList[r + 1])) {
24809
- rowOptions.extraAfter = rowLead(ctx, rowList[r + 1], {
24810
- rowY: rowY(zone, rowList[r + 1])
24811
- });
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, {});
24812
24817
  }
24813
- const lead = rowOptions.pageBreakBefore ? rowLead(ctx, row, rowOptions) : 0;
24818
+ const lead = rowOptions.pageBreakBefore ? unitLead(ctx, unit, zone, rowOptions) : 0;
24814
24819
  if (lead) {
24815
24820
  children.push(createSpacerParagraph(true, lead / PX_TO_TWIP));
24816
24821
  rowOptions.pageBreakBefore = false;
24817
24822
  rowOptions.skipLead = true;
24818
24823
  }
24819
- 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
+ );
24820
24827
  }
24821
24828
  return children;
24822
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
+ }
24823
24859
  function rowY(zone, row) {
24824
24860
  return zone.positionList[row.startIndex]?.coordinate.leftTop[1];
24825
24861
  }
24826
- function isTextRow(row) {
24827
- return !row.elementList.some((el) => el.type === "table" /* TABLE */);
24828
- }
24829
- async function serializeRow(ctx, row, zone, options, suffix) {
24830
- const { pageBreakBefore = false } = options;
24862
+ async function appendRowRuns(ctx, row, zone, line) {
24831
24863
  const { draw, scale } = ctx;
24832
24864
  const positions = zone.positionList;
24833
- const children = [];
24834
- const tabStops = [];
24835
- const firstPosition = positions[row.startIndex];
24836
- let pen = 0;
24837
- let indent = firstPosition ? (firstPosition.coordinate.leftTop[0] - zone.startX) / scale : 0;
24838
- let started = false;
24839
24865
  const anchorTo = (layoutX) => {
24840
24866
  const target = (layoutX - zone.startX) / scale;
24841
- if (!started) {
24842
- indent = target;
24843
- pen = target;
24844
- started = true;
24867
+ if (!line.started) {
24868
+ line.indent = target;
24869
+ line.pen = target;
24870
+ line.started = true;
24845
24871
  return;
24846
24872
  }
24847
- if (target - pen > ANCHOR_EPS) {
24848
- tabStops.push(pxTw(target));
24849
- children.push(new import_docx2.TextRun({ children: [new import_docx2.Tab()] }));
24850
- 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;
24851
24877
  }
24852
24878
  };
24853
- if (row.isList && firstPosition) {
24854
- const listParticle = draw.getListParticle();
24855
- const markerX = listParticle.getListMarkerX(row, firstPosition);
24856
- const marker = markerX === null ? null : listParticle.getListMarker(row);
24857
- if (markerX !== null && marker) {
24858
- anchorTo(markerX);
24859
- children.push(createTextRun(ctx, marker.text, marker.styleElement));
24860
- pen += measure(ctx, marker.text, marker.styleElement);
24861
- }
24862
- }
24863
24879
  let run = null;
24864
24880
  const flush = () => {
24865
24881
  if (!run) return;
24866
- 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
+ );
24867
24892
  run = null;
24868
24893
  };
24869
24894
  for (let j = 0; j < row.elementList.length; j++) {
@@ -24871,19 +24896,7 @@ async function serializeRow(ctx, row, zone, options, suffix) {
24871
24896
  const position = positions[row.startIndex + j];
24872
24897
  if (!position) continue;
24873
24898
  if (element.hide || element.control?.hide || element.area?.hide) continue;
24874
- if (element.type === "separator" /* SEPARATOR */) {
24875
- flush();
24876
- return createSeparatorParagraph(
24877
- ctx,
24878
- row,
24879
- element,
24880
- position.coordinate.leftTop[0],
24881
- position.coordinate.leftTop[1],
24882
- zone,
24883
- options
24884
- );
24885
- }
24886
- 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 */) {
24887
24900
  continue;
24888
24901
  }
24889
24902
  const x = position.coordinate.leftTop[0];
@@ -24892,25 +24905,32 @@ async function serializeRow(ctx, row, zone, options, suffix) {
24892
24905
  flush();
24893
24906
  anchorTo(x);
24894
24907
  const image = await createImageRun(element);
24895
- if (image) children.push(image);
24896
- pen += layoutWidth;
24908
+ if (image) line.children.push(image);
24909
+ line.pen += layoutWidth;
24897
24910
  continue;
24898
24911
  }
24899
24912
  if (element.type === "label" /* LABEL */) {
24900
24913
  flush();
24901
24914
  const padding = element.label?.padding || draw.getOptions().label.defaultPadding;
24902
24915
  anchorTo(x + padding[3] * scale);
24903
- children.push(
24904
- 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
+ )
24905
24925
  );
24906
- pen += measure(ctx, element.value, element);
24926
+ line.pen += measure(ctx, element.value, element);
24907
24927
  continue;
24908
24928
  }
24909
24929
  const text = getElementText(element);
24910
24930
  if (!text) continue;
24911
24931
  const natural = measure(ctx, text, element);
24912
24932
  const target = (x - zone.startX) / scale;
24913
- const isDrift = !started || target - pen > ANCHOR_EPS;
24933
+ const isDrift = !line.started || target - line.pen > ANCHOR_EPS;
24914
24934
  const extra = layoutWidth - natural;
24915
24935
  const needsSpacing = Math.abs(extra) * PX_TO_TWIP >= 1;
24916
24936
  const canJoin = run && !isDrift && !needsSpacing && isSameRunStyle(run.element, element);
@@ -24920,21 +24940,72 @@ async function serializeRow(ctx, row, zone, options, suffix) {
24920
24940
  flush();
24921
24941
  anchorTo(x);
24922
24942
  if (needsSpacing) {
24923
- children.push(
24924
- 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
+ )
24925
24952
  );
24926
24953
  } else {
24927
24954
  run = { text, element };
24928
24955
  }
24929
24956
  }
24930
- pen = target + layoutWidth;
24957
+ line.pen = target + layoutWidth;
24931
24958
  }
24932
24959
  flush();
24933
- 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) {
24934
25005
  const total = (options.skipLead ? 0 : rowLead(ctx, row, options)) + rowLine(ctx, row).lineTw + rowSpacing(ctx, row, options).after;
24935
- return createSpacerParagraph(pageBreakBefore, total / PX_TO_TWIP);
25006
+ return createSpacerParagraph(pageBreakBefore, total / PX_TO_TWIP, anchor);
24936
25007
  }
24937
- const stops = tabStops.map((position) => ({ type: import_docx2.TabStopType.LEFT, position }));
25008
+ const stops = line.tabStops.map((position) => ({ type: import_docx2.TabStopType.LEFT, position }));
24938
25009
  if (suffix) {
24939
25010
  stops.push({ type: suffix.tabType, position: suffix.tabStop });
24940
25011
  children.push(new import_docx2.TextRun({ children: [new import_docx2.Tab()] }), ...suffix.children);
@@ -24946,10 +25017,191 @@ async function serializeRow(ctx, row, zone, options, suffix) {
24946
25017
  pageBreakBefore,
24947
25018
  widowControl: false,
24948
25019
  tabStops: stops,
24949
- indent: { left: pxTw(indent), right: RIGHT_SLACK_TWIP },
25020
+ indent: { left: pxTw(line.indent), right: RIGHT_SLACK_TWIP },
24950
25021
  spacing: rowSpacing(ctx, row, options)
24951
25022
  });
24952
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
+ }
24953
25205
  var EXACT_BASELINE_RATIO = 0.8;
24954
25206
  var IMAGE_MARK_HALF_POINTS = 2;
24955
25207
  var IMAGE_MARK_DESCENT_PX = 0.3;
@@ -25046,10 +25298,7 @@ function createLineImage(width, height, color, dashArray) {
25046
25298
  ctx.moveTo(0, canvas.height / 2);
25047
25299
  ctx.lineTo(canvas.width, canvas.height / 2);
25048
25300
  ctx.stroke();
25049
- const binary = atob(canvas.toDataURL("image/png").split(",")[1]);
25050
- const bytes = new Uint8Array(binary.length);
25051
- for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
25052
- return bytes;
25301
+ return canvasToPng(canvas);
25053
25302
  }
25054
25303
  function endWithParagraph(children) {
25055
25304
  if (children[children.length - 1] instanceof import_docx2.Table) {
@@ -25057,11 +25306,12 @@ function endWithParagraph(children) {
25057
25306
  }
25058
25307
  return children;
25059
25308
  }
25060
- function createSpacerParagraph(pageBreakBefore, height = 0) {
25309
+ function createSpacerParagraph(pageBreakBefore, height = 0, anchor) {
25061
25310
  return new import_docx2.Paragraph({
25062
25311
  pageBreakBefore,
25063
25312
  widowControl: false,
25064
- 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 })],
25065
25315
  spacing: {
25066
25316
  before: 0,
25067
25317
  after: 0,
@@ -25220,6 +25470,7 @@ async function serializeFooter(ctx, pageWidth, pageHeight, margins) {
25220
25470
  const footer = draw.getFooter();
25221
25471
  const opts = draw.getOptions();
25222
25472
  const barHeight = footer.getHeight() / scale;
25473
+ const footerBottom = footer.getFooterBottom() / scale;
25223
25474
  const contentHeight = footer.getRowHeight() / scale;
25224
25475
  const paddingTop = Math.floor(Math.max(0, (barHeight - contentHeight) / 2) * scale) / scale;
25225
25476
  const zone = {
@@ -25241,56 +25492,73 @@ async function serializeFooter(ctx, pageWidth, pageHeight, margins) {
25241
25492
  }
25242
25493
  }
25243
25494
  }
25495
+ const band = opts.footer.backgroundColor ? createBandImage(
25496
+ pageWidth,
25497
+ pageHeight - footerBottom - barHeight,
25498
+ barHeight,
25499
+ opts.footer.backgroundColor
25500
+ ) : void 0;
25244
25501
  const children = [];
25245
25502
  for (let r = 0; r < rowList.length; r++) {
25246
25503
  const row = rowList[r];
25247
- const rowOptions = { padTop: r === 0 ? paddingTop : 0 };
25248
- if (r !== pageNumberRow) {
25249
- children.push(...await serializeRows(ctx, [row], zone, rowOptions));
25250
- continue;
25251
- }
25252
- const top = zone.positionList[row.startIndex].coordinate.leftTop[1] / scale;
25253
- const shift = pageNumber.baseline - (top + row.ascent / scale);
25254
- children.push(
25255
- 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 = {
25256
25508
  tabStop: pageNumber.tabStop,
25257
25509
  tabType: pageNumber.tabType,
25258
- children: pageNumber.runs(shift),
25510
+ children: pageNumber.runs(
25511
+ pageNumber.baseline - (top + row.ascent / scale)
25512
+ ),
25259
25513
  style: PAGE_NUMBER_STYLE
25260
- })
25514
+ };
25515
+ }
25516
+ children.push(
25517
+ await serializeRow(ctx, row, zone, {}, suffix, r === 0 ? band : void 0)
25261
25518
  );
25262
25519
  }
25263
- const fill = opts.footer.backgroundColor ? normalizeHexColor(opts.footer.backgroundColor, "FFFFFF") : void 0;
25264
- const none = { style: import_docx2.BorderStyle.NONE, size: 0, color: "auto" };
25265
- const band = new import_docx2.Table({
25266
- layout: import_docx2.TableLayoutType.FIXED,
25267
- width: { size: pxTw(pageWidth), type: import_docx2.WidthType.DXA },
25268
- columnWidths: [pxTw(pageWidth)],
25269
- indent: { size: -pxTw(margins[3]), type: import_docx2.WidthType.DXA },
25270
- borders: noTableBorders(),
25271
- rows: [
25272
- new import_docx2.TableRow({
25273
- cantSplit: true,
25274
- height: { value: pxTw(barHeight), rule: import_docx2.HeightRule.EXACT },
25275
- children: [
25276
- new import_docx2.TableCell({
25277
- width: { size: pxTw(pageWidth), type: import_docx2.WidthType.DXA },
25278
- margins: {
25279
- top: 0,
25280
- bottom: 0,
25281
- left: pxTw(margins[3]),
25282
- right: pxTw(margins[1]),
25283
- marginUnitType: import_docx2.WidthType.DXA
25284
- },
25285
- shading: fill ? { fill, type: import_docx2.ShadingType.CLEAR, color: "auto" } : void 0,
25286
- borders: { top: none, right: none, bottom: none, left: none },
25287
- children: children.length ? children : [createSpacerParagraph(false)]
25288
- })
25289
- ]
25290
- })
25291
- ]
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
+ }
25292
25546
  });
25293
- 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;
25294
25562
  }
25295
25563
  var PAGE_NUMBER_STYLE = "WindocPageNumber";
25296
25564
  var FieldCharAttributes = class extends import_docx2.XmlAttributeComponent {
@@ -25364,7 +25632,17 @@ function createPageNumberRuns(ctx, pageHeight, textWidth) {
25364
25632
  }).flat()
25365
25633
  };
25366
25634
  }
25367
- 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) {
25368
25646
  const opts = ctx.draw.getOptions();
25369
25647
  const isLink = element.type === "hyperlink" /* HYPERLINK */;
25370
25648
  const color = normalizeHexColor(
@@ -25384,7 +25662,8 @@ function createTextRun(ctx, text, element, shading, characterSpacing) {
25384
25662
  underline: element.underline || isLink ? { type: mapUnderlineType(element.textDecoration?.style) } : void 0,
25385
25663
  color,
25386
25664
  shading: shading || (highlight ? { fill: highlight, type: import_docx2.ShadingType.CLEAR, color: "auto" } : void 0),
25387
- characterSpacing
25665
+ characterSpacing,
25666
+ position
25388
25667
  });
25389
25668
  if (isLink && element.url) {
25390
25669
  return new import_docx2.ExternalHyperlink({ link: element.url, children: [textRun] });