@windoc/core 0.3.26 → 0.3.27

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.26";
2
+ var version = "0.3.27";
3
3
 
4
4
  // src/dataset/enum/Common.ts
5
5
  var MaxHeightRatio = /* @__PURE__ */ ((MaxHeightRatio2) => {
@@ -19111,10 +19111,11 @@ var ListParticle = class {
19111
19111
  if (!cycle) return "\u25CF";
19112
19112
  return cycle[level % cycle.length];
19113
19113
  }
19114
- drawListStyle(ctx, row, position) {
19115
- const { elementList, offsetX, listIndex, ascent } = row;
19114
+ // Marker x for a list row's first line (shared by canvas drawing and export)
19115
+ getListMarkerX(row, position) {
19116
+ const { elementList, offsetX } = row;
19116
19117
  const startElement = elementList[0];
19117
- if (startElement.value !== ZERO || startElement.listWrap) return;
19118
+ if (startElement.value !== ZERO || startElement.listWrap) return null;
19118
19119
  let tabWidth = 0;
19119
19120
  const { defaultTabWidth, scale } = this.options;
19120
19121
  for (let i = 1; i < elementList.length; i++) {
@@ -19124,12 +19125,29 @@ var ListParticle = class {
19124
19125
  }
19125
19126
  const {
19126
19127
  coordinate: {
19127
- leftTop: [startX, startY]
19128
+ leftTop: [startX]
19128
19129
  }
19129
19130
  } = position;
19130
19131
  const indentWidth = this.getListIndentWidth(startElement);
19131
- const x = startX - offsetX + tabWidth + indentWidth;
19132
- const y = startY + ascent;
19132
+ return startX - offsetX + tabWidth + indentWidth;
19133
+ }
19134
+ getListMarker(row) {
19135
+ const startElement = row.elementList[0];
19136
+ if (startElement.listStyle === "checkbox" /* CHECKBOX */) return null;
19137
+ const text = this._getListMarkerText(startElement, row.listIndex);
19138
+ if (!text) return null;
19139
+ return {
19140
+ text,
19141
+ styleElement: this._getListMarkerStyleElement(row.elementList)
19142
+ };
19143
+ }
19144
+ drawListStyle(ctx, row, position) {
19145
+ const { elementList, ascent } = row;
19146
+ const startElement = elementList[0];
19147
+ const x = this.getListMarkerX(row, position);
19148
+ if (x === null) return;
19149
+ const { scale } = this.options;
19150
+ const y = position.coordinate.leftTop[1] + ascent;
19133
19151
  if (startElement.listStyle === "checkbox" /* CHECKBOX */) {
19134
19152
  const { width, height, gap } = this.options.checkbox;
19135
19153
  const checkboxRowElement = {
@@ -19154,12 +19172,11 @@ var ListParticle = class {
19154
19172
  }
19155
19173
  });
19156
19174
  } else {
19157
- const text = this._getListMarkerText(startElement, listIndex);
19158
- if (!text) return;
19159
- const markerStyleElement = this._getListMarkerStyleElement(elementList);
19175
+ const marker = this.getListMarker(row);
19176
+ if (!marker) return;
19160
19177
  ctx.save();
19161
- ctx.font = this.draw.getElementFont(markerStyleElement, scale);
19162
- ctx.fillText(text, x, y);
19178
+ ctx.font = this.draw.getElementFont(marker.styleElement, scale);
19179
+ ctx.fillText(marker.text, x, y);
19163
19180
  ctx.restore();
19164
19181
  }
19165
19182
  }
@@ -24347,1273 +24364,1016 @@ var Command = class {
24347
24364
  }
24348
24365
  };
24349
24366
 
24350
- // src/utils/docx.ts
24367
+ // src/utils/docxLayout.ts
24351
24368
  import {
24352
- AlignmentType,
24353
24369
  BorderStyle,
24354
- ColumnBreak,
24355
24370
  Document as Document2,
24356
24371
  ExternalHyperlink,
24357
24372
  Footer as Footer2,
24358
24373
  Header as Header2,
24359
- HeadingLevel,
24374
+ HeightRule,
24360
24375
  ImageRun,
24361
- LevelFormat,
24362
24376
  LineRuleType,
24363
24377
  Packer,
24364
- PageBreak,
24365
- PageNumber as PageNumber2,
24366
24378
  PageOrientation,
24367
24379
  Paragraph,
24368
24380
  ShadingType,
24381
+ Tab,
24382
+ TabStopType,
24369
24383
  Table,
24370
24384
  TableCell,
24371
24385
  TableLayoutType,
24372
24386
  TableRow,
24373
24387
  TextRun,
24374
- UnderlineType,
24375
24388
  VerticalAlign as DocxVerticalAlign,
24376
- WidthType
24389
+ WidthType,
24390
+ XmlAttributeComponent,
24391
+ XmlComponent
24377
24392
  } from "docx";
24393
+
24394
+ // src/utils/docx.ts
24395
+ import { UnderlineType } from "docx";
24378
24396
  var DEFAULT_DOCX_FILE_NAME = "document.docx";
24379
24397
  var DEFAULT_IMAGE_WIDTH = 320;
24380
24398
  var DEFAULT_IMAGE_HEIGHT = 180;
24381
- var DEFAULT_LINE_HEIGHT = 1.15;
24382
- var DOCX_FOOTER_TEXT_COLOR = "#000000";
24383
- var docxBulletCharMap = {
24384
- ["disc" /* DISC */]: "\u2022",
24385
- ["circle" /* CIRCLE */]: "\u25E6",
24386
- ["square" /* SQUARE */]: "\u25A0",
24387
- ["checkbox" /* CHECKBOX */]: "\u2611"
24388
- };
24389
- var titleHeadingMap = {
24390
- ["first" /* FIRST */]: HeadingLevel.HEADING_1,
24391
- ["second" /* SECOND */]: HeadingLevel.HEADING_2,
24392
- ["third" /* THIRD */]: HeadingLevel.HEADING_3,
24393
- ["fourth" /* FOURTH */]: HeadingLevel.HEADING_4,
24394
- ["fifth" /* FIFTH */]: HeadingLevel.HEADING_5,
24395
- ["sixth" /* SIXTH */]: HeadingLevel.HEADING_6
24396
- };
24397
- var orderedStyleFormatMap = {
24398
- ["decimal" /* DECIMAL */]: LevelFormat.DECIMAL,
24399
- ["lowerAlpha" /* LOWER_ALPHA */]: LevelFormat.LOWER_LETTER,
24400
- ["upperAlpha" /* UPPER_ALPHA */]: LevelFormat.UPPER_LETTER,
24401
- ["lowerRoman" /* LOWER_ROMAN */]: LevelFormat.LOWER_ROMAN,
24402
- ["upperRoman" /* UPPER_ROMAN */]: LevelFormat.UPPER_ROMAN,
24403
- ["decimalParen" /* DECIMAL_PAREN */]: LevelFormat.DECIMAL,
24404
- decimalZero: LevelFormat.DECIMAL_ZERO,
24405
- lowerAlphaParen: LevelFormat.LOWER_LETTER,
24406
- lowerRomanParen: LevelFormat.LOWER_ROMAN,
24407
- outline: LevelFormat.DECIMAL
24408
- };
24409
- async function exportEditorDataToDocx(payload, options = {}) {
24410
- const fileName = normalizeDocxFileName(options.fileName);
24411
- const file = await createDocxDocument(payload);
24412
- const blob = await Packer.toBlob(file);
24399
+ async function loadImagePayload(src) {
24400
+ const source = src.trim();
24401
+ if (source.startsWith("data:")) {
24402
+ return getImagePayloadFromDataUrl(source);
24403
+ }
24404
+ const response = await fetch(source);
24405
+ if (!response.ok) {
24406
+ throw new Error(`Image request failed: ${response.status}`);
24407
+ }
24408
+ const contentType = response.headers.get("content-type") || "";
24409
+ const data2 = await response.arrayBuffer();
24410
+ return normalizeImagePayload(data2, contentType);
24411
+ }
24412
+ async function getImagePayloadFromDataUrl(src) {
24413
+ const [, meta = "", encoded = ""] = src.match(/^data:([^,]*),(.*)$/) || [];
24414
+ const mime = meta.split(";")[0] || "";
24415
+ const isBase64 = meta.includes(";base64");
24416
+ const text = isBase64 ? atob(encoded) : decodeURIComponent(encoded);
24417
+ const bytes = new Uint8Array(text.length);
24418
+ for (let i = 0; i < text.length; i++) {
24419
+ bytes[i] = text.charCodeAt(i);
24420
+ }
24421
+ return normalizeImagePayload(bytes.buffer, mime);
24422
+ }
24423
+ async function normalizeImagePayload(data2, mime) {
24424
+ const type = getRegularImageType(mime);
24425
+ if (type) {
24426
+ return {
24427
+ type,
24428
+ data: data2
24429
+ };
24430
+ }
24431
+ if (mime.includes("svg")) {
24432
+ return {
24433
+ type: "svg",
24434
+ data: data2,
24435
+ fallbackPng: await rasterizeSvgToPng(data2)
24436
+ };
24437
+ }
24438
+ const fallbackPng = await rasterizeImageToPng(data2, mime);
24413
24439
  return {
24414
- blob,
24415
- fileName
24440
+ type: "png",
24441
+ data: fallbackPng
24416
24442
  };
24417
24443
  }
24418
- async function createDocxDocument(payload) {
24419
- const { data: data2, options } = payload;
24420
- const editorOptions = options;
24421
- const context = createSerializeContext();
24422
- const headerChildren = editorOptions.header.disabled ? [] : await serializeElementList(data2.header || [], editorOptions, context);
24423
- const docxFooterElementList = forceDocxFooterTextColor(data2.footer || []);
24424
- const footerChildren = editorOptions.footer.disabled ? [] : await serializeElementList(
24425
- docxFooterElementList,
24426
- editorOptions,
24427
- context
24428
- );
24429
- const pageNumberParagraph = createPageNumberParagraph(
24430
- {
24431
- ...editorOptions.pageNumber,
24432
- color: DOCX_FOOTER_TEXT_COLOR
24444
+ async function rasterizeSvgToPng(data2) {
24445
+ return rasterizeImageToPng(data2, "image/svg+xml");
24446
+ }
24447
+ async function rasterizeImageToPng(data2, mime) {
24448
+ const blob = new Blob([data2], {
24449
+ type: mime || "image/png"
24450
+ });
24451
+ const url = URL.createObjectURL(blob);
24452
+ try {
24453
+ const image = await loadHtmlImage(url);
24454
+ const canvas = document.createElement("canvas");
24455
+ canvas.width = image.naturalWidth || DEFAULT_IMAGE_WIDTH;
24456
+ canvas.height = image.naturalHeight || DEFAULT_IMAGE_HEIGHT;
24457
+ const context = canvas.getContext("2d");
24458
+ if (!context) {
24459
+ throw new Error("Canvas context is unavailable");
24433
24460
  }
24434
- );
24435
- if (pageNumberParagraph) {
24436
- footerChildren.push(pageNumberParagraph);
24461
+ context.drawImage(image, 0, 0, canvas.width, canvas.height);
24462
+ const pngBlob = await new Promise((resolve, reject) => {
24463
+ canvas.toBlob((output) => {
24464
+ if (output) {
24465
+ resolve(output);
24466
+ } else {
24467
+ reject(new Error("Failed to create PNG blob"));
24468
+ }
24469
+ }, "image/png");
24470
+ });
24471
+ return await pngBlob.arrayBuffer();
24472
+ } finally {
24473
+ URL.revokeObjectURL(url);
24437
24474
  }
24438
- const sectionChildren = await serializeElementList(
24439
- data2.main,
24440
- editorOptions,
24441
- context
24442
- );
24443
- const { width, height, paperDirection } = editorOptions;
24444
- const pageWidth = paperDirection === "horizontal" /* HORIZONTAL */ ? height : width;
24445
- const pageHeight = paperDirection === "horizontal" /* HORIZONTAL */ ? width : height;
24475
+ }
24476
+ function loadHtmlImage(src) {
24477
+ return new Promise((resolve, reject) => {
24478
+ const image = new Image();
24479
+ image.onload = () => resolve(image);
24480
+ image.onerror = () => reject(new Error("Failed to load image"));
24481
+ image.src = src;
24482
+ });
24483
+ }
24484
+ function mapUnderlineType(style) {
24485
+ switch (style) {
24486
+ case "double" /* DOUBLE */:
24487
+ return UnderlineType.DOUBLE;
24488
+ case "dashed" /* DASHED */:
24489
+ return UnderlineType.DASH;
24490
+ case "dotted" /* DOTTED */:
24491
+ return UnderlineType.DOTTED;
24492
+ case "wavy" /* WAVY */:
24493
+ return UnderlineType.WAVE;
24494
+ default:
24495
+ return UnderlineType.SINGLE;
24496
+ }
24497
+ }
24498
+ function normalizeHexColor(color, fallback) {
24499
+ const normalized = normalizeHexLiteral(color) || normalizeRgbColor(color) || normalizeBrowserColor(color);
24500
+ if (normalized) {
24501
+ return normalized;
24502
+ }
24503
+ return fallback ? normalizeHexLiteral(fallback) || void 0 : void 0;
24504
+ }
24505
+ function normalizeHexLiteral(color) {
24506
+ const value = color.trim().replace(/^#/, "");
24507
+ if (/^[\da-f]{3}$/i.test(value)) {
24508
+ return value.split("").map((part) => `${part}${part}`).join("").toUpperCase();
24509
+ }
24510
+ if (/^[\da-f]{4}$/i.test(value)) {
24511
+ return value.slice(0, 3).split("").map((part) => `${part}${part}`).join("").toUpperCase();
24512
+ }
24513
+ if (/^[\da-f]{6}$/i.test(value)) {
24514
+ return value.toUpperCase();
24515
+ }
24516
+ if (/^[\da-f]{8}$/i.test(value)) {
24517
+ return value.slice(0, 6).toUpperCase();
24518
+ }
24519
+ return void 0;
24520
+ }
24521
+ function normalizeRgbColor(color) {
24522
+ const match = color.trim().match(/^rgba?\((.+)\)$/i);
24523
+ if (!match) {
24524
+ return void 0;
24525
+ }
24526
+ const parts = match[1].replace(/\s*\/\s*/g, ",").split(/\s*,\s*|\s+/).filter(Boolean);
24527
+ if (parts.length < 3) {
24528
+ return void 0;
24529
+ }
24530
+ const red = parseRgbChannel(parts[0]);
24531
+ const green = parseRgbChannel(parts[1]);
24532
+ const blue = parseRgbChannel(parts[2]);
24533
+ if (red === null || green === null || blue === null) {
24534
+ return void 0;
24535
+ }
24536
+ const alpha = parts[3] !== void 0 ? parseAlphaChannel(parts[3]) : 1;
24537
+ if (alpha === null || alpha <= 0) {
24538
+ return void 0;
24539
+ }
24540
+ const flattened = alpha >= 1 ? [red, green, blue] : [
24541
+ flattenChannel(red, alpha),
24542
+ flattenChannel(green, alpha),
24543
+ flattenChannel(blue, alpha)
24544
+ ];
24545
+ return flattened.map(toHexChannel).join("");
24546
+ }
24547
+ function normalizeBrowserColor(color) {
24548
+ if (typeof document === "undefined") {
24549
+ return void 0;
24550
+ }
24551
+ const canvas = document.createElement("canvas");
24552
+ const context = canvas.getContext("2d");
24553
+ if (!context) {
24554
+ return void 0;
24555
+ }
24556
+ context.fillStyle = "#000000";
24557
+ context.fillStyle = color;
24558
+ const normalized = context.fillStyle;
24559
+ if (typeof normalized !== "string") {
24560
+ return void 0;
24561
+ }
24562
+ return normalizeHexLiteral(normalized) || normalizeRgbColor(normalized);
24563
+ }
24564
+ function parseRgbChannel(value) {
24565
+ if (value.endsWith("%")) {
24566
+ const percent = Number(value.slice(0, -1));
24567
+ if (!Number.isFinite(percent)) {
24568
+ return null;
24569
+ }
24570
+ return clampColorChannel(Math.round(percent / 100 * 255));
24571
+ }
24572
+ const channel = Number(value);
24573
+ if (!Number.isFinite(channel)) {
24574
+ return null;
24575
+ }
24576
+ return clampColorChannel(Math.round(channel));
24577
+ }
24578
+ function parseAlphaChannel(value) {
24579
+ if (value.endsWith("%")) {
24580
+ const percent = Number(value.slice(0, -1));
24581
+ if (!Number.isFinite(percent)) {
24582
+ return null;
24583
+ }
24584
+ return Math.min(Math.max(percent / 100, 0), 1);
24585
+ }
24586
+ const alpha = Number(value);
24587
+ if (!Number.isFinite(alpha)) {
24588
+ return null;
24589
+ }
24590
+ return Math.min(Math.max(alpha, 0), 1);
24591
+ }
24592
+ function clampColorChannel(value) {
24593
+ return Math.min(Math.max(value, 0), 255);
24594
+ }
24595
+ function flattenChannel(value, alpha) {
24596
+ return clampColorChannel(Math.round(255 * (1 - alpha) + value * alpha));
24597
+ }
24598
+ function toHexChannel(value) {
24599
+ return value.toString(16).padStart(2, "0").toUpperCase();
24600
+ }
24601
+ function getRegularImageType(mime) {
24602
+ if (mime.includes("png")) return "png";
24603
+ if (mime.includes("jpeg") || mime.includes("jpg")) return "jpg";
24604
+ if (mime.includes("gif")) return "gif";
24605
+ if (mime.includes("bmp")) return "bmp";
24606
+ return null;
24607
+ }
24608
+ function normalizeDocxFileName(fileName) {
24609
+ const trimmed = fileName?.trim();
24610
+ if (!trimmed) {
24611
+ return DEFAULT_DOCX_FILE_NAME;
24612
+ }
24613
+ return trimmed.toLowerCase().endsWith(".docx") ? trimmed : `${trimmed}.docx`;
24614
+ }
24615
+
24616
+ // src/utils/docxLayout.ts
24617
+ var PX_TO_TWIP = 15;
24618
+ var ANCHOR_EPS = 0.5;
24619
+ var RIGHT_SLACK_TWIP = -14400;
24620
+ var TINY_TWIP = 1;
24621
+ var tw = (ctx, layoutPx) => Math.round(layoutPx / ctx.scale * PX_TO_TWIP);
24622
+ var pxTw = (px) => Math.round(px * PX_TO_TWIP);
24623
+ async function exportDrawToDocx(draw, options = {}) {
24624
+ const canvas = document.createElement("canvas");
24625
+ const measureCtx = canvas.getContext("2d");
24626
+ const ctx = {
24627
+ draw,
24628
+ scale: draw.getOptions().scale,
24629
+ measureCtx
24630
+ };
24631
+ const file = await createDocument(ctx);
24632
+ const blob = await Packer.toBlob(file);
24633
+ return { blob, fileName: normalizeDocxFileName(options.fileName) };
24634
+ }
24635
+ async function createDocument(ctx) {
24636
+ const { draw, scale } = ctx;
24637
+ const opts = draw.getOptions();
24638
+ const width = draw.getOriginalWidth();
24639
+ const height = draw.getOriginalHeight();
24640
+ const margins = draw.getOriginalMargins();
24641
+ const header = draw.getHeader();
24642
+ const footer = draw.getFooter();
24643
+ const headerTop = header.getHeaderTop() / scale;
24644
+ const headerExtra = header.getExtraHeight() / scale;
24645
+ const footerExtra = footer.getExtraHeight() / scale;
24646
+ const layoutMargins = draw.getMargins();
24647
+ const body = await serializeMain(ctx, layoutMargins[3]);
24648
+ const headerChildren = opts.header.disabled ? [] : await serializeRows(ctx, header.getRowList(), {
24649
+ startX: layoutMargins[3],
24650
+ width: draw.getInnerWidth(),
24651
+ positionList: header.getPositionList()
24652
+ });
24653
+ const footerChildren = opts.footer.disabled ? [] : await serializeFooter(ctx, width, height, margins);
24654
+ const { pageNumber } = draw.getOptions();
24446
24655
  return new Document2({
24447
- features: {
24448
- updateFields: true
24449
- },
24450
- numbering: {
24451
- config: createNumberingConfig()
24656
+ compatabilityModeVersion: 15,
24657
+ // LibreOffice formats PAGE/NUMPAGES results from the paragraph style
24658
+ styles: {
24659
+ paragraphStyles: [
24660
+ {
24661
+ id: PAGE_NUMBER_STYLE,
24662
+ name: "Windoc Page Number",
24663
+ run: pageNumberRunStyle(pageNumber)
24664
+ }
24665
+ ]
24452
24666
  },
24667
+ defaultTabStop: pxTw(width),
24453
24668
  sections: [
24454
24669
  {
24455
24670
  properties: {
24456
24671
  page: {
24457
24672
  size: {
24458
- width: pxToTwips(pageWidth),
24459
- height: pxToTwips(pageHeight),
24460
- orientation: paperDirection === "horizontal" /* HORIZONTAL */ ? PageOrientation.LANDSCAPE : PageOrientation.PORTRAIT
24673
+ width: pxTw(width),
24674
+ height: pxTw(height),
24675
+ orientation: opts.paperDirection === "horizontal" /* HORIZONTAL */ ? PageOrientation.LANDSCAPE : PageOrientation.PORTRAIT
24461
24676
  },
24462
24677
  margin: {
24463
- top: pxToTwips(editorOptions.margins[0]),
24464
- right: pxToTwips(editorOptions.margins[1]),
24465
- bottom: pxToTwips(editorOptions.margins[2]),
24466
- left: pxToTwips(editorOptions.margins[3]),
24467
- header: pxToTwips(editorOptions.header.top),
24468
- footer: pxToTwips(editorOptions.footer.bottom)
24469
- },
24470
- pageNumbers: !editorOptions.pageNumber.disabled && editorOptions.pageNumber.fromPageNo === 0 ? {
24471
- start: editorOptions.pageNumber.startPageNo
24472
- } : void 0
24678
+ top: pxTw(margins[0] + headerExtra),
24679
+ right: pxTw(margins[1]),
24680
+ bottom: pxTw(margins[2] + footerExtra),
24681
+ left: pxTw(margins[3]),
24682
+ header: pxTw(headerTop),
24683
+ footer: pxTw(footer.getFooterBottom() / scale),
24684
+ gutter: 0
24685
+ }
24473
24686
  }
24474
24687
  },
24475
- headers: headerChildren.length > 0 ? {
24476
- default: new Header2({
24477
- children: headerChildren
24478
- })
24479
- } : void 0,
24480
- footers: footerChildren.length > 0 ? {
24481
- default: new Footer2({
24482
- children: footerChildren
24483
- })
24484
- } : void 0,
24485
- children: sectionChildren.length ? sectionChildren : [new Paragraph({})]
24688
+ headers: headerChildren.length ? { default: new Header2({ children: headerChildren }) } : void 0,
24689
+ footers: footerChildren.length ? { default: new Footer2({ children: footerChildren }) } : void 0,
24690
+ children: body.length ? body : [new Paragraph({})]
24486
24691
  }
24487
24692
  ]
24488
24693
  });
24489
24694
  }
24490
- async function serializeElementList(elementList, options, context) {
24491
- const blocks = [];
24492
- let inlineBuffer = [];
24493
- const flushInlineBuffer = async () => {
24494
- if (!inlineBuffer.length) return;
24495
- blocks.push(
24496
- ...await serializeInlineElements(inlineBuffer, options, context)
24497
- );
24498
- inlineBuffer = [];
24695
+ async function serializeMain(ctx, startX) {
24696
+ const { draw } = ctx;
24697
+ const zone = {
24698
+ startX,
24699
+ width: draw.getInnerWidth(),
24700
+ positionList: draw.getPosition().getOriginalMainPositionList()
24499
24701
  };
24500
- for (let i = 0; i < elementList.length; i++) {
24501
- const element = elementList[i];
24502
- if (element.type === "area" /* AREA */ && element.valueList?.length) {
24503
- await flushInlineBuffer();
24504
- blocks.push(
24505
- ...await serializeElementList(element.valueList, options, context)
24506
- );
24507
- continue;
24508
- }
24509
- if (element.type === "title" /* TITLE */ && element.valueList?.length) {
24510
- await flushInlineBuffer();
24511
- blocks.push(
24512
- ...await serializeInlineElements(element.valueList, options, context, {
24513
- heading: titleHeadingMap[element.level || "first" /* FIRST */]
24514
- })
24515
- );
24516
- continue;
24517
- }
24518
- if (element.type === "list" /* LIST */ && element.valueList?.length) {
24519
- await flushInlineBuffer();
24520
- blocks.push(...await serializeListElement(element, options, context));
24521
- continue;
24522
- }
24523
- if (element.type === "table" /* TABLE */ && element.trList?.length) {
24524
- await flushInlineBuffer();
24525
- blocks.push(await serializeTableElement(element, options, context));
24526
- continue;
24527
- }
24528
- if (element.type === "pageBreak" /* PAGE_BREAK */) {
24529
- await flushInlineBuffer();
24530
- blocks.push(
24531
- new Paragraph({
24532
- children: [new PageBreak()]
24533
- })
24534
- );
24535
- continue;
24536
- }
24537
- if (element.type === "separator" /* SEPARATOR */) {
24538
- await flushInlineBuffer();
24539
- blocks.push(
24540
- new Paragraph({
24541
- thematicBreak: true
24542
- })
24543
- );
24544
- continue;
24545
- }
24546
- if (element.type === "image" /* IMAGE */ && element.imgDisplay && element.imgDisplay !== "inline") {
24547
- await flushInlineBuffer();
24548
- blocks.push(...await serializeInlineElements([element], options));
24549
- continue;
24550
- }
24551
- if (element.type === "block" /* BLOCK */) {
24552
- await flushInlineBuffer();
24553
- const blockText = getBlockFallbackText(element);
24554
- if (blockText) {
24555
- blocks.push(
24556
- ...await serializeInlineElements(
24557
- [{ value: blockText }],
24558
- options,
24559
- context
24702
+ const children = [];
24703
+ const pageRowList = draw.getPageRowList();
24704
+ for (let p = 0; p < pageRowList.length; p++) {
24705
+ children.push(
24706
+ ...await serializeRows(ctx, pageRowList[p], zone, {
24707
+ pageBreakBefore: p > 0
24708
+ })
24709
+ );
24710
+ }
24711
+ return children;
24712
+ }
24713
+ async function serializeRows(ctx, rowList, zone, options = {}) {
24714
+ const { pageBreakBefore = false, padTop = 0, padBottom = 0 } = options;
24715
+ const children = [];
24716
+ for (let r = 0; r < rowList.length; r++) {
24717
+ const row = rowList[r];
24718
+ const isFirst = r === 0;
24719
+ const isLast = r === rowList.length - 1;
24720
+ const table = row.elementList.find((el) => el.type === "table" /* TABLE */);
24721
+ if (table) {
24722
+ if (isFirst && (pageBreakBefore || padTop) || row.offsetY) {
24723
+ children.push(
24724
+ createSpacerParagraph(
24725
+ isFirst && pageBreakBefore,
24726
+ (isFirst ? padTop : 0) + (row.offsetY || 0) / ctx.scale
24560
24727
  )
24561
24728
  );
24562
24729
  }
24730
+ const position = zone.positionList[row.startIndex + row.elementList.indexOf(table)];
24731
+ children.push(await serializeTable(ctx, table, position, zone));
24732
+ const rest = (row.height + (row.spaceBelow || 0)) / ctx.scale - table.height + (isLast ? padBottom : 0);
24733
+ if (rest * PX_TO_TWIP >= 1) {
24734
+ children.push(createSpacerParagraph(false, rest));
24735
+ }
24563
24736
  continue;
24564
24737
  }
24565
- inlineBuffer.push(element);
24738
+ const rowOptions = {
24739
+ pageBreakBefore: isFirst && pageBreakBefore,
24740
+ padTop: isFirst ? padTop : 0,
24741
+ padBottom: isLast ? padBottom : 0
24742
+ };
24743
+ if (!isFirst && isTextRow(rowList[r - 1])) rowOptions.skipLead = true;
24744
+ rowOptions.rowY = rowY(zone, row);
24745
+ if (!isLast && isTextRow(rowList[r + 1])) {
24746
+ rowOptions.extraAfter = rowLead(ctx, rowList[r + 1], {
24747
+ rowY: rowY(zone, rowList[r + 1])
24748
+ });
24749
+ }
24750
+ const lead = rowOptions.pageBreakBefore ? rowLead(ctx, row, rowOptions) : 0;
24751
+ if (lead) {
24752
+ children.push(createSpacerParagraph(true, lead / PX_TO_TWIP));
24753
+ rowOptions.pageBreakBefore = false;
24754
+ rowOptions.skipLead = true;
24755
+ }
24756
+ children.push(await serializeRow(ctx, row, zone, rowOptions));
24566
24757
  }
24567
- await flushInlineBuffer();
24568
- return blocks;
24758
+ return children;
24569
24759
  }
24570
- async function serializeInlineElements(elementList, options, _context, overrides = {}) {
24571
- const paragraphs = [];
24572
- let current = null;
24573
- const getParagraphContext = (element) => ({
24574
- heading: overrides.heading,
24575
- numbering: overrides.numbering,
24576
- alignment: overrides.alignment !== void 0 ? overrides.alignment : mapRowFlexToAlignment(element?.rowFlex),
24577
- rowMargin: overrides.rowMargin !== void 0 ? overrides.rowMargin : element?.rowMargin
24578
- });
24579
- const flushParagraph = (context) => {
24580
- if (!current) {
24581
- if (!context) return;
24582
- paragraphs.push(createParagraph([], context, options.defaultRowMargin));
24760
+ function rowY(zone, row) {
24761
+ return zone.positionList[row.startIndex]?.coordinate.leftTop[1];
24762
+ }
24763
+ function isTextRow(row) {
24764
+ return !row.elementList.some((el) => el.type === "table" /* TABLE */);
24765
+ }
24766
+ async function serializeRow(ctx, row, zone, options, suffix) {
24767
+ const { pageBreakBefore = false } = options;
24768
+ const { draw, scale } = ctx;
24769
+ const positions = zone.positionList;
24770
+ const children = [];
24771
+ const tabStops = [];
24772
+ const firstPosition = positions[row.startIndex];
24773
+ let pen = 0;
24774
+ let indent = firstPosition ? (firstPosition.coordinate.leftTop[0] - zone.startX) / scale : 0;
24775
+ let started = false;
24776
+ const anchorTo = (layoutX) => {
24777
+ const target = (layoutX - zone.startX) / scale;
24778
+ if (!started) {
24779
+ indent = target;
24780
+ pen = target;
24781
+ started = true;
24583
24782
  return;
24584
24783
  }
24585
- paragraphs.push(
24586
- createParagraph(
24587
- current.children,
24588
- current.context,
24589
- options.defaultRowMargin
24590
- )
24591
- );
24592
- current = null;
24593
- };
24594
- const ensureParagraph = (element) => {
24595
- if (!current) {
24596
- current = {
24597
- children: [],
24598
- context: getParagraphContext(element)
24599
- };
24784
+ if (target - pen > ANCHOR_EPS) {
24785
+ tabStops.push(pxTw(target));
24786
+ children.push(new TextRun({ children: [new Tab()] }));
24787
+ pen = target;
24600
24788
  }
24601
- return current;
24602
24789
  };
24603
- const appendText = (element, text, childFactory, preserveTrailingBreak = false) => {
24604
- const normalized = normalizeText(text);
24605
- const parts = normalized.split("\n");
24606
- let lastSeparatorFlushedContent = false;
24607
- for (let i = 0; i < parts.length; i++) {
24608
- const segment = parts[i];
24609
- if (segment) {
24610
- ensureParagraph(element).children.push(childFactory(segment));
24611
- }
24612
- if (i < parts.length - 1) {
24613
- if (!current) {
24614
- paragraphs.push(
24615
- createParagraph(
24616
- [],
24617
- getParagraphContext(element),
24618
- options.defaultRowMargin
24619
- )
24620
- );
24621
- lastSeparatorFlushedContent = false;
24622
- } else {
24623
- flushParagraph();
24624
- lastSeparatorFlushedContent = true;
24625
- }
24626
- }
24627
- }
24628
- if (preserveTrailingBreak && normalized.endsWith("\n") && lastSeparatorFlushedContent) {
24629
- paragraphs.push(
24630
- createParagraph(
24631
- [],
24632
- getParagraphContext(element),
24633
- options.defaultRowMargin
24634
- )
24790
+ if (row.isList && firstPosition) {
24791
+ const listParticle = draw.getListParticle();
24792
+ const markerX = listParticle.getListMarkerX(row, firstPosition);
24793
+ const marker = markerX === null ? null : listParticle.getListMarker(row);
24794
+ if (markerX !== null && marker) {
24795
+ anchorTo(markerX);
24796
+ children.push(createTextRun(ctx, marker.text, marker.styleElement));
24797
+ pen += measure(ctx, marker.text, marker.styleElement);
24798
+ }
24799
+ }
24800
+ let run = null;
24801
+ const flush = () => {
24802
+ if (!run) return;
24803
+ children.push(createTextRun(ctx, run.text, run.element));
24804
+ run = null;
24805
+ };
24806
+ for (let j = 0; j < row.elementList.length; j++) {
24807
+ const element = row.elementList[j];
24808
+ const position = positions[row.startIndex + j];
24809
+ if (!position) continue;
24810
+ if (element.hide || element.control?.hide || element.area?.hide) continue;
24811
+ if (element.type === "separator" /* SEPARATOR */) {
24812
+ flush();
24813
+ return createSeparatorParagraph(
24814
+ ctx,
24815
+ row,
24816
+ element,
24817
+ position.coordinate.leftTop[0],
24818
+ position.coordinate.leftTop[1],
24819
+ zone,
24820
+ options
24635
24821
  );
24636
24822
  }
24637
- };
24638
- for (let i = 0; i < elementList.length; i++) {
24639
- const element = elementList[i];
24640
- if (element.type === "hyperlink" /* HYPERLINK */ && element.valueList?.length) {
24641
- const hyperlink = await createHyperlinkChild(element, options);
24642
- if (hyperlink) {
24643
- ensureParagraph(element).children.push(hyperlink);
24644
- }
24823
+ if (element.value === ZERO || element.type === "tab" /* TAB */ || element.type === "pageBreak" /* PAGE_BREAK */ || element.type === "columnBreak" /* COLUMN_BREAK */) {
24645
24824
  continue;
24646
24825
  }
24826
+ const x = position.coordinate.leftTop[0];
24827
+ const layoutWidth = element.metrics.width / scale;
24647
24828
  if (element.type === "image" /* IMAGE */) {
24648
- const imageChild = await createImageChild(element);
24649
- if (!imageChild) {
24650
- appendText(
24651
- element,
24652
- "[Image unavailable]",
24653
- (segment) => createTextRun(
24654
- segment,
24655
- element,
24656
- options.defaultSize,
24657
- options.defaultFont
24658
- ),
24659
- i === elementList.length - 1
24660
- );
24661
- continue;
24662
- }
24663
- ensureParagraph(element).children.push(imageChild);
24664
- continue;
24665
- }
24666
- if (element.type === "columnBreak" /* COLUMN_BREAK */) {
24667
- ensureParagraph(element).children.push(new ColumnBreak());
24829
+ flush();
24830
+ anchorTo(x);
24831
+ const image = await createImageRun(element);
24832
+ if (image) children.push(image);
24833
+ pen += layoutWidth;
24668
24834
  continue;
24669
24835
  }
24670
- if (element.type === "tab" /* TAB */) {
24671
- appendText(
24672
- element,
24673
- " ",
24674
- (segment) => createTextRun(
24675
- segment,
24676
- element,
24677
- options.defaultSize,
24678
- options.defaultFont
24679
- ),
24680
- i === elementList.length - 1
24836
+ if (element.type === "label" /* LABEL */) {
24837
+ flush();
24838
+ const padding = element.label?.padding || draw.getOptions().label.defaultPadding;
24839
+ anchorTo(x + padding[3] * scale);
24840
+ children.push(
24841
+ createTextRun(ctx, element.value, element, labelShading(ctx, element))
24681
24842
  );
24843
+ pen += measure(ctx, element.value, element);
24682
24844
  continue;
24683
24845
  }
24684
- const textValue = getInlineElementText(element);
24685
- if (!textValue) {
24686
- continue;
24687
- }
24688
- appendText(
24689
- element,
24690
- textValue,
24691
- (segment) => createTextRun(
24692
- segment,
24693
- element,
24694
- options.defaultSize,
24695
- options.defaultFont
24696
- ),
24697
- i === elementList.length - 1
24698
- );
24699
- }
24700
- if (current) {
24701
- flushParagraph();
24702
- }
24703
- return paragraphs.length ? paragraphs : [createParagraph([], overrides, options.defaultRowMargin)];
24704
- }
24705
- async function serializeListElement(element, options, context) {
24706
- const zipList = zipElementList(element.valueList || []);
24707
- const listItemMap = splitListElement(zipList);
24708
- const paragraphs = [];
24709
- const listInstance = createListInstance(context);
24710
- for (const listItemElements of listItemMap.values()) {
24711
- const numbering = getListNumbering(
24712
- getListItemNumberingElement(listItemElements, element),
24713
- listInstance
24714
- );
24715
- paragraphs.push(
24716
- ...await serializeInlineElements(listItemElements, options, context, {
24717
- numbering
24718
- })
24719
- );
24720
- }
24721
- return paragraphs;
24722
- }
24723
- async function serializeTableElement(element, options, context) {
24724
- const rows = [];
24725
- const trList = element.trList || [];
24726
- const tableContext = createTableSerializeContext(element);
24727
- for (let i = 0; i < trList.length; i++) {
24728
- rows.push(
24729
- await serializeTableRow(trList[i], options, context, tableContext)
24730
- );
24731
- }
24732
- const tableWidth = getTableWidthFromColgroup(element.colgroup);
24733
- return new Table({
24734
- rows,
24735
- width: tableWidth ? {
24736
- size: pxToTwips(tableWidth),
24737
- type: WidthType.DXA
24738
- } : {
24739
- size: 100,
24740
- type: WidthType.PERCENTAGE
24741
- },
24742
- columnWidths: element.colgroup?.map((col) => pxToTwips(col.width)),
24743
- layout: TableLayoutType.FIXED,
24744
- borders: createTableBorders(element)
24745
- });
24746
- }
24747
- async function serializeTableRow(tr, options, context, tableContext) {
24748
- const children = [];
24749
- for (let i = 0; i < tr.tdList.length; i++) {
24750
- children.push(
24751
- await serializeTableCell(tr.tdList[i], options, context, tableContext)
24752
- );
24753
- }
24754
- return new TableRow({
24755
- children
24756
- });
24757
- }
24758
- async function serializeTableCell(td, options, context, tableContext) {
24759
- const children = await serializeElementList(td.value, options, context);
24760
- const shadingFill = td.backgroundColor ? normalizeHexColor(td.backgroundColor) : void 0;
24761
- const cellWidth = tableContext.cellLayoutMap.get(td)?.width || td.width;
24762
- return new TableCell({
24763
- children: children.length ? children : [new Paragraph({})],
24764
- columnSpan: td.colspan > 1 ? td.colspan : void 0,
24765
- rowSpan: td.rowspan > 1 ? td.rowspan : void 0,
24766
- verticalAlign: mapCellVerticalAlign(td.verticalAlign),
24767
- width: cellWidth ? {
24768
- size: pxToTwips(cellWidth),
24769
- type: WidthType.DXA
24770
- } : void 0,
24771
- shading: shadingFill ? {
24772
- fill: shadingFill,
24773
- type: ShadingType.CLEAR
24774
- } : void 0,
24775
- margins: mapPaddingToTableMargins(td.padding),
24776
- borders: createTableCellBorders(
24777
- td,
24778
- tableContext.borderColor,
24779
- tableContext.borderWidth
24780
- )
24781
- });
24782
- }
24783
- function createParagraph(children, context, defaultRowMargin) {
24784
- return new Paragraph({
24785
- children,
24786
- heading: context.heading,
24787
- numbering: context.numbering,
24788
- alignment: context.alignment,
24789
- spacing: {
24790
- line: Math.round(
24791
- 240 * (context.rowMargin || defaultRowMargin || DEFAULT_LINE_HEIGHT)
24792
- ),
24793
- lineRule: LineRuleType.AUTO
24794
- }
24795
- });
24796
- }
24797
- function createTextRun(text, element, defaultSize, defaultFont) {
24798
- const color = element.color ? normalizeHexColor(element.color, "000000") : void 0;
24799
- const highlightFill = element.highlight ? normalizeHexColor(element.highlight) : void 0;
24800
- return new TextRun({
24801
- text,
24802
- bold: !!element.bold,
24803
- italics: !!element.italic,
24804
- strike: !!element.strikeout,
24805
- subScript: element.type === "subscript" /* SUBSCRIPT */,
24806
- superScript: element.type === "superscript" /* SUPERSCRIPT */,
24807
- color,
24808
- shading: highlightFill ? {
24809
- fill: highlightFill,
24810
- type: ShadingType.CLEAR
24811
- } : void 0,
24812
- underline: element.underline ? {
24813
- type: mapUnderlineType(element.textDecoration?.style)
24814
- } : void 0,
24815
- font: element.font || defaultFont,
24816
- size: Math.round((element.size || defaultSize) * 2)
24817
- });
24818
- }
24819
- async function createHyperlinkChild(element, options) {
24820
- if (!element.url) {
24821
- const fallbackText = getTextFromElementList(element.valueList || []);
24822
- return fallbackText ? createTextRun(
24823
- fallbackText,
24824
- element.valueList?.[0] || element,
24825
- options.defaultSize,
24826
- options.defaultFont
24827
- ) : null;
24828
- }
24829
- const children = await createHyperlinkRuns(
24830
- element.valueList || [],
24831
- options.defaultSize,
24832
- options.defaultFont
24833
- );
24834
- if (!children.length) {
24835
- return null;
24836
- }
24837
- return new ExternalHyperlink({
24838
- link: element.url,
24839
- children
24840
- });
24841
- }
24842
- async function createHyperlinkRuns(valueList, defaultSize, defaultFont) {
24843
- const children = [];
24844
- for (let i = 0; i < valueList.length; i++) {
24845
- const element = valueList[i];
24846
- if (element.type === "tab" /* TAB */) {
24847
- children.push(createTextRun(" ", element, defaultSize, defaultFont));
24848
- continue;
24849
- }
24850
- const text = normalizeText(getInlineElementText(element)).replace(
24851
- /\n/g,
24852
- " "
24853
- );
24854
- if (text) {
24855
- children.push(createTextRun(text, element, defaultSize, defaultFont));
24856
- }
24857
- }
24858
- return children;
24859
- }
24860
- async function createImageChild(element) {
24861
- try {
24862
- const image = await loadImagePayload(element.value);
24863
- const width = Math.max(1, Math.round(element.width || DEFAULT_IMAGE_WIDTH));
24864
- const height = Math.max(
24865
- 1,
24866
- Math.round(element.height || DEFAULT_IMAGE_HEIGHT)
24867
- );
24868
- if (image.type === "svg" && image.fallbackPng) {
24869
- return new ImageRun({
24870
- type: "svg",
24871
- data: image.data,
24872
- fallback: {
24873
- type: "png",
24874
- data: image.fallbackPng
24875
- },
24876
- transformation: {
24877
- width,
24878
- height
24879
- }
24880
- });
24881
- }
24882
- return new ImageRun({
24883
- type: image.type,
24884
- data: image.data,
24885
- transformation: {
24886
- width,
24887
- height
24846
+ const text = getElementText(element);
24847
+ if (!text) continue;
24848
+ const natural = measure(ctx, text, element);
24849
+ const target = (x - zone.startX) / scale;
24850
+ const isDrift = !started || target - pen > ANCHOR_EPS;
24851
+ const extra = layoutWidth - natural;
24852
+ const needsSpacing = Math.abs(extra) * PX_TO_TWIP >= 1;
24853
+ const canJoin = run && !isDrift && !needsSpacing && isSameRunStyle(run.element, element);
24854
+ if (canJoin) {
24855
+ run.text += text;
24856
+ } else {
24857
+ flush();
24858
+ anchorTo(x);
24859
+ if (needsSpacing) {
24860
+ children.push(
24861
+ createTextRun(ctx, text, element, void 0, pxTw(extra))
24862
+ );
24863
+ } else {
24864
+ run = { text, element };
24888
24865
  }
24889
- });
24890
- } catch {
24891
- return null;
24892
- }
24893
- }
24894
- async function loadImagePayload(src) {
24895
- const source = src.trim();
24896
- if (source.startsWith("data:")) {
24897
- return getImagePayloadFromDataUrl(source);
24898
- }
24899
- const response = await fetch(source);
24900
- if (!response.ok) {
24901
- throw new Error(`Image request failed: ${response.status}`);
24902
- }
24903
- const contentType = response.headers.get("content-type") || "";
24904
- const data2 = await response.arrayBuffer();
24905
- return normalizeImagePayload(data2, contentType);
24906
- }
24907
- async function getImagePayloadFromDataUrl(src) {
24908
- const [, meta = "", encoded = ""] = src.match(/^data:([^,]*),(.*)$/) || [];
24909
- const mime = meta.split(";")[0] || "";
24910
- const isBase64 = meta.includes(";base64");
24911
- const text = isBase64 ? atob(encoded) : decodeURIComponent(encoded);
24912
- const bytes = new Uint8Array(text.length);
24913
- for (let i = 0; i < text.length; i++) {
24914
- bytes[i] = text.charCodeAt(i);
24915
- }
24916
- return normalizeImagePayload(bytes.buffer, mime);
24917
- }
24918
- async function normalizeImagePayload(data2, mime) {
24919
- const type = getRegularImageType(mime);
24920
- if (type) {
24921
- return {
24922
- type,
24923
- data: data2
24924
- };
24925
- }
24926
- if (mime.includes("svg")) {
24927
- return {
24928
- type: "svg",
24929
- data: data2,
24930
- fallbackPng: await rasterizeSvgToPng(data2)
24931
- };
24932
- }
24933
- const fallbackPng = await rasterizeImageToPng(data2, mime);
24934
- return {
24935
- type: "png",
24936
- data: fallbackPng
24937
- };
24938
- }
24939
- async function rasterizeSvgToPng(data2) {
24940
- return rasterizeImageToPng(data2, "image/svg+xml");
24941
- }
24942
- async function rasterizeImageToPng(data2, mime) {
24943
- const blob = new Blob([data2], {
24944
- type: mime || "image/png"
24945
- });
24946
- const url = URL.createObjectURL(blob);
24947
- try {
24948
- const image = await loadHtmlImage(url);
24949
- const canvas = document.createElement("canvas");
24950
- canvas.width = image.naturalWidth || DEFAULT_IMAGE_WIDTH;
24951
- canvas.height = image.naturalHeight || DEFAULT_IMAGE_HEIGHT;
24952
- const context = canvas.getContext("2d");
24953
- if (!context) {
24954
- throw new Error("Canvas context is unavailable");
24955
24866
  }
24956
- context.drawImage(image, 0, 0, canvas.width, canvas.height);
24957
- const pngBlob = await new Promise((resolve, reject) => {
24958
- canvas.toBlob((output) => {
24959
- if (output) {
24960
- resolve(output);
24961
- } else {
24962
- reject(new Error("Failed to create PNG blob"));
24963
- }
24964
- }, "image/png");
24965
- });
24966
- return await pngBlob.arrayBuffer();
24967
- } finally {
24968
- URL.revokeObjectURL(url);
24867
+ pen = target + layoutWidth;
24969
24868
  }
24970
- }
24971
- function loadHtmlImage(src) {
24972
- return new Promise((resolve, reject) => {
24973
- const image = new Image();
24974
- image.onload = () => resolve(image);
24975
- image.onerror = () => reject(new Error("Failed to load image"));
24976
- image.src = src;
24977
- });
24978
- }
24979
- function createPageNumberParagraph(pageNumber) {
24980
- if (pageNumber.disabled || pageNumber.fromPageNo > 0) {
24981
- return null;
24869
+ flush();
24870
+ if (!children.length && !suffix) {
24871
+ const total = (options.skipLead ? 0 : rowLead(ctx, row, options)) + rowLine(ctx, row).lineTw + rowSpacing(ctx, row, options).after;
24872
+ return createSpacerParagraph(pageBreakBefore, total / PX_TO_TWIP);
24982
24873
  }
24983
- const children = [];
24984
- const format = pageNumber.format || FORMAT_PLACEHOLDER.PAGE_NO;
24985
- const tokens = format.split(/(\{pageNo\}|\{pageCount\})/);
24986
- for (let i = 0; i < tokens.length; i++) {
24987
- const token = tokens[i];
24988
- if (!token) continue;
24989
- const runChildren = token === FORMAT_PLACEHOLDER.PAGE_NO ? [PageNumber2.CURRENT] : token === FORMAT_PLACEHOLDER.PAGE_COUNT ? [PageNumber2.TOTAL_PAGES] : void 0;
24990
- children.push(
24991
- new TextRun({
24992
- text: runChildren ? void 0 : token,
24993
- children: runChildren,
24994
- color: normalizeHexColor(pageNumber.color || "#000000", "000000"),
24995
- font: pageNumber.font,
24996
- size: Math.round((pageNumber.size || 12) * 2)
24997
- })
24998
- );
24874
+ const stops = tabStops.map((position) => ({ type: TabStopType.LEFT, position }));
24875
+ if (suffix) {
24876
+ stops.push({ type: suffix.tabType, position: suffix.tabStop });
24877
+ children.push(new TextRun({ children: [new Tab()] }), ...suffix.children);
24999
24878
  }
25000
24879
  return new Paragraph({
25001
24880
  children,
25002
- alignment: mapRowFlexToAlignment(pageNumber.rowFlex)
24881
+ style: suffix?.style,
24882
+ pageBreakBefore,
24883
+ widowControl: false,
24884
+ tabStops: stops,
24885
+ indent: { left: pxTw(indent), right: RIGHT_SLACK_TWIP },
24886
+ spacing: rowSpacing(ctx, row, options)
25003
24887
  });
25004
24888
  }
25005
- function forceDocxFooterTextColor(elementList) {
25006
- const footerElementList = deepClone(elementList);
25007
- forceColorValue(footerElementList);
25008
- return footerElementList;
25009
- }
25010
- function forceColorValue(value) {
25011
- if (!value || typeof value !== "object") {
25012
- return;
25013
- }
25014
- if (Array.isArray(value)) {
25015
- for (let i = 0; i < value.length; i++) {
25016
- forceColorValue(value[i]);
25017
- }
25018
- return;
25019
- }
25020
- const record = value;
25021
- if ("color" in record) {
25022
- record.color = DOCX_FOOTER_TEXT_COLOR;
25023
- }
25024
- const keys = Object.keys(record);
25025
- for (let i = 0; i < keys.length; i++) {
25026
- forceColorValue(record[keys[i]]);
25027
- }
25028
- }
25029
- function createNumberingConfig() {
25030
- const config = [
25031
- createOrderedReference("windoc-ol-decimal", Array(9).fill("decimal" /* DECIMAL */)),
25032
- createOrderedReference(
25033
- "windoc-ol-lower-alpha",
25034
- Array(9).fill("lowerAlpha" /* LOWER_ALPHA */)
25035
- ),
25036
- createOrderedReference(
25037
- "windoc-ol-upper-alpha",
25038
- Array(9).fill("upperAlpha" /* UPPER_ALPHA */)
25039
- ),
25040
- createOrderedReference(
25041
- "windoc-ol-lower-roman",
25042
- Array(9).fill("lowerRoman" /* LOWER_ROMAN */)
25043
- ),
25044
- createOrderedReference(
25045
- "windoc-ol-upper-roman",
25046
- Array(9).fill("upperRoman" /* UPPER_ROMAN */)
25047
- ),
25048
- createOrderedReference(
25049
- "windoc-ol-decimal-paren",
25050
- Array(9).fill("decimalParen" /* DECIMAL_PAREN */)
25051
- ),
25052
- createOrderedReference(
25053
- `windoc-ol-${"olDefault" /* DEFAULT */}`,
25054
- createCycleList(olPresetCycles["olDefault" /* DEFAULT */], 9)
25055
- ),
25056
- createOrderedReference(
25057
- `windoc-ol-${"olParen" /* PARENTHESIS */}`,
25058
- createCycleList(olPresetCycles["olParen" /* PARENTHESIS */], 9)
25059
- ),
25060
- createOrderedReference(
25061
- `windoc-ol-${"olOutline" /* OUTLINE */}`,
25062
- createCycleList(olPresetCycles["olOutline" /* OUTLINE */], 9)
25063
- ),
25064
- createOrderedReference(
25065
- `windoc-ol-${"olUpperA" /* UPPER_ALPHA */}`,
25066
- createCycleList(olPresetCycles["olUpperA" /* UPPER_ALPHA */], 9)
25067
- ),
25068
- createOrderedReference(
25069
- `windoc-ol-${"olRoman" /* ROMAN */}`,
25070
- createCycleList(olPresetCycles["olRoman" /* ROMAN */], 9)
25071
- ),
25072
- createOrderedReference(
25073
- `windoc-ol-${"olZeroPad" /* ZERO_PAD */}`,
25074
- createCycleList(olPresetCycles["olZeroPad" /* ZERO_PAD */], 9)
25075
- ),
25076
- createBulletReference(
25077
- "windoc-ul-disc",
25078
- Array(9).fill(docxBulletCharMap["disc" /* DISC */])
25079
- ),
25080
- createBulletReference(
25081
- "windoc-ul-circle",
25082
- Array(9).fill(docxBulletCharMap["circle" /* CIRCLE */])
25083
- ),
25084
- createBulletReference(
25085
- "windoc-ul-square",
25086
- Array(9).fill(docxBulletCharMap["square" /* SQUARE */])
25087
- ),
25088
- createBulletReference(
25089
- "windoc-ul-checkbox",
25090
- Array(9).fill(docxBulletCharMap["checkbox" /* CHECKBOX */])
25091
- ),
25092
- createBulletReference(
25093
- `windoc-ul-${"ulDefault" /* DEFAULT */}`,
25094
- createCycleList(ulPresetCycles["ulDefault" /* DEFAULT */], 9)
25095
- ),
25096
- createBulletReference(
25097
- `windoc-ul-${"ulDiamond" /* DIAMOND */}`,
25098
- createCycleList(ulPresetCycles["ulDiamond" /* DIAMOND */], 9)
25099
- ),
25100
- createBulletReference(
25101
- `windoc-ul-${"ulHollowSq" /* HOLLOW_SQ */}`,
25102
- createCycleList(ulPresetCycles["ulHollowSq" /* HOLLOW_SQ */], 9)
25103
- ),
25104
- createBulletReference(
25105
- `windoc-ul-${"ulArrow" /* ARROW */}`,
25106
- createCycleList(ulPresetCycles["ulArrow" /* ARROW */], 9)
25107
- ),
25108
- createBulletReference(
25109
- `windoc-ul-${"ulStar" /* STAR */}`,
25110
- createCycleList(ulPresetCycles["ulStar" /* STAR */], 9)
25111
- ),
25112
- createBulletReference(
25113
- `windoc-ul-${"ulCheckArr" /* CHECK_ARROW */}`,
25114
- createCycleList(ulPresetCycles["ulCheckArr" /* CHECK_ARROW */], 9)
25115
- )
25116
- ];
25117
- return config;
25118
- }
25119
- function createOrderedReference(reference, styles) {
25120
- return {
25121
- reference,
25122
- levels: styles.map((style, level) => ({
25123
- level,
25124
- format: orderedStyleFormatMap[style] || LevelFormat.DECIMAL,
25125
- text: getOrderedLevelText(style, level),
25126
- alignment: AlignmentType.START,
25127
- style: {
25128
- paragraph: {
25129
- indent: {
25130
- left: 720 * (level + 1),
25131
- hanging: 360
25132
- }
25133
- }
25134
- }
25135
- }))
25136
- };
25137
- }
25138
- function createBulletReference(reference, bullets) {
25139
- return {
25140
- reference,
25141
- levels: bullets.map((bullet, level) => ({
25142
- level,
25143
- format: LevelFormat.BULLET,
25144
- text: bullet,
25145
- alignment: AlignmentType.START,
25146
- style: {
25147
- paragraph: {
25148
- indent: {
25149
- left: 720 * (level + 1),
25150
- hanging: 360
25151
- }
25152
- }
25153
- }
25154
- }))
25155
- };
25156
- }
25157
- function getOrderedLevelText(style, level) {
25158
- const placeholder = `%${level + 1}`;
25159
- if (style === "outline") {
25160
- return Array.from({ length: level + 1 }, (_, index) => `%${index + 1}`).join(
25161
- "."
25162
- ) + ".";
25163
- }
25164
- if (style.endsWith("Paren") || style === "decimalParen" /* DECIMAL_PAREN */) {
25165
- return `${placeholder})`;
25166
- }
25167
- return `${placeholder}.`;
25168
- }
25169
- function createCycleList(source = [], size) {
25170
- const result = [];
25171
- for (let i = 0; i < size; i++) {
25172
- result.push(source[i % source.length]);
25173
- }
25174
- return result;
25175
- }
25176
- function getListNumbering(element, instance) {
25177
- const level = Math.max(0, Math.min(element.listLevel || 0, 8));
25178
- if (element.listType === "ul" /* UL */) {
25179
- const reference2 = element.listPreset ? `windoc-ul-${element.listPreset}` : `windoc-ul-${element.listStyle || "disc" /* DISC */}`;
25180
- return {
25181
- reference: reference2,
25182
- level,
25183
- instance
25184
- };
25185
- }
25186
- const reference = element.listPreset ? `windoc-ol-${element.listPreset}` : getOrderedReferenceFromStyle(element.listStyle);
25187
- return {
25188
- reference,
25189
- level,
25190
- instance
25191
- };
25192
- }
25193
- function getOrderedReferenceFromStyle(style) {
25194
- switch (style) {
25195
- case "lowerAlpha" /* LOWER_ALPHA */:
25196
- return "windoc-ol-lower-alpha";
25197
- case "upperAlpha" /* UPPER_ALPHA */:
25198
- return "windoc-ol-upper-alpha";
25199
- case "lowerRoman" /* LOWER_ROMAN */:
25200
- return "windoc-ol-lower-roman";
25201
- case "upperRoman" /* UPPER_ROMAN */:
25202
- return "windoc-ol-upper-roman";
25203
- case "decimalParen" /* DECIMAL_PAREN */:
25204
- return "windoc-ol-decimal-paren";
25205
- default:
25206
- return "windoc-ol-decimal";
25207
- }
25208
- }
25209
- function createTableBorders(element) {
25210
- const outerBorder = createBorder(
25211
- element.borderColor,
25212
- BorderStyle.SINGLE,
25213
- element.borderExternalWidth || element.borderWidth
25214
- );
25215
- const innerBorder = createBorder(
25216
- element.borderColor,
25217
- BorderStyle.SINGLE,
25218
- element.borderWidth
25219
- );
25220
- switch (element.borderType) {
25221
- case "empty" /* EMPTY */:
25222
- return {
25223
- top: noneBorder(),
25224
- bottom: noneBorder(),
25225
- left: noneBorder(),
25226
- right: noneBorder(),
25227
- insideHorizontal: noneBorder(),
25228
- insideVertical: noneBorder()
25229
- };
25230
- case "external" /* EXTERNAL */:
25231
- return {
25232
- top: outerBorder,
25233
- bottom: outerBorder,
25234
- left: outerBorder,
25235
- right: outerBorder,
25236
- insideHorizontal: noneBorder(),
25237
- insideVertical: noneBorder()
25238
- };
25239
- case "internal" /* INTERNAL */:
25240
- return {
25241
- top: noneBorder(),
25242
- bottom: noneBorder(),
25243
- left: noneBorder(),
25244
- right: noneBorder(),
25245
- insideHorizontal: innerBorder,
25246
- insideVertical: innerBorder
25247
- };
25248
- case "dash" /* DASH */:
25249
- return {
25250
- top: createBorder(
25251
- element.borderColor,
25252
- BorderStyle.DASHED,
25253
- element.borderExternalWidth || element.borderWidth
25254
- ),
25255
- bottom: createBorder(
25256
- element.borderColor,
25257
- BorderStyle.DASHED,
25258
- element.borderExternalWidth || element.borderWidth
25259
- ),
25260
- left: createBorder(
25261
- element.borderColor,
25262
- BorderStyle.DASHED,
25263
- element.borderExternalWidth || element.borderWidth
25264
- ),
25265
- right: createBorder(
25266
- element.borderColor,
25267
- BorderStyle.DASHED,
25268
- element.borderExternalWidth || element.borderWidth
25269
- ),
25270
- insideHorizontal: createBorder(
25271
- element.borderColor,
25272
- BorderStyle.DASHED,
25273
- element.borderWidth
25274
- ),
25275
- insideVertical: createBorder(
25276
- element.borderColor,
25277
- BorderStyle.DASHED,
25278
- element.borderWidth
25279
- )
25280
- };
25281
- default:
25282
- return {
25283
- top: outerBorder,
25284
- bottom: outerBorder,
25285
- left: outerBorder,
25286
- right: outerBorder,
25287
- insideHorizontal: innerBorder,
25288
- insideVertical: innerBorder
25289
- };
25290
- }
25291
- }
25292
- function createTableCellBorders(td, inheritedColor, inheritedWidth) {
25293
- if (!td.borderTypes?.length && !td.borderColor) {
25294
- return void 0;
25295
- }
25296
- const color = td.borderColor || inheritedColor;
25297
- const createCellBorder = () => createBorder(color, BorderStyle.SINGLE, inheritedWidth);
25298
- if (td.borderColor && !td.borderTypes?.length) {
25299
- return {
25300
- top: createCellBorder(),
25301
- right: createCellBorder(),
25302
- bottom: createCellBorder(),
25303
- left: createCellBorder()
25304
- };
25305
- }
25306
- const top = td.borderTypes?.includes("top" /* TOP */) ? createCellBorder() : noneBorder();
25307
- const right2 = td.borderTypes?.includes("right" /* RIGHT */) ? createCellBorder() : noneBorder();
25308
- const bottom = td.borderTypes?.includes("bottom" /* BOTTOM */) ? createCellBorder() : noneBorder();
25309
- const left2 = td.borderTypes?.includes("left" /* LEFT */) ? createCellBorder() : noneBorder();
25310
- return {
25311
- top,
25312
- right: right2,
25313
- bottom,
25314
- left: left2
25315
- };
25316
- }
25317
- function createBorder(color = "#000000", style = BorderStyle.SINGLE, width = 1) {
25318
- return {
25319
- style,
25320
- color: normalizeHexColor(color, "000000") || "000000",
25321
- size: pxBorderToDocxSize(width)
25322
- };
25323
- }
25324
- function noneBorder() {
25325
- return {
25326
- style: BorderStyle.NONE,
25327
- size: 0,
25328
- color: "FFFFFF"
25329
- };
25330
- }
25331
- function mapPaddingToTableMargins(padding) {
25332
- if (!padding) return void 0;
25333
- return {
25334
- top: pxToTwips(padding[0]),
25335
- right: pxToTwips(padding[1]),
25336
- bottom: pxToTwips(padding[2]),
25337
- left: pxToTwips(padding[3]),
25338
- marginUnitType: WidthType.DXA
25339
- };
25340
- }
25341
- function mapCellVerticalAlign(verticalAlign) {
25342
- switch (verticalAlign) {
25343
- case VerticalAlign.CENTER:
25344
- return DocxVerticalAlign.CENTER;
25345
- case "bottom" /* BOTTOM */:
25346
- return DocxVerticalAlign.BOTTOM;
25347
- default:
25348
- return DocxVerticalAlign.TOP;
25349
- }
25350
- }
25351
- function mapRowFlexToAlignment(rowFlex) {
25352
- switch (rowFlex) {
25353
- case "center" /* CENTER */:
25354
- return AlignmentType.CENTER;
25355
- case "right" /* RIGHT */:
25356
- return AlignmentType.RIGHT;
25357
- case "alignment" /* ALIGNMENT */:
25358
- case "justify" /* JUSTIFY */:
25359
- return AlignmentType.JUSTIFIED;
25360
- default:
25361
- return AlignmentType.LEFT;
25362
- }
25363
- }
25364
- function mapUnderlineType(style) {
25365
- switch (style) {
25366
- case "double" /* DOUBLE */:
25367
- return UnderlineType.DOUBLE;
25368
- case "dashed" /* DASHED */:
25369
- return UnderlineType.DASH;
25370
- case "dotted" /* DOTTED */:
25371
- return UnderlineType.DOTTED;
25372
- case "wavy" /* WAVY */:
25373
- return UnderlineType.WAVE;
25374
- default:
25375
- return UnderlineType.SINGLE;
25376
- }
25377
- }
25378
- function getInlineElementText(element) {
25379
- switch (element.type) {
25380
- case "control" /* CONTROL */:
25381
- return getControlText(element.control);
25382
- case "date" /* DATE */:
25383
- return element.valueList?.length ? getTextFromElementList(element.valueList) : element.value;
25384
- case "checkbox" /* CHECKBOX */:
25385
- return element.checkbox?.value ? "\u2611" : "\u2610";
25386
- case "radio" /* RADIO */:
25387
- return element.radio?.value ? "\u25C9" : "\u25CB";
25388
- case "label" /* LABEL */:
25389
- case "latex" /* LATEX */:
25390
- case "subscript" /* SUBSCRIPT */:
25391
- case "superscript" /* SUPERSCRIPT */:
25392
- return element.value;
25393
- default:
25394
- return element.value;
25395
- }
25396
- }
25397
- function getControlText(control) {
25398
- if (!control) return "";
25399
- if (control.type === "text" /* TEXT */ || control.type === "date" /* DATE */ || control.type === "number" /* NUMBER */) {
25400
- const value = control.value?.length ? getTextFromElementList(control.value) : "";
25401
- const content = value || control.placeholder || "";
25402
- return `${control.preText || ""}${content}${control.postText || ""}`;
25403
- }
25404
- if (control.type === "select" /* SELECT */) {
25405
- const labels = getSelectedControlLabels(control.code, control.valueSets);
25406
- const content = labels.length ? labels.join(control.multiSelectDelimiter || ", ") : control.placeholder || "";
25407
- return `${control.preText || ""}${content}${control.postText || ""}`;
25408
- }
25409
- if (control.type === "checkbox" /* CHECKBOX */ || control.type === "radio" /* RADIO */) {
25410
- const isRadio = control.type === "radio" /* RADIO */;
25411
- return (control.valueSets || []).map((valueSet) => {
25412
- const checked = control.code?.split(",").includes(valueSet.code) || false;
25413
- return `${checked ? isRadio ? "\u25C9" : "\u2611" : isRadio ? "\u25CB" : "\u2610"} ${valueSet.value}`;
25414
- }).join(" ");
25415
- }
25416
- return "";
25417
- }
25418
- function getSelectedControlLabels(code, valueSets) {
25419
- if (!code || !valueSets?.length) return [];
25420
- return code.split(",").map(
25421
- (selectCode) => valueSets.find((valueSet) => valueSet.code === selectCode)?.value
25422
- ).filter((value) => !!value);
25423
- }
25424
- function getBlockFallbackText(element) {
25425
- if (element.block?.iframeBlock?.src) {
25426
- return element.block.iframeBlock.src;
25427
- }
25428
- if (element.block?.videoBlock?.src) {
25429
- return element.block.videoBlock.src;
25430
- }
25431
- return "";
25432
- }
25433
- function normalizeText(text = "") {
25434
- return text.replace(new RegExp(ZERO, "g"), "").replace(/\r\n/g, "\n");
24889
+ var EXACT_BASELINE_RATIO = 0.8;
24890
+ function rowLine(ctx, row, baseline = row.ascent / ctx.scale) {
24891
+ const { scale } = ctx;
24892
+ const height = row.height / scale;
24893
+ const ascent = Math.min(baseline, height);
24894
+ const line = Math.min(
24895
+ ascent / EXACT_BASELINE_RATIO,
24896
+ (height - ascent) / (1 - EXACT_BASELINE_RATIO)
24897
+ );
24898
+ const lineTw = Math.max(TINY_TWIP, pxTw(line));
24899
+ const beforeTw = Math.max(
24900
+ 0,
24901
+ pxTw(ascent) - Math.round(lineTw * EXACT_BASELINE_RATIO)
24902
+ );
24903
+ const afterTw = Math.max(0, pxTw(height) - lineTw - beforeTw);
24904
+ return { lineTw, beforeTw, afterTw };
25435
24905
  }
25436
- function createSerializeContext() {
24906
+ function rowLead(ctx, row, options) {
24907
+ const separator = row.elementList.find(
24908
+ (el) => el.type === "separator" /* SEPARATOR */
24909
+ );
24910
+ const baseline = separator && options.rowY !== void 0 ? separatorBaseline(
24911
+ ctx,
24912
+ row,
24913
+ options.rowY,
24914
+ separator.lineWidth || ctx.draw.getOptions().separator.lineWidth
24915
+ ) : void 0;
24916
+ return rowLine(ctx, row, baseline).beforeTw + tw(ctx, (row.offsetY || 0) + (row.spaceAbove || 0)) + pxTw(options.padTop || 0);
24917
+ }
24918
+ function rowSpacing(ctx, row, options) {
24919
+ const { lineTw, afterTw } = rowLine(ctx, row);
25437
24920
  return {
25438
- nextListInstance: 1
24921
+ before: options.skipLead ? 0 : rowLead(ctx, row, options),
24922
+ after: afterTw + tw(ctx, row.spaceBelow || 0) + pxTw(options.padBottom || 0) + (options.extraAfter || 0),
24923
+ line: lineTw,
24924
+ lineRule: LineRuleType.EXACT
25439
24925
  };
25440
24926
  }
25441
- function getListItemNumberingElement(listItemElements, fallback) {
25442
- return listItemElements.find(
25443
- (listItem) => listItem.listId || listItem.listLevel !== void 0 || !!listItem.listPreset || !!listItem.listStyle || !!listItem.listType
25444
- ) || fallback;
24927
+ function createSeparatorParagraph(ctx, row, element, x, rowY2, zone, options) {
24928
+ const { scale } = ctx;
24929
+ const opts = ctx.draw.getOptions();
24930
+ const lineWidth = element.lineWidth || opts.separator.lineWidth;
24931
+ const sideGap = 4;
24932
+ const left2 = (x - zone.startX) / scale + sideGap;
24933
+ const width = Math.max(1, (element.width || 0) - sideGap * 2);
24934
+ const color = element.color || opts.separator.strokeStyle;
24935
+ const line = rowLine(ctx, row, separatorBaseline(ctx, row, rowY2, lineWidth));
24936
+ return new Paragraph({
24937
+ pageBreakBefore: options.pageBreakBefore,
24938
+ widowControl: false,
24939
+ indent: { left: pxTw(left2), right: RIGHT_SLACK_TWIP },
24940
+ children: [
24941
+ new ImageRun({
24942
+ type: "png",
24943
+ data: createLineImage(width, lineWidth, color, element.dashArray),
24944
+ transformation: { width, height: lineWidth }
24945
+ })
24946
+ ],
24947
+ spacing: {
24948
+ before: options.skipLead ? 0 : rowLead(ctx, row, options),
24949
+ after: line.afterTw + tw(ctx, row.spaceBelow || 0) + pxTw(options.padBottom || 0) + (options.extraAfter || 0),
24950
+ line: line.lineTw,
24951
+ lineRule: LineRuleType.EXACT
24952
+ }
24953
+ });
25445
24954
  }
25446
- function createListInstance(context) {
25447
- return context.nextListInstance++;
24955
+ function separatorBaseline(ctx, row, rowY2, lineWidth) {
24956
+ return (Math.round(rowY2 + row.ascent) - rowY2) / ctx.scale + lineWidth;
25448
24957
  }
25449
- function createTableSerializeContext(element) {
25450
- return {
25451
- cellLayoutMap: computeTableCellLayout(
25452
- element.trList || [],
25453
- element.colgroup || []
25454
- ),
25455
- borderColor: element.borderColor,
25456
- borderWidth: element.borderWidth,
25457
- borderExternalWidth: element.borderExternalWidth
25458
- };
24958
+ function createLineImage(width, height, color, dashArray) {
24959
+ const ratio = 4;
24960
+ const canvas = document.createElement("canvas");
24961
+ canvas.width = Math.max(1, Math.round(width * ratio));
24962
+ canvas.height = Math.max(1, Math.round(height * ratio));
24963
+ const ctx = canvas.getContext("2d");
24964
+ ctx.strokeStyle = color;
24965
+ ctx.lineWidth = canvas.height;
24966
+ if (dashArray?.length) ctx.setLineDash(dashArray.map((v) => v * ratio));
24967
+ ctx.beginPath();
24968
+ ctx.moveTo(0, canvas.height / 2);
24969
+ ctx.lineTo(canvas.width, canvas.height / 2);
24970
+ ctx.stroke();
24971
+ const binary = atob(canvas.toDataURL("image/png").split(",")[1]);
24972
+ const bytes = new Uint8Array(binary.length);
24973
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
24974
+ return bytes;
24975
+ }
24976
+ function createSpacerParagraph(pageBreakBefore, height = 0) {
24977
+ return new Paragraph({
24978
+ pageBreakBefore,
24979
+ widowControl: false,
24980
+ children: [new TextRun({ text: "", size: 2 })],
24981
+ spacing: {
24982
+ before: 0,
24983
+ after: 0,
24984
+ line: Math.max(TINY_TWIP, pxTw(height)),
24985
+ lineRule: LineRuleType.EXACT
24986
+ }
24987
+ });
25459
24988
  }
25460
- function computeTableCellLayout(trList, colgroup) {
25461
- const cellLayoutMap = /* @__PURE__ */ new WeakMap();
25462
- if (!trList.length || !colgroup.length) {
25463
- return cellLayoutMap;
25464
- }
25465
- const occupiedUntilRow = Array(colgroup.length).fill(0);
25466
- for (let rowIndex = 0; rowIndex < trList.length; rowIndex++) {
25467
- const tr = trList[rowIndex];
25468
- let colIndex = 0;
25469
- for (let tdIndex = 0; tdIndex < tr.tdList.length; tdIndex++) {
25470
- while (colIndex < colgroup.length && occupiedUntilRow[colIndex] > rowIndex) {
25471
- colIndex += 1;
25472
- }
25473
- const td = tr.tdList[tdIndex];
25474
- let width = 0;
25475
- for (let currentCol = colIndex; currentCol < colIndex + td.colspan && currentCol < colgroup.length; currentCol++) {
25476
- width += colgroup[currentCol].width;
25477
- occupiedUntilRow[currentCol] = Math.max(
25478
- occupiedUntilRow[currentCol],
25479
- rowIndex + td.rowspan
25480
- );
25481
- }
25482
- cellLayoutMap.set(td, { width });
25483
- colIndex += td.colspan;
24989
+ async function serializeTable(ctx, element, position, zone) {
24990
+ const { draw, scale } = ctx;
24991
+ const opts = draw.getOptions();
24992
+ const tableX = position.coordinate.leftTop[0];
24993
+ const trList = element.trList || [];
24994
+ const colgroup = element.colgroup || [];
24995
+ const rows = [];
24996
+ for (let t = 0; t < trList.length; t++) {
24997
+ const tr = trList[t];
24998
+ const cells = [];
24999
+ let rowTopBorder = 0;
25000
+ for (let d = 0; d < tr.tdList.length; d++) {
25001
+ const td = tr.tdList[d];
25002
+ const padding = td.padding || opts.table.tdPadding;
25003
+ const borders = createCellBorders(ctx, element, td);
25004
+ const topBorder = t === 0 ? borderPx(borders.top) : 0;
25005
+ rowTopBorder = Math.max(rowTopBorder, topBorder);
25006
+ const cellChildren = await serializeRows(
25007
+ ctx,
25008
+ td.rowList || [],
25009
+ {
25010
+ startX: (td.x + padding[3]) * scale + tableX,
25011
+ width: (td.width - padding[1] - padding[3]) * scale,
25012
+ positionList: td.positionList || []
25013
+ },
25014
+ { padTop: Math.max(0, padding[0] - topBorder), padBottom: padding[2] }
25015
+ );
25016
+ cells.push(
25017
+ new TableCell({
25018
+ children: cellChildren.length ? cellChildren : [createSpacerParagraph(false)],
25019
+ columnSpan: td.colspan > 1 ? td.colspan : void 0,
25020
+ rowSpan: td.rowspan > 1 ? td.rowspan : void 0,
25021
+ width: { size: pxTw(td.width), type: WidthType.DXA },
25022
+ verticalAlign: mapVerticalAlign(td.verticalAlign),
25023
+ margins: {
25024
+ top: 0,
25025
+ right: pxTw(padding[1]),
25026
+ bottom: 0,
25027
+ left: pxTw(Math.max(0, padding[3] - borderPx(borders.left) / 2)),
25028
+ marginUnitType: WidthType.DXA
25029
+ },
25030
+ shading: td.backgroundColor ? {
25031
+ fill: normalizeHexColor(td.backgroundColor, "FFFFFF"),
25032
+ type: ShadingType.CLEAR,
25033
+ color: "auto"
25034
+ } : void 0,
25035
+ borders
25036
+ })
25037
+ );
25484
25038
  }
25039
+ rows.push(
25040
+ new TableRow({
25041
+ children: cells,
25042
+ cantSplit: true,
25043
+ height: {
25044
+ value: pxTw(tr.height - rowTopBorder),
25045
+ rule: HeightRule.EXACT
25046
+ }
25047
+ })
25048
+ );
25485
25049
  }
25486
- return cellLayoutMap;
25050
+ return new Table({
25051
+ rows,
25052
+ layout: TableLayoutType.FIXED,
25053
+ width: { size: pxTw(element.width), type: WidthType.DXA },
25054
+ columnWidths: colgroup.map((col) => pxTw(col.width)),
25055
+ indent: { size: tw(ctx, tableX - zone.startX), type: WidthType.DXA },
25056
+ borders: noTableBorders()
25057
+ });
25487
25058
  }
25488
- function getTableWidthFromColgroup(colgroup) {
25489
- if (!colgroup?.length) {
25490
- return void 0;
25491
- }
25492
- return colgroup.reduce((sum, col) => sum + col.width, 0);
25059
+ function createCellBorders(ctx, table, td) {
25060
+ const opts = ctx.draw.getOptions();
25061
+ const color = normalizeHexColor(
25062
+ td.borderColor || table.borderColor || opts.table.defaultBorderColor,
25063
+ "000000"
25064
+ );
25065
+ const width = table.borderWidth || 1;
25066
+ const externalWidth = table.borderExternalWidth || width;
25067
+ const isDash = table.borderType === "dash" /* DASH */;
25068
+ const line = (w) => ({
25069
+ style: isDash ? BorderStyle.DASHED : BorderStyle.SINGLE,
25070
+ size: Math.max(2, Math.round(w * 6)),
25071
+ color
25072
+ });
25073
+ const none = { style: BorderStyle.NONE, size: 0, color: "auto" };
25074
+ const isTop = td.rowIndex === 0;
25075
+ const isLeft = td.colIndex === 0;
25076
+ const isBottom = td.rowIndex + td.rowspan === table.trList.length;
25077
+ const isRight = td.colIndex + td.colspan === table.colgroup.length;
25078
+ const edge = (outer) => outer ? line(externalWidth) : line(width);
25079
+ let top = none;
25080
+ let right2 = none;
25081
+ let bottom = none;
25082
+ let left2 = none;
25083
+ switch (table.borderType) {
25084
+ case "empty" /* EMPTY */:
25085
+ break;
25086
+ case "external" /* EXTERNAL */:
25087
+ if (isTop) top = edge(true);
25088
+ if (isBottom) bottom = edge(true);
25089
+ if (isLeft) left2 = edge(true);
25090
+ if (isRight) right2 = edge(true);
25091
+ break;
25092
+ case "internal" /* INTERNAL */:
25093
+ if (!isTop) top = edge(false);
25094
+ if (!isBottom) bottom = edge(false);
25095
+ if (!isLeft) left2 = edge(false);
25096
+ if (!isRight) right2 = edge(false);
25097
+ break;
25098
+ default:
25099
+ top = edge(isTop);
25100
+ bottom = edge(isBottom);
25101
+ left2 = edge(isLeft);
25102
+ right2 = edge(isRight);
25103
+ }
25104
+ if (td.borderTypes?.includes("top" /* TOP */)) top = line(width);
25105
+ if (td.borderTypes?.includes("right" /* RIGHT */)) right2 = line(width);
25106
+ if (td.borderTypes?.includes("bottom" /* BOTTOM */)) bottom = line(width);
25107
+ if (td.borderTypes?.includes("left" /* LEFT */)) left2 = line(width);
25108
+ return { top, right: right2, bottom, left: left2 };
25109
+ }
25110
+ function borderPx(border) {
25111
+ return border.style === BorderStyle.NONE ? 0 : border.size / 8 * (4 / 3);
25112
+ }
25113
+ function noTableBorders() {
25114
+ const none = { style: BorderStyle.NONE, size: 0, color: "auto" };
25115
+ return {
25116
+ top: none,
25117
+ bottom: none,
25118
+ left: none,
25119
+ right: none,
25120
+ insideHorizontal: none,
25121
+ insideVertical: none
25122
+ };
25493
25123
  }
25494
- function normalizeHexColor(color, fallback) {
25495
- const normalized = normalizeHexLiteral(color) || normalizeRgbColor(color) || normalizeBrowserColor(color);
25496
- if (normalized) {
25497
- return normalized;
25124
+ function mapVerticalAlign(verticalAlign) {
25125
+ switch (verticalAlign) {
25126
+ case "middle" /* MIDDLE */:
25127
+ return DocxVerticalAlign.CENTER;
25128
+ case "bottom" /* BOTTOM */:
25129
+ return DocxVerticalAlign.BOTTOM;
25130
+ default:
25131
+ return DocxVerticalAlign.TOP;
25498
25132
  }
25499
- return fallback ? normalizeHexLiteral(fallback) || void 0 : void 0;
25500
25133
  }
25501
- function normalizeHexLiteral(color) {
25502
- const value = color.trim().replace(/^#/, "");
25503
- if (/^[\da-f]{3}$/i.test(value)) {
25504
- return value.split("").map((part) => `${part}${part}`).join("").toUpperCase();
25505
- }
25506
- if (/^[\da-f]{4}$/i.test(value)) {
25507
- return value.slice(0, 3).split("").map((part) => `${part}${part}`).join("").toUpperCase();
25508
- }
25509
- if (/^[\da-f]{6}$/i.test(value)) {
25510
- return value.toUpperCase();
25134
+ async function serializeFooter(ctx, pageWidth, pageHeight, margins) {
25135
+ const { draw, scale } = ctx;
25136
+ const footer = draw.getFooter();
25137
+ const opts = draw.getOptions();
25138
+ const barHeight = footer.getHeight() / scale;
25139
+ const contentHeight = footer.getRowHeight() / scale;
25140
+ const paddingTop = Math.floor(Math.max(0, (barHeight - contentHeight) / 2) * scale) / scale;
25141
+ const zone = {
25142
+ startX: draw.getMargins()[3],
25143
+ width: draw.getInnerWidth(),
25144
+ positionList: footer.getPositionList()
25145
+ };
25146
+ const rowList = footer.getRowList();
25147
+ const textWidth = pageWidth - margins[1] - margins[3];
25148
+ const pageNumber = createPageNumberRuns(ctx, pageHeight, textWidth);
25149
+ let pageNumberRow = -1;
25150
+ if (pageNumber) {
25151
+ pageNumberRow = rowList.length - 1;
25152
+ for (let r = 0; r < rowList.length; r++) {
25153
+ const top = zone.positionList[rowList[r].startIndex].coordinate.leftTop[1] / scale;
25154
+ if (pageNumber.baseline <= top + rowList[r].height / scale) {
25155
+ pageNumberRow = r;
25156
+ break;
25157
+ }
25158
+ }
25511
25159
  }
25512
- if (/^[\da-f]{8}$/i.test(value)) {
25513
- return value.slice(0, 6).toUpperCase();
25160
+ const children = [];
25161
+ for (let r = 0; r < rowList.length; r++) {
25162
+ const row = rowList[r];
25163
+ const rowOptions = { padTop: r === 0 ? paddingTop : 0 };
25164
+ if (r !== pageNumberRow) {
25165
+ children.push(...await serializeRows(ctx, [row], zone, rowOptions));
25166
+ continue;
25167
+ }
25168
+ const top = zone.positionList[row.startIndex].coordinate.leftTop[1] / scale;
25169
+ const shift = pageNumber.baseline - (top + row.ascent / scale);
25170
+ children.push(
25171
+ await serializeRow(ctx, row, zone, rowOptions, {
25172
+ tabStop: pageNumber.tabStop,
25173
+ tabType: pageNumber.tabType,
25174
+ children: pageNumber.runs(shift),
25175
+ style: PAGE_NUMBER_STYLE
25176
+ })
25177
+ );
25514
25178
  }
25515
- return void 0;
25179
+ const fill = opts.footer.backgroundColor ? normalizeHexColor(opts.footer.backgroundColor, "FFFFFF") : void 0;
25180
+ const none = { style: BorderStyle.NONE, size: 0, color: "auto" };
25181
+ const band = new Table({
25182
+ layout: TableLayoutType.FIXED,
25183
+ width: { size: pxTw(pageWidth), type: WidthType.DXA },
25184
+ columnWidths: [pxTw(pageWidth)],
25185
+ indent: { size: -pxTw(margins[3]), type: WidthType.DXA },
25186
+ borders: noTableBorders(),
25187
+ rows: [
25188
+ new TableRow({
25189
+ cantSplit: true,
25190
+ height: { value: pxTw(barHeight), rule: HeightRule.EXACT },
25191
+ children: [
25192
+ new TableCell({
25193
+ width: { size: pxTw(pageWidth), type: WidthType.DXA },
25194
+ margins: {
25195
+ top: 0,
25196
+ bottom: 0,
25197
+ left: pxTw(margins[3]),
25198
+ right: pxTw(margins[1]),
25199
+ marginUnitType: WidthType.DXA
25200
+ },
25201
+ shading: fill ? { fill, type: ShadingType.CLEAR, color: "auto" } : void 0,
25202
+ borders: { top: none, right: none, bottom: none, left: none },
25203
+ children: children.length ? children : [createSpacerParagraph(false)]
25204
+ })
25205
+ ]
25206
+ })
25207
+ ]
25208
+ });
25209
+ return [band];
25516
25210
  }
25517
- function normalizeRgbColor(color) {
25518
- const match = color.trim().match(/^rgba?\((.+)\)$/i);
25519
- if (!match) {
25520
- return void 0;
25211
+ var PAGE_NUMBER_STYLE = "WindocPageNumber";
25212
+ var FieldCharAttributes = class extends XmlAttributeComponent {
25213
+ constructor() {
25214
+ super(...arguments);
25215
+ this.xmlKeys = { type: "w:fldCharType" };
25521
25216
  }
25522
- const parts = match[1].replace(/\s*\/\s*/g, ",").split(/\s*,\s*|\s+/).filter(Boolean);
25523
- if (parts.length < 3) {
25524
- return void 0;
25217
+ };
25218
+ var FieldChar = class extends XmlComponent {
25219
+ constructor(type) {
25220
+ super("w:fldChar");
25221
+ this.root.push(new FieldCharAttributes({ type }));
25525
25222
  }
25526
- const red = parseRgbChannel(parts[0]);
25527
- const green = parseRgbChannel(parts[1]);
25528
- const blue = parseRgbChannel(parts[2]);
25529
- if (red === null || green === null || blue === null) {
25530
- return void 0;
25223
+ };
25224
+ var InstrTextAttributes = class extends XmlAttributeComponent {
25225
+ constructor() {
25226
+ super(...arguments);
25227
+ this.xmlKeys = { space: "xml:space" };
25531
25228
  }
25532
- const alpha = parts[3] !== void 0 ? parseAlphaChannel(parts[3]) : 1;
25533
- if (alpha === null || alpha <= 0) {
25534
- return void 0;
25229
+ };
25230
+ var InstrText = class extends XmlComponent {
25231
+ constructor(instruction) {
25232
+ super("w:instrText");
25233
+ this.root.push(new InstrTextAttributes({ space: "preserve" }));
25234
+ this.root.push(` ${instruction} `);
25535
25235
  }
25536
- const flattened = alpha >= 1 ? [red, green, blue] : [
25537
- flattenChannel(red, alpha),
25538
- flattenChannel(green, alpha),
25539
- flattenChannel(blue, alpha)
25236
+ };
25237
+ function createFieldRuns(instruction, cached, style) {
25238
+ return [
25239
+ new TextRun({ ...style, children: [new FieldChar("begin")] }),
25240
+ new TextRun({ ...style, children: [new InstrText(instruction)] }),
25241
+ new TextRun({ ...style, children: [new FieldChar("separate")] }),
25242
+ new TextRun({ ...style, text: cached }),
25243
+ new TextRun({ ...style, children: [new FieldChar("end")] })
25540
25244
  ];
25541
- return flattened.map(toHexChannel).join("");
25542
25245
  }
25543
- function normalizeBrowserColor(color) {
25544
- if (typeof document === "undefined") {
25545
- return void 0;
25546
- }
25547
- const canvas = document.createElement("canvas");
25548
- const context = canvas.getContext("2d");
25549
- if (!context) {
25550
- return void 0;
25551
- }
25552
- context.fillStyle = "#000000";
25553
- context.fillStyle = color;
25554
- const normalized = context.fillStyle;
25555
- if (typeof normalized !== "string") {
25556
- return void 0;
25557
- }
25558
- return normalizeHexLiteral(normalized) || normalizeRgbColor(normalized);
25246
+ function pageNumberRunStyle(pageNumber) {
25247
+ return {
25248
+ font: mapFont(pageNumber?.font || "sans-serif"),
25249
+ // PageNumber draws `${size}px`; half-points = px * 0.75 * 2
25250
+ size: Math.round((pageNumber?.size || 12) * 1.5),
25251
+ color: normalizeHexColor(pageNumber?.color || "#000000", "000000")
25252
+ };
25559
25253
  }
25560
- function parseRgbChannel(value) {
25561
- if (value.endsWith("%")) {
25562
- const percent = Number(value.slice(0, -1));
25563
- if (!Number.isFinite(percent)) {
25564
- return null;
25565
- }
25566
- return clampColorChannel(Math.round(percent / 100 * 255));
25567
- }
25568
- const channel = Number(value);
25569
- if (!Number.isFinite(channel)) {
25570
- return null;
25254
+ function createPageNumberRuns(ctx, pageHeight, textWidth) {
25255
+ const { pageNumber } = ctx.draw.getOptions();
25256
+ if (pageNumber.disabled || pageNumber.fromPageNo > 0) return null;
25257
+ const pageCount = ctx.draw.getPageCount();
25258
+ const tokens = (pageNumber.format || FORMAT_PLACEHOLDER.PAGE_NO).split(
25259
+ /(\{pageNo\}|\{pageCount\})/
25260
+ );
25261
+ const tabType = pageNumber.rowFlex === "center" /* CENTER */ ? TabStopType.CENTER : pageNumber.rowFlex === "right" /* RIGHT */ ? TabStopType.RIGHT : TabStopType.LEFT;
25262
+ const tabStop = tabType === TabStopType.CENTER ? pxTw(textWidth / 2) : tabType === TabStopType.RIGHT ? pxTw(textWidth) : 0;
25263
+ const position = (shift) => {
25264
+ const halfPoints = Math.round(-shift * 0.75 * 2);
25265
+ return halfPoints ? `${halfPoints}` : void 0;
25266
+ };
25267
+ return {
25268
+ baseline: pageHeight - pageNumber.bottom,
25269
+ tabType,
25270
+ tabStop,
25271
+ // shift > 0 means the number sits lower than the row baseline
25272
+ runs: (shift) => tokens.filter(Boolean).map((token) => {
25273
+ const style = {
25274
+ ...pageNumberRunStyle(pageNumber),
25275
+ position: position(shift)
25276
+ };
25277
+ const field = token === FORMAT_PLACEHOLDER.PAGE_NO ? { instruction: "PAGE", cached: "1" } : token === FORMAT_PLACEHOLDER.PAGE_COUNT ? { instruction: "NUMPAGES", cached: `${pageCount}` } : null;
25278
+ if (!field) return [new TextRun({ text: token, ...style })];
25279
+ return createFieldRuns(field.instruction, field.cached, style);
25280
+ }).flat()
25281
+ };
25282
+ }
25283
+ function createTextRun(ctx, text, element, shading, characterSpacing) {
25284
+ const opts = ctx.draw.getOptions();
25285
+ const isLink = element.type === "hyperlink" /* HYPERLINK */;
25286
+ const color = normalizeHexColor(
25287
+ element.color || (isLink ? opts.defaultHyperlinkColor : opts.defaultColor),
25288
+ "000000"
25289
+ );
25290
+ const highlight = element.highlight ? normalizeHexColor(element.highlight) : void 0;
25291
+ const textRun = new TextRun({
25292
+ text,
25293
+ font: mapFont(element.font || opts.defaultFont),
25294
+ size: Math.round(getSize(ctx, element) * 2),
25295
+ bold: !!element.bold,
25296
+ italics: !!element.italic,
25297
+ strike: !!element.strikeout,
25298
+ superScript: element.type === "superscript" /* SUPERSCRIPT */,
25299
+ subScript: element.type === "subscript" /* SUBSCRIPT */,
25300
+ underline: element.underline || isLink ? { type: mapUnderlineType(element.textDecoration?.style) } : void 0,
25301
+ color,
25302
+ shading: shading || (highlight ? { fill: highlight, type: ShadingType.CLEAR, color: "auto" } : void 0),
25303
+ characterSpacing
25304
+ });
25305
+ if (isLink && element.url) {
25306
+ return new ExternalHyperlink({ link: element.url, children: [textRun] });
25571
25307
  }
25572
- return clampColorChannel(Math.round(channel));
25308
+ return textRun;
25573
25309
  }
25574
- function parseAlphaChannel(value) {
25575
- if (value.endsWith("%")) {
25576
- const percent = Number(value.slice(0, -1));
25577
- if (!Number.isFinite(percent)) {
25578
- return null;
25310
+ function labelShading(ctx, element) {
25311
+ const { defaultBackgroundColor } = ctx.draw.getOptions().label;
25312
+ return {
25313
+ fill: normalizeHexColor(
25314
+ element.label?.backgroundColor || defaultBackgroundColor,
25315
+ "FFFFFF"
25316
+ ),
25317
+ type: ShadingType.CLEAR,
25318
+ color: "auto"
25319
+ };
25320
+ }
25321
+ async function createImageRun(element) {
25322
+ try {
25323
+ const image = await loadImagePayload(element.value);
25324
+ const transformation = {
25325
+ width: Math.max(1, element.width || 1),
25326
+ height: Math.max(1, element.height || 1)
25327
+ };
25328
+ if (image.type === "svg" && image.fallbackPng) {
25329
+ return new ImageRun({
25330
+ type: "svg",
25331
+ data: image.data,
25332
+ fallback: { type: "png", data: image.fallbackPng },
25333
+ transformation
25334
+ });
25579
25335
  }
25580
- return Math.min(Math.max(percent / 100, 0), 1);
25581
- }
25582
- const alpha = Number(value);
25583
- if (!Number.isFinite(alpha)) {
25336
+ return new ImageRun({
25337
+ type: image.type,
25338
+ data: image.data,
25339
+ transformation
25340
+ });
25341
+ } catch {
25584
25342
  return null;
25585
25343
  }
25586
- return Math.min(Math.max(alpha, 0), 1);
25587
- }
25588
- function clampColorChannel(value) {
25589
- return Math.min(Math.max(value, 0), 255);
25590
25344
  }
25591
- function flattenChannel(value, alpha) {
25592
- return clampColorChannel(Math.round(255 * (1 - alpha) + value * alpha));
25345
+ function getElementText(element) {
25346
+ switch (element.type) {
25347
+ case "checkbox" /* CHECKBOX */:
25348
+ return element.checkbox?.value ? "\u2611" : "\u2610";
25349
+ case "radio" /* RADIO */:
25350
+ return element.radio?.value ? "\u25C9" : "\u25CB";
25351
+ default:
25352
+ return (element.value || "").replace(new RegExp(ZERO, "g"), "");
25353
+ }
25593
25354
  }
25594
- function toHexChannel(value) {
25595
- return value.toString(16).padStart(2, "0").toUpperCase();
25355
+ function getSize(ctx, element) {
25356
+ return element.actualSize || element.size || ctx.draw.getOptions().defaultSize;
25596
25357
  }
25597
- function pxBorderToDocxSize(width) {
25598
- const safeWidth = Number.isFinite(width) && width > 0 ? width : 1;
25599
- return Math.max(2, Math.round(safeWidth * 6));
25358
+ function measure(ctx, text, element) {
25359
+ ctx.measureCtx.font = ctx.draw.getElementFont(element, 1);
25360
+ return ctx.measureCtx.measureText(text).width;
25600
25361
  }
25601
- function getRegularImageType(mime) {
25602
- if (mime.includes("png")) return "png";
25603
- if (mime.includes("jpeg") || mime.includes("jpg")) return "jpg";
25604
- if (mime.includes("gif")) return "gif";
25605
- if (mime.includes("bmp")) return "bmp";
25606
- return null;
25362
+ function isSameRunStyle(a, b) {
25363
+ return a.type === b.type && a.font === b.font && a.size === b.size && a.actualSize === b.actualSize && !!a.bold === !!b.bold && !!a.italic === !!b.italic && !!a.underline === !!b.underline && !!a.strikeout === !!b.strikeout && a.color === b.color && a.highlight === b.highlight && a.url === b.url;
25607
25364
  }
25608
- function normalizeDocxFileName(fileName) {
25609
- const trimmed = fileName?.trim();
25610
- if (!trimmed) {
25611
- return DEFAULT_DOCX_FILE_NAME;
25365
+ function mapFont(font) {
25366
+ const name = font.trim().replace(/^['"]|['"]$/g, "");
25367
+ switch (name.toLowerCase()) {
25368
+ case "sans-serif":
25369
+ return "Arial";
25370
+ case "serif":
25371
+ return "Times New Roman";
25372
+ case "monospace":
25373
+ return "Courier New";
25374
+ default:
25375
+ return name;
25612
25376
  }
25613
- return trimmed.toLowerCase().endsWith(".docx") ? trimmed : `${trimmed}.docx`;
25614
- }
25615
- function pxToTwips(px) {
25616
- return Math.round(px * 15);
25617
25377
  }
25618
25378
 
25619
25379
  // src/utils/pdf.ts
@@ -25625,7 +25385,7 @@ import {
25625
25385
  var DEFAULT_PDF_FILE_NAME = "document.pdf";
25626
25386
  var DEFAULT_IMAGE_WIDTH2 = 320;
25627
25387
  var DEFAULT_IMAGE_HEIGHT2 = 180;
25628
- var DEFAULT_LINE_HEIGHT2 = 1.15;
25388
+ var DEFAULT_LINE_HEIGHT = 1.15;
25629
25389
  var PAGE_REGION_GAP = 12;
25630
25390
  var SEPARATOR_HEIGHT = 12;
25631
25391
  var LIST_GAP = 8;
@@ -25820,7 +25580,7 @@ async function parseElementList(elementList, context, options) {
25820
25580
  }
25821
25581
  if (element.type === "block" /* BLOCK */) {
25822
25582
  await flushInlineBuffer();
25823
- const blockText = getBlockFallbackText2(element);
25583
+ const blockText = getBlockFallbackText(element);
25824
25584
  if (blockText) {
25825
25585
  blocks.push(
25826
25586
  ...await parseInlineElements(
@@ -25872,7 +25632,7 @@ async function parseInlineElements(elementList, context, options, overrides = {}
25872
25632
  current = null;
25873
25633
  };
25874
25634
  const appendText = (element, text, factory, preserveTrailingBreak = false) => {
25875
- const normalized = normalizeText2(text);
25635
+ const normalized = normalizeText(text);
25876
25636
  const parts = normalized.split("\n");
25877
25637
  let lastSeparatorFlushedContent = false;
25878
25638
  for (let i = 0; i < parts.length; i++) {
@@ -25908,7 +25668,7 @@ async function parseInlineElements(elementList, context, options, overrides = {}
25908
25668
  const children = element.valueList || [];
25909
25669
  for (let childIndex = 0; childIndex < children.length; childIndex++) {
25910
25670
  const child = children[childIndex];
25911
- const text = normalizeText2(getInlineElementText2(child));
25671
+ const text = normalizeText(getInlineElementText(child));
25912
25672
  if (!text) continue;
25913
25673
  appendText(
25914
25674
  element,
@@ -25957,7 +25717,7 @@ async function parseInlineElements(elementList, context, options, overrides = {}
25957
25717
  ensureParagraph(element).runs.push(badgeRun);
25958
25718
  continue;
25959
25719
  }
25960
- const textValue = getInlineElementText2(element);
25720
+ const textValue = getInlineElementText(element);
25961
25721
  if (!textValue) {
25962
25722
  continue;
25963
25723
  }
@@ -25985,7 +25745,7 @@ async function parseListBlock(element, context, options) {
25985
25745
  const blocks = [];
25986
25746
  const orderedCounts = Array(9).fill(0);
25987
25747
  for (const listItemElements of listItemMap.values()) {
25988
- const itemElement = getListItemNumberingElement2(listItemElements, element);
25748
+ const itemElement = getListItemNumberingElement(listItemElements, element);
25989
25749
  const marker = getListMarker(itemElement, orderedCounts);
25990
25750
  blocks.push(
25991
25751
  ...await parseInlineElements(listItemElements, context, options, {
@@ -26544,10 +26304,11 @@ function layoutParagraph(block, width, context) {
26544
26304
  }
26545
26305
  if (token.width > availableWidth && token.kind === "text" && token.run.type === "text") {
26546
26306
  const segments = splitTextToken(token, availableWidth, context);
26547
- for (let segmentIndex = 0; segmentIndex < segments.length; segmentIndex++) {
26548
- tokens.splice(i + segmentIndex, 0, segments[segmentIndex]);
26307
+ if (segments.length > 1) {
26308
+ tokens.splice(i, 1, ...segments);
26309
+ i--;
26310
+ continue;
26549
26311
  }
26550
- continue;
26551
26312
  }
26552
26313
  if (line.width + token.width > availableWidth && line.fragments.length) {
26553
26314
  commitLine();
@@ -26906,7 +26667,7 @@ function getEmptyLineHeight(block, context) {
26906
26667
  block.context.rowMargin || context.options.defaultRowMargin
26907
26668
  );
26908
26669
  }
26909
- function getRunHeight(run, rowMargin = DEFAULT_LINE_HEIGHT2) {
26670
+ function getRunHeight(run, rowMargin = DEFAULT_LINE_HEIGHT) {
26910
26671
  return run.size * rowMargin;
26911
26672
  }
26912
26673
  function resolveTextMetrics(run, context) {
@@ -27115,10 +26876,10 @@ function loadHtmlImage2(src) {
27115
26876
  image.src = src;
27116
26877
  });
27117
26878
  }
27118
- function getInlineElementText2(element) {
26879
+ function getInlineElementText(element) {
27119
26880
  switch (element.type) {
27120
26881
  case "control" /* CONTROL */:
27121
- return getControlText2(element.control);
26882
+ return getControlText(element.control);
27122
26883
  case "date" /* DATE */:
27123
26884
  return element.valueList?.length ? getTextFromElementList(element.valueList) : element.value;
27124
26885
  case "checkbox" /* CHECKBOX */:
@@ -27134,7 +26895,7 @@ function getInlineElementText2(element) {
27134
26895
  return element.value;
27135
26896
  }
27136
26897
  }
27137
- function getControlText2(control) {
26898
+ function getControlText(control) {
27138
26899
  if (!control) return "";
27139
26900
  if (control.type === "text" /* TEXT */ || control.type === "date" /* DATE */ || control.type === "number" /* NUMBER */) {
27140
26901
  const value = control.value?.length ? getTextFromElementList(control.value) : "";
@@ -27142,7 +26903,7 @@ function getControlText2(control) {
27142
26903
  return `${control.preText || ""}${content}${control.postText || ""}`;
27143
26904
  }
27144
26905
  if (control.type === "select" /* SELECT */) {
27145
- const labels = getSelectedControlLabels2(control.code, control.valueSets);
26906
+ const labels = getSelectedControlLabels(control.code, control.valueSets);
27146
26907
  const content = labels.length ? labels.join(control.multiSelectDelimiter || ", ") : control.placeholder || "";
27147
26908
  return `${control.preText || ""}${content}${control.postText || ""}`;
27148
26909
  }
@@ -27155,13 +26916,13 @@ function getControlText2(control) {
27155
26916
  }
27156
26917
  return "";
27157
26918
  }
27158
- function getSelectedControlLabels2(code, valueSets) {
26919
+ function getSelectedControlLabels(code, valueSets) {
27159
26920
  if (!code || !valueSets?.length) return [];
27160
26921
  return code.split(",").map(
27161
26922
  (selectCode) => valueSets.find((valueSet) => valueSet.code === selectCode)?.value
27162
26923
  ).filter((value) => !!value);
27163
26924
  }
27164
- function getBlockFallbackText2(element) {
26925
+ function getBlockFallbackText(element) {
27165
26926
  if (element.block?.iframeBlock?.src) {
27166
26927
  return element.block.iframeBlock.src;
27167
26928
  }
@@ -27170,7 +26931,7 @@ function getBlockFallbackText2(element) {
27170
26931
  }
27171
26932
  return "";
27172
26933
  }
27173
- function getListItemNumberingElement2(listItemElements, fallback) {
26934
+ function getListItemNumberingElement(listItemElements, fallback) {
27174
26935
  return listItemElements.find(
27175
26936
  (listItem) => listItem.listId || listItem.listLevel !== void 0 || !!listItem.listPreset || !!listItem.listStyle || !!listItem.listType
27176
26937
  ) || fallback;
@@ -27392,7 +27153,7 @@ function getReservedPageNumberBottom(pageNumber, pageNumberHeight) {
27392
27153
  }
27393
27154
  return pxToPt(pageNumber.bottom + 4) + pageNumberHeight;
27394
27155
  }
27395
- function normalizeText2(text = "") {
27156
+ function normalizeText(text = "") {
27396
27157
  return text.replace(new RegExp(ZERO, "g"), "").replace(/\r\n/g, "\n");
27397
27158
  }
27398
27159
  function normalizePdfFileName(fileName) {
@@ -28732,8 +28493,7 @@ var CommandAdapt = class {
28732
28493
  }
28733
28494
  }
28734
28495
  async exportDocx(payload = {}) {
28735
- const result = this.draw.getValue();
28736
- const { blob, fileName } = await exportEditorDataToDocx(result, payload);
28496
+ const { blob, fileName } = await exportDrawToDocx(this.draw, payload);
28737
28497
  downloadBlob(blob, fileName);
28738
28498
  }
28739
28499
  async exportPdf(payload = {}) {