pptx-viewer-core 1.2.3 → 1.2.5

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.js CHANGED
@@ -7175,6 +7175,32 @@ function findAinkInkPayload(graphicData) {
7175
7175
  }
7176
7176
  return void 0;
7177
7177
  }
7178
+ function findOleObjPayload(graphicData) {
7179
+ if (!graphicData) {
7180
+ return void 0;
7181
+ }
7182
+ const direct = graphicData["p:oleObj"];
7183
+ if (direct) {
7184
+ return direct;
7185
+ }
7186
+ const altContent = graphicData["mc:AlternateContent"];
7187
+ if (!altContent) {
7188
+ return void 0;
7189
+ }
7190
+ const fallback = altContent["mc:Fallback"];
7191
+ const fallbackOleObj = fallback?.["p:oleObj"];
7192
+ if (fallbackOleObj) {
7193
+ return fallbackOleObj;
7194
+ }
7195
+ const choices = ensureArrayLike(altContent["mc:Choice"]);
7196
+ for (const choice of choices) {
7197
+ const node = choice?.["p:oleObj"];
7198
+ if (node) {
7199
+ return node;
7200
+ }
7201
+ }
7202
+ return void 0;
7203
+ }
7178
7204
  function decodeAinkInk(inkRoot) {
7179
7205
  const inkPaths = [];
7180
7206
  const inkColors = [];
@@ -7287,7 +7313,7 @@ var PptxGraphicFrameParser = class {
7287
7313
  };
7288
7314
  }
7289
7315
  if (type === "ole" && graphicData) {
7290
- const oleObject = graphicData["p:oleObj"];
7316
+ const oleObject = findOleObjPayload(graphicData);
7291
7317
  const oleProgId = String(oleObject?.["@_progId"] || "").trim() || void 0;
7292
7318
  const oleName = String(oleObject?.["@_name"] || "").trim() || void 0;
7293
7319
  const oleClsId = String(oleObject?.["@_classid"] || "").trim() || void 0;
@@ -7378,7 +7404,7 @@ var PptxGraphicFrameParser = class {
7378
7404
  if (graphicData["dgm:relIds"] || uri.includes("/drawingml/2006/diagram")) {
7379
7405
  return "smartArt";
7380
7406
  }
7381
- if (graphicData["p:oleObj"] || uri.includes("/drawingml/2006/ole")) {
7407
+ if (uri.includes("/presentationml/2006/ole") || uri.includes("/drawingml/2006/ole") || findOleObjPayload(graphicData)) {
7382
7408
  return "ole";
7383
7409
  }
7384
7410
  if (graphicData["a:videoFile"] || graphicData["a:audioFile"] || uri.includes("/drawingml/2006/media")) {
@@ -8679,6 +8705,87 @@ function parseGuideNode(node) {
8679
8705
  return { id, orientation, positionEmu, color };
8680
8706
  }
8681
8707
 
8708
+ // src/core/services/animation-target-reconcile.ts
8709
+ var NV_CONTAINERS = [
8710
+ "p:nvSpPr",
8711
+ "p:nvPicPr",
8712
+ "p:nvCxnSpPr",
8713
+ "p:nvGraphicFramePr",
8714
+ "p:nvGrpSpPr"
8715
+ ];
8716
+ function readCnvPrId(rawXml) {
8717
+ if (!rawXml) {
8718
+ return void 0;
8719
+ }
8720
+ for (const nvKey of NV_CONTAINERS) {
8721
+ const nv = rawXml[nvKey];
8722
+ const cNvPr = nv?.["p:cNvPr"];
8723
+ const id = cNvPr?.["@_id"];
8724
+ if (id !== void 0 && id !== null && String(id).length > 0) {
8725
+ return String(id);
8726
+ }
8727
+ }
8728
+ return void 0;
8729
+ }
8730
+ function isTemplateElementId(elementId) {
8731
+ return elementId.startsWith("layout-") || elementId.startsWith("master-");
8732
+ }
8733
+ function collectShapeIdMap(elements) {
8734
+ const map = /* @__PURE__ */ new Map();
8735
+ const walk = (els) => {
8736
+ for (const el of els) {
8737
+ const cnvId = readCnvPrId(el.rawXml);
8738
+ if (cnvId) {
8739
+ el.shapeId = cnvId;
8740
+ if (!isTemplateElementId(el.id)) {
8741
+ map.set(cnvId, el.id);
8742
+ }
8743
+ }
8744
+ if (el.type === "group" && Array.isArray(el.children)) {
8745
+ walk(el.children);
8746
+ }
8747
+ }
8748
+ };
8749
+ walk(elements);
8750
+ return map;
8751
+ }
8752
+ function reconcileAnimationTargets(elements, nativeAnimations, editorAnimations) {
8753
+ const map = collectShapeIdMap(elements);
8754
+ if (map.size === 0) {
8755
+ return;
8756
+ }
8757
+ if (nativeAnimations) {
8758
+ for (const anim of nativeAnimations) {
8759
+ if (anim.targetId !== void 0) {
8760
+ const resolved = map.get(anim.targetId);
8761
+ if (resolved) {
8762
+ anim.targetId = resolved;
8763
+ }
8764
+ }
8765
+ if (anim.triggerShapeId !== void 0) {
8766
+ const resolved = map.get(anim.triggerShapeId);
8767
+ if (resolved) {
8768
+ anim.triggerShapeId = resolved;
8769
+ }
8770
+ }
8771
+ }
8772
+ }
8773
+ if (editorAnimations) {
8774
+ for (const anim of editorAnimations) {
8775
+ const resolvedElement = map.get(anim.elementId);
8776
+ if (resolvedElement) {
8777
+ anim.elementId = resolvedElement;
8778
+ }
8779
+ if (anim.triggerShapeId !== void 0) {
8780
+ const resolvedTrigger = map.get(anim.triggerShapeId);
8781
+ if (resolvedTrigger) {
8782
+ anim.triggerShapeId = resolvedTrigger;
8783
+ }
8784
+ }
8785
+ }
8786
+ }
8787
+ }
8788
+
8682
8789
  // src/core/services/PptxSlideLoaderService.ts
8683
8790
  var PptxSlideLoaderService = class {
8684
8791
  /**
@@ -8819,6 +8926,7 @@ var PptxSlideLoaderService = class {
8819
8926
  const transition = params.parseSlideTransition(slideXmlObj, path);
8820
8927
  const animations = params.parseEditorAnimations(slideXmlObj);
8821
8928
  const nativeAnimations = params.parseNativeAnimations(slideXmlObj);
8929
+ reconcileAnimationTargets(elements, nativeAnimations, animations);
8822
8930
  const rawTiming = slideXmlObj["p:sld"]?.["p:timing"];
8823
8931
  const drawingGuides = parseSlideDrawingGuides(slideXmlObj);
8824
8932
  const customerData = await params.parseSlideCustomerData(slideXmlObj, path);
@@ -9318,6 +9426,60 @@ var PptxEditorAnimationService = class {
9318
9426
  }
9319
9427
  };
9320
9428
 
9429
+ // src/core/services/animation-shape-id-assign.ts
9430
+ function flattenElements(elements, out) {
9431
+ for (const el of elements) {
9432
+ out.push(el);
9433
+ if (el.type === "group" && Array.isArray(el.children)) {
9434
+ flattenElements(el.children, out);
9435
+ }
9436
+ }
9437
+ }
9438
+ function maxShapeId(elements) {
9439
+ let max = 0;
9440
+ for (const el of elements) {
9441
+ if (el.shapeId !== void 0) {
9442
+ const n = Number.parseInt(el.shapeId, 10);
9443
+ if (Number.isFinite(n) && n > max) {
9444
+ max = n;
9445
+ }
9446
+ }
9447
+ }
9448
+ return max;
9449
+ }
9450
+ function remapEditorAnimationsToShapeIds(elements, animations, reservedMaxId = 0) {
9451
+ const flat = [];
9452
+ flattenElements(elements, flat);
9453
+ const byId = /* @__PURE__ */ new Map();
9454
+ for (const el of flat) {
9455
+ byId.set(el.id, el);
9456
+ }
9457
+ let nextId2 = Math.max(maxShapeId(flat), reservedMaxId) + 1;
9458
+ const resolve = (elementId) => {
9459
+ const el = byId.get(elementId);
9460
+ if (!el) {
9461
+ return void 0;
9462
+ }
9463
+ if (el.shapeId === void 0) {
9464
+ el.shapeId = String(nextId2);
9465
+ nextId2 += 1;
9466
+ }
9467
+ return el.shapeId;
9468
+ };
9469
+ return animations.map((anim) => {
9470
+ const resolvedElement = resolve(anim.elementId);
9471
+ const resolvedTrigger = anim.triggerShapeId !== void 0 ? resolve(anim.triggerShapeId) : void 0;
9472
+ if (resolvedElement === void 0 && resolvedTrigger === void 0) {
9473
+ return anim;
9474
+ }
9475
+ return {
9476
+ ...anim,
9477
+ elementId: resolvedElement ?? anim.elementId,
9478
+ triggerShapeId: resolvedTrigger ?? anim.triggerShapeId
9479
+ };
9480
+ });
9481
+ }
9482
+
9321
9483
  // src/core/services/native-animation-helpers.ts
9322
9484
  function extractSoundAction(cTn) {
9323
9485
  const stSnd = cTn["p:stSnd"];
@@ -10540,7 +10702,7 @@ var PptxSlideTransitionService = class {
10540
10702
  }
10541
10703
  parseSlideTransition(slideXml2) {
10542
10704
  const slideRoot = this.xmlLookupService.getChildByLocalName(slideXml2, "sld");
10543
- const transitionNode = this.xmlLookupService.getChildByLocalName(slideRoot, "transition");
10705
+ const transitionNode = this.xmlLookupService.getChildByLocalName(slideRoot, "transition") || this.findTransitionInAlternateContent(slideRoot);
10544
10706
  if (!transitionNode) {
10545
10707
  return void 0;
10546
10708
  }
@@ -10612,7 +10774,8 @@ var PptxSlideTransitionService = class {
10612
10774
  transitionType = "morph";
10613
10775
  }
10614
10776
  }
10615
- const parsedDuration = Number.parseInt(String(transitionNode["@_dur"] || ""), 10);
10777
+ const rawDuration = transitionNode["@_dur"] ?? transitionNode["@_p14:dur"];
10778
+ const parsedDuration = Number.parseInt(String(rawDuration || ""), 10);
10616
10779
  const durationMs = Number.isFinite(parsedDuration) && parsedDuration > 0 ? parsedDuration : void 0;
10617
10780
  const advanceOnClickToken = String(transitionNode["@_advClick"] || "").trim();
10618
10781
  const advanceOnClick = advanceOnClickToken.length > 0 ? !["0", "false", "off"].includes(advanceOnClickToken.toLowerCase()) : void 0;
@@ -10661,6 +10824,35 @@ var PptxSlideTransitionService = class {
10661
10824
  rawExtLst
10662
10825
  };
10663
10826
  }
10827
+ /**
10828
+ * Locate a `<p:transition>` wrapped in a slide-root `mc:AlternateContent`
10829
+ * envelope.
10830
+ *
10831
+ * Real PowerPoint (verified via COM-authored fixtures) wraps the
10832
+ * transition in `mc:AlternateContent` whenever it carries an Office
10833
+ * 2010+ attribute such as `p14:dur` (sub-second transition duration):
10834
+ * an `mc:Choice Requires="p14"` branch carries the richer transition,
10835
+ * and `mc:Fallback` carries a plain one for older readers. Without this
10836
+ * unwrap, `p:sld`'s direct-child lookup for `transition` finds nothing
10837
+ * and the whole transition (including plain ones falling back with no
10838
+ * p14 data) is silently dropped, even though `mc:Choice` is otherwise a
10839
+ * complete, directly usable `p:transition` node.
10840
+ */
10841
+ findTransitionInAlternateContent(slideRoot) {
10842
+ const altContent = this.xmlLookupService.getChildByLocalName(slideRoot, "AlternateContent");
10843
+ if (!altContent) {
10844
+ return void 0;
10845
+ }
10846
+ const choices = this.xmlLookupService.getChildrenArrayByLocalName(altContent, "Choice");
10847
+ for (const choice of choices) {
10848
+ const transitionNode = this.xmlLookupService.getChildByLocalName(choice, "transition");
10849
+ if (transitionNode) {
10850
+ return transitionNode;
10851
+ }
10852
+ }
10853
+ const fallback = this.xmlLookupService.getChildByLocalName(altContent, "Fallback");
10854
+ return this.xmlLookupService.getChildByLocalName(fallback, "transition");
10855
+ }
10664
10856
  /**
10665
10857
  * Detects the PowerPoint 2016+ `morph` transition stored as a p159 extension
10666
10858
  * inside the transition's extLst.
@@ -16907,6 +17099,7 @@ function getDefaultShapeType(layoutType) {
16907
17099
  case "cycle":
16908
17100
  case "target":
16909
17101
  case "gear":
17102
+ return "ellipse";
16910
17103
  case "relationship":
16911
17104
  case "venn":
16912
17105
  return "ellipse";
@@ -16914,7 +17107,10 @@ function getDefaultShapeType(layoutType) {
16914
17107
  return "chevron";
16915
17108
  case "pyramid":
16916
17109
  case "funnel":
16917
- return "rect";
17110
+ return "trapezoid";
17111
+ case "timeline":
17112
+ case "bending":
17113
+ return "roundRect";
16918
17114
  default:
16919
17115
  return "roundRect";
16920
17116
  }
@@ -17004,7 +17200,7 @@ function layoutCycle(nodes, bounds, themeColorMap) {
17004
17200
  const ny = cy + radius * Math.sin(angle) - nodeH / 2;
17005
17201
  const fill = accentColor(i, themeColorMap);
17006
17202
  elements.push(
17007
- makeShapeElement(nextId("sa-cycle"), nx, ny, nodeW, nodeH, "roundRect", fill, node.text, {
17203
+ makeShapeElement(nextId("sa-cycle"), nx, ny, nodeW, nodeH, "ellipse", fill, node.text, {
17008
17204
  fontSize: Math.max(7, Math.min(10, nodeW * 0.1))
17009
17205
  })
17010
17206
  );
@@ -17071,7 +17267,7 @@ function layoutPyramid(nodes, bounds, themeColorMap) {
17071
17267
  const x = bounds.x + (bounds.width - w) / 2;
17072
17268
  const y = bounds.y + padding + i * (bandH + gap);
17073
17269
  const fill = accentColor(i, themeColorMap);
17074
- return makeShapeElement(nextId("sa-pyramid"), x, y, w, bandH, "rect", fill, node.text, {
17270
+ return makeShapeElement(nextId("sa-pyramid"), x, y, w, bandH, "trapezoid", fill, node.text, {
17075
17271
  fontSize: Math.max(8, Math.min(11, bandH * 0.4))
17076
17272
  });
17077
17273
  });
@@ -17820,7 +18016,7 @@ function decomposeSmartArt(smartArtData, containerBounds, themeColorMap, layoutD
17820
18016
  themeColorMap,
17821
18017
  smartArtData.colorTransform?.fillColors
17822
18018
  );
17823
- const layoutType = smartArtData.resolvedLayoutType ?? resolveLayoutFromRawType(smartArtData.layoutType);
18019
+ const layoutType = resolveEffectiveLayoutType(smartArtData);
17824
18020
  const namedLayout = smartArtData.layout;
17825
18021
  if (namedLayout) {
17826
18022
  const namedResult = dispatchNamedLayout(namedLayout, nodes, containerBounds, effectiveThemeMap);
@@ -17851,6 +18047,52 @@ function dispatchLayoutByType(layoutType, nodes, containerBounds, effectiveTheme
17851
18047
  return layoutWithHeuristic(nodes, containerBounds, effectiveThemeMap);
17852
18048
  }
17853
18049
  }
18050
+ var LAYOUT_PRESET_TO_TYPE = {
18051
+ basicBlockList: "list",
18052
+ alternatingHexagons: "list",
18053
+ horizontalBulletList: "list",
18054
+ stackedList: "list",
18055
+ tableList: "list",
18056
+ trapezoidList: "list",
18057
+ pictureAccentList: "list",
18058
+ verticalBlockList: "list",
18059
+ groupedList: "list",
18060
+ pyramidList: "list",
18061
+ horizontalPictureList: "list",
18062
+ basicMatrix: "matrix",
18063
+ basicPyramid: "pyramid",
18064
+ invertedPyramid: "pyramid",
18065
+ basicChevronProcess: "chevron",
18066
+ continuousBlockProcess: "process",
18067
+ segmentedProcess: "process",
18068
+ upwardArrow: "process",
18069
+ basicTimeline: "timeline",
18070
+ bendingProcess: "bending",
18071
+ stepDownProcess: "process",
18072
+ alternatingFlow: "process",
18073
+ descendingProcess: "process",
18074
+ accentProcess: "process",
18075
+ verticalChevronList: "chevron",
18076
+ basicFunnel: "funnel",
18077
+ basicCycle: "cycle",
18078
+ basicPie: "cycle",
18079
+ basicRadial: "cycle",
18080
+ basicVenn: "relationship",
18081
+ convergingRadial: "cycle",
18082
+ linearVenn: "relationship",
18083
+ basicTarget: "target",
18084
+ interlockingGears: "gear",
18085
+ hierarchy: "hierarchy"
18086
+ };
18087
+ function resolveEffectiveLayoutType(data) {
18088
+ if (data.resolvedLayoutType && data.resolvedLayoutType !== "unknown") {
18089
+ return data.resolvedLayoutType;
18090
+ }
18091
+ if (data.layout && LAYOUT_PRESET_TO_TYPE[data.layout]) {
18092
+ return LAYOUT_PRESET_TO_TYPE[data.layout];
18093
+ }
18094
+ return resolveLayoutFromRawType(data.layoutType);
18095
+ }
17854
18096
  function buildEffectiveThemeMap(themeColorMap, colorTransformFills) {
17855
18097
  if (!colorTransformFills || colorTransformFills.length === 0) {
17856
18098
  return themeColorMap;
@@ -36091,14 +36333,19 @@ function transPointXml(guid, type, cxnGuid) {
36091
36333
  function docPointXml(docGuid, ids) {
36092
36334
  return `<dgm:pt modelId="${docGuid}" type="doc"><dgm:prSet loTypeId="${xmlEscape(ids.layoutUniqueId)}" loCatId="${xmlEscape(ids.layoutCategory)}" qsTypeId="${xmlEscape(ids.quickStyleUniqueId)}" qsCatId="simple" csTypeId="${xmlEscape(ids.colorsUniqueId)}" csCatId="${xmlEscape(ids.colorsCategory)}"/><dgm:spPr/>${EMPTY_TEXT_BODY}</dgm:pt>`;
36093
36335
  }
36094
- function buildFabricatedDiagramDataXml(data, ids) {
36095
- const docGuid = newSmartArtGuid();
36336
+ function buildNodeGuidMap(nodes) {
36096
36337
  const guidByNodeId = /* @__PURE__ */ new Map();
36097
- for (const node of data.nodes) {
36338
+ for (const node of nodes) {
36098
36339
  if (node.id && !guidByNodeId.has(node.id)) {
36099
36340
  guidByNodeId.set(node.id, GUID_MODEL_ID.test(node.id) ? node.id : newSmartArtGuid());
36100
36341
  }
36101
36342
  }
36343
+ return guidByNodeId;
36344
+ }
36345
+ var DSP_DATA_MODEL_EXT_URI = "http://schemas.microsoft.com/office/drawing/2008/diagram";
36346
+ function buildFabricatedDiagramDataXml(data, ids, options = {}) {
36347
+ const docGuid = newSmartArtGuid();
36348
+ const guidByNodeId = options.guidByNodeId ?? buildNodeGuidMap(data.nodes);
36102
36349
  const points2 = [docPointXml(docGuid, ids)];
36103
36350
  const connections = [];
36104
36351
  const nextSrcOrd = /* @__PURE__ */ new Map();
@@ -36121,7 +36368,121 @@ function buildFabricatedDiagramDataXml(data, ids) {
36121
36368
  );
36122
36369
  }
36123
36370
  return `${XML_PROLOG}\r
36124
- <dgm:dataModel ${DGM_XMLNS}><dgm:ptLst>${points2.join("")}</dgm:ptLst><dgm:cxnLst>${connections.join("")}</dgm:cxnLst><dgm:bg/><dgm:whole/></dgm:dataModel>`;
36371
+ <dgm:dataModel ${DGM_XMLNS}><dgm:ptLst>${points2.join("")}</dgm:ptLst><dgm:cxnLst>${connections.join("")}</dgm:cxnLst><dgm:bg/><dgm:whole/>${dataModelExtXml(options.drawingRelId)}</dgm:dataModel>`;
36372
+ }
36373
+ function dataModelExtXml(drawingRelId) {
36374
+ if (!drawingRelId) {
36375
+ return "";
36376
+ }
36377
+ return `<dgm:extLst><a:ext uri="${DSP_DATA_MODEL_EXT_URI}"><dsp:dataModelExt xmlns:dsp="${DSP_DATA_MODEL_EXT_URI}" relId="${xmlEscape(drawingRelId)}" minVer="http://schemas.openxmlformats.org/drawingml/2006/diagram"/></a:ext></dgm:extLst>`;
36378
+ }
36379
+
36380
+ // src/core/core/runtime/smartart-fabrication-drawing.ts
36381
+ var DIAGRAM_DRAWING_CONTENT_TYPE = "application/vnd.ms-office.drawingml.diagramDrawing+xml";
36382
+ var DIAGRAM_DRAWING_REL_TYPE = "http://schemas.microsoft.com/office/2007/relationships/diagramDrawing";
36383
+ var DSP_XMLNS = 'xmlns:dsp="http://schemas.microsoft.com/office/drawing/2008/diagram" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"';
36384
+ var ACCENTS = ["accent1", "accent2", "accent3", "accent4", "accent5", "accent6"];
36385
+ function toEmu(px2) {
36386
+ return Math.round(px2 * EMU_PER_PX);
36387
+ }
36388
+ function normalizeHex3(color) {
36389
+ if (!color) {
36390
+ return void 0;
36391
+ }
36392
+ const hex8 = color.replace(/^#/u, "").trim();
36393
+ return /^[0-9A-Fa-f]{6}$/u.test(hex8) ? hex8.toUpperCase() : void 0;
36394
+ }
36395
+ function resolveShapeModelId(shape, index, nodes, guidByNodeId) {
36396
+ const direct = guidByNodeId.get(shape.id);
36397
+ if (direct) {
36398
+ return direct;
36399
+ }
36400
+ const matched = nodes.find(
36401
+ (node) => node.id && (shape.id === node.id || shape.id.endsWith(`-${node.id}`))
36402
+ );
36403
+ if (matched?.id) {
36404
+ const guid = guidByNodeId.get(matched.id);
36405
+ if (guid) {
36406
+ return guid;
36407
+ }
36408
+ }
36409
+ const positional = nodes[index]?.id;
36410
+ if (positional) {
36411
+ const guid = guidByNodeId.get(positional);
36412
+ if (guid) {
36413
+ return guid;
36414
+ }
36415
+ }
36416
+ return newSmartArtGuid();
36417
+ }
36418
+ function textBodyXml(shape) {
36419
+ const text = shape.text ?? "";
36420
+ const fontColor = normalizeHex3(shape.fontColor);
36421
+ const size = shape.fontSize && shape.fontSize > 0 ? ` sz="${Math.round(shape.fontSize * 100)}"` : "";
36422
+ const fill = fontColor ? `<a:solidFill><a:srgbClr val="${fontColor}"/></a:solidFill>` : "";
36423
+ const rPr = `<a:rPr lang="en-US"${size}>${fill}</a:rPr>`;
36424
+ const run = text ? `<a:r>${rPr}<a:t>${xmlEscape(text)}</a:t></a:r>` : `<a:endParaRPr lang="en-US"/>`;
36425
+ return `<dsp:txBody><a:bodyPr/><a:lstStyle/><a:p><a:pPr algn="ctr"/>${run}</a:p></dsp:txBody>`;
36426
+ }
36427
+ function styleXml(index) {
36428
+ const accent = ACCENTS[index % ACCENTS.length];
36429
+ return `<dsp:style><a:lnRef idx="2"><a:schemeClr val="${accent}"><a:shade val="50000"/></a:schemeClr></a:lnRef><a:fillRef idx="1"><a:schemeClr val="${accent}"/></a:fillRef><a:effectRef idx="0"><a:schemeClr val="${accent}"/></a:effectRef><a:fontRef idx="minor"><a:schemeClr val="lt1"/></a:fontRef></dsp:style>`;
36430
+ }
36431
+ function shapePropsXml(shape) {
36432
+ const rot = shape.rotation ? ` rot="${Math.round(shape.rotation * 6e4)}"` : "";
36433
+ const xfrm = `<a:xfrm${rot}><a:off x="${toEmu(shape.x)}" y="${toEmu(shape.y)}"/><a:ext cx="${toEmu(Math.max(shape.width, 1))}" cy="${toEmu(Math.max(shape.height, 1))}"/></a:xfrm>`;
36434
+ const prst = shape.shapeType && shape.shapeType.length > 0 ? shape.shapeType : "rect";
36435
+ const geom = `<a:prstGeom prst="${xmlEscape(prst)}"><a:avLst/></a:prstGeom>`;
36436
+ const fillHex = normalizeHex3(shape.fillColor);
36437
+ const fill = fillHex ? `<a:solidFill><a:srgbClr val="${fillHex}"/></a:solidFill>` : "";
36438
+ const strokeHex = normalizeHex3(shape.strokeColor);
36439
+ const strokeW = shape.strokeWidth && shape.strokeWidth > 0 ? ` w="${Math.round(shape.strokeWidth * 12700)}"` : "";
36440
+ const ln = strokeHex ? `<a:ln${strokeW}><a:solidFill><a:srgbClr val="${strokeHex}"/></a:solidFill></a:ln>` : "";
36441
+ return `<dsp:spPr>${xfrm}${geom}${fill}${ln}</dsp:spPr>`;
36442
+ }
36443
+ function shapeXml(shape, index, nodes, guidByNodeId) {
36444
+ const modelId = resolveShapeModelId(shape, index, nodes, guidByNodeId);
36445
+ return `<dsp:sp modelId="${modelId}"><dsp:nvSpPr><dsp:cNvPr id="0" name=""/><dsp:cNvSpPr/></dsp:nvSpPr>${shapePropsXml(shape)}${styleXml(index)}${textBodyXml(shape)}</dsp:sp>`;
36446
+ }
36447
+ function buildFabricatedDrawingXml(shapes, nodes, guidByNodeId) {
36448
+ if (!shapes || shapes.length === 0) {
36449
+ return void 0;
36450
+ }
36451
+ const body = shapes.map((shape, index) => shapeXml(shape, index, nodes, guidByNodeId)).join("");
36452
+ return `${XML_PROLOG}\r
36453
+ <dsp:drawing ${DSP_XMLNS}><dsp:spTree><dsp:nvGrpSpPr><dsp:cNvPr id="0" name=""/><dsp:cNvGrpSpPr/></dsp:nvGrpSpPr><dsp:grpSpPr/>${body}</dsp:spTree></dsp:drawing>`;
36454
+ }
36455
+ function buildDiagramDataRelsXml(drawingRelId, drawingFileName) {
36456
+ return `${XML_PROLOG}\r
36457
+ <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="${xmlEscape(drawingRelId)}" Type="${DIAGRAM_DRAWING_REL_TYPE}" Target="${xmlEscape(drawingFileName)}"/></Relationships>`;
36458
+ }
36459
+ function smartArtElementsToDrawingShapes(elements) {
36460
+ if (!elements || elements.length === 0) {
36461
+ return [];
36462
+ }
36463
+ const shapes = [];
36464
+ for (const el of elements) {
36465
+ if (el.type !== "shape") {
36466
+ continue;
36467
+ }
36468
+ const shape = el;
36469
+ shapes.push({
36470
+ id: shape.id,
36471
+ shapeType: shape.shapeType ?? "rect",
36472
+ x: shape.x,
36473
+ y: shape.y,
36474
+ width: shape.width,
36475
+ height: shape.height,
36476
+ rotation: shape.rotation,
36477
+ fillColor: shape.shapeStyle?.fillColor,
36478
+ strokeColor: shape.shapeStyle?.strokeColor,
36479
+ strokeWidth: shape.shapeStyle?.strokeWidth,
36480
+ text: shape.text,
36481
+ fontSize: shape.textStyle?.fontSize,
36482
+ fontColor: shape.textStyle?.color
36483
+ });
36484
+ }
36485
+ return shapes;
36125
36486
  }
36126
36487
 
36127
36488
  // src/core/core/runtime/smartart-fabrication-hierarchy.ts
@@ -36329,14 +36690,29 @@ var PptxHandlerRuntime32 = class _PptxHandlerRuntime extends PptxHandlerRuntime3
36329
36690
  const data = el.smartArtData;
36330
36691
  const family = resolveFabricatedLayoutFamily(data);
36331
36692
  const index = this.nextDiagramPartIndex();
36693
+ const guidByNodeId = buildNodeGuidMap(data.nodes);
36694
+ const drawingShapes = data.drawingShapes && data.drawingShapes.length > 0 ? data.drawingShapes : smartArtElementsToDrawingShapes(
36695
+ decomposeSmartArt(data, {
36696
+ x: 0,
36697
+ y: 0,
36698
+ width: Math.max(el.width, 1),
36699
+ height: Math.max(el.height, 1)
36700
+ })
36701
+ );
36702
+ const drawingRelId = "rId1";
36703
+ const drawingXml = buildFabricatedDrawingXml(drawingShapes, data.nodes, guidByNodeId);
36332
36704
  const payloads = {
36333
- data: buildFabricatedDiagramDataXml(data, {
36334
- layoutUniqueId: fabricatedLayoutUniqueId(family),
36335
- layoutCategory: fabricatedLayoutCategory(family),
36336
- quickStyleUniqueId: FABRICATED_QUICKSTYLE_UNIQUE_ID,
36337
- colorsUniqueId: fabricatedColorsUniqueId(data.colorScheme),
36338
- colorsCategory: fabricatedColorsCategory(data.colorScheme)
36339
- }),
36705
+ data: buildFabricatedDiagramDataXml(
36706
+ data,
36707
+ {
36708
+ layoutUniqueId: fabricatedLayoutUniqueId(family),
36709
+ layoutCategory: fabricatedLayoutCategory(family),
36710
+ quickStyleUniqueId: FABRICATED_QUICKSTYLE_UNIQUE_ID,
36711
+ colorsUniqueId: fabricatedColorsUniqueId(data.colorScheme),
36712
+ colorsCategory: fabricatedColorsCategory(data.colorScheme)
36713
+ },
36714
+ { guidByNodeId, drawingRelId: drawingXml ? drawingRelId : void 0 }
36715
+ ),
36340
36716
  layout: buildFabricatedLayoutDefXml(family),
36341
36717
  quickStyle: buildFabricatedQuickStyleXml(),
36342
36718
  colors: buildFabricatedColorsXml(data.colorScheme)
@@ -36360,6 +36736,19 @@ var PptxHandlerRuntime32 = class _PptxHandlerRuntime extends PptxHandlerRuntime3
36360
36736
  });
36361
36737
  relIds[kind.relAttr] = relId;
36362
36738
  }
36739
+ if (drawingXml) {
36740
+ const drawingFile = `drawing${index}.xml`;
36741
+ const drawingPath = `ppt/diagrams/${drawingFile}`;
36742
+ this.zip.file(drawingPath, drawingXml);
36743
+ (this.pendingDiagramContentTypes ??= []).push({
36744
+ partName: `/${drawingPath}`,
36745
+ contentType: DIAGRAM_DRAWING_CONTENT_TYPE
36746
+ });
36747
+ this.zip.file(
36748
+ `ppt/diagrams/_rels/data${index}.xml.rels`,
36749
+ buildDiagramDataRelsXml(drawingRelId, drawingFile)
36750
+ );
36751
+ }
36363
36752
  const EMU = _PptxHandlerRuntime.EMU_PER_PX;
36364
36753
  return {
36365
36754
  "p:nvGraphicFramePr": {
@@ -36418,6 +36807,22 @@ var PptxHandlerRuntime32 = class _PptxHandlerRuntime extends PptxHandlerRuntime3
36418
36807
 
36419
36808
  // src/core/core/runtime/PptxHandlerRuntimeSaveElementWriter.ts
36420
36809
  var PptxHandlerRuntime33 = class _PptxHandlerRuntime extends PptxHandlerRuntime32 {
36810
+ /**
36811
+ * Whether a shape XML represents a `<p:pic>` (picture-shaped) node.
36812
+ *
36813
+ * Real PowerPoint (verified via COM-authored fixtures) represents video
36814
+ * *and* audio media as `<p:pic>` (poster-frame blip + `p:nvPr/a:videoFile`
36815
+ * or `a:audioFile` + a `p14:media` extension) rather than the older
36816
+ * `<p:graphicFrame>` form. A `media`-typed element's `rawXml` is
36817
+ * therefore frequently `p:pic`-shaped, not a graphic frame; without this
36818
+ * check it falls into the generic `shapes` bucket, which the slide
36819
+ * writer serializes under `<p:sp>` -- corrupting the picture markup
36820
+ * (`p:nvPicPr`/`p:blipFill`) into an invalid shape and permanently
36821
+ * losing the media relationship on save.
36822
+ */
36823
+ isPictureShape(shape) {
36824
+ return Boolean(shape["p:nvPicPr"]);
36825
+ }
36421
36826
  /** Whether a shape XML represents a graphic frame. */
36422
36827
  isGraphicFrameShape(shape) {
36423
36828
  return Boolean(shape["p:nvGraphicFramePr"] || shape["a:graphic"] && shape["p:xfrm"]);
@@ -36533,6 +36938,34 @@ var PptxHandlerRuntime33 = class _PptxHandlerRuntime extends PptxHandlerRuntime3
36533
36938
  isTemplateElementId(elementId) {
36534
36939
  return elementId.startsWith("layout-") || elementId.startsWith("master-");
36535
36940
  }
36941
+ /** Non-visual property containers that hold a `p:cNvPr`. */
36942
+ static NV_CONTAINERS = [
36943
+ "p:nvSpPr",
36944
+ "p:nvPicPr",
36945
+ "p:nvCxnSpPr",
36946
+ "p:nvGraphicFramePr",
36947
+ "p:nvGrpSpPr"
36948
+ ];
36949
+ /**
36950
+ * Write an element's native shape id (`element.shapeId`) into the serialized
36951
+ * shape's `p:cNvPr/@id`. Animation targets (`p:spTgt/@spid`) reference this
36952
+ * id, so the two must agree for PowerPoint to bind an animation to its shape.
36953
+ * A no-op when the element carries no `shapeId` (nothing to reconcile) or the
36954
+ * shape XML has no cNvPr container.
36955
+ */
36956
+ applyShapeIdToCnvPr(shape, el) {
36957
+ if (el.shapeId === void 0) {
36958
+ return;
36959
+ }
36960
+ for (const nvKey of _PptxHandlerRuntime.NV_CONTAINERS) {
36961
+ const nv = shape[nvKey];
36962
+ const cNvPr = nv?.["p:cNvPr"];
36963
+ if (cNvPr) {
36964
+ cNvPr["@_id"] = el.shapeId;
36965
+ return;
36966
+ }
36967
+ }
36968
+ }
36536
36969
  /**
36537
36970
  * Process a single slide element during save. Handles embedding,
36538
36971
  * transforms, geometry, styles, text, and sorts into collectors.
@@ -36642,12 +37075,15 @@ var PptxHandlerRuntime33 = class _PptxHandlerRuntime extends PptxHandlerRuntime3
36642
37075
  }
36643
37076
  return;
36644
37077
  }
37078
+ this.applyShapeIdToCnvPr(shape, el);
36645
37079
  if (el.type === "picture" || el.type === "image") {
36646
37080
  collectors.pics.push(shape);
36647
37081
  } else if (el.type === "connector") {
36648
37082
  collectors.connectors.push(shape);
36649
37083
  } else if (el.type === "model3d") {
36650
37084
  collectors.model3ds.push(shape);
37085
+ } else if (el.type === "media" && this.isPictureShape(shape)) {
37086
+ collectors.pics.push(shape);
36651
37087
  } else if (this.isGraphicFrameShape(shape)) {
36652
37088
  collectors.graphicFrames.push(shape);
36653
37089
  } else {
@@ -36686,12 +37122,17 @@ var PptxHandlerRuntime34 = class extends PptxHandlerRuntime33 {
36686
37122
  delete slideNode["p:transition"];
36687
37123
  }
36688
37124
  }
36689
- if (slide.animations !== void 0) {
36690
- this.applyEditorAnimations(slideNode, slide.animations);
37125
+ const shapeIdAnimations = slide.animations !== void 0 ? remapEditorAnimationsToShapeIds(
37126
+ slide.elements,
37127
+ slide.animations,
37128
+ this.maxCnvPrId(this.ensureSlideTree(xmlObj))
37129
+ ) : void 0;
37130
+ if (shapeIdAnimations !== void 0) {
37131
+ this.applyEditorAnimations(slideNode, shapeIdAnimations);
36691
37132
  }
36692
- if (slide.animations && slide.animations.length > 0) {
37133
+ if (shapeIdAnimations && shapeIdAnimations.length > 0) {
36693
37134
  const generatedTiming = this.animationWriteService.buildTimingXml(
36694
- slide.animations,
37135
+ shapeIdAnimations,
36695
37136
  slide.rawTiming
36696
37137
  );
36697
37138
  if (generatedTiming) {
@@ -36844,6 +37285,40 @@ var PptxHandlerRuntime34 = class extends PptxHandlerRuntime33 {
36844
37285
  }
36845
37286
  this.zip.file(slide.id, this.builder.build(xmlObj));
36846
37287
  }
37288
+ /**
37289
+ * Largest `p:cNvPr/@id` already present anywhere in a shape tree, including
37290
+ * the implicit `<p:spTree>` group's own reserved id. Used to seed minting of
37291
+ * fresh animation-target shape ids so they never collide with a reserved id.
37292
+ */
37293
+ maxCnvPrId(spTree) {
37294
+ let max = 0;
37295
+ const nvContainers = [
37296
+ "p:nvSpPr",
37297
+ "p:nvPicPr",
37298
+ "p:nvCxnSpPr",
37299
+ "p:nvGraphicFramePr",
37300
+ "p:nvGrpSpPr"
37301
+ ];
37302
+ const visit = (node) => {
37303
+ for (const nvKey of nvContainers) {
37304
+ const nv = node[nvKey];
37305
+ const cNvPr = nv?.["p:cNvPr"];
37306
+ if (cNvPr?.["@_id"] !== void 0) {
37307
+ const n = Number.parseInt(String(cNvPr["@_id"]), 10);
37308
+ if (Number.isFinite(n) && n > max) {
37309
+ max = n;
37310
+ }
37311
+ }
37312
+ }
37313
+ for (const listKey of ["p:sp", "p:pic", "p:cxnSp", "p:graphicFrame", "p:grpSp"]) {
37314
+ for (const child of this.ensureArray(node[listKey])) {
37315
+ visit(child);
37316
+ }
37317
+ }
37318
+ };
37319
+ visit(spTree);
37320
+ return max;
37321
+ }
36847
37322
  /**
36848
37323
  * Re-wrap selected children with their original `<mc:AlternateContent>`
36849
37324
  * envelope (CC-4).
@@ -46562,7 +47037,22 @@ var PptxHandlerRuntime79 = class _PptxHandlerRuntime extends PptxHandlerRuntime7
46562
47037
  await this.enrichOleElementsWithEmbeddedData(el.children, slidePath, depth + 1);
46563
47038
  continue;
46564
47039
  }
46565
- if (el.type !== "ole" || el.isLinked || !el.oleTarget) {
47040
+ if (el.type !== "ole") {
47041
+ continue;
47042
+ }
47043
+ if (el.previewImage && !el.previewImageData) {
47044
+ try {
47045
+ const previewPath = this.resolveImagePath(slidePath, el.previewImage);
47046
+ if (previewPath) {
47047
+ const previewData = await this.getImageData(previewPath);
47048
+ if (previewData) {
47049
+ el.previewImageData = previewData;
47050
+ }
47051
+ }
47052
+ } catch {
47053
+ }
47054
+ }
47055
+ if (el.isLinked || !el.oleTarget) {
46566
47056
  continue;
46567
47057
  }
46568
47058
  try {
@@ -65242,9 +65732,11 @@ exports.pt = pt;
65242
65732
  exports.reResolveSlideColors = reResolveSlideColors;
65243
65733
  exports.readFileAsDataUrl = readFileAsDataUrl;
65244
65734
  exports.rebuildTableStructureInRawXml = rebuildTableStructureInRawXml;
65735
+ exports.reconcileAnimationTargets = reconcileAnimationTargets;
65245
65736
  exports.reflowSmartArtLayout = reflowSmartArtLayout;
65246
65737
  exports.relativeLuminance = relativeLuminance;
65247
65738
  exports.relayoutSmartArt = relayoutSmartArt;
65739
+ exports.remapEditorAnimationsToShapeIds = remapEditorAnimationsToShapeIds;
65248
65740
  exports.removeChartCategory = removeChartCategory;
65249
65741
  exports.removeChartSeries = removeChartSeries;
65250
65742
  exports.removeSection = removeSection;