docgen-utils 1.0.9 → 1.0.10
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/bundle.js +1282 -124
- package/dist/bundle.min.js +82 -80
- package/dist/cli.js +322 -29
- package/dist/packages/docs/convert.d.ts.map +1 -1
- package/dist/packages/docs/convert.js +18 -2
- package/dist/packages/docs/convert.js.map +1 -1
- package/dist/packages/slides/common.d.ts +17 -0
- package/dist/packages/slides/common.d.ts.map +1 -1
- package/dist/packages/slides/convert.d.ts +5 -2
- package/dist/packages/slides/convert.d.ts.map +1 -1
- package/dist/packages/slides/convert.js +122 -28
- package/dist/packages/slides/convert.js.map +1 -1
- package/dist/packages/slides/createPresentation.d.ts.map +1 -1
- package/dist/packages/slides/createPresentation.js +18 -1
- package/dist/packages/slides/createPresentation.js.map +1 -1
- package/dist/packages/slides/import-pptx.d.ts.map +1 -1
- package/dist/packages/slides/import-pptx.js +388 -25
- package/dist/packages/slides/import-pptx.js.map +1 -1
- package/dist/packages/slides/parse.d.ts.map +1 -1
- package/dist/packages/slides/parse.js +1103 -89
- package/dist/packages/slides/parse.js.map +1 -1
- package/dist/packages/slides/transform.d.ts.map +1 -1
- package/dist/packages/slides/transform.js +60 -10
- package/dist/packages/slides/transform.js.map +1 -1
- package/package.json +9 -4
package/dist/cli.js
CHANGED
|
@@ -22587,6 +22587,108 @@ var import_jszip2 = __toESM(require_lib4(), 1);
|
|
|
22587
22587
|
var TARGET_WIDTH = 1280;
|
|
22588
22588
|
var TARGET_HEIGHT = 720;
|
|
22589
22589
|
var EMU_PER_PX2 = 914400 / 96;
|
|
22590
|
+
var FONT_FALLBACK_MAP = {
|
|
22591
|
+
// Microsoft Office fonts → metrically compatible open-source alternatives
|
|
22592
|
+
"Calibri": "'Calibri','Carlito','Helvetica Neue',Helvetica,Arial,sans-serif",
|
|
22593
|
+
"Calibri Light": "'Calibri Light','Carlito','Helvetica Neue Light','Helvetica Neue',Arial,sans-serif",
|
|
22594
|
+
"Cambria": "'Cambria','Caladea','Times New Roman',Georgia,serif",
|
|
22595
|
+
"Cambria Math": "'Cambria Math','Caladea','Times New Roman',serif",
|
|
22596
|
+
"Consolas": "'Consolas','Courier New',monospace",
|
|
22597
|
+
"Aptos": "'Aptos','Carlito','Helvetica Neue',Arial,sans-serif",
|
|
22598
|
+
"Times New Roman": "'Times New Roman','Liberation Serif',Georgia,serif",
|
|
22599
|
+
// Handwriting / decorative fonts
|
|
22600
|
+
"MV Boli": "'MV Boli','Comic Sans MS','Marker Felt',cursive",
|
|
22601
|
+
"Kristen ITC": "'Kristen ITC','Comic Sans MS','Marker Felt',cursive",
|
|
22602
|
+
"Stylus BT": "'Stylus BT','Brush Script MT','Snell Roundhand',cursive",
|
|
22603
|
+
// Japanese sans-serif fonts → Noto Sans CJK JP (commonly installed)
|
|
22604
|
+
"MS Gothic": "'MS Gothic','Noto Sans CJK JP','Hiragino Kaku Gothic ProN','Yu Gothic',sans-serif",
|
|
22605
|
+
"MS PGothic": "'MS PGothic','Noto Sans CJK JP','Hiragino Kaku Gothic ProN','Yu Gothic',sans-serif",
|
|
22606
|
+
"\uFF2D\uFF33 \uFF30\u30B4\u30B7\u30C3\u30AF": "'\uFF2D\uFF33 \uFF30\u30B4\u30B7\u30C3\u30AF','Noto Sans CJK JP','Hiragino Kaku Gothic ProN','Yu Gothic',sans-serif",
|
|
22607
|
+
"\uFF2D\uFF33 \u30B4\u30B7\u30C3\u30AF": "'\uFF2D\uFF33 \u30B4\u30B7\u30C3\u30AF','Noto Sans CJK JP','Hiragino Kaku Gothic ProN','Yu Gothic',sans-serif",
|
|
22608
|
+
"Kozuka Gothic Pro R": "'Kozuka Gothic Pro R','Noto Sans CJK JP','Hiragino Kaku Gothic ProN',sans-serif",
|
|
22609
|
+
"Kozuka Gothic Pro B": "'Kozuka Gothic Pro B','Noto Sans CJK JP Bold','Hiragino Kaku Gothic ProN',sans-serif",
|
|
22610
|
+
"Kozuka Gothic Pro M": "'Kozuka Gothic Pro M','Noto Sans CJK JP Medium','Hiragino Kaku Gothic ProN',sans-serif",
|
|
22611
|
+
"Kozuka Gothic Pro EL": "'Kozuka Gothic Pro EL','Noto Sans CJK JP Light','Hiragino Kaku Gothic ProN',sans-serif",
|
|
22612
|
+
"HGSKyokashotai": "'HGSKyokashotai','Noto Sans CJK JP','Hiragino Kaku Gothic ProN',sans-serif",
|
|
22613
|
+
// Japanese serif fonts → Noto Serif CJK JP
|
|
22614
|
+
"MS Mincho": "'MS Mincho','Noto Serif CJK JP','Hiragino Mincho ProN','Yu Mincho',serif",
|
|
22615
|
+
"MS PMincho": "'MS PMincho','Noto Serif CJK JP','Hiragino Mincho ProN','Yu Mincho',serif",
|
|
22616
|
+
// CJK fonts
|
|
22617
|
+
"\u5B8B\u4F53": "'\u5B8B\u4F53','Noto Serif CJK SC','Songti SC','STSong',serif",
|
|
22618
|
+
"\u65B0\u7D30\u660E\u9AD4": "'\u65B0\u7D30\u660E\u9AD4','Noto Serif CJK TC','Songti TC',serif",
|
|
22619
|
+
"\u9ED1\u4F53": "'\u9ED1\u4F53','Noto Sans CJK SC','Heiti SC','STHeiti',sans-serif",
|
|
22620
|
+
"\u5FAE\u8EDF\u6B63\u9ED1\u9AD4": "'\u5FAE\u8EDF\u6B63\u9ED1\u9AD4','Noto Sans CJK TC','Heiti TC',sans-serif",
|
|
22621
|
+
"\uB9D1\uC740 \uACE0\uB515": "'\uB9D1\uC740 \uACE0\uB515','Apple SD Gothic Neo',sans-serif",
|
|
22622
|
+
// UI / system fonts
|
|
22623
|
+
"Lucida Sans Unicode": "'Lucida Sans Unicode','Lucida Grande','Lucida Sans',sans-serif",
|
|
22624
|
+
"Segoe UI": "'Segoe UI','-apple-system','Helvetica Neue',sans-serif",
|
|
22625
|
+
"Segoe Sans Display": "'Segoe Sans Display','-apple-system','Helvetica Neue',Arial,sans-serif",
|
|
22626
|
+
"Segoe Sans Display Semibold": "'Segoe Sans Display Semibold','-apple-system','Helvetica Neue',Arial,sans-serif",
|
|
22627
|
+
// Google Fonts / web fonts commonly used in presentations
|
|
22628
|
+
"Inter": "'Inter','Helvetica Neue',Helvetica,Arial,sans-serif",
|
|
22629
|
+
"Inter Light": "'Inter Light','Inter','Helvetica Neue',Arial,sans-serif",
|
|
22630
|
+
"Inter ExtraBold": "'Inter ExtraBold','Inter','Helvetica Neue',Arial,sans-serif",
|
|
22631
|
+
"Space Grotesk": "'Space Grotesk','Helvetica Neue',Helvetica,Arial,sans-serif",
|
|
22632
|
+
"Montserrat": "'Montserrat','Helvetica Neue',Helvetica,Arial,sans-serif",
|
|
22633
|
+
"Open Sans": "'Open Sans','Helvetica Neue',Helvetica,Arial,sans-serif",
|
|
22634
|
+
"Lato": "'Lato','Helvetica Neue',Helvetica,Arial,sans-serif",
|
|
22635
|
+
"Oswald": "'Oswald','Helvetica Neue',Helvetica,Arial,sans-serif",
|
|
22636
|
+
"Archivo": "'Archivo','Helvetica Neue',Helvetica,Arial,sans-serif",
|
|
22637
|
+
"Economica": "'Economica','Helvetica Neue',Arial,sans-serif",
|
|
22638
|
+
"Libre Baskerville": "'Libre Baskerville','Georgia','Times New Roman',serif",
|
|
22639
|
+
// GitHub Copilot fonts
|
|
22640
|
+
"Ginto Copilot": "'Ginto Copilot','Helvetica Neue',Helvetica,Arial,sans-serif",
|
|
22641
|
+
"Ginto Copilot Light": "'Ginto Copilot Light','Helvetica Neue Light','Helvetica Neue',Arial,sans-serif",
|
|
22642
|
+
"Ginto Copilot 400": "'Ginto Copilot 400','Helvetica Neue',Helvetica,Arial,sans-serif",
|
|
22643
|
+
// Google Fonts / decorative (serif & display)
|
|
22644
|
+
"Playfair Display": "'Playfair Display','Georgia','Times New Roman',serif",
|
|
22645
|
+
"Playfair Display SemiBold": "'Playfair Display SemiBold','Playfair Display','Georgia',serif",
|
|
22646
|
+
"Caveat": "'Caveat','Comic Sans MS','Marker Felt',cursive",
|
|
22647
|
+
"Syncopate": "'Syncopate','Helvetica Neue',Helvetica,Arial,sans-serif",
|
|
22648
|
+
// Montserrat weight variants
|
|
22649
|
+
"Montserrat SemiBold": "'Montserrat SemiBold','Montserrat','Helvetica Neue',Arial,sans-serif",
|
|
22650
|
+
"Montserrat ExtraBold": "'Montserrat ExtraBold','Montserrat','Helvetica Neue',Arial,sans-serif",
|
|
22651
|
+
// GitHub Copilot font variants
|
|
22652
|
+
"Ginto Copilot Medium": "'Ginto Copilot Medium','Ginto Copilot','Helvetica Neue',Arial,sans-serif",
|
|
22653
|
+
"Ginto Copilot Black": "'Ginto Copilot Black','Ginto Copilot','Helvetica Neue',Arial,sans-serif",
|
|
22654
|
+
"Ginto Copilot Thin": "'Ginto Copilot Thin','Ginto Copilot Light','Helvetica Neue',Arial,sans-serif",
|
|
22655
|
+
// Microsoft UI fonts
|
|
22656
|
+
"Segoe Sans Small Regular": "'Segoe Sans Small Regular','Segoe UI','-apple-system','Helvetica Neue',sans-serif",
|
|
22657
|
+
"Segoe Sans Text Regular": "'Segoe Sans Text Regular','Segoe UI','-apple-system','Helvetica Neue',sans-serif",
|
|
22658
|
+
"Grandview": "'Grandview','Helvetica Neue',Arial,sans-serif",
|
|
22659
|
+
"Nirmala UI": "'Nirmala UI','Helvetica Neue',Arial,sans-serif",
|
|
22660
|
+
"Ebrima": "'Ebrima','Helvetica Neue',Arial,sans-serif",
|
|
22661
|
+
// Common system fonts with fallbacks
|
|
22662
|
+
"Arial": "Arial,'Helvetica Neue',Helvetica,sans-serif",
|
|
22663
|
+
"Arial Black": "'Arial Black','Helvetica Neue',Helvetica,Arial,sans-serif",
|
|
22664
|
+
"Georgia": "Georgia,'Times New Roman',serif",
|
|
22665
|
+
"Georgia Regular": "'Georgia Regular',Georgia,'Times New Roman',serif",
|
|
22666
|
+
"Courier New": "'Courier New',Courier,monospace",
|
|
22667
|
+
"Times": "Times,'Times New Roman',serif",
|
|
22668
|
+
// Symbol fonts (preserved as-is with system fallback)
|
|
22669
|
+
"Wingdings": "'Wingdings','Zapf Dingbats',sans-serif",
|
|
22670
|
+
"Wingdings 2": "'Wingdings 2','Zapf Dingbats',sans-serif",
|
|
22671
|
+
"Wingdings 3": "'Wingdings 3','Zapf Dingbats',sans-serif",
|
|
22672
|
+
// Common fallbacks
|
|
22673
|
+
"Tahoma": "'Tahoma','Verdana','Geneva',sans-serif",
|
|
22674
|
+
"Verdana": "'Verdana','Geneva',sans-serif",
|
|
22675
|
+
"Helvetica Neue Light": "'Helvetica Neue Light','Helvetica Neue',Helvetica,Arial,sans-serif"
|
|
22676
|
+
};
|
|
22677
|
+
function cssFontFamily(fontName) {
|
|
22678
|
+
const mapped = FONT_FALLBACK_MAP[fontName];
|
|
22679
|
+
if (mapped) return mapped;
|
|
22680
|
+
if (fontName.includes(",")) {
|
|
22681
|
+
return fontName.split(",").map((f) => {
|
|
22682
|
+
const trimmed = f.trim();
|
|
22683
|
+
const lower = trimmed.toLowerCase();
|
|
22684
|
+
if (lower === "sans-serif" || lower === "serif" || lower === "monospace" || lower === "cursive" || lower === "fantasy") {
|
|
22685
|
+
return lower;
|
|
22686
|
+
}
|
|
22687
|
+
return `'${trimmed}'`;
|
|
22688
|
+
}).join(",");
|
|
22689
|
+
}
|
|
22690
|
+
return `'${fontName}',sans-serif`;
|
|
22691
|
+
}
|
|
22590
22692
|
function emuToPx2(emu) {
|
|
22591
22693
|
return emu / EMU_PER_PX2;
|
|
22592
22694
|
}
|
|
@@ -22660,6 +22762,20 @@ function extractGradientFill(parent, themeColors) {
|
|
|
22660
22762
|
if (color) stops.push({ pos, color });
|
|
22661
22763
|
}
|
|
22662
22764
|
if (stops.length === 0) return void 0;
|
|
22765
|
+
const pathEl = findChild2(gradFill, "path");
|
|
22766
|
+
if (pathEl && pathEl.getAttribute("path") === "circle") {
|
|
22767
|
+
const fillToRect = findChild2(pathEl, "fillToRect");
|
|
22768
|
+
let centerX = 50;
|
|
22769
|
+
let centerY = 50;
|
|
22770
|
+
if (fillToRect) {
|
|
22771
|
+
const l = parseInt(fillToRect.getAttribute("l") ?? "50000", 10) / 1e3;
|
|
22772
|
+
const t = parseInt(fillToRect.getAttribute("t") ?? "50000", 10) / 1e3;
|
|
22773
|
+
centerX = l;
|
|
22774
|
+
centerY = t;
|
|
22775
|
+
}
|
|
22776
|
+
const stopStr2 = stops.map((s) => `${s.color} ${s.pos}%`).join(",");
|
|
22777
|
+
return `radial-gradient(ellipse at ${centerX}% ${centerY}%,${stopStr2})`;
|
|
22778
|
+
}
|
|
22663
22779
|
const lin = findChild2(gradFill, "lin");
|
|
22664
22780
|
const angAttr = lin?.getAttribute("ang");
|
|
22665
22781
|
const cssDeg = angAttr ? ooxmlAngleToCss(parseInt(angAttr, 10)) : 180;
|
|
@@ -22685,11 +22801,68 @@ function extractRunProps(rPr, scale, themeColors) {
|
|
|
22685
22801
|
const color = resolveColor2(solidFill, themeColors);
|
|
22686
22802
|
if (color) result.color = color;
|
|
22687
22803
|
}
|
|
22804
|
+
if (!result.color) {
|
|
22805
|
+
const gradFill = findChild2(rPr, "gradFill");
|
|
22806
|
+
if (gradFill) {
|
|
22807
|
+
const gsLst = findChild2(gradFill, "gsLst");
|
|
22808
|
+
if (gsLst) {
|
|
22809
|
+
const gsEls = findChildren2(gsLst, "gs");
|
|
22810
|
+
if (gsEls.length > 0) {
|
|
22811
|
+
const stops = [];
|
|
22812
|
+
for (const gs of gsEls) {
|
|
22813
|
+
const pos = parseInt(gs.getAttribute("pos") ?? "0", 10) / 1e3;
|
|
22814
|
+
const color = resolveColor2(gs, themeColors);
|
|
22815
|
+
if (color) stops.push({ pos, color });
|
|
22816
|
+
}
|
|
22817
|
+
if (stops.length >= 2) {
|
|
22818
|
+
const lin = findChild2(gradFill, "lin");
|
|
22819
|
+
const angAttr = lin?.getAttribute("ang");
|
|
22820
|
+
const cssDeg = angAttr ? ooxmlAngleToCss(parseInt(angAttr, 10)) : 135;
|
|
22821
|
+
const stopStr = stops.map((s) => `${s.color} ${s.pos}%`).join(",");
|
|
22822
|
+
result.gradientFill = `linear-gradient(${cssDeg}deg,${stopStr})`;
|
|
22823
|
+
}
|
|
22824
|
+
const firstColor = resolveColor2(gsEls[0], themeColors);
|
|
22825
|
+
if (firstColor) result.color = firstColor;
|
|
22826
|
+
}
|
|
22827
|
+
}
|
|
22828
|
+
}
|
|
22829
|
+
}
|
|
22688
22830
|
const latin = findChild2(rPr, "latin");
|
|
22689
22831
|
if (latin) {
|
|
22690
22832
|
const typeface = latin.getAttribute("typeface");
|
|
22691
22833
|
if (typeface) result.fontFamily = typeface;
|
|
22692
22834
|
}
|
|
22835
|
+
const effectLst = findChild2(rPr, "effectLst");
|
|
22836
|
+
if (effectLst) {
|
|
22837
|
+
const glow = findChild2(effectLst, "glow");
|
|
22838
|
+
if (glow) {
|
|
22839
|
+
const radAttr = glow.getAttribute("rad");
|
|
22840
|
+
const radiusEmu = radAttr ? parseInt(radAttr, 10) : 0;
|
|
22841
|
+
const radiusPx = Math.round(emuToPx2(radiusEmu) * scale);
|
|
22842
|
+
const glowColor = resolveColor2(glow, themeColors);
|
|
22843
|
+
if (glowColor && radiusPx > 0) {
|
|
22844
|
+
const INVERSE_GLOW_SIZE_SCALE = 0.4;
|
|
22845
|
+
const INVERSE_GLOW_OPACITY_SCALE = 3.33;
|
|
22846
|
+
const cssRadius = Math.round(radiusPx * INVERSE_GLOW_SIZE_SCALE);
|
|
22847
|
+
const rgbaMatch = glowColor.match(/rgba?\((\d+),(\d+),(\d+)(?:,([0-9.]+))?\)/);
|
|
22848
|
+
if (rgbaMatch) {
|
|
22849
|
+
const r = rgbaMatch[1];
|
|
22850
|
+
const g = rgbaMatch[2];
|
|
22851
|
+
const b2 = rgbaMatch[3];
|
|
22852
|
+
const originalAlpha = rgbaMatch[4] ? parseFloat(rgbaMatch[4]) : 1;
|
|
22853
|
+
const scaledAlpha = Math.min(originalAlpha * INVERSE_GLOW_OPACITY_SCALE, 1);
|
|
22854
|
+
result.textShadow = `0 0 ${cssRadius}px rgba(${r},${g},${b2},${scaledAlpha.toFixed(2)})`;
|
|
22855
|
+
} else if (glowColor.startsWith("#")) {
|
|
22856
|
+
const r = parseInt(glowColor.slice(1, 3), 16);
|
|
22857
|
+
const g = parseInt(glowColor.slice(3, 5), 16);
|
|
22858
|
+
const b2 = parseInt(glowColor.slice(5, 7), 16);
|
|
22859
|
+
result.textShadow = `0 0 ${cssRadius}px rgba(${r},${g},${b2},1)`;
|
|
22860
|
+
} else {
|
|
22861
|
+
result.textShadow = `0 0 ${cssRadius}px ${glowColor}`;
|
|
22862
|
+
}
|
|
22863
|
+
}
|
|
22864
|
+
}
|
|
22865
|
+
}
|
|
22693
22866
|
return result;
|
|
22694
22867
|
}
|
|
22695
22868
|
function parseShape(sp, scale, themeColors) {
|
|
@@ -22711,13 +22884,16 @@ function parseShape(sp, scale, themeColors) {
|
|
|
22711
22884
|
paragraphs: []
|
|
22712
22885
|
};
|
|
22713
22886
|
const prstGeom = findChild2(spPr, "prstGeom");
|
|
22714
|
-
|
|
22887
|
+
const prstType = prstGeom?.getAttribute("prst");
|
|
22888
|
+
if (prstType === "roundRect" && prstGeom) {
|
|
22715
22889
|
const avLst = findChild2(prstGeom, "avLst");
|
|
22716
22890
|
const gd = avLst ? findChild2(avLst, "gd") : null;
|
|
22717
22891
|
const adjVal = gd ? parseInt(gd.getAttribute("fmla")?.replace("val ", "") ?? "16667", 10) : 16667;
|
|
22718
22892
|
const minDim = Math.min(wEmu, hEmu);
|
|
22719
22893
|
const radiusEmu = minDim * Math.min(adjVal, 5e4) / 1e5;
|
|
22720
22894
|
shape.borderRadius = Math.round(emuToPx2(radiusEmu) * scale);
|
|
22895
|
+
} else if (prstType === "ellipse") {
|
|
22896
|
+
shape.isEllipse = true;
|
|
22721
22897
|
}
|
|
22722
22898
|
const ln = findChild2(spPr, "ln");
|
|
22723
22899
|
if (ln) {
|
|
@@ -22731,6 +22907,13 @@ function parseShape(sp, scale, themeColors) {
|
|
|
22731
22907
|
if (lnFill) {
|
|
22732
22908
|
shape.borderColor = resolveColor2(lnFill, themeColors);
|
|
22733
22909
|
}
|
|
22910
|
+
const prstDash = findChild2(ln, "prstDash");
|
|
22911
|
+
if (prstDash) {
|
|
22912
|
+
const dashVal = prstDash.getAttribute("val");
|
|
22913
|
+
if (dashVal && dashVal !== "solid") {
|
|
22914
|
+
shape.borderDashType = dashVal;
|
|
22915
|
+
}
|
|
22916
|
+
}
|
|
22734
22917
|
}
|
|
22735
22918
|
}
|
|
22736
22919
|
const txBody = findChild2(sp, "txBody");
|
|
@@ -22799,21 +22982,33 @@ function parseShape(sp, scale, themeColors) {
|
|
|
22799
22982
|
para.bulletChar = buChar.getAttribute("char") ?? void 0;
|
|
22800
22983
|
}
|
|
22801
22984
|
}
|
|
22802
|
-
const
|
|
22803
|
-
|
|
22804
|
-
const
|
|
22805
|
-
const
|
|
22806
|
-
|
|
22807
|
-
|
|
22808
|
-
|
|
22809
|
-
|
|
22810
|
-
|
|
22811
|
-
|
|
22812
|
-
|
|
22813
|
-
|
|
22814
|
-
|
|
22815
|
-
|
|
22816
|
-
|
|
22985
|
+
for (const child of Array.from(p.childNodes)) {
|
|
22986
|
+
if (child.nodeType !== 1) continue;
|
|
22987
|
+
const el = child;
|
|
22988
|
+
const localName = el.localName || el.nodeName.split(":").pop();
|
|
22989
|
+
if (localName === "r") {
|
|
22990
|
+
const rPr = findChild2(el, "rPr");
|
|
22991
|
+
const props = extractRunProps(rPr, scale, themeColors);
|
|
22992
|
+
const tEls = findChildren2(el, "t");
|
|
22993
|
+
const text = tEls.map((t) => t.textContent ?? "").join("");
|
|
22994
|
+
if (text) {
|
|
22995
|
+
para.runs.push({
|
|
22996
|
+
text,
|
|
22997
|
+
bold: props.bold ?? defaults?.bold,
|
|
22998
|
+
italic: props.italic ?? defaults?.italic,
|
|
22999
|
+
fontSize: props.fontSize ?? defaults?.fontSize,
|
|
23000
|
+
color: props.color ?? defaults?.color,
|
|
23001
|
+
fontFamily: props.fontFamily ?? defaults?.fontFamily,
|
|
23002
|
+
textShadow: props.textShadow ?? defaults?.textShadow,
|
|
23003
|
+
gradientFill: props.gradientFill ?? defaults?.gradientFill
|
|
23004
|
+
});
|
|
23005
|
+
}
|
|
23006
|
+
} else if (localName === "br") {
|
|
23007
|
+
if (para.runs.length > 0) {
|
|
23008
|
+
para.runs[para.runs.length - 1].text += "\n";
|
|
23009
|
+
} else {
|
|
23010
|
+
para.runs.push({ text: "\n" });
|
|
23011
|
+
}
|
|
22817
23012
|
}
|
|
22818
23013
|
}
|
|
22819
23014
|
if (para.runs.length > 0) {
|
|
@@ -22835,23 +23030,68 @@ function parsePicture(pic, scale, imageMap) {
|
|
|
22835
23030
|
if (!blipFill) return null;
|
|
22836
23031
|
const blip = findChild2(blipFill, "blip");
|
|
22837
23032
|
if (!blip) return null;
|
|
22838
|
-
|
|
22839
|
-
|
|
22840
|
-
|
|
22841
|
-
|
|
23033
|
+
let rEmbed = null;
|
|
23034
|
+
const extLst = findChild2(blip, "extLst");
|
|
23035
|
+
if (extLst) {
|
|
23036
|
+
for (let i = 0; i < extLst.children.length; i++) {
|
|
23037
|
+
const ext2 = extLst.children[i];
|
|
23038
|
+
if (ext2.localName === "ext") {
|
|
23039
|
+
for (let j = 0; j < ext2.children.length; j++) {
|
|
23040
|
+
const child = ext2.children[j];
|
|
23041
|
+
if (child.localName === "svgBlip") {
|
|
23042
|
+
rEmbed = child.getAttribute("r:embed") ?? child.getAttributeNS(
|
|
23043
|
+
"http://schemas.openxmlformats.org/officeDocument/2006/relationships",
|
|
23044
|
+
"embed"
|
|
23045
|
+
);
|
|
23046
|
+
break;
|
|
23047
|
+
}
|
|
23048
|
+
}
|
|
23049
|
+
if (rEmbed) break;
|
|
23050
|
+
}
|
|
23051
|
+
}
|
|
23052
|
+
}
|
|
23053
|
+
if (!rEmbed) {
|
|
23054
|
+
rEmbed = blip.getAttribute("r:embed") ?? blip.getAttributeNS(
|
|
23055
|
+
"http://schemas.openxmlformats.org/officeDocument/2006/relationships",
|
|
23056
|
+
"embed"
|
|
23057
|
+
);
|
|
23058
|
+
}
|
|
22842
23059
|
if (!rEmbed) return null;
|
|
22843
23060
|
const dataUri = imageMap.get(rEmbed);
|
|
22844
23061
|
if (!dataUri) return null;
|
|
22845
23062
|
const nvPicPr = findChild2(pic, "nvPicPr");
|
|
22846
23063
|
const cNvPr = nvPicPr ? findChild2(nvPicPr, "cNvPr") : null;
|
|
22847
23064
|
const alt = cNvPr?.getAttribute("descr") ?? void 0;
|
|
23065
|
+
const srcRect = findChild2(blipFill, "srcRect");
|
|
23066
|
+
let hasCrop = false;
|
|
23067
|
+
if (srcRect) {
|
|
23068
|
+
const l = parseInt(srcRect.getAttribute("l") ?? "0", 10);
|
|
23069
|
+
const r = parseInt(srcRect.getAttribute("r") ?? "0", 10);
|
|
23070
|
+
const t = parseInt(srcRect.getAttribute("t") ?? "0", 10);
|
|
23071
|
+
const b = parseInt(srcRect.getAttribute("b") ?? "0", 10);
|
|
23072
|
+
hasCrop = l > 0 || r > 0 || t > 0 || b > 0;
|
|
23073
|
+
}
|
|
23074
|
+
let borderRadius;
|
|
23075
|
+
const prstGeom = findChild2(spPr, "prstGeom");
|
|
23076
|
+
if (prstGeom?.getAttribute("prst") === "roundRect") {
|
|
23077
|
+
const avLst = findChild2(prstGeom, "avLst");
|
|
23078
|
+
const gd = avLst ? findChild2(avLst, "gd") : null;
|
|
23079
|
+
const adjVal = gd ? parseInt(gd.getAttribute("fmla")?.replace("val ", "") ?? "16667", 10) : 16667;
|
|
23080
|
+
const wEmu = parseInt(ext.getAttribute("cx") ?? "0", 10);
|
|
23081
|
+
const hEmu = parseInt(ext.getAttribute("cy") ?? "0", 10);
|
|
23082
|
+
const minDim = Math.min(wEmu, hEmu);
|
|
23083
|
+
const radiusEmu = minDim * Math.min(adjVal, 5e4) / 1e5;
|
|
23084
|
+
borderRadius = Math.round(emuToPx2(radiusEmu) * scale);
|
|
23085
|
+
}
|
|
22848
23086
|
return {
|
|
22849
23087
|
x: Math.round(emuToPx2(parseInt(off.getAttribute("x") ?? "0", 10)) * scale),
|
|
22850
23088
|
y: Math.round(emuToPx2(parseInt(off.getAttribute("y") ?? "0", 10)) * scale),
|
|
22851
23089
|
w: Math.round(emuToPx2(parseInt(ext.getAttribute("cx") ?? "0", 10)) * scale),
|
|
22852
23090
|
h: Math.round(emuToPx2(parseInt(ext.getAttribute("cy") ?? "0", 10)) * scale),
|
|
22853
23091
|
dataUri,
|
|
22854
|
-
alt
|
|
23092
|
+
alt,
|
|
23093
|
+
borderRadius,
|
|
23094
|
+
hasCrop
|
|
22855
23095
|
};
|
|
22856
23096
|
}
|
|
22857
23097
|
function renderSlideHtml(elements, bgColor) {
|
|
@@ -22861,14 +23101,20 @@ function renderSlideHtml(elements, bgColor) {
|
|
|
22861
23101
|
const elId = `el-${elementIndex++}`;
|
|
22862
23102
|
if (el.kind === "image") {
|
|
22863
23103
|
const img = el.data;
|
|
22864
|
-
const
|
|
23104
|
+
const isFullbleed = img.x <= 10 && img.y <= 10 && img.w >= TARGET_WIDTH - 20 && img.h >= TARGET_HEIGHT - 20;
|
|
23105
|
+
const objectFit = isFullbleed || img.hasCrop ? "cover" : "contain";
|
|
23106
|
+
const stylesList = [
|
|
22865
23107
|
"position:absolute",
|
|
22866
23108
|
`left:${img.x}px`,
|
|
22867
23109
|
`top:${img.y}px`,
|
|
22868
23110
|
`width:${img.w}px`,
|
|
22869
23111
|
`height:${img.h}px`,
|
|
22870
|
-
|
|
22871
|
-
]
|
|
23112
|
+
`object-fit:${objectFit}`
|
|
23113
|
+
];
|
|
23114
|
+
if (img.borderRadius && img.borderRadius > 0) {
|
|
23115
|
+
stylesList.push(`border-radius:${img.borderRadius}px`);
|
|
23116
|
+
}
|
|
23117
|
+
const styles2 = stylesList.join(";");
|
|
22872
23118
|
const altAttr = img.alt ? ` alt="${img.alt.replace(/"/g, """)}"` : "";
|
|
22873
23119
|
inner += `<img id="${elId}" data-elementType="image" src="${img.dataUri}"${altAttr} style="${styles2}" />
|
|
22874
23120
|
`;
|
|
@@ -22888,9 +23134,25 @@ function renderSlideHtml(elements, bgColor) {
|
|
|
22888
23134
|
}
|
|
22889
23135
|
if (shape.borderRadius) {
|
|
22890
23136
|
styles.push(`border-radius:${shape.borderRadius}px`);
|
|
23137
|
+
} else if (shape.isEllipse) {
|
|
23138
|
+
styles.push(`border-radius:50%`);
|
|
22891
23139
|
}
|
|
22892
23140
|
if (shape.borderWidth && shape.borderColor) {
|
|
22893
|
-
|
|
23141
|
+
let borderStyle = "solid";
|
|
23142
|
+
if (shape.borderDashType) {
|
|
23143
|
+
switch (shape.borderDashType) {
|
|
23144
|
+
case "dash":
|
|
23145
|
+
case "lgDash":
|
|
23146
|
+
case "sysDash":
|
|
23147
|
+
borderStyle = "dashed";
|
|
23148
|
+
break;
|
|
23149
|
+
case "sysDot":
|
|
23150
|
+
case "dot":
|
|
23151
|
+
borderStyle = "dotted";
|
|
23152
|
+
break;
|
|
23153
|
+
}
|
|
23154
|
+
}
|
|
23155
|
+
styles.push(`border:${shape.borderWidth}px ${borderStyle} ${shape.borderColor}`);
|
|
22894
23156
|
styles.push("box-sizing:border-box");
|
|
22895
23157
|
}
|
|
22896
23158
|
if (shape.padding) {
|
|
@@ -22930,11 +23192,19 @@ function renderSlideHtml(elements, bgColor) {
|
|
|
22930
23192
|
for (const run of para.runs) {
|
|
22931
23193
|
const rStyles = [];
|
|
22932
23194
|
if (run.fontSize) rStyles.push(`font-size:${run.fontSize}px`);
|
|
22933
|
-
if (run.
|
|
23195
|
+
if (run.gradientFill) {
|
|
23196
|
+
rStyles.push(`background:${run.gradientFill}`);
|
|
23197
|
+
rStyles.push("-webkit-background-clip:text");
|
|
23198
|
+
rStyles.push("-webkit-text-fill-color:transparent");
|
|
23199
|
+
rStyles.push("background-clip:text");
|
|
23200
|
+
} else if (run.color) {
|
|
23201
|
+
rStyles.push(`color:${run.color}`);
|
|
23202
|
+
}
|
|
22934
23203
|
if (run.bold) rStyles.push("font-weight:bold");
|
|
22935
23204
|
if (run.italic) rStyles.push("font-style:italic");
|
|
22936
23205
|
if (run.fontFamily)
|
|
22937
|
-
rStyles.push(`font-family
|
|
23206
|
+
rStyles.push(`font-family:${cssFontFamily(run.fontFamily)}`);
|
|
23207
|
+
if (run.textShadow) rStyles.push(`text-shadow:${run.textShadow}`);
|
|
22938
23208
|
const escapedText = run.text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
22939
23209
|
if (rStyles.length > 0) {
|
|
22940
23210
|
runHtml += `<span style="${rStyles.join(";")}">${escapedText}</span>`;
|
|
@@ -23050,6 +23320,20 @@ async function importPptx(arrayBuffer) {
|
|
|
23050
23320
|
}
|
|
23051
23321
|
}
|
|
23052
23322
|
}
|
|
23323
|
+
const embeddedFontNames = /* @__PURE__ */ new Set();
|
|
23324
|
+
const embeddedFontEls = presDoc.getElementsByTagName("p:embeddedFont");
|
|
23325
|
+
for (let i = 0; i < embeddedFontEls.length; i++) {
|
|
23326
|
+
const fontEl = embeddedFontEls[i].getElementsByTagName("p:font")[0];
|
|
23327
|
+
if (fontEl) {
|
|
23328
|
+
const typeface = fontEl.getAttribute("typeface");
|
|
23329
|
+
if (typeface) embeddedFontNames.add(typeface);
|
|
23330
|
+
}
|
|
23331
|
+
}
|
|
23332
|
+
let fontStyleBlock = "";
|
|
23333
|
+
if (embeddedFontNames.size > 0) {
|
|
23334
|
+
const fontFamilies = Array.from(embeddedFontNames).map((name) => name.replace(/ /g, "+") + ":ital,wght@0,400;0,700;1,400;1,700").join("&family=");
|
|
23335
|
+
fontStyleBlock = `<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=${fontFamilies}&display=swap">`;
|
|
23336
|
+
}
|
|
23053
23337
|
const slides = [];
|
|
23054
23338
|
for (const slideFile of slideFiles) {
|
|
23055
23339
|
const slideXml = await zip.file(slideFile)?.async("text");
|
|
@@ -23107,6 +23391,9 @@ async function importPptx(arrayBuffer) {
|
|
|
23107
23391
|
}
|
|
23108
23392
|
slides.push(renderSlideHtml(elements, slideBg));
|
|
23109
23393
|
}
|
|
23394
|
+
if (fontStyleBlock && slides.length > 0) {
|
|
23395
|
+
slides[0] = fontStyleBlock + slides[0];
|
|
23396
|
+
}
|
|
23110
23397
|
return slides;
|
|
23111
23398
|
}
|
|
23112
23399
|
|
|
@@ -46278,7 +46565,7 @@ function createTableRow(cells, isHeaderRow, columnCount, cellPadding, headerBack
|
|
|
46278
46565
|
return new TableRow({
|
|
46279
46566
|
tableHeader: isHeaderRow,
|
|
46280
46567
|
children: cells.map(
|
|
46281
|
-
(cell) => {
|
|
46568
|
+
(cell, cellIndex) => {
|
|
46282
46569
|
const textRuns = typeof cell === "string" ? [new TextRun({
|
|
46283
46570
|
text: cell,
|
|
46284
46571
|
bold: isHeaderRow,
|
|
@@ -46318,6 +46605,10 @@ function createTableRow(cells, isHeaderRow, columnCount, cellPadding, headerBack
|
|
|
46318
46605
|
fill: "F9FAFB"
|
|
46319
46606
|
};
|
|
46320
46607
|
}
|
|
46608
|
+
const isLastCell = cellIndex === cells.length - 1;
|
|
46609
|
+
const remainingColumns = columnCount - cells.length;
|
|
46610
|
+
const needsSpan = isLastCell && remainingColumns > 0;
|
|
46611
|
+
const cellColumnSpan = needsSpan ? remainingColumns + 1 : void 0;
|
|
46321
46612
|
return new TableCell({
|
|
46322
46613
|
children: [
|
|
46323
46614
|
new Paragraph({
|
|
@@ -46328,6 +46619,7 @@ function createTableRow(cells, isHeaderRow, columnCount, cellPadding, headerBack
|
|
|
46328
46619
|
size: 100 / columnCount,
|
|
46329
46620
|
type: WidthType.PERCENTAGE
|
|
46330
46621
|
},
|
|
46622
|
+
columnSpan: cellColumnSpan,
|
|
46331
46623
|
shading,
|
|
46332
46624
|
// Apply cell padding from CSS
|
|
46333
46625
|
margins: cellPadding ? {
|
|
@@ -46471,11 +46763,12 @@ function convertElementToDocx(element) {
|
|
|
46471
46763
|
}
|
|
46472
46764
|
case "table": {
|
|
46473
46765
|
const useHeaderStyling = element.noBorders ? false : element.hasHeader !== false;
|
|
46766
|
+
const maxColumnCount = Math.max(...element.rows.map((row) => row.length));
|
|
46474
46767
|
const tableRows = element.rows.map(
|
|
46475
46768
|
(row, rowIndex) => createTableRow(
|
|
46476
46769
|
row,
|
|
46477
46770
|
useHeaderStyling && rowIndex === 0,
|
|
46478
|
-
|
|
46771
|
+
maxColumnCount,
|
|
46479
46772
|
element.cellPadding,
|
|
46480
46773
|
element.headerBackgroundColor,
|
|
46481
46774
|
element.headerTextColor,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"convert.d.ts","sourceRoot":"","sources":["../../../packages/docs/convert.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsD,SAAS,EAAe,KAAK,EAA8G,MAAM,MAAM,CAAC;AACrN,OAAO,EAAwD,aAAa,EAA8D,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"convert.d.ts","sourceRoot":"","sources":["../../../packages/docs/convert.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsD,SAAS,EAAe,KAAK,EAA8G,MAAM,MAAM,CAAC;AACrN,OAAO,EAAwD,aAAa,EAA8D,MAAM,UAAU,CAAC;AA+qB3J;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,aAAa,GAAG,CAAC,SAAS,GAAG,KAAK,CAAC,EAAE,CAk4BlF"}
|
|
@@ -471,7 +471,7 @@ function createTableRow(cells, isHeaderRow, columnCount, cellPadding, headerBack
|
|
|
471
471
|
};
|
|
472
472
|
return new TableRow({
|
|
473
473
|
tableHeader: isHeaderRow,
|
|
474
|
-
children: cells.map((cell) => {
|
|
474
|
+
children: cells.map((cell, cellIndex) => {
|
|
475
475
|
// Build text runs with formatting preserved
|
|
476
476
|
// Apply header text color if specified, otherwise use run's color or default
|
|
477
477
|
const textRuns = typeof cell === "string"
|
|
@@ -519,6 +519,15 @@ function createTableRow(cells, isHeaderRow, columnCount, cellPadding, headerBack
|
|
|
519
519
|
fill: "F9FAFB",
|
|
520
520
|
};
|
|
521
521
|
}
|
|
522
|
+
// When this row has fewer cells than the table's column count,
|
|
523
|
+
// the last cell must span the remaining grid columns via columnSpan.
|
|
524
|
+
// Without this, the OOXML is structurally invalid (cells don't cover
|
|
525
|
+
// all gridCol entries) and strict parsers like Azure Document
|
|
526
|
+
// Intelligence will reject the document.
|
|
527
|
+
const isLastCell = cellIndex === cells.length - 1;
|
|
528
|
+
const remainingColumns = columnCount - cells.length;
|
|
529
|
+
const needsSpan = isLastCell && remainingColumns > 0;
|
|
530
|
+
const cellColumnSpan = needsSpan ? remainingColumns + 1 : undefined;
|
|
522
531
|
return new DocxTableCell({
|
|
523
532
|
children: [
|
|
524
533
|
new Paragraph({
|
|
@@ -529,6 +538,7 @@ function createTableRow(cells, isHeaderRow, columnCount, cellPadding, headerBack
|
|
|
529
538
|
size: 100 / columnCount,
|
|
530
539
|
type: WidthType.PERCENTAGE,
|
|
531
540
|
},
|
|
541
|
+
columnSpan: cellColumnSpan,
|
|
532
542
|
shading,
|
|
533
543
|
// Apply cell padding from CSS
|
|
534
544
|
margins: cellPadding ? {
|
|
@@ -710,7 +720,13 @@ export function convertElementToDocx(element) {
|
|
|
710
720
|
// For noBorders tables (like flex column layouts), don't apply header styling
|
|
711
721
|
// For regular tables (with borders), default to treating first row as header unless explicitly disabled
|
|
712
722
|
const useHeaderStyling = element.noBorders ? false : (element.hasHeader !== false);
|
|
713
|
-
|
|
723
|
+
// Compute the maximum column count across all rows so that rows with fewer
|
|
724
|
+
// cells can set columnSpan to fill the remaining grid columns. Without this,
|
|
725
|
+
// the docx library creates gridCol entries for the max column count but rows
|
|
726
|
+
// with fewer cells lack a gridSpan attribute, producing invalid OOXML that
|
|
727
|
+
// strict parsers like Azure Document Intelligence reject.
|
|
728
|
+
const maxColumnCount = Math.max(...element.rows.map(row => row.length));
|
|
729
|
+
const tableRows = element.rows.map((row, rowIndex) => createTableRow(row, useHeaderStyling && rowIndex === 0, maxColumnCount, element.cellPadding, element.headerBackgroundColor, element.headerTextColor,
|
|
714
730
|
// Apply even row background color for alternating row styling (rowIndex > 0 and odd = even rows in 0-indexed)
|
|
715
731
|
rowIndex > 0 && rowIndex % 2 === 0 ? element.evenRowBackgroundColor : undefined));
|
|
716
732
|
// Default table border color (light gray), or no borders
|