@json-to-office/core-pptx 0.24.0 → 0.26.0
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/components/chart.d.ts +21 -0
- package/dist/components/chart.d.ts.map +1 -1
- package/dist/components/shape.d.ts +22 -7
- package/dist/components/shape.d.ts.map +1 -1
- package/dist/components/text.d.ts +21 -1
- package/dist/components/text.d.ts.map +1 -1
- package/dist/core/generationContext.d.ts +56 -0
- package/dist/core/generationContext.d.ts.map +1 -0
- package/dist/core/generator.d.ts +21 -2
- package/dist/core/generator.d.ts.map +1 -1
- package/dist/core/packagePresentation.d.ts +7 -0
- package/dist/core/packagePresentation.d.ts.map +1 -1
- package/dist/core/render.d.ts +2 -2
- package/dist/core/render.d.ts.map +1 -1
- package/dist/core/structure.d.ts.map +1 -1
- package/dist/index.js +343 -123
- package/dist/index.js.map +1 -1
- package/dist/plugin/createPresentationGenerator.d.ts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types.d.ts +21 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/fillXml.d.ts +19 -0
- package/dist/utils/fillXml.d.ts.map +1 -0
- package/dist/utils/warn.d.ts +3 -0
- package/dist/utils/warn.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -25,6 +25,9 @@ var W = {
|
|
|
25
25
|
THEME_COLOR_FALLBACK: "THEME_COLOR_FALLBACK",
|
|
26
26
|
UNKNOWN_COLOR: "UNKNOWN_COLOR",
|
|
27
27
|
GRID_POSITION_CLAMPED: "GRID_POSITION_CLAMPED",
|
|
28
|
+
TEXT_NO_CONTENT: "TEXT_NO_CONTENT",
|
|
29
|
+
UNKNOWN_PATTERN_PRESET: "UNKNOWN_PATTERN_PRESET",
|
|
30
|
+
ADVANCED_FILL_FALLBACK: "ADVANCED_FILL_FALLBACK",
|
|
28
31
|
IMAGE_ZERO_BOX: "IMAGE_ZERO_BOX",
|
|
29
32
|
FONT_UNRESOLVED: "FONT_UNRESOLVED"
|
|
30
33
|
};
|
|
@@ -384,7 +387,7 @@ function buildSlideIndexMap(children) {
|
|
|
384
387
|
}
|
|
385
388
|
function processPresentation(document, options) {
|
|
386
389
|
const { props, children = [] } = document;
|
|
387
|
-
const baseTheme = typeof props.theme === "object" && props.theme !== null ? props.theme : options?.customThemes?.[props.theme ?? "default"] ?? getPptxTheme(props.theme ?? "default");
|
|
390
|
+
const baseTheme = options?.theme ?? (typeof props.theme === "object" && props.theme !== null ? props.theme : options?.customThemes?.[props.theme ?? "default"] ?? getPptxTheme(props.theme ?? "default"));
|
|
388
391
|
const presDefaults = props.componentDefaults;
|
|
389
392
|
const theme = presDefaults ? {
|
|
390
393
|
...baseTheme,
|
|
@@ -591,6 +594,16 @@ function resolvePagePlaceholders(text, ctx) {
|
|
|
591
594
|
return text.replace(/\{PAGE_NUMBER\}/g, fmt(slideNumber)).replace(/\{PAGE_COUNT\}/g, fmt(totalSlides));
|
|
592
595
|
}
|
|
593
596
|
function renderTextComponent(slide, props, theme, warnings, slideCtx) {
|
|
597
|
+
const runs = props.runs && props.runs.length > 0 ? props.runs : void 0;
|
|
598
|
+
if (props.text === void 0 && !runs) {
|
|
599
|
+
warn(
|
|
600
|
+
warnings,
|
|
601
|
+
W.TEXT_NO_CONTENT,
|
|
602
|
+
'Text component has neither "text" nor "runs" \u2014 skipped',
|
|
603
|
+
{ component: "text" }
|
|
604
|
+
);
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
594
607
|
const style = props.style ? theme.styles?.[props.style] : void 0;
|
|
595
608
|
const isHeadingStyle = props.style && /^(title|heading)/.test(props.style);
|
|
596
609
|
const opts = {};
|
|
@@ -600,7 +613,10 @@ function renderTextComponent(slide, props, theme, warnings, slideCtx) {
|
|
|
600
613
|
if (props.h !== void 0) opts.h = props.h;
|
|
601
614
|
if (props.h === void 0) {
|
|
602
615
|
const fontSize = props.fontSize ?? theme.defaults.fontSize ?? 18;
|
|
603
|
-
const lines =
|
|
616
|
+
const lines = runs ? runs.reduce(
|
|
617
|
+
(count, run) => count + (run.breakLine ? 1 : 0) + (run.text.match(/\n/g)?.length ?? 0),
|
|
618
|
+
1
|
|
619
|
+
) : (props.text.match(/\n/g)?.length ?? 0) + 1;
|
|
604
620
|
opts.h = Math.max(0.5, fontSize / 72 * 1.6 * lines);
|
|
605
621
|
opts.isTextBox = true;
|
|
606
622
|
}
|
|
@@ -611,6 +627,7 @@ function renderTextComponent(slide, props, theme, warnings, slideCtx) {
|
|
|
611
627
|
theme,
|
|
612
628
|
warnings
|
|
613
629
|
);
|
|
630
|
+
const preAliasFamily = opts.fontFace;
|
|
614
631
|
const bold = props.bold ?? style?.bold;
|
|
615
632
|
const italic = props.italic ?? style?.italic;
|
|
616
633
|
const fontWeight = props.fontWeight ?? style?.fontWeight;
|
|
@@ -661,7 +678,11 @@ function renderTextComponent(slide, props, theme, warnings, slideCtx) {
|
|
|
661
678
|
}
|
|
662
679
|
applyHyperlink(opts, props.hyperlink, "text", warnings);
|
|
663
680
|
const lineSpacing = props.lineSpacing ?? style?.lineSpacing;
|
|
664
|
-
if (
|
|
681
|
+
if (props.lineSpacingMultiple !== void 0) {
|
|
682
|
+
opts.lineSpacingMultiple = props.lineSpacingMultiple;
|
|
683
|
+
} else if (lineSpacing !== void 0) {
|
|
684
|
+
opts.lineSpacing = lineSpacing;
|
|
685
|
+
}
|
|
665
686
|
const charSpacing = props.charSpacing ?? style?.charSpacing;
|
|
666
687
|
if (charSpacing !== void 0) opts.charSpacing = charSpacing;
|
|
667
688
|
if (props.paraSpaceBefore !== void 0)
|
|
@@ -669,6 +690,49 @@ function renderTextComponent(slide, props, theme, warnings, slideCtx) {
|
|
|
669
690
|
const paraSpaceAfter = props.paraSpaceAfter ?? style?.paraSpaceAfter;
|
|
670
691
|
if (paraSpaceAfter !== void 0) opts.paraSpaceAfter = paraSpaceAfter;
|
|
671
692
|
if (props.breakLine) opts.breakLine = true;
|
|
693
|
+
if (runs) {
|
|
694
|
+
const runSegments = runs.map((run) => {
|
|
695
|
+
const runOpts = {};
|
|
696
|
+
if (run.fontSize != null) runOpts.fontSize = run.fontSize;
|
|
697
|
+
if (run.fontFace != null) runOpts.fontFace = run.fontFace;
|
|
698
|
+
if (run.color != null)
|
|
699
|
+
runOpts.color = resolveColor(run.color, theme, warnings);
|
|
700
|
+
if (run.strike != null) runOpts.strike = run.strike;
|
|
701
|
+
if (run.underline !== void 0) {
|
|
702
|
+
if (typeof run.underline === "boolean") {
|
|
703
|
+
if (run.underline) runOpts.underline = { style: "sng" };
|
|
704
|
+
} else {
|
|
705
|
+
runOpts.underline = run.underline;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
if (run.superscript != null) runOpts.superscript = run.superscript;
|
|
709
|
+
if (run.subscript != null) runOpts.subscript = run.subscript;
|
|
710
|
+
if (run.charSpacing != null) runOpts.charSpacing = run.charSpacing;
|
|
711
|
+
if (run.breakLine != null) runOpts.breakLine = run.breakLine;
|
|
712
|
+
const effWeight = run.fontWeight ?? fontWeight;
|
|
713
|
+
const effBold = run.bold ?? bold;
|
|
714
|
+
const effItalic = run.italic ?? italic;
|
|
715
|
+
if (effBold != null) runOpts.bold = effBold;
|
|
716
|
+
if (effItalic != null) runOpts.italic = effItalic;
|
|
717
|
+
if (effWeight != null || effBold === true) {
|
|
718
|
+
if (run.fontFace == null) {
|
|
719
|
+
const w = applyFontWeight({
|
|
720
|
+
family: preAliasFamily,
|
|
721
|
+
fontWeight: effWeight,
|
|
722
|
+
italic: effItalic,
|
|
723
|
+
bold: effBold
|
|
724
|
+
});
|
|
725
|
+
if (w.fontFace !== void 0) runOpts.fontFace = w.fontFace;
|
|
726
|
+
if (w.bold !== void 0) runOpts.bold = w.bold;
|
|
727
|
+
if (w.italic !== void 0) runOpts.italic = w.italic;
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
const runText = slideCtx ? resolvePagePlaceholders(run.text, slideCtx) : run.text;
|
|
731
|
+
return { text: runText, options: runOpts };
|
|
732
|
+
});
|
|
733
|
+
slide.addText(runSegments, opts);
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
672
736
|
const text = slideCtx ? resolvePagePlaceholders(props.text, slideCtx) : props.text;
|
|
673
737
|
slide.addText(text, opts);
|
|
674
738
|
}
|
|
@@ -842,6 +906,44 @@ async function renderImageComponent(slide, props, theme, warnings, slideWidth =
|
|
|
842
906
|
slide.addImage(opts);
|
|
843
907
|
}
|
|
844
908
|
|
|
909
|
+
// src/components/shape.ts
|
|
910
|
+
import { PATTERN_FILL_PRESETS } from "@json-to-office/shared-pptx";
|
|
911
|
+
|
|
912
|
+
// src/utils/fillXml.ts
|
|
913
|
+
var ANGLE_UNIT = 6e4;
|
|
914
|
+
var PCT_UNIT = 1e3;
|
|
915
|
+
var RADIAL_FOCUS_RECTS = {
|
|
916
|
+
center: { l: 5e4, t: 5e4, r: 5e4, b: 5e4 },
|
|
917
|
+
topLeft: { l: 0, t: 0, r: 1e5, b: 1e5 },
|
|
918
|
+
topRight: { l: 1e5, t: 0, r: 0, b: 1e5 },
|
|
919
|
+
bottomLeft: { l: 0, t: 1e5, r: 1e5, b: 0 },
|
|
920
|
+
bottomRight: { l: 1e5, t: 1e5, r: 0, b: 0 }
|
|
921
|
+
};
|
|
922
|
+
function gradientStopXml(color, pos, transparency, theme, warnings) {
|
|
923
|
+
const hex = resolveColor(color, theme, warnings).toUpperCase();
|
|
924
|
+
const alpha = transparency !== void 0 ? `<a:alpha val="${Math.round((100 - transparency) * PCT_UNIT)}"/>` : "";
|
|
925
|
+
return `<a:gs pos="${Math.round(pos * PCT_UNIT)}"><a:srgbClr val="${hex}">${alpha}</a:srgbClr></a:gs>`;
|
|
926
|
+
}
|
|
927
|
+
function buildGradientFillXml(gradient, theme, warnings) {
|
|
928
|
+
const stops = gradient.stops.map(
|
|
929
|
+
(stop) => gradientStopXml(stop.color, stop.pos, stop.transparency, theme, warnings)
|
|
930
|
+
).join("");
|
|
931
|
+
let shade;
|
|
932
|
+
if (gradient.type === "radial") {
|
|
933
|
+
const rect = RADIAL_FOCUS_RECTS[gradient.focus ?? "center"];
|
|
934
|
+
shade = `<a:path path="circle"><a:fillToRect l="${rect.l}" t="${rect.t}" r="${rect.r}" b="${rect.b}"/></a:path>`;
|
|
935
|
+
} else {
|
|
936
|
+
const angle = ((gradient.angle ?? 0) % 360 + 360) % 360;
|
|
937
|
+
shade = `<a:lin ang="${Math.round(angle * ANGLE_UNIT)}" scaled="1"/>`;
|
|
938
|
+
}
|
|
939
|
+
return `<a:gradFill rotWithShape="1"><a:gsLst>${stops}</a:gsLst>${shade}</a:gradFill>`;
|
|
940
|
+
}
|
|
941
|
+
function buildPatternFillXml(pattern, theme, warnings) {
|
|
942
|
+
const fg = resolveColor(pattern.foreground, theme, warnings).toUpperCase();
|
|
943
|
+
const bg = resolveColor(pattern.background, theme, warnings).toUpperCase();
|
|
944
|
+
return `<a:pattFill prst="${pattern.preset}"><a:fgClr><a:srgbClr val="${fg}"/></a:fgClr><a:bgClr><a:srgbClr val="${bg}"/></a:bgClr></a:pattFill>`;
|
|
945
|
+
}
|
|
946
|
+
|
|
845
947
|
// src/components/shape.ts
|
|
846
948
|
var SHAPE_TYPE_MAP = {
|
|
847
949
|
rect: "rect",
|
|
@@ -860,17 +962,67 @@ var SHAPE_TYPE_MAP = {
|
|
|
860
962
|
heart: "heart",
|
|
861
963
|
lightning: "lightningBolt"
|
|
862
964
|
};
|
|
863
|
-
function
|
|
965
|
+
function applyShapeFill(opts, fill, theme, warnings, pendingFills) {
|
|
966
|
+
let gradient = fill.gradient;
|
|
967
|
+
let pattern = fill.pattern;
|
|
968
|
+
if (gradient && pattern) {
|
|
969
|
+
warn(
|
|
970
|
+
warnings,
|
|
971
|
+
W.ADVANCED_FILL_FALLBACK,
|
|
972
|
+
'Shape fill sets both "gradient" and "pattern" \u2014 using the gradient',
|
|
973
|
+
{ component: "shape" }
|
|
974
|
+
);
|
|
975
|
+
pattern = void 0;
|
|
976
|
+
}
|
|
977
|
+
let unknownPresetForeground;
|
|
978
|
+
if (pattern && !PATTERN_FILL_PRESETS.includes(pattern.preset)) {
|
|
979
|
+
warn(
|
|
980
|
+
warnings,
|
|
981
|
+
W.UNKNOWN_PATTERN_PRESET,
|
|
982
|
+
`Unknown pattern preset "${pattern.preset}" \u2014 falling back to solid foreground`,
|
|
983
|
+
{ component: "shape" }
|
|
984
|
+
);
|
|
985
|
+
unknownPresetForeground = pattern.foreground;
|
|
986
|
+
pattern = void 0;
|
|
987
|
+
}
|
|
988
|
+
if (gradient || pattern) {
|
|
989
|
+
const sentinel = resolveColor(
|
|
990
|
+
fill.color ?? (gradient ? gradient.stops[0].color : pattern.foreground),
|
|
991
|
+
theme,
|
|
992
|
+
warnings
|
|
993
|
+
);
|
|
994
|
+
if (pendingFills) {
|
|
995
|
+
const xml = gradient ? buildGradientFillXml(gradient, theme, warnings) : buildPatternFillXml(pattern, theme, warnings);
|
|
996
|
+
const objectName = `__jto_fill_${pendingFills.length}__`;
|
|
997
|
+
pendingFills.push({ objectName, xml });
|
|
998
|
+
opts.objectName = objectName;
|
|
999
|
+
} else {
|
|
1000
|
+
warn(
|
|
1001
|
+
warnings,
|
|
1002
|
+
W.ADVANCED_FILL_FALLBACK,
|
|
1003
|
+
`${gradient ? "Gradient" : "Pattern"} fill requires the buffer generation pipeline \u2014 rendering a solid fill instead`,
|
|
1004
|
+
{ component: "shape" }
|
|
1005
|
+
);
|
|
1006
|
+
}
|
|
1007
|
+
opts.fill = { color: sentinel };
|
|
1008
|
+
return;
|
|
1009
|
+
}
|
|
1010
|
+
const solid = fill.color ?? unknownPresetForeground;
|
|
1011
|
+
if (solid !== void 0) {
|
|
1012
|
+
opts.fill = { color: resolveColor(solid, theme, warnings) };
|
|
1013
|
+
if (fill.transparency !== void 0) {
|
|
1014
|
+
opts.fill.transparency = fill.transparency;
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
function buildShapeOpts(props, theme, warnings, pendingFills) {
|
|
864
1019
|
const opts = {};
|
|
865
1020
|
if (props.x !== void 0) opts.x = props.x;
|
|
866
1021
|
if (props.y !== void 0) opts.y = props.y;
|
|
867
1022
|
if (props.w !== void 0) opts.w = props.w;
|
|
868
1023
|
if (props.h !== void 0) opts.h = props.h;
|
|
869
1024
|
if (props.fill) {
|
|
870
|
-
opts
|
|
871
|
-
if (props.fill.transparency !== void 0) {
|
|
872
|
-
opts.fill.transparency = props.fill.transparency;
|
|
873
|
-
}
|
|
1025
|
+
applyShapeFill(opts, props.fill, theme, warnings, pendingFills);
|
|
874
1026
|
}
|
|
875
1027
|
if (props.line) {
|
|
876
1028
|
opts.line = {};
|
|
@@ -886,6 +1038,9 @@ function buildShapeOpts(props, theme, warnings) {
|
|
|
886
1038
|
opts.line.dashType = props.line.dashType;
|
|
887
1039
|
}
|
|
888
1040
|
if (props.rotate !== void 0) opts.rotate = props.rotate;
|
|
1041
|
+
if (props.angleRange !== void 0) opts.angleRange = props.angleRange;
|
|
1042
|
+
if (props.flipH !== void 0) opts.flipH = props.flipH;
|
|
1043
|
+
if (props.flipV !== void 0) opts.flipV = props.flipV;
|
|
889
1044
|
if (props.rectRadius !== void 0) opts.rectRadius = props.rectRadius;
|
|
890
1045
|
if (props.shadow) {
|
|
891
1046
|
opts.shadow = {
|
|
@@ -899,7 +1054,7 @@ function buildShapeOpts(props, theme, warnings) {
|
|
|
899
1054
|
}
|
|
900
1055
|
return opts;
|
|
901
1056
|
}
|
|
902
|
-
function renderShapeComponent(slide, props, theme, pptx, warnings) {
|
|
1057
|
+
function renderShapeComponent(slide, props, theme, pptx, warnings, ctx) {
|
|
903
1058
|
const shapeTypeName = SHAPE_TYPE_MAP[props.type] || props.type;
|
|
904
1059
|
const shapeType = pptx.ShapeType[shapeTypeName];
|
|
905
1060
|
if (!shapeType) {
|
|
@@ -910,7 +1065,7 @@ function renderShapeComponent(slide, props, theme, pptx, warnings) {
|
|
|
910
1065
|
}
|
|
911
1066
|
const style = props.style ? theme.styles?.[props.style] : void 0;
|
|
912
1067
|
const isHeadingStyle = props.style && /^(title|heading)/.test(props.style);
|
|
913
|
-
const opts = buildShapeOpts(props, theme, warnings);
|
|
1068
|
+
const opts = buildShapeOpts(props, theme, warnings, ctx?.pendingFills);
|
|
914
1069
|
if (props.text && (!Array.isArray(props.text) || props.text.length > 0)) {
|
|
915
1070
|
opts.shape = shapeType;
|
|
916
1071
|
opts.fontSize = props.fontSize ?? style?.fontSize ?? theme.defaults.fontSize;
|
|
@@ -1262,6 +1417,14 @@ var CHART_TYPE_MAP = {
|
|
|
1262
1417
|
radar: "radar",
|
|
1263
1418
|
scatter: "scatter"
|
|
1264
1419
|
};
|
|
1420
|
+
function resolveGridLine(gridLine, theme, warnings) {
|
|
1421
|
+
const resolved = {};
|
|
1422
|
+
if (gridLine.style !== void 0) resolved.style = gridLine.style;
|
|
1423
|
+
if (gridLine.size !== void 0) resolved.size = gridLine.size;
|
|
1424
|
+
if (gridLine.color !== void 0)
|
|
1425
|
+
resolved.color = resolveColor(gridLine.color, theme, warnings);
|
|
1426
|
+
return resolved;
|
|
1427
|
+
}
|
|
1265
1428
|
function renderChartComponent(slide, props, theme, _pptx, warnings) {
|
|
1266
1429
|
const chartType = CHART_TYPE_MAP[props.type];
|
|
1267
1430
|
if (!chartType) {
|
|
@@ -1319,6 +1482,18 @@ function renderChartComponent(slide, props, theme, _pptx, warnings) {
|
|
|
1319
1482
|
opts.legendColor = props.legendColor ? resolveColor(props.legendColor, theme, warnings) : themeTextColor;
|
|
1320
1483
|
opts.catAxisLabelColor = props.catAxisLabelColor ? resolveColor(props.catAxisLabelColor, theme, warnings) : themeTextColor;
|
|
1321
1484
|
opts.valAxisLabelColor = props.valAxisLabelColor ? resolveColor(props.valAxisLabelColor, theme, warnings) : themeTextColor;
|
|
1485
|
+
if (props.valAxisLabelFontSize !== void 0)
|
|
1486
|
+
opts.valAxisLabelFontSize = props.valAxisLabelFontSize;
|
|
1487
|
+
if (props.catAxisLineShow !== void 0)
|
|
1488
|
+
opts.catAxisLineShow = props.catAxisLineShow;
|
|
1489
|
+
if (props.valAxisLineShow !== void 0)
|
|
1490
|
+
opts.valAxisLineShow = props.valAxisLineShow;
|
|
1491
|
+
if (props.dataBorder !== void 0) {
|
|
1492
|
+
opts.dataBorder = {
|
|
1493
|
+
pt: props.dataBorder.pt,
|
|
1494
|
+
color: resolveColor(props.dataBorder.color, theme, warnings)
|
|
1495
|
+
};
|
|
1496
|
+
}
|
|
1322
1497
|
if (props.showLegend !== void 0) opts.showLegend = props.showLegend;
|
|
1323
1498
|
if (props.showTitle !== void 0) opts.showTitle = props.showTitle;
|
|
1324
1499
|
if (props.showValue !== void 0) opts.showValue = props.showValue;
|
|
@@ -1345,6 +1520,10 @@ function renderChartComponent(slide, props, theme, _pptx, warnings) {
|
|
|
1345
1520
|
opts.catAxisLabelRotate = props.catAxisLabelRotate;
|
|
1346
1521
|
if (props.catAxisLabelFontSize !== void 0)
|
|
1347
1522
|
opts.catAxisLabelFontSize = props.catAxisLabelFontSize;
|
|
1523
|
+
if (props.catAxisLabelFontFace !== void 0)
|
|
1524
|
+
opts.catAxisLabelFontFace = props.catAxisLabelFontFace;
|
|
1525
|
+
if (props.catGridLine !== void 0)
|
|
1526
|
+
opts.catGridLine = resolveGridLine(props.catGridLine, theme, warnings);
|
|
1348
1527
|
if (props.valAxisTitle !== void 0) {
|
|
1349
1528
|
opts.valAxisTitle = props.valAxisTitle;
|
|
1350
1529
|
opts.showValAxisTitle = true;
|
|
@@ -1359,14 +1538,22 @@ function renderChartComponent(slide, props, theme, _pptx, warnings) {
|
|
|
1359
1538
|
opts.valAxisLabelFormatCode = props.valAxisLabelFormatCode;
|
|
1360
1539
|
if (props.valAxisMajorUnit !== void 0)
|
|
1361
1540
|
opts.valAxisMajorUnit = props.valAxisMajorUnit;
|
|
1541
|
+
if (props.valAxisLabelFontFace !== void 0)
|
|
1542
|
+
opts.valAxisLabelFontFace = props.valAxisLabelFontFace;
|
|
1543
|
+
if (props.valGridLine !== void 0)
|
|
1544
|
+
opts.valGridLine = resolveGridLine(props.valGridLine, theme, warnings);
|
|
1362
1545
|
if (props.barDir !== void 0) opts.barDir = props.barDir;
|
|
1363
1546
|
if (props.barGrouping !== void 0) opts.barGrouping = props.barGrouping;
|
|
1364
1547
|
if (props.barGapWidthPct !== void 0)
|
|
1365
1548
|
opts.barGapWidthPct = props.barGapWidthPct;
|
|
1549
|
+
if (props.barOverlapPct !== void 0)
|
|
1550
|
+
opts.barOverlapPct = props.barOverlapPct;
|
|
1366
1551
|
if (props.lineSmooth !== void 0) opts.lineSmooth = props.lineSmooth;
|
|
1367
1552
|
if (props.lineDataSymbol !== void 0)
|
|
1368
1553
|
opts.lineDataSymbol = props.lineDataSymbol;
|
|
1369
1554
|
if (props.lineSize !== void 0) opts.lineSize = props.lineSize;
|
|
1555
|
+
if (props.lineDataSymbolSize !== void 0)
|
|
1556
|
+
opts.lineDataSymbolSize = props.lineDataSymbolSize;
|
|
1370
1557
|
if (props.firstSliceAng !== void 0)
|
|
1371
1558
|
opts.firstSliceAng = props.firstSliceAng;
|
|
1372
1559
|
if (props.holeSize !== void 0) opts.holeSize = props.holeSize;
|
|
@@ -1403,7 +1590,7 @@ async function renderComponent(slide, component, theme, pptx, warnings, ctx) {
|
|
|
1403
1590
|
);
|
|
1404
1591
|
break;
|
|
1405
1592
|
case "shape":
|
|
1406
|
-
renderShapeComponent(slide, p, theme, pptx, warnings);
|
|
1593
|
+
renderShapeComponent(slide, p, theme, pptx, warnings, ctx);
|
|
1407
1594
|
break;
|
|
1408
1595
|
case "table":
|
|
1409
1596
|
renderTableComponent(slide, p, theme, pptx, warnings);
|
|
@@ -1460,7 +1647,7 @@ function buildSlideTemplateProps(def, theme, warnings) {
|
|
|
1460
1647
|
|
|
1461
1648
|
// src/core/render.ts
|
|
1462
1649
|
import { mergeWithDefaults as mergeWithDefaults3 } from "@json-to-office/shared";
|
|
1463
|
-
async function renderPresentation(processed, warnings) {
|
|
1650
|
+
async function renderPresentation(processed, warnings, pendingFills) {
|
|
1464
1651
|
const pptx = new PptxGenJS();
|
|
1465
1652
|
if (processed.metadata.title) pptx.title = processed.metadata.title;
|
|
1466
1653
|
if (processed.metadata.author) pptx.author = processed.metadata.author;
|
|
@@ -1505,10 +1692,37 @@ async function renderPresentation(processed, warnings) {
|
|
|
1505
1692
|
slideCtx,
|
|
1506
1693
|
services: processed.services,
|
|
1507
1694
|
slideWidth: processed.slideWidth,
|
|
1508
|
-
slideHeight: processed.slideHeight
|
|
1695
|
+
slideHeight: processed.slideHeight,
|
|
1696
|
+
pendingFills
|
|
1509
1697
|
};
|
|
1510
1698
|
const slide = slideData.template ? pptx.addSlide({ masterName: slideData.template }) : pptx.addSlide();
|
|
1511
|
-
|
|
1699
|
+
const templateDef = slideData.template ? templateMap.get(slideData.template) : void 0;
|
|
1700
|
+
if (slideData.template && !templateDef) {
|
|
1701
|
+
warn(
|
|
1702
|
+
warnings,
|
|
1703
|
+
W.MISSING_TEMPLATE,
|
|
1704
|
+
`Unknown template "${slideData.template}". Available: ${[...templateMap.keys()].join(", ")}`,
|
|
1705
|
+
{ slide: slideIdx }
|
|
1706
|
+
);
|
|
1707
|
+
}
|
|
1708
|
+
const backgroundGradient = slideData.background?.gradient ?? (slideData.background ? void 0 : templateDef?.background?.gradient);
|
|
1709
|
+
if (backgroundGradient) {
|
|
1710
|
+
renderShapeComponent(
|
|
1711
|
+
slide,
|
|
1712
|
+
{
|
|
1713
|
+
type: "rect",
|
|
1714
|
+
x: 0,
|
|
1715
|
+
y: 0,
|
|
1716
|
+
w: processed.slideWidth,
|
|
1717
|
+
h: processed.slideHeight,
|
|
1718
|
+
fill: { gradient: backgroundGradient }
|
|
1719
|
+
},
|
|
1720
|
+
processed.theme,
|
|
1721
|
+
pptx,
|
|
1722
|
+
warnings,
|
|
1723
|
+
renderCtx
|
|
1724
|
+
);
|
|
1725
|
+
} else if (slideData.background) {
|
|
1512
1726
|
if (slideData.background.color) {
|
|
1513
1727
|
slide.background = {
|
|
1514
1728
|
color: resolveColor(
|
|
@@ -1528,15 +1742,6 @@ async function renderPresentation(processed, warnings) {
|
|
|
1528
1742
|
if (slideData.hidden) {
|
|
1529
1743
|
slide.hidden = true;
|
|
1530
1744
|
}
|
|
1531
|
-
const templateDef = slideData.template ? templateMap.get(slideData.template) : void 0;
|
|
1532
|
-
if (slideData.template && !templateDef) {
|
|
1533
|
-
warn(
|
|
1534
|
-
warnings,
|
|
1535
|
-
W.MISSING_TEMPLATE,
|
|
1536
|
-
`Unknown template "${slideData.template}". Available: ${[...templateMap.keys()].join(", ")}`,
|
|
1537
|
-
{ slide: slideIdx }
|
|
1538
|
-
);
|
|
1539
|
-
}
|
|
1540
1745
|
const effectiveGrid = mergeGridConfigs(processed.grid, templateDef?.grid);
|
|
1541
1746
|
if (templateDef?.objects) {
|
|
1542
1747
|
for (const obj of templateDef.objects) {
|
|
@@ -1708,10 +1913,43 @@ async function resolveDocumentFonts(document, theme, warnings, fonts) {
|
|
|
1708
1913
|
return resolved;
|
|
1709
1914
|
}
|
|
1710
1915
|
|
|
1711
|
-
// src/core/
|
|
1916
|
+
// src/core/generationContext.ts
|
|
1712
1917
|
import { applyExportMode, scopedThemeName } from "@json-to-office/shared";
|
|
1918
|
+
function resolveThemeContext(documentIn, options = {}) {
|
|
1919
|
+
const { customThemes, fonts, warnings, defaultThemeName, resolveNamedTheme } = options;
|
|
1920
|
+
if (documentIn.props === null) {
|
|
1921
|
+
throw new Error(
|
|
1922
|
+
"Document `props` is null. Omit it, or provide an object \u2014 a null props cannot carry a theme."
|
|
1923
|
+
);
|
|
1924
|
+
}
|
|
1925
|
+
let document = documentIn.props === void 0 ? { ...documentIn, props: {} } : documentIn;
|
|
1926
|
+
let inlineTheme;
|
|
1927
|
+
if (typeof document.props.theme === "object" && document.props.theme !== null) {
|
|
1928
|
+
inlineTheme = document.props.theme;
|
|
1929
|
+
}
|
|
1930
|
+
const baseThemeName = inlineTheme ? inlineTheme.name || "inline-theme" : document.props.theme ?? defaultThemeName ?? "default";
|
|
1931
|
+
let theme = inlineTheme ?? (resolveNamedTheme ? resolveNamedTheme(baseThemeName) : customThemes?.[baseThemeName] ?? getPptxTheme(baseThemeName));
|
|
1932
|
+
const mode = applyExportMode({ doc: document, theme, fonts });
|
|
1933
|
+
document = mode.doc;
|
|
1934
|
+
theme = mode.theme;
|
|
1935
|
+
for (const w of mode.warnings) {
|
|
1936
|
+
warnings?.push({
|
|
1937
|
+
code: w.code,
|
|
1938
|
+
message: w.message,
|
|
1939
|
+
component: "fontRegistry"
|
|
1940
|
+
});
|
|
1941
|
+
}
|
|
1942
|
+
return {
|
|
1943
|
+
document,
|
|
1944
|
+
theme,
|
|
1945
|
+
themeName: scopedThemeName(baseThemeName, fonts?.mode)
|
|
1946
|
+
};
|
|
1947
|
+
}
|
|
1948
|
+
|
|
1949
|
+
// src/core/generator.ts
|
|
1713
1950
|
import {
|
|
1714
1951
|
collectImageSourceConflicts,
|
|
1952
|
+
collectTextContentConflicts,
|
|
1715
1953
|
validateJsonPresentationDocument,
|
|
1716
1954
|
validatePresentationDocument
|
|
1717
1955
|
} from "@json-to-office/shared-pptx";
|
|
@@ -1721,6 +1959,23 @@ import JSZip from "jszip";
|
|
|
1721
1959
|
var MEDIUM_STYLE_2_ACCENT_1 = "{5C22544A-7EE6-4342-B048-85BDC9FD1C3A}";
|
|
1722
1960
|
var NO_STYLE_NO_GRID = "{2D5ABB26-0587-4C30-8999-92F81FD0307C}";
|
|
1723
1961
|
var DEFAULT_GENERATED_AT = "2000-01-01T00:00:00.000Z";
|
|
1962
|
+
function applyPendingFills(xml, pendingFills) {
|
|
1963
|
+
let out = xml;
|
|
1964
|
+
for (const [index, fill] of pendingFills.entries()) {
|
|
1965
|
+
const marker = `name="${fill.objectName}"`;
|
|
1966
|
+
const markerIdx = out.indexOf(marker);
|
|
1967
|
+
if (markerIdx === -1) continue;
|
|
1968
|
+
const spEnd = out.indexOf("</p:sp>", markerIdx);
|
|
1969
|
+
const solidStart = out.indexOf("<a:solidFill>", markerIdx);
|
|
1970
|
+
const solidEndTag = "</a:solidFill>";
|
|
1971
|
+
const solidEnd = out.indexOf(solidEndTag, solidStart);
|
|
1972
|
+
if (solidStart !== -1 && solidEnd !== -1 && spEnd !== -1 && solidStart < spEnd) {
|
|
1973
|
+
out = out.slice(0, solidStart) + fill.xml + out.slice(solidEnd + solidEndTag.length);
|
|
1974
|
+
}
|
|
1975
|
+
out = out.slice(0, markerIdx) + `name="Fill ${index + 1}"` + out.slice(markerIdx + marker.length);
|
|
1976
|
+
}
|
|
1977
|
+
return out;
|
|
1978
|
+
}
|
|
1724
1979
|
function resolveGeneratedAt(value) {
|
|
1725
1980
|
const date = value === void 0 ? new Date(DEFAULT_GENERATED_AT) : new Date(value);
|
|
1726
1981
|
if (Number.isNaN(date.getTime())) {
|
|
@@ -1820,9 +2075,21 @@ async function packagePresentationBuffer(buffer, options = {}) {
|
|
|
1820
2075
|
let changed = false;
|
|
1821
2076
|
for (const [path2, entry] of Object.entries(zip.files)) {
|
|
1822
2077
|
if (!path2.match(/^ppt\/slides\/slide\d+\.xml$/)) continue;
|
|
1823
|
-
|
|
2078
|
+
let xml = await entry.async("string");
|
|
2079
|
+
let fileChanged = false;
|
|
1824
2080
|
if (xml.includes(MEDIUM_STYLE_2_ACCENT_1)) {
|
|
1825
|
-
|
|
2081
|
+
xml = xml.replaceAll(MEDIUM_STYLE_2_ACCENT_1, NO_STYLE_NO_GRID);
|
|
2082
|
+
fileChanged = true;
|
|
2083
|
+
}
|
|
2084
|
+
if (options.pendingFills?.length) {
|
|
2085
|
+
const withFills = applyPendingFills(xml, options.pendingFills);
|
|
2086
|
+
if (withFills !== xml) {
|
|
2087
|
+
xml = withFills;
|
|
2088
|
+
fileChanged = true;
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
2091
|
+
if (fileChanged) {
|
|
2092
|
+
zip.file(path2, xml);
|
|
1826
2093
|
changed = true;
|
|
1827
2094
|
}
|
|
1828
2095
|
}
|
|
@@ -1858,25 +2125,31 @@ function assertValidPresentation(input, validation) {
|
|
|
1858
2125
|
throw new PresentationValidationError(result.errors);
|
|
1859
2126
|
}
|
|
1860
2127
|
}
|
|
2128
|
+
function assertNoContentConflicts(document) {
|
|
2129
|
+
const sourceConflicts = [
|
|
2130
|
+
...collectImageSourceConflicts(document),
|
|
2131
|
+
...collectTextContentConflicts(document)
|
|
2132
|
+
];
|
|
2133
|
+
if (sourceConflicts.length > 0) {
|
|
2134
|
+
throw new Error(
|
|
2135
|
+
`Document validation failed:
|
|
2136
|
+
${sourceConflicts.map((e) => ` - ${e.path}: ${e.message}`).join("\n")}`
|
|
2137
|
+
);
|
|
2138
|
+
}
|
|
2139
|
+
}
|
|
1861
2140
|
function isPresentationComponentDefinition(definition) {
|
|
1862
2141
|
if (typeof definition !== "object" || definition === null) return false;
|
|
1863
2142
|
const def = definition;
|
|
1864
2143
|
return def.name === "pptx" && "props" in def;
|
|
1865
2144
|
}
|
|
1866
|
-
async function generatePresentation(document, options, warnings) {
|
|
2145
|
+
async function generatePresentation(document, options, warnings, pendingFills) {
|
|
1867
2146
|
assertValidPresentation(document, options?.validation);
|
|
1868
2147
|
if (!document || document.name !== "pptx") {
|
|
1869
2148
|
throw new Error("Top-level component must be a pptx component");
|
|
1870
2149
|
}
|
|
1871
|
-
|
|
1872
|
-
if (sourceConflicts.length > 0) {
|
|
1873
|
-
throw new Error(
|
|
1874
|
-
`Document validation failed:
|
|
1875
|
-
${sourceConflicts.map((e) => ` - ${e.path}: ${e.message}`).join("\n")}`
|
|
1876
|
-
);
|
|
1877
|
-
}
|
|
2150
|
+
assertNoContentConflicts(document);
|
|
1878
2151
|
const processed = processPresentation(document, options);
|
|
1879
|
-
return await renderPresentation(processed, warnings);
|
|
2152
|
+
return await renderPresentation(processed, warnings, pendingFills);
|
|
1880
2153
|
}
|
|
1881
2154
|
async function generateBufferFromJson(jsonConfig, options) {
|
|
1882
2155
|
const result = await generateBufferWithWarnings(jsonConfig, options);
|
|
@@ -1895,64 +2168,34 @@ async function generateBufferWithWarnings(jsonConfig, options) {
|
|
|
1895
2168
|
component = jsonConfig;
|
|
1896
2169
|
}
|
|
1897
2170
|
const warnings = [];
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
...component,
|
|
1903
|
-
props: { ...component.props, theme: inlineName }
|
|
1904
|
-
};
|
|
1905
|
-
options = {
|
|
1906
|
-
...options,
|
|
1907
|
-
customThemes: {
|
|
1908
|
-
...options?.customThemes ?? {},
|
|
1909
|
-
[inlineName]: inlineTheme
|
|
1910
|
-
}
|
|
1911
|
-
};
|
|
1912
|
-
}
|
|
1913
|
-
const baseThemeName = component.props?.theme ?? "default";
|
|
1914
|
-
let resolvedTheme = options?.customThemes?.[baseThemeName] ?? getPptxTheme(baseThemeName);
|
|
1915
|
-
const mode = applyExportMode({
|
|
1916
|
-
doc: component,
|
|
1917
|
-
theme: resolvedTheme,
|
|
1918
|
-
fonts: options?.fonts
|
|
2171
|
+
const context = resolveThemeContext(component, {
|
|
2172
|
+
customThemes: options?.customThemes,
|
|
2173
|
+
fonts: options?.fonts,
|
|
2174
|
+
warnings
|
|
1919
2175
|
});
|
|
1920
|
-
component =
|
|
1921
|
-
resolvedTheme = mode.theme;
|
|
1922
|
-
for (const w of mode.warnings) {
|
|
1923
|
-
warnings.push({
|
|
1924
|
-
code: w.code,
|
|
1925
|
-
message: w.message,
|
|
1926
|
-
component: "fontRegistry"
|
|
1927
|
-
});
|
|
1928
|
-
}
|
|
2176
|
+
component = context.document;
|
|
1929
2177
|
await resolveDocumentFonts(
|
|
1930
2178
|
component,
|
|
1931
|
-
|
|
2179
|
+
context.theme,
|
|
1932
2180
|
warnings,
|
|
1933
2181
|
options?.fonts
|
|
1934
2182
|
);
|
|
1935
|
-
const themeName = scopedThemeName(baseThemeName, options?.fonts?.mode);
|
|
1936
|
-
if (themeName !== baseThemeName) {
|
|
1937
|
-
component = {
|
|
1938
|
-
...component,
|
|
1939
|
-
props: { ...component.props, theme: themeName }
|
|
1940
|
-
};
|
|
1941
|
-
}
|
|
1942
2183
|
const effectiveOptions = {
|
|
1943
2184
|
...options,
|
|
1944
|
-
|
|
1945
|
-
...options?.customThemes ?? {},
|
|
1946
|
-
[themeName]: resolvedTheme
|
|
1947
|
-
}
|
|
2185
|
+
theme: context.theme
|
|
1948
2186
|
};
|
|
2187
|
+
const pendingFills = [];
|
|
1949
2188
|
const pptx = await generatePresentation(
|
|
1950
2189
|
component,
|
|
1951
2190
|
effectiveOptions,
|
|
1952
|
-
warnings
|
|
2191
|
+
warnings,
|
|
2192
|
+
pendingFills
|
|
1953
2193
|
);
|
|
1954
2194
|
const data = await pptx.write({ outputType: "nodebuffer" });
|
|
1955
|
-
const buffer = await packagePresentationBuffer(data,
|
|
2195
|
+
const buffer = await packagePresentationBuffer(data, {
|
|
2196
|
+
...options,
|
|
2197
|
+
pendingFills
|
|
2198
|
+
});
|
|
1956
2199
|
return { buffer, warnings };
|
|
1957
2200
|
}
|
|
1958
2201
|
async function generateAndSaveFromJson(jsonConfig, outputPath, options) {
|
|
@@ -2107,7 +2350,6 @@ async function exportPluginSchema(customComponents, outputPath, options = {}) {
|
|
|
2107
2350
|
}
|
|
2108
2351
|
|
|
2109
2352
|
// src/plugin/createPresentationGenerator.ts
|
|
2110
|
-
import { applyExportMode as applyExportMode2, scopedThemeName as scopedThemeName2 } from "@json-to-office/shared";
|
|
2111
2353
|
function createBuilderImpl(state) {
|
|
2112
2354
|
const componentMap = new Map(state.components.map((c) => [c.name, c]));
|
|
2113
2355
|
async function processSlideComponents(components, warningsCollector, theme, validateEmitted, parentName, depth = 0) {
|
|
@@ -2251,41 +2493,23 @@ function createBuilderImpl(state) {
|
|
|
2251
2493
|
} else if (!internalDocument || internalDocument.name !== "pptx") {
|
|
2252
2494
|
throw new Error("Top-level component must be a pptx component");
|
|
2253
2495
|
}
|
|
2254
|
-
let inlineTheme;
|
|
2255
|
-
if (typeof internalDocument.props.theme === "object" && internalDocument.props.theme !== null) {
|
|
2256
|
-
inlineTheme = internalDocument.props.theme;
|
|
2257
|
-
internalDocument = {
|
|
2258
|
-
...internalDocument,
|
|
2259
|
-
props: {
|
|
2260
|
-
...internalDocument.props,
|
|
2261
|
-
theme: inlineTheme.name || "inline-theme"
|
|
2262
|
-
}
|
|
2263
|
-
};
|
|
2264
|
-
}
|
|
2265
|
-
const docThemeName = internalDocument.props.theme;
|
|
2266
|
-
const baseThemeName = docThemeName ?? (typeof state.theme === "string" ? state.theme : "default");
|
|
2267
|
-
let resolvedTheme = inlineTheme ?? state.customThemes?.[baseThemeName] ?? (typeof state.theme === "object" && state.theme !== null ? state.theme : getPptxTheme(baseThemeName));
|
|
2268
2496
|
const warnings = [];
|
|
2269
|
-
const
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2497
|
+
const context = resolveThemeContext(internalDocument, {
|
|
2498
|
+
customThemes: state.customThemes,
|
|
2499
|
+
fonts: state.fonts,
|
|
2500
|
+
warnings,
|
|
2501
|
+
defaultThemeName: typeof state.theme === "string" ? state.theme : void 0,
|
|
2502
|
+
resolveNamedTheme: (name) => state.customThemes?.[name] ?? (typeof state.theme === "object" && state.theme !== null ? state.theme : getPptxTheme(name))
|
|
2273
2503
|
});
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
warnings.push({
|
|
2277
|
-
code: w.code,
|
|
2278
|
-
message: w.message,
|
|
2279
|
-
component: "fontRegistry"
|
|
2280
|
-
});
|
|
2281
|
-
}
|
|
2504
|
+
const modedRoot = context.document;
|
|
2505
|
+
const resolvedTheme = context.theme;
|
|
2282
2506
|
const validateEmitted = validationOptions.enabled === false ? void 0 : (emitted, componentLabel, parentName) => {
|
|
2283
2507
|
let validationDocument;
|
|
2284
2508
|
if (parentName === "pptx") {
|
|
2285
|
-
validationDocument = { ...
|
|
2509
|
+
validationDocument = { ...modedRoot, children: emitted };
|
|
2286
2510
|
} else if (parentName === "slide") {
|
|
2287
2511
|
validationDocument = {
|
|
2288
|
-
...
|
|
2512
|
+
...modedRoot,
|
|
2289
2513
|
children: [{ name: "slide", props: {}, children: emitted }]
|
|
2290
2514
|
};
|
|
2291
2515
|
} else {
|
|
@@ -2306,19 +2530,16 @@ function createBuilderImpl(state) {
|
|
|
2306
2530
|
);
|
|
2307
2531
|
}
|
|
2308
2532
|
};
|
|
2309
|
-
const processedChildren =
|
|
2310
|
-
|
|
2533
|
+
const processedChildren = modedRoot.children ? await processAllSlides(
|
|
2534
|
+
modedRoot.children,
|
|
2311
2535
|
warnings,
|
|
2312
2536
|
resolvedTheme,
|
|
2313
2537
|
validateEmitted
|
|
2314
2538
|
) : [];
|
|
2315
|
-
const
|
|
2316
|
-
|
|
2317
|
-
...mode.doc,
|
|
2318
|
-
props: { ...mode.doc.props, theme: themeName },
|
|
2539
|
+
const processedDocument = {
|
|
2540
|
+
...modedRoot,
|
|
2319
2541
|
children: processedChildren
|
|
2320
|
-
}
|
|
2321
|
-
const processedDocument = docWithScopedTheme;
|
|
2542
|
+
};
|
|
2322
2543
|
if (validationOptions.enabled !== false) {
|
|
2323
2544
|
const result = validatePresentation(processedDocument, [], {
|
|
2324
2545
|
allowUnknownFields: validationOptions.allowUnknownFields
|
|
@@ -2339,19 +2560,18 @@ function createBuilderImpl(state) {
|
|
|
2339
2560
|
warnings,
|
|
2340
2561
|
state.fonts
|
|
2341
2562
|
);
|
|
2342
|
-
|
|
2343
|
-
...state.customThemes ?? {},
|
|
2344
|
-
[themeName]: resolvedTheme
|
|
2345
|
-
};
|
|
2563
|
+
assertNoContentConflicts(processedDocument);
|
|
2346
2564
|
const processed = processPresentation(processedDocument, {
|
|
2347
|
-
|
|
2565
|
+
theme: resolvedTheme,
|
|
2348
2566
|
services: state.services
|
|
2349
2567
|
});
|
|
2350
|
-
const
|
|
2568
|
+
const pendingFills = [];
|
|
2569
|
+
const pptx = await renderPresentation(processed, warnings, pendingFills);
|
|
2351
2570
|
const data = await pptx.write({ outputType: "nodebuffer" });
|
|
2352
2571
|
const buffer = await packagePresentationBuffer(data, {
|
|
2353
2572
|
deterministic: options?.deterministic ?? state.packaging.deterministic,
|
|
2354
|
-
generatedAt: options?.generatedAt ?? state.packaging.generatedAt
|
|
2573
|
+
generatedAt: options?.generatedAt ?? state.packaging.generatedAt,
|
|
2574
|
+
pendingFills
|
|
2355
2575
|
});
|
|
2356
2576
|
return { buffer, warnings };
|
|
2357
2577
|
} catch (error) {
|