@harbour-enterprises/superdoc 1.5.0-next.5 → 1.5.0-next.7

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.
@@ -8332,6 +8332,11 @@
8332
8332
  "xmlns:v": "urn:schemas-microsoft-com:vml",
8333
8333
  "xmlns:wp14": "http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing",
8334
8334
  "xmlns:wp": "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing",
8335
+ "xmlns:a": "http://schemas.openxmlformats.org/drawingml/2006/main",
8336
+ "xmlns:pic": "http://schemas.openxmlformats.org/drawingml/2006/picture",
8337
+ "xmlns:c": "http://schemas.openxmlformats.org/drawingml/2006/chart",
8338
+ "xmlns:dgm": "http://schemas.openxmlformats.org/drawingml/2006/diagram",
8339
+ "xmlns:lc": "http://schemas.openxmlformats.org/drawingml/2006/lockedCanvas",
8335
8340
  "xmlns:w10": "urn:schemas-microsoft-com:office:word",
8336
8341
  "xmlns:w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
8337
8342
  "xmlns:w14": "http://schemas.microsoft.com/office/word/2010/wordml",
@@ -15124,6 +15129,11 @@
15124
15129
  const validXmlAttributes$9 = ["w:rsidDel", "w:rsidR", "w:rsidRPr", "w:rsidTr", "w14:paraId", "w14:textId"].map(
15125
15130
  (xmlName) => createAttributeHandler(xmlName)
15126
15131
  );
15132
+ const getColspan$1 = (cell2) => {
15133
+ const rawColspan = cell2?.attrs?.colspan;
15134
+ const numericColspan = typeof rawColspan === "string" ? parseInt(rawColspan, 10) : rawColspan;
15135
+ return Number.isFinite(numericColspan) && numericColspan > 0 ? numericColspan : 1;
15136
+ };
15127
15137
  const encode$w = (params2, encodedAttrs) => {
15128
15138
  const { row: row2 } = params2.extraParams;
15129
15139
  let tableRowProperties = {};
@@ -15256,7 +15266,27 @@
15256
15266
  }
15257
15267
  return cell2;
15258
15268
  });
15259
- const trimmedContent = sanitizedCells.filter((_2, index2) => !isPlaceholderCell(trimmedSlice[index2]));
15269
+ let trimmedContent = sanitizedCells.filter((_2, index2) => !isPlaceholderCell(trimmedSlice[index2]));
15270
+ const preferTableGrid = params2.extraParams?.preferTableGrid === true;
15271
+ const totalColumns = params2.extraParams?.totalColumns;
15272
+ if (preferTableGrid && typeof totalColumns === "number" && Number.isFinite(totalColumns) && totalColumns > 0) {
15273
+ const rawGridBefore = node2.attrs?.tableRowProperties?.gridBefore;
15274
+ const numericGridBefore = typeof rawGridBefore === "string" ? parseInt(rawGridBefore, 10) : rawGridBefore;
15275
+ const safeGridBefore = Number.isFinite(numericGridBefore) && numericGridBefore > 0 ? numericGridBefore : 0;
15276
+ const effectiveGridBefore = leadingPlaceholders > 0 ? leadingPlaceholders : safeGridBefore;
15277
+ const availableColumns = Math.max(totalColumns - effectiveGridBefore, 0);
15278
+ let usedColumns = 0;
15279
+ const constrainedCells = [];
15280
+ for (const cell2 of trimmedContent) {
15281
+ const colspan = getColspan$1(cell2);
15282
+ if (usedColumns + colspan > availableColumns) {
15283
+ break;
15284
+ }
15285
+ constrainedCells.push(cell2);
15286
+ usedColumns += colspan;
15287
+ }
15288
+ trimmedContent = constrainedCells;
15289
+ }
15260
15290
  const translateParams = {
15261
15291
  ...params2,
15262
15292
  node: { ...node2, content: trimmedContent }
@@ -24278,9 +24308,9 @@
24278
24308
  if (!blip) {
24279
24309
  return null;
24280
24310
  }
24281
- const stretch = blipFill?.elements.find((el) => el.name === "a:stretch");
24282
- const fillRect = stretch?.elements.find((el) => el.name === "a:fillRect");
24283
- const srcRect = blipFill?.elements.find((el) => el.name === "a:srcRect");
24311
+ const stretch = blipFill?.elements?.find((el) => el.name === "a:stretch");
24312
+ const fillRect = stretch?.elements?.find((el) => el.name === "a:fillRect");
24313
+ const srcRect = blipFill?.elements?.find((el) => el.name === "a:srcRect");
24284
24314
  const srcRectAttrs = srcRect?.attributes || {};
24285
24315
  const srcRectHasNegativeValues = ["l", "t", "r", "b"].some((attr) => {
24286
24316
  const val = srcRectAttrs[attr];
@@ -31536,6 +31566,53 @@ Please report this to https://github.com/markedjs/marked.`, e) {
31536
31566
  attributes: validXmlAttributes$5
31537
31567
  };
31538
31568
  const translator$s = NodeTranslator.from(config$d);
31569
+ const getColspan = (cell2) => {
31570
+ const rawColspan = cell2?.attrs?.colspan;
31571
+ const numericColspan = typeof rawColspan === "string" ? parseInt(rawColspan, 10) : rawColspan;
31572
+ return Number.isFinite(numericColspan) && numericColspan > 0 ? numericColspan : 1;
31573
+ };
31574
+ const resolveGridBefore = (row2) => {
31575
+ const rawGridBefore = row2?.attrs?.tableRowProperties?.gridBefore ?? row2?.attrs?.gridBefore;
31576
+ const numericGridBefore = typeof rawGridBefore === "string" ? parseInt(rawGridBefore, 10) : rawGridBefore;
31577
+ if (!Number.isFinite(numericGridBefore) || numericGridBefore <= 0) return 0;
31578
+ const cells = Array.isArray(row2.content) ? row2.content : [];
31579
+ let leadingGridBefore = 0;
31580
+ while (leadingGridBefore < cells.length && cells[leadingGridBefore]?.attrs?.__placeholder === "gridBefore") {
31581
+ leadingGridBefore += 1;
31582
+ }
31583
+ return leadingGridBefore > 0 ? 0 : numericGridBefore;
31584
+ };
31585
+ const advanceColumnsForCell = (columnIndex, cell2) => columnIndex + getColspan(cell2);
31586
+ const getCellStartColumn = (row2, targetCell) => {
31587
+ const cells = Array.isArray(row2.content) ? row2.content : [];
31588
+ let columnIndex = resolveGridBefore(row2);
31589
+ for (const cell2 of cells) {
31590
+ if (cell2 === targetCell) return columnIndex;
31591
+ columnIndex = advanceColumnsForCell(columnIndex, cell2);
31592
+ }
31593
+ return columnIndex;
31594
+ };
31595
+ const findCellCoveringColumn = (row2, targetColumn) => {
31596
+ const cells = Array.isArray(row2.content) ? row2.content : [];
31597
+ let columnIndex = resolveGridBefore(row2);
31598
+ for (const cell2 of cells) {
31599
+ const colspan = getColspan(cell2);
31600
+ if (targetColumn >= columnIndex && targetColumn < columnIndex + colspan) {
31601
+ return cell2;
31602
+ }
31603
+ columnIndex = advanceColumnsForCell(columnIndex, cell2);
31604
+ }
31605
+ return null;
31606
+ };
31607
+ const findInsertionIndexForColumn = (row2, targetColumn) => {
31608
+ const cells = Array.isArray(row2.content) ? row2.content : [];
31609
+ let columnIndex = resolveGridBefore(row2);
31610
+ for (let index2 = 0; index2 < cells.length; index2++) {
31611
+ if (columnIndex >= targetColumn) return index2;
31612
+ columnIndex = advanceColumnsForCell(columnIndex, cells[index2]);
31613
+ }
31614
+ return cells.length;
31615
+ };
31539
31616
  function preProcessVerticalMergeCells(table2, { editorSchema }) {
31540
31617
  if (!table2 || !Array.isArray(table2.content)) {
31541
31618
  return table2;
@@ -31551,15 +31628,17 @@ Please report this to https://github.com/markedjs/marked.`, e) {
31551
31628
  const cell2 = row2.content[cellIndex];
31552
31629
  if (!cell2) continue;
31553
31630
  const attrs = cell2.attrs || {};
31554
- if (!attrs.rowspan || attrs.rowspan <= 1) continue;
31555
- const maxRowspan = Math.min(attrs.rowspan, rows.length - rowIndex);
31631
+ const rawRowspan = typeof attrs.rowspan === "string" ? parseInt(attrs.rowspan, 10) : attrs.rowspan;
31632
+ if (!Number.isFinite(rawRowspan) || rawRowspan <= 1) continue;
31633
+ const maxRowspan = Math.min(rawRowspan, rows.length - rowIndex);
31634
+ const startColumn = getCellStartColumn(row2, cell2);
31556
31635
  for (let offset2 = 1; offset2 < maxRowspan; offset2++) {
31557
31636
  const rowToChange = rows[rowIndex + offset2];
31558
31637
  if (!rowToChange) continue;
31559
31638
  if (!Array.isArray(rowToChange.content)) {
31560
31639
  rowToChange.content = [];
31561
31640
  }
31562
- const existingCell = rowToChange.content[cellIndex];
31641
+ const existingCell = findCellCoveringColumn(rowToChange, startColumn);
31563
31642
  if (existingCell?.attrs?.continueMerge) continue;
31564
31643
  const mergedCell = {
31565
31644
  type: cell2.type,
@@ -31570,7 +31649,8 @@ Please report this to https://github.com/markedjs/marked.`, e) {
31570
31649
  continueMerge: true
31571
31650
  }
31572
31651
  };
31573
- rowToChange.content.splice(cellIndex, 0, mergedCell);
31652
+ const insertionIndex = findInsertionIndexForColumn(rowToChange, startColumn);
31653
+ rowToChange.content.splice(insertionIndex, 0, mergedCell);
31574
31654
  }
31575
31655
  }
31576
31656
  }
@@ -31722,15 +31802,24 @@ Please report this to https://github.com/markedjs/marked.`, e) {
31722
31802
  const decode$t = (params2) => {
31723
31803
  const { grid: rawGrid } = params2.node.attrs || {};
31724
31804
  const grid = Array.isArray(rawGrid) ? rawGrid : [];
31725
- const { firstRow = {} } = params2.extraParams || {};
31805
+ const { firstRow = {}, preferTableGrid = false, totalColumns: requestedColumns } = params2.extraParams || {};
31726
31806
  const cellNodes = firstRow.content?.filter((n) => n.type === "tableCell") ?? [];
31727
- const colWidthsFromCellNodes = cellNodes.flatMap((cell2) => {
31807
+ let colWidthsFromCellNodes = cellNodes.flatMap((cell2) => {
31728
31808
  const spanCount = Math.max(1, cell2?.attrs?.colspan ?? 1);
31729
31809
  const colwidth = cell2.attrs?.colwidth;
31730
31810
  return Array.from({ length: spanCount }).map((_2, span) => Array.isArray(colwidth) ? colwidth[span] : void 0);
31731
31811
  });
31732
31812
  const columnCountFromCells = colWidthsFromCellNodes.length;
31733
- const totalColumns = Math.max(columnCountFromCells, grid.length);
31813
+ const gridColumnCount = grid.length;
31814
+ let totalColumns = Math.max(columnCountFromCells, gridColumnCount);
31815
+ if (typeof requestedColumns === "number" && Number.isFinite(requestedColumns) && requestedColumns > 0) {
31816
+ totalColumns = requestedColumns;
31817
+ } else if (preferTableGrid && gridColumnCount > 0) {
31818
+ totalColumns = gridColumnCount;
31819
+ }
31820
+ if (colWidthsFromCellNodes.length > totalColumns) {
31821
+ colWidthsFromCellNodes = colWidthsFromCellNodes.slice(0, totalColumns);
31822
+ }
31734
31823
  const fallbackColumnWidthTwips = resolveFallbackColumnWidthTwips(params2, totalColumns, cellMinWidth);
31735
31824
  const elements = [];
31736
31825
  const pushColumn = (widthTwips, { enforceMinimum = false } = {}) => {
@@ -31990,22 +32079,31 @@ Please report this to https://github.com/markedjs/marked.`, e) {
31990
32079
  const decode$s = (params2, decodedAttrs) => {
31991
32080
  params2.node = preProcessVerticalMergeCells(params2.node, params2);
31992
32081
  const { node: node2 } = params2;
31993
- const elements = translateChildNodes(params2);
32082
+ const rawGrid = node2.attrs?.grid;
32083
+ const grid = Array.isArray(rawGrid) ? rawGrid : [];
32084
+ const preferTableGrid = node2.attrs?.userEdited !== true && grid.length > 0;
32085
+ const totalColumns = preferTableGrid ? grid.length : void 0;
32086
+ const extraParams = {
32087
+ ...params2.extraParams || {},
32088
+ preferTableGrid,
32089
+ totalColumns
32090
+ };
32091
+ const elements = translateChildNodes({ ...params2, extraParams });
31994
32092
  const firstRow = node2.content?.find((n) => n.type === "tableRow");
31995
- const properties = node2.attrs.grid;
31996
32093
  const element2 = translator$c.decode({
31997
32094
  ...params2,
31998
- node: { ...node2, attrs: { ...node2.attrs, grid: properties } },
32095
+ node: { ...node2, attrs: { ...node2.attrs, grid } },
31999
32096
  extraParams: {
32097
+ ...extraParams,
32000
32098
  firstRow
32001
32099
  }
32002
32100
  });
32003
32101
  if (element2) elements.unshift(element2);
32004
32102
  if (node2.attrs?.tableProperties) {
32005
- const properties2 = { ...node2.attrs.tableProperties };
32103
+ const properties = { ...node2.attrs.tableProperties };
32006
32104
  const element22 = translator$e.decode({
32007
32105
  ...params2,
32008
- node: { ...node2, attrs: { ...node2.attrs, tableProperties: properties2 } }
32106
+ node: { ...node2, attrs: { ...node2.attrs, tableProperties: properties } }
32009
32107
  });
32010
32108
  if (element22) elements.unshift(element22);
32011
32109
  }
@@ -35461,7 +35559,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
35461
35559
  }
35462
35560
  return style2;
35463
35561
  }
35464
- function handleShapeImageImport({ params: params2, pict }) {
35562
+ function handleShapeImageWatermarkImport({ params: params2, pict }) {
35465
35563
  const shape = pict.elements?.find((el) => el.name === "v:shape");
35466
35564
  if (!shape) return null;
35467
35565
  const imagedata = shape.elements?.find((el) => el.name === "v:imagedata");
@@ -35487,7 +35585,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
35487
35585
  const targetPath = rel.attributes["Target"];
35488
35586
  const normalizedPath = normalizeTargetPath(targetPath);
35489
35587
  const style2 = shapeAttrs.style || "";
35490
- const styleObj = parseVmlStyle(style2);
35588
+ const styleObj = parseVmlStyle$1(style2);
35491
35589
  const width = styleObj.width || "100px";
35492
35590
  const height = styleObj.height || "100px";
35493
35591
  const position2 = {
@@ -35533,12 +35631,12 @@ Please report this to https://github.com/markedjs/marked.`, e) {
35533
35631
  },
35534
35632
  // Size
35535
35633
  size: {
35536
- width: convertToPixels(width),
35537
- height: convertToPixels(height)
35634
+ width: convertToPixels$1(width),
35635
+ height: convertToPixels$1(height)
35538
35636
  },
35539
35637
  marginOffset: {
35540
- horizontal: convertToPixels(position2.marginLeft),
35541
- top: convertToPixels(position2.marginTop)
35638
+ horizontal: convertToPixels$1(position2.marginLeft),
35639
+ top: convertToPixels$1(position2.marginTop)
35542
35640
  },
35543
35641
  // Image adjustments
35544
35642
  ...gain && { gain },
@@ -35554,7 +35652,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
35554
35652
  if (trimmed.startsWith("media/")) return `word/${trimmed}`;
35555
35653
  return `word/${trimmed}`;
35556
35654
  }
35557
- function parseVmlStyle(style2) {
35655
+ function parseVmlStyle$1(style2) {
35558
35656
  const result = {};
35559
35657
  if (!style2) return result;
35560
35658
  const declarations = style2.split(";").filter((s2) => s2.trim());
@@ -35566,6 +35664,267 @@ Please report this to https://github.com/markedjs/marked.`, e) {
35566
35664
  }
35567
35665
  return result;
35568
35666
  }
35667
+ function convertToPixels$1(value) {
35668
+ if (typeof value === "number") return value;
35669
+ if (!value || typeof value !== "string") return 0;
35670
+ const match = value.match(/^([\d.]+)([a-z%]+)?$/i);
35671
+ if (!match) return 0;
35672
+ const num = parseFloat(match[1]);
35673
+ const unit = match[2] || "px";
35674
+ switch (unit.toLowerCase()) {
35675
+ case "px":
35676
+ return num;
35677
+ case "pt":
35678
+ return num * (96 / 72);
35679
+ // 1pt = 1/72 inch, 96 DPI
35680
+ case "in":
35681
+ return num * 96;
35682
+ case "cm":
35683
+ return num * (96 / 2.54);
35684
+ case "mm":
35685
+ return num * (96 / 25.4);
35686
+ case "pc":
35687
+ return num * 16;
35688
+ // 1pc = 12pt
35689
+ default:
35690
+ return num;
35691
+ }
35692
+ }
35693
+ function handleShapeTextWatermarkImport({ pict }) {
35694
+ const shape = pict.elements?.find((el) => el.name === "v:shape");
35695
+ if (!shape) return null;
35696
+ const textpath = shape.elements?.find((el) => el.name === "v:textpath");
35697
+ if (!textpath) return null;
35698
+ const shapeAttrs = shape.attributes || {};
35699
+ const textpathAttrs = textpath.attributes || {};
35700
+ const watermarkText = textpathAttrs["string"] || "";
35701
+ if (!watermarkText) {
35702
+ console.warn("v:textpath missing string attribute");
35703
+ return null;
35704
+ }
35705
+ const style2 = shapeAttrs.style || "";
35706
+ const styleObj = parseVmlStyle(style2);
35707
+ const width = styleObj.width || "481.8pt";
35708
+ const height = styleObj.height || "82.8pt";
35709
+ const position2 = {
35710
+ type: styleObj.position || "absolute",
35711
+ marginLeft: styleObj["margin-left"] || "0",
35712
+ marginTop: styleObj["margin-top"] || "0"
35713
+ };
35714
+ const rotation = parseFloat(styleObj.rotation) || 0;
35715
+ const hPosition = styleObj["mso-position-horizontal"] || "center";
35716
+ const vPosition = styleObj["mso-position-vertical"] || "center";
35717
+ const hRelativeTo = styleObj["mso-position-horizontal-relative"] || "margin";
35718
+ const vRelativeTo = styleObj["mso-position-vertical-relative"] || "margin";
35719
+ const textAnchor = styleObj["v-text-anchor"] || "middle";
35720
+ const fill = shape.elements?.find((el) => el.name === "v:fill");
35721
+ const fillAttrs = fill?.attributes || {};
35722
+ const rawFillColor = shapeAttrs.fillcolor || fillAttrs.color || "silver";
35723
+ const rawFillColor2 = fillAttrs.color2 || "#3f3f3f";
35724
+ const fillColor = sanitizeColor(rawFillColor, "silver");
35725
+ const fillColor2 = sanitizeColor(rawFillColor2, "#3f3f3f");
35726
+ const opacity = fillAttrs.opacity || "0.5";
35727
+ const fillType = fillAttrs.type || "solid";
35728
+ const stroke = shape.elements?.find((el) => el.name === "v:stroke");
35729
+ const strokeAttrs = stroke?.attributes || {};
35730
+ const stroked = shapeAttrs.stroked || "f";
35731
+ const strokeColor = strokeAttrs.color || "#3465a4";
35732
+ const strokeJoinstyle = strokeAttrs.joinstyle || "round";
35733
+ const strokeEndcap = strokeAttrs.endcap || "flat";
35734
+ const textpathStyle = textpathAttrs.style || "";
35735
+ const textStyleObj = parseVmlStyle(textpathStyle);
35736
+ const rawFontFamily = textStyleObj["font-family"]?.replace(/['"]/g, "");
35737
+ const fontFamily2 = sanitizeFontFamily$1(rawFontFamily);
35738
+ const fontSize2 = textStyleObj["font-size"] || "1pt";
35739
+ const fitshape = textpathAttrs.fitshape || "t";
35740
+ const trim = textpathAttrs.trim || "t";
35741
+ const textpathOn = textpathAttrs.on || "t";
35742
+ const path2 = shape.elements?.find((el) => el.name === "v:path");
35743
+ const pathAttrs = path2?.attributes || {};
35744
+ const textpathok = pathAttrs.textpathok || "t";
35745
+ const wrap2 = shape.elements?.find((el) => el.name === "w10:wrap");
35746
+ const wrapAttrs = wrap2?.attributes || {};
35747
+ const wrapType = wrapAttrs.type || "none";
35748
+ const widthPx = convertToPixels(width);
35749
+ const heightPx = convertToPixels(height);
35750
+ const sanitizedOpacity = sanitizeNumeric(parseFloat(opacity), 0.5, 0, 1);
35751
+ const sanitizedRotation = sanitizeNumeric(rotation, 0, -360, 360);
35752
+ const svgResult = generateTextWatermarkSVG({
35753
+ text: watermarkText,
35754
+ width: widthPx,
35755
+ height: heightPx,
35756
+ rotation: sanitizedRotation,
35757
+ fill: {
35758
+ color: fillColor,
35759
+ opacity: sanitizedOpacity
35760
+ },
35761
+ textStyle: {
35762
+ fontFamily: fontFamily2,
35763
+ fontSize: fontSize2
35764
+ }
35765
+ });
35766
+ const svgDataUri = svgResult.dataUri;
35767
+ const imageWatermarkNode = {
35768
+ type: "image",
35769
+ attrs: {
35770
+ src: svgDataUri,
35771
+ alt: watermarkText,
35772
+ title: watermarkText,
35773
+ extension: "svg",
35774
+ // Mark this as a text watermark for export
35775
+ vmlWatermark: true,
35776
+ vmlTextWatermark: true,
35777
+ // Store VML-specific attributes for round-trip
35778
+ vmlStyle: style2,
35779
+ vmlAttributes: shapeAttrs,
35780
+ vmlTextpathAttributes: textpathAttrs,
35781
+ vmlPathAttributes: pathAttrs,
35782
+ vmlFillAttributes: fillAttrs,
35783
+ vmlStrokeAttributes: strokeAttrs,
35784
+ vmlWrapAttributes: wrapAttrs,
35785
+ // Positioning (same as image watermarks)
35786
+ isAnchor: true,
35787
+ inline: false,
35788
+ wrap: {
35789
+ type: wrapType === "none" ? "None" : wrapType,
35790
+ attrs: {
35791
+ behindDoc: true
35792
+ }
35793
+ },
35794
+ anchorData: {
35795
+ hRelativeFrom: hRelativeTo,
35796
+ vRelativeFrom: vRelativeTo,
35797
+ alignH: hPosition,
35798
+ alignV: vPosition
35799
+ },
35800
+ // Size - use rotated bounding box dimensions to prevent clipping
35801
+ size: {
35802
+ width: svgResult.svgWidth,
35803
+ height: svgResult.svgHeight
35804
+ },
35805
+ marginOffset: {
35806
+ horizontal: convertToPixels(position2.marginLeft),
35807
+ // For center-aligned watermarks relative to margin, Word's margin-top value
35808
+ // is not suitable for browser rendering. Set to 0 to let center alignment work.
35809
+ top: vPosition === "center" && vRelativeTo === "margin" ? 0 : convertToPixels(position2.marginTop)
35810
+ },
35811
+ // Store text watermark specific data for export
35812
+ textWatermarkData: {
35813
+ text: watermarkText,
35814
+ rotation: sanitizedRotation,
35815
+ textStyle: {
35816
+ fontFamily: fontFamily2,
35817
+ fontSize: fontSize2,
35818
+ textAnchor
35819
+ },
35820
+ fill: {
35821
+ color: fillColor,
35822
+ color2: fillColor2,
35823
+ opacity: sanitizedOpacity,
35824
+ type: fillType
35825
+ },
35826
+ stroke: {
35827
+ enabled: stroked !== "f",
35828
+ color: strokeColor,
35829
+ joinstyle: strokeJoinstyle,
35830
+ endcap: strokeEndcap
35831
+ },
35832
+ textpath: {
35833
+ on: textpathOn === "t",
35834
+ fitshape: fitshape === "t",
35835
+ trim: trim === "t",
35836
+ textpathok: textpathok === "t"
35837
+ }
35838
+ }
35839
+ }
35840
+ };
35841
+ return imageWatermarkNode;
35842
+ }
35843
+ function sanitizeFontFamily$1(fontFamily2) {
35844
+ if (!fontFamily2 || typeof fontFamily2 !== "string") {
35845
+ return "Arial";
35846
+ }
35847
+ const sanitized = fontFamily2.replace(/[^a-zA-Z0-9\s,\-]/g, "").trim();
35848
+ return sanitized || "Arial";
35849
+ }
35850
+ function sanitizeColor(color2, defaultColor = "silver") {
35851
+ if (!color2 || typeof color2 !== "string") {
35852
+ return defaultColor;
35853
+ }
35854
+ const sanitized = color2.replace(/[^a-zA-Z0-9#%(),.]/g, "").trim();
35855
+ return sanitized || defaultColor;
35856
+ }
35857
+ function sanitizeNumeric(value, defaultValue, min2 = -Infinity, max2 = Infinity) {
35858
+ const num = typeof value === "number" ? value : parseFloat(value);
35859
+ if (isNaN(num) || !isFinite(num)) {
35860
+ return defaultValue;
35861
+ }
35862
+ return Math.max(min2, Math.min(max2, num));
35863
+ }
35864
+ function generateTextWatermarkSVG({ text: text2, width, height, rotation, fill, textStyle }) {
35865
+ let fontSize2 = height * 0.9;
35866
+ if (textStyle?.fontSize && textStyle.fontSize.trim() !== "1pt") {
35867
+ const match = textStyle.fontSize.match(/^([\d.]+)(pt|px)?$/);
35868
+ if (match) {
35869
+ const value = parseFloat(match[1]);
35870
+ const unit = match[2] || "pt";
35871
+ fontSize2 = (unit === "pt" ? value * (96 / 72) : value) * 50;
35872
+ }
35873
+ }
35874
+ fontSize2 = Math.max(fontSize2, 48);
35875
+ const color2 = sanitizeColor(fill?.color, "silver");
35876
+ const opacity = sanitizeNumeric(fill?.opacity, 0.5, 0, 1);
35877
+ const fontFamily2 = sanitizeFontFamily$1(textStyle?.fontFamily);
35878
+ const sanitizedRotation = sanitizeNumeric(rotation, 0, -360, 360);
35879
+ const sanitizedWidth = sanitizeNumeric(width, 100, 1, 1e4);
35880
+ const sanitizedHeight = sanitizeNumeric(height, 100, 1, 1e4);
35881
+ const sanitizedFontSize = sanitizeNumeric(fontSize2, 48, 1, 1e3);
35882
+ const radians = sanitizedRotation * Math.PI / 180;
35883
+ const cos = Math.abs(Math.cos(radians));
35884
+ const sin = Math.abs(Math.sin(radians));
35885
+ const rotatedWidth = sanitizedWidth * cos + sanitizedHeight * sin;
35886
+ const rotatedHeight = sanitizedWidth * sin + sanitizedHeight * cos;
35887
+ const svgWidth = Math.max(sanitizedWidth, rotatedWidth);
35888
+ const svgHeight = Math.max(sanitizedHeight, rotatedHeight);
35889
+ const centerX = svgWidth / 2;
35890
+ const centerY = svgHeight / 2;
35891
+ const svg2 = `<svg xmlns="http://www.w3.org/2000/svg" width="${svgWidth}" height="${svgHeight}" viewBox="0 0 ${svgWidth} ${svgHeight}">
35892
+ <text
35893
+ x="${centerX}"
35894
+ y="${centerY}"
35895
+ text-anchor="middle"
35896
+ dominant-baseline="middle"
35897
+ font-family="${fontFamily2}"
35898
+ font-size="${sanitizedFontSize}px"
35899
+ font-weight="bold"
35900
+ fill="${color2}"
35901
+ opacity="${opacity}"
35902
+ transform="rotate(${sanitizedRotation} ${centerX} ${centerY})">${escapeXml(text2)}</text>
35903
+ </svg>`;
35904
+ return {
35905
+ dataUri: `data:image/svg+xml,${encodeURIComponent(svg2)}`,
35906
+ svgWidth,
35907
+ svgHeight
35908
+ };
35909
+ }
35910
+ function escapeXml(text2) {
35911
+ return text2.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
35912
+ }
35913
+ function parseVmlStyle(style2) {
35914
+ const result = {};
35915
+ if (!style2) return result;
35916
+ const declarations = style2.split(";").filter((s2) => s2.trim());
35917
+ for (const decl of declarations) {
35918
+ const colonIndex = decl.indexOf(":");
35919
+ if (colonIndex === -1) continue;
35920
+ const prop = decl.substring(0, colonIndex).trim();
35921
+ const value = decl.substring(colonIndex + 1).trim();
35922
+ if (prop && value) {
35923
+ result[prop] = value;
35924
+ }
35925
+ }
35926
+ return result;
35927
+ }
35569
35928
  function convertToPixels(value) {
35570
35929
  if (typeof value === "number") return value;
35571
35930
  if (!value || typeof value !== "string") return 0;
@@ -35610,9 +35969,13 @@ Please report this to https://github.com/markedjs/marked.`, e) {
35610
35969
  if (textbox) {
35611
35970
  return { type: "shapeContainer", handler: handleShapeTextboxImport };
35612
35971
  }
35972
+ const textpath = shape.elements?.find((el) => el.name === "v:textpath");
35973
+ if (textpath) {
35974
+ return { type: "image", handler: handleShapeTextWatermarkImport };
35975
+ }
35613
35976
  const imagedata = shape.elements?.find((el) => el.name === "v:imagedata");
35614
35977
  if (imagedata) {
35615
- return { type: "image", handler: handleShapeImageImport };
35978
+ return { type: "image", handler: handleShapeImageWatermarkImport };
35616
35979
  }
35617
35980
  }
35618
35981
  return { type: "unknown", handler: null };
@@ -35712,7 +36075,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
35712
36075
  };
35713
36076
  return wrapTextInRun(pict);
35714
36077
  }
35715
- function translateVmlWatermark(params2) {
36078
+ function translateImageWatermark(params2) {
35716
36079
  const { node: node2 } = params2;
35717
36080
  const { attrs } = node2;
35718
36081
  if (attrs.vmlAttributes && attrs.vmlImagedata) {
@@ -35742,7 +36105,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
35742
36105
  };
35743
36106
  return par2;
35744
36107
  }
35745
- const style2 = buildVmlStyle(attrs);
36108
+ const style2 = buildVmlStyle$1(attrs);
35746
36109
  const shape = {
35747
36110
  name: "v:shape",
35748
36111
  attributes: {
@@ -35777,23 +36140,23 @@ Please report this to https://github.com/markedjs/marked.`, e) {
35777
36140
  };
35778
36141
  return par;
35779
36142
  }
35780
- function buildVmlStyle(attrs) {
36143
+ function buildVmlStyle$1(attrs) {
35781
36144
  const styles = [];
35782
36145
  styles.push("position:absolute");
35783
36146
  if (attrs.size) {
35784
36147
  if (attrs.size.width) {
35785
- styles.push(`width:${convertToPt(attrs.size.width)}pt`);
36148
+ styles.push(`width:${convertToPt$1(attrs.size.width)}pt`);
35786
36149
  }
35787
36150
  if (attrs.size.height) {
35788
- styles.push(`height:${convertToPt(attrs.size.height)}pt`);
36151
+ styles.push(`height:${convertToPt$1(attrs.size.height)}pt`);
35789
36152
  }
35790
36153
  }
35791
36154
  if (attrs.marginOffset) {
35792
36155
  if (attrs.marginOffset.horizontal !== void 0) {
35793
- styles.push(`margin-left:${convertToPt(attrs.marginOffset.horizontal)}pt`);
36156
+ styles.push(`margin-left:${convertToPt$1(attrs.marginOffset.horizontal)}pt`);
35794
36157
  }
35795
36158
  if (attrs.marginOffset.top !== void 0) {
35796
- styles.push(`margin-top:${convertToPt(attrs.marginOffset.top)}pt`);
36159
+ styles.push(`margin-top:${convertToPt$1(attrs.marginOffset.top)}pt`);
35797
36160
  }
35798
36161
  }
35799
36162
  if (attrs.wrap?.attrs?.behindDoc) {
@@ -35817,9 +36180,215 @@ Please report this to https://github.com/markedjs/marked.`, e) {
35817
36180
  styles.push("mso-height-percent:0");
35818
36181
  return styles.join(";");
35819
36182
  }
35820
- function convertToPt(pixels) {
36183
+ function convertToPt$1(pixels) {
35821
36184
  return pixels * 72 / 96;
35822
36185
  }
36186
+ function translateTextWatermark(params2) {
36187
+ const { node: node2 } = params2;
36188
+ const { attrs } = node2;
36189
+ const text2 = attrs.textWatermarkData?.text || attrs.vmlTextpathAttributes?.string || "";
36190
+ if (attrs.vmlAttributes && attrs.vmlTextpathAttributes) {
36191
+ const shapeElements2 = [];
36192
+ if (attrs.vmlPathAttributes) {
36193
+ shapeElements2.push({
36194
+ name: "v:path",
36195
+ attributes: attrs.vmlPathAttributes
36196
+ });
36197
+ }
36198
+ shapeElements2.push({
36199
+ name: "v:textpath",
36200
+ attributes: {
36201
+ ...attrs.vmlTextpathAttributes,
36202
+ string: text2
36203
+ }
36204
+ });
36205
+ if (attrs.vmlFillAttributes && Object.keys(attrs.vmlFillAttributes).length > 0) {
36206
+ shapeElements2.push({
36207
+ name: "v:fill",
36208
+ attributes: attrs.vmlFillAttributes
36209
+ });
36210
+ }
36211
+ if (attrs.vmlStrokeAttributes && Object.keys(attrs.vmlStrokeAttributes).length > 0) {
36212
+ shapeElements2.push({
36213
+ name: "v:stroke",
36214
+ attributes: attrs.vmlStrokeAttributes
36215
+ });
36216
+ }
36217
+ if (attrs.vmlWrapAttributes) {
36218
+ shapeElements2.push({
36219
+ name: "w10:wrap",
36220
+ attributes: attrs.vmlWrapAttributes
36221
+ });
36222
+ }
36223
+ const shape2 = {
36224
+ name: "v:shape",
36225
+ attributes: attrs.vmlAttributes,
36226
+ elements: shapeElements2
36227
+ };
36228
+ const pict2 = {
36229
+ name: "w:pict",
36230
+ elements: [shape2]
36231
+ };
36232
+ const par2 = {
36233
+ name: "w:p",
36234
+ elements: [wrapTextInRun(pict2)]
36235
+ };
36236
+ return par2;
36237
+ }
36238
+ const wmData = attrs.textWatermarkData || {};
36239
+ const style2 = buildVmlStyle(attrs, wmData);
36240
+ const textpathStyle = buildTextpathStyle(wmData);
36241
+ const shapeElements = [];
36242
+ shapeElements.push({
36243
+ name: "v:path",
36244
+ attributes: {
36245
+ textpathok: "t"
36246
+ }
36247
+ });
36248
+ shapeElements.push({
36249
+ name: "v:textpath",
36250
+ attributes: {
36251
+ on: "t",
36252
+ fitshape: "t",
36253
+ string: text2,
36254
+ style: textpathStyle,
36255
+ ...wmData.textpath?.trim !== void 0 && { trim: wmData.textpath.trim ? "t" : "f" }
36256
+ }
36257
+ });
36258
+ const fillAttrs = {};
36259
+ const fill = wmData.fill || attrs.fill;
36260
+ if (fill) {
36261
+ if (fill.type) fillAttrs.type = fill.type;
36262
+ if (fill.color2) fillAttrs.color2 = fill.color2;
36263
+ if (fill.opacity !== void 0) fillAttrs.opacity = fill.opacity.toString();
36264
+ if (fill.detectmouseclick !== void 0) {
36265
+ fillAttrs["o:detectmouseclick"] = fill.detectmouseclick ? "t" : "f";
36266
+ }
36267
+ }
36268
+ if (Object.keys(fillAttrs).length > 0) {
36269
+ shapeElements.push({
36270
+ name: "v:fill",
36271
+ attributes: fillAttrs
36272
+ });
36273
+ }
36274
+ const stroke = wmData.stroke || attrs.stroke;
36275
+ if (stroke && stroke.enabled !== false) {
36276
+ const strokeAttrs = {};
36277
+ if (stroke.color) strokeAttrs.color = stroke.color;
36278
+ if (stroke.joinstyle) strokeAttrs.joinstyle = stroke.joinstyle;
36279
+ if (stroke.endcap) strokeAttrs.endcap = stroke.endcap;
36280
+ if (Object.keys(strokeAttrs).length > 0) {
36281
+ shapeElements.push({
36282
+ name: "v:stroke",
36283
+ attributes: strokeAttrs
36284
+ });
36285
+ }
36286
+ }
36287
+ shapeElements.push({
36288
+ name: "w10:wrap",
36289
+ attributes: {
36290
+ type: attrs.wrap?.type?.toLowerCase() || "none"
36291
+ }
36292
+ });
36293
+ const shape = {
36294
+ name: "v:shape",
36295
+ attributes: {
36296
+ id: `PowerPlusWaterMarkObject${generateRandomSigned32BitIntStrId().replace("-", "")}`,
36297
+ "o:spid": `shape_${Math.floor(Math.random() * 1e4)}`,
36298
+ type: "#_x0000_t136",
36299
+ style: style2,
36300
+ fillcolor: fill?.color || "silver",
36301
+ stroked: stroke?.enabled !== false ? "t" : "f",
36302
+ "o:allowincell": "f",
36303
+ ...attrs.vmlAttributes?.adj && { adj: attrs.vmlAttributes.adj }
36304
+ },
36305
+ elements: shapeElements
36306
+ };
36307
+ const pict = {
36308
+ name: "w:pict",
36309
+ elements: [shape]
36310
+ };
36311
+ const par = {
36312
+ name: "w:p",
36313
+ elements: [wrapTextInRun(pict)]
36314
+ };
36315
+ return par;
36316
+ }
36317
+ function buildVmlStyle(attrs, wmData) {
36318
+ const styles = [];
36319
+ styles.push("position:absolute");
36320
+ if (attrs.marginOffset) {
36321
+ if (attrs.marginOffset.horizontal !== void 0) {
36322
+ styles.push(`margin-left:${convertToPt(attrs.marginOffset.horizontal)}pt`);
36323
+ }
36324
+ if (attrs.marginOffset.top !== void 0) {
36325
+ styles.push(`margin-top:${convertToPt(attrs.marginOffset.top)}pt`);
36326
+ }
36327
+ } else {
36328
+ styles.push("margin-left:0.05pt");
36329
+ styles.push("margin-top:315.7pt");
36330
+ }
36331
+ if (attrs.size) {
36332
+ if (attrs.size.width) {
36333
+ styles.push(`width:${convertToPt(attrs.size.width)}pt`);
36334
+ }
36335
+ if (attrs.size.height) {
36336
+ styles.push(`height:${convertToPt(attrs.size.height)}pt`);
36337
+ }
36338
+ }
36339
+ const wrapType = attrs.wrap?.type;
36340
+ let msoWrapStyle = "none";
36341
+ if (wrapType) {
36342
+ const wrapTypeLower = wrapType.toLowerCase();
36343
+ if (wrapTypeLower === "topandbottom") {
36344
+ msoWrapStyle = "top-and-bottom";
36345
+ } else if (["square", "tight", "through"].includes(wrapTypeLower)) {
36346
+ msoWrapStyle = wrapTypeLower;
36347
+ }
36348
+ }
36349
+ styles.push(`mso-wrap-style:${msoWrapStyle}`);
36350
+ const textAnchor = wmData.textStyle?.textAnchor || attrs.textStyle?.textAnchor;
36351
+ if (textAnchor) {
36352
+ styles.push(`v-text-anchor:${textAnchor}`);
36353
+ }
36354
+ const rotation = wmData.rotation || attrs.rotation;
36355
+ if (rotation !== void 0 && rotation !== 0) {
36356
+ styles.push(`rotation:${rotation}`);
36357
+ }
36358
+ if (attrs.anchorData) {
36359
+ if (attrs.anchorData.alignH) {
36360
+ styles.push(`mso-position-horizontal:${attrs.anchorData.alignH}`);
36361
+ }
36362
+ if (attrs.anchorData.alignV) {
36363
+ styles.push(`mso-position-vertical:${attrs.anchorData.alignV}`);
36364
+ }
36365
+ if (attrs.anchorData.hRelativeFrom) {
36366
+ styles.push(`mso-position-horizontal-relative:${attrs.anchorData.hRelativeFrom}`);
36367
+ }
36368
+ if (attrs.anchorData.vRelativeFrom) {
36369
+ styles.push(`mso-position-vertical-relative:${attrs.anchorData.vRelativeFrom}`);
36370
+ }
36371
+ }
36372
+ return styles.join(";");
36373
+ }
36374
+ function buildTextpathStyle(wmData) {
36375
+ const styles = [];
36376
+ if (wmData.textStyle) {
36377
+ if (wmData.textStyle.fontFamily) {
36378
+ styles.push(`font-family:"${wmData.textStyle.fontFamily}"`);
36379
+ }
36380
+ if (wmData.textStyle.fontSize) {
36381
+ styles.push(`font-size:${wmData.textStyle.fontSize}`);
36382
+ }
36383
+ }
36384
+ return styles.join(";");
36385
+ }
36386
+ function convertToPt(pixels) {
36387
+ if (typeof pixels === "number") {
36388
+ return pixels * 72 / 96;
36389
+ }
36390
+ return parseFloat(pixels) || 0;
36391
+ }
35823
36392
  const XML_NODE_NAME = "w:pict";
35824
36393
  const SD_NODE_NAME = ["shapeContainer", "contentBlock", "image"];
35825
36394
  const validXmlAttributes = [];
@@ -35847,7 +36416,10 @@ Please report this to https://github.com/markedjs/marked.`, e) {
35847
36416
  contentBlock: () => translateContentBlock(params2),
35848
36417
  image: () => {
35849
36418
  if (node2.attrs?.vmlWatermark) {
35850
- return translateVmlWatermark(params2);
36419
+ if (node2.attrs?.vmlTextWatermark) {
36420
+ return translateTextWatermark(params2);
36421
+ }
36422
+ return translateImageWatermark(params2);
35851
36423
  }
35852
36424
  return null;
35853
36425
  },
@@ -36992,7 +37564,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
36992
37564
  static getStoredSuperdocVersion(docx) {
36993
37565
  return SuperConverter.getStoredCustomProperty(docx, "SuperdocVersion");
36994
37566
  }
36995
- static setStoredSuperdocVersion(docx = this.convertedXml, version2 = "1.5.0-next.5") {
37567
+ static setStoredSuperdocVersion(docx = this.convertedXml, version2 = "1.5.0-next.7") {
36996
37568
  return SuperConverter.setStoredCustomProperty(docx, "SuperdocVersion", version2, false);
36997
37569
  }
36998
37570
  /**
@@ -62875,7 +63447,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
62875
63447
  return false;
62876
63448
  }
62877
63449
  };
62878
- const summaryVersion = "1.5.0-next.5";
63450
+ const summaryVersion = "1.5.0-next.7";
62879
63451
  const nodeKeys = ["group", "content", "marks", "inline", "atom", "defining", "code", "tableRole", "summary"];
62880
63452
  const markKeys = ["group", "inclusive", "excludes", "spanning", "code"];
62881
63453
  function mapAttributes(attrs) {
@@ -65533,7 +66105,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
65533
66105
  * Process collaboration migrations
65534
66106
  */
65535
66107
  processCollaborationMigrations() {
65536
- console.debug("[checkVersionMigrations] Current editor version", "1.5.0-next.5");
66108
+ console.debug("[checkVersionMigrations] Current editor version", "1.5.0-next.7");
65537
66109
  if (!this.options.ydoc) return;
65538
66110
  const metaMap = this.options.ydoc.getMap("meta");
65539
66111
  let docVersion = metaMap.get("version");
@@ -91008,7 +91580,14 @@ ${o}
91008
91580
  definitions: {},
91009
91581
  abstracts: {}
91010
91582
  };
91011
- const ooxmlResolver = createOoxmlResolver({ pPr: translator$14, rPr: translator$1O });
91583
+ const toOoxmlTranslator = (translator2) => ({
91584
+ xmlName: translator2.xmlName,
91585
+ encode: (params2) => translator2.encode(params2)
91586
+ });
91587
+ const ooxmlResolver = createOoxmlResolver({
91588
+ pPr: toOoxmlTranslator(translator$14),
91589
+ rPr: toOoxmlTranslator(translator$1O)
91590
+ });
91012
91591
  const hydrateParagraphStyleAttrs = (para, context, preResolved) => {
91013
91592
  if (!hasParagraphStyleContext(context)) {
91014
91593
  return null;
@@ -146937,7 +147516,7 @@ ${reason}`);
146937
147516
  this.config.colors = shuffleArray(this.config.colors);
146938
147517
  this.userColorMap = /* @__PURE__ */ new Map();
146939
147518
  this.colorIndex = 0;
146940
- this.version = "1.5.0-next.5";
147519
+ this.version = "1.5.0-next.7";
146941
147520
  this.#log("🦋 [superdoc] Using SuperDoc version:", this.version);
146942
147521
  this.superdocId = config2.superdocId || v4();
146943
147522
  this.colors = this.config.colors;