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/CHANGELOG.md +12 -0
- package/README.md +20 -19
- package/dist/index.d.ts +237 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +486 -172
- package/dist/index.mjs +479 -174
- package/dist/mcp/index.js +1044 -281
- package/dist/mcp/index.mjs +1045 -282
- package/dist/schemas/index.d.ts +604 -1
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/schemas/index.js +338 -2
- package/dist/schemas/index.mjs +325 -3
- package/package.json +2 -2
package/dist/mcp/index.js
CHANGED
|
@@ -68,6 +68,32 @@ var ConvertToMarkdownSchema = zod.z.object({
|
|
|
68
68
|
var AccessibilityCheckSchema = zod.z.object({
|
|
69
69
|
filePath: zod.z.string().describe("Path to the PPTX file")
|
|
70
70
|
});
|
|
71
|
+
var ThemeColorRefSchema = zod.z.object({
|
|
72
|
+
scheme: zod.z.enum([
|
|
73
|
+
"dk1",
|
|
74
|
+
"lt1",
|
|
75
|
+
"dk2",
|
|
76
|
+
"lt2",
|
|
77
|
+
"accent1",
|
|
78
|
+
"accent2",
|
|
79
|
+
"accent3",
|
|
80
|
+
"accent4",
|
|
81
|
+
"accent5",
|
|
82
|
+
"accent6",
|
|
83
|
+
"hlink",
|
|
84
|
+
"folHlink",
|
|
85
|
+
"bg1",
|
|
86
|
+
"tx1",
|
|
87
|
+
"bg2",
|
|
88
|
+
"tx2",
|
|
89
|
+
"phClr"
|
|
90
|
+
]),
|
|
91
|
+
lumMod: zod.z.number().optional().describe("Multiply HSL luminance (0..1)"),
|
|
92
|
+
lumOff: zod.z.number().optional().describe("Add to HSL luminance after lumMod (0..1)"),
|
|
93
|
+
tint: zod.z.number().optional().describe("Blend towards white (0..1)"),
|
|
94
|
+
shade: zod.z.number().optional().describe("Blend towards black (0..1)"),
|
|
95
|
+
alpha: zod.z.number().optional().describe("Opacity fraction, 1 = opaque")
|
|
96
|
+
});
|
|
71
97
|
var AddElementSchema = zod.z.object({
|
|
72
98
|
filePath: zod.z.string().describe("Path to the PPTX file"),
|
|
73
99
|
slideIndex: zod.z.number().int().min(0).describe("Zero-based slide index"),
|
|
@@ -112,6 +138,12 @@ var UpdateElementSchema = zod.z.object({
|
|
|
112
138
|
fontSize: zod.z.number().optional(),
|
|
113
139
|
fontFamily: zod.z.string().optional(),
|
|
114
140
|
fontColor: zod.z.string().optional(),
|
|
141
|
+
/**
|
|
142
|
+
* A theme colour for the run text. Wins on save; resolves `fontColor`
|
|
143
|
+
* immediately when `fontColor` was not also given. Passing `fontColor`
|
|
144
|
+
* alone clears a previously-set text theme colour.
|
|
145
|
+
*/
|
|
146
|
+
fontThemeColor: ThemeColorRefSchema.optional(),
|
|
115
147
|
bold: zod.z.boolean().optional(),
|
|
116
148
|
italic: zod.z.boolean().optional(),
|
|
117
149
|
underline: zod.z.boolean().optional(),
|
|
@@ -122,7 +154,13 @@ var UpdateElementSchema = zod.z.object({
|
|
|
122
154
|
opacity: zod.z.number().min(0).max(1).optional(),
|
|
123
155
|
hidden: zod.z.boolean().optional(),
|
|
124
156
|
flipH: zod.z.boolean().optional(),
|
|
125
|
-
flipV: zod.z.boolean().optional()
|
|
157
|
+
flipV: zod.z.boolean().optional(),
|
|
158
|
+
altText: zod.z.string().optional().describe(
|
|
159
|
+
"Accessibility description (p:cNvPr/@descr) for image, picture, table, chart, smartArt, ole, media, text, shape and connector elements"
|
|
160
|
+
),
|
|
161
|
+
title: zod.z.string().optional().describe(
|
|
162
|
+
"Accessibility title (p:cNvPr/@title) for table, chart, smartArt, ole, media, text, shape and connector elements (not pictures)"
|
|
163
|
+
)
|
|
126
164
|
});
|
|
127
165
|
var RenameElementSchema = zod.z.object({
|
|
128
166
|
filePath: zod.z.string().describe("Path to the PPTX file"),
|
|
@@ -184,6 +222,32 @@ var BatchUpdateElementsSchema = zod.z.object({
|
|
|
184
222
|
opacity: zod.z.number().min(0).max(1).optional(),
|
|
185
223
|
hidden: zod.z.boolean().optional()
|
|
186
224
|
});
|
|
225
|
+
var ThemeColorRefSchema2 = zod.z.object({
|
|
226
|
+
scheme: zod.z.enum([
|
|
227
|
+
"dk1",
|
|
228
|
+
"lt1",
|
|
229
|
+
"dk2",
|
|
230
|
+
"lt2",
|
|
231
|
+
"accent1",
|
|
232
|
+
"accent2",
|
|
233
|
+
"accent3",
|
|
234
|
+
"accent4",
|
|
235
|
+
"accent5",
|
|
236
|
+
"accent6",
|
|
237
|
+
"hlink",
|
|
238
|
+
"folHlink",
|
|
239
|
+
"bg1",
|
|
240
|
+
"tx1",
|
|
241
|
+
"bg2",
|
|
242
|
+
"tx2",
|
|
243
|
+
"phClr"
|
|
244
|
+
]),
|
|
245
|
+
lumMod: zod.z.number().optional().describe("Multiply HSL luminance (0..1)"),
|
|
246
|
+
lumOff: zod.z.number().optional().describe("Add to HSL luminance after lumMod (0..1)"),
|
|
247
|
+
tint: zod.z.number().optional().describe("Blend towards white (0..1)"),
|
|
248
|
+
shade: zod.z.number().optional().describe("Blend towards black (0..1)"),
|
|
249
|
+
alpha: zod.z.number().optional().describe("Opacity fraction, 1 = opaque")
|
|
250
|
+
});
|
|
187
251
|
var UpdateTableCellsSchema = zod.z.object({
|
|
188
252
|
filePath: zod.z.string().describe("Path to the PPTX file"),
|
|
189
253
|
slideIndex: zod.z.number().int().min(0),
|
|
@@ -210,6 +274,14 @@ var UpdateElementStyleSchema = zod.z.object({
|
|
|
210
274
|
slideIndex: zod.z.number().int().min(0),
|
|
211
275
|
elementId: zod.z.string(),
|
|
212
276
|
fillColor: zod.z.string().optional(),
|
|
277
|
+
/**
|
|
278
|
+
* A theme colour for the fill (e.g. `{ scheme: 'accent1', lumMod: 0.8 }`
|
|
279
|
+
* for "Accent 1, Lighter 80%"). When set, the shape saves as
|
|
280
|
+
* `<a:schemeClr>` and keeps following the theme after a later theme
|
|
281
|
+
* change, instead of freezing today's resolved hex. Setting `fillColor`
|
|
282
|
+
* without this clears any previously-set fill theme colour.
|
|
283
|
+
*/
|
|
284
|
+
fillThemeColor: ThemeColorRefSchema2.optional(),
|
|
213
285
|
fillMode: zod.z.string().optional(),
|
|
214
286
|
fillGradientStops: zod.z.array(
|
|
215
287
|
zod.z.object({
|
|
@@ -222,6 +294,8 @@ var UpdateElementStyleSchema = zod.z.object({
|
|
|
222
294
|
fillGradientType: zod.z.string().optional(),
|
|
223
295
|
fillOpacity: zod.z.number().optional(),
|
|
224
296
|
strokeColor: zod.z.string().optional(),
|
|
297
|
+
/** A theme colour for the outline; see `fillThemeColor` above. */
|
|
298
|
+
strokeThemeColor: ThemeColorRefSchema2.optional(),
|
|
225
299
|
strokeWidth: zod.z.number().optional(),
|
|
226
300
|
strokeDash: zod.z.string().optional(),
|
|
227
301
|
strokeOpacity: zod.z.number().optional(),
|
|
@@ -241,7 +315,12 @@ var UpdateElementStyleSchema = zod.z.object({
|
|
|
241
315
|
brightness: zod.z.number().optional(),
|
|
242
316
|
contrast: zod.z.number().optional(),
|
|
243
317
|
grayscale: zod.z.boolean().optional(),
|
|
244
|
-
altText: zod.z.string().optional()
|
|
318
|
+
altText: zod.z.string().optional().describe(
|
|
319
|
+
"Accessibility description (p:cNvPr/@descr) for image, picture, table, chart, smartArt, ole, media, text, shape and connector elements"
|
|
320
|
+
),
|
|
321
|
+
title: zod.z.string().optional().describe(
|
|
322
|
+
"Accessibility title (p:cNvPr/@title) for table, chart, smartArt, ole, media, text, shape and connector elements (not pictures)"
|
|
323
|
+
)
|
|
245
324
|
});
|
|
246
325
|
var FindTextSchema = zod.z.object({
|
|
247
326
|
filePath: zod.z.string().describe("Path to the PPTX file"),
|
|
@@ -268,6 +347,116 @@ var ManageCommentsSchema = zod.z.object({
|
|
|
268
347
|
resolved: zod.z.boolean().optional(),
|
|
269
348
|
includeResolved: zod.z.boolean().optional()
|
|
270
349
|
});
|
|
350
|
+
var TABLE_STYLE_SECTIONS = [
|
|
351
|
+
"wholeTbl",
|
|
352
|
+
"band1H",
|
|
353
|
+
"band2H",
|
|
354
|
+
"band1V",
|
|
355
|
+
"band2V",
|
|
356
|
+
"lastCol",
|
|
357
|
+
"firstCol",
|
|
358
|
+
"lastRow",
|
|
359
|
+
"seCell",
|
|
360
|
+
"swCell",
|
|
361
|
+
"firstRow",
|
|
362
|
+
"neCell",
|
|
363
|
+
"nwCell"
|
|
364
|
+
];
|
|
365
|
+
var TableStyleSimpleColorSchema = zod.z.object({
|
|
366
|
+
schemeColor: zod.z.string().describe('Theme colour key (e.g. "accent1"), or "" for a non-scheme fill'),
|
|
367
|
+
tint: zod.z.number().optional().describe("0-100000"),
|
|
368
|
+
shade: zod.z.number().optional().describe("0-100000"),
|
|
369
|
+
color: zod.z.string().optional().describe('Explicit hex colour, e.g. "#FF8800"')
|
|
370
|
+
});
|
|
371
|
+
var TableStyleFillSchema = zod.z.object({
|
|
372
|
+
schemeColor: zod.z.string(),
|
|
373
|
+
tint: zod.z.number().optional(),
|
|
374
|
+
shade: zod.z.number().optional(),
|
|
375
|
+
color: zod.z.string().optional(),
|
|
376
|
+
noFill: zod.z.boolean().optional(),
|
|
377
|
+
gradient: zod.z.object({
|
|
378
|
+
type: zod.z.enum(["linear", "radial"]),
|
|
379
|
+
angle: zod.z.number().optional(),
|
|
380
|
+
stops: zod.z.array(zod.z.object({ position: zod.z.number(), fill: TableStyleSimpleColorSchema }))
|
|
381
|
+
}).optional(),
|
|
382
|
+
pattern: zod.z.object({
|
|
383
|
+
preset: zod.z.string(),
|
|
384
|
+
foreground: TableStyleSimpleColorSchema.optional(),
|
|
385
|
+
background: TableStyleSimpleColorSchema.optional()
|
|
386
|
+
}).optional(),
|
|
387
|
+
image: zod.z.object({ path: zod.z.string().optional(), data: zod.z.string().optional() }).optional()
|
|
388
|
+
});
|
|
389
|
+
var TableStyleTextSchema = zod.z.object({
|
|
390
|
+
bold: zod.z.boolean().optional(),
|
|
391
|
+
italic: zod.z.boolean().optional(),
|
|
392
|
+
underline: zod.z.boolean().optional(),
|
|
393
|
+
fontSchemeColor: zod.z.string().optional(),
|
|
394
|
+
fontTint: zod.z.number().optional(),
|
|
395
|
+
fontShade: zod.z.number().optional(),
|
|
396
|
+
fontColor: zod.z.string().optional(),
|
|
397
|
+
fontFace: zod.z.string().optional(),
|
|
398
|
+
fontRefIdx: zod.z.string().optional()
|
|
399
|
+
});
|
|
400
|
+
var TableStyleBorderSideSchema = zod.z.object({
|
|
401
|
+
width: zod.z.number().optional(),
|
|
402
|
+
dash: zod.z.string().optional(),
|
|
403
|
+
fill: TableStyleSimpleColorSchema.optional(),
|
|
404
|
+
color: zod.z.string().optional(),
|
|
405
|
+
noFill: zod.z.boolean().optional()
|
|
406
|
+
});
|
|
407
|
+
var TableStyleBordersSchema = zod.z.object({
|
|
408
|
+
left: TableStyleBorderSideSchema.optional(),
|
|
409
|
+
right: TableStyleBorderSideSchema.optional(),
|
|
410
|
+
top: TableStyleBorderSideSchema.optional(),
|
|
411
|
+
bottom: TableStyleBorderSideSchema.optional(),
|
|
412
|
+
insideH: TableStyleBorderSideSchema.optional(),
|
|
413
|
+
insideV: TableStyleBorderSideSchema.optional(),
|
|
414
|
+
tl2br: TableStyleBorderSideSchema.optional(),
|
|
415
|
+
tr2bl: TableStyleBorderSideSchema.optional()
|
|
416
|
+
});
|
|
417
|
+
var TableStyleCell3DSchema = zod.z.object({
|
|
418
|
+
bevelWidth: zod.z.number().optional(),
|
|
419
|
+
bevelHeight: zod.z.number().optional(),
|
|
420
|
+
bevelPreset: zod.z.string().optional(),
|
|
421
|
+
material: zod.z.string().optional(),
|
|
422
|
+
lightRig: zod.z.string().optional(),
|
|
423
|
+
lightRigDirection: zod.z.string().optional()
|
|
424
|
+
});
|
|
425
|
+
var SetTableStyleSectionSchema = zod.z.object({
|
|
426
|
+
filePath: zod.z.string().describe("Path to the PPTX file"),
|
|
427
|
+
styleId: zod.z.string().describe('Table style GUID, e.g. "{5C22544A-7EE6-4342-B048-85BDC9FD1C3A}"'),
|
|
428
|
+
section: zod.z.enum(TABLE_STYLE_SECTIONS).describe("Which of the 13 CT_TableStyle parts to patch"),
|
|
429
|
+
styleName: zod.z.string().optional().describe("Rename the style"),
|
|
430
|
+
fill: TableStyleFillSchema.optional(),
|
|
431
|
+
text: TableStyleTextSchema.optional(),
|
|
432
|
+
borders: TableStyleBordersSchema.optional(),
|
|
433
|
+
cell3D: TableStyleCell3DSchema.optional()
|
|
434
|
+
});
|
|
435
|
+
var CreateTableStyleSchema = zod.z.object({
|
|
436
|
+
filePath: zod.z.string().describe("Path to the PPTX file"),
|
|
437
|
+
styleName: zod.z.string().describe("Display name for the new style"),
|
|
438
|
+
basedOnStyleId: zod.z.string().optional().describe("Deep-clone every section from this existing style GUID as the starting point"),
|
|
439
|
+
setAsDefault: zod.z.boolean().optional().describe("Repoint ppt/tableStyles.xml's default style at the new one")
|
|
440
|
+
});
|
|
441
|
+
var DeleteTableStyleSchema = zod.z.object({
|
|
442
|
+
filePath: zod.z.string().describe("Path to the PPTX file"),
|
|
443
|
+
styleId: zod.z.string().describe("Table style GUID to remove"),
|
|
444
|
+
force: zod.z.boolean().optional().describe("Delete even though a table on this deck still references the style")
|
|
445
|
+
});
|
|
446
|
+
var AssignTableStyleSchema = zod.z.object({
|
|
447
|
+
filePath: zod.z.string().describe("Path to the PPTX file"),
|
|
448
|
+
slideIndex: zod.z.number().int().min(0),
|
|
449
|
+
elementId: zod.z.string().describe("Table element ID"),
|
|
450
|
+
styleId: zod.z.string().optional().describe(
|
|
451
|
+
"Table style GUID to assign. Defaults to the presentation's current default table style when omitted."
|
|
452
|
+
),
|
|
453
|
+
bandedRows: zod.z.boolean().optional(),
|
|
454
|
+
bandedColumns: zod.z.boolean().optional(),
|
|
455
|
+
firstRowHeader: zod.z.boolean().optional(),
|
|
456
|
+
lastRow: zod.z.boolean().optional(),
|
|
457
|
+
firstCol: zod.z.boolean().optional(),
|
|
458
|
+
lastCol: zod.z.boolean().optional()
|
|
459
|
+
});
|
|
271
460
|
var GetThemeInfoSchema = zod.z.object({
|
|
272
461
|
filePath: zod.z.string().describe("Path to the PPTX file")
|
|
273
462
|
});
|
|
@@ -297,6 +486,139 @@ var UpdateThemeFontsSchema = zod.z.object({
|
|
|
297
486
|
majorFont: zod.z.string().optional().describe("Heading (major) font family"),
|
|
298
487
|
minorFont: zod.z.string().optional().describe("Body (minor) font family")
|
|
299
488
|
});
|
|
489
|
+
var MarkerSymbolSchema = zod.z.enum([
|
|
490
|
+
"circle",
|
|
491
|
+
"dash",
|
|
492
|
+
"diamond",
|
|
493
|
+
"dot",
|
|
494
|
+
"none",
|
|
495
|
+
"picture",
|
|
496
|
+
"plus",
|
|
497
|
+
"square",
|
|
498
|
+
"star",
|
|
499
|
+
"triangle",
|
|
500
|
+
"x",
|
|
501
|
+
"auto"
|
|
502
|
+
]);
|
|
503
|
+
var DataLabelPositionSchema = zod.z.enum([
|
|
504
|
+
"bestFit",
|
|
505
|
+
"b",
|
|
506
|
+
"ctr",
|
|
507
|
+
"inBase",
|
|
508
|
+
"inEnd",
|
|
509
|
+
"l",
|
|
510
|
+
"outEnd",
|
|
511
|
+
"r",
|
|
512
|
+
"t"
|
|
513
|
+
]);
|
|
514
|
+
var FormatChartDataPointSchema = zod.z.object({
|
|
515
|
+
filePath: zod.z.string().describe("Path to the PPTX file"),
|
|
516
|
+
slideIndex: zod.z.number().int().min(0).describe("Zero-based slide index"),
|
|
517
|
+
elementId: zod.z.string().describe("Chart element ID"),
|
|
518
|
+
seriesIndex: zod.z.number().int().min(0).describe("Zero-based series index"),
|
|
519
|
+
pointIndex: zod.z.number().int().min(0).describe("Zero-based data point (category) index"),
|
|
520
|
+
fillColor: zod.z.string().optional().describe("Fill colour (hex) for this point only"),
|
|
521
|
+
strokeColor: zod.z.string().optional().describe("Outline colour (hex) for this point only"),
|
|
522
|
+
strokeWidth: zod.z.number().optional().describe("Outline width in points"),
|
|
523
|
+
strokeDashStyle: zod.z.string().optional().describe("Outline dash style, e.g. solid, dash, dashDot, sysDot"),
|
|
524
|
+
clearStyle: zod.z.boolean().optional().describe("Remove all per-point shape formatting"),
|
|
525
|
+
explosion: zod.z.number().nullable().optional().describe("Pie/doughnut slice pull-out distance 0-100; null clears it"),
|
|
526
|
+
marker: zod.z.object({
|
|
527
|
+
symbol: MarkerSymbolSchema.optional(),
|
|
528
|
+
size: zod.z.number().optional(),
|
|
529
|
+
fillColor: zod.z.string().optional()
|
|
530
|
+
}).nullable().optional().describe("Per-point marker override (line/scatter/bubble); null clears it")
|
|
531
|
+
});
|
|
532
|
+
var FormatChartDataLabelSchema = zod.z.object({
|
|
533
|
+
filePath: zod.z.string().describe("Path to the PPTX file"),
|
|
534
|
+
slideIndex: zod.z.number().int().min(0).describe("Zero-based slide index"),
|
|
535
|
+
elementId: zod.z.string().describe("Chart element ID"),
|
|
536
|
+
seriesIndex: zod.z.number().int().min(0).describe("Zero-based series index"),
|
|
537
|
+
pointIndex: zod.z.number().int().min(0).describe("Zero-based data point (category) index"),
|
|
538
|
+
remove: zod.z.boolean().optional().describe("Remove the per-point label override entirely"),
|
|
539
|
+
showValue: zod.z.boolean().optional(),
|
|
540
|
+
showCategory: zod.z.boolean().optional(),
|
|
541
|
+
showSeriesName: zod.z.boolean().optional(),
|
|
542
|
+
showPercent: zod.z.boolean().optional(),
|
|
543
|
+
showLegendKey: zod.z.boolean().optional(),
|
|
544
|
+
position: DataLabelPositionSchema.optional(),
|
|
545
|
+
text: zod.z.string().optional().describe("Custom label text override; '' clears it"),
|
|
546
|
+
spPr: zod.z.object({
|
|
547
|
+
fillColor: zod.z.string().optional(),
|
|
548
|
+
strokeColor: zod.z.string().optional(),
|
|
549
|
+
strokeWidth: zod.z.number().optional(),
|
|
550
|
+
strokeDashStyle: zod.z.string().optional()
|
|
551
|
+
}).nullable().optional().describe("This label's own fill/line formatting; null removes it"),
|
|
552
|
+
txPr: zod.z.object({
|
|
553
|
+
fontFamily: zod.z.string().optional(),
|
|
554
|
+
fontSize: zod.z.number().optional(),
|
|
555
|
+
bold: zod.z.boolean().optional(),
|
|
556
|
+
italic: zod.z.boolean().optional(),
|
|
557
|
+
color: zod.z.string().optional()
|
|
558
|
+
}).nullable().optional().describe("This label's own font; null removes it")
|
|
559
|
+
});
|
|
560
|
+
var FormatChartSeriesSchema = zod.z.object({
|
|
561
|
+
filePath: zod.z.string().describe("Path to the PPTX file"),
|
|
562
|
+
slideIndex: zod.z.number().int().min(0).describe("Zero-based slide index"),
|
|
563
|
+
elementId: zod.z.string().describe("Chart element ID"),
|
|
564
|
+
seriesIndex: zod.z.number().int().min(0).describe("Zero-based series index"),
|
|
565
|
+
marker: zod.z.object({
|
|
566
|
+
symbol: MarkerSymbolSchema.optional(),
|
|
567
|
+
size: zod.z.number().optional(),
|
|
568
|
+
fillColor: zod.z.string().optional(),
|
|
569
|
+
strokeColor: zod.z.string().optional(),
|
|
570
|
+
strokeWidth: zod.z.number().optional(),
|
|
571
|
+
strokeDashStyle: zod.z.string().optional()
|
|
572
|
+
}).nullable().optional().describe("Series marker (line/scatter/bubble/radar); null removes it"),
|
|
573
|
+
trendline: zod.z.object({
|
|
574
|
+
trendlineType: zod.z.enum([
|
|
575
|
+
"linear",
|
|
576
|
+
"exponential",
|
|
577
|
+
"logarithmic",
|
|
578
|
+
"polynomial",
|
|
579
|
+
"power",
|
|
580
|
+
"movingAvg"
|
|
581
|
+
]),
|
|
582
|
+
color: zod.z.string().optional(),
|
|
583
|
+
lineWidth: zod.z.number().optional().describe("Trendline width in points"),
|
|
584
|
+
lineDashStyle: zod.z.string().optional(),
|
|
585
|
+
order: zod.z.number().optional().describe("Polynomial order, 2-6"),
|
|
586
|
+
period: zod.z.number().optional().describe("Moving-average period"),
|
|
587
|
+
displayEq: zod.z.boolean().optional(),
|
|
588
|
+
displayRSq: zod.z.boolean().optional()
|
|
589
|
+
}).nullable().optional().describe("Series trendline; null removes it"),
|
|
590
|
+
errorBars: zod.z.object({
|
|
591
|
+
direction: zod.z.enum(["x", "y"]),
|
|
592
|
+
barType: zod.z.enum(["both", "minus", "plus"]),
|
|
593
|
+
valType: zod.z.enum(["cust", "fixedVal", "percentage", "stdDev", "stdErr"]),
|
|
594
|
+
val: zod.z.number().optional(),
|
|
595
|
+
customPlus: zod.z.array(zod.z.number()).optional(),
|
|
596
|
+
customMinus: zod.z.array(zod.z.number()).optional(),
|
|
597
|
+
noEndCap: zod.z.boolean().optional(),
|
|
598
|
+
color: zod.z.string().optional(),
|
|
599
|
+
width: zod.z.number().optional().describe("Error-bar line width in points"),
|
|
600
|
+
dashStyle: zod.z.string().optional()
|
|
601
|
+
}).nullable().optional().describe("Series error bars; null removes them")
|
|
602
|
+
});
|
|
603
|
+
var SetChartHelperLineSchema = zod.z.object({
|
|
604
|
+
filePath: zod.z.string().describe("Path to the PPTX file"),
|
|
605
|
+
slideIndex: zod.z.number().int().min(0).describe("Zero-based slide index"),
|
|
606
|
+
elementId: zod.z.string().describe("Chart element ID"),
|
|
607
|
+
line: zod.z.enum(["dropLines", "hiLowLines"]).describe("Which helper line to set"),
|
|
608
|
+
style: zod.z.object({
|
|
609
|
+
color: zod.z.string().optional(),
|
|
610
|
+
width: zod.z.number().optional(),
|
|
611
|
+
dashStyle: zod.z.string().optional()
|
|
612
|
+
}).nullable().describe("Line colour/width/dash; {} shows the line with defaults, null removes it")
|
|
613
|
+
});
|
|
614
|
+
var SetChartColorMapOverrideSchema = zod.z.object({
|
|
615
|
+
filePath: zod.z.string().describe("Path to the PPTX file"),
|
|
616
|
+
slideIndex: zod.z.number().int().min(0).describe("Zero-based slide index"),
|
|
617
|
+
elementId: zod.z.string().describe("Chart element ID"),
|
|
618
|
+
overrides: zod.z.record(zod.z.string(), zod.z.string()).nullable().describe(
|
|
619
|
+
'Theme colour role remap (bg1/tx1/bg2/tx2/accent1-6/hlink/folHlink -> role), e.g. { "accent1": "accent2" }; null removes the override'
|
|
620
|
+
)
|
|
621
|
+
});
|
|
300
622
|
var UpdateChartSchema = zod.z.object({
|
|
301
623
|
filePath: zod.z.string().describe("Path to the PPTX file"),
|
|
302
624
|
slideIndex: zod.z.number().int().min(0).describe("Zero-based slide index"),
|
|
@@ -559,39 +881,6 @@ var ApplyLayoutSchema = zod.z.object({
|
|
|
559
881
|
layoutName: zod.z.string().optional().describe("Layout name to apply"),
|
|
560
882
|
layoutType: zod.z.string().optional().describe("Layout type to apply (alternative to name)")
|
|
561
883
|
});
|
|
562
|
-
|
|
563
|
-
// src/tools/chart-pareto.ts
|
|
564
|
-
function cumulativePercent(values) {
|
|
565
|
-
const total = values.reduce((sum, value) => sum + value, 0);
|
|
566
|
-
if (total === 0) {
|
|
567
|
-
return values.map(() => 0);
|
|
568
|
-
}
|
|
569
|
-
let running = 0;
|
|
570
|
-
return values.map((value) => {
|
|
571
|
-
running += value;
|
|
572
|
-
return Math.round(running / total * 1e4) / 100;
|
|
573
|
-
});
|
|
574
|
-
}
|
|
575
|
-
function applyParetoChartTypeAlias(chart, requestedType) {
|
|
576
|
-
if (requestedType.trim().toLowerCase() !== "pareto" || !chart.chartData) {
|
|
577
|
-
return;
|
|
578
|
-
}
|
|
579
|
-
const data = chart.chartData;
|
|
580
|
-
data.chartType = "histogram";
|
|
581
|
-
const [frequency] = data.series;
|
|
582
|
-
if (!frequency) {
|
|
583
|
-
return;
|
|
584
|
-
}
|
|
585
|
-
frequency.histogramOptions = { ...frequency.histogramOptions, layout: "histogram" };
|
|
586
|
-
const hasParetoLine = data.series.some((s) => s.histogramOptions?.layout === "pareto");
|
|
587
|
-
if (!hasParetoLine) {
|
|
588
|
-
data.series.push({
|
|
589
|
-
name: "Cumulative %",
|
|
590
|
-
values: cumulativePercent(frequency.values),
|
|
591
|
-
histogramOptions: { layout: "pareto" }
|
|
592
|
-
});
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
884
|
function generateElementId() {
|
|
596
885
|
return `el-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
597
886
|
}
|
|
@@ -699,6 +988,133 @@ function validateSlideIndex(slideIndex, slideCount) {
|
|
|
699
988
|
return null;
|
|
700
989
|
}
|
|
701
990
|
|
|
991
|
+
// src/tools/chart-formatting-tools.ts
|
|
992
|
+
function findChartElement(ctx, slideIndex, elementId) {
|
|
993
|
+
const err = validateSlideIndex(slideIndex, ctx.pptxData.slides.length);
|
|
994
|
+
if (err) {
|
|
995
|
+
throw new Error(err);
|
|
996
|
+
}
|
|
997
|
+
const slide = ctx.pptxData.slides[slideIndex];
|
|
998
|
+
const el = slide.elements.find((e) => e.id === elementId);
|
|
999
|
+
if (!el) {
|
|
1000
|
+
throw new Error(`Element '${elementId}' not found on slide ${slideIndex}.`);
|
|
1001
|
+
}
|
|
1002
|
+
if (el.type !== "chart") {
|
|
1003
|
+
throw new Error(`Element '${elementId}' is not a chart.`);
|
|
1004
|
+
}
|
|
1005
|
+
return el;
|
|
1006
|
+
}
|
|
1007
|
+
function formatChartDataPoint(ctx, params) {
|
|
1008
|
+
const chart = findChartElement(ctx, params.slideIndex, params.elementId);
|
|
1009
|
+
if (params.clearStyle) {
|
|
1010
|
+
pptxViewerCore.setChartDataPointStyle(chart, params.seriesIndex, params.pointIndex, null);
|
|
1011
|
+
} else if (params.fillColor !== void 0 || params.strokeColor !== void 0 || params.strokeWidth !== void 0 || params.strokeDashStyle !== void 0) {
|
|
1012
|
+
pptxViewerCore.setChartDataPointStyle(chart, params.seriesIndex, params.pointIndex, {
|
|
1013
|
+
...params.fillColor !== void 0 ? { fillColor: params.fillColor } : {},
|
|
1014
|
+
...params.strokeColor !== void 0 ? { strokeColor: params.strokeColor } : {},
|
|
1015
|
+
...params.strokeWidth !== void 0 ? { strokeWidth: params.strokeWidth } : {},
|
|
1016
|
+
...params.strokeDashStyle !== void 0 ? { strokeDashStyle: params.strokeDashStyle } : {}
|
|
1017
|
+
});
|
|
1018
|
+
}
|
|
1019
|
+
if (params.explosion !== void 0) {
|
|
1020
|
+
pptxViewerCore.setChartDataPointExplosion(chart, params.seriesIndex, params.pointIndex, params.explosion);
|
|
1021
|
+
}
|
|
1022
|
+
if (params.marker !== void 0) {
|
|
1023
|
+
pptxViewerCore.setChartDataPointMarker(chart, params.seriesIndex, params.pointIndex, params.marker);
|
|
1024
|
+
}
|
|
1025
|
+
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
1026
|
+
}
|
|
1027
|
+
function formatChartDataLabel(ctx, params) {
|
|
1028
|
+
const chart = findChartElement(ctx, params.slideIndex, params.elementId);
|
|
1029
|
+
if (params.remove) {
|
|
1030
|
+
pptxViewerCore.setChartDataPointLabel(chart, params.seriesIndex, params.pointIndex, null);
|
|
1031
|
+
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
1032
|
+
}
|
|
1033
|
+
pptxViewerCore.setChartDataPointLabel(chart, params.seriesIndex, params.pointIndex, {
|
|
1034
|
+
...params.showValue !== void 0 ? { showValue: params.showValue } : {},
|
|
1035
|
+
...params.showCategory !== void 0 ? { showCategory: params.showCategory } : {},
|
|
1036
|
+
...params.showSeriesName !== void 0 ? { showSeriesName: params.showSeriesName } : {},
|
|
1037
|
+
...params.showPercent !== void 0 ? { showPercent: params.showPercent } : {},
|
|
1038
|
+
...params.showLegendKey !== void 0 ? { showLegendKey: params.showLegendKey } : {},
|
|
1039
|
+
...params.position !== void 0 ? { position: params.position } : {},
|
|
1040
|
+
...params.text !== void 0 ? { text: params.text } : {},
|
|
1041
|
+
...params.spPr !== void 0 ? { spPr: params.spPr } : {},
|
|
1042
|
+
...params.txPr !== void 0 ? { txPr: params.txPr } : {}
|
|
1043
|
+
});
|
|
1044
|
+
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
1045
|
+
}
|
|
1046
|
+
function formatChartSeries(ctx, params) {
|
|
1047
|
+
const chart = findChartElement(ctx, params.slideIndex, params.elementId);
|
|
1048
|
+
if (params.marker !== void 0) {
|
|
1049
|
+
if (params.marker === null) {
|
|
1050
|
+
pptxViewerCore.setChartSeriesMarker(chart, params.seriesIndex, null);
|
|
1051
|
+
} else if (params.marker.strokeColor !== void 0 || params.marker.strokeWidth !== void 0 || params.marker.strokeDashStyle !== void 0) {
|
|
1052
|
+
pptxViewerCore.setChartSeriesMarker(chart, params.seriesIndex, {
|
|
1053
|
+
symbol: params.marker.symbol ?? "circle",
|
|
1054
|
+
...params.marker.size !== void 0 ? { size: params.marker.size } : {},
|
|
1055
|
+
spPr: {
|
|
1056
|
+
...params.marker.fillColor !== void 0 ? { fillColor: params.marker.fillColor } : {},
|
|
1057
|
+
...params.marker.strokeColor !== void 0 ? { strokeColor: params.marker.strokeColor } : {},
|
|
1058
|
+
...params.marker.strokeWidth !== void 0 ? { strokeWidth: params.marker.strokeWidth } : {},
|
|
1059
|
+
...params.marker.strokeDashStyle !== void 0 ? { strokeDashStyle: params.marker.strokeDashStyle } : {}
|
|
1060
|
+
}
|
|
1061
|
+
});
|
|
1062
|
+
} else {
|
|
1063
|
+
pptxViewerCore.setChartSeriesMarker(chart, params.seriesIndex, params.marker);
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
if (params.trendline !== void 0) {
|
|
1067
|
+
pptxViewerCore.setChartSeriesTrendline(chart, params.seriesIndex, params.trendline);
|
|
1068
|
+
}
|
|
1069
|
+
if (params.errorBars !== void 0) {
|
|
1070
|
+
pptxViewerCore.setChartSeriesErrorBars(chart, params.seriesIndex, params.errorBars);
|
|
1071
|
+
}
|
|
1072
|
+
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
1073
|
+
}
|
|
1074
|
+
function setChartHelperLineT(ctx, params) {
|
|
1075
|
+
const chart = findChartElement(ctx, params.slideIndex, params.elementId);
|
|
1076
|
+
pptxViewerCore.setChartHelperLine(chart, params.line, params.style);
|
|
1077
|
+
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
1078
|
+
}
|
|
1079
|
+
function setChartColorMapOverrideT(ctx, params) {
|
|
1080
|
+
const chart = findChartElement(ctx, params.slideIndex, params.elementId);
|
|
1081
|
+
pptxViewerCore.setChartColorMapOverride(chart, params.overrides);
|
|
1082
|
+
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
// src/tools/chart-pareto.ts
|
|
1086
|
+
function cumulativePercent(values) {
|
|
1087
|
+
const total = values.reduce((sum, value) => sum + value, 0);
|
|
1088
|
+
if (total === 0) {
|
|
1089
|
+
return values.map(() => 0);
|
|
1090
|
+
}
|
|
1091
|
+
let running = 0;
|
|
1092
|
+
return values.map((value) => {
|
|
1093
|
+
running += value;
|
|
1094
|
+
return Math.round(running / total * 1e4) / 100;
|
|
1095
|
+
});
|
|
1096
|
+
}
|
|
1097
|
+
function applyParetoChartTypeAlias(chart, requestedType) {
|
|
1098
|
+
if (requestedType.trim().toLowerCase() !== "pareto" || !chart.chartData) {
|
|
1099
|
+
return;
|
|
1100
|
+
}
|
|
1101
|
+
const data = chart.chartData;
|
|
1102
|
+
data.chartType = "histogram";
|
|
1103
|
+
const [frequency] = data.series;
|
|
1104
|
+
if (!frequency) {
|
|
1105
|
+
return;
|
|
1106
|
+
}
|
|
1107
|
+
frequency.histogramOptions = { ...frequency.histogramOptions, layout: "histogram" };
|
|
1108
|
+
const hasParetoLine = data.series.some((s) => s.histogramOptions?.layout === "pareto");
|
|
1109
|
+
if (!hasParetoLine) {
|
|
1110
|
+
data.series.push({
|
|
1111
|
+
name: "Cumulative %",
|
|
1112
|
+
values: cumulativePercent(frequency.values),
|
|
1113
|
+
histogramOptions: { layout: "pareto" }
|
|
1114
|
+
});
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
|
|
702
1118
|
// src/tools/chart-tools.ts
|
|
703
1119
|
function updateChart(ctx, params) {
|
|
704
1120
|
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
@@ -839,7 +1255,7 @@ function createChart(ctx, params) {
|
|
|
839
1255
|
result: { elementId: chart.id, slideIndex: params.slideIndex }
|
|
840
1256
|
};
|
|
841
1257
|
}
|
|
842
|
-
function
|
|
1258
|
+
function findChartElement2(ctx, slideIndex, elementId) {
|
|
843
1259
|
const err = validateSlideIndex(slideIndex, ctx.pptxData.slides.length);
|
|
844
1260
|
if (err) {
|
|
845
1261
|
throw new Error(err);
|
|
@@ -869,17 +1285,17 @@ function buildShape(input) {
|
|
|
869
1285
|
};
|
|
870
1286
|
}
|
|
871
1287
|
function listChartUserShapesT(ctx, params) {
|
|
872
|
-
const chart =
|
|
1288
|
+
const chart = findChartElement2(ctx, params.slideIndex, params.elementId);
|
|
873
1289
|
return { pptxData: ctx.pptxData, dirty: false, result: { shapes: pptxViewerCore.listChartUserShapes(chart) } };
|
|
874
1290
|
}
|
|
875
1291
|
function addChartUserShapeT(ctx, params) {
|
|
876
|
-
const chart =
|
|
1292
|
+
const chart = findChartElement2(ctx, params.slideIndex, params.elementId);
|
|
877
1293
|
pptxViewerCore.addChartUserShape(chart, buildShape(params.shape));
|
|
878
1294
|
const index = (chart.chartData?.userShapes?.length ?? 1) - 1;
|
|
879
1295
|
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId, index } };
|
|
880
1296
|
}
|
|
881
1297
|
function updateChartUserShapeT(ctx, params) {
|
|
882
|
-
const chart =
|
|
1298
|
+
const chart = findChartElement2(ctx, params.slideIndex, params.elementId);
|
|
883
1299
|
const patch = {
|
|
884
1300
|
...params.patch.kind ? { kind: params.patch.kind } : {},
|
|
885
1301
|
...params.patch.anchor ? { anchor: params.patch.anchor } : {},
|
|
@@ -896,7 +1312,7 @@ function updateChartUserShapeT(ctx, params) {
|
|
|
896
1312
|
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
897
1313
|
}
|
|
898
1314
|
function removeChartUserShapeT(ctx, params) {
|
|
899
|
-
const chart =
|
|
1315
|
+
const chart = findChartElement2(ctx, params.slideIndex, params.elementId);
|
|
900
1316
|
pptxViewerCore.removeChartUserShape(chart, params.index);
|
|
901
1317
|
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
902
1318
|
}
|
|
@@ -1226,85 +1642,319 @@ async function convertToMarkdown(ctx, params) {
|
|
|
1226
1642
|
}
|
|
1227
1643
|
};
|
|
1228
1644
|
}
|
|
1229
|
-
|
|
1645
|
+
var ALT_TEXT_ELEMENT_TYPES = /* @__PURE__ */ new Set(["image", "picture", "table", "chart", "smartArt", "ole", "media", "text", "shape", "connector"]);
|
|
1646
|
+
var TITLE_ELEMENT_TYPES = /* @__PURE__ */ new Set([
|
|
1647
|
+
"table",
|
|
1648
|
+
"chart",
|
|
1649
|
+
"smartArt",
|
|
1650
|
+
"ole",
|
|
1651
|
+
"media",
|
|
1652
|
+
"text",
|
|
1653
|
+
"shape",
|
|
1654
|
+
"connector"
|
|
1655
|
+
]);
|
|
1656
|
+
function applyElementAltText(el, altText) {
|
|
1657
|
+
if (!ALT_TEXT_ELEMENT_TYPES.has(el.type)) {
|
|
1658
|
+
throw new Error(
|
|
1659
|
+
`Element '${el.id}' (${el.type}) does not support altText; only ${[...ALT_TEXT_ELEMENT_TYPES].join(", ")} elements do.`
|
|
1660
|
+
);
|
|
1661
|
+
}
|
|
1662
|
+
el.altText = altText;
|
|
1663
|
+
}
|
|
1664
|
+
function applyElementTitle(el, title) {
|
|
1665
|
+
if (!TITLE_ELEMENT_TYPES.has(el.type)) {
|
|
1666
|
+
throw new Error(
|
|
1667
|
+
`Element '${el.id}' (${el.type}) does not support title; only ${[...TITLE_ELEMENT_TYPES].join(", ")} elements do.`
|
|
1668
|
+
);
|
|
1669
|
+
}
|
|
1670
|
+
el.title = title;
|
|
1671
|
+
}
|
|
1672
|
+
function updateElementStyle(ctx, params) {
|
|
1230
1673
|
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
1231
1674
|
if (err) {
|
|
1232
1675
|
throw new Error(err);
|
|
1233
1676
|
}
|
|
1234
1677
|
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
1235
|
-
const
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
const el = {
|
|
1243
|
-
id,
|
|
1244
|
-
type: "text",
|
|
1245
|
-
x,
|
|
1246
|
-
y,
|
|
1247
|
-
width,
|
|
1248
|
-
height,
|
|
1249
|
-
text: params.text ?? "",
|
|
1250
|
-
textStyle: {
|
|
1251
|
-
fontSize: params.fontSize,
|
|
1252
|
-
fontFamily: params.fontFamily,
|
|
1253
|
-
color: params.fontColor,
|
|
1254
|
-
bold: params.bold,
|
|
1255
|
-
italic: params.italic,
|
|
1256
|
-
underline: params.underline,
|
|
1257
|
-
align: params.alignment
|
|
1258
|
-
},
|
|
1259
|
-
textSegments: [
|
|
1260
|
-
{
|
|
1261
|
-
text: params.text ?? "",
|
|
1262
|
-
style: {
|
|
1263
|
-
fontSize: params.fontSize,
|
|
1264
|
-
fontFamily: params.fontFamily,
|
|
1265
|
-
color: params.fontColor,
|
|
1266
|
-
bold: params.bold,
|
|
1267
|
-
italic: params.italic,
|
|
1268
|
-
underline: params.underline
|
|
1269
|
-
}
|
|
1270
|
-
}
|
|
1271
|
-
]
|
|
1272
|
-
};
|
|
1273
|
-
slide.elements.push(el);
|
|
1274
|
-
break;
|
|
1678
|
+
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
1679
|
+
if (!el) {
|
|
1680
|
+
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
1681
|
+
}
|
|
1682
|
+
if ("shapeStyle" in el) {
|
|
1683
|
+
if (!el.shapeStyle) {
|
|
1684
|
+
el.shapeStyle = {};
|
|
1275
1685
|
}
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
fontFamily: params.fontFamily,
|
|
1289
|
-
color: params.fontColor,
|
|
1290
|
-
bold: params.bold,
|
|
1291
|
-
italic: params.italic,
|
|
1292
|
-
align: params.alignment
|
|
1293
|
-
} : void 0,
|
|
1294
|
-
shapeStyle: {
|
|
1295
|
-
fillColor: params.fillColor,
|
|
1296
|
-
strokeColor: params.strokeColor,
|
|
1297
|
-
strokeWidth: params.strokeWidth
|
|
1298
|
-
}
|
|
1299
|
-
};
|
|
1300
|
-
slide.elements.push(el);
|
|
1301
|
-
break;
|
|
1686
|
+
const ss = el.shapeStyle;
|
|
1687
|
+
if (params.fillThemeColor !== void 0) {
|
|
1688
|
+
ss.fillColorRef = params.fillThemeColor;
|
|
1689
|
+
const resolved = pptxViewerCore.resolveThemeColorRef(params.fillThemeColor, ctx.pptxData.themeColorMap);
|
|
1690
|
+
if (params.fillColor !== void 0) {
|
|
1691
|
+
ss.fillColor = params.fillColor;
|
|
1692
|
+
} else if (resolved) {
|
|
1693
|
+
ss.fillColor = resolved;
|
|
1694
|
+
}
|
|
1695
|
+
} else if (params.fillColor !== void 0) {
|
|
1696
|
+
ss.fillColor = params.fillColor;
|
|
1697
|
+
ss.fillColorRef = void 0;
|
|
1302
1698
|
}
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1699
|
+
if (params.fillMode !== void 0) {
|
|
1700
|
+
ss.fillMode = params.fillMode;
|
|
1701
|
+
}
|
|
1702
|
+
if (params.fillGradientStops !== void 0) {
|
|
1703
|
+
ss.fillGradientStops = params.fillGradientStops;
|
|
1704
|
+
}
|
|
1705
|
+
if (params.fillGradientAngle !== void 0) {
|
|
1706
|
+
ss.fillGradientAngle = params.fillGradientAngle;
|
|
1707
|
+
}
|
|
1708
|
+
if (params.fillGradientType !== void 0) {
|
|
1709
|
+
ss.fillGradientType = params.fillGradientType;
|
|
1710
|
+
}
|
|
1711
|
+
if (params.fillOpacity !== void 0) {
|
|
1712
|
+
ss.fillOpacity = params.fillOpacity;
|
|
1713
|
+
}
|
|
1714
|
+
if (params.strokeThemeColor !== void 0) {
|
|
1715
|
+
ss.strokeColorRef = params.strokeThemeColor;
|
|
1716
|
+
const resolved = pptxViewerCore.resolveThemeColorRef(params.strokeThemeColor, ctx.pptxData.themeColorMap);
|
|
1717
|
+
if (params.strokeColor !== void 0) {
|
|
1718
|
+
ss.strokeColor = params.strokeColor;
|
|
1719
|
+
} else if (resolved) {
|
|
1720
|
+
ss.strokeColor = resolved;
|
|
1721
|
+
}
|
|
1722
|
+
} else if (params.strokeColor !== void 0) {
|
|
1723
|
+
ss.strokeColor = params.strokeColor;
|
|
1724
|
+
ss.strokeColorRef = void 0;
|
|
1725
|
+
}
|
|
1726
|
+
if (params.strokeWidth !== void 0) {
|
|
1727
|
+
ss.strokeWidth = params.strokeWidth;
|
|
1728
|
+
}
|
|
1729
|
+
if (params.strokeDash !== void 0) {
|
|
1730
|
+
ss.strokeDash = params.strokeDash;
|
|
1731
|
+
}
|
|
1732
|
+
if (params.strokeOpacity !== void 0) {
|
|
1733
|
+
ss.strokeOpacity = params.strokeOpacity;
|
|
1734
|
+
}
|
|
1735
|
+
if (params.shadowColor !== void 0) {
|
|
1736
|
+
ss.shadowColor = params.shadowColor;
|
|
1737
|
+
}
|
|
1738
|
+
if (params.shadowBlur !== void 0) {
|
|
1739
|
+
ss.shadowBlur = params.shadowBlur;
|
|
1740
|
+
}
|
|
1741
|
+
if (params.shadowOffsetX !== void 0) {
|
|
1742
|
+
ss.shadowOffsetX = params.shadowOffsetX;
|
|
1743
|
+
}
|
|
1744
|
+
if (params.shadowOffsetY !== void 0) {
|
|
1745
|
+
ss.shadowOffsetY = params.shadowOffsetY;
|
|
1746
|
+
}
|
|
1747
|
+
if (params.shadowOpacity !== void 0) {
|
|
1748
|
+
ss.shadowOpacity = params.shadowOpacity;
|
|
1749
|
+
}
|
|
1750
|
+
if (params.glowColor !== void 0) {
|
|
1751
|
+
ss.glowColor = params.glowColor;
|
|
1752
|
+
}
|
|
1753
|
+
if (params.glowRadius !== void 0) {
|
|
1754
|
+
ss.glowRadius = params.glowRadius;
|
|
1755
|
+
}
|
|
1756
|
+
if (params.glowOpacity !== void 0) {
|
|
1757
|
+
ss.glowOpacity = params.glowOpacity;
|
|
1758
|
+
}
|
|
1759
|
+
if (params.softEdgeRadius !== void 0) {
|
|
1760
|
+
ss.softEdgeRadius = params.softEdgeRadius;
|
|
1761
|
+
}
|
|
1762
|
+
}
|
|
1763
|
+
if (params.altText !== void 0) {
|
|
1764
|
+
applyElementAltText(el, params.altText);
|
|
1765
|
+
}
|
|
1766
|
+
if (params.title !== void 0) {
|
|
1767
|
+
applyElementTitle(el, params.title);
|
|
1768
|
+
}
|
|
1769
|
+
if (el.type === "image" || el.type === "picture") {
|
|
1770
|
+
const img = el;
|
|
1771
|
+
if (params.cropLeft !== void 0) {
|
|
1772
|
+
img.cropLeft = params.cropLeft;
|
|
1773
|
+
}
|
|
1774
|
+
if (params.cropTop !== void 0) {
|
|
1775
|
+
img.cropTop = params.cropTop;
|
|
1776
|
+
}
|
|
1777
|
+
if (params.cropRight !== void 0) {
|
|
1778
|
+
img.cropRight = params.cropRight;
|
|
1779
|
+
}
|
|
1780
|
+
if (params.cropBottom !== void 0) {
|
|
1781
|
+
img.cropBottom = params.cropBottom;
|
|
1782
|
+
}
|
|
1783
|
+
if (params.brightness !== void 0 || params.contrast !== void 0 || params.grayscale !== void 0) {
|
|
1784
|
+
if (!img.imageEffects) {
|
|
1785
|
+
img.imageEffects = {};
|
|
1786
|
+
}
|
|
1787
|
+
if (params.brightness !== void 0) {
|
|
1788
|
+
img.imageEffects.brightness = params.brightness;
|
|
1789
|
+
}
|
|
1790
|
+
if (params.contrast !== void 0) {
|
|
1791
|
+
img.imageEffects.contrast = params.contrast;
|
|
1792
|
+
}
|
|
1793
|
+
if (params.grayscale !== void 0) {
|
|
1794
|
+
img.imageEffects.grayscale = params.grayscale;
|
|
1795
|
+
}
|
|
1796
|
+
}
|
|
1797
|
+
}
|
|
1798
|
+
return {
|
|
1799
|
+
pptxData: ctx.pptxData,
|
|
1800
|
+
dirty: true,
|
|
1801
|
+
result: { elementId: params.elementId }
|
|
1802
|
+
};
|
|
1803
|
+
}
|
|
1804
|
+
function runAccessibilityCheck(ctx) {
|
|
1805
|
+
const issues = [];
|
|
1806
|
+
for (let si = 0; si < ctx.pptxData.slides.length; si++) {
|
|
1807
|
+
const slide = ctx.pptxData.slides[si];
|
|
1808
|
+
let slideHasText = false;
|
|
1809
|
+
for (const el of slide.elements) {
|
|
1810
|
+
if (el.type === "image" || el.type === "picture") {
|
|
1811
|
+
const img = el;
|
|
1812
|
+
if (!img.altText) {
|
|
1813
|
+
issues.push({
|
|
1814
|
+
slideIndex: si,
|
|
1815
|
+
elementId: el.id,
|
|
1816
|
+
severity: "error",
|
|
1817
|
+
message: `Image element '${el.id}' has no alt text.`
|
|
1818
|
+
});
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
if (pptxViewerCore.hasTextProperties(el)) {
|
|
1822
|
+
const textEl = el;
|
|
1823
|
+
slideHasText = true;
|
|
1824
|
+
if (!textEl.text || textEl.text.trim() === "") {
|
|
1825
|
+
issues.push({
|
|
1826
|
+
slideIndex: si,
|
|
1827
|
+
elementId: el.id,
|
|
1828
|
+
severity: "info",
|
|
1829
|
+
message: `Text element '${el.id}' is empty.`
|
|
1830
|
+
});
|
|
1831
|
+
}
|
|
1832
|
+
const fs = textEl.textStyle?.fontSize;
|
|
1833
|
+
if (fs !== void 0 && fs < 10) {
|
|
1834
|
+
issues.push({
|
|
1835
|
+
slideIndex: si,
|
|
1836
|
+
elementId: el.id,
|
|
1837
|
+
severity: "warning",
|
|
1838
|
+
message: `Text element '${el.id}' has very small font size (${fs}pt < 10pt).`
|
|
1839
|
+
});
|
|
1840
|
+
}
|
|
1841
|
+
const textColor = textEl.textStyle?.color?.toLowerCase();
|
|
1842
|
+
const bgColor = slide.backgroundColor?.toLowerCase();
|
|
1843
|
+
if (textColor && bgColor && textColor === bgColor) {
|
|
1844
|
+
issues.push({
|
|
1845
|
+
slideIndex: si,
|
|
1846
|
+
elementId: el.id,
|
|
1847
|
+
severity: "error",
|
|
1848
|
+
message: `Text element '${el.id}' has same color as slide background (${textColor}).`
|
|
1849
|
+
});
|
|
1850
|
+
}
|
|
1851
|
+
}
|
|
1852
|
+
}
|
|
1853
|
+
if (!slideHasText) {
|
|
1854
|
+
issues.push({
|
|
1855
|
+
slideIndex: si,
|
|
1856
|
+
severity: "warning",
|
|
1857
|
+
message: `Slide ${si + 1} contains no text elements.`
|
|
1858
|
+
});
|
|
1859
|
+
}
|
|
1860
|
+
}
|
|
1861
|
+
const errorCount = issues.filter((i) => i.severity === "error").length;
|
|
1862
|
+
const warningCount = issues.filter((i) => i.severity === "warning").length;
|
|
1863
|
+
const infoCount = issues.filter((i) => i.severity === "info").length;
|
|
1864
|
+
return {
|
|
1865
|
+
pptxData: ctx.pptxData,
|
|
1866
|
+
dirty: false,
|
|
1867
|
+
result: {
|
|
1868
|
+
slideCount: ctx.pptxData.slides.length,
|
|
1869
|
+
totalIssues: issues.length,
|
|
1870
|
+
errorCount,
|
|
1871
|
+
warningCount,
|
|
1872
|
+
infoCount,
|
|
1873
|
+
issues
|
|
1874
|
+
}
|
|
1875
|
+
};
|
|
1876
|
+
}
|
|
1877
|
+
|
|
1878
|
+
// src/tools/element-tools.ts
|
|
1879
|
+
function addElement(ctx, params) {
|
|
1880
|
+
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
1881
|
+
if (err) {
|
|
1882
|
+
throw new Error(err);
|
|
1883
|
+
}
|
|
1884
|
+
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
1885
|
+
const id = generateElementId();
|
|
1886
|
+
const x = params.x ?? 100;
|
|
1887
|
+
const y = params.y ?? 100;
|
|
1888
|
+
const width = params.width ?? 300;
|
|
1889
|
+
const height = params.height ?? 60;
|
|
1890
|
+
switch (params.type) {
|
|
1891
|
+
case "text": {
|
|
1892
|
+
const el = {
|
|
1893
|
+
id,
|
|
1894
|
+
type: "text",
|
|
1895
|
+
x,
|
|
1896
|
+
y,
|
|
1897
|
+
width,
|
|
1898
|
+
height,
|
|
1899
|
+
text: params.text ?? "",
|
|
1900
|
+
textStyle: {
|
|
1901
|
+
fontSize: params.fontSize,
|
|
1902
|
+
fontFamily: params.fontFamily,
|
|
1903
|
+
color: params.fontColor,
|
|
1904
|
+
bold: params.bold,
|
|
1905
|
+
italic: params.italic,
|
|
1906
|
+
underline: params.underline,
|
|
1907
|
+
align: params.alignment
|
|
1908
|
+
},
|
|
1909
|
+
textSegments: [
|
|
1910
|
+
{
|
|
1911
|
+
text: params.text ?? "",
|
|
1912
|
+
style: {
|
|
1913
|
+
fontSize: params.fontSize,
|
|
1914
|
+
fontFamily: params.fontFamily,
|
|
1915
|
+
color: params.fontColor,
|
|
1916
|
+
bold: params.bold,
|
|
1917
|
+
italic: params.italic,
|
|
1918
|
+
underline: params.underline
|
|
1919
|
+
}
|
|
1920
|
+
}
|
|
1921
|
+
]
|
|
1922
|
+
};
|
|
1923
|
+
slide.elements.push(el);
|
|
1924
|
+
break;
|
|
1925
|
+
}
|
|
1926
|
+
case "shape": {
|
|
1927
|
+
const el = {
|
|
1928
|
+
id,
|
|
1929
|
+
type: "shape",
|
|
1930
|
+
x,
|
|
1931
|
+
y,
|
|
1932
|
+
width,
|
|
1933
|
+
height,
|
|
1934
|
+
shapeType: params.shapeType ?? "rect",
|
|
1935
|
+
text: params.text,
|
|
1936
|
+
textStyle: params.text ? {
|
|
1937
|
+
fontSize: params.fontSize,
|
|
1938
|
+
fontFamily: params.fontFamily,
|
|
1939
|
+
color: params.fontColor,
|
|
1940
|
+
bold: params.bold,
|
|
1941
|
+
italic: params.italic,
|
|
1942
|
+
align: params.alignment
|
|
1943
|
+
} : void 0,
|
|
1944
|
+
shapeStyle: {
|
|
1945
|
+
fillColor: params.fillColor,
|
|
1946
|
+
strokeColor: params.strokeColor,
|
|
1947
|
+
strokeWidth: params.strokeWidth
|
|
1948
|
+
}
|
|
1949
|
+
};
|
|
1950
|
+
slide.elements.push(el);
|
|
1951
|
+
break;
|
|
1952
|
+
}
|
|
1953
|
+
case "image": {
|
|
1954
|
+
const el = {
|
|
1955
|
+
id,
|
|
1956
|
+
type: "image",
|
|
1957
|
+
x,
|
|
1308
1958
|
y,
|
|
1309
1959
|
width,
|
|
1310
1960
|
height,
|
|
@@ -1405,6 +2055,12 @@ function updateElement(ctx, params) {
|
|
|
1405
2055
|
if (params.flipV !== void 0) {
|
|
1406
2056
|
el.flipVertical = params.flipV;
|
|
1407
2057
|
}
|
|
2058
|
+
if (params.altText !== void 0) {
|
|
2059
|
+
applyElementAltText(el, params.altText);
|
|
2060
|
+
}
|
|
2061
|
+
if (params.title !== void 0) {
|
|
2062
|
+
applyElementTitle(el, params.title);
|
|
2063
|
+
}
|
|
1408
2064
|
if (pptxViewerCore.hasTextProperties(el)) {
|
|
1409
2065
|
const textEl = el;
|
|
1410
2066
|
if (params.text !== void 0) {
|
|
@@ -1424,8 +2080,17 @@ function updateElement(ctx, params) {
|
|
|
1424
2080
|
if (params.fontFamily !== void 0) {
|
|
1425
2081
|
textEl.textStyle.fontFamily = params.fontFamily;
|
|
1426
2082
|
}
|
|
1427
|
-
if (params.
|
|
2083
|
+
if (params.fontThemeColor !== void 0) {
|
|
2084
|
+
textEl.textStyle.colorRef = params.fontThemeColor;
|
|
2085
|
+
const resolved = pptxViewerCore.resolveThemeColorRef(params.fontThemeColor, ctx.pptxData.themeColorMap);
|
|
2086
|
+
if (params.fontColor !== void 0) {
|
|
2087
|
+
textEl.textStyle.color = params.fontColor;
|
|
2088
|
+
} else if (resolved) {
|
|
2089
|
+
textEl.textStyle.color = resolved;
|
|
2090
|
+
}
|
|
2091
|
+
} else if (params.fontColor !== void 0) {
|
|
1428
2092
|
textEl.textStyle.color = params.fontColor;
|
|
2093
|
+
textEl.textStyle.colorRef = void 0;
|
|
1429
2094
|
}
|
|
1430
2095
|
if (params.bold !== void 0) {
|
|
1431
2096
|
textEl.textStyle.bold = params.bold;
|
|
@@ -2650,188 +3315,140 @@ function manageSmartArt(ctx, params) {
|
|
|
2650
3315
|
throw new Error(`Unknown SmartArt action: ${String(params.action)}`);
|
|
2651
3316
|
}
|
|
2652
3317
|
}
|
|
2653
|
-
function
|
|
2654
|
-
const err = validateSlideIndex(
|
|
3318
|
+
function findTableElement(ctx, slideIndex, elementId) {
|
|
3319
|
+
const err = validateSlideIndex(slideIndex, ctx.pptxData.slides.length);
|
|
2655
3320
|
if (err) {
|
|
2656
3321
|
throw new Error(err);
|
|
2657
3322
|
}
|
|
2658
|
-
const slide = ctx.pptxData.slides[
|
|
2659
|
-
const el = slide.elements.find((e) => e.id ===
|
|
2660
|
-
if (!el) {
|
|
2661
|
-
throw new Error(`Element '${
|
|
3323
|
+
const slide = ctx.pptxData.slides[slideIndex];
|
|
3324
|
+
const el = slide.elements.find((e) => e.id === elementId);
|
|
3325
|
+
if (!el) {
|
|
3326
|
+
throw new Error(`Element '${elementId}' not found on slide ${slideIndex}.`);
|
|
2662
3327
|
}
|
|
2663
|
-
if ("
|
|
2664
|
-
|
|
2665
|
-
el.shapeStyle = {};
|
|
2666
|
-
}
|
|
2667
|
-
const ss = el.shapeStyle;
|
|
2668
|
-
if (params.fillColor !== void 0) {
|
|
2669
|
-
ss.fillColor = params.fillColor;
|
|
2670
|
-
}
|
|
2671
|
-
if (params.fillMode !== void 0) {
|
|
2672
|
-
ss.fillMode = params.fillMode;
|
|
2673
|
-
}
|
|
2674
|
-
if (params.fillGradientStops !== void 0) {
|
|
2675
|
-
ss.fillGradientStops = params.fillGradientStops;
|
|
2676
|
-
}
|
|
2677
|
-
if (params.fillGradientAngle !== void 0) {
|
|
2678
|
-
ss.fillGradientAngle = params.fillGradientAngle;
|
|
2679
|
-
}
|
|
2680
|
-
if (params.fillGradientType !== void 0) {
|
|
2681
|
-
ss.fillGradientType = params.fillGradientType;
|
|
2682
|
-
}
|
|
2683
|
-
if (params.fillOpacity !== void 0) {
|
|
2684
|
-
ss.fillOpacity = params.fillOpacity;
|
|
2685
|
-
}
|
|
2686
|
-
if (params.strokeColor !== void 0) {
|
|
2687
|
-
ss.strokeColor = params.strokeColor;
|
|
2688
|
-
}
|
|
2689
|
-
if (params.strokeWidth !== void 0) {
|
|
2690
|
-
ss.strokeWidth = params.strokeWidth;
|
|
2691
|
-
}
|
|
2692
|
-
if (params.strokeDash !== void 0) {
|
|
2693
|
-
ss.strokeDash = params.strokeDash;
|
|
2694
|
-
}
|
|
2695
|
-
if (params.strokeOpacity !== void 0) {
|
|
2696
|
-
ss.strokeOpacity = params.strokeOpacity;
|
|
2697
|
-
}
|
|
2698
|
-
if (params.shadowColor !== void 0) {
|
|
2699
|
-
ss.shadowColor = params.shadowColor;
|
|
2700
|
-
}
|
|
2701
|
-
if (params.shadowBlur !== void 0) {
|
|
2702
|
-
ss.shadowBlur = params.shadowBlur;
|
|
2703
|
-
}
|
|
2704
|
-
if (params.shadowOffsetX !== void 0) {
|
|
2705
|
-
ss.shadowOffsetX = params.shadowOffsetX;
|
|
2706
|
-
}
|
|
2707
|
-
if (params.shadowOffsetY !== void 0) {
|
|
2708
|
-
ss.shadowOffsetY = params.shadowOffsetY;
|
|
2709
|
-
}
|
|
2710
|
-
if (params.shadowOpacity !== void 0) {
|
|
2711
|
-
ss.shadowOpacity = params.shadowOpacity;
|
|
2712
|
-
}
|
|
2713
|
-
if (params.glowColor !== void 0) {
|
|
2714
|
-
ss.glowColor = params.glowColor;
|
|
2715
|
-
}
|
|
2716
|
-
if (params.glowRadius !== void 0) {
|
|
2717
|
-
ss.glowRadius = params.glowRadius;
|
|
2718
|
-
}
|
|
2719
|
-
if (params.glowOpacity !== void 0) {
|
|
2720
|
-
ss.glowOpacity = params.glowOpacity;
|
|
2721
|
-
}
|
|
2722
|
-
if (params.softEdgeRadius !== void 0) {
|
|
2723
|
-
ss.softEdgeRadius = params.softEdgeRadius;
|
|
2724
|
-
}
|
|
3328
|
+
if (el.type !== "table") {
|
|
3329
|
+
throw new Error(`Element '${elementId}' is not a table.`);
|
|
2725
3330
|
}
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
if (params.cropTop !== void 0) {
|
|
2735
|
-
img.cropTop = params.cropTop;
|
|
2736
|
-
}
|
|
2737
|
-
if (params.cropRight !== void 0) {
|
|
2738
|
-
img.cropRight = params.cropRight;
|
|
2739
|
-
}
|
|
2740
|
-
if (params.cropBottom !== void 0) {
|
|
2741
|
-
img.cropBottom = params.cropBottom;
|
|
2742
|
-
}
|
|
2743
|
-
if (params.brightness !== void 0 || params.contrast !== void 0 || params.grayscale !== void 0) {
|
|
2744
|
-
if (!img.imageEffects) {
|
|
2745
|
-
img.imageEffects = {};
|
|
2746
|
-
}
|
|
2747
|
-
if (params.brightness !== void 0) {
|
|
2748
|
-
img.imageEffects.brightness = params.brightness;
|
|
2749
|
-
}
|
|
2750
|
-
if (params.contrast !== void 0) {
|
|
2751
|
-
img.imageEffects.contrast = params.contrast;
|
|
2752
|
-
}
|
|
2753
|
-
if (params.grayscale !== void 0) {
|
|
2754
|
-
img.imageEffects.grayscale = params.grayscale;
|
|
3331
|
+
return el;
|
|
3332
|
+
}
|
|
3333
|
+
function tableStyleIdsInUse(ctx) {
|
|
3334
|
+
const used = /* @__PURE__ */ new Set();
|
|
3335
|
+
for (const slide of ctx.pptxData.slides) {
|
|
3336
|
+
for (const el of slide.elements) {
|
|
3337
|
+
if (el.type === "table" && el.tableData?.tableStyleId) {
|
|
3338
|
+
used.add(pptxViewerCore.normalizeTableStyleGuid(el.tableData.tableStyleId));
|
|
2755
3339
|
}
|
|
2756
3340
|
}
|
|
2757
3341
|
}
|
|
3342
|
+
return used;
|
|
3343
|
+
}
|
|
3344
|
+
function setTableStyleSection(ctx, params) {
|
|
3345
|
+
if (!pptxViewerCore.TABLE_STYLE_PART_SEQUENCE.includes(params.section)) {
|
|
3346
|
+
throw new Error(
|
|
3347
|
+
`Unknown table style section '${params.section}'. Valid sections: ${pptxViewerCore.TABLE_STYLE_PART_SEQUENCE.join(", ")}.`
|
|
3348
|
+
);
|
|
3349
|
+
}
|
|
3350
|
+
const map = ctx.pptxData.tableStyleMap ?? {};
|
|
3351
|
+
ctx.pptxData.tableStyleMap = map;
|
|
3352
|
+
const normalizedId = pptxViewerCore.normalizeTableStyleGuid(params.styleId);
|
|
3353
|
+
const entry = map[normalizedId];
|
|
3354
|
+
if (!entry) {
|
|
3355
|
+
throw new Error(
|
|
3356
|
+
`Table style '${params.styleId}' is not loaded in this presentation. Use create_table_style to add a new one.`
|
|
3357
|
+
);
|
|
3358
|
+
}
|
|
3359
|
+
if (params.styleName !== void 0) {
|
|
3360
|
+
entry.styleName = params.styleName;
|
|
3361
|
+
}
|
|
3362
|
+
const mutableEntry = entry;
|
|
3363
|
+
if (params.fill !== void 0) {
|
|
3364
|
+
mutableEntry[`${params.section}Fill`] = params.fill;
|
|
3365
|
+
}
|
|
3366
|
+
if (params.text !== void 0) {
|
|
3367
|
+
mutableEntry[`${params.section}Text`] = params.text;
|
|
3368
|
+
}
|
|
3369
|
+
if (params.borders !== void 0) {
|
|
3370
|
+
mutableEntry[`${params.section}Borders`] = params.borders;
|
|
3371
|
+
}
|
|
3372
|
+
if (params.cell3D !== void 0) {
|
|
3373
|
+
mutableEntry[`${params.section}Cell3D`] = params.cell3D;
|
|
3374
|
+
}
|
|
2758
3375
|
return {
|
|
2759
3376
|
pptxData: ctx.pptxData,
|
|
2760
3377
|
dirty: true,
|
|
2761
|
-
result: {
|
|
3378
|
+
result: { styleId: normalizedId, section: params.section }
|
|
2762
3379
|
};
|
|
2763
3380
|
}
|
|
2764
|
-
function
|
|
2765
|
-
const
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
severity: "info",
|
|
2789
|
-
message: `Text element '${el.id}' is empty.`
|
|
2790
|
-
});
|
|
2791
|
-
}
|
|
2792
|
-
const fs = textEl.textStyle?.fontSize;
|
|
2793
|
-
if (fs !== void 0 && fs < 10) {
|
|
2794
|
-
issues.push({
|
|
2795
|
-
slideIndex: si,
|
|
2796
|
-
elementId: el.id,
|
|
2797
|
-
severity: "warning",
|
|
2798
|
-
message: `Text element '${el.id}' has very small font size (${fs}pt < 10pt).`
|
|
2799
|
-
});
|
|
2800
|
-
}
|
|
2801
|
-
const textColor = textEl.textStyle?.color?.toLowerCase();
|
|
2802
|
-
const bgColor = slide.backgroundColor?.toLowerCase();
|
|
2803
|
-
if (textColor && bgColor && textColor === bgColor) {
|
|
2804
|
-
issues.push({
|
|
2805
|
-
slideIndex: si,
|
|
2806
|
-
elementId: el.id,
|
|
2807
|
-
severity: "error",
|
|
2808
|
-
message: `Text element '${el.id}' has same color as slide background (${textColor}).`
|
|
2809
|
-
});
|
|
2810
|
-
}
|
|
2811
|
-
}
|
|
2812
|
-
}
|
|
2813
|
-
if (!slideHasText) {
|
|
2814
|
-
issues.push({
|
|
2815
|
-
slideIndex: si,
|
|
2816
|
-
severity: "warning",
|
|
2817
|
-
message: `Slide ${si + 1} contains no text elements.`
|
|
2818
|
-
});
|
|
3381
|
+
function createTableStyle(ctx, params) {
|
|
3382
|
+
const map = ctx.pptxData.tableStyleMap ?? {};
|
|
3383
|
+
ctx.pptxData.tableStyleMap = map;
|
|
3384
|
+
const basedOn = params.basedOnStyleId ? map[pptxViewerCore.normalizeTableStyleGuid(params.basedOnStyleId)] : void 0;
|
|
3385
|
+
if (params.basedOnStyleId && !basedOn) {
|
|
3386
|
+
throw new Error(`basedOnStyleId '${params.basedOnStyleId}' is not a loaded table style.`);
|
|
3387
|
+
}
|
|
3388
|
+
const entry = pptxViewerCore.createTableStyleEntry(map, { styleName: params.styleName, basedOn });
|
|
3389
|
+
pptxViewerCore.addTableStyleToMap(map, entry);
|
|
3390
|
+
return {
|
|
3391
|
+
pptxData: ctx.pptxData,
|
|
3392
|
+
dirty: true,
|
|
3393
|
+
result: { styleId: entry.styleId },
|
|
3394
|
+
...params.setAsDefault ? { saveOptions: { tableStylesDefaultId: entry.styleId } } : {}
|
|
3395
|
+
};
|
|
3396
|
+
}
|
|
3397
|
+
function deleteTableStyle(ctx, params) {
|
|
3398
|
+
const normalizedId = pptxViewerCore.normalizeTableStyleGuid(params.styleId);
|
|
3399
|
+
if (!params.force) {
|
|
3400
|
+
const used = tableStyleIdsInUse(ctx);
|
|
3401
|
+
if (used.has(normalizedId)) {
|
|
3402
|
+
throw new Error(
|
|
3403
|
+
`Table style '${params.styleId}' is assigned to at least one table on this deck. Reassign those tables first, or pass force: true.`
|
|
3404
|
+
);
|
|
2819
3405
|
}
|
|
2820
3406
|
}
|
|
2821
|
-
const
|
|
2822
|
-
|
|
2823
|
-
|
|
3407
|
+
const map = ctx.pptxData.tableStyleMap ?? {};
|
|
3408
|
+
ctx.pptxData.tableStyleMap = map;
|
|
3409
|
+
pptxViewerCore.deleteTableStyleFromMap(map, normalizedId);
|
|
2824
3410
|
return {
|
|
2825
3411
|
pptxData: ctx.pptxData,
|
|
2826
|
-
dirty:
|
|
2827
|
-
result: {
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
}
|
|
3412
|
+
dirty: true,
|
|
3413
|
+
result: { deleted: true },
|
|
3414
|
+
saveOptions: { tableStylesToDelete: [normalizedId] }
|
|
3415
|
+
};
|
|
3416
|
+
}
|
|
3417
|
+
function assignTableStyle(ctx, params) {
|
|
3418
|
+
const el = findTableElement(ctx, params.slideIndex, params.elementId);
|
|
3419
|
+
if (!el.tableData) {
|
|
3420
|
+
throw new Error(`Table '${params.elementId}' has no tableData.`);
|
|
3421
|
+
}
|
|
3422
|
+
const styleId = params.styleId ?? ctx.pptxData.tableStylesDefaultId;
|
|
3423
|
+
if (!styleId) {
|
|
3424
|
+
throw new Error(
|
|
3425
|
+
"styleId was not provided and this presentation has no tableStylesDefaultId to fall back to."
|
|
3426
|
+
);
|
|
3427
|
+
}
|
|
3428
|
+
const normalizedId = pptxViewerCore.normalizeTableStyleGuid(styleId);
|
|
3429
|
+
el.tableData.tableStyleId = normalizedId;
|
|
3430
|
+
if (params.bandedRows !== void 0) {
|
|
3431
|
+
el.tableData.bandedRows = params.bandedRows;
|
|
3432
|
+
}
|
|
3433
|
+
if (params.bandedColumns !== void 0) {
|
|
3434
|
+
el.tableData.bandedColumns = params.bandedColumns;
|
|
3435
|
+
}
|
|
3436
|
+
if (params.firstRowHeader !== void 0) {
|
|
3437
|
+
el.tableData.firstRowHeader = params.firstRowHeader;
|
|
3438
|
+
}
|
|
3439
|
+
if (params.lastRow !== void 0) {
|
|
3440
|
+
el.tableData.lastRow = params.lastRow;
|
|
3441
|
+
}
|
|
3442
|
+
if (params.firstCol !== void 0) {
|
|
3443
|
+
el.tableData.firstCol = params.firstCol;
|
|
3444
|
+
}
|
|
3445
|
+
if (params.lastCol !== void 0) {
|
|
3446
|
+
el.tableData.lastCol = params.lastCol;
|
|
3447
|
+
}
|
|
3448
|
+
return {
|
|
3449
|
+
pptxData: ctx.pptxData,
|
|
3450
|
+
dirty: true,
|
|
3451
|
+
result: { elementId: params.elementId, styleId: normalizedId }
|
|
2835
3452
|
};
|
|
2836
3453
|
}
|
|
2837
3454
|
|
|
@@ -3113,11 +3730,17 @@ async function loadPresentation(filePath, execCtx) {
|
|
|
3113
3730
|
const pptxData = await handler.load(rawBytes.buffer);
|
|
3114
3731
|
return { pptxData, rawBytes };
|
|
3115
3732
|
}
|
|
3116
|
-
async function savePresentation(filePath, pptxData, rawBytes, execCtx) {
|
|
3733
|
+
async function savePresentation(filePath, pptxData, rawBytes, execCtx, tableStyleSaveOptions) {
|
|
3117
3734
|
const handler = new pptxViewerCore.PptxHandler();
|
|
3118
3735
|
await handler.load(rawBytes.buffer);
|
|
3119
3736
|
const outputBytes = await handler.save(pptxData.slides, {
|
|
3120
|
-
headerFooter: pptxData.headerFooter
|
|
3737
|
+
headerFooter: pptxData.headerFooter,
|
|
3738
|
+
// `pptxData.tableStyleMap` carries any in-memory table-style edits a
|
|
3739
|
+
// tool made (e.g. `set_table_style_section`, `create_table_style`);
|
|
3740
|
+
// without forwarding it here those edits were silently dropped on
|
|
3741
|
+
// save even though the core save pipeline already supports them.
|
|
3742
|
+
tableStyles: pptxData.tableStyleMap,
|
|
3743
|
+
...tableStyleSaveOptions
|
|
3121
3744
|
});
|
|
3122
3745
|
if (execCtx.collaboration) {
|
|
3123
3746
|
const room = execCtx.collaboration.getRoom(filePath);
|
|
@@ -3149,7 +3772,13 @@ async function executeToolWithContext(filePath, execCtx, toolFn) {
|
|
|
3149
3772
|
const { pptxData, rawBytes } = await loadPresentation(filePath, execCtx);
|
|
3150
3773
|
const toolResult = await toolFn({ pptxData });
|
|
3151
3774
|
if (toolResult.dirty) {
|
|
3152
|
-
const saveResult = await savePresentation(
|
|
3775
|
+
const saveResult = await savePresentation(
|
|
3776
|
+
filePath,
|
|
3777
|
+
toolResult.pptxData,
|
|
3778
|
+
rawBytes,
|
|
3779
|
+
execCtx,
|
|
3780
|
+
toolResult.saveOptions
|
|
3781
|
+
);
|
|
3153
3782
|
return { ...toolResult.result, ...saveResult };
|
|
3154
3783
|
}
|
|
3155
3784
|
return toolResult.result;
|
|
@@ -3629,6 +4258,70 @@ function createServer() {
|
|
|
3629
4258
|
};
|
|
3630
4259
|
}
|
|
3631
4260
|
);
|
|
4261
|
+
server2.registerTool(
|
|
4262
|
+
"set_table_style_section",
|
|
4263
|
+
{
|
|
4264
|
+
description: "Patch the fill, text, borders, or cell3D of one section (wholeTbl, banding, first/last row/col, or a corner cell) of an existing loaded table style",
|
|
4265
|
+
inputSchema: SetTableStyleSectionSchema.shape
|
|
4266
|
+
},
|
|
4267
|
+
async (params) => {
|
|
4268
|
+
const result = await runMcpTool(
|
|
4269
|
+
params.filePath,
|
|
4270
|
+
(ctx) => setTableStyleSection(ctx, params)
|
|
4271
|
+
);
|
|
4272
|
+
return {
|
|
4273
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
4274
|
+
};
|
|
4275
|
+
}
|
|
4276
|
+
);
|
|
4277
|
+
server2.registerTool(
|
|
4278
|
+
"create_table_style",
|
|
4279
|
+
{
|
|
4280
|
+
description: "Create a new table style (optionally cloned from an existing one) and optionally set it as the default",
|
|
4281
|
+
inputSchema: CreateTableStyleSchema.shape
|
|
4282
|
+
},
|
|
4283
|
+
async (params) => {
|
|
4284
|
+
const result = await runMcpTool(
|
|
4285
|
+
params.filePath,
|
|
4286
|
+
(ctx) => createTableStyle(ctx, params)
|
|
4287
|
+
);
|
|
4288
|
+
return {
|
|
4289
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
4290
|
+
};
|
|
4291
|
+
}
|
|
4292
|
+
);
|
|
4293
|
+
server2.registerTool(
|
|
4294
|
+
"delete_table_style",
|
|
4295
|
+
{
|
|
4296
|
+
description: "Remove a table style from the presentation",
|
|
4297
|
+
inputSchema: DeleteTableStyleSchema.shape
|
|
4298
|
+
},
|
|
4299
|
+
async (params) => {
|
|
4300
|
+
const result = await runMcpTool(
|
|
4301
|
+
params.filePath,
|
|
4302
|
+
(ctx) => deleteTableStyle(ctx, params)
|
|
4303
|
+
);
|
|
4304
|
+
return {
|
|
4305
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
4306
|
+
};
|
|
4307
|
+
}
|
|
4308
|
+
);
|
|
4309
|
+
server2.registerTool(
|
|
4310
|
+
"assign_table_style",
|
|
4311
|
+
{
|
|
4312
|
+
description: "Assign a table style (and row/column emphasis flags) to an existing table",
|
|
4313
|
+
inputSchema: AssignTableStyleSchema.shape
|
|
4314
|
+
},
|
|
4315
|
+
async (params) => {
|
|
4316
|
+
const result = await runMcpTool(
|
|
4317
|
+
params.filePath,
|
|
4318
|
+
(ctx) => assignTableStyle(ctx, params)
|
|
4319
|
+
);
|
|
4320
|
+
return {
|
|
4321
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
4322
|
+
};
|
|
4323
|
+
}
|
|
4324
|
+
);
|
|
3632
4325
|
server2.registerTool(
|
|
3633
4326
|
"update_element_style",
|
|
3634
4327
|
{
|
|
@@ -3875,6 +4568,76 @@ function createServer() {
|
|
|
3875
4568
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
3876
4569
|
}
|
|
3877
4570
|
);
|
|
4571
|
+
server2.registerTool(
|
|
4572
|
+
"format_chart_data_point",
|
|
4573
|
+
{
|
|
4574
|
+
description: "Set per-data-point chart formatting: fill/stroke colour, stroke width, dash style (c:dPt/c:spPr), explosion, and marker override",
|
|
4575
|
+
inputSchema: FormatChartDataPointSchema.shape
|
|
4576
|
+
},
|
|
4577
|
+
async (params) => {
|
|
4578
|
+
const result = await runMcpTool(
|
|
4579
|
+
params.filePath,
|
|
4580
|
+
(ctx) => formatChartDataPoint(ctx, params)
|
|
4581
|
+
);
|
|
4582
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4583
|
+
}
|
|
4584
|
+
);
|
|
4585
|
+
server2.registerTool(
|
|
4586
|
+
"format_chart_data_label",
|
|
4587
|
+
{
|
|
4588
|
+
description: "Set a per-data-point data-label override (c:dLbl): show flags, position, custom text, and the label's own fill/line formatting (c:spPr) and font (c:txPr)",
|
|
4589
|
+
inputSchema: FormatChartDataLabelSchema.shape
|
|
4590
|
+
},
|
|
4591
|
+
async (params) => {
|
|
4592
|
+
const result = await runMcpTool(
|
|
4593
|
+
params.filePath,
|
|
4594
|
+
(ctx) => formatChartDataLabel(ctx, params)
|
|
4595
|
+
);
|
|
4596
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4597
|
+
}
|
|
4598
|
+
);
|
|
4599
|
+
server2.registerTool(
|
|
4600
|
+
"format_chart_series",
|
|
4601
|
+
{
|
|
4602
|
+
description: "Set a chart series marker (c:marker), trendline (c:trendline, incl. line width/dash), or error bars (c:errBars, incl. line width/dash)",
|
|
4603
|
+
inputSchema: FormatChartSeriesSchema.shape
|
|
4604
|
+
},
|
|
4605
|
+
async (params) => {
|
|
4606
|
+
const result = await runMcpTool(
|
|
4607
|
+
params.filePath,
|
|
4608
|
+
(ctx) => formatChartSeries(ctx, params)
|
|
4609
|
+
);
|
|
4610
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4611
|
+
}
|
|
4612
|
+
);
|
|
4613
|
+
server2.registerTool(
|
|
4614
|
+
"set_chart_helper_line",
|
|
4615
|
+
{
|
|
4616
|
+
description: "Set or remove a chart-level helper line on a line/stock/combo chart: c:dropLines or c:hiLowLines",
|
|
4617
|
+
inputSchema: SetChartHelperLineSchema.shape
|
|
4618
|
+
},
|
|
4619
|
+
async (params) => {
|
|
4620
|
+
const result = await runMcpTool(
|
|
4621
|
+
params.filePath,
|
|
4622
|
+
(ctx) => setChartHelperLineT(ctx, params)
|
|
4623
|
+
);
|
|
4624
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4625
|
+
}
|
|
4626
|
+
);
|
|
4627
|
+
server2.registerTool(
|
|
4628
|
+
"set_chart_color_map_override",
|
|
4629
|
+
{
|
|
4630
|
+
description: "Set or remove a chart's theme colour-map override (c:clrMapOvr), remapping theme colour roles for this chart only",
|
|
4631
|
+
inputSchema: SetChartColorMapOverrideSchema.shape
|
|
4632
|
+
},
|
|
4633
|
+
async (params) => {
|
|
4634
|
+
const result = await runMcpTool(
|
|
4635
|
+
params.filePath,
|
|
4636
|
+
(ctx) => setChartColorMapOverrideT(ctx, params)
|
|
4637
|
+
);
|
|
4638
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4639
|
+
}
|
|
4640
|
+
);
|
|
3878
4641
|
server2.registerTool(
|
|
3879
4642
|
"chart_user_shape_list",
|
|
3880
4643
|
{
|