pptx-react-viewer 1.1.4 → 1.1.6

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.
Files changed (38) hide show
  1. package/dist/index.js +865 -159
  2. package/dist/index.mjs +866 -161
  3. package/dist/viewer/index.js +883 -165
  4. package/dist/viewer/index.mjs +884 -167
  5. package/node_modules/emf-converter/dist/index.d.mts +2 -2
  6. package/node_modules/emf-converter/dist/index.d.ts +2 -2
  7. package/node_modules/emf-converter/dist/index.js +91 -33
  8. package/node_modules/emf-converter/dist/index.mjs +91 -33
  9. package/node_modules/emf-converter/package.json +1 -1
  10. package/node_modules/mtx-decompressor/dist/index.js +39 -9
  11. package/node_modules/mtx-decompressor/dist/index.mjs +39 -9
  12. package/node_modules/mtx-decompressor/package.json +1 -1
  13. package/node_modules/pptx-viewer-core/dist/{SvgExporter-BQ4KbRO9.d.mts → SvgExporter-BTkk4oNQ.d.mts} +1 -1
  14. package/node_modules/pptx-viewer-core/dist/{SvgExporter-0TxiiorD.d.ts → SvgExporter-CTDG-t_z.d.ts} +1 -1
  15. package/node_modules/pptx-viewer-core/dist/cli/index.d.mts +2 -2
  16. package/node_modules/pptx-viewer-core/dist/cli/index.d.ts +2 -2
  17. package/node_modules/pptx-viewer-core/dist/cli/index.js +0 -0
  18. package/node_modules/pptx-viewer-core/dist/cli/index.mjs +0 -0
  19. package/node_modules/pptx-viewer-core/dist/converter/index.d.mts +3 -3
  20. package/node_modules/pptx-viewer-core/dist/converter/index.d.ts +3 -3
  21. package/node_modules/pptx-viewer-core/dist/converter/index.js +0 -0
  22. package/node_modules/pptx-viewer-core/dist/converter/index.mjs +0 -0
  23. package/node_modules/pptx-viewer-core/dist/index.d.mts +961 -59
  24. package/node_modules/pptx-viewer-core/dist/index.d.ts +961 -59
  25. package/node_modules/pptx-viewer-core/dist/index.js +29880 -16692
  26. package/node_modules/pptx-viewer-core/dist/index.mjs +29859 -16692
  27. package/node_modules/pptx-viewer-core/dist/{presentation-ArhfImJ5.d.mts → presentation-4fhI3din.d.mts} +835 -26
  28. package/node_modules/pptx-viewer-core/dist/{presentation-ArhfImJ5.d.ts → presentation-4fhI3din.d.ts} +835 -26
  29. package/node_modules/pptx-viewer-core/dist/{signature-inspection-status-BcJSdOvb.d.mts → signature-inspection-status-BCUpfCQh.d.mts} +13 -2
  30. package/node_modules/pptx-viewer-core/dist/{signature-inspection-status-BcJSdOvb.d.ts → signature-inspection-status-BCUpfCQh.d.ts} +13 -2
  31. package/node_modules/pptx-viewer-core/dist/signature-node/index.d.mts +2 -2
  32. package/node_modules/pptx-viewer-core/dist/signature-node/index.d.ts +2 -2
  33. package/node_modules/pptx-viewer-core/dist/signature-node/index.js +17 -3
  34. package/node_modules/pptx-viewer-core/dist/signature-node/index.mjs +16 -4
  35. package/node_modules/pptx-viewer-core/dist/{text-operations-rhJV-A_W.d.ts → text-operations-B9EwbptL.d.ts} +1 -1
  36. package/node_modules/pptx-viewer-core/dist/{text-operations-CLj-sJyk.d.mts → text-operations-C89Jn6S0.d.mts} +1 -1
  37. package/node_modules/pptx-viewer-core/package.json +1 -1
  38. package/package.json +6 -4
package/dist/index.js CHANGED
@@ -7,6 +7,7 @@ var clsx = require('clsx');
7
7
  var tailwindMerge = require('tailwind-merge');
8
8
  var lu = require('react-icons/lu');
9
9
  var pptxViewerCore = require('pptx-viewer-core');
10
+ var DOMPurify = require('dompurify');
10
11
  var reactI18next = require('react-i18next');
11
12
  var html2canvasPro = require('html2canvas-pro');
12
13
  var JSZip = require('jszip');
@@ -33,6 +34,7 @@ function _interopNamespace(e) {
33
34
 
34
35
  var React10__namespace = /*#__PURE__*/_interopNamespace(React10);
35
36
  var ReactDOM__namespace = /*#__PURE__*/_interopNamespace(ReactDOM);
37
+ var DOMPurify__default = /*#__PURE__*/_interopDefault(DOMPurify);
36
38
  var html2canvasPro__default = /*#__PURE__*/_interopDefault(html2canvasPro);
37
39
  var JSZip__default = /*#__PURE__*/_interopDefault(JSZip);
38
40
 
@@ -196,7 +198,7 @@ function generateUUID() {
196
198
  const uuid = _lut[d0 & 255] + _lut[d0 >> 8 & 255] + _lut[d0 >> 16 & 255] + _lut[d0 >> 24 & 255] + "-" + _lut[d1 & 255] + _lut[d1 >> 8 & 255] + "-" + _lut[d1 >> 16 & 15 | 64] + _lut[d1 >> 24 & 255] + "-" + _lut[d2 & 63 | 128] + _lut[d2 >> 8 & 255] + "-" + _lut[d2 >> 16 & 255] + _lut[d2 >> 24 & 255] + _lut[d3 & 255] + _lut[d3 >> 8 & 255] + _lut[d3 >> 16 & 255] + _lut[d3 >> 24 & 255];
197
199
  return uuid.toLowerCase();
198
200
  }
199
- function clamp(value, min2, max2) {
201
+ function clamp2(value, min2, max2) {
200
202
  return Math.max(min2, Math.min(max2, value));
201
203
  }
202
204
  function euclideanModulo(n, m2) {
@@ -571,7 +573,7 @@ function _generateTables() {
571
573
  }
572
574
  function toHalfFloat(val2) {
573
575
  if (Math.abs(val2) > 65504) warn("DataUtils.toHalfFloat(): Value out of range.");
574
- val2 = clamp(val2, -65504, 65504);
576
+ val2 = clamp2(val2, -65504, 65504);
575
577
  _tables.floatView[0] = val2;
576
578
  const f = _tables.uint32View[0];
577
579
  const e2 = f >> 23 & 511;
@@ -2060,7 +2062,7 @@ var init_three_core = __esm({
2060
2062
  * @param {number} max - The max value.
2061
2063
  * @return {number} The clamped value.
2062
2064
  */
2063
- clamp,
2065
+ clamp: clamp2,
2064
2066
  /**
2065
2067
  * Computes the Euclidean modulo of the given parameters that
2066
2068
  * is `( ( n % m ) + m ) % m`.
@@ -2587,8 +2589,8 @@ var init_three_core = __esm({
2587
2589
  * @return {Vector2} A reference to this vector.
2588
2590
  */
2589
2591
  clamp(min2, max2) {
2590
- this.x = clamp(this.x, min2.x, max2.x);
2591
- this.y = clamp(this.y, min2.y, max2.y);
2592
+ this.x = clamp2(this.x, min2.x, max2.x);
2593
+ this.y = clamp2(this.y, min2.y, max2.y);
2592
2594
  return this;
2593
2595
  }
2594
2596
  /**
@@ -2602,8 +2604,8 @@ var init_three_core = __esm({
2602
2604
  * @return {Vector2} A reference to this vector.
2603
2605
  */
2604
2606
  clampScalar(minVal, maxVal) {
2605
- this.x = clamp(this.x, minVal, maxVal);
2606
- this.y = clamp(this.y, minVal, maxVal);
2607
+ this.x = clamp2(this.x, minVal, maxVal);
2608
+ this.y = clamp2(this.y, minVal, maxVal);
2607
2609
  return this;
2608
2610
  }
2609
2611
  /**
@@ -2618,7 +2620,7 @@ var init_three_core = __esm({
2618
2620
  */
2619
2621
  clampLength(min2, max2) {
2620
2622
  const length2 = this.length();
2621
- return this.divideScalar(length2 || 1).multiplyScalar(clamp(length2, min2, max2));
2623
+ return this.divideScalar(length2 || 1).multiplyScalar(clamp2(length2, min2, max2));
2622
2624
  }
2623
2625
  /**
2624
2626
  * The components of this vector are rounded down to the nearest integer value.
@@ -2743,7 +2745,7 @@ var init_three_core = __esm({
2743
2745
  const denominator = Math.sqrt(this.lengthSq() * v.lengthSq());
2744
2746
  if (denominator === 0) return Math.PI / 2;
2745
2747
  const theta = this.dot(v) / denominator;
2746
- return Math.acos(clamp(theta, -1, 1));
2748
+ return Math.acos(clamp2(theta, -1, 1));
2747
2749
  }
2748
2750
  /**
2749
2751
  * Computes the distance from the given vector to this instance.
@@ -3230,7 +3232,7 @@ var init_three_core = __esm({
3230
3232
  * @return {number} The angle in radians.
3231
3233
  */
3232
3234
  angleTo(q) {
3233
- return 2 * Math.acos(Math.abs(clamp(this.dot(q), -1, 1)));
3235
+ return 2 * Math.acos(Math.abs(clamp2(this.dot(q), -1, 1)));
3234
3236
  }
3235
3237
  /**
3236
3238
  * Rotates this quaternion by a given angular step to the given quaternion.
@@ -3936,9 +3938,9 @@ var init_three_core = __esm({
3936
3938
  * @return {Vector3} A reference to this vector.
3937
3939
  */
3938
3940
  clamp(min2, max2) {
3939
- this.x = clamp(this.x, min2.x, max2.x);
3940
- this.y = clamp(this.y, min2.y, max2.y);
3941
- this.z = clamp(this.z, min2.z, max2.z);
3941
+ this.x = clamp2(this.x, min2.x, max2.x);
3942
+ this.y = clamp2(this.y, min2.y, max2.y);
3943
+ this.z = clamp2(this.z, min2.z, max2.z);
3942
3944
  return this;
3943
3945
  }
3944
3946
  /**
@@ -3952,9 +3954,9 @@ var init_three_core = __esm({
3952
3954
  * @return {Vector3} A reference to this vector.
3953
3955
  */
3954
3956
  clampScalar(minVal, maxVal) {
3955
- this.x = clamp(this.x, minVal, maxVal);
3956
- this.y = clamp(this.y, minVal, maxVal);
3957
- this.z = clamp(this.z, minVal, maxVal);
3957
+ this.x = clamp2(this.x, minVal, maxVal);
3958
+ this.y = clamp2(this.y, minVal, maxVal);
3959
+ this.z = clamp2(this.z, minVal, maxVal);
3958
3960
  return this;
3959
3961
  }
3960
3962
  /**
@@ -3969,7 +3971,7 @@ var init_three_core = __esm({
3969
3971
  */
3970
3972
  clampLength(min2, max2) {
3971
3973
  const length2 = this.length();
3972
- return this.divideScalar(length2 || 1).multiplyScalar(clamp(length2, min2, max2));
3974
+ return this.divideScalar(length2 || 1).multiplyScalar(clamp2(length2, min2, max2));
3973
3975
  }
3974
3976
  /**
3975
3977
  * The components of this vector are rounded down to the nearest integer value.
@@ -4179,7 +4181,7 @@ var init_three_core = __esm({
4179
4181
  const denominator = Math.sqrt(this.lengthSq() * v.lengthSq());
4180
4182
  if (denominator === 0) return Math.PI / 2;
4181
4183
  const theta = this.dot(v) / denominator;
4182
- return Math.acos(clamp(theta, -1, 1));
4184
+ return Math.acos(clamp2(theta, -1, 1));
4183
4185
  }
4184
4186
  /**
4185
4187
  * Computes the distance from the given vector to this instance.
@@ -5868,10 +5870,10 @@ var init_three_core = __esm({
5868
5870
  * @return {Vector4} A reference to this vector.
5869
5871
  */
5870
5872
  clamp(min2, max2) {
5871
- this.x = clamp(this.x, min2.x, max2.x);
5872
- this.y = clamp(this.y, min2.y, max2.y);
5873
- this.z = clamp(this.z, min2.z, max2.z);
5874
- this.w = clamp(this.w, min2.w, max2.w);
5873
+ this.x = clamp2(this.x, min2.x, max2.x);
5874
+ this.y = clamp2(this.y, min2.y, max2.y);
5875
+ this.z = clamp2(this.z, min2.z, max2.z);
5876
+ this.w = clamp2(this.w, min2.w, max2.w);
5875
5877
  return this;
5876
5878
  }
5877
5879
  /**
@@ -5885,10 +5887,10 @@ var init_three_core = __esm({
5885
5887
  * @return {Vector4} A reference to this vector.
5886
5888
  */
5887
5889
  clampScalar(minVal, maxVal) {
5888
- this.x = clamp(this.x, minVal, maxVal);
5889
- this.y = clamp(this.y, minVal, maxVal);
5890
- this.z = clamp(this.z, minVal, maxVal);
5891
- this.w = clamp(this.w, minVal, maxVal);
5890
+ this.x = clamp2(this.x, minVal, maxVal);
5891
+ this.y = clamp2(this.y, minVal, maxVal);
5892
+ this.z = clamp2(this.z, minVal, maxVal);
5893
+ this.w = clamp2(this.w, minVal, maxVal);
5892
5894
  return this;
5893
5895
  }
5894
5896
  /**
@@ -5903,7 +5905,7 @@ var init_three_core = __esm({
5903
5905
  */
5904
5906
  clampLength(min2, max2) {
5905
5907
  const length2 = this.length();
5906
- return this.divideScalar(length2 || 1).multiplyScalar(clamp(length2, min2, max2));
5908
+ return this.divideScalar(length2 || 1).multiplyScalar(clamp2(length2, min2, max2));
5907
5909
  }
5908
5910
  /**
5909
5911
  * The components of this vector are rounded down to the nearest integer value.
@@ -7686,7 +7688,7 @@ var init_three_core = __esm({
7686
7688
  const m31 = te[2], m32 = te[6], m33 = te[10];
7687
7689
  switch (order) {
7688
7690
  case "XYZ":
7689
- this._y = Math.asin(clamp(m13, -1, 1));
7691
+ this._y = Math.asin(clamp2(m13, -1, 1));
7690
7692
  if (Math.abs(m13) < 0.9999999) {
7691
7693
  this._x = Math.atan2(-m23, m33);
7692
7694
  this._z = Math.atan2(-m12, m11);
@@ -7696,7 +7698,7 @@ var init_three_core = __esm({
7696
7698
  }
7697
7699
  break;
7698
7700
  case "YXZ":
7699
- this._x = Math.asin(-clamp(m23, -1, 1));
7701
+ this._x = Math.asin(-clamp2(m23, -1, 1));
7700
7702
  if (Math.abs(m23) < 0.9999999) {
7701
7703
  this._y = Math.atan2(m13, m33);
7702
7704
  this._z = Math.atan2(m21, m22);
@@ -7706,7 +7708,7 @@ var init_three_core = __esm({
7706
7708
  }
7707
7709
  break;
7708
7710
  case "ZXY":
7709
- this._x = Math.asin(clamp(m32, -1, 1));
7711
+ this._x = Math.asin(clamp2(m32, -1, 1));
7710
7712
  if (Math.abs(m32) < 0.9999999) {
7711
7713
  this._y = Math.atan2(-m31, m33);
7712
7714
  this._z = Math.atan2(-m12, m22);
@@ -7716,7 +7718,7 @@ var init_three_core = __esm({
7716
7718
  }
7717
7719
  break;
7718
7720
  case "ZYX":
7719
- this._y = Math.asin(-clamp(m31, -1, 1));
7721
+ this._y = Math.asin(-clamp2(m31, -1, 1));
7720
7722
  if (Math.abs(m31) < 0.9999999) {
7721
7723
  this._x = Math.atan2(m32, m33);
7722
7724
  this._z = Math.atan2(m21, m11);
@@ -7726,7 +7728,7 @@ var init_three_core = __esm({
7726
7728
  }
7727
7729
  break;
7728
7730
  case "YZX":
7729
- this._z = Math.asin(clamp(m21, -1, 1));
7731
+ this._z = Math.asin(clamp2(m21, -1, 1));
7730
7732
  if (Math.abs(m21) < 0.9999999) {
7731
7733
  this._x = Math.atan2(-m23, m22);
7732
7734
  this._y = Math.atan2(-m31, m11);
@@ -7736,7 +7738,7 @@ var init_three_core = __esm({
7736
7738
  }
7737
7739
  break;
7738
7740
  case "XZY":
7739
- this._z = Math.asin(-clamp(m12, -1, 1));
7741
+ this._z = Math.asin(-clamp2(m12, -1, 1));
7740
7742
  if (Math.abs(m12) < 0.9999999) {
7741
7743
  this._x = Math.atan2(m32, m22);
7742
7744
  this._y = Math.atan2(m13, m11);
@@ -9360,8 +9362,8 @@ var init_three_core = __esm({
9360
9362
  */
9361
9363
  setHSL(h2, s, l2, colorSpace = ColorManagement.workingColorSpace) {
9362
9364
  h2 = euclideanModulo(h2, 1);
9363
- s = clamp(s, 0, 1);
9364
- l2 = clamp(l2, 0, 1);
9365
+ s = clamp2(s, 0, 1);
9366
+ l2 = clamp2(l2, 0, 1);
9365
9367
  if (s === 0) {
9366
9368
  this.r = this.g = this.b = l2;
9367
9369
  } else {
@@ -9547,7 +9549,7 @@ var init_three_core = __esm({
9547
9549
  */
9548
9550
  getHex(colorSpace = SRGBColorSpace) {
9549
9551
  ColorManagement.workingToColorSpace(_color.copy(this), colorSpace);
9550
- return Math.round(clamp(_color.r * 255, 0, 255)) * 65536 + Math.round(clamp(_color.g * 255, 0, 255)) * 256 + Math.round(clamp(_color.b * 255, 0, 255));
9552
+ return Math.round(clamp2(_color.r * 255, 0, 255)) * 65536 + Math.round(clamp2(_color.g * 255, 0, 255)) * 256 + Math.round(clamp2(_color.b * 255, 0, 255));
9551
9553
  }
9552
9554
  /**
9553
9555
  * Returns the hexadecimal value of this color as a string (for example, 'FFFFFF').
@@ -18478,13 +18480,13 @@ var init_three_core = __esm({
18478
18480
  vec.crossVectors(tangents[i3 - 1], tangents[i3]);
18479
18481
  if (vec.length() > Number.EPSILON) {
18480
18482
  vec.normalize();
18481
- const theta = Math.acos(clamp(tangents[i3 - 1].dot(tangents[i3]), -1, 1));
18483
+ const theta = Math.acos(clamp2(tangents[i3 - 1].dot(tangents[i3]), -1, 1));
18482
18484
  normals[i3].applyMatrix4(mat.makeRotationAxis(vec, theta));
18483
18485
  }
18484
18486
  binormals[i3].crossVectors(tangents[i3], normals[i3]);
18485
18487
  }
18486
18488
  if (closed === true) {
18487
- let theta = Math.acos(clamp(normals[0].dot(normals[segments]), -1, 1));
18489
+ let theta = Math.acos(clamp2(normals[0].dot(normals[segments]), -1, 1));
18488
18490
  theta /= segments;
18489
18491
  if (tangents[0].dot(vec.crossVectors(normals[0], normals[segments])) > 0) {
18490
18492
  theta = -theta;
@@ -20273,7 +20275,7 @@ var init_three_core = __esm({
20273
20275
  phiLength
20274
20276
  };
20275
20277
  segments = Math.floor(segments);
20276
- phiLength = clamp(phiLength, 0, Math.PI * 2);
20278
+ phiLength = clamp2(phiLength, 0, Math.PI * 2);
20277
20279
  const indices = [];
20278
20280
  const vertices = [];
20279
20281
  const uvs = [];
@@ -21489,7 +21491,7 @@ var init_three_core = __esm({
21489
21491
  this.ior = 1.5;
21490
21492
  Object.defineProperty(this, "reflectivity", {
21491
21493
  get: function() {
21492
- return clamp(2.5 * (this.ior - 1) / (this.ior + 1), 0, 1);
21494
+ return clamp2(2.5 * (this.ior - 1) / (this.ior + 1), 0, 1);
21493
21495
  },
21494
21496
  set: function(reflectivity) {
21495
21497
  this.ior = (1 + 0.4 * reflectivity) / (1 - 0.4 * reflectivity);
@@ -29757,7 +29759,7 @@ var init_three_core = __esm({
29757
29759
  */
29758
29760
  makeSafe() {
29759
29761
  const EPS = 1e-6;
29760
- this.phi = clamp(this.phi, EPS, Math.PI - EPS);
29762
+ this.phi = clamp2(this.phi, EPS, Math.PI - EPS);
29761
29763
  return this;
29762
29764
  }
29763
29765
  /**
@@ -29785,7 +29787,7 @@ var init_three_core = __esm({
29785
29787
  this.phi = 0;
29786
29788
  } else {
29787
29789
  this.theta = Math.atan2(x2, z);
29788
- this.phi = Math.acos(clamp(y / this.radius, -1, 1));
29790
+ this.phi = Math.acos(clamp2(y / this.radius, -1, 1));
29789
29791
  }
29790
29792
  return this;
29791
29793
  }
@@ -30300,7 +30302,7 @@ var init_three_core = __esm({
30300
30302
  const startEnd_startP = _startEnd.dot(_startP);
30301
30303
  let t2 = startEnd_startP / startEnd2;
30302
30304
  if (clampToLine) {
30303
- t2 = clamp(t2, 0, 1);
30305
+ t2 = clamp2(t2, 0, 1);
30304
30306
  }
30305
30307
  return t2;
30306
30308
  }
@@ -30346,27 +30348,27 @@ var init_three_core = __esm({
30346
30348
  if (a2 <= EPSILON) {
30347
30349
  s = 0;
30348
30350
  t2 = f / e2;
30349
- t2 = clamp(t2, 0, 1);
30351
+ t2 = clamp2(t2, 0, 1);
30350
30352
  } else {
30351
30353
  const c3 = _d1.dot(_r);
30352
30354
  if (e2 <= EPSILON) {
30353
30355
  t2 = 0;
30354
- s = clamp(-c3 / a2, 0, 1);
30356
+ s = clamp2(-c3 / a2, 0, 1);
30355
30357
  } else {
30356
30358
  const b2 = _d1.dot(_d2);
30357
30359
  const denom = a2 * e2 - b2 * b2;
30358
30360
  if (denom !== 0) {
30359
- s = clamp((b2 * f - c3 * e2) / denom, 0, 1);
30361
+ s = clamp2((b2 * f - c3 * e2) / denom, 0, 1);
30360
30362
  } else {
30361
30363
  s = 0;
30362
30364
  }
30363
30365
  t2 = (b2 * s + f) / e2;
30364
30366
  if (t2 < 0) {
30365
30367
  t2 = 0;
30366
- s = clamp(-c3 / a2, 0, 1);
30368
+ s = clamp2(-c3 / a2, 0, 1);
30367
30369
  } else if (t2 > 1) {
30368
30370
  t2 = 1;
30369
- s = clamp((b2 - c3) / a2, 0, 1);
30371
+ s = clamp2((b2 - c3) / a2, 0, 1);
30370
30372
  }
30371
30373
  }
30372
30374
  }
@@ -43596,7 +43598,7 @@ var require_use_sync_external_store_shim_development = __commonJS({
43596
43598
  return x2 === y && (0 !== x2 || 1 / x2 === 1 / y) || x2 !== x2 && y !== y;
43597
43599
  }
43598
43600
  function useSyncExternalStore$2(subscribe3, getSnapshot2) {
43599
- didWarnOld18Alpha || void 0 === React97.startTransition || (didWarnOld18Alpha = true, console.error(
43601
+ didWarnOld18Alpha || void 0 === React100.startTransition || (didWarnOld18Alpha = true, console.error(
43600
43602
  "You are using an outdated, pre-release alpha of React 18 that does not support useSyncExternalStore. The use-sync-external-store shim will not work correctly. Upgrade to a newer pre-release."
43601
43603
  ));
43602
43604
  var value = getSnapshot2();
@@ -43606,7 +43608,7 @@ var require_use_sync_external_store_shim_development = __commonJS({
43606
43608
  "The result of getSnapshot should be cached to avoid an infinite loop"
43607
43609
  ), didWarnUncachedGetSnapshot = true);
43608
43610
  }
43609
- cachedValue = useState85({
43611
+ cachedValue = useState86({
43610
43612
  inst: { value, getSnapshot: getSnapshot2 }
43611
43613
  });
43612
43614
  var inst = cachedValue[0].inst, forceUpdate = cachedValue[1];
@@ -43644,8 +43646,8 @@ var require_use_sync_external_store_shim_development = __commonJS({
43644
43646
  return getSnapshot2();
43645
43647
  }
43646
43648
  "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
43647
- var React97 = __require("react"), objectIs = "function" === typeof Object.is ? Object.is : is2, useState85 = React97.useState, useEffect72 = React97.useEffect, useLayoutEffect7 = React97.useLayoutEffect, useDebugValue = React97.useDebugValue, didWarnOld18Alpha = false, didWarnUncachedGetSnapshot = false, shim = "undefined" === typeof window || "undefined" === typeof window.document || "undefined" === typeof window.document.createElement ? useSyncExternalStore$1 : useSyncExternalStore$2;
43648
- exports$1.useSyncExternalStore = void 0 !== React97.useSyncExternalStore ? React97.useSyncExternalStore : shim;
43649
+ var React100 = __require("react"), objectIs = "function" === typeof Object.is ? Object.is : is2, useState86 = React100.useState, useEffect72 = React100.useEffect, useLayoutEffect7 = React100.useLayoutEffect, useDebugValue = React100.useDebugValue, didWarnOld18Alpha = false, didWarnUncachedGetSnapshot = false, shim = "undefined" === typeof window || "undefined" === typeof window.document || "undefined" === typeof window.document.createElement ? useSyncExternalStore$1 : useSyncExternalStore$2;
43650
+ exports$1.useSyncExternalStore = void 0 !== React100.useSyncExternalStore ? React100.useSyncExternalStore : shim;
43649
43651
  "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error());
43650
43652
  })();
43651
43653
  }
@@ -43668,7 +43670,7 @@ var require_with_selector_development = __commonJS({
43668
43670
  return x2 === y && (0 !== x2 || 1 / x2 === 1 / y) || x2 !== x2 && y !== y;
43669
43671
  }
43670
43672
  "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
43671
- var React97 = __require("react"), shim = require_shim(), objectIs = "function" === typeof Object.is ? Object.is : is2, useSyncExternalStore3 = shim.useSyncExternalStore, useRef73 = React97.useRef, useEffect72 = React97.useEffect, useMemo41 = React97.useMemo, useDebugValue = React97.useDebugValue;
43673
+ var React100 = __require("react"), shim = require_shim(), objectIs = "function" === typeof Object.is ? Object.is : is2, useSyncExternalStore3 = shim.useSyncExternalStore, useRef73 = React100.useRef, useEffect72 = React100.useEffect, useMemo41 = React100.useMemo, useDebugValue = React100.useDebugValue;
43672
43674
  exports$1.useSyncExternalStoreWithSelector = function(subscribe3, getSnapshot2, getServerSnapshot2, selector, isEqual) {
43673
43675
  var instRef = useRef73(null);
43674
43676
  if (null === instRef.current) {
@@ -70316,6 +70318,55 @@ var ACTION_BUTTON_PRESETS = [
70316
70318
  label: "Return",
70317
70319
  defaultAction: "prevSlide",
70318
70320
  iconPath: "M18 8 L18 14 L6 14 M6 14 L10 10 M6 14 L10 18"
70321
+ },
70322
+ {
70323
+ shapeType: "actionButtonHome",
70324
+ label: "Home",
70325
+ defaultAction: "firstSlide",
70326
+ // House: roof + body
70327
+ iconPath: "M12 4 L20 11 L20 20 L14 20 L14 14 L10 14 L10 20 L4 20 L4 11 Z"
70328
+ },
70329
+ {
70330
+ shapeType: "actionButtonHelp",
70331
+ label: "Help",
70332
+ defaultAction: "none",
70333
+ // Question mark
70334
+ iconPath: "M9 9 a3 3 0 1 1 4 2.8 c-1 0.4 -1 1.2 -1 2 M12 17 v0.5"
70335
+ },
70336
+ {
70337
+ shapeType: "actionButtonInformation",
70338
+ label: "Information",
70339
+ defaultAction: "none",
70340
+ // Lower-case "i": dot + body
70341
+ iconPath: "M12 6 v0.01 M12 10 v8"
70342
+ },
70343
+ {
70344
+ shapeType: "actionButtonDocument",
70345
+ label: "Document",
70346
+ defaultAction: "none",
70347
+ // Document with folded corner
70348
+ iconPath: "M6 4 L14 4 L18 8 L18 20 L6 20 Z M14 4 L14 8 L18 8"
70349
+ },
70350
+ {
70351
+ shapeType: "actionButtonSound",
70352
+ label: "Sound",
70353
+ defaultAction: "none",
70354
+ // Speaker cone + sound waves
70355
+ iconPath: "M4 10 L4 14 L8 14 L12 18 L12 6 L8 10 Z M16 9 a4 4 0 0 1 0 6 M18 7 a7 7 0 0 1 0 10"
70356
+ },
70357
+ {
70358
+ shapeType: "actionButtonMovie",
70359
+ label: "Movie",
70360
+ defaultAction: "none",
70361
+ // Film strip with play triangle
70362
+ iconPath: "M4 6 L20 6 L20 18 L4 18 Z M10 9 L15 12 L10 15 Z"
70363
+ },
70364
+ {
70365
+ shapeType: "actionButtonBlank",
70366
+ label: "Custom",
70367
+ defaultAction: "none",
70368
+ // No glyph — empty path. The button still renders as a rounded rect via clip-path.
70369
+ iconPath: ""
70319
70370
  }
70320
70371
  ];
70321
70372
  Object.fromEntries(ACTION_BUTTON_PRESETS.map((p3) => [p3.shapeType, p3.defaultAction]));
@@ -72595,8 +72646,8 @@ function hexToRgb2(hex) {
72595
72646
  };
72596
72647
  }
72597
72648
  function rgbToHex(r2, g2, b2) {
72598
- const clamp2 = (v) => Math.max(0, Math.min(255, Math.round(v)));
72599
- return `#${clamp2(r2).toString(16).padStart(2, "0")}${clamp2(g2).toString(16).padStart(2, "0")}${clamp2(b2).toString(16).padStart(2, "0")}`;
72649
+ const clamp3 = (v) => Math.max(0, Math.min(255, Math.round(v)));
72650
+ return `#${clamp3(r2).toString(16).padStart(2, "0")}${clamp3(g2).toString(16).padStart(2, "0")}${clamp3(b2).toString(16).padStart(2, "0")}`;
72600
72651
  }
72601
72652
  function rgbToHsl(r2, g2, b2) {
72602
72653
  const rn = r2 / 255;
@@ -74100,6 +74151,13 @@ function hasDistinctScriptFonts(fonts) {
74100
74151
  }
74101
74152
  return Boolean(fonts.eastAsia) && fonts.eastAsia !== base || Boolean(fonts.complexScript) && fonts.complexScript !== base || Boolean(fonts.symbol) && fonts.symbol !== base;
74102
74153
  }
74154
+ function sanitizeMathMl(markup) {
74155
+ const purify = DOMPurify__default.default;
74156
+ if (typeof purify.sanitize !== "function") {
74157
+ return markup;
74158
+ }
74159
+ return purify.sanitize(markup, { USE_PROFILES: { mathMl: true, svg: true } });
74160
+ }
74103
74161
  function renderScriptAwareText(text2, needsScriptFonts, scriptFonts, baseFontFamily, keyPrefix) {
74104
74162
  if (!needsScriptFonts || !text2) {
74105
74163
  return text2;
@@ -74190,14 +74248,15 @@ function renderSegmentContent(elementId, segmentIndex, textValue, lines, needsSc
74190
74248
  }
74191
74249
  function renderEquationSegment(elementId, segmentIndex, equationXml, equationNumber) {
74192
74250
  const mathml = convertOmmlToMathMl(equationXml);
74193
- const equationContent = mathml ? /* @__PURE__ */ jsxRuntime.jsx(
74251
+ const safeMathml = mathml ? sanitizeMathMl(mathml) : "";
74252
+ const equationContent = safeMathml ? /* @__PURE__ */ jsxRuntime.jsx(
74194
74253
  "span",
74195
74254
  {
74196
74255
  className: "inline-block align-middle",
74197
74256
  style: {
74198
74257
  fontFamily: '"Cambria Math", "STIX Two Math", serif'
74199
74258
  },
74200
- dangerouslySetInnerHTML: { __html: mathml }
74259
+ dangerouslySetInnerHTML: { __html: safeMathml }
74201
74260
  }
74202
74261
  ) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-block px-1 py-0.5 rounded text-xs bg-gray-200/20 text-gray-400 italic", children: "Equation" });
74203
74262
  if (equationNumber) {
@@ -74798,6 +74857,11 @@ function getShapeClipPath(shapeType, adjustments, width, height) {
74798
74857
  }
74799
74858
  const normalized = shapeType.toLowerCase();
74800
74859
  if (normalized === "round1rect" || normalized === "round2samerect" || normalized === "round2diagrect" || normalized === "sniproundrect" || normalized === "snip1rect" || normalized === "snip2diagrect") {
74860
+ if (adjustments?.adj !== void 0 && width && height) {
74861
+ const ratio = Math.min(Math.max(adjustments.adj / 1e5, 0), 0.5);
74862
+ const radiusPx = Math.round(Math.min(width, height) * ratio);
74863
+ return `inset(0 round ${radiusPx}px)`;
74864
+ }
74801
74865
  return "inset(0 round 18px)";
74802
74866
  }
74803
74867
  if (normalized === "can" || normalized === "cylinder") {
@@ -75444,6 +75508,128 @@ function mapDagBlendModeToCss(blend) {
75444
75508
  return void 0;
75445
75509
  }
75446
75510
  }
75511
+ function getImageAlphaFilterId(elementId) {
75512
+ return `imgalpha-${elementId}`;
75513
+ }
75514
+ function hasAdvancedImageAlphaEffects(element2) {
75515
+ if (!pptxViewerCore.isImageLikeElement(element2)) {
75516
+ return false;
75517
+ }
75518
+ const e2 = element2.imageEffects;
75519
+ if (!e2) {
75520
+ return false;
75521
+ }
75522
+ return Boolean(
75523
+ typeof e2.alphaModFix === "number" || e2.alphaInv || e2.alphaCeiling || e2.alphaFloor || typeof e2.alphaRepl === "number" || typeof e2.alphaBiLevel === "number" || typeof e2.biLevel === "number" || e2.lum && (typeof e2.lum.bright === "number" || typeof e2.lum.contrast === "number") || e2.hsl && (typeof e2.hsl.sat === "number" || typeof e2.hsl.lum === "number") || e2.tint && typeof e2.tint.amt === "number" || e2.clrRepl
75524
+ );
75525
+ }
75526
+ function renderImageAlphaSvgFilter(element2) {
75527
+ if (!pptxViewerCore.isImageLikeElement(element2)) {
75528
+ return null;
75529
+ }
75530
+ const e2 = element2.imageEffects;
75531
+ if (!e2 || !hasAdvancedImageAlphaEffects(element2)) {
75532
+ return null;
75533
+ }
75534
+ const filterId = getImageAlphaFilterId(element2.id);
75535
+ const primitives = [];
75536
+ let resultIdx = 0;
75537
+ let inputRef = "SourceGraphic";
75538
+ const next = (jsx229) => {
75539
+ const result = `r${resultIdx++}`;
75540
+ primitives.push(jsx229(inputRef, result));
75541
+ inputRef = result;
75542
+ };
75543
+ if (typeof e2.alphaModFix === "number") {
75544
+ const mul = clamp(e2.alphaModFix / 100, 0, 1);
75545
+ next((inp, out) => /* @__PURE__ */ jsxRuntime.jsx(
75546
+ "feColorMatrix",
75547
+ {
75548
+ in: inp,
75549
+ result: out,
75550
+ type: "matrix",
75551
+ values: `1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 ${mul} 0`
75552
+ },
75553
+ out
75554
+ ));
75555
+ }
75556
+ if (e2.alphaInv) {
75557
+ next((inp, out) => /* @__PURE__ */ jsxRuntime.jsx("feComponentTransfer", { in: inp, result: out, children: /* @__PURE__ */ jsxRuntime.jsx("feFuncA", { type: "linear", slope: -1, intercept: 1 }) }, out));
75558
+ }
75559
+ if (e2.alphaCeiling) {
75560
+ next((inp, out) => /* @__PURE__ */ jsxRuntime.jsx("feComponentTransfer", { in: inp, result: out, children: /* @__PURE__ */ jsxRuntime.jsx("feFuncA", { type: "discrete", tableValues: "0 1 1 1 1 1 1 1 1 1" }) }, out));
75561
+ }
75562
+ if (e2.alphaFloor) {
75563
+ next((inp, out) => /* @__PURE__ */ jsxRuntime.jsx("feComponentTransfer", { in: inp, result: out, children: /* @__PURE__ */ jsxRuntime.jsx("feFuncA", { type: "discrete", tableValues: "0 0 0 0 0 0 0 0 0 1" }) }, out));
75564
+ }
75565
+ if (typeof e2.alphaRepl === "number") {
75566
+ const a2 = clamp(e2.alphaRepl / 100, 0, 1);
75567
+ next((inp, out) => /* @__PURE__ */ jsxRuntime.jsx("feComponentTransfer", { in: inp, result: out, children: /* @__PURE__ */ jsxRuntime.jsx("feFuncA", { type: "linear", slope: 0, intercept: a2 }) }, out));
75568
+ }
75569
+ if (typeof e2.alphaBiLevel === "number") {
75570
+ const t2 = clamp(e2.alphaBiLevel / 100, 0, 1);
75571
+ const table = Array.from({ length: 10 }, (_, i3) => i3 / 10 >= t2 ? "1" : "0").join(" ");
75572
+ next((inp, out) => /* @__PURE__ */ jsxRuntime.jsx("feComponentTransfer", { in: inp, result: out, children: /* @__PURE__ */ jsxRuntime.jsx("feFuncA", { type: "discrete", tableValues: table }) }, out));
75573
+ }
75574
+ if (typeof e2.biLevel === "number") {
75575
+ next((inp, out) => /* @__PURE__ */ jsxRuntime.jsx("feColorMatrix", { in: inp, result: out, type: "saturate", values: "0" }, out));
75576
+ const t2 = clamp(e2.biLevel / 100, 0, 1);
75577
+ const tbl = t2 < 0.5 ? "0 1" : "0 1";
75578
+ next((inp, out) => /* @__PURE__ */ jsxRuntime.jsxs("feComponentTransfer", { in: inp, result: out, children: [
75579
+ /* @__PURE__ */ jsxRuntime.jsx("feFuncR", { type: "discrete", tableValues: tbl }),
75580
+ /* @__PURE__ */ jsxRuntime.jsx("feFuncG", { type: "discrete", tableValues: tbl }),
75581
+ /* @__PURE__ */ jsxRuntime.jsx("feFuncB", { type: "discrete", tableValues: tbl })
75582
+ ] }, out));
75583
+ }
75584
+ if (e2.lum && (typeof e2.lum.bright === "number" || typeof e2.lum.contrast === "number")) {
75585
+ const b2 = (e2.lum.bright ?? 0) / 100;
75586
+ const c2 = 1 + (e2.lum.contrast ?? 0) / 100;
75587
+ const slope = c2;
75588
+ const intercept = b2 + (1 - c2) / 2;
75589
+ next((inp, out) => /* @__PURE__ */ jsxRuntime.jsxs("feComponentTransfer", { in: inp, result: out, children: [
75590
+ /* @__PURE__ */ jsxRuntime.jsx("feFuncR", { type: "linear", slope, intercept }),
75591
+ /* @__PURE__ */ jsxRuntime.jsx("feFuncG", { type: "linear", slope, intercept }),
75592
+ /* @__PURE__ */ jsxRuntime.jsx("feFuncB", { type: "linear", slope, intercept })
75593
+ ] }, out));
75594
+ }
75595
+ if (e2.hsl && typeof e2.hsl.sat === "number") {
75596
+ const v = clamp(1 + e2.hsl.sat / 100, 0, 2);
75597
+ next((inp, out) => /* @__PURE__ */ jsxRuntime.jsx("feColorMatrix", { in: inp, result: out, type: "saturate", values: String(v) }, out));
75598
+ }
75599
+ if (e2.tint && typeof e2.tint.amt === "number" && e2.tint.amt < 0) {
75600
+ const v = clamp(1 + e2.tint.amt / 100, 0, 1);
75601
+ next((inp, out) => /* @__PURE__ */ jsxRuntime.jsx("feColorMatrix", { in: inp, result: out, type: "saturate", values: String(v) }, out));
75602
+ }
75603
+ if (e2.clrRepl) {
75604
+ const c2 = hexToRgbUnit(e2.clrRepl.color);
75605
+ next((inp, out) => /* @__PURE__ */ jsxRuntime.jsx(
75606
+ "feColorMatrix",
75607
+ {
75608
+ in: inp,
75609
+ result: out,
75610
+ type: "matrix",
75611
+ values: `0 0 0 0 ${c2.r} 0 0 0 0 ${c2.g} 0 0 0 0 ${c2.b} 0 0 0 1 0`
75612
+ },
75613
+ out
75614
+ ));
75615
+ }
75616
+ if (primitives.length === 0) {
75617
+ return null;
75618
+ }
75619
+ return /* @__PURE__ */ jsxRuntime.jsx(
75620
+ "svg",
75621
+ {
75622
+ width: 0,
75623
+ height: 0,
75624
+ style: { position: "absolute", overflow: "hidden" },
75625
+ "aria-hidden": "true",
75626
+ children: /* @__PURE__ */ jsxRuntime.jsx("defs", { children: /* @__PURE__ */ jsxRuntime.jsx("filter", { id: filterId, colorInterpolationFilters: "sRGB", children: primitives }) })
75627
+ }
75628
+ );
75629
+ }
75630
+ function clamp(v, lo, hi) {
75631
+ return v < lo ? lo : v > hi ? hi : v;
75632
+ }
75447
75633
  function getDagDuotoneFilterId(elementId) {
75448
75634
  return `dag-duotone-${elementId}`;
75449
75635
  }
@@ -75527,6 +75713,9 @@ function getImageEffectsFilter(element2, options) {
75527
75713
  const filterId = getDuotoneFilterId(element2.id);
75528
75714
  filters.push(`url(#${filterId})`);
75529
75715
  }
75716
+ if (hasAdvancedImageAlphaEffects(element2)) {
75717
+ filters.push(`url(#${getImageAlphaFilterId(element2.id)})`);
75718
+ }
75530
75719
  if (effects.artisticEffect) {
75531
75720
  const radius = effects.artisticRadius ?? 5;
75532
75721
  if (needsSvgArtisticFilter(effects.artisticEffect)) {
@@ -75700,6 +75889,39 @@ function getEffectDagCssFilter(style, elementId) {
75700
75889
  return filters.length > 0 ? filters.join(" ") : void 0;
75701
75890
  }
75702
75891
  var getEffectDagFilter = getEffectDagCssFilter;
75892
+ function getResolvedShapeClipPathFor(shapeType, width, height, adjustments) {
75893
+ if (!shapeType) {
75894
+ return void 0;
75895
+ }
75896
+ if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {
75897
+ return getShapeClipPath(shapeType, adjustments, width, height);
75898
+ }
75899
+ if (adjustments && Object.keys(adjustments).length > 0) {
75900
+ const adjusted = pptxViewerCore.getAdjustmentAwareShapeClipPath(shapeType, width, height, adjustments);
75901
+ if (adjusted !== void 0) {
75902
+ return adjusted;
75903
+ }
75904
+ }
75905
+ const fromPreset = pptxViewerCore.getShapeClipPathFromPreset(shapeType, width, height, adjustments);
75906
+ if (fromPreset !== void 0) {
75907
+ return fromPreset;
75908
+ }
75909
+ const cloud = pptxViewerCore.getCloudPathForRendering(shapeType, width, height);
75910
+ if (cloud !== void 0) {
75911
+ return cloud;
75912
+ }
75913
+ return getShapeClipPath(shapeType, adjustments, width, height);
75914
+ }
75915
+ function getResolvedShapeClipPath(element2, width, height) {
75916
+ const shapeType = element2.shapeType;
75917
+ if (!shapeType) {
75918
+ return void 0;
75919
+ }
75920
+ const w = element2.width;
75921
+ const h2 = element2.height;
75922
+ const adjustments = element2.shapeAdjustments;
75923
+ return getResolvedShapeClipPathFor(shapeType, w, h2, adjustments);
75924
+ }
75703
75925
 
75704
75926
  // src/viewer/utils/shape-round-rect.ts
75705
75927
  function localClampAdjustment(value) {
@@ -75771,6 +75993,27 @@ var MATERIAL_MAP = {
75771
75993
  filter: "brightness(1.1) contrast(0.85)",
75772
75994
  // Translucent powder: slight translucent glow
75773
75995
  backgroundImage: "radial-gradient(ellipse at 30% 30%, rgba(255,255,255,0.1) 0%, transparent 60%)"
75996
+ },
75997
+ // Legacy materials (PowerPoint 2007 / earlier). Render as muted variants
75998
+ // of the modern equivalents so legacy decks still resemble the originals.
75999
+ legacyMatte: {
76000
+ filter: "brightness(0.92) saturate(0.85)",
76001
+ backgroundImage: "linear-gradient(180deg, rgba(255,255,255,0.03) 0%, transparent 50%, rgba(0,0,0,0.04) 100%)"
76002
+ },
76003
+ legacyPlastic: {
76004
+ filter: "brightness(1.02) contrast(1.03)",
76005
+ boxShadow: "inset -2px -2px 5px rgba(255,255,255,0.3)",
76006
+ backgroundImage: "radial-gradient(ellipse 35% 25% at 25% 20%, rgba(255,255,255,0.15) 0%, transparent 70%)"
76007
+ },
76008
+ legacyMetal: {
76009
+ filter: "brightness(1.05) contrast(1.1) saturate(1.1)",
76010
+ boxShadow: "inset -2px -2px 6px rgba(255,255,255,0.35), inset 1px 1px 3px rgba(255,255,255,0.15)",
76011
+ backgroundImage: "linear-gradient(135deg, rgba(255,255,255,0.18) 0%, rgba(255,255,255,0.06) 25%, transparent 50%, rgba(0,0,0,0.05) 80%)"
76012
+ },
76013
+ legacyWireframe: {
76014
+ filter: "brightness(1) contrast(1.4) saturate(0.6)",
76015
+ // Wireframe: high contrast outline-emphasising look
76016
+ boxShadow: "inset 0 0 0 1px rgba(0,0,0,0.4)"
75774
76017
  }
75775
76018
  };
75776
76019
  function getMaterialCssOverrides(material) {
@@ -76725,8 +76968,7 @@ function getShapeVisualStyle(element2, hasFill, fillColor, strokeWidth, strokeCo
76725
76968
  return {};
76726
76969
  }
76727
76970
  const normalizedShapeType = getShapeType(element2.shapeType);
76728
- const shapeType = element2.shapeType || normalizedShapeType;
76729
- const clipPath = getShapeClipPath(shapeType);
76971
+ const clipPath = getResolvedShapeClipPath(element2);
76730
76972
  const fillOpacity = element2.shapeStyle?.fillOpacity;
76731
76973
  const strokeOpacity = element2.shapeStyle?.strokeOpacity;
76732
76974
  const strokeDash = normalizeStrokeDashType(element2.shapeStyle?.strokeDash);
@@ -77328,7 +77570,7 @@ function getImageMaskStyle(element2) {
77328
77570
  if (normalized === "can" || normalized === "cylinder") {
77329
77571
  return { borderRadius: "48% / 12%" };
77330
77572
  }
77331
- const clipPath = getShapeClipPath(shapeType);
77573
+ const clipPath = getResolvedShapeClipPath(element2);
77332
77574
  if (!clipPath) {
77333
77575
  return void 0;
77334
77576
  }
@@ -77991,8 +78233,8 @@ function hexToRgb3(hex) {
77991
78233
  };
77992
78234
  }
77993
78235
  function rgbToHex2(r2, g2, b2) {
77994
- const clamp2 = (v) => Math.max(0, Math.min(255, Math.round(v)));
77995
- return `#${clamp2(r2).toString(16).padStart(2, "0").toUpperCase()}${clamp2(g2).toString(16).padStart(2, "0").toUpperCase()}${clamp2(b2).toString(16).padStart(2, "0").toUpperCase()}`;
78236
+ const clamp3 = (v) => Math.max(0, Math.min(255, Math.round(v)));
78237
+ return `#${clamp3(r2).toString(16).padStart(2, "0").toUpperCase()}${clamp3(g2).toString(16).padStart(2, "0").toUpperCase()}${clamp3(b2).toString(16).padStart(2, "0").toUpperCase()}`;
77996
78238
  }
77997
78239
  function tintColor(hex, tintFactor) {
77998
78240
  const { r: r2, g: g2, b: b2 } = hexToRgb3(hex);
@@ -78923,13 +79165,13 @@ function cellStyleToCss(style) {
78923
79165
  }
78924
79166
  if (style.textDirection) {
78925
79167
  switch (style.textDirection) {
78926
- case "vertical":
79168
+ case "vert":
78927
79169
  case "eaVert":
78928
79170
  case "wordArtVert":
78929
79171
  case "wordArtVertRtl":
78930
79172
  css.writingMode = "vertical-rl";
78931
79173
  break;
78932
- case "vertical270":
79174
+ case "vert270":
78933
79175
  case "mongolianVert":
78934
79176
  css.writingMode = "vertical-lr";
78935
79177
  break;
@@ -79456,8 +79698,8 @@ function hexToRgb4(hex) {
79456
79698
  ];
79457
79699
  }
79458
79700
  function rgbToHex3(r2, g2, b2) {
79459
- const clamp2 = (v) => Math.max(0, Math.min(255, Math.round(v)));
79460
- return `#${clamp2(r2).toString(16).padStart(2, "0")}${clamp2(g2).toString(16).padStart(2, "0")}${clamp2(b2).toString(16).padStart(2, "0")}`;
79701
+ const clamp3 = (v) => Math.max(0, Math.min(255, Math.round(v)));
79702
+ return `#${clamp3(r2).toString(16).padStart(2, "0")}${clamp3(g2).toString(16).padStart(2, "0")}${clamp3(b2).toString(16).padStart(2, "0")}`;
79461
79703
  }
79462
79704
  function tint(hex, amount) {
79463
79705
  const [r2, g2, b2] = hexToRgb4(hex);
@@ -81375,7 +81617,7 @@ function resolveRegionCode(label) {
81375
81617
  return REGION_ALIAS_MAP[normalized];
81376
81618
  }
81377
81619
  function lerpColor(a2, b2, t2) {
81378
- const clamp2 = (v) => Math.max(0, Math.min(255, Math.round(v)));
81620
+ const clamp3 = (v) => Math.max(0, Math.min(255, Math.round(v)));
81379
81621
  const parse = (hex) => {
81380
81622
  const h2 = hex.replace("#", "");
81381
81623
  return [
@@ -81386,9 +81628,9 @@ function lerpColor(a2, b2, t2) {
81386
81628
  };
81387
81629
  const [r1, g1, b1] = parse(a2);
81388
81630
  const [r2, g2, b22] = parse(b2);
81389
- const r3 = clamp2(r1 + (r2 - r1) * t2);
81390
- const g3 = clamp2(g1 + (g2 - g1) * t2);
81391
- const bl = clamp2(b1 + (b22 - b1) * t2);
81631
+ const r3 = clamp3(r1 + (r2 - r1) * t2);
81632
+ const g3 = clamp3(g1 + (g2 - g1) * t2);
81633
+ const bl = clamp3(b1 + (b22 - b1) * t2);
81392
81634
  return `#${r3.toString(16).padStart(2, "0")}${g3.toString(16).padStart(2, "0")}${bl.toString(16).padStart(2, "0")}`;
81393
81635
  }
81394
81636
  function sequentialColorScale(t2) {
@@ -86554,7 +86796,7 @@ function ResizeHandle({
86554
86796
  }
86555
86797
  );
86556
86798
  }
86557
- function SlideThumbnail({
86799
+ function SlideThumbnailImpl({
86558
86800
  slide,
86559
86801
  templateElements,
86560
86802
  canvasSize
@@ -86792,6 +87034,37 @@ function ThumbnailTable({
86792
87034
  }
86793
87035
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center text-[10px] text-muted-foreground pointer-events-none", children: "Table" });
86794
87036
  }
87037
+ function arePropsEqual(prev, next) {
87038
+ if (prev.slide.id !== next.slide.id) {
87039
+ return false;
87040
+ }
87041
+ if (prev.slide.isDirty !== next.slide.isDirty) {
87042
+ return false;
87043
+ }
87044
+ if (prev.slide.hidden !== next.slide.hidden) {
87045
+ return false;
87046
+ }
87047
+ if (prev.slide.elements !== next.slide.elements) {
87048
+ return false;
87049
+ }
87050
+ if (prev.slide.backgroundColor !== next.slide.backgroundColor) {
87051
+ return false;
87052
+ }
87053
+ if (prev.slide.backgroundImage !== next.slide.backgroundImage) {
87054
+ return false;
87055
+ }
87056
+ if (prev.slide.backgroundGradient !== next.slide.backgroundGradient) {
87057
+ return false;
87058
+ }
87059
+ if (prev.templateElements !== next.templateElements) {
87060
+ return false;
87061
+ }
87062
+ if (prev.canvasSize.width !== next.canvasSize.width || prev.canvasSize.height !== next.canvasSize.height) {
87063
+ return false;
87064
+ }
87065
+ return true;
87066
+ }
87067
+ var SlideThumbnail = React10__namespace.default.memo(SlideThumbnailImpl, arePropsEqual);
86795
87068
  function ContextMenu({
86796
87069
  contextMenuState,
86797
87070
  mode,
@@ -88109,6 +88382,59 @@ function WarpedText({
88109
88382
  }
88110
88383
  );
88111
88384
  }
88385
+ var GLYPH_BY_SHAPE = Object.fromEntries(
88386
+ ACTION_BUTTON_PRESETS.map((p3) => [p3.shapeType, p3.iconPath])
88387
+ );
88388
+ GLYPH_BY_SHAPE["actionButtonForwardOrNext"] = GLYPH_BY_SHAPE["actionButtonForwardNext"];
88389
+ GLYPH_BY_SHAPE["actionButtonBackOrPrevious"] = GLYPH_BY_SHAPE["actionButtonBackPrevious"];
88390
+ function isActionButtonShape(shapeType) {
88391
+ return Boolean(shapeType && shapeType in GLYPH_BY_SHAPE);
88392
+ }
88393
+ function getActionButtonGlyphPath(shapeType) {
88394
+ if (!shapeType) {
88395
+ return void 0;
88396
+ }
88397
+ const path = GLYPH_BY_SHAPE[shapeType];
88398
+ return path && path.length > 0 ? path : void 0;
88399
+ }
88400
+ function ActionButtonGlyphOverlay({
88401
+ element: element2,
88402
+ color
88403
+ }) {
88404
+ const shapeType = "shapeType" in element2 ? element2.shapeType : void 0;
88405
+ const path = getActionButtonGlyphPath(shapeType);
88406
+ if (!path) {
88407
+ return null;
88408
+ }
88409
+ const stroke = color ?? ("textStyle" in element2 && element2.textStyle?.color || "#ffffff");
88410
+ return /* @__PURE__ */ jsxRuntime.jsx(
88411
+ "svg",
88412
+ {
88413
+ viewBox: "0 0 24 24",
88414
+ width: "100%",
88415
+ height: "100%",
88416
+ preserveAspectRatio: "xMidYMid meet",
88417
+ style: {
88418
+ position: "absolute",
88419
+ inset: 0,
88420
+ pointerEvents: "none",
88421
+ padding: "20%"
88422
+ },
88423
+ "aria-hidden": "true",
88424
+ children: /* @__PURE__ */ jsxRuntime.jsx(
88425
+ "path",
88426
+ {
88427
+ d: path,
88428
+ fill: "none",
88429
+ stroke,
88430
+ strokeWidth: 2,
88431
+ strokeLinecap: "round",
88432
+ strokeLinejoin: "round"
88433
+ }
88434
+ )
88435
+ }
88436
+ );
88437
+ }
88112
88438
  function ColorChangedImage({
88113
88439
  src,
88114
88440
  clrChange,
@@ -88379,6 +88705,7 @@ function renderImg(el, style, filter, alt, opacity) {
88379
88705
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
88380
88706
  tileDuotoneColors && renderDuotoneSvgFilter(el.id, tileDuotoneColors.color1, tileDuotoneColors.color2),
88381
88707
  renderArtisticEffectSvgFilter(el.id, artisticEffectName, artisticRadius),
88708
+ renderImageAlphaSvgFilter(el),
88382
88709
  /* @__PURE__ */ jsxRuntime.jsx(
88383
88710
  "div",
88384
88711
  {
@@ -88400,6 +88727,7 @@ function renderImg(el, style, filter, alt, opacity) {
88400
88727
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
88401
88728
  duotoneColors && !useDuotoneCanvas && renderDuotoneSvgFilter(el.id, duotoneColors.color1, duotoneColors.color2),
88402
88729
  renderArtisticEffectSvgFilter(el.id, artisticEffectName, artisticRadius),
88730
+ renderImageAlphaSvgFilter(el),
88403
88731
  useDuotoneCanvas && duotoneColors ? /* @__PURE__ */ jsxRuntime.jsx(
88404
88732
  DuotoneImage,
88405
88733
  {
@@ -90525,7 +90853,7 @@ function BendingProcessRenderer({
90525
90853
  }
90526
90854
  );
90527
90855
  }
90528
- function SmartArtRenderer({
90856
+ function SmartArtRendererImpl({
90529
90857
  element: element2,
90530
90858
  className = ""
90531
90859
  }) {
@@ -90636,6 +90964,30 @@ function renderLayout(layoutType, element2, nodes, palette, style) {
90636
90964
  }
90637
90965
  return /* @__PURE__ */ jsxRuntime.jsx(ListRenderer, { element: element2, nodes, palette, style });
90638
90966
  }
90967
+ function arePropsEqual2(prev, next) {
90968
+ if (prev.className !== next.className) {
90969
+ return false;
90970
+ }
90971
+ if (prev.element.id !== next.element.id) {
90972
+ return false;
90973
+ }
90974
+ if (prev.element.type !== next.element.type) {
90975
+ return false;
90976
+ }
90977
+ if (prev.element.width !== next.element.width || prev.element.height !== next.element.height) {
90978
+ return false;
90979
+ }
90980
+ if (prev.element.x !== next.element.x || prev.element.y !== next.element.y) {
90981
+ return false;
90982
+ }
90983
+ const prevData = prev.element.type === "smartArt" ? prev.element.smartArtData : void 0;
90984
+ const nextData = next.element.type === "smartArt" ? next.element.smartArtData : void 0;
90985
+ if (prevData !== nextData) {
90986
+ return false;
90987
+ }
90988
+ return true;
90989
+ }
90990
+ var SmartArtRenderer = React10__namespace.default.memo(SmartArtRendererImpl, arePropsEqual2);
90639
90991
  function ZoomElementRenderer({
90640
90992
  element: element2,
90641
90993
  slides,
@@ -90884,8 +91236,11 @@ function renderBody(el, isImg, isEditing, editText, spellCheck, txtSE, txtS, vec
90884
91236
  ...scene3dStyle.perspective ? { perspective: scene3dStyle.perspective } : {},
90885
91237
  ...scene3dStyle.transformStyle ? { transformStyle: scene3dStyle.transformStyle } : {}
90886
91238
  } : void 0;
91239
+ const shapeTypeForGlyph = "shapeType" in el ? el.shapeType : void 0;
91240
+ const showActionButtonGlyph = isActionButtonShape(shapeTypeForGlyph);
90887
91241
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
90888
91242
  vecShape,
91243
+ showActionButtonGlyph && /* @__PURE__ */ jsxRuntime.jsx(ActionButtonGlyphOverlay, { element: el }),
90889
91244
  isTxtEl ? useSvgWarp ? /* @__PURE__ */ jsxRuntime.jsx(
90890
91245
  "div",
90891
91246
  {
@@ -93579,7 +93934,7 @@ function SectionBlock({
93579
93934
  )
93580
93935
  ] });
93581
93936
  }
93582
- function SlideCard({
93937
+ function SlideCardImpl({
93583
93938
  slide,
93584
93939
  index,
93585
93940
  isActive,
@@ -93633,6 +93988,49 @@ function SlideCard({
93633
93988
  }
93634
93989
  );
93635
93990
  }
93991
+ function arePropsEqual3(prev, next) {
93992
+ if (prev.slide.id !== next.slide.id) {
93993
+ return false;
93994
+ }
93995
+ if (prev.slide.isDirty !== next.slide.isDirty) {
93996
+ return false;
93997
+ }
93998
+ if (prev.slide.hidden !== next.slide.hidden) {
93999
+ return false;
94000
+ }
94001
+ if (prev.slide.elements !== next.slide.elements) {
94002
+ return false;
94003
+ }
94004
+ if (prev.index !== next.index) {
94005
+ return false;
94006
+ }
94007
+ if (prev.isActive !== next.isActive) {
94008
+ return false;
94009
+ }
94010
+ if (prev.isDragTarget !== next.isDragTarget) {
94011
+ return false;
94012
+ }
94013
+ if (prev.isSelected !== next.isSelected) {
94014
+ return false;
94015
+ }
94016
+ if (prev.selectedCount !== next.selectedCount) {
94017
+ return false;
94018
+ }
94019
+ if (prev.selectionOrder !== next.selectionOrder) {
94020
+ return false;
94021
+ }
94022
+ if (prev.canEdit !== next.canEdit) {
94023
+ return false;
94024
+ }
94025
+ if (prev.canvasSize.width !== next.canvasSize.width || prev.canvasSize.height !== next.canvasSize.height) {
94026
+ return false;
94027
+ }
94028
+ if (prev.onSlideClick !== next.onSlideClick || prev.onDoubleClick !== next.onDoubleClick || prev.onContextMenu !== next.onContextMenu || prev.onDragStart !== next.onDragStart || prev.onDragOver !== next.onDragOver || prev.onDragLeave !== next.onDragLeave || prev.onDrop !== next.onDrop) {
94029
+ return false;
94030
+ }
94031
+ return true;
94032
+ }
94033
+ var SlideCard = React10__namespace.default.memo(SlideCardImpl, arePropsEqual3);
93636
94034
  function SorterContextMenu({
93637
94035
  x: x2,
93638
94036
  y,
@@ -94426,6 +94824,14 @@ function getCurrentParagraphIndex(editorEl, segments) {
94426
94824
  }
94427
94825
  return paraIdx;
94428
94826
  }
94827
+ var CSS_VALUE_SAFE = /^[a-zA-Z0-9 _,.\-+#'%/]{1,100}$/;
94828
+ function isCssValueSafe(value) {
94829
+ if (value === void 0 || value === null) {
94830
+ return false;
94831
+ }
94832
+ const str = String(value);
94833
+ return str.length > 0 && CSS_VALUE_SAFE.test(str);
94834
+ }
94429
94835
  function deriveStyleFromElement(element2, inheritedStyle) {
94430
94836
  const style = { ...inheritedStyle };
94431
94837
  const tagName = element2.tagName.toLowerCase();
@@ -94558,17 +94964,17 @@ function segmentsToEditorHtml(segments) {
94558
94964
  if (segment.style.strikethrough) {
94559
94965
  inlineStyles.push("text-decoration:line-through");
94560
94966
  }
94561
- if (segment.style.color) {
94967
+ if (segment.style.color && isCssValueSafe(segment.style.color)) {
94562
94968
  inlineStyles.push(`color:${segment.style.color}`);
94563
94969
  }
94564
- if (segment.style.fontSize) {
94565
- inlineStyles.push(`font-size:${segment.style.fontSize}pt`);
94970
+ if (segment.style.fontSize && Number.isFinite(Number(segment.style.fontSize))) {
94971
+ inlineStyles.push(`font-size:${Number(segment.style.fontSize)}pt`);
94566
94972
  }
94567
- if (segment.style.fontFamily) {
94973
+ if (segment.style.fontFamily && isCssValueSafe(segment.style.fontFamily)) {
94568
94974
  inlineStyles.push(`font-family:${segment.style.fontFamily}`);
94569
94975
  }
94570
94976
  const text2 = escapeHtml(segment.text);
94571
- if (segment.style.hyperlink) {
94977
+ if (segment.style.hyperlink && isUrlSafe(segment.style.hyperlink)) {
94572
94978
  const href = escapeHtml(segment.style.hyperlink);
94573
94979
  return `<a href="${href}" style="color:#4a9eff;text-decoration:underline;cursor:pointer" data-hyperlink="${href}">${text2}</a>`;
94574
94980
  }
@@ -94651,7 +95057,8 @@ function renderRichNotesSegments(segments) {
94651
95057
  if (segment.style.fontFamily) {
94652
95058
  style.fontFamily = segment.style.fontFamily;
94653
95059
  }
94654
- if (segment.style.hyperlink) {
95060
+ if (segment.style.hyperlink && isUrlSafe(segment.style.hyperlink)) {
95061
+ const safeHref = segment.style.hyperlink;
94655
95062
  style.color = "#4a9eff";
94656
95063
  style.textDecoration = "underline";
94657
95064
  style.cursor = "pointer";
@@ -94659,11 +95066,11 @@ function renderRichNotesSegments(segments) {
94659
95066
  /* @__PURE__ */ jsxRuntime.jsx(
94660
95067
  "a",
94661
95068
  {
94662
- href: segment.style.hyperlink,
95069
+ href: safeHref,
94663
95070
  style,
94664
95071
  onClick: (e2) => {
94665
95072
  e2.preventDefault();
94666
- window.open(segment.style.hyperlink, "_blank");
95073
+ safeOpenUrl(safeHref);
94667
95074
  },
94668
95075
  children: segment.text
94669
95076
  },
@@ -95215,7 +95622,7 @@ function useSlideNotes({
95215
95622
  const href = target.getAttribute("data-hyperlink") || target.getAttribute("href");
95216
95623
  if (href && (e2.ctrlKey || e2.metaKey)) {
95217
95624
  e2.preventDefault();
95218
- window.open(href, "_blank");
95625
+ safeOpenUrl(href);
95219
95626
  }
95220
95627
  }, []);
95221
95628
  return {
@@ -96888,7 +97295,7 @@ function renderNotesSegments(segments) {
96888
97295
  return React10__namespace.default.createElement("span", { key: `seg-${index}`, style }, segment.text);
96889
97296
  });
96890
97297
  }
96891
- function ScaledSlidePreview({
97298
+ function ScaledSlidePreviewImpl({
96892
97299
  slide,
96893
97300
  templateElements,
96894
97301
  canvasSize,
@@ -97035,6 +97442,40 @@ function ScaledSlidePreview({
97035
97442
  }
97036
97443
  );
97037
97444
  }
97445
+ function arePropsEqual4(prev, next) {
97446
+ if (prev.slide.id !== next.slide.id) {
97447
+ return false;
97448
+ }
97449
+ if (prev.slide.isDirty !== next.slide.isDirty) {
97450
+ return false;
97451
+ }
97452
+ if (prev.slide.hidden !== next.slide.hidden) {
97453
+ return false;
97454
+ }
97455
+ if (prev.slide.elements !== next.slide.elements) {
97456
+ return false;
97457
+ }
97458
+ if (prev.slide.backgroundColor !== next.slide.backgroundColor) {
97459
+ return false;
97460
+ }
97461
+ if (prev.slide.backgroundImage !== next.slide.backgroundImage) {
97462
+ return false;
97463
+ }
97464
+ if (prev.slide.backgroundGradient !== next.slide.backgroundGradient) {
97465
+ return false;
97466
+ }
97467
+ if (prev.templateElements !== next.templateElements) {
97468
+ return false;
97469
+ }
97470
+ if (prev.canvasSize.width !== next.canvasSize.width || prev.canvasSize.height !== next.canvasSize.height) {
97471
+ return false;
97472
+ }
97473
+ if (prev.className !== next.className) {
97474
+ return false;
97475
+ }
97476
+ return true;
97477
+ }
97478
+ var ScaledSlidePreview = React10__namespace.default.memo(ScaledSlidePreviewImpl, arePropsEqual4);
97038
97479
  function PresenterView({
97039
97480
  slides,
97040
97481
  currentSlideIndex,
@@ -111338,6 +111779,13 @@ function convertOmmlToLatex(omml) {
111338
111779
  }
111339
111780
  return ommlChildrenToLatex(oMath);
111340
111781
  }
111782
+ function sanitizeMathMl2(markup) {
111783
+ const purify = DOMPurify__default.default;
111784
+ if (typeof purify.sanitize !== "function") {
111785
+ return markup;
111786
+ }
111787
+ return purify.sanitize(markup, { USE_PROFILES: { mathMl: true, svg: true } });
111788
+ }
111341
111789
  var TEMPLATES = [
111342
111790
  {
111343
111791
  label: "Fraction",
@@ -111403,7 +111851,8 @@ var TEMPLATES = [
111403
111851
  var TEMPLATE_MATHML = TEMPLATES.map((tmpl) => {
111404
111852
  try {
111405
111853
  const tmplOmml = convertLatexToOmml(tmpl.latex);
111406
- return convertOmmlToMathMl(tmplOmml);
111854
+ const raw = convertOmmlToMathMl(tmplOmml);
111855
+ return raw ? sanitizeMathMl2(raw) : "";
111407
111856
  } catch {
111408
111857
  return "";
111409
111858
  }
@@ -111415,7 +111864,7 @@ function MathMlPreview({ mathml }) {
111415
111864
  return;
111416
111865
  }
111417
111866
  if (mathml) {
111418
- containerRef.current.innerHTML = mathml;
111867
+ containerRef.current.innerHTML = sanitizeMathMl2(mathml);
111419
111868
  } else {
111420
111869
  containerRef.current.innerHTML = "";
111421
111870
  }
@@ -111443,6 +111892,7 @@ function EquationEditorDialog({
111443
111892
  return convertOmmlToLatex(existingOmml);
111444
111893
  }, [existingOmml]);
111445
111894
  const [latex, setLatex] = React10.useState(initialLatex);
111895
+ const deferredLatex = React10.useDeferredValue(latex);
111446
111896
  const textareaRef = React10.useRef(null);
111447
111897
  React10.useEffect(() => {
111448
111898
  if (isOpen) {
@@ -111451,17 +111901,17 @@ function EquationEditorDialog({
111451
111901
  }
111452
111902
  }, [isOpen, initialLatex]);
111453
111903
  const { mathml, omml } = React10.useMemo(() => {
111454
- if (!latex.trim()) {
111904
+ if (!deferredLatex.trim()) {
111455
111905
  return { mathml: "", omml: {} };
111456
111906
  }
111457
111907
  try {
111458
- const ommlObj = convertLatexToOmml(latex);
111908
+ const ommlObj = convertLatexToOmml(deferredLatex);
111459
111909
  const mathmlStr = convertOmmlToMathMl(ommlObj);
111460
111910
  return { mathml: mathmlStr, omml: ommlObj };
111461
111911
  } catch {
111462
111912
  return { mathml: "", omml: {} };
111463
111913
  }
111464
- }, [latex]);
111914
+ }, [deferredLatex]);
111465
111915
  const handleInsert = React10.useCallback(() => {
111466
111916
  if (!latex.trim()) {
111467
111917
  return;
@@ -114196,6 +114646,7 @@ function useEditorHistory(input) {
114196
114646
  const historyFutureRef = React10.useRef([]);
114197
114647
  const lastHistorySnapshotRef = React10.useRef(null);
114198
114648
  const lastHistorySerializedRef = React10.useRef("");
114649
+ const lastCheapHashRef = React10.useRef("");
114199
114650
  const isApplyingHistoryRef = React10.useRef(false);
114200
114651
  const unlockHistoryTimerRef = React10.useRef(null);
114201
114652
  const [canUndo, setCanUndo] = React10.useState(false);
@@ -114337,15 +114788,21 @@ function useEditorHistory(input) {
114337
114788
  if (hasActivePointerInteraction()) {
114338
114789
  return;
114339
114790
  }
114791
+ const cheapHash = `${slides.length}|${activeSlideIndex}|${canvasSize.width}x${canvasSize.height}|${slides.map((s) => `${s.id}:${s.elements.length}`).join("/")}`;
114792
+ if (cheapHash === lastCheapHashRef.current) {
114793
+ return;
114794
+ }
114340
114795
  const snapshot2 = buildHistorySnapshot();
114341
114796
  const serialized = JSON.stringify(snapshot2);
114342
114797
  if (serialized === lastHistorySerializedRef.current) {
114798
+ lastCheapHashRef.current = cheapHash;
114343
114799
  return;
114344
114800
  }
114345
114801
  const previousSnapshot = lastHistorySnapshotRef.current;
114346
114802
  if (!previousSnapshot) {
114347
114803
  lastHistorySnapshotRef.current = cloneHistorySnapshot(snapshot2);
114348
114804
  lastHistorySerializedRef.current = serialized;
114805
+ lastCheapHashRef.current = cheapHash;
114349
114806
  updateHistoryAvailability();
114350
114807
  return;
114351
114808
  }
@@ -114356,13 +114813,18 @@ function useEditorHistory(input) {
114356
114813
  historyFutureRef.current = [];
114357
114814
  lastHistorySnapshotRef.current = cloneHistorySnapshot(snapshot2);
114358
114815
  lastHistorySerializedRef.current = serialized;
114816
+ lastCheapHashRef.current = cheapHash;
114359
114817
  updateHistoryAvailability();
114360
114818
  }, [
114819
+ activeSlideIndex,
114361
114820
  buildHistorySnapshot,
114821
+ canvasSize.height,
114822
+ canvasSize.width,
114362
114823
  error2,
114363
114824
  hasActivePointerInteraction,
114364
114825
  loading2,
114365
114826
  pointerCommitNonce,
114827
+ slides,
114366
114828
  updateHistoryAvailability
114367
114829
  ]);
114368
114830
  return {
@@ -118074,7 +118536,8 @@ async function storeAudienceContent(content) {
118074
118536
  const tx = db.transaction(STORE_NAME2, "readwrite");
118075
118537
  const store = tx.objectStore(STORE_NAME2);
118076
118538
  const bytes = content instanceof Uint8Array ? content : new Uint8Array(content);
118077
- store.put(bytes, CONTENT_KEY);
118539
+ const record = { bytes, createdAt: Date.now() };
118540
+ store.put(record, CONTENT_KEY);
118078
118541
  tx.oncomplete = () => {
118079
118542
  db.close();
118080
118543
  resolve2();
@@ -118107,14 +118570,34 @@ async function clearAudienceContent() {
118107
118570
  var PRESENTER_CHANNEL_NAME = "pptx-viewer-presenter";
118108
118571
  var AUDIENCE_HASH = "#pptx-audience";
118109
118572
  var PRESENTER_MSG_ORIGIN = "pptx-viewer-presenter";
118573
+ var AUDIENCE_NONCE_KEY = "nonce";
118574
+ function generateSessionId() {
118575
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
118576
+ return crypto.randomUUID();
118577
+ }
118578
+ return `s${Date.now().toString(36)}${Math.random().toString(36).slice(2, 10)}`;
118579
+ }
118580
+ function parseAudienceNonce() {
118581
+ const hash = window.location.hash;
118582
+ if (!hash.startsWith(AUDIENCE_HASH)) {
118583
+ return null;
118584
+ }
118585
+ const trailing = hash.slice(AUDIENCE_HASH.length);
118586
+ if (!trailing) {
118587
+ return null;
118588
+ }
118589
+ const params2 = new URLSearchParams(trailing.replace(/^[&;?]/, ""));
118590
+ return params2.get(AUDIENCE_NONCE_KEY);
118591
+ }
118110
118592
  function isAudienceTab() {
118111
- return window.location.hash === AUDIENCE_HASH;
118593
+ return window.location.hash.startsWith(AUDIENCE_HASH);
118112
118594
  }
118113
118595
  function usePresenterWindow(input) {
118114
118596
  const { currentSlideIndex, isPresenterMode, content } = input;
118115
118597
  const audienceWindowRef = React10.useRef(null);
118116
118598
  const channelRef = React10.useRef(null);
118117
118599
  const pollTimerRef = React10.useRef(null);
118600
+ const sessionIdRef = React10.useRef("");
118118
118601
  const getChannel2 = React10.useCallback(() => {
118119
118602
  if (!channelRef.current) {
118120
118603
  channelRef.current = new BroadcastChannel(PRESENTER_CHANNEL_NAME);
@@ -118126,10 +118609,14 @@ function usePresenterWindow(input) {
118126
118609
  }, []);
118127
118610
  const syncSlideToAudience = React10.useCallback(
118128
118611
  (slideIndex) => {
118612
+ if (!sessionIdRef.current) {
118613
+ return;
118614
+ }
118129
118615
  const msg = {
118130
118616
  origin: PRESENTER_MSG_ORIGIN,
118131
118617
  type: "presenter-slide-change",
118132
- slideIndex
118618
+ slideIndex,
118619
+ sessionId: sessionIdRef.current
118133
118620
  };
118134
118621
  try {
118135
118622
  getChannel2().postMessage(msg);
@@ -118139,13 +118626,16 @@ function usePresenterWindow(input) {
118139
118626
  [getChannel2]
118140
118627
  );
118141
118628
  const closeAudienceWindow = React10.useCallback(() => {
118142
- try {
118143
- const exitMsg = {
118144
- origin: PRESENTER_MSG_ORIGIN,
118145
- type: "presenter-exit"
118146
- };
118147
- getChannel2().postMessage(exitMsg);
118148
- } catch {
118629
+ if (sessionIdRef.current) {
118630
+ try {
118631
+ const exitMsg = {
118632
+ origin: PRESENTER_MSG_ORIGIN,
118633
+ type: "presenter-exit",
118634
+ sessionId: sessionIdRef.current
118635
+ };
118636
+ getChannel2().postMessage(exitMsg);
118637
+ } catch {
118638
+ }
118149
118639
  }
118150
118640
  const win = audienceWindowRef.current;
118151
118641
  if (win && !win.closed) {
@@ -118155,6 +118645,7 @@ function usePresenterWindow(input) {
118155
118645
  }
118156
118646
  }
118157
118647
  audienceWindowRef.current = null;
118648
+ sessionIdRef.current = "";
118158
118649
  if (pollTimerRef.current !== null) {
118159
118650
  clearInterval(pollTimerRef.current);
118160
118651
  pollTimerRef.current = null;
@@ -118165,20 +118656,53 @@ function usePresenterWindow(input) {
118165
118656
  if (isAudienceWindowOpen()) {
118166
118657
  closeAudienceWindow();
118167
118658
  }
118168
- if (content) {
118169
- void storeAudienceContent(content);
118170
- }
118171
- const url = new URL(window.location.href);
118172
- url.hash = AUDIENCE_HASH;
118173
- const win = window.open(url.toString(), "_blank");
118174
- if (!win) {
118659
+ const blankWin = window.open("about:blank", "_blank");
118660
+ if (!blankWin) {
118175
118661
  return false;
118176
118662
  }
118177
- audienceWindowRef.current = win;
118663
+ audienceWindowRef.current = blankWin;
118664
+ const sessionId = generateSessionId();
118665
+ sessionIdRef.current = sessionId;
118666
+ const audienceUrl = new URL(window.location.href);
118667
+ const params2 = new URLSearchParams();
118668
+ params2.set(AUDIENCE_NONCE_KEY, sessionId);
118669
+ audienceUrl.hash = `${AUDIENCE_HASH}&${params2.toString()}`;
118670
+ const navigateOrClose = (ok) => {
118671
+ const win = audienceWindowRef.current;
118672
+ if (!win || win.closed) {
118673
+ return;
118674
+ }
118675
+ if (!ok) {
118676
+ try {
118677
+ win.close();
118678
+ } catch {
118679
+ }
118680
+ audienceWindowRef.current = null;
118681
+ sessionIdRef.current = "";
118682
+ return;
118683
+ }
118684
+ try {
118685
+ win.location.replace(audienceUrl.toString());
118686
+ } catch {
118687
+ try {
118688
+ win.close();
118689
+ } catch {
118690
+ }
118691
+ audienceWindowRef.current = null;
118692
+ sessionIdRef.current = "";
118693
+ }
118694
+ };
118695
+ if (content) {
118696
+ void storeAudienceContent(content).then(() => navigateOrClose(true)).catch(() => navigateOrClose(false));
118697
+ } else {
118698
+ navigateOrClose(true);
118699
+ }
118178
118700
  window.setTimeout(() => syncSlideToAudience(currentSlideIndex), 1500);
118179
118701
  pollTimerRef.current = setInterval(() => {
118180
- if (win.closed) {
118702
+ const win = audienceWindowRef.current;
118703
+ if (!win || win.closed) {
118181
118704
  audienceWindowRef.current = null;
118705
+ sessionIdRef.current = "";
118182
118706
  if (pollTimerRef.current !== null) {
118183
118707
  clearInterval(pollTimerRef.current);
118184
118708
  pollTimerRef.current = null;
@@ -118206,6 +118730,13 @@ function usePresenterWindow(input) {
118206
118730
  closeAudienceWindow();
118207
118731
  }
118208
118732
  }, [isPresenterMode, closeAudienceWindow]);
118733
+ React10.useEffect(() => {
118734
+ const handleBeforeUnload = () => {
118735
+ void clearAudienceContent();
118736
+ };
118737
+ window.addEventListener("beforeunload", handleBeforeUnload);
118738
+ return () => window.removeEventListener("beforeunload", handleBeforeUnload);
118739
+ }, []);
118209
118740
  return {
118210
118741
  openAudienceWindow,
118211
118742
  closeAudienceWindow,
@@ -118243,6 +118774,7 @@ function useAudienceMode(input) {
118243
118774
  if (!isAudienceTab()) {
118244
118775
  return;
118245
118776
  }
118777
+ const expectedSessionId = parseAudienceNonce();
118246
118778
  let channel;
118247
118779
  try {
118248
118780
  channel = new BroadcastChannel(PRESENTER_CHANNEL_NAME);
@@ -118254,6 +118786,9 @@ function useAudienceMode(input) {
118254
118786
  if (!data || data.origin !== PRESENTER_MSG_ORIGIN) {
118255
118787
  return;
118256
118788
  }
118789
+ if (expectedSessionId && data.sessionId !== expectedSessionId) {
118790
+ return;
118791
+ }
118257
118792
  if (data.type === "presenter-slide-change") {
118258
118793
  onSetActiveSlideIndex(data.slideIndex);
118259
118794
  }
@@ -119187,6 +119722,12 @@ function useTouchGestures(input) {
119187
119722
  callbacksRef.current = callbacks;
119188
119723
  const scaleRef = React10.useRef(currentScale);
119189
119724
  scaleRef.current = currentScale;
119725
+ const [targetVersion, setTargetVersion] = React10.useState(0);
119726
+ const lastTargetRef = React10.useRef(null);
119727
+ if (targetRef.current !== lastTargetRef.current) {
119728
+ lastTargetRef.current = targetRef.current;
119729
+ queueMicrotask(() => setTargetVersion((v) => v + 1));
119730
+ }
119190
119731
  React10.useEffect(() => {
119191
119732
  const el = targetRef.current;
119192
119733
  if (!el || !enabled) {
@@ -119275,7 +119816,7 @@ function useTouchGestures(input) {
119275
119816
  el.removeEventListener("touchcancel", handleTouchCancel);
119276
119817
  cancelLongPress();
119277
119818
  };
119278
- }, [targetRef, enabled]);
119819
+ }, [targetRef, enabled, targetVersion]);
119279
119820
  }
119280
119821
 
119281
119822
  // src/viewer/utils/dom-helpers.ts
@@ -119296,11 +119837,31 @@ function safeConfirm(message) {
119296
119837
  return false;
119297
119838
  }
119298
119839
  }
119840
+ function sanitizeDownloadFilename(input) {
119841
+ if (typeof input !== "string" || input.trim().length === 0) {
119842
+ return "presentation.pptx";
119843
+ }
119844
+ let cleaned = input.replace(/[\x00-\x1f\x7f"\\/:*?<>|]/g, "_").replace(/\.\./g, "__").replace(/^\.+/, "").trim();
119845
+ if (cleaned.length === 0) {
119846
+ return "presentation.pptx";
119847
+ }
119848
+ if (cleaned.length > 200) {
119849
+ const dot = cleaned.lastIndexOf(".");
119850
+ if (dot > 0 && cleaned.length - dot <= 16) {
119851
+ const ext = cleaned.slice(dot);
119852
+ cleaned = cleaned.slice(0, 200 - ext.length) + ext;
119853
+ } else {
119854
+ cleaned = cleaned.slice(0, 200);
119855
+ }
119856
+ }
119857
+ return cleaned;
119858
+ }
119299
119859
  function downloadBlob(blob, filename) {
119860
+ const safeName = sanitizeDownloadFilename(filename);
119300
119861
  const url = URL.createObjectURL(blob);
119301
119862
  const a2 = document.createElement("a");
119302
119863
  a2.href = url;
119303
- a2.download = filename;
119864
+ a2.download = safeName;
119304
119865
  document.body.appendChild(a2);
119305
119866
  a2.click();
119306
119867
  setTimeout(() => {
@@ -119731,27 +120292,82 @@ function openAutosaveDb2() {
119731
120292
  req.onerror = () => reject(req.error);
119732
120293
  });
119733
120294
  }
119734
- async function saveToIndexedDb(filePath, data) {
120295
+ async function deleteOldestAutosaveEntry() {
119735
120296
  const db = await openAutosaveDb2();
119736
- return new Promise((resolve2, reject) => {
119737
- const tx = db.transaction(STORE_NAME3, "readwrite");
119738
- const store = tx.objectStore(STORE_NAME3);
119739
- store.put({
119740
- key: filePath,
119741
- data,
119742
- timestamp: Date.now(),
119743
- size: data.byteLength
119744
- });
119745
- tx.oncomplete = () => {
119746
- db.close();
119747
- resolve2(true);
119748
- };
119749
- tx.onerror = () => {
119750
- db.close();
119751
- reject(tx.error);
119752
- };
120297
+ return new Promise((resolve2) => {
120298
+ try {
120299
+ const tx = db.transaction(STORE_NAME3, "readwrite");
120300
+ const store = tx.objectStore(STORE_NAME3);
120301
+ let oldestKey = null;
120302
+ let oldestTimestamp = Infinity;
120303
+ const cursorReq = store.openCursor();
120304
+ cursorReq.onsuccess = () => {
120305
+ const cursor = cursorReq.result;
120306
+ if (cursor) {
120307
+ const value = cursor.value;
120308
+ if (typeof value.timestamp === "number" && value.timestamp < oldestTimestamp) {
120309
+ oldestTimestamp = value.timestamp;
120310
+ oldestKey = cursor.primaryKey;
120311
+ }
120312
+ cursor.continue();
120313
+ } else if (oldestKey !== null) {
120314
+ store.delete(oldestKey);
120315
+ }
120316
+ };
120317
+ tx.oncomplete = () => {
120318
+ db.close();
120319
+ resolve2(oldestKey !== null);
120320
+ };
120321
+ tx.onerror = () => {
120322
+ db.close();
120323
+ resolve2(false);
120324
+ };
120325
+ } catch {
120326
+ try {
120327
+ db.close();
120328
+ } catch {
120329
+ }
120330
+ resolve2(false);
120331
+ }
119753
120332
  });
119754
120333
  }
120334
+ function putAutosaveRecord(filePath, data) {
120335
+ return openAutosaveDb2().then(
120336
+ (db) => new Promise((resolve2, reject) => {
120337
+ const tx = db.transaction(STORE_NAME3, "readwrite");
120338
+ const store = tx.objectStore(STORE_NAME3);
120339
+ store.put({
120340
+ key: filePath,
120341
+ data,
120342
+ timestamp: Date.now(),
120343
+ size: data.byteLength
120344
+ });
120345
+ tx.oncomplete = () => {
120346
+ db.close();
120347
+ resolve2(true);
120348
+ };
120349
+ tx.onerror = () => {
120350
+ db.close();
120351
+ reject(tx.error);
120352
+ };
120353
+ })
120354
+ );
120355
+ }
120356
+ async function saveToIndexedDb(filePath, data) {
120357
+ try {
120358
+ return await putAutosaveRecord(filePath, data);
120359
+ } catch (err) {
120360
+ const errName = err instanceof Error || err instanceof DOMException ? err.name : "";
120361
+ if (errName !== "QuotaExceededError") {
120362
+ throw err;
120363
+ }
120364
+ const deleted = await deleteOldestAutosaveEntry();
120365
+ if (!deleted) {
120366
+ throw err;
120367
+ }
120368
+ return putAutosaveRecord(filePath, data);
120369
+ }
120370
+ }
119755
120371
  function useAutosave(input) {
119756
120372
  const {
119757
120373
  isDirty,
@@ -119868,6 +120484,25 @@ function collectReferencedFontFamilies(slides) {
119868
120484
  }
119869
120485
  return families;
119870
120486
  }
120487
+ var FONT_NAME_UNSAFE_CHARS = /["\\\n\r;}<>]/;
120488
+ var FONT_FORMAT_ALLOWED = /* @__PURE__ */ new Set([
120489
+ "truetype",
120490
+ "opentype",
120491
+ "woff",
120492
+ "woff2",
120493
+ "svg",
120494
+ "embedded-opentype"
120495
+ ]);
120496
+ var FONT_DATA_URL_PATTERN = /^data:font\/[a-z0-9+.-]+(?:;charset=[a-z0-9-]+)?;base64,[A-Za-z0-9+/=]+$/i;
120497
+ function isFontDataUrlSafe(url) {
120498
+ if (typeof url !== "string" || url.length === 0) {
120499
+ return false;
120500
+ }
120501
+ if (url.startsWith("blob:")) {
120502
+ return true;
120503
+ }
120504
+ return FONT_DATA_URL_PATTERN.test(url);
120505
+ }
119871
120506
  function useFontInjection({ embeddedFonts, slides }) {
119872
120507
  React10.useEffect(() => {
119873
120508
  if (!embeddedFonts.length) {
@@ -119875,17 +120510,28 @@ function useFontInjection({ embeddedFonts, slides }) {
119875
120510
  }
119876
120511
  const styleEl = document.createElement("style");
119877
120512
  styleEl.id = EMBEDDED_FONTS_STYLE_ID;
119878
- const cssRules = embeddedFonts.map((font) => {
120513
+ const cssRules = embeddedFonts.flatMap((font) => {
120514
+ if (typeof font.name !== "string" || font.name.length === 0 || FONT_NAME_UNSAFE_CHARS.test(font.name)) {
120515
+ return [];
120516
+ }
120517
+ if (!isFontDataUrlSafe(font.dataUrl)) {
120518
+ return [];
120519
+ }
120520
+ const fontFormat = font.format ?? "truetype";
120521
+ if (!FONT_FORMAT_ALLOWED.has(fontFormat)) {
120522
+ return [];
120523
+ }
119879
120524
  const fontWeight = font.bold ? "700" : "400";
119880
120525
  const fontStyleCss = font.italic ? "italic" : "normal";
119881
- const fontFormat = font.format ?? "truetype";
119882
- return `@font-face {
120526
+ return [
120527
+ `@font-face {
119883
120528
  font-family: "${font.name}";
119884
120529
  src: url("${font.dataUrl}") format("${fontFormat}");
119885
120530
  font-weight: ${fontWeight};
119886
120531
  font-style: ${fontStyleCss};
119887
120532
  font-display: swap;
119888
- }`;
120533
+ }`
120534
+ ];
119889
120535
  }).join("\n");
119890
120536
  styleEl.textContent = cssRules;
119891
120537
  document.head.appendChild(styleEl);
@@ -119914,7 +120560,7 @@ function useFontInjection({ embeddedFonts, slides }) {
119914
120560
  const linkEl = document.createElement("link");
119915
120561
  linkEl.id = GOOGLE_FONTS_LINK_ID;
119916
120562
  linkEl.rel = "stylesheet";
119917
- linkEl.href = `https://fonts.googleapis.com/css2?${googleFamilies.map((f) => `family=${GOOGLE_FONTS_AVAILABLE[f]}`).join("&")}&display=swap`;
120563
+ linkEl.href = `https://fonts.googleapis.com/css2?${googleFamilies.map((f) => `family=${encodeURIComponent(GOOGLE_FONTS_AVAILABLE[f])}`).join("&")}&display=swap`;
119918
120564
  document.head.appendChild(linkEl);
119919
120565
  return () => {
119920
120566
  const existing = document.getElementById(GOOGLE_FONTS_LINK_ID);
@@ -119930,13 +120576,18 @@ function useFontInjection({ embeddedFonts, slides }) {
119930
120576
  }
119931
120577
  const styleEl = document.createElement("style");
119932
120578
  styleEl.id = SYMBOL_FONTS_STYLE_ID;
119933
- const rules = neededSymbolFonts.map(
119934
- (font) => `@font-face {
120579
+ const rules = neededSymbolFonts.flatMap((font) => {
120580
+ if (typeof font !== "string" || FONT_NAME_UNSAFE_CHARS.test(font)) {
120581
+ return [];
120582
+ }
120583
+ return [
120584
+ `@font-face {
119935
120585
  font-family: "${font}";
119936
120586
  src: local("${font}"), local("${font} Regular");
119937
120587
  font-display: swap;
119938
120588
  }`
119939
- ).join("\n");
120589
+ ];
120590
+ }).join("\n");
119940
120591
  styleEl.textContent = rules;
119941
120592
  document.head.appendChild(styleEl);
119942
120593
  return () => {
@@ -120079,16 +120730,17 @@ function useLoadContent({
120079
120730
  `[pptx] Large file detected (${fileSizeMB.toFixed(1)} MB). Loading may use significant memory.`
120080
120731
  );
120081
120732
  }
120082
- if (handlerRef.current) {
120083
- handlerRef.current.dispose();
120084
- handlerRef.current = null;
120085
- }
120733
+ const previousHandler = handlerRef.current;
120086
120734
  const handler = new pptxViewerCore.PptxHandler();
120087
120735
  const parsed = await handler.load(buffer);
120088
120736
  if (cancelled || token !== renderTokenRef.current) {
120089
120737
  handler.dispose();
120090
120738
  return;
120091
120739
  }
120740
+ if (previousHandler) {
120741
+ previousHandler.dispose();
120742
+ }
120743
+ handlerRef.current = null;
120092
120744
  const mediaElements = [];
120093
120745
  for (const slide of parsed.slides) {
120094
120746
  collectMediaElements(slide.elements, mediaElements);
@@ -120133,6 +120785,7 @@ function useLoadContent({
120133
120785
  })
120134
120786
  );
120135
120787
  const { paths: imagePaths, refs: imageRefs } = collectImagePaths(parsed.slides);
120788
+ let nextSlides = parsed.slides;
120136
120789
  if (imagePaths.size > 0) {
120137
120790
  const resolvedMap = /* @__PURE__ */ new Map();
120138
120791
  await Promise.all(
@@ -120146,15 +120799,47 @@ function useLoadContent({
120146
120799
  }
120147
120800
  })
120148
120801
  );
120802
+ const elementPatches = /* @__PURE__ */ new Map();
120149
120803
  for (const ref of imageRefs) {
120150
120804
  const url = resolvedMap.get(ref.path);
120151
- if (url) {
120152
- ref.element[ref.field] = url;
120805
+ if (!url) {
120806
+ continue;
120153
120807
  }
120808
+ const id2 = ref.element.id;
120809
+ const existing = elementPatches.get(id2) ?? {};
120810
+ existing[ref.field] = url;
120811
+ elementPatches.set(id2, existing);
120812
+ }
120813
+ if (elementPatches.size > 0) {
120814
+ const patchElements = (elements) => {
120815
+ let mutated = false;
120816
+ const next = elements.map((el) => {
120817
+ let updated = el;
120818
+ const patch = elementPatches.get(el.id);
120819
+ if (patch) {
120820
+ updated = { ...el, ...patch };
120821
+ }
120822
+ if (updated.type === "group" && updated.children?.length) {
120823
+ const newChildren = patchElements(updated.children);
120824
+ if (newChildren !== updated.children) {
120825
+ updated = { ...updated, children: newChildren };
120826
+ }
120827
+ }
120828
+ if (updated !== el) {
120829
+ mutated = true;
120830
+ }
120831
+ return updated;
120832
+ });
120833
+ return mutated ? next : elements;
120834
+ };
120835
+ nextSlides = parsed.slides.map((s) => {
120836
+ const newElements = patchElements(s.elements);
120837
+ return newElements === s.elements ? s : { ...s, elements: newElements };
120838
+ });
120154
120839
  }
120155
120840
  }
120156
120841
  handlerRef.current = handler;
120157
- setSlides(parsed.slides);
120842
+ setSlides(nextSlides);
120158
120843
  setTemplateElementsBySlideId({});
120159
120844
  setCanvasSize({
120160
120845
  width: parsed.width ?? DEFAULT_CANVAS_WIDTH,
@@ -121328,7 +122013,19 @@ function injectFontFaces(svg, fontFaces) {
121328
122013
  if (!fontFaces.length) {
121329
122014
  return svg;
121330
122015
  }
121331
- const styleBlock = `<style type="text/css">${fontFaces.map((f) => f.css).join("\n")}</style>`;
122016
+ const safeFontFaces = fontFaces.filter((f) => {
122017
+ if (f.css.toLowerCase().includes("</style")) {
122018
+ console.warn(
122019
+ `[export-svg] Dropping @font-face entry for "${f.family}" containing "</style" \u2014 would break out of the <style> block.`
122020
+ );
122021
+ return false;
122022
+ }
122023
+ return true;
122024
+ });
122025
+ if (!safeFontFaces.length) {
122026
+ return svg;
122027
+ }
122028
+ const styleBlock = `<style type="text/css">${safeFontFaces.map((f) => f.css).join("\n")}</style>`;
121332
122029
  if (svg.includes("<defs>")) {
121333
122030
  return svg.replace("<defs>", `<defs>${styleBlock}`);
121334
122031
  }
@@ -121654,7 +122351,7 @@ function useExportHandlers(input) {
121654
122351
  activeSlideIndexForGuides,
121655
122352
  modalControls
121656
122353
  });
121657
- const handleExportPng = async () => {
122354
+ const handleExportPng = React10.useCallback(async () => {
121658
122355
  const stageEl = canvasStageRef.current;
121659
122356
  if (!stageEl) {
121660
122357
  return;
@@ -121666,8 +122363,8 @@ function useExportHandlers(input) {
121666
122363
  } catch (err) {
121667
122364
  console.error("[PowerPointViewer] PNG export failed:", err);
121668
122365
  }
121669
- };
121670
- const handleExportPdf = async () => {
122366
+ }, [canvasStageRef, activeSlideIndex, activeSlide?.backgroundColor]);
122367
+ const handleExportPdf = React10.useCallback(async () => {
121671
122368
  if (!canvasStageRef.current) {
121672
122369
  return;
121673
122370
  }
@@ -121708,8 +122405,8 @@ function useExportHandlers(input) {
121708
122405
  exportAbortRef.current = null;
121709
122406
  setExportModalOpen(false);
121710
122407
  }
121711
- };
121712
- const handleExportNotesPdf = async () => {
122408
+ }, [canvasStageRef, slides.length, setActiveSlideIndex, activeSlideIndex]);
122409
+ const handleExportNotesPdf = React10.useCallback(async () => {
121713
122410
  if (!canvasStageRef.current) {
121714
122411
  return;
121715
122412
  }
@@ -121752,8 +122449,8 @@ function useExportHandlers(input) {
121752
122449
  exportAbortRef.current = null;
121753
122450
  setExportModalOpen(false);
121754
122451
  }
121755
- };
121756
- const handleCopySlideAsImage = async () => {
122452
+ }, [canvasStageRef, slides, setActiveSlideIndex, activeSlideIndex]);
122453
+ const handleCopySlideAsImage = React10.useCallback(async () => {
121757
122454
  const stageEl = canvasStageRef.current;
121758
122455
  if (!stageEl) {
121759
122456
  return;
@@ -121765,8 +122462,8 @@ function useExportHandlers(input) {
121765
122462
  } catch (err) {
121766
122463
  console.error("[PowerPointViewer] Copy slide as image failed:", err);
121767
122464
  }
121768
- };
121769
- const handleExportVideo = async () => {
122465
+ }, [canvasStageRef, activeSlide?.backgroundColor]);
122466
+ const handleExportVideo = React10.useCallback(async () => {
121770
122467
  if (!canvasStageRef.current) {
121771
122468
  return;
121772
122469
  }
@@ -121808,8 +122505,8 @@ function useExportHandlers(input) {
121808
122505
  exportAbortRef.current = null;
121809
122506
  setExportModalOpen(false);
121810
122507
  }
121811
- };
121812
- const handleExportGif = async () => {
122508
+ }, [canvasStageRef, slides.length, setActiveSlideIndex, activeSlideIndex]);
122509
+ const handleExportGif = React10.useCallback(async () => {
121813
122510
  if (!canvasStageRef.current) {
121814
122511
  return;
121815
122512
  }
@@ -121847,7 +122544,7 @@ function useExportHandlers(input) {
121847
122544
  exportAbortRef.current = null;
121848
122545
  setExportModalOpen(false);
121849
122546
  }
121850
- };
122547
+ }, [canvasStageRef, slides.length, setActiveSlideIndex, activeSlideIndex]);
121851
122548
  const handleCancelExport = React10.useCallback(() => {
121852
122549
  exportAbortRef.current?.abort();
121853
122550
  exportAbortRef.current = null;
@@ -121873,6 +122570,15 @@ function useExportHandlers(input) {
121873
122570
  exportStatusMessage
121874
122571
  };
121875
122572
  }
122573
+ function escapeHtmlAttr(value) {
122574
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
122575
+ }
122576
+ function safeDataImageSrc(src) {
122577
+ if (typeof src !== "string" || !src.startsWith("data:image/")) {
122578
+ return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNgAAIAAAUAAen63NgAAAAASUVORK5CYII=";
122579
+ }
122580
+ return escapeHtmlAttr(src);
122581
+ }
121876
122582
  function openPrintWindow(title, bodyHtml, orientation, colorFilter, frameSlides) {
121877
122583
  const printWindow = window.open("", "_blank", "noopener,noreferrer");
121878
122584
  if (!printWindow) {
@@ -122055,7 +122761,7 @@ function usePrintHandlers(input) {
122055
122761
  const slideImages = slideIndices.map((idx) => allImages[idx]).filter(Boolean);
122056
122762
  if (settings.printWhat === "slides") {
122057
122763
  const bodyHtml = slideImages.map(
122058
- (img, i3) => `<section class="page slide-page"><img class="slide-img" src="${img}" alt="Slide ${slideIndices[i3] + 1}" /></section>`
122764
+ (img, i3) => `<section class="page slide-page"><img class="slide-img" src="${safeDataImageSrc(img)}" alt="Slide ${slideIndices[i3] + 1}" /></section>`
122059
122765
  ).join("");
122060
122766
  openPrintWindow(
122061
122767
  "Slides",
@@ -122071,7 +122777,7 @@ function usePrintHandlers(input) {
122071
122777
  const idx = slideIndices[i3];
122072
122778
  const notes = slides[idx]?.notes?.trim() || "";
122073
122779
  return `<section class="page notes-page">
122074
- <img class="notes-slide" src="${img}" alt="Slide ${idx + 1}" />
122780
+ <img class="notes-slide" src="${safeDataImageSrc(img)}" alt="Slide ${idx + 1}" />
122075
122781
  <div class="notes-text">${escapeHtml2(notes)}</div>
122076
122782
  </section>`;
122077
122783
  }).join("");
@@ -122103,14 +122809,14 @@ function usePrintHandlers(input) {
122103
122809
  if (isThreePerPage) {
122104
122810
  const rows = Array.from({ length: spp }, (_, cellIndex) => {
122105
122811
  const img = pageImgs[cellIndex];
122106
- const slideCell = img ? `<div class="handout-cell"><img src="${img}" alt="Slide ${slideIndices[i3 + cellIndex] + 1}" /></div>` : `<div class="handout-cell"></div>`;
122812
+ const slideCell = img ? `<div class="handout-cell"><img src="${safeDataImageSrc(img)}" alt="Slide ${slideIndices[i3 + cellIndex] + 1}" /></div>` : `<div class="handout-cell"></div>`;
122107
122813
  return `<div class="handout-row-3">${slideCell}${buildNoteLines()}</div>`;
122108
122814
  }).join("");
122109
122815
  pages.push(`<section class="page"><div class="handout-grid-3">${rows}</div></section>`);
122110
122816
  } else {
122111
122817
  const cells = Array.from({ length: spp }, (_, cellIndex) => {
122112
122818
  const img = pageImgs[cellIndex];
122113
- return img ? `<div class="handout-cell"><img src="${img}" alt="Slide ${slideIndices[i3 + cellIndex] + 1}" /></div>` : `<div class="handout-cell"></div>`;
122819
+ return img ? `<div class="handout-cell"><img src="${safeDataImageSrc(img)}" alt="Slide ${slideIndices[i3 + cellIndex] + 1}" /></div>` : `<div class="handout-cell"></div>`;
122114
122820
  }).join("");
122115
122821
  pages.push(
122116
122822
  `<section class="page"><div class="handout-grid" style="grid-template-columns: repeat(${grid.columns}, minmax(0, 1fr)); grid-template-rows: repeat(${grid.rows}, minmax(0, 1fr));">${cells}</div></section>`