@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.js CHANGED
@@ -78,7 +78,7 @@ __export(index_exports, {
78
78
  module.exports = __toCommonJS(index_exports);
79
79
 
80
80
  // src/version.ts
81
- var version = "0.3.26";
81
+ var version = "0.3.27";
82
82
 
83
83
  // src/dataset/enum/Common.ts
84
84
  var MaxHeightRatio = /* @__PURE__ */ ((MaxHeightRatio2) => {
@@ -19190,10 +19190,11 @@ var ListParticle = class {
19190
19190
  if (!cycle) return "\u25CF";
19191
19191
  return cycle[level % cycle.length];
19192
19192
  }
19193
- drawListStyle(ctx, row, position) {
19194
- const { elementList, offsetX, listIndex, ascent } = row;
19193
+ // Marker x for a list row's first line (shared by canvas drawing and export)
19194
+ getListMarkerX(row, position) {
19195
+ const { elementList, offsetX } = row;
19195
19196
  const startElement = elementList[0];
19196
- if (startElement.value !== ZERO || startElement.listWrap) return;
19197
+ if (startElement.value !== ZERO || startElement.listWrap) return null;
19197
19198
  let tabWidth = 0;
19198
19199
  const { defaultTabWidth, scale } = this.options;
19199
19200
  for (let i = 1; i < elementList.length; i++) {
@@ -19203,12 +19204,29 @@ var ListParticle = class {
19203
19204
  }
19204
19205
  const {
19205
19206
  coordinate: {
19206
- leftTop: [startX, startY]
19207
+ leftTop: [startX]
19207
19208
  }
19208
19209
  } = position;
19209
19210
  const indentWidth = this.getListIndentWidth(startElement);
19210
- const x = startX - offsetX + tabWidth + indentWidth;
19211
- const y = startY + ascent;
19211
+ return startX - offsetX + tabWidth + indentWidth;
19212
+ }
19213
+ getListMarker(row) {
19214
+ const startElement = row.elementList[0];
19215
+ if (startElement.listStyle === "checkbox" /* CHECKBOX */) return null;
19216
+ const text = this._getListMarkerText(startElement, row.listIndex);
19217
+ if (!text) return null;
19218
+ return {
19219
+ text,
19220
+ styleElement: this._getListMarkerStyleElement(row.elementList)
19221
+ };
19222
+ }
19223
+ drawListStyle(ctx, row, position) {
19224
+ const { elementList, ascent } = row;
19225
+ const startElement = elementList[0];
19226
+ const x = this.getListMarkerX(row, position);
19227
+ if (x === null) return;
19228
+ const { scale } = this.options;
19229
+ const y = position.coordinate.leftTop[1] + ascent;
19212
19230
  if (startElement.listStyle === "checkbox" /* CHECKBOX */) {
19213
19231
  const { width, height, gap } = this.options.checkbox;
19214
19232
  const checkboxRowElement = {
@@ -19233,12 +19251,11 @@ var ListParticle = class {
19233
19251
  }
19234
19252
  });
19235
19253
  } else {
19236
- const text = this._getListMarkerText(startElement, listIndex);
19237
- if (!text) return;
19238
- const markerStyleElement = this._getListMarkerStyleElement(elementList);
19254
+ const marker = this.getListMarker(row);
19255
+ if (!marker) return;
19239
19256
  ctx.save();
19240
- ctx.font = this.draw.getElementFont(markerStyleElement, scale);
19241
- ctx.fillText(text, x, y);
19257
+ ctx.font = this.draw.getElementFont(marker.styleElement, scale);
19258
+ ctx.fillText(marker.text, x, y);
19242
19259
  ctx.restore();
19243
19260
  }
19244
19261
  }
@@ -24426,1247 +24443,992 @@ var Command = class {
24426
24443
  }
24427
24444
  };
24428
24445
 
24446
+ // src/utils/docxLayout.ts
24447
+ var import_docx2 = require("docx");
24448
+
24429
24449
  // src/utils/docx.ts
24430
24450
  var import_docx = require("docx");
24431
24451
  var DEFAULT_DOCX_FILE_NAME = "document.docx";
24432
24452
  var DEFAULT_IMAGE_WIDTH = 320;
24433
24453
  var DEFAULT_IMAGE_HEIGHT = 180;
24434
- var DEFAULT_LINE_HEIGHT = 1.15;
24435
- var DOCX_FOOTER_TEXT_COLOR = "#000000";
24436
- var docxBulletCharMap = {
24437
- ["disc" /* DISC */]: "\u2022",
24438
- ["circle" /* CIRCLE */]: "\u25E6",
24439
- ["square" /* SQUARE */]: "\u25A0",
24440
- ["checkbox" /* CHECKBOX */]: "\u2611"
24441
- };
24442
- var titleHeadingMap = {
24443
- ["first" /* FIRST */]: import_docx.HeadingLevel.HEADING_1,
24444
- ["second" /* SECOND */]: import_docx.HeadingLevel.HEADING_2,
24445
- ["third" /* THIRD */]: import_docx.HeadingLevel.HEADING_3,
24446
- ["fourth" /* FOURTH */]: import_docx.HeadingLevel.HEADING_4,
24447
- ["fifth" /* FIFTH */]: import_docx.HeadingLevel.HEADING_5,
24448
- ["sixth" /* SIXTH */]: import_docx.HeadingLevel.HEADING_6
24449
- };
24450
- var orderedStyleFormatMap = {
24451
- ["decimal" /* DECIMAL */]: import_docx.LevelFormat.DECIMAL,
24452
- ["lowerAlpha" /* LOWER_ALPHA */]: import_docx.LevelFormat.LOWER_LETTER,
24453
- ["upperAlpha" /* UPPER_ALPHA */]: import_docx.LevelFormat.UPPER_LETTER,
24454
- ["lowerRoman" /* LOWER_ROMAN */]: import_docx.LevelFormat.LOWER_ROMAN,
24455
- ["upperRoman" /* UPPER_ROMAN */]: import_docx.LevelFormat.UPPER_ROMAN,
24456
- ["decimalParen" /* DECIMAL_PAREN */]: import_docx.LevelFormat.DECIMAL,
24457
- decimalZero: import_docx.LevelFormat.DECIMAL_ZERO,
24458
- lowerAlphaParen: import_docx.LevelFormat.LOWER_LETTER,
24459
- lowerRomanParen: import_docx.LevelFormat.LOWER_ROMAN,
24460
- outline: import_docx.LevelFormat.DECIMAL
24461
- };
24462
- async function exportEditorDataToDocx(payload, options = {}) {
24463
- const fileName = normalizeDocxFileName(options.fileName);
24464
- const file = await createDocxDocument(payload);
24465
- const blob = await import_docx.Packer.toBlob(file);
24454
+ async function loadImagePayload(src) {
24455
+ const source = src.trim();
24456
+ if (source.startsWith("data:")) {
24457
+ return getImagePayloadFromDataUrl(source);
24458
+ }
24459
+ const response = await fetch(source);
24460
+ if (!response.ok) {
24461
+ throw new Error(`Image request failed: ${response.status}`);
24462
+ }
24463
+ const contentType = response.headers.get("content-type") || "";
24464
+ const data2 = await response.arrayBuffer();
24465
+ return normalizeImagePayload(data2, contentType);
24466
+ }
24467
+ async function getImagePayloadFromDataUrl(src) {
24468
+ const [, meta = "", encoded = ""] = src.match(/^data:([^,]*),(.*)$/) || [];
24469
+ const mime = meta.split(";")[0] || "";
24470
+ const isBase64 = meta.includes(";base64");
24471
+ const text = isBase64 ? atob(encoded) : decodeURIComponent(encoded);
24472
+ const bytes = new Uint8Array(text.length);
24473
+ for (let i = 0; i < text.length; i++) {
24474
+ bytes[i] = text.charCodeAt(i);
24475
+ }
24476
+ return normalizeImagePayload(bytes.buffer, mime);
24477
+ }
24478
+ async function normalizeImagePayload(data2, mime) {
24479
+ const type = getRegularImageType(mime);
24480
+ if (type) {
24481
+ return {
24482
+ type,
24483
+ data: data2
24484
+ };
24485
+ }
24486
+ if (mime.includes("svg")) {
24487
+ return {
24488
+ type: "svg",
24489
+ data: data2,
24490
+ fallbackPng: await rasterizeSvgToPng(data2)
24491
+ };
24492
+ }
24493
+ const fallbackPng = await rasterizeImageToPng(data2, mime);
24466
24494
  return {
24467
- blob,
24468
- fileName
24495
+ type: "png",
24496
+ data: fallbackPng
24469
24497
  };
24470
24498
  }
24471
- async function createDocxDocument(payload) {
24472
- const { data: data2, options } = payload;
24473
- const editorOptions = options;
24474
- const context = createSerializeContext();
24475
- const headerChildren = editorOptions.header.disabled ? [] : await serializeElementList(data2.header || [], editorOptions, context);
24476
- const docxFooterElementList = forceDocxFooterTextColor(data2.footer || []);
24477
- const footerChildren = editorOptions.footer.disabled ? [] : await serializeElementList(
24478
- docxFooterElementList,
24479
- editorOptions,
24480
- context
24481
- );
24482
- const pageNumberParagraph = createPageNumberParagraph(
24483
- {
24484
- ...editorOptions.pageNumber,
24485
- color: DOCX_FOOTER_TEXT_COLOR
24499
+ async function rasterizeSvgToPng(data2) {
24500
+ return rasterizeImageToPng(data2, "image/svg+xml");
24501
+ }
24502
+ async function rasterizeImageToPng(data2, mime) {
24503
+ const blob = new Blob([data2], {
24504
+ type: mime || "image/png"
24505
+ });
24506
+ const url = URL.createObjectURL(blob);
24507
+ try {
24508
+ const image = await loadHtmlImage(url);
24509
+ const canvas = document.createElement("canvas");
24510
+ canvas.width = image.naturalWidth || DEFAULT_IMAGE_WIDTH;
24511
+ canvas.height = image.naturalHeight || DEFAULT_IMAGE_HEIGHT;
24512
+ const context = canvas.getContext("2d");
24513
+ if (!context) {
24514
+ throw new Error("Canvas context is unavailable");
24486
24515
  }
24487
- );
24488
- if (pageNumberParagraph) {
24489
- footerChildren.push(pageNumberParagraph);
24516
+ context.drawImage(image, 0, 0, canvas.width, canvas.height);
24517
+ const pngBlob = await new Promise((resolve, reject) => {
24518
+ canvas.toBlob((output) => {
24519
+ if (output) {
24520
+ resolve(output);
24521
+ } else {
24522
+ reject(new Error("Failed to create PNG blob"));
24523
+ }
24524
+ }, "image/png");
24525
+ });
24526
+ return await pngBlob.arrayBuffer();
24527
+ } finally {
24528
+ URL.revokeObjectURL(url);
24490
24529
  }
24491
- const sectionChildren = await serializeElementList(
24492
- data2.main,
24493
- editorOptions,
24494
- context
24495
- );
24496
- const { width, height, paperDirection } = editorOptions;
24497
- const pageWidth = paperDirection === "horizontal" /* HORIZONTAL */ ? height : width;
24498
- const pageHeight = paperDirection === "horizontal" /* HORIZONTAL */ ? width : height;
24499
- return new import_docx.Document({
24500
- features: {
24501
- updateFields: true
24502
- },
24503
- numbering: {
24504
- config: createNumberingConfig()
24530
+ }
24531
+ function loadHtmlImage(src) {
24532
+ return new Promise((resolve, reject) => {
24533
+ const image = new Image();
24534
+ image.onload = () => resolve(image);
24535
+ image.onerror = () => reject(new Error("Failed to load image"));
24536
+ image.src = src;
24537
+ });
24538
+ }
24539
+ function mapUnderlineType(style) {
24540
+ switch (style) {
24541
+ case "double" /* DOUBLE */:
24542
+ return import_docx.UnderlineType.DOUBLE;
24543
+ case "dashed" /* DASHED */:
24544
+ return import_docx.UnderlineType.DASH;
24545
+ case "dotted" /* DOTTED */:
24546
+ return import_docx.UnderlineType.DOTTED;
24547
+ case "wavy" /* WAVY */:
24548
+ return import_docx.UnderlineType.WAVE;
24549
+ default:
24550
+ return import_docx.UnderlineType.SINGLE;
24551
+ }
24552
+ }
24553
+ function normalizeHexColor(color, fallback) {
24554
+ const normalized = normalizeHexLiteral(color) || normalizeRgbColor(color) || normalizeBrowserColor(color);
24555
+ if (normalized) {
24556
+ return normalized;
24557
+ }
24558
+ return fallback ? normalizeHexLiteral(fallback) || void 0 : void 0;
24559
+ }
24560
+ function normalizeHexLiteral(color) {
24561
+ const value = color.trim().replace(/^#/, "");
24562
+ if (/^[\da-f]{3}$/i.test(value)) {
24563
+ return value.split("").map((part) => `${part}${part}`).join("").toUpperCase();
24564
+ }
24565
+ if (/^[\da-f]{4}$/i.test(value)) {
24566
+ return value.slice(0, 3).split("").map((part) => `${part}${part}`).join("").toUpperCase();
24567
+ }
24568
+ if (/^[\da-f]{6}$/i.test(value)) {
24569
+ return value.toUpperCase();
24570
+ }
24571
+ if (/^[\da-f]{8}$/i.test(value)) {
24572
+ return value.slice(0, 6).toUpperCase();
24573
+ }
24574
+ return void 0;
24575
+ }
24576
+ function normalizeRgbColor(color) {
24577
+ const match = color.trim().match(/^rgba?\((.+)\)$/i);
24578
+ if (!match) {
24579
+ return void 0;
24580
+ }
24581
+ const parts = match[1].replace(/\s*\/\s*/g, ",").split(/\s*,\s*|\s+/).filter(Boolean);
24582
+ if (parts.length < 3) {
24583
+ return void 0;
24584
+ }
24585
+ const red = parseRgbChannel(parts[0]);
24586
+ const green = parseRgbChannel(parts[1]);
24587
+ const blue = parseRgbChannel(parts[2]);
24588
+ if (red === null || green === null || blue === null) {
24589
+ return void 0;
24590
+ }
24591
+ const alpha = parts[3] !== void 0 ? parseAlphaChannel(parts[3]) : 1;
24592
+ if (alpha === null || alpha <= 0) {
24593
+ return void 0;
24594
+ }
24595
+ const flattened = alpha >= 1 ? [red, green, blue] : [
24596
+ flattenChannel(red, alpha),
24597
+ flattenChannel(green, alpha),
24598
+ flattenChannel(blue, alpha)
24599
+ ];
24600
+ return flattened.map(toHexChannel).join("");
24601
+ }
24602
+ function normalizeBrowserColor(color) {
24603
+ if (typeof document === "undefined") {
24604
+ return void 0;
24605
+ }
24606
+ const canvas = document.createElement("canvas");
24607
+ const context = canvas.getContext("2d");
24608
+ if (!context) {
24609
+ return void 0;
24610
+ }
24611
+ context.fillStyle = "#000000";
24612
+ context.fillStyle = color;
24613
+ const normalized = context.fillStyle;
24614
+ if (typeof normalized !== "string") {
24615
+ return void 0;
24616
+ }
24617
+ return normalizeHexLiteral(normalized) || normalizeRgbColor(normalized);
24618
+ }
24619
+ function parseRgbChannel(value) {
24620
+ if (value.endsWith("%")) {
24621
+ const percent = Number(value.slice(0, -1));
24622
+ if (!Number.isFinite(percent)) {
24623
+ return null;
24624
+ }
24625
+ return clampColorChannel(Math.round(percent / 100 * 255));
24626
+ }
24627
+ const channel = Number(value);
24628
+ if (!Number.isFinite(channel)) {
24629
+ return null;
24630
+ }
24631
+ return clampColorChannel(Math.round(channel));
24632
+ }
24633
+ function parseAlphaChannel(value) {
24634
+ if (value.endsWith("%")) {
24635
+ const percent = Number(value.slice(0, -1));
24636
+ if (!Number.isFinite(percent)) {
24637
+ return null;
24638
+ }
24639
+ return Math.min(Math.max(percent / 100, 0), 1);
24640
+ }
24641
+ const alpha = Number(value);
24642
+ if (!Number.isFinite(alpha)) {
24643
+ return null;
24644
+ }
24645
+ return Math.min(Math.max(alpha, 0), 1);
24646
+ }
24647
+ function clampColorChannel(value) {
24648
+ return Math.min(Math.max(value, 0), 255);
24649
+ }
24650
+ function flattenChannel(value, alpha) {
24651
+ return clampColorChannel(Math.round(255 * (1 - alpha) + value * alpha));
24652
+ }
24653
+ function toHexChannel(value) {
24654
+ return value.toString(16).padStart(2, "0").toUpperCase();
24655
+ }
24656
+ function getRegularImageType(mime) {
24657
+ if (mime.includes("png")) return "png";
24658
+ if (mime.includes("jpeg") || mime.includes("jpg")) return "jpg";
24659
+ if (mime.includes("gif")) return "gif";
24660
+ if (mime.includes("bmp")) return "bmp";
24661
+ return null;
24662
+ }
24663
+ function normalizeDocxFileName(fileName) {
24664
+ const trimmed = fileName?.trim();
24665
+ if (!trimmed) {
24666
+ return DEFAULT_DOCX_FILE_NAME;
24667
+ }
24668
+ return trimmed.toLowerCase().endsWith(".docx") ? trimmed : `${trimmed}.docx`;
24669
+ }
24670
+
24671
+ // src/utils/docxLayout.ts
24672
+ var PX_TO_TWIP = 15;
24673
+ var ANCHOR_EPS = 0.5;
24674
+ var RIGHT_SLACK_TWIP = -14400;
24675
+ var TINY_TWIP = 1;
24676
+ var tw = (ctx, layoutPx) => Math.round(layoutPx / ctx.scale * PX_TO_TWIP);
24677
+ var pxTw = (px) => Math.round(px * PX_TO_TWIP);
24678
+ async function exportDrawToDocx(draw, options = {}) {
24679
+ const canvas = document.createElement("canvas");
24680
+ const measureCtx = canvas.getContext("2d");
24681
+ const ctx = {
24682
+ draw,
24683
+ scale: draw.getOptions().scale,
24684
+ measureCtx
24685
+ };
24686
+ const file = await createDocument(ctx);
24687
+ const blob = await import_docx2.Packer.toBlob(file);
24688
+ return { blob, fileName: normalizeDocxFileName(options.fileName) };
24689
+ }
24690
+ async function createDocument(ctx) {
24691
+ const { draw, scale } = ctx;
24692
+ const opts = draw.getOptions();
24693
+ const width = draw.getOriginalWidth();
24694
+ const height = draw.getOriginalHeight();
24695
+ const margins = draw.getOriginalMargins();
24696
+ const header = draw.getHeader();
24697
+ const footer = draw.getFooter();
24698
+ const headerTop = header.getHeaderTop() / scale;
24699
+ const headerExtra = header.getExtraHeight() / scale;
24700
+ const footerExtra = footer.getExtraHeight() / scale;
24701
+ const layoutMargins = draw.getMargins();
24702
+ const body = await serializeMain(ctx, layoutMargins[3]);
24703
+ const headerChildren = opts.header.disabled ? [] : await serializeRows(ctx, header.getRowList(), {
24704
+ startX: layoutMargins[3],
24705
+ width: draw.getInnerWidth(),
24706
+ positionList: header.getPositionList()
24707
+ });
24708
+ const footerChildren = opts.footer.disabled ? [] : await serializeFooter(ctx, width, height, margins);
24709
+ const { pageNumber } = draw.getOptions();
24710
+ return new import_docx2.Document({
24711
+ compatabilityModeVersion: 15,
24712
+ // LibreOffice formats PAGE/NUMPAGES results from the paragraph style
24713
+ styles: {
24714
+ paragraphStyles: [
24715
+ {
24716
+ id: PAGE_NUMBER_STYLE,
24717
+ name: "Windoc Page Number",
24718
+ run: pageNumberRunStyle(pageNumber)
24719
+ }
24720
+ ]
24505
24721
  },
24722
+ defaultTabStop: pxTw(width),
24506
24723
  sections: [
24507
24724
  {
24508
24725
  properties: {
24509
24726
  page: {
24510
24727
  size: {
24511
- width: pxToTwips(pageWidth),
24512
- height: pxToTwips(pageHeight),
24513
- orientation: paperDirection === "horizontal" /* HORIZONTAL */ ? import_docx.PageOrientation.LANDSCAPE : import_docx.PageOrientation.PORTRAIT
24728
+ width: pxTw(width),
24729
+ height: pxTw(height),
24730
+ orientation: opts.paperDirection === "horizontal" /* HORIZONTAL */ ? import_docx2.PageOrientation.LANDSCAPE : import_docx2.PageOrientation.PORTRAIT
24514
24731
  },
24515
24732
  margin: {
24516
- top: pxToTwips(editorOptions.margins[0]),
24517
- right: pxToTwips(editorOptions.margins[1]),
24518
- bottom: pxToTwips(editorOptions.margins[2]),
24519
- left: pxToTwips(editorOptions.margins[3]),
24520
- header: pxToTwips(editorOptions.header.top),
24521
- footer: pxToTwips(editorOptions.footer.bottom)
24522
- },
24523
- pageNumbers: !editorOptions.pageNumber.disabled && editorOptions.pageNumber.fromPageNo === 0 ? {
24524
- start: editorOptions.pageNumber.startPageNo
24525
- } : void 0
24733
+ top: pxTw(margins[0] + headerExtra),
24734
+ right: pxTw(margins[1]),
24735
+ bottom: pxTw(margins[2] + footerExtra),
24736
+ left: pxTw(margins[3]),
24737
+ header: pxTw(headerTop),
24738
+ footer: pxTw(footer.getFooterBottom() / scale),
24739
+ gutter: 0
24740
+ }
24526
24741
  }
24527
24742
  },
24528
- headers: headerChildren.length > 0 ? {
24529
- default: new import_docx.Header({
24530
- children: headerChildren
24531
- })
24532
- } : void 0,
24533
- footers: footerChildren.length > 0 ? {
24534
- default: new import_docx.Footer({
24535
- children: footerChildren
24536
- })
24537
- } : void 0,
24538
- children: sectionChildren.length ? sectionChildren : [new import_docx.Paragraph({})]
24743
+ headers: headerChildren.length ? { default: new import_docx2.Header({ children: headerChildren }) } : void 0,
24744
+ footers: footerChildren.length ? { default: new import_docx2.Footer({ children: footerChildren }) } : void 0,
24745
+ children: body.length ? body : [new import_docx2.Paragraph({})]
24539
24746
  }
24540
24747
  ]
24541
24748
  });
24542
24749
  }
24543
- async function serializeElementList(elementList, options, context) {
24544
- const blocks = [];
24545
- let inlineBuffer = [];
24546
- const flushInlineBuffer = async () => {
24547
- if (!inlineBuffer.length) return;
24548
- blocks.push(
24549
- ...await serializeInlineElements(inlineBuffer, options, context)
24550
- );
24551
- inlineBuffer = [];
24750
+ async function serializeMain(ctx, startX) {
24751
+ const { draw } = ctx;
24752
+ const zone = {
24753
+ startX,
24754
+ width: draw.getInnerWidth(),
24755
+ positionList: draw.getPosition().getOriginalMainPositionList()
24552
24756
  };
24553
- for (let i = 0; i < elementList.length; i++) {
24554
- const element = elementList[i];
24555
- if (element.type === "area" /* AREA */ && element.valueList?.length) {
24556
- await flushInlineBuffer();
24557
- blocks.push(
24558
- ...await serializeElementList(element.valueList, options, context)
24559
- );
24560
- continue;
24561
- }
24562
- if (element.type === "title" /* TITLE */ && element.valueList?.length) {
24563
- await flushInlineBuffer();
24564
- blocks.push(
24565
- ...await serializeInlineElements(element.valueList, options, context, {
24566
- heading: titleHeadingMap[element.level || "first" /* FIRST */]
24567
- })
24568
- );
24569
- continue;
24570
- }
24571
- if (element.type === "list" /* LIST */ && element.valueList?.length) {
24572
- await flushInlineBuffer();
24573
- blocks.push(...await serializeListElement(element, options, context));
24574
- continue;
24575
- }
24576
- if (element.type === "table" /* TABLE */ && element.trList?.length) {
24577
- await flushInlineBuffer();
24578
- blocks.push(await serializeTableElement(element, options, context));
24579
- continue;
24580
- }
24581
- if (element.type === "pageBreak" /* PAGE_BREAK */) {
24582
- await flushInlineBuffer();
24583
- blocks.push(
24584
- new import_docx.Paragraph({
24585
- children: [new import_docx.PageBreak()]
24586
- })
24587
- );
24588
- continue;
24589
- }
24590
- if (element.type === "separator" /* SEPARATOR */) {
24591
- await flushInlineBuffer();
24592
- blocks.push(
24593
- new import_docx.Paragraph({
24594
- thematicBreak: true
24595
- })
24596
- );
24597
- continue;
24598
- }
24599
- if (element.type === "image" /* IMAGE */ && element.imgDisplay && element.imgDisplay !== "inline") {
24600
- await flushInlineBuffer();
24601
- blocks.push(...await serializeInlineElements([element], options));
24602
- continue;
24603
- }
24604
- if (element.type === "block" /* BLOCK */) {
24605
- await flushInlineBuffer();
24606
- const blockText = getBlockFallbackText(element);
24607
- if (blockText) {
24608
- blocks.push(
24609
- ...await serializeInlineElements(
24610
- [{ value: blockText }],
24611
- options,
24612
- context
24757
+ const children = [];
24758
+ const pageRowList = draw.getPageRowList();
24759
+ for (let p = 0; p < pageRowList.length; p++) {
24760
+ children.push(
24761
+ ...await serializeRows(ctx, pageRowList[p], zone, {
24762
+ pageBreakBefore: p > 0
24763
+ })
24764
+ );
24765
+ }
24766
+ return children;
24767
+ }
24768
+ async function serializeRows(ctx, rowList, zone, options = {}) {
24769
+ const { pageBreakBefore = false, padTop = 0, padBottom = 0 } = options;
24770
+ const children = [];
24771
+ for (let r = 0; r < rowList.length; r++) {
24772
+ const row = rowList[r];
24773
+ const isFirst = r === 0;
24774
+ const isLast = r === rowList.length - 1;
24775
+ const table = row.elementList.find((el) => el.type === "table" /* TABLE */);
24776
+ if (table) {
24777
+ if (isFirst && (pageBreakBefore || padTop) || row.offsetY) {
24778
+ children.push(
24779
+ createSpacerParagraph(
24780
+ isFirst && pageBreakBefore,
24781
+ (isFirst ? padTop : 0) + (row.offsetY || 0) / ctx.scale
24613
24782
  )
24614
24783
  );
24615
24784
  }
24785
+ const position = zone.positionList[row.startIndex + row.elementList.indexOf(table)];
24786
+ children.push(await serializeTable(ctx, table, position, zone));
24787
+ const rest = (row.height + (row.spaceBelow || 0)) / ctx.scale - table.height + (isLast ? padBottom : 0);
24788
+ if (rest * PX_TO_TWIP >= 1) {
24789
+ children.push(createSpacerParagraph(false, rest));
24790
+ }
24616
24791
  continue;
24617
24792
  }
24618
- inlineBuffer.push(element);
24793
+ const rowOptions = {
24794
+ pageBreakBefore: isFirst && pageBreakBefore,
24795
+ padTop: isFirst ? padTop : 0,
24796
+ padBottom: isLast ? padBottom : 0
24797
+ };
24798
+ if (!isFirst && isTextRow(rowList[r - 1])) rowOptions.skipLead = true;
24799
+ rowOptions.rowY = rowY(zone, row);
24800
+ if (!isLast && isTextRow(rowList[r + 1])) {
24801
+ rowOptions.extraAfter = rowLead(ctx, rowList[r + 1], {
24802
+ rowY: rowY(zone, rowList[r + 1])
24803
+ });
24804
+ }
24805
+ const lead = rowOptions.pageBreakBefore ? rowLead(ctx, row, rowOptions) : 0;
24806
+ if (lead) {
24807
+ children.push(createSpacerParagraph(true, lead / PX_TO_TWIP));
24808
+ rowOptions.pageBreakBefore = false;
24809
+ rowOptions.skipLead = true;
24810
+ }
24811
+ children.push(await serializeRow(ctx, row, zone, rowOptions));
24619
24812
  }
24620
- await flushInlineBuffer();
24621
- return blocks;
24813
+ return children;
24622
24814
  }
24623
- async function serializeInlineElements(elementList, options, _context, overrides = {}) {
24624
- const paragraphs = [];
24625
- let current = null;
24626
- const getParagraphContext = (element) => ({
24627
- heading: overrides.heading,
24628
- numbering: overrides.numbering,
24629
- alignment: overrides.alignment !== void 0 ? overrides.alignment : mapRowFlexToAlignment(element?.rowFlex),
24630
- rowMargin: overrides.rowMargin !== void 0 ? overrides.rowMargin : element?.rowMargin
24631
- });
24632
- const flushParagraph = (context) => {
24633
- if (!current) {
24634
- if (!context) return;
24635
- paragraphs.push(createParagraph([], context, options.defaultRowMargin));
24815
+ function rowY(zone, row) {
24816
+ return zone.positionList[row.startIndex]?.coordinate.leftTop[1];
24817
+ }
24818
+ function isTextRow(row) {
24819
+ return !row.elementList.some((el) => el.type === "table" /* TABLE */);
24820
+ }
24821
+ async function serializeRow(ctx, row, zone, options, suffix) {
24822
+ const { pageBreakBefore = false } = options;
24823
+ const { draw, scale } = ctx;
24824
+ const positions = zone.positionList;
24825
+ const children = [];
24826
+ const tabStops = [];
24827
+ const firstPosition = positions[row.startIndex];
24828
+ let pen = 0;
24829
+ let indent = firstPosition ? (firstPosition.coordinate.leftTop[0] - zone.startX) / scale : 0;
24830
+ let started = false;
24831
+ const anchorTo = (layoutX) => {
24832
+ const target = (layoutX - zone.startX) / scale;
24833
+ if (!started) {
24834
+ indent = target;
24835
+ pen = target;
24836
+ started = true;
24636
24837
  return;
24637
24838
  }
24638
- paragraphs.push(
24639
- createParagraph(
24640
- current.children,
24641
- current.context,
24642
- options.defaultRowMargin
24643
- )
24644
- );
24645
- current = null;
24646
- };
24647
- const ensureParagraph = (element) => {
24648
- if (!current) {
24649
- current = {
24650
- children: [],
24651
- context: getParagraphContext(element)
24652
- };
24839
+ if (target - pen > ANCHOR_EPS) {
24840
+ tabStops.push(pxTw(target));
24841
+ children.push(new import_docx2.TextRun({ children: [new import_docx2.Tab()] }));
24842
+ pen = target;
24653
24843
  }
24654
- return current;
24655
24844
  };
24656
- const appendText = (element, text, childFactory, preserveTrailingBreak = false) => {
24657
- const normalized = normalizeText(text);
24658
- const parts = normalized.split("\n");
24659
- let lastSeparatorFlushedContent = false;
24660
- for (let i = 0; i < parts.length; i++) {
24661
- const segment = parts[i];
24662
- if (segment) {
24663
- ensureParagraph(element).children.push(childFactory(segment));
24664
- }
24665
- if (i < parts.length - 1) {
24666
- if (!current) {
24667
- paragraphs.push(
24668
- createParagraph(
24669
- [],
24670
- getParagraphContext(element),
24671
- options.defaultRowMargin
24672
- )
24673
- );
24674
- lastSeparatorFlushedContent = false;
24675
- } else {
24676
- flushParagraph();
24677
- lastSeparatorFlushedContent = true;
24678
- }
24679
- }
24680
- }
24681
- if (preserveTrailingBreak && normalized.endsWith("\n") && lastSeparatorFlushedContent) {
24682
- paragraphs.push(
24683
- createParagraph(
24684
- [],
24685
- getParagraphContext(element),
24686
- options.defaultRowMargin
24687
- )
24845
+ if (row.isList && firstPosition) {
24846
+ const listParticle = draw.getListParticle();
24847
+ const markerX = listParticle.getListMarkerX(row, firstPosition);
24848
+ const marker = markerX === null ? null : listParticle.getListMarker(row);
24849
+ if (markerX !== null && marker) {
24850
+ anchorTo(markerX);
24851
+ children.push(createTextRun(ctx, marker.text, marker.styleElement));
24852
+ pen += measure(ctx, marker.text, marker.styleElement);
24853
+ }
24854
+ }
24855
+ let run = null;
24856
+ const flush = () => {
24857
+ if (!run) return;
24858
+ children.push(createTextRun(ctx, run.text, run.element));
24859
+ run = null;
24860
+ };
24861
+ for (let j = 0; j < row.elementList.length; j++) {
24862
+ const element = row.elementList[j];
24863
+ const position = positions[row.startIndex + j];
24864
+ if (!position) continue;
24865
+ if (element.hide || element.control?.hide || element.area?.hide) continue;
24866
+ if (element.type === "separator" /* SEPARATOR */) {
24867
+ flush();
24868
+ return createSeparatorParagraph(
24869
+ ctx,
24870
+ row,
24871
+ element,
24872
+ position.coordinate.leftTop[0],
24873
+ position.coordinate.leftTop[1],
24874
+ zone,
24875
+ options
24688
24876
  );
24689
24877
  }
24690
- };
24691
- for (let i = 0; i < elementList.length; i++) {
24692
- const element = elementList[i];
24693
- if (element.type === "hyperlink" /* HYPERLINK */ && element.valueList?.length) {
24694
- const hyperlink = await createHyperlinkChild(element, options);
24695
- if (hyperlink) {
24696
- ensureParagraph(element).children.push(hyperlink);
24697
- }
24878
+ if (element.value === ZERO || element.type === "tab" /* TAB */ || element.type === "pageBreak" /* PAGE_BREAK */ || element.type === "columnBreak" /* COLUMN_BREAK */) {
24698
24879
  continue;
24699
24880
  }
24881
+ const x = position.coordinate.leftTop[0];
24882
+ const layoutWidth = element.metrics.width / scale;
24700
24883
  if (element.type === "image" /* IMAGE */) {
24701
- const imageChild = await createImageChild(element);
24702
- if (!imageChild) {
24703
- appendText(
24704
- element,
24705
- "[Image unavailable]",
24706
- (segment) => createTextRun(
24707
- segment,
24708
- element,
24709
- options.defaultSize,
24710
- options.defaultFont
24711
- ),
24712
- i === elementList.length - 1
24713
- );
24714
- continue;
24715
- }
24716
- ensureParagraph(element).children.push(imageChild);
24884
+ flush();
24885
+ anchorTo(x);
24886
+ const image = await createImageRun(element);
24887
+ if (image) children.push(image);
24888
+ pen += layoutWidth;
24717
24889
  continue;
24718
24890
  }
24719
- if (element.type === "columnBreak" /* COLUMN_BREAK */) {
24720
- ensureParagraph(element).children.push(new import_docx.ColumnBreak());
24721
- continue;
24722
- }
24723
- if (element.type === "tab" /* TAB */) {
24724
- appendText(
24725
- element,
24726
- " ",
24727
- (segment) => createTextRun(
24728
- segment,
24729
- element,
24730
- options.defaultSize,
24731
- options.defaultFont
24732
- ),
24733
- i === elementList.length - 1
24891
+ if (element.type === "label" /* LABEL */) {
24892
+ flush();
24893
+ const padding = element.label?.padding || draw.getOptions().label.defaultPadding;
24894
+ anchorTo(x + padding[3] * scale);
24895
+ children.push(
24896
+ createTextRun(ctx, element.value, element, labelShading(ctx, element))
24734
24897
  );
24898
+ pen += measure(ctx, element.value, element);
24735
24899
  continue;
24736
24900
  }
24737
- const textValue = getInlineElementText(element);
24738
- if (!textValue) {
24739
- continue;
24740
- }
24741
- appendText(
24742
- element,
24743
- textValue,
24744
- (segment) => createTextRun(
24745
- segment,
24746
- element,
24747
- options.defaultSize,
24748
- options.defaultFont
24749
- ),
24750
- i === elementList.length - 1
24751
- );
24752
- }
24753
- if (current) {
24754
- flushParagraph();
24755
- }
24756
- return paragraphs.length ? paragraphs : [createParagraph([], overrides, options.defaultRowMargin)];
24757
- }
24758
- async function serializeListElement(element, options, context) {
24759
- const zipList = zipElementList(element.valueList || []);
24760
- const listItemMap = splitListElement(zipList);
24761
- const paragraphs = [];
24762
- const listInstance = createListInstance(context);
24763
- for (const listItemElements of listItemMap.values()) {
24764
- const numbering = getListNumbering(
24765
- getListItemNumberingElement(listItemElements, element),
24766
- listInstance
24767
- );
24768
- paragraphs.push(
24769
- ...await serializeInlineElements(listItemElements, options, context, {
24770
- numbering
24771
- })
24772
- );
24773
- }
24774
- return paragraphs;
24775
- }
24776
- async function serializeTableElement(element, options, context) {
24777
- const rows = [];
24778
- const trList = element.trList || [];
24779
- const tableContext = createTableSerializeContext(element);
24780
- for (let i = 0; i < trList.length; i++) {
24781
- rows.push(
24782
- await serializeTableRow(trList[i], options, context, tableContext)
24783
- );
24784
- }
24785
- const tableWidth = getTableWidthFromColgroup(element.colgroup);
24786
- return new import_docx.Table({
24787
- rows,
24788
- width: tableWidth ? {
24789
- size: pxToTwips(tableWidth),
24790
- type: import_docx.WidthType.DXA
24791
- } : {
24792
- size: 100,
24793
- type: import_docx.WidthType.PERCENTAGE
24794
- },
24795
- columnWidths: element.colgroup?.map((col) => pxToTwips(col.width)),
24796
- layout: import_docx.TableLayoutType.FIXED,
24797
- borders: createTableBorders(element)
24798
- });
24799
- }
24800
- async function serializeTableRow(tr, options, context, tableContext) {
24801
- const children = [];
24802
- for (let i = 0; i < tr.tdList.length; i++) {
24803
- children.push(
24804
- await serializeTableCell(tr.tdList[i], options, context, tableContext)
24805
- );
24806
- }
24807
- return new import_docx.TableRow({
24808
- children
24809
- });
24810
- }
24811
- async function serializeTableCell(td, options, context, tableContext) {
24812
- const children = await serializeElementList(td.value, options, context);
24813
- const shadingFill = td.backgroundColor ? normalizeHexColor(td.backgroundColor) : void 0;
24814
- const cellWidth = tableContext.cellLayoutMap.get(td)?.width || td.width;
24815
- return new import_docx.TableCell({
24816
- children: children.length ? children : [new import_docx.Paragraph({})],
24817
- columnSpan: td.colspan > 1 ? td.colspan : void 0,
24818
- rowSpan: td.rowspan > 1 ? td.rowspan : void 0,
24819
- verticalAlign: mapCellVerticalAlign(td.verticalAlign),
24820
- width: cellWidth ? {
24821
- size: pxToTwips(cellWidth),
24822
- type: import_docx.WidthType.DXA
24823
- } : void 0,
24824
- shading: shadingFill ? {
24825
- fill: shadingFill,
24826
- type: import_docx.ShadingType.CLEAR
24827
- } : void 0,
24828
- margins: mapPaddingToTableMargins(td.padding),
24829
- borders: createTableCellBorders(
24830
- td,
24831
- tableContext.borderColor,
24832
- tableContext.borderWidth
24833
- )
24834
- });
24835
- }
24836
- function createParagraph(children, context, defaultRowMargin) {
24837
- return new import_docx.Paragraph({
24838
- children,
24839
- heading: context.heading,
24840
- numbering: context.numbering,
24841
- alignment: context.alignment,
24842
- spacing: {
24843
- line: Math.round(
24844
- 240 * (context.rowMargin || defaultRowMargin || DEFAULT_LINE_HEIGHT)
24845
- ),
24846
- lineRule: import_docx.LineRuleType.AUTO
24847
- }
24848
- });
24849
- }
24850
- function createTextRun(text, element, defaultSize, defaultFont) {
24851
- const color = element.color ? normalizeHexColor(element.color, "000000") : void 0;
24852
- const highlightFill = element.highlight ? normalizeHexColor(element.highlight) : void 0;
24853
- return new import_docx.TextRun({
24854
- text,
24855
- bold: !!element.bold,
24856
- italics: !!element.italic,
24857
- strike: !!element.strikeout,
24858
- subScript: element.type === "subscript" /* SUBSCRIPT */,
24859
- superScript: element.type === "superscript" /* SUPERSCRIPT */,
24860
- color,
24861
- shading: highlightFill ? {
24862
- fill: highlightFill,
24863
- type: import_docx.ShadingType.CLEAR
24864
- } : void 0,
24865
- underline: element.underline ? {
24866
- type: mapUnderlineType(element.textDecoration?.style)
24867
- } : void 0,
24868
- font: element.font || defaultFont,
24869
- size: Math.round((element.size || defaultSize) * 2)
24870
- });
24871
- }
24872
- async function createHyperlinkChild(element, options) {
24873
- if (!element.url) {
24874
- const fallbackText = getTextFromElementList(element.valueList || []);
24875
- return fallbackText ? createTextRun(
24876
- fallbackText,
24877
- element.valueList?.[0] || element,
24878
- options.defaultSize,
24879
- options.defaultFont
24880
- ) : null;
24881
- }
24882
- const children = await createHyperlinkRuns(
24883
- element.valueList || [],
24884
- options.defaultSize,
24885
- options.defaultFont
24886
- );
24887
- if (!children.length) {
24888
- return null;
24889
- }
24890
- return new import_docx.ExternalHyperlink({
24891
- link: element.url,
24892
- children
24893
- });
24894
- }
24895
- async function createHyperlinkRuns(valueList, defaultSize, defaultFont) {
24896
- const children = [];
24897
- for (let i = 0; i < valueList.length; i++) {
24898
- const element = valueList[i];
24899
- if (element.type === "tab" /* TAB */) {
24900
- children.push(createTextRun(" ", element, defaultSize, defaultFont));
24901
- continue;
24902
- }
24903
- const text = normalizeText(getInlineElementText(element)).replace(
24904
- /\n/g,
24905
- " "
24906
- );
24907
- if (text) {
24908
- children.push(createTextRun(text, element, defaultSize, defaultFont));
24909
- }
24910
- }
24911
- return children;
24912
- }
24913
- async function createImageChild(element) {
24914
- try {
24915
- const image = await loadImagePayload(element.value);
24916
- const width = Math.max(1, Math.round(element.width || DEFAULT_IMAGE_WIDTH));
24917
- const height = Math.max(
24918
- 1,
24919
- Math.round(element.height || DEFAULT_IMAGE_HEIGHT)
24920
- );
24921
- if (image.type === "svg" && image.fallbackPng) {
24922
- return new import_docx.ImageRun({
24923
- type: "svg",
24924
- data: image.data,
24925
- fallback: {
24926
- type: "png",
24927
- data: image.fallbackPng
24928
- },
24929
- transformation: {
24930
- width,
24931
- height
24932
- }
24933
- });
24934
- }
24935
- return new import_docx.ImageRun({
24936
- type: image.type,
24937
- data: image.data,
24938
- transformation: {
24939
- width,
24940
- height
24901
+ const text = getElementText(element);
24902
+ if (!text) continue;
24903
+ const natural = measure(ctx, text, element);
24904
+ const target = (x - zone.startX) / scale;
24905
+ const isDrift = !started || target - pen > ANCHOR_EPS;
24906
+ const extra = layoutWidth - natural;
24907
+ const needsSpacing = Math.abs(extra) * PX_TO_TWIP >= 1;
24908
+ const canJoin = run && !isDrift && !needsSpacing && isSameRunStyle(run.element, element);
24909
+ if (canJoin) {
24910
+ run.text += text;
24911
+ } else {
24912
+ flush();
24913
+ anchorTo(x);
24914
+ if (needsSpacing) {
24915
+ children.push(
24916
+ createTextRun(ctx, text, element, void 0, pxTw(extra))
24917
+ );
24918
+ } else {
24919
+ run = { text, element };
24941
24920
  }
24942
- });
24943
- } catch {
24944
- return null;
24945
- }
24946
- }
24947
- async function loadImagePayload(src) {
24948
- const source = src.trim();
24949
- if (source.startsWith("data:")) {
24950
- return getImagePayloadFromDataUrl(source);
24951
- }
24952
- const response = await fetch(source);
24953
- if (!response.ok) {
24954
- throw new Error(`Image request failed: ${response.status}`);
24955
- }
24956
- const contentType = response.headers.get("content-type") || "";
24957
- const data2 = await response.arrayBuffer();
24958
- return normalizeImagePayload(data2, contentType);
24959
- }
24960
- async function getImagePayloadFromDataUrl(src) {
24961
- const [, meta = "", encoded = ""] = src.match(/^data:([^,]*),(.*)$/) || [];
24962
- const mime = meta.split(";")[0] || "";
24963
- const isBase64 = meta.includes(";base64");
24964
- const text = isBase64 ? atob(encoded) : decodeURIComponent(encoded);
24965
- const bytes = new Uint8Array(text.length);
24966
- for (let i = 0; i < text.length; i++) {
24967
- bytes[i] = text.charCodeAt(i);
24968
- }
24969
- return normalizeImagePayload(bytes.buffer, mime);
24970
- }
24971
- async function normalizeImagePayload(data2, mime) {
24972
- const type = getRegularImageType(mime);
24973
- if (type) {
24974
- return {
24975
- type,
24976
- data: data2
24977
- };
24978
- }
24979
- if (mime.includes("svg")) {
24980
- return {
24981
- type: "svg",
24982
- data: data2,
24983
- fallbackPng: await rasterizeSvgToPng(data2)
24984
- };
24985
- }
24986
- const fallbackPng = await rasterizeImageToPng(data2, mime);
24987
- return {
24988
- type: "png",
24989
- data: fallbackPng
24990
- };
24991
- }
24992
- async function rasterizeSvgToPng(data2) {
24993
- return rasterizeImageToPng(data2, "image/svg+xml");
24994
- }
24995
- async function rasterizeImageToPng(data2, mime) {
24996
- const blob = new Blob([data2], {
24997
- type: mime || "image/png"
24998
- });
24999
- const url = URL.createObjectURL(blob);
25000
- try {
25001
- const image = await loadHtmlImage(url);
25002
- const canvas = document.createElement("canvas");
25003
- canvas.width = image.naturalWidth || DEFAULT_IMAGE_WIDTH;
25004
- canvas.height = image.naturalHeight || DEFAULT_IMAGE_HEIGHT;
25005
- const context = canvas.getContext("2d");
25006
- if (!context) {
25007
- throw new Error("Canvas context is unavailable");
25008
- }
25009
- context.drawImage(image, 0, 0, canvas.width, canvas.height);
25010
- const pngBlob = await new Promise((resolve, reject) => {
25011
- canvas.toBlob((output) => {
25012
- if (output) {
25013
- resolve(output);
25014
- } else {
25015
- reject(new Error("Failed to create PNG blob"));
25016
- }
25017
- }, "image/png");
25018
- });
25019
- return await pngBlob.arrayBuffer();
25020
- } finally {
25021
- URL.revokeObjectURL(url);
25022
- }
25023
- }
25024
- function loadHtmlImage(src) {
25025
- return new Promise((resolve, reject) => {
25026
- const image = new Image();
25027
- image.onload = () => resolve(image);
25028
- image.onerror = () => reject(new Error("Failed to load image"));
25029
- image.src = src;
25030
- });
25031
- }
25032
- function createPageNumberParagraph(pageNumber) {
25033
- if (pageNumber.disabled || pageNumber.fromPageNo > 0) {
25034
- return null;
25035
- }
25036
- const children = [];
25037
- const format = pageNumber.format || FORMAT_PLACEHOLDER.PAGE_NO;
25038
- const tokens = format.split(/(\{pageNo\}|\{pageCount\})/);
25039
- for (let i = 0; i < tokens.length; i++) {
25040
- const token = tokens[i];
25041
- if (!token) continue;
25042
- const runChildren = token === FORMAT_PLACEHOLDER.PAGE_NO ? [import_docx.PageNumber.CURRENT] : token === FORMAT_PLACEHOLDER.PAGE_COUNT ? [import_docx.PageNumber.TOTAL_PAGES] : void 0;
25043
- children.push(
25044
- new import_docx.TextRun({
25045
- text: runChildren ? void 0 : token,
25046
- children: runChildren,
25047
- color: normalizeHexColor(pageNumber.color || "#000000", "000000"),
25048
- font: pageNumber.font,
25049
- size: Math.round((pageNumber.size || 12) * 2)
25050
- })
25051
- );
25052
- }
25053
- return new import_docx.Paragraph({
25054
- children,
25055
- alignment: mapRowFlexToAlignment(pageNumber.rowFlex)
25056
- });
25057
- }
25058
- function forceDocxFooterTextColor(elementList) {
25059
- const footerElementList = deepClone(elementList);
25060
- forceColorValue(footerElementList);
25061
- return footerElementList;
25062
- }
25063
- function forceColorValue(value) {
25064
- if (!value || typeof value !== "object") {
25065
- return;
25066
- }
25067
- if (Array.isArray(value)) {
25068
- for (let i = 0; i < value.length; i++) {
25069
- forceColorValue(value[i]);
25070
24921
  }
25071
- return;
25072
- }
25073
- const record = value;
25074
- if ("color" in record) {
25075
- record.color = DOCX_FOOTER_TEXT_COLOR;
25076
- }
25077
- const keys = Object.keys(record);
25078
- for (let i = 0; i < keys.length; i++) {
25079
- forceColorValue(record[keys[i]]);
25080
- }
25081
- }
25082
- function createNumberingConfig() {
25083
- const config = [
25084
- createOrderedReference("windoc-ol-decimal", Array(9).fill("decimal" /* DECIMAL */)),
25085
- createOrderedReference(
25086
- "windoc-ol-lower-alpha",
25087
- Array(9).fill("lowerAlpha" /* LOWER_ALPHA */)
25088
- ),
25089
- createOrderedReference(
25090
- "windoc-ol-upper-alpha",
25091
- Array(9).fill("upperAlpha" /* UPPER_ALPHA */)
25092
- ),
25093
- createOrderedReference(
25094
- "windoc-ol-lower-roman",
25095
- Array(9).fill("lowerRoman" /* LOWER_ROMAN */)
25096
- ),
25097
- createOrderedReference(
25098
- "windoc-ol-upper-roman",
25099
- Array(9).fill("upperRoman" /* UPPER_ROMAN */)
25100
- ),
25101
- createOrderedReference(
25102
- "windoc-ol-decimal-paren",
25103
- Array(9).fill("decimalParen" /* DECIMAL_PAREN */)
25104
- ),
25105
- createOrderedReference(
25106
- `windoc-ol-${"olDefault" /* DEFAULT */}`,
25107
- createCycleList(olPresetCycles["olDefault" /* DEFAULT */], 9)
25108
- ),
25109
- createOrderedReference(
25110
- `windoc-ol-${"olParen" /* PARENTHESIS */}`,
25111
- createCycleList(olPresetCycles["olParen" /* PARENTHESIS */], 9)
25112
- ),
25113
- createOrderedReference(
25114
- `windoc-ol-${"olOutline" /* OUTLINE */}`,
25115
- createCycleList(olPresetCycles["olOutline" /* OUTLINE */], 9)
25116
- ),
25117
- createOrderedReference(
25118
- `windoc-ol-${"olUpperA" /* UPPER_ALPHA */}`,
25119
- createCycleList(olPresetCycles["olUpperA" /* UPPER_ALPHA */], 9)
25120
- ),
25121
- createOrderedReference(
25122
- `windoc-ol-${"olRoman" /* ROMAN */}`,
25123
- createCycleList(olPresetCycles["olRoman" /* ROMAN */], 9)
25124
- ),
25125
- createOrderedReference(
25126
- `windoc-ol-${"olZeroPad" /* ZERO_PAD */}`,
25127
- createCycleList(olPresetCycles["olZeroPad" /* ZERO_PAD */], 9)
25128
- ),
25129
- createBulletReference(
25130
- "windoc-ul-disc",
25131
- Array(9).fill(docxBulletCharMap["disc" /* DISC */])
25132
- ),
25133
- createBulletReference(
25134
- "windoc-ul-circle",
25135
- Array(9).fill(docxBulletCharMap["circle" /* CIRCLE */])
25136
- ),
25137
- createBulletReference(
25138
- "windoc-ul-square",
25139
- Array(9).fill(docxBulletCharMap["square" /* SQUARE */])
25140
- ),
25141
- createBulletReference(
25142
- "windoc-ul-checkbox",
25143
- Array(9).fill(docxBulletCharMap["checkbox" /* CHECKBOX */])
25144
- ),
25145
- createBulletReference(
25146
- `windoc-ul-${"ulDefault" /* DEFAULT */}`,
25147
- createCycleList(ulPresetCycles["ulDefault" /* DEFAULT */], 9)
25148
- ),
25149
- createBulletReference(
25150
- `windoc-ul-${"ulDiamond" /* DIAMOND */}`,
25151
- createCycleList(ulPresetCycles["ulDiamond" /* DIAMOND */], 9)
25152
- ),
25153
- createBulletReference(
25154
- `windoc-ul-${"ulHollowSq" /* HOLLOW_SQ */}`,
25155
- createCycleList(ulPresetCycles["ulHollowSq" /* HOLLOW_SQ */], 9)
25156
- ),
25157
- createBulletReference(
25158
- `windoc-ul-${"ulArrow" /* ARROW */}`,
25159
- createCycleList(ulPresetCycles["ulArrow" /* ARROW */], 9)
25160
- ),
25161
- createBulletReference(
25162
- `windoc-ul-${"ulStar" /* STAR */}`,
25163
- createCycleList(ulPresetCycles["ulStar" /* STAR */], 9)
25164
- ),
25165
- createBulletReference(
25166
- `windoc-ul-${"ulCheckArr" /* CHECK_ARROW */}`,
25167
- createCycleList(ulPresetCycles["ulCheckArr" /* CHECK_ARROW */], 9)
25168
- )
25169
- ];
25170
- return config;
25171
- }
25172
- function createOrderedReference(reference, styles) {
25173
- return {
25174
- reference,
25175
- levels: styles.map((style, level) => ({
25176
- level,
25177
- format: orderedStyleFormatMap[style] || import_docx.LevelFormat.DECIMAL,
25178
- text: getOrderedLevelText(style, level),
25179
- alignment: import_docx.AlignmentType.START,
25180
- style: {
25181
- paragraph: {
25182
- indent: {
25183
- left: 720 * (level + 1),
25184
- hanging: 360
25185
- }
25186
- }
25187
- }
25188
- }))
25189
- };
25190
- }
25191
- function createBulletReference(reference, bullets) {
25192
- return {
25193
- reference,
25194
- levels: bullets.map((bullet, level) => ({
25195
- level,
25196
- format: import_docx.LevelFormat.BULLET,
25197
- text: bullet,
25198
- alignment: import_docx.AlignmentType.START,
25199
- style: {
25200
- paragraph: {
25201
- indent: {
25202
- left: 720 * (level + 1),
25203
- hanging: 360
25204
- }
25205
- }
25206
- }
25207
- }))
25208
- };
25209
- }
25210
- function getOrderedLevelText(style, level) {
25211
- const placeholder = `%${level + 1}`;
25212
- if (style === "outline") {
25213
- return Array.from({ length: level + 1 }, (_, index) => `%${index + 1}`).join(
25214
- "."
25215
- ) + ".";
25216
- }
25217
- if (style.endsWith("Paren") || style === "decimalParen" /* DECIMAL_PAREN */) {
25218
- return `${placeholder})`;
25219
- }
25220
- return `${placeholder}.`;
25221
- }
25222
- function createCycleList(source = [], size) {
25223
- const result = [];
25224
- for (let i = 0; i < size; i++) {
25225
- result.push(source[i % source.length]);
25226
- }
25227
- return result;
25228
- }
25229
- function getListNumbering(element, instance) {
25230
- const level = Math.max(0, Math.min(element.listLevel || 0, 8));
25231
- if (element.listType === "ul" /* UL */) {
25232
- const reference2 = element.listPreset ? `windoc-ul-${element.listPreset}` : `windoc-ul-${element.listStyle || "disc" /* DISC */}`;
25233
- return {
25234
- reference: reference2,
25235
- level,
25236
- instance
25237
- };
25238
- }
25239
- const reference = element.listPreset ? `windoc-ol-${element.listPreset}` : getOrderedReferenceFromStyle(element.listStyle);
25240
- return {
25241
- reference,
25242
- level,
25243
- instance
25244
- };
25245
- }
25246
- function getOrderedReferenceFromStyle(style) {
25247
- switch (style) {
25248
- case "lowerAlpha" /* LOWER_ALPHA */:
25249
- return "windoc-ol-lower-alpha";
25250
- case "upperAlpha" /* UPPER_ALPHA */:
25251
- return "windoc-ol-upper-alpha";
25252
- case "lowerRoman" /* LOWER_ROMAN */:
25253
- return "windoc-ol-lower-roman";
25254
- case "upperRoman" /* UPPER_ROMAN */:
25255
- return "windoc-ol-upper-roman";
25256
- case "decimalParen" /* DECIMAL_PAREN */:
25257
- return "windoc-ol-decimal-paren";
25258
- default:
25259
- return "windoc-ol-decimal";
25260
- }
25261
- }
25262
- function createTableBorders(element) {
25263
- const outerBorder = createBorder(
25264
- element.borderColor,
25265
- import_docx.BorderStyle.SINGLE,
25266
- element.borderExternalWidth || element.borderWidth
25267
- );
25268
- const innerBorder = createBorder(
25269
- element.borderColor,
25270
- import_docx.BorderStyle.SINGLE,
25271
- element.borderWidth
25272
- );
25273
- switch (element.borderType) {
25274
- case "empty" /* EMPTY */:
25275
- return {
25276
- top: noneBorder(),
25277
- bottom: noneBorder(),
25278
- left: noneBorder(),
25279
- right: noneBorder(),
25280
- insideHorizontal: noneBorder(),
25281
- insideVertical: noneBorder()
25282
- };
25283
- case "external" /* EXTERNAL */:
25284
- return {
25285
- top: outerBorder,
25286
- bottom: outerBorder,
25287
- left: outerBorder,
25288
- right: outerBorder,
25289
- insideHorizontal: noneBorder(),
25290
- insideVertical: noneBorder()
25291
- };
25292
- case "internal" /* INTERNAL */:
25293
- return {
25294
- top: noneBorder(),
25295
- bottom: noneBorder(),
25296
- left: noneBorder(),
25297
- right: noneBorder(),
25298
- insideHorizontal: innerBorder,
25299
- insideVertical: innerBorder
25300
- };
25301
- case "dash" /* DASH */:
25302
- return {
25303
- top: createBorder(
25304
- element.borderColor,
25305
- import_docx.BorderStyle.DASHED,
25306
- element.borderExternalWidth || element.borderWidth
25307
- ),
25308
- bottom: createBorder(
25309
- element.borderColor,
25310
- import_docx.BorderStyle.DASHED,
25311
- element.borderExternalWidth || element.borderWidth
25312
- ),
25313
- left: createBorder(
25314
- element.borderColor,
25315
- import_docx.BorderStyle.DASHED,
25316
- element.borderExternalWidth || element.borderWidth
25317
- ),
25318
- right: createBorder(
25319
- element.borderColor,
25320
- import_docx.BorderStyle.DASHED,
25321
- element.borderExternalWidth || element.borderWidth
25322
- ),
25323
- insideHorizontal: createBorder(
25324
- element.borderColor,
25325
- import_docx.BorderStyle.DASHED,
25326
- element.borderWidth
25327
- ),
25328
- insideVertical: createBorder(
25329
- element.borderColor,
25330
- import_docx.BorderStyle.DASHED,
25331
- element.borderWidth
25332
- )
25333
- };
25334
- default:
25335
- return {
25336
- top: outerBorder,
25337
- bottom: outerBorder,
25338
- left: outerBorder,
25339
- right: outerBorder,
25340
- insideHorizontal: innerBorder,
25341
- insideVertical: innerBorder
25342
- };
25343
- }
25344
- }
25345
- function createTableCellBorders(td, inheritedColor, inheritedWidth) {
25346
- if (!td.borderTypes?.length && !td.borderColor) {
25347
- return void 0;
25348
- }
25349
- const color = td.borderColor || inheritedColor;
25350
- const createCellBorder = () => createBorder(color, import_docx.BorderStyle.SINGLE, inheritedWidth);
25351
- if (td.borderColor && !td.borderTypes?.length) {
25352
- return {
25353
- top: createCellBorder(),
25354
- right: createCellBorder(),
25355
- bottom: createCellBorder(),
25356
- left: createCellBorder()
25357
- };
25358
- }
25359
- const top = td.borderTypes?.includes("top" /* TOP */) ? createCellBorder() : noneBorder();
25360
- const right2 = td.borderTypes?.includes("right" /* RIGHT */) ? createCellBorder() : noneBorder();
25361
- const bottom = td.borderTypes?.includes("bottom" /* BOTTOM */) ? createCellBorder() : noneBorder();
25362
- const left2 = td.borderTypes?.includes("left" /* LEFT */) ? createCellBorder() : noneBorder();
25363
- return {
25364
- top,
25365
- right: right2,
25366
- bottom,
25367
- left: left2
25368
- };
25369
- }
25370
- function createBorder(color = "#000000", style = import_docx.BorderStyle.SINGLE, width = 1) {
25371
- return {
25372
- style,
25373
- color: normalizeHexColor(color, "000000") || "000000",
25374
- size: pxBorderToDocxSize(width)
25375
- };
25376
- }
25377
- function noneBorder() {
25378
- return {
25379
- style: import_docx.BorderStyle.NONE,
25380
- size: 0,
25381
- color: "FFFFFF"
25382
- };
25383
- }
25384
- function mapPaddingToTableMargins(padding) {
25385
- if (!padding) return void 0;
25386
- return {
25387
- top: pxToTwips(padding[0]),
25388
- right: pxToTwips(padding[1]),
25389
- bottom: pxToTwips(padding[2]),
25390
- left: pxToTwips(padding[3]),
25391
- marginUnitType: import_docx.WidthType.DXA
25392
- };
25393
- }
25394
- function mapCellVerticalAlign(verticalAlign) {
25395
- switch (verticalAlign) {
25396
- case VerticalAlign.CENTER:
25397
- return import_docx.VerticalAlign.CENTER;
25398
- case "bottom" /* BOTTOM */:
25399
- return import_docx.VerticalAlign.BOTTOM;
25400
- default:
25401
- return import_docx.VerticalAlign.TOP;
25402
- }
25403
- }
25404
- function mapRowFlexToAlignment(rowFlex) {
25405
- switch (rowFlex) {
25406
- case "center" /* CENTER */:
25407
- return import_docx.AlignmentType.CENTER;
25408
- case "right" /* RIGHT */:
25409
- return import_docx.AlignmentType.RIGHT;
25410
- case "alignment" /* ALIGNMENT */:
25411
- case "justify" /* JUSTIFY */:
25412
- return import_docx.AlignmentType.JUSTIFIED;
25413
- default:
25414
- return import_docx.AlignmentType.LEFT;
25415
- }
25416
- }
25417
- function mapUnderlineType(style) {
25418
- switch (style) {
25419
- case "double" /* DOUBLE */:
25420
- return import_docx.UnderlineType.DOUBLE;
25421
- case "dashed" /* DASHED */:
25422
- return import_docx.UnderlineType.DASH;
25423
- case "dotted" /* DOTTED */:
25424
- return import_docx.UnderlineType.DOTTED;
25425
- case "wavy" /* WAVY */:
25426
- return import_docx.UnderlineType.WAVE;
25427
- default:
25428
- return import_docx.UnderlineType.SINGLE;
25429
- }
25430
- }
25431
- function getInlineElementText(element) {
25432
- switch (element.type) {
25433
- case "control" /* CONTROL */:
25434
- return getControlText(element.control);
25435
- case "date" /* DATE */:
25436
- return element.valueList?.length ? getTextFromElementList(element.valueList) : element.value;
25437
- case "checkbox" /* CHECKBOX */:
25438
- return element.checkbox?.value ? "\u2611" : "\u2610";
25439
- case "radio" /* RADIO */:
25440
- return element.radio?.value ? "\u25C9" : "\u25CB";
25441
- case "label" /* LABEL */:
25442
- case "latex" /* LATEX */:
25443
- case "subscript" /* SUBSCRIPT */:
25444
- case "superscript" /* SUPERSCRIPT */:
25445
- return element.value;
25446
- default:
25447
- return element.value;
25448
- }
25449
- }
25450
- function getControlText(control) {
25451
- if (!control) return "";
25452
- if (control.type === "text" /* TEXT */ || control.type === "date" /* DATE */ || control.type === "number" /* NUMBER */) {
25453
- const value = control.value?.length ? getTextFromElementList(control.value) : "";
25454
- const content = value || control.placeholder || "";
25455
- return `${control.preText || ""}${content}${control.postText || ""}`;
25456
- }
25457
- if (control.type === "select" /* SELECT */) {
25458
- const labels = getSelectedControlLabels(control.code, control.valueSets);
25459
- const content = labels.length ? labels.join(control.multiSelectDelimiter || ", ") : control.placeholder || "";
25460
- return `${control.preText || ""}${content}${control.postText || ""}`;
25461
- }
25462
- if (control.type === "checkbox" /* CHECKBOX */ || control.type === "radio" /* RADIO */) {
25463
- const isRadio = control.type === "radio" /* RADIO */;
25464
- return (control.valueSets || []).map((valueSet) => {
25465
- const checked = control.code?.split(",").includes(valueSet.code) || false;
25466
- return `${checked ? isRadio ? "\u25C9" : "\u2611" : isRadio ? "\u25CB" : "\u2610"} ${valueSet.value}`;
25467
- }).join(" ");
25468
- }
25469
- return "";
25470
- }
25471
- function getSelectedControlLabels(code, valueSets) {
25472
- if (!code || !valueSets?.length) return [];
25473
- return code.split(",").map(
25474
- (selectCode) => valueSets.find((valueSet) => valueSet.code === selectCode)?.value
25475
- ).filter((value) => !!value);
25476
- }
25477
- function getBlockFallbackText(element) {
25478
- if (element.block?.iframeBlock?.src) {
25479
- return element.block.iframeBlock.src;
24922
+ pen = target + layoutWidth;
25480
24923
  }
25481
- if (element.block?.videoBlock?.src) {
25482
- return element.block.videoBlock.src;
24924
+ flush();
24925
+ if (!children.length && !suffix) {
24926
+ const total = (options.skipLead ? 0 : rowLead(ctx, row, options)) + rowLine(ctx, row).lineTw + rowSpacing(ctx, row, options).after;
24927
+ return createSpacerParagraph(pageBreakBefore, total / PX_TO_TWIP);
25483
24928
  }
25484
- return "";
24929
+ const stops = tabStops.map((position) => ({ type: import_docx2.TabStopType.LEFT, position }));
24930
+ if (suffix) {
24931
+ stops.push({ type: suffix.tabType, position: suffix.tabStop });
24932
+ children.push(new import_docx2.TextRun({ children: [new import_docx2.Tab()] }), ...suffix.children);
24933
+ }
24934
+ return new import_docx2.Paragraph({
24935
+ children,
24936
+ style: suffix?.style,
24937
+ pageBreakBefore,
24938
+ widowControl: false,
24939
+ tabStops: stops,
24940
+ indent: { left: pxTw(indent), right: RIGHT_SLACK_TWIP },
24941
+ spacing: rowSpacing(ctx, row, options)
24942
+ });
25485
24943
  }
25486
- function normalizeText(text = "") {
25487
- return text.replace(new RegExp(ZERO, "g"), "").replace(/\r\n/g, "\n");
24944
+ var EXACT_BASELINE_RATIO = 0.8;
24945
+ function rowLine(ctx, row, baseline = row.ascent / ctx.scale) {
24946
+ const { scale } = ctx;
24947
+ const height = row.height / scale;
24948
+ const ascent = Math.min(baseline, height);
24949
+ const line = Math.min(
24950
+ ascent / EXACT_BASELINE_RATIO,
24951
+ (height - ascent) / (1 - EXACT_BASELINE_RATIO)
24952
+ );
24953
+ const lineTw = Math.max(TINY_TWIP, pxTw(line));
24954
+ const beforeTw = Math.max(
24955
+ 0,
24956
+ pxTw(ascent) - Math.round(lineTw * EXACT_BASELINE_RATIO)
24957
+ );
24958
+ const afterTw = Math.max(0, pxTw(height) - lineTw - beforeTw);
24959
+ return { lineTw, beforeTw, afterTw };
25488
24960
  }
25489
- function createSerializeContext() {
24961
+ function rowLead(ctx, row, options) {
24962
+ const separator = row.elementList.find(
24963
+ (el) => el.type === "separator" /* SEPARATOR */
24964
+ );
24965
+ const baseline = separator && options.rowY !== void 0 ? separatorBaseline(
24966
+ ctx,
24967
+ row,
24968
+ options.rowY,
24969
+ separator.lineWidth || ctx.draw.getOptions().separator.lineWidth
24970
+ ) : void 0;
24971
+ return rowLine(ctx, row, baseline).beforeTw + tw(ctx, (row.offsetY || 0) + (row.spaceAbove || 0)) + pxTw(options.padTop || 0);
24972
+ }
24973
+ function rowSpacing(ctx, row, options) {
24974
+ const { lineTw, afterTw } = rowLine(ctx, row);
25490
24975
  return {
25491
- nextListInstance: 1
24976
+ before: options.skipLead ? 0 : rowLead(ctx, row, options),
24977
+ after: afterTw + tw(ctx, row.spaceBelow || 0) + pxTw(options.padBottom || 0) + (options.extraAfter || 0),
24978
+ line: lineTw,
24979
+ lineRule: import_docx2.LineRuleType.EXACT
25492
24980
  };
25493
24981
  }
25494
- function getListItemNumberingElement(listItemElements, fallback) {
25495
- return listItemElements.find(
25496
- (listItem) => listItem.listId || listItem.listLevel !== void 0 || !!listItem.listPreset || !!listItem.listStyle || !!listItem.listType
25497
- ) || fallback;
25498
- }
25499
- function createListInstance(context) {
25500
- return context.nextListInstance++;
24982
+ function createSeparatorParagraph(ctx, row, element, x, rowY2, zone, options) {
24983
+ const { scale } = ctx;
24984
+ const opts = ctx.draw.getOptions();
24985
+ const lineWidth = element.lineWidth || opts.separator.lineWidth;
24986
+ const sideGap = 4;
24987
+ const left2 = (x - zone.startX) / scale + sideGap;
24988
+ const width = Math.max(1, (element.width || 0) - sideGap * 2);
24989
+ const color = element.color || opts.separator.strokeStyle;
24990
+ const line = rowLine(ctx, row, separatorBaseline(ctx, row, rowY2, lineWidth));
24991
+ return new import_docx2.Paragraph({
24992
+ pageBreakBefore: options.pageBreakBefore,
24993
+ widowControl: false,
24994
+ indent: { left: pxTw(left2), right: RIGHT_SLACK_TWIP },
24995
+ children: [
24996
+ new import_docx2.ImageRun({
24997
+ type: "png",
24998
+ data: createLineImage(width, lineWidth, color, element.dashArray),
24999
+ transformation: { width, height: lineWidth }
25000
+ })
25001
+ ],
25002
+ spacing: {
25003
+ before: options.skipLead ? 0 : rowLead(ctx, row, options),
25004
+ after: line.afterTw + tw(ctx, row.spaceBelow || 0) + pxTw(options.padBottom || 0) + (options.extraAfter || 0),
25005
+ line: line.lineTw,
25006
+ lineRule: import_docx2.LineRuleType.EXACT
25007
+ }
25008
+ });
25501
25009
  }
25502
- function createTableSerializeContext(element) {
25503
- return {
25504
- cellLayoutMap: computeTableCellLayout(
25505
- element.trList || [],
25506
- element.colgroup || []
25507
- ),
25508
- borderColor: element.borderColor,
25509
- borderWidth: element.borderWidth,
25510
- borderExternalWidth: element.borderExternalWidth
25511
- };
25010
+ function separatorBaseline(ctx, row, rowY2, lineWidth) {
25011
+ return (Math.round(rowY2 + row.ascent) - rowY2) / ctx.scale + lineWidth;
25512
25012
  }
25513
- function computeTableCellLayout(trList, colgroup) {
25514
- const cellLayoutMap = /* @__PURE__ */ new WeakMap();
25515
- if (!trList.length || !colgroup.length) {
25516
- return cellLayoutMap;
25517
- }
25518
- const occupiedUntilRow = Array(colgroup.length).fill(0);
25519
- for (let rowIndex = 0; rowIndex < trList.length; rowIndex++) {
25520
- const tr = trList[rowIndex];
25521
- let colIndex = 0;
25522
- for (let tdIndex = 0; tdIndex < tr.tdList.length; tdIndex++) {
25523
- while (colIndex < colgroup.length && occupiedUntilRow[colIndex] > rowIndex) {
25524
- colIndex += 1;
25525
- }
25526
- const td = tr.tdList[tdIndex];
25527
- let width = 0;
25528
- for (let currentCol = colIndex; currentCol < colIndex + td.colspan && currentCol < colgroup.length; currentCol++) {
25529
- width += colgroup[currentCol].width;
25530
- occupiedUntilRow[currentCol] = Math.max(
25531
- occupiedUntilRow[currentCol],
25532
- rowIndex + td.rowspan
25533
- );
25534
- }
25535
- cellLayoutMap.set(td, { width });
25536
- colIndex += td.colspan;
25013
+ function createLineImage(width, height, color, dashArray) {
25014
+ const ratio = 4;
25015
+ const canvas = document.createElement("canvas");
25016
+ canvas.width = Math.max(1, Math.round(width * ratio));
25017
+ canvas.height = Math.max(1, Math.round(height * ratio));
25018
+ const ctx = canvas.getContext("2d");
25019
+ ctx.strokeStyle = color;
25020
+ ctx.lineWidth = canvas.height;
25021
+ if (dashArray?.length) ctx.setLineDash(dashArray.map((v) => v * ratio));
25022
+ ctx.beginPath();
25023
+ ctx.moveTo(0, canvas.height / 2);
25024
+ ctx.lineTo(canvas.width, canvas.height / 2);
25025
+ ctx.stroke();
25026
+ const binary = atob(canvas.toDataURL("image/png").split(",")[1]);
25027
+ const bytes = new Uint8Array(binary.length);
25028
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
25029
+ return bytes;
25030
+ }
25031
+ function createSpacerParagraph(pageBreakBefore, height = 0) {
25032
+ return new import_docx2.Paragraph({
25033
+ pageBreakBefore,
25034
+ widowControl: false,
25035
+ children: [new import_docx2.TextRun({ text: "", size: 2 })],
25036
+ spacing: {
25037
+ before: 0,
25038
+ after: 0,
25039
+ line: Math.max(TINY_TWIP, pxTw(height)),
25040
+ lineRule: import_docx2.LineRuleType.EXACT
25537
25041
  }
25538
- }
25539
- return cellLayoutMap;
25042
+ });
25540
25043
  }
25541
- function getTableWidthFromColgroup(colgroup) {
25542
- if (!colgroup?.length) {
25543
- return void 0;
25044
+ async function serializeTable(ctx, element, position, zone) {
25045
+ const { draw, scale } = ctx;
25046
+ const opts = draw.getOptions();
25047
+ const tableX = position.coordinate.leftTop[0];
25048
+ const trList = element.trList || [];
25049
+ const colgroup = element.colgroup || [];
25050
+ const rows = [];
25051
+ for (let t = 0; t < trList.length; t++) {
25052
+ const tr = trList[t];
25053
+ const cells = [];
25054
+ let rowTopBorder = 0;
25055
+ for (let d = 0; d < tr.tdList.length; d++) {
25056
+ const td = tr.tdList[d];
25057
+ const padding = td.padding || opts.table.tdPadding;
25058
+ const borders = createCellBorders(ctx, element, td);
25059
+ const topBorder = t === 0 ? borderPx(borders.top) : 0;
25060
+ rowTopBorder = Math.max(rowTopBorder, topBorder);
25061
+ const cellChildren = await serializeRows(
25062
+ ctx,
25063
+ td.rowList || [],
25064
+ {
25065
+ startX: (td.x + padding[3]) * scale + tableX,
25066
+ width: (td.width - padding[1] - padding[3]) * scale,
25067
+ positionList: td.positionList || []
25068
+ },
25069
+ { padTop: Math.max(0, padding[0] - topBorder), padBottom: padding[2] }
25070
+ );
25071
+ cells.push(
25072
+ new import_docx2.TableCell({
25073
+ children: cellChildren.length ? cellChildren : [createSpacerParagraph(false)],
25074
+ columnSpan: td.colspan > 1 ? td.colspan : void 0,
25075
+ rowSpan: td.rowspan > 1 ? td.rowspan : void 0,
25076
+ width: { size: pxTw(td.width), type: import_docx2.WidthType.DXA },
25077
+ verticalAlign: mapVerticalAlign(td.verticalAlign),
25078
+ margins: {
25079
+ top: 0,
25080
+ right: pxTw(padding[1]),
25081
+ bottom: 0,
25082
+ left: pxTw(Math.max(0, padding[3] - borderPx(borders.left) / 2)),
25083
+ marginUnitType: import_docx2.WidthType.DXA
25084
+ },
25085
+ shading: td.backgroundColor ? {
25086
+ fill: normalizeHexColor(td.backgroundColor, "FFFFFF"),
25087
+ type: import_docx2.ShadingType.CLEAR,
25088
+ color: "auto"
25089
+ } : void 0,
25090
+ borders
25091
+ })
25092
+ );
25093
+ }
25094
+ rows.push(
25095
+ new import_docx2.TableRow({
25096
+ children: cells,
25097
+ cantSplit: true,
25098
+ height: {
25099
+ value: pxTw(tr.height - rowTopBorder),
25100
+ rule: import_docx2.HeightRule.EXACT
25101
+ }
25102
+ })
25103
+ );
25544
25104
  }
25545
- return colgroup.reduce((sum, col) => sum + col.width, 0);
25105
+ return new import_docx2.Table({
25106
+ rows,
25107
+ layout: import_docx2.TableLayoutType.FIXED,
25108
+ width: { size: pxTw(element.width), type: import_docx2.WidthType.DXA },
25109
+ columnWidths: colgroup.map((col) => pxTw(col.width)),
25110
+ indent: { size: tw(ctx, tableX - zone.startX), type: import_docx2.WidthType.DXA },
25111
+ borders: noTableBorders()
25112
+ });
25546
25113
  }
25547
- function normalizeHexColor(color, fallback) {
25548
- const normalized = normalizeHexLiteral(color) || normalizeRgbColor(color) || normalizeBrowserColor(color);
25549
- if (normalized) {
25550
- return normalized;
25551
- }
25552
- return fallback ? normalizeHexLiteral(fallback) || void 0 : void 0;
25114
+ function createCellBorders(ctx, table, td) {
25115
+ const opts = ctx.draw.getOptions();
25116
+ const color = normalizeHexColor(
25117
+ td.borderColor || table.borderColor || opts.table.defaultBorderColor,
25118
+ "000000"
25119
+ );
25120
+ const width = table.borderWidth || 1;
25121
+ const externalWidth = table.borderExternalWidth || width;
25122
+ const isDash = table.borderType === "dash" /* DASH */;
25123
+ const line = (w) => ({
25124
+ style: isDash ? import_docx2.BorderStyle.DASHED : import_docx2.BorderStyle.SINGLE,
25125
+ size: Math.max(2, Math.round(w * 6)),
25126
+ color
25127
+ });
25128
+ const none = { style: import_docx2.BorderStyle.NONE, size: 0, color: "auto" };
25129
+ const isTop = td.rowIndex === 0;
25130
+ const isLeft = td.colIndex === 0;
25131
+ const isBottom = td.rowIndex + td.rowspan === table.trList.length;
25132
+ const isRight = td.colIndex + td.colspan === table.colgroup.length;
25133
+ const edge = (outer) => outer ? line(externalWidth) : line(width);
25134
+ let top = none;
25135
+ let right2 = none;
25136
+ let bottom = none;
25137
+ let left2 = none;
25138
+ switch (table.borderType) {
25139
+ case "empty" /* EMPTY */:
25140
+ break;
25141
+ case "external" /* EXTERNAL */:
25142
+ if (isTop) top = edge(true);
25143
+ if (isBottom) bottom = edge(true);
25144
+ if (isLeft) left2 = edge(true);
25145
+ if (isRight) right2 = edge(true);
25146
+ break;
25147
+ case "internal" /* INTERNAL */:
25148
+ if (!isTop) top = edge(false);
25149
+ if (!isBottom) bottom = edge(false);
25150
+ if (!isLeft) left2 = edge(false);
25151
+ if (!isRight) right2 = edge(false);
25152
+ break;
25153
+ default:
25154
+ top = edge(isTop);
25155
+ bottom = edge(isBottom);
25156
+ left2 = edge(isLeft);
25157
+ right2 = edge(isRight);
25158
+ }
25159
+ if (td.borderTypes?.includes("top" /* TOP */)) top = line(width);
25160
+ if (td.borderTypes?.includes("right" /* RIGHT */)) right2 = line(width);
25161
+ if (td.borderTypes?.includes("bottom" /* BOTTOM */)) bottom = line(width);
25162
+ if (td.borderTypes?.includes("left" /* LEFT */)) left2 = line(width);
25163
+ return { top, right: right2, bottom, left: left2 };
25164
+ }
25165
+ function borderPx(border) {
25166
+ return border.style === import_docx2.BorderStyle.NONE ? 0 : border.size / 8 * (4 / 3);
25167
+ }
25168
+ function noTableBorders() {
25169
+ const none = { style: import_docx2.BorderStyle.NONE, size: 0, color: "auto" };
25170
+ return {
25171
+ top: none,
25172
+ bottom: none,
25173
+ left: none,
25174
+ right: none,
25175
+ insideHorizontal: none,
25176
+ insideVertical: none
25177
+ };
25553
25178
  }
25554
- function normalizeHexLiteral(color) {
25555
- const value = color.trim().replace(/^#/, "");
25556
- if (/^[\da-f]{3}$/i.test(value)) {
25557
- return value.split("").map((part) => `${part}${part}`).join("").toUpperCase();
25558
- }
25559
- if (/^[\da-f]{4}$/i.test(value)) {
25560
- return value.slice(0, 3).split("").map((part) => `${part}${part}`).join("").toUpperCase();
25561
- }
25562
- if (/^[\da-f]{6}$/i.test(value)) {
25563
- return value.toUpperCase();
25179
+ function mapVerticalAlign(verticalAlign) {
25180
+ switch (verticalAlign) {
25181
+ case "middle" /* MIDDLE */:
25182
+ return import_docx2.VerticalAlign.CENTER;
25183
+ case "bottom" /* BOTTOM */:
25184
+ return import_docx2.VerticalAlign.BOTTOM;
25185
+ default:
25186
+ return import_docx2.VerticalAlign.TOP;
25187
+ }
25188
+ }
25189
+ async function serializeFooter(ctx, pageWidth, pageHeight, margins) {
25190
+ const { draw, scale } = ctx;
25191
+ const footer = draw.getFooter();
25192
+ const opts = draw.getOptions();
25193
+ const barHeight = footer.getHeight() / scale;
25194
+ const contentHeight = footer.getRowHeight() / scale;
25195
+ const paddingTop = Math.floor(Math.max(0, (barHeight - contentHeight) / 2) * scale) / scale;
25196
+ const zone = {
25197
+ startX: draw.getMargins()[3],
25198
+ width: draw.getInnerWidth(),
25199
+ positionList: footer.getPositionList()
25200
+ };
25201
+ const rowList = footer.getRowList();
25202
+ const textWidth = pageWidth - margins[1] - margins[3];
25203
+ const pageNumber = createPageNumberRuns(ctx, pageHeight, textWidth);
25204
+ let pageNumberRow = -1;
25205
+ if (pageNumber) {
25206
+ pageNumberRow = rowList.length - 1;
25207
+ for (let r = 0; r < rowList.length; r++) {
25208
+ const top = zone.positionList[rowList[r].startIndex].coordinate.leftTop[1] / scale;
25209
+ if (pageNumber.baseline <= top + rowList[r].height / scale) {
25210
+ pageNumberRow = r;
25211
+ break;
25212
+ }
25213
+ }
25564
25214
  }
25565
- if (/^[\da-f]{8}$/i.test(value)) {
25566
- return value.slice(0, 6).toUpperCase();
25215
+ const children = [];
25216
+ for (let r = 0; r < rowList.length; r++) {
25217
+ const row = rowList[r];
25218
+ const rowOptions = { padTop: r === 0 ? paddingTop : 0 };
25219
+ if (r !== pageNumberRow) {
25220
+ children.push(...await serializeRows(ctx, [row], zone, rowOptions));
25221
+ continue;
25222
+ }
25223
+ const top = zone.positionList[row.startIndex].coordinate.leftTop[1] / scale;
25224
+ const shift = pageNumber.baseline - (top + row.ascent / scale);
25225
+ children.push(
25226
+ await serializeRow(ctx, row, zone, rowOptions, {
25227
+ tabStop: pageNumber.tabStop,
25228
+ tabType: pageNumber.tabType,
25229
+ children: pageNumber.runs(shift),
25230
+ style: PAGE_NUMBER_STYLE
25231
+ })
25232
+ );
25567
25233
  }
25568
- return void 0;
25234
+ const fill = opts.footer.backgroundColor ? normalizeHexColor(opts.footer.backgroundColor, "FFFFFF") : void 0;
25235
+ const none = { style: import_docx2.BorderStyle.NONE, size: 0, color: "auto" };
25236
+ const band = new import_docx2.Table({
25237
+ layout: import_docx2.TableLayoutType.FIXED,
25238
+ width: { size: pxTw(pageWidth), type: import_docx2.WidthType.DXA },
25239
+ columnWidths: [pxTw(pageWidth)],
25240
+ indent: { size: -pxTw(margins[3]), type: import_docx2.WidthType.DXA },
25241
+ borders: noTableBorders(),
25242
+ rows: [
25243
+ new import_docx2.TableRow({
25244
+ cantSplit: true,
25245
+ height: { value: pxTw(barHeight), rule: import_docx2.HeightRule.EXACT },
25246
+ children: [
25247
+ new import_docx2.TableCell({
25248
+ width: { size: pxTw(pageWidth), type: import_docx2.WidthType.DXA },
25249
+ margins: {
25250
+ top: 0,
25251
+ bottom: 0,
25252
+ left: pxTw(margins[3]),
25253
+ right: pxTw(margins[1]),
25254
+ marginUnitType: import_docx2.WidthType.DXA
25255
+ },
25256
+ shading: fill ? { fill, type: import_docx2.ShadingType.CLEAR, color: "auto" } : void 0,
25257
+ borders: { top: none, right: none, bottom: none, left: none },
25258
+ children: children.length ? children : [createSpacerParagraph(false)]
25259
+ })
25260
+ ]
25261
+ })
25262
+ ]
25263
+ });
25264
+ return [band];
25569
25265
  }
25570
- function normalizeRgbColor(color) {
25571
- const match = color.trim().match(/^rgba?\((.+)\)$/i);
25572
- if (!match) {
25573
- return void 0;
25266
+ var PAGE_NUMBER_STYLE = "WindocPageNumber";
25267
+ var FieldCharAttributes = class extends import_docx2.XmlAttributeComponent {
25268
+ constructor() {
25269
+ super(...arguments);
25270
+ this.xmlKeys = { type: "w:fldCharType" };
25574
25271
  }
25575
- const parts = match[1].replace(/\s*\/\s*/g, ",").split(/\s*,\s*|\s+/).filter(Boolean);
25576
- if (parts.length < 3) {
25577
- return void 0;
25272
+ };
25273
+ var FieldChar = class extends import_docx2.XmlComponent {
25274
+ constructor(type) {
25275
+ super("w:fldChar");
25276
+ this.root.push(new FieldCharAttributes({ type }));
25578
25277
  }
25579
- const red = parseRgbChannel(parts[0]);
25580
- const green = parseRgbChannel(parts[1]);
25581
- const blue = parseRgbChannel(parts[2]);
25582
- if (red === null || green === null || blue === null) {
25583
- return void 0;
25278
+ };
25279
+ var InstrTextAttributes = class extends import_docx2.XmlAttributeComponent {
25280
+ constructor() {
25281
+ super(...arguments);
25282
+ this.xmlKeys = { space: "xml:space" };
25584
25283
  }
25585
- const alpha = parts[3] !== void 0 ? parseAlphaChannel(parts[3]) : 1;
25586
- if (alpha === null || alpha <= 0) {
25587
- return void 0;
25284
+ };
25285
+ var InstrText = class extends import_docx2.XmlComponent {
25286
+ constructor(instruction) {
25287
+ super("w:instrText");
25288
+ this.root.push(new InstrTextAttributes({ space: "preserve" }));
25289
+ this.root.push(` ${instruction} `);
25588
25290
  }
25589
- const flattened = alpha >= 1 ? [red, green, blue] : [
25590
- flattenChannel(red, alpha),
25591
- flattenChannel(green, alpha),
25592
- flattenChannel(blue, alpha)
25291
+ };
25292
+ function createFieldRuns(instruction, cached, style) {
25293
+ return [
25294
+ new import_docx2.TextRun({ ...style, children: [new FieldChar("begin")] }),
25295
+ new import_docx2.TextRun({ ...style, children: [new InstrText(instruction)] }),
25296
+ new import_docx2.TextRun({ ...style, children: [new FieldChar("separate")] }),
25297
+ new import_docx2.TextRun({ ...style, text: cached }),
25298
+ new import_docx2.TextRun({ ...style, children: [new FieldChar("end")] })
25593
25299
  ];
25594
- return flattened.map(toHexChannel).join("");
25595
25300
  }
25596
- function normalizeBrowserColor(color) {
25597
- if (typeof document === "undefined") {
25598
- return void 0;
25599
- }
25600
- const canvas = document.createElement("canvas");
25601
- const context = canvas.getContext("2d");
25602
- if (!context) {
25603
- return void 0;
25604
- }
25605
- context.fillStyle = "#000000";
25606
- context.fillStyle = color;
25607
- const normalized = context.fillStyle;
25608
- if (typeof normalized !== "string") {
25609
- return void 0;
25610
- }
25611
- return normalizeHexLiteral(normalized) || normalizeRgbColor(normalized);
25301
+ function pageNumberRunStyle(pageNumber) {
25302
+ return {
25303
+ font: mapFont(pageNumber?.font || "sans-serif"),
25304
+ // PageNumber draws `${size}px`; half-points = px * 0.75 * 2
25305
+ size: Math.round((pageNumber?.size || 12) * 1.5),
25306
+ color: normalizeHexColor(pageNumber?.color || "#000000", "000000")
25307
+ };
25612
25308
  }
25613
- function parseRgbChannel(value) {
25614
- if (value.endsWith("%")) {
25615
- const percent = Number(value.slice(0, -1));
25616
- if (!Number.isFinite(percent)) {
25617
- return null;
25618
- }
25619
- return clampColorChannel(Math.round(percent / 100 * 255));
25620
- }
25621
- const channel = Number(value);
25622
- if (!Number.isFinite(channel)) {
25623
- return null;
25309
+ function createPageNumberRuns(ctx, pageHeight, textWidth) {
25310
+ const { pageNumber } = ctx.draw.getOptions();
25311
+ if (pageNumber.disabled || pageNumber.fromPageNo > 0) return null;
25312
+ const pageCount = ctx.draw.getPageCount();
25313
+ const tokens = (pageNumber.format || FORMAT_PLACEHOLDER.PAGE_NO).split(
25314
+ /(\{pageNo\}|\{pageCount\})/
25315
+ );
25316
+ const tabType = pageNumber.rowFlex === "center" /* CENTER */ ? import_docx2.TabStopType.CENTER : pageNumber.rowFlex === "right" /* RIGHT */ ? import_docx2.TabStopType.RIGHT : import_docx2.TabStopType.LEFT;
25317
+ const tabStop = tabType === import_docx2.TabStopType.CENTER ? pxTw(textWidth / 2) : tabType === import_docx2.TabStopType.RIGHT ? pxTw(textWidth) : 0;
25318
+ const position = (shift) => {
25319
+ const halfPoints = Math.round(-shift * 0.75 * 2);
25320
+ return halfPoints ? `${halfPoints}` : void 0;
25321
+ };
25322
+ return {
25323
+ baseline: pageHeight - pageNumber.bottom,
25324
+ tabType,
25325
+ tabStop,
25326
+ // shift > 0 means the number sits lower than the row baseline
25327
+ runs: (shift) => tokens.filter(Boolean).map((token) => {
25328
+ const style = {
25329
+ ...pageNumberRunStyle(pageNumber),
25330
+ position: position(shift)
25331
+ };
25332
+ const field = token === FORMAT_PLACEHOLDER.PAGE_NO ? { instruction: "PAGE", cached: "1" } : token === FORMAT_PLACEHOLDER.PAGE_COUNT ? { instruction: "NUMPAGES", cached: `${pageCount}` } : null;
25333
+ if (!field) return [new import_docx2.TextRun({ text: token, ...style })];
25334
+ return createFieldRuns(field.instruction, field.cached, style);
25335
+ }).flat()
25336
+ };
25337
+ }
25338
+ function createTextRun(ctx, text, element, shading, characterSpacing) {
25339
+ const opts = ctx.draw.getOptions();
25340
+ const isLink = element.type === "hyperlink" /* HYPERLINK */;
25341
+ const color = normalizeHexColor(
25342
+ element.color || (isLink ? opts.defaultHyperlinkColor : opts.defaultColor),
25343
+ "000000"
25344
+ );
25345
+ const highlight = element.highlight ? normalizeHexColor(element.highlight) : void 0;
25346
+ const textRun = new import_docx2.TextRun({
25347
+ text,
25348
+ font: mapFont(element.font || opts.defaultFont),
25349
+ size: Math.round(getSize(ctx, element) * 2),
25350
+ bold: !!element.bold,
25351
+ italics: !!element.italic,
25352
+ strike: !!element.strikeout,
25353
+ superScript: element.type === "superscript" /* SUPERSCRIPT */,
25354
+ subScript: element.type === "subscript" /* SUBSCRIPT */,
25355
+ underline: element.underline || isLink ? { type: mapUnderlineType(element.textDecoration?.style) } : void 0,
25356
+ color,
25357
+ shading: shading || (highlight ? { fill: highlight, type: import_docx2.ShadingType.CLEAR, color: "auto" } : void 0),
25358
+ characterSpacing
25359
+ });
25360
+ if (isLink && element.url) {
25361
+ return new import_docx2.ExternalHyperlink({ link: element.url, children: [textRun] });
25624
25362
  }
25625
- return clampColorChannel(Math.round(channel));
25363
+ return textRun;
25626
25364
  }
25627
- function parseAlphaChannel(value) {
25628
- if (value.endsWith("%")) {
25629
- const percent = Number(value.slice(0, -1));
25630
- if (!Number.isFinite(percent)) {
25631
- return null;
25365
+ function labelShading(ctx, element) {
25366
+ const { defaultBackgroundColor } = ctx.draw.getOptions().label;
25367
+ return {
25368
+ fill: normalizeHexColor(
25369
+ element.label?.backgroundColor || defaultBackgroundColor,
25370
+ "FFFFFF"
25371
+ ),
25372
+ type: import_docx2.ShadingType.CLEAR,
25373
+ color: "auto"
25374
+ };
25375
+ }
25376
+ async function createImageRun(element) {
25377
+ try {
25378
+ const image = await loadImagePayload(element.value);
25379
+ const transformation = {
25380
+ width: Math.max(1, element.width || 1),
25381
+ height: Math.max(1, element.height || 1)
25382
+ };
25383
+ if (image.type === "svg" && image.fallbackPng) {
25384
+ return new import_docx2.ImageRun({
25385
+ type: "svg",
25386
+ data: image.data,
25387
+ fallback: { type: "png", data: image.fallbackPng },
25388
+ transformation
25389
+ });
25632
25390
  }
25633
- return Math.min(Math.max(percent / 100, 0), 1);
25634
- }
25635
- const alpha = Number(value);
25636
- if (!Number.isFinite(alpha)) {
25391
+ return new import_docx2.ImageRun({
25392
+ type: image.type,
25393
+ data: image.data,
25394
+ transformation
25395
+ });
25396
+ } catch {
25637
25397
  return null;
25638
25398
  }
25639
- return Math.min(Math.max(alpha, 0), 1);
25640
- }
25641
- function clampColorChannel(value) {
25642
- return Math.min(Math.max(value, 0), 255);
25643
25399
  }
25644
- function flattenChannel(value, alpha) {
25645
- return clampColorChannel(Math.round(255 * (1 - alpha) + value * alpha));
25400
+ function getElementText(element) {
25401
+ switch (element.type) {
25402
+ case "checkbox" /* CHECKBOX */:
25403
+ return element.checkbox?.value ? "\u2611" : "\u2610";
25404
+ case "radio" /* RADIO */:
25405
+ return element.radio?.value ? "\u25C9" : "\u25CB";
25406
+ default:
25407
+ return (element.value || "").replace(new RegExp(ZERO, "g"), "");
25408
+ }
25646
25409
  }
25647
- function toHexChannel(value) {
25648
- return value.toString(16).padStart(2, "0").toUpperCase();
25410
+ function getSize(ctx, element) {
25411
+ return element.actualSize || element.size || ctx.draw.getOptions().defaultSize;
25649
25412
  }
25650
- function pxBorderToDocxSize(width) {
25651
- const safeWidth = Number.isFinite(width) && width > 0 ? width : 1;
25652
- return Math.max(2, Math.round(safeWidth * 6));
25413
+ function measure(ctx, text, element) {
25414
+ ctx.measureCtx.font = ctx.draw.getElementFont(element, 1);
25415
+ return ctx.measureCtx.measureText(text).width;
25653
25416
  }
25654
- function getRegularImageType(mime) {
25655
- if (mime.includes("png")) return "png";
25656
- if (mime.includes("jpeg") || mime.includes("jpg")) return "jpg";
25657
- if (mime.includes("gif")) return "gif";
25658
- if (mime.includes("bmp")) return "bmp";
25659
- return null;
25417
+ function isSameRunStyle(a, b) {
25418
+ 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;
25660
25419
  }
25661
- function normalizeDocxFileName(fileName) {
25662
- const trimmed = fileName?.trim();
25663
- if (!trimmed) {
25664
- return DEFAULT_DOCX_FILE_NAME;
25420
+ function mapFont(font) {
25421
+ const name = font.trim().replace(/^['"]|['"]$/g, "");
25422
+ switch (name.toLowerCase()) {
25423
+ case "sans-serif":
25424
+ return "Arial";
25425
+ case "serif":
25426
+ return "Times New Roman";
25427
+ case "monospace":
25428
+ return "Courier New";
25429
+ default:
25430
+ return name;
25665
25431
  }
25666
- return trimmed.toLowerCase().endsWith(".docx") ? trimmed : `${trimmed}.docx`;
25667
- }
25668
- function pxToTwips(px) {
25669
- return Math.round(px * 15);
25670
25432
  }
25671
25433
 
25672
25434
  // src/utils/pdf.ts
@@ -25674,7 +25436,7 @@ var import_pdf_lib = require("pdf-lib");
25674
25436
  var DEFAULT_PDF_FILE_NAME = "document.pdf";
25675
25437
  var DEFAULT_IMAGE_WIDTH2 = 320;
25676
25438
  var DEFAULT_IMAGE_HEIGHT2 = 180;
25677
- var DEFAULT_LINE_HEIGHT2 = 1.15;
25439
+ var DEFAULT_LINE_HEIGHT = 1.15;
25678
25440
  var PAGE_REGION_GAP = 12;
25679
25441
  var SEPARATOR_HEIGHT = 12;
25680
25442
  var LIST_GAP = 8;
@@ -25869,7 +25631,7 @@ async function parseElementList(elementList, context, options) {
25869
25631
  }
25870
25632
  if (element.type === "block" /* BLOCK */) {
25871
25633
  await flushInlineBuffer();
25872
- const blockText = getBlockFallbackText2(element);
25634
+ const blockText = getBlockFallbackText(element);
25873
25635
  if (blockText) {
25874
25636
  blocks.push(
25875
25637
  ...await parseInlineElements(
@@ -25921,7 +25683,7 @@ async function parseInlineElements(elementList, context, options, overrides = {}
25921
25683
  current = null;
25922
25684
  };
25923
25685
  const appendText = (element, text, factory, preserveTrailingBreak = false) => {
25924
- const normalized = normalizeText2(text);
25686
+ const normalized = normalizeText(text);
25925
25687
  const parts = normalized.split("\n");
25926
25688
  let lastSeparatorFlushedContent = false;
25927
25689
  for (let i = 0; i < parts.length; i++) {
@@ -25957,7 +25719,7 @@ async function parseInlineElements(elementList, context, options, overrides = {}
25957
25719
  const children = element.valueList || [];
25958
25720
  for (let childIndex = 0; childIndex < children.length; childIndex++) {
25959
25721
  const child = children[childIndex];
25960
- const text = normalizeText2(getInlineElementText2(child));
25722
+ const text = normalizeText(getInlineElementText(child));
25961
25723
  if (!text) continue;
25962
25724
  appendText(
25963
25725
  element,
@@ -26006,7 +25768,7 @@ async function parseInlineElements(elementList, context, options, overrides = {}
26006
25768
  ensureParagraph(element).runs.push(badgeRun);
26007
25769
  continue;
26008
25770
  }
26009
- const textValue = getInlineElementText2(element);
25771
+ const textValue = getInlineElementText(element);
26010
25772
  if (!textValue) {
26011
25773
  continue;
26012
25774
  }
@@ -26034,7 +25796,7 @@ async function parseListBlock(element, context, options) {
26034
25796
  const blocks = [];
26035
25797
  const orderedCounts = Array(9).fill(0);
26036
25798
  for (const listItemElements of listItemMap.values()) {
26037
- const itemElement = getListItemNumberingElement2(listItemElements, element);
25799
+ const itemElement = getListItemNumberingElement(listItemElements, element);
26038
25800
  const marker = getListMarker(itemElement, orderedCounts);
26039
25801
  blocks.push(
26040
25802
  ...await parseInlineElements(listItemElements, context, options, {
@@ -26593,10 +26355,11 @@ function layoutParagraph(block, width, context) {
26593
26355
  }
26594
26356
  if (token.width > availableWidth && token.kind === "text" && token.run.type === "text") {
26595
26357
  const segments = splitTextToken(token, availableWidth, context);
26596
- for (let segmentIndex = 0; segmentIndex < segments.length; segmentIndex++) {
26597
- tokens.splice(i + segmentIndex, 0, segments[segmentIndex]);
26358
+ if (segments.length > 1) {
26359
+ tokens.splice(i, 1, ...segments);
26360
+ i--;
26361
+ continue;
26598
26362
  }
26599
- continue;
26600
26363
  }
26601
26364
  if (line.width + token.width > availableWidth && line.fragments.length) {
26602
26365
  commitLine();
@@ -26955,7 +26718,7 @@ function getEmptyLineHeight(block, context) {
26955
26718
  block.context.rowMargin || context.options.defaultRowMargin
26956
26719
  );
26957
26720
  }
26958
- function getRunHeight(run, rowMargin = DEFAULT_LINE_HEIGHT2) {
26721
+ function getRunHeight(run, rowMargin = DEFAULT_LINE_HEIGHT) {
26959
26722
  return run.size * rowMargin;
26960
26723
  }
26961
26724
  function resolveTextMetrics(run, context) {
@@ -27164,10 +26927,10 @@ function loadHtmlImage2(src) {
27164
26927
  image.src = src;
27165
26928
  });
27166
26929
  }
27167
- function getInlineElementText2(element) {
26930
+ function getInlineElementText(element) {
27168
26931
  switch (element.type) {
27169
26932
  case "control" /* CONTROL */:
27170
- return getControlText2(element.control);
26933
+ return getControlText(element.control);
27171
26934
  case "date" /* DATE */:
27172
26935
  return element.valueList?.length ? getTextFromElementList(element.valueList) : element.value;
27173
26936
  case "checkbox" /* CHECKBOX */:
@@ -27183,7 +26946,7 @@ function getInlineElementText2(element) {
27183
26946
  return element.value;
27184
26947
  }
27185
26948
  }
27186
- function getControlText2(control) {
26949
+ function getControlText(control) {
27187
26950
  if (!control) return "";
27188
26951
  if (control.type === "text" /* TEXT */ || control.type === "date" /* DATE */ || control.type === "number" /* NUMBER */) {
27189
26952
  const value = control.value?.length ? getTextFromElementList(control.value) : "";
@@ -27191,7 +26954,7 @@ function getControlText2(control) {
27191
26954
  return `${control.preText || ""}${content}${control.postText || ""}`;
27192
26955
  }
27193
26956
  if (control.type === "select" /* SELECT */) {
27194
- const labels = getSelectedControlLabels2(control.code, control.valueSets);
26957
+ const labels = getSelectedControlLabels(control.code, control.valueSets);
27195
26958
  const content = labels.length ? labels.join(control.multiSelectDelimiter || ", ") : control.placeholder || "";
27196
26959
  return `${control.preText || ""}${content}${control.postText || ""}`;
27197
26960
  }
@@ -27204,13 +26967,13 @@ function getControlText2(control) {
27204
26967
  }
27205
26968
  return "";
27206
26969
  }
27207
- function getSelectedControlLabels2(code, valueSets) {
26970
+ function getSelectedControlLabels(code, valueSets) {
27208
26971
  if (!code || !valueSets?.length) return [];
27209
26972
  return code.split(",").map(
27210
26973
  (selectCode) => valueSets.find((valueSet) => valueSet.code === selectCode)?.value
27211
26974
  ).filter((value) => !!value);
27212
26975
  }
27213
- function getBlockFallbackText2(element) {
26976
+ function getBlockFallbackText(element) {
27214
26977
  if (element.block?.iframeBlock?.src) {
27215
26978
  return element.block.iframeBlock.src;
27216
26979
  }
@@ -27219,7 +26982,7 @@ function getBlockFallbackText2(element) {
27219
26982
  }
27220
26983
  return "";
27221
26984
  }
27222
- function getListItemNumberingElement2(listItemElements, fallback) {
26985
+ function getListItemNumberingElement(listItemElements, fallback) {
27223
26986
  return listItemElements.find(
27224
26987
  (listItem) => listItem.listId || listItem.listLevel !== void 0 || !!listItem.listPreset || !!listItem.listStyle || !!listItem.listType
27225
26988
  ) || fallback;
@@ -27441,7 +27204,7 @@ function getReservedPageNumberBottom(pageNumber, pageNumberHeight) {
27441
27204
  }
27442
27205
  return pxToPt(pageNumber.bottom + 4) + pageNumberHeight;
27443
27206
  }
27444
- function normalizeText2(text = "") {
27207
+ function normalizeText(text = "") {
27445
27208
  return text.replace(new RegExp(ZERO, "g"), "").replace(/\r\n/g, "\n");
27446
27209
  }
27447
27210
  function normalizePdfFileName(fileName) {
@@ -28781,8 +28544,7 @@ var CommandAdapt = class {
28781
28544
  }
28782
28545
  }
28783
28546
  async exportDocx(payload = {}) {
28784
- const result = this.draw.getValue();
28785
- const { blob, fileName } = await exportEditorDataToDocx(result, payload);
28547
+ const { blob, fileName } = await exportDrawToDocx(this.draw, payload);
28786
28548
  downloadBlob(blob, fileName);
28787
28549
  }
28788
28550
  async exportPdf(payload = {}) {