pptx-viewer-core 1.1.29 → 1.1.31

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/cli/index.js CHANGED
Binary file
Binary file
package/dist/index.d.mts CHANGED
@@ -3406,9 +3406,14 @@ declare function buildGuideListExtension(guides: PptxDrawingGuide[]): XmlObject;
3406
3406
  /**
3407
3407
  * Supported layout types for the visual layout switcher.
3408
3408
  *
3409
- * These are the layout categories that have dedicated renderers
3410
- * in SmartArtRenderer and can be switched between while preserving
3411
- * node data and connections.
3409
+ * These are the layout categories that have a working reflow implementation in
3410
+ * `reflowSmartArtLayout` (see `smartart-editing-reflow*`), so switching to any
3411
+ * of them re-lays-out the diagram while preserving node data and connections.
3412
+ * Every entry below has a matching `case` in the reflow dispatcher:
3413
+ * list, process, hierarchy, cycle, matrix, pyramid, funnel, target, gear,
3414
+ * venn, timeline, relationship, chevron, bending.
3415
+ *
3416
+ * `unknown` is intentionally excluded (it has no meaningful target layout).
3412
3417
  */
3413
3418
  declare const SWITCHABLE_LAYOUT_TYPES: readonly SmartArtLayoutType[];
3414
3419
  /**
@@ -3538,7 +3543,9 @@ declare function resolveModel3DMimeType(modelPath: string): string | undefined;
3538
3543
  type OoxmlConformanceClass = 'strict' | 'transitional';
3539
3544
  /**
3540
3545
  * Convert a Strict Open XML namespace URI to its Transitional equivalent.
3541
- * If the URI is already Transitional (or unknown), it is returned unchanged.
3546
+ * The explicit map takes precedence; any other Strict URI in a remapped family
3547
+ * is derived structurally. If the URI is already Transitional (or unknown), it
3548
+ * is returned unchanged.
3542
3549
  */
3543
3550
  declare function normalizeNamespaceUri(uri: string): string;
3544
3551
  /**
@@ -3565,11 +3572,14 @@ declare function detectStrictConformance(xmlObj: Record<string, unknown>): boole
3565
3572
  declare function normalizeStrictXml(node: Record<string, unknown>): Record<string, unknown>;
3566
3573
  /**
3567
3574
  * Convert a Transitional Open XML namespace URI to its Strict equivalent.
3568
- * If the URI is already Strict (or unknown), it is returned unchanged.
3575
+ * The explicit map takes precedence; any other versioned Transitional URI in a
3576
+ * remapped family is derived structurally. If the URI is already Strict (or
3577
+ * unknown), it is returned unchanged.
3569
3578
  */
3570
3579
  declare function toStrictNamespaceUri(uri: string): string;
3571
3580
  /**
3572
- * Check whether a URI belongs to the Transitional Open XML namespace family.
3581
+ * Check whether a URI belongs to the Transitional Open XML namespace family,
3582
+ * either by explicit mapping or by the structural family rule.
3573
3583
  */
3574
3584
  declare function isTransitionalNamespaceUri(uri: string): boolean;
3575
3585
  /**
package/dist/index.d.ts CHANGED
@@ -3406,9 +3406,14 @@ declare function buildGuideListExtension(guides: PptxDrawingGuide[]): XmlObject;
3406
3406
  /**
3407
3407
  * Supported layout types for the visual layout switcher.
3408
3408
  *
3409
- * These are the layout categories that have dedicated renderers
3410
- * in SmartArtRenderer and can be switched between while preserving
3411
- * node data and connections.
3409
+ * These are the layout categories that have a working reflow implementation in
3410
+ * `reflowSmartArtLayout` (see `smartart-editing-reflow*`), so switching to any
3411
+ * of them re-lays-out the diagram while preserving node data and connections.
3412
+ * Every entry below has a matching `case` in the reflow dispatcher:
3413
+ * list, process, hierarchy, cycle, matrix, pyramid, funnel, target, gear,
3414
+ * venn, timeline, relationship, chevron, bending.
3415
+ *
3416
+ * `unknown` is intentionally excluded (it has no meaningful target layout).
3412
3417
  */
3413
3418
  declare const SWITCHABLE_LAYOUT_TYPES: readonly SmartArtLayoutType[];
3414
3419
  /**
@@ -3538,7 +3543,9 @@ declare function resolveModel3DMimeType(modelPath: string): string | undefined;
3538
3543
  type OoxmlConformanceClass = 'strict' | 'transitional';
3539
3544
  /**
3540
3545
  * Convert a Strict Open XML namespace URI to its Transitional equivalent.
3541
- * If the URI is already Transitional (or unknown), it is returned unchanged.
3546
+ * The explicit map takes precedence; any other Strict URI in a remapped family
3547
+ * is derived structurally. If the URI is already Transitional (or unknown), it
3548
+ * is returned unchanged.
3542
3549
  */
3543
3550
  declare function normalizeNamespaceUri(uri: string): string;
3544
3551
  /**
@@ -3565,11 +3572,14 @@ declare function detectStrictConformance(xmlObj: Record<string, unknown>): boole
3565
3572
  declare function normalizeStrictXml(node: Record<string, unknown>): Record<string, unknown>;
3566
3573
  /**
3567
3574
  * Convert a Transitional Open XML namespace URI to its Strict equivalent.
3568
- * If the URI is already Strict (or unknown), it is returned unchanged.
3575
+ * The explicit map takes precedence; any other versioned Transitional URI in a
3576
+ * remapped family is derived structurally. If the URI is already Strict (or
3577
+ * unknown), it is returned unchanged.
3569
3578
  */
3570
3579
  declare function toStrictNamespaceUri(uri: string): string;
3571
3580
  /**
3572
- * Check whether a URI belongs to the Transitional Open XML namespace family.
3581
+ * Check whether a URI belongs to the Transitional Open XML namespace family,
3582
+ * either by explicit mapping or by the structural family rule.
3573
3583
  */
3574
3584
  declare function isTransitionalNamespaceUri(uri: string): boolean;
3575
3585
  /**
package/dist/index.js CHANGED
@@ -13772,6 +13772,9 @@ async function parseEmbeddedXlsx(xlsxData) {
13772
13772
  }
13773
13773
  }
13774
13774
 
13775
+ // src/core/core/builders/smart-art-text-helpers.ts
13776
+ var MAX_SMARTART_NODES = 2e3;
13777
+
13775
13778
  // src/core/utils/vml-color-parser.ts
13776
13779
  var NAMED_COLORS = {
13777
13780
  black: "#000000",
@@ -19941,12 +19944,20 @@ function chartDataRemoveCategory(chartData, categoryIndex) {
19941
19944
 
19942
19945
  // src/core/utils/smartart-layout-switch.ts
19943
19946
  var SWITCHABLE_LAYOUT_TYPES = [
19947
+ "list",
19944
19948
  "process",
19945
19949
  "hierarchy",
19946
19950
  "cycle",
19947
19951
  "matrix",
19948
19952
  "pyramid",
19949
- "list"
19953
+ "funnel",
19954
+ "target",
19955
+ "gear",
19956
+ "venn",
19957
+ "timeline",
19958
+ "relationship",
19959
+ "chevron",
19960
+ "bending"
19950
19961
  ];
19951
19962
  function switchSmartArtLayout(currentData, newLayoutType) {
19952
19963
  if (currentData.resolvedLayoutType === newLayoutType) {
@@ -20212,8 +20223,41 @@ var STRICT_TO_TRANSITIONAL_NS = new Map(NAMESPACE_PAIRS);
20212
20223
  var TRANSITIONAL_TO_STRICT_NS = new Map(
20213
20224
  NAMESPACE_PAIRS.map(([strict, transitional]) => [transitional, strict])
20214
20225
  );
20226
+ var STRICT_BASE = "http://purl.oclc.org/ooxml/";
20227
+ var TRANSITIONAL_BASE = "http://schemas.openxmlformats.org/";
20228
+ var ALGORITHMIC_FAMILIES = /* @__PURE__ */ new Set([
20229
+ "presentationml",
20230
+ "drawingml",
20231
+ "spreadsheetml",
20232
+ "wordprocessingml",
20233
+ "officeDocument"
20234
+ ]);
20235
+ function deriveTransitionalUri(uri) {
20236
+ if (!uri.startsWith(STRICT_BASE)) {
20237
+ return void 0;
20238
+ }
20239
+ const segments = uri.slice(STRICT_BASE.length).split("/");
20240
+ if (segments.length < 2 || !ALGORITHMIC_FAMILIES.has(segments[0])) {
20241
+ return void 0;
20242
+ }
20243
+ if (segments[1] !== "2006") {
20244
+ segments.splice(1, 0, "2006");
20245
+ }
20246
+ return TRANSITIONAL_BASE + segments.join("/");
20247
+ }
20248
+ function deriveStrictUri(uri) {
20249
+ if (!uri.startsWith(TRANSITIONAL_BASE)) {
20250
+ return void 0;
20251
+ }
20252
+ const segments = uri.slice(TRANSITIONAL_BASE.length).split("/");
20253
+ if (segments.length < 3 || !ALGORITHMIC_FAMILIES.has(segments[0]) || segments[1] !== "2006") {
20254
+ return void 0;
20255
+ }
20256
+ segments.splice(1, 1);
20257
+ return STRICT_BASE + segments.join("/");
20258
+ }
20215
20259
  function normalizeNamespaceUri(uri) {
20216
- return STRICT_TO_TRANSITIONAL_NS.get(uri) ?? uri;
20260
+ return STRICT_TO_TRANSITIONAL_NS.get(uri) ?? deriveTransitionalUri(uri) ?? uri;
20217
20261
  }
20218
20262
  function isStrictNamespaceUri(uri) {
20219
20263
  return uri.startsWith("http://purl.oclc.org/ooxml/");
@@ -20245,25 +20289,16 @@ function normalizeStrictXml(node) {
20245
20289
  const value = node[key];
20246
20290
  if (key.startsWith("@_xmlns")) {
20247
20291
  if (typeof value === "string") {
20248
- const mapped = STRICT_TO_TRANSITIONAL_NS.get(value);
20249
- if (mapped) {
20250
- node[key] = mapped;
20251
- }
20292
+ node[key] = normalizeNamespaceUri(value);
20252
20293
  }
20253
20294
  continue;
20254
20295
  }
20255
20296
  if (key === "@_Type" && typeof value === "string") {
20256
- const mapped = STRICT_TO_TRANSITIONAL_NS.get(value);
20257
- if (mapped) {
20258
- node[key] = mapped;
20259
- }
20297
+ node[key] = normalizeNamespaceUri(value);
20260
20298
  continue;
20261
20299
  }
20262
20300
  if (key === "@_uri" && typeof value === "string") {
20263
- const mapped = STRICT_TO_TRANSITIONAL_NS.get(value);
20264
- if (mapped) {
20265
- node[key] = mapped;
20266
- }
20301
+ node[key] = normalizeNamespaceUri(value);
20267
20302
  continue;
20268
20303
  }
20269
20304
  if (key.startsWith("@_")) {
@@ -20282,10 +20317,10 @@ function normalizeStrictXml(node) {
20282
20317
  return node;
20283
20318
  }
20284
20319
  function toStrictNamespaceUri(uri) {
20285
- return TRANSITIONAL_TO_STRICT_NS.get(uri) ?? uri;
20320
+ return TRANSITIONAL_TO_STRICT_NS.get(uri) ?? deriveStrictUri(uri) ?? uri;
20286
20321
  }
20287
20322
  function isTransitionalNamespaceUri(uri) {
20288
- return TRANSITIONAL_TO_STRICT_NS.has(uri);
20323
+ return TRANSITIONAL_TO_STRICT_NS.has(uri) || deriveStrictUri(uri) !== void 0;
20289
20324
  }
20290
20325
  function convertXmlToStrict(node, setConformance = false) {
20291
20326
  if (typeof node !== "object" || node === null || Array.isArray(node)) {
@@ -20301,25 +20336,16 @@ function convertXmlToStrict(node, setConformance = false) {
20301
20336
  const value = node[key];
20302
20337
  if (key.startsWith("@_xmlns")) {
20303
20338
  if (typeof value === "string") {
20304
- const mapped = TRANSITIONAL_TO_STRICT_NS.get(value);
20305
- if (mapped) {
20306
- node[key] = mapped;
20307
- }
20339
+ node[key] = toStrictNamespaceUri(value);
20308
20340
  }
20309
20341
  continue;
20310
20342
  }
20311
20343
  if (key === "@_Type" && typeof value === "string") {
20312
- const mapped = TRANSITIONAL_TO_STRICT_NS.get(value);
20313
- if (mapped) {
20314
- node[key] = mapped;
20315
- }
20344
+ node[key] = toStrictNamespaceUri(value);
20316
20345
  continue;
20317
20346
  }
20318
20347
  if (key === "@_uri" && typeof value === "string") {
20319
- const mapped = TRANSITIONAL_TO_STRICT_NS.get(value);
20320
- if (mapped) {
20321
- node[key] = mapped;
20322
- }
20348
+ node[key] = toStrictNamespaceUri(value);
20323
20349
  continue;
20324
20350
  }
20325
20351
  if (key.startsWith("@_")) {
@@ -32836,27 +32862,151 @@ var PptxHandlerRuntime23 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
32836
32862
  }
32837
32863
  };
32838
32864
 
32865
+ // src/core/core/runtime/smartart-save-chrome.ts
32866
+ function asObject(value) {
32867
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
32868
+ }
32869
+ function applySmartArtChrome(dataModel, chrome, getLocalName) {
32870
+ if (!chrome || !chrome.backgroundColor && !chrome.outlineColor && (chrome.outlineWidth === null || chrome.outlineWidth === void 0)) {
32871
+ return;
32872
+ }
32873
+ const findKey10 = (obj, name) => Object.keys(obj).find((k) => getLocalName(k) === name);
32874
+ if (chrome.backgroundColor) {
32875
+ const hex7 = chrome.backgroundColor.replace("#", "");
32876
+ const bgKey = findKey10(dataModel, "bg") ?? "dgm:bg";
32877
+ const bg = asObject(dataModel[bgKey]);
32878
+ const fillKey = findKey10(bg, "solidFill") ?? "a:solidFill";
32879
+ bg[fillKey] = { "a:srgbClr": { "@_val": hex7 } };
32880
+ dataModel[bgKey] = bg;
32881
+ }
32882
+ const hasOutlineWidth = chrome.outlineWidth !== null && chrome.outlineWidth !== void 0;
32883
+ if (chrome.outlineColor || hasOutlineWidth) {
32884
+ const wholeKey = findKey10(dataModel, "whole") ?? "dgm:whole";
32885
+ const whole = asObject(dataModel[wholeKey]);
32886
+ const lnKey = findKey10(whole, "ln") ?? "a:ln";
32887
+ const ln = asObject(whole[lnKey]);
32888
+ if (hasOutlineWidth) {
32889
+ ln["@_w"] = String(Math.round(chrome.outlineWidth * 12700));
32890
+ }
32891
+ if (chrome.outlineColor) {
32892
+ const hex7 = chrome.outlineColor.replace("#", "");
32893
+ const fillKey = findKey10(ln, "solidFill") ?? "a:solidFill";
32894
+ ln[fillKey] = { "a:srgbClr": { "@_val": hex7 } };
32895
+ }
32896
+ whole[lnKey] = ln;
32897
+ dataModel[wholeKey] = whole;
32898
+ }
32899
+ }
32900
+
32839
32901
  // src/core/core/runtime/smartart-xml-builders.ts
32840
- function buildSmartArtPointXml(nodes) {
32841
- return nodes.map((node) => {
32842
- const ptNode = {
32843
- "@_modelId": node.id
32844
- };
32845
- if (node.nodeType) {
32846
- ptNode["@_type"] = node.nodeType;
32902
+ var NON_CONTENT_POINT_TYPES = /* @__PURE__ */ new Set([
32903
+ "doc",
32904
+ "pres",
32905
+ "parTrans",
32906
+ "sibTrans"
32907
+ ]);
32908
+ function pointType(pt2) {
32909
+ return String(pt2["@_type"] || "").trim();
32910
+ }
32911
+ function pointModelId(pt2) {
32912
+ return String(pt2["@_modelId"] || "").trim();
32913
+ }
32914
+ function isContentPoint(pt2) {
32915
+ return !NON_CONTENT_POINT_TYPES.has(pointType(pt2));
32916
+ }
32917
+ function buildPointText(text) {
32918
+ return {
32919
+ "a:bodyPr": {},
32920
+ "a:lstStyle": {},
32921
+ "a:p": {
32922
+ "a:r": {
32923
+ "a:rPr": { "@_lang": "en-US", "@_dirty": "0" },
32924
+ "a:t": text
32925
+ }
32847
32926
  }
32848
- ptNode["dgm:t"] = {
32849
- "a:bodyPr": {},
32850
- "a:lstStyle": {},
32851
- "a:p": {
32852
- "a:r": {
32853
- "a:rPr": { "@_lang": "en-US", "@_dirty": "0" },
32854
- "a:t": node.text
32855
- }
32927
+ };
32928
+ }
32929
+ function applyTextToExistingPoint(pt2, text) {
32930
+ const tKey = Object.keys(pt2).find((k) => stripPrefix(k) === "t");
32931
+ if (!tKey) {
32932
+ pt2["dgm:t"] = buildPointText(text);
32933
+ return;
32934
+ }
32935
+ const body = pt2[tKey];
32936
+ if (!body || typeof body !== "object" || Array.isArray(body)) {
32937
+ pt2[tKey] = buildPointText(text);
32938
+ return;
32939
+ }
32940
+ const bodyObj = body;
32941
+ const pKey = Object.keys(bodyObj).find((k) => stripPrefix(k) === "p");
32942
+ const paragraph = pKey ? bodyObj[pKey] : void 0;
32943
+ if (!pKey || Array.isArray(paragraph) || !paragraph || typeof paragraph !== "object") {
32944
+ bodyObj[pKey ?? "a:p"] = {
32945
+ "a:r": {
32946
+ "a:rPr": { "@_lang": "en-US", "@_dirty": "0" },
32947
+ "a:t": text
32856
32948
  }
32857
32949
  };
32858
- return ptNode;
32859
- });
32950
+ return;
32951
+ }
32952
+ const paragraphObj = paragraph;
32953
+ const rKey = Object.keys(paragraphObj).find((k) => stripPrefix(k) === "r");
32954
+ const run = rKey ? paragraphObj[rKey] : void 0;
32955
+ if (!rKey || Array.isArray(run) || !run || typeof run !== "object") {
32956
+ paragraphObj[rKey ?? "a:r"] = {
32957
+ "a:rPr": { "@_lang": "en-US", "@_dirty": "0" },
32958
+ "a:t": text
32959
+ };
32960
+ return;
32961
+ }
32962
+ const runObj = run;
32963
+ const textKey = Object.keys(runObj).find((k) => stripPrefix(k) === "t");
32964
+ runObj[textKey ?? "a:t"] = text;
32965
+ }
32966
+ function stripPrefix(key) {
32967
+ const idx = key.indexOf(":");
32968
+ return idx >= 0 ? key.slice(idx + 1) : key;
32969
+ }
32970
+ function mergeSmartArtPointXml(existingPts, nodes) {
32971
+ const desiredById = /* @__PURE__ */ new Map();
32972
+ for (const node of nodes) {
32973
+ const id = String(node.id || "").trim();
32974
+ if (id.length > 0) {
32975
+ desiredById.set(id, node);
32976
+ }
32977
+ }
32978
+ const seenContentIds = /* @__PURE__ */ new Set();
32979
+ const merged = [];
32980
+ for (const pt2 of existingPts) {
32981
+ if (!pt2 || typeof pt2 !== "object") {
32982
+ continue;
32983
+ }
32984
+ if (!isContentPoint(pt2)) {
32985
+ merged.push(pt2);
32986
+ continue;
32987
+ }
32988
+ const modelId = pointModelId(pt2);
32989
+ const desired = modelId.length > 0 ? desiredById.get(modelId) : void 0;
32990
+ if (!desired) {
32991
+ continue;
32992
+ }
32993
+ applyTextToExistingPoint(pt2, desired.text);
32994
+ seenContentIds.add(modelId);
32995
+ merged.push(pt2);
32996
+ }
32997
+ for (const node of nodes) {
32998
+ const id = String(node.id || "").trim();
32999
+ if (id.length === 0 || seenContentIds.has(id)) {
33000
+ continue;
33001
+ }
33002
+ const ptNode = { "@_modelId": id };
33003
+ if (node.nodeType && !NON_CONTENT_POINT_TYPES.has(node.nodeType)) {
33004
+ ptNode["@_type"] = node.nodeType;
33005
+ }
33006
+ ptNode["dgm:t"] = buildPointText(node.text);
33007
+ merged.push(ptNode);
33008
+ }
33009
+ return merged;
32860
33010
  }
32861
33011
  function buildSmartArtConnectionXml(connections) {
32862
33012
  return connections.map((conn) => {
@@ -32901,12 +33051,12 @@ var PptxHandlerRuntime24 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
32901
33051
  if (!this.pendingSmartArtUpdates || this.pendingSmartArtUpdates.length === 0) {
32902
33052
  return;
32903
33053
  }
32904
- for (const { element } of this.pendingSmartArtUpdates) {
33054
+ for (const { element, slidePath: capturedSlidePath } of this.pendingSmartArtUpdates) {
32905
33055
  const smartArtData = element.smartArtData;
32906
33056
  if (!smartArtData?.dataRelId) {
32907
33057
  continue;
32908
33058
  }
32909
- const slidePath = element.rawXml ? this.findSlidePathForElement(element) : void 0;
33059
+ const slidePath = capturedSlidePath && capturedSlidePath.length > 0 ? capturedSlidePath : this.findSlidePathForElement(element);
32910
33060
  if (!slidePath) {
32911
33061
  continue;
32912
33062
  }
@@ -32935,7 +33085,8 @@ var PptxHandlerRuntime24 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
32935
33085
  (k) => this.compatibilityService.getXmlLocalName(k) === "pt"
32936
33086
  );
32937
33087
  if (ptKey) {
32938
- ptList[ptKey] = buildSmartArtPointXml(smartArtData.nodes);
33088
+ const existingPts = this.ensureArray(ptList[ptKey]);
33089
+ ptList[ptKey] = mergeSmartArtPointXml(existingPts, smartArtData.nodes);
32939
33090
  }
32940
33091
  }
32941
33092
  if (smartArtData.connections && smartArtData.connections.length > 0) {
@@ -32952,6 +33103,11 @@ var PptxHandlerRuntime24 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
32952
33103
  }
32953
33104
  }
32954
33105
  }
33106
+ applySmartArtChrome(
33107
+ dataModel,
33108
+ smartArtData.chrome,
33109
+ (k) => this.compatibilityService.getXmlLocalName(k)
33110
+ );
32955
33111
  this.zip.file(dataPartPath, this.builder.build(parsed));
32956
33112
  } catch (e) {
32957
33113
  console.warn(`Failed to save SmartArt data at ${dataPartPath}:`, e);
@@ -33081,7 +33237,7 @@ var PptxHandlerRuntime24 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
33081
33237
  if (this.customXmlParts.length === 0) {
33082
33238
  return;
33083
33239
  }
33084
- const SAFE_ID = /^[A-Za-z0-9_-]+$/;
33240
+ const SAFE_ID = /^[A-Za-z0-9_-]+$/u;
33085
33241
  let fallbackIndex = 1;
33086
33242
  for (const part of this.customXmlParts) {
33087
33243
  const rawId = String(part.id);
@@ -33192,7 +33348,7 @@ var PptxHandlerRuntime24 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
33192
33348
  let maxId = 0;
33193
33349
  for (const rel of relationships) {
33194
33350
  const id = String(rel?.["@_Id"] || "");
33195
- const num = parseInt(id.replace(/^rId/, ""), 10);
33351
+ const num = parseInt(id.replace(/^rId/u, ""), 10);
33196
33352
  if (Number.isFinite(num) && num > maxId) {
33197
33353
  maxId = num;
33198
33354
  }
@@ -33315,7 +33471,7 @@ var PptxHandlerRuntime24 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
33315
33471
  let maxId = 0;
33316
33472
  for (const rel of relationships) {
33317
33473
  const id = String(rel?.["@_Id"] || "");
33318
- const num = parseInt(id.replace(/^rId/, ""), 10);
33474
+ const num = parseInt(id.replace(/^rId/u, ""), 10);
33319
33475
  if (Number.isFinite(num) && num > maxId) {
33320
33476
  maxId = num;
33321
33477
  }
@@ -42986,13 +43142,13 @@ var PptxHandlerRuntime70 = class _PptxHandlerRuntime extends PptxHandlerRuntime6
42986
43142
  parentId: parentByNodeId.get(pointId),
42987
43143
  nodeType
42988
43144
  };
42989
- }).filter((entry) => Boolean(entry)).slice(0, 50);
43145
+ }).filter((entry) => Boolean(entry)).slice(0, MAX_SMARTART_NODES);
42990
43146
  if (nodes.length === 0) {
42991
43147
  return void 0;
42992
43148
  }
42993
43149
  const layoutRelationshipId = String(relationshipIds["@_r:lo"] || "").trim();
42994
43150
  const layoutPart = layoutRelationshipId.length > 0 ? await this.readXmlPartByRelationshipId(slidePath, layoutRelationshipId) : void 0;
42995
- const layoutType = layoutPart?.partPath?.split("/").pop()?.replace(/\.[^.]+$/, "") || void 0;
43151
+ const layoutType = layoutPart?.partPath?.split("/").pop()?.replace(/\.[^.]+$/u, "") || void 0;
42996
43152
  const chrome = this.parseSmartArtChrome(dataModel);
42997
43153
  const colorsRelationshipId = String(relationshipIds["@_r:cs"] || "").trim();
42998
43154
  const colorTransform = await this.parseSmartArtColorTransform(slidePath, colorsRelationshipId);
@@ -43040,7 +43196,7 @@ var PptxHandlerRuntime70 = class _PptxHandlerRuntime extends PptxHandlerRuntime6
43040
43196
  return void 0;
43041
43197
  }
43042
43198
  const dataPath = this.resolveImagePath(slidePath, dataTarget);
43043
- const dataDir = dataPath.replace(/\/[^/]+$/, "");
43199
+ const dataDir = dataPath.replace(/\/[^/]+$/u, "");
43044
43200
  const dataFile = dataPath.split("/").pop() ?? "";
43045
43201
  const dataRelsPath = `${dataDir}/_rels/${dataFile}.rels`;
43046
43202
  const relsXml = await this.zip.file(dataRelsPath)?.async("string");
package/dist/index.mjs CHANGED
@@ -13767,6 +13767,9 @@ async function parseEmbeddedXlsx(xlsxData) {
13767
13767
  }
13768
13768
  }
13769
13769
 
13770
+ // src/core/core/builders/smart-art-text-helpers.ts
13771
+ var MAX_SMARTART_NODES = 2e3;
13772
+
13770
13773
  // src/core/utils/vml-color-parser.ts
13771
13774
  var NAMED_COLORS = {
13772
13775
  black: "#000000",
@@ -19936,12 +19939,20 @@ function chartDataRemoveCategory(chartData, categoryIndex) {
19936
19939
 
19937
19940
  // src/core/utils/smartart-layout-switch.ts
19938
19941
  var SWITCHABLE_LAYOUT_TYPES = [
19942
+ "list",
19939
19943
  "process",
19940
19944
  "hierarchy",
19941
19945
  "cycle",
19942
19946
  "matrix",
19943
19947
  "pyramid",
19944
- "list"
19948
+ "funnel",
19949
+ "target",
19950
+ "gear",
19951
+ "venn",
19952
+ "timeline",
19953
+ "relationship",
19954
+ "chevron",
19955
+ "bending"
19945
19956
  ];
19946
19957
  function switchSmartArtLayout(currentData, newLayoutType) {
19947
19958
  if (currentData.resolvedLayoutType === newLayoutType) {
@@ -20207,8 +20218,41 @@ var STRICT_TO_TRANSITIONAL_NS = new Map(NAMESPACE_PAIRS);
20207
20218
  var TRANSITIONAL_TO_STRICT_NS = new Map(
20208
20219
  NAMESPACE_PAIRS.map(([strict, transitional]) => [transitional, strict])
20209
20220
  );
20221
+ var STRICT_BASE = "http://purl.oclc.org/ooxml/";
20222
+ var TRANSITIONAL_BASE = "http://schemas.openxmlformats.org/";
20223
+ var ALGORITHMIC_FAMILIES = /* @__PURE__ */ new Set([
20224
+ "presentationml",
20225
+ "drawingml",
20226
+ "spreadsheetml",
20227
+ "wordprocessingml",
20228
+ "officeDocument"
20229
+ ]);
20230
+ function deriveTransitionalUri(uri) {
20231
+ if (!uri.startsWith(STRICT_BASE)) {
20232
+ return void 0;
20233
+ }
20234
+ const segments = uri.slice(STRICT_BASE.length).split("/");
20235
+ if (segments.length < 2 || !ALGORITHMIC_FAMILIES.has(segments[0])) {
20236
+ return void 0;
20237
+ }
20238
+ if (segments[1] !== "2006") {
20239
+ segments.splice(1, 0, "2006");
20240
+ }
20241
+ return TRANSITIONAL_BASE + segments.join("/");
20242
+ }
20243
+ function deriveStrictUri(uri) {
20244
+ if (!uri.startsWith(TRANSITIONAL_BASE)) {
20245
+ return void 0;
20246
+ }
20247
+ const segments = uri.slice(TRANSITIONAL_BASE.length).split("/");
20248
+ if (segments.length < 3 || !ALGORITHMIC_FAMILIES.has(segments[0]) || segments[1] !== "2006") {
20249
+ return void 0;
20250
+ }
20251
+ segments.splice(1, 1);
20252
+ return STRICT_BASE + segments.join("/");
20253
+ }
20210
20254
  function normalizeNamespaceUri(uri) {
20211
- return STRICT_TO_TRANSITIONAL_NS.get(uri) ?? uri;
20255
+ return STRICT_TO_TRANSITIONAL_NS.get(uri) ?? deriveTransitionalUri(uri) ?? uri;
20212
20256
  }
20213
20257
  function isStrictNamespaceUri(uri) {
20214
20258
  return uri.startsWith("http://purl.oclc.org/ooxml/");
@@ -20240,25 +20284,16 @@ function normalizeStrictXml(node) {
20240
20284
  const value = node[key];
20241
20285
  if (key.startsWith("@_xmlns")) {
20242
20286
  if (typeof value === "string") {
20243
- const mapped = STRICT_TO_TRANSITIONAL_NS.get(value);
20244
- if (mapped) {
20245
- node[key] = mapped;
20246
- }
20287
+ node[key] = normalizeNamespaceUri(value);
20247
20288
  }
20248
20289
  continue;
20249
20290
  }
20250
20291
  if (key === "@_Type" && typeof value === "string") {
20251
- const mapped = STRICT_TO_TRANSITIONAL_NS.get(value);
20252
- if (mapped) {
20253
- node[key] = mapped;
20254
- }
20292
+ node[key] = normalizeNamespaceUri(value);
20255
20293
  continue;
20256
20294
  }
20257
20295
  if (key === "@_uri" && typeof value === "string") {
20258
- const mapped = STRICT_TO_TRANSITIONAL_NS.get(value);
20259
- if (mapped) {
20260
- node[key] = mapped;
20261
- }
20296
+ node[key] = normalizeNamespaceUri(value);
20262
20297
  continue;
20263
20298
  }
20264
20299
  if (key.startsWith("@_")) {
@@ -20277,10 +20312,10 @@ function normalizeStrictXml(node) {
20277
20312
  return node;
20278
20313
  }
20279
20314
  function toStrictNamespaceUri(uri) {
20280
- return TRANSITIONAL_TO_STRICT_NS.get(uri) ?? uri;
20315
+ return TRANSITIONAL_TO_STRICT_NS.get(uri) ?? deriveStrictUri(uri) ?? uri;
20281
20316
  }
20282
20317
  function isTransitionalNamespaceUri(uri) {
20283
- return TRANSITIONAL_TO_STRICT_NS.has(uri);
20318
+ return TRANSITIONAL_TO_STRICT_NS.has(uri) || deriveStrictUri(uri) !== void 0;
20284
20319
  }
20285
20320
  function convertXmlToStrict(node, setConformance = false) {
20286
20321
  if (typeof node !== "object" || node === null || Array.isArray(node)) {
@@ -20296,25 +20331,16 @@ function convertXmlToStrict(node, setConformance = false) {
20296
20331
  const value = node[key];
20297
20332
  if (key.startsWith("@_xmlns")) {
20298
20333
  if (typeof value === "string") {
20299
- const mapped = TRANSITIONAL_TO_STRICT_NS.get(value);
20300
- if (mapped) {
20301
- node[key] = mapped;
20302
- }
20334
+ node[key] = toStrictNamespaceUri(value);
20303
20335
  }
20304
20336
  continue;
20305
20337
  }
20306
20338
  if (key === "@_Type" && typeof value === "string") {
20307
- const mapped = TRANSITIONAL_TO_STRICT_NS.get(value);
20308
- if (mapped) {
20309
- node[key] = mapped;
20310
- }
20339
+ node[key] = toStrictNamespaceUri(value);
20311
20340
  continue;
20312
20341
  }
20313
20342
  if (key === "@_uri" && typeof value === "string") {
20314
- const mapped = TRANSITIONAL_TO_STRICT_NS.get(value);
20315
- if (mapped) {
20316
- node[key] = mapped;
20317
- }
20343
+ node[key] = toStrictNamespaceUri(value);
20318
20344
  continue;
20319
20345
  }
20320
20346
  if (key.startsWith("@_")) {
@@ -32831,27 +32857,151 @@ var PptxHandlerRuntime23 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
32831
32857
  }
32832
32858
  };
32833
32859
 
32860
+ // src/core/core/runtime/smartart-save-chrome.ts
32861
+ function asObject(value) {
32862
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
32863
+ }
32864
+ function applySmartArtChrome(dataModel, chrome, getLocalName) {
32865
+ if (!chrome || !chrome.backgroundColor && !chrome.outlineColor && (chrome.outlineWidth === null || chrome.outlineWidth === void 0)) {
32866
+ return;
32867
+ }
32868
+ const findKey10 = (obj, name) => Object.keys(obj).find((k) => getLocalName(k) === name);
32869
+ if (chrome.backgroundColor) {
32870
+ const hex7 = chrome.backgroundColor.replace("#", "");
32871
+ const bgKey = findKey10(dataModel, "bg") ?? "dgm:bg";
32872
+ const bg = asObject(dataModel[bgKey]);
32873
+ const fillKey = findKey10(bg, "solidFill") ?? "a:solidFill";
32874
+ bg[fillKey] = { "a:srgbClr": { "@_val": hex7 } };
32875
+ dataModel[bgKey] = bg;
32876
+ }
32877
+ const hasOutlineWidth = chrome.outlineWidth !== null && chrome.outlineWidth !== void 0;
32878
+ if (chrome.outlineColor || hasOutlineWidth) {
32879
+ const wholeKey = findKey10(dataModel, "whole") ?? "dgm:whole";
32880
+ const whole = asObject(dataModel[wholeKey]);
32881
+ const lnKey = findKey10(whole, "ln") ?? "a:ln";
32882
+ const ln = asObject(whole[lnKey]);
32883
+ if (hasOutlineWidth) {
32884
+ ln["@_w"] = String(Math.round(chrome.outlineWidth * 12700));
32885
+ }
32886
+ if (chrome.outlineColor) {
32887
+ const hex7 = chrome.outlineColor.replace("#", "");
32888
+ const fillKey = findKey10(ln, "solidFill") ?? "a:solidFill";
32889
+ ln[fillKey] = { "a:srgbClr": { "@_val": hex7 } };
32890
+ }
32891
+ whole[lnKey] = ln;
32892
+ dataModel[wholeKey] = whole;
32893
+ }
32894
+ }
32895
+
32834
32896
  // src/core/core/runtime/smartart-xml-builders.ts
32835
- function buildSmartArtPointXml(nodes) {
32836
- return nodes.map((node) => {
32837
- const ptNode = {
32838
- "@_modelId": node.id
32839
- };
32840
- if (node.nodeType) {
32841
- ptNode["@_type"] = node.nodeType;
32897
+ var NON_CONTENT_POINT_TYPES = /* @__PURE__ */ new Set([
32898
+ "doc",
32899
+ "pres",
32900
+ "parTrans",
32901
+ "sibTrans"
32902
+ ]);
32903
+ function pointType(pt2) {
32904
+ return String(pt2["@_type"] || "").trim();
32905
+ }
32906
+ function pointModelId(pt2) {
32907
+ return String(pt2["@_modelId"] || "").trim();
32908
+ }
32909
+ function isContentPoint(pt2) {
32910
+ return !NON_CONTENT_POINT_TYPES.has(pointType(pt2));
32911
+ }
32912
+ function buildPointText(text) {
32913
+ return {
32914
+ "a:bodyPr": {},
32915
+ "a:lstStyle": {},
32916
+ "a:p": {
32917
+ "a:r": {
32918
+ "a:rPr": { "@_lang": "en-US", "@_dirty": "0" },
32919
+ "a:t": text
32920
+ }
32842
32921
  }
32843
- ptNode["dgm:t"] = {
32844
- "a:bodyPr": {},
32845
- "a:lstStyle": {},
32846
- "a:p": {
32847
- "a:r": {
32848
- "a:rPr": { "@_lang": "en-US", "@_dirty": "0" },
32849
- "a:t": node.text
32850
- }
32922
+ };
32923
+ }
32924
+ function applyTextToExistingPoint(pt2, text) {
32925
+ const tKey = Object.keys(pt2).find((k) => stripPrefix(k) === "t");
32926
+ if (!tKey) {
32927
+ pt2["dgm:t"] = buildPointText(text);
32928
+ return;
32929
+ }
32930
+ const body = pt2[tKey];
32931
+ if (!body || typeof body !== "object" || Array.isArray(body)) {
32932
+ pt2[tKey] = buildPointText(text);
32933
+ return;
32934
+ }
32935
+ const bodyObj = body;
32936
+ const pKey = Object.keys(bodyObj).find((k) => stripPrefix(k) === "p");
32937
+ const paragraph = pKey ? bodyObj[pKey] : void 0;
32938
+ if (!pKey || Array.isArray(paragraph) || !paragraph || typeof paragraph !== "object") {
32939
+ bodyObj[pKey ?? "a:p"] = {
32940
+ "a:r": {
32941
+ "a:rPr": { "@_lang": "en-US", "@_dirty": "0" },
32942
+ "a:t": text
32851
32943
  }
32852
32944
  };
32853
- return ptNode;
32854
- });
32945
+ return;
32946
+ }
32947
+ const paragraphObj = paragraph;
32948
+ const rKey = Object.keys(paragraphObj).find((k) => stripPrefix(k) === "r");
32949
+ const run = rKey ? paragraphObj[rKey] : void 0;
32950
+ if (!rKey || Array.isArray(run) || !run || typeof run !== "object") {
32951
+ paragraphObj[rKey ?? "a:r"] = {
32952
+ "a:rPr": { "@_lang": "en-US", "@_dirty": "0" },
32953
+ "a:t": text
32954
+ };
32955
+ return;
32956
+ }
32957
+ const runObj = run;
32958
+ const textKey = Object.keys(runObj).find((k) => stripPrefix(k) === "t");
32959
+ runObj[textKey ?? "a:t"] = text;
32960
+ }
32961
+ function stripPrefix(key) {
32962
+ const idx = key.indexOf(":");
32963
+ return idx >= 0 ? key.slice(idx + 1) : key;
32964
+ }
32965
+ function mergeSmartArtPointXml(existingPts, nodes) {
32966
+ const desiredById = /* @__PURE__ */ new Map();
32967
+ for (const node of nodes) {
32968
+ const id = String(node.id || "").trim();
32969
+ if (id.length > 0) {
32970
+ desiredById.set(id, node);
32971
+ }
32972
+ }
32973
+ const seenContentIds = /* @__PURE__ */ new Set();
32974
+ const merged = [];
32975
+ for (const pt2 of existingPts) {
32976
+ if (!pt2 || typeof pt2 !== "object") {
32977
+ continue;
32978
+ }
32979
+ if (!isContentPoint(pt2)) {
32980
+ merged.push(pt2);
32981
+ continue;
32982
+ }
32983
+ const modelId = pointModelId(pt2);
32984
+ const desired = modelId.length > 0 ? desiredById.get(modelId) : void 0;
32985
+ if (!desired) {
32986
+ continue;
32987
+ }
32988
+ applyTextToExistingPoint(pt2, desired.text);
32989
+ seenContentIds.add(modelId);
32990
+ merged.push(pt2);
32991
+ }
32992
+ for (const node of nodes) {
32993
+ const id = String(node.id || "").trim();
32994
+ if (id.length === 0 || seenContentIds.has(id)) {
32995
+ continue;
32996
+ }
32997
+ const ptNode = { "@_modelId": id };
32998
+ if (node.nodeType && !NON_CONTENT_POINT_TYPES.has(node.nodeType)) {
32999
+ ptNode["@_type"] = node.nodeType;
33000
+ }
33001
+ ptNode["dgm:t"] = buildPointText(node.text);
33002
+ merged.push(ptNode);
33003
+ }
33004
+ return merged;
32855
33005
  }
32856
33006
  function buildSmartArtConnectionXml(connections) {
32857
33007
  return connections.map((conn) => {
@@ -32896,12 +33046,12 @@ var PptxHandlerRuntime24 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
32896
33046
  if (!this.pendingSmartArtUpdates || this.pendingSmartArtUpdates.length === 0) {
32897
33047
  return;
32898
33048
  }
32899
- for (const { element } of this.pendingSmartArtUpdates) {
33049
+ for (const { element, slidePath: capturedSlidePath } of this.pendingSmartArtUpdates) {
32900
33050
  const smartArtData = element.smartArtData;
32901
33051
  if (!smartArtData?.dataRelId) {
32902
33052
  continue;
32903
33053
  }
32904
- const slidePath = element.rawXml ? this.findSlidePathForElement(element) : void 0;
33054
+ const slidePath = capturedSlidePath && capturedSlidePath.length > 0 ? capturedSlidePath : this.findSlidePathForElement(element);
32905
33055
  if (!slidePath) {
32906
33056
  continue;
32907
33057
  }
@@ -32930,7 +33080,8 @@ var PptxHandlerRuntime24 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
32930
33080
  (k) => this.compatibilityService.getXmlLocalName(k) === "pt"
32931
33081
  );
32932
33082
  if (ptKey) {
32933
- ptList[ptKey] = buildSmartArtPointXml(smartArtData.nodes);
33083
+ const existingPts = this.ensureArray(ptList[ptKey]);
33084
+ ptList[ptKey] = mergeSmartArtPointXml(existingPts, smartArtData.nodes);
32934
33085
  }
32935
33086
  }
32936
33087
  if (smartArtData.connections && smartArtData.connections.length > 0) {
@@ -32947,6 +33098,11 @@ var PptxHandlerRuntime24 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
32947
33098
  }
32948
33099
  }
32949
33100
  }
33101
+ applySmartArtChrome(
33102
+ dataModel,
33103
+ smartArtData.chrome,
33104
+ (k) => this.compatibilityService.getXmlLocalName(k)
33105
+ );
32950
33106
  this.zip.file(dataPartPath, this.builder.build(parsed));
32951
33107
  } catch (e) {
32952
33108
  console.warn(`Failed to save SmartArt data at ${dataPartPath}:`, e);
@@ -33076,7 +33232,7 @@ var PptxHandlerRuntime24 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
33076
33232
  if (this.customXmlParts.length === 0) {
33077
33233
  return;
33078
33234
  }
33079
- const SAFE_ID = /^[A-Za-z0-9_-]+$/;
33235
+ const SAFE_ID = /^[A-Za-z0-9_-]+$/u;
33080
33236
  let fallbackIndex = 1;
33081
33237
  for (const part of this.customXmlParts) {
33082
33238
  const rawId = String(part.id);
@@ -33187,7 +33343,7 @@ var PptxHandlerRuntime24 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
33187
33343
  let maxId = 0;
33188
33344
  for (const rel of relationships) {
33189
33345
  const id = String(rel?.["@_Id"] || "");
33190
- const num = parseInt(id.replace(/^rId/, ""), 10);
33346
+ const num = parseInt(id.replace(/^rId/u, ""), 10);
33191
33347
  if (Number.isFinite(num) && num > maxId) {
33192
33348
  maxId = num;
33193
33349
  }
@@ -33310,7 +33466,7 @@ var PptxHandlerRuntime24 = class _PptxHandlerRuntime extends PptxHandlerRuntime2
33310
33466
  let maxId = 0;
33311
33467
  for (const rel of relationships) {
33312
33468
  const id = String(rel?.["@_Id"] || "");
33313
- const num = parseInt(id.replace(/^rId/, ""), 10);
33469
+ const num = parseInt(id.replace(/^rId/u, ""), 10);
33314
33470
  if (Number.isFinite(num) && num > maxId) {
33315
33471
  maxId = num;
33316
33472
  }
@@ -42981,13 +43137,13 @@ var PptxHandlerRuntime70 = class _PptxHandlerRuntime extends PptxHandlerRuntime6
42981
43137
  parentId: parentByNodeId.get(pointId),
42982
43138
  nodeType
42983
43139
  };
42984
- }).filter((entry) => Boolean(entry)).slice(0, 50);
43140
+ }).filter((entry) => Boolean(entry)).slice(0, MAX_SMARTART_NODES);
42985
43141
  if (nodes.length === 0) {
42986
43142
  return void 0;
42987
43143
  }
42988
43144
  const layoutRelationshipId = String(relationshipIds["@_r:lo"] || "").trim();
42989
43145
  const layoutPart = layoutRelationshipId.length > 0 ? await this.readXmlPartByRelationshipId(slidePath, layoutRelationshipId) : void 0;
42990
- const layoutType = layoutPart?.partPath?.split("/").pop()?.replace(/\.[^.]+$/, "") || void 0;
43146
+ const layoutType = layoutPart?.partPath?.split("/").pop()?.replace(/\.[^.]+$/u, "") || void 0;
42991
43147
  const chrome = this.parseSmartArtChrome(dataModel);
42992
43148
  const colorsRelationshipId = String(relationshipIds["@_r:cs"] || "").trim();
42993
43149
  const colorTransform = await this.parseSmartArtColorTransform(slidePath, colorsRelationshipId);
@@ -43035,7 +43191,7 @@ var PptxHandlerRuntime70 = class _PptxHandlerRuntime extends PptxHandlerRuntime6
43035
43191
  return void 0;
43036
43192
  }
43037
43193
  const dataPath = this.resolveImagePath(slidePath, dataTarget);
43038
- const dataDir = dataPath.replace(/\/[^/]+$/, "");
43194
+ const dataDir = dataPath.replace(/\/[^/]+$/u, "");
43039
43195
  const dataFile = dataPath.split("/").pop() ?? "";
43040
43196
  const dataRelsPath = `${dataDir}/_rels/${dataFile}.rels`;
43041
43197
  const relsXml = await this.zip.file(dataRelsPath)?.async("string");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pptx-viewer-core",
3
- "version": "1.1.29",
3
+ "version": "1.1.31",
4
4
  "description": "PowerPoint PPTX engine: parse, edit, serialize, and convert .pptx files. Framework-agnostic TypeScript SDK.",
5
5
  "keywords": [
6
6
  "converter",