pptx-react-viewer 2.17.0 → 2.18.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 (133) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/README.md +14 -14
  3. package/dist/{AiChatPanel-RZ4A7P4H.mjs → AiChatPanel-SSSBERWJ.mjs} +4 -4
  4. package/dist/AiChatPanel-SSSBERWJ.mjs.br +0 -0
  5. package/dist/AiChatPanel-SSSBERWJ.mjs.gz +0 -0
  6. package/dist/{AiChatPanel-HCHCVQN2.js → AiChatPanel-UN5DHPZY.js} +24 -24
  7. package/dist/AiChatPanel-UN5DHPZY.js.br +0 -0
  8. package/dist/AiChatPanel-UN5DHPZY.js.gz +0 -0
  9. package/dist/{Model3DScene-LK7LSQNH.js → Model3DScene-4RPYKC2I.js} +2 -2
  10. package/dist/Model3DScene-4RPYKC2I.js.br +0 -0
  11. package/dist/Model3DScene-4RPYKC2I.js.gz +0 -0
  12. package/dist/{Model3DScene-I7FR74AD.mjs → Model3DScene-LYEESYAI.mjs} +1 -1
  13. package/dist/Model3DScene-LYEESYAI.mjs.br +0 -0
  14. package/dist/Model3DScene-LYEESYAI.mjs.gz +0 -0
  15. package/dist/{PowerPointViewer-Du7u4INi.d.ts → PowerPointViewer-Cf4YHjdF.d.ts} +2 -2
  16. package/dist/{PowerPointViewer-Du7u4INi.d.ts.map → PowerPointViewer-Cf4YHjdF.d.ts.map} +1 -1
  17. package/dist/{SurfaceChart3DScene-ODQY77SZ.js → SurfaceChart3DScene-ACPKCWLJ.js} +2 -2
  18. package/dist/SurfaceChart3DScene-ACPKCWLJ.js.br +0 -0
  19. package/dist/SurfaceChart3DScene-ACPKCWLJ.js.gz +0 -0
  20. package/dist/{SurfaceChart3DScene-DEQP5O3U.mjs → SurfaceChart3DScene-JR62SOYO.mjs} +1 -1
  21. package/dist/{SurfaceChart3DScene-DEQP5O3U.mjs.br → SurfaceChart3DScene-JR62SOYO.mjs.br} +0 -0
  22. package/dist/SurfaceChart3DScene-JR62SOYO.mjs.gz +0 -0
  23. package/dist/{audience-content-store-BvqKy7Hf.d.ts → audience-content-store-CyS0oP6t.d.ts} +2 -2
  24. package/dist/{audience-content-store-BvqKy7Hf.d.ts.map → audience-content-store-CyS0oP6t.d.ts.map} +1 -1
  25. package/dist/{chunk-5BXATG54.js → chunk-4LWGAVAP.js} +239 -293
  26. package/dist/chunk-4LWGAVAP.js.br +0 -0
  27. package/dist/chunk-4LWGAVAP.js.gz +0 -0
  28. package/dist/{chunk-FXJOTEPO.mjs → chunk-7XF6S4AM.mjs} +1 -1
  29. package/dist/chunk-7XF6S4AM.mjs.br +0 -0
  30. package/dist/chunk-7XF6S4AM.mjs.gz +0 -0
  31. package/dist/{chunk-TCGXGD6E.js → chunk-ASKYZ5ZY.js} +544 -426
  32. package/dist/chunk-ASKYZ5ZY.js.br +0 -0
  33. package/dist/chunk-ASKYZ5ZY.js.gz +0 -0
  34. package/dist/{chunk-MQHC5TXI.mjs → chunk-BZOL6FXF.mjs} +25 -80
  35. package/dist/chunk-BZOL6FXF.mjs.br +0 -0
  36. package/dist/chunk-BZOL6FXF.mjs.gz +0 -0
  37. package/dist/{chunk-K2QU73KB.mjs → chunk-GODW6RNR.mjs} +9801 -6455
  38. package/dist/chunk-GODW6RNR.mjs.br +0 -0
  39. package/dist/chunk-GODW6RNR.mjs.gz +0 -0
  40. package/dist/{chunk-NQJPPIVH.js → chunk-ICZDMFF2.js} +1444 -1131
  41. package/dist/chunk-ICZDMFF2.js.br +0 -0
  42. package/dist/chunk-ICZDMFF2.js.gz +0 -0
  43. package/dist/{chunk-ATOUVRRQ.js → chunk-MAVLV56S.js} +3 -3
  44. package/dist/chunk-MAVLV56S.js.br +0 -0
  45. package/dist/chunk-MAVLV56S.js.gz +0 -0
  46. package/dist/{chunk-422DF424.mjs → chunk-O7FTUUXP.mjs} +464 -151
  47. package/dist/chunk-O7FTUUXP.mjs.br +0 -0
  48. package/dist/chunk-O7FTUUXP.mjs.gz +0 -0
  49. package/dist/{chunk-ZA5JONCW.mjs → chunk-QUB5OSKY.mjs} +193 -75
  50. package/dist/chunk-QUB5OSKY.mjs.br +0 -0
  51. package/dist/chunk-QUB5OSKY.mjs.gz +0 -0
  52. package/dist/{chunk-AONFHTTJ.js → chunk-RTUGI4HQ.js} +27 -4
  53. package/dist/chunk-RTUGI4HQ.js.br +0 -0
  54. package/dist/chunk-RTUGI4HQ.js.gz +0 -0
  55. package/dist/{chunk-S64T7C4V.mjs → chunk-SNL6LBRX.mjs} +27 -4
  56. package/dist/chunk-SNL6LBRX.mjs.br +0 -0
  57. package/dist/{chunk-S64T7C4V.mjs.gz → chunk-SNL6LBRX.mjs.gz} +0 -0
  58. package/dist/{chunk-7JPLVECA.js → chunk-WVDM36ZM.js} +9838 -6458
  59. package/dist/chunk-WVDM36ZM.js.br +0 -0
  60. package/dist/chunk-WVDM36ZM.js.gz +0 -0
  61. package/dist/i18n.js +4 -4
  62. package/dist/i18n.js.br +0 -0
  63. package/dist/i18n.js.gz +0 -0
  64. package/dist/i18n.mjs +1 -1
  65. package/dist/i18n.mjs.br +0 -0
  66. package/dist/i18n.mjs.gz +0 -0
  67. package/dist/index.d.ts +497 -16
  68. package/dist/index.d.ts.map +1 -1
  69. package/dist/index.js +65 -41
  70. package/dist/index.js.br +0 -0
  71. package/dist/index.js.gz +0 -0
  72. package/dist/index.mjs +6 -6
  73. package/dist/index.mjs.br +0 -0
  74. package/dist/index.mjs.gz +0 -0
  75. package/dist/internals.d.ts +543 -32
  76. package/dist/internals.d.ts.map +1 -1
  77. package/dist/internals.js +79 -79
  78. package/dist/internals.js.br +0 -0
  79. package/dist/internals.js.gz +0 -0
  80. package/dist/internals.mjs +4 -4
  81. package/dist/internals.mjs.br +0 -0
  82. package/dist/internals.mjs.gz +0 -0
  83. package/dist/pptx-viewer.css +1 -1
  84. package/dist/pptx-viewer.css.br +0 -0
  85. package/dist/pptx-viewer.css.gz +0 -0
  86. package/dist/{types-DU35aAJK.d.ts → types-C_CTI-QE.d.ts} +3 -31
  87. package/dist/types-C_CTI-QE.d.ts.map +1 -0
  88. package/dist/{useViewerBuildingBlocks-C9-prKYB.d.ts → useViewerBuildingBlocks-DItilDbP.d.ts} +16 -3
  89. package/dist/useViewerBuildingBlocks-DItilDbP.d.ts.map +1 -0
  90. package/dist/viewer/index.d.ts +427 -39
  91. package/dist/viewer/index.js +27 -27
  92. package/dist/viewer/index.js.br +0 -0
  93. package/dist/viewer/index.js.gz +0 -0
  94. package/dist/viewer/index.mjs +6 -6
  95. package/dist/viewer/index.mjs.br +0 -0
  96. package/dist/viewer/index.mjs.gz +0 -0
  97. package/package.json +2 -2
  98. package/dist/AiChatPanel-HCHCVQN2.js.br +0 -0
  99. package/dist/AiChatPanel-HCHCVQN2.js.gz +0 -0
  100. package/dist/AiChatPanel-RZ4A7P4H.mjs.br +0 -0
  101. package/dist/AiChatPanel-RZ4A7P4H.mjs.gz +0 -0
  102. package/dist/Model3DScene-I7FR74AD.mjs.br +0 -0
  103. package/dist/Model3DScene-I7FR74AD.mjs.gz +0 -0
  104. package/dist/Model3DScene-LK7LSQNH.js.br +0 -0
  105. package/dist/Model3DScene-LK7LSQNH.js.gz +0 -0
  106. package/dist/SurfaceChart3DScene-DEQP5O3U.mjs.gz +0 -0
  107. package/dist/SurfaceChart3DScene-ODQY77SZ.js.br +0 -0
  108. package/dist/SurfaceChart3DScene-ODQY77SZ.js.gz +0 -0
  109. package/dist/chunk-422DF424.mjs.br +0 -0
  110. package/dist/chunk-422DF424.mjs.gz +0 -0
  111. package/dist/chunk-5BXATG54.js.br +0 -0
  112. package/dist/chunk-5BXATG54.js.gz +0 -0
  113. package/dist/chunk-7JPLVECA.js.br +0 -0
  114. package/dist/chunk-7JPLVECA.js.gz +0 -0
  115. package/dist/chunk-AONFHTTJ.js.br +0 -0
  116. package/dist/chunk-AONFHTTJ.js.gz +0 -0
  117. package/dist/chunk-ATOUVRRQ.js.br +0 -0
  118. package/dist/chunk-ATOUVRRQ.js.gz +0 -0
  119. package/dist/chunk-FXJOTEPO.mjs.br +0 -0
  120. package/dist/chunk-FXJOTEPO.mjs.gz +0 -0
  121. package/dist/chunk-K2QU73KB.mjs.br +0 -0
  122. package/dist/chunk-K2QU73KB.mjs.gz +0 -0
  123. package/dist/chunk-MQHC5TXI.mjs.br +0 -0
  124. package/dist/chunk-MQHC5TXI.mjs.gz +0 -0
  125. package/dist/chunk-NQJPPIVH.js.br +0 -0
  126. package/dist/chunk-NQJPPIVH.js.gz +0 -0
  127. package/dist/chunk-S64T7C4V.mjs.br +0 -0
  128. package/dist/chunk-TCGXGD6E.js.br +0 -0
  129. package/dist/chunk-TCGXGD6E.js.gz +0 -0
  130. package/dist/chunk-ZA5JONCW.mjs.br +0 -0
  131. package/dist/chunk-ZA5JONCW.mjs.gz +0 -0
  132. package/dist/types-DU35aAJK.d.ts.map +0 -1
  133. package/dist/useViewerBuildingBlocks-C9-prKYB.d.ts.map +0 -1
@@ -1,6 +1,6 @@
1
- import { cloneHistorySnapshot, MIN_ELEMENT_SIZE, ZOOM_TO_SELECTION_PADDING, DEFAULT_CANVAS_HEIGHT, DEFAULT_CANVAS_WIDTH, UNGROUPED_SECTION_ID, DEFAULT_TABLE_ROWS, DEFAULT_TABLE_COLUMNS, executeMediaCommand, buildPdfFromImageData, buildNotesPdf, EMU_PER_PX, GRID_SIZE, DEFAULT_TEXT_FONT_SIZE } from './chunk-MQHC5TXI.mjs';
2
- import { translationsEn } from './chunk-S64T7C4V.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, createWheelStepBuffer, createViewerZoomStore, clampZoomScale, mapEditingWheel, 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, buildMorphAnimationRules, findInSlides, applyFindReplacements, createCollaborationLivePatcher, publishLiveInlineText, PptxHandler, collectMediaElements, collectImagePaths, partitionTemplateElements, buildInitialGuides, EncryptedFileError, saveAutosaveSnapshot, updateMasterViewElement, isTemplateElementId, hasShapeProperties, hasTextProperties, getInlineEditorSelection, applyStyleToSelectedSegments, setPendingSelectionRestore, applyCaseTransformToSegments, transformTextCase, masterViewElements, replaceMasterViewElements, 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, describeFontEmbedding, mayLeaveSlideShow, stopAllPersistentAudio, remapTextToSegments, guidePxToEmu, buildSaveSlides, embeddedFontSaveOptions, saveDeckWithPassword, shouldLoopContinuously, applyRehearsalTimings, copyFormatFromElement, applyFormatToElement, mapEditorKey, isEditorTextInputTarget, createViewerOptionsStore, readSlidesFromYDoc, reconcileSlidesInYDoc, LOCAL_SYNC_ORIGIN, observeYDocSlides, shouldAutoFollowBroadcaster, createTouchGestureRecognizer, MAX_ZOOM_SCALE, MIN_ZOOM_SCALE, isKeyboardOpen, scopeLayoutOptionsToSlide, openPptxFile, readBackstageRecentFile, isActionHidden, canInteractWithElement, filterInteractableIds, buildElementClipboardPayload, generatePackageReadme, exportDeckJson, groupElements, generateElementId, makeCloneId, ungroupElements, alignElements, distributeElements, bringForward, sendBackward, bringToFront, sendToBack, newTableElement, createDefaultChartElement, readViewportMetrics, computeKeyboardInset, mergeShapes, mapPresentationKey, lastShowSlideIndex, firstShowSlideIndex, mapPresentationWheel, 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, masterViewPseudoSlide, 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, getDraggedShapeAdjustmentValue, computeMarqueeHitIds, mergeAdditiveSelection, applyResize, snapBoxToGrid, applyMotionPathPreset } from './chunk-K2QU73KB.mjs';
1
+ import { cloneHistorySnapshot, MIN_ELEMENT_SIZE, ZOOM_TO_SELECTION_PADDING, DEFAULT_CANVAS_HEIGHT, DEFAULT_CANVAS_WIDTH, UNGROUPED_SECTION_ID, DEFAULT_SECTION_GROUP_ID, DEFAULT_TABLE_ROWS, DEFAULT_TABLE_COLUMNS, executeMediaCommand, buildPdfFromImageData, buildNotesPdf, EMU_PER_PX, GRID_SIZE, DEFAULT_TEXT_FONT_SIZE } from './chunk-BZOL6FXF.mjs';
2
+ import { translationsEn } from './chunk-SNL6LBRX.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, createWheelStepBuffer, createViewerZoomStore, clampZoomScale, mapEditingWheel, 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, buildMorphAnimationRules, findInSlides, applyFindReplacements, createCollaborationLivePatcher, publishLiveInlineText, PptxHandler, collectMediaElements, collectImagePaths, partitionTemplateElements, resolveAuthoredCustomShowId, buildInitialGuides, EncryptedFileError, shouldWriteAutosaveSnapshot, saveAutosaveSnapshot, autosaveSnapshotMark, updateMasterViewElement, isTemplateElementId, hasShapeProperties, hasTextProperties, getInlineEditorSelection, applyStyleToSelectedSegments, setPendingSelectionRestore, applyCaseTransformToSegments, transformTextCase, masterViewElements, replaceMasterViewElements, 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, describeFontEmbedding, mayLeaveSlideShow, stopAllPersistentAudio, remapTextToSegments, guidePxToEmu, buildSaveSlides, embeddedFontSaveOptions, resolveSlideSizeSelection, saveDeckWithPassword, shouldLoopContinuously, applyRehearsalTimings, copyFormatFromElement, applyFormatToElement, mapEditorKey, isEditorTextInputTarget, createViewerOptionsStore, readSlidesFromYDoc, reconcileSlidesInYDoc, LOCAL_SYNC_ORIGIN, observeYDocSlides, shouldAutoFollowBroadcaster, createTouchGestureRecognizer, MAX_ZOOM_SCALE, MIN_ZOOM_SCALE, isKeyboardOpen, scopeLayoutOptionsToSlide, openPptxFile, readBackstageRecentFile, isActionHidden, canInteractWithElement, filterInteractableIds, beginShapeAdjustment, buildElementClipboardPayload, savedPresentationFileName, generatePackageReadme, presentationBaseName, exportDeckJson, groupElements, generateElementId, makeCloneId, ungroupElements, alignElements, distributeElements, bringForward, sendBackward, bringToFront, sendToBack, newTableElement, createDefaultChartElement, readViewportMetrics, computeKeyboardInset, mergeShapes, mapPresentationKey, lastShowSlideIndex, firstShowSlideIndex, mapPresentationWheel, 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, masterViewPseudoSlide, 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, getDraggedShapeAdjustments, computeMarqueeHitIds, mergeAdditiveSelection, applyResize, snapBoxToGrid, applyMotionPathPreset } from './chunk-GODW6RNR.mjs';
4
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';
@@ -1676,6 +1676,7 @@ function usePresentationKeyboard(input) {
1676
1676
  onToggleInkMarkup,
1677
1677
  onToggleToolbar,
1678
1678
  onShowAllSlides,
1679
+ onToggleSubtitles,
1679
1680
  onToggleBlackScreen,
1680
1681
  onToggleWhiteScreen,
1681
1682
  rehearsing,
@@ -1741,6 +1742,9 @@ function usePresentationKeyboard(input) {
1741
1742
  case "showAllSlides":
1742
1743
  onShowAllSlides?.();
1743
1744
  return;
1745
+ case "toggleSubtitles":
1746
+ onToggleSubtitles?.();
1747
+ return;
1744
1748
  case "toggleBlackScreen":
1745
1749
  onToggleBlackScreen?.();
1746
1750
  return;
@@ -1780,6 +1784,7 @@ function usePresentationKeyboard(input) {
1780
1784
  onToggleInkMarkup,
1781
1785
  onToggleToolbar,
1782
1786
  onShowAllSlides,
1787
+ onToggleSubtitles,
1783
1788
  onToggleBlackScreen,
1784
1789
  onToggleWhiteScreen,
1785
1790
  rehearsing,
@@ -2220,6 +2225,7 @@ function usePresentationMode(input) {
2220
2225
  onEraseAnnotations,
2221
2226
  onToggleInkMarkup,
2222
2227
  onToggleToolbar,
2228
+ onToggleSubtitles,
2223
2229
  onSaveRehearsalTimings,
2224
2230
  loopContinuously,
2225
2231
  showWithAnimation,
@@ -2427,6 +2433,7 @@ function usePresentationMode(input) {
2427
2433
  onToggleInkMarkup,
2428
2434
  onToggleToolbar,
2429
2435
  onShowAllSlides: openAllSlides,
2436
+ onToggleSubtitles,
2430
2437
  onToggleBlackScreen: () => presenterConsole.setBlackout(
2431
2438
  presenterConsole.snapshot.blackout === "black" ? "none" : "black"
2432
2439
  ),
@@ -2909,13 +2916,15 @@ function useFindReplace({
2909
2916
  }, [findResults, applyReplacements, performFind]);
2910
2917
  useEffect(() => {
2911
2918
  const handler = (event) => {
2912
- if ((event.metaKey || event.ctrlKey) && event.key === "f") {
2913
- if (mode !== "edit") {
2914
- return;
2915
- }
2916
- event.preventDefault();
2917
- setFindReplaceOpen((prev) => !prev);
2919
+ const { action } = mapEditorKey(event, {
2920
+ canEdit: mode === "edit",
2921
+ isTextInputTarget: isEditorTextInputTarget(event.target)
2922
+ });
2923
+ if (action !== "find") {
2924
+ return;
2918
2925
  }
2926
+ event.preventDefault();
2927
+ setFindReplaceOpen((prev) => !prev);
2919
2928
  };
2920
2929
  window.addEventListener("keydown", handler);
2921
2930
  return () => window.removeEventListener("keydown", handler);
@@ -3355,9 +3364,28 @@ function useDerivedElementState(input) {
3355
3364
  }
3356
3365
  return templateElementsBySlideId[activeSlide.id] ?? [];
3357
3366
  }, [activeSlide, templateElementsBySlideId]);
3367
+ const activeMaster = slideMasters[activeMasterIndex];
3368
+ const activeLayout = useMemo(
3369
+ () => resolveActiveLayout(activeMaster, activeLayoutIndex),
3370
+ [activeMaster, activeLayoutIndex]
3371
+ );
3372
+ const masterViewElements2 = useMemo(
3373
+ () => computeMasterViewElements(activeMaster, activeLayout),
3374
+ [activeMaster, activeLayout]
3375
+ );
3376
+ const notesMasterElements = useMemo(() => notesMaster?.elements ?? [], [notesMaster]);
3377
+ const handoutMasterElements = useMemo(() => handoutMaster?.elements ?? [], [handoutMaster]);
3358
3378
  const elementLookup = useMemo(
3359
- () => buildElementLookup(templateElements, activeSlide?.elements ?? []),
3360
- [activeSlide, templateElements]
3379
+ () => buildElementLookup(
3380
+ [
3381
+ ...templateElements,
3382
+ ...masterViewElements2,
3383
+ ...notesMasterElements,
3384
+ ...handoutMasterElements
3385
+ ],
3386
+ activeSlide?.elements ?? []
3387
+ ),
3388
+ [activeSlide, templateElements, masterViewElements2, notesMasterElements, handoutMasterElements]
3361
3389
  );
3362
3390
  const selectedElement = useMemo(() => {
3363
3391
  if (!selectedElementId) {
@@ -3374,17 +3402,6 @@ function useDerivedElementState(input) {
3374
3402
  () => effectiveSelectedIds.map((id) => elementLookup.get(id)).filter(Boolean),
3375
3403
  [effectiveSelectedIds, elementLookup]
3376
3404
  );
3377
- const activeMaster = slideMasters[activeMasterIndex];
3378
- const activeLayout = useMemo(
3379
- () => resolveActiveLayout(activeMaster, activeLayoutIndex),
3380
- [activeMaster, activeLayoutIndex]
3381
- );
3382
- const masterViewElements2 = useMemo(
3383
- () => computeMasterViewElements(activeMaster, activeLayout),
3384
- [activeMaster, activeLayout]
3385
- );
3386
- const notesMasterElements = useMemo(() => notesMaster?.elements ?? [], [notesMaster]);
3387
- const handoutMasterElements = useMemo(() => handoutMaster?.elements ?? [], [handoutMaster]);
3388
3405
  return {
3389
3406
  activeSlide,
3390
3407
  templateElements,
@@ -3423,6 +3440,7 @@ function useViewerCoreState(_input) {
3423
3440
  width: DEFAULT_CANVAS_WIDTH,
3424
3441
  height: DEFAULT_CANVAS_HEIGHT
3425
3442
  });
3443
+ const [slideSizeEmu, setSlideSizeEmu] = useState();
3426
3444
  const [activeSlideIndex, setActiveSlideIndex] = useState(0);
3427
3445
  const [selectedElementId, setSelectedElementId] = useState(null);
3428
3446
  const [selectedElementIds, setSelectedElementIds] = useState([]);
@@ -3521,6 +3539,8 @@ function useViewerCoreState(_input) {
3521
3539
  setTemplateElementsBySlideId,
3522
3540
  canvasSize,
3523
3541
  setCanvasSize,
3542
+ slideSizeEmu,
3543
+ setSlideSizeEmu,
3524
3544
  activeSlideIndex,
3525
3545
  setActiveSlideIndex,
3526
3546
  selectedElementId,
@@ -3725,6 +3745,7 @@ function useLoadContent({
3725
3745
  setTemplateElementsBySlideId,
3726
3746
  mediaDataUrls,
3727
3747
  setCanvasSize,
3748
+ setSlideSizeEmu,
3728
3749
  setHeaderFooter,
3729
3750
  setLayoutOptions,
3730
3751
  setSlideMasters,
@@ -3732,6 +3753,7 @@ function useLoadContent({
3732
3753
  setTableStyleMap,
3733
3754
  setThemeOptions,
3734
3755
  setCustomShows,
3756
+ setActiveCustomShowId,
3735
3757
  setSections,
3736
3758
  setPresentationProperties,
3737
3759
  setNotesMaster,
@@ -3891,6 +3913,13 @@ function useLoadContent({
3891
3913
  width: parsed.width ?? DEFAULT_CANVAS_WIDTH,
3892
3914
  height: parsed.height ?? DEFAULT_CANVAS_HEIGHT
3893
3915
  });
3916
+ setSlideSizeEmu(
3917
+ typeof parsed.widthEmu === "number" && typeof parsed.heightEmu === "number" && parsed.widthEmu > 0 && parsed.heightEmu > 0 ? {
3918
+ widthEmu: parsed.widthEmu,
3919
+ heightEmu: parsed.heightEmu,
3920
+ type: parsed.slideSizeType ?? ""
3921
+ } : void 0
3922
+ );
3894
3923
  setHeaderFooter(parsed.headerFooter ?? {});
3895
3924
  setLayoutOptions(parsed.layoutOptions ?? []);
3896
3925
  setSlideMasters(parsed.slideMasters ?? []);
@@ -3898,6 +3927,9 @@ function useLoadContent({
3898
3927
  setTableStyleMap(parsed.tableStyleMap);
3899
3928
  setThemeOptions(parsed.themeOptions ?? []);
3900
3929
  setCustomShows(parsed.customShows ?? []);
3930
+ setActiveCustomShowId(
3931
+ resolveAuthoredCustomShowId(parsed.presentationProperties, parsed.customShows) ?? null
3932
+ );
3901
3933
  setSections(parsed.sections ?? []);
3902
3934
  setPresentationProperties(parsed.presentationProperties ?? {});
3903
3935
  setNotesMaster(parsed.notesMaster);
@@ -3966,7 +3998,8 @@ function useAutosave(input) {
3966
3998
  filePath,
3967
3999
  serializeSlides,
3968
4000
  intervalSeconds = DEFAULT_AUTOSAVE_INTERVAL_SECONDS,
3969
- enabled = true
4001
+ enabled = true,
4002
+ getChangeSources
3970
4003
  } = input;
3971
4004
  const [autosaveStatus, setAutosaveStatus] = useState({
3972
4005
  state: "idle"
@@ -3975,6 +4008,8 @@ function useAutosave(input) {
3975
4008
  const filePathRef = useRef(filePath);
3976
4009
  const serializeRef = useRef(serializeSlides);
3977
4010
  const isSavingRef = useRef(false);
4011
+ const changeSourcesRef = useRef(getChangeSources);
4012
+ const lastSnapshotRef = useRef(void 0);
3978
4013
  useEffect(() => {
3979
4014
  isDirtyRef.current = isDirty;
3980
4015
  }, [isDirty]);
@@ -3984,14 +4019,22 @@ function useAutosave(input) {
3984
4019
  useEffect(() => {
3985
4020
  serializeRef.current = serializeSlides;
3986
4021
  }, [serializeSlides]);
3987
- const doAutosave = useCallback(async () => {
3988
- if (!filePathRef.current) {
3989
- return;
3990
- }
3991
- if (!isDirtyRef.current) {
3992
- return;
3993
- }
3994
- if (isSavingRef.current) {
4022
+ useEffect(() => {
4023
+ changeSourcesRef.current = getChangeSources;
4024
+ }, [getChangeSources]);
4025
+ const doAutosave = useCallback(async (options) => {
4026
+ const path = filePathRef.current;
4027
+ if (!path) {
4028
+ return;
4029
+ }
4030
+ const sources = changeSourcesRef.current?.() ?? [];
4031
+ if (!shouldWriteAutosaveSnapshot({
4032
+ filePath: path,
4033
+ isDirty: isDirtyRef.current,
4034
+ saving: isSavingRef.current,
4035
+ sources: options?.polled === true ? sources : [],
4036
+ lastSnapshot: lastSnapshotRef.current
4037
+ })) {
3995
4038
  return;
3996
4039
  }
3997
4040
  isSavingRef.current = true;
@@ -4003,7 +4046,8 @@ function useAutosave(input) {
4003
4046
  isSavingRef.current = false;
4004
4047
  return;
4005
4048
  }
4006
- await saveAutosaveSnapshot(filePathRef.current, data);
4049
+ await saveAutosaveSnapshot(path, data);
4050
+ lastSnapshotRef.current = autosaveSnapshotMark(path, sources);
4007
4051
  setAutosaveStatus({ state: "saved", timestamp: Date.now() });
4008
4052
  } catch (err) {
4009
4053
  setAutosaveStatus({
@@ -4029,13 +4073,13 @@ function useAutosave(input) {
4029
4073
  setAutosaveStatus((prev) => prev.state === "disabled" ? { state: "idle" } : prev);
4030
4074
  const ms = computeAutosaveIntervalMs(intervalSeconds);
4031
4075
  const id = setInterval(() => {
4032
- void doAutosave();
4076
+ void doAutosave({ polled: true });
4033
4077
  }, ms);
4034
4078
  return () => clearInterval(id);
4035
4079
  }, [enabled, filePath, intervalSeconds, doAutosave]);
4036
4080
  return {
4037
4081
  autosaveStatus,
4038
- triggerAutosave: doAutosave
4082
+ triggerAutosave: () => doAutosave()
4039
4083
  };
4040
4084
  }
4041
4085
  function useElementOperations(input) {
@@ -4327,13 +4371,23 @@ function useSectionOperations(input) {
4327
4371
  },
4328
4372
  [sections, slides, setSlides, setSections, markDirty]
4329
4373
  );
4374
+ const toggleSectionCollapse = useCallback(
4375
+ (sectionId) => {
4376
+ setSections(
4377
+ (prev) => prev.map((sec) => sec.id === sectionId ? { ...sec, collapsed: !sec.collapsed } : sec)
4378
+ );
4379
+ markDirty();
4380
+ },
4381
+ [setSections, markDirty]
4382
+ );
4330
4383
  return {
4331
4384
  addSection: addSection2,
4332
4385
  renameSection: renameSection2,
4333
4386
  deleteSection: deleteSection2,
4334
4387
  moveSectionUp: moveSectionUp2,
4335
4388
  moveSectionDown: moveSectionDown2,
4336
- moveSlidesToSection: moveSlidesToSection2
4389
+ moveSlidesToSection: moveSlidesToSection2,
4390
+ toggleSectionCollapse
4337
4391
  };
4338
4392
  }
4339
4393
 
@@ -4551,13 +4605,14 @@ function processResizeMove(e, rs, editorScale, snapToGrid, gridSpacingPx, live)
4551
4605
  }
4552
4606
  function processAdjustmentMove(e, adj, editorScale, updateElementById) {
4553
4607
  const dx = (e.clientX - adj.startClientX) / editorScale;
4554
- const newValue = getDraggedShapeAdjustmentValue(adj, dx);
4555
- if (!adj.moved && Math.abs(dx) > 2) {
4608
+ const dy = (e.clientY - adj.startClientY) / editorScale;
4609
+ const adjustments = getDraggedShapeAdjustments(adj, dx, dy);
4610
+ if (!adj.moved && Math.hypot(dx, dy) > 2) {
4556
4611
  adj.moved = true;
4557
4612
  }
4558
4613
  if (adj.moved) {
4559
4614
  updateElementById(adj.elementId, {
4560
- shapeAdjustments: { [adj.key]: newValue }
4615
+ shapeAdjustments: adjustments
4561
4616
  });
4562
4617
  }
4563
4618
  }
@@ -5034,33 +5089,18 @@ function useCanvasInteractions(input) {
5034
5089
  const handleFormatText = (updates) => {
5035
5090
  ops.updateSelectedTextStyle(updates);
5036
5091
  };
5037
- const handleAdjustmentPointerDown = (elementId, e) => {
5092
+ const handleAdjustmentPointerDown = (elementId, e, descriptor) => {
5038
5093
  e.stopPropagation();
5039
5094
  const el = elementLookup.get(elementId);
5040
- if (!el || !("shapeType" in el) || !("shapeAdjustments" in el)) {
5041
- return;
5042
- }
5043
- if (!canInteractWithElement(el, "adjustHandle")) {
5095
+ if (!el || !canInteractWithElement(el, "adjustHandle")) {
5044
5096
  return;
5045
5097
  }
5046
- const adjEntries = Object.entries(
5047
- el.shapeAdjustments ?? {}
5098
+ shapeAdjustmentDragStateRef.current = beginShapeAdjustment(
5099
+ el,
5100
+ descriptor,
5101
+ e.clientX,
5102
+ e.clientY
5048
5103
  );
5049
- if (!adjEntries.length) {
5050
- return;
5051
- }
5052
- const [key, value] = adjEntries[0];
5053
- shapeAdjustmentDragStateRef.current = {
5054
- elementId,
5055
- key,
5056
- shapeType: el.shapeType ?? "rect",
5057
- startClientX: e.clientX,
5058
- startClientY: e.clientY,
5059
- startAdjustment: value,
5060
- startWidth: el.width,
5061
- startHeight: el.height,
5062
- moved: false
5063
- };
5064
5104
  };
5065
5105
  return {
5066
5106
  handleElementClick,
@@ -6975,12 +7015,14 @@ function useExportSaveAs(input) {
6975
7015
  appProperties,
6976
7016
  customProperties,
6977
7017
  tagCollections,
7018
+ slideMasters,
6978
7019
  notesMaster,
6979
7020
  handoutMaster,
6980
7021
  guides,
6981
7022
  activeSlideIndexForGuides,
6982
7023
  theme,
6983
7024
  canvasSize,
7025
+ slideSizeEmu,
6984
7026
  modalControls,
6985
7027
  password
6986
7028
  } = input;
@@ -7004,7 +7046,7 @@ function useExportSaveAs(input) {
7004
7046
  setExportProgress(10);
7005
7047
  setExportStatusMessage("Adding presentation...");
7006
7048
  const pptxData = await serializeSlides();
7007
- const pptxFilename = filePath ? filePath.replace(/\\/gu, "/").split("/").pop() ?? "presentation.pptx" : "presentation.pptx";
7049
+ const pptxFilename = savedPresentationFileName(filePath);
7008
7050
  if (pptxData) {
7009
7051
  pkgFolder.file(pptxFilename, pptxData);
7010
7052
  }
@@ -7020,8 +7062,7 @@ function useExportSaveAs(input) {
7020
7062
  const zipBlob = await zip.generateAsync({ type: "blob" });
7021
7063
  setExportProgress(95);
7022
7064
  setExportStatusMessage("Downloading...");
7023
- const baseName = pptxFilename.replace(/\.[^.]+$/u, "");
7024
- downloadBlob(zipBlob, `${baseName}-package.zip`);
7065
+ downloadBlob(zipBlob, `${presentationBaseName(pptxFilename)}-package.zip`);
7025
7066
  setExportProgress(100);
7026
7067
  } catch (err) {
7027
7068
  if (err.name !== "AbortError") {
@@ -7037,16 +7078,15 @@ function useExportSaveAs(input) {
7037
7078
  if (!handler) {
7038
7079
  return;
7039
7080
  }
7040
- const ext = format === "ppsx" ? "ppsx" : format === "pptm" ? "pptm" : "pptx";
7041
- const baseName = filePath ? filePath.replace(/\\/gu, "/").split("/").pop()?.replace(/\.[^.]+$/u, "") ?? "presentation" : "presentation";
7081
+ const downloadName = savedPresentationFileName(filePath, format);
7042
7082
  try {
7043
7083
  const data = await buildSaveAsData(handler, format);
7044
7084
  const blob = new Blob([data], {
7045
7085
  type: "application/vnd.openxmlformats-officedocument.presentationml.presentation"
7046
7086
  });
7047
- downloadBlob(blob, `${baseName}.${ext}`);
7087
+ downloadBlob(blob, downloadName);
7048
7088
  } catch (err) {
7049
- console.error(`[PowerPointViewer] Save as .${ext} failed:`, err);
7089
+ console.error(`[PowerPointViewer] Save as .${format} failed:`, err);
7050
7090
  }
7051
7091
  };
7052
7092
  const buildSaveAsData = async (handler, format) => {
@@ -7066,6 +7106,9 @@ function useExportSaveAs(input) {
7066
7106
  });
7067
7107
  const slidesToSave = buildSaveSlides(slidesWithGuides, templateElementsBySlideId);
7068
7108
  const saveOptions = {
7109
+ // Save As shares Save's slide-size decision; leaving it out here is how
7110
+ // a preset picked in the inspector reached one save path and not the other.
7111
+ slideSize: resolveSlideSizeSelection({ current: slideSizeEmu, canvas: canvasSize }).size,
7069
7112
  headerFooter,
7070
7113
  presentationProperties,
7071
7114
  customShows: customShows.length > 0 ? customShows : void 0,
@@ -7074,6 +7117,7 @@ function useExportSaveAs(input) {
7074
7117
  appProperties: appProperties ?? void 0,
7075
7118
  customProperties: customProperties.length > 0 ? customProperties : void 0,
7076
7119
  tags: tagCollections.length > 0 ? tagCollections : void 0,
7120
+ slideMasters,
7077
7121
  notesMaster,
7078
7122
  handoutMaster,
7079
7123
  outputFormat: format
@@ -7082,12 +7126,14 @@ function useExportSaveAs(input) {
7082
7126
  };
7083
7127
  const handleExportJson = () => {
7084
7128
  const sourceName = filePath ? filePath.replace(/\\/gu, "/").split("/").pop() : void 0;
7129
+ const slideSize = resolveSlideSizeSelection({ current: slideSizeEmu, canvas: canvasSize }).size;
7085
7130
  const data = {
7086
7131
  slides: buildSaveSlides(slides, templateElementsBySlideId),
7087
7132
  width: canvasSize.width,
7088
7133
  height: canvasSize.height,
7089
- widthEmu: guidePxToEmu(canvasSize.width),
7090
- heightEmu: guidePxToEmu(canvasSize.height),
7134
+ widthEmu: slideSize.widthEmu,
7135
+ heightEmu: slideSize.heightEmu,
7136
+ slideSizeType: slideSize.type === "" ? void 0 : slideSize.type,
7091
7137
  theme,
7092
7138
  headerFooter,
7093
7139
  presentationProperties,
@@ -7164,12 +7210,14 @@ function useExportHandlers(input) {
7164
7210
  appProperties,
7165
7211
  customProperties,
7166
7212
  tagCollections,
7213
+ slideMasters,
7167
7214
  notesMaster,
7168
7215
  handoutMaster,
7169
7216
  guides,
7170
7217
  activeSlideIndexForGuides,
7171
7218
  theme,
7172
7219
  canvasSize,
7220
+ slideSizeEmu,
7173
7221
  password
7174
7222
  } = input;
7175
7223
  const [exportModalOpen, setExportModalOpen] = useState(false);
@@ -7205,12 +7253,14 @@ function useExportHandlers(input) {
7205
7253
  appProperties,
7206
7254
  customProperties,
7207
7255
  tagCollections,
7256
+ slideMasters,
7208
7257
  notesMaster,
7209
7258
  handoutMaster,
7210
7259
  guides,
7211
7260
  activeSlideIndexForGuides,
7212
7261
  theme,
7213
7262
  canvasSize,
7263
+ slideSizeEmu,
7214
7264
  modalControls,
7215
7265
  password
7216
7266
  });
@@ -8380,7 +8430,7 @@ function computeVisibleSlideIndexes(slides, activeCustomShowId, customShows) {
8380
8430
  }
8381
8431
  function computeSlideSectionGroups(slides, sections) {
8382
8432
  return groupSlidesBySection(sections, slides).map((group) => ({
8383
- id: group.section?.id ?? (sections.length > 0 ? UNGROUPED_SECTION_ID : "default"),
8433
+ id: group.section?.id ?? (sections.length > 0 ? UNGROUPED_SECTION_ID : DEFAULT_SECTION_GROUP_ID),
8384
8434
  label: group.section?.name ?? (sections.length > 0 ? "Ungrouped Slides" : "Slides"),
8385
8435
  slideIndexes: group.slideIndexes,
8386
8436
  ...group.section?.color !== void 0 ? { color: group.section.color } : {},
@@ -8423,7 +8473,7 @@ function useDerivedSlideState(input) {
8423
8473
  if (group.id === UNGROUPED_SECTION_ID && group.label === "Ungrouped Slides") {
8424
8474
  return { ...group, label: t("pptx.slides.ungroupedSlides") };
8425
8475
  }
8426
- if (group.id === "default" && group.label === "Slides") {
8476
+ if (group.id === DEFAULT_SECTION_GROUP_ID && group.label === "Slides") {
8427
8477
  return { ...group, label: t("pptx.sections.slides") };
8428
8478
  }
8429
8479
  return group;
@@ -8577,6 +8627,8 @@ function useSerialize(input) {
8577
8627
  slides,
8578
8628
  templateElementsBySlideId,
8579
8629
  activeSlideIndex,
8630
+ canvasSize,
8631
+ slideSizeEmu,
8580
8632
  guides,
8581
8633
  headerFooter,
8582
8634
  presentationProperties,
@@ -8586,6 +8638,7 @@ function useSerialize(input) {
8586
8638
  appProperties,
8587
8639
  customProperties,
8588
8640
  tagCollections,
8641
+ slideMasters,
8589
8642
  notesMaster,
8590
8643
  handoutMaster,
8591
8644
  handlerRef,
@@ -8634,6 +8687,10 @@ function useSerialize(input) {
8634
8687
  });
8635
8688
  const slidesToSave = buildSaveSlides(slidesWithGuides, templateElementsBySlideId);
8636
8689
  const saveOptions = {
8690
+ // Without this the Slide Size card edited a viewer-only pixel value and
8691
+ // the saved `p:sldSz` never moved: passing `slideSize` is the only way a
8692
+ // slide-size edit reaches the file.
8693
+ slideSize: resolveSlideSizeSelection({ current: slideSizeEmu, canvas: canvasSize }).size,
8637
8694
  headerFooter,
8638
8695
  presentationProperties,
8639
8696
  customShows: customShows.length > 0 ? customShows : void 0,
@@ -8642,6 +8699,7 @@ function useSerialize(input) {
8642
8699
  appProperties,
8643
8700
  customProperties: customProperties.length > 0 ? customProperties : void 0,
8644
8701
  tags: tagCollections.length > 0 ? tagCollections : void 0,
8702
+ slideMasters,
8645
8703
  notesMaster,
8646
8704
  handoutMaster,
8647
8705
  ...embeddedFontSaveOptions(embedFonts)
@@ -8650,6 +8708,8 @@ function useSerialize(input) {
8650
8708
  }, [
8651
8709
  slides,
8652
8710
  templateElementsBySlideId,
8711
+ canvasSize,
8712
+ slideSizeEmu,
8653
8713
  headerFooter,
8654
8714
  presentationProperties,
8655
8715
  customShows,
@@ -8658,6 +8718,7 @@ function useSerialize(input) {
8658
8718
  appProperties,
8659
8719
  customProperties,
8660
8720
  tagCollections,
8721
+ slideMasters,
8661
8722
  notesMaster,
8662
8723
  handoutMaster,
8663
8724
  guides,
@@ -8783,7 +8844,8 @@ function usePresentationSetup(input) {
8783
8844
  history,
8784
8845
  endWithBlackSlide = true,
8785
8846
  promptKeepInkAnnotations = true,
8786
- popupToolbarEnabled = true
8847
+ popupToolbarEnabled = true,
8848
+ onToggleSubtitles
8787
8849
  } = input;
8788
8850
  const actionSoundHandlerRef = useRef(null);
8789
8851
  const [, setShowKeepAnnotationsDialog] = useState(false);
@@ -8862,6 +8924,7 @@ function usePresentationSetup(input) {
8862
8924
  onEraseAnnotations: () => annotations.clearAnnotations(),
8863
8925
  onToggleInkMarkup: () => annotations.setInkMarkupVisible(!annotations.inkMarkupVisible),
8864
8926
  onToggleToolbar: () => annotations.setToolbarVisible(!annotations.toolbarVisible),
8927
+ onToggleSubtitles,
8865
8928
  onSaveRehearsalTimings: (timings) => {
8866
8929
  setSlides((prev) => applyRehearsalTimings(prev, timings));
8867
8930
  history.markDirty();
@@ -9161,12 +9224,14 @@ function useIOHandlers(input) {
9161
9224
  appProperties: state.appProperties ?? null,
9162
9225
  customProperties: state.customProperties,
9163
9226
  tagCollections: state.tagCollections,
9227
+ slideMasters: state.slideMasters,
9164
9228
  notesMaster: state.notesMaster,
9165
9229
  handoutMaster: state.handoutMaster,
9166
9230
  guides: state.guides,
9167
9231
  activeSlideIndexForGuides: state.activeSlideIndex,
9168
9232
  theme: state.theme,
9169
9233
  canvasSize,
9234
+ slideSizeEmu: state.slideSizeEmu,
9170
9235
  password
9171
9236
  });
9172
9237
  const printHandlers = usePrintHandlers({
@@ -9391,6 +9456,7 @@ function useContentLifecycle(input) {
9391
9456
  setTemplateElementsBySlideId: state.setTemplateElementsBySlideId,
9392
9457
  mediaDataUrls: state.mediaDataUrls,
9393
9458
  setCanvasSize: state.setCanvasSize,
9459
+ setSlideSizeEmu: state.setSlideSizeEmu,
9394
9460
  setHeaderFooter: state.setHeaderFooter,
9395
9461
  setLayoutOptions: state.setLayoutOptions,
9396
9462
  setSlideMasters: state.setSlideMasters,
@@ -9398,6 +9464,7 @@ function useContentLifecycle(input) {
9398
9464
  setTableStyleMap: state.setTableStyleMap,
9399
9465
  setThemeOptions: state.setThemeOptions,
9400
9466
  setCustomShows: state.setCustomShows,
9467
+ setActiveCustomShowId: state.setActiveCustomShowId,
9401
9468
  setSections: state.setSections,
9402
9469
  setPresentationProperties: state.setPresentationProperties,
9403
9470
  setNotesMaster: state.setNotesMaster,
@@ -9427,6 +9494,8 @@ function useContentLifecycle(input) {
9427
9494
  slides,
9428
9495
  templateElementsBySlideId: state.templateElementsBySlideId,
9429
9496
  activeSlideIndex: state.activeSlideIndex,
9497
+ canvasSize: state.canvasSize,
9498
+ slideSizeEmu: state.slideSizeEmu,
9430
9499
  guides: state.guides,
9431
9500
  headerFooter: state.headerFooter,
9432
9501
  presentationProperties: state.presentationProperties,
@@ -9436,6 +9505,7 @@ function useContentLifecycle(input) {
9436
9505
  appProperties: state.appProperties,
9437
9506
  customProperties: state.customProperties,
9438
9507
  tagCollections: state.tagCollections,
9508
+ slideMasters: state.slideMasters,
9439
9509
  notesMaster: state.notesMaster,
9440
9510
  handoutMaster: state.handoutMaster,
9441
9511
  handlerRef,
@@ -9451,7 +9521,31 @@ function useContentLifecycle(input) {
9451
9521
  filePath,
9452
9522
  serializeSlides: serializeForRecovery,
9453
9523
  enabled: autosaveEnabled,
9454
- ...autosaveIntervalSeconds === void 0 ? {} : { intervalSeconds: autosaveIntervalSeconds }
9524
+ ...autosaveIntervalSeconds === void 0 ? {} : { intervalSeconds: autosaveIntervalSeconds },
9525
+ // Everything `serializeForRecovery` reads that changes by REASSIGNMENT,
9526
+ // so a poll that finds all of them unchanged can skip re-serializing a
9527
+ // deck it has already snapshotted. The two refs are read by `.current`
9528
+ // because an inline edit in progress lives there and nowhere else yet.
9529
+ getChangeSources: () => [
9530
+ slides,
9531
+ state.templateElementsBySlideId,
9532
+ state.guides,
9533
+ state.headerFooter,
9534
+ state.presentationProperties,
9535
+ state.customShows,
9536
+ state.sections,
9537
+ state.coreProperties,
9538
+ state.appProperties,
9539
+ state.customProperties,
9540
+ state.tagCollections,
9541
+ state.notesMaster,
9542
+ state.handoutMaster,
9543
+ state.embeddedFonts,
9544
+ embedFonts,
9545
+ password,
9546
+ state.inlineEditingElementIdRef.current,
9547
+ state.inlineEditingTextRef.current
9548
+ ]
9455
9549
  });
9456
9550
  return { handlerRef, serializeSlides, serializeForRecovery, autosaveStatus };
9457
9551
  }
@@ -9462,7 +9556,14 @@ function useKeyboardShortcuts(input) {
9462
9556
  const current = inputRef.current;
9463
9557
  const { action, dx, dy } = mapEditorKey(e, {
9464
9558
  canEdit: current.canEdit,
9465
- isPresenting: current.mode !== "edit",
9559
+ // The Slide Master view is an editing surface, not a viewing one.
9560
+ // Gating on `mode !== 'edit'` alone made `mapEditorKey` return
9561
+ // NO_ACTION there, so Delete, the arrow-key nudges and the clipboard
9562
+ // keys were all inert over a master shape even though the write path
9563
+ // behind them routes to the owning part correctly. Svelte and
9564
+ // vanilla, which render the master into their ordinary editable
9565
+ // stage, never had the gap.
9566
+ isPresenting: current.mode !== "edit" && current.mode !== "master",
9466
9567
  hasSelection: current.hasSelection,
9467
9568
  isEditingText: Boolean(current.inlineEditingElementId || current.tableEditorState?.isEditing),
9468
9569
  isDrawing: current.activeTool !== "select",
@@ -9509,6 +9610,9 @@ function useKeyboardShortcuts(input) {
9509
9610
  case "toggleShortcuts":
9510
9611
  current.onToggleShortcuts?.();
9511
9612
  break;
9613
+ case "find":
9614
+ current.onFind?.();
9615
+ break;
9512
9616
  case "nudge":
9513
9617
  current.onNudge(dx ?? 0, dy ?? 0);
9514
9618
  break;
@@ -10855,6 +10959,15 @@ function buildToolbarProps(input) {
10855
10959
  onToggleVersionHistory: () => propertyHandlers.setIsVersionHistoryOpen((p) => !p),
10856
10960
  onOpenPasswordProtection: () => dialogs.setIsPasswordDialogOpen(true),
10857
10961
  onOpenDocumentProperties: () => dialogs.setIsDocPropsDialogOpen(true),
10962
+ // Design > Slide Size: the size control is the inspector's SLIDE SIZE
10963
+ // card, which the deck (no-selection) panel renders. Drop the selection so
10964
+ // that panel is what the pane shows, then open it.
10965
+ onOpenSlideSize: () => {
10966
+ s.setSelectedElementId(null);
10967
+ s.setSelectedElementIds([]);
10968
+ s.setSidebarPanelMode("properties");
10969
+ s.setIsInspectorPaneOpen(true);
10970
+ },
10858
10971
  onOpenFontEmbedding: () => dialogs.setIsFontEmbeddingOpen(true),
10859
10972
  onOpenDigitalSignatures: () => dialogs.setIsDigitalSigDialogOpen(true),
10860
10973
  onEnterPresenterView,
@@ -10981,7 +11094,12 @@ function useViewerBuildingBlocksCore(input) {
10981
11094
  setMode: state.setMode,
10982
11095
  setActiveSlideIndex: state.setActiveSlideIndex,
10983
11096
  setSlides: state.setSlides,
10984
- history
11097
+ history,
11098
+ // PowerPoint's bare `J` during a show toggles live captions.
11099
+ onToggleSubtitles: () => state.setPresentationProperties((prev) => ({
11100
+ ...prev,
11101
+ showSubtitles: !prev.showSubtitles
11102
+ }))
10985
11103
  });
10986
11104
  return {
10987
11105
  state,
Binary file