pptx-react-viewer 4.51.0 → 4.52.0

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 (87) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/dist/{AiChatPanel-EV22O7UO.js → AiChatPanel-7GJQ66GR.js} +19 -19
  3. package/dist/AiChatPanel-7GJQ66GR.js.br +0 -0
  4. package/dist/AiChatPanel-7GJQ66GR.js.gz +0 -0
  5. package/dist/{AiChatPanel-R323KNGN.mjs → AiChatPanel-AI75AT6C.mjs} +1 -1
  6. package/dist/AiChatPanel-AI75AT6C.mjs.br +0 -0
  7. package/dist/AiChatPanel-AI75AT6C.mjs.gz +0 -0
  8. package/dist/{chunk-ACFR4LFQ.mjs → chunk-3KXEJCMG.mjs} +284 -301
  9. package/dist/chunk-3KXEJCMG.mjs.br +0 -0
  10. package/dist/chunk-3KXEJCMG.mjs.gz +0 -0
  11. package/dist/{chunk-Z22RD3E2.js → chunk-3TN5SUQR.js} +4 -1
  12. package/dist/chunk-3TN5SUQR.js.br +0 -0
  13. package/dist/chunk-3TN5SUQR.js.gz +0 -0
  14. package/dist/{chunk-V3XADJ2O.js → chunk-6GAWXARM.js} +480 -497
  15. package/dist/chunk-6GAWXARM.js.br +0 -0
  16. package/dist/chunk-6GAWXARM.js.gz +0 -0
  17. package/dist/{chunk-ETJ752B5.mjs → chunk-E6A6ZBAM.mjs} +49 -69
  18. package/dist/chunk-E6A6ZBAM.mjs.br +0 -0
  19. package/dist/chunk-E6A6ZBAM.mjs.gz +0 -0
  20. package/dist/{chunk-VI5DQRQZ.js → chunk-I63IFSNX.js} +597 -617
  21. package/dist/chunk-I63IFSNX.js.br +0 -0
  22. package/dist/chunk-I63IFSNX.js.gz +0 -0
  23. package/dist/{chunk-ZCGYPCZM.mjs → chunk-ID37Y3HG.mjs} +4 -1
  24. package/dist/chunk-ID37Y3HG.mjs.br +0 -0
  25. package/dist/chunk-ID37Y3HG.mjs.gz +0 -0
  26. package/dist/i18n/de.cjs +1 -24
  27. package/dist/i18n/de.cjs.br +0 -0
  28. package/dist/i18n/de.cjs.gz +0 -0
  29. package/dist/i18n/de.mjs +1 -24
  30. package/dist/i18n/de.mjs.br +0 -0
  31. package/dist/i18n/de.mjs.gz +0 -0
  32. package/dist/i18n/es.cjs +1 -24
  33. package/dist/i18n/es.cjs.br +0 -0
  34. package/dist/i18n/es.cjs.gz +0 -0
  35. package/dist/i18n/es.mjs +1 -24
  36. package/dist/i18n/es.mjs.br +0 -0
  37. package/dist/i18n/es.mjs.gz +0 -0
  38. package/dist/i18n/fr.cjs +1 -24
  39. package/dist/i18n/fr.cjs.br +0 -0
  40. package/dist/i18n/fr.cjs.gz +0 -0
  41. package/dist/i18n/fr.mjs +1 -24
  42. package/dist/i18n/fr.mjs.br +0 -0
  43. package/dist/i18n/fr.mjs.gz +0 -0
  44. package/dist/i18n/zh-CN.cjs +0 -23
  45. package/dist/i18n/zh-CN.cjs.br +0 -0
  46. package/dist/i18n/zh-CN.cjs.gz +0 -0
  47. package/dist/i18n/zh-CN.mjs +0 -23
  48. package/dist/i18n/zh-CN.mjs.br +0 -0
  49. package/dist/i18n/zh-CN.mjs.gz +0 -0
  50. package/dist/index.d.ts +13 -1
  51. package/dist/index.js +25 -25
  52. package/dist/index.js.br +0 -0
  53. package/dist/index.js.gz +0 -0
  54. package/dist/index.mjs +3 -3
  55. package/dist/index.mjs.br +0 -0
  56. package/dist/index.mjs.gz +0 -0
  57. package/dist/internals.d.ts +59 -17
  58. package/dist/internals.js +81 -81
  59. package/dist/internals.js.br +0 -0
  60. package/dist/internals.js.gz +0 -0
  61. package/dist/internals.mjs +2 -2
  62. package/dist/internals.mjs.br +0 -0
  63. package/dist/internals.mjs.gz +0 -0
  64. package/dist/viewer/index.d.ts +13 -1
  65. package/dist/viewer/index.js +20 -20
  66. package/dist/viewer/index.js.br +0 -0
  67. package/dist/viewer/index.js.gz +0 -0
  68. package/dist/viewer/index.mjs +3 -3
  69. package/dist/viewer/index.mjs.br +0 -0
  70. package/dist/viewer/index.mjs.gz +0 -0
  71. package/package.json +3 -3
  72. package/dist/AiChatPanel-EV22O7UO.js.br +0 -0
  73. package/dist/AiChatPanel-EV22O7UO.js.gz +0 -0
  74. package/dist/AiChatPanel-R323KNGN.mjs.br +0 -0
  75. package/dist/AiChatPanel-R323KNGN.mjs.gz +0 -0
  76. package/dist/chunk-ACFR4LFQ.mjs.br +0 -0
  77. package/dist/chunk-ACFR4LFQ.mjs.gz +0 -0
  78. package/dist/chunk-ETJ752B5.mjs.br +0 -0
  79. package/dist/chunk-ETJ752B5.mjs.gz +0 -0
  80. package/dist/chunk-V3XADJ2O.js.br +0 -0
  81. package/dist/chunk-V3XADJ2O.js.gz +0 -0
  82. package/dist/chunk-VI5DQRQZ.js.br +0 -0
  83. package/dist/chunk-VI5DQRQZ.js.gz +0 -0
  84. package/dist/chunk-Z22RD3E2.js.br +0 -0
  85. package/dist/chunk-Z22RD3E2.js.gz +0 -0
  86. package/dist/chunk-ZCGYPCZM.mjs.br +0 -0
  87. package/dist/chunk-ZCGYPCZM.mjs.gz +0 -0
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkZ22RD3E2_js = require('./chunk-Z22RD3E2.js');
3
+ var chunk3TN5SUQR_js = require('./chunk-3TN5SUQR.js');
4
4
  var pptx = require('ooxml-ui/pptx');
5
5
  var React17 = require('react');
6
6
  var jsxRuntime = require('react/jsx-runtime');
@@ -577,14 +577,35 @@ function serializeHistoryDocument(snapshot) {
577
577
  slideId,
578
578
  elements.map(historyElementContent)
579
579
  ])
580
- )
580
+ ),
581
+ // A theme pick that changes nothing on the slides is still an edit, and an undo step.
582
+ theme: snapshot.theme
581
583
  });
582
584
  }
585
+ function withMasterPathsIn(snapshot, paths) {
586
+ const { theme, ...rest } = snapshot;
587
+ if (!theme?.masterThemePaths) {
588
+ return snapshot;
589
+ }
590
+ const { masterThemePaths, ...parts } = theme;
591
+ const kept = Object.entries(masterThemePaths).filter(([path]) => paths.has(path));
592
+ const next = kept.length > 0 ? { ...parts, masterThemePaths: Object.fromEntries(kept) } : parts;
593
+ return Object.keys(next).length > 0 ? { ...rest, theme: next } : rest;
594
+ }
595
+ function differsOnlyInMasterSet(previous, next) {
596
+ const before = Object.keys(previous.theme?.masterThemePaths ?? {});
597
+ const after = new Set(Object.keys(next.theme?.masterThemePaths ?? {}));
598
+ if (before.length === after.size && before.every((path) => after.has(path))) {
599
+ return false;
600
+ }
601
+ const shared = new Set(before.filter((path) => after.has(path)));
602
+ return serializeHistoryDocument(withMasterPathsIn(previous, shared)) === serializeHistoryDocument(withMasterPathsIn(next, shared));
603
+ }
583
604
  function recordExplicitSlideUpdate(history, previous, before, label) {
584
605
  if (previous && serializeHistoryDocument(previous) !== serializeHistoryDocument(before)) {
585
- history.record(chunkZ22RD3E2_js.cloneHistorySnapshot(previous), previous.actionLabel);
606
+ history.record(chunk3TN5SUQR_js.cloneHistorySnapshot(previous), previous.actionLabel);
586
607
  }
587
- history.record({ ...chunkZ22RD3E2_js.cloneHistorySnapshot(before), actionLabel: label }, label);
608
+ history.record({ ...chunk3TN5SUQR_js.cloneHistorySnapshot(before), actionLabel: label }, label);
588
609
  }
589
610
  var POLL_INTERVAL_MS = 16;
590
611
  function usePointerReleaseWakeup(hasActivePointerInteraction) {
@@ -632,6 +653,9 @@ function useEditorHistory(input) {
632
653
  hasActivePointerInteraction,
633
654
  pointerCommitNonce,
634
655
  onDirty,
656
+ theme,
657
+ slideMasters,
658
+ onRestoreTheme,
635
659
  setSlides,
636
660
  setCanvasSize,
637
661
  setActiveSlideIndex,
@@ -658,16 +682,18 @@ function useEditorHistory(input) {
658
682
  }, [history, maxHistoryEntries]);
659
683
  const buildHistorySnapshot = React17.useCallback(
660
684
  (actionLabel) => {
685
+ const recordedTheme = pptx.historyTheme(theme, slideMasters);
661
686
  return {
662
687
  width: canvasSize.width,
663
688
  height: canvasSize.height,
664
689
  activeSlideIndex,
665
- slides: slides.map(chunkZ22RD3E2_js.cloneSlide),
666
- templateElementsBySlideId: chunkZ22RD3E2_js.cloneTemplateElementsBySlideId(templateElementsBySlideId),
690
+ slides: slides.map(chunk3TN5SUQR_js.cloneSlide),
691
+ templateElementsBySlideId: chunk3TN5SUQR_js.cloneTemplateElementsBySlideId(templateElementsBySlideId),
692
+ ...recordedTheme ? { theme: recordedTheme } : {},
667
693
  ...actionLabel ? { actionLabel } : {}
668
694
  };
669
695
  },
670
- [activeSlideIndex, canvasSize, slides, templateElementsBySlideId]
696
+ [activeSlideIndex, canvasSize, slideMasters, slides, templateElementsBySlideId, theme]
671
697
  );
672
698
  const applyHistorySnapshot = React17.useCallback(
673
699
  (snapshot) => {
@@ -676,9 +702,9 @@ function useEditorHistory(input) {
676
702
  width: snapshot.width,
677
703
  height: snapshot.height
678
704
  });
679
- setSlides(snapshot.slides.map(chunkZ22RD3E2_js.cloneSlide));
705
+ setSlides(snapshot.slides.map(chunk3TN5SUQR_js.cloneSlide));
680
706
  setTemplateElementsBySlideId(
681
- chunkZ22RD3E2_js.cloneTemplateElementsBySlideId(snapshot.templateElementsBySlideId)
707
+ chunk3TN5SUQR_js.cloneTemplateElementsBySlideId(snapshot.templateElementsBySlideId)
682
708
  );
683
709
  setActiveSlideIndex(Math.min(snapshot.activeSlideIndex, maxSlideIndex));
684
710
  setSelectedElementIds([]);
@@ -709,43 +735,74 @@ function useEditorHistory(input) {
709
735
  setEditCommitNonce((previous) => previous + 1);
710
736
  onDirtyRef.current?.();
711
737
  }, []);
738
+ const onRestoreThemeRef = React17.useRef(onRestoreTheme);
739
+ React17.useEffect(() => {
740
+ onRestoreThemeRef.current = onRestoreTheme;
741
+ }, [onRestoreTheme]);
742
+ const restoreTheme = React17.useCallback(
743
+ (current, target) => {
744
+ const crossed = pptx.crossedHistoryTheme(current.theme, target.theme);
745
+ if (crossed) {
746
+ onRestoreThemeRef.current?.(crossed);
747
+ }
748
+ },
749
+ []
750
+ );
712
751
  const handleUndo = React17.useCallback(() => {
713
752
  if (!history.getSnapshot().canUndo) {
714
753
  return;
715
754
  }
716
- const result = history.undo(buildHistorySnapshot());
755
+ const currentSnapshot = buildHistorySnapshot();
756
+ const result = history.undo(currentSnapshot);
717
757
  if (!result) {
718
758
  return;
719
759
  }
720
760
  isApplyingHistoryRef.current = true;
721
- const nextSnapshot = chunkZ22RD3E2_js.cloneHistorySnapshot(result.snapshot);
722
- lastHistorySnapshotRef.current = chunkZ22RD3E2_js.cloneHistorySnapshot(nextSnapshot);
761
+ const nextSnapshot = chunk3TN5SUQR_js.cloneHistorySnapshot(result.snapshot);
762
+ lastHistorySnapshotRef.current = chunk3TN5SUQR_js.cloneHistorySnapshot(nextSnapshot);
723
763
  lastHistorySerializedRef.current = serializeHistoryDocument(nextSnapshot);
724
764
  applyHistorySnapshot(nextSnapshot);
765
+ restoreTheme(currentSnapshot, nextSnapshot);
725
766
  unlockHistoryTracking();
726
767
  markDirty();
727
- }, [applyHistorySnapshot, buildHistorySnapshot, history, markDirty, unlockHistoryTracking]);
768
+ }, [
769
+ applyHistorySnapshot,
770
+ buildHistorySnapshot,
771
+ history,
772
+ markDirty,
773
+ restoreTheme,
774
+ unlockHistoryTracking
775
+ ]);
728
776
  const handleRedo = React17.useCallback(() => {
729
777
  if (!history.getSnapshot().canRedo) {
730
778
  return;
731
779
  }
732
- const result = history.redo(buildHistorySnapshot());
780
+ const currentSnapshot = buildHistorySnapshot();
781
+ const result = history.redo(currentSnapshot);
733
782
  if (!result) {
734
783
  return;
735
784
  }
736
785
  isApplyingHistoryRef.current = true;
737
- const targetSnapshot = chunkZ22RD3E2_js.cloneHistorySnapshot(result.snapshot);
738
- lastHistorySnapshotRef.current = chunkZ22RD3E2_js.cloneHistorySnapshot(targetSnapshot);
786
+ const targetSnapshot = chunk3TN5SUQR_js.cloneHistorySnapshot(result.snapshot);
787
+ lastHistorySnapshotRef.current = chunk3TN5SUQR_js.cloneHistorySnapshot(targetSnapshot);
739
788
  lastHistorySerializedRef.current = serializeHistoryDocument(targetSnapshot);
740
789
  applyHistorySnapshot(targetSnapshot);
790
+ restoreTheme(currentSnapshot, targetSnapshot);
741
791
  unlockHistoryTracking();
742
792
  markDirty();
743
- }, [applyHistorySnapshot, buildHistorySnapshot, history, markDirty, unlockHistoryTracking]);
793
+ }, [
794
+ applyHistorySnapshot,
795
+ buildHistorySnapshot,
796
+ history,
797
+ markDirty,
798
+ restoreTheme,
799
+ unlockHistoryTracking
800
+ ]);
744
801
  const resetHistory = React17.useCallback(
745
802
  (initialSnapshot) => {
746
803
  history.clear();
747
804
  if (initialSnapshot) {
748
- const clonedInitial = chunkZ22RD3E2_js.cloneHistorySnapshot(initialSnapshot);
805
+ const clonedInitial = chunk3TN5SUQR_js.cloneHistorySnapshot(initialSnapshot);
749
806
  lastHistorySnapshotRef.current = clonedInitial;
750
807
  lastHistorySerializedRef.current = serializeHistoryDocument(clonedInitial);
751
808
  } else {
@@ -792,7 +849,7 @@ function useEditorHistory(input) {
792
849
  return;
793
850
  }
794
851
  const previousSnapshot = lastHistorySnapshotRef.current;
795
- if (!previousSnapshot) {
852
+ if (!previousSnapshot || differsOnlyInMasterSet(previousSnapshot, snapshot)) {
796
853
  lastHistorySnapshotRef.current = snapshot;
797
854
  lastHistorySerializedRef.current = serialized;
798
855
  lastCheapHashRef.current = cheapHash;
@@ -818,11 +875,17 @@ function useEditorHistory(input) {
818
875
  pointerReleaseNonce,
819
876
  slides
820
877
  ]);
821
- const commitSlides = (nextSlides, label, beforeSlides = slides) => {
822
- const before = { ...buildHistorySnapshot(), slides: beforeSlides.map(chunkZ22RD3E2_js.cloneSlide) };
823
- const after = { ...before, slides: nextSlides.map(chunkZ22RD3E2_js.cloneSlide) };
878
+ const commitSlides = (nextSlides, label, beforeSlides = slides, nextSlideMasters) => {
879
+ const before = { ...buildHistorySnapshot(), slides: beforeSlides.map(chunk3TN5SUQR_js.cloneSlide) };
880
+ const { theme: beforeTheme, ...unthemed } = before;
881
+ const afterTheme = nextSlideMasters ? pptx.historyTheme(theme, nextSlideMasters) : beforeTheme;
882
+ const after = {
883
+ ...unthemed,
884
+ slides: nextSlides.map(chunk3TN5SUQR_js.cloneSlide),
885
+ ...afterTheme ? { theme: afterTheme } : {}
886
+ };
824
887
  recordExplicitSlideUpdate(history, lastHistorySnapshotRef.current, before, label);
825
- lastHistorySnapshotRef.current = chunkZ22RD3E2_js.cloneHistorySnapshot(after);
888
+ lastHistorySnapshotRef.current = chunk3TN5SUQR_js.cloneHistorySnapshot(after);
826
889
  lastHistorySerializedRef.current = serializeHistoryDocument(after);
827
890
  isApplyingHistoryRef.current = false;
828
891
  setSlides(nextSlides);
@@ -841,6 +904,7 @@ function useEditorHistory(input) {
841
904
  handleUndo,
842
905
  handleRedo,
843
906
  resetHistory,
907
+ forgetHistory: history.forget,
844
908
  markDirty,
845
909
  buildHistorySnapshot
846
910
  };
@@ -1007,22 +1071,22 @@ function useZoomViewport({
1007
1071
  selectedElements.forEach((element) => {
1008
1072
  minX = Math.min(minX, element.x);
1009
1073
  minY = Math.min(minY, element.y);
1010
- maxX = Math.max(maxX, element.x + Math.max(element.width, chunkZ22RD3E2_js.MIN_ELEMENT_SIZE));
1011
- maxY = Math.max(maxY, element.y + Math.max(element.height, chunkZ22RD3E2_js.MIN_ELEMENT_SIZE));
1074
+ maxX = Math.max(maxX, element.x + Math.max(element.width, chunk3TN5SUQR_js.MIN_ELEMENT_SIZE));
1075
+ maxY = Math.max(maxY, element.y + Math.max(element.height, chunk3TN5SUQR_js.MIN_ELEMENT_SIZE));
1012
1076
  });
1013
1077
  if (!Number.isFinite(minX) || !Number.isFinite(minY) || !Number.isFinite(maxX) || !Number.isFinite(maxY)) {
1014
1078
  return;
1015
1079
  }
1016
1080
  const selectionBounds = { minX, minY, maxX, maxY };
1017
- const boundsWidth = Math.max(selectionBounds.maxX - selectionBounds.minX, chunkZ22RD3E2_js.MIN_ELEMENT_SIZE);
1018
- const boundsHeight = Math.max(selectionBounds.maxY - selectionBounds.minY, chunkZ22RD3E2_js.MIN_ELEMENT_SIZE);
1081
+ const boundsWidth = Math.max(selectionBounds.maxX - selectionBounds.minX, chunk3TN5SUQR_js.MIN_ELEMENT_SIZE);
1082
+ const boundsHeight = Math.max(selectionBounds.maxY - selectionBounds.minY, chunk3TN5SUQR_js.MIN_ELEMENT_SIZE);
1019
1083
  const availableWidth = Math.max(
1020
- effectiveEditorDimensions.width - chunkZ22RD3E2_js.ZOOM_TO_SELECTION_PADDING,
1021
- chunkZ22RD3E2_js.MIN_ELEMENT_SIZE
1084
+ effectiveEditorDimensions.width - chunk3TN5SUQR_js.ZOOM_TO_SELECTION_PADDING,
1085
+ chunk3TN5SUQR_js.MIN_ELEMENT_SIZE
1022
1086
  );
1023
1087
  const availableHeight = Math.max(
1024
- effectiveEditorDimensions.height - chunkZ22RD3E2_js.ZOOM_TO_SELECTION_PADDING,
1025
- chunkZ22RD3E2_js.MIN_ELEMENT_SIZE
1088
+ effectiveEditorDimensions.height - chunk3TN5SUQR_js.ZOOM_TO_SELECTION_PADDING,
1089
+ chunk3TN5SUQR_js.MIN_ELEMENT_SIZE
1026
1090
  );
1027
1091
  const targetEditorScale = Math.min(
1028
1092
  availableWidth / boundsWidth,
@@ -3974,8 +4038,8 @@ function useViewerCoreState(_input) {
3974
4038
  const { slides, setSlides, slidesRef } = useSlideState();
3975
4039
  const [templateElementsBySlideId, setTemplateElementsBySlideId] = React17.useState({});
3976
4040
  const [canvasSize, setCanvasSize] = React17.useState({
3977
- width: chunkZ22RD3E2_js.DEFAULT_CANVAS_WIDTH,
3978
- height: chunkZ22RD3E2_js.DEFAULT_CANVAS_HEIGHT
4041
+ width: chunk3TN5SUQR_js.DEFAULT_CANVAS_WIDTH,
4042
+ height: chunk3TN5SUQR_js.DEFAULT_CANVAS_HEIGHT
3979
4043
  });
3980
4044
  const [slideSizeEmu, setSlideSizeEmu] = React17.useState();
3981
4045
  const [activeSlideIndex, setActiveSlideIndex] = React17.useState(0);
@@ -4451,12 +4515,12 @@ function useLoadContent({
4451
4515
  }
4452
4516
  resources.commit();
4453
4517
  handlerRef.current = handler;
4454
- const partition = chunkZ22RD3E2_js.partitionTemplateElements(nextSlides);
4518
+ const partition = chunk3TN5SUQR_js.partitionTemplateElements(nextSlides);
4455
4519
  setSlides(partition.slides);
4456
4520
  setTemplateElementsBySlideId(partition.templateElementsBySlideId);
4457
4521
  setCanvasSize({
4458
- width: parsed.width ?? chunkZ22RD3E2_js.DEFAULT_CANVAS_WIDTH,
4459
- height: parsed.height ?? chunkZ22RD3E2_js.DEFAULT_CANVAS_HEIGHT
4522
+ width: parsed.width ?? chunk3TN5SUQR_js.DEFAULT_CANVAS_WIDTH,
4523
+ height: parsed.height ?? chunk3TN5SUQR_js.DEFAULT_CANVAS_HEIGHT
4460
4524
  });
4461
4525
  setSlideSizeEmu(
4462
4526
  typeof parsed.widthEmu === "number" && typeof parsed.heightEmu === "number" && parsed.widthEmu > 0 && parsed.heightEmu > 0 ? {
@@ -4862,7 +4926,7 @@ function useElementOperations(input) {
4862
4926
  );
4863
4927
  return;
4864
4928
  }
4865
- if (chunkZ22RD3E2_js.isTemplateElementId(elementId)) {
4929
+ if (chunk3TN5SUQR_js.isTemplateElementId(elementId)) {
4866
4930
  const slideId = activeSlide?.id;
4867
4931
  if (slideId) {
4868
4932
  setTemplateElementsBySlideId((prev) => ({
@@ -5148,8 +5212,8 @@ function createCanvasGestures(getInput, frames = animationFrames) {
5148
5212
  }
5149
5213
  function paintResize(resize, transform) {
5150
5214
  const { x, y } = transform;
5151
- const width = Math.max(transform.width, chunkZ22RD3E2_js.MIN_ELEMENT_SIZE);
5152
- const height = Math.max(transform.height, chunkZ22RD3E2_js.MIN_ELEMENT_SIZE);
5215
+ const width = Math.max(transform.width, chunk3TN5SUQR_js.MIN_ELEMENT_SIZE);
5216
+ const height = Math.max(transform.height, chunk3TN5SUQR_js.MIN_ELEMENT_SIZE);
5153
5217
  resize.lastX = x;
5154
5218
  resize.lastY = y;
5155
5219
  resize.lastWidth = transform.width;
@@ -5206,7 +5270,7 @@ function createCanvasGestures(getInput, frames = animationFrames) {
5206
5270
  getGridSize: () => getInput().gridSpacingPx,
5207
5271
  getSnapToShape: () => getInput().snapToShape,
5208
5272
  getGuides: () => getInput().guides.map(({ axis, position }) => ({ axis, position })),
5209
- getMinSize: () => chunkZ22RD3E2_js.MIN_ELEMENT_SIZE,
5273
+ getMinSize: () => chunk3TN5SUQR_js.MIN_ELEMENT_SIZE,
5210
5274
  getSnapExcludeIds: () => armed?.kind === "move" ? Object.keys(armed.drag.startPositionsById) : [],
5211
5275
  getStageOrigin: () => {
5212
5276
  const rect = getInput().canvasStageRef.current?.getBoundingClientRect();
@@ -5287,7 +5351,7 @@ function commitMove(input, drag) {
5287
5351
  const start = drag.startPositionsById[el.id];
5288
5352
  return start ? { ...el, x: start.x + dx, y: start.y + dy } : el;
5289
5353
  });
5290
- return chunkZ22RD3E2_js.applyReroutedConnectors(moved, chunkZ22RD3E2_js.rerouteConnectorsForMovedElements(moved, movedIds));
5354
+ return chunk3TN5SUQR_js.applyReroutedConnectors(moved, chunk3TN5SUQR_js.rerouteConnectorsForMovedElements(moved, movedIds));
5291
5355
  };
5292
5356
  if (input.editTemplateMode) {
5293
5357
  const slideId = input.activeSlide?.id;
@@ -5318,8 +5382,8 @@ function commitResize(input, resize) {
5318
5382
  if (i !== input.activeSlideIndex) {
5319
5383
  return s;
5320
5384
  }
5321
- const rerouted = chunkZ22RD3E2_js.rerouteConnectorsForMovedElements(s.elements, movedIds);
5322
- return rerouted.length === 0 ? s : { ...s, elements: chunkZ22RD3E2_js.applyReroutedConnectors(s.elements, rerouted) };
5385
+ const rerouted = chunk3TN5SUQR_js.rerouteConnectorsForMovedElements(s.elements, movedIds);
5386
+ return rerouted.length === 0 ? s : { ...s, elements: chunk3TN5SUQR_js.applyReroutedConnectors(s.elements, rerouted) };
5323
5387
  })
5324
5388
  );
5325
5389
  }
@@ -6154,7 +6218,7 @@ function createStructuredElementHandlers(deps) {
6154
6218
  return;
6155
6219
  }
6156
6220
  const resolved = resolveHyperlinkEditResult(data);
6157
- if (resolved.url && !chunkZ22RD3E2_js.isUrlSafe(resolved.url)) {
6221
+ if (resolved.url && !chunk3TN5SUQR_js.isUrlSafe(resolved.url)) {
6158
6222
  return;
6159
6223
  }
6160
6224
  const actionClick = {
@@ -6200,7 +6264,7 @@ function createStructuredElementHandlers(deps) {
6200
6264
  if (!activeSlide) {
6201
6265
  return;
6202
6266
  }
6203
- const preset = chunkZ22RD3E2_js.ACTION_BUTTON_PRESETS.find((p) => p.shapeType === shapeType);
6267
+ const preset = chunk3TN5SUQR_js.ACTION_BUTTON_PRESETS.find((p) => p.shapeType === shapeType);
6204
6268
  if (!preset) {
6205
6269
  return;
6206
6270
  }
@@ -6287,7 +6351,7 @@ function useInsertElements(input) {
6287
6351
  width: 300,
6288
6352
  height: 60,
6289
6353
  text: "",
6290
- textStyle: { fontSize: chunkZ22RD3E2_js.DEFAULT_TEXT_FONT_SIZE }
6354
+ textStyle: { fontSize: chunk3TN5SUQR_js.DEFAULT_TEXT_FONT_SIZE }
6291
6355
  });
6292
6356
  };
6293
6357
  const handleAddShape = () => {
@@ -6309,7 +6373,7 @@ function useInsertElements(input) {
6309
6373
  }
6310
6374
  });
6311
6375
  };
6312
- const handleAddTable = (rows = chunkZ22RD3E2_js.DEFAULT_TABLE_ROWS, columns = chunkZ22RD3E2_js.DEFAULT_TABLE_COLUMNS) => {
6376
+ const handleAddTable = (rows = chunk3TN5SUQR_js.DEFAULT_TABLE_ROWS, columns = chunk3TN5SUQR_js.DEFAULT_TABLE_COLUMNS) => {
6313
6377
  if (!activeSlide) {
6314
6378
  return;
6315
6379
  }
@@ -6483,7 +6547,7 @@ function useGroupAlignLayerHandlers(input) {
6483
6547
  history
6484
6548
  } = input;
6485
6549
  const updateElementsOwning = (elementId, updater) => {
6486
- if (editTemplateMode && !chunkZ22RD3E2_js.isTemplateElementId(elementId)) {
6550
+ if (editTemplateMode && !chunk3TN5SUQR_js.isTemplateElementId(elementId)) {
6487
6551
  ops.updateSlides(
6488
6552
  (prev) => prev.map(
6489
6553
  (slide, index) => index === activeSlideIndex ? { ...slide, elements: updater(slide.elements) } : slide
@@ -6517,9 +6581,9 @@ function useGroupAlignLayerHandlers(input) {
6517
6581
  return;
6518
6582
  }
6519
6583
  const group = selectedElement;
6520
- const intoTemplate = chunkZ22RD3E2_js.isTemplateElementId(group.id);
6584
+ const intoTemplate = chunk3TN5SUQR_js.isTemplateElementId(group.id);
6521
6585
  const childIds = group.children.map(
6522
- (child) => intoTemplate ? chunkZ22RD3E2_js.makeCloneId(true, child.id || group.id) : child.id || pptx.generateElementId()
6586
+ (child) => intoTemplate ? chunk3TN5SUQR_js.makeCloneId(true, child.id || group.id) : child.id || pptx.generateElementId()
6523
6587
  );
6524
6588
  const { elements, childIds: usedIds } = pptx.ungroupElements(
6525
6589
  ops.activeElements,
@@ -6891,7 +6955,7 @@ function useSlideManagement(input) {
6891
6955
  async (updated) => {
6892
6956
  const templateElements = await handler.getTemplateElementsForSlide(updated.id).catch(() => []);
6893
6957
  ops.updateSlides((prev) => {
6894
- if (prev[insertAt]?.id !== draft.id) {
6958
+ if (pptx.insertedLayoutCompletion(prev[insertAt], draft) !== "replace") {
6895
6959
  return prev;
6896
6960
  }
6897
6961
  const next = [...prev];
@@ -6955,7 +7019,7 @@ function createTableMergeHandlers(input) {
6955
7019
  if (!nextCell || nextCell.hMerge || nextCell.vMerge) {
6956
7020
  return;
6957
7021
  }
6958
- const newTableData = chunkZ22RD3E2_js.mergeCells(
7022
+ const newTableData = chunk3TN5SUQR_js.mergeCells(
6959
7023
  [
6960
7024
  { row: rowIndex, col: columnIndex },
6961
7025
  { row: rowIndex, col: nextColIdx }
@@ -6963,7 +7027,7 @@ function createTableMergeHandlers(input) {
6963
7027
  td
6964
7028
  );
6965
7029
  const updates = { tableData: newTableData };
6966
- const newRawXml = chunkZ22RD3E2_js.updateMergeAttrsInRawXml(selectedElement, newTableData);
7030
+ const newRawXml = chunk3TN5SUQR_js.updateMergeAttrsInRawXml(selectedElement, newTableData);
6967
7031
  if (newRawXml) {
6968
7032
  updates.rawXml = newRawXml;
6969
7033
  }
@@ -6989,7 +7053,7 @@ function createTableMergeHandlers(input) {
6989
7053
  if (!targetNextCell || targetNextCell.hMerge || targetNextCell.vMerge) {
6990
7054
  return;
6991
7055
  }
6992
- const newTableData = chunkZ22RD3E2_js.mergeCells(
7056
+ const newTableData = chunk3TN5SUQR_js.mergeCells(
6993
7057
  [
6994
7058
  { row: rowIndex, col: columnIndex },
6995
7059
  { row: targetNextRowIdx, col: columnIndex }
@@ -6997,7 +7061,7 @@ function createTableMergeHandlers(input) {
6997
7061
  td
6998
7062
  );
6999
7063
  const updates = { tableData: newTableData };
7000
- const newRawXml = chunkZ22RD3E2_js.updateMergeAttrsInRawXml(selectedElement, newTableData);
7064
+ const newRawXml = chunk3TN5SUQR_js.updateMergeAttrsInRawXml(selectedElement, newTableData);
7001
7065
  if (newRawXml) {
7002
7066
  updates.rawXml = newRawXml;
7003
7067
  }
@@ -7012,9 +7076,9 @@ function createTableMergeHandlers(input) {
7012
7076
  return;
7013
7077
  }
7014
7078
  const td = selectedElement.tableData;
7015
- const newTableData = chunkZ22RD3E2_js.mergeCells(ts.selectedCells, td);
7079
+ const newTableData = chunk3TN5SUQR_js.mergeCells(ts.selectedCells, td);
7016
7080
  const updates = { tableData: newTableData };
7017
- const newRawXml = chunkZ22RD3E2_js.updateMergeAttrsInRawXml(selectedElement, newTableData);
7081
+ const newRawXml = chunk3TN5SUQR_js.updateMergeAttrsInRawXml(selectedElement, newTableData);
7018
7082
  if (newRawXml) {
7019
7083
  updates.rawXml = newRawXml;
7020
7084
  }
@@ -7031,9 +7095,9 @@ function createTableMergeHandlers(input) {
7031
7095
  }
7032
7096
  const { rowIndex, columnIndex } = ts;
7033
7097
  const td = selectedElement.tableData;
7034
- const newTableData = chunkZ22RD3E2_js.splitCell(rowIndex, columnIndex, td);
7098
+ const newTableData = chunk3TN5SUQR_js.splitCell(rowIndex, columnIndex, td);
7035
7099
  const updates = { tableData: newTableData };
7036
- const newRawXml = chunkZ22RD3E2_js.updateMergeAttrsInRawXml(selectedElement, newTableData);
7100
+ const newRawXml = chunk3TN5SUQR_js.updateMergeAttrsInRawXml(selectedElement, newTableData);
7037
7101
  if (newRawXml) {
7038
7102
  updates.rawXml = newRawXml;
7039
7103
  }
@@ -7068,7 +7132,7 @@ function createTableStructHandlers(input) {
7068
7132
  updates.tableData = pptx.setCellText(el, rowIndex, colIndex, text).tableData;
7069
7133
  }
7070
7134
  if (el.rawXml) {
7071
- const newRawXml = chunkZ22RD3E2_js.updateCellTextInRawXml(el, rowIndex, colIndex, text);
7135
+ const newRawXml = chunk3TN5SUQR_js.updateCellTextInRawXml(el, rowIndex, colIndex, text);
7072
7136
  if (newRawXml) {
7073
7137
  updates.rawXml = newRawXml;
7074
7138
  }
@@ -7092,7 +7156,7 @@ function createTableStructHandlers(input) {
7092
7156
  const { rowIndex, columnIndex: colIndex } = ts;
7093
7157
  const updates = {};
7094
7158
  if (selectedElement.rawXml) {
7095
- const newRawXml = chunkZ22RD3E2_js.updateCellTextStyleInRawXml(
7159
+ const newRawXml = chunk3TN5SUQR_js.updateCellTextStyleInRawXml(
7096
7160
  selectedElement,
7097
7161
  rowIndex,
7098
7162
  colIndex,
@@ -7270,7 +7334,7 @@ function useExportSaveAs(input) {
7270
7334
  const sourceName = filePath ? filePath.replace(/\\/gu, "/").split("/").pop() : void 0;
7271
7335
  const slideSize = pptx.resolveSlideSizeSelection({ current: slideSizeEmu, canvas: canvasSize }).size;
7272
7336
  const data = {
7273
- slides: chunkZ22RD3E2_js.buildSaveSlides(slides, templateElementsBySlideId),
7337
+ slides: chunk3TN5SUQR_js.buildSaveSlides(slides, templateElementsBySlideId),
7274
7338
  width: canvasSize.width,
7275
7339
  height: canvasSize.height,
7276
7340
  widthEmu: slideSize.widthEmu,
@@ -7411,28 +7475,29 @@ async function copySlideToClipboard(slideElement, options = {}) {
7411
7475
  const blob = await exportSlideToPngBlob(slideElement, options);
7412
7476
  await navigator.clipboard.write([new ClipboardItem({ "image/png": blob })]);
7413
7477
  }
7414
- async function captureAllSlidesAsPngDataUrls(slideStageRef, totalSlides, setActiveSlide, currentSlideIndex, options = {}) {
7478
+ async function captureSlidesAsPngDataUrls(slideStageRef, slideIndices, setActiveSlide, currentSlideIndex, options = {}) {
7415
7479
  const { scale = 2, onProgress } = options;
7416
- const dataUrls = [];
7417
- for (let i = 0; i < totalSlides; i++) {
7418
- onProgress?.(i, totalSlides);
7419
- setActiveSlide(i);
7480
+ const total = slideIndices.length;
7481
+ const captures = [];
7482
+ for (const [position, slideIndex] of slideIndices.entries()) {
7483
+ onProgress?.(position, total);
7484
+ setActiveSlide(slideIndex);
7420
7485
  await waitForRender(150);
7421
7486
  const stageEl = slideStageRef.current;
7422
7487
  if (!stageEl) {
7423
- console.warn(`[export] Could not find slide stage element for slide ${i}`);
7488
+ console.warn(`[export] Could not find slide stage element for slide ${slideIndex}`);
7424
7489
  continue;
7425
7490
  }
7426
7491
  const { canvas } = await renderElementToTiledCanvas(stageEl, scale);
7427
- dataUrls.push(canvas.toDataURL("image/png"));
7492
+ captures.push({ slideIndex, dataUrl: canvas.toDataURL("image/png") });
7428
7493
  }
7429
- onProgress?.(totalSlides, totalSlides);
7494
+ onProgress?.(total, total);
7430
7495
  setActiveSlide(currentSlideIndex);
7431
- return dataUrls;
7496
+ return captures;
7432
7497
  }
7433
7498
  function tilesToPdfPage(tilesResult) {
7434
7499
  return tilesResult.tiles.map((tile) => ({
7435
- image: chunkZ22RD3E2_js.canvasToJpegData(tile.canvas),
7500
+ image: chunk3TN5SUQR_js.canvasToJpegData(tile.canvas),
7436
7501
  placement: pptx.placeTileOnPage(
7437
7502
  tile,
7438
7503
  tilesResult.fullWidth,
@@ -7465,7 +7530,7 @@ async function exportAllSlidesAsPdf(slideStageRef, totalSlides, setActiveSlide,
7465
7530
  if (pages.length === 0) {
7466
7531
  throw new Error(i18n.translationsEn["pptx.export.errorNoSlidesPdf"]);
7467
7532
  }
7468
- const pdfBlobUrl = chunkZ22RD3E2_js.buildPdfFromTiledImageData(pages);
7533
+ const pdfBlobUrl = chunk3TN5SUQR_js.buildPdfFromTiledImageData(pages);
7469
7534
  pptx.downloadDataUrl(pdfBlobUrl, filename);
7470
7535
  }
7471
7536
  async function exportAllSlidesAsNotesPdf(slideStageRef, totalSlides, setActiveSlide, currentSlideIndex, slideNotes, filename = "presentation-notes.pdf", options = {}) {
@@ -7495,7 +7560,7 @@ async function exportAllSlidesAsNotesPdf(slideStageRef, totalSlides, setActiveSl
7495
7560
  if (pages.length === 0) {
7496
7561
  throw new Error(i18n.translationsEn["pptx.export.errorNoSlidesNotesPdf"]);
7497
7562
  }
7498
- const pdfDataUrl = chunkZ22RD3E2_js.buildNotesPdf(pages);
7563
+ const pdfDataUrl = chunk3TN5SUQR_js.buildNotesPdf(pages);
7499
7564
  pptx.downloadDataUrl(pdfDataUrl, filename);
7500
7565
  }
7501
7566
  async function exportAllSlidesAsVideo(slideStageRef, totalSlides, setActiveSlide, currentSlideIndex, options = {}) {
@@ -7668,35 +7733,12 @@ function injectFontFaces(svg, fontFaces) {
7668
7733
  }
7669
7734
  return `${svg.slice(0, closingBracket + 1)}<defs>${styleBlock}</defs>${svg.slice(closingBracket + 1)}`;
7670
7735
  }
7671
- function exportAllSlidesToSvg(data, options = {}) {
7672
- const { onProgress, embedFonts, fontFaces } = options;
7673
- const svgOptions = {
7674
- includeHidden: options.includeHidden,
7675
- slideIndices: options.slideIndices,
7676
- defaultFontFamily: options.defaultFontFamily,
7677
- defaultFontSize: options.defaultFontSize
7678
- };
7679
- const results = [];
7680
- const includeHidden = svgOptions.includeHidden ?? false;
7681
- let processedCount = 0;
7682
- for (let i = 0; i < data.slides.length; i++) {
7683
- if (svgOptions.slideIndices && !svgOptions.slideIndices.includes(i)) {
7684
- continue;
7685
- }
7686
- const slide = data.slides[i];
7687
- if (slide.hidden && !includeHidden) {
7688
- continue;
7689
- }
7690
- onProgress?.(processedCount, data.slides.length);
7691
- let svg = pptx$1.SvgExporter.exportSlide(slide, data.width, data.height, svgOptions);
7692
- if (embedFonts && fontFaces?.length) {
7693
- svg = injectFontFaces(svg, fontFaces);
7694
- }
7695
- results.push(svg);
7696
- processedCount++;
7736
+ function exportSlideToSvg(slide, width, height, options = {}) {
7737
+ let svg = pptx$1.SvgExporter.exportSlide(slide, width, height, options);
7738
+ if (options.embedFonts && options.fontFaces?.length) {
7739
+ svg = injectFontFaces(svg, options.fontFaces);
7697
7740
  }
7698
- onProgress?.(processedCount, data.slides.length);
7699
- return results;
7741
+ return svg;
7700
7742
  }
7701
7743
  function safePrompt(message, defaultValue) {
7702
7744
  try {
@@ -8105,161 +8147,95 @@ function useViewerOptionsContext() {
8105
8147
  }
8106
8148
 
8107
8149
  // src/viewer/hooks/usePrintHandlers.ts
8150
+ var BLOCKED_WARNING = "[PowerPointViewer] Print window was blocked by the browser. Allow popups for this site to print.";
8108
8151
  function usePrintHandlers(input) {
8109
- const { slides, activeSlideIndex, canvasStageRef, setActiveSlideIndex, pptxData } = input;
8152
+ const { slides, activeSlideIndex, canvasStageRef, setActiveSlideIndex, canvasSize } = input;
8153
+ const handoutMaster = input.handoutMaster ?? input.pptxData?.handoutMaster;
8110
8154
  const [isPrintDialogOpen, setIsPrintDialogOpen] = React17.useState(false);
8111
- const { t } = chunkZ22RD3E2_js.useTranslation();
8155
+ const { t } = chunk3TN5SUQR_js.useTranslation();
8112
8156
  const viewerOptions = useViewerOptionsContext();
8113
- const includeHiddenSlides = viewerOptions.advanced.printHiddenSlides;
8114
8157
  const printRasterScale = (viewerOptions.advanced.printHighQuality ? 4 : 3) * pptx.resolveImageResolutionScale(viewerOptions);
8115
8158
  const handlePrint = () => {
8116
8159
  setIsPrintDialogOpen(true);
8117
8160
  };
8118
- const handlePrintSvg = async (settings) => {
8119
- setIsPrintDialogOpen(false);
8120
- const printWindow = pptx.openPendingPrintWindow(t("pptx.print.preparingToPrint"));
8121
- if (!printWindow) {
8122
- console.warn(
8123
- "[PowerPointViewer] Print window was blocked by the browser. Allow popups for this site to print."
8124
- );
8125
- return;
8126
- }
8127
- if (!pptxData || settings.printWhat !== "slides") {
8128
- return runRasterPrint(printWindow, settings);
8129
- }
8130
- const colorFilter = pptx.computeColorFilter(settings.colorMode);
8131
- const slideIndices = pptx.filterHiddenSlideIndices(
8132
- pptx.computeSlideIndices(
8133
- settings.slideRange,
8134
- activeSlideIndex,
8135
- slides.length,
8136
- settings.customRangeFrom,
8137
- settings.customRangeTo
8138
- ),
8139
- slides,
8140
- includeHiddenSlides
8141
- );
8142
- try {
8143
- const svgs = exportAllSlidesToSvg(pptxData, {
8144
- slideIndices
8145
- });
8146
- if (svgs.length === 0) {
8147
- printWindow.close();
8148
- return;
8149
- }
8150
- const printDoc = pptx.buildPrintDocument(svgs, pptxData.width, pptxData.height, {
8151
- title: "Slides (Vector)",
8152
- orientation: settings.orientation,
8153
- colorFilter,
8154
- scaleToFit: settings.scaleToFit
8155
- });
8156
- pptx.finishPrintWindow(printWindow, printDoc);
8157
- } catch (err) {
8158
- console.warn("[PowerPointViewer] SVG print path failed, falling back to raster:", err);
8159
- return runRasterPrint(printWindow, settings);
8160
- }
8161
- };
8162
- const runRasterPrint = async (printWindow, settings) => {
8163
- const colorFilter = pptx.computeColorFilter(settings.colorMode);
8164
- const slideIndices = pptx.filterHiddenSlideIndices(
8165
- pptx.computeSlideIndices(
8166
- settings.slideRange,
8167
- activeSlideIndex,
8168
- slides.length,
8169
- settings.customRangeFrom,
8170
- settings.customRangeTo
8171
- ),
8172
- slides,
8173
- includeHiddenSlides
8174
- );
8175
- if (settings.printWhat === "outline") {
8176
- pptx.finishPrintWindow(
8177
- printWindow,
8178
- pptx.buildPrintHtmlDocument({
8179
- title: "Outline",
8180
- bodyHtml: `<div class="outline-page">${pptx.buildOutlineHtml(slideIndices, slides)}</div>`,
8181
- orientation: settings.orientation,
8182
- colorFilter,
8183
- frameSlides: settings.frameSlides,
8184
- scaleToFit: settings.scaleToFit
8185
- })
8186
- );
8187
- return;
8188
- }
8161
+ const deckSlides = () => input.templateElementsBySlideId ? chunk3TN5SUQR_js.buildSaveSlides(slides, input.templateElementsBySlideId) : slides;
8162
+ const plan = (settings, deck) => pptx.planPrintJob(settings, {
8163
+ slides: deck,
8164
+ activeSlideIndex,
8165
+ // Options > Advanced > "Print hidden slides".
8166
+ includeHiddenSlides: viewerOptions.advanced.printHiddenSlides
8167
+ });
8168
+ const title = (job) => t(job.title.key, job.title.params);
8169
+ const runRasterPrint = async (printWindow, job, deck) => {
8189
8170
  try {
8190
8171
  if (!canvasStageRef.current) {
8191
8172
  printWindow.close();
8192
8173
  return;
8193
8174
  }
8194
- const allImages = await captureAllSlidesAsPngDataUrls(
8175
+ const captures = await captureSlidesAsPngDataUrls(
8195
8176
  canvasStageRef,
8196
- slides.length,
8177
+ job.slideIndices,
8197
8178
  setActiveSlideIndex,
8198
8179
  activeSlideIndex,
8199
8180
  { scale: printRasterScale }
8200
8181
  );
8201
- if (allImages.length === 0) {
8182
+ if (captures.length === 0) {
8202
8183
  printWindow.close();
8203
8184
  return;
8204
8185
  }
8205
- const slideImages = slideIndices.map((idx) => allImages[idx]).filter(Boolean);
8206
- if (settings.printWhat === "slides") {
8207
- pptx.finishPrintWindow(
8208
- printWindow,
8209
- pptx.buildPrintHtmlDocument({
8210
- title: "Slides",
8211
- bodyHtml: pptx.buildSlidesHtml(slideImages, slideIndices),
8212
- orientation: settings.orientation,
8213
- colorFilter,
8214
- frameSlides: settings.frameSlides,
8215
- scaleToFit: settings.scaleToFit
8216
- })
8217
- );
8218
- return;
8219
- }
8220
- if (settings.printWhat === "notes") {
8221
- pptx.finishPrintWindow(
8222
- printWindow,
8223
- pptx.buildPrintHtmlDocument({
8224
- title: "Notes Pages",
8225
- bodyHtml: pptx.buildNotesHtml(slideImages, slideIndices, slides),
8226
- orientation: "portrait",
8227
- colorFilter,
8228
- frameSlides: settings.frameSlides,
8229
- scaleToFit: settings.scaleToFit
8230
- })
8231
- );
8232
- return;
8233
- }
8234
- if (settings.printWhat === "handouts") {
8235
- const spp = settings.slidesPerPage;
8236
- pptx.finishPrintWindow(
8237
- printWindow,
8238
- pptx.buildPrintHtmlDocument({
8239
- title: `Handout ${spp} per page`,
8240
- bodyHtml: pptx.buildHandoutsHtml(slideImages, slideIndices, spp, pptxData?.handoutMaster),
8241
- orientation: "portrait",
8242
- colorFilter,
8243
- frameSlides: settings.frameSlides,
8244
- scaleToFit: settings.scaleToFit
8245
- })
8246
- );
8247
- }
8186
+ pptx.finishPrintWindow(
8187
+ printWindow,
8188
+ pptx.buildRasterPrintJobDocument(job, title(job), captures, deck, handoutMaster)
8189
+ );
8248
8190
  } catch (err) {
8249
8191
  console.error("[PowerPointViewer] Print layout failed:", err);
8192
+ printWindow.close();
8250
8193
  }
8251
8194
  };
8252
- const handlePrintWithSettings = async (settings) => {
8253
- setIsPrintDialogOpen(false);
8195
+ const openNow = (html) => {
8196
+ if (!pptx.openPrintWindow(html)) {
8197
+ console.warn(BLOCKED_WARNING);
8198
+ }
8199
+ };
8200
+ const startRasterPrint = async (job, deck) => {
8254
8201
  const printWindow = pptx.openPendingPrintWindow(t("pptx.print.preparingToPrint"));
8255
8202
  if (!printWindow) {
8256
- console.warn(
8257
- "[PowerPointViewer] Print window was blocked by the browser. Allow popups for this site to print."
8203
+ console.warn(BLOCKED_WARNING);
8204
+ return;
8205
+ }
8206
+ await runRasterPrint(printWindow, job, deck);
8207
+ };
8208
+ const vectorDocument = (job, deck) => {
8209
+ try {
8210
+ const svgs = job.slideIndices.map(
8211
+ (index) => exportSlideToSvg(deck[index], canvasSize.width, canvasSize.height)
8258
8212
  );
8213
+ return pptx.buildVectorPrintJobDocument(job, title(job), svgs, canvasSize);
8214
+ } catch (err) {
8215
+ console.warn("[PowerPointViewer] SVG print path failed, falling back to raster:", err);
8216
+ return void 0;
8217
+ }
8218
+ };
8219
+ const runPrintJob = async (settings, vector) => {
8220
+ setIsPrintDialogOpen(false);
8221
+ const deck = deckSlides();
8222
+ const job = plan(settings, deck);
8223
+ if (!job.ok) {
8259
8224
  return;
8260
8225
  }
8261
- return runRasterPrint(printWindow, settings);
8226
+ if (job.output === "outline") {
8227
+ openNow(pptx.buildOutlinePrintJobDocument(job, title(job), deck));
8228
+ return;
8229
+ }
8230
+ const html = vector && job.output === "vector" ? vectorDocument(job, deck) : void 0;
8231
+ if (html !== void 0) {
8232
+ openNow(html);
8233
+ return;
8234
+ }
8235
+ await startRasterPrint(pptx.printJobRasterFallback(job), deck);
8262
8236
  };
8237
+ const handlePrintSvg = (settings) => runPrintJob(settings, true);
8238
+ const handlePrintWithSettings = (settings) => runPrintJob(settings, false);
8263
8239
  return {
8264
8240
  handlePrint,
8265
8241
  handlePrintWithSettings,
@@ -8268,6 +8244,27 @@ function usePrintHandlers(input) {
8268
8244
  setIsPrintDialogOpen
8269
8245
  };
8270
8246
  }
8247
+ async function applyThemePartInPlace(input, themePath, applyToAllMasters) {
8248
+ const change = await pptx.applyThemeByPath(input.handlerRef.current, {
8249
+ themePath,
8250
+ applyToAllMasters,
8251
+ slides: input.slides,
8252
+ slideMasters: input.slideMasters,
8253
+ theme: input.theme,
8254
+ templateElementsBySlideId: input.templateElementsBySlideId
8255
+ });
8256
+ if (!change) {
8257
+ return;
8258
+ }
8259
+ input.bumpHistory();
8260
+ input.setSlides(change.slides);
8261
+ input.setTemplateElementsBySlideId(change.templateElementsBySlideId);
8262
+ input.setSlideMasters(change.slideMasters);
8263
+ if (change.deckTheme) {
8264
+ input.setTheme(change.deckTheme.theme);
8265
+ }
8266
+ input.history.markDirty();
8267
+ }
8271
8268
  async function applyThemeEditorEdit(input, { colorScheme, fontScheme, name }) {
8272
8269
  const {
8273
8270
  handlerRef,
@@ -8282,7 +8279,7 @@ async function applyThemeEditorEdit(input, { colorScheme, fontScheme, name }) {
8282
8279
  if (!handler) {
8283
8280
  return;
8284
8281
  }
8285
- await handler.applyTheme(colorScheme, fontScheme, name);
8282
+ await pptx.queueThemeWrite(handler, () => handler.applyTheme(colorScheme, fontScheme, name));
8286
8283
  const previousMap = theme?.colorScheme ? pptx$1.buildThemeColorMap(theme.colorScheme) : {};
8287
8284
  bumpHistory();
8288
8285
  setSlides(
@@ -8308,14 +8305,27 @@ async function applyThemeEditorEdit(input, { colorScheme, fontScheme, name }) {
8308
8305
  setTheme((prev) => ({ ...prev, colorScheme, fontScheme, name }));
8309
8306
  history.markDirty();
8310
8307
  }
8308
+ function restoreHistoryTheme(input, target) {
8309
+ const masters = input.slideMasters;
8310
+ const current = pptx.historyTheme(input.theme, masters);
8311
+ input.setTheme((prev) => pptx.withHistoryTheme(prev, target));
8312
+ if (target.masterThemePaths) {
8313
+ input.setSlideMasters(
8314
+ (prev) => pptx.withHistoryMasterThemes(prev, target)
8315
+ );
8316
+ }
8317
+ return pptx.writeThemeParts(
8318
+ input.handlerRef.current,
8319
+ current,
8320
+ target,
8321
+ pptx.loadedThemeName(input.themeOptions, input.slideMasters)
8322
+ );
8323
+ }
8311
8324
 
8312
8325
  // src/viewer/hooks/useThemeHandlers.ts
8313
8326
  function useThemeHandlers(input) {
8314
8327
  const {
8315
8328
  handlerRef,
8316
- serializeSlides,
8317
- setContent,
8318
- onContentChange,
8319
8329
  setTheme,
8320
8330
  setSlideMasters,
8321
8331
  slideMasters,
@@ -8326,36 +8336,13 @@ function useThemeHandlers(input) {
8326
8336
  theme,
8327
8337
  bumpHistory
8328
8338
  } = input;
8329
- const refreshContentAfterThemeChange = async () => {
8330
- const updated = await serializeSlides();
8331
- if (!updated) {
8332
- return;
8333
- }
8334
- setContent(updated);
8335
- if (onContentChange) {
8336
- onContentChange(updated);
8337
- }
8338
- history.markDirty();
8339
- };
8340
- const handleApplyTheme = async (themePath, applyToAllMasters) => {
8341
- const handler = handlerRef.current;
8342
- if (!handler) {
8343
- return;
8344
- }
8345
- await handler.setPresentationTheme(themePath, applyToAllMasters);
8346
- setSlideMasters(
8347
- (prev) => prev.map(
8348
- (master, index) => applyToAllMasters || index === 0 ? { ...master, themePath } : master
8349
- )
8350
- );
8351
- await refreshContentAfterThemeChange();
8352
- };
8339
+ const handleApplyTheme = (themePath, applyToAllMasters) => applyThemePartInPlace(input, themePath, applyToAllMasters);
8353
8340
  const handleUpdateThemeColorScheme = async (colorScheme) => {
8354
8341
  const handler = handlerRef.current;
8355
8342
  if (!handler) {
8356
8343
  return;
8357
8344
  }
8358
- await handler.updateThemeColorScheme(colorScheme);
8345
+ await pptx.queueThemeWrite(handler, () => handler.updateThemeColorScheme(colorScheme));
8359
8346
  const previousMap = theme?.colorScheme ? pptx$1.buildThemeColorMap(theme.colorScheme) : {};
8360
8347
  setSlides((prev) => pptx$1.reResolveSlideColors(prev, previousMap, colorScheme));
8361
8348
  if (Object.keys(templateElementsBySlideId).length > 0) {
@@ -8376,7 +8363,7 @@ function useThemeHandlers(input) {
8376
8363
  if (!handler) {
8377
8364
  return;
8378
8365
  }
8379
- await handler.updateThemeFontScheme(fontScheme);
8366
+ await pptx.queueThemeWrite(handler, () => handler.updateThemeFontScheme(fontScheme));
8380
8367
  const previousFonts = theme?.fontScheme;
8381
8368
  bumpHistory();
8382
8369
  setSlides((prev) => pptx$1.reResolveSlideFonts(prev, previousFonts, fontScheme));
@@ -8396,20 +8383,15 @@ function useThemeHandlers(input) {
8396
8383
  if (!handler) {
8397
8384
  return;
8398
8385
  }
8399
- await handler.updateThemeName(name);
8386
+ await pptx.queueThemeWrite(handler, () => handler.updateThemeName(name));
8400
8387
  setTheme((prev) => prev ? { ...prev, name } : { name });
8401
8388
  history.markDirty();
8402
8389
  };
8403
8390
  const handleApplyThemeToPresentation = async () => {
8404
- const handler = handlerRef.current;
8405
- if (!handler) {
8406
- return;
8407
- }
8408
8391
  const primaryThemePath = slideMasters[0]?.themePath;
8409
8392
  if (primaryThemePath) {
8410
- await handler.setPresentationTheme(primaryThemePath, true);
8393
+ await applyThemePartInPlace(input, primaryThemePath, true);
8411
8394
  }
8412
- await refreshContentAfterThemeChange();
8413
8395
  };
8414
8396
  const handleApplyThemeData = (colorScheme, fontScheme, themeName) => applyThemeEditorEdit(input, { colorScheme, fontScheme, name: themeName ?? theme?.name ?? "" });
8415
8397
  const handleSetTemplateBackground = (path, backgroundColor) => {
@@ -8437,16 +8419,9 @@ function useThemeHandlers(input) {
8437
8419
  }
8438
8420
  return handler.getAvailableThemes();
8439
8421
  };
8440
- const handleSwitchTheme = async (themePath) => {
8441
- const handler = handlerRef.current;
8442
- if (!handler) {
8443
- return;
8444
- }
8445
- await handler.setPresentationTheme(themePath, true);
8446
- setSlideMasters((prev) => prev.map((master) => ({ ...master, themePath })));
8447
- await refreshContentAfterThemeChange();
8448
- };
8422
+ const handleSwitchTheme = (themePath) => applyThemePartInPlace(input, themePath, true);
8449
8423
  const handleApplyThemeEdit = (edit) => applyThemeEditorEdit(input, edit);
8424
+ const handleRestoreHistoryTheme = (target) => restoreHistoryTheme(input, target);
8450
8425
  return {
8451
8426
  handleApplyThemeEdit,
8452
8427
  handleApplyTheme,
@@ -8455,6 +8430,7 @@ function useThemeHandlers(input) {
8455
8430
  handleUpdateThemeName,
8456
8431
  handleApplyThemeToPresentation,
8457
8432
  handleApplyThemeData,
8433
+ handleRestoreHistoryTheme,
8458
8434
  handleSetTemplateBackground,
8459
8435
  handleGetTemplateBackgroundColor,
8460
8436
  handleGetAvailableThemes,
@@ -8596,7 +8572,7 @@ function usePropertyHandlers(input) {
8596
8572
  width: canvasSize.width,
8597
8573
  height: canvasSize.height
8598
8574
  };
8599
- setCompareResult(chunkZ22RD3E2_js.comparePresentation(cur, other));
8575
+ setCompareResult(chunk3TN5SUQR_js.comparePresentation(cur, other));
8600
8576
  setIsComparePanelOpen(true);
8601
8577
  } catch (err) {
8602
8578
  console.warn("Compare failed:", err);
@@ -8952,7 +8928,7 @@ function useViewerDialogs(input) {
8952
8928
  };
8953
8929
  }
8954
8930
  function computeGridSpacingPx(documentGridSpacing) {
8955
- return pptx.computeGridSpacingPx(documentGridSpacing, chunkZ22RD3E2_js.GRID_SIZE);
8931
+ return pptx.computeGridSpacingPx(documentGridSpacing, chunk3TN5SUQR_js.GRID_SIZE);
8956
8932
  }
8957
8933
  function computeVisibleSlideIndexes(slides, activeCustomShowId, customShows, presentationProperties) {
8958
8934
  const activeShow = activeCustomShowId ? customShows.find((show) => show.id === activeCustomShowId) : void 0;
@@ -8961,7 +8937,7 @@ function computeVisibleSlideIndexes(slides, activeCustomShowId, customShows, pre
8961
8937
  }
8962
8938
  function computeSlideSectionGroups(slides, sections) {
8963
8939
  return pptx.groupSlidesBySection(sections, slides).map((group) => ({
8964
- id: group.section?.id ?? (sections.length > 0 ? chunkZ22RD3E2_js.UNGROUPED_SECTION_ID : chunkZ22RD3E2_js.DEFAULT_SECTION_GROUP_ID),
8940
+ id: group.section?.id ?? (sections.length > 0 ? chunk3TN5SUQR_js.UNGROUPED_SECTION_ID : chunk3TN5SUQR_js.DEFAULT_SECTION_GROUP_ID),
8965
8941
  label: group.section?.name ?? (sections.length > 0 ? "Ungrouped Slides" : "Slides"),
8966
8942
  slideIndexes: group.slideIndexes,
8967
8943
  ...group.section?.color !== void 0 ? { color: group.section.color } : {},
@@ -8980,7 +8956,7 @@ function computeMasterPseudoSlide(mode, activeLayout, activeMaster) {
8980
8956
  });
8981
8957
  }
8982
8958
  function useDerivedSlideState(input) {
8983
- const { t } = chunkZ22RD3E2_js.useTranslation();
8959
+ const { t } = chunk3TN5SUQR_js.useTranslation();
8984
8960
  const {
8985
8961
  slides,
8986
8962
  sections,
@@ -9006,10 +8982,10 @@ function useDerivedSlideState(input) {
9006
8982
  );
9007
8983
  const slideSectionGroups = React17.useMemo(
9008
8984
  () => computeSlideSectionGroups(slides, sections).map((group) => {
9009
- if (group.id === chunkZ22RD3E2_js.UNGROUPED_SECTION_ID && group.label === "Ungrouped Slides") {
8985
+ if (group.id === chunk3TN5SUQR_js.UNGROUPED_SECTION_ID && group.label === "Ungrouped Slides") {
9010
8986
  return { ...group, label: t("pptx.slides.ungroupedSlides") };
9011
8987
  }
9012
- if (group.id === chunkZ22RD3E2_js.DEFAULT_SECTION_GROUP_ID && group.label === "Slides") {
8988
+ if (group.id === chunk3TN5SUQR_js.DEFAULT_SECTION_GROUP_ID && group.label === "Slides") {
9013
8989
  return { ...group, label: t("pptx.sections.slides") };
9014
8990
  }
9015
8991
  return group;
@@ -9116,7 +9092,7 @@ function useAnnotationHandlers(input) {
9116
9092
  if (nextMode === "present") {
9117
9093
  presentation.enterPresentMode();
9118
9094
  } else if (mode === "present" && annotations.hasAnyAnnotations) {
9119
- chunkZ22RD3E2_js.stopAllPersistentAudio();
9095
+ chunk3TN5SUQR_js.stopAllPersistentAudio();
9120
9096
  if (promptKeepInkAnnotations) {
9121
9097
  pendingModeAfterAnnotationsRef.current = nextMode;
9122
9098
  setShowKeepAnnotationsDialog(true);
@@ -9126,7 +9102,7 @@ function useAnnotationHandlers(input) {
9126
9102
  }
9127
9103
  } else {
9128
9104
  if (mode === "present") {
9129
- chunkZ22RD3E2_js.stopAllPersistentAudio();
9105
+ chunk3TN5SUQR_js.stopAllPersistentAudio();
9130
9106
  }
9131
9107
  setMode(nextMode);
9132
9108
  }
@@ -9293,7 +9269,7 @@ function useSerialize(input) {
9293
9269
  guides: pptxGuides.length > 0 ? pptxGuides : void 0
9294
9270
  };
9295
9271
  });
9296
- const slidesToSave = chunkZ22RD3E2_js.buildSaveSlides(slidesWithGuides, pending.templateElementsBySlideId);
9272
+ const slidesToSave = chunk3TN5SUQR_js.buildSaveSlides(slidesWithGuides, pending.templateElementsBySlideId);
9297
9273
  const saveOptions = pptx.buildDeckSaveOptions({
9298
9274
  // Without this the Slide Size card edited a viewer-only pixel value and
9299
9275
  // the saved `p:sldSz` never moved: passing `slideSize` is the only way a
@@ -9437,7 +9413,7 @@ function usePresentationSetup(input) {
9437
9413
  return;
9438
9414
  }
9439
9415
  if (mode === "present" && nextMode !== "present") {
9440
- chunkZ22RD3E2_js.stopAllPersistentAudio();
9416
+ chunk3TN5SUQR_js.stopAllPersistentAudio();
9441
9417
  stopAnimationSound();
9442
9418
  const exitHandler = exitModeHandlerRef.current;
9443
9419
  if (exitHandler) {
@@ -9558,7 +9534,7 @@ function useCanvasImagePaste(input) {
9558
9534
  );
9559
9535
  }
9560
9536
  function formatPatchFor(element, format) {
9561
- const updated = chunkZ22RD3E2_js.applyFormatToElement(element, format);
9537
+ const updated = chunk3TN5SUQR_js.applyFormatToElement(element, format);
9562
9538
  const updates = {};
9563
9539
  if (pptx$1.hasShapeProperties(updated)) {
9564
9540
  updates.shapeStyle = updated.shapeStyle;
@@ -9581,7 +9557,7 @@ function useFormatPainterEditing(input) {
9581
9557
  const prevFormatPainterRef = React17.useRef(false);
9582
9558
  React17.useEffect(() => {
9583
9559
  if (formatPainterActive && !prevFormatPainterRef.current && selectedElement) {
9584
- copiedFormatRef.current = chunkZ22RD3E2_js.copyFormatFromElement(selectedElement);
9560
+ copiedFormatRef.current = chunk3TN5SUQR_js.copyFormatFromElement(selectedElement);
9585
9561
  } else if (!formatPainterActive) {
9586
9562
  copiedFormatRef.current = null;
9587
9563
  }
@@ -10031,9 +10007,7 @@ function useIOHandlers(input) {
10031
10007
  zoom,
10032
10008
  handlerRef,
10033
10009
  serializeSlides,
10034
- serializeForRecovery,
10035
10010
  setContent,
10036
- onContentChange,
10037
10011
  onPropertiesChange,
10038
10012
  onNotesUpdate,
10039
10013
  imageExportScale,
@@ -10070,19 +10044,19 @@ function useIOHandlers(input) {
10070
10044
  slides,
10071
10045
  activeSlideIndex,
10072
10046
  canvasStageRef: zoom.canvasStageRef,
10073
- setActiveSlideIndex: state.setActiveSlideIndex
10047
+ setActiveSlideIndex: state.setActiveSlideIndex,
10048
+ canvasSize,
10049
+ templateElementsBySlideId: state.templateElementsBySlideId,
10050
+ handoutMaster: state.handoutMaster
10074
10051
  });
10075
10052
  const themeHandlers = useThemeHandlers({
10076
10053
  handlerRef,
10077
- // Theme apply re-serialises and re-parses through `setContent`, so these
10078
- // bytes go back into our own loader: plaintext, never the protected save.
10079
- serializeSlides: serializeForRecovery,
10080
- setContent,
10081
- onContentChange,
10082
10054
  setTheme: state.setTheme,
10083
10055
  setSlideMasters: state.setSlideMasters,
10084
10056
  slideMasters: state.slideMasters,
10057
+ themeOptions: state.themeOptions,
10085
10058
  history,
10059
+ slides,
10086
10060
  setSlides: state.setSlides,
10087
10061
  templateElementsBySlideId: state.templateElementsBySlideId,
10088
10062
  setTemplateElementsBySlideId: state.setTemplateElementsBySlideId,
@@ -10136,7 +10110,12 @@ function isFontDataUrlSafe(url) {
10136
10110
  }
10137
10111
  return FONT_DATA_URL_PATTERN.test(url);
10138
10112
  }
10139
- function useFontInjection({ embeddedFonts, slides }) {
10113
+ function useFontInjection({
10114
+ embeddedFonts,
10115
+ slides,
10116
+ googleFonts
10117
+ }) {
10118
+ const googleFontsBase = pptx.resolveGoogleFontsCss2Base(googleFonts);
10140
10119
  React17.useEffect(() => {
10141
10120
  if (!embeddedFonts.length) {
10142
10121
  return;
@@ -10178,17 +10157,19 @@ function useFontInjection({ embeddedFonts, slides }) {
10178
10157
  const referencedFamilies = React17.useMemo(() => pptx.collectReferencedFontFamilies(slides), [slides]);
10179
10158
  React17.useEffect(() => {
10180
10159
  let cancelled = false;
10181
- void pptx.resolveGoogleWebfontHref(slides, embeddedFonts).then((href) => {
10182
- if (cancelled) {
10183
- return null;
10160
+ void pptx.resolveGoogleWebfontHref(slides, embeddedFonts, void 0, googleFontsBase).then(
10161
+ (href) => {
10162
+ if (cancelled) {
10163
+ return null;
10164
+ }
10165
+ pptx.syncGoogleWebfontStylesheet(document, GOOGLE_FONTS_LINK_ID, href);
10166
+ return href;
10184
10167
  }
10185
- pptx.syncGoogleWebfontStylesheet(document, GOOGLE_FONTS_LINK_ID, href);
10186
- return href;
10187
- });
10168
+ );
10188
10169
  return () => {
10189
10170
  cancelled = true;
10190
10171
  };
10191
- }, [embeddedFonts, slides]);
10172
+ }, [embeddedFonts, slides, googleFontsBase]);
10192
10173
  React17.useEffect(() => () => document.getElementById(GOOGLE_FONTS_LINK_ID)?.remove(), []);
10193
10174
  const [, setOutlineFontsTick] = React17.useState(0);
10194
10175
  React17.useEffect(() => {
@@ -10201,41 +10182,43 @@ function useFontInjection({ embeddedFonts, slides }) {
10201
10182
  if (candidates.length === 0) {
10202
10183
  return;
10203
10184
  }
10204
- void pptx.resolveGoogleWebfontHref(slides, embeddedFonts).then(async (href) => {
10205
- if (cancelled || !href) {
10206
- return;
10207
- }
10208
- const boldItalicVariants = [
10209
- { bold: false, italic: false },
10210
- { bold: true, italic: false }
10211
- ];
10212
- let registeredAny = false;
10213
- for (const family of candidates) {
10214
- for (const variant of boldItalicVariants) {
10215
- if (cancelled) {
10216
- return;
10217
- }
10218
- const bytes = await pptx.fetchGoogleWebfontOutlineBytes(
10219
- href,
10220
- family,
10221
- variant.bold,
10222
- variant.italic,
10223
- fetch
10224
- );
10225
- if (bytes && glyphOutlineFontCache.registerFontBytes(family, variant.bold, variant.italic, bytes)) {
10226
- registeredAny = true;
10185
+ void pptx.resolveGoogleWebfontHref(slides, embeddedFonts, void 0, googleFontsBase).then(
10186
+ async (href) => {
10187
+ if (cancelled || !href) {
10188
+ return;
10189
+ }
10190
+ const boldItalicVariants = [
10191
+ { bold: false, italic: false },
10192
+ { bold: true, italic: false }
10193
+ ];
10194
+ let registeredAny = false;
10195
+ for (const family of candidates) {
10196
+ for (const variant of boldItalicVariants) {
10197
+ if (cancelled) {
10198
+ return;
10199
+ }
10200
+ const bytes = await pptx.fetchGoogleWebfontOutlineBytes(
10201
+ href,
10202
+ family,
10203
+ variant.bold,
10204
+ variant.italic,
10205
+ fetch
10206
+ );
10207
+ if (bytes && glyphOutlineFontCache.registerFontBytes(family, variant.bold, variant.italic, bytes)) {
10208
+ registeredAny = true;
10209
+ }
10227
10210
  }
10228
10211
  }
10212
+ if (registeredAny && !cancelled) {
10213
+ setOutlineFontsTick((tick) => tick + 1);
10214
+ }
10215
+ return void 0;
10229
10216
  }
10230
- if (registeredAny && !cancelled) {
10231
- setOutlineFontsTick((tick) => tick + 1);
10232
- }
10233
- return void 0;
10234
- });
10217
+ );
10235
10218
  return () => {
10236
10219
  cancelled = true;
10237
10220
  };
10238
- }, [embeddedFonts, slides]);
10221
+ }, [embeddedFonts, slides, googleFontsBase]);
10239
10222
  React17.useEffect(() => {
10240
10223
  const neededSymbolFonts = SYMBOL_FONT_FAMILIES.filter((f) => referencedFamilies.has(f));
10241
10224
  if (neededSymbolFonts.length === 0) {
@@ -10283,6 +10266,7 @@ function useContentLifecycle(input) {
10283
10266
  onContentApplied,
10284
10267
  allowExternalImages,
10285
10268
  initialSlide,
10269
+ googleFonts,
10286
10270
  setReadOnlyRecommendation,
10287
10271
  setModifyVerifier,
10288
10272
  setCompatToasts
@@ -10339,7 +10323,7 @@ function useContentLifecycle(input) {
10339
10323
  React17.useEffect(() => {
10340
10324
  actionSoundHandlerRef.current = handlerRef.current;
10341
10325
  }, [handlerRef, actionSoundHandlerRef, state.loading]);
10342
- useFontInjection({ embeddedFonts: state.embeddedFonts, slides });
10326
+ useFontInjection({ embeddedFonts: state.embeddedFonts, slides, googleFonts });
10343
10327
  const serializeInput = {
10344
10328
  slides,
10345
10329
  templateElementsBySlideId: state.templateElementsBySlideId,
@@ -10695,6 +10679,7 @@ function useViewerIntegration(input) {
10695
10679
  autosaveIntervalMs,
10696
10680
  allowExternalImages,
10697
10681
  initialSlide,
10682
+ googleFonts,
10698
10683
  setReadOnlyRecommendation,
10699
10684
  setModifyVerifier,
10700
10685
  setCompatToasts,
@@ -10759,32 +10744,31 @@ function useViewerIntegration(input) {
10759
10744
  });
10760
10745
  const [isEncryptedDialogOpen, setIsEncryptedDialogOpen] = React17.useState(false);
10761
10746
  const [loadVersion, setLoadVersion] = React17.useState(0);
10762
- const { handlerRef, serializeSlides, serializeForRecovery, autosaveStatus } = useContentLifecycle(
10763
- {
10764
- content,
10765
- filePath,
10766
- storage,
10767
- autosaveEnabled,
10768
- autosaveIntervalMs,
10769
- onAutosave,
10770
- // The File > Fonts toggle, finally reaching a save call.
10771
- embedFonts: dialogs.embedFontsEnabled,
10772
- slides,
10773
- state,
10774
- history,
10775
- ops: editorOps.ops,
10776
- transformCommittedText: input.transformCommittedText,
10777
- actionSoundHandlerRef,
10778
- setIsEncryptedDialogOpen,
10779
- password: dialogs.presentationPassword ?? void 0,
10780
- onContentApplied: () => setLoadVersion((v) => v + 1),
10781
- allowExternalImages,
10782
- initialSlide,
10783
- setReadOnlyRecommendation,
10784
- setModifyVerifier,
10785
- setCompatToasts
10786
- }
10787
- );
10747
+ const { handlerRef, serializeSlides, autosaveStatus } = useContentLifecycle({
10748
+ content,
10749
+ filePath,
10750
+ storage,
10751
+ autosaveEnabled,
10752
+ autosaveIntervalMs,
10753
+ onAutosave,
10754
+ // The File > Fonts toggle, finally reaching a save call.
10755
+ embedFonts: dialogs.embedFontsEnabled,
10756
+ slides,
10757
+ state,
10758
+ history,
10759
+ ops: editorOps.ops,
10760
+ transformCommittedText: input.transformCommittedText,
10761
+ actionSoundHandlerRef,
10762
+ setIsEncryptedDialogOpen,
10763
+ password: dialogs.presentationPassword ?? void 0,
10764
+ onContentApplied: () => setLoadVersion((v) => v + 1),
10765
+ allowExternalImages,
10766
+ initialSlide,
10767
+ googleFonts,
10768
+ setReadOnlyRecommendation,
10769
+ setModifyVerifier,
10770
+ setCompatToasts
10771
+ });
10788
10772
  const { exportHandlers, printHandlers, themeHandlers, propertyHandlers } = useIOHandlers({
10789
10773
  state,
10790
10774
  slides,
@@ -10798,9 +10782,7 @@ function useViewerIntegration(input) {
10798
10782
  zoom,
10799
10783
  handlerRef,
10800
10784
  serializeSlides,
10801
- serializeForRecovery,
10802
10785
  setContent,
10803
- onContentChange,
10804
10786
  onPropertiesChange,
10805
10787
  onNotesUpdate,
10806
10788
  imageExportScale,
@@ -11203,7 +11185,7 @@ function useCollaborationWriteBack(input) {
11203
11185
  getSourceBytes: () => latest.current.getSourceBytes?.() ?? null,
11204
11186
  getSaveOptions: () => latest.current.getSaveOptions?.(),
11205
11187
  getTemplateElements: () => latest.current.templateElementsBySlideId,
11206
- mergeTemplateElements: chunkZ22RD3E2_js.buildSaveSlides,
11188
+ mergeTemplateElements: chunk3TN5SUQR_js.buildSaveSlides,
11207
11189
  onWriteBackStatus: () => latest.current.onWriteBackStatus?.(
11208
11190
  pptx.writeBackReport(latest.current.config, created.getState())
11209
11191
  )
@@ -11613,11 +11595,9 @@ function useLayoutSwitching(input) {
11613
11595
  }
11614
11596
  setIsLoading(true);
11615
11597
  try {
11616
- const updated = await handler.applyLayoutToSlide(
11617
- activeSlideIndex,
11618
- layoutPath,
11619
- slidesRef.current
11620
- );
11598
+ const updated = await handler.applyLayoutToSlide(activeSlideIndex, layoutPath, [
11599
+ ...slidesRef.current
11600
+ ]);
11621
11601
  ops.updateSlides((prev) => {
11622
11602
  const next = [...prev];
11623
11603
  next[activeSlideIndex] = updated;
@@ -11762,8 +11742,8 @@ function useTouchGestures(input) {
11762
11742
  }
11763
11743
  const recognizer = pptx.createTouchGestureRecognizer({
11764
11744
  getScale: () => scaleRef.current,
11765
- minScale: chunkZ22RD3E2_js.MIN_ZOOM_SCALE,
11766
- maxScale: chunkZ22RD3E2_js.MAX_ZOOM_SCALE,
11745
+ minScale: chunk3TN5SUQR_js.MIN_ZOOM_SCALE,
11746
+ maxScale: chunk3TN5SUQR_js.MAX_ZOOM_SCALE,
11767
11747
  callbacks: {
11768
11748
  onPinchZoom: (newScale) => callbacksRef.current.onPinchZoom?.(newScale),
11769
11749
  onSwipe: (direction) => callbacksRef.current.onSwipe?.(direction),
@@ -11887,7 +11867,7 @@ function buildCanvasProps(input) {
11887
11867
  if (pptx.shouldConfirmExternalHyperlink(viewerOptions, url) && !window.confirm(buildHyperlinkConfirmMessage(url))) {
11888
11868
  return;
11889
11869
  }
11890
- chunkZ22RD3E2_js.safeOpenUrl(url, target);
11870
+ chunk3TN5SUQR_js.safeOpenUrl(url, target);
11891
11871
  };
11892
11872
  const handleActionClick = (elementId, action) => {
11893
11873
  if (mode === "present") {
@@ -11902,9 +11882,9 @@ function buildCanvasProps(input) {
11902
11882
  }
11903
11883
  };
11904
11884
  const handleHyperlinkClick = (url, target) => {
11905
- if (chunkZ22RD3E2_js.isPpactionUrl(url)) {
11885
+ if (chunk3TN5SUQR_js.isPpactionUrl(url)) {
11906
11886
  if (mode === "present") {
11907
- const parsed = chunkZ22RD3E2_js.parsePpactionUrl(url);
11887
+ const parsed = chunk3TN5SUQR_js.parsePpactionUrl(url);
11908
11888
  if (parsed) {
11909
11889
  presentation.handlePresentationAction({
11910
11890
  action: parsed.action,
@@ -12332,7 +12312,7 @@ function buildToolbarProps(input) {
12332
12312
  markDirty: history.markDirty
12333
12313
  }),
12334
12314
  formatPainterActive: s.formatPainterActive,
12335
- canActivateFormatPainter: chunkZ22RD3E2_js.hasCopyableFormat(selectedElement),
12315
+ canActivateFormatPainter: chunk3TN5SUQR_js.hasCopyableFormat(selectedElement),
12336
12316
  onToggleFormatPainter: () => s.setFormatPainterActive((p) => !p),
12337
12317
  isSelectionPaneOpen: s.isSelectionPaneOpen,
12338
12318
  onToggleSelectionPane: () => s.setIsSelectionPaneOpen((p) => !p),
@@ -12838,7 +12818,7 @@ function useViewPreferencesSync(input) {
12838
12818
  // src/viewer/hooks/useViewerBuildingBlocksState.ts
12839
12819
  function useViewerBuildingBlocksState(input) {
12840
12820
  const { core, content, canEdit, filePath, autosaveEnabled, userName, handle, setContent } = input;
12841
- const { initialSlide } = input;
12821
+ const { initialSlide, googleFonts } = input;
12842
12822
  const {
12843
12823
  onContentChange,
12844
12824
  onDirtyChange,
@@ -12942,6 +12922,7 @@ function useViewerBuildingBlocksState(input) {
12942
12922
  filePath,
12943
12923
  autosaveEnabled,
12944
12924
  initialSlide,
12925
+ googleFonts,
12945
12926
  // Trust Center > "Allow external content": same gate `PowerPointViewer`
12946
12927
  // applies, so the headless building-blocks API loads http(s) images
12947
12928
  // under the same default-off, core-side SSRF/privacy guard.
@@ -13006,6 +12987,7 @@ function useViewerBuildingBlocks(input) {
13006
12987
  filePath,
13007
12988
  fileName,
13008
12989
  initialSlide,
12990
+ googleFonts,
13009
12991
  autosaveEnabled = true,
13010
12992
  userName,
13011
12993
  hiddenActions,
@@ -13023,7 +13005,7 @@ function useViewerBuildingBlocks(input) {
13023
13005
  } = input;
13024
13006
  const collaborationConfig = pptx.resolveCollaborationConfig(input.collaboration);
13025
13007
  const [collaborationReadOnly, setCollaborationReadOnly] = React17.useState(Boolean(collaborationConfig));
13026
- const { t } = chunkZ22RD3E2_js.useTranslation();
13008
+ const { t } = chunk3TN5SUQR_js.useTranslation();
13027
13009
  const [content, setContent] = React17.useState(incomingContent ?? null);
13028
13010
  const [loadOrigin, setLoadOrigin] = React17.useState("bootstrap");
13029
13011
  React17.useEffect(() => {
@@ -13094,6 +13076,7 @@ function useViewerBuildingBlocks(input) {
13094
13076
  canEdit,
13095
13077
  filePath,
13096
13078
  initialSlide,
13079
+ googleFonts,
13097
13080
  autosaveEnabled,
13098
13081
  userName,
13099
13082
  handle,
@@ -13210,23 +13193,23 @@ function ColorChangedImage({
13210
13193
  className,
13211
13194
  alt
13212
13195
  }) {
13213
- const tolerance = tolerancePct ?? chunkZ22RD3E2_js.DEFAULT_COLOR_CHANGE_TOLERANCE;
13214
- const cacheKey = chunkZ22RD3E2_js.buildCacheKey(
13196
+ const tolerance = tolerancePct ?? chunk3TN5SUQR_js.DEFAULT_COLOR_CHANGE_TOLERANCE;
13197
+ const cacheKey = chunk3TN5SUQR_js.buildCacheKey(
13215
13198
  src,
13216
13199
  clrChange.clrFrom,
13217
13200
  clrChange.clrTo,
13218
13201
  tolerance,
13219
13202
  Boolean(clrChange.clrToTransparent)
13220
13203
  );
13221
- const cached = chunkZ22RD3E2_js.getCachedResult(cacheKey);
13204
+ const cached = chunk3TN5SUQR_js.getCachedResult(cacheKey);
13222
13205
  const [processedSrc, setProcessedSrc] = React17.useState(cached ?? null);
13223
13206
  React17.useEffect(() => {
13224
- if (chunkZ22RD3E2_js.getCachedResult(cacheKey)) {
13225
- setProcessedSrc(chunkZ22RD3E2_js.getCachedResult(cacheKey) ?? null);
13207
+ if (chunk3TN5SUQR_js.getCachedResult(cacheKey)) {
13208
+ setProcessedSrc(chunk3TN5SUQR_js.getCachedResult(cacheKey) ?? null);
13226
13209
  return;
13227
13210
  }
13228
13211
  let cancelled = false;
13229
- chunkZ22RD3E2_js.applyColorChange(
13212
+ chunk3TN5SUQR_js.applyColorChange(
13230
13213
  src,
13231
13214
  clrChange.clrFrom,
13232
13215
  clrChange.clrTo,
@@ -13234,7 +13217,7 @@ function ColorChangedImage({
13234
13217
  Boolean(clrChange.clrToTransparent)
13235
13218
  ).then((result) => {
13236
13219
  if (!cancelled) {
13237
- chunkZ22RD3E2_js.setCachedResult(cacheKey, result.dataUrl);
13220
+ chunk3TN5SUQR_js.setCachedResult(cacheKey, result.dataUrl);
13238
13221
  setProcessedSrc(result.dataUrl);
13239
13222
  }
13240
13223
  return void 0;
@@ -13326,7 +13309,7 @@ function TiledImageLayer({
13326
13309
  cancelled = true;
13327
13310
  };
13328
13311
  }, [src]);
13329
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style: { ...chunkZ22RD3E2_js.getImageTilingStyle(element, nativeSize), ...style } });
13312
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style: { ...chunk3TN5SUQR_js.getImageTilingStyle(element, nativeSize), ...style } });
13330
13313
  }
13331
13314
  function renderImageEffectDefinitions(element, excludeDuotone = false) {
13332
13315
  return pptx.getImageSvgFilters(element).filter((definition) => !excludeDuotone || definition.id !== `duotone-${element.id}`).map((definition) => /* @__PURE__ */ jsxRuntime.jsx(
@@ -13395,7 +13378,7 @@ function renderImg(el, style, filter, alt, opacity) {
13395
13378
  ...filter ? { filter } : {},
13396
13379
  ...opacity !== void 0 ? { opacity } : {}
13397
13380
  };
13398
- if (chunkZ22RD3E2_js.isImageTiled(el)) {
13381
+ if (chunk3TN5SUQR_js.isImageTiled(el)) {
13399
13382
  const tileSrc = imgSrc(el);
13400
13383
  if (!tileSrc) {
13401
13384
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center text-[11px] text-gray-500 bg-gray-100", children: "Image" });
@@ -13417,9 +13400,9 @@ function renderImg(el, style, filter, alt, opacity) {
13417
13400
  pptx$1.isImageLikeElement(el) ? el.imageEffects?.colorWash : void 0
13418
13401
  );
13419
13402
  const clrChange = "imageEffects" in el ? el.imageEffects?.clrChange : void 0;
13420
- const duotoneColors = chunkZ22RD3E2_js.getDuotoneColors(el);
13403
+ const duotoneColors = chunk3TN5SUQR_js.getDuotoneColors(el);
13421
13404
  const useDuotoneCanvas = Boolean(duotoneColors && !clrChange);
13422
- const filterForImg = useDuotoneCanvas ? chunkZ22RD3E2_js.getImageEffectsFilter(el, { excludeDuotone: true }) : filter;
13405
+ const filterForImg = useDuotoneCanvas ? chunk3TN5SUQR_js.getImageEffectsFilter(el, { excludeDuotone: true }) : filter;
13423
13406
  const canvasEffectStyles = {
13424
13407
  ...filterForImg ? { filter: filterForImg } : {},
13425
13408
  ...opacity !== void 0 ? { opacity } : {}
@@ -13495,10 +13478,10 @@ function SlideBackgroundImageLayer({
13495
13478
  style: { zIndex: 0 },
13496
13479
  children: renderImg(
13497
13480
  backgroundElement,
13498
- chunkZ22RD3E2_js.getImageRenderStyle(backgroundElement),
13499
- chunkZ22RD3E2_js.getImageEffectsFilter(backgroundElement),
13481
+ chunk3TN5SUQR_js.getImageRenderStyle(backgroundElement),
13482
+ chunk3TN5SUQR_js.getImageEffectsFilter(backgroundElement),
13500
13483
  "",
13501
- chunkZ22RD3E2_js.getImageEffectsOpacity(backgroundElement)
13484
+ chunk3TN5SUQR_js.getImageEffectsOpacity(backgroundElement)
13502
13485
  )
13503
13486
  }
13504
13487
  );
@@ -13769,7 +13752,7 @@ function ChartElementView({
13769
13752
  onUpdateElement,
13770
13753
  animationState
13771
13754
  }) {
13772
- const { t } = chunkZ22RD3E2_js.useTranslation();
13755
+ const { t } = chunk3TN5SUQR_js.useTranslation();
13773
13756
  const wrapperRef = React17.useRef(null);
13774
13757
  const { selection, setSelection } = useChartPartSelection();
13775
13758
  const [titleDraft, setTitleDraft] = React17.useState(null);
@@ -13784,7 +13767,7 @@ function ChartElementView({
13784
13767
  pptx.getBarFacePicturePixelSampleVersion
13785
13768
  );
13786
13769
  const viewModel = React17.useMemo(() => {
13787
- return canEdit ? chunkZ22RD3E2_js.buildReactChartViewModel(element) : null;
13770
+ return canEdit ? chunk3TN5SUQR_js.buildReactChartViewModel(element) : null;
13788
13771
  }, [canEdit, element, barFacePictureSampleVersion]);
13789
13772
  React17.useEffect(pptx.ensureChartInteractionStyles, []);
13790
13773
  React17.useEffect(() => {
@@ -13889,9 +13872,9 @@ function ChartElementView({
13889
13872
  textStyle: animationState?.textStyle,
13890
13873
  onSelect: chart3D.onSelect,
13891
13874
  onDrag: chart3D.onDrag,
13892
- children: chunkZ22RD3E2_js.renderChartElement(renderedElement, (key) => t(key))
13875
+ children: chunk3TN5SUQR_js.renderChartElement(renderedElement, (key) => t(key))
13893
13876
  }
13894
- ) : chunkZ22RD3E2_js.renderChartElement(renderedElement, (key) => t(key)),
13877
+ ) : chunk3TN5SUQR_js.renderChartElement(renderedElement, (key) => t(key)),
13895
13878
  dragValue !== null && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-1 right-1 z-10 rounded bg-primary/90 px-1.5 py-0.5 text-[10px] font-medium text-white pointer-events-none", children: pptx.formatAxisValue(dragValue) }),
13896
13879
  titleDraft !== null && /* @__PURE__ */ jsxRuntime.jsx(
13897
13880
  "input",
@@ -13919,7 +13902,7 @@ function ChartElementView({
13919
13902
  );
13920
13903
  }
13921
13904
  function useActionAffordance(element, canInteract) {
13922
- const { t } = chunkZ22RD3E2_js.useTranslation();
13905
+ const { t } = chunk3TN5SUQR_js.useTranslation();
13923
13906
  pptx.ensureActionAffordanceStyles();
13924
13907
  return React17.useMemo(
13925
13908
  () => pptx.resolveElementActionAffordance(element, {
@@ -14197,7 +14180,7 @@ function ResizeHandles({
14197
14180
  nonRotationTransform,
14198
14181
  onRotate
14199
14182
  }) {
14200
- const { t } = chunkZ22RD3E2_js.useTranslation();
14183
+ const { t } = chunk3TN5SUQR_js.useTranslation();
14201
14184
  const rotateRef = useRotateHandlePlacement(elementId, Boolean(onRotate));
14202
14185
  const peStyle = forcePointerEvents ? { ...HANDLE_TOUCH_ACTION, pointerEvents: "auto" } : HANDLE_TOUCH_ACTION;
14203
14186
  const resizeStyle = { ...HANDLE_TOUCH_ACTION, pointerEvents: "none" };
@@ -14230,7 +14213,7 @@ function ResizeHandles({
14230
14213
  "aria-label": t("pptx.selectionOverlay.resize", { handle }),
14231
14214
  "data-pptx-handle-kind": "resize",
14232
14215
  "data-pptx-compact": true,
14233
- className: chunkZ22RD3E2_js.cn(
14216
+ className: chunk3TN5SUQR_js.cn(
14234
14217
  "absolute z-10 group border-0 bg-transparent p-0",
14235
14218
  RESIZE_DEFAULT_CLASSES,
14236
14219
  posClass,
@@ -14256,7 +14239,7 @@ function ResizeHandles({
14256
14239
  "div",
14257
14240
  {
14258
14241
  "data-pptx-handle-hit": true,
14259
- className: chunkZ22RD3E2_js.cn(
14242
+ className: chunk3TN5SUQR_js.cn(
14260
14243
  "absolute -inset-px pointer-events-auto [--pptx-handle-hit-inset:-1px]",
14261
14244
  corner ? "max-md:-inset-1.5 max-md:[--pptx-handle-hit-inset:-6px]" : "max-md:-inset-2 max-md:[--pptx-handle-hit-inset:-8px]"
14262
14245
  ),
@@ -14277,7 +14260,7 @@ function ResizeHandles({
14277
14260
  "aria-label": t("pptx.selectionOverlay.rotate"),
14278
14261
  "data-pptx-handle-kind": "rotate",
14279
14262
  "data-pptx-compact": true,
14280
- className: chunkZ22RD3E2_js.cn(
14263
+ className: chunk3TN5SUQR_js.cn(
14281
14264
  "absolute left-1/2 top-0 -translate-x-1/2 -translate-y-1/2 z-20 border-0 bg-transparent p-0 cursor-grab active:cursor-grabbing",
14282
14265
  ROTATE_DEFAULT_CLASSES
14283
14266
  ),
@@ -14354,10 +14337,10 @@ var ConnectorElementRendererMemo = /* @__PURE__ */ React17__default.default.memo
14354
14337
  const svgHeight = Math.max(el.height, 1);
14355
14338
  const ss = shapeEl?.shapeStyle;
14356
14339
  const strokeWidth = Math.max(0, ss?.strokeWidth ?? 2);
14357
- const strokeColor = chunkZ22RD3E2_js.normalizeHexColor(ss?.strokeColor, chunkZ22RD3E2_js.DEFAULT_STROKE_COLOR);
14358
- const strokePaint = chunkZ22RD3E2_js.colorWithOpacity(strokeColor, ss?.strokeOpacity);
14359
- const dashType = chunkZ22RD3E2_js.normalizeStrokeDashType(ss?.strokeDash);
14360
- const dashArray = chunkZ22RD3E2_js.getSvgStrokeDasharray(
14340
+ const strokeColor = chunk3TN5SUQR_js.normalizeHexColor(ss?.strokeColor, chunk3TN5SUQR_js.DEFAULT_STROKE_COLOR);
14341
+ const strokePaint = chunk3TN5SUQR_js.colorWithOpacity(strokeColor, ss?.strokeOpacity);
14342
+ const dashType = chunk3TN5SUQR_js.normalizeStrokeDashType(ss?.strokeDash);
14343
+ const dashArray = chunk3TN5SUQR_js.getSvgStrokeDasharray(
14361
14344
  dashType,
14362
14345
  Math.max(strokeWidth, 1),
14363
14346
  ss?.customDashSegments
@@ -14368,14 +14351,14 @@ var ConnectorElementRendererMemo = /* @__PURE__ */ React17__default.default.memo
14368
14351
  const markerSeed = el.id.replace(/[^a-zA-Z0-9_-]/gu, "_");
14369
14352
  const startMarkerId = `${markerSeed}-sel-start`;
14370
14353
  const endMarkerId = `${markerSeed}-sel-end`;
14371
- const compoundOffsets = chunkZ22RD3E2_js.getCompoundLineOffsets(compoundLine, strokeWidth);
14372
- const compoundWidths = chunkZ22RD3E2_js.getCompoundLineWidths(compoundLine, strokeWidth);
14354
+ const compoundOffsets = chunk3TN5SUQR_js.getCompoundLineOffsets(compoundLine, strokeWidth);
14355
+ const compoundWidths = chunk3TN5SUQR_js.getCompoundLineWidths(compoundLine, strokeWidth);
14373
14356
  const strokeCap = pptx.svgLineCap(ss?.lineCap);
14374
14357
  const textEl = pptx$1.hasTextProperties(el) ? el : void 0;
14375
14358
  const connectorText = textEl?.text?.trim() ?? "";
14376
14359
  const connectorTextSegments = textEl?.textSegments;
14377
14360
  const connectorTextStyle = textEl?.textStyle;
14378
- const pathGeometry = shapeEl ? chunkZ22RD3E2_js.getConnectorPathGeometry(shapeEl) : {
14361
+ const pathGeometry = shapeEl ? chunk3TN5SUQR_js.getConnectorPathGeometry(shapeEl) : {
14379
14362
  pathData: `M 0 0 L ${viewWidth} ${viewHeight}`,
14380
14363
  startX: 0,
14381
14364
  startY: 0,
@@ -14384,16 +14367,16 @@ var ConnectorElementRendererMemo = /* @__PURE__ */ React17__default.default.memo
14384
14367
  };
14385
14368
  const hitTargetWidth = Math.max(strokeWidth * 3, 14);
14386
14369
  const selColor = selClr === "blue-400" ? "#60a5fa" : "#3b82f6";
14387
- const lineShadow = chunkZ22RD3E2_js.buildLineShadowCss(el);
14388
- const lineGlow = chunkZ22RD3E2_js.buildLineGlowFilter(el);
14370
+ const lineShadow = chunk3TN5SUQR_js.buildLineShadowCss(el);
14371
+ const lineGlow = chunk3TN5SUQR_js.buildLineGlowFilter(el);
14389
14372
  return /* @__PURE__ */ jsxRuntime.jsxs(
14390
14373
  "div",
14391
14374
  {
14392
14375
  "data-pptx-element": "true",
14393
14376
  "data-element-id": el.id,
14394
- role: chunkZ22RD3E2_js.getAriaRole(el, { actionable: false }),
14395
- "aria-label": chunkZ22RD3E2_js.getAriaLabel(el),
14396
- "aria-roledescription": chunkZ22RD3E2_js.getAriaRoleDescription(el),
14377
+ role: chunk3TN5SUQR_js.getAriaRole(el, { actionable: false }),
14378
+ "aria-label": chunk3TN5SUQR_js.getAriaLabel(el),
14379
+ "aria-roledescription": chunk3TN5SUQR_js.getAriaRoleDescription(el),
14397
14380
  "aria-selected": isSelected ? true : void 0,
14398
14381
  className: "absolute",
14399
14382
  style: {
@@ -14426,14 +14409,14 @@ var ConnectorElementRendererMemo = /* @__PURE__ */ React17__default.default.memo
14426
14409
  style: { overflow: "visible", pointerEvents: "none" },
14427
14410
  children: [
14428
14411
  /* @__PURE__ */ jsxRuntime.jsxs("defs", { children: [
14429
- chunkZ22RD3E2_js.renderConnectorMarker(
14412
+ chunk3TN5SUQR_js.renderConnectorMarker(
14430
14413
  startMarkerId,
14431
14414
  startArrow,
14432
14415
  strokePaint,
14433
14416
  ss?.connectorStartArrowWidth,
14434
14417
  ss?.connectorStartArrowLength
14435
14418
  ),
14436
- chunkZ22RD3E2_js.renderConnectorMarker(
14419
+ chunk3TN5SUQR_js.renderConnectorMarker(
14437
14420
  endMarkerId,
14438
14421
  endArrow,
14439
14422
  strokePaint,
@@ -14642,14 +14625,14 @@ function getElementInteractionProps({
14642
14625
  };
14643
14626
  }
14644
14627
  function renderDagDuotoneFilterForElement(el) {
14645
- if (!chunkZ22RD3E2_js.hasDagDuotoneEffect(el)) {
14628
+ if (!chunk3TN5SUQR_js.hasDagDuotoneEffect(el)) {
14646
14629
  return null;
14647
14630
  }
14648
14631
  const duotone = el.shapeStyle?.dagDuotone;
14649
14632
  if (!duotone) {
14650
14633
  return null;
14651
14634
  }
14652
- return chunkZ22RD3E2_js.renderDagDuotoneSvgFilter(el.id, duotone.color1, duotone.color2);
14635
+ return chunk3TN5SUQR_js.renderDagDuotoneSvgFilter(el.id, duotone.color1, duotone.color2);
14653
14636
  }
14654
14637
  function getContainerStyle({
14655
14638
  el,
@@ -14676,10 +14659,10 @@ function getContainerStyle({
14676
14659
  top: isFullscreenMedia ? fs.top : el.y,
14677
14660
  width: isFullscreenMedia ? fs.width : painted.width,
14678
14661
  ...heightStyle,
14679
- transform: isFullscreenMedia ? fs.transform : chunkZ22RD3E2_js.getElementTransform(el),
14662
+ transform: isFullscreenMedia ? fs.transform : chunk3TN5SUQR_js.getElementTransform(el),
14680
14663
  transformOrigin: "center",
14681
14664
  overflow: overflowValue,
14682
- clipPath: isPicture ? void 0 : isImg && !has3DExtrusion ? chunkZ22RD3E2_js.getCropShapeClipPath(el) : void 0,
14665
+ clipPath: isPicture ? void 0 : isImg && !has3DExtrusion ? chunk3TN5SUQR_js.getCropShapeClipPath(el) : void 0,
14683
14666
  zIndex: isFullscreenMedia ? fs.zIndex : zIndex,
14684
14667
  visibility: animationState?.visible === false ? "hidden" : "visible",
14685
14668
  animation: animationState?.cssAnimation,
@@ -14716,9 +14699,9 @@ function getContainerStyle({
14716
14699
  function shapeParams(element) {
14717
14700
  const style = pptx$1.hasShapeProperties(element) ? element.shapeStyle : void 0;
14718
14701
  const strokeWidth = pptx.paintedStrokeWidth(style);
14719
- const strokeColor = chunkZ22RD3E2_js.normalizeHexColor(style?.strokeColor, chunkZ22RD3E2_js.DEFAULT_STROKE_COLOR);
14720
- const fillColor = chunkZ22RD3E2_js.normalizeHexColor(style?.fillColor, chunkZ22RD3E2_js.DEFAULT_FILL_COLOR);
14721
- const hasFill = style?.fillColor !== void 0 && style.fillColor !== "transparent" || Boolean(chunkZ22RD3E2_js.buildCssGradientFromShapeStyle(style) || style?.fillGradient) || style?.fillMode === "pattern" && Boolean(style.fillPatternPreset);
14702
+ const strokeColor = chunk3TN5SUQR_js.normalizeHexColor(style?.strokeColor, chunk3TN5SUQR_js.DEFAULT_STROKE_COLOR);
14703
+ const fillColor = chunk3TN5SUQR_js.normalizeHexColor(style?.fillColor, chunk3TN5SUQR_js.DEFAULT_FILL_COLOR);
14704
+ const hasFill = style?.fillColor !== void 0 && style.fillColor !== "transparent" || Boolean(chunk3TN5SUQR_js.buildCssGradientFromShapeStyle(style) || style?.fillGradient) || style?.fillMode === "pattern" && Boolean(style.fillPatternPreset);
14722
14705
  return { hf: hasFill, fc: fillColor, sw: strokeWidth, sc: strokeColor };
14723
14706
  }
14724
14707
  var Extrusion3DOverlayMemo = /* @__PURE__ */ React17__default.default.memo(
@@ -14826,7 +14809,7 @@ function ShapeEffectOverlay({
14826
14809
  const fillOverlayStyle = overlay ? {
14827
14810
  position: "absolute",
14828
14811
  inset: 0,
14829
- ...pptx$1.isImageLikeElement(element) ? chunkZ22RD3E2_js.getImageSurfaceMaskStyle(element) : {},
14812
+ ...pptx$1.isImageLikeElement(element) ? chunk3TN5SUQR_js.getImageSurfaceMaskStyle(element) : {},
14830
14813
  background: overlay.color,
14831
14814
  mixBlendMode: overlay.blendMode,
14832
14815
  pointerEvents: "none"
@@ -14910,7 +14893,7 @@ function ShapeEffectOverlay({
14910
14893
  strokeOutline.strands.map((strand, idx) => /* @__PURE__ */ jsxRuntime.jsx(
14911
14894
  "path",
14912
14895
  {
14913
- d: strokeOutline.d,
14896
+ d: strand.d ?? strokeOutline.d,
14914
14897
  markerStart: idx === 0 ? strokeOutline.markers?.start : void 0,
14915
14898
  markerEnd: idx === 0 ? strokeOutline.markers?.end : void 0,
14916
14899
  fill: "none",
@@ -15033,10 +15016,10 @@ var ElementRenderer = /* @__PURE__ */ React17__default.default.memo(
15033
15016
  const backgroundAnimationState = pptx.getBackgroundAnimationState(el, presentationElementStates);
15034
15017
  const effectPlacement = pptx.getShapeEffectLayerPlacement(el);
15035
15018
  const visualAnimationState = backgroundAnimationState ?? animationState;
15036
- const isTxt = chunkZ22RD3E2_js.isEditableTextElement(el) && allow.textEditable;
15019
+ const isTxt = chunk3TN5SUQR_js.isEditableTextElement(el) && allow.textEditable;
15037
15020
  const txtSE = pptx$1.hasTextProperties(el) ? el.textStyle : void 0;
15038
15021
  const textStyleOverrideCss = pptx.buildTextStyleOverrideCss(el.id, visualAnimationState?.textStyle);
15039
- const ss = chunkZ22RD3E2_js.getShapeVisualStyle(
15022
+ const ss = chunk3TN5SUQR_js.getShapeVisualStyle(
15040
15023
  el,
15041
15024
  hf,
15042
15025
  fc,
@@ -15045,9 +15028,9 @@ var ElementRenderer = /* @__PURE__ */ React17__default.default.memo(
15045
15028
  visualAnimationState?.animatesFill,
15046
15029
  visualAnimationState?.animatesStroke
15047
15030
  );
15048
- const ts = chunkZ22RD3E2_js.getTextStyleForElement(el, chunkZ22RD3E2_js.DEFAULT_TEXT_COLOR);
15031
+ const ts = chunk3TN5SUQR_js.getTextStyleForElement(el, chunk3TN5SUQR_js.DEFAULT_TEXT_COLOR);
15049
15032
  const isImg = el.type === "picture" || el.type === "image";
15050
- const vs = chunkZ22RD3E2_js.renderVectorShape(
15033
+ const vs = chunk3TN5SUQR_js.renderVectorShape(
15051
15034
  el,
15052
15035
  isImg ? false : hf,
15053
15036
  fc,
@@ -15057,10 +15040,10 @@ var ElementRenderer = /* @__PURE__ */ React17__default.default.memo(
15057
15040
  visualAnimationState?.animatesStroke
15058
15041
  );
15059
15042
  const isModel3D = el.type === "model3d";
15060
- const isConn = chunkZ22RD3E2_js.isConnectorOrLineElement(el);
15043
+ const isConn = chunk3TN5SUQR_js.isConnectorOrLineElement(el);
15061
15044
  const shapeStyle3d = pptx$1.hasShapeProperties(el) ? el.shapeStyle : void 0;
15062
15045
  const extrusionData = React17.useMemo(
15063
- () => chunkZ22RD3E2_js.build3DExtrusionData(shapeStyle3d?.shape3d, shapeStyle3d?.scene3d, fc, el.width, el.height),
15046
+ () => chunk3TN5SUQR_js.build3DExtrusionData(shapeStyle3d?.shape3d, shapeStyle3d?.scene3d, fc, el.width, el.height),
15064
15047
  [shapeStyle3d?.shape3d, shapeStyle3d?.scene3d, fc, el.width, el.height]
15065
15048
  );
15066
15049
  const actionAffordance = useActionAffordance(el, canInteract);
@@ -15150,7 +15133,7 @@ var ElementRenderer = /* @__PURE__ */ React17__default.default.memo(
15150
15133
  "aria-hidden": aria.hidden ? true : void 0,
15151
15134
  "aria-selected": isSelected ? true : void 0,
15152
15135
  tabIndex: isFocusable ? 0 : -1,
15153
- className: chunkZ22RD3E2_js.cn(
15136
+ className: chunk3TN5SUQR_js.cn(
15154
15137
  "absolute",
15155
15138
  "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500",
15156
15139
  cur,
@@ -15223,9 +15206,9 @@ var ElementRenderer = /* @__PURE__ */ React17__default.default.memo(
15223
15206
  txtSE,
15224
15207
  txtS: ts,
15225
15208
  vecShape: backgroundAnimationState && !isImg ? null : vs,
15226
- imgStyle: chunkZ22RD3E2_js.getImageRenderStyle(el),
15227
- imgFilter: chunkZ22RD3E2_js.getImageEffectsFilter(el),
15228
- imgOpacity: chunkZ22RD3E2_js.getImageEffectsOpacity(el),
15209
+ imgStyle: chunk3TN5SUQR_js.getImageRenderStyle(el),
15210
+ imgFilter: chunk3TN5SUQR_js.getImageEffectsFilter(el),
15211
+ imgOpacity: chunk3TN5SUQR_js.getImageEffectsOpacity(el),
15229
15212
  imgAlt: imageAltText,
15230
15213
  isTxtEl: isTxt,
15231
15214
  media: mediaDataUrls,
@@ -15362,10 +15345,10 @@ function renderStrokeView(view, pressureSensitive, replayStyle, key) {
15362
15345
  }
15363
15346
  function renderInk(el, options) {
15364
15347
  const replay = options?.replay ?? false;
15365
- const strokes = chunkZ22RD3E2_js.buildInkGroupStrokes(el, { color: "#000", width: 3 });
15348
+ const strokes = chunk3TN5SUQR_js.buildInkGroupStrokes(el, { color: "#000", width: 3 });
15366
15349
  strokes.some((s) => s.circles || s.nibMarks);
15367
15350
  const pressureSensitive = options?.pressureSensitive;
15368
- const replayStyles = replay ? chunkZ22RD3E2_js.getInkReplayStyles(el, options?.replayConfig) : null;
15351
+ const replayStyles = replay ? chunk3TN5SUQR_js.getInkReplayStyles(el, options?.replayConfig) : null;
15369
15352
  return /* @__PURE__ */ jsxRuntime.jsxs(
15370
15353
  "svg",
15371
15354
  {
@@ -15373,7 +15356,7 @@ function renderInk(el, options) {
15373
15356
  viewBox: `0 0 ${Math.max(el.width, 1)} ${Math.max(el.height, 1)}`,
15374
15357
  preserveAspectRatio: "none",
15375
15358
  children: [
15376
- replay && /* @__PURE__ */ jsxRuntime.jsx("style", { children: chunkZ22RD3E2_js.INK_REPLAY_KEYFRAMES }),
15359
+ replay && /* @__PURE__ */ jsxRuntime.jsx("style", { children: chunk3TN5SUQR_js.INK_REPLAY_KEYFRAMES }),
15377
15360
  strokes.map(
15378
15361
  (s, i) => renderStrokeView(s, pressureSensitive, replayStyles?.[i], `${el.id}-ink-${i}`)
15379
15362
  )
@@ -15384,7 +15367,7 @@ function renderInk(el, options) {
15384
15367
  function renderGroup(children, parentGroupFill) {
15385
15368
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative w-full h-full pointer-events-none", children: pptx.filterRenderedElements(children).map((c, childIndex) => {
15386
15369
  const { hf, fc, sw, sc } = shapeParams(c);
15387
- const baseSs = chunkZ22RD3E2_js.getShapeVisualStyle(c, hf, fc, sw, sc);
15370
+ const baseSs = chunk3TN5SUQR_js.getShapeVisualStyle(c, hf, fc, sw, sc);
15388
15371
  const inheritedFill = pptx.resolveGroupChildFill(c, parentGroupFill);
15389
15372
  const ss = inheritedFill ? {
15390
15373
  ...baseSs,
@@ -15395,9 +15378,9 @@ function renderGroup(children, parentGroupFill) {
15395
15378
  backgroundPosition: inheritedFill.backgroundPosition
15396
15379
  } : baseSs;
15397
15380
  const isI = c.type === "picture" || c.type === "image";
15398
- const vs = chunkZ22RD3E2_js.renderVectorShape(c, isI ? false : hf, fc, sw, sc);
15399
- const ts = chunkZ22RD3E2_js.getTextStyleForElement(c, chunkZ22RD3E2_js.DEFAULT_TEXT_COLOR);
15400
- const isTxt = chunkZ22RD3E2_js.isEditableTextElement(c);
15381
+ const vs = chunk3TN5SUQR_js.renderVectorShape(c, isI ? false : hf, fc, sw, sc);
15382
+ const ts = chunk3TN5SUQR_js.getTextStyleForElement(c, chunk3TN5SUQR_js.DEFAULT_TEXT_COLOR);
15383
+ const isTxt = chunk3TN5SUQR_js.isEditableTextElement(c);
15401
15384
  return /* @__PURE__ */ jsxRuntime.jsxs(
15402
15385
  "div",
15403
15386
  {
@@ -15406,9 +15389,9 @@ function renderGroup(children, parentGroupFill) {
15406
15389
  style: {
15407
15390
  left: c.x,
15408
15391
  top: c.y,
15409
- width: Math.max(c.width, chunkZ22RD3E2_js.MIN_ELEMENT_SIZE),
15410
- height: Math.max(c.height, chunkZ22RD3E2_js.MIN_ELEMENT_SIZE),
15411
- transform: chunkZ22RD3E2_js.getElementTransform(c),
15392
+ width: Math.max(c.width, chunk3TN5SUQR_js.MIN_ELEMENT_SIZE),
15393
+ height: Math.max(c.height, chunk3TN5SUQR_js.MIN_ELEMENT_SIZE),
15394
+ transform: chunk3TN5SUQR_js.getElementTransform(c),
15412
15395
  transformOrigin: "center",
15413
15396
  ...ss,
15414
15397
  ...isI ? {
@@ -15433,8 +15416,8 @@ function renderGroup(children, parentGroupFill) {
15433
15416
  // A nested group: recurse, chaining the inherited fill so a
15434
15417
  // `grpFill` shape under a fill-less sub-group still paints.
15435
15418
  renderGroup(c.children, pptx.getGroupChildParentFill(c, parentGroupFill))
15436
- ) : isI && ("svgData" in c && c.svgData || "imageData" in c && c.imageData) ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute inset-0 pointer-events-none", style: chunkZ22RD3E2_js.getImageSurfaceStyle(c), children: [
15437
- chunkZ22RD3E2_js.isImageTiled(c) ? /* @__PURE__ */ jsxRuntime.jsx(
15419
+ ) : isI && ("svgData" in c && c.svgData || "imageData" in c && c.imageData) ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute inset-0 pointer-events-none", style: chunk3TN5SUQR_js.getImageSurfaceStyle(c), children: [
15420
+ chunk3TN5SUQR_js.isImageTiled(c) ? /* @__PURE__ */ jsxRuntime.jsx(
15438
15421
  TiledImageLayer,
15439
15422
  {
15440
15423
  element: c,
@@ -15447,7 +15430,7 @@ function renderGroup(children, parentGroupFill) {
15447
15430
  src: "svgData" in c && c.svgData ? c.svgData : c.imageData,
15448
15431
  alt: i18n.translationsEn["pptx.ink.groupChildAlt"],
15449
15432
  className: "pointer-events-none select-none",
15450
- style: chunkZ22RD3E2_js.getImageRenderStyle(c),
15433
+ style: chunk3TN5SUQR_js.getImageRenderStyle(c),
15451
15434
  draggable: false
15452
15435
  }
15453
15436
  ),
@@ -15459,7 +15442,7 @@ function renderGroup(children, parentGroupFill) {
15459
15442
  {
15460
15443
  className: "relative z-10 w-full h-full pointer-events-none whitespace-pre-wrap break-words leading-[1.3]",
15461
15444
  style: ts,
15462
- children: chunkZ22RD3E2_js.renderTextSegments(c, chunkZ22RD3E2_js.DEFAULT_TEXT_COLOR)
15445
+ children: chunk3TN5SUQR_js.renderTextSegments(c, chunk3TN5SUQR_js.DEFAULT_TEXT_COLOR)
15463
15446
  }
15464
15447
  ) : null
15465
15448
  ] })
@@ -15473,8 +15456,8 @@ function renderContentPart(el, options) {
15473
15456
  if (el.inkStrokes && el.inkStrokes.length > 0) {
15474
15457
  const replay = options?.replay ?? false;
15475
15458
  const pressureSensitive = options?.pressureSensitive ?? true;
15476
- const strokes = chunkZ22RD3E2_js.buildContentPartStrokes(el);
15477
- const replayStyles = replay ? chunkZ22RD3E2_js.getContentPartReplayStyles(el.inkStrokes, options?.replayConfig) : null;
15459
+ const strokes = chunk3TN5SUQR_js.buildContentPartStrokes(el);
15460
+ const replayStyles = replay ? chunk3TN5SUQR_js.getContentPartReplayStyles(el.inkStrokes, options?.replayConfig) : null;
15478
15461
  return /* @__PURE__ */ jsxRuntime.jsxs(
15479
15462
  "svg",
15480
15463
  {
@@ -15482,7 +15465,7 @@ function renderContentPart(el, options) {
15482
15465
  viewBox: `0 0 ${Math.max(el.width, 1)} ${Math.max(el.height, 1)}`,
15483
15466
  preserveAspectRatio: "none",
15484
15467
  children: [
15485
- replay && /* @__PURE__ */ jsxRuntime.jsx("style", { children: chunkZ22RD3E2_js.INK_REPLAY_KEYFRAMES }),
15468
+ replay && /* @__PURE__ */ jsxRuntime.jsx("style", { children: chunk3TN5SUQR_js.INK_REPLAY_KEYFRAMES }),
15486
15469
  strokes.map(
15487
15470
  (s, i) => renderStrokeView(s, pressureSensitive, replayStyles?.[i], `${el.id}-cp-ink-${i}`)
15488
15471
  )
@@ -15709,9 +15692,9 @@ function useInlineListEditor(element, rootRef, onChange, onModelReplacement) {
15709
15692
  collaboration: connected,
15710
15693
  model: pptx.createInlineListModelObserver(element),
15711
15694
  activationSelection,
15712
- children: seed && !connected ? chunkZ22RD3E2_js.renderTextSegments(
15695
+ children: seed && !connected ? chunk3TN5SUQR_js.renderTextSegments(
15713
15696
  element,
15714
- chunkZ22RD3E2_js.DEFAULT_TEXT_COLOR,
15697
+ chunk3TN5SUQR_js.DEFAULT_TEXT_COLOR,
15715
15698
  void 0,
15716
15699
  void 0,
15717
15700
  void 0,
@@ -15947,8 +15930,8 @@ function InlineTextEditor({
15947
15930
  pending.endOffset
15948
15931
  );
15949
15932
  });
15950
- const warpStyle = chunkZ22RD3E2_js.getTextWarpStyle(textStyleRaw);
15951
- const compensationTransform = chunkZ22RD3E2_js.getTextCompensationTransform(element);
15933
+ const warpStyle = chunk3TN5SUQR_js.getTextWarpStyle(textStyleRaw);
15934
+ const compensationTransform = chunk3TN5SUQR_js.getTextCompensationTransform(element);
15952
15935
  const warpTransform = warpStyle?.transform;
15953
15936
  const mergedTransform = [compensationTransform, warpTransform].filter(Boolean).join(" ") || void 0;
15954
15937
  const wrapperStyle = {
@@ -16036,7 +16019,7 @@ function InlineTextEditor({
16036
16019
  const text = e.clipboardData.getData("text/plain");
16037
16020
  document.execCommand("insertText", false, text);
16038
16021
  },
16039
- children: list.seed ? list.children : seed.hasRichSegments ? chunkZ22RD3E2_js.renderTextSegments(element, chunkZ22RD3E2_js.DEFAULT_TEXT_COLOR) : seed.initialText
16022
+ children: list.seed ? list.children : seed.hasRichSegments ? chunk3TN5SUQR_js.renderTextSegments(element, chunk3TN5SUQR_js.DEFAULT_TEXT_COLOR) : seed.initialText
16040
16023
  },
16041
16024
  list.seed?.paragraphs[0].token ?? "plain"
16042
16025
  );
@@ -16201,7 +16184,7 @@ function OleActionFooter({
16201
16184
  info,
16202
16185
  showActions
16203
16186
  }) {
16204
- const { t } = chunkZ22RD3E2_js.useTranslation();
16187
+ const { t } = chunk3TN5SUQR_js.useTranslation();
16205
16188
  if (!showActions || !info.canDownload || !el.oleEmbeddedData) {
16206
16189
  return null;
16207
16190
  }
@@ -16310,7 +16293,7 @@ function SmartArtInlineNodeEditor({
16310
16293
  onCommit,
16311
16294
  onCancel
16312
16295
  }) {
16313
- const { t } = chunkZ22RD3E2_js.useTranslation();
16296
+ const { t } = chunk3TN5SUQR_js.useTranslation();
16314
16297
  const ref = React17__default.default.useRef(null);
16315
16298
  const [value, setValue] = React17__default.default.useState(initialText);
16316
16299
  const settled = React17__default.default.useRef(false);
@@ -16937,7 +16920,7 @@ function SmartArtRendererImpl({
16937
16920
  onUpdateElement,
16938
16921
  animationState
16939
16922
  }) {
16940
- const { t } = chunkZ22RD3E2_js.useTranslation();
16923
+ const { t } = chunk3TN5SUQR_js.useTranslation();
16941
16924
  if (element.type !== "smartArt" || !element.smartArtData) {
16942
16925
  return /* @__PURE__ */ jsxRuntime.jsx(
16943
16926
  "div",
@@ -17183,7 +17166,7 @@ function groupIntoParagraphs(element, fieldContext) {
17183
17166
  element,
17184
17167
  fieldContext ? (seg) => {
17185
17168
  if (seg.fieldType) {
17186
- const substituted = chunkZ22RD3E2_js.substituteFieldText(
17169
+ const substituted = chunk3TN5SUQR_js.substituteFieldText(
17187
17170
  seg.text,
17188
17171
  seg.fieldType,
17189
17172
  fieldContext,
@@ -17218,13 +17201,13 @@ function getSegmentTspanProps(segment, element, fallbackColor) {
17218
17201
  if (s.strikethrough) {
17219
17202
  decos.push("line-through");
17220
17203
  }
17221
- const fill = s.hyperlink ? chunkZ22RD3E2_js.normalizeHexColor(s.color || element.textStyle?.color, chunkZ22RD3E2_js.HYPERLINK_COLOR) : chunkZ22RD3E2_js.normalizeHexColor(s.color || element.textStyle?.color, fallbackColor);
17204
+ const fill = s.hyperlink ? chunk3TN5SUQR_js.normalizeHexColor(s.color || element.textStyle?.color, chunk3TN5SUQR_js.HYPERLINK_COLOR) : chunk3TN5SUQR_js.normalizeHexColor(s.color || element.textStyle?.color, fallbackColor);
17222
17205
  return {
17223
17206
  fill,
17224
- fontSize: s.fontSize ?? element.textStyle?.fontSize ?? chunkZ22RD3E2_js.DEFAULT_TEXT_FONT_SIZE,
17207
+ fontSize: s.fontSize ?? element.textStyle?.fontSize ?? chunk3TN5SUQR_js.DEFAULT_TEXT_FONT_SIZE,
17225
17208
  fontWeight: pptx.resolveFontWeight(s.fontFamily || element.textStyle?.fontFamily, s.bold),
17226
17209
  fontStyle: pptx.resolveFontItalic(s.fontFamily || element.textStyle?.fontFamily, s.italic) ? "italic" : void 0,
17227
- fontFamily: s.fontFamily || element.textStyle?.fontFamily ? pptx$1.getSubstituteFontFamily(s.fontFamily || element.textStyle?.fontFamily || "") : chunkZ22RD3E2_js.DEFAULT_FONT_FAMILY,
17210
+ fontFamily: s.fontFamily || element.textStyle?.fontFamily ? pptx$1.getSubstituteFontFamily(s.fontFamily || element.textStyle?.fontFamily || "") : chunk3TN5SUQR_js.DEFAULT_FONT_FAMILY,
17228
17211
  textDecoration: decos.length > 0 ? decos.join(" ") : void 0
17229
17212
  };
17230
17213
  }
@@ -17232,8 +17215,8 @@ function resolveSegmentFont(segment, element) {
17232
17215
  const s = segment.style || {};
17233
17216
  const family = s.fontFamily || element.textStyle?.fontFamily;
17234
17217
  return {
17235
- fontFamily: family ? pptx$1.getSubstituteFontFamily(family) : chunkZ22RD3E2_js.DEFAULT_FONT_FAMILY,
17236
- fontSizePx: s.fontSize ?? element.textStyle?.fontSize ?? chunkZ22RD3E2_js.DEFAULT_TEXT_FONT_SIZE,
17218
+ fontFamily: family ? pptx$1.getSubstituteFontFamily(family) : chunk3TN5SUQR_js.DEFAULT_FONT_FAMILY,
17219
+ fontSizePx: s.fontSize ?? element.textStyle?.fontSize ?? chunk3TN5SUQR_js.DEFAULT_TEXT_FONT_SIZE,
17237
17220
  bold: s.bold ?? element.textStyle?.bold,
17238
17221
  italic: s.italic ?? element.textStyle?.italic
17239
17222
  };
@@ -17317,9 +17300,9 @@ function WarpedText({
17317
17300
  const warpAdj2 = textEl.textStyle?.textWarpAdj2;
17318
17301
  const align = textEl.textStyle?.align ?? "center";
17319
17302
  const { startOffset, textAnchor } = getAlignmentProps(align);
17320
- const baseFontSize = textEl.textStyle?.fontSize ?? chunkZ22RD3E2_js.DEFAULT_TEXT_FONT_SIZE;
17321
- const baseFontFamily = textEl.textStyle?.fontFamily ? pptx$1.getSubstituteFontFamily(textEl.textStyle.fontFamily) : chunkZ22RD3E2_js.DEFAULT_FONT_FAMILY;
17322
- const baseFill = chunkZ22RD3E2_js.normalizeHexColor(textEl.textStyle?.color, fallbackColor);
17303
+ const baseFontSize = textEl.textStyle?.fontSize ?? chunk3TN5SUQR_js.DEFAULT_TEXT_FONT_SIZE;
17304
+ const baseFontFamily = textEl.textStyle?.fontFamily ? pptx$1.getSubstituteFontFamily(textEl.textStyle.fontFamily) : chunk3TN5SUQR_js.DEFAULT_FONT_FAMILY;
17305
+ const baseFill = chunk3TN5SUQR_js.normalizeHexColor(textEl.textStyle?.color, fallbackColor);
17323
17306
  if (pptx.hasGlyphEnvelope(preset)) {
17324
17307
  const perLine = pptx.buildGlyphEnvelopeBlock(
17325
17308
  preset,
@@ -17421,7 +17404,7 @@ function WarpedText({
17421
17404
  var GLYPH_BY_SHAPE = /* @__PURE__ */ buildGlyphByShape();
17422
17405
  function buildGlyphByShape() {
17423
17406
  const glyphs = Object.fromEntries(
17424
- chunkZ22RD3E2_js.ACTION_BUTTON_PRESETS.map((p) => [p.shapeType, p.iconPath])
17407
+ chunk3TN5SUQR_js.ACTION_BUTTON_PRESETS.map((p) => [p.shapeType, p.iconPath])
17425
17408
  );
17426
17409
  glyphs["actionButtonForwardOrNext"] = glyphs["actionButtonForwardNext"];
17427
17410
  glyphs["actionButtonBackOrPrevious"] = glyphs["actionButtonBackPrevious"];
@@ -17495,9 +17478,9 @@ function renderTextElementBody(options) {
17495
17478
  const useSvgWarp = pptx.shouldUseSvgWarp(
17496
17479
  pptx$1.hasTextProperties(el) ? el.textStyle?.textWarpPreset : void 0
17497
17480
  );
17498
- const scene3dStyle = pptx$1.hasTextProperties(el) ? chunkZ22RD3E2_js.buildTextBody3DSceneStyle(el.textStyle, { width: el.width, height: el.height }) : void 0;
17481
+ const scene3dStyle = pptx$1.hasTextProperties(el) ? chunk3TN5SUQR_js.buildTextBody3DSceneStyle(el.textStyle, { width: el.width, height: el.height }) : void 0;
17499
17482
  const rotationTransform = pptx.getTextBodyRotationTransform(el);
17500
- const composedTransform = [rotationTransform, chunkZ22RD3E2_js.getTextCompensationTransform(el), scene3dStyle?.transform].filter(Boolean).join(" ") || void 0;
17483
+ const composedTransform = [rotationTransform, chunk3TN5SUQR_js.getTextCompensationTransform(el), scene3dStyle?.transform].filter(Boolean).join(" ") || void 0;
17501
17484
  const transformStyle = {
17502
17485
  transform: composedTransform,
17503
17486
  // A COM-measured homography (`scene3dStyle.transformOrigin === '0 0'`)
@@ -17527,18 +17510,18 @@ function renderTextElementBody(options) {
17527
17510
  shouldRenderText && (useSvgWarp ? /* @__PURE__ */ jsxRuntime.jsx(
17528
17511
  "div",
17529
17512
  {
17530
- className: chunkZ22RD3E2_js.cn(
17513
+ className: chunk3TN5SUQR_js.cn(
17531
17514
  "relative z-10 w-full h-full",
17532
17515
  onHyperlinkClick ? "" : "pointer-events-none"
17533
17516
  ),
17534
- style: { ...chunkZ22RD3E2_js.getTextLayoutStyle(el), ...transformStyle },
17517
+ style: { ...chunk3TN5SUQR_js.getTextLayoutStyle(el), ...transformStyle },
17535
17518
  children: /* @__PURE__ */ jsxRuntime.jsx(
17536
17519
  WarpedText,
17537
17520
  {
17538
17521
  element: el,
17539
17522
  width: el.width,
17540
17523
  height: el.height,
17541
- fallbackColor: chunkZ22RD3E2_js.DEFAULT_TEXT_COLOR,
17524
+ fallbackColor: chunk3TN5SUQR_js.DEFAULT_TEXT_COLOR,
17542
17525
  findHighlights: findHl,
17543
17526
  fieldContext
17544
17527
  }
@@ -17547,19 +17530,19 @@ function renderTextElementBody(options) {
17547
17530
  ) : /* @__PURE__ */ jsxRuntime.jsx(
17548
17531
  "div",
17549
17532
  {
17550
- className: chunkZ22RD3E2_js.cn(
17533
+ className: chunk3TN5SUQR_js.cn(
17551
17534
  "relative z-10 w-full h-full whitespace-pre-wrap break-words leading-[1.3]",
17552
17535
  onHyperlinkClick ? "" : "pointer-events-none"
17553
17536
  ),
17554
17537
  style: {
17555
- ...chunkZ22RD3E2_js.getTextLayoutStyle(el),
17538
+ ...chunk3TN5SUQR_js.getTextLayoutStyle(el),
17556
17539
  ...txtS,
17557
- ...chunkZ22RD3E2_js.getTextWarpStyle(txtSE),
17540
+ ...chunk3TN5SUQR_js.getTextWarpStyle(txtSE),
17558
17541
  ...transformStyle
17559
17542
  },
17560
- children: chunkZ22RD3E2_js.renderTextSegments(
17543
+ children: chunk3TN5SUQR_js.renderTextSegments(
17561
17544
  el,
17562
- chunkZ22RD3E2_js.DEFAULT_TEXT_COLOR,
17545
+ chunk3TN5SUQR_js.DEFAULT_TEXT_COLOR,
17563
17546
  void 0,
17564
17547
  findHl,
17565
17548
  onHyperlinkClick,
@@ -17580,7 +17563,7 @@ function ZoomElementRenderer({
17580
17563
  onZoomClick,
17581
17564
  sourceSlideIndex
17582
17565
  }) {
17583
- const { t } = chunkZ22RD3E2_js.useTranslation();
17566
+ const { t } = chunk3TN5SUQR_js.useTranslation();
17584
17567
  const summaryView = pptx.buildSummaryZoomView(
17585
17568
  element,
17586
17569
  (index) => {
@@ -17878,7 +17861,7 @@ function renderBody(options) {
17878
17861
  );
17879
17862
  }
17880
17863
  if (isImg) {
17881
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute inset-0 pointer-events-none", style: chunkZ22RD3E2_js.getImageSurfaceStyle(el), children: [
17864
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute inset-0 pointer-events-none", style: chunk3TN5SUQR_js.getImageSurfaceStyle(el), children: [
17882
17865
  renderImg(el, imgStyle, imgFilter, imgAlt, imgOpacity),
17883
17866
  vecShape ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-none absolute inset-0", children: vecShape }) : null
17884
17867
  ] });
@@ -17895,7 +17878,7 @@ function renderBody(options) {
17895
17878
  textDirection: txtSE?.textDirection,
17896
17879
  textStyle: txtS,
17897
17880
  textStyleRaw: txtSE,
17898
- layoutStyle: chunkZ22RD3E2_js.getTextLayoutStyle(el),
17881
+ layoutStyle: chunk3TN5SUQR_js.getTextLayoutStyle(el),
17899
17882
  element: el,
17900
17883
  onCommit,
17901
17884
  onCancel,
@@ -17906,7 +17889,7 @@ function renderBody(options) {
17906
17889
  ] });
17907
17890
  }
17908
17891
  if (el.type === "table") {
17909
- return chunkZ22RD3E2_js.renderTableElement(el, txtS, {
17892
+ return chunk3TN5SUQR_js.renderTableElement(el, txtS, {
17910
17893
  editable: isSel,
17911
17894
  selectedCell: isSel ? tableSt : null,
17912
17895
  onSelectCell: onCellSel,
@@ -17939,7 +17922,7 @@ function renderBody(options) {
17939
17922
  );
17940
17923
  }
17941
17924
  if (el.type === "media") {
17942
- return chunkZ22RD3E2_js.renderMediaElement(el, media, {
17925
+ return chunk3TN5SUQR_js.renderMediaElement(el, media, {
17943
17926
  // Present mode autoplays every media element on the active slide,
17944
17927
  // not only ones persisted with their own `autoPlay` flag (matching
17945
17928
  // the other four bindings' unconditional `presenting`-gated
@@ -17991,27 +17974,27 @@ function renderBody(options) {
17991
17974
  }
17992
17975
  return renderGroup(el.children, pptx.getGroupChildParentFill(el));
17993
17976
  }
17994
- if (chunkZ22RD3E2_js.shouldRenderFallbackLabel(el, isTxtEl)) {
17995
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center text-[11px] text-white/80 pointer-events-none", children: chunkZ22RD3E2_js.getElementLabel(el) });
17977
+ if (chunk3TN5SUQR_js.shouldRenderFallbackLabel(el, isTxtEl)) {
17978
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center text-[11px] text-white/80 pointer-events-none", children: chunk3TN5SUQR_js.getElementLabel(el) });
17996
17979
  }
17997
17980
  return renderTextElementBody(options);
17998
17981
  }
17999
17982
  function defaultTextColorForFill(fillColor) {
18000
17983
  const hex = String(fillColor ?? "").replace(/^#/u, "");
18001
17984
  if (!/^[0-9a-f]{6}$/iu.test(hex)) {
18002
- return chunkZ22RD3E2_js.DEFAULT_TEXT_COLOR;
17985
+ return chunk3TN5SUQR_js.DEFAULT_TEXT_COLOR;
18003
17986
  }
18004
17987
  const channels = [0, 2, 4].map((offset) => Number.parseInt(hex.slice(offset, offset + 2), 16) / 255).map((channel) => channel <= 0.04045 ? channel / 12.92 : ((channel + 0.055) / 1.055) ** 2.4);
18005
17988
  const luminance = channels[0] * 0.2126 + channels[1] * 0.7152 + channels[2] * 0.0722;
18006
- return luminance > 0.179 ? chunkZ22RD3E2_js.DEFAULT_TEXT_COLOR : "#ffffff";
17989
+ return luminance > 0.179 ? chunk3TN5SUQR_js.DEFAULT_TEXT_COLOR : "#ffffff";
18007
17990
  }
18008
17991
  function getStaticElementVisualState(element, parentGroupFill) {
18009
17992
  const style = pptx$1.hasShapeProperties(element) ? element.shapeStyle : void 0;
18010
- const hasFill = style?.fillColor !== void 0 && style.fillColor !== "transparent" || Boolean(chunkZ22RD3E2_js.buildCssGradientFromShapeStyle(style) || style?.fillGradient) || style?.fillMode === "pattern" && Boolean(style.fillPatternPreset);
18011
- const fill = chunkZ22RD3E2_js.normalizeHexColor(style?.fillColor, chunkZ22RD3E2_js.DEFAULT_FILL_COLOR);
17993
+ const hasFill = style?.fillColor !== void 0 && style.fillColor !== "transparent" || Boolean(chunk3TN5SUQR_js.buildCssGradientFromShapeStyle(style) || style?.fillGradient) || style?.fillMode === "pattern" && Boolean(style.fillPatternPreset);
17994
+ const fill = chunk3TN5SUQR_js.normalizeHexColor(style?.fillColor, chunk3TN5SUQR_js.DEFAULT_FILL_COLOR);
18012
17995
  const strokeWidth = pptx.paintedStrokeWidth(style);
18013
- const stroke = chunkZ22RD3E2_js.normalizeHexColor(style?.strokeColor, chunkZ22RD3E2_js.DEFAULT_STROKE_COLOR);
18014
- const baseVisualStyle = chunkZ22RD3E2_js.getShapeVisualStyle(element, hasFill, fill, strokeWidth, stroke);
17996
+ const stroke = chunk3TN5SUQR_js.normalizeHexColor(style?.strokeColor, chunk3TN5SUQR_js.DEFAULT_STROKE_COLOR);
17997
+ const baseVisualStyle = chunk3TN5SUQR_js.getShapeVisualStyle(element, hasFill, fill, strokeWidth, stroke);
18015
17998
  const inheritedFill = pptx.resolveGroupChildFill(element, parentGroupFill);
18016
17999
  const visualStyle = inheritedFill ? {
18017
18000
  ...baseVisualStyle,
@@ -18021,9 +18004,9 @@ function getStaticElementVisualState(element, parentGroupFill) {
18021
18004
  backgroundSize: inheritedFill.backgroundSize,
18022
18005
  backgroundPosition: inheritedFill.backgroundPosition
18023
18006
  } : baseVisualStyle;
18024
- const textStyle = chunkZ22RD3E2_js.getTextStyleForElement(
18007
+ const textStyle = chunk3TN5SUQR_js.getTextStyleForElement(
18025
18008
  element,
18026
- element.type === "shape" && hasFill ? defaultTextColorForFill(fill) : chunkZ22RD3E2_js.DEFAULT_TEXT_COLOR
18009
+ element.type === "shape" && hasFill ? defaultTextColorForFill(fill) : chunk3TN5SUQR_js.DEFAULT_TEXT_COLOR
18027
18010
  );
18028
18011
  const isImage = element.type === "picture" || element.type === "image";
18029
18012
  const letsTextOverflow = pptx$1.hasTextProperties(element) && element.textStyle?.autoFitMode === "shrink" && (element.type === "text" || element.locks?.txBox === true);
@@ -18048,7 +18031,7 @@ function getStaticElementInteractionState(element, hasActionHandler, exposeEleme
18048
18031
  return { action, isActionable, contractRole };
18049
18032
  }
18050
18033
  function getStaticElementWrapperClassName(element, visual, positioned, isActionable) {
18051
- const overflowClass = visual.isImage || visual.strokeWidth > 0 || element.type === "group" || chunkZ22RD3E2_js.isConnectorOrLineElement(element) || visual.isCallout || visual.letsTextOverflow ? "" : "overflow-hidden";
18034
+ const overflowClass = visual.isImage || visual.strokeWidth > 0 || element.type === "group" || chunk3TN5SUQR_js.isConnectorOrLineElement(element) || visual.isCallout || visual.letsTextOverflow ? "" : "overflow-hidden";
18052
18035
  const pointerClass = isActionable ? "pointer-events-auto cursor-pointer" : "pointer-events-none";
18053
18036
  return `${positioned ? "absolute" : "relative"} ${overflowClass} ${pointerClass}`;
18054
18037
  }
@@ -18131,7 +18114,7 @@ function StaticElementRendererImpl({
18131
18114
  top: positioned ? element.y : void 0,
18132
18115
  width: positioned ? Math.max(element.width, 1) : "100%",
18133
18116
  height: positioned ? Math.max(element.height, 1) : "100%",
18134
- transform: positioned ? chunkZ22RD3E2_js.getElementTransform(element) : void 0,
18117
+ transform: positioned ? chunk3TN5SUQR_js.getElementTransform(element) : void 0,
18135
18118
  transformOrigin: "center",
18136
18119
  zIndex,
18137
18120
  ...visualStyle,
@@ -18174,18 +18157,18 @@ function StaticElementRendererImpl({
18174
18157
  spellCheck: false,
18175
18158
  txtSE: pptx$1.hasTextProperties(element) ? element.textStyle : void 0,
18176
18159
  txtS: textStyle,
18177
- vecShape: chunkZ22RD3E2_js.renderVectorShape(
18160
+ vecShape: chunk3TN5SUQR_js.renderVectorShape(
18178
18161
  element,
18179
18162
  isImage ? false : hasFill,
18180
18163
  fill,
18181
18164
  strokeWidth,
18182
18165
  stroke
18183
18166
  ),
18184
- imgStyle: imageAnimation ? { ...chunkZ22RD3E2_js.getImageRenderStyle(element), animation: imageAnimation } : chunkZ22RD3E2_js.getImageRenderStyle(element),
18185
- imgFilter: chunkZ22RD3E2_js.getImageEffectsFilter(element),
18186
- imgOpacity: chunkZ22RD3E2_js.getImageEffectsOpacity(element),
18167
+ imgStyle: imageAnimation ? { ...chunk3TN5SUQR_js.getImageRenderStyle(element), animation: imageAnimation } : chunk3TN5SUQR_js.getImageRenderStyle(element),
18168
+ imgFilter: chunk3TN5SUQR_js.getImageEffectsFilter(element),
18169
+ imgOpacity: chunk3TN5SUQR_js.getImageEffectsOpacity(element),
18187
18170
  imgAlt: "",
18188
- isTxtEl: chunkZ22RD3E2_js.isEditableTextElement(element),
18171
+ isTxtEl: chunk3TN5SUQR_js.isEditableTextElement(element),
18189
18172
  media: mediaDataUrls,
18190
18173
  tableSt: null,
18191
18174
  isSel: false,
@@ -18233,7 +18216,7 @@ function SlideLayer({
18233
18216
  style: {
18234
18217
  width: safeWidth,
18235
18218
  height: safeHeight,
18236
- backgroundColor: slide.backgroundColor ? chunkZ22RD3E2_js.normalizeHexColor(slide.backgroundColor, "#ffffff") : "#ffffff",
18219
+ backgroundColor: slide.backgroundColor ? chunk3TN5SUQR_js.normalizeHexColor(slide.backgroundColor, "#ffffff") : "#ffffff",
18237
18220
  backgroundImage: slide.backgroundImage ? `url(${slide.backgroundImage})` : slide.backgroundGradient ? slide.backgroundGradient : void 0,
18238
18221
  backgroundSize: slide.backgroundImage ? "cover" : void 0,
18239
18222
  backgroundPosition: slide.backgroundImage ? "center" : void 0