pptx-react-viewer 2.13.1 → 2.14.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 (132) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/{AiChatPanel-FXPGFU6H.js → AiChatPanel-BJDFFVJG.js} +23 -23
  3. package/dist/AiChatPanel-BJDFFVJG.js.br +0 -0
  4. package/dist/AiChatPanel-BJDFFVJG.js.gz +0 -0
  5. package/dist/{AiChatPanel-WMGS5TNX.mjs → AiChatPanel-UJUN6HB3.mjs} +4 -4
  6. package/dist/AiChatPanel-UJUN6HB3.mjs.br +0 -0
  7. package/dist/AiChatPanel-UJUN6HB3.mjs.gz +0 -0
  8. package/dist/{Model3DScene-K5FPZTRG.js → Model3DScene-F53NQFY7.js} +2 -2
  9. package/dist/Model3DScene-F53NQFY7.js.br +0 -0
  10. package/dist/Model3DScene-F53NQFY7.js.gz +0 -0
  11. package/dist/{Model3DScene-E2XRQAMR.mjs → Model3DScene-LVFHZUVF.mjs} +1 -1
  12. package/dist/Model3DScene-LVFHZUVF.mjs.br +0 -0
  13. package/dist/Model3DScene-LVFHZUVF.mjs.gz +0 -0
  14. package/dist/{PowerPointViewer-Cjn1RgSz.d.ts → PowerPointViewer-Du7u4INi.d.ts} +2 -2
  15. package/dist/{PowerPointViewer-Cjn1RgSz.d.ts.map → PowerPointViewer-Du7u4INi.d.ts.map} +1 -1
  16. package/dist/{SurfaceChart3DScene-JDCFTXYT.js → SurfaceChart3DScene-IDJDIHVC.js} +2 -2
  17. package/dist/SurfaceChart3DScene-IDJDIHVC.js.br +0 -0
  18. package/dist/SurfaceChart3DScene-IDJDIHVC.js.gz +0 -0
  19. package/dist/{SurfaceChart3DScene-2W2IFPLE.mjs → SurfaceChart3DScene-MVBQTD6J.mjs} +1 -1
  20. package/dist/{SurfaceChart3DScene-2W2IFPLE.mjs.br → SurfaceChart3DScene-MVBQTD6J.mjs.br} +0 -0
  21. package/dist/SurfaceChart3DScene-MVBQTD6J.mjs.gz +0 -0
  22. package/dist/{audience-content-store-BMlth_3U.d.ts → audience-content-store-DaABTAcQ.d.ts} +2 -2
  23. package/dist/{audience-content-store-BMlth_3U.d.ts.map → audience-content-store-DaABTAcQ.d.ts.map} +1 -1
  24. package/dist/{chunk-CQ2CKMG4.mjs → chunk-2KRHLUCG.mjs} +37 -3
  25. package/dist/chunk-2KRHLUCG.mjs.br +0 -0
  26. package/dist/chunk-2KRHLUCG.mjs.gz +0 -0
  27. package/dist/{chunk-BXAK3JFM.js → chunk-3ISYPBSX.js} +74 -2
  28. package/dist/chunk-3ISYPBSX.js.br +0 -0
  29. package/dist/chunk-3ISYPBSX.js.gz +0 -0
  30. package/dist/{chunk-OWGPRVRK.mjs → chunk-5MMC7ZR3.mjs} +8532 -576
  31. package/dist/chunk-5MMC7ZR3.mjs.br +0 -0
  32. package/dist/chunk-5MMC7ZR3.mjs.gz +0 -0
  33. package/dist/{chunk-TEXIGSA6.mjs → chunk-5YV26HMJ.mjs} +74 -2
  34. package/dist/chunk-5YV26HMJ.mjs.br +0 -0
  35. package/dist/chunk-5YV26HMJ.mjs.gz +0 -0
  36. package/dist/{chunk-QFNJCEMS.js → chunk-7TEZJZ2O.js} +572 -427
  37. package/dist/chunk-7TEZJZ2O.js.br +0 -0
  38. package/dist/chunk-7TEZJZ2O.js.gz +0 -0
  39. package/dist/{chunk-3OV4FR6S.mjs → chunk-GROIHKI5.mjs} +11166 -10887
  40. package/dist/chunk-GROIHKI5.mjs.br +0 -0
  41. package/dist/chunk-GROIHKI5.mjs.gz +0 -0
  42. package/dist/{chunk-ZMIFFURL.js → chunk-HOIF5RQI.js} +12315 -12034
  43. package/dist/chunk-HOIF5RQI.js.br +0 -0
  44. package/dist/chunk-HOIF5RQI.js.gz +0 -0
  45. package/dist/{chunk-DD2YRS6Z.js → chunk-PB7KVDNV.js} +8551 -582
  46. package/dist/chunk-PB7KVDNV.js.br +0 -0
  47. package/dist/chunk-PB7KVDNV.js.gz +0 -0
  48. package/dist/{chunk-PTFCMG3A.js → chunk-QVQDC7HZ.js} +39 -5
  49. package/dist/chunk-QVQDC7HZ.js.br +0 -0
  50. package/dist/chunk-QVQDC7HZ.js.gz +0 -0
  51. package/dist/{chunk-GJEH27GD.mjs → chunk-R7MGJCZN.mjs} +285 -325
  52. package/dist/chunk-R7MGJCZN.mjs.br +0 -0
  53. package/dist/chunk-R7MGJCZN.mjs.gz +0 -0
  54. package/dist/{chunk-66ZHD7Y4.js → chunk-SMECSYCT.js} +527 -567
  55. package/dist/chunk-SMECSYCT.js.br +0 -0
  56. package/dist/chunk-SMECSYCT.js.gz +0 -0
  57. package/dist/{chunk-H5H57XMH.mjs → chunk-T4NHPN76.mjs} +249 -104
  58. package/dist/chunk-T4NHPN76.mjs.br +0 -0
  59. package/dist/chunk-T4NHPN76.mjs.gz +0 -0
  60. package/dist/i18n.js +4 -4
  61. package/dist/i18n.js.br +0 -0
  62. package/dist/i18n.js.gz +0 -0
  63. package/dist/i18n.mjs +1 -1
  64. package/dist/i18n.mjs.br +0 -0
  65. package/dist/i18n.mjs.gz +0 -0
  66. package/dist/index.d.ts +139 -5
  67. package/dist/index.d.ts.map +1 -1
  68. package/dist/index.js +56 -36
  69. package/dist/index.js.br +0 -0
  70. package/dist/index.js.gz +0 -0
  71. package/dist/index.mjs +6 -6
  72. package/dist/index.mjs.br +0 -0
  73. package/dist/index.mjs.gz +0 -0
  74. package/dist/internals.d.ts +124 -4
  75. package/dist/internals.d.ts.map +1 -1
  76. package/dist/internals.js +79 -79
  77. package/dist/internals.js.br +0 -0
  78. package/dist/internals.js.gz +0 -0
  79. package/dist/internals.mjs +4 -4
  80. package/dist/internals.mjs.br +0 -0
  81. package/dist/internals.mjs.gz +0 -0
  82. package/dist/pptx-viewer.css +1 -1
  83. package/dist/pptx-viewer.css.br +0 -0
  84. package/dist/pptx-viewer.css.gz +0 -0
  85. package/dist/{types-DciBT90G.d.ts → types-DU35aAJK.d.ts} +2 -2
  86. package/dist/{types-DciBT90G.d.ts.map → types-DU35aAJK.d.ts.map} +1 -1
  87. package/dist/{useViewerBuildingBlocks-YvCYsxa3.d.ts → useViewerBuildingBlocks-CBZrHhxl.d.ts} +10 -5
  88. package/dist/useViewerBuildingBlocks-CBZrHhxl.d.ts.map +1 -0
  89. package/dist/viewer/index.d.ts +44 -2
  90. package/dist/viewer/index.js +22 -22
  91. package/dist/viewer/index.js.br +0 -0
  92. package/dist/viewer/index.js.gz +0 -0
  93. package/dist/viewer/index.mjs +6 -6
  94. package/dist/viewer/index.mjs.br +0 -0
  95. package/dist/viewer/index.mjs.gz +0 -0
  96. package/package.json +1 -1
  97. package/dist/AiChatPanel-FXPGFU6H.js.br +0 -0
  98. package/dist/AiChatPanel-FXPGFU6H.js.gz +0 -0
  99. package/dist/AiChatPanel-WMGS5TNX.mjs.br +0 -0
  100. package/dist/AiChatPanel-WMGS5TNX.mjs.gz +0 -0
  101. package/dist/Model3DScene-E2XRQAMR.mjs.br +0 -0
  102. package/dist/Model3DScene-E2XRQAMR.mjs.gz +0 -0
  103. package/dist/Model3DScene-K5FPZTRG.js.br +0 -0
  104. package/dist/Model3DScene-K5FPZTRG.js.gz +0 -0
  105. package/dist/SurfaceChart3DScene-2W2IFPLE.mjs.gz +0 -0
  106. package/dist/SurfaceChart3DScene-JDCFTXYT.js.br +0 -0
  107. package/dist/SurfaceChart3DScene-JDCFTXYT.js.gz +0 -0
  108. package/dist/chunk-3OV4FR6S.mjs.br +0 -0
  109. package/dist/chunk-3OV4FR6S.mjs.gz +0 -0
  110. package/dist/chunk-66ZHD7Y4.js.br +0 -0
  111. package/dist/chunk-66ZHD7Y4.js.gz +0 -0
  112. package/dist/chunk-BXAK3JFM.js.br +0 -0
  113. package/dist/chunk-BXAK3JFM.js.gz +0 -0
  114. package/dist/chunk-CQ2CKMG4.mjs.br +0 -0
  115. package/dist/chunk-CQ2CKMG4.mjs.gz +0 -0
  116. package/dist/chunk-DD2YRS6Z.js.br +0 -0
  117. package/dist/chunk-DD2YRS6Z.js.gz +0 -0
  118. package/dist/chunk-GJEH27GD.mjs.br +0 -0
  119. package/dist/chunk-GJEH27GD.mjs.gz +0 -0
  120. package/dist/chunk-H5H57XMH.mjs.br +0 -0
  121. package/dist/chunk-H5H57XMH.mjs.gz +0 -0
  122. package/dist/chunk-OWGPRVRK.mjs.br +0 -0
  123. package/dist/chunk-OWGPRVRK.mjs.gz +0 -0
  124. package/dist/chunk-PTFCMG3A.js.br +0 -0
  125. package/dist/chunk-PTFCMG3A.js.gz +0 -0
  126. package/dist/chunk-QFNJCEMS.js.br +0 -0
  127. package/dist/chunk-QFNJCEMS.js.gz +0 -0
  128. package/dist/chunk-TEXIGSA6.mjs.br +0 -0
  129. package/dist/chunk-TEXIGSA6.mjs.gz +0 -0
  130. package/dist/chunk-ZMIFFURL.js.br +0 -0
  131. package/dist/chunk-ZMIFFURL.js.gz +0 -0
  132. package/dist/useViewerBuildingBlocks-YvCYsxa3.d.ts.map +0 -1
Binary file
Binary file
@@ -1,7 +1,7 @@
1
- import { cloneHistorySnapshot, MIN_ELEMENT_SIZE, ZOOM_TO_SELECTION_PADDING, DEFAULT_CANVAS_HEIGHT, DEFAULT_CANVAS_WIDTH, partitionTemplateElements, UNGROUPED_SECTION_ID, buildSaveSlides, DEFAULT_TABLE_ROWS, DEFAULT_TABLE_COLUMNS, executeMediaCommand, buildPdfFromImageData, buildNotesPdf, EMU_PER_PX, GRID_SIZE, DEFAULT_TEXT_FONT_SIZE } from './chunk-GJEH27GD.mjs';
2
- import { translationsEn } from './chunk-TEXIGSA6.mjs';
3
- import { TOOLBAR_TABS, computeVirtualRange, DEFAULT_VIRTUAL_OVERSCAN, BROADCAST_THROTTLE_MS, createSyncGate, clearLocalAwareness, validateRoomId, createDepartureChannel, resolveTransportForServerUrl, isMixedContentBlocked, CONNECTION_TIMEOUT_MS, registerCollaborationTeardown, sanitizeColor, cloneTemplateElementsBySlideId, cloneSlide, clampZoomScale, zoomInScale, zoomOutScale, PresentationAnimationController, computeEntranceAnimationDelay, PRESENTATION_HASH, PRESENTATION_NONCE_KEY, PRESENTATION_CHANNEL_NAME, swapPresentationWindows, PRESENTATION_MESSAGE_ORIGIN, clearAudienceContent, buildPresentationAudienceUrl, resolveAudienceScreenPlacement, placeAudienceWindow, storeAudienceContent, isPresentationSessionMessage, endAudienceDisplay, createPresentationKeyBuffer, acceptsPresentationInput, resolveAutoAdvanceDelayMs, hasShowSlideAfter, nextShowSlideIndex, previousShowSlideIndex, createPresenterShowGuard, attachPresentationVisibilityPause, buildMorphTransitionPlan, morphOptionToMode, createCollaborationLivePatcher, publishLiveInlineText, PptxHandler, collectMediaElements, collectImagePaths, buildInitialGuides, EncryptedFileError, saveAutosaveSnapshot, isTemplateElementId, hasShapeProperties, hasTextProperties, getInlineEditorSelection, applyStyleToSelectedSegments, setPendingSelectionRestore, applyCaseTransformToSegments, transformTextCase, addSection, renameSection, deleteSection, moveSectionUp, moveSectionDown, moveSlidesToSection, normalizeColorsForCapture, preprocessCssForCapture, downloadBlob, sanitizeDownloadFilename, slideProgressPercent, slideStatusLabel, EXPORT_ASSEMBLING_PERCENT, EXPORT_DONE_PERCENT, isExportAbortError, recordProgressPercent, applyThemeToData, THEME_PRESETS, themeColorSchemesEqual, comparePresentation, applyAcceptSlide, applyAcceptAllSlides, collectUsedFonts, detectTouchDevice, detectOrientation, isMobileViewport, MOBILE_BREAKPOINT, TABLET_BREAKPOINT, mayLeaveSlideShow, stopAllPersistentAudio, remapTextToSegments, guidePxToEmu, shouldLoopContinuously, applyRehearsalTimings, copyFormatFromElement, applyFormatToElement, mapEditorKey, isEditorTextInputTarget, createViewerOptionsStore, readSlidesFromYDoc, reconcileSlidesInYDoc, LOCAL_SYNC_ORIGIN, observeYDocSlides, shouldAutoFollowBroadcaster, createTouchGestureRecognizer, MAX_ZOOM_SCALE, MIN_ZOOM_SCALE, isKeyboardOpen, openPptxFile, readBackstageRecentFile, isActionHidden, buildElementClipboardPayload, generatePackageReadme, groupElements, generateElementId, makeCloneId, alignElements, distributeElements, bringForward, sendBackward, bringToFront, sendToBack, newTableElement, createDefaultChartElement, readViewportMetrics, computeKeyboardInset, mergeShapes, derivePresenceList, mapPresentationKey, lastShowSlideIndex, firstShowSlideIndex, buildPrintDocument, buildOutlineHtml, buildSlidesHtml, buildNotesHtml, buildHandoutsHtml, createBlankSlide, makeSlideId, buildThemeColorMap, reResolveSlideColors, createPresentationSessionId, resolveTransitionDurationMs, runPresentationAction, createPresenterTimer, createInitialPresentationSnapshot, mergePresentationSnapshot, presenterElapsed, stepPresenterZoom, resetPresenterTimer, togglePresenterTimer, canvasToJpegData, downloadDataUrl, pickSupportedMimeType, WEBM_MIME_CANDIDATES, fpsToFrameIntervalMs, segmentFrameCount, encodeGif, resolveShowSlideIndexes, groupSlidesBySection, hasCopyableFormat, createBackstagePresentation, buildFieldSubstitutionContext, cloneElementForPaste, computeScrollDelta, getPresetShapeClipPath, svgPathToPolygons, polygonsToSvgPath, rerouteConnectorsForMovedElements, applyReroutedConnectors, SvgExporter, buildPrintHtmlDocument, deleteTableColumn, rebuildTableStructureInRawXml, insertTableColumn, deleteTableRow, insertTableRow, updateCellTextStyleInRawXml, updateCellTextInRawXml, splitCell, updateMergeAttrsInRawXml, mergeCells, isPpactionUrl, parsePpactionUrl, safeOpenUrl, ACTION_BUTTON_PRESETS, elementActionToPptxAction, buildSmartArtPresetData, computeSnapToShape, publishLiveGeometry, computeMarqueeHitIds, mergeAdditiveSelection, applyResize, snapBoxToGrid, applyMotionPathPreset } from './chunk-OWGPRVRK.mjs';
4
- import { useRef, useState, useEffect, useCallback, useMemo, useSyncExternalStore, useImperativeHandle } from 'react';
1
+ import { cloneHistorySnapshot, MIN_ELEMENT_SIZE, ZOOM_TO_SELECTION_PADDING, DEFAULT_CANVAS_HEIGHT, DEFAULT_CANVAS_WIDTH, partitionTemplateElements, UNGROUPED_SECTION_ID, buildSaveSlides, DEFAULT_TABLE_ROWS, DEFAULT_TABLE_COLUMNS, executeMediaCommand, buildPdfFromImageData, buildNotesPdf, EMU_PER_PX, GRID_SIZE, DEFAULT_TEXT_FONT_SIZE } from './chunk-R7MGJCZN.mjs';
2
+ import { translationsEn } from './chunk-5YV26HMJ.mjs';
3
+ import { TOOLBAR_TABS, computeVirtualRange, DEFAULT_VIRTUAL_OVERSCAN, createPresenceProjector, BROADCAST_THROTTLE_MS, createSyncGate, clearLocalAwareness, validateRoomId, createDepartureChannel, resolveTransportForServerUrl, isMixedContentBlocked, CONNECTION_TIMEOUT_MS, registerCollaborationTeardown, sanitizeColor, cloneTemplateElementsBySlideId, cloneSlide, createViewerZoomStore, clampZoomScale, PresentationAnimationController, PRESENTATION_HASH, PRESENTATION_NONCE_KEY, PRESENTATION_CHANNEL_NAME, swapPresentationWindows, PRESENTATION_MESSAGE_ORIGIN, clearAudienceContent, buildPresentationAudienceUrl, resolveAudienceScreenPlacement, placeAudienceWindow, storeAudienceContent, isPresentationSessionMessage, endAudienceDisplay, createPresentationKeyBuffer, acceptsPresentationInput, resolveAutoAdvanceDelayMs, hasShowSlideAfter, nextShowSlideIndex, previousShowSlideIndex, createPresenterShowGuard, attachPresentationVisibilityPause, buildMorphTransitionPlan, morphOptionToMode, createCollaborationLivePatcher, publishLiveInlineText, PptxHandler, collectMediaElements, collectImagePaths, buildInitialGuides, EncryptedFileError, saveAutosaveSnapshot, isTemplateElementId, hasShapeProperties, hasTextProperties, getInlineEditorSelection, applyStyleToSelectedSegments, setPendingSelectionRestore, applyCaseTransformToSegments, transformTextCase, addSection, renameSection, deleteSection, moveSectionUp, moveSectionDown, moveSlidesToSection, normalizeColorsForCapture, preprocessCssForCapture, downloadBlob, sanitizeDownloadFilename, slideProgressPercent, slideStatusLabel, EXPORT_ASSEMBLING_PERCENT, EXPORT_DONE_PERCENT, isExportAbortError, recordProgressPercent, applyThemeToData, THEME_PRESETS, themeColorSchemesEqual, comparePresentation, applyAcceptSlide, applyAcceptAllSlides, collectUsedFonts, detectTouchDevice, detectOrientation, isMobileViewport, MOBILE_BREAKPOINT, TABLET_BREAKPOINT, mayLeaveSlideShow, stopAllPersistentAudio, remapTextToSegments, guidePxToEmu, shouldLoopContinuously, applyRehearsalTimings, copyFormatFromElement, applyFormatToElement, mapEditorKey, isEditorTextInputTarget, createViewerOptionsStore, readSlidesFromYDoc, reconcileSlidesInYDoc, LOCAL_SYNC_ORIGIN, observeYDocSlides, shouldAutoFollowBroadcaster, createTouchGestureRecognizer, MAX_ZOOM_SCALE, MIN_ZOOM_SCALE, isKeyboardOpen, openPptxFile, readBackstageRecentFile, isActionHidden, buildElementClipboardPayload, generatePackageReadme, exportDeckJson, groupElements, generateElementId, makeCloneId, alignElements, distributeElements, bringForward, sendBackward, bringToFront, sendToBack, newTableElement, createDefaultChartElement, readViewportMetrics, computeKeyboardInset, mergeShapes, mapPresentationKey, lastShowSlideIndex, firstShowSlideIndex, buildPrintDocument, buildOutlineHtml, buildSlidesHtml, buildNotesHtml, buildHandoutsHtml, createBlankSlide, makeSlideId, buildSlideTemplateSlide, templateSchemeFromTheme, buildThemeColorMap, reResolveSlideColors, computeEntranceAnimationDelay, createPresentationSessionId, resolveTransitionDurationMs, runPresentationAction, createPresenterTimer, createInitialPresentationSnapshot, mergePresentationSnapshot, resetPresenterTimer, presenterElapsed, stepPresenterZoom, togglePresenterTimer, canvasToJpegData, downloadDataUrl, pickSupportedMimeType, WEBM_MIME_CANDIDATES, fpsToFrameIntervalMs, segmentFrameCount, encodeGif, resolveShowSlideIndexes, groupSlidesBySection, hasCopyableFormat, createBackstagePresentation, buildFieldSubstitutionContext, cloneElementForPaste, computeScrollDelta, getPresetShapeClipPath, svgPathToPolygons, polygonsToSvgPath, rerouteConnectorsForMovedElements, applyReroutedConnectors, SvgExporter, buildPrintHtmlDocument, deleteTableColumn, rebuildTableStructureInRawXml, insertTableColumn, deleteTableRow, insertTableRow, updateCellTextStyleInRawXml, updateCellTextInRawXml, splitCell, updateMergeAttrsInRawXml, mergeCells, isPpactionUrl, parsePpactionUrl, safeOpenUrl, ACTION_BUTTON_PRESETS, elementActionToPptxAction, buildSmartArtPresetData, computeSnapToShape, publishLiveGeometry, computeMarqueeHitIds, mergeAdditiveSelection, applyResize, snapBoxToGrid, applyMotionPathPreset } from './chunk-5MMC7ZR3.mjs';
4
+ import { useRef, useState, useEffect, useCallback, useMemo, useLayoutEffect, useSyncExternalStore, useImperativeHandle } from 'react';
5
5
  import JSZip from 'jszip';
6
6
  import { useTranslation } from 'react-i18next';
7
7
 
@@ -78,6 +78,9 @@ function usePresenceTracking({
78
78
  canvasHeight
79
79
  }) {
80
80
  const [remoteUsers, setRemoteUsers] = useState([]);
81
+ const projectorRef = useRef(null);
82
+ projectorRef.current ??= createPresenceProjector();
83
+ const projector = projectorRef.current;
81
84
  const lastBroadcastRef = useRef(0);
82
85
  const pendingBroadcastRef = useRef(null);
83
86
  const latestLocalState = useRef({});
@@ -136,13 +139,16 @@ function usePresenceTracking({
136
139
  return;
137
140
  }
138
141
  const handleChange = () => {
139
- const users = derivePresenceList(
142
+ const { list, changed } = projector.project(
140
143
  awareness.getStates(),
141
144
  localClientId,
142
145
  canvasWidth,
143
146
  canvasHeight
144
147
  );
145
- setRemoteUsers(users);
148
+ if (!changed) {
149
+ return;
150
+ }
151
+ setRemoteUsers(list);
146
152
  };
147
153
  awareness.on("change", handleChange);
148
154
  awareness.on("update", handleChange);
@@ -151,7 +157,7 @@ function usePresenceTracking({
151
157
  awareness.off("change", handleChange);
152
158
  awareness.off("update", handleChange);
153
159
  };
154
- }, [awareness, localClientId, canvasWidth, canvasHeight]);
160
+ }, [awareness, localClientId, canvasWidth, canvasHeight, projector]);
155
161
  useEffect(() => {
156
162
  if (!awareness) {
157
163
  return;
@@ -684,6 +690,28 @@ function useEditorHistory(input) {
684
690
  buildHistorySnapshot
685
691
  };
686
692
  }
693
+ function useViewerStore(store, selector, isEqual = Object.is) {
694
+ const cache = useRef(null);
695
+ const getSnapshot2 = useCallback(() => {
696
+ const state = store.getState();
697
+ const last = cache.current;
698
+ if (last && Object.is(last.state, state)) {
699
+ return last.value;
700
+ }
701
+ const next = selector(state);
702
+ const value = last && isEqual(last.value, next) ? last.value : next;
703
+ cache.current = { state, value };
704
+ return value;
705
+ }, [store, selector, isEqual]);
706
+ const subscribe2 = useCallback(
707
+ (onStoreChange) => store.subscribe(onStoreChange),
708
+ [store]
709
+ );
710
+ return useSyncExternalStore(subscribe2, getSnapshot2, getSnapshot2);
711
+ }
712
+
713
+ // src/viewer/hooks/useZoomViewport.ts
714
+ var selectZoom = (state) => state.zoom;
687
715
  function useZoomViewport({
688
716
  canvasSize,
689
717
  selectedElements
@@ -692,7 +720,14 @@ function useZoomViewport({
692
720
  const canvasStageRef = useRef(null);
693
721
  const canvasViewportRef = useRef(null);
694
722
  const renderScaleRef = useRef(1);
695
- const [scale, setScale] = useState(1);
723
+ const storeRef = useRef(null);
724
+ storeRef.current ??= createViewerZoomStore();
725
+ const store = storeRef.current;
726
+ const scale = useViewerStore(store, selectZoom);
727
+ const setScale = useCallback(
728
+ (next) => store.dispatch({ type: "set-zoom", zoom: next }),
729
+ [store]
730
+ );
696
731
  const [editorDimensions, setEditorDimensions] = useState(null);
697
732
  const effectiveEditorDimensions = editorDimensions || {
698
733
  width: canvasSize.width,
@@ -710,6 +745,9 @@ function useZoomViewport({
710
745
  useEffect(() => {
711
746
  renderScaleRef.current = editorScale;
712
747
  }, [editorScale]);
748
+ useEffect(() => {
749
+ store.dispatch({ type: "set-fit-scale", fitScale });
750
+ }, [store, fitScale]);
713
751
  useEffect(() => {
714
752
  let observer = null;
715
753
  let raf = 0;
@@ -759,17 +797,17 @@ function useZoomViewport({
759
797
  [fitScale]
760
798
  );
761
799
  const handleZoomIn = useCallback(() => {
762
- setScale((currentScale) => zoomInScale(currentScale));
763
- }, []);
800
+ store.dispatch({ type: "zoom-in" });
801
+ }, [store]);
764
802
  const handleZoomOut = useCallback(() => {
765
- setScale((currentScale) => zoomOutScale(currentScale));
766
- }, []);
803
+ store.dispatch({ type: "zoom-out" });
804
+ }, [store]);
767
805
  const handleResetZoom = useCallback(() => {
768
- setScale(1);
769
- }, []);
806
+ store.dispatch({ type: "zoom-to-fit" });
807
+ }, [store]);
770
808
  const handleZoomToFit = useCallback(() => {
771
- setScale(1);
772
- }, []);
809
+ store.dispatch({ type: "zoom-to-fit" });
810
+ }, [store]);
773
811
  const handleZoomToSelection = useCallback(() => {
774
812
  if (selectedElements.length === 0) {
775
813
  return;
@@ -815,16 +853,23 @@ function useZoomViewport({
815
853
  effectiveEditorDimensions.height,
816
854
  effectiveEditorDimensions.width,
817
855
  fitScale,
818
- selectedElements
856
+ selectedElements,
857
+ setScale
819
858
  ]);
820
- const handleWheel = useCallback((event) => {
821
- if (!event.ctrlKey) {
822
- return;
823
- }
824
- event.preventDefault();
825
- const delta = event.deltaY * -1e-3;
826
- setScale((currentScale) => clampZoomScale(currentScale + delta));
827
- }, []);
859
+ const handleWheel = useCallback(
860
+ (event) => {
861
+ if (!event.ctrlKey) {
862
+ return;
863
+ }
864
+ event.preventDefault();
865
+ const delta = event.deltaY * -1e-3;
866
+ store.dispatch({
867
+ type: "set-zoom",
868
+ zoom: clampZoomScale(store.getState().zoom + delta)
869
+ });
870
+ },
871
+ [store]
872
+ );
828
873
  useEffect(() => {
829
874
  const viewport = canvasViewportRef.current;
830
875
  if (!viewport) {
@@ -997,6 +1042,58 @@ function driveBuildReveal(controller, buildIds, setStates, handle) {
997
1042
  tick();
998
1043
  }
999
1044
 
1045
+ // src/viewer/hooks/presentation-mode/entrance-animation-timers.ts
1046
+ function scheduleOpeningAutoPlayGroup(controller, deps) {
1047
+ if (!controller.hasMoreSteps()) {
1048
+ return;
1049
+ }
1050
+ const firstGroup = controller.peekNext();
1051
+ if (!firstGroup?.autoAdvance) {
1052
+ return;
1053
+ }
1054
+ const timer = window.setTimeout(() => {
1055
+ const group = controller.advance();
1056
+ if (!group) {
1057
+ return;
1058
+ }
1059
+ applyAnimationGroupSteps(
1060
+ group,
1061
+ deps.onPlayActionSound,
1062
+ deps.setPresentationElementStates,
1063
+ deps.presentationTimersRef
1064
+ );
1065
+ deps.startBuildReveal(controller, group);
1066
+ deps.scheduleAutoAdvanceChain(controller);
1067
+ }, firstGroup.autoAdvanceDelayMs ?? 0);
1068
+ deps.presentationTimersRef.current.push(timer);
1069
+ }
1070
+ function scheduleEntranceAnimationTimers(slide, setPresentationAnimations, presentationTimersRef) {
1071
+ const entranceAnimations = [...slide.animations || []].filter((animation) => Boolean(animation.entrance)).sort(
1072
+ (left, right) => (left.order || Number.MAX_SAFE_INTEGER) - (right.order || Number.MAX_SAFE_INTEGER)
1073
+ );
1074
+ if (entranceAnimations.length === 0) {
1075
+ return;
1076
+ }
1077
+ setPresentationAnimations(
1078
+ entranceAnimations.map((animation) => ({
1079
+ elementId: animation.elementId,
1080
+ state: "hidden",
1081
+ animation
1082
+ }))
1083
+ );
1084
+ entranceAnimations.forEach((animation, animationIndex) => {
1085
+ const delay = computeEntranceAnimationDelay(animation.delayMs, animationIndex);
1086
+ const timer = window.setTimeout(() => {
1087
+ setPresentationAnimations(
1088
+ (previousAnimations) => previousAnimations.map(
1089
+ (entry) => entry.elementId === animation.elementId ? { ...entry, state: "visible" } : entry
1090
+ )
1091
+ );
1092
+ }, delay);
1093
+ presentationTimersRef.current.push(timer);
1094
+ });
1095
+ }
1096
+
1000
1097
  // src/viewer/hooks/presentation-mode/useAnimationPlayback.ts
1001
1098
  function useAnimationPlayback(input) {
1002
1099
  const { slides, onPlayActionSound, showWithAnimation } = input;
@@ -1012,6 +1109,7 @@ function useAnimationPlayback(input) {
1012
1109
  const controllerRef = useRef(null);
1013
1110
  const buildRafRef = useRef(null);
1014
1111
  const seededCompletedRef = useRef(false);
1112
+ const lastSeedCompletedRef = useRef(false);
1015
1113
  const startBuildReveal = useCallback(
1016
1114
  (controller, group) => {
1017
1115
  driveBuildReveal(
@@ -1163,12 +1261,12 @@ function useAnimationPlayback(input) {
1163
1261
  }
1164
1262
  controller.resetHover(shapeId);
1165
1263
  }, []);
1166
- const runPresentationEntranceAnimations = useCallback(
1264
+ const seedSlideAnimations = useCallback(
1167
1265
  (slideIndex, options) => {
1168
1266
  clearPresentationTimers();
1267
+ setPresentationAnimations([]);
1169
1268
  if (!animationsEnabled) {
1170
1269
  controllerRef.current = null;
1171
- setPresentationAnimations([]);
1172
1270
  setPresentationElementStates(/* @__PURE__ */ new Map());
1173
1271
  setPresentationKeyframesCss("");
1174
1272
  setInteractiveTriggerShapeIds(/* @__PURE__ */ new Set());
@@ -1176,12 +1274,8 @@ function useAnimationPlayback(input) {
1176
1274
  return;
1177
1275
  }
1178
1276
  resetSlideTimeline(slideIndex);
1179
- const slide = slides[slideIndex];
1180
- if (!slide) {
1181
- setPresentationAnimations([]);
1182
- return;
1183
- }
1184
1277
  seededCompletedRef.current = false;
1278
+ lastSeedCompletedRef.current = options?.completed === true;
1185
1279
  if (options?.completed) {
1186
1280
  const seeded = controllerRef.current;
1187
1281
  if (seeded) {
@@ -1189,64 +1283,39 @@ function useAnimationPlayback(input) {
1189
1283
  seeded.completeAll();
1190
1284
  setPresentationElementStates(seeded.computeStates());
1191
1285
  }
1192
- setPresentationAnimations([]);
1193
- return;
1194
1286
  }
1195
- const controller = controllerRef.current;
1196
- if (controller && controller.hasMoreSteps()) {
1197
- const firstGroup = controller.peekNext();
1198
- if (firstGroup && firstGroup.autoAdvance) {
1199
- const timer = window.setTimeout(() => {
1200
- const group = controller.advance();
1201
- if (group) {
1202
- applyAnimationGroupSteps(
1203
- group,
1204
- onPlayActionSound,
1205
- setPresentationElementStates,
1206
- presentationTimersRef
1207
- );
1208
- startBuildReveal(controller, group);
1209
- scheduleAutoAdvanceChain(controller);
1210
- }
1211
- }, firstGroup.autoAdvanceDelayMs ?? 0);
1212
- presentationTimersRef.current.push(timer);
1213
- }
1287
+ },
1288
+ [animationsEnabled, clearPresentationTimers, resetSlideTimeline]
1289
+ );
1290
+ const startSlideAnimations = useCallback(
1291
+ (slideIndex) => {
1292
+ if (!animationsEnabled || lastSeedCompletedRef.current) {
1293
+ return;
1214
1294
  }
1215
- const entranceAnimations = [...slide.animations || []].filter((animation) => Boolean(animation.entrance)).sort(
1216
- (left, right) => (left.order || Number.MAX_SAFE_INTEGER) - (right.order || Number.MAX_SAFE_INTEGER)
1217
- );
1218
- if (entranceAnimations.length === 0) {
1219
- setPresentationAnimations([]);
1295
+ const slide = slides[slideIndex];
1296
+ if (!slide) {
1220
1297
  return;
1221
1298
  }
1222
- setPresentationAnimations(
1223
- entranceAnimations.map((animation) => ({
1224
- elementId: animation.elementId,
1225
- state: "hidden",
1226
- animation
1227
- }))
1228
- );
1229
- entranceAnimations.forEach((animation, animationIndex) => {
1230
- const delay = computeEntranceAnimationDelay(animation.delayMs, animationIndex);
1231
- const timer = window.setTimeout(() => {
1232
- setPresentationAnimations(
1233
- (previousAnimations) => previousAnimations.map(
1234
- (entry) => entry.elementId === animation.elementId ? { ...entry, state: "visible" } : entry
1235
- )
1236
- );
1237
- }, delay);
1238
- presentationTimersRef.current.push(timer);
1239
- });
1299
+ const controller = controllerRef.current;
1300
+ if (controller) {
1301
+ scheduleOpeningAutoPlayGroup(controller, {
1302
+ onPlayActionSound,
1303
+ setPresentationElementStates,
1304
+ presentationTimersRef,
1305
+ startBuildReveal,
1306
+ scheduleAutoAdvanceChain
1307
+ });
1308
+ }
1309
+ scheduleEntranceAnimationTimers(slide, setPresentationAnimations, presentationTimersRef);
1240
1310
  },
1241
- [
1242
- animationsEnabled,
1243
- clearPresentationTimers,
1244
- resetSlideTimeline,
1245
- slides,
1246
- onPlayActionSound,
1247
- scheduleAutoAdvanceChain,
1248
- startBuildReveal
1249
- ]
1311
+ [animationsEnabled, slides, onPlayActionSound, scheduleAutoAdvanceChain, startBuildReveal]
1312
+ );
1313
+ const runPresentationEntranceAnimations = useCallback(
1314
+ (slideIndex, options) => {
1315
+ seedSlideAnimations(slideIndex, options);
1316
+ startSlideAnimations(slideIndex);
1317
+ },
1318
+ [seedSlideAnimations, startSlideAnimations]
1250
1319
  );
1251
1320
  return {
1252
1321
  presentationAnimations,
@@ -1260,6 +1329,8 @@ function useAnimationPlayback(input) {
1260
1329
  handleHoverStart,
1261
1330
  handleHoverEnd,
1262
1331
  runPresentationEntranceAnimations,
1332
+ seedSlideAnimations,
1333
+ startSlideAnimations,
1263
1334
  isSeededCompleted: () => seededCompletedRef.current,
1264
1335
  presentationTimersRef
1265
1336
  };
@@ -1809,6 +1880,7 @@ function executeSlideTransition(nextSlideIndex, deps) {
1809
1880
  deps.setPresentationSlideIndex(nextSlideIndex);
1810
1881
  deps.onSetActiveSlideIndex(nextSlideIndex);
1811
1882
  deps.setPresentationSlideVisible(true);
1883
+ deps.seedSlideAnimations(nextSlideIndex, { completed: deps.seedCompleted });
1812
1884
  if (durationMs > 0 && transition) {
1813
1885
  if (transition.soundPath && deps.onPlayActionSound) {
1814
1886
  deps.onPlayActionSound(transition.soundPath, { loop: transition.soundLoop === true });
@@ -1820,16 +1892,14 @@ function executeSlideTransition(nextSlideIndex, deps) {
1820
1892
  durationMs
1821
1893
  });
1822
1894
  const timer = window.setTimeout(() => {
1823
- deps.runPresentationEntranceAnimations(nextSlideIndex, {
1824
- completed: deps.seedCompleted
1825
- });
1895
+ deps.startSlideAnimations(nextSlideIndex);
1826
1896
  deps.scheduleAutoAdvanceForSlide?.(nextSlideIndex);
1827
1897
  }, durationMs);
1828
1898
  deps.presentationTimersRef.current.push(timer);
1829
1899
  return;
1830
1900
  }
1831
1901
  deps.setTransitionOverlay(null);
1832
- deps.runPresentationEntranceAnimations(nextSlideIndex, { completed: deps.seedCompleted });
1902
+ deps.startSlideAnimations(nextSlideIndex);
1833
1903
  deps.scheduleAutoAdvanceForSlide?.(nextSlideIndex);
1834
1904
  }
1835
1905
 
@@ -1853,7 +1923,8 @@ function useSlideNavigation(input) {
1853
1923
  onAdvancePastLastSlide,
1854
1924
  playNextAnimationGroup,
1855
1925
  clearPresentationTimers,
1856
- runPresentationEntranceAnimations,
1926
+ seedSlideAnimations,
1927
+ startSlideAnimations,
1857
1928
  presentationTimersRef,
1858
1929
  rehearsing,
1859
1930
  recordCurrentSlideTime,
@@ -1921,7 +1992,8 @@ function useSlideNavigation(input) {
1921
1992
  clearPresentationTimers,
1922
1993
  setPresentationSlideIndex,
1923
1994
  onSetActiveSlideIndex,
1924
- runPresentationEntranceAnimations,
1995
+ seedSlideAnimations,
1996
+ startSlideAnimations,
1925
1997
  scheduleAutoAdvanceForSlide: rehearsing ? void 0 : scheduleAutoAdvanceForSlide,
1926
1998
  presentationTimersRef,
1927
1999
  setTransitionOverlay,
@@ -1943,7 +2015,8 @@ function useSlideNavigation(input) {
1943
2015
  presentationTimersRef,
1944
2016
  recordCurrentSlideTime,
1945
2017
  rehearsing,
1946
- runPresentationEntranceAnimations,
2018
+ seedSlideAnimations,
2019
+ startSlideAnimations,
1947
2020
  scheduleAutoAdvanceForSlide,
1948
2021
  setShowRehearsalSummary,
1949
2022
  slides,
@@ -1970,7 +2043,8 @@ function useSlideNavigation(input) {
1970
2043
  clearPresentationTimers,
1971
2044
  setPresentationSlideIndex,
1972
2045
  onSetActiveSlideIndex,
1973
- runPresentationEntranceAnimations,
2046
+ seedSlideAnimations,
2047
+ startSlideAnimations,
1974
2048
  scheduleAutoAdvanceForSlide,
1975
2049
  presentationTimersRef,
1976
2050
  setTransitionOverlay,
@@ -1990,7 +2064,8 @@ function useSlideNavigation(input) {
1990
2064
  onSetActiveSlideIndex,
1991
2065
  presentationSlideIndex,
1992
2066
  presentationTimersRef,
1993
- runPresentationEntranceAnimations,
2067
+ seedSlideAnimations,
2068
+ startSlideAnimations,
1994
2069
  scheduleAutoAdvanceForSlide,
1995
2070
  slides,
1996
2071
  setPresentationSlideIndex,
@@ -2046,7 +2121,7 @@ function useZoomNavigation(input) {
2046
2121
  clearZoomReturn
2047
2122
  };
2048
2123
  }
2049
- function usePresenterConsole(slideIndex) {
2124
+ function usePresenterConsole(slideIndex, active) {
2050
2125
  const timerRef = useRef(createPresenterTimer());
2051
2126
  const [snapshot, setSnapshot] = useState(() => createInitialPresentationSnapshot(slideIndex));
2052
2127
  const patch = useCallback((value) => {
@@ -2054,6 +2129,11 @@ function usePresenterConsole(slideIndex) {
2054
2129
  }, []);
2055
2130
  useEffect(() => patch({ slideIndex }), [patch, slideIndex]);
2056
2131
  useEffect(() => {
2132
+ if (!active) {
2133
+ return;
2134
+ }
2135
+ timerRef.current = resetPresenterTimer();
2136
+ patch({ paused: false, elapsedMs: 0 });
2057
2137
  const timer = window.setInterval(() => {
2058
2138
  patch({
2059
2139
  paused: timerRef.current.paused,
@@ -2061,7 +2141,7 @@ function usePresenterConsole(slideIndex) {
2061
2141
  });
2062
2142
  }, 1e3);
2063
2143
  return () => window.clearInterval(timer);
2064
- }, [patch]);
2144
+ }, [active, patch]);
2065
2145
  return {
2066
2146
  snapshot,
2067
2147
  applyAudienceSnapshot: setSnapshot,
@@ -2137,6 +2217,8 @@ function usePresentationMode(input) {
2137
2217
  handleHoverStart,
2138
2218
  handleHoverEnd,
2139
2219
  runPresentationEntranceAnimations,
2220
+ seedSlideAnimations,
2221
+ startSlideAnimations,
2140
2222
  isSeededCompleted,
2141
2223
  presentationTimersRef
2142
2224
  } = useAnimationPlayback({ slides, onPlayActionSound, showWithAnimation });
@@ -2192,7 +2274,8 @@ function usePresentationMode(input) {
2192
2274
  onAdvancePastLastSlide: handleAdvancePastLastSlide,
2193
2275
  playNextAnimationGroup,
2194
2276
  clearPresentationTimers,
2195
- runPresentationEntranceAnimations,
2277
+ seedSlideAnimations,
2278
+ startSlideAnimations,
2196
2279
  presentationTimersRef,
2197
2280
  rehearsing,
2198
2281
  recordCurrentSlideTime,
@@ -2228,7 +2311,7 @@ function usePresentationMode(input) {
2228
2311
  const { handleZoomClick, zoomReturnSlideIndex, returnToZoomSlide, clearZoomReturn } = useZoomNavigation({ navigateToSlide });
2229
2312
  const openAllSlides = useCallback(() => setAllSlidesOpen(true), []);
2230
2313
  const closeAllSlides = useCallback(() => setAllSlidesOpen(false), []);
2231
- const presenterConsole = usePresenterConsole(presentationSlideIndex);
2314
+ const presenterConsole = usePresenterConsole(presentationSlideIndex, mode === "present");
2232
2315
  const {
2233
2316
  openAudienceWindow,
2234
2317
  closeAudienceWindow,
@@ -2343,7 +2426,7 @@ function usePresentationMode(input) {
2343
2426
  onVisible: () => scheduleAutoAdvanceRef.current(presentationSlideIndexRef.current)
2344
2427
  });
2345
2428
  }, [mode, containerRef]);
2346
- useEffect(() => {
2429
+ useLayoutEffect(() => {
2347
2430
  if (mode === "present") {
2348
2431
  const idx = activeSlideIndexRef.current;
2349
2432
  setPresentationSlideIndex(idx);
@@ -5434,11 +5517,11 @@ function useInsertElements(input) {
5434
5517
  id: generateElementId()
5435
5518
  });
5436
5519
  };
5437
- const handleAddChart = (chartType) => {
5520
+ const handleAddChart = (chartKind) => {
5438
5521
  if (!activeSlide) {
5439
5522
  return;
5440
5523
  }
5441
- addElement(createDefaultChartElement(chartType));
5524
+ addElement(createDefaultChartElement(chartKind));
5442
5525
  };
5443
5526
  const structured = createStructuredElementHandlers({
5444
5527
  activeSlide,
@@ -6064,7 +6147,16 @@ function insertSlideFromLayoutUpdater(slides, activeIndex, draft) {
6064
6147
  return next;
6065
6148
  }
6066
6149
  function useSlideManagement(input) {
6067
- const { slides, activeSlideIndex, setActiveSlideIndex, ops, history, handlerRef } = input;
6150
+ const {
6151
+ slides,
6152
+ activeSlideIndex,
6153
+ setActiveSlideIndex,
6154
+ ops,
6155
+ history,
6156
+ handlerRef,
6157
+ canvasSize,
6158
+ theme
6159
+ } = input;
6068
6160
  const handleAddSlide = () => {
6069
6161
  const newSlide = createBlankSlide(slides.length + 1);
6070
6162
  ops.updateSlides((prev) => {
@@ -6192,6 +6284,16 @@ function useSlideManagement(input) {
6192
6284
  );
6193
6285
  }
6194
6286
  };
6287
+ const handleInsertSlideFromTemplate = (templateId) => {
6288
+ const insertAt = activeSlideIndex + 1;
6289
+ const draft = buildSlideTemplateSlide(templateId, makeSlideId(), slides.length + 1, {
6290
+ ...canvasSize ? { slideWidth: canvasSize.width, slideHeight: canvasSize.height } : {},
6291
+ scheme: templateSchemeFromTheme(theme?.colorScheme)
6292
+ });
6293
+ ops.updateSlides((prev) => insertSlideFromLayoutUpdater(prev, activeSlideIndex, draft));
6294
+ setActiveSlideIndex(insertAt);
6295
+ history.markDirty();
6296
+ };
6195
6297
  return {
6196
6298
  handleAddSlide,
6197
6299
  handleMoveSlide,
@@ -6199,7 +6301,8 @@ function useSlideManagement(input) {
6199
6301
  handleDeleteSlides,
6200
6302
  handleDuplicateSlides,
6201
6303
  handleToggleHideSlides,
6202
- handleInsertSlideFromLayout
6304
+ handleInsertSlideFromLayout,
6305
+ handleInsertSlideFromTemplate
6203
6306
  };
6204
6307
  }
6205
6308
 
@@ -6858,6 +6961,8 @@ function useExportSaveAs(input) {
6858
6961
  handoutMaster,
6859
6962
  guides,
6860
6963
  activeSlideIndexForGuides,
6964
+ theme,
6965
+ canvasSize,
6861
6966
  modalControls,
6862
6967
  password
6863
6968
  } = input;
@@ -6964,6 +7069,32 @@ function useExportSaveAs(input) {
6964
7069
  }
6965
7070
  return handler.save(slidesToSave, saveOptions);
6966
7071
  };
7072
+ const handleExportJson = () => {
7073
+ const sourceName = filePath ? filePath.replace(/\\/gu, "/").split("/").pop() : void 0;
7074
+ const data = {
7075
+ slides: buildSaveSlides(slides, templateElementsBySlideId),
7076
+ width: canvasSize.width,
7077
+ height: canvasSize.height,
7078
+ widthEmu: guidePxToEmu(canvasSize.width),
7079
+ heightEmu: guidePxToEmu(canvasSize.height),
7080
+ theme,
7081
+ headerFooter,
7082
+ presentationProperties,
7083
+ customShows: customShows.length > 0 ? customShows : void 0,
7084
+ sections: sections.length > 0 ? sections : void 0,
7085
+ coreProperties: coreProperties ?? void 0,
7086
+ appProperties: appProperties ?? void 0,
7087
+ customProperties: customProperties.length > 0 ? customProperties : void 0,
7088
+ tags: tagCollections.length > 0 ? tagCollections : void 0,
7089
+ notesMaster,
7090
+ handoutMaster
7091
+ };
7092
+ try {
7093
+ exportDeckJson(data, sourceName);
7094
+ } catch (err) {
7095
+ console.error("[PowerPointViewer] JSON export failed:", err);
7096
+ }
7097
+ };
6967
7098
  const handleSaveAsPptx = () => {
6968
7099
  void handleSaveAsFormat("pptx");
6969
7100
  };
@@ -6974,6 +7105,7 @@ function useExportSaveAs(input) {
6974
7105
  void handleSaveAsFormat("pptm");
6975
7106
  };
6976
7107
  return {
7108
+ handleExportJson,
6977
7109
  handlePackageForSharing,
6978
7110
  handleSaveAsFormat,
6979
7111
  handleSaveAsPptx,
@@ -7025,6 +7157,8 @@ function useExportHandlers(input) {
7025
7157
  handoutMaster,
7026
7158
  guides,
7027
7159
  activeSlideIndexForGuides,
7160
+ theme,
7161
+ canvasSize,
7028
7162
  password
7029
7163
  } = input;
7030
7164
  const [exportModalOpen, setExportModalOpen] = useState(false);
@@ -7040,6 +7174,7 @@ function useExportHandlers(input) {
7040
7174
  exportAbortRef
7041
7175
  };
7042
7176
  const {
7177
+ handleExportJson,
7043
7178
  handlePackageForSharing,
7044
7179
  handleSaveAsFormat,
7045
7180
  handleSaveAsPptx,
@@ -7063,6 +7198,8 @@ function useExportHandlers(input) {
7063
7198
  handoutMaster,
7064
7199
  guides,
7065
7200
  activeSlideIndexForGuides,
7201
+ theme,
7202
+ canvasSize,
7066
7203
  modalControls,
7067
7204
  password
7068
7205
  });
@@ -7273,6 +7410,7 @@ function useExportHandlers(input) {
7273
7410
  handleCopySlideAsImage,
7274
7411
  handleExportVideo,
7275
7412
  handleExportGif,
7413
+ handleExportJson,
7276
7414
  handlePackageForSharing,
7277
7415
  handleSaveAsFormat,
7278
7416
  handleSaveAsPptx,
@@ -8850,7 +8988,9 @@ function useEditorOperations(input) {
8850
8988
  setActiveSlideIndex: state.setActiveSlideIndex,
8851
8989
  ops,
8852
8990
  history,
8853
- handlerRef
8991
+ handlerRef,
8992
+ canvasSize,
8993
+ theme: state.theme
8854
8994
  });
8855
8995
  const tableOps = useTableOperations({
8856
8996
  selectedElement,
@@ -8987,6 +9127,8 @@ function useIOHandlers(input) {
8987
9127
  handoutMaster: state.handoutMaster,
8988
9128
  guides: state.guides,
8989
9129
  activeSlideIndexForGuides: state.activeSlideIndex,
9130
+ theme: state.theme,
9131
+ canvasSize,
8990
9132
  password
8991
9133
  });
8992
9134
  const printHandlers = usePrintHandlers({
@@ -10634,6 +10776,7 @@ function buildToolbarProps(input) {
10634
10776
  onExportPdf: exportHandlers.handleExportPdf,
10635
10777
  onExportVideo: exportHandlers.handleExportVideo,
10636
10778
  onExportGif: exportHandlers.handleExportGif,
10779
+ onExportJson: exportHandlers.handleExportJson,
10637
10780
  onPackageForSharing: exportHandlers.handlePackageForSharing,
10638
10781
  onOpenFile,
10639
10782
  onOpenRecentFile,
@@ -10664,6 +10807,8 @@ function buildToolbarProps(input) {
10664
10807
  onSetOverflowMenuOpen: s.setIsOverflowMenuOpen,
10665
10808
  layoutOptions: scopedLayoutOptions,
10666
10809
  onInsertSlideFromLayout: slideOps.handleInsertSlideFromLayout,
10810
+ onInsertSlideFromTemplate: slideOps.handleInsertSlideFromTemplate,
10811
+ templateScheme: templateSchemeFromTheme(s.theme?.colorScheme),
10667
10812
  customShows: s.customShows,
10668
10813
  activeCustomShowId: s.activeCustomShowId,
10669
10814
  onSetActiveCustomShowId: s.setActiveCustomShowId,