pptx-react-viewer 1.1.5 → 1.1.7

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 (33) hide show
  1. package/dist/{PowerPointViewer-CX0a7wz_.d.mts → PowerPointViewer-C5jGuKGB.d.mts} +3 -1
  2. package/dist/{PowerPointViewer-CX0a7wz_.d.ts → PowerPointViewer-C5jGuKGB.d.ts} +3 -1
  3. package/dist/index.d.mts +3 -2
  4. package/dist/index.d.ts +3 -2
  5. package/dist/index.js +1575 -515
  6. package/dist/index.mjs +1577 -517
  7. package/dist/pptx-viewer.css +1 -1
  8. package/dist/viewer/index.d.mts +6 -25
  9. package/dist/viewer/index.d.ts +6 -25
  10. package/dist/viewer/index.js +1575 -515
  11. package/dist/viewer/index.mjs +1577 -517
  12. package/node_modules/emf-converter/package.json +1 -1
  13. package/node_modules/mtx-decompressor/package.json +1 -1
  14. package/node_modules/pptx-viewer-core/dist/{SvgExporter-0TxiiorD.d.ts → SvgExporter-BtZczTlB.d.ts} +1 -1
  15. package/node_modules/pptx-viewer-core/dist/{SvgExporter-BQ4KbRO9.d.mts → SvgExporter-D4mBWJHE.d.mts} +1 -1
  16. package/node_modules/pptx-viewer-core/dist/cli/index.d.mts +2 -2
  17. package/node_modules/pptx-viewer-core/dist/cli/index.d.ts +2 -2
  18. package/node_modules/pptx-viewer-core/dist/cli/index.js +0 -0
  19. package/node_modules/pptx-viewer-core/dist/cli/index.mjs +0 -0
  20. package/node_modules/pptx-viewer-core/dist/converter/index.d.mts +3 -3
  21. package/node_modules/pptx-viewer-core/dist/converter/index.d.ts +3 -3
  22. package/node_modules/pptx-viewer-core/dist/converter/index.js +0 -0
  23. package/node_modules/pptx-viewer-core/dist/converter/index.mjs +0 -0
  24. package/node_modules/pptx-viewer-core/dist/index.d.mts +967 -60
  25. package/node_modules/pptx-viewer-core/dist/index.d.ts +967 -60
  26. package/node_modules/pptx-viewer-core/dist/index.js +29613 -16737
  27. package/node_modules/pptx-viewer-core/dist/index.mjs +29588 -16737
  28. package/node_modules/pptx-viewer-core/dist/{presentation-ArhfImJ5.d.mts → presentation-nZxgWvXq.d.mts} +875 -27
  29. package/node_modules/pptx-viewer-core/dist/{presentation-ArhfImJ5.d.ts → presentation-nZxgWvXq.d.ts} +875 -27
  30. package/node_modules/pptx-viewer-core/dist/{text-operations-CLj-sJyk.d.mts → text-operations-DCTGMltY.d.mts} +1 -1
  31. package/node_modules/pptx-viewer-core/dist/{text-operations-rhJV-A_W.d.ts → text-operations-DYmhoi7U.d.ts} +1 -1
  32. package/node_modules/pptx-viewer-core/package.json +1 -1
  33. package/package.json +4 -4
package/dist/index.mjs CHANGED
@@ -4,8 +4,8 @@ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
4
  import * as ReactDOM from 'react-dom/client';
5
5
  import { clsx } from 'clsx';
6
6
  import { twMerge } from 'tailwind-merge';
7
- import { LuMessageSquare, LuEyeOff, LuSettings, LuX, LuCast, LuShieldCheck, LuPlus, LuPanelLeftClose, LuStickyNote, LuMonitor, LuColumns2, LuPresentation, LuMinus, LuClock, LuDownload, LuTrash2, LuCheck, LuLock, LuEye, LuFileText, LuType, LuLoader, LuShieldAlert, LuSignature, LuInfo, LuTriangleAlert, LuPrinter, LuPenTool, LuWifi, LuWifiOff, LuUsers, LuCopy, LuMonitorOff, LuChevronLeft, LuChevronRight, LuPlay, LuPause, LuPanelLeft, LuUndo, LuRedo, LuSearch, LuShare2, LuPanelRight, LuFolderOpen, LuVideo, LuImage, LuClipboardPaste, LuScissors, LuPaintbrush, LuChevronDown, LuSquare, LuDatabase, LuLayers, LuAArrowUp, LuAArrowDown, LuRemoveFormatting, LuHighlighter, LuList, LuListOrdered, LuIndentDecrease, LuIndentIncrease, LuChevronUp, LuPalette, LuPencil, LuPaintBucket, LuSparkles, LuCaptions, LuSpellCheck, LuGitCompare, LuPipette, LuCaseSensitive, LuReplace, LuTimer, LuMousePointer2, LuEraser, LuGripVertical, LuUpload, LuBold, LuItalic, LuUnderline, LuStrikethrough, LuLink, LuGrid2X2, LuCopyPlus, LuEllipsis, LuCircle, LuMoveRight, LuTriangle, LuDiamond, LuAlignLeft, LuAlignCenter, LuAlignRight, LuAlignJustify, LuSpline, LuSettings2, LuMove, LuRadio, LuArrowDown, LuArrowUp, LuArrowRight, LuArrowLeft, LuReply, LuRotateCw, LuBookmark } from 'react-icons/lu';
8
- import { hasShapeProperties, hasTextProperties, SWITCHABLE_LAYOUT_TYPES, isCalloutShape, getCalloutLeaderLineGeometry, buildCalloutLeaderLineSvgPath, getCalloutViewBoxBounds, isInkElement, getLinkedTextBoxSegments, isImageLikeElement, getSubstituteFontFamily, PptxHandler, EncryptedFileError, guidePxToEmu, guideEmuToPx, THEME_COLOR_SCHEME_KEYS, hslToRgb, PRESET_COLOR_MAP, elementActionToPptxAction, mergeShapes, SvgExporter, applyDrawingColorTransforms as applyDrawingColorTransforms$1, getPresetShapeClipPath, svgPathToPolygons, polygonsToSvgPath, EMU_PER_PX as EMU_PER_PX$1, chartDataChangeType, chartDataUpdatePoint, chartDataAddCategory, chartDataRemoveCategory, chartDataAddSeries, chartDataRemoveSeries, getOleObjectTypeLabel, pptxActionToElementAction, hasNonTrivialOverride, COLOR_MAP_ALIAS_KEYS, DEFAULT_COLOR_MAP, addSmartArtNodeAsChild, updateSmartArtNodeText, removeSmartArtNode, switchSmartArtLayout } from 'pptx-viewer-core';
7
+ import { LuMessageSquare, LuEyeOff, LuSettings, LuX, LuCast, LuShieldCheck, LuPlus, LuPanelLeftClose, LuStickyNote, LuMonitor, LuColumns2, LuPresentation, LuMinus, LuLayers, LuSettings2, LuClock, LuDownload, LuTrash2, LuCheck, LuLock, LuEye, LuFileText, LuType, LuLoader, LuShieldAlert, LuSignature, LuInfo, LuTriangleAlert, LuPrinter, LuPenTool, LuWifi, LuWifiOff, LuUsers, LuCopy, LuMonitorOff, LuChevronLeft, LuChevronRight, LuPlay, LuPause, LuMenu, LuUndo, LuRedo, LuShare2, LuPanelLeft, LuSearch, LuPanelRight, LuFolderOpen, LuVideo, LuImage, LuClipboardPaste, LuScissors, LuPaintbrush, LuChevronDown, LuSquare, LuDatabase, LuAArrowUp, LuAArrowDown, LuRemoveFormatting, LuHighlighter, LuList, LuListOrdered, LuIndentDecrease, LuIndentIncrease, LuChevronUp, LuPalette, LuPencil, LuPaintBucket, LuSparkles, LuCaptions, LuSpellCheck, LuGitCompare, LuPipette, LuCaseSensitive, LuReplace, LuTimer, LuMousePointer2, LuEraser, LuGripVertical, LuUpload, LuBold, LuItalic, LuUnderline, LuStrikethrough, LuLink, LuGrid2X2, LuCopyPlus, LuClipboardCopy, LuShapes, LuLayoutGrid, LuWand, LuTextCursorInput, LuFile, LuEllipsis, LuCircle, LuMoveRight, LuTriangle, LuDiamond, LuAlignLeft, LuAlignCenter, LuAlignRight, LuAlignJustify, LuSpline, LuMove, LuRadio, LuArrowDown, LuArrowUp, LuArrowRight, LuArrowLeft, LuReply, LuRotateCw, LuBookmark } from 'react-icons/lu';
8
+ import { hasShapeProperties, hasTextProperties, SWITCHABLE_LAYOUT_TYPES, isCalloutShape, getCalloutLeaderLineGeometry, buildCalloutLeaderLineSvgPath, getCalloutViewBoxBounds, isInkElement, getLinkedTextBoxSegments, isImageLikeElement, getSubstituteFontFamily, getAdjustmentAwareShapeClipPath, getShapeClipPathFromPreset, getCloudPathForRendering, PptxHandler, EncryptedFileError, guidePxToEmu, guideEmuToPx, THEME_COLOR_SCHEME_KEYS, hslToRgb, PRESET_COLOR_MAP, elementActionToPptxAction, mergeShapes, SvgExporter, applyDrawingColorTransforms as applyDrawingColorTransforms$1, getPresetShapeClipPath, svgPathToPolygons, polygonsToSvgPath, EMU_PER_PX as EMU_PER_PX$1, chartDataChangeType, chartDataUpdatePoint, chartDataAddCategory, chartDataRemoveCategory, chartDataAddSeries, chartDataRemoveSeries, getOleObjectTypeLabel, pptxActionToElementAction, hasNonTrivialOverride, COLOR_MAP_ALIAS_KEYS, DEFAULT_COLOR_MAP, addSmartArtNodeAsChild, updateSmartArtNodeText, removeSmartArtNode, switchSmartArtLayout } from 'pptx-viewer-core';
9
9
  import DOMPurify from 'dompurify';
10
10
  import { useTranslation } from 'react-i18next';
11
11
  import html2canvasPro from 'html2canvas-pro';
@@ -171,7 +171,7 @@ function generateUUID() {
171
171
  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];
172
172
  return uuid.toLowerCase();
173
173
  }
174
- function clamp(value, min2, max2) {
174
+ function clamp2(value, min2, max2) {
175
175
  return Math.max(min2, Math.min(max2, value));
176
176
  }
177
177
  function euclideanModulo(n, m2) {
@@ -546,7 +546,7 @@ function _generateTables() {
546
546
  }
547
547
  function toHalfFloat(val2) {
548
548
  if (Math.abs(val2) > 65504) warn("DataUtils.toHalfFloat(): Value out of range.");
549
- val2 = clamp(val2, -65504, 65504);
549
+ val2 = clamp2(val2, -65504, 65504);
550
550
  _tables.floatView[0] = val2;
551
551
  const f = _tables.uint32View[0];
552
552
  const e2 = f >> 23 & 511;
@@ -2035,7 +2035,7 @@ var init_three_core = __esm({
2035
2035
  * @param {number} max - The max value.
2036
2036
  * @return {number} The clamped value.
2037
2037
  */
2038
- clamp,
2038
+ clamp: clamp2,
2039
2039
  /**
2040
2040
  * Computes the Euclidean modulo of the given parameters that
2041
2041
  * is `( ( n % m ) + m ) % m`.
@@ -2562,8 +2562,8 @@ var init_three_core = __esm({
2562
2562
  * @return {Vector2} A reference to this vector.
2563
2563
  */
2564
2564
  clamp(min2, max2) {
2565
- this.x = clamp(this.x, min2.x, max2.x);
2566
- this.y = clamp(this.y, min2.y, max2.y);
2565
+ this.x = clamp2(this.x, min2.x, max2.x);
2566
+ this.y = clamp2(this.y, min2.y, max2.y);
2567
2567
  return this;
2568
2568
  }
2569
2569
  /**
@@ -2577,8 +2577,8 @@ var init_three_core = __esm({
2577
2577
  * @return {Vector2} A reference to this vector.
2578
2578
  */
2579
2579
  clampScalar(minVal, maxVal) {
2580
- this.x = clamp(this.x, minVal, maxVal);
2581
- this.y = clamp(this.y, minVal, maxVal);
2580
+ this.x = clamp2(this.x, minVal, maxVal);
2581
+ this.y = clamp2(this.y, minVal, maxVal);
2582
2582
  return this;
2583
2583
  }
2584
2584
  /**
@@ -2593,7 +2593,7 @@ var init_three_core = __esm({
2593
2593
  */
2594
2594
  clampLength(min2, max2) {
2595
2595
  const length2 = this.length();
2596
- return this.divideScalar(length2 || 1).multiplyScalar(clamp(length2, min2, max2));
2596
+ return this.divideScalar(length2 || 1).multiplyScalar(clamp2(length2, min2, max2));
2597
2597
  }
2598
2598
  /**
2599
2599
  * The components of this vector are rounded down to the nearest integer value.
@@ -2718,7 +2718,7 @@ var init_three_core = __esm({
2718
2718
  const denominator = Math.sqrt(this.lengthSq() * v.lengthSq());
2719
2719
  if (denominator === 0) return Math.PI / 2;
2720
2720
  const theta = this.dot(v) / denominator;
2721
- return Math.acos(clamp(theta, -1, 1));
2721
+ return Math.acos(clamp2(theta, -1, 1));
2722
2722
  }
2723
2723
  /**
2724
2724
  * Computes the distance from the given vector to this instance.
@@ -3205,7 +3205,7 @@ var init_three_core = __esm({
3205
3205
  * @return {number} The angle in radians.
3206
3206
  */
3207
3207
  angleTo(q) {
3208
- return 2 * Math.acos(Math.abs(clamp(this.dot(q), -1, 1)));
3208
+ return 2 * Math.acos(Math.abs(clamp2(this.dot(q), -1, 1)));
3209
3209
  }
3210
3210
  /**
3211
3211
  * Rotates this quaternion by a given angular step to the given quaternion.
@@ -3911,9 +3911,9 @@ var init_three_core = __esm({
3911
3911
  * @return {Vector3} A reference to this vector.
3912
3912
  */
3913
3913
  clamp(min2, max2) {
3914
- this.x = clamp(this.x, min2.x, max2.x);
3915
- this.y = clamp(this.y, min2.y, max2.y);
3916
- this.z = clamp(this.z, min2.z, max2.z);
3914
+ this.x = clamp2(this.x, min2.x, max2.x);
3915
+ this.y = clamp2(this.y, min2.y, max2.y);
3916
+ this.z = clamp2(this.z, min2.z, max2.z);
3917
3917
  return this;
3918
3918
  }
3919
3919
  /**
@@ -3927,9 +3927,9 @@ var init_three_core = __esm({
3927
3927
  * @return {Vector3} A reference to this vector.
3928
3928
  */
3929
3929
  clampScalar(minVal, maxVal) {
3930
- this.x = clamp(this.x, minVal, maxVal);
3931
- this.y = clamp(this.y, minVal, maxVal);
3932
- this.z = clamp(this.z, minVal, maxVal);
3930
+ this.x = clamp2(this.x, minVal, maxVal);
3931
+ this.y = clamp2(this.y, minVal, maxVal);
3932
+ this.z = clamp2(this.z, minVal, maxVal);
3933
3933
  return this;
3934
3934
  }
3935
3935
  /**
@@ -3944,7 +3944,7 @@ var init_three_core = __esm({
3944
3944
  */
3945
3945
  clampLength(min2, max2) {
3946
3946
  const length2 = this.length();
3947
- return this.divideScalar(length2 || 1).multiplyScalar(clamp(length2, min2, max2));
3947
+ return this.divideScalar(length2 || 1).multiplyScalar(clamp2(length2, min2, max2));
3948
3948
  }
3949
3949
  /**
3950
3950
  * The components of this vector are rounded down to the nearest integer value.
@@ -4154,7 +4154,7 @@ var init_three_core = __esm({
4154
4154
  const denominator = Math.sqrt(this.lengthSq() * v.lengthSq());
4155
4155
  if (denominator === 0) return Math.PI / 2;
4156
4156
  const theta = this.dot(v) / denominator;
4157
- return Math.acos(clamp(theta, -1, 1));
4157
+ return Math.acos(clamp2(theta, -1, 1));
4158
4158
  }
4159
4159
  /**
4160
4160
  * Computes the distance from the given vector to this instance.
@@ -5843,10 +5843,10 @@ var init_three_core = __esm({
5843
5843
  * @return {Vector4} A reference to this vector.
5844
5844
  */
5845
5845
  clamp(min2, max2) {
5846
- this.x = clamp(this.x, min2.x, max2.x);
5847
- this.y = clamp(this.y, min2.y, max2.y);
5848
- this.z = clamp(this.z, min2.z, max2.z);
5849
- this.w = clamp(this.w, min2.w, max2.w);
5846
+ this.x = clamp2(this.x, min2.x, max2.x);
5847
+ this.y = clamp2(this.y, min2.y, max2.y);
5848
+ this.z = clamp2(this.z, min2.z, max2.z);
5849
+ this.w = clamp2(this.w, min2.w, max2.w);
5850
5850
  return this;
5851
5851
  }
5852
5852
  /**
@@ -5860,10 +5860,10 @@ var init_three_core = __esm({
5860
5860
  * @return {Vector4} A reference to this vector.
5861
5861
  */
5862
5862
  clampScalar(minVal, maxVal) {
5863
- this.x = clamp(this.x, minVal, maxVal);
5864
- this.y = clamp(this.y, minVal, maxVal);
5865
- this.z = clamp(this.z, minVal, maxVal);
5866
- this.w = clamp(this.w, minVal, maxVal);
5863
+ this.x = clamp2(this.x, minVal, maxVal);
5864
+ this.y = clamp2(this.y, minVal, maxVal);
5865
+ this.z = clamp2(this.z, minVal, maxVal);
5866
+ this.w = clamp2(this.w, minVal, maxVal);
5867
5867
  return this;
5868
5868
  }
5869
5869
  /**
@@ -5878,7 +5878,7 @@ var init_three_core = __esm({
5878
5878
  */
5879
5879
  clampLength(min2, max2) {
5880
5880
  const length2 = this.length();
5881
- return this.divideScalar(length2 || 1).multiplyScalar(clamp(length2, min2, max2));
5881
+ return this.divideScalar(length2 || 1).multiplyScalar(clamp2(length2, min2, max2));
5882
5882
  }
5883
5883
  /**
5884
5884
  * The components of this vector are rounded down to the nearest integer value.
@@ -7661,7 +7661,7 @@ var init_three_core = __esm({
7661
7661
  const m31 = te[2], m32 = te[6], m33 = te[10];
7662
7662
  switch (order) {
7663
7663
  case "XYZ":
7664
- this._y = Math.asin(clamp(m13, -1, 1));
7664
+ this._y = Math.asin(clamp2(m13, -1, 1));
7665
7665
  if (Math.abs(m13) < 0.9999999) {
7666
7666
  this._x = Math.atan2(-m23, m33);
7667
7667
  this._z = Math.atan2(-m12, m11);
@@ -7671,7 +7671,7 @@ var init_three_core = __esm({
7671
7671
  }
7672
7672
  break;
7673
7673
  case "YXZ":
7674
- this._x = Math.asin(-clamp(m23, -1, 1));
7674
+ this._x = Math.asin(-clamp2(m23, -1, 1));
7675
7675
  if (Math.abs(m23) < 0.9999999) {
7676
7676
  this._y = Math.atan2(m13, m33);
7677
7677
  this._z = Math.atan2(m21, m22);
@@ -7681,7 +7681,7 @@ var init_three_core = __esm({
7681
7681
  }
7682
7682
  break;
7683
7683
  case "ZXY":
7684
- this._x = Math.asin(clamp(m32, -1, 1));
7684
+ this._x = Math.asin(clamp2(m32, -1, 1));
7685
7685
  if (Math.abs(m32) < 0.9999999) {
7686
7686
  this._y = Math.atan2(-m31, m33);
7687
7687
  this._z = Math.atan2(-m12, m22);
@@ -7691,7 +7691,7 @@ var init_three_core = __esm({
7691
7691
  }
7692
7692
  break;
7693
7693
  case "ZYX":
7694
- this._y = Math.asin(-clamp(m31, -1, 1));
7694
+ this._y = Math.asin(-clamp2(m31, -1, 1));
7695
7695
  if (Math.abs(m31) < 0.9999999) {
7696
7696
  this._x = Math.atan2(m32, m33);
7697
7697
  this._z = Math.atan2(m21, m11);
@@ -7701,7 +7701,7 @@ var init_three_core = __esm({
7701
7701
  }
7702
7702
  break;
7703
7703
  case "YZX":
7704
- this._z = Math.asin(clamp(m21, -1, 1));
7704
+ this._z = Math.asin(clamp2(m21, -1, 1));
7705
7705
  if (Math.abs(m21) < 0.9999999) {
7706
7706
  this._x = Math.atan2(-m23, m22);
7707
7707
  this._y = Math.atan2(-m31, m11);
@@ -7711,7 +7711,7 @@ var init_three_core = __esm({
7711
7711
  }
7712
7712
  break;
7713
7713
  case "XZY":
7714
- this._z = Math.asin(-clamp(m12, -1, 1));
7714
+ this._z = Math.asin(-clamp2(m12, -1, 1));
7715
7715
  if (Math.abs(m12) < 0.9999999) {
7716
7716
  this._x = Math.atan2(m32, m22);
7717
7717
  this._y = Math.atan2(m13, m11);
@@ -9335,8 +9335,8 @@ var init_three_core = __esm({
9335
9335
  */
9336
9336
  setHSL(h2, s, l2, colorSpace = ColorManagement.workingColorSpace) {
9337
9337
  h2 = euclideanModulo(h2, 1);
9338
- s = clamp(s, 0, 1);
9339
- l2 = clamp(l2, 0, 1);
9338
+ s = clamp2(s, 0, 1);
9339
+ l2 = clamp2(l2, 0, 1);
9340
9340
  if (s === 0) {
9341
9341
  this.r = this.g = this.b = l2;
9342
9342
  } else {
@@ -9522,7 +9522,7 @@ var init_three_core = __esm({
9522
9522
  */
9523
9523
  getHex(colorSpace = SRGBColorSpace) {
9524
9524
  ColorManagement.workingToColorSpace(_color.copy(this), colorSpace);
9525
- 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));
9525
+ 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));
9526
9526
  }
9527
9527
  /**
9528
9528
  * Returns the hexadecimal value of this color as a string (for example, 'FFFFFF').
@@ -18453,13 +18453,13 @@ var init_three_core = __esm({
18453
18453
  vec.crossVectors(tangents[i3 - 1], tangents[i3]);
18454
18454
  if (vec.length() > Number.EPSILON) {
18455
18455
  vec.normalize();
18456
- const theta = Math.acos(clamp(tangents[i3 - 1].dot(tangents[i3]), -1, 1));
18456
+ const theta = Math.acos(clamp2(tangents[i3 - 1].dot(tangents[i3]), -1, 1));
18457
18457
  normals[i3].applyMatrix4(mat.makeRotationAxis(vec, theta));
18458
18458
  }
18459
18459
  binormals[i3].crossVectors(tangents[i3], normals[i3]);
18460
18460
  }
18461
18461
  if (closed === true) {
18462
- let theta = Math.acos(clamp(normals[0].dot(normals[segments]), -1, 1));
18462
+ let theta = Math.acos(clamp2(normals[0].dot(normals[segments]), -1, 1));
18463
18463
  theta /= segments;
18464
18464
  if (tangents[0].dot(vec.crossVectors(normals[0], normals[segments])) > 0) {
18465
18465
  theta = -theta;
@@ -20248,7 +20248,7 @@ var init_three_core = __esm({
20248
20248
  phiLength
20249
20249
  };
20250
20250
  segments = Math.floor(segments);
20251
- phiLength = clamp(phiLength, 0, Math.PI * 2);
20251
+ phiLength = clamp2(phiLength, 0, Math.PI * 2);
20252
20252
  const indices = [];
20253
20253
  const vertices = [];
20254
20254
  const uvs = [];
@@ -21464,7 +21464,7 @@ var init_three_core = __esm({
21464
21464
  this.ior = 1.5;
21465
21465
  Object.defineProperty(this, "reflectivity", {
21466
21466
  get: function() {
21467
- return clamp(2.5 * (this.ior - 1) / (this.ior + 1), 0, 1);
21467
+ return clamp2(2.5 * (this.ior - 1) / (this.ior + 1), 0, 1);
21468
21468
  },
21469
21469
  set: function(reflectivity) {
21470
21470
  this.ior = (1 + 0.4 * reflectivity) / (1 - 0.4 * reflectivity);
@@ -29732,7 +29732,7 @@ var init_three_core = __esm({
29732
29732
  */
29733
29733
  makeSafe() {
29734
29734
  const EPS = 1e-6;
29735
- this.phi = clamp(this.phi, EPS, Math.PI - EPS);
29735
+ this.phi = clamp2(this.phi, EPS, Math.PI - EPS);
29736
29736
  return this;
29737
29737
  }
29738
29738
  /**
@@ -29760,7 +29760,7 @@ var init_three_core = __esm({
29760
29760
  this.phi = 0;
29761
29761
  } else {
29762
29762
  this.theta = Math.atan2(x2, z);
29763
- this.phi = Math.acos(clamp(y / this.radius, -1, 1));
29763
+ this.phi = Math.acos(clamp2(y / this.radius, -1, 1));
29764
29764
  }
29765
29765
  return this;
29766
29766
  }
@@ -30275,7 +30275,7 @@ var init_three_core = __esm({
30275
30275
  const startEnd_startP = _startEnd.dot(_startP);
30276
30276
  let t2 = startEnd_startP / startEnd2;
30277
30277
  if (clampToLine) {
30278
- t2 = clamp(t2, 0, 1);
30278
+ t2 = clamp2(t2, 0, 1);
30279
30279
  }
30280
30280
  return t2;
30281
30281
  }
@@ -30321,27 +30321,27 @@ var init_three_core = __esm({
30321
30321
  if (a2 <= EPSILON) {
30322
30322
  s = 0;
30323
30323
  t2 = f / e2;
30324
- t2 = clamp(t2, 0, 1);
30324
+ t2 = clamp2(t2, 0, 1);
30325
30325
  } else {
30326
30326
  const c3 = _d1.dot(_r);
30327
30327
  if (e2 <= EPSILON) {
30328
30328
  t2 = 0;
30329
- s = clamp(-c3 / a2, 0, 1);
30329
+ s = clamp2(-c3 / a2, 0, 1);
30330
30330
  } else {
30331
30331
  const b2 = _d1.dot(_d2);
30332
30332
  const denom = a2 * e2 - b2 * b2;
30333
30333
  if (denom !== 0) {
30334
- s = clamp((b2 * f - c3 * e2) / denom, 0, 1);
30334
+ s = clamp2((b2 * f - c3 * e2) / denom, 0, 1);
30335
30335
  } else {
30336
30336
  s = 0;
30337
30337
  }
30338
30338
  t2 = (b2 * s + f) / e2;
30339
30339
  if (t2 < 0) {
30340
30340
  t2 = 0;
30341
- s = clamp(-c3 / a2, 0, 1);
30341
+ s = clamp2(-c3 / a2, 0, 1);
30342
30342
  } else if (t2 > 1) {
30343
30343
  t2 = 1;
30344
- s = clamp((b2 - c3) / a2, 0, 1);
30344
+ s = clamp2((b2 - c3) / a2, 0, 1);
30345
30345
  }
30346
30346
  }
30347
30347
  }
@@ -43571,7 +43571,7 @@ var require_use_sync_external_store_shim_development = __commonJS({
43571
43571
  return x2 === y && (0 !== x2 || 1 / x2 === 1 / y) || x2 !== x2 && y !== y;
43572
43572
  }
43573
43573
  function useSyncExternalStore$2(subscribe3, getSnapshot2) {
43574
- didWarnOld18Alpha || void 0 === React100.startTransition || (didWarnOld18Alpha = true, console.error(
43574
+ didWarnOld18Alpha || void 0 === React103.startTransition || (didWarnOld18Alpha = true, console.error(
43575
43575
  "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."
43576
43576
  ));
43577
43577
  var value = getSnapshot2();
@@ -43581,7 +43581,7 @@ var require_use_sync_external_store_shim_development = __commonJS({
43581
43581
  "The result of getSnapshot should be cached to avoid an infinite loop"
43582
43582
  ), didWarnUncachedGetSnapshot = true);
43583
43583
  }
43584
- cachedValue = useState86({
43584
+ cachedValue = useState89({
43585
43585
  inst: { value, getSnapshot: getSnapshot2 }
43586
43586
  });
43587
43587
  var inst = cachedValue[0].inst, forceUpdate = cachedValue[1];
@@ -43593,7 +43593,7 @@ var require_use_sync_external_store_shim_development = __commonJS({
43593
43593
  },
43594
43594
  [subscribe3, value, getSnapshot2]
43595
43595
  );
43596
- useEffect72(
43596
+ useEffect73(
43597
43597
  function() {
43598
43598
  checkIfSnapshotChanged(inst) && forceUpdate({ inst });
43599
43599
  return subscribe3(function() {
@@ -43619,8 +43619,8 @@ var require_use_sync_external_store_shim_development = __commonJS({
43619
43619
  return getSnapshot2();
43620
43620
  }
43621
43621
  "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
43622
- 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;
43623
- exports$1.useSyncExternalStore = void 0 !== React100.useSyncExternalStore ? React100.useSyncExternalStore : shim;
43622
+ var React103 = __require("react"), objectIs = "function" === typeof Object.is ? Object.is : is2, useState89 = React103.useState, useEffect73 = React103.useEffect, useLayoutEffect7 = React103.useLayoutEffect, useDebugValue = React103.useDebugValue, didWarnOld18Alpha = false, didWarnUncachedGetSnapshot = false, shim = "undefined" === typeof window || "undefined" === typeof window.document || "undefined" === typeof window.document.createElement ? useSyncExternalStore$1 : useSyncExternalStore$2;
43623
+ exports$1.useSyncExternalStore = void 0 !== React103.useSyncExternalStore ? React103.useSyncExternalStore : shim;
43624
43624
  "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error());
43625
43625
  })();
43626
43626
  }
@@ -43643,9 +43643,9 @@ var require_with_selector_development = __commonJS({
43643
43643
  return x2 === y && (0 !== x2 || 1 / x2 === 1 / y) || x2 !== x2 && y !== y;
43644
43644
  }
43645
43645
  "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
43646
- 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;
43646
+ var React103 = __require("react"), shim = require_shim(), objectIs = "function" === typeof Object.is ? Object.is : is2, useSyncExternalStore3 = shim.useSyncExternalStore, useRef74 = React103.useRef, useEffect73 = React103.useEffect, useMemo41 = React103.useMemo, useDebugValue = React103.useDebugValue;
43647
43647
  exports$1.useSyncExternalStoreWithSelector = function(subscribe3, getSnapshot2, getServerSnapshot2, selector, isEqual) {
43648
- var instRef = useRef73(null);
43648
+ var instRef = useRef74(null);
43649
43649
  if (null === instRef.current) {
43650
43650
  var inst = { hasValue: false, value: null };
43651
43651
  instRef.current = inst;
@@ -43686,7 +43686,7 @@ var require_with_selector_development = __commonJS({
43686
43686
  [getSnapshot2, getServerSnapshot2, selector, isEqual]
43687
43687
  );
43688
43688
  var value = useSyncExternalStore3(subscribe3, instRef[0], instRef[1]);
43689
- useEffect72(
43689
+ useEffect73(
43690
43690
  function() {
43691
43691
  inst.hasValue = true;
43692
43692
  inst.value = value;
@@ -70291,6 +70291,55 @@ var ACTION_BUTTON_PRESETS = [
70291
70291
  label: "Return",
70292
70292
  defaultAction: "prevSlide",
70293
70293
  iconPath: "M18 8 L18 14 L6 14 M6 14 L10 10 M6 14 L10 18"
70294
+ },
70295
+ {
70296
+ shapeType: "actionButtonHome",
70297
+ label: "Home",
70298
+ defaultAction: "firstSlide",
70299
+ // House: roof + body
70300
+ iconPath: "M12 4 L20 11 L20 20 L14 20 L14 14 L10 14 L10 20 L4 20 L4 11 Z"
70301
+ },
70302
+ {
70303
+ shapeType: "actionButtonHelp",
70304
+ label: "Help",
70305
+ defaultAction: "none",
70306
+ // Question mark
70307
+ iconPath: "M9 9 a3 3 0 1 1 4 2.8 c-1 0.4 -1 1.2 -1 2 M12 17 v0.5"
70308
+ },
70309
+ {
70310
+ shapeType: "actionButtonInformation",
70311
+ label: "Information",
70312
+ defaultAction: "none",
70313
+ // Lower-case "i": dot + body
70314
+ iconPath: "M12 6 v0.01 M12 10 v8"
70315
+ },
70316
+ {
70317
+ shapeType: "actionButtonDocument",
70318
+ label: "Document",
70319
+ defaultAction: "none",
70320
+ // Document with folded corner
70321
+ iconPath: "M6 4 L14 4 L18 8 L18 20 L6 20 Z M14 4 L14 8 L18 8"
70322
+ },
70323
+ {
70324
+ shapeType: "actionButtonSound",
70325
+ label: "Sound",
70326
+ defaultAction: "none",
70327
+ // Speaker cone + sound waves
70328
+ 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"
70329
+ },
70330
+ {
70331
+ shapeType: "actionButtonMovie",
70332
+ label: "Movie",
70333
+ defaultAction: "none",
70334
+ // Film strip with play triangle
70335
+ iconPath: "M4 6 L20 6 L20 18 L4 18 Z M10 9 L15 12 L10 15 Z"
70336
+ },
70337
+ {
70338
+ shapeType: "actionButtonBlank",
70339
+ label: "Custom",
70340
+ defaultAction: "none",
70341
+ // No glyph — empty path. The button still renders as a rounded rect via clip-path.
70342
+ iconPath: ""
70294
70343
  }
70295
70344
  ];
70296
70345
  Object.fromEntries(ACTION_BUTTON_PRESETS.map((p3) => [p3.shapeType, p3.defaultAction]));
@@ -72570,8 +72619,8 @@ function hexToRgb2(hex) {
72570
72619
  };
72571
72620
  }
72572
72621
  function rgbToHex(r2, g2, b2) {
72573
- const clamp2 = (v) => Math.max(0, Math.min(255, Math.round(v)));
72574
- return `#${clamp2(r2).toString(16).padStart(2, "0")}${clamp2(g2).toString(16).padStart(2, "0")}${clamp2(b2).toString(16).padStart(2, "0")}`;
72622
+ const clamp3 = (v) => Math.max(0, Math.min(255, Math.round(v)));
72623
+ return `#${clamp3(r2).toString(16).padStart(2, "0")}${clamp3(g2).toString(16).padStart(2, "0")}${clamp3(b2).toString(16).padStart(2, "0")}`;
72575
72624
  }
72576
72625
  function rgbToHsl(r2, g2, b2) {
72577
72626
  const rn = r2 / 255;
@@ -74781,6 +74830,11 @@ function getShapeClipPath(shapeType, adjustments, width, height) {
74781
74830
  }
74782
74831
  const normalized = shapeType.toLowerCase();
74783
74832
  if (normalized === "round1rect" || normalized === "round2samerect" || normalized === "round2diagrect" || normalized === "sniproundrect" || normalized === "snip1rect" || normalized === "snip2diagrect") {
74833
+ if (adjustments?.adj !== void 0 && width && height) {
74834
+ const ratio = Math.min(Math.max(adjustments.adj / 1e5, 0), 0.5);
74835
+ const radiusPx = Math.round(Math.min(width, height) * ratio);
74836
+ return `inset(0 round ${radiusPx}px)`;
74837
+ }
74784
74838
  return "inset(0 round 18px)";
74785
74839
  }
74786
74840
  if (normalized === "can" || normalized === "cylinder") {
@@ -75427,6 +75481,128 @@ function mapDagBlendModeToCss(blend) {
75427
75481
  return void 0;
75428
75482
  }
75429
75483
  }
75484
+ function getImageAlphaFilterId(elementId) {
75485
+ return `imgalpha-${elementId}`;
75486
+ }
75487
+ function hasAdvancedImageAlphaEffects(element2) {
75488
+ if (!isImageLikeElement(element2)) {
75489
+ return false;
75490
+ }
75491
+ const e2 = element2.imageEffects;
75492
+ if (!e2) {
75493
+ return false;
75494
+ }
75495
+ return Boolean(
75496
+ 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
75497
+ );
75498
+ }
75499
+ function renderImageAlphaSvgFilter(element2) {
75500
+ if (!isImageLikeElement(element2)) {
75501
+ return null;
75502
+ }
75503
+ const e2 = element2.imageEffects;
75504
+ if (!e2 || !hasAdvancedImageAlphaEffects(element2)) {
75505
+ return null;
75506
+ }
75507
+ const filterId = getImageAlphaFilterId(element2.id);
75508
+ const primitives = [];
75509
+ let resultIdx = 0;
75510
+ let inputRef = "SourceGraphic";
75511
+ const next = (jsx235) => {
75512
+ const result = `r${resultIdx++}`;
75513
+ primitives.push(jsx235(inputRef, result));
75514
+ inputRef = result;
75515
+ };
75516
+ if (typeof e2.alphaModFix === "number") {
75517
+ const mul = clamp(e2.alphaModFix / 100, 0, 1);
75518
+ next((inp, out) => /* @__PURE__ */ jsx(
75519
+ "feColorMatrix",
75520
+ {
75521
+ in: inp,
75522
+ result: out,
75523
+ type: "matrix",
75524
+ values: `1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 ${mul} 0`
75525
+ },
75526
+ out
75527
+ ));
75528
+ }
75529
+ if (e2.alphaInv) {
75530
+ next((inp, out) => /* @__PURE__ */ jsx("feComponentTransfer", { in: inp, result: out, children: /* @__PURE__ */ jsx("feFuncA", { type: "linear", slope: -1, intercept: 1 }) }, out));
75531
+ }
75532
+ if (e2.alphaCeiling) {
75533
+ next((inp, out) => /* @__PURE__ */ jsx("feComponentTransfer", { in: inp, result: out, children: /* @__PURE__ */ jsx("feFuncA", { type: "discrete", tableValues: "0 1 1 1 1 1 1 1 1 1" }) }, out));
75534
+ }
75535
+ if (e2.alphaFloor) {
75536
+ next((inp, out) => /* @__PURE__ */ jsx("feComponentTransfer", { in: inp, result: out, children: /* @__PURE__ */ jsx("feFuncA", { type: "discrete", tableValues: "0 0 0 0 0 0 0 0 0 1" }) }, out));
75537
+ }
75538
+ if (typeof e2.alphaRepl === "number") {
75539
+ const a2 = clamp(e2.alphaRepl / 100, 0, 1);
75540
+ next((inp, out) => /* @__PURE__ */ jsx("feComponentTransfer", { in: inp, result: out, children: /* @__PURE__ */ jsx("feFuncA", { type: "linear", slope: 0, intercept: a2 }) }, out));
75541
+ }
75542
+ if (typeof e2.alphaBiLevel === "number") {
75543
+ const t2 = clamp(e2.alphaBiLevel / 100, 0, 1);
75544
+ const table = Array.from({ length: 10 }, (_, i3) => i3 / 10 >= t2 ? "1" : "0").join(" ");
75545
+ next((inp, out) => /* @__PURE__ */ jsx("feComponentTransfer", { in: inp, result: out, children: /* @__PURE__ */ jsx("feFuncA", { type: "discrete", tableValues: table }) }, out));
75546
+ }
75547
+ if (typeof e2.biLevel === "number") {
75548
+ next((inp, out) => /* @__PURE__ */ jsx("feColorMatrix", { in: inp, result: out, type: "saturate", values: "0" }, out));
75549
+ const t2 = clamp(e2.biLevel / 100, 0, 1);
75550
+ const tbl = t2 < 0.5 ? "0 1" : "0 1";
75551
+ next((inp, out) => /* @__PURE__ */ jsxs("feComponentTransfer", { in: inp, result: out, children: [
75552
+ /* @__PURE__ */ jsx("feFuncR", { type: "discrete", tableValues: tbl }),
75553
+ /* @__PURE__ */ jsx("feFuncG", { type: "discrete", tableValues: tbl }),
75554
+ /* @__PURE__ */ jsx("feFuncB", { type: "discrete", tableValues: tbl })
75555
+ ] }, out));
75556
+ }
75557
+ if (e2.lum && (typeof e2.lum.bright === "number" || typeof e2.lum.contrast === "number")) {
75558
+ const b2 = (e2.lum.bright ?? 0) / 100;
75559
+ const c2 = 1 + (e2.lum.contrast ?? 0) / 100;
75560
+ const slope = c2;
75561
+ const intercept = b2 + (1 - c2) / 2;
75562
+ next((inp, out) => /* @__PURE__ */ jsxs("feComponentTransfer", { in: inp, result: out, children: [
75563
+ /* @__PURE__ */ jsx("feFuncR", { type: "linear", slope, intercept }),
75564
+ /* @__PURE__ */ jsx("feFuncG", { type: "linear", slope, intercept }),
75565
+ /* @__PURE__ */ jsx("feFuncB", { type: "linear", slope, intercept })
75566
+ ] }, out));
75567
+ }
75568
+ if (e2.hsl && typeof e2.hsl.sat === "number") {
75569
+ const v = clamp(1 + e2.hsl.sat / 100, 0, 2);
75570
+ next((inp, out) => /* @__PURE__ */ jsx("feColorMatrix", { in: inp, result: out, type: "saturate", values: String(v) }, out));
75571
+ }
75572
+ if (e2.tint && typeof e2.tint.amt === "number" && e2.tint.amt < 0) {
75573
+ const v = clamp(1 + e2.tint.amt / 100, 0, 1);
75574
+ next((inp, out) => /* @__PURE__ */ jsx("feColorMatrix", { in: inp, result: out, type: "saturate", values: String(v) }, out));
75575
+ }
75576
+ if (e2.clrRepl) {
75577
+ const c2 = hexToRgbUnit(e2.clrRepl.color);
75578
+ next((inp, out) => /* @__PURE__ */ jsx(
75579
+ "feColorMatrix",
75580
+ {
75581
+ in: inp,
75582
+ result: out,
75583
+ type: "matrix",
75584
+ values: `0 0 0 0 ${c2.r} 0 0 0 0 ${c2.g} 0 0 0 0 ${c2.b} 0 0 0 1 0`
75585
+ },
75586
+ out
75587
+ ));
75588
+ }
75589
+ if (primitives.length === 0) {
75590
+ return null;
75591
+ }
75592
+ return /* @__PURE__ */ jsx(
75593
+ "svg",
75594
+ {
75595
+ width: 0,
75596
+ height: 0,
75597
+ style: { position: "absolute", overflow: "hidden" },
75598
+ "aria-hidden": "true",
75599
+ children: /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx("filter", { id: filterId, colorInterpolationFilters: "sRGB", children: primitives }) })
75600
+ }
75601
+ );
75602
+ }
75603
+ function clamp(v, lo, hi) {
75604
+ return v < lo ? lo : v > hi ? hi : v;
75605
+ }
75430
75606
  function getDagDuotoneFilterId(elementId) {
75431
75607
  return `dag-duotone-${elementId}`;
75432
75608
  }
@@ -75510,6 +75686,9 @@ function getImageEffectsFilter(element2, options) {
75510
75686
  const filterId = getDuotoneFilterId(element2.id);
75511
75687
  filters.push(`url(#${filterId})`);
75512
75688
  }
75689
+ if (hasAdvancedImageAlphaEffects(element2)) {
75690
+ filters.push(`url(#${getImageAlphaFilterId(element2.id)})`);
75691
+ }
75513
75692
  if (effects.artisticEffect) {
75514
75693
  const radius = effects.artisticRadius ?? 5;
75515
75694
  if (needsSvgArtisticFilter(effects.artisticEffect)) {
@@ -75683,6 +75862,39 @@ function getEffectDagCssFilter(style, elementId) {
75683
75862
  return filters.length > 0 ? filters.join(" ") : void 0;
75684
75863
  }
75685
75864
  var getEffectDagFilter = getEffectDagCssFilter;
75865
+ function getResolvedShapeClipPathFor(shapeType, width, height, adjustments) {
75866
+ if (!shapeType) {
75867
+ return void 0;
75868
+ }
75869
+ if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {
75870
+ return getShapeClipPath(shapeType, adjustments, width, height);
75871
+ }
75872
+ if (adjustments && Object.keys(adjustments).length > 0) {
75873
+ const adjusted = getAdjustmentAwareShapeClipPath(shapeType, width, height, adjustments);
75874
+ if (adjusted !== void 0) {
75875
+ return adjusted;
75876
+ }
75877
+ }
75878
+ const fromPreset = getShapeClipPathFromPreset(shapeType, width, height, adjustments);
75879
+ if (fromPreset !== void 0) {
75880
+ return fromPreset;
75881
+ }
75882
+ const cloud = getCloudPathForRendering(shapeType, width, height);
75883
+ if (cloud !== void 0) {
75884
+ return cloud;
75885
+ }
75886
+ return getShapeClipPath(shapeType, adjustments, width, height);
75887
+ }
75888
+ function getResolvedShapeClipPath(element2, width, height) {
75889
+ const shapeType = element2.shapeType;
75890
+ if (!shapeType) {
75891
+ return void 0;
75892
+ }
75893
+ const w = element2.width;
75894
+ const h2 = element2.height;
75895
+ const adjustments = element2.shapeAdjustments;
75896
+ return getResolvedShapeClipPathFor(shapeType, w, h2, adjustments);
75897
+ }
75686
75898
 
75687
75899
  // src/viewer/utils/shape-round-rect.ts
75688
75900
  function localClampAdjustment(value) {
@@ -75754,6 +75966,27 @@ var MATERIAL_MAP = {
75754
75966
  filter: "brightness(1.1) contrast(0.85)",
75755
75967
  // Translucent powder: slight translucent glow
75756
75968
  backgroundImage: "radial-gradient(ellipse at 30% 30%, rgba(255,255,255,0.1) 0%, transparent 60%)"
75969
+ },
75970
+ // Legacy materials (PowerPoint 2007 / earlier). Render as muted variants
75971
+ // of the modern equivalents so legacy decks still resemble the originals.
75972
+ legacyMatte: {
75973
+ filter: "brightness(0.92) saturate(0.85)",
75974
+ backgroundImage: "linear-gradient(180deg, rgba(255,255,255,0.03) 0%, transparent 50%, rgba(0,0,0,0.04) 100%)"
75975
+ },
75976
+ legacyPlastic: {
75977
+ filter: "brightness(1.02) contrast(1.03)",
75978
+ boxShadow: "inset -2px -2px 5px rgba(255,255,255,0.3)",
75979
+ backgroundImage: "radial-gradient(ellipse 35% 25% at 25% 20%, rgba(255,255,255,0.15) 0%, transparent 70%)"
75980
+ },
75981
+ legacyMetal: {
75982
+ filter: "brightness(1.05) contrast(1.1) saturate(1.1)",
75983
+ boxShadow: "inset -2px -2px 6px rgba(255,255,255,0.35), inset 1px 1px 3px rgba(255,255,255,0.15)",
75984
+ 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%)"
75985
+ },
75986
+ legacyWireframe: {
75987
+ filter: "brightness(1) contrast(1.4) saturate(0.6)",
75988
+ // Wireframe: high contrast outline-emphasising look
75989
+ boxShadow: "inset 0 0 0 1px rgba(0,0,0,0.4)"
75757
75990
  }
75758
75991
  };
75759
75992
  function getMaterialCssOverrides(material) {
@@ -76708,8 +76941,7 @@ function getShapeVisualStyle(element2, hasFill, fillColor, strokeWidth, strokeCo
76708
76941
  return {};
76709
76942
  }
76710
76943
  const normalizedShapeType = getShapeType(element2.shapeType);
76711
- const shapeType = element2.shapeType || normalizedShapeType;
76712
- const clipPath = getShapeClipPath(shapeType);
76944
+ const clipPath = getResolvedShapeClipPath(element2);
76713
76945
  const fillOpacity = element2.shapeStyle?.fillOpacity;
76714
76946
  const strokeOpacity = element2.shapeStyle?.strokeOpacity;
76715
76947
  const strokeDash = normalizeStrokeDashType(element2.shapeStyle?.strokeDash);
@@ -77311,7 +77543,7 @@ function getImageMaskStyle(element2) {
77311
77543
  if (normalized === "can" || normalized === "cylinder") {
77312
77544
  return { borderRadius: "48% / 12%" };
77313
77545
  }
77314
- const clipPath = getShapeClipPath(shapeType);
77546
+ const clipPath = getResolvedShapeClipPath(element2);
77315
77547
  if (!clipPath) {
77316
77548
  return void 0;
77317
77549
  }
@@ -77974,8 +78206,8 @@ function hexToRgb3(hex) {
77974
78206
  };
77975
78207
  }
77976
78208
  function rgbToHex2(r2, g2, b2) {
77977
- const clamp2 = (v) => Math.max(0, Math.min(255, Math.round(v)));
77978
- 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()}`;
78209
+ const clamp3 = (v) => Math.max(0, Math.min(255, Math.round(v)));
78210
+ 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()}`;
77979
78211
  }
77980
78212
  function tintColor(hex, tintFactor) {
77981
78213
  const { r: r2, g: g2, b: b2 } = hexToRgb3(hex);
@@ -78906,13 +79138,13 @@ function cellStyleToCss(style) {
78906
79138
  }
78907
79139
  if (style.textDirection) {
78908
79140
  switch (style.textDirection) {
78909
- case "vertical":
79141
+ case "vert":
78910
79142
  case "eaVert":
78911
79143
  case "wordArtVert":
78912
79144
  case "wordArtVertRtl":
78913
79145
  css.writingMode = "vertical-rl";
78914
79146
  break;
78915
- case "vertical270":
79147
+ case "vert270":
78916
79148
  case "mongolianVert":
78917
79149
  css.writingMode = "vertical-lr";
78918
79150
  break;
@@ -79319,8 +79551,8 @@ function renderTableElement(element2, textStyle, options) {
79319
79551
  {
79320
79552
  style: rowHeight ? { height: rowHeight } : void 0,
79321
79553
  children: cells.map((cell, cellIndex) => {
79322
- const isHMerged = cell["@_hMerge"] === "1" || cell["@_hMerge"] === true;
79323
- const isVMerged = cell["@_vMerge"] === "1" || cell["@_vMerge"] === true;
79554
+ const isHMerged = cell["@_hMerge"] === "1";
79555
+ const isVMerged = cell["@_vMerge"] === "1";
79324
79556
  if (isHMerged || isVMerged) {
79325
79557
  return null;
79326
79558
  }
@@ -79439,8 +79671,8 @@ function hexToRgb4(hex) {
79439
79671
  ];
79440
79672
  }
79441
79673
  function rgbToHex3(r2, g2, b2) {
79442
- const clamp2 = (v) => Math.max(0, Math.min(255, Math.round(v)));
79443
- return `#${clamp2(r2).toString(16).padStart(2, "0")}${clamp2(g2).toString(16).padStart(2, "0")}${clamp2(b2).toString(16).padStart(2, "0")}`;
79674
+ const clamp3 = (v) => Math.max(0, Math.min(255, Math.round(v)));
79675
+ return `#${clamp3(r2).toString(16).padStart(2, "0")}${clamp3(g2).toString(16).padStart(2, "0")}${clamp3(b2).toString(16).padStart(2, "0")}`;
79444
79676
  }
79445
79677
  function tint(hex, amount) {
79446
79678
  const [r2, g2, b2] = hexToRgb4(hex);
@@ -81358,7 +81590,7 @@ function resolveRegionCode(label) {
81358
81590
  return REGION_ALIAS_MAP[normalized];
81359
81591
  }
81360
81592
  function lerpColor(a2, b2, t2) {
81361
- const clamp2 = (v) => Math.max(0, Math.min(255, Math.round(v)));
81593
+ const clamp3 = (v) => Math.max(0, Math.min(255, Math.round(v)));
81362
81594
  const parse = (hex) => {
81363
81595
  const h2 = hex.replace("#", "");
81364
81596
  return [
@@ -81369,9 +81601,9 @@ function lerpColor(a2, b2, t2) {
81369
81601
  };
81370
81602
  const [r1, g1, b1] = parse(a2);
81371
81603
  const [r2, g2, b22] = parse(b2);
81372
- const r3 = clamp2(r1 + (r2 - r1) * t2);
81373
- const g3 = clamp2(g1 + (g2 - g1) * t2);
81374
- const bl = clamp2(b1 + (b22 - b1) * t2);
81604
+ const r3 = clamp3(r1 + (r2 - r1) * t2);
81605
+ const g3 = clamp3(g1 + (g2 - g1) * t2);
81606
+ const bl = clamp3(b1 + (b22 - b1) * t2);
81375
81607
  return `#${r3.toString(16).padStart(2, "0")}${g3.toString(16).padStart(2, "0")}${bl.toString(16).padStart(2, "0")}`;
81376
81608
  }
81377
81609
  function sequentialColorScale(t2) {
@@ -85329,6 +85561,15 @@ function copyFormatFromElement(element2) {
85329
85561
  }
85330
85562
  return result;
85331
85563
  }
85564
+ function definedEntries(obj) {
85565
+ const out = {};
85566
+ for (const key in obj) {
85567
+ if (obj[key] !== void 0) {
85568
+ out[key] = obj[key];
85569
+ }
85570
+ }
85571
+ return out;
85572
+ }
85332
85573
  function applyFormatToElement(element2, format) {
85333
85574
  let updated = { ...element2 };
85334
85575
  if (format.shapeStyle && hasShapeProperties(updated)) {
@@ -85336,7 +85577,7 @@ function applyFormatToElement(element2, format) {
85336
85577
  ...updated,
85337
85578
  shapeStyle: {
85338
85579
  ...updated.shapeStyle,
85339
- ...format.shapeStyle
85580
+ ...definedEntries(format.shapeStyle)
85340
85581
  }
85341
85582
  };
85342
85583
  }
@@ -85345,12 +85586,18 @@ function applyFormatToElement(element2, format) {
85345
85586
  ...updated,
85346
85587
  textStyle: {
85347
85588
  ...updated.textStyle,
85348
- ...format.textStyle
85589
+ ...definedEntries(format.textStyle)
85349
85590
  }
85350
85591
  };
85351
85592
  }
85352
85593
  return updated;
85353
85594
  }
85595
+ function hasCopyableFormat(element2) {
85596
+ if (!element2) {
85597
+ return false;
85598
+ }
85599
+ return hasShapeProperties(element2) || hasTextProperties(element2);
85600
+ }
85354
85601
 
85355
85602
  // src/viewer/utils/animation-preview.ts
85356
85603
  var PRESET_TO_EFFECT = {
@@ -86699,8 +86946,8 @@ function ThumbnailTable({
86699
86946
  {
86700
86947
  style: rowHeight ? { height: rowHeight } : void 0,
86701
86948
  children: cells.map((cell, ci) => {
86702
- const isHMerged = cell["@_hMerge"] === "1" || cell["@_hMerge"] === true;
86703
- const isVMerged = cell["@_vMerge"] === "1" || cell["@_vMerge"] === true;
86949
+ const isHMerged = cell["@_hMerge"] === "1";
86950
+ const isVMerged = cell["@_vMerge"] === "1";
86704
86951
  if (isHMerged || isVMerged) {
86705
86952
  return null;
86706
86953
  }
@@ -88123,6 +88370,59 @@ function WarpedText({
88123
88370
  }
88124
88371
  );
88125
88372
  }
88373
+ var GLYPH_BY_SHAPE = Object.fromEntries(
88374
+ ACTION_BUTTON_PRESETS.map((p3) => [p3.shapeType, p3.iconPath])
88375
+ );
88376
+ GLYPH_BY_SHAPE["actionButtonForwardOrNext"] = GLYPH_BY_SHAPE["actionButtonForwardNext"];
88377
+ GLYPH_BY_SHAPE["actionButtonBackOrPrevious"] = GLYPH_BY_SHAPE["actionButtonBackPrevious"];
88378
+ function isActionButtonShape(shapeType) {
88379
+ return Boolean(shapeType && shapeType in GLYPH_BY_SHAPE);
88380
+ }
88381
+ function getActionButtonGlyphPath(shapeType) {
88382
+ if (!shapeType) {
88383
+ return void 0;
88384
+ }
88385
+ const path = GLYPH_BY_SHAPE[shapeType];
88386
+ return path && path.length > 0 ? path : void 0;
88387
+ }
88388
+ function ActionButtonGlyphOverlay({
88389
+ element: element2,
88390
+ color
88391
+ }) {
88392
+ const shapeType = "shapeType" in element2 ? element2.shapeType : void 0;
88393
+ const path = getActionButtonGlyphPath(shapeType);
88394
+ if (!path) {
88395
+ return null;
88396
+ }
88397
+ const stroke = color ?? ("textStyle" in element2 && element2.textStyle?.color || "#ffffff");
88398
+ return /* @__PURE__ */ jsx(
88399
+ "svg",
88400
+ {
88401
+ viewBox: "0 0 24 24",
88402
+ width: "100%",
88403
+ height: "100%",
88404
+ preserveAspectRatio: "xMidYMid meet",
88405
+ style: {
88406
+ position: "absolute",
88407
+ inset: 0,
88408
+ pointerEvents: "none",
88409
+ padding: "20%"
88410
+ },
88411
+ "aria-hidden": "true",
88412
+ children: /* @__PURE__ */ jsx(
88413
+ "path",
88414
+ {
88415
+ d: path,
88416
+ fill: "none",
88417
+ stroke,
88418
+ strokeWidth: 2,
88419
+ strokeLinecap: "round",
88420
+ strokeLinejoin: "round"
88421
+ }
88422
+ )
88423
+ }
88424
+ );
88425
+ }
88126
88426
  function ColorChangedImage({
88127
88427
  src,
88128
88428
  clrChange,
@@ -88393,6 +88693,7 @@ function renderImg(el, style, filter, alt, opacity) {
88393
88693
  return /* @__PURE__ */ jsxs(Fragment, { children: [
88394
88694
  tileDuotoneColors && renderDuotoneSvgFilter(el.id, tileDuotoneColors.color1, tileDuotoneColors.color2),
88395
88695
  renderArtisticEffectSvgFilter(el.id, artisticEffectName, artisticRadius),
88696
+ renderImageAlphaSvgFilter(el),
88396
88697
  /* @__PURE__ */ jsx(
88397
88698
  "div",
88398
88699
  {
@@ -88414,6 +88715,7 @@ function renderImg(el, style, filter, alt, opacity) {
88414
88715
  return /* @__PURE__ */ jsxs(Fragment, { children: [
88415
88716
  duotoneColors && !useDuotoneCanvas && renderDuotoneSvgFilter(el.id, duotoneColors.color1, duotoneColors.color2),
88416
88717
  renderArtisticEffectSvgFilter(el.id, artisticEffectName, artisticRadius),
88718
+ renderImageAlphaSvgFilter(el),
88417
88719
  useDuotoneCanvas && duotoneColors ? /* @__PURE__ */ jsx(
88418
88720
  DuotoneImage,
88419
88721
  {
@@ -90922,8 +91224,11 @@ function renderBody(el, isImg, isEditing, editText, spellCheck, txtSE, txtS, vec
90922
91224
  ...scene3dStyle.perspective ? { perspective: scene3dStyle.perspective } : {},
90923
91225
  ...scene3dStyle.transformStyle ? { transformStyle: scene3dStyle.transformStyle } : {}
90924
91226
  } : void 0;
91227
+ const shapeTypeForGlyph = "shapeType" in el ? el.shapeType : void 0;
91228
+ const showActionButtonGlyph = isActionButtonShape(shapeTypeForGlyph);
90925
91229
  return /* @__PURE__ */ jsxs(Fragment, { children: [
90926
91230
  vecShape,
91231
+ showActionButtonGlyph && /* @__PURE__ */ jsx(ActionButtonGlyphOverlay, { element: el }),
90927
91232
  isTxtEl ? useSvgWarp ? /* @__PURE__ */ jsx(
90928
91233
  "div",
90929
91234
  {
@@ -91733,11 +92038,16 @@ function usePresenceTracking({
91733
92038
  if (cid === localClientId) {
91734
92039
  return;
91735
92040
  }
91736
- const raw = state2?.presence;
92041
+ const stateRecord = state2;
92042
+ const raw = stateRecord?.presence;
91737
92043
  if (!raw || typeof raw !== "object") {
91738
92044
  return;
91739
92045
  }
91740
- const sanitized = sanitizePresence({ ...raw, clientId: cid }, canvasWidth, canvasHeight);
92046
+ const sanitized = sanitizePresence(
92047
+ { ...raw, clientId: cid },
92048
+ canvasWidth,
92049
+ canvasHeight
92050
+ );
91741
92051
  if (!sanitized) {
91742
92052
  return;
91743
92053
  }
@@ -91805,15 +92115,9 @@ function useYjsProvider({ config }) {
91805
92115
  try {
91806
92116
  const [Y, { WebsocketProvider: WebsocketProvider2 }] = await Promise.all([Promise.resolve().then(() => (init_yjs(), yjs_exports)), Promise.resolve().then(() => (init_y_websocket(), y_websocket_exports))]);
91807
92117
  const yDoc = new Y.Doc();
91808
- const provider = new WebsocketProvider2(
91809
- config.serverUrl,
91810
- roomId,
91811
- yDoc,
91812
- // eslint-disable-line @typescript-eslint/no-explicit-any
91813
- {
91814
- params: config.authToken ? { token: config.authToken } : void 0
91815
- }
91816
- );
92118
+ const provider = new WebsocketProvider2(config.serverUrl, roomId, yDoc, {
92119
+ params: config.authToken ? { token: config.authToken } : void 0
92120
+ });
91817
92121
  let connected = false;
91818
92122
  const handleStatus = (event) => {
91819
92123
  if (event.status === "connected") {
@@ -95379,90 +95683,101 @@ var SlideNotesPanel = ({
95379
95683
  });
95380
95684
  const hasNotes = draft.trim().length > 0;
95381
95685
  const slideLabel = activeSlide ? t2("pptx.notes.slideN", { n: activeSlide.slideNumber }) : t2("pptx.notes.noSlide");
95382
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col border-t border-border/60 bg-background select-none", children: [
95383
- /* @__PURE__ */ jsxs(
95384
- "button",
95385
- {
95386
- type: "button",
95387
- onClick: onToggle,
95388
- className: "flex items-center gap-1.5 px-3 py-1 text-[11px] text-muted-foreground hover:text-foreground hover:bg-accent/30 transition-colors w-full text-left shrink-0",
95389
- "aria-expanded": isExpanded,
95390
- "aria-controls": "slide-notes-content",
95391
- children: [
95392
- "Notes",
95393
- !isExpanded && hasNotes && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/50 text-[10px]", children: "(has notes)" })
95394
- ]
95395
- }
95396
- ),
95397
- isExpanded && /* @__PURE__ */ jsxs(
95398
- "div",
95399
- {
95400
- id: "slide-notes-content",
95401
- className: "px-3 pb-2 overflow-y-auto",
95402
- style: { maxHeight: panelHeight ?? EXPANDED_MAX_HEIGHT + 40 },
95403
- children: [
95404
- /* @__PURE__ */ jsx("div", { className: "text-[10px] text-muted-foreground mb-1", children: slideLabel }),
95405
- canEdit ? /* @__PURE__ */ jsxs(Fragment, { children: [
95406
- /* @__PURE__ */ jsx(
95407
- NotesToolbar,
95408
- {
95409
- isRichEditEnabled,
95410
- showLinkPopover,
95411
- savedSelectionText: savedSelectionRef.current?.text ?? "",
95412
- hasAllSlides: allSlides !== void 0 && allSlides.length > 0,
95413
- onApplyRichCommand: applyRichCommand,
95414
- onToggleBulletList: toggleBulletList,
95415
- onToggleNumberedList: toggleNumberedList,
95416
- onIndent: handleIndent,
95417
- onOutdent: handleOutdent,
95418
- onLinkButtonClick: handleLinkButtonClick,
95419
- onInsertLink: handleInsertLink,
95420
- onCloseLinkPopover: () => setShowLinkPopover(false),
95421
- onPrintClick: () => setShowPrintDialog(true),
95422
- onToggleRichEdit: () => setIsRichEditEnabled((prev) => !prev)
95423
- }
95424
- ),
95425
- isRichEditEnabled ? /* @__PURE__ */ jsx(
95426
- "div",
95427
- {
95428
- ref: richEditorRef,
95429
- contentEditable: true,
95430
- suppressContentEditableWarning: true,
95431
- onInput: handleRichInput,
95432
- onBlur: handleBlur,
95433
- onKeyDown: handleKeyDownRich,
95434
- onClick: handleEditorClick,
95435
- className: "w-full overflow-y-auto rounded-md border border-border/50 bg-muted/60 px-2.5 py-1.5 text-xs text-foreground focus:border-primary/50 focus:outline-none focus:ring-1 focus:ring-primary/30 transition-colors whitespace-pre-wrap",
95436
- style: { maxHeight: EXPANDED_MAX_HEIGHT - 8, minHeight: 72 }
95437
- }
95438
- ) : /* @__PURE__ */ jsx(
95439
- "textarea",
95440
- {
95441
- ref: textareaRef,
95442
- name: "slide-notes",
95443
- value: draft,
95444
- onChange: handlePlainChange,
95445
- onBlur: handleBlur,
95446
- onKeyDown: handleKeyDownPlain,
95447
- placeholder: t2("pptx.notes.clickToAddNotes"),
95448
- rows: 4,
95449
- className: "w-full resize-none rounded-md border border-border/50 bg-muted/60 px-2.5 py-1.5 text-xs text-foreground placeholder:text-muted-foreground focus:border-primary/50 focus:outline-none focus:ring-1 focus:ring-primary/30 transition-colors",
95450
- style: { maxHeight: EXPANDED_MAX_HEIGHT - 8 }
95451
- }
95452
- )
95453
- ] }) : /* @__PURE__ */ jsx(
95454
- "div",
95455
- {
95456
- className: "w-full rounded-md border border-border/30 bg-muted/40 px-2.5 py-1.5 text-xs text-muted-foreground overflow-y-auto whitespace-pre-wrap",
95457
- style: { maxHeight: EXPANDED_MAX_HEIGHT - 32, minHeight: 60 },
95458
- children: hasNotes ? renderRichNotesSegments(draftSegments) : /* @__PURE__ */ jsx("span", { className: "italic text-muted-foreground", children: t2("pptx.notes.noNotes") })
95459
- }
95460
- )
95461
- ]
95462
- }
95463
- ),
95464
- showPrintDialog && allSlides && /* @__PURE__ */ jsx(NotesPrintDialog, { slides: allSlides, onClose: () => setShowPrintDialog(false) })
95465
- ] });
95686
+ return /* @__PURE__ */ jsxs(
95687
+ "div",
95688
+ {
95689
+ className: cn(
95690
+ "flex flex-col border-t border-border/60 bg-background select-none",
95691
+ // On mobile, hide the entire notes strip when collapsed — the
95692
+ // MobileBottomBar's Notes button is the entry point instead.
95693
+ !isExpanded && "max-md:hidden"
95694
+ ),
95695
+ children: [
95696
+ /* @__PURE__ */ jsxs(
95697
+ "button",
95698
+ {
95699
+ type: "button",
95700
+ onClick: onToggle,
95701
+ className: "flex items-center gap-1.5 px-3 py-1 text-[11px] text-muted-foreground hover:text-foreground hover:bg-accent/30 transition-colors w-full text-left shrink-0 max-md:hidden",
95702
+ "aria-expanded": isExpanded,
95703
+ "aria-controls": "slide-notes-content",
95704
+ children: [
95705
+ "Notes",
95706
+ !isExpanded && hasNotes && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/50 text-[10px]", children: "(has notes)" })
95707
+ ]
95708
+ }
95709
+ ),
95710
+ isExpanded && /* @__PURE__ */ jsxs(
95711
+ "div",
95712
+ {
95713
+ id: "slide-notes-content",
95714
+ className: "px-3 pb-2 overflow-y-auto",
95715
+ style: { maxHeight: panelHeight ?? EXPANDED_MAX_HEIGHT + 40 },
95716
+ children: [
95717
+ /* @__PURE__ */ jsx("div", { className: "text-[10px] text-muted-foreground mb-1", children: slideLabel }),
95718
+ canEdit ? /* @__PURE__ */ jsxs(Fragment, { children: [
95719
+ /* @__PURE__ */ jsx(
95720
+ NotesToolbar,
95721
+ {
95722
+ isRichEditEnabled,
95723
+ showLinkPopover,
95724
+ savedSelectionText: savedSelectionRef.current?.text ?? "",
95725
+ hasAllSlides: allSlides !== void 0 && allSlides.length > 0,
95726
+ onApplyRichCommand: applyRichCommand,
95727
+ onToggleBulletList: toggleBulletList,
95728
+ onToggleNumberedList: toggleNumberedList,
95729
+ onIndent: handleIndent,
95730
+ onOutdent: handleOutdent,
95731
+ onLinkButtonClick: handleLinkButtonClick,
95732
+ onInsertLink: handleInsertLink,
95733
+ onCloseLinkPopover: () => setShowLinkPopover(false),
95734
+ onPrintClick: () => setShowPrintDialog(true),
95735
+ onToggleRichEdit: () => setIsRichEditEnabled((prev) => !prev)
95736
+ }
95737
+ ),
95738
+ isRichEditEnabled ? /* @__PURE__ */ jsx(
95739
+ "div",
95740
+ {
95741
+ ref: richEditorRef,
95742
+ contentEditable: true,
95743
+ suppressContentEditableWarning: true,
95744
+ onInput: handleRichInput,
95745
+ onBlur: handleBlur,
95746
+ onKeyDown: handleKeyDownRich,
95747
+ onClick: handleEditorClick,
95748
+ className: "w-full overflow-y-auto rounded-md border border-border/50 bg-muted/60 px-2.5 py-1.5 text-xs text-foreground focus:border-primary/50 focus:outline-none focus:ring-1 focus:ring-primary/30 transition-colors whitespace-pre-wrap",
95749
+ style: { maxHeight: EXPANDED_MAX_HEIGHT - 8, minHeight: 72 }
95750
+ }
95751
+ ) : /* @__PURE__ */ jsx(
95752
+ "textarea",
95753
+ {
95754
+ ref: textareaRef,
95755
+ name: "slide-notes",
95756
+ value: draft,
95757
+ onChange: handlePlainChange,
95758
+ onBlur: handleBlur,
95759
+ onKeyDown: handleKeyDownPlain,
95760
+ placeholder: t2("pptx.notes.clickToAddNotes"),
95761
+ rows: 4,
95762
+ className: "w-full resize-none rounded-md border border-border/50 bg-muted/60 px-2.5 py-1.5 text-xs text-foreground placeholder:text-muted-foreground focus:border-primary/50 focus:outline-none focus:ring-1 focus:ring-primary/30 transition-colors",
95763
+ style: { maxHeight: EXPANDED_MAX_HEIGHT - 8 }
95764
+ }
95765
+ )
95766
+ ] }) : /* @__PURE__ */ jsx(
95767
+ "div",
95768
+ {
95769
+ className: "w-full rounded-md border border-border/30 bg-muted/40 px-2.5 py-1.5 text-xs text-muted-foreground overflow-y-auto whitespace-pre-wrap",
95770
+ style: { maxHeight: EXPANDED_MAX_HEIGHT - 32, minHeight: 60 },
95771
+ children: hasNotes ? renderRichNotesSegments(draftSegments) : /* @__PURE__ */ jsx("span", { className: "italic text-muted-foreground", children: t2("pptx.notes.noNotes") })
95772
+ }
95773
+ )
95774
+ ]
95775
+ }
95776
+ ),
95777
+ showPrintDialog && allSlides && /* @__PURE__ */ jsx(NotesPrintDialog, { slides: allSlides, onClose: () => setShowPrintDialog(false) })
95778
+ ]
95779
+ }
95780
+ );
95466
95781
  };
95467
95782
  var DB_NAME = "pptx-viewer-autosave";
95468
95783
  var DB_VERSION = 1;
@@ -97999,7 +98314,8 @@ function ArrangeSection(p3) {
97999
98314
  {
98000
98315
  type: "button",
98001
98316
  onClick: p3.onToggleFormatPainter,
98002
- disabled: !p3.canEdit,
98317
+ disabled: !p3.canEdit || p3.canActivateFormatPainter === false && !p3.formatPainterActive,
98318
+ "data-testid": "format-painter-toggle",
98003
98319
  className: cn(
98004
98320
  pill,
98005
98321
  p3.formatPainterActive ? "bg-amber-600 hover:bg-amber-500 text-amber-50" : ""
@@ -98451,7 +98767,8 @@ function HomeSection(p3) {
98451
98767
  const { fontFamily, fontSize } = extractFontInfo(p3.selectedElement);
98452
98768
  const handleNewSlide = useCallback(() => {
98453
98769
  if (p3.layoutOptions.length > 0) {
98454
- p3.onInsertSlideFromLayout(p3.layoutOptions[0].path);
98770
+ const first = p3.layoutOptions[0];
98771
+ p3.onInsertSlideFromLayout(first.path, first.name);
98455
98772
  }
98456
98773
  }, [p3]);
98457
98774
  useEffect(() => {
@@ -98538,7 +98855,8 @@ function HomeSection(p3) {
98538
98855
  {
98539
98856
  type: "button",
98540
98857
  onClick: p3.onToggleFormatPainter,
98541
- disabled: !p3.canEdit,
98858
+ disabled: !p3.canEdit || p3.canActivateFormatPainter === false && !p3.formatPainterActive,
98859
+ "data-testid": "format-painter-toggle",
98542
98860
  className: cn(
98543
98861
  gL,
98544
98862
  p3.formatPainterActive ? "bg-amber-600 hover:bg-amber-500 text-amber-50" : ""
@@ -98588,7 +98906,7 @@ function HomeSection(p3) {
98588
98906
  type: "button",
98589
98907
  className: "flex items-center gap-2 w-full px-3 py-1.5 text-xs text-foreground hover:bg-muted transition-colors",
98590
98908
  onClick: () => {
98591
- p3.onInsertSlideFromLayout(lo.path);
98909
+ p3.onInsertSlideFromLayout(lo.path, lo.name);
98592
98910
  setLayoutMenuOpen(false);
98593
98911
  },
98594
98912
  children: lo.name
@@ -99488,6 +99806,561 @@ function TextSection(p3) {
99488
99806
  ] })
99489
99807
  ] });
99490
99808
  }
99809
+ function ViewSection(p3) {
99810
+ const { t: t2 } = useTranslation();
99811
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
99812
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-0.5", children: [
99813
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5", children: [
99814
+ /* @__PURE__ */ jsx("button", { className: pill, title: "Normal view", children: "Normal" }),
99815
+ p3.onToggleSlideSorter ? /* @__PURE__ */ jsx("button", { className: pill, onClick: p3.onToggleSlideSorter, title: "Slide Sorter view", children: "Slide Sorter" }) : /* @__PURE__ */ jsx("button", { className: pill, title: "Slide Sorter view", children: "Slide Sorter" }),
99816
+ /* @__PURE__ */ jsx("button", { className: pill, title: "Reading View", children: "Reading View" })
99817
+ ] }),
99818
+ /* @__PURE__ */ jsx("span", { className: "text-[9px] text-muted-foreground leading-none", children: "Presentation Views" })
99819
+ ] }),
99820
+ sep,
99821
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-0.5", children: [
99822
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-0.5", children: /* @__PURE__ */ jsx(
99823
+ "button",
99824
+ {
99825
+ onClick: p3.onEnterMasterView,
99826
+ disabled: !p3.canEdit,
99827
+ className: pill,
99828
+ title: "Edit slide masters and layouts",
99829
+ children: "Slide Master"
99830
+ }
99831
+ ) }),
99832
+ /* @__PURE__ */ jsx("span", { className: "text-[9px] text-muted-foreground leading-none", children: "Master Views" })
99833
+ ] }),
99834
+ sep,
99835
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-0.5", children: [
99836
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-0.5", children: p3.onZoomToFit && /* @__PURE__ */ jsx("button", { className: pill, onClick: p3.onZoomToFit, title: "Zoom to fit slide in window", children: "Zoom to Fit" }) }),
99837
+ /* @__PURE__ */ jsx("span", { className: "text-[9px] text-muted-foreground leading-none", children: "Zoom" })
99838
+ ] }),
99839
+ sep,
99840
+ /* @__PURE__ */ jsx(
99841
+ "button",
99842
+ {
99843
+ onClick: () => p3.onSetEditTemplateMode(!p3.editTemplateMode),
99844
+ disabled: !p3.canEdit,
99845
+ className: cn(
99846
+ pill,
99847
+ p3.editTemplateMode ? "bg-amber-600 hover:bg-amber-500 text-amber-50" : ""
99848
+ ),
99849
+ title: "Toggle template/master element editing",
99850
+ children: p3.editTemplateMode ? "Templates On" : "Templates Off"
99851
+ }
99852
+ ),
99853
+ p3.onToggleSelectionPane && /* @__PURE__ */ jsxs(
99854
+ "button",
99855
+ {
99856
+ type: "button",
99857
+ onClick: p3.onToggleSelectionPane,
99858
+ className: cn(
99859
+ pill,
99860
+ p3.isSelectionPaneOpen ? "bg-primary hover:bg-primary/80 text-primary-foreground" : ""
99861
+ ),
99862
+ title: "Selection Pane",
99863
+ children: [
99864
+ /* @__PURE__ */ jsx(LuList, { className: ic2 }),
99865
+ "Selection"
99866
+ ]
99867
+ }
99868
+ ),
99869
+ p3.onToggleEyedropper && /* @__PURE__ */ jsxs(
99870
+ "button",
99871
+ {
99872
+ type: "button",
99873
+ onClick: p3.onToggleEyedropper,
99874
+ disabled: !p3.canEdit,
99875
+ className: cn(
99876
+ pill,
99877
+ p3.eyedropperActive ? "bg-purple-600 hover:bg-purple-500 text-purple-50" : ""
99878
+ ),
99879
+ title: "Eyedropper \u2014 sample a colour from the slide",
99880
+ children: [
99881
+ /* @__PURE__ */ jsx(LuPipette, { className: ic2 }),
99882
+ "Eyedropper"
99883
+ ]
99884
+ }
99885
+ ),
99886
+ /* @__PURE__ */ jsx(
99887
+ "button",
99888
+ {
99889
+ onClick: () => p3.onSetShowGrid(!p3.showGrid),
99890
+ className: cn(pill, p3.showGrid ? "bg-primary text-primary-foreground" : ""),
99891
+ title: t2("pptx.grid.toggleGrid"),
99892
+ children: t2("pptx.grid.grid")
99893
+ }
99894
+ ),
99895
+ /* @__PURE__ */ jsx(
99896
+ "button",
99897
+ {
99898
+ onClick: () => p3.onSetShowRulers(!p3.showRulers),
99899
+ className: cn(pill, p3.showRulers ? "bg-primary text-primary-foreground" : ""),
99900
+ title: t2("pptx.ruler.toggleRulers"),
99901
+ children: t2("pptx.ruler.rulers")
99902
+ }
99903
+ ),
99904
+ /* @__PURE__ */ jsx(
99905
+ "button",
99906
+ {
99907
+ onClick: () => p3.onSetSnapToGrid(!p3.snapToGrid),
99908
+ className: cn(pill, p3.snapToGrid ? "bg-primary text-primary-foreground" : ""),
99909
+ title: t2("pptx.grid.snapToGrid"),
99910
+ children: t2("pptx.grid.snapToGrid")
99911
+ }
99912
+ ),
99913
+ /* @__PURE__ */ jsx(
99914
+ "button",
99915
+ {
99916
+ onClick: () => p3.onSetSnapToShape(!p3.snapToShape),
99917
+ className: cn(pill, p3.snapToShape ? "bg-primary text-primary-foreground" : ""),
99918
+ title: t2("pptx.grid.snapToShape"),
99919
+ children: t2("pptx.grid.snapToShape")
99920
+ }
99921
+ ),
99922
+ /* @__PURE__ */ jsx("button", { onClick: () => p3.onAddGuide("h"), className: pill, title: "Add horizontal guide", children: "H Guide" }),
99923
+ /* @__PURE__ */ jsx("button", { onClick: () => p3.onAddGuide("v"), className: pill, title: "Add vertical guide", children: "V Guide" }),
99924
+ /* @__PURE__ */ jsx(
99925
+ "button",
99926
+ {
99927
+ onClick: () => p3.onSetSpellCheckEnabled(!p3.spellCheckEnabled),
99928
+ className: cn(pill, p3.spellCheckEnabled ? "bg-primary text-primary-foreground" : ""),
99929
+ title: "Toggle spell check",
99930
+ children: "Spell"
99931
+ }
99932
+ )
99933
+ ] });
99934
+ }
99935
+ function MobileSheet({
99936
+ open,
99937
+ onClose,
99938
+ title,
99939
+ children,
99940
+ heightFraction = 0.6,
99941
+ fullScreen = false,
99942
+ className,
99943
+ headerRight
99944
+ }) {
99945
+ const sheetRef = useRef(null);
99946
+ const [dragY, setDragY] = useState(0);
99947
+ const dragStartRef = useRef(null);
99948
+ const onPointerDown = useCallback((e2) => {
99949
+ dragStartRef.current = e2.clientY;
99950
+ e2.target.setPointerCapture?.(e2.pointerId);
99951
+ }, []);
99952
+ const onPointerMove = useCallback((e2) => {
99953
+ if (dragStartRef.current === null) {
99954
+ return;
99955
+ }
99956
+ const delta = e2.clientY - dragStartRef.current;
99957
+ setDragY(Math.max(0, delta));
99958
+ }, []);
99959
+ const onPointerUp = useCallback(
99960
+ (e2) => {
99961
+ if (dragStartRef.current === null) {
99962
+ return;
99963
+ }
99964
+ const delta = e2.clientY - dragStartRef.current;
99965
+ dragStartRef.current = null;
99966
+ e2.target.releasePointerCapture?.(e2.pointerId);
99967
+ if (delta > 120) {
99968
+ onClose();
99969
+ }
99970
+ setDragY(0);
99971
+ },
99972
+ [onClose]
99973
+ );
99974
+ useEffect(() => {
99975
+ if (!open) {
99976
+ return;
99977
+ }
99978
+ const handleKey = (e2) => {
99979
+ if (e2.key === "Escape") {
99980
+ onClose();
99981
+ }
99982
+ };
99983
+ window.addEventListener("keydown", handleKey);
99984
+ return () => window.removeEventListener("keydown", handleKey);
99985
+ }, [open, onClose]);
99986
+ if (!open) {
99987
+ return null;
99988
+ }
99989
+ const heightStyle = fullScreen ? { height: "calc(100dvh - env(safe-area-inset-top))" } : { height: `${Math.round(heightFraction * 100)}dvh` };
99990
+ return /* @__PURE__ */ jsxs(
99991
+ "div",
99992
+ {
99993
+ className: "fixed inset-0 z-50 flex flex-col justify-end md:hidden",
99994
+ role: "dialog",
99995
+ "aria-modal": "true",
99996
+ children: [
99997
+ /* @__PURE__ */ jsx(
99998
+ "button",
99999
+ {
100000
+ type: "button",
100001
+ "aria-label": "Close",
100002
+ className: "absolute inset-0 bg-black/40 backdrop-blur-[2px] animate-in fade-in duration-150",
100003
+ onClick: onClose
100004
+ }
100005
+ ),
100006
+ /* @__PURE__ */ jsxs(
100007
+ "div",
100008
+ {
100009
+ ref: sheetRef,
100010
+ className: cn(
100011
+ "relative bg-background border-t border-border rounded-t-2xl shadow-2xl flex flex-col overflow-hidden",
100012
+ "animate-in slide-in-from-bottom duration-200",
100013
+ className
100014
+ ),
100015
+ style: {
100016
+ ...heightStyle,
100017
+ transform: dragY > 0 ? `translateY(${dragY}px)` : void 0,
100018
+ transition: dragStartRef.current === null ? "transform 150ms ease-out" : "none"
100019
+ },
100020
+ children: [
100021
+ /* @__PURE__ */ jsx(
100022
+ "div",
100023
+ {
100024
+ className: "flex items-center justify-center pt-2 pb-1 cursor-grab active:cursor-grabbing touch-none",
100025
+ onPointerDown,
100026
+ onPointerMove,
100027
+ onPointerUp,
100028
+ onPointerCancel: onPointerUp,
100029
+ children: /* @__PURE__ */ jsx("div", { className: "h-1 w-10 rounded-full bg-muted-foreground/40" })
100030
+ }
100031
+ ),
100032
+ (title || headerRight) && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 px-4 pb-2 border-b border-border/60", children: [
100033
+ /* @__PURE__ */ jsx("div", { className: "text-sm font-semibold text-foreground truncate", children: title }),
100034
+ headerRight
100035
+ ] }),
100036
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto overscroll-contain", children })
100037
+ ]
100038
+ }
100039
+ )
100040
+ ]
100041
+ }
100042
+ );
100043
+ }
100044
+ var MENU_ITEMS = [
100045
+ { key: "home", label: "Home", icon: LuClipboardCopy },
100046
+ { key: "insert", label: "Insert", icon: LuPlus },
100047
+ { key: "text", label: "Text", icon: LuType },
100048
+ { key: "draw", label: "Draw", icon: LuPaintbrush },
100049
+ { key: "arrange", label: "Arrange", icon: LuShapes },
100050
+ { key: "design", label: "Design", icon: LuLayoutGrid },
100051
+ { key: "transitions", label: "Transitions", icon: LuSparkles },
100052
+ { key: "animations", label: "Animations", icon: LuWand },
100053
+ { key: "slideShow", label: "Slide Show", icon: LuPresentation },
100054
+ { key: "review", label: "Review", icon: LuTextCursorInput },
100055
+ { key: "view", label: "View", icon: LuSettings },
100056
+ { key: "file", label: "File", icon: LuFile }
100057
+ ];
100058
+ function MobileMenuSheet(props) {
100059
+ const { open, onClose } = props;
100060
+ const [active, setActive] = useState("home");
100061
+ return /* @__PURE__ */ jsx(MobileSheet, { open, onClose, fullScreen: true, title: "Menu", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
100062
+ /* @__PURE__ */ jsx("div", { className: "sticky top-0 z-10 bg-background border-b border-border", children: /* @__PURE__ */ jsx("div", { className: "flex gap-1.5 overflow-x-auto px-3 py-2 scrollbar-none", children: MENU_ITEMS.map(({ key, label, icon: Icon }) => /* @__PURE__ */ jsxs(
100063
+ "button",
100064
+ {
100065
+ type: "button",
100066
+ onClick: () => setActive(active === key ? null : key),
100067
+ className: cn(
100068
+ "inline-flex items-center gap-1.5 shrink-0 px-3 py-2 rounded-full text-[12px] font-medium border transition-colors min-h-[36px]",
100069
+ active === key ? "bg-primary text-primary-foreground border-primary" : "border-border text-muted-foreground hover:text-foreground hover:bg-accent/40"
100070
+ ),
100071
+ children: [
100072
+ /* @__PURE__ */ jsx(Icon, { className: "w-4 h-4" }),
100073
+ label
100074
+ ]
100075
+ },
100076
+ key
100077
+ )) }) }),
100078
+ /* @__PURE__ */ jsx("div", { className: "p-3", children: /* @__PURE__ */ jsx(MobileSectionBody, { active, ...props }) })
100079
+ ] }) });
100080
+ }
100081
+ function MobileSectionBody({
100082
+ active,
100083
+ ...p3
100084
+ }) {
100085
+ const wrap = "flex flex-wrap items-center gap-2";
100086
+ switch (active) {
100087
+ case "home":
100088
+ return /* @__PURE__ */ jsx("div", { className: wrap, children: /* @__PURE__ */ jsx(
100089
+ HomeSection,
100090
+ {
100091
+ canEdit: p3.canEdit,
100092
+ clipboardPayload: p3.clipboardPayload,
100093
+ formatPainterActive: p3.formatPainterActive,
100094
+ canActivateFormatPainter: p3.canActivateFormatPainter,
100095
+ onCopy: p3.onCopy,
100096
+ onCut: p3.onCut,
100097
+ onPaste: p3.onPaste,
100098
+ onToggleFormatPainter: p3.onToggleFormatPainter,
100099
+ layoutOptions: p3.layoutOptions,
100100
+ onInsertSlideFromLayout: p3.onInsertSlideFromLayout,
100101
+ selectedElement: p3.selectedElement,
100102
+ onUpdateTextStyle: p3.onUpdateTextStyle
100103
+ }
100104
+ ) });
100105
+ case "insert":
100106
+ return /* @__PURE__ */ jsx("div", { className: wrap, children: /* @__PURE__ */ jsx(
100107
+ InsertSection,
100108
+ {
100109
+ canEdit: p3.canEdit,
100110
+ newShapeType: p3.newShapeType,
100111
+ onSetNewShapeType: p3.onSetNewShapeType,
100112
+ onAddTextBox: p3.onAddTextBox,
100113
+ onAddShape: p3.onAddShape,
100114
+ onAddTable: p3.onAddTable,
100115
+ onAddSmartArt: p3.onAddSmartArt,
100116
+ onAddEquation: p3.onAddEquation,
100117
+ onAddActionButton: p3.onAddActionButton,
100118
+ onInsertField: p3.onInsertField,
100119
+ onOpenImagePicker: p3.onOpenImagePicker,
100120
+ onOpenMediaPicker: p3.onOpenMediaPicker
100121
+ }
100122
+ ) });
100123
+ case "text":
100124
+ return /* @__PURE__ */ jsx("div", { className: wrap, children: /* @__PURE__ */ jsx(
100125
+ TextSection,
100126
+ {
100127
+ canEdit: p3.canEdit,
100128
+ selectedElement: p3.selectedElement,
100129
+ tableEditorState: p3.tableEditorState,
100130
+ onUpdateTextStyle: p3.onUpdateTextStyle
100131
+ }
100132
+ ) });
100133
+ case "draw":
100134
+ return /* @__PURE__ */ jsx("div", { className: wrap, children: /* @__PURE__ */ jsx(
100135
+ DrawSection,
100136
+ {
100137
+ activeTool: p3.activeTool,
100138
+ drawingColor: p3.drawingColor,
100139
+ drawingWidth: p3.drawingWidth,
100140
+ onSetActiveTool: p3.onSetActiveTool,
100141
+ onSetDrawingColor: p3.onSetDrawingColor,
100142
+ onSetDrawingWidth: p3.onSetDrawingWidth
100143
+ }
100144
+ ) });
100145
+ case "arrange":
100146
+ return /* @__PURE__ */ jsx("div", { className: wrap, children: /* @__PURE__ */ jsx(
100147
+ ArrangeSection,
100148
+ {
100149
+ canEdit: p3.canEdit,
100150
+ selectedElement: p3.selectedElement,
100151
+ clipboardPayload: p3.clipboardPayload,
100152
+ onAlignElements: p3.onAlignElements,
100153
+ onCopy: p3.onCopy,
100154
+ onCut: p3.onCut,
100155
+ onPaste: p3.onPaste,
100156
+ onFlip: p3.onFlip,
100157
+ onMoveLayer: p3.onMoveLayer,
100158
+ onMoveLayerToEdge: p3.onMoveLayerToEdge,
100159
+ onDuplicate: p3.onDuplicate,
100160
+ onDelete: p3.onDelete,
100161
+ formatPainterActive: p3.formatPainterActive,
100162
+ onToggleFormatPainter: p3.onToggleFormatPainter,
100163
+ canActivateFormatPainter: p3.canActivateFormatPainter
100164
+ }
100165
+ ) });
100166
+ case "design":
100167
+ return /* @__PURE__ */ jsx("div", { className: wrap, children: /* @__PURE__ */ jsx(
100168
+ DesignSection,
100169
+ {
100170
+ canEdit: p3.canEdit,
100171
+ onToggleThemeGallery: p3.onToggleThemeGallery,
100172
+ isThemeGalleryOpen: p3.isThemeGalleryOpen,
100173
+ onToggleThemeEditor: p3.onToggleThemeEditor,
100174
+ isThemeEditorOpen: p3.isThemeEditorOpen,
100175
+ onOpenDocumentProperties: p3.onOpenDocumentProperties,
100176
+ onToggleInspector: p3.onToggleInspector,
100177
+ isInspectorPaneOpen: p3.isInspectorPaneOpen
100178
+ }
100179
+ ) });
100180
+ case "transitions":
100181
+ return /* @__PURE__ */ jsx("div", { className: wrap, children: /* @__PURE__ */ jsx(
100182
+ TransitionsSection,
100183
+ {
100184
+ isInspectorPaneOpen: p3.isInspectorPaneOpen,
100185
+ onToggleInspector: p3.onToggleInspector
100186
+ }
100187
+ ) });
100188
+ case "animations":
100189
+ return /* @__PURE__ */ jsx("div", { className: wrap, children: /* @__PURE__ */ jsx(
100190
+ AnimationsSection,
100191
+ {
100192
+ canEdit: p3.canEdit,
100193
+ selectedElement: p3.selectedElement,
100194
+ isInspectorPaneOpen: p3.isInspectorPaneOpen,
100195
+ onToggleInspector: p3.onToggleInspector,
100196
+ onOpenAnimationPanel: p3.onOpenAnimationPanel,
100197
+ onAddAnimation: p3.onAddAnimation,
100198
+ onRemoveAnimation: p3.onRemoveAnimation
100199
+ }
100200
+ ) });
100201
+ case "slideShow":
100202
+ return /* @__PURE__ */ jsx("div", { className: wrap, children: /* @__PURE__ */ jsx(
100203
+ SlideShowSection,
100204
+ {
100205
+ onPresent: () => p3.onSetMode("present"),
100206
+ onEnterPresenterView: p3.onEnterPresenterView ?? (() => {
100207
+ }),
100208
+ onEnterRehearsalMode: p3.onEnterRehearsalMode ?? (() => {
100209
+ }),
100210
+ onOpenSetUpSlideShow: p3.onOpenSetUpSlideShow ?? (() => {
100211
+ }),
100212
+ onOpenBroadcastDialog: p3.onOpenBroadcastDialog ?? (() => {
100213
+ }),
100214
+ onToggleSubtitles: p3.onToggleSubtitles ?? (() => {
100215
+ }),
100216
+ showSubtitles: p3.showSubtitles ?? false,
100217
+ onSetMode: p3.onSetMode
100218
+ }
100219
+ ) });
100220
+ case "review":
100221
+ return /* @__PURE__ */ jsx("div", { className: wrap, children: /* @__PURE__ */ jsx(
100222
+ ReviewSection,
100223
+ {
100224
+ canEdit: p3.canEdit,
100225
+ spellCheckEnabled: p3.spellCheckEnabled,
100226
+ onSetSpellCheckEnabled: p3.onSetSpellCheckEnabled,
100227
+ onToggleComments: p3.onToggleComments,
100228
+ isCommentsPanelOpen: p3.isCommentsPanelOpen,
100229
+ slideCommentCount: p3.slideCommentCount,
100230
+ onCompare: p3.onCompare
100231
+ }
100232
+ ) });
100233
+ case "view":
100234
+ return /* @__PURE__ */ jsx("div", { className: wrap, children: /* @__PURE__ */ jsx(
100235
+ ViewSection,
100236
+ {
100237
+ canEdit: p3.canEdit,
100238
+ editTemplateMode: p3.editTemplateMode,
100239
+ onSetEditTemplateMode: p3.onSetEditTemplateMode,
100240
+ spellCheckEnabled: p3.spellCheckEnabled,
100241
+ onSetSpellCheckEnabled: p3.onSetSpellCheckEnabled,
100242
+ showGrid: p3.showGrid,
100243
+ showRulers: p3.showRulers,
100244
+ snapToGrid: p3.snapToGrid,
100245
+ snapToShape: p3.snapToShape,
100246
+ onSetShowGrid: p3.onSetShowGrid,
100247
+ onSetShowRulers: p3.onSetShowRulers,
100248
+ onSetSnapToGrid: p3.onSetSnapToGrid,
100249
+ onSetSnapToShape: p3.onSetSnapToShape,
100250
+ onAddGuide: p3.onAddGuide,
100251
+ onEnterMasterView: p3.onEnterMasterView,
100252
+ isSelectionPaneOpen: p3.isSelectionPaneOpen,
100253
+ onToggleSelectionPane: p3.onToggleSelectionPane,
100254
+ eyedropperActive: p3.eyedropperActive,
100255
+ onToggleEyedropper: p3.onToggleEyedropper
100256
+ }
100257
+ ) });
100258
+ case "file":
100259
+ return /* @__PURE__ */ jsx("div", { className: wrap, children: /* @__PURE__ */ jsx(
100260
+ FileSection,
100261
+ {
100262
+ onExportPng: p3.onExportPng,
100263
+ onExportPdf: p3.onExportPdf,
100264
+ onExportVideo: p3.onExportVideo,
100265
+ onExportGif: p3.onExportGif,
100266
+ onPackageForSharing: p3.onPackageForSharing,
100267
+ onSaveAsPptx: p3.onSaveAsPptx,
100268
+ onSaveAsPpsx: p3.onSaveAsPpsx,
100269
+ onSaveAsPptm: p3.onSaveAsPptm,
100270
+ hasMacros: p3.hasMacros,
100271
+ onCopySlideAsImage: p3.onCopySlideAsImage,
100272
+ onPrint: p3.onPrint,
100273
+ onOpenDocumentProperties: p3.onOpenDocumentProperties,
100274
+ onOpenPasswordProtection: p3.onOpenPasswordProtection,
100275
+ onOpenFontEmbedding: p3.onOpenFontEmbedding,
100276
+ onOpenDigitalSignatures: p3.onOpenDigitalSignatures
100277
+ }
100278
+ ) });
100279
+ default:
100280
+ return /* @__PURE__ */ jsxs("div", { className: "text-center text-sm text-muted-foreground py-8", children: [
100281
+ /* @__PURE__ */ jsx(LuChevronRight, { className: "w-5 h-5 inline-block opacity-50" }),
100282
+ " Select a section above"
100283
+ ] });
100284
+ }
100285
+ }
100286
+ function MobileToolbar(props) {
100287
+ const { t: t2 } = useTranslation();
100288
+ const { mode, canUndo, canRedo, onUndo, onRedo, onSetMode } = props;
100289
+ const [menuOpen, setMenuOpen] = useState(false);
100290
+ const showEdit = mode === "edit" || mode === "master";
100291
+ const btn = "inline-flex items-center justify-center min-w-[44px] min-h-[44px] rounded-md text-foreground/80 hover:bg-accent/60 disabled:opacity-40 disabled:cursor-not-allowed active:scale-95 transition-transform";
100292
+ return /* @__PURE__ */ jsxs(
100293
+ "div",
100294
+ {
100295
+ role: "toolbar",
100296
+ "aria-label": "Toolbar",
100297
+ className: "relative z-20 flex items-center gap-1 px-2 py-1 border-b border-border bg-secondary/50 min-h-[52px] pt-[max(env(safe-area-inset-top),0px)]",
100298
+ children: [
100299
+ showEdit && /* @__PURE__ */ jsx(
100300
+ "button",
100301
+ {
100302
+ type: "button",
100303
+ onClick: () => setMenuOpen(true),
100304
+ className: btn,
100305
+ title: "Menu",
100306
+ "aria-label": "Menu",
100307
+ children: /* @__PURE__ */ jsx(LuMenu, { className: "w-5 h-5" })
100308
+ }
100309
+ ),
100310
+ showEdit && /* @__PURE__ */ jsxs(Fragment, { children: [
100311
+ /* @__PURE__ */ jsx(
100312
+ "button",
100313
+ {
100314
+ type: "button",
100315
+ onClick: onUndo,
100316
+ disabled: !canUndo,
100317
+ className: btn,
100318
+ title: t2("pptx.toolbar.undo"),
100319
+ "aria-label": t2("pptx.toolbar.undo"),
100320
+ children: /* @__PURE__ */ jsx(LuUndo, { className: "w-5 h-5" })
100321
+ }
100322
+ ),
100323
+ /* @__PURE__ */ jsx(
100324
+ "button",
100325
+ {
100326
+ type: "button",
100327
+ onClick: onRedo,
100328
+ disabled: !canRedo,
100329
+ className: btn,
100330
+ title: t2("pptx.toolbar.redo"),
100331
+ "aria-label": t2("pptx.toolbar.redo"),
100332
+ children: /* @__PURE__ */ jsx(LuRedo, { className: "w-5 h-5" })
100333
+ }
100334
+ )
100335
+ ] }),
100336
+ /* @__PURE__ */ jsx("div", { className: "flex-1" }),
100337
+ /* @__PURE__ */ jsx(
100338
+ "button",
100339
+ {
100340
+ type: "button",
100341
+ onClick: () => onSetMode("present"),
100342
+ className: cn(btn, "text-primary"),
100343
+ title: t2("pptx.toolbar.present"),
100344
+ "aria-label": t2("pptx.toolbar.present"),
100345
+ children: /* @__PURE__ */ jsx(LuPresentation, { className: "w-5 h-5" })
100346
+ }
100347
+ ),
100348
+ showEdit && /* @__PURE__ */ jsx(
100349
+ "button",
100350
+ {
100351
+ type: "button",
100352
+ onClick: props.onOpenShareDialog ?? props.onPackageForSharing,
100353
+ className: cn(btn, "bg-primary text-primary-foreground hover:bg-primary/90 px-3"),
100354
+ title: t2("pptx.toolbar.share"),
100355
+ "aria-label": t2("pptx.toolbar.share"),
100356
+ children: /* @__PURE__ */ jsx(LuShare2, { className: "w-4 h-4" })
100357
+ }
100358
+ ),
100359
+ /* @__PURE__ */ jsx(MobileMenuSheet, { open: menuOpen, onClose: () => setMenuOpen(false), ...props })
100360
+ ]
100361
+ }
100362
+ );
100363
+ }
99491
100364
  function CustomShowsControls({
99492
100365
  customShows,
99493
100366
  activeCustomShowId,
@@ -99916,7 +100789,7 @@ function ToolbarPrimaryRow(p3) {
99916
100789
  onClick: p3.onToggleComments,
99917
100790
  className: cn(
99918
100791
  qab,
99919
- "max-md:hidden",
100792
+ "relative max-md:hidden",
99920
100793
  p3.isCommentsPanelOpen ? "text-foreground" : "text-muted-foreground"
99921
100794
  ),
99922
100795
  title: t2("pptx.toolbar.comments"),
@@ -100032,134 +100905,11 @@ function ToolbarPrimaryRow(p3) {
100032
100905
  /* @__PURE__ */ jsx(OverflowMenu, { ...p3 })
100033
100906
  ] });
100034
100907
  }
100035
- function ViewSection(p3) {
100036
- const { t: t2 } = useTranslation();
100037
- return /* @__PURE__ */ jsxs(Fragment, { children: [
100038
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-0.5", children: [
100039
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5", children: [
100040
- /* @__PURE__ */ jsx("button", { className: pill, title: "Normal view", children: "Normal" }),
100041
- p3.onToggleSlideSorter ? /* @__PURE__ */ jsx("button", { className: pill, onClick: p3.onToggleSlideSorter, title: "Slide Sorter view", children: "Slide Sorter" }) : /* @__PURE__ */ jsx("button", { className: pill, title: "Slide Sorter view", children: "Slide Sorter" }),
100042
- /* @__PURE__ */ jsx("button", { className: pill, title: "Reading View", children: "Reading View" })
100043
- ] }),
100044
- /* @__PURE__ */ jsx("span", { className: "text-[9px] text-muted-foreground leading-none", children: "Presentation Views" })
100045
- ] }),
100046
- sep,
100047
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-0.5", children: [
100048
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-0.5", children: /* @__PURE__ */ jsx(
100049
- "button",
100050
- {
100051
- onClick: p3.onEnterMasterView,
100052
- disabled: !p3.canEdit,
100053
- className: pill,
100054
- title: "Edit slide masters and layouts",
100055
- children: "Slide Master"
100056
- }
100057
- ) }),
100058
- /* @__PURE__ */ jsx("span", { className: "text-[9px] text-muted-foreground leading-none", children: "Master Views" })
100059
- ] }),
100060
- sep,
100061
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-0.5", children: [
100062
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-0.5", children: p3.onZoomToFit && /* @__PURE__ */ jsx("button", { className: pill, onClick: p3.onZoomToFit, title: "Zoom to fit slide in window", children: "Zoom to Fit" }) }),
100063
- /* @__PURE__ */ jsx("span", { className: "text-[9px] text-muted-foreground leading-none", children: "Zoom" })
100064
- ] }),
100065
- sep,
100066
- /* @__PURE__ */ jsx(
100067
- "button",
100068
- {
100069
- onClick: () => p3.onSetEditTemplateMode(!p3.editTemplateMode),
100070
- disabled: !p3.canEdit,
100071
- className: cn(
100072
- pill,
100073
- p3.editTemplateMode ? "bg-amber-600 hover:bg-amber-500 text-amber-50" : ""
100074
- ),
100075
- title: "Toggle template/master element editing",
100076
- children: p3.editTemplateMode ? "Templates On" : "Templates Off"
100077
- }
100078
- ),
100079
- p3.onToggleSelectionPane && /* @__PURE__ */ jsxs(
100080
- "button",
100081
- {
100082
- type: "button",
100083
- onClick: p3.onToggleSelectionPane,
100084
- className: cn(
100085
- pill,
100086
- p3.isSelectionPaneOpen ? "bg-primary hover:bg-primary/80 text-primary-foreground" : ""
100087
- ),
100088
- title: "Selection Pane",
100089
- children: [
100090
- /* @__PURE__ */ jsx(LuList, { className: ic2 }),
100091
- "Selection"
100092
- ]
100093
- }
100094
- ),
100095
- p3.onToggleEyedropper && /* @__PURE__ */ jsxs(
100096
- "button",
100097
- {
100098
- type: "button",
100099
- onClick: p3.onToggleEyedropper,
100100
- disabled: !p3.canEdit,
100101
- className: cn(
100102
- pill,
100103
- p3.eyedropperActive ? "bg-purple-600 hover:bg-purple-500 text-purple-50" : ""
100104
- ),
100105
- title: "Eyedropper \u2014 sample a colour from the slide",
100106
- children: [
100107
- /* @__PURE__ */ jsx(LuPipette, { className: ic2 }),
100108
- "Eyedropper"
100109
- ]
100110
- }
100111
- ),
100112
- /* @__PURE__ */ jsx(
100113
- "button",
100114
- {
100115
- onClick: () => p3.onSetShowGrid(!p3.showGrid),
100116
- className: cn(pill, p3.showGrid ? "bg-primary text-primary-foreground" : ""),
100117
- title: t2("pptx.grid.toggleGrid"),
100118
- children: t2("pptx.grid.grid")
100119
- }
100120
- ),
100121
- /* @__PURE__ */ jsx(
100122
- "button",
100123
- {
100124
- onClick: () => p3.onSetShowRulers(!p3.showRulers),
100125
- className: cn(pill, p3.showRulers ? "bg-primary text-primary-foreground" : ""),
100126
- title: t2("pptx.ruler.toggleRulers"),
100127
- children: t2("pptx.ruler.rulers")
100128
- }
100129
- ),
100130
- /* @__PURE__ */ jsx(
100131
- "button",
100132
- {
100133
- onClick: () => p3.onSetSnapToGrid(!p3.snapToGrid),
100134
- className: cn(pill, p3.snapToGrid ? "bg-primary text-primary-foreground" : ""),
100135
- title: t2("pptx.grid.snapToGrid"),
100136
- children: t2("pptx.grid.snapToGrid")
100137
- }
100138
- ),
100139
- /* @__PURE__ */ jsx(
100140
- "button",
100141
- {
100142
- onClick: () => p3.onSetSnapToShape(!p3.snapToShape),
100143
- className: cn(pill, p3.snapToShape ? "bg-primary text-primary-foreground" : ""),
100144
- title: t2("pptx.grid.snapToShape"),
100145
- children: t2("pptx.grid.snapToShape")
100146
- }
100147
- ),
100148
- /* @__PURE__ */ jsx("button", { onClick: () => p3.onAddGuide("h"), className: pill, title: "Add horizontal guide", children: "H Guide" }),
100149
- /* @__PURE__ */ jsx("button", { onClick: () => p3.onAddGuide("v"), className: pill, title: "Add vertical guide", children: "V Guide" }),
100150
- /* @__PURE__ */ jsx(
100151
- "button",
100152
- {
100153
- onClick: () => p3.onSetSpellCheckEnabled(!p3.spellCheckEnabled),
100154
- className: cn(pill, p3.spellCheckEnabled ? "bg-primary text-primary-foreground" : ""),
100155
- title: "Toggle spell check",
100156
- children: "Spell"
100157
- }
100158
- )
100159
- ] });
100160
- }
100161
100908
  function Toolbar(p3) {
100162
100909
  const { mode, isNarrowViewport, isCompactToolbarOpen, toolbarSection, onSetToolbarSection } = p3;
100910
+ if (isNarrowViewport && mode !== "present") {
100911
+ return /* @__PURE__ */ jsx(MobileToolbar, { ...p3 });
100912
+ }
100163
100913
  const sFil = toolbarSection === "file";
100164
100914
  const sHome = toolbarSection === "home";
100165
100915
  const sIns = toolbarSection === "insert";
@@ -100245,6 +100995,7 @@ function Toolbar(p3) {
100245
100995
  canEdit: p3.canEdit,
100246
100996
  clipboardPayload: p3.clipboardPayload,
100247
100997
  formatPainterActive: p3.formatPainterActive,
100998
+ canActivateFormatPainter: p3.canActivateFormatPainter,
100248
100999
  onCopy: p3.onCopy,
100249
101000
  onCut: p3.onCut,
100250
101001
  onPaste: p3.onPaste,
@@ -100308,7 +101059,8 @@ function Toolbar(p3) {
100308
101059
  onDuplicate: p3.onDuplicate,
100309
101060
  onDelete: p3.onDelete,
100310
101061
  formatPainterActive: p3.formatPainterActive,
100311
- onToggleFormatPainter: p3.onToggleFormatPainter
101062
+ onToggleFormatPainter: p3.onToggleFormatPainter,
101063
+ canActivateFormatPainter: p3.canActivateFormatPainter
100312
101064
  }
100313
101065
  ),
100314
101066
  sDes && /* @__PURE__ */ jsx(
@@ -106021,181 +106773,194 @@ function InspectorPane(props) {
106021
106773
  const fallback = themeOptions[0]?.path ?? "";
106022
106774
  setSelectedThemePath((previous) => previous || fallback);
106023
106775
  }, [slideMasters, themeOptions]);
106024
- return /* @__PURE__ */ jsxs(
106025
- "div",
106026
- {
106027
- className: cn(
106028
- // Shared styles
106029
- "bg-background flex flex-col text-xs text-foreground shadow-xl",
106030
- // Mobile: absolute bottom sheet overlay
106031
- "max-md:fixed max-md:inset-x-0 max-md:bottom-0 max-md:top-auto max-md:w-full max-md:max-h-[60vh] max-md:rounded-t-xl max-md:border-t max-md:border-border max-md:z-30",
106032
- "max-md:transition-transform max-md:duration-200 max-md:ease-in-out",
106033
- isOpen ? "max-md:translate-y-0" : "max-md:translate-y-full",
106034
- // Desktop: flow-based flex child (takes space from canvas)
106035
- "md:h-full md:border-l md:border-border",
106036
- !panelWidth && "md:w-72"
106037
- ),
106038
- style: panelWidth ? { width: panelWidth } : void 0,
106039
- children: [
106040
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 px-3 py-2 border-b border-border", children: [
106041
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1 rounded bg-muted p-0.5", children: INSPECTOR_TABS.map(({ key, label, icon: Icon }) => /* @__PURE__ */ jsxs(
106042
- "button",
106043
- {
106044
- type: "button",
106045
- title: label,
106046
- className: cn(
106047
- "flex items-center gap-1 px-2 py-1 rounded text-[11px] transition-colors",
106048
- activeTab === key ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:text-foreground hover:bg-accent"
106049
- ),
106050
- onClick: () => onSetActiveTab(key),
106051
- children: [
106052
- /* @__PURE__ */ jsx(Icon, { className: "w-3.5 h-3.5" }),
106053
- /* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: label })
106054
- ]
106055
- },
106056
- key
106057
- )) }),
106058
- /* @__PURE__ */ jsx(
106059
- "button",
106060
- {
106061
- type: "button",
106062
- onClick: onClose,
106063
- title: t2("common.close"),
106064
- className: "p-1 rounded text-muted-foreground hover:text-foreground hover:bg-muted transition-colors",
106065
- children: /* @__PURE__ */ jsx(LuX, { className: "w-4 h-4" })
106066
- }
106067
- )
106068
- ] }),
106069
- /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto p-3 space-y-3", children: [
106070
- activeTab === "elements" && /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
106071
- /* @__PURE__ */ jsx("div", { className: cn(HEADING, "mb-2"), children: t2("pptx.inspector.layerOrder") }),
106072
- activeSlide ? [...activeSlide.elements || []].reverse().map((el, ri) => {
106073
- const idx = (activeSlide.elements || []).length - 1 - ri;
106074
- const sel = selectedElement?.id === el.id || selectedElementIds.includes(el.id);
106075
- const label = (hasTextProperties(el) ? (el.text || "").slice(0, 24) : void 0) || el.type;
106076
- return /* @__PURE__ */ jsxs(
106077
- "div",
106078
- {
106079
- title: `${el.type} \u2014 ${el.id}`,
106080
- className: cn(
106081
- "flex items-center gap-2 px-2 py-1 rounded cursor-pointer transition-colors",
106082
- sel ? "bg-primary/30 text-primary" : "hover:bg-muted text-foreground"
106083
- ),
106084
- onClick: () => onSelectElement(el.id),
106085
- children: [
106086
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground w-4 text-right", children: idx + 1 }),
106087
- /* @__PURE__ */ jsx("span", { className: "flex-1 truncate", children: label })
106088
- ]
106089
- },
106090
- el.id
106091
- );
106092
- }) : /* @__PURE__ */ jsx("div", { className: "text-muted-foreground italic", children: t2("pptx.inspector.noSlideSelected") })
106093
- ] }),
106094
- activeTab === "properties" && /* @__PURE__ */ jsx("div", { className: "space-y-3", children: hasSelection && selectedElement ? /* @__PURE__ */ jsx(
106095
- ElementInspectorBody,
106096
- {
106097
- selectedElement,
106098
- canEdit,
106099
- slides,
106100
- tableEditorState,
106101
- mediaDataUrls,
106102
- onUpdateElement,
106103
- onUpdateElementStyle,
106104
- onUpdateTextStyle,
106105
- onMoveLayer
106106
- }
106107
- ) : /* @__PURE__ */ jsxs(Fragment, { children: [
106776
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
106777
+ isOpen && /* @__PURE__ */ jsx(
106778
+ "button",
106779
+ {
106780
+ type: "button",
106781
+ "aria-label": t2("common.close"),
106782
+ onClick: onClose,
106783
+ className: "md:hidden fixed inset-0 z-20 bg-black/40 backdrop-blur-[2px] animate-in fade-in duration-150"
106784
+ }
106785
+ ),
106786
+ /* @__PURE__ */ jsxs(
106787
+ "div",
106788
+ {
106789
+ className: cn(
106790
+ // Shared styles
106791
+ "bg-background flex flex-col text-xs text-foreground shadow-xl",
106792
+ // Mobile: absolute bottom sheet overlay sized via dvh so it
106793
+ // adapts to the on-screen keyboard / dynamic browser chrome.
106794
+ "max-md:fixed max-md:inset-x-0 max-md:bottom-0 max-md:top-auto max-md:w-full max-md:max-h-[75dvh] max-md:rounded-t-2xl max-md:border-t max-md:border-border max-md:z-30 max-md:pb-[max(env(safe-area-inset-bottom),0px)]",
106795
+ "max-md:transition-transform max-md:duration-200 max-md:ease-in-out",
106796
+ isOpen ? "max-md:translate-y-0" : "max-md:translate-y-full",
106797
+ // Desktop: flow-based flex child (takes space from canvas)
106798
+ "md:h-full md:border-l md:border-border",
106799
+ !panelWidth && "md:w-72"
106800
+ ),
106801
+ style: panelWidth ? { width: panelWidth } : void 0,
106802
+ children: [
106803
+ /* @__PURE__ */ jsx("div", { className: "md:hidden flex items-center justify-center pt-2 pb-1", children: /* @__PURE__ */ jsx("div", { className: "h-1 w-10 rounded-full bg-muted-foreground/40" }) }),
106804
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 px-3 py-2 border-b border-border", children: [
106805
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1 rounded bg-muted p-0.5", children: INSPECTOR_TABS.map(({ key, label, icon: Icon }) => /* @__PURE__ */ jsxs(
106806
+ "button",
106807
+ {
106808
+ type: "button",
106809
+ title: label,
106810
+ className: cn(
106811
+ "flex items-center gap-1 px-2 py-1 rounded text-[11px] transition-colors",
106812
+ activeTab === key ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:text-foreground hover:bg-accent"
106813
+ ),
106814
+ onClick: () => onSetActiveTab(key),
106815
+ children: [
106816
+ /* @__PURE__ */ jsx(Icon, { className: "w-3.5 h-3.5" }),
106817
+ /* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: label })
106818
+ ]
106819
+ },
106820
+ key
106821
+ )) }),
106108
106822
  /* @__PURE__ */ jsx(
106109
- PresentationPropertiesPanel,
106823
+ "button",
106110
106824
  {
106111
- canEdit,
106112
- canvasSize,
106113
- presentationProperties,
106114
- onUpdatePresentationProperties,
106115
- notesMaster,
106116
- handoutMaster,
106117
- notesCanvasSize,
106118
- coreProperties,
106119
- appProperties,
106120
- customProperties,
106121
- themeOptions,
106122
- selectedThemePath,
106123
- setSelectedThemePath,
106124
- onApplyTheme,
106125
- onUpdateCoreProperties,
106126
- onUpdateAppProperties,
106127
- onUpdateCustomProperties,
106128
- tagCollections,
106129
- onUpdateTagCollections,
106130
- onUpdateCanvasSize,
106131
- activeSlide,
106132
- theme,
106133
- onUpdateSlide
106825
+ type: "button",
106826
+ onClick: onClose,
106827
+ title: t2("common.close"),
106828
+ className: "p-1 rounded text-muted-foreground hover:text-foreground hover:bg-muted transition-colors",
106829
+ children: /* @__PURE__ */ jsx(LuX, { className: "w-4 h-4" })
106134
106830
  }
106135
- ),
106136
- activeSlide && /* @__PURE__ */ jsx(
106137
- SlideBackgroundPanel,
106831
+ )
106832
+ ] }),
106833
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto p-3 space-y-3", children: [
106834
+ activeTab === "elements" && /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
106835
+ /* @__PURE__ */ jsx("div", { className: cn(HEADING, "mb-2"), children: t2("pptx.inspector.layerOrder") }),
106836
+ activeSlide ? [...activeSlide.elements || []].reverse().map((el, ri) => {
106837
+ const idx = (activeSlide.elements || []).length - 1 - ri;
106838
+ const sel = selectedElement?.id === el.id || selectedElementIds.includes(el.id);
106839
+ const label = (hasTextProperties(el) ? (el.text || "").slice(0, 24) : void 0) || el.type;
106840
+ return /* @__PURE__ */ jsxs(
106841
+ "div",
106842
+ {
106843
+ title: `${el.type} \u2014 ${el.id}`,
106844
+ className: cn(
106845
+ "flex items-center gap-2 px-2 py-1 rounded cursor-pointer transition-colors",
106846
+ sel ? "bg-primary/30 text-primary" : "hover:bg-muted text-foreground"
106847
+ ),
106848
+ onClick: () => onSelectElement(el.id),
106849
+ children: [
106850
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground w-4 text-right", children: idx + 1 }),
106851
+ /* @__PURE__ */ jsx("span", { className: "flex-1 truncate", children: label })
106852
+ ]
106853
+ },
106854
+ el.id
106855
+ );
106856
+ }) : /* @__PURE__ */ jsx("div", { className: "text-muted-foreground italic", children: t2("pptx.inspector.noSlideSelected") })
106857
+ ] }),
106858
+ activeTab === "properties" && /* @__PURE__ */ jsx("div", { className: "space-y-3", children: hasSelection && selectedElement ? /* @__PURE__ */ jsx(
106859
+ ElementInspectorBody,
106138
106860
  {
106139
- activeSlide,
106861
+ selectedElement,
106140
106862
  canEdit,
106141
- onUpdateSlide,
106142
- editTemplateMode,
106143
- slideMasters,
106144
- onSetTemplateBackground,
106145
- onGetTemplateBackgroundColor
106863
+ slides,
106864
+ tableEditorState,
106865
+ mediaDataUrls,
106866
+ onUpdateElement,
106867
+ onUpdateElementStyle,
106868
+ onUpdateTextStyle,
106869
+ onMoveLayer
106146
106870
  }
106147
- )
106148
- ] }) }),
106149
- activeTab === "comments" && /* @__PURE__ */ jsx(
106150
- InspectorCommentsSection,
106151
- {
106152
- comments,
106153
- canEdit,
106154
- activeSlide,
106155
- selectedElement,
106156
- editingCommentId,
106157
- commentEditDraft,
106158
- commentDraft,
106159
- replyingToCommentId: replyingToCommentId ?? null,
106160
- replyDraftByCommentId: replyDraftByCommentId ?? {},
106161
- onSetCommentDraft,
106162
- onAddComment,
106163
- onDeleteComment,
106164
- onStartEditComment,
106165
- onSaveEditComment,
106166
- onCancelEditComment,
106167
- onSetCommentEditDraft,
106168
- onToggleCommentResolved,
106169
- onStartReply,
106170
- onCancelReply,
106171
- onReplyDraftChange,
106172
- onSubmitReply,
106173
- onSelectElement
106174
- }
106175
- )
106176
- ] }),
106177
- hasSelection && selectedElement && activeSlide && /* @__PURE__ */ jsxs(Fragment, { children: [
106178
- /* @__PURE__ */ jsx(ResizeHandle, { direction: "vertical", onResize: onResizeAnim }),
106179
- /* @__PURE__ */ jsx(
106180
- "div",
106181
- {
106182
- className: "border-t border-border p-3 overflow-y-auto flex-shrink-0",
106183
- style: { height: animPanelHeight },
106184
- children: /* @__PURE__ */ jsx(
106185
- AnimationPanel,
106871
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
106872
+ /* @__PURE__ */ jsx(
106873
+ PresentationPropertiesPanel,
106186
106874
  {
106187
- selectedElement,
106188
- activeSlide,
106189
106875
  canEdit,
106876
+ canvasSize,
106877
+ presentationProperties,
106878
+ onUpdatePresentationProperties,
106879
+ notesMaster,
106880
+ handoutMaster,
106881
+ notesCanvasSize,
106882
+ coreProperties,
106883
+ appProperties,
106884
+ customProperties,
106885
+ themeOptions,
106886
+ selectedThemePath,
106887
+ setSelectedThemePath,
106888
+ onApplyTheme,
106889
+ onUpdateCoreProperties,
106890
+ onUpdateAppProperties,
106891
+ onUpdateCustomProperties,
106892
+ tagCollections,
106893
+ onUpdateTagCollections,
106894
+ onUpdateCanvasSize,
106895
+ activeSlide,
106896
+ theme,
106190
106897
  onUpdateSlide
106191
106898
  }
106899
+ ),
106900
+ activeSlide && /* @__PURE__ */ jsx(
106901
+ SlideBackgroundPanel,
106902
+ {
106903
+ activeSlide,
106904
+ canEdit,
106905
+ onUpdateSlide,
106906
+ editTemplateMode,
106907
+ slideMasters,
106908
+ onSetTemplateBackground,
106909
+ onGetTemplateBackgroundColor
106910
+ }
106192
106911
  )
106193
- }
106194
- )
106195
- ] })
106196
- ]
106197
- }
106198
- );
106912
+ ] }) }),
106913
+ activeTab === "comments" && /* @__PURE__ */ jsx(
106914
+ InspectorCommentsSection,
106915
+ {
106916
+ comments,
106917
+ canEdit,
106918
+ activeSlide,
106919
+ selectedElement,
106920
+ editingCommentId,
106921
+ commentEditDraft,
106922
+ commentDraft,
106923
+ replyingToCommentId: replyingToCommentId ?? null,
106924
+ replyDraftByCommentId: replyDraftByCommentId ?? {},
106925
+ onSetCommentDraft,
106926
+ onAddComment,
106927
+ onDeleteComment,
106928
+ onStartEditComment,
106929
+ onSaveEditComment,
106930
+ onCancelEditComment,
106931
+ onSetCommentEditDraft,
106932
+ onToggleCommentResolved,
106933
+ onStartReply,
106934
+ onCancelReply,
106935
+ onReplyDraftChange,
106936
+ onSubmitReply,
106937
+ onSelectElement
106938
+ }
106939
+ )
106940
+ ] }),
106941
+ hasSelection && selectedElement && activeSlide && /* @__PURE__ */ jsxs(Fragment, { children: [
106942
+ /* @__PURE__ */ jsx(ResizeHandle, { direction: "vertical", onResize: onResizeAnim }),
106943
+ /* @__PURE__ */ jsx(
106944
+ "div",
106945
+ {
106946
+ className: "border-t border-border p-3 overflow-y-auto flex-shrink-0",
106947
+ style: { height: animPanelHeight },
106948
+ children: /* @__PURE__ */ jsx(
106949
+ AnimationPanel,
106950
+ {
106951
+ selectedElement,
106952
+ activeSlide,
106953
+ canEdit,
106954
+ onUpdateSlide
106955
+ }
106956
+ )
106957
+ }
106958
+ )
106959
+ ] })
106960
+ ]
106961
+ }
106962
+ )
106963
+ ] });
106199
106964
  }
106200
106965
  function buildPathD(points) {
106201
106966
  if (points.length === 0) {
@@ -110329,7 +111094,8 @@ function ViewerBottomPanels({
110329
111094
  onZoomToFit,
110330
111095
  mode,
110331
111096
  onSetMode,
110332
- onToggleSlideSorter
111097
+ onToggleSlideSorter,
111098
+ hideStatusBar = false
110333
111099
  }) {
110334
111100
  return /* @__PURE__ */ jsxs(Fragment, { children: [
110335
111101
  onResizeBottom && !isSlideNotesCollapsed && /* @__PURE__ */ jsx(ResizeHandle, { direction: "vertical", onResize: onResizeBottom }),
@@ -110345,7 +111111,7 @@ function ViewerBottomPanels({
110345
111111
  panelHeight: notesPanelHeight
110346
111112
  }
110347
111113
  ),
110348
- /* @__PURE__ */ jsx(
111114
+ !hideStatusBar && /* @__PURE__ */ jsx(
110349
111115
  StatusBar,
110350
111116
  {
110351
111117
  slideCount,
@@ -110502,6 +111268,45 @@ function ViewerInspector({
110502
111268
  }
110503
111269
  );
110504
111270
  }
111271
+
111272
+ // src/viewer/hooks/useScopedLayoutOptions.ts
111273
+ function scopeLayoutOptionsToActiveSlide(options, activeSlide) {
111274
+ if (!activeSlide?.layoutPath) {
111275
+ return options;
111276
+ }
111277
+ const hasAnyMasterInfo = options.some((o3) => o3.masterPath);
111278
+ if (!hasAnyMasterInfo) {
111279
+ return options;
111280
+ }
111281
+ const activeOption = options.find((o3) => o3.path === activeSlide.layoutPath);
111282
+ const activeMaster = activeOption?.masterPath;
111283
+ if (!activeMaster) {
111284
+ return options;
111285
+ }
111286
+ const scoped = options.filter((o3) => o3.masterPath === activeMaster);
111287
+ const seen = /* @__PURE__ */ new Map();
111288
+ for (const opt of scoped) {
111289
+ const isActive = opt.path === activeSlide.layoutPath;
111290
+ const existing = seen.get(opt.name);
111291
+ if (!existing || isActive) {
111292
+ seen.set(opt.name, opt);
111293
+ }
111294
+ }
111295
+ const chosen = new Set(Array.from(seen.values()).map((o3) => o3.path));
111296
+ const result = [];
111297
+ const usedNames = /* @__PURE__ */ new Set();
111298
+ for (const opt of scoped) {
111299
+ if (!chosen.has(opt.path)) {
111300
+ continue;
111301
+ }
111302
+ if (usedNames.has(opt.name)) {
111303
+ continue;
111304
+ }
111305
+ usedNames.add(opt.name);
111306
+ result.push(opt);
111307
+ }
111308
+ return result;
111309
+ }
110505
111310
  function ViewerToolbarSection(props) {
110506
111311
  const {
110507
111312
  mode,
@@ -110571,6 +111376,10 @@ function ViewerToolbarSection(props) {
110571
111376
  },
110572
111377
  [activeSlide, propertyHandlers]
110573
111378
  );
111379
+ const scopedLayoutOptions = React10__default.useMemo(
111380
+ () => scopeLayoutOptionsToActiveSlide(s.layoutOptions, activeSlide),
111381
+ [s.layoutOptions, activeSlide]
111382
+ );
110574
111383
  const handleApplyTransitionToAll = useCallback(() => {
110575
111384
  const transition = activeSlide?.transition;
110576
111385
  if (!transition) {
@@ -110677,7 +111486,7 @@ function ViewerToolbarSection(props) {
110677
111486
  onUpdateTextStyle: ops.updateSelectedTextStyle,
110678
111487
  isOverflowMenuOpen: s.isOverflowMenuOpen,
110679
111488
  onSetOverflowMenuOpen: s.setIsOverflowMenuOpen,
110680
- layoutOptions: s.layoutOptions,
111489
+ layoutOptions: scopedLayoutOptions,
110681
111490
  onInsertSlideFromLayout: slideOps.handleInsertSlideFromLayout,
110682
111491
  customShows: s.customShows,
110683
111492
  activeCustomShowId: s.activeCustomShowId,
@@ -110710,6 +111519,7 @@ function ViewerToolbarSection(props) {
110710
111519
  isCommentsPanelOpen: s.isInspectorPaneOpen,
110711
111520
  slideCommentCount: activeSlide?.comments?.length ?? 0,
110712
111521
  formatPainterActive: s.formatPainterActive,
111522
+ canActivateFormatPainter: hasCopyableFormat(selectedElement),
110713
111523
  onToggleFormatPainter: onToggleFormatPainterProp ?? (() => s.setFormatPainterActive((p3) => !p3)),
110714
111524
  isSelectionPaneOpen: s.isSelectionPaneOpen,
110715
111525
  onToggleSelectionPane: () => s.setIsSelectionPaneOpen((p3) => !p3),
@@ -113858,6 +114668,166 @@ function ViewerMainContent(props) {
113858
114668
  )
113859
114669
  ] });
113860
114670
  }
114671
+ function MobileBottomBar({
114672
+ onOpenSlides,
114673
+ onOpenInsert,
114674
+ onOpenInspector,
114675
+ onOpenComments,
114676
+ onToggleNotes,
114677
+ activeSheet,
114678
+ commentCount
114679
+ }) {
114680
+ const actions = [
114681
+ {
114682
+ key: "slides",
114683
+ label: "Slides",
114684
+ icon: LuLayers,
114685
+ onClick: onOpenSlides
114686
+ },
114687
+ {
114688
+ key: "insert",
114689
+ label: "Insert",
114690
+ icon: LuPlus,
114691
+ onClick: onOpenInsert
114692
+ },
114693
+ {
114694
+ key: "inspector",
114695
+ label: "Format",
114696
+ icon: LuSettings2,
114697
+ onClick: onOpenInspector
114698
+ },
114699
+ {
114700
+ key: "comments",
114701
+ label: "Comments",
114702
+ icon: LuMessageSquare,
114703
+ onClick: onOpenComments,
114704
+ badge: commentCount
114705
+ },
114706
+ {
114707
+ key: "notes",
114708
+ label: "Notes",
114709
+ icon: LuStickyNote,
114710
+ onClick: onToggleNotes
114711
+ }
114712
+ ];
114713
+ return /* @__PURE__ */ jsx(
114714
+ "nav",
114715
+ {
114716
+ "aria-label": "Editor actions",
114717
+ className: "md:hidden flex items-stretch justify-around border-t border-border bg-secondary/80 backdrop-blur supports-[backdrop-filter]:bg-secondary/60 pb-[max(env(safe-area-inset-bottom),0px)]",
114718
+ children: actions.map(({ key, label, icon: Icon, onClick, badge }) => {
114719
+ const active = activeSheet === key;
114720
+ return /* @__PURE__ */ jsxs(
114721
+ "button",
114722
+ {
114723
+ type: "button",
114724
+ onClick,
114725
+ className: cn(
114726
+ "relative flex flex-col items-center justify-center gap-0.5 flex-1 min-h-[56px] py-1.5 text-[10px] font-medium transition-colors active:scale-95",
114727
+ active ? "text-primary" : "text-muted-foreground hover:text-foreground"
114728
+ ),
114729
+ "aria-pressed": active,
114730
+ children: [
114731
+ /* @__PURE__ */ jsx(Icon, { className: "w-5 h-5" }),
114732
+ /* @__PURE__ */ jsx("span", { children: label }),
114733
+ badge !== void 0 && badge > 0 && /* @__PURE__ */ jsx("span", { className: "absolute top-1 right-1/4 flex items-center justify-center min-w-[16px] h-4 px-1 rounded-full bg-primary text-[9px] font-semibold text-primary-foreground", children: badge > 99 ? "99+" : badge }),
114734
+ active && /* @__PURE__ */ jsx("span", { className: "absolute top-0 left-1/2 -translate-x-1/2 w-8 h-0.5 rounded-full bg-primary" })
114735
+ ]
114736
+ },
114737
+ key
114738
+ );
114739
+ })
114740
+ }
114741
+ );
114742
+ }
114743
+ function MobileSlidesSheet({
114744
+ open,
114745
+ onClose,
114746
+ ...sidebar
114747
+ }) {
114748
+ return /* @__PURE__ */ jsx(MobileSheet, { open, onClose, heightFraction: 0.7, title: "Slides", children: /* @__PURE__ */ jsx("div", { className: "h-full", children: /* @__PURE__ */ jsx(SlidesPaneSidebar, { ...sidebar }) }) });
114749
+ }
114750
+ function MobileChromeOverlay(props) {
114751
+ const {
114752
+ state: s,
114753
+ editorOps,
114754
+ presentation,
114755
+ slides,
114756
+ activeSlideIndex,
114757
+ canvasSize,
114758
+ slideSectionGroups,
114759
+ canEdit,
114760
+ commentCount
114761
+ } = props;
114762
+ const activeSheet = s.isSlidesPaneOpen ? "slides" : s.isInspectorPaneOpen ? s.sidebarPanelMode === "comments" ? "comments" : "inspector" : !s.isSlideNotesCollapsed ? "notes" : null;
114763
+ const closeAllSheets = () => {
114764
+ s.setIsSlidesPaneOpen(false);
114765
+ s.setIsInspectorPaneOpen(false);
114766
+ s.setIsSlideNotesCollapsed(true);
114767
+ };
114768
+ const openSheet = (which) => {
114769
+ closeAllSheets();
114770
+ switch (which) {
114771
+ case "slides":
114772
+ s.setIsSlidesPaneOpen(true);
114773
+ break;
114774
+ case "inspector":
114775
+ s.setSidebarPanelMode("properties");
114776
+ s.setIsInspectorPaneOpen(true);
114777
+ break;
114778
+ case "comments":
114779
+ s.setSidebarPanelMode("comments");
114780
+ s.setIsInspectorPaneOpen(true);
114781
+ break;
114782
+ case "notes":
114783
+ s.setIsSlideNotesCollapsed(false);
114784
+ break;
114785
+ }
114786
+ };
114787
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
114788
+ /* @__PURE__ */ jsx(
114789
+ MobileSlidesSheet,
114790
+ {
114791
+ open: s.isSlidesPaneOpen,
114792
+ onClose: () => s.setIsSlidesPaneOpen(false),
114793
+ slides,
114794
+ activeSlideIndex,
114795
+ canvasSize,
114796
+ sectionGroups: slideSectionGroups,
114797
+ isOpen: true,
114798
+ canEdit,
114799
+ onSelectSlide: (index) => {
114800
+ s.setActiveSlideIndex(index);
114801
+ s.setIsSlidesPaneOpen(false);
114802
+ },
114803
+ onSlideContextMenu: editorOps.slideOps.handleSlideContextMenu,
114804
+ onMoveSlide: editorOps.slideOps.handleMoveSlide,
114805
+ onAddSlide: editorOps.slideOps.handleAddSlide,
114806
+ onCollapse: () => s.setIsSlidesPaneOpen(false),
114807
+ onAddSection: editorOps.sectionOps.addSection,
114808
+ onRenameSection: editorOps.sectionOps.renameSection,
114809
+ onDeleteSection: editorOps.sectionOps.deleteSection,
114810
+ onMoveSectionUp: editorOps.sectionOps.moveSectionUp,
114811
+ onMoveSectionDown: editorOps.sectionOps.moveSectionDown,
114812
+ rehearsalTimings: Object.keys(presentation.recordedTimings).length > 0 ? presentation.recordedTimings : void 0
114813
+ }
114814
+ ),
114815
+ /* @__PURE__ */ jsx(
114816
+ MobileBottomBar,
114817
+ {
114818
+ activeSheet,
114819
+ commentCount,
114820
+ onOpenSlides: () => s.isSlidesPaneOpen ? s.setIsSlidesPaneOpen(false) : openSheet("slides"),
114821
+ onOpenInsert: () => {
114822
+ editorOps.insertHandlers.handleAddTextBox();
114823
+ },
114824
+ onOpenInspector: () => s.isInspectorPaneOpen && s.sidebarPanelMode !== "comments" ? s.setIsInspectorPaneOpen(false) : openSheet("inspector"),
114825
+ onOpenComments: () => s.isInspectorPaneOpen && s.sidebarPanelMode === "comments" ? s.setIsInspectorPaneOpen(false) : openSheet("comments"),
114826
+ onToggleNotes: () => !s.isSlideNotesCollapsed ? s.setIsSlideNotesCollapsed(true) : openSheet("notes")
114827
+ }
114828
+ )
114829
+ ] });
114830
+ }
113861
114831
  function ToggleSwitch({
113862
114832
  label,
113863
114833
  enabled,
@@ -114050,14 +115020,10 @@ function useYjsDocumentSync({
114050
115020
  const lastSyncedRef = useRef("");
114051
115021
  const hasInitializedRef = useRef(false);
114052
115022
  const getDocMap = useCallback(() => {
114053
- if (!doc2 || typeof doc2 !== "object") {
115023
+ if (!doc2) {
114054
115024
  return null;
114055
115025
  }
114056
- const d = doc2;
114057
- if (typeof d.getMap !== "function") {
114058
- return null;
114059
- }
114060
- return d.getMap("slides-data");
115026
+ return doc2.getMap("slides-data");
114061
115027
  }, [doc2]);
114062
115028
  useEffect(() => {
114063
115029
  if (!isConnected || !doc2) {
@@ -114078,10 +115044,9 @@ function useYjsDocumentSync({
114078
115044
  return;
114079
115045
  }
114080
115046
  lastSyncedRef.current = serialized;
114081
- const d = doc2;
114082
- d.transact(() => {
115047
+ doc2.transact(() => {
114083
115048
  const currentCount = map3.get("count");
114084
- if (currentCount && currentCount > slides.length) {
115049
+ if (typeof currentCount === "number" && currentCount > slides.length) {
114085
115050
  for (let i3 = slides.length; i3 < currentCount; i3++) {
114086
115051
  map3.delete(`slide-${i3}`);
114087
115052
  }
@@ -114106,13 +115071,13 @@ function useYjsDocumentSync({
114106
115071
  }
114107
115072
  const handleUpdate = () => {
114108
115073
  const count = map3.get("count");
114109
- if (!count || count === 0) {
115074
+ if (typeof count !== "number" || count === 0) {
114110
115075
  return;
114111
115076
  }
114112
115077
  const remoteSlides = [];
114113
115078
  for (let i3 = 0; i3 < count; i3++) {
114114
115079
  const slideJson = map3.get(`slide-${i3}`);
114115
- if (slideJson) {
115080
+ if (typeof slideJson === "string") {
114116
115081
  try {
114117
115082
  remoteSlides.push(JSON.parse(slideJson));
114118
115083
  } catch {
@@ -114137,7 +115102,7 @@ function useYjsDocumentSync({
114137
115102
  if (!hasInitializedRef.current) {
114138
115103
  hasInitializedRef.current = true;
114139
115104
  const count = map3.get("count");
114140
- if (count && count > 0) {
115105
+ if (typeof count === "number" && count > 0) {
114141
115106
  handleUpdate();
114142
115107
  }
114143
115108
  }
@@ -114698,13 +115663,14 @@ function useCanvasInteractions(input) {
114698
115663
  if (e2.button !== 0) {
114699
115664
  return;
114700
115665
  }
114701
- if (!selectedElementIdSet.has(elementId)) {
115666
+ const wasSelected = selectedElementIdSet.has(elementId);
115667
+ if (!wasSelected) {
114702
115668
  ops.applySelection(elementId);
114703
115669
  justSelectedRef.current = true;
114704
115670
  } else {
114705
115671
  justSelectedRef.current = false;
114706
115672
  }
114707
- const ids = effectiveSelectedIds.length ? effectiveSelectedIds : [elementId];
115673
+ const ids = !wasSelected ? [elementId] : effectiveSelectedIds.length ? effectiveSelectedIds : [elementId];
114708
115674
  const startPositions = {};
114709
115675
  const domEls = /* @__PURE__ */ new Map();
114710
115676
  for (const id2 of ids) {
@@ -116741,8 +117707,14 @@ function useSectionOperations(input) {
116741
117707
  }
116742
117708
 
116743
117709
  // src/viewer/hooks/useSlideManagement.ts
117710
+ function insertSlideFromLayoutUpdater(slides, activeIndex, draft) {
117711
+ const next = [...slides];
117712
+ const insertAt = Math.max(0, Math.min(activeIndex + 1, next.length));
117713
+ next.splice(insertAt, 0, draft);
117714
+ return next;
117715
+ }
116744
117716
  function useSlideManagement(input) {
116745
- const { slides, activeSlideIndex, setActiveSlideIndex, ops, history } = input;
117717
+ const { slides, activeSlideIndex, setActiveSlideIndex, ops, history, handlerRef } = input;
116746
117718
  const handleAddSlide = () => {
116747
117719
  const newSlide = {
116748
117720
  id: `slide-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,
@@ -116841,8 +117813,42 @@ function useSlideManagement(input) {
116841
117813
  });
116842
117814
  history.markDirty();
116843
117815
  };
116844
- const handleInsertSlideFromLayout = (_layoutPath) => {
116845
- handleAddSlide();
117816
+ const handleInsertSlideFromLayout = (layoutPath, layoutName) => {
117817
+ const insertAt = activeSlideIndex + 1;
117818
+ const draft = {
117819
+ id: `slide-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,
117820
+ rId: "",
117821
+ slideNumber: slides.length + 1,
117822
+ elements: [],
117823
+ layoutPath,
117824
+ ...layoutName ? { layoutName } : {}
117825
+ };
117826
+ let inserted = [];
117827
+ ops.updateSlides((prev) => {
117828
+ inserted = insertSlideFromLayoutUpdater(prev, activeSlideIndex, draft);
117829
+ return inserted;
117830
+ });
117831
+ setActiveSlideIndex(insertAt);
117832
+ history.markDirty();
117833
+ const handler = handlerRef?.current;
117834
+ if (handler) {
117835
+ void handler.applyLayoutToSlide(insertAt, layoutPath, inserted).then(
117836
+ (updated) => {
117837
+ ops.updateSlides((prev) => {
117838
+ if (prev[insertAt]?.id !== draft.id) {
117839
+ return prev;
117840
+ }
117841
+ const next = [...prev];
117842
+ next[insertAt] = updated;
117843
+ return next;
117844
+ });
117845
+ return void 0;
117846
+ },
117847
+ () => {
117848
+ return void 0;
117849
+ }
117850
+ );
117851
+ }
116846
117852
  };
116847
117853
  return {
116848
117854
  handleAddSlide,
@@ -117378,7 +118384,8 @@ function useEditorOperations(input) {
117378
118384
  canvasSize,
117379
118385
  dialogs,
117380
118386
  presentation,
117381
- userName
118387
+ userName,
118388
+ handlerRef
117382
118389
  } = input;
117383
118390
  const ops = useElementOperations({
117384
118391
  activeSlide,
@@ -117480,7 +118487,8 @@ function useEditorOperations(input) {
117480
118487
  activeSlideIndex,
117481
118488
  setActiveSlideIndex: state2.setActiveSlideIndex,
117482
118489
  ops,
117483
- history
118490
+ history,
118491
+ handlerRef
117484
118492
  });
117485
118493
  const tableOps = useTableOperations({
117486
118494
  selectedElement,
@@ -117509,21 +118517,34 @@ function useEditorOperations(input) {
117509
118517
  );
117510
118518
  const copiedFormatRef = useRef(null);
117511
118519
  const prevFormatPainterRef = useRef(false);
118520
+ const { formatPainterActive, setFormatPainterActive, elementLookup } = state2;
117512
118521
  useEffect(() => {
117513
- if (state2.formatPainterActive && !prevFormatPainterRef.current && selectedElement) {
118522
+ if (formatPainterActive && !prevFormatPainterRef.current && selectedElement) {
117514
118523
  copiedFormatRef.current = copyFormatFromElement(selectedElement);
117515
- } else if (!state2.formatPainterActive) {
118524
+ } else if (!formatPainterActive) {
117516
118525
  copiedFormatRef.current = null;
117517
118526
  }
117518
- prevFormatPainterRef.current = state2.formatPainterActive;
117519
- }, [state2.formatPainterActive, selectedElement]);
118527
+ prevFormatPainterRef.current = formatPainterActive;
118528
+ }, [formatPainterActive, selectedElement]);
118529
+ useEffect(() => {
118530
+ if (!formatPainterActive) {
118531
+ return;
118532
+ }
118533
+ const onKey = (e2) => {
118534
+ if (e2.key === "Escape") {
118535
+ setFormatPainterActive(false);
118536
+ }
118537
+ };
118538
+ window.addEventListener("keydown", onKey);
118539
+ return () => window.removeEventListener("keydown", onKey);
118540
+ }, [formatPainterActive, setFormatPainterActive]);
117520
118541
  const formatPainterCanvasHandlers = useMemo(
117521
118542
  () => ({
117522
118543
  ...canvasHandlers,
117523
118544
  handleElementClick: (elementId, e2) => {
117524
- if (state2.formatPainterActive && copiedFormatRef.current) {
118545
+ if (formatPainterActive && copiedFormatRef.current) {
117525
118546
  e2.stopPropagation();
117526
- const element2 = state2.elementLookup.get(elementId);
118547
+ const element2 = elementLookup.get(elementId);
117527
118548
  if (element2) {
117528
118549
  const updated = applyFormatToElement(element2, copiedFormatRef.current);
117529
118550
  const updates = {};
@@ -117536,14 +118557,21 @@ function useEditorOperations(input) {
117536
118557
  ops.updateElementById(elementId, updates);
117537
118558
  }
117538
118559
  copiedFormatRef.current = null;
117539
- state2.setFormatPainterActive(false);
118560
+ setFormatPainterActive(false);
117540
118561
  ops.applySelection(elementId);
117541
118562
  return;
117542
118563
  }
117543
118564
  canvasHandlers.handleElementClick(elementId, e2);
118565
+ },
118566
+ handleCanvasMouseDown: (e2) => {
118567
+ if (formatPainterActive) {
118568
+ setFormatPainterActive(false);
118569
+ return;
118570
+ }
118571
+ canvasHandlers.handleCanvasMouseDown(e2);
117544
118572
  }
117545
118573
  }),
117546
- [canvasHandlers, ops, state2]
118574
+ [canvasHandlers, ops, formatPainterActive, setFormatPainterActive, elementLookup]
117547
118575
  );
117548
118576
  return {
117549
118577
  ops: combinedOps,
@@ -119682,21 +120710,35 @@ function useViewerDialogs(input) {
119682
120710
  null
119683
120711
  );
119684
120712
  const [embedFontsEnabled, setEmbedFontsEnabled] = useState(false);
119685
- const [isNarrowViewport, setIsNarrowViewport] = useState(false);
120713
+ const [isNarrowViewport, setIsNarrowViewport] = useState(
120714
+ () => typeof window !== "undefined" ? window.innerWidth < 768 : false
120715
+ );
119686
120716
  useEffect(() => {
119687
- const el = containerRef.current;
119688
- if (!el) {
119689
- return;
119690
- }
119691
- const observer = new ResizeObserver((entries) => {
119692
- const entry = entries[0];
119693
- if (entry) {
119694
- setIsNarrowViewport(entry.contentRect.width < 768);
120717
+ const handleWindow = () => setIsNarrowViewport(window.innerWidth < 768);
120718
+ let observer = null;
120719
+ let raf = 0;
120720
+ const attach2 = () => {
120721
+ const el = containerRef.current;
120722
+ if (!el) {
120723
+ raf = requestAnimationFrame(attach2);
120724
+ return;
119695
120725
  }
119696
- });
119697
- observer.observe(el);
119698
- setIsNarrowViewport(el.clientWidth < 768);
119699
- return () => observer.disconnect();
120726
+ observer = new ResizeObserver((entries) => {
120727
+ const entry = entries[0];
120728
+ if (entry) {
120729
+ setIsNarrowViewport(entry.contentRect.width < 768);
120730
+ }
120731
+ });
120732
+ observer.observe(el);
120733
+ setIsNarrowViewport(el.clientWidth < 768);
120734
+ };
120735
+ attach2();
120736
+ window.addEventListener("resize", handleWindow);
120737
+ return () => {
120738
+ cancelAnimationFrame(raf);
120739
+ observer?.disconnect();
120740
+ window.removeEventListener("resize", handleWindow);
120741
+ };
119700
120742
  }, []);
119701
120743
  useEffect(() => {
119702
120744
  if (isDirty && hasDigitalSignatures && !signatureStripAcknowledgedRef.current) {
@@ -124168,7 +125210,9 @@ function useViewerCoreState(_input) {
124168
125210
  function useViewerUIState() {
124169
125211
  const [isCompactToolbarOpen, setIsCompactToolbarOpen] = useState(false);
124170
125212
  const [toolbarSection, setToolbarSection] = useState("home");
124171
- const [isSlidesPaneOpen, setIsSlidesPaneOpen] = useState(true);
125213
+ const [isSlidesPaneOpen, setIsSlidesPaneOpen] = useState(
125214
+ () => typeof window === "undefined" ? true : window.innerWidth >= 768
125215
+ );
124172
125216
  const [isInspectorPaneOpen, setIsInspectorPaneOpen] = useState(false);
124173
125217
  const [isSlideNotesCollapsed, setIsSlideNotesCollapsed] = useState(true);
124174
125218
  const [isOverflowMenuOpen, setIsOverflowMenuOpen] = useState(false);
@@ -124611,7 +125655,8 @@ var PowerPointViewer = forwardRef(
124611
125655
  canvasSize,
124612
125656
  dialogs,
124613
125657
  presentation,
124614
- userName: authorName ?? collaboration?.userName
125658
+ userName: authorName ?? collaboration?.userName,
125659
+ handlerRef: actionSoundHandlerRef
124615
125660
  });
124616
125661
  const {
124617
125662
  exportHandlers,
@@ -124734,7 +125779,7 @@ var PowerPointViewer = forwardRef(
124734
125779
  {
124735
125780
  activeSlide,
124736
125781
  allSlides: slides,
124737
- isSlideNotesCollapsed: isMobile || state2.isSlideNotesCollapsed,
125782
+ isSlideNotesCollapsed: state2.isSlideNotesCollapsed,
124738
125783
  canEdit,
124739
125784
  slideCount: slides.length,
124740
125785
  activeSlideIndex,
@@ -124751,7 +125796,22 @@ var PowerPointViewer = forwardRef(
124751
125796
  onZoomToFit: zoom.handleZoomToFit,
124752
125797
  mode,
124753
125798
  onSetMode: handleSetMode,
124754
- onToggleSlideSorter: () => state2.setShowSlideSorter((p3) => !p3)
125799
+ onToggleSlideSorter: () => state2.setShowSlideSorter((p3) => !p3),
125800
+ hideStatusBar: isMobile
125801
+ }
125802
+ ),
125803
+ mode !== "present" && isMobile && /* @__PURE__ */ jsx(
125804
+ MobileChromeOverlay,
125805
+ {
125806
+ state: state2,
125807
+ editorOps,
125808
+ presentation,
125809
+ slides,
125810
+ activeSlideIndex,
125811
+ canvasSize,
125812
+ slideSectionGroups,
125813
+ canEdit,
125814
+ commentCount: activeSlide?.comments?.length ?? 0
124755
125815
  }
124756
125816
  ),
124757
125817
  /* @__PURE__ */ jsx(