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
@@ -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, applyThemeToData, THEME_PRESETS } 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, applyThemeToData, THEME_PRESETS } 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, useMemo42 = 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, useMemo42 = 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;
@@ -70280,6 +70280,55 @@ var ACTION_BUTTON_PRESETS = [
70280
70280
  label: "Return",
70281
70281
  defaultAction: "prevSlide",
70282
70282
  iconPath: "M18 8 L18 14 L6 14 M6 14 L10 10 M6 14 L10 18"
70283
+ },
70284
+ {
70285
+ shapeType: "actionButtonHome",
70286
+ label: "Home",
70287
+ defaultAction: "firstSlide",
70288
+ // House: roof + body
70289
+ iconPath: "M12 4 L20 11 L20 20 L14 20 L14 14 L10 14 L10 20 L4 20 L4 11 Z"
70290
+ },
70291
+ {
70292
+ shapeType: "actionButtonHelp",
70293
+ label: "Help",
70294
+ defaultAction: "none",
70295
+ // Question mark
70296
+ iconPath: "M9 9 a3 3 0 1 1 4 2.8 c-1 0.4 -1 1.2 -1 2 M12 17 v0.5"
70297
+ },
70298
+ {
70299
+ shapeType: "actionButtonInformation",
70300
+ label: "Information",
70301
+ defaultAction: "none",
70302
+ // Lower-case "i": dot + body
70303
+ iconPath: "M12 6 v0.01 M12 10 v8"
70304
+ },
70305
+ {
70306
+ shapeType: "actionButtonDocument",
70307
+ label: "Document",
70308
+ defaultAction: "none",
70309
+ // Document with folded corner
70310
+ iconPath: "M6 4 L14 4 L18 8 L18 20 L6 20 Z M14 4 L14 8 L18 8"
70311
+ },
70312
+ {
70313
+ shapeType: "actionButtonSound",
70314
+ label: "Sound",
70315
+ defaultAction: "none",
70316
+ // Speaker cone + sound waves
70317
+ 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"
70318
+ },
70319
+ {
70320
+ shapeType: "actionButtonMovie",
70321
+ label: "Movie",
70322
+ defaultAction: "none",
70323
+ // Film strip with play triangle
70324
+ iconPath: "M4 6 L20 6 L20 18 L4 18 Z M10 9 L15 12 L10 15 Z"
70325
+ },
70326
+ {
70327
+ shapeType: "actionButtonBlank",
70328
+ label: "Custom",
70329
+ defaultAction: "none",
70330
+ // No glyph — empty path. The button still renders as a rounded rect via clip-path.
70331
+ iconPath: ""
70283
70332
  }
70284
70333
  ];
70285
70334
  Object.fromEntries(ACTION_BUTTON_PRESETS.map((p3) => [p3.shapeType, p3.defaultAction]));
@@ -72559,8 +72608,8 @@ function hexToRgb2(hex) {
72559
72608
  };
72560
72609
  }
72561
72610
  function rgbToHex(r2, g2, b2) {
72562
- const clamp2 = (v) => Math.max(0, Math.min(255, Math.round(v)));
72563
- return `#${clamp2(r2).toString(16).padStart(2, "0")}${clamp2(g2).toString(16).padStart(2, "0")}${clamp2(b2).toString(16).padStart(2, "0")}`;
72611
+ const clamp3 = (v) => Math.max(0, Math.min(255, Math.round(v)));
72612
+ return `#${clamp3(r2).toString(16).padStart(2, "0")}${clamp3(g2).toString(16).padStart(2, "0")}${clamp3(b2).toString(16).padStart(2, "0")}`;
72564
72613
  }
72565
72614
  function rgbToHsl(r2, g2, b2) {
72566
72615
  const rn = r2 / 255;
@@ -74770,6 +74819,11 @@ function getShapeClipPath(shapeType, adjustments, width, height) {
74770
74819
  }
74771
74820
  const normalized = shapeType.toLowerCase();
74772
74821
  if (normalized === "round1rect" || normalized === "round2samerect" || normalized === "round2diagrect" || normalized === "sniproundrect" || normalized === "snip1rect" || normalized === "snip2diagrect") {
74822
+ if (adjustments?.adj !== void 0 && width && height) {
74823
+ const ratio = Math.min(Math.max(adjustments.adj / 1e5, 0), 0.5);
74824
+ const radiusPx = Math.round(Math.min(width, height) * ratio);
74825
+ return `inset(0 round ${radiusPx}px)`;
74826
+ }
74773
74827
  return "inset(0 round 18px)";
74774
74828
  }
74775
74829
  if (normalized === "can" || normalized === "cylinder") {
@@ -75416,6 +75470,128 @@ function mapDagBlendModeToCss(blend) {
75416
75470
  return void 0;
75417
75471
  }
75418
75472
  }
75473
+ function getImageAlphaFilterId(elementId) {
75474
+ return `imgalpha-${elementId}`;
75475
+ }
75476
+ function hasAdvancedImageAlphaEffects(element2) {
75477
+ if (!isImageLikeElement(element2)) {
75478
+ return false;
75479
+ }
75480
+ const e2 = element2.imageEffects;
75481
+ if (!e2) {
75482
+ return false;
75483
+ }
75484
+ return Boolean(
75485
+ 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
75486
+ );
75487
+ }
75488
+ function renderImageAlphaSvgFilter(element2) {
75489
+ if (!isImageLikeElement(element2)) {
75490
+ return null;
75491
+ }
75492
+ const e2 = element2.imageEffects;
75493
+ if (!e2 || !hasAdvancedImageAlphaEffects(element2)) {
75494
+ return null;
75495
+ }
75496
+ const filterId = getImageAlphaFilterId(element2.id);
75497
+ const primitives = [];
75498
+ let resultIdx = 0;
75499
+ let inputRef = "SourceGraphic";
75500
+ const next = (jsx235) => {
75501
+ const result = `r${resultIdx++}`;
75502
+ primitives.push(jsx235(inputRef, result));
75503
+ inputRef = result;
75504
+ };
75505
+ if (typeof e2.alphaModFix === "number") {
75506
+ const mul = clamp(e2.alphaModFix / 100, 0, 1);
75507
+ next((inp, out) => /* @__PURE__ */ jsx(
75508
+ "feColorMatrix",
75509
+ {
75510
+ in: inp,
75511
+ result: out,
75512
+ type: "matrix",
75513
+ values: `1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 ${mul} 0`
75514
+ },
75515
+ out
75516
+ ));
75517
+ }
75518
+ if (e2.alphaInv) {
75519
+ next((inp, out) => /* @__PURE__ */ jsx("feComponentTransfer", { in: inp, result: out, children: /* @__PURE__ */ jsx("feFuncA", { type: "linear", slope: -1, intercept: 1 }) }, out));
75520
+ }
75521
+ if (e2.alphaCeiling) {
75522
+ 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));
75523
+ }
75524
+ if (e2.alphaFloor) {
75525
+ 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));
75526
+ }
75527
+ if (typeof e2.alphaRepl === "number") {
75528
+ const a2 = clamp(e2.alphaRepl / 100, 0, 1);
75529
+ next((inp, out) => /* @__PURE__ */ jsx("feComponentTransfer", { in: inp, result: out, children: /* @__PURE__ */ jsx("feFuncA", { type: "linear", slope: 0, intercept: a2 }) }, out));
75530
+ }
75531
+ if (typeof e2.alphaBiLevel === "number") {
75532
+ const t2 = clamp(e2.alphaBiLevel / 100, 0, 1);
75533
+ const table = Array.from({ length: 10 }, (_, i3) => i3 / 10 >= t2 ? "1" : "0").join(" ");
75534
+ next((inp, out) => /* @__PURE__ */ jsx("feComponentTransfer", { in: inp, result: out, children: /* @__PURE__ */ jsx("feFuncA", { type: "discrete", tableValues: table }) }, out));
75535
+ }
75536
+ if (typeof e2.biLevel === "number") {
75537
+ next((inp, out) => /* @__PURE__ */ jsx("feColorMatrix", { in: inp, result: out, type: "saturate", values: "0" }, out));
75538
+ const t2 = clamp(e2.biLevel / 100, 0, 1);
75539
+ const tbl = t2 < 0.5 ? "0 1" : "0 1";
75540
+ next((inp, out) => /* @__PURE__ */ jsxs("feComponentTransfer", { in: inp, result: out, children: [
75541
+ /* @__PURE__ */ jsx("feFuncR", { type: "discrete", tableValues: tbl }),
75542
+ /* @__PURE__ */ jsx("feFuncG", { type: "discrete", tableValues: tbl }),
75543
+ /* @__PURE__ */ jsx("feFuncB", { type: "discrete", tableValues: tbl })
75544
+ ] }, out));
75545
+ }
75546
+ if (e2.lum && (typeof e2.lum.bright === "number" || typeof e2.lum.contrast === "number")) {
75547
+ const b2 = (e2.lum.bright ?? 0) / 100;
75548
+ const c2 = 1 + (e2.lum.contrast ?? 0) / 100;
75549
+ const slope = c2;
75550
+ const intercept = b2 + (1 - c2) / 2;
75551
+ next((inp, out) => /* @__PURE__ */ jsxs("feComponentTransfer", { in: inp, result: out, children: [
75552
+ /* @__PURE__ */ jsx("feFuncR", { type: "linear", slope, intercept }),
75553
+ /* @__PURE__ */ jsx("feFuncG", { type: "linear", slope, intercept }),
75554
+ /* @__PURE__ */ jsx("feFuncB", { type: "linear", slope, intercept })
75555
+ ] }, out));
75556
+ }
75557
+ if (e2.hsl && typeof e2.hsl.sat === "number") {
75558
+ const v = clamp(1 + e2.hsl.sat / 100, 0, 2);
75559
+ next((inp, out) => /* @__PURE__ */ jsx("feColorMatrix", { in: inp, result: out, type: "saturate", values: String(v) }, out));
75560
+ }
75561
+ if (e2.tint && typeof e2.tint.amt === "number" && e2.tint.amt < 0) {
75562
+ const v = clamp(1 + e2.tint.amt / 100, 0, 1);
75563
+ next((inp, out) => /* @__PURE__ */ jsx("feColorMatrix", { in: inp, result: out, type: "saturate", values: String(v) }, out));
75564
+ }
75565
+ if (e2.clrRepl) {
75566
+ const c2 = hexToRgbUnit(e2.clrRepl.color);
75567
+ next((inp, out) => /* @__PURE__ */ jsx(
75568
+ "feColorMatrix",
75569
+ {
75570
+ in: inp,
75571
+ result: out,
75572
+ type: "matrix",
75573
+ values: `0 0 0 0 ${c2.r} 0 0 0 0 ${c2.g} 0 0 0 0 ${c2.b} 0 0 0 1 0`
75574
+ },
75575
+ out
75576
+ ));
75577
+ }
75578
+ if (primitives.length === 0) {
75579
+ return null;
75580
+ }
75581
+ return /* @__PURE__ */ jsx(
75582
+ "svg",
75583
+ {
75584
+ width: 0,
75585
+ height: 0,
75586
+ style: { position: "absolute", overflow: "hidden" },
75587
+ "aria-hidden": "true",
75588
+ children: /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx("filter", { id: filterId, colorInterpolationFilters: "sRGB", children: primitives }) })
75589
+ }
75590
+ );
75591
+ }
75592
+ function clamp(v, lo, hi) {
75593
+ return v < lo ? lo : v > hi ? hi : v;
75594
+ }
75419
75595
  function getDagDuotoneFilterId(elementId) {
75420
75596
  return `dag-duotone-${elementId}`;
75421
75597
  }
@@ -75499,6 +75675,9 @@ function getImageEffectsFilter(element2, options) {
75499
75675
  const filterId = getDuotoneFilterId(element2.id);
75500
75676
  filters.push(`url(#${filterId})`);
75501
75677
  }
75678
+ if (hasAdvancedImageAlphaEffects(element2)) {
75679
+ filters.push(`url(#${getImageAlphaFilterId(element2.id)})`);
75680
+ }
75502
75681
  if (effects.artisticEffect) {
75503
75682
  const radius = effects.artisticRadius ?? 5;
75504
75683
  if (needsSvgArtisticFilter(effects.artisticEffect)) {
@@ -75672,6 +75851,39 @@ function getEffectDagCssFilter(style, elementId) {
75672
75851
  return filters.length > 0 ? filters.join(" ") : void 0;
75673
75852
  }
75674
75853
  var getEffectDagFilter = getEffectDagCssFilter;
75854
+ function getResolvedShapeClipPathFor(shapeType, width, height, adjustments) {
75855
+ if (!shapeType) {
75856
+ return void 0;
75857
+ }
75858
+ if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {
75859
+ return getShapeClipPath(shapeType, adjustments, width, height);
75860
+ }
75861
+ if (adjustments && Object.keys(adjustments).length > 0) {
75862
+ const adjusted = getAdjustmentAwareShapeClipPath(shapeType, width, height, adjustments);
75863
+ if (adjusted !== void 0) {
75864
+ return adjusted;
75865
+ }
75866
+ }
75867
+ const fromPreset = getShapeClipPathFromPreset(shapeType, width, height, adjustments);
75868
+ if (fromPreset !== void 0) {
75869
+ return fromPreset;
75870
+ }
75871
+ const cloud = getCloudPathForRendering(shapeType, width, height);
75872
+ if (cloud !== void 0) {
75873
+ return cloud;
75874
+ }
75875
+ return getShapeClipPath(shapeType, adjustments, width, height);
75876
+ }
75877
+ function getResolvedShapeClipPath(element2, width, height) {
75878
+ const shapeType = element2.shapeType;
75879
+ if (!shapeType) {
75880
+ return void 0;
75881
+ }
75882
+ const w = element2.width;
75883
+ const h2 = element2.height;
75884
+ const adjustments = element2.shapeAdjustments;
75885
+ return getResolvedShapeClipPathFor(shapeType, w, h2, adjustments);
75886
+ }
75675
75887
 
75676
75888
  // src/viewer/utils/shape-round-rect.ts
75677
75889
  function localClampAdjustment(value) {
@@ -75743,6 +75955,27 @@ var MATERIAL_MAP = {
75743
75955
  filter: "brightness(1.1) contrast(0.85)",
75744
75956
  // Translucent powder: slight translucent glow
75745
75957
  backgroundImage: "radial-gradient(ellipse at 30% 30%, rgba(255,255,255,0.1) 0%, transparent 60%)"
75958
+ },
75959
+ // Legacy materials (PowerPoint 2007 / earlier). Render as muted variants
75960
+ // of the modern equivalents so legacy decks still resemble the originals.
75961
+ legacyMatte: {
75962
+ filter: "brightness(0.92) saturate(0.85)",
75963
+ backgroundImage: "linear-gradient(180deg, rgba(255,255,255,0.03) 0%, transparent 50%, rgba(0,0,0,0.04) 100%)"
75964
+ },
75965
+ legacyPlastic: {
75966
+ filter: "brightness(1.02) contrast(1.03)",
75967
+ boxShadow: "inset -2px -2px 5px rgba(255,255,255,0.3)",
75968
+ backgroundImage: "radial-gradient(ellipse 35% 25% at 25% 20%, rgba(255,255,255,0.15) 0%, transparent 70%)"
75969
+ },
75970
+ legacyMetal: {
75971
+ filter: "brightness(1.05) contrast(1.1) saturate(1.1)",
75972
+ boxShadow: "inset -2px -2px 6px rgba(255,255,255,0.35), inset 1px 1px 3px rgba(255,255,255,0.15)",
75973
+ 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%)"
75974
+ },
75975
+ legacyWireframe: {
75976
+ filter: "brightness(1) contrast(1.4) saturate(0.6)",
75977
+ // Wireframe: high contrast outline-emphasising look
75978
+ boxShadow: "inset 0 0 0 1px rgba(0,0,0,0.4)"
75746
75979
  }
75747
75980
  };
75748
75981
  function getMaterialCssOverrides(material) {
@@ -76697,8 +76930,7 @@ function getShapeVisualStyle(element2, hasFill, fillColor, strokeWidth, strokeCo
76697
76930
  return {};
76698
76931
  }
76699
76932
  const normalizedShapeType = getShapeType(element2.shapeType);
76700
- const shapeType = element2.shapeType || normalizedShapeType;
76701
- const clipPath = getShapeClipPath(shapeType);
76933
+ const clipPath = getResolvedShapeClipPath(element2);
76702
76934
  const fillOpacity = element2.shapeStyle?.fillOpacity;
76703
76935
  const strokeOpacity = element2.shapeStyle?.strokeOpacity;
76704
76936
  const strokeDash = normalizeStrokeDashType(element2.shapeStyle?.strokeDash);
@@ -77300,7 +77532,7 @@ function getImageMaskStyle(element2) {
77300
77532
  if (normalized === "can" || normalized === "cylinder") {
77301
77533
  return { borderRadius: "48% / 12%" };
77302
77534
  }
77303
- const clipPath = getShapeClipPath(shapeType);
77535
+ const clipPath = getResolvedShapeClipPath(element2);
77304
77536
  if (!clipPath) {
77305
77537
  return void 0;
77306
77538
  }
@@ -77963,8 +78195,8 @@ function hexToRgb3(hex) {
77963
78195
  };
77964
78196
  }
77965
78197
  function rgbToHex2(r2, g2, b2) {
77966
- const clamp2 = (v) => Math.max(0, Math.min(255, Math.round(v)));
77967
- 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()}`;
78198
+ const clamp3 = (v) => Math.max(0, Math.min(255, Math.round(v)));
78199
+ 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()}`;
77968
78200
  }
77969
78201
  function tintColor(hex, tintFactor) {
77970
78202
  const { r: r2, g: g2, b: b2 } = hexToRgb3(hex);
@@ -78895,13 +79127,13 @@ function cellStyleToCss(style) {
78895
79127
  }
78896
79128
  if (style.textDirection) {
78897
79129
  switch (style.textDirection) {
78898
- case "vertical":
79130
+ case "vert":
78899
79131
  case "eaVert":
78900
79132
  case "wordArtVert":
78901
79133
  case "wordArtVertRtl":
78902
79134
  css.writingMode = "vertical-rl";
78903
79135
  break;
78904
- case "vertical270":
79136
+ case "vert270":
78905
79137
  case "mongolianVert":
78906
79138
  css.writingMode = "vertical-lr";
78907
79139
  break;
@@ -79308,8 +79540,8 @@ function renderTableElement(element2, textStyle, options) {
79308
79540
  {
79309
79541
  style: rowHeight ? { height: rowHeight } : void 0,
79310
79542
  children: cells.map((cell, cellIndex) => {
79311
- const isHMerged = cell["@_hMerge"] === "1" || cell["@_hMerge"] === true;
79312
- const isVMerged = cell["@_vMerge"] === "1" || cell["@_vMerge"] === true;
79543
+ const isHMerged = cell["@_hMerge"] === "1";
79544
+ const isVMerged = cell["@_vMerge"] === "1";
79313
79545
  if (isHMerged || isVMerged) {
79314
79546
  return null;
79315
79547
  }
@@ -79428,8 +79660,8 @@ function hexToRgb4(hex) {
79428
79660
  ];
79429
79661
  }
79430
79662
  function rgbToHex3(r2, g2, b2) {
79431
- const clamp2 = (v) => Math.max(0, Math.min(255, Math.round(v)));
79432
- return `#${clamp2(r2).toString(16).padStart(2, "0")}${clamp2(g2).toString(16).padStart(2, "0")}${clamp2(b2).toString(16).padStart(2, "0")}`;
79663
+ const clamp3 = (v) => Math.max(0, Math.min(255, Math.round(v)));
79664
+ return `#${clamp3(r2).toString(16).padStart(2, "0")}${clamp3(g2).toString(16).padStart(2, "0")}${clamp3(b2).toString(16).padStart(2, "0")}`;
79433
79665
  }
79434
79666
  function tint(hex, amount) {
79435
79667
  const [r2, g2, b2] = hexToRgb4(hex);
@@ -81347,7 +81579,7 @@ function resolveRegionCode(label) {
81347
81579
  return REGION_ALIAS_MAP[normalized];
81348
81580
  }
81349
81581
  function lerpColor(a2, b2, t2) {
81350
- const clamp2 = (v) => Math.max(0, Math.min(255, Math.round(v)));
81582
+ const clamp3 = (v) => Math.max(0, Math.min(255, Math.round(v)));
81351
81583
  const parse = (hex) => {
81352
81584
  const h2 = hex.replace("#", "");
81353
81585
  return [
@@ -81358,9 +81590,9 @@ function lerpColor(a2, b2, t2) {
81358
81590
  };
81359
81591
  const [r1, g1, b1] = parse(a2);
81360
81592
  const [r2, g2, b22] = parse(b2);
81361
- const r3 = clamp2(r1 + (r2 - r1) * t2);
81362
- const g3 = clamp2(g1 + (g2 - g1) * t2);
81363
- const bl = clamp2(b1 + (b22 - b1) * t2);
81593
+ const r3 = clamp3(r1 + (r2 - r1) * t2);
81594
+ const g3 = clamp3(g1 + (g2 - g1) * t2);
81595
+ const bl = clamp3(b1 + (b22 - b1) * t2);
81364
81596
  return `#${r3.toString(16).padStart(2, "0")}${g3.toString(16).padStart(2, "0")}${bl.toString(16).padStart(2, "0")}`;
81365
81597
  }
81366
81598
  function sequentialColorScale(t2) {
@@ -85318,6 +85550,15 @@ function copyFormatFromElement(element2) {
85318
85550
  }
85319
85551
  return result;
85320
85552
  }
85553
+ function definedEntries(obj) {
85554
+ const out = {};
85555
+ for (const key in obj) {
85556
+ if (obj[key] !== void 0) {
85557
+ out[key] = obj[key];
85558
+ }
85559
+ }
85560
+ return out;
85561
+ }
85321
85562
  function applyFormatToElement(element2, format) {
85322
85563
  let updated = { ...element2 };
85323
85564
  if (format.shapeStyle && hasShapeProperties(updated)) {
@@ -85325,7 +85566,7 @@ function applyFormatToElement(element2, format) {
85325
85566
  ...updated,
85326
85567
  shapeStyle: {
85327
85568
  ...updated.shapeStyle,
85328
- ...format.shapeStyle
85569
+ ...definedEntries(format.shapeStyle)
85329
85570
  }
85330
85571
  };
85331
85572
  }
@@ -85334,12 +85575,18 @@ function applyFormatToElement(element2, format) {
85334
85575
  ...updated,
85335
85576
  textStyle: {
85336
85577
  ...updated.textStyle,
85337
- ...format.textStyle
85578
+ ...definedEntries(format.textStyle)
85338
85579
  }
85339
85580
  };
85340
85581
  }
85341
85582
  return updated;
85342
85583
  }
85584
+ function hasCopyableFormat(element2) {
85585
+ if (!element2) {
85586
+ return false;
85587
+ }
85588
+ return hasShapeProperties(element2) || hasTextProperties(element2);
85589
+ }
85343
85590
 
85344
85591
  // src/viewer/utils/animation-preview.ts
85345
85592
  var PRESET_TO_EFFECT = {
@@ -86688,8 +86935,8 @@ function ThumbnailTable({
86688
86935
  {
86689
86936
  style: rowHeight ? { height: rowHeight } : void 0,
86690
86937
  children: cells.map((cell, ci) => {
86691
- const isHMerged = cell["@_hMerge"] === "1" || cell["@_hMerge"] === true;
86692
- const isVMerged = cell["@_vMerge"] === "1" || cell["@_vMerge"] === true;
86938
+ const isHMerged = cell["@_hMerge"] === "1";
86939
+ const isVMerged = cell["@_vMerge"] === "1";
86693
86940
  if (isHMerged || isVMerged) {
86694
86941
  return null;
86695
86942
  }
@@ -88112,6 +88359,59 @@ function WarpedText({
88112
88359
  }
88113
88360
  );
88114
88361
  }
88362
+ var GLYPH_BY_SHAPE = Object.fromEntries(
88363
+ ACTION_BUTTON_PRESETS.map((p3) => [p3.shapeType, p3.iconPath])
88364
+ );
88365
+ GLYPH_BY_SHAPE["actionButtonForwardOrNext"] = GLYPH_BY_SHAPE["actionButtonForwardNext"];
88366
+ GLYPH_BY_SHAPE["actionButtonBackOrPrevious"] = GLYPH_BY_SHAPE["actionButtonBackPrevious"];
88367
+ function isActionButtonShape(shapeType) {
88368
+ return Boolean(shapeType && shapeType in GLYPH_BY_SHAPE);
88369
+ }
88370
+ function getActionButtonGlyphPath(shapeType) {
88371
+ if (!shapeType) {
88372
+ return void 0;
88373
+ }
88374
+ const path = GLYPH_BY_SHAPE[shapeType];
88375
+ return path && path.length > 0 ? path : void 0;
88376
+ }
88377
+ function ActionButtonGlyphOverlay({
88378
+ element: element2,
88379
+ color
88380
+ }) {
88381
+ const shapeType = "shapeType" in element2 ? element2.shapeType : void 0;
88382
+ const path = getActionButtonGlyphPath(shapeType);
88383
+ if (!path) {
88384
+ return null;
88385
+ }
88386
+ const stroke = color ?? ("textStyle" in element2 && element2.textStyle?.color || "#ffffff");
88387
+ return /* @__PURE__ */ jsx(
88388
+ "svg",
88389
+ {
88390
+ viewBox: "0 0 24 24",
88391
+ width: "100%",
88392
+ height: "100%",
88393
+ preserveAspectRatio: "xMidYMid meet",
88394
+ style: {
88395
+ position: "absolute",
88396
+ inset: 0,
88397
+ pointerEvents: "none",
88398
+ padding: "20%"
88399
+ },
88400
+ "aria-hidden": "true",
88401
+ children: /* @__PURE__ */ jsx(
88402
+ "path",
88403
+ {
88404
+ d: path,
88405
+ fill: "none",
88406
+ stroke,
88407
+ strokeWidth: 2,
88408
+ strokeLinecap: "round",
88409
+ strokeLinejoin: "round"
88410
+ }
88411
+ )
88412
+ }
88413
+ );
88414
+ }
88115
88415
  function ColorChangedImage({
88116
88416
  src,
88117
88417
  clrChange,
@@ -88382,6 +88682,7 @@ function renderImg(el, style, filter, alt, opacity) {
88382
88682
  return /* @__PURE__ */ jsxs(Fragment, { children: [
88383
88683
  tileDuotoneColors && renderDuotoneSvgFilter(el.id, tileDuotoneColors.color1, tileDuotoneColors.color2),
88384
88684
  renderArtisticEffectSvgFilter(el.id, artisticEffectName, artisticRadius),
88685
+ renderImageAlphaSvgFilter(el),
88385
88686
  /* @__PURE__ */ jsx(
88386
88687
  "div",
88387
88688
  {
@@ -88403,6 +88704,7 @@ function renderImg(el, style, filter, alt, opacity) {
88403
88704
  return /* @__PURE__ */ jsxs(Fragment, { children: [
88404
88705
  duotoneColors && !useDuotoneCanvas && renderDuotoneSvgFilter(el.id, duotoneColors.color1, duotoneColors.color2),
88405
88706
  renderArtisticEffectSvgFilter(el.id, artisticEffectName, artisticRadius),
88707
+ renderImageAlphaSvgFilter(el),
88406
88708
  useDuotoneCanvas && duotoneColors ? /* @__PURE__ */ jsx(
88407
88709
  DuotoneImage,
88408
88710
  {
@@ -90911,8 +91213,11 @@ function renderBody(el, isImg, isEditing, editText, spellCheck, txtSE, txtS, vec
90911
91213
  ...scene3dStyle.perspective ? { perspective: scene3dStyle.perspective } : {},
90912
91214
  ...scene3dStyle.transformStyle ? { transformStyle: scene3dStyle.transformStyle } : {}
90913
91215
  } : void 0;
91216
+ const shapeTypeForGlyph = "shapeType" in el ? el.shapeType : void 0;
91217
+ const showActionButtonGlyph = isActionButtonShape(shapeTypeForGlyph);
90914
91218
  return /* @__PURE__ */ jsxs(Fragment, { children: [
90915
91219
  vecShape,
91220
+ showActionButtonGlyph && /* @__PURE__ */ jsx(ActionButtonGlyphOverlay, { element: el }),
90916
91221
  isTxtEl ? useSvgWarp ? /* @__PURE__ */ jsx(
90917
91222
  "div",
90918
91223
  {
@@ -91722,11 +92027,16 @@ function usePresenceTracking({
91722
92027
  if (cid === localClientId) {
91723
92028
  return;
91724
92029
  }
91725
- const raw = state2?.presence;
92030
+ const stateRecord = state2;
92031
+ const raw = stateRecord?.presence;
91726
92032
  if (!raw || typeof raw !== "object") {
91727
92033
  return;
91728
92034
  }
91729
- const sanitized = sanitizePresence({ ...raw, clientId: cid }, canvasWidth, canvasHeight);
92035
+ const sanitized = sanitizePresence(
92036
+ { ...raw, clientId: cid },
92037
+ canvasWidth,
92038
+ canvasHeight
92039
+ );
91730
92040
  if (!sanitized) {
91731
92041
  return;
91732
92042
  }
@@ -91794,15 +92104,9 @@ function useYjsProvider({ config }) {
91794
92104
  try {
91795
92105
  const [Y, { WebsocketProvider: WebsocketProvider2 }] = await Promise.all([Promise.resolve().then(() => (init_yjs(), yjs_exports)), Promise.resolve().then(() => (init_y_websocket(), y_websocket_exports))]);
91796
92106
  const yDoc = new Y.Doc();
91797
- const provider = new WebsocketProvider2(
91798
- config.serverUrl,
91799
- roomId,
91800
- yDoc,
91801
- // eslint-disable-line @typescript-eslint/no-explicit-any
91802
- {
91803
- params: config.authToken ? { token: config.authToken } : void 0
91804
- }
91805
- );
92107
+ const provider = new WebsocketProvider2(config.serverUrl, roomId, yDoc, {
92108
+ params: config.authToken ? { token: config.authToken } : void 0
92109
+ });
91806
92110
  let connected = false;
91807
92111
  const handleStatus = (event) => {
91808
92112
  if (event.status === "connected") {
@@ -95463,90 +95767,101 @@ var SlideNotesPanel = ({
95463
95767
  });
95464
95768
  const hasNotes = draft.trim().length > 0;
95465
95769
  const slideLabel = activeSlide ? t2("pptx.notes.slideN", { n: activeSlide.slideNumber }) : t2("pptx.notes.noSlide");
95466
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col border-t border-border/60 bg-background select-none", children: [
95467
- /* @__PURE__ */ jsxs(
95468
- "button",
95469
- {
95470
- type: "button",
95471
- onClick: onToggle,
95472
- 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",
95473
- "aria-expanded": isExpanded,
95474
- "aria-controls": "slide-notes-content",
95475
- children: [
95476
- "Notes",
95477
- !isExpanded && hasNotes && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/50 text-[10px]", children: "(has notes)" })
95478
- ]
95479
- }
95480
- ),
95481
- isExpanded && /* @__PURE__ */ jsxs(
95482
- "div",
95483
- {
95484
- id: "slide-notes-content",
95485
- className: "px-3 pb-2 overflow-y-auto",
95486
- style: { maxHeight: panelHeight ?? EXPANDED_MAX_HEIGHT + 40 },
95487
- children: [
95488
- /* @__PURE__ */ jsx("div", { className: "text-[10px] text-muted-foreground mb-1", children: slideLabel }),
95489
- canEdit ? /* @__PURE__ */ jsxs(Fragment, { children: [
95490
- /* @__PURE__ */ jsx(
95491
- NotesToolbar,
95492
- {
95493
- isRichEditEnabled,
95494
- showLinkPopover,
95495
- savedSelectionText: savedSelectionRef.current?.text ?? "",
95496
- hasAllSlides: allSlides !== void 0 && allSlides.length > 0,
95497
- onApplyRichCommand: applyRichCommand,
95498
- onToggleBulletList: toggleBulletList,
95499
- onToggleNumberedList: toggleNumberedList,
95500
- onIndent: handleIndent,
95501
- onOutdent: handleOutdent,
95502
- onLinkButtonClick: handleLinkButtonClick,
95503
- onInsertLink: handleInsertLink,
95504
- onCloseLinkPopover: () => setShowLinkPopover(false),
95505
- onPrintClick: () => setShowPrintDialog(true),
95506
- onToggleRichEdit: () => setIsRichEditEnabled((prev) => !prev)
95507
- }
95508
- ),
95509
- isRichEditEnabled ? /* @__PURE__ */ jsx(
95510
- "div",
95511
- {
95512
- ref: richEditorRef,
95513
- contentEditable: true,
95514
- suppressContentEditableWarning: true,
95515
- onInput: handleRichInput,
95516
- onBlur: handleBlur,
95517
- onKeyDown: handleKeyDownRich,
95518
- onClick: handleEditorClick,
95519
- 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",
95520
- style: { maxHeight: EXPANDED_MAX_HEIGHT - 8, minHeight: 72 }
95521
- }
95522
- ) : /* @__PURE__ */ jsx(
95523
- "textarea",
95524
- {
95525
- ref: textareaRef,
95526
- name: "slide-notes",
95527
- value: draft,
95528
- onChange: handlePlainChange,
95529
- onBlur: handleBlur,
95530
- onKeyDown: handleKeyDownPlain,
95531
- placeholder: t2("pptx.notes.clickToAddNotes"),
95532
- rows: 4,
95533
- 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",
95534
- style: { maxHeight: EXPANDED_MAX_HEIGHT - 8 }
95535
- }
95536
- )
95537
- ] }) : /* @__PURE__ */ jsx(
95538
- "div",
95539
- {
95540
- 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",
95541
- style: { maxHeight: EXPANDED_MAX_HEIGHT - 32, minHeight: 60 },
95542
- children: hasNotes ? renderRichNotesSegments(draftSegments) : /* @__PURE__ */ jsx("span", { className: "italic text-muted-foreground", children: t2("pptx.notes.noNotes") })
95543
- }
95544
- )
95545
- ]
95546
- }
95547
- ),
95548
- showPrintDialog && allSlides && /* @__PURE__ */ jsx(NotesPrintDialog, { slides: allSlides, onClose: () => setShowPrintDialog(false) })
95549
- ] });
95770
+ return /* @__PURE__ */ jsxs(
95771
+ "div",
95772
+ {
95773
+ className: cn(
95774
+ "flex flex-col border-t border-border/60 bg-background select-none",
95775
+ // On mobile, hide the entire notes strip when collapsed — the
95776
+ // MobileBottomBar's Notes button is the entry point instead.
95777
+ !isExpanded && "max-md:hidden"
95778
+ ),
95779
+ children: [
95780
+ /* @__PURE__ */ jsxs(
95781
+ "button",
95782
+ {
95783
+ type: "button",
95784
+ onClick: onToggle,
95785
+ 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",
95786
+ "aria-expanded": isExpanded,
95787
+ "aria-controls": "slide-notes-content",
95788
+ children: [
95789
+ "Notes",
95790
+ !isExpanded && hasNotes && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/50 text-[10px]", children: "(has notes)" })
95791
+ ]
95792
+ }
95793
+ ),
95794
+ isExpanded && /* @__PURE__ */ jsxs(
95795
+ "div",
95796
+ {
95797
+ id: "slide-notes-content",
95798
+ className: "px-3 pb-2 overflow-y-auto",
95799
+ style: { maxHeight: panelHeight ?? EXPANDED_MAX_HEIGHT + 40 },
95800
+ children: [
95801
+ /* @__PURE__ */ jsx("div", { className: "text-[10px] text-muted-foreground mb-1", children: slideLabel }),
95802
+ canEdit ? /* @__PURE__ */ jsxs(Fragment, { children: [
95803
+ /* @__PURE__ */ jsx(
95804
+ NotesToolbar,
95805
+ {
95806
+ isRichEditEnabled,
95807
+ showLinkPopover,
95808
+ savedSelectionText: savedSelectionRef.current?.text ?? "",
95809
+ hasAllSlides: allSlides !== void 0 && allSlides.length > 0,
95810
+ onApplyRichCommand: applyRichCommand,
95811
+ onToggleBulletList: toggleBulletList,
95812
+ onToggleNumberedList: toggleNumberedList,
95813
+ onIndent: handleIndent,
95814
+ onOutdent: handleOutdent,
95815
+ onLinkButtonClick: handleLinkButtonClick,
95816
+ onInsertLink: handleInsertLink,
95817
+ onCloseLinkPopover: () => setShowLinkPopover(false),
95818
+ onPrintClick: () => setShowPrintDialog(true),
95819
+ onToggleRichEdit: () => setIsRichEditEnabled((prev) => !prev)
95820
+ }
95821
+ ),
95822
+ isRichEditEnabled ? /* @__PURE__ */ jsx(
95823
+ "div",
95824
+ {
95825
+ ref: richEditorRef,
95826
+ contentEditable: true,
95827
+ suppressContentEditableWarning: true,
95828
+ onInput: handleRichInput,
95829
+ onBlur: handleBlur,
95830
+ onKeyDown: handleKeyDownRich,
95831
+ onClick: handleEditorClick,
95832
+ 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",
95833
+ style: { maxHeight: EXPANDED_MAX_HEIGHT - 8, minHeight: 72 }
95834
+ }
95835
+ ) : /* @__PURE__ */ jsx(
95836
+ "textarea",
95837
+ {
95838
+ ref: textareaRef,
95839
+ name: "slide-notes",
95840
+ value: draft,
95841
+ onChange: handlePlainChange,
95842
+ onBlur: handleBlur,
95843
+ onKeyDown: handleKeyDownPlain,
95844
+ placeholder: t2("pptx.notes.clickToAddNotes"),
95845
+ rows: 4,
95846
+ 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",
95847
+ style: { maxHeight: EXPANDED_MAX_HEIGHT - 8 }
95848
+ }
95849
+ )
95850
+ ] }) : /* @__PURE__ */ jsx(
95851
+ "div",
95852
+ {
95853
+ 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",
95854
+ style: { maxHeight: EXPANDED_MAX_HEIGHT - 32, minHeight: 60 },
95855
+ children: hasNotes ? renderRichNotesSegments(draftSegments) : /* @__PURE__ */ jsx("span", { className: "italic text-muted-foreground", children: t2("pptx.notes.noNotes") })
95856
+ }
95857
+ )
95858
+ ]
95859
+ }
95860
+ ),
95861
+ showPrintDialog && allSlides && /* @__PURE__ */ jsx(NotesPrintDialog, { slides: allSlides, onClose: () => setShowPrintDialog(false) })
95862
+ ]
95863
+ }
95864
+ );
95550
95865
  };
95551
95866
  var DB_NAME = "pptx-viewer-autosave";
95552
95867
  var DB_VERSION = 1;
@@ -98083,7 +98398,8 @@ function ArrangeSection(p3) {
98083
98398
  {
98084
98399
  type: "button",
98085
98400
  onClick: p3.onToggleFormatPainter,
98086
- disabled: !p3.canEdit,
98401
+ disabled: !p3.canEdit || p3.canActivateFormatPainter === false && !p3.formatPainterActive,
98402
+ "data-testid": "format-painter-toggle",
98087
98403
  className: cn(
98088
98404
  pill,
98089
98405
  p3.formatPainterActive ? "bg-amber-600 hover:bg-amber-500 text-amber-50" : ""
@@ -98535,7 +98851,8 @@ function HomeSection(p3) {
98535
98851
  const { fontFamily, fontSize } = extractFontInfo(p3.selectedElement);
98536
98852
  const handleNewSlide = useCallback(() => {
98537
98853
  if (p3.layoutOptions.length > 0) {
98538
- p3.onInsertSlideFromLayout(p3.layoutOptions[0].path);
98854
+ const first = p3.layoutOptions[0];
98855
+ p3.onInsertSlideFromLayout(first.path, first.name);
98539
98856
  }
98540
98857
  }, [p3]);
98541
98858
  useEffect(() => {
@@ -98622,7 +98939,8 @@ function HomeSection(p3) {
98622
98939
  {
98623
98940
  type: "button",
98624
98941
  onClick: p3.onToggleFormatPainter,
98625
- disabled: !p3.canEdit,
98942
+ disabled: !p3.canEdit || p3.canActivateFormatPainter === false && !p3.formatPainterActive,
98943
+ "data-testid": "format-painter-toggle",
98626
98944
  className: cn(
98627
98945
  gL,
98628
98946
  p3.formatPainterActive ? "bg-amber-600 hover:bg-amber-500 text-amber-50" : ""
@@ -98672,7 +98990,7 @@ function HomeSection(p3) {
98672
98990
  type: "button",
98673
98991
  className: "flex items-center gap-2 w-full px-3 py-1.5 text-xs text-foreground hover:bg-muted transition-colors",
98674
98992
  onClick: () => {
98675
- p3.onInsertSlideFromLayout(lo.path);
98993
+ p3.onInsertSlideFromLayout(lo.path, lo.name);
98676
98994
  setLayoutMenuOpen(false);
98677
98995
  },
98678
98996
  children: lo.name
@@ -99572,6 +99890,561 @@ function TextSection(p3) {
99572
99890
  ] })
99573
99891
  ] });
99574
99892
  }
99893
+ function ViewSection(p3) {
99894
+ const { t: t2 } = useTranslation();
99895
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
99896
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-0.5", children: [
99897
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5", children: [
99898
+ /* @__PURE__ */ jsx("button", { className: pill, title: "Normal view", children: "Normal" }),
99899
+ 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" }),
99900
+ /* @__PURE__ */ jsx("button", { className: pill, title: "Reading View", children: "Reading View" })
99901
+ ] }),
99902
+ /* @__PURE__ */ jsx("span", { className: "text-[9px] text-muted-foreground leading-none", children: "Presentation Views" })
99903
+ ] }),
99904
+ sep,
99905
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-0.5", children: [
99906
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-0.5", children: /* @__PURE__ */ jsx(
99907
+ "button",
99908
+ {
99909
+ onClick: p3.onEnterMasterView,
99910
+ disabled: !p3.canEdit,
99911
+ className: pill,
99912
+ title: "Edit slide masters and layouts",
99913
+ children: "Slide Master"
99914
+ }
99915
+ ) }),
99916
+ /* @__PURE__ */ jsx("span", { className: "text-[9px] text-muted-foreground leading-none", children: "Master Views" })
99917
+ ] }),
99918
+ sep,
99919
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-0.5", children: [
99920
+ /* @__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" }) }),
99921
+ /* @__PURE__ */ jsx("span", { className: "text-[9px] text-muted-foreground leading-none", children: "Zoom" })
99922
+ ] }),
99923
+ sep,
99924
+ /* @__PURE__ */ jsx(
99925
+ "button",
99926
+ {
99927
+ onClick: () => p3.onSetEditTemplateMode(!p3.editTemplateMode),
99928
+ disabled: !p3.canEdit,
99929
+ className: cn(
99930
+ pill,
99931
+ p3.editTemplateMode ? "bg-amber-600 hover:bg-amber-500 text-amber-50" : ""
99932
+ ),
99933
+ title: "Toggle template/master element editing",
99934
+ children: p3.editTemplateMode ? "Templates On" : "Templates Off"
99935
+ }
99936
+ ),
99937
+ p3.onToggleSelectionPane && /* @__PURE__ */ jsxs(
99938
+ "button",
99939
+ {
99940
+ type: "button",
99941
+ onClick: p3.onToggleSelectionPane,
99942
+ className: cn(
99943
+ pill,
99944
+ p3.isSelectionPaneOpen ? "bg-primary hover:bg-primary/80 text-primary-foreground" : ""
99945
+ ),
99946
+ title: "Selection Pane",
99947
+ children: [
99948
+ /* @__PURE__ */ jsx(LuList, { className: ic2 }),
99949
+ "Selection"
99950
+ ]
99951
+ }
99952
+ ),
99953
+ p3.onToggleEyedropper && /* @__PURE__ */ jsxs(
99954
+ "button",
99955
+ {
99956
+ type: "button",
99957
+ onClick: p3.onToggleEyedropper,
99958
+ disabled: !p3.canEdit,
99959
+ className: cn(
99960
+ pill,
99961
+ p3.eyedropperActive ? "bg-purple-600 hover:bg-purple-500 text-purple-50" : ""
99962
+ ),
99963
+ title: "Eyedropper \u2014 sample a colour from the slide",
99964
+ children: [
99965
+ /* @__PURE__ */ jsx(LuPipette, { className: ic2 }),
99966
+ "Eyedropper"
99967
+ ]
99968
+ }
99969
+ ),
99970
+ /* @__PURE__ */ jsx(
99971
+ "button",
99972
+ {
99973
+ onClick: () => p3.onSetShowGrid(!p3.showGrid),
99974
+ className: cn(pill, p3.showGrid ? "bg-primary text-primary-foreground" : ""),
99975
+ title: t2("pptx.grid.toggleGrid"),
99976
+ children: t2("pptx.grid.grid")
99977
+ }
99978
+ ),
99979
+ /* @__PURE__ */ jsx(
99980
+ "button",
99981
+ {
99982
+ onClick: () => p3.onSetShowRulers(!p3.showRulers),
99983
+ className: cn(pill, p3.showRulers ? "bg-primary text-primary-foreground" : ""),
99984
+ title: t2("pptx.ruler.toggleRulers"),
99985
+ children: t2("pptx.ruler.rulers")
99986
+ }
99987
+ ),
99988
+ /* @__PURE__ */ jsx(
99989
+ "button",
99990
+ {
99991
+ onClick: () => p3.onSetSnapToGrid(!p3.snapToGrid),
99992
+ className: cn(pill, p3.snapToGrid ? "bg-primary text-primary-foreground" : ""),
99993
+ title: t2("pptx.grid.snapToGrid"),
99994
+ children: t2("pptx.grid.snapToGrid")
99995
+ }
99996
+ ),
99997
+ /* @__PURE__ */ jsx(
99998
+ "button",
99999
+ {
100000
+ onClick: () => p3.onSetSnapToShape(!p3.snapToShape),
100001
+ className: cn(pill, p3.snapToShape ? "bg-primary text-primary-foreground" : ""),
100002
+ title: t2("pptx.grid.snapToShape"),
100003
+ children: t2("pptx.grid.snapToShape")
100004
+ }
100005
+ ),
100006
+ /* @__PURE__ */ jsx("button", { onClick: () => p3.onAddGuide("h"), className: pill, title: "Add horizontal guide", children: "H Guide" }),
100007
+ /* @__PURE__ */ jsx("button", { onClick: () => p3.onAddGuide("v"), className: pill, title: "Add vertical guide", children: "V Guide" }),
100008
+ /* @__PURE__ */ jsx(
100009
+ "button",
100010
+ {
100011
+ onClick: () => p3.onSetSpellCheckEnabled(!p3.spellCheckEnabled),
100012
+ className: cn(pill, p3.spellCheckEnabled ? "bg-primary text-primary-foreground" : ""),
100013
+ title: "Toggle spell check",
100014
+ children: "Spell"
100015
+ }
100016
+ )
100017
+ ] });
100018
+ }
100019
+ function MobileSheet({
100020
+ open,
100021
+ onClose,
100022
+ title,
100023
+ children,
100024
+ heightFraction = 0.6,
100025
+ fullScreen = false,
100026
+ className,
100027
+ headerRight
100028
+ }) {
100029
+ const sheetRef = useRef(null);
100030
+ const [dragY, setDragY] = useState(0);
100031
+ const dragStartRef = useRef(null);
100032
+ const onPointerDown = useCallback((e2) => {
100033
+ dragStartRef.current = e2.clientY;
100034
+ e2.target.setPointerCapture?.(e2.pointerId);
100035
+ }, []);
100036
+ const onPointerMove = useCallback((e2) => {
100037
+ if (dragStartRef.current === null) {
100038
+ return;
100039
+ }
100040
+ const delta = e2.clientY - dragStartRef.current;
100041
+ setDragY(Math.max(0, delta));
100042
+ }, []);
100043
+ const onPointerUp = useCallback(
100044
+ (e2) => {
100045
+ if (dragStartRef.current === null) {
100046
+ return;
100047
+ }
100048
+ const delta = e2.clientY - dragStartRef.current;
100049
+ dragStartRef.current = null;
100050
+ e2.target.releasePointerCapture?.(e2.pointerId);
100051
+ if (delta > 120) {
100052
+ onClose();
100053
+ }
100054
+ setDragY(0);
100055
+ },
100056
+ [onClose]
100057
+ );
100058
+ useEffect(() => {
100059
+ if (!open) {
100060
+ return;
100061
+ }
100062
+ const handleKey = (e2) => {
100063
+ if (e2.key === "Escape") {
100064
+ onClose();
100065
+ }
100066
+ };
100067
+ window.addEventListener("keydown", handleKey);
100068
+ return () => window.removeEventListener("keydown", handleKey);
100069
+ }, [open, onClose]);
100070
+ if (!open) {
100071
+ return null;
100072
+ }
100073
+ const heightStyle = fullScreen ? { height: "calc(100dvh - env(safe-area-inset-top))" } : { height: `${Math.round(heightFraction * 100)}dvh` };
100074
+ return /* @__PURE__ */ jsxs(
100075
+ "div",
100076
+ {
100077
+ className: "fixed inset-0 z-50 flex flex-col justify-end md:hidden",
100078
+ role: "dialog",
100079
+ "aria-modal": "true",
100080
+ children: [
100081
+ /* @__PURE__ */ jsx(
100082
+ "button",
100083
+ {
100084
+ type: "button",
100085
+ "aria-label": "Close",
100086
+ className: "absolute inset-0 bg-black/40 backdrop-blur-[2px] animate-in fade-in duration-150",
100087
+ onClick: onClose
100088
+ }
100089
+ ),
100090
+ /* @__PURE__ */ jsxs(
100091
+ "div",
100092
+ {
100093
+ ref: sheetRef,
100094
+ className: cn(
100095
+ "relative bg-background border-t border-border rounded-t-2xl shadow-2xl flex flex-col overflow-hidden",
100096
+ "animate-in slide-in-from-bottom duration-200",
100097
+ className
100098
+ ),
100099
+ style: {
100100
+ ...heightStyle,
100101
+ transform: dragY > 0 ? `translateY(${dragY}px)` : void 0,
100102
+ transition: dragStartRef.current === null ? "transform 150ms ease-out" : "none"
100103
+ },
100104
+ children: [
100105
+ /* @__PURE__ */ jsx(
100106
+ "div",
100107
+ {
100108
+ className: "flex items-center justify-center pt-2 pb-1 cursor-grab active:cursor-grabbing touch-none",
100109
+ onPointerDown,
100110
+ onPointerMove,
100111
+ onPointerUp,
100112
+ onPointerCancel: onPointerUp,
100113
+ children: /* @__PURE__ */ jsx("div", { className: "h-1 w-10 rounded-full bg-muted-foreground/40" })
100114
+ }
100115
+ ),
100116
+ (title || headerRight) && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 px-4 pb-2 border-b border-border/60", children: [
100117
+ /* @__PURE__ */ jsx("div", { className: "text-sm font-semibold text-foreground truncate", children: title }),
100118
+ headerRight
100119
+ ] }),
100120
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto overscroll-contain", children })
100121
+ ]
100122
+ }
100123
+ )
100124
+ ]
100125
+ }
100126
+ );
100127
+ }
100128
+ var MENU_ITEMS = [
100129
+ { key: "home", label: "Home", icon: LuClipboardCopy },
100130
+ { key: "insert", label: "Insert", icon: LuPlus },
100131
+ { key: "text", label: "Text", icon: LuType },
100132
+ { key: "draw", label: "Draw", icon: LuPaintbrush },
100133
+ { key: "arrange", label: "Arrange", icon: LuShapes },
100134
+ { key: "design", label: "Design", icon: LuLayoutGrid },
100135
+ { key: "transitions", label: "Transitions", icon: LuSparkles },
100136
+ { key: "animations", label: "Animations", icon: LuWand },
100137
+ { key: "slideShow", label: "Slide Show", icon: LuPresentation },
100138
+ { key: "review", label: "Review", icon: LuTextCursorInput },
100139
+ { key: "view", label: "View", icon: LuSettings },
100140
+ { key: "file", label: "File", icon: LuFile }
100141
+ ];
100142
+ function MobileMenuSheet(props) {
100143
+ const { open, onClose } = props;
100144
+ const [active, setActive] = useState("home");
100145
+ return /* @__PURE__ */ jsx(MobileSheet, { open, onClose, fullScreen: true, title: "Menu", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
100146
+ /* @__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(
100147
+ "button",
100148
+ {
100149
+ type: "button",
100150
+ onClick: () => setActive(active === key ? null : key),
100151
+ className: cn(
100152
+ "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]",
100153
+ active === key ? "bg-primary text-primary-foreground border-primary" : "border-border text-muted-foreground hover:text-foreground hover:bg-accent/40"
100154
+ ),
100155
+ children: [
100156
+ /* @__PURE__ */ jsx(Icon, { className: "w-4 h-4" }),
100157
+ label
100158
+ ]
100159
+ },
100160
+ key
100161
+ )) }) }),
100162
+ /* @__PURE__ */ jsx("div", { className: "p-3", children: /* @__PURE__ */ jsx(MobileSectionBody, { active, ...props }) })
100163
+ ] }) });
100164
+ }
100165
+ function MobileSectionBody({
100166
+ active,
100167
+ ...p3
100168
+ }) {
100169
+ const wrap = "flex flex-wrap items-center gap-2";
100170
+ switch (active) {
100171
+ case "home":
100172
+ return /* @__PURE__ */ jsx("div", { className: wrap, children: /* @__PURE__ */ jsx(
100173
+ HomeSection,
100174
+ {
100175
+ canEdit: p3.canEdit,
100176
+ clipboardPayload: p3.clipboardPayload,
100177
+ formatPainterActive: p3.formatPainterActive,
100178
+ canActivateFormatPainter: p3.canActivateFormatPainter,
100179
+ onCopy: p3.onCopy,
100180
+ onCut: p3.onCut,
100181
+ onPaste: p3.onPaste,
100182
+ onToggleFormatPainter: p3.onToggleFormatPainter,
100183
+ layoutOptions: p3.layoutOptions,
100184
+ onInsertSlideFromLayout: p3.onInsertSlideFromLayout,
100185
+ selectedElement: p3.selectedElement,
100186
+ onUpdateTextStyle: p3.onUpdateTextStyle
100187
+ }
100188
+ ) });
100189
+ case "insert":
100190
+ return /* @__PURE__ */ jsx("div", { className: wrap, children: /* @__PURE__ */ jsx(
100191
+ InsertSection,
100192
+ {
100193
+ canEdit: p3.canEdit,
100194
+ newShapeType: p3.newShapeType,
100195
+ onSetNewShapeType: p3.onSetNewShapeType,
100196
+ onAddTextBox: p3.onAddTextBox,
100197
+ onAddShape: p3.onAddShape,
100198
+ onAddTable: p3.onAddTable,
100199
+ onAddSmartArt: p3.onAddSmartArt,
100200
+ onAddEquation: p3.onAddEquation,
100201
+ onAddActionButton: p3.onAddActionButton,
100202
+ onInsertField: p3.onInsertField,
100203
+ onOpenImagePicker: p3.onOpenImagePicker,
100204
+ onOpenMediaPicker: p3.onOpenMediaPicker
100205
+ }
100206
+ ) });
100207
+ case "text":
100208
+ return /* @__PURE__ */ jsx("div", { className: wrap, children: /* @__PURE__ */ jsx(
100209
+ TextSection,
100210
+ {
100211
+ canEdit: p3.canEdit,
100212
+ selectedElement: p3.selectedElement,
100213
+ tableEditorState: p3.tableEditorState,
100214
+ onUpdateTextStyle: p3.onUpdateTextStyle
100215
+ }
100216
+ ) });
100217
+ case "draw":
100218
+ return /* @__PURE__ */ jsx("div", { className: wrap, children: /* @__PURE__ */ jsx(
100219
+ DrawSection,
100220
+ {
100221
+ activeTool: p3.activeTool,
100222
+ drawingColor: p3.drawingColor,
100223
+ drawingWidth: p3.drawingWidth,
100224
+ onSetActiveTool: p3.onSetActiveTool,
100225
+ onSetDrawingColor: p3.onSetDrawingColor,
100226
+ onSetDrawingWidth: p3.onSetDrawingWidth
100227
+ }
100228
+ ) });
100229
+ case "arrange":
100230
+ return /* @__PURE__ */ jsx("div", { className: wrap, children: /* @__PURE__ */ jsx(
100231
+ ArrangeSection,
100232
+ {
100233
+ canEdit: p3.canEdit,
100234
+ selectedElement: p3.selectedElement,
100235
+ clipboardPayload: p3.clipboardPayload,
100236
+ onAlignElements: p3.onAlignElements,
100237
+ onCopy: p3.onCopy,
100238
+ onCut: p3.onCut,
100239
+ onPaste: p3.onPaste,
100240
+ onFlip: p3.onFlip,
100241
+ onMoveLayer: p3.onMoveLayer,
100242
+ onMoveLayerToEdge: p3.onMoveLayerToEdge,
100243
+ onDuplicate: p3.onDuplicate,
100244
+ onDelete: p3.onDelete,
100245
+ formatPainterActive: p3.formatPainterActive,
100246
+ onToggleFormatPainter: p3.onToggleFormatPainter,
100247
+ canActivateFormatPainter: p3.canActivateFormatPainter
100248
+ }
100249
+ ) });
100250
+ case "design":
100251
+ return /* @__PURE__ */ jsx("div", { className: wrap, children: /* @__PURE__ */ jsx(
100252
+ DesignSection,
100253
+ {
100254
+ canEdit: p3.canEdit,
100255
+ onToggleThemeGallery: p3.onToggleThemeGallery,
100256
+ isThemeGalleryOpen: p3.isThemeGalleryOpen,
100257
+ onToggleThemeEditor: p3.onToggleThemeEditor,
100258
+ isThemeEditorOpen: p3.isThemeEditorOpen,
100259
+ onOpenDocumentProperties: p3.onOpenDocumentProperties,
100260
+ onToggleInspector: p3.onToggleInspector,
100261
+ isInspectorPaneOpen: p3.isInspectorPaneOpen
100262
+ }
100263
+ ) });
100264
+ case "transitions":
100265
+ return /* @__PURE__ */ jsx("div", { className: wrap, children: /* @__PURE__ */ jsx(
100266
+ TransitionsSection,
100267
+ {
100268
+ isInspectorPaneOpen: p3.isInspectorPaneOpen,
100269
+ onToggleInspector: p3.onToggleInspector
100270
+ }
100271
+ ) });
100272
+ case "animations":
100273
+ return /* @__PURE__ */ jsx("div", { className: wrap, children: /* @__PURE__ */ jsx(
100274
+ AnimationsSection,
100275
+ {
100276
+ canEdit: p3.canEdit,
100277
+ selectedElement: p3.selectedElement,
100278
+ isInspectorPaneOpen: p3.isInspectorPaneOpen,
100279
+ onToggleInspector: p3.onToggleInspector,
100280
+ onOpenAnimationPanel: p3.onOpenAnimationPanel,
100281
+ onAddAnimation: p3.onAddAnimation,
100282
+ onRemoveAnimation: p3.onRemoveAnimation
100283
+ }
100284
+ ) });
100285
+ case "slideShow":
100286
+ return /* @__PURE__ */ jsx("div", { className: wrap, children: /* @__PURE__ */ jsx(
100287
+ SlideShowSection,
100288
+ {
100289
+ onPresent: () => p3.onSetMode("present"),
100290
+ onEnterPresenterView: p3.onEnterPresenterView ?? (() => {
100291
+ }),
100292
+ onEnterRehearsalMode: p3.onEnterRehearsalMode ?? (() => {
100293
+ }),
100294
+ onOpenSetUpSlideShow: p3.onOpenSetUpSlideShow ?? (() => {
100295
+ }),
100296
+ onOpenBroadcastDialog: p3.onOpenBroadcastDialog ?? (() => {
100297
+ }),
100298
+ onToggleSubtitles: p3.onToggleSubtitles ?? (() => {
100299
+ }),
100300
+ showSubtitles: p3.showSubtitles ?? false,
100301
+ onSetMode: p3.onSetMode
100302
+ }
100303
+ ) });
100304
+ case "review":
100305
+ return /* @__PURE__ */ jsx("div", { className: wrap, children: /* @__PURE__ */ jsx(
100306
+ ReviewSection,
100307
+ {
100308
+ canEdit: p3.canEdit,
100309
+ spellCheckEnabled: p3.spellCheckEnabled,
100310
+ onSetSpellCheckEnabled: p3.onSetSpellCheckEnabled,
100311
+ onToggleComments: p3.onToggleComments,
100312
+ isCommentsPanelOpen: p3.isCommentsPanelOpen,
100313
+ slideCommentCount: p3.slideCommentCount,
100314
+ onCompare: p3.onCompare
100315
+ }
100316
+ ) });
100317
+ case "view":
100318
+ return /* @__PURE__ */ jsx("div", { className: wrap, children: /* @__PURE__ */ jsx(
100319
+ ViewSection,
100320
+ {
100321
+ canEdit: p3.canEdit,
100322
+ editTemplateMode: p3.editTemplateMode,
100323
+ onSetEditTemplateMode: p3.onSetEditTemplateMode,
100324
+ spellCheckEnabled: p3.spellCheckEnabled,
100325
+ onSetSpellCheckEnabled: p3.onSetSpellCheckEnabled,
100326
+ showGrid: p3.showGrid,
100327
+ showRulers: p3.showRulers,
100328
+ snapToGrid: p3.snapToGrid,
100329
+ snapToShape: p3.snapToShape,
100330
+ onSetShowGrid: p3.onSetShowGrid,
100331
+ onSetShowRulers: p3.onSetShowRulers,
100332
+ onSetSnapToGrid: p3.onSetSnapToGrid,
100333
+ onSetSnapToShape: p3.onSetSnapToShape,
100334
+ onAddGuide: p3.onAddGuide,
100335
+ onEnterMasterView: p3.onEnterMasterView,
100336
+ isSelectionPaneOpen: p3.isSelectionPaneOpen,
100337
+ onToggleSelectionPane: p3.onToggleSelectionPane,
100338
+ eyedropperActive: p3.eyedropperActive,
100339
+ onToggleEyedropper: p3.onToggleEyedropper
100340
+ }
100341
+ ) });
100342
+ case "file":
100343
+ return /* @__PURE__ */ jsx("div", { className: wrap, children: /* @__PURE__ */ jsx(
100344
+ FileSection,
100345
+ {
100346
+ onExportPng: p3.onExportPng,
100347
+ onExportPdf: p3.onExportPdf,
100348
+ onExportVideo: p3.onExportVideo,
100349
+ onExportGif: p3.onExportGif,
100350
+ onPackageForSharing: p3.onPackageForSharing,
100351
+ onSaveAsPptx: p3.onSaveAsPptx,
100352
+ onSaveAsPpsx: p3.onSaveAsPpsx,
100353
+ onSaveAsPptm: p3.onSaveAsPptm,
100354
+ hasMacros: p3.hasMacros,
100355
+ onCopySlideAsImage: p3.onCopySlideAsImage,
100356
+ onPrint: p3.onPrint,
100357
+ onOpenDocumentProperties: p3.onOpenDocumentProperties,
100358
+ onOpenPasswordProtection: p3.onOpenPasswordProtection,
100359
+ onOpenFontEmbedding: p3.onOpenFontEmbedding,
100360
+ onOpenDigitalSignatures: p3.onOpenDigitalSignatures
100361
+ }
100362
+ ) });
100363
+ default:
100364
+ return /* @__PURE__ */ jsxs("div", { className: "text-center text-sm text-muted-foreground py-8", children: [
100365
+ /* @__PURE__ */ jsx(LuChevronRight, { className: "w-5 h-5 inline-block opacity-50" }),
100366
+ " Select a section above"
100367
+ ] });
100368
+ }
100369
+ }
100370
+ function MobileToolbar(props) {
100371
+ const { t: t2 } = useTranslation();
100372
+ const { mode, canUndo, canRedo, onUndo, onRedo, onSetMode } = props;
100373
+ const [menuOpen, setMenuOpen] = useState(false);
100374
+ const showEdit = mode === "edit" || mode === "master";
100375
+ 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";
100376
+ return /* @__PURE__ */ jsxs(
100377
+ "div",
100378
+ {
100379
+ role: "toolbar",
100380
+ "aria-label": "Toolbar",
100381
+ 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)]",
100382
+ children: [
100383
+ showEdit && /* @__PURE__ */ jsx(
100384
+ "button",
100385
+ {
100386
+ type: "button",
100387
+ onClick: () => setMenuOpen(true),
100388
+ className: btn,
100389
+ title: "Menu",
100390
+ "aria-label": "Menu",
100391
+ children: /* @__PURE__ */ jsx(LuMenu, { className: "w-5 h-5" })
100392
+ }
100393
+ ),
100394
+ showEdit && /* @__PURE__ */ jsxs(Fragment, { children: [
100395
+ /* @__PURE__ */ jsx(
100396
+ "button",
100397
+ {
100398
+ type: "button",
100399
+ onClick: onUndo,
100400
+ disabled: !canUndo,
100401
+ className: btn,
100402
+ title: t2("pptx.toolbar.undo"),
100403
+ "aria-label": t2("pptx.toolbar.undo"),
100404
+ children: /* @__PURE__ */ jsx(LuUndo, { className: "w-5 h-5" })
100405
+ }
100406
+ ),
100407
+ /* @__PURE__ */ jsx(
100408
+ "button",
100409
+ {
100410
+ type: "button",
100411
+ onClick: onRedo,
100412
+ disabled: !canRedo,
100413
+ className: btn,
100414
+ title: t2("pptx.toolbar.redo"),
100415
+ "aria-label": t2("pptx.toolbar.redo"),
100416
+ children: /* @__PURE__ */ jsx(LuRedo, { className: "w-5 h-5" })
100417
+ }
100418
+ )
100419
+ ] }),
100420
+ /* @__PURE__ */ jsx("div", { className: "flex-1" }),
100421
+ /* @__PURE__ */ jsx(
100422
+ "button",
100423
+ {
100424
+ type: "button",
100425
+ onClick: () => onSetMode("present"),
100426
+ className: cn(btn, "text-primary"),
100427
+ title: t2("pptx.toolbar.present"),
100428
+ "aria-label": t2("pptx.toolbar.present"),
100429
+ children: /* @__PURE__ */ jsx(LuPresentation, { className: "w-5 h-5" })
100430
+ }
100431
+ ),
100432
+ showEdit && /* @__PURE__ */ jsx(
100433
+ "button",
100434
+ {
100435
+ type: "button",
100436
+ onClick: props.onOpenShareDialog ?? props.onPackageForSharing,
100437
+ className: cn(btn, "bg-primary text-primary-foreground hover:bg-primary/90 px-3"),
100438
+ title: t2("pptx.toolbar.share"),
100439
+ "aria-label": t2("pptx.toolbar.share"),
100440
+ children: /* @__PURE__ */ jsx(LuShare2, { className: "w-4 h-4" })
100441
+ }
100442
+ ),
100443
+ /* @__PURE__ */ jsx(MobileMenuSheet, { open: menuOpen, onClose: () => setMenuOpen(false), ...props })
100444
+ ]
100445
+ }
100446
+ );
100447
+ }
99575
100448
  function CustomShowsControls({
99576
100449
  customShows,
99577
100450
  activeCustomShowId,
@@ -100000,7 +100873,7 @@ function ToolbarPrimaryRow(p3) {
100000
100873
  onClick: p3.onToggleComments,
100001
100874
  className: cn(
100002
100875
  qab,
100003
- "max-md:hidden",
100876
+ "relative max-md:hidden",
100004
100877
  p3.isCommentsPanelOpen ? "text-foreground" : "text-muted-foreground"
100005
100878
  ),
100006
100879
  title: t2("pptx.toolbar.comments"),
@@ -100116,134 +100989,11 @@ function ToolbarPrimaryRow(p3) {
100116
100989
  /* @__PURE__ */ jsx(OverflowMenu, { ...p3 })
100117
100990
  ] });
100118
100991
  }
100119
- function ViewSection(p3) {
100120
- const { t: t2 } = useTranslation();
100121
- return /* @__PURE__ */ jsxs(Fragment, { children: [
100122
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-0.5", children: [
100123
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5", children: [
100124
- /* @__PURE__ */ jsx("button", { className: pill, title: "Normal view", children: "Normal" }),
100125
- 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" }),
100126
- /* @__PURE__ */ jsx("button", { className: pill, title: "Reading View", children: "Reading View" })
100127
- ] }),
100128
- /* @__PURE__ */ jsx("span", { className: "text-[9px] text-muted-foreground leading-none", children: "Presentation Views" })
100129
- ] }),
100130
- sep,
100131
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-0.5", children: [
100132
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-0.5", children: /* @__PURE__ */ jsx(
100133
- "button",
100134
- {
100135
- onClick: p3.onEnterMasterView,
100136
- disabled: !p3.canEdit,
100137
- className: pill,
100138
- title: "Edit slide masters and layouts",
100139
- children: "Slide Master"
100140
- }
100141
- ) }),
100142
- /* @__PURE__ */ jsx("span", { className: "text-[9px] text-muted-foreground leading-none", children: "Master Views" })
100143
- ] }),
100144
- sep,
100145
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-0.5", children: [
100146
- /* @__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" }) }),
100147
- /* @__PURE__ */ jsx("span", { className: "text-[9px] text-muted-foreground leading-none", children: "Zoom" })
100148
- ] }),
100149
- sep,
100150
- /* @__PURE__ */ jsx(
100151
- "button",
100152
- {
100153
- onClick: () => p3.onSetEditTemplateMode(!p3.editTemplateMode),
100154
- disabled: !p3.canEdit,
100155
- className: cn(
100156
- pill,
100157
- p3.editTemplateMode ? "bg-amber-600 hover:bg-amber-500 text-amber-50" : ""
100158
- ),
100159
- title: "Toggle template/master element editing",
100160
- children: p3.editTemplateMode ? "Templates On" : "Templates Off"
100161
- }
100162
- ),
100163
- p3.onToggleSelectionPane && /* @__PURE__ */ jsxs(
100164
- "button",
100165
- {
100166
- type: "button",
100167
- onClick: p3.onToggleSelectionPane,
100168
- className: cn(
100169
- pill,
100170
- p3.isSelectionPaneOpen ? "bg-primary hover:bg-primary/80 text-primary-foreground" : ""
100171
- ),
100172
- title: "Selection Pane",
100173
- children: [
100174
- /* @__PURE__ */ jsx(LuList, { className: ic2 }),
100175
- "Selection"
100176
- ]
100177
- }
100178
- ),
100179
- p3.onToggleEyedropper && /* @__PURE__ */ jsxs(
100180
- "button",
100181
- {
100182
- type: "button",
100183
- onClick: p3.onToggleEyedropper,
100184
- disabled: !p3.canEdit,
100185
- className: cn(
100186
- pill,
100187
- p3.eyedropperActive ? "bg-purple-600 hover:bg-purple-500 text-purple-50" : ""
100188
- ),
100189
- title: "Eyedropper \u2014 sample a colour from the slide",
100190
- children: [
100191
- /* @__PURE__ */ jsx(LuPipette, { className: ic2 }),
100192
- "Eyedropper"
100193
- ]
100194
- }
100195
- ),
100196
- /* @__PURE__ */ jsx(
100197
- "button",
100198
- {
100199
- onClick: () => p3.onSetShowGrid(!p3.showGrid),
100200
- className: cn(pill, p3.showGrid ? "bg-primary text-primary-foreground" : ""),
100201
- title: t2("pptx.grid.toggleGrid"),
100202
- children: t2("pptx.grid.grid")
100203
- }
100204
- ),
100205
- /* @__PURE__ */ jsx(
100206
- "button",
100207
- {
100208
- onClick: () => p3.onSetShowRulers(!p3.showRulers),
100209
- className: cn(pill, p3.showRulers ? "bg-primary text-primary-foreground" : ""),
100210
- title: t2("pptx.ruler.toggleRulers"),
100211
- children: t2("pptx.ruler.rulers")
100212
- }
100213
- ),
100214
- /* @__PURE__ */ jsx(
100215
- "button",
100216
- {
100217
- onClick: () => p3.onSetSnapToGrid(!p3.snapToGrid),
100218
- className: cn(pill, p3.snapToGrid ? "bg-primary text-primary-foreground" : ""),
100219
- title: t2("pptx.grid.snapToGrid"),
100220
- children: t2("pptx.grid.snapToGrid")
100221
- }
100222
- ),
100223
- /* @__PURE__ */ jsx(
100224
- "button",
100225
- {
100226
- onClick: () => p3.onSetSnapToShape(!p3.snapToShape),
100227
- className: cn(pill, p3.snapToShape ? "bg-primary text-primary-foreground" : ""),
100228
- title: t2("pptx.grid.snapToShape"),
100229
- children: t2("pptx.grid.snapToShape")
100230
- }
100231
- ),
100232
- /* @__PURE__ */ jsx("button", { onClick: () => p3.onAddGuide("h"), className: pill, title: "Add horizontal guide", children: "H Guide" }),
100233
- /* @__PURE__ */ jsx("button", { onClick: () => p3.onAddGuide("v"), className: pill, title: "Add vertical guide", children: "V Guide" }),
100234
- /* @__PURE__ */ jsx(
100235
- "button",
100236
- {
100237
- onClick: () => p3.onSetSpellCheckEnabled(!p3.spellCheckEnabled),
100238
- className: cn(pill, p3.spellCheckEnabled ? "bg-primary text-primary-foreground" : ""),
100239
- title: "Toggle spell check",
100240
- children: "Spell"
100241
- }
100242
- )
100243
- ] });
100244
- }
100245
100992
  function Toolbar(p3) {
100246
100993
  const { mode, isNarrowViewport, isCompactToolbarOpen, toolbarSection, onSetToolbarSection } = p3;
100994
+ if (isNarrowViewport && mode !== "present") {
100995
+ return /* @__PURE__ */ jsx(MobileToolbar, { ...p3 });
100996
+ }
100247
100997
  const sFil = toolbarSection === "file";
100248
100998
  const sHome = toolbarSection === "home";
100249
100999
  const sIns = toolbarSection === "insert";
@@ -100329,6 +101079,7 @@ function Toolbar(p3) {
100329
101079
  canEdit: p3.canEdit,
100330
101080
  clipboardPayload: p3.clipboardPayload,
100331
101081
  formatPainterActive: p3.formatPainterActive,
101082
+ canActivateFormatPainter: p3.canActivateFormatPainter,
100332
101083
  onCopy: p3.onCopy,
100333
101084
  onCut: p3.onCut,
100334
101085
  onPaste: p3.onPaste,
@@ -100392,7 +101143,8 @@ function Toolbar(p3) {
100392
101143
  onDuplicate: p3.onDuplicate,
100393
101144
  onDelete: p3.onDelete,
100394
101145
  formatPainterActive: p3.formatPainterActive,
100395
- onToggleFormatPainter: p3.onToggleFormatPainter
101146
+ onToggleFormatPainter: p3.onToggleFormatPainter,
101147
+ canActivateFormatPainter: p3.canActivateFormatPainter
100396
101148
  }
100397
101149
  ),
100398
101150
  sDes && /* @__PURE__ */ jsx(
@@ -106105,181 +106857,194 @@ function InspectorPane(props) {
106105
106857
  const fallback = themeOptions[0]?.path ?? "";
106106
106858
  setSelectedThemePath((previous) => previous || fallback);
106107
106859
  }, [slideMasters, themeOptions]);
106108
- return /* @__PURE__ */ jsxs(
106109
- "div",
106110
- {
106111
- className: cn(
106112
- // Shared styles
106113
- "bg-background flex flex-col text-xs text-foreground shadow-xl",
106114
- // Mobile: absolute bottom sheet overlay
106115
- "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",
106116
- "max-md:transition-transform max-md:duration-200 max-md:ease-in-out",
106117
- isOpen ? "max-md:translate-y-0" : "max-md:translate-y-full",
106118
- // Desktop: flow-based flex child (takes space from canvas)
106119
- "md:h-full md:border-l md:border-border",
106120
- !panelWidth && "md:w-72"
106121
- ),
106122
- style: panelWidth ? { width: panelWidth } : void 0,
106123
- children: [
106124
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 px-3 py-2 border-b border-border", children: [
106125
- /* @__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(
106126
- "button",
106127
- {
106128
- type: "button",
106129
- title: label,
106130
- className: cn(
106131
- "flex items-center gap-1 px-2 py-1 rounded text-[11px] transition-colors",
106132
- activeTab === key ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:text-foreground hover:bg-accent"
106133
- ),
106134
- onClick: () => onSetActiveTab(key),
106135
- children: [
106136
- /* @__PURE__ */ jsx(Icon, { className: "w-3.5 h-3.5" }),
106137
- /* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: label })
106138
- ]
106139
- },
106140
- key
106141
- )) }),
106142
- /* @__PURE__ */ jsx(
106143
- "button",
106144
- {
106145
- type: "button",
106146
- onClick: onClose,
106147
- title: t2("common.close"),
106148
- className: "p-1 rounded text-muted-foreground hover:text-foreground hover:bg-muted transition-colors",
106149
- children: /* @__PURE__ */ jsx(LuX, { className: "w-4 h-4" })
106150
- }
106151
- )
106152
- ] }),
106153
- /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto p-3 space-y-3", children: [
106154
- activeTab === "elements" && /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
106155
- /* @__PURE__ */ jsx("div", { className: cn(HEADING, "mb-2"), children: t2("pptx.inspector.layerOrder") }),
106156
- activeSlide ? [...activeSlide.elements || []].reverse().map((el, ri) => {
106157
- const idx = (activeSlide.elements || []).length - 1 - ri;
106158
- const sel = selectedElement?.id === el.id || selectedElementIds.includes(el.id);
106159
- const label = (hasTextProperties(el) ? (el.text || "").slice(0, 24) : void 0) || el.type;
106160
- return /* @__PURE__ */ jsxs(
106161
- "div",
106162
- {
106163
- title: `${el.type} \u2014 ${el.id}`,
106164
- className: cn(
106165
- "flex items-center gap-2 px-2 py-1 rounded cursor-pointer transition-colors",
106166
- sel ? "bg-primary/30 text-primary" : "hover:bg-muted text-foreground"
106167
- ),
106168
- onClick: () => onSelectElement(el.id),
106169
- children: [
106170
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground w-4 text-right", children: idx + 1 }),
106171
- /* @__PURE__ */ jsx("span", { className: "flex-1 truncate", children: label })
106172
- ]
106173
- },
106174
- el.id
106175
- );
106176
- }) : /* @__PURE__ */ jsx("div", { className: "text-muted-foreground italic", children: t2("pptx.inspector.noSlideSelected") })
106177
- ] }),
106178
- activeTab === "properties" && /* @__PURE__ */ jsx("div", { className: "space-y-3", children: hasSelection && selectedElement ? /* @__PURE__ */ jsx(
106179
- ElementInspectorBody,
106180
- {
106181
- selectedElement,
106182
- canEdit,
106183
- slides,
106184
- tableEditorState,
106185
- mediaDataUrls,
106186
- onUpdateElement,
106187
- onUpdateElementStyle,
106188
- onUpdateTextStyle,
106189
- onMoveLayer
106190
- }
106191
- ) : /* @__PURE__ */ jsxs(Fragment, { children: [
106860
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
106861
+ isOpen && /* @__PURE__ */ jsx(
106862
+ "button",
106863
+ {
106864
+ type: "button",
106865
+ "aria-label": t2("common.close"),
106866
+ onClick: onClose,
106867
+ className: "md:hidden fixed inset-0 z-20 bg-black/40 backdrop-blur-[2px] animate-in fade-in duration-150"
106868
+ }
106869
+ ),
106870
+ /* @__PURE__ */ jsxs(
106871
+ "div",
106872
+ {
106873
+ className: cn(
106874
+ // Shared styles
106875
+ "bg-background flex flex-col text-xs text-foreground shadow-xl",
106876
+ // Mobile: absolute bottom sheet overlay sized via dvh so it
106877
+ // adapts to the on-screen keyboard / dynamic browser chrome.
106878
+ "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)]",
106879
+ "max-md:transition-transform max-md:duration-200 max-md:ease-in-out",
106880
+ isOpen ? "max-md:translate-y-0" : "max-md:translate-y-full",
106881
+ // Desktop: flow-based flex child (takes space from canvas)
106882
+ "md:h-full md:border-l md:border-border",
106883
+ !panelWidth && "md:w-72"
106884
+ ),
106885
+ style: panelWidth ? { width: panelWidth } : void 0,
106886
+ children: [
106887
+ /* @__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" }) }),
106888
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 px-3 py-2 border-b border-border", children: [
106889
+ /* @__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(
106890
+ "button",
106891
+ {
106892
+ type: "button",
106893
+ title: label,
106894
+ className: cn(
106895
+ "flex items-center gap-1 px-2 py-1 rounded text-[11px] transition-colors",
106896
+ activeTab === key ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:text-foreground hover:bg-accent"
106897
+ ),
106898
+ onClick: () => onSetActiveTab(key),
106899
+ children: [
106900
+ /* @__PURE__ */ jsx(Icon, { className: "w-3.5 h-3.5" }),
106901
+ /* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: label })
106902
+ ]
106903
+ },
106904
+ key
106905
+ )) }),
106192
106906
  /* @__PURE__ */ jsx(
106193
- PresentationPropertiesPanel,
106907
+ "button",
106194
106908
  {
106195
- canEdit,
106196
- canvasSize,
106197
- presentationProperties,
106198
- onUpdatePresentationProperties,
106199
- notesMaster,
106200
- handoutMaster,
106201
- notesCanvasSize,
106202
- coreProperties,
106203
- appProperties,
106204
- customProperties,
106205
- themeOptions,
106206
- selectedThemePath,
106207
- setSelectedThemePath,
106208
- onApplyTheme,
106209
- onUpdateCoreProperties,
106210
- onUpdateAppProperties,
106211
- onUpdateCustomProperties,
106212
- tagCollections,
106213
- onUpdateTagCollections,
106214
- onUpdateCanvasSize,
106215
- activeSlide,
106216
- theme,
106217
- onUpdateSlide
106909
+ type: "button",
106910
+ onClick: onClose,
106911
+ title: t2("common.close"),
106912
+ className: "p-1 rounded text-muted-foreground hover:text-foreground hover:bg-muted transition-colors",
106913
+ children: /* @__PURE__ */ jsx(LuX, { className: "w-4 h-4" })
106218
106914
  }
106219
- ),
106220
- activeSlide && /* @__PURE__ */ jsx(
106221
- SlideBackgroundPanel,
106915
+ )
106916
+ ] }),
106917
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto p-3 space-y-3", children: [
106918
+ activeTab === "elements" && /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
106919
+ /* @__PURE__ */ jsx("div", { className: cn(HEADING, "mb-2"), children: t2("pptx.inspector.layerOrder") }),
106920
+ activeSlide ? [...activeSlide.elements || []].reverse().map((el, ri) => {
106921
+ const idx = (activeSlide.elements || []).length - 1 - ri;
106922
+ const sel = selectedElement?.id === el.id || selectedElementIds.includes(el.id);
106923
+ const label = (hasTextProperties(el) ? (el.text || "").slice(0, 24) : void 0) || el.type;
106924
+ return /* @__PURE__ */ jsxs(
106925
+ "div",
106926
+ {
106927
+ title: `${el.type} \u2014 ${el.id}`,
106928
+ className: cn(
106929
+ "flex items-center gap-2 px-2 py-1 rounded cursor-pointer transition-colors",
106930
+ sel ? "bg-primary/30 text-primary" : "hover:bg-muted text-foreground"
106931
+ ),
106932
+ onClick: () => onSelectElement(el.id),
106933
+ children: [
106934
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground w-4 text-right", children: idx + 1 }),
106935
+ /* @__PURE__ */ jsx("span", { className: "flex-1 truncate", children: label })
106936
+ ]
106937
+ },
106938
+ el.id
106939
+ );
106940
+ }) : /* @__PURE__ */ jsx("div", { className: "text-muted-foreground italic", children: t2("pptx.inspector.noSlideSelected") })
106941
+ ] }),
106942
+ activeTab === "properties" && /* @__PURE__ */ jsx("div", { className: "space-y-3", children: hasSelection && selectedElement ? /* @__PURE__ */ jsx(
106943
+ ElementInspectorBody,
106222
106944
  {
106223
- activeSlide,
106945
+ selectedElement,
106224
106946
  canEdit,
106225
- onUpdateSlide,
106226
- editTemplateMode,
106227
- slideMasters,
106228
- onSetTemplateBackground,
106229
- onGetTemplateBackgroundColor
106947
+ slides,
106948
+ tableEditorState,
106949
+ mediaDataUrls,
106950
+ onUpdateElement,
106951
+ onUpdateElementStyle,
106952
+ onUpdateTextStyle,
106953
+ onMoveLayer
106230
106954
  }
106231
- )
106232
- ] }) }),
106233
- activeTab === "comments" && /* @__PURE__ */ jsx(
106234
- InspectorCommentsSection,
106235
- {
106236
- comments,
106237
- canEdit,
106238
- activeSlide,
106239
- selectedElement,
106240
- editingCommentId,
106241
- commentEditDraft,
106242
- commentDraft,
106243
- replyingToCommentId: replyingToCommentId ?? null,
106244
- replyDraftByCommentId: replyDraftByCommentId ?? {},
106245
- onSetCommentDraft,
106246
- onAddComment,
106247
- onDeleteComment,
106248
- onStartEditComment,
106249
- onSaveEditComment,
106250
- onCancelEditComment,
106251
- onSetCommentEditDraft,
106252
- onToggleCommentResolved,
106253
- onStartReply,
106254
- onCancelReply,
106255
- onReplyDraftChange,
106256
- onSubmitReply,
106257
- onSelectElement
106258
- }
106259
- )
106260
- ] }),
106261
- hasSelection && selectedElement && activeSlide && /* @__PURE__ */ jsxs(Fragment, { children: [
106262
- /* @__PURE__ */ jsx(ResizeHandle, { direction: "vertical", onResize: onResizeAnim }),
106263
- /* @__PURE__ */ jsx(
106264
- "div",
106265
- {
106266
- className: "border-t border-border p-3 overflow-y-auto flex-shrink-0",
106267
- style: { height: animPanelHeight },
106268
- children: /* @__PURE__ */ jsx(
106269
- AnimationPanel,
106955
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
106956
+ /* @__PURE__ */ jsx(
106957
+ PresentationPropertiesPanel,
106270
106958
  {
106271
- selectedElement,
106272
- activeSlide,
106273
106959
  canEdit,
106960
+ canvasSize,
106961
+ presentationProperties,
106962
+ onUpdatePresentationProperties,
106963
+ notesMaster,
106964
+ handoutMaster,
106965
+ notesCanvasSize,
106966
+ coreProperties,
106967
+ appProperties,
106968
+ customProperties,
106969
+ themeOptions,
106970
+ selectedThemePath,
106971
+ setSelectedThemePath,
106972
+ onApplyTheme,
106973
+ onUpdateCoreProperties,
106974
+ onUpdateAppProperties,
106975
+ onUpdateCustomProperties,
106976
+ tagCollections,
106977
+ onUpdateTagCollections,
106978
+ onUpdateCanvasSize,
106979
+ activeSlide,
106980
+ theme,
106274
106981
  onUpdateSlide
106275
106982
  }
106983
+ ),
106984
+ activeSlide && /* @__PURE__ */ jsx(
106985
+ SlideBackgroundPanel,
106986
+ {
106987
+ activeSlide,
106988
+ canEdit,
106989
+ onUpdateSlide,
106990
+ editTemplateMode,
106991
+ slideMasters,
106992
+ onSetTemplateBackground,
106993
+ onGetTemplateBackgroundColor
106994
+ }
106276
106995
  )
106277
- }
106278
- )
106279
- ] })
106280
- ]
106281
- }
106282
- );
106996
+ ] }) }),
106997
+ activeTab === "comments" && /* @__PURE__ */ jsx(
106998
+ InspectorCommentsSection,
106999
+ {
107000
+ comments,
107001
+ canEdit,
107002
+ activeSlide,
107003
+ selectedElement,
107004
+ editingCommentId,
107005
+ commentEditDraft,
107006
+ commentDraft,
107007
+ replyingToCommentId: replyingToCommentId ?? null,
107008
+ replyDraftByCommentId: replyDraftByCommentId ?? {},
107009
+ onSetCommentDraft,
107010
+ onAddComment,
107011
+ onDeleteComment,
107012
+ onStartEditComment,
107013
+ onSaveEditComment,
107014
+ onCancelEditComment,
107015
+ onSetCommentEditDraft,
107016
+ onToggleCommentResolved,
107017
+ onStartReply,
107018
+ onCancelReply,
107019
+ onReplyDraftChange,
107020
+ onSubmitReply,
107021
+ onSelectElement
107022
+ }
107023
+ )
107024
+ ] }),
107025
+ hasSelection && selectedElement && activeSlide && /* @__PURE__ */ jsxs(Fragment, { children: [
107026
+ /* @__PURE__ */ jsx(ResizeHandle, { direction: "vertical", onResize: onResizeAnim }),
107027
+ /* @__PURE__ */ jsx(
107028
+ "div",
107029
+ {
107030
+ className: "border-t border-border p-3 overflow-y-auto flex-shrink-0",
107031
+ style: { height: animPanelHeight },
107032
+ children: /* @__PURE__ */ jsx(
107033
+ AnimationPanel,
107034
+ {
107035
+ selectedElement,
107036
+ activeSlide,
107037
+ canEdit,
107038
+ onUpdateSlide
107039
+ }
107040
+ )
107041
+ }
107042
+ )
107043
+ ] })
107044
+ ]
107045
+ }
107046
+ )
107047
+ ] });
106283
107048
  }
106284
107049
  function buildPathD(points) {
106285
107050
  if (points.length === 0) {
@@ -110413,7 +111178,8 @@ function ViewerBottomPanels({
110413
111178
  onZoomToFit,
110414
111179
  mode,
110415
111180
  onSetMode,
110416
- onToggleSlideSorter
111181
+ onToggleSlideSorter,
111182
+ hideStatusBar = false
110417
111183
  }) {
110418
111184
  return /* @__PURE__ */ jsxs(Fragment, { children: [
110419
111185
  onResizeBottom && !isSlideNotesCollapsed && /* @__PURE__ */ jsx(ResizeHandle, { direction: "vertical", onResize: onResizeBottom }),
@@ -110429,7 +111195,7 @@ function ViewerBottomPanels({
110429
111195
  panelHeight: notesPanelHeight
110430
111196
  }
110431
111197
  ),
110432
- /* @__PURE__ */ jsx(
111198
+ !hideStatusBar && /* @__PURE__ */ jsx(
110433
111199
  StatusBar,
110434
111200
  {
110435
111201
  slideCount,
@@ -110586,6 +111352,45 @@ function ViewerInspector({
110586
111352
  }
110587
111353
  );
110588
111354
  }
111355
+
111356
+ // src/viewer/hooks/useScopedLayoutOptions.ts
111357
+ function scopeLayoutOptionsToActiveSlide(options, activeSlide) {
111358
+ if (!activeSlide?.layoutPath) {
111359
+ return options;
111360
+ }
111361
+ const hasAnyMasterInfo = options.some((o3) => o3.masterPath);
111362
+ if (!hasAnyMasterInfo) {
111363
+ return options;
111364
+ }
111365
+ const activeOption = options.find((o3) => o3.path === activeSlide.layoutPath);
111366
+ const activeMaster = activeOption?.masterPath;
111367
+ if (!activeMaster) {
111368
+ return options;
111369
+ }
111370
+ const scoped = options.filter((o3) => o3.masterPath === activeMaster);
111371
+ const seen = /* @__PURE__ */ new Map();
111372
+ for (const opt of scoped) {
111373
+ const isActive = opt.path === activeSlide.layoutPath;
111374
+ const existing = seen.get(opt.name);
111375
+ if (!existing || isActive) {
111376
+ seen.set(opt.name, opt);
111377
+ }
111378
+ }
111379
+ const chosen = new Set(Array.from(seen.values()).map((o3) => o3.path));
111380
+ const result = [];
111381
+ const usedNames = /* @__PURE__ */ new Set();
111382
+ for (const opt of scoped) {
111383
+ if (!chosen.has(opt.path)) {
111384
+ continue;
111385
+ }
111386
+ if (usedNames.has(opt.name)) {
111387
+ continue;
111388
+ }
111389
+ usedNames.add(opt.name);
111390
+ result.push(opt);
111391
+ }
111392
+ return result;
111393
+ }
110589
111394
  function ViewerToolbarSection(props) {
110590
111395
  const {
110591
111396
  mode,
@@ -110655,6 +111460,10 @@ function ViewerToolbarSection(props) {
110655
111460
  },
110656
111461
  [activeSlide, propertyHandlers]
110657
111462
  );
111463
+ const scopedLayoutOptions = React10__default.useMemo(
111464
+ () => scopeLayoutOptionsToActiveSlide(s.layoutOptions, activeSlide),
111465
+ [s.layoutOptions, activeSlide]
111466
+ );
110658
111467
  const handleApplyTransitionToAll = useCallback(() => {
110659
111468
  const transition = activeSlide?.transition;
110660
111469
  if (!transition) {
@@ -110761,7 +111570,7 @@ function ViewerToolbarSection(props) {
110761
111570
  onUpdateTextStyle: ops.updateSelectedTextStyle,
110762
111571
  isOverflowMenuOpen: s.isOverflowMenuOpen,
110763
111572
  onSetOverflowMenuOpen: s.setIsOverflowMenuOpen,
110764
- layoutOptions: s.layoutOptions,
111573
+ layoutOptions: scopedLayoutOptions,
110765
111574
  onInsertSlideFromLayout: slideOps.handleInsertSlideFromLayout,
110766
111575
  customShows: s.customShows,
110767
111576
  activeCustomShowId: s.activeCustomShowId,
@@ -110794,6 +111603,7 @@ function ViewerToolbarSection(props) {
110794
111603
  isCommentsPanelOpen: s.isInspectorPaneOpen,
110795
111604
  slideCommentCount: activeSlide?.comments?.length ?? 0,
110796
111605
  formatPainterActive: s.formatPainterActive,
111606
+ canActivateFormatPainter: hasCopyableFormat(selectedElement),
110797
111607
  onToggleFormatPainter: onToggleFormatPainterProp ?? (() => s.setFormatPainterActive((p3) => !p3)),
110798
111608
  isSelectionPaneOpen: s.isSelectionPaneOpen,
110799
111609
  onToggleSelectionPane: () => s.setIsSelectionPaneOpen((p3) => !p3),
@@ -113942,6 +114752,166 @@ function ViewerMainContent(props) {
113942
114752
  )
113943
114753
  ] });
113944
114754
  }
114755
+ function MobileBottomBar({
114756
+ onOpenSlides,
114757
+ onOpenInsert,
114758
+ onOpenInspector,
114759
+ onOpenComments,
114760
+ onToggleNotes,
114761
+ activeSheet,
114762
+ commentCount
114763
+ }) {
114764
+ const actions = [
114765
+ {
114766
+ key: "slides",
114767
+ label: "Slides",
114768
+ icon: LuLayers,
114769
+ onClick: onOpenSlides
114770
+ },
114771
+ {
114772
+ key: "insert",
114773
+ label: "Insert",
114774
+ icon: LuPlus,
114775
+ onClick: onOpenInsert
114776
+ },
114777
+ {
114778
+ key: "inspector",
114779
+ label: "Format",
114780
+ icon: LuSettings2,
114781
+ onClick: onOpenInspector
114782
+ },
114783
+ {
114784
+ key: "comments",
114785
+ label: "Comments",
114786
+ icon: LuMessageSquare,
114787
+ onClick: onOpenComments,
114788
+ badge: commentCount
114789
+ },
114790
+ {
114791
+ key: "notes",
114792
+ label: "Notes",
114793
+ icon: LuStickyNote,
114794
+ onClick: onToggleNotes
114795
+ }
114796
+ ];
114797
+ return /* @__PURE__ */ jsx(
114798
+ "nav",
114799
+ {
114800
+ "aria-label": "Editor actions",
114801
+ 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)]",
114802
+ children: actions.map(({ key, label, icon: Icon, onClick, badge }) => {
114803
+ const active = activeSheet === key;
114804
+ return /* @__PURE__ */ jsxs(
114805
+ "button",
114806
+ {
114807
+ type: "button",
114808
+ onClick,
114809
+ className: cn(
114810
+ "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",
114811
+ active ? "text-primary" : "text-muted-foreground hover:text-foreground"
114812
+ ),
114813
+ "aria-pressed": active,
114814
+ children: [
114815
+ /* @__PURE__ */ jsx(Icon, { className: "w-5 h-5" }),
114816
+ /* @__PURE__ */ jsx("span", { children: label }),
114817
+ 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 }),
114818
+ active && /* @__PURE__ */ jsx("span", { className: "absolute top-0 left-1/2 -translate-x-1/2 w-8 h-0.5 rounded-full bg-primary" })
114819
+ ]
114820
+ },
114821
+ key
114822
+ );
114823
+ })
114824
+ }
114825
+ );
114826
+ }
114827
+ function MobileSlidesSheet({
114828
+ open,
114829
+ onClose,
114830
+ ...sidebar
114831
+ }) {
114832
+ return /* @__PURE__ */ jsx(MobileSheet, { open, onClose, heightFraction: 0.7, title: "Slides", children: /* @__PURE__ */ jsx("div", { className: "h-full", children: /* @__PURE__ */ jsx(SlidesPaneSidebar, { ...sidebar }) }) });
114833
+ }
114834
+ function MobileChromeOverlay(props) {
114835
+ const {
114836
+ state: s,
114837
+ editorOps,
114838
+ presentation,
114839
+ slides,
114840
+ activeSlideIndex,
114841
+ canvasSize,
114842
+ slideSectionGroups,
114843
+ canEdit,
114844
+ commentCount
114845
+ } = props;
114846
+ const activeSheet = s.isSlidesPaneOpen ? "slides" : s.isInspectorPaneOpen ? s.sidebarPanelMode === "comments" ? "comments" : "inspector" : !s.isSlideNotesCollapsed ? "notes" : null;
114847
+ const closeAllSheets = () => {
114848
+ s.setIsSlidesPaneOpen(false);
114849
+ s.setIsInspectorPaneOpen(false);
114850
+ s.setIsSlideNotesCollapsed(true);
114851
+ };
114852
+ const openSheet = (which) => {
114853
+ closeAllSheets();
114854
+ switch (which) {
114855
+ case "slides":
114856
+ s.setIsSlidesPaneOpen(true);
114857
+ break;
114858
+ case "inspector":
114859
+ s.setSidebarPanelMode("properties");
114860
+ s.setIsInspectorPaneOpen(true);
114861
+ break;
114862
+ case "comments":
114863
+ s.setSidebarPanelMode("comments");
114864
+ s.setIsInspectorPaneOpen(true);
114865
+ break;
114866
+ case "notes":
114867
+ s.setIsSlideNotesCollapsed(false);
114868
+ break;
114869
+ }
114870
+ };
114871
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
114872
+ /* @__PURE__ */ jsx(
114873
+ MobileSlidesSheet,
114874
+ {
114875
+ open: s.isSlidesPaneOpen,
114876
+ onClose: () => s.setIsSlidesPaneOpen(false),
114877
+ slides,
114878
+ activeSlideIndex,
114879
+ canvasSize,
114880
+ sectionGroups: slideSectionGroups,
114881
+ isOpen: true,
114882
+ canEdit,
114883
+ onSelectSlide: (index) => {
114884
+ s.setActiveSlideIndex(index);
114885
+ s.setIsSlidesPaneOpen(false);
114886
+ },
114887
+ onSlideContextMenu: editorOps.slideOps.handleSlideContextMenu,
114888
+ onMoveSlide: editorOps.slideOps.handleMoveSlide,
114889
+ onAddSlide: editorOps.slideOps.handleAddSlide,
114890
+ onCollapse: () => s.setIsSlidesPaneOpen(false),
114891
+ onAddSection: editorOps.sectionOps.addSection,
114892
+ onRenameSection: editorOps.sectionOps.renameSection,
114893
+ onDeleteSection: editorOps.sectionOps.deleteSection,
114894
+ onMoveSectionUp: editorOps.sectionOps.moveSectionUp,
114895
+ onMoveSectionDown: editorOps.sectionOps.moveSectionDown,
114896
+ rehearsalTimings: Object.keys(presentation.recordedTimings).length > 0 ? presentation.recordedTimings : void 0
114897
+ }
114898
+ ),
114899
+ /* @__PURE__ */ jsx(
114900
+ MobileBottomBar,
114901
+ {
114902
+ activeSheet,
114903
+ commentCount,
114904
+ onOpenSlides: () => s.isSlidesPaneOpen ? s.setIsSlidesPaneOpen(false) : openSheet("slides"),
114905
+ onOpenInsert: () => {
114906
+ editorOps.insertHandlers.handleAddTextBox();
114907
+ },
114908
+ onOpenInspector: () => s.isInspectorPaneOpen && s.sidebarPanelMode !== "comments" ? s.setIsInspectorPaneOpen(false) : openSheet("inspector"),
114909
+ onOpenComments: () => s.isInspectorPaneOpen && s.sidebarPanelMode === "comments" ? s.setIsInspectorPaneOpen(false) : openSheet("comments"),
114910
+ onToggleNotes: () => !s.isSlideNotesCollapsed ? s.setIsSlideNotesCollapsed(true) : openSheet("notes")
114911
+ }
114912
+ )
114913
+ ] });
114914
+ }
113945
114915
  function ToggleSwitch({
113946
114916
  label,
113947
114917
  enabled,
@@ -114163,14 +115133,10 @@ function useYjsDocumentSync({
114163
115133
  const lastSyncedRef = useRef("");
114164
115134
  const hasInitializedRef = useRef(false);
114165
115135
  const getDocMap = useCallback(() => {
114166
- if (!doc2 || typeof doc2 !== "object") {
115136
+ if (!doc2) {
114167
115137
  return null;
114168
115138
  }
114169
- const d = doc2;
114170
- if (typeof d.getMap !== "function") {
114171
- return null;
114172
- }
114173
- return d.getMap("slides-data");
115139
+ return doc2.getMap("slides-data");
114174
115140
  }, [doc2]);
114175
115141
  useEffect(() => {
114176
115142
  if (!isConnected || !doc2) {
@@ -114191,10 +115157,9 @@ function useYjsDocumentSync({
114191
115157
  return;
114192
115158
  }
114193
115159
  lastSyncedRef.current = serialized;
114194
- const d = doc2;
114195
- d.transact(() => {
115160
+ doc2.transact(() => {
114196
115161
  const currentCount = map3.get("count");
114197
- if (currentCount && currentCount > slides.length) {
115162
+ if (typeof currentCount === "number" && currentCount > slides.length) {
114198
115163
  for (let i3 = slides.length; i3 < currentCount; i3++) {
114199
115164
  map3.delete(`slide-${i3}`);
114200
115165
  }
@@ -114219,13 +115184,13 @@ function useYjsDocumentSync({
114219
115184
  }
114220
115185
  const handleUpdate = () => {
114221
115186
  const count = map3.get("count");
114222
- if (!count || count === 0) {
115187
+ if (typeof count !== "number" || count === 0) {
114223
115188
  return;
114224
115189
  }
114225
115190
  const remoteSlides = [];
114226
115191
  for (let i3 = 0; i3 < count; i3++) {
114227
115192
  const slideJson = map3.get(`slide-${i3}`);
114228
- if (slideJson) {
115193
+ if (typeof slideJson === "string") {
114229
115194
  try {
114230
115195
  remoteSlides.push(JSON.parse(slideJson));
114231
115196
  } catch {
@@ -114250,7 +115215,7 @@ function useYjsDocumentSync({
114250
115215
  if (!hasInitializedRef.current) {
114251
115216
  hasInitializedRef.current = true;
114252
115217
  const count = map3.get("count");
114253
- if (count && count > 0) {
115218
+ if (typeof count === "number" && count > 0) {
114254
115219
  handleUpdate();
114255
115220
  }
114256
115221
  }
@@ -114811,13 +115776,14 @@ function useCanvasInteractions(input) {
114811
115776
  if (e2.button !== 0) {
114812
115777
  return;
114813
115778
  }
114814
- if (!selectedElementIdSet.has(elementId)) {
115779
+ const wasSelected = selectedElementIdSet.has(elementId);
115780
+ if (!wasSelected) {
114815
115781
  ops.applySelection(elementId);
114816
115782
  justSelectedRef.current = true;
114817
115783
  } else {
114818
115784
  justSelectedRef.current = false;
114819
115785
  }
114820
- const ids = effectiveSelectedIds.length ? effectiveSelectedIds : [elementId];
115786
+ const ids = !wasSelected ? [elementId] : effectiveSelectedIds.length ? effectiveSelectedIds : [elementId];
114821
115787
  const startPositions = {};
114822
115788
  const domEls = /* @__PURE__ */ new Map();
114823
115789
  for (const id2 of ids) {
@@ -116854,8 +117820,14 @@ function useSectionOperations(input) {
116854
117820
  }
116855
117821
 
116856
117822
  // src/viewer/hooks/useSlideManagement.ts
117823
+ function insertSlideFromLayoutUpdater(slides, activeIndex, draft) {
117824
+ const next = [...slides];
117825
+ const insertAt = Math.max(0, Math.min(activeIndex + 1, next.length));
117826
+ next.splice(insertAt, 0, draft);
117827
+ return next;
117828
+ }
116857
117829
  function useSlideManagement(input) {
116858
- const { slides, activeSlideIndex, setActiveSlideIndex, ops, history } = input;
117830
+ const { slides, activeSlideIndex, setActiveSlideIndex, ops, history, handlerRef } = input;
116859
117831
  const handleAddSlide = () => {
116860
117832
  const newSlide = {
116861
117833
  id: `slide-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,
@@ -116954,8 +117926,42 @@ function useSlideManagement(input) {
116954
117926
  });
116955
117927
  history.markDirty();
116956
117928
  };
116957
- const handleInsertSlideFromLayout = (_layoutPath) => {
116958
- handleAddSlide();
117929
+ const handleInsertSlideFromLayout = (layoutPath, layoutName) => {
117930
+ const insertAt = activeSlideIndex + 1;
117931
+ const draft = {
117932
+ id: `slide-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,
117933
+ rId: "",
117934
+ slideNumber: slides.length + 1,
117935
+ elements: [],
117936
+ layoutPath,
117937
+ ...layoutName ? { layoutName } : {}
117938
+ };
117939
+ let inserted = [];
117940
+ ops.updateSlides((prev) => {
117941
+ inserted = insertSlideFromLayoutUpdater(prev, activeSlideIndex, draft);
117942
+ return inserted;
117943
+ });
117944
+ setActiveSlideIndex(insertAt);
117945
+ history.markDirty();
117946
+ const handler = handlerRef?.current;
117947
+ if (handler) {
117948
+ void handler.applyLayoutToSlide(insertAt, layoutPath, inserted).then(
117949
+ (updated) => {
117950
+ ops.updateSlides((prev) => {
117951
+ if (prev[insertAt]?.id !== draft.id) {
117952
+ return prev;
117953
+ }
117954
+ const next = [...prev];
117955
+ next[insertAt] = updated;
117956
+ return next;
117957
+ });
117958
+ return void 0;
117959
+ },
117960
+ () => {
117961
+ return void 0;
117962
+ }
117963
+ );
117964
+ }
116959
117965
  };
116960
117966
  return {
116961
117967
  handleAddSlide,
@@ -117491,7 +118497,8 @@ function useEditorOperations(input) {
117491
118497
  canvasSize,
117492
118498
  dialogs,
117493
118499
  presentation,
117494
- userName
118500
+ userName,
118501
+ handlerRef
117495
118502
  } = input;
117496
118503
  const ops = useElementOperations({
117497
118504
  activeSlide,
@@ -117593,7 +118600,8 @@ function useEditorOperations(input) {
117593
118600
  activeSlideIndex,
117594
118601
  setActiveSlideIndex: state2.setActiveSlideIndex,
117595
118602
  ops,
117596
- history
118603
+ history,
118604
+ handlerRef
117597
118605
  });
117598
118606
  const tableOps = useTableOperations({
117599
118607
  selectedElement,
@@ -117622,21 +118630,34 @@ function useEditorOperations(input) {
117622
118630
  );
117623
118631
  const copiedFormatRef = useRef(null);
117624
118632
  const prevFormatPainterRef = useRef(false);
118633
+ const { formatPainterActive, setFormatPainterActive, elementLookup } = state2;
117625
118634
  useEffect(() => {
117626
- if (state2.formatPainterActive && !prevFormatPainterRef.current && selectedElement) {
118635
+ if (formatPainterActive && !prevFormatPainterRef.current && selectedElement) {
117627
118636
  copiedFormatRef.current = copyFormatFromElement(selectedElement);
117628
- } else if (!state2.formatPainterActive) {
118637
+ } else if (!formatPainterActive) {
117629
118638
  copiedFormatRef.current = null;
117630
118639
  }
117631
- prevFormatPainterRef.current = state2.formatPainterActive;
117632
- }, [state2.formatPainterActive, selectedElement]);
118640
+ prevFormatPainterRef.current = formatPainterActive;
118641
+ }, [formatPainterActive, selectedElement]);
118642
+ useEffect(() => {
118643
+ if (!formatPainterActive) {
118644
+ return;
118645
+ }
118646
+ const onKey = (e2) => {
118647
+ if (e2.key === "Escape") {
118648
+ setFormatPainterActive(false);
118649
+ }
118650
+ };
118651
+ window.addEventListener("keydown", onKey);
118652
+ return () => window.removeEventListener("keydown", onKey);
118653
+ }, [formatPainterActive, setFormatPainterActive]);
117633
118654
  const formatPainterCanvasHandlers = useMemo(
117634
118655
  () => ({
117635
118656
  ...canvasHandlers,
117636
118657
  handleElementClick: (elementId, e2) => {
117637
- if (state2.formatPainterActive && copiedFormatRef.current) {
118658
+ if (formatPainterActive && copiedFormatRef.current) {
117638
118659
  e2.stopPropagation();
117639
- const element2 = state2.elementLookup.get(elementId);
118660
+ const element2 = elementLookup.get(elementId);
117640
118661
  if (element2) {
117641
118662
  const updated = applyFormatToElement(element2, copiedFormatRef.current);
117642
118663
  const updates = {};
@@ -117649,14 +118670,21 @@ function useEditorOperations(input) {
117649
118670
  ops.updateElementById(elementId, updates);
117650
118671
  }
117651
118672
  copiedFormatRef.current = null;
117652
- state2.setFormatPainterActive(false);
118673
+ setFormatPainterActive(false);
117653
118674
  ops.applySelection(elementId);
117654
118675
  return;
117655
118676
  }
117656
118677
  canvasHandlers.handleElementClick(elementId, e2);
118678
+ },
118679
+ handleCanvasMouseDown: (e2) => {
118680
+ if (formatPainterActive) {
118681
+ setFormatPainterActive(false);
118682
+ return;
118683
+ }
118684
+ canvasHandlers.handleCanvasMouseDown(e2);
117657
118685
  }
117658
118686
  }),
117659
- [canvasHandlers, ops, state2]
118687
+ [canvasHandlers, ops, formatPainterActive, setFormatPainterActive, elementLookup]
117660
118688
  );
117661
118689
  return {
117662
118690
  ops: combinedOps,
@@ -119834,21 +120862,35 @@ function useViewerDialogs(input) {
119834
120862
  null
119835
120863
  );
119836
120864
  const [embedFontsEnabled, setEmbedFontsEnabled] = useState(false);
119837
- const [isNarrowViewport, setIsNarrowViewport] = useState(false);
120865
+ const [isNarrowViewport, setIsNarrowViewport] = useState(
120866
+ () => typeof window !== "undefined" ? window.innerWidth < 768 : false
120867
+ );
119838
120868
  useEffect(() => {
119839
- const el = containerRef.current;
119840
- if (!el) {
119841
- return;
119842
- }
119843
- const observer = new ResizeObserver((entries) => {
119844
- const entry = entries[0];
119845
- if (entry) {
119846
- setIsNarrowViewport(entry.contentRect.width < 768);
120869
+ const handleWindow = () => setIsNarrowViewport(window.innerWidth < 768);
120870
+ let observer = null;
120871
+ let raf = 0;
120872
+ const attach2 = () => {
120873
+ const el = containerRef.current;
120874
+ if (!el) {
120875
+ raf = requestAnimationFrame(attach2);
120876
+ return;
119847
120877
  }
119848
- });
119849
- observer.observe(el);
119850
- setIsNarrowViewport(el.clientWidth < 768);
119851
- return () => observer.disconnect();
120878
+ observer = new ResizeObserver((entries) => {
120879
+ const entry = entries[0];
120880
+ if (entry) {
120881
+ setIsNarrowViewport(entry.contentRect.width < 768);
120882
+ }
120883
+ });
120884
+ observer.observe(el);
120885
+ setIsNarrowViewport(el.clientWidth < 768);
120886
+ };
120887
+ attach2();
120888
+ window.addEventListener("resize", handleWindow);
120889
+ return () => {
120890
+ cancelAnimationFrame(raf);
120891
+ observer?.disconnect();
120892
+ window.removeEventListener("resize", handleWindow);
120893
+ };
119852
120894
  }, []);
119853
120895
  useEffect(() => {
119854
120896
  if (isDirty && hasDigitalSignatures && !signatureStripAcknowledgedRef.current) {
@@ -124320,7 +125362,9 @@ function useViewerCoreState(_input) {
124320
125362
  function useViewerUIState() {
124321
125363
  const [isCompactToolbarOpen, setIsCompactToolbarOpen] = useState(false);
124322
125364
  const [toolbarSection, setToolbarSection] = useState("home");
124323
- const [isSlidesPaneOpen, setIsSlidesPaneOpen] = useState(true);
125365
+ const [isSlidesPaneOpen, setIsSlidesPaneOpen] = useState(
125366
+ () => typeof window === "undefined" ? true : window.innerWidth >= 768
125367
+ );
124324
125368
  const [isInspectorPaneOpen, setIsInspectorPaneOpen] = useState(false);
124325
125369
  const [isSlideNotesCollapsed, setIsSlideNotesCollapsed] = useState(true);
124326
125370
  const [isOverflowMenuOpen, setIsOverflowMenuOpen] = useState(false);
@@ -124763,7 +125807,8 @@ var PowerPointViewer = forwardRef(
124763
125807
  canvasSize,
124764
125808
  dialogs,
124765
125809
  presentation,
124766
- userName: authorName ?? collaboration?.userName
125810
+ userName: authorName ?? collaboration?.userName,
125811
+ handlerRef: actionSoundHandlerRef
124767
125812
  });
124768
125813
  const {
124769
125814
  exportHandlers,
@@ -124886,7 +125931,7 @@ var PowerPointViewer = forwardRef(
124886
125931
  {
124887
125932
  activeSlide,
124888
125933
  allSlides: slides,
124889
- isSlideNotesCollapsed: isMobile || state2.isSlideNotesCollapsed,
125934
+ isSlideNotesCollapsed: state2.isSlideNotesCollapsed,
124890
125935
  canEdit,
124891
125936
  slideCount: slides.length,
124892
125937
  activeSlideIndex,
@@ -124903,7 +125948,22 @@ var PowerPointViewer = forwardRef(
124903
125948
  onZoomToFit: zoom.handleZoomToFit,
124904
125949
  mode,
124905
125950
  onSetMode: handleSetMode,
124906
- onToggleSlideSorter: () => state2.setShowSlideSorter((p3) => !p3)
125951
+ onToggleSlideSorter: () => state2.setShowSlideSorter((p3) => !p3),
125952
+ hideStatusBar: isMobile
125953
+ }
125954
+ ),
125955
+ mode !== "present" && isMobile && /* @__PURE__ */ jsx(
125956
+ MobileChromeOverlay,
125957
+ {
125958
+ state: state2,
125959
+ editorOps,
125960
+ presentation,
125961
+ slides,
125962
+ activeSlideIndex,
125963
+ canvasSize,
125964
+ slideSectionGroups,
125965
+ canEdit,
125966
+ commentCount: activeSlide?.comments?.length ?? 0
124907
125967
  }
124908
125968
  ),
124909
125969
  /* @__PURE__ */ jsx(