@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.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/version.ts
2
- var version = "0.3.28";
2
+ var version = "0.3.29";
3
3
 
4
4
  // src/dataset/enum/Common.ts
5
5
  var MaxHeightRatio = /* @__PURE__ */ ((MaxHeightRatio2) => {
@@ -24372,13 +24372,16 @@ var Command = class {
24372
24372
 
24373
24373
  // src/utils/docxLayout.ts
24374
24374
  import {
24375
+ AlignmentType,
24375
24376
  BorderStyle,
24376
24377
  Document as Document2,
24377
24378
  ExternalHyperlink,
24378
24379
  Footer as Footer2,
24379
24380
  Header as Header2,
24380
24381
  HeightRule,
24382
+ HorizontalPositionRelativeFrom,
24381
24383
  ImageRun,
24384
+ LevelFormat,
24382
24385
  LineRuleType,
24383
24386
  Packer,
24384
24387
  PageOrientation,
@@ -24391,7 +24394,9 @@ import {
24391
24394
  TableLayoutType,
24392
24395
  TableRow,
24393
24396
  TextRun,
24397
+ TextWrappingType,
24394
24398
  VerticalAlign as DocxVerticalAlign,
24399
+ VerticalPositionRelativeFrom,
24395
24400
  WidthType,
24396
24401
  XmlAttributeComponent,
24397
24402
  XmlComponent
@@ -24632,7 +24637,8 @@ async function exportDrawToDocx(draw, options = {}) {
24632
24637
  const ctx = {
24633
24638
  draw,
24634
24639
  scale: draw.getOptions().scale,
24635
- measureCtx
24640
+ measureCtx,
24641
+ lists: /* @__PURE__ */ new Map()
24636
24642
  };
24637
24643
  const file = await createDocument(ctx);
24638
24644
  const blob = await Packer.toBlob(file);
@@ -24650,18 +24656,21 @@ async function createDocument(ctx) {
24650
24656
  const headerExtra = header.getExtraHeight() / scale;
24651
24657
  const footerExtra = footer.getExtraHeight() / scale;
24652
24658
  const layoutMargins = draw.getMargins();
24659
+ planLists(ctx);
24653
24660
  const body = await serializeMain(ctx, layoutMargins[3]);
24654
24661
  const headerChildren = opts.header.disabled ? [] : await serializeRows(ctx, header.getRowList(), {
24655
24662
  startX: layoutMargins[3],
24656
24663
  width: draw.getInnerWidth(),
24657
24664
  positionList: header.getPositionList()
24658
24665
  });
24659
- const footerChildren = opts.footer.disabled ? [] : await serializeFooter(ctx, width, height, margins);
24666
+ const footerResult = opts.footer.disabled ? { children: [], distance: footer.getFooterBottom() / scale } : await serializeFooter(ctx, width, height, margins);
24667
+ const footerChildren = footerResult.children;
24660
24668
  const { pageNumber } = draw.getOptions();
24661
24669
  endWithParagraph(headerChildren);
24662
24670
  endWithParagraph(footerChildren);
24663
24671
  return new Document2({
24664
24672
  compatabilityModeVersion: 15,
24673
+ numbering: { config: createNumberingConfig(ctx) },
24665
24674
  // LibreOffice formats PAGE/NUMPAGES results from the paragraph style
24666
24675
  styles: {
24667
24676
  paragraphStyles: [
@@ -24688,7 +24697,7 @@ async function createDocument(ctx) {
24688
24697
  bottom: pxTw(margins[2] + footerExtra),
24689
24698
  left: pxTw(margins[3]),
24690
24699
  header: pxTw(headerTop),
24691
- footer: pxTw(footer.getFooterBottom() / scale),
24700
+ footer: pxTw(footerResult.distance),
24692
24701
  gutter: 0
24693
24702
  }
24694
24703
  }
@@ -24720,13 +24729,14 @@ async function serializeMain(ctx, startX) {
24720
24729
  }
24721
24730
  async function serializeRows(ctx, rowList, zone, options = {}) {
24722
24731
  const { pageBreakBefore = false, padTop = 0, padBottom = 0 } = options;
24732
+ const units = groupUnits(ctx, rowList, zone);
24723
24733
  const children = [];
24724
- for (let r = 0; r < rowList.length; r++) {
24725
- const row = rowList[r];
24726
- const isFirst = r === 0;
24727
- const isLast = r === rowList.length - 1;
24728
- const table = row.elementList.find((el) => el.type === "table" /* TABLE */);
24729
- if (table) {
24734
+ for (let u = 0; u < units.length; u++) {
24735
+ const unit = units[u];
24736
+ const isFirst = u === 0;
24737
+ const isLast = u === units.length - 1;
24738
+ if (unit.kind === "table") {
24739
+ const { row, table } = unit;
24730
24740
  if (isFirst && (pageBreakBefore || padTop) || row.offsetY) {
24731
24741
  children.push(
24732
24742
  createSpacerParagraph(
@@ -24743,72 +24753,92 @@ async function serializeRows(ctx, rowList, zone, options = {}) {
24743
24753
  }
24744
24754
  continue;
24745
24755
  }
24756
+ const first = unitFirstRow(unit);
24746
24757
  const rowOptions = {
24747
24758
  pageBreakBefore: isFirst && pageBreakBefore,
24748
24759
  padTop: isFirst ? padTop : 0,
24749
- padBottom: isLast ? padBottom : 0
24760
+ padBottom: isLast ? padBottom : 0,
24761
+ rowY: rowY(zone, first)
24750
24762
  };
24751
- if (!isFirst && isTextRow(rowList[r - 1])) rowOptions.skipLead = true;
24752
- rowOptions.rowY = rowY(zone, row);
24753
- if (!isLast && isTextRow(rowList[r + 1])) {
24754
- rowOptions.extraAfter = rowLead(ctx, rowList[r + 1], {
24755
- rowY: rowY(zone, rowList[r + 1])
24756
- });
24763
+ if (!isFirst && units[u - 1].kind !== "table") rowOptions.skipLead = true;
24764
+ const next = units[u + 1];
24765
+ if (next && next.kind !== "table") {
24766
+ rowOptions.extraAfter = unitLead(ctx, next, zone, {});
24757
24767
  }
24758
- const lead = rowOptions.pageBreakBefore ? rowLead(ctx, row, rowOptions) : 0;
24768
+ const lead = rowOptions.pageBreakBefore ? unitLead(ctx, unit, zone, rowOptions) : 0;
24759
24769
  if (lead) {
24760
24770
  children.push(createSpacerParagraph(true, lead / PX_TO_TWIP));
24761
24771
  rowOptions.pageBreakBefore = false;
24762
24772
  rowOptions.skipLead = true;
24763
24773
  }
24764
- children.push(await serializeRow(ctx, row, zone, rowOptions));
24774
+ children.push(
24775
+ unit.kind === "list" ? await serializeListItem(ctx, unit.rows, zone, rowOptions) : await serializeRow(ctx, unit.row, zone, rowOptions)
24776
+ );
24765
24777
  }
24766
24778
  return children;
24767
24779
  }
24780
+ function unitFirstRow(unit) {
24781
+ return unit.kind === "list" ? unit.rows[0] : unit.row;
24782
+ }
24783
+ function unitLead(ctx, unit, zone, options) {
24784
+ if (unit.kind === "list") return listLead(ctx, unit.rows[0], options);
24785
+ const row = unitFirstRow(unit);
24786
+ return rowLead(ctx, row, { ...options, rowY: rowY(zone, row) });
24787
+ }
24788
+ function groupUnits(ctx, rowList, zone) {
24789
+ const units = [];
24790
+ for (let r = 0; r < rowList.length; r++) {
24791
+ const row = rowList[r];
24792
+ const table = row.elementList.find((el) => el.type === "table" /* TABLE */);
24793
+ if (table) {
24794
+ units.push({ kind: "table", row, table });
24795
+ continue;
24796
+ }
24797
+ if (isNativeListStart(ctx, row, zone)) {
24798
+ const rows = [row];
24799
+ while (r + 1 < rowList.length && isListContinuation(row, rowList[r + 1])) {
24800
+ rows.push(rowList[++r]);
24801
+ }
24802
+ units.push({ kind: "list", rows });
24803
+ continue;
24804
+ }
24805
+ units.push({ kind: "row", row });
24806
+ }
24807
+ return units;
24808
+ }
24768
24809
  function rowY(zone, row) {
24769
24810
  return zone.positionList[row.startIndex]?.coordinate.leftTop[1];
24770
24811
  }
24771
- function isTextRow(row) {
24772
- return !row.elementList.some((el) => el.type === "table" /* TABLE */);
24773
- }
24774
- async function serializeRow(ctx, row, zone, options, suffix) {
24775
- const { pageBreakBefore = false } = options;
24812
+ async function appendRowRuns(ctx, row, zone, line) {
24776
24813
  const { draw, scale } = ctx;
24777
24814
  const positions = zone.positionList;
24778
- const children = [];
24779
- const tabStops = [];
24780
- const firstPosition = positions[row.startIndex];
24781
- let pen = 0;
24782
- let indent = firstPosition ? (firstPosition.coordinate.leftTop[0] - zone.startX) / scale : 0;
24783
- let started = false;
24784
24815
  const anchorTo = (layoutX) => {
24785
24816
  const target = (layoutX - zone.startX) / scale;
24786
- if (!started) {
24787
- indent = target;
24788
- pen = target;
24789
- started = true;
24817
+ if (!line.started) {
24818
+ line.indent = target;
24819
+ line.pen = target;
24820
+ line.started = true;
24790
24821
  return;
24791
24822
  }
24792
- if (target - pen > ANCHOR_EPS) {
24793
- tabStops.push(pxTw(target));
24794
- children.push(new TextRun({ children: [new Tab()] }));
24795
- pen = target;
24823
+ if (target - line.pen > ANCHOR_EPS) {
24824
+ line.tabStops.push(pxTw(target));
24825
+ line.children.push(new TextRun({ children: [new Tab()] }));
24826
+ line.pen = target;
24796
24827
  }
24797
24828
  };
24798
- if (row.isList && firstPosition) {
24799
- const listParticle = draw.getListParticle();
24800
- const markerX = listParticle.getListMarkerX(row, firstPosition);
24801
- const marker = markerX === null ? null : listParticle.getListMarker(row);
24802
- if (markerX !== null && marker) {
24803
- anchorTo(markerX);
24804
- children.push(createTextRun(ctx, marker.text, marker.styleElement));
24805
- pen += measure(ctx, marker.text, marker.styleElement);
24806
- }
24807
- }
24808
24829
  let run = null;
24809
24830
  const flush = () => {
24810
24831
  if (!run) return;
24811
- children.push(createTextRun(ctx, run.text, run.element));
24832
+ line.children.push(
24833
+ createTextRun(
24834
+ ctx,
24835
+ run.text,
24836
+ run.element,
24837
+ void 0,
24838
+ void 0,
24839
+ line.position
24840
+ )
24841
+ );
24812
24842
  run = null;
24813
24843
  };
24814
24844
  for (let j = 0; j < row.elementList.length; j++) {
@@ -24816,19 +24846,7 @@ async function serializeRow(ctx, row, zone, options, suffix) {
24816
24846
  const position = positions[row.startIndex + j];
24817
24847
  if (!position) continue;
24818
24848
  if (element.hide || element.control?.hide || element.area?.hide) continue;
24819
- if (element.type === "separator" /* SEPARATOR */) {
24820
- flush();
24821
- return createSeparatorParagraph(
24822
- ctx,
24823
- row,
24824
- element,
24825
- position.coordinate.leftTop[0],
24826
- position.coordinate.leftTop[1],
24827
- zone,
24828
- options
24829
- );
24830
- }
24831
- if (element.value === ZERO || element.type === "tab" /* TAB */ || element.type === "pageBreak" /* PAGE_BREAK */ || element.type === "columnBreak" /* COLUMN_BREAK */) {
24849
+ if (element.value === ZERO || element.type === "tab" /* TAB */ || element.type === "pageBreak" /* PAGE_BREAK */ || element.type === "columnBreak" /* COLUMN_BREAK */ || element.type === "separator" /* SEPARATOR */) {
24832
24850
  continue;
24833
24851
  }
24834
24852
  const x = position.coordinate.leftTop[0];
@@ -24837,25 +24855,32 @@ async function serializeRow(ctx, row, zone, options, suffix) {
24837
24855
  flush();
24838
24856
  anchorTo(x);
24839
24857
  const image = await createImageRun(element);
24840
- if (image) children.push(image);
24841
- pen += layoutWidth;
24858
+ if (image) line.children.push(image);
24859
+ line.pen += layoutWidth;
24842
24860
  continue;
24843
24861
  }
24844
24862
  if (element.type === "label" /* LABEL */) {
24845
24863
  flush();
24846
24864
  const padding = element.label?.padding || draw.getOptions().label.defaultPadding;
24847
24865
  anchorTo(x + padding[3] * scale);
24848
- children.push(
24849
- createTextRun(ctx, element.value, element, labelShading(ctx, element))
24866
+ line.children.push(
24867
+ createTextRun(
24868
+ ctx,
24869
+ element.value,
24870
+ element,
24871
+ labelShading(ctx, element),
24872
+ void 0,
24873
+ line.position
24874
+ )
24850
24875
  );
24851
- pen += measure(ctx, element.value, element);
24876
+ line.pen += measure(ctx, element.value, element);
24852
24877
  continue;
24853
24878
  }
24854
24879
  const text = getElementText(element);
24855
24880
  if (!text) continue;
24856
24881
  const natural = measure(ctx, text, element);
24857
24882
  const target = (x - zone.startX) / scale;
24858
- const isDrift = !started || target - pen > ANCHOR_EPS;
24883
+ const isDrift = !line.started || target - line.pen > ANCHOR_EPS;
24859
24884
  const extra = layoutWidth - natural;
24860
24885
  const needsSpacing = Math.abs(extra) * PX_TO_TWIP >= 1;
24861
24886
  const canJoin = run && !isDrift && !needsSpacing && isSameRunStyle(run.element, element);
@@ -24865,21 +24890,72 @@ async function serializeRow(ctx, row, zone, options, suffix) {
24865
24890
  flush();
24866
24891
  anchorTo(x);
24867
24892
  if (needsSpacing) {
24868
- children.push(
24869
- createTextRun(ctx, text, element, void 0, pxTw(extra))
24893
+ line.children.push(
24894
+ createTextRun(
24895
+ ctx,
24896
+ text,
24897
+ element,
24898
+ void 0,
24899
+ pxTw(extra),
24900
+ line.position
24901
+ )
24870
24902
  );
24871
24903
  } else {
24872
24904
  run = { text, element };
24873
24905
  }
24874
24906
  }
24875
- pen = target + layoutWidth;
24907
+ line.pen = target + layoutWidth;
24876
24908
  }
24877
24909
  flush();
24878
- if (!children.length && !suffix) {
24910
+ }
24911
+ async function serializeRow(ctx, row, zone, options, suffix, anchor) {
24912
+ const { pageBreakBefore = false } = options;
24913
+ const { draw, scale } = ctx;
24914
+ const firstPosition = zone.positionList[row.startIndex];
24915
+ const separatorIndex = row.elementList.findIndex(
24916
+ (el) => el.type === "separator" /* SEPARATOR */
24917
+ );
24918
+ if (separatorIndex >= 0) {
24919
+ const position = zone.positionList[row.startIndex + separatorIndex];
24920
+ if (position) {
24921
+ return createSeparatorParagraph(
24922
+ ctx,
24923
+ row,
24924
+ row.elementList[separatorIndex],
24925
+ position.coordinate.leftTop[0],
24926
+ position.coordinate.leftTop[1],
24927
+ zone,
24928
+ options
24929
+ );
24930
+ }
24931
+ }
24932
+ const line = {
24933
+ children: [],
24934
+ tabStops: [],
24935
+ pen: 0,
24936
+ started: false,
24937
+ indent: firstPosition ? (firstPosition.coordinate.leftTop[0] - zone.startX) / scale : 0
24938
+ };
24939
+ if (row.isList && firstPosition) {
24940
+ const listParticle = draw.getListParticle();
24941
+ const markerX = listParticle.getListMarkerX(row, firstPosition);
24942
+ const marker = markerX === null ? null : listParticle.getListMarker(row);
24943
+ if (markerX !== null && marker) {
24944
+ line.indent = (markerX - zone.startX) / scale;
24945
+ line.pen = line.indent;
24946
+ line.started = true;
24947
+ line.children.push(createTextRun(ctx, marker.text, marker.styleElement));
24948
+ line.pen += measure(ctx, marker.text, marker.styleElement);
24949
+ }
24950
+ }
24951
+ await appendRowRuns(ctx, row, zone, line);
24952
+ const { children } = line;
24953
+ if (anchor) children.unshift(anchor);
24954
+ if (!line.started && !suffix) {
24879
24955
  const total = (options.skipLead ? 0 : rowLead(ctx, row, options)) + rowLine(ctx, row).lineTw + rowSpacing(ctx, row, options).after;
24880
- return createSpacerParagraph(pageBreakBefore, total / PX_TO_TWIP);
24956
+ return createSpacerParagraph(pageBreakBefore, total / PX_TO_TWIP, anchor);
24881
24957
  }
24882
- const stops = tabStops.map((position) => ({ type: TabStopType.LEFT, position }));
24958
+ const stops = line.tabStops.map((position) => ({ type: TabStopType.LEFT, position }));
24883
24959
  if (suffix) {
24884
24960
  stops.push({ type: suffix.tabType, position: suffix.tabStop });
24885
24961
  children.push(new TextRun({ children: [new Tab()] }), ...suffix.children);
@@ -24891,10 +24967,191 @@ async function serializeRow(ctx, row, zone, options, suffix) {
24891
24967
  pageBreakBefore,
24892
24968
  widowControl: false,
24893
24969
  tabStops: stops,
24894
- indent: { left: pxTw(indent), right: RIGHT_SLACK_TWIP },
24970
+ indent: { left: pxTw(line.indent), right: RIGHT_SLACK_TWIP },
24895
24971
  spacing: rowSpacing(ctx, row, options)
24896
24972
  });
24897
24973
  }
24974
+ var olStyleFormat = {
24975
+ decimal: { format: LevelFormat.DECIMAL, suffix: "." },
24976
+ decimalParen: { format: LevelFormat.DECIMAL, suffix: ")" },
24977
+ decimalZero: { format: LevelFormat.DECIMAL_ZERO, suffix: "." },
24978
+ lowerAlpha: { format: LevelFormat.LOWER_LETTER, suffix: "." },
24979
+ lowerAlphaParen: { format: LevelFormat.LOWER_LETTER, suffix: ")" },
24980
+ upperAlpha: { format: LevelFormat.UPPER_LETTER, suffix: "." },
24981
+ lowerRoman: { format: LevelFormat.LOWER_ROMAN, suffix: "." },
24982
+ lowerRomanParen: { format: LevelFormat.LOWER_ROMAN, suffix: ")" },
24983
+ upperRoman: { format: LevelFormat.UPPER_ROMAN, suffix: "." },
24984
+ outline: { format: LevelFormat.DECIMAL, suffix: "." }
24985
+ };
24986
+ function isListItemStart(row) {
24987
+ const first = row.elementList[0];
24988
+ return !!row.isList && first?.value === ZERO && !first.listWrap;
24989
+ }
24990
+ function rowListId(row) {
24991
+ return row.elementList.find((el) => el.listId)?.listId;
24992
+ }
24993
+ function levelSpec(element, markerText) {
24994
+ const level = Math.min(element.listLevel ?? 0, 8);
24995
+ if (element.listType === "ul" /* UL */) {
24996
+ return { level, format: LevelFormat.BULLET, text: markerText };
24997
+ }
24998
+ const cycle = element.listPreset ? olPresetCycles[element.listPreset] : void 0;
24999
+ const style = cycle ? cycle[level % cycle.length] : "decimal";
25000
+ const spec = olStyleFormat[style] || olStyleFormat.decimal;
25001
+ return { level, format: spec.format, text: `%${level + 1}${spec.suffix}` };
25002
+ }
25003
+ function planLists(ctx) {
25004
+ const listParticle = ctx.draw.getListParticle();
25005
+ const counters = /* @__PURE__ */ new Map();
25006
+ const visit = (rowList) => {
25007
+ for (const row of rowList) {
25008
+ const table = row.elementList.find((el) => el.type === "table" /* TABLE */);
25009
+ if (table) {
25010
+ for (const tr of table.trList || []) {
25011
+ for (const td of tr.tdList) visit(td.rowList || []);
25012
+ }
25013
+ continue;
25014
+ }
25015
+ if (!isListItemStart(row)) continue;
25016
+ const listId = rowListId(row);
25017
+ if (!listId) continue;
25018
+ let plan2 = ctx.lists.get(listId);
25019
+ if (!plan2) {
25020
+ plan2 = {
25021
+ reference: `windoc-list-${ctx.lists.size + 1}`,
25022
+ native: true,
25023
+ levels: /* @__PURE__ */ new Map()
25024
+ };
25025
+ ctx.lists.set(listId, plan2);
25026
+ }
25027
+ const marker = listParticle.getListMarker(row);
25028
+ if (!marker || hasInlineImage(row)) {
25029
+ plan2.native = false;
25030
+ continue;
25031
+ }
25032
+ const spec = levelSpec(row.elementList[0], marker.text);
25033
+ const known = plan2.levels.get(spec.level);
25034
+ if (known && (known.format !== spec.format || known.text !== spec.text)) {
25035
+ plan2.native = false;
25036
+ }
25037
+ plan2.levels.set(spec.level, spec);
25038
+ const count = counters.get(listId) || [];
25039
+ counters.set(listId, count);
25040
+ count[spec.level] = (count[spec.level] || 0) + 1;
25041
+ count.length = spec.level + 1;
25042
+ if (spec.format !== LevelFormat.BULLET && count[spec.level] !== (row.listIndex ?? 0) + 1) {
25043
+ plan2.native = false;
25044
+ }
25045
+ }
25046
+ };
25047
+ ctx.draw.getPageRowList().forEach(visit);
25048
+ }
25049
+ function createNumberingConfig(ctx) {
25050
+ return [...ctx.lists.values()].filter((plan2) => plan2.native).map((plan2) => ({
25051
+ reference: plan2.reference,
25052
+ levels: Array.from({ length: 9 }, (_, level) => {
25053
+ const spec = plan2.levels.get(level) || {
25054
+ format: LevelFormat.DECIMAL,
25055
+ text: `%${level + 1}.`
25056
+ };
25057
+ return {
25058
+ level,
25059
+ format: spec.format,
25060
+ text: spec.text,
25061
+ alignment: AlignmentType.LEFT
25062
+ };
25063
+ })
25064
+ }));
25065
+ }
25066
+ function listMarkerGeometry(ctx, row, zone) {
25067
+ const listParticle = ctx.draw.getListParticle();
25068
+ const firstPosition = zone.positionList[row.startIndex];
25069
+ if (!firstPosition) return null;
25070
+ const markerX = listParticle.getListMarkerX(row, firstPosition);
25071
+ const marker = listParticle.getListMarker(row);
25072
+ if (markerX === null || !marker) return null;
25073
+ const textIndex = row.elementList.findIndex(
25074
+ (el) => el.value !== ZERO && el.type !== "tab" /* TAB */
25075
+ );
25076
+ const textPosition = textIndex >= 0 ? zone.positionList[row.startIndex + textIndex] : firstPosition;
25077
+ const textX = textPosition.coordinate.leftTop[0];
25078
+ if (textX - markerX <= 0) return null;
25079
+ return {
25080
+ marker,
25081
+ indent: (textX - zone.startX) / ctx.scale,
25082
+ hanging: (textX - markerX) / ctx.scale
25083
+ };
25084
+ }
25085
+ function isNativeListStart(ctx, row, zone) {
25086
+ if (!isListItemStart(row) || hasInlineImage(row)) return false;
25087
+ const listId = rowListId(row);
25088
+ if (!listId || !ctx.lists.get(listId)?.native) return false;
25089
+ if (row.elementList.some((el) => el.type === "separator" /* SEPARATOR */)) {
25090
+ return false;
25091
+ }
25092
+ return !!listMarkerGeometry(ctx, row, zone);
25093
+ }
25094
+ function isListContinuation(start, row) {
25095
+ 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(
25096
+ (el) => el.type === "table" /* TABLE */ || el.type === "separator" /* SEPARATOR */
25097
+ );
25098
+ }
25099
+ function listLead(ctx, row, options) {
25100
+ return tw(ctx, (row.offsetY || 0) + (row.spaceAbove || 0)) + pxTw(options.padTop || 0);
25101
+ }
25102
+ async function serializeListItem(ctx, rows, zone, options) {
25103
+ const { scale } = ctx;
25104
+ const first = rows[0];
25105
+ const last = rows[rows.length - 1];
25106
+ const geometry = listMarkerGeometry(ctx, first, zone);
25107
+ const plan2 = ctx.lists.get(rowListId(first));
25108
+ const height = first.height / scale;
25109
+ const raise = Math.round(
25110
+ (EXACT_BASELINE_RATIO * height - first.ascent / scale) * 1.5
25111
+ );
25112
+ const position = raise ? `${raise}` : void 0;
25113
+ const line = {
25114
+ children: [],
25115
+ tabStops: [],
25116
+ pen: geometry.indent,
25117
+ started: true,
25118
+ indent: geometry.indent,
25119
+ position
25120
+ };
25121
+ for (let i = 0; i < rows.length; i++) {
25122
+ if (i > 0) {
25123
+ line.children.push(new TextRun({ break: 1 }));
25124
+ line.pen = geometry.indent;
25125
+ }
25126
+ await appendRowRuns(ctx, rows[i], zone, line);
25127
+ }
25128
+ return new Paragraph({
25129
+ children: line.children,
25130
+ numbering: {
25131
+ reference: plan2.reference,
25132
+ level: Math.min(first.elementList[0].listLevel ?? 0, 8)
25133
+ },
25134
+ // the number is drawn with the paragraph mark's formatting
25135
+ run: { ...runStyle(ctx, geometry.marker.styleElement), position },
25136
+ pageBreakBefore: options.pageBreakBefore,
25137
+ widowControl: false,
25138
+ tabStops: [...new Set(line.tabStops)].map((tabPosition) => ({
25139
+ type: TabStopType.LEFT,
25140
+ position: tabPosition
25141
+ })),
25142
+ indent: {
25143
+ left: pxTw(geometry.indent),
25144
+ hanging: pxTw(geometry.hanging),
25145
+ right: RIGHT_SLACK_TWIP
25146
+ },
25147
+ spacing: {
25148
+ before: options.skipLead ? 0 : listLead(ctx, first, options),
25149
+ after: tw(ctx, last.spaceBelow || 0) + pxTw(options.padBottom || 0) + (options.extraAfter || 0),
25150
+ line: pxTw(height),
25151
+ lineRule: LineRuleType.EXACT
25152
+ }
25153
+ });
25154
+ }
24898
25155
  var EXACT_BASELINE_RATIO = 0.8;
24899
25156
  var IMAGE_MARK_HALF_POINTS = 2;
24900
25157
  var IMAGE_MARK_DESCENT_PX = 0.3;
@@ -24991,10 +25248,7 @@ function createLineImage(width, height, color, dashArray) {
24991
25248
  ctx.moveTo(0, canvas.height / 2);
24992
25249
  ctx.lineTo(canvas.width, canvas.height / 2);
24993
25250
  ctx.stroke();
24994
- const binary = atob(canvas.toDataURL("image/png").split(",")[1]);
24995
- const bytes = new Uint8Array(binary.length);
24996
- for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
24997
- return bytes;
25251
+ return canvasToPng(canvas);
24998
25252
  }
24999
25253
  function endWithParagraph(children) {
25000
25254
  if (children[children.length - 1] instanceof Table) {
@@ -25002,11 +25256,12 @@ function endWithParagraph(children) {
25002
25256
  }
25003
25257
  return children;
25004
25258
  }
25005
- function createSpacerParagraph(pageBreakBefore, height = 0) {
25259
+ function createSpacerParagraph(pageBreakBefore, height = 0, anchor) {
25006
25260
  return new Paragraph({
25007
25261
  pageBreakBefore,
25008
25262
  widowControl: false,
25009
- children: [new TextRun({ text: "", size: 2 })],
25263
+ run: { size: 2 },
25264
+ children: anchor ? [anchor, new TextRun({ text: "", size: 2 })] : [new TextRun({ text: "", size: 2 })],
25010
25265
  spacing: {
25011
25266
  before: 0,
25012
25267
  after: 0,
@@ -25165,6 +25420,7 @@ async function serializeFooter(ctx, pageWidth, pageHeight, margins) {
25165
25420
  const footer = draw.getFooter();
25166
25421
  const opts = draw.getOptions();
25167
25422
  const barHeight = footer.getHeight() / scale;
25423
+ const footerBottom = footer.getFooterBottom() / scale;
25168
25424
  const contentHeight = footer.getRowHeight() / scale;
25169
25425
  const paddingTop = Math.floor(Math.max(0, (barHeight - contentHeight) / 2) * scale) / scale;
25170
25426
  const zone = {
@@ -25186,56 +25442,73 @@ async function serializeFooter(ctx, pageWidth, pageHeight, margins) {
25186
25442
  }
25187
25443
  }
25188
25444
  }
25445
+ const band = opts.footer.backgroundColor ? createBandImage(
25446
+ pageWidth,
25447
+ pageHeight - footerBottom - barHeight,
25448
+ barHeight,
25449
+ opts.footer.backgroundColor
25450
+ ) : void 0;
25189
25451
  const children = [];
25190
25452
  for (let r = 0; r < rowList.length; r++) {
25191
25453
  const row = rowList[r];
25192
- const rowOptions = { padTop: r === 0 ? paddingTop : 0 };
25193
- if (r !== pageNumberRow) {
25194
- children.push(...await serializeRows(ctx, [row], zone, rowOptions));
25195
- continue;
25196
- }
25197
- const top = zone.positionList[row.startIndex].coordinate.leftTop[1] / scale;
25198
- const shift = pageNumber.baseline - (top + row.ascent / scale);
25199
- children.push(
25200
- await serializeRow(ctx, row, zone, rowOptions, {
25454
+ let suffix;
25455
+ if (r === pageNumberRow) {
25456
+ const top = zone.positionList[row.startIndex].coordinate.leftTop[1] / scale;
25457
+ suffix = {
25201
25458
  tabStop: pageNumber.tabStop,
25202
25459
  tabType: pageNumber.tabType,
25203
- children: pageNumber.runs(shift),
25460
+ children: pageNumber.runs(
25461
+ pageNumber.baseline - (top + row.ascent / scale)
25462
+ ),
25204
25463
  style: PAGE_NUMBER_STYLE
25205
- })
25464
+ };
25465
+ }
25466
+ children.push(
25467
+ await serializeRow(ctx, row, zone, {}, suffix, r === 0 ? band : void 0)
25206
25468
  );
25207
25469
  }
25208
- const fill = opts.footer.backgroundColor ? normalizeHexColor(opts.footer.backgroundColor, "FFFFFF") : void 0;
25209
- const none = { style: BorderStyle.NONE, size: 0, color: "auto" };
25210
- const band = new Table({
25211
- layout: TableLayoutType.FIXED,
25212
- width: { size: pxTw(pageWidth), type: WidthType.DXA },
25213
- columnWidths: [pxTw(pageWidth)],
25214
- indent: { size: -pxTw(margins[3]), type: WidthType.DXA },
25215
- borders: noTableBorders(),
25216
- rows: [
25217
- new TableRow({
25218
- cantSplit: true,
25219
- height: { value: pxTw(barHeight), rule: HeightRule.EXACT },
25220
- children: [
25221
- new TableCell({
25222
- width: { size: pxTw(pageWidth), type: WidthType.DXA },
25223
- margins: {
25224
- top: 0,
25225
- bottom: 0,
25226
- left: pxTw(margins[3]),
25227
- right: pxTw(margins[1]),
25228
- marginUnitType: WidthType.DXA
25229
- },
25230
- shading: fill ? { fill, type: ShadingType.CLEAR, color: "auto" } : void 0,
25231
- borders: { top: none, right: none, bottom: none, left: none },
25232
- children: children.length ? children : [createSpacerParagraph(false)]
25233
- })
25234
- ]
25235
- })
25236
- ]
25470
+ if (!children.length && band) {
25471
+ children.push(createSpacerParagraph(false, 0, band));
25472
+ }
25473
+ const contentTop = pageHeight - footerBottom - barHeight + paddingTop;
25474
+ const distance = Math.max(0, pageHeight - contentTop - contentHeight);
25475
+ return { children, distance };
25476
+ }
25477
+ var EMU_PER_PX = 9525;
25478
+ function createBandImage(width, top, height, color) {
25479
+ return new ImageRun({
25480
+ type: "png",
25481
+ data: createFillImage(color),
25482
+ transformation: { width, height },
25483
+ floating: {
25484
+ horizontalPosition: {
25485
+ relative: HorizontalPositionRelativeFrom.PAGE,
25486
+ offset: 0
25487
+ },
25488
+ verticalPosition: {
25489
+ relative: VerticalPositionRelativeFrom.PAGE,
25490
+ offset: Math.round(top * EMU_PER_PX)
25491
+ },
25492
+ behindDocument: true,
25493
+ allowOverlap: true,
25494
+ wrap: { type: TextWrappingType.NONE }
25495
+ }
25237
25496
  });
25238
- return [band];
25497
+ }
25498
+ function createFillImage(color) {
25499
+ const canvas = document.createElement("canvas");
25500
+ canvas.width = 4;
25501
+ canvas.height = 4;
25502
+ const ctx = canvas.getContext("2d");
25503
+ ctx.fillStyle = color;
25504
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
25505
+ return canvasToPng(canvas);
25506
+ }
25507
+ function canvasToPng(canvas) {
25508
+ const binary = atob(canvas.toDataURL("image/png").split(",")[1]);
25509
+ const bytes = new Uint8Array(binary.length);
25510
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
25511
+ return bytes;
25239
25512
  }
25240
25513
  var PAGE_NUMBER_STYLE = "WindocPageNumber";
25241
25514
  var FieldCharAttributes = class extends XmlAttributeComponent {
@@ -25309,7 +25582,17 @@ function createPageNumberRuns(ctx, pageHeight, textWidth) {
25309
25582
  }).flat()
25310
25583
  };
25311
25584
  }
25312
- function createTextRun(ctx, text, element, shading, characterSpacing) {
25585
+ function runStyle(ctx, element) {
25586
+ const opts = ctx.draw.getOptions();
25587
+ return {
25588
+ font: mapFont(element.font || opts.defaultFont),
25589
+ size: Math.round(getSize(ctx, element) * 2),
25590
+ bold: !!element.bold,
25591
+ italics: !!element.italic,
25592
+ color: normalizeHexColor(element.color || opts.defaultColor, "000000")
25593
+ };
25594
+ }
25595
+ function createTextRun(ctx, text, element, shading, characterSpacing, position) {
25313
25596
  const opts = ctx.draw.getOptions();
25314
25597
  const isLink = element.type === "hyperlink" /* HYPERLINK */;
25315
25598
  const color = normalizeHexColor(
@@ -25329,7 +25612,8 @@ function createTextRun(ctx, text, element, shading, characterSpacing) {
25329
25612
  underline: element.underline || isLink ? { type: mapUnderlineType(element.textDecoration?.style) } : void 0,
25330
25613
  color,
25331
25614
  shading: shading || (highlight ? { fill: highlight, type: ShadingType.CLEAR, color: "auto" } : void 0),
25332
- characterSpacing
25615
+ characterSpacing,
25616
+ position
25333
25617
  });
25334
25618
  if (isLink && element.url) {
25335
25619
  return new ExternalHyperlink({ link: element.url, children: [textRun] });