pptx-viewer-mcp 2.2.0 → 2.4.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/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { PptxHandler, hasTextProperties, cloneElement as cloneElement$1, isTemplateElementId, makeStoreAwareId, reassignDescendantIds, groupElements as groupElements$1, ungroupElements as ungroupElements$1, PptxMarkdownConverter, ThemePresets, getThemePreset, setChartType, setChartTitle, setChartGrouping, setChartLegend, setChartDataLabels, setChartAxis, setChartCategories, addChartSeries, removeChartSeries, updateChartSeriesValues, ChartBuilder, listChartUserShapes, addChartUserShape, updateChartUserShape, removeChartUserShape, decomposeSmartArt, demoteSmartArtNode, promoteSmartArtNode, reorderSmartArtNode, updateSmartArtNodeText, removeSmartArtNode, addSmartArtNode, mergePresentation, diffPresentations, findPlaceholders, applyTemplate, getSectionForSlide, moveSlidesToSection, reorderSections, removeSection, addSection, SvgExporter, buildPptxJsonDocument, deserializePptxFromJson, applyImportedPptxData, replaceWithCustomGeometry, replaceShapeGeometry, setElementLocked, validatePptx, repairPptx, findLayoutByName, findLayoutByType } from 'pptx-viewer-core';
1
+ import { PptxHandler, hasTextProperties, resolveThemeColorRef, cloneElement as cloneElement$1, isTemplateElementId, makeStoreAwareId, reassignDescendantIds, groupElements as groupElements$1, ungroupElements as ungroupElements$1, TABLE_STYLE_PART_SEQUENCE, normalizeTableStyleGuid, createTableStyleEntry, addTableStyleToMap, deleteTableStyleFromMap, PptxMarkdownConverter, ThemePresets, getThemePreset, setChartType, setChartTitle, setChartGrouping, setChartLegend, setChartDataLabels, setChartAxis, setChartCategories, addChartSeries, removeChartSeries, updateChartSeriesValues, ChartBuilder, setChartDataPointStyle, setChartDataPointExplosion, setChartDataPointMarker, setChartDataPointLabel, setChartSeriesMarker, setChartSeriesTrendline, setChartSeriesErrorBars, setChartHelperLine, setChartColorMapOverride, listChartUserShapes, addChartUserShape, updateChartUserShape, removeChartUserShape, decomposeSmartArt, demoteSmartArtNode, promoteSmartArtNode, reorderSmartArtNode, updateSmartArtNodeText, removeSmartArtNode, addSmartArtNode, mergePresentation, diffPresentations, findPlaceholders, applyTemplate, getSectionForSlide, moveSlidesToSection, reorderSections, removeSection, addSection, SvgExporter, buildPptxJsonDocument, deserializePptxFromJson, applyImportedPptxData, replaceWithCustomGeometry, replaceShapeGeometry, setElementLocked, validatePptx, repairPptx, findLayoutByName, findLayoutByType } from 'pptx-viewer-core';
2
2
  export { PptxHandler } from 'pptx-viewer-core';
3
3
 
4
4
  // src/execution.ts
@@ -21,11 +21,17 @@ async function loadPresentation(filePath, execCtx) {
21
21
  const pptxData = await handler.load(rawBytes.buffer);
22
22
  return { pptxData, rawBytes };
23
23
  }
24
- async function savePresentation(filePath, pptxData, rawBytes, execCtx) {
24
+ async function savePresentation(filePath, pptxData, rawBytes, execCtx, tableStyleSaveOptions) {
25
25
  const handler = new PptxHandler();
26
26
  await handler.load(rawBytes.buffer);
27
27
  const outputBytes = await handler.save(pptxData.slides, {
28
- headerFooter: pptxData.headerFooter
28
+ headerFooter: pptxData.headerFooter,
29
+ // `pptxData.tableStyleMap` carries any in-memory table-style edits a
30
+ // tool made (e.g. `set_table_style_section`, `create_table_style`);
31
+ // without forwarding it here those edits were silently dropped on
32
+ // save even though the core save pipeline already supports them.
33
+ tableStyles: pptxData.tableStyleMap,
34
+ ...tableStyleSaveOptions
29
35
  });
30
36
  if (execCtx.collaboration) {
31
37
  const room = execCtx.collaboration.getRoom(filePath);
@@ -57,7 +63,13 @@ async function executeToolWithContext(filePath, execCtx, toolFn) {
57
63
  const { pptxData, rawBytes } = await loadPresentation(filePath, execCtx);
58
64
  const toolResult = await toolFn({ pptxData });
59
65
  if (toolResult.dirty) {
60
- const saveResult = await savePresentation(filePath, toolResult.pptxData, rawBytes, execCtx);
66
+ const saveResult = await savePresentation(
67
+ filePath,
68
+ toolResult.pptxData,
69
+ rawBytes,
70
+ execCtx,
71
+ toolResult.saveOptions
72
+ );
61
73
  return { ...toolResult.result, ...saveResult };
62
74
  }
63
75
  return toolResult.result;
@@ -382,6 +394,240 @@ function setCanvasSize(ctx, params) {
382
394
  result: { canvasWidth: params.width, canvasHeight: params.height }
383
395
  };
384
396
  }
397
+ var ALT_TEXT_ELEMENT_TYPES = /* @__PURE__ */ new Set(["image", "picture", "table", "chart", "smartArt", "ole", "media", "text", "shape", "connector"]);
398
+ var TITLE_ELEMENT_TYPES = /* @__PURE__ */ new Set([
399
+ "table",
400
+ "chart",
401
+ "smartArt",
402
+ "ole",
403
+ "media",
404
+ "text",
405
+ "shape",
406
+ "connector"
407
+ ]);
408
+ function applyElementAltText(el, altText) {
409
+ if (!ALT_TEXT_ELEMENT_TYPES.has(el.type)) {
410
+ throw new Error(
411
+ `Element '${el.id}' (${el.type}) does not support altText; only ${[...ALT_TEXT_ELEMENT_TYPES].join(", ")} elements do.`
412
+ );
413
+ }
414
+ el.altText = altText;
415
+ }
416
+ function applyElementTitle(el, title) {
417
+ if (!TITLE_ELEMENT_TYPES.has(el.type)) {
418
+ throw new Error(
419
+ `Element '${el.id}' (${el.type}) does not support title; only ${[...TITLE_ELEMENT_TYPES].join(", ")} elements do.`
420
+ );
421
+ }
422
+ el.title = title;
423
+ }
424
+ function updateElementStyle(ctx, params) {
425
+ const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
426
+ if (err) {
427
+ throw new Error(err);
428
+ }
429
+ const slide = ctx.pptxData.slides[params.slideIndex];
430
+ const el = slide.elements.find((e) => e.id === params.elementId);
431
+ if (!el) {
432
+ throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
433
+ }
434
+ if ("shapeStyle" in el) {
435
+ if (!el.shapeStyle) {
436
+ el.shapeStyle = {};
437
+ }
438
+ const ss = el.shapeStyle;
439
+ if (params.fillThemeColor !== void 0) {
440
+ ss.fillColorRef = params.fillThemeColor;
441
+ const resolved = resolveThemeColorRef(params.fillThemeColor, ctx.pptxData.themeColorMap);
442
+ if (params.fillColor !== void 0) {
443
+ ss.fillColor = params.fillColor;
444
+ } else if (resolved) {
445
+ ss.fillColor = resolved;
446
+ }
447
+ } else if (params.fillColor !== void 0) {
448
+ ss.fillColor = params.fillColor;
449
+ ss.fillColorRef = void 0;
450
+ }
451
+ if (params.fillMode !== void 0) {
452
+ ss.fillMode = params.fillMode;
453
+ }
454
+ if (params.fillGradientStops !== void 0) {
455
+ ss.fillGradientStops = params.fillGradientStops;
456
+ }
457
+ if (params.fillGradientAngle !== void 0) {
458
+ ss.fillGradientAngle = params.fillGradientAngle;
459
+ }
460
+ if (params.fillGradientType !== void 0) {
461
+ ss.fillGradientType = params.fillGradientType;
462
+ }
463
+ if (params.fillOpacity !== void 0) {
464
+ ss.fillOpacity = params.fillOpacity;
465
+ }
466
+ if (params.strokeThemeColor !== void 0) {
467
+ ss.strokeColorRef = params.strokeThemeColor;
468
+ const resolved = resolveThemeColorRef(params.strokeThemeColor, ctx.pptxData.themeColorMap);
469
+ if (params.strokeColor !== void 0) {
470
+ ss.strokeColor = params.strokeColor;
471
+ } else if (resolved) {
472
+ ss.strokeColor = resolved;
473
+ }
474
+ } else if (params.strokeColor !== void 0) {
475
+ ss.strokeColor = params.strokeColor;
476
+ ss.strokeColorRef = void 0;
477
+ }
478
+ if (params.strokeWidth !== void 0) {
479
+ ss.strokeWidth = params.strokeWidth;
480
+ }
481
+ if (params.strokeDash !== void 0) {
482
+ ss.strokeDash = params.strokeDash;
483
+ }
484
+ if (params.strokeOpacity !== void 0) {
485
+ ss.strokeOpacity = params.strokeOpacity;
486
+ }
487
+ if (params.shadowColor !== void 0) {
488
+ ss.shadowColor = params.shadowColor;
489
+ }
490
+ if (params.shadowBlur !== void 0) {
491
+ ss.shadowBlur = params.shadowBlur;
492
+ }
493
+ if (params.shadowOffsetX !== void 0) {
494
+ ss.shadowOffsetX = params.shadowOffsetX;
495
+ }
496
+ if (params.shadowOffsetY !== void 0) {
497
+ ss.shadowOffsetY = params.shadowOffsetY;
498
+ }
499
+ if (params.shadowOpacity !== void 0) {
500
+ ss.shadowOpacity = params.shadowOpacity;
501
+ }
502
+ if (params.glowColor !== void 0) {
503
+ ss.glowColor = params.glowColor;
504
+ }
505
+ if (params.glowRadius !== void 0) {
506
+ ss.glowRadius = params.glowRadius;
507
+ }
508
+ if (params.glowOpacity !== void 0) {
509
+ ss.glowOpacity = params.glowOpacity;
510
+ }
511
+ if (params.softEdgeRadius !== void 0) {
512
+ ss.softEdgeRadius = params.softEdgeRadius;
513
+ }
514
+ }
515
+ if (params.altText !== void 0) {
516
+ applyElementAltText(el, params.altText);
517
+ }
518
+ if (params.title !== void 0) {
519
+ applyElementTitle(el, params.title);
520
+ }
521
+ if (el.type === "image" || el.type === "picture") {
522
+ const img = el;
523
+ if (params.cropLeft !== void 0) {
524
+ img.cropLeft = params.cropLeft;
525
+ }
526
+ if (params.cropTop !== void 0) {
527
+ img.cropTop = params.cropTop;
528
+ }
529
+ if (params.cropRight !== void 0) {
530
+ img.cropRight = params.cropRight;
531
+ }
532
+ if (params.cropBottom !== void 0) {
533
+ img.cropBottom = params.cropBottom;
534
+ }
535
+ if (params.brightness !== void 0 || params.contrast !== void 0 || params.grayscale !== void 0) {
536
+ if (!img.imageEffects) {
537
+ img.imageEffects = {};
538
+ }
539
+ if (params.brightness !== void 0) {
540
+ img.imageEffects.brightness = params.brightness;
541
+ }
542
+ if (params.contrast !== void 0) {
543
+ img.imageEffects.contrast = params.contrast;
544
+ }
545
+ if (params.grayscale !== void 0) {
546
+ img.imageEffects.grayscale = params.grayscale;
547
+ }
548
+ }
549
+ }
550
+ return {
551
+ pptxData: ctx.pptxData,
552
+ dirty: true,
553
+ result: { elementId: params.elementId }
554
+ };
555
+ }
556
+ function runAccessibilityCheck(ctx) {
557
+ const issues = [];
558
+ for (let si = 0; si < ctx.pptxData.slides.length; si++) {
559
+ const slide = ctx.pptxData.slides[si];
560
+ let slideHasText = false;
561
+ for (const el of slide.elements) {
562
+ if (el.type === "image" || el.type === "picture") {
563
+ const img = el;
564
+ if (!img.altText) {
565
+ issues.push({
566
+ slideIndex: si,
567
+ elementId: el.id,
568
+ severity: "error",
569
+ message: `Image element '${el.id}' has no alt text.`
570
+ });
571
+ }
572
+ }
573
+ if (hasTextProperties(el)) {
574
+ const textEl = el;
575
+ slideHasText = true;
576
+ if (!textEl.text || textEl.text.trim() === "") {
577
+ issues.push({
578
+ slideIndex: si,
579
+ elementId: el.id,
580
+ severity: "info",
581
+ message: `Text element '${el.id}' is empty.`
582
+ });
583
+ }
584
+ const fs = textEl.textStyle?.fontSize;
585
+ if (fs !== void 0 && fs < 10) {
586
+ issues.push({
587
+ slideIndex: si,
588
+ elementId: el.id,
589
+ severity: "warning",
590
+ message: `Text element '${el.id}' has very small font size (${fs}pt < 10pt).`
591
+ });
592
+ }
593
+ const textColor = textEl.textStyle?.color?.toLowerCase();
594
+ const bgColor = slide.backgroundColor?.toLowerCase();
595
+ if (textColor && bgColor && textColor === bgColor) {
596
+ issues.push({
597
+ slideIndex: si,
598
+ elementId: el.id,
599
+ severity: "error",
600
+ message: `Text element '${el.id}' has same color as slide background (${textColor}).`
601
+ });
602
+ }
603
+ }
604
+ }
605
+ if (!slideHasText) {
606
+ issues.push({
607
+ slideIndex: si,
608
+ severity: "warning",
609
+ message: `Slide ${si + 1} contains no text elements.`
610
+ });
611
+ }
612
+ }
613
+ const errorCount = issues.filter((i) => i.severity === "error").length;
614
+ const warningCount = issues.filter((i) => i.severity === "warning").length;
615
+ const infoCount = issues.filter((i) => i.severity === "info").length;
616
+ return {
617
+ pptxData: ctx.pptxData,
618
+ dirty: false,
619
+ result: {
620
+ slideCount: ctx.pptxData.slides.length,
621
+ totalIssues: issues.length,
622
+ errorCount,
623
+ warningCount,
624
+ infoCount,
625
+ issues
626
+ }
627
+ };
628
+ }
629
+
630
+ // src/tools/element-tools.ts
385
631
  function addElement(ctx, params) {
386
632
  const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
387
633
  if (err) {
@@ -561,6 +807,12 @@ function updateElement(ctx, params) {
561
807
  if (params.flipV !== void 0) {
562
808
  el.flipVertical = params.flipV;
563
809
  }
810
+ if (params.altText !== void 0) {
811
+ applyElementAltText(el, params.altText);
812
+ }
813
+ if (params.title !== void 0) {
814
+ applyElementTitle(el, params.title);
815
+ }
564
816
  if (hasTextProperties(el)) {
565
817
  const textEl = el;
566
818
  if (params.text !== void 0) {
@@ -580,8 +832,17 @@ function updateElement(ctx, params) {
580
832
  if (params.fontFamily !== void 0) {
581
833
  textEl.textStyle.fontFamily = params.fontFamily;
582
834
  }
583
- if (params.fontColor !== void 0) {
835
+ if (params.fontThemeColor !== void 0) {
836
+ textEl.textStyle.colorRef = params.fontThemeColor;
837
+ const resolved = resolveThemeColorRef(params.fontThemeColor, ctx.pptxData.themeColorMap);
838
+ if (params.fontColor !== void 0) {
839
+ textEl.textStyle.color = params.fontColor;
840
+ } else if (resolved) {
841
+ textEl.textStyle.color = resolved;
842
+ }
843
+ } else if (params.fontColor !== void 0) {
584
844
  textEl.textStyle.color = params.fontColor;
845
+ textEl.textStyle.colorRef = void 0;
585
846
  }
586
847
  if (params.bold !== void 0) {
587
848
  textEl.textStyle.bold = params.bold;
@@ -1072,188 +1333,140 @@ function manageTableStructure(ctx, params) {
1072
1333
  }
1073
1334
  };
1074
1335
  }
1075
- function updateElementStyle(ctx, params) {
1076
- const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
1336
+ function findTableElement(ctx, slideIndex, elementId) {
1337
+ const err = validateSlideIndex(slideIndex, ctx.pptxData.slides.length);
1077
1338
  if (err) {
1078
1339
  throw new Error(err);
1079
1340
  }
1080
- const slide = ctx.pptxData.slides[params.slideIndex];
1081
- const el = slide.elements.find((e) => e.id === params.elementId);
1341
+ const slide = ctx.pptxData.slides[slideIndex];
1342
+ const el = slide.elements.find((e) => e.id === elementId);
1082
1343
  if (!el) {
1083
- throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
1344
+ throw new Error(`Element '${elementId}' not found on slide ${slideIndex}.`);
1084
1345
  }
1085
- if ("shapeStyle" in el) {
1086
- if (!el.shapeStyle) {
1087
- el.shapeStyle = {};
1088
- }
1089
- const ss = el.shapeStyle;
1090
- if (params.fillColor !== void 0) {
1091
- ss.fillColor = params.fillColor;
1092
- }
1093
- if (params.fillMode !== void 0) {
1094
- ss.fillMode = params.fillMode;
1095
- }
1096
- if (params.fillGradientStops !== void 0) {
1097
- ss.fillGradientStops = params.fillGradientStops;
1098
- }
1099
- if (params.fillGradientAngle !== void 0) {
1100
- ss.fillGradientAngle = params.fillGradientAngle;
1101
- }
1102
- if (params.fillGradientType !== void 0) {
1103
- ss.fillGradientType = params.fillGradientType;
1104
- }
1105
- if (params.fillOpacity !== void 0) {
1106
- ss.fillOpacity = params.fillOpacity;
1107
- }
1108
- if (params.strokeColor !== void 0) {
1109
- ss.strokeColor = params.strokeColor;
1110
- }
1111
- if (params.strokeWidth !== void 0) {
1112
- ss.strokeWidth = params.strokeWidth;
1113
- }
1114
- if (params.strokeDash !== void 0) {
1115
- ss.strokeDash = params.strokeDash;
1116
- }
1117
- if (params.strokeOpacity !== void 0) {
1118
- ss.strokeOpacity = params.strokeOpacity;
1119
- }
1120
- if (params.shadowColor !== void 0) {
1121
- ss.shadowColor = params.shadowColor;
1122
- }
1123
- if (params.shadowBlur !== void 0) {
1124
- ss.shadowBlur = params.shadowBlur;
1125
- }
1126
- if (params.shadowOffsetX !== void 0) {
1127
- ss.shadowOffsetX = params.shadowOffsetX;
1128
- }
1129
- if (params.shadowOffsetY !== void 0) {
1130
- ss.shadowOffsetY = params.shadowOffsetY;
1131
- }
1132
- if (params.shadowOpacity !== void 0) {
1133
- ss.shadowOpacity = params.shadowOpacity;
1134
- }
1135
- if (params.glowColor !== void 0) {
1136
- ss.glowColor = params.glowColor;
1137
- }
1138
- if (params.glowRadius !== void 0) {
1139
- ss.glowRadius = params.glowRadius;
1140
- }
1141
- if (params.glowOpacity !== void 0) {
1142
- ss.glowOpacity = params.glowOpacity;
1143
- }
1144
- if (params.softEdgeRadius !== void 0) {
1145
- ss.softEdgeRadius = params.softEdgeRadius;
1146
- }
1346
+ if (el.type !== "table") {
1347
+ throw new Error(`Element '${elementId}' is not a table.`);
1147
1348
  }
1148
- if (el.type === "image" || el.type === "picture") {
1149
- const img = el;
1150
- if (params.altText !== void 0) {
1151
- img.altText = params.altText;
1152
- }
1153
- if (params.cropLeft !== void 0) {
1154
- img.cropLeft = params.cropLeft;
1155
- }
1156
- if (params.cropTop !== void 0) {
1157
- img.cropTop = params.cropTop;
1158
- }
1159
- if (params.cropRight !== void 0) {
1160
- img.cropRight = params.cropRight;
1161
- }
1162
- if (params.cropBottom !== void 0) {
1163
- img.cropBottom = params.cropBottom;
1164
- }
1165
- if (params.brightness !== void 0 || params.contrast !== void 0 || params.grayscale !== void 0) {
1166
- if (!img.imageEffects) {
1167
- img.imageEffects = {};
1168
- }
1169
- if (params.brightness !== void 0) {
1170
- img.imageEffects.brightness = params.brightness;
1171
- }
1172
- if (params.contrast !== void 0) {
1173
- img.imageEffects.contrast = params.contrast;
1174
- }
1175
- if (params.grayscale !== void 0) {
1176
- img.imageEffects.grayscale = params.grayscale;
1349
+ return el;
1350
+ }
1351
+ function tableStyleIdsInUse(ctx) {
1352
+ const used = /* @__PURE__ */ new Set();
1353
+ for (const slide of ctx.pptxData.slides) {
1354
+ for (const el of slide.elements) {
1355
+ if (el.type === "table" && el.tableData?.tableStyleId) {
1356
+ used.add(normalizeTableStyleGuid(el.tableData.tableStyleId));
1177
1357
  }
1178
1358
  }
1179
1359
  }
1360
+ return used;
1361
+ }
1362
+ function setTableStyleSection(ctx, params) {
1363
+ if (!TABLE_STYLE_PART_SEQUENCE.includes(params.section)) {
1364
+ throw new Error(
1365
+ `Unknown table style section '${params.section}'. Valid sections: ${TABLE_STYLE_PART_SEQUENCE.join(", ")}.`
1366
+ );
1367
+ }
1368
+ const map = ctx.pptxData.tableStyleMap ?? {};
1369
+ ctx.pptxData.tableStyleMap = map;
1370
+ const normalizedId = normalizeTableStyleGuid(params.styleId);
1371
+ const entry = map[normalizedId];
1372
+ if (!entry) {
1373
+ throw new Error(
1374
+ `Table style '${params.styleId}' is not loaded in this presentation. Use create_table_style to add a new one.`
1375
+ );
1376
+ }
1377
+ if (params.styleName !== void 0) {
1378
+ entry.styleName = params.styleName;
1379
+ }
1380
+ const mutableEntry = entry;
1381
+ if (params.fill !== void 0) {
1382
+ mutableEntry[`${params.section}Fill`] = params.fill;
1383
+ }
1384
+ if (params.text !== void 0) {
1385
+ mutableEntry[`${params.section}Text`] = params.text;
1386
+ }
1387
+ if (params.borders !== void 0) {
1388
+ mutableEntry[`${params.section}Borders`] = params.borders;
1389
+ }
1390
+ if (params.cell3D !== void 0) {
1391
+ mutableEntry[`${params.section}Cell3D`] = params.cell3D;
1392
+ }
1180
1393
  return {
1181
1394
  pptxData: ctx.pptxData,
1182
1395
  dirty: true,
1183
- result: { elementId: params.elementId }
1396
+ result: { styleId: normalizedId, section: params.section }
1184
1397
  };
1185
1398
  }
1186
- function runAccessibilityCheck(ctx) {
1187
- const issues = [];
1188
- for (let si = 0; si < ctx.pptxData.slides.length; si++) {
1189
- const slide = ctx.pptxData.slides[si];
1190
- let slideHasText = false;
1191
- for (const el of slide.elements) {
1192
- if (el.type === "image" || el.type === "picture") {
1193
- const img = el;
1194
- if (!img.altText) {
1195
- issues.push({
1196
- slideIndex: si,
1197
- elementId: el.id,
1198
- severity: "error",
1199
- message: `Image element '${el.id}' has no alt text.`
1200
- });
1201
- }
1202
- }
1203
- if (hasTextProperties(el)) {
1204
- const textEl = el;
1205
- slideHasText = true;
1206
- if (!textEl.text || textEl.text.trim() === "") {
1207
- issues.push({
1208
- slideIndex: si,
1209
- elementId: el.id,
1210
- severity: "info",
1211
- message: `Text element '${el.id}' is empty.`
1212
- });
1213
- }
1214
- const fs = textEl.textStyle?.fontSize;
1215
- if (fs !== void 0 && fs < 10) {
1216
- issues.push({
1217
- slideIndex: si,
1218
- elementId: el.id,
1219
- severity: "warning",
1220
- message: `Text element '${el.id}' has very small font size (${fs}pt < 10pt).`
1221
- });
1222
- }
1223
- const textColor = textEl.textStyle?.color?.toLowerCase();
1224
- const bgColor = slide.backgroundColor?.toLowerCase();
1225
- if (textColor && bgColor && textColor === bgColor) {
1226
- issues.push({
1227
- slideIndex: si,
1228
- elementId: el.id,
1229
- severity: "error",
1230
- message: `Text element '${el.id}' has same color as slide background (${textColor}).`
1231
- });
1232
- }
1233
- }
1234
- }
1235
- if (!slideHasText) {
1236
- issues.push({
1237
- slideIndex: si,
1238
- severity: "warning",
1239
- message: `Slide ${si + 1} contains no text elements.`
1240
- });
1241
- }
1399
+ function createTableStyle(ctx, params) {
1400
+ const map = ctx.pptxData.tableStyleMap ?? {};
1401
+ ctx.pptxData.tableStyleMap = map;
1402
+ const basedOn = params.basedOnStyleId ? map[normalizeTableStyleGuid(params.basedOnStyleId)] : void 0;
1403
+ if (params.basedOnStyleId && !basedOn) {
1404
+ throw new Error(`basedOnStyleId '${params.basedOnStyleId}' is not a loaded table style.`);
1242
1405
  }
1243
- const errorCount = issues.filter((i) => i.severity === "error").length;
1244
- const warningCount = issues.filter((i) => i.severity === "warning").length;
1245
- const infoCount = issues.filter((i) => i.severity === "info").length;
1406
+ const entry = createTableStyleEntry(map, { styleName: params.styleName, basedOn });
1407
+ addTableStyleToMap(map, entry);
1246
1408
  return {
1247
1409
  pptxData: ctx.pptxData,
1248
- dirty: false,
1249
- result: {
1250
- slideCount: ctx.pptxData.slides.length,
1251
- totalIssues: issues.length,
1252
- errorCount,
1253
- warningCount,
1254
- infoCount,
1255
- issues
1410
+ dirty: true,
1411
+ result: { styleId: entry.styleId },
1412
+ ...params.setAsDefault ? { saveOptions: { tableStylesDefaultId: entry.styleId } } : {}
1413
+ };
1414
+ }
1415
+ function deleteTableStyle(ctx, params) {
1416
+ const normalizedId = normalizeTableStyleGuid(params.styleId);
1417
+ if (!params.force) {
1418
+ const used = tableStyleIdsInUse(ctx);
1419
+ if (used.has(normalizedId)) {
1420
+ throw new Error(
1421
+ `Table style '${params.styleId}' is assigned to at least one table on this deck. Reassign those tables first, or pass force: true.`
1422
+ );
1256
1423
  }
1424
+ }
1425
+ const map = ctx.pptxData.tableStyleMap ?? {};
1426
+ ctx.pptxData.tableStyleMap = map;
1427
+ deleteTableStyleFromMap(map, normalizedId);
1428
+ return {
1429
+ pptxData: ctx.pptxData,
1430
+ dirty: true,
1431
+ result: { deleted: true },
1432
+ saveOptions: { tableStylesToDelete: [normalizedId] }
1433
+ };
1434
+ }
1435
+ function assignTableStyle(ctx, params) {
1436
+ const el = findTableElement(ctx, params.slideIndex, params.elementId);
1437
+ if (!el.tableData) {
1438
+ throw new Error(`Table '${params.elementId}' has no tableData.`);
1439
+ }
1440
+ const styleId = params.styleId ?? ctx.pptxData.tableStylesDefaultId;
1441
+ if (!styleId) {
1442
+ throw new Error(
1443
+ "styleId was not provided and this presentation has no tableStylesDefaultId to fall back to."
1444
+ );
1445
+ }
1446
+ const normalizedId = normalizeTableStyleGuid(styleId);
1447
+ el.tableData.tableStyleId = normalizedId;
1448
+ if (params.bandedRows !== void 0) {
1449
+ el.tableData.bandedRows = params.bandedRows;
1450
+ }
1451
+ if (params.bandedColumns !== void 0) {
1452
+ el.tableData.bandedColumns = params.bandedColumns;
1453
+ }
1454
+ if (params.firstRowHeader !== void 0) {
1455
+ el.tableData.firstRowHeader = params.firstRowHeader;
1456
+ }
1457
+ if (params.lastRow !== void 0) {
1458
+ el.tableData.lastRow = params.lastRow;
1459
+ }
1460
+ if (params.firstCol !== void 0) {
1461
+ el.tableData.firstCol = params.firstCol;
1462
+ }
1463
+ if (params.lastCol !== void 0) {
1464
+ el.tableData.lastCol = params.lastCol;
1465
+ }
1466
+ return {
1467
+ pptxData: ctx.pptxData,
1468
+ dirty: true,
1469
+ result: { elementId: params.elementId, styleId: normalizedId }
1257
1470
  };
1258
1471
  }
1259
1472
  var MAX_REGEX_LEN = 200;
@@ -1862,6 +2075,98 @@ function findChartElement(ctx, slideIndex, elementId) {
1862
2075
  }
1863
2076
  return el;
1864
2077
  }
2078
+ function formatChartDataPoint(ctx, params) {
2079
+ const chart = findChartElement(ctx, params.slideIndex, params.elementId);
2080
+ if (params.clearStyle) {
2081
+ setChartDataPointStyle(chart, params.seriesIndex, params.pointIndex, null);
2082
+ } else if (params.fillColor !== void 0 || params.strokeColor !== void 0 || params.strokeWidth !== void 0 || params.strokeDashStyle !== void 0) {
2083
+ setChartDataPointStyle(chart, params.seriesIndex, params.pointIndex, {
2084
+ ...params.fillColor !== void 0 ? { fillColor: params.fillColor } : {},
2085
+ ...params.strokeColor !== void 0 ? { strokeColor: params.strokeColor } : {},
2086
+ ...params.strokeWidth !== void 0 ? { strokeWidth: params.strokeWidth } : {},
2087
+ ...params.strokeDashStyle !== void 0 ? { strokeDashStyle: params.strokeDashStyle } : {}
2088
+ });
2089
+ }
2090
+ if (params.explosion !== void 0) {
2091
+ setChartDataPointExplosion(chart, params.seriesIndex, params.pointIndex, params.explosion);
2092
+ }
2093
+ if (params.marker !== void 0) {
2094
+ setChartDataPointMarker(chart, params.seriesIndex, params.pointIndex, params.marker);
2095
+ }
2096
+ return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
2097
+ }
2098
+ function formatChartDataLabel(ctx, params) {
2099
+ const chart = findChartElement(ctx, params.slideIndex, params.elementId);
2100
+ if (params.remove) {
2101
+ setChartDataPointLabel(chart, params.seriesIndex, params.pointIndex, null);
2102
+ return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
2103
+ }
2104
+ setChartDataPointLabel(chart, params.seriesIndex, params.pointIndex, {
2105
+ ...params.showValue !== void 0 ? { showValue: params.showValue } : {},
2106
+ ...params.showCategory !== void 0 ? { showCategory: params.showCategory } : {},
2107
+ ...params.showSeriesName !== void 0 ? { showSeriesName: params.showSeriesName } : {},
2108
+ ...params.showPercent !== void 0 ? { showPercent: params.showPercent } : {},
2109
+ ...params.showLegendKey !== void 0 ? { showLegendKey: params.showLegendKey } : {},
2110
+ ...params.position !== void 0 ? { position: params.position } : {},
2111
+ ...params.text !== void 0 ? { text: params.text } : {},
2112
+ ...params.spPr !== void 0 ? { spPr: params.spPr } : {},
2113
+ ...params.txPr !== void 0 ? { txPr: params.txPr } : {}
2114
+ });
2115
+ return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
2116
+ }
2117
+ function formatChartSeries(ctx, params) {
2118
+ const chart = findChartElement(ctx, params.slideIndex, params.elementId);
2119
+ if (params.marker !== void 0) {
2120
+ if (params.marker === null) {
2121
+ setChartSeriesMarker(chart, params.seriesIndex, null);
2122
+ } else if (params.marker.strokeColor !== void 0 || params.marker.strokeWidth !== void 0 || params.marker.strokeDashStyle !== void 0) {
2123
+ setChartSeriesMarker(chart, params.seriesIndex, {
2124
+ symbol: params.marker.symbol ?? "circle",
2125
+ ...params.marker.size !== void 0 ? { size: params.marker.size } : {},
2126
+ spPr: {
2127
+ ...params.marker.fillColor !== void 0 ? { fillColor: params.marker.fillColor } : {},
2128
+ ...params.marker.strokeColor !== void 0 ? { strokeColor: params.marker.strokeColor } : {},
2129
+ ...params.marker.strokeWidth !== void 0 ? { strokeWidth: params.marker.strokeWidth } : {},
2130
+ ...params.marker.strokeDashStyle !== void 0 ? { strokeDashStyle: params.marker.strokeDashStyle } : {}
2131
+ }
2132
+ });
2133
+ } else {
2134
+ setChartSeriesMarker(chart, params.seriesIndex, params.marker);
2135
+ }
2136
+ }
2137
+ if (params.trendline !== void 0) {
2138
+ setChartSeriesTrendline(chart, params.seriesIndex, params.trendline);
2139
+ }
2140
+ if (params.errorBars !== void 0) {
2141
+ setChartSeriesErrorBars(chart, params.seriesIndex, params.errorBars);
2142
+ }
2143
+ return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
2144
+ }
2145
+ function setChartHelperLineT(ctx, params) {
2146
+ const chart = findChartElement(ctx, params.slideIndex, params.elementId);
2147
+ setChartHelperLine(chart, params.line, params.style);
2148
+ return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
2149
+ }
2150
+ function setChartColorMapOverrideT(ctx, params) {
2151
+ const chart = findChartElement(ctx, params.slideIndex, params.elementId);
2152
+ setChartColorMapOverride(chart, params.overrides);
2153
+ return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
2154
+ }
2155
+ function findChartElement2(ctx, slideIndex, elementId) {
2156
+ const err = validateSlideIndex(slideIndex, ctx.pptxData.slides.length);
2157
+ if (err) {
2158
+ throw new Error(err);
2159
+ }
2160
+ const slide = ctx.pptxData.slides[slideIndex];
2161
+ const el = slide.elements.find((e) => e.id === elementId);
2162
+ if (!el) {
2163
+ throw new Error(`Element '${elementId}' not found on slide ${slideIndex}.`);
2164
+ }
2165
+ if (el.type !== "chart") {
2166
+ throw new Error(`Element '${elementId}' is not a chart.`);
2167
+ }
2168
+ return el;
2169
+ }
1865
2170
  function buildShape(input) {
1866
2171
  return {
1867
2172
  kind: input.kind ?? "sp",
@@ -1877,17 +2182,17 @@ function buildShape(input) {
1877
2182
  };
1878
2183
  }
1879
2184
  function listChartUserShapesT(ctx, params) {
1880
- const chart = findChartElement(ctx, params.slideIndex, params.elementId);
2185
+ const chart = findChartElement2(ctx, params.slideIndex, params.elementId);
1881
2186
  return { pptxData: ctx.pptxData, dirty: false, result: { shapes: listChartUserShapes(chart) } };
1882
2187
  }
1883
2188
  function addChartUserShapeT(ctx, params) {
1884
- const chart = findChartElement(ctx, params.slideIndex, params.elementId);
2189
+ const chart = findChartElement2(ctx, params.slideIndex, params.elementId);
1885
2190
  addChartUserShape(chart, buildShape(params.shape));
1886
2191
  const index = (chart.chartData?.userShapes?.length ?? 1) - 1;
1887
2192
  return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId, index } };
1888
2193
  }
1889
2194
  function updateChartUserShapeT(ctx, params) {
1890
- const chart = findChartElement(ctx, params.slideIndex, params.elementId);
2195
+ const chart = findChartElement2(ctx, params.slideIndex, params.elementId);
1891
2196
  const patch = {
1892
2197
  ...params.patch.kind ? { kind: params.patch.kind } : {},
1893
2198
  ...params.patch.anchor ? { anchor: params.patch.anchor } : {},
@@ -1904,7 +2209,7 @@ function updateChartUserShapeT(ctx, params) {
1904
2209
  return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
1905
2210
  }
1906
2211
  function removeChartUserShapeT(ctx, params) {
1907
- const chart = findChartElement(ctx, params.slideIndex, params.elementId);
2212
+ const chart = findChartElement2(ctx, params.slideIndex, params.elementId);
1908
2213
  removeChartUserShape(chart, params.index);
1909
2214
  return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
1910
2215
  }
@@ -2648,4 +2953,4 @@ function applyLayout(ctx, params) {
2648
2953
  };
2649
2954
  }
2650
2955
 
2651
- export { addChartSeriesT, addChartUserShapeT, addElement, addSlide, applyLayout, applyTemplateT, applyThemePreset, arrangeElements, batchUpdateElements, cloneElement, convertToMarkdown, createChart, deleteElements, deleteSlides, describeElement, diffPresentationsT, duplicateSlide, executeToolWithContext, exportSlideSvg, exportToJson, exportToSvg, extractSlideText, findPlaceholdersT, findText, generateElementId, generateSlideId, getLayouts, getMetadata, getPresentationProperties, getSlide, getThemeInfo, groupElements, importFromJson, listChartUserShapesT, loadPresentation, manageComments, manageHyperlinks, manageSections, manageSmartArt, manageTableStructure, mergePresentationT, removeChartSeriesT, removeChartUserShapeT, renameElement, reorderSlides, repairPresentation, replaceGeometry, replaceText, runAccessibilityCheck, savePresentation, setCanvasSize, setElementAnimation, setElementLockT, setSlideTransition, ungroupElements, updateChart, updateChartSeriesData, updateChartUserShapeT, updateElement, updateElementStyle, updateMetadata, updatePresentationProperties, updateSlideProperties, updateTableCells, updateThemeColors, updateThemeFonts, validatePresentation, validateSlideIndex };
2956
+ export { addChartSeriesT, addChartUserShapeT, addElement, addSlide, applyLayout, applyTemplateT, applyThemePreset, arrangeElements, assignTableStyle, batchUpdateElements, cloneElement, convertToMarkdown, createChart, createTableStyle, deleteElements, deleteSlides, deleteTableStyle, describeElement, diffPresentationsT, duplicateSlide, executeToolWithContext, exportSlideSvg, exportToJson, exportToSvg, extractSlideText, findPlaceholdersT, findText, formatChartDataLabel, formatChartDataPoint, formatChartSeries, generateElementId, generateSlideId, getLayouts, getMetadata, getPresentationProperties, getSlide, getThemeInfo, groupElements, importFromJson, listChartUserShapesT, loadPresentation, manageComments, manageHyperlinks, manageSections, manageSmartArt, manageTableStructure, mergePresentationT, removeChartSeriesT, removeChartUserShapeT, renameElement, reorderSlides, repairPresentation, replaceGeometry, replaceText, runAccessibilityCheck, savePresentation, setCanvasSize, setChartColorMapOverrideT, setChartHelperLineT, setElementAnimation, setElementLockT, setSlideTransition, setTableStyleSection, ungroupElements, updateChart, updateChartSeriesData, updateChartUserShapeT, updateElement, updateElementStyle, updateMetadata, updatePresentationProperties, updateSlideProperties, updateTableCells, updateThemeColors, updateThemeFonts, validatePresentation, validateSlideIndex };