pptx-react-viewer 2.17.0 → 2.19.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.
- package/CHANGELOG.md +703 -0
- package/README.md +14 -14
- package/dist/{AiChatPanel-HCHCVQN2.js → AiChatPanel-2GBJETOY.js} +24 -24
- package/dist/AiChatPanel-2GBJETOY.js.br +0 -0
- package/dist/AiChatPanel-2GBJETOY.js.gz +0 -0
- package/dist/{AiChatPanel-RZ4A7P4H.mjs → AiChatPanel-FZUKTQPQ.mjs} +4 -4
- package/dist/AiChatPanel-FZUKTQPQ.mjs.br +0 -0
- package/dist/AiChatPanel-FZUKTQPQ.mjs.gz +0 -0
- package/dist/{Model3DScene-LK7LSQNH.js → Model3DScene-JHTI2AQ6.js} +2 -2
- package/dist/Model3DScene-JHTI2AQ6.js.br +0 -0
- package/dist/Model3DScene-JHTI2AQ6.js.gz +0 -0
- package/dist/{Model3DScene-I7FR74AD.mjs → Model3DScene-WRRQSYAZ.mjs} +1 -1
- package/dist/Model3DScene-WRRQSYAZ.mjs.br +0 -0
- package/dist/Model3DScene-WRRQSYAZ.mjs.gz +0 -0
- package/dist/{PowerPointViewer-Du7u4INi.d.ts → PowerPointViewer-DVFkeluD.d.ts} +2 -2
- package/dist/PowerPointViewer-DVFkeluD.d.ts.map +1 -0
- package/dist/{audience-content-store-BvqKy7Hf.d.ts → audience-content-store-ChVOSdBh.d.ts} +2 -2
- package/dist/{audience-content-store-BvqKy7Hf.d.ts.map → audience-content-store-ChVOSdBh.d.ts.map} +1 -1
- package/dist/{chunk-7JPLVECA.js → chunk-7ARD2J6Y.js} +10502 -7059
- package/dist/chunk-7ARD2J6Y.js.br +0 -0
- package/dist/chunk-7ARD2J6Y.js.gz +0 -0
- package/dist/{chunk-ZA5JONCW.mjs → chunk-BO373PYH.mjs} +257 -184
- package/dist/chunk-BO373PYH.mjs.br +0 -0
- package/dist/chunk-BO373PYH.mjs.gz +0 -0
- package/dist/{chunk-TCGXGD6E.js → chunk-IRLOXBO7.js} +608 -535
- package/dist/chunk-IRLOXBO7.js.br +0 -0
- package/dist/chunk-IRLOXBO7.js.gz +0 -0
- package/dist/{chunk-AONFHTTJ.js → chunk-MVKRI3CZ.js} +36 -4
- package/dist/chunk-MVKRI3CZ.js.br +0 -0
- package/dist/chunk-MVKRI3CZ.js.gz +0 -0
- package/dist/{chunk-MQHC5TXI.mjs → chunk-MWEBCWVD.mjs} +38 -2347
- package/dist/chunk-MWEBCWVD.mjs.br +0 -0
- package/dist/chunk-MWEBCWVD.mjs.gz +0 -0
- package/dist/{chunk-NQJPPIVH.js → chunk-NFFV3RDS.js} +1632 -1201
- package/dist/chunk-NFFV3RDS.js.br +0 -0
- package/dist/chunk-NFFV3RDS.js.gz +0 -0
- package/dist/{chunk-5BXATG54.js → chunk-OVPJT4EQ.js} +182 -2490
- package/dist/chunk-OVPJT4EQ.js.br +0 -0
- package/dist/chunk-OVPJT4EQ.js.gz +0 -0
- package/dist/{chunk-ATOUVRRQ.js → chunk-RPJ2BIQ7.js} +3 -3
- package/dist/chunk-RPJ2BIQ7.js.br +0 -0
- package/dist/chunk-RPJ2BIQ7.js.gz +0 -0
- package/dist/{chunk-S64T7C4V.mjs → chunk-SQJBFMEX.mjs} +36 -4
- package/dist/chunk-SQJBFMEX.mjs.br +0 -0
- package/dist/chunk-SQJBFMEX.mjs.gz +0 -0
- package/dist/{chunk-K2QU73KB.mjs → chunk-XF3EOHY2.mjs} +10455 -7039
- package/dist/chunk-XF3EOHY2.mjs.br +0 -0
- package/dist/chunk-XF3EOHY2.mjs.gz +0 -0
- package/dist/{chunk-422DF424.mjs → chunk-YWJBD7KV.mjs} +654 -223
- package/dist/chunk-YWJBD7KV.mjs.br +0 -0
- package/dist/chunk-YWJBD7KV.mjs.gz +0 -0
- package/dist/{chunk-FXJOTEPO.mjs → chunk-ZMEYXAC6.mjs} +1 -1
- package/dist/chunk-ZMEYXAC6.mjs.br +0 -0
- package/dist/chunk-ZMEYXAC6.mjs.gz +0 -0
- package/dist/i18n.js +4 -4
- package/dist/i18n.js.br +0 -0
- package/dist/i18n.js.gz +0 -0
- package/dist/i18n.mjs +1 -1
- package/dist/i18n.mjs.br +0 -0
- package/dist/i18n.mjs.gz +0 -0
- package/dist/index.d.ts +535 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +65 -41
- package/dist/index.js.br +0 -0
- package/dist/index.js.gz +0 -0
- package/dist/index.mjs +6 -6
- package/dist/index.mjs.br +0 -0
- package/dist/index.mjs.gz +0 -0
- package/dist/internals.d.ts +645 -47
- package/dist/internals.d.ts.map +1 -1
- package/dist/internals.js +79 -79
- package/dist/internals.js.br +0 -0
- package/dist/internals.js.gz +0 -0
- package/dist/internals.mjs +4 -4
- package/dist/internals.mjs.br +0 -0
- package/dist/internals.mjs.gz +0 -0
- package/dist/pptx-viewer.css +1 -1
- package/dist/pptx-viewer.css.br +0 -0
- package/dist/pptx-viewer.css.gz +0 -0
- package/dist/{types-DU35aAJK.d.ts → types-TCH6icpi.d.ts} +25 -31
- package/dist/types-TCH6icpi.d.ts.map +1 -0
- package/dist/{useViewerBuildingBlocks-C9-prKYB.d.ts → useViewerBuildingBlocks-BKb0qs1j.d.ts} +34 -5
- package/dist/useViewerBuildingBlocks-BKb0qs1j.d.ts.map +1 -0
- package/dist/viewer/index.d.ts +465 -40
- package/dist/viewer/index.js +27 -27
- package/dist/viewer/index.js.br +0 -0
- package/dist/viewer/index.js.gz +0 -0
- package/dist/viewer/index.mjs +6 -6
- package/dist/viewer/index.mjs.br +0 -0
- package/dist/viewer/index.mjs.gz +0 -0
- package/package.json +2 -2
- package/dist/AiChatPanel-HCHCVQN2.js.br +0 -0
- package/dist/AiChatPanel-HCHCVQN2.js.gz +0 -0
- package/dist/AiChatPanel-RZ4A7P4H.mjs.br +0 -0
- package/dist/AiChatPanel-RZ4A7P4H.mjs.gz +0 -0
- package/dist/Model3DScene-I7FR74AD.mjs.br +0 -0
- package/dist/Model3DScene-I7FR74AD.mjs.gz +0 -0
- package/dist/Model3DScene-LK7LSQNH.js.br +0 -0
- package/dist/Model3DScene-LK7LSQNH.js.gz +0 -0
- package/dist/PowerPointViewer-Du7u4INi.d.ts.map +0 -1
- package/dist/SurfaceChart3DScene-DEQP5O3U.mjs +0 -76
- package/dist/SurfaceChart3DScene-DEQP5O3U.mjs.br +0 -0
- package/dist/SurfaceChart3DScene-DEQP5O3U.mjs.gz +0 -0
- package/dist/SurfaceChart3DScene-ODQY77SZ.js +0 -78
- package/dist/SurfaceChart3DScene-ODQY77SZ.js.br +0 -0
- package/dist/SurfaceChart3DScene-ODQY77SZ.js.gz +0 -0
- package/dist/chunk-422DF424.mjs.br +0 -0
- package/dist/chunk-422DF424.mjs.gz +0 -0
- package/dist/chunk-5BXATG54.js.br +0 -0
- package/dist/chunk-5BXATG54.js.gz +0 -0
- package/dist/chunk-7JPLVECA.js.br +0 -0
- package/dist/chunk-7JPLVECA.js.gz +0 -0
- package/dist/chunk-AONFHTTJ.js.br +0 -0
- package/dist/chunk-AONFHTTJ.js.gz +0 -0
- package/dist/chunk-ATOUVRRQ.js.br +0 -0
- package/dist/chunk-ATOUVRRQ.js.gz +0 -0
- package/dist/chunk-FXJOTEPO.mjs.br +0 -0
- package/dist/chunk-FXJOTEPO.mjs.gz +0 -0
- package/dist/chunk-K2QU73KB.mjs.br +0 -0
- package/dist/chunk-K2QU73KB.mjs.gz +0 -0
- package/dist/chunk-MQHC5TXI.mjs.br +0 -0
- package/dist/chunk-MQHC5TXI.mjs.gz +0 -0
- package/dist/chunk-NQJPPIVH.js.br +0 -0
- package/dist/chunk-NQJPPIVH.js.gz +0 -0
- package/dist/chunk-S64T7C4V.mjs.br +0 -0
- package/dist/chunk-S64T7C4V.mjs.gz +0 -0
- package/dist/chunk-TCGXGD6E.js.br +0 -0
- package/dist/chunk-TCGXGD6E.js.gz +0 -0
- package/dist/chunk-ZA5JONCW.mjs.br +0 -0
- package/dist/chunk-ZA5JONCW.mjs.gz +0 -0
- package/dist/types-DU35aAJK.d.ts.map +0 -1
- 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-
|
|
2
|
-
import { translationsEn } from './chunk-
|
|
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,
|
|
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-MWEBCWVD.mjs';
|
|
2
|
+
import { translationsEn } from './chunk-SQJBFMEX.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, resolveAutosaveIntervalMs, 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, shouldProbeAutosaveRecovery, probeAutosaveRecovery, acceptAutosaveRecovery, discardAutosaveRecovery, 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-XF3EOHY2.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';
|
|
@@ -473,6 +473,14 @@ function useSheetDismissDrag(onClose, threshold = 120) {
|
|
|
473
473
|
};
|
|
474
474
|
}
|
|
475
475
|
var DEFAULT_MAX_HISTORY_ENTRIES = 120;
|
|
476
|
+
function serializeDocument(snapshot) {
|
|
477
|
+
return JSON.stringify({
|
|
478
|
+
width: snapshot.width,
|
|
479
|
+
height: snapshot.height,
|
|
480
|
+
slides: snapshot.slides,
|
|
481
|
+
templateElementsBySlideId: snapshot.templateElementsBySlideId
|
|
482
|
+
});
|
|
483
|
+
}
|
|
476
484
|
function useEditorHistory(input) {
|
|
477
485
|
const {
|
|
478
486
|
slides,
|
|
@@ -575,7 +583,7 @@ function useEditorHistory(input) {
|
|
|
575
583
|
isApplyingHistoryRef.current = true;
|
|
576
584
|
const nextSnapshot = cloneHistorySnapshot(previousSnapshot);
|
|
577
585
|
lastHistorySnapshotRef.current = cloneHistorySnapshot(nextSnapshot);
|
|
578
|
-
lastHistorySerializedRef.current =
|
|
586
|
+
lastHistorySerializedRef.current = serializeDocument(nextSnapshot);
|
|
579
587
|
applyHistorySnapshot(nextSnapshot);
|
|
580
588
|
updateHistoryAvailability();
|
|
581
589
|
unlockHistoryTracking();
|
|
@@ -597,7 +605,7 @@ function useEditorHistory(input) {
|
|
|
597
605
|
isApplyingHistoryRef.current = true;
|
|
598
606
|
const targetSnapshot = cloneHistorySnapshot(nextSnapshot);
|
|
599
607
|
lastHistorySnapshotRef.current = cloneHistorySnapshot(targetSnapshot);
|
|
600
|
-
lastHistorySerializedRef.current =
|
|
608
|
+
lastHistorySerializedRef.current = serializeDocument(targetSnapshot);
|
|
601
609
|
applyHistorySnapshot(targetSnapshot);
|
|
602
610
|
updateHistoryAvailability();
|
|
603
611
|
unlockHistoryTracking();
|
|
@@ -616,7 +624,7 @@ function useEditorHistory(input) {
|
|
|
616
624
|
if (initialSnapshot) {
|
|
617
625
|
const clonedInitial = cloneHistorySnapshot(initialSnapshot);
|
|
618
626
|
lastHistorySnapshotRef.current = clonedInitial;
|
|
619
|
-
lastHistorySerializedRef.current =
|
|
627
|
+
lastHistorySerializedRef.current = serializeDocument(clonedInitial);
|
|
620
628
|
} else {
|
|
621
629
|
lastHistorySnapshotRef.current = null;
|
|
622
630
|
lastHistorySerializedRef.current = "";
|
|
@@ -648,8 +656,15 @@ function useEditorHistory(input) {
|
|
|
648
656
|
return;
|
|
649
657
|
}
|
|
650
658
|
const snapshot = buildHistorySnapshot();
|
|
651
|
-
const serialized =
|
|
659
|
+
const serialized = serializeDocument(snapshot);
|
|
652
660
|
if (serialized === lastHistorySerializedRef.current) {
|
|
661
|
+
const previous = lastHistorySnapshotRef.current;
|
|
662
|
+
if (previous && previous.activeSlideIndex !== snapshot.activeSlideIndex) {
|
|
663
|
+
lastHistorySnapshotRef.current = {
|
|
664
|
+
...previous,
|
|
665
|
+
activeSlideIndex: snapshot.activeSlideIndex
|
|
666
|
+
};
|
|
667
|
+
}
|
|
653
668
|
lastCheapHashRef.current = cheapHash;
|
|
654
669
|
return;
|
|
655
670
|
}
|
|
@@ -1676,6 +1691,7 @@ function usePresentationKeyboard(input) {
|
|
|
1676
1691
|
onToggleInkMarkup,
|
|
1677
1692
|
onToggleToolbar,
|
|
1678
1693
|
onShowAllSlides,
|
|
1694
|
+
onToggleSubtitles,
|
|
1679
1695
|
onToggleBlackScreen,
|
|
1680
1696
|
onToggleWhiteScreen,
|
|
1681
1697
|
rehearsing,
|
|
@@ -1741,6 +1757,9 @@ function usePresentationKeyboard(input) {
|
|
|
1741
1757
|
case "showAllSlides":
|
|
1742
1758
|
onShowAllSlides?.();
|
|
1743
1759
|
return;
|
|
1760
|
+
case "toggleSubtitles":
|
|
1761
|
+
onToggleSubtitles?.();
|
|
1762
|
+
return;
|
|
1744
1763
|
case "toggleBlackScreen":
|
|
1745
1764
|
onToggleBlackScreen?.();
|
|
1746
1765
|
return;
|
|
@@ -1780,6 +1799,7 @@ function usePresentationKeyboard(input) {
|
|
|
1780
1799
|
onToggleInkMarkup,
|
|
1781
1800
|
onToggleToolbar,
|
|
1782
1801
|
onShowAllSlides,
|
|
1802
|
+
onToggleSubtitles,
|
|
1783
1803
|
onToggleBlackScreen,
|
|
1784
1804
|
onToggleWhiteScreen,
|
|
1785
1805
|
rehearsing,
|
|
@@ -2220,6 +2240,7 @@ function usePresentationMode(input) {
|
|
|
2220
2240
|
onEraseAnnotations,
|
|
2221
2241
|
onToggleInkMarkup,
|
|
2222
2242
|
onToggleToolbar,
|
|
2243
|
+
onToggleSubtitles,
|
|
2223
2244
|
onSaveRehearsalTimings,
|
|
2224
2245
|
loopContinuously,
|
|
2225
2246
|
showWithAnimation,
|
|
@@ -2427,6 +2448,7 @@ function usePresentationMode(input) {
|
|
|
2427
2448
|
onToggleInkMarkup,
|
|
2428
2449
|
onToggleToolbar,
|
|
2429
2450
|
onShowAllSlides: openAllSlides,
|
|
2451
|
+
onToggleSubtitles,
|
|
2430
2452
|
onToggleBlackScreen: () => presenterConsole.setBlackout(
|
|
2431
2453
|
presenterConsole.snapshot.blackout === "black" ? "none" : "black"
|
|
2432
2454
|
),
|
|
@@ -2909,13 +2931,15 @@ function useFindReplace({
|
|
|
2909
2931
|
}, [findResults, applyReplacements, performFind]);
|
|
2910
2932
|
useEffect(() => {
|
|
2911
2933
|
const handler = (event) => {
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2934
|
+
const { action } = mapEditorKey(event, {
|
|
2935
|
+
canEdit: mode === "edit",
|
|
2936
|
+
isTextInputTarget: isEditorTextInputTarget(event.target)
|
|
2937
|
+
});
|
|
2938
|
+
if (action !== "find") {
|
|
2939
|
+
return;
|
|
2918
2940
|
}
|
|
2941
|
+
event.preventDefault();
|
|
2942
|
+
setFindReplaceOpen((prev) => !prev);
|
|
2919
2943
|
};
|
|
2920
2944
|
window.addEventListener("keydown", handler);
|
|
2921
2945
|
return () => window.removeEventListener("keydown", handler);
|
|
@@ -3355,9 +3379,28 @@ function useDerivedElementState(input) {
|
|
|
3355
3379
|
}
|
|
3356
3380
|
return templateElementsBySlideId[activeSlide.id] ?? [];
|
|
3357
3381
|
}, [activeSlide, templateElementsBySlideId]);
|
|
3382
|
+
const activeMaster = slideMasters[activeMasterIndex];
|
|
3383
|
+
const activeLayout = useMemo(
|
|
3384
|
+
() => resolveActiveLayout(activeMaster, activeLayoutIndex),
|
|
3385
|
+
[activeMaster, activeLayoutIndex]
|
|
3386
|
+
);
|
|
3387
|
+
const masterViewElements2 = useMemo(
|
|
3388
|
+
() => computeMasterViewElements(activeMaster, activeLayout),
|
|
3389
|
+
[activeMaster, activeLayout]
|
|
3390
|
+
);
|
|
3391
|
+
const notesMasterElements = useMemo(() => notesMaster?.elements ?? [], [notesMaster]);
|
|
3392
|
+
const handoutMasterElements = useMemo(() => handoutMaster?.elements ?? [], [handoutMaster]);
|
|
3358
3393
|
const elementLookup = useMemo(
|
|
3359
|
-
() => buildElementLookup(
|
|
3360
|
-
|
|
3394
|
+
() => buildElementLookup(
|
|
3395
|
+
[
|
|
3396
|
+
...templateElements,
|
|
3397
|
+
...masterViewElements2,
|
|
3398
|
+
...notesMasterElements,
|
|
3399
|
+
...handoutMasterElements
|
|
3400
|
+
],
|
|
3401
|
+
activeSlide?.elements ?? []
|
|
3402
|
+
),
|
|
3403
|
+
[activeSlide, templateElements, masterViewElements2, notesMasterElements, handoutMasterElements]
|
|
3361
3404
|
);
|
|
3362
3405
|
const selectedElement = useMemo(() => {
|
|
3363
3406
|
if (!selectedElementId) {
|
|
@@ -3374,17 +3417,6 @@ function useDerivedElementState(input) {
|
|
|
3374
3417
|
() => effectiveSelectedIds.map((id) => elementLookup.get(id)).filter(Boolean),
|
|
3375
3418
|
[effectiveSelectedIds, elementLookup]
|
|
3376
3419
|
);
|
|
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
3420
|
return {
|
|
3389
3421
|
activeSlide,
|
|
3390
3422
|
templateElements,
|
|
@@ -3423,6 +3455,7 @@ function useViewerCoreState(_input) {
|
|
|
3423
3455
|
width: DEFAULT_CANVAS_WIDTH,
|
|
3424
3456
|
height: DEFAULT_CANVAS_HEIGHT
|
|
3425
3457
|
});
|
|
3458
|
+
const [slideSizeEmu, setSlideSizeEmu] = useState();
|
|
3426
3459
|
const [activeSlideIndex, setActiveSlideIndex] = useState(0);
|
|
3427
3460
|
const [selectedElementId, setSelectedElementId] = useState(null);
|
|
3428
3461
|
const [selectedElementIds, setSelectedElementIds] = useState([]);
|
|
@@ -3521,6 +3554,8 @@ function useViewerCoreState(_input) {
|
|
|
3521
3554
|
setTemplateElementsBySlideId,
|
|
3522
3555
|
canvasSize,
|
|
3523
3556
|
setCanvasSize,
|
|
3557
|
+
slideSizeEmu,
|
|
3558
|
+
setSlideSizeEmu,
|
|
3524
3559
|
activeSlideIndex,
|
|
3525
3560
|
setActiveSlideIndex,
|
|
3526
3561
|
selectedElementId,
|
|
@@ -3725,6 +3760,7 @@ function useLoadContent({
|
|
|
3725
3760
|
setTemplateElementsBySlideId,
|
|
3726
3761
|
mediaDataUrls,
|
|
3727
3762
|
setCanvasSize,
|
|
3763
|
+
setSlideSizeEmu,
|
|
3728
3764
|
setHeaderFooter,
|
|
3729
3765
|
setLayoutOptions,
|
|
3730
3766
|
setSlideMasters,
|
|
@@ -3732,6 +3768,7 @@ function useLoadContent({
|
|
|
3732
3768
|
setTableStyleMap,
|
|
3733
3769
|
setThemeOptions,
|
|
3734
3770
|
setCustomShows,
|
|
3771
|
+
setActiveCustomShowId,
|
|
3735
3772
|
setSections,
|
|
3736
3773
|
setPresentationProperties,
|
|
3737
3774
|
setNotesMaster,
|
|
@@ -3891,6 +3928,13 @@ function useLoadContent({
|
|
|
3891
3928
|
width: parsed.width ?? DEFAULT_CANVAS_WIDTH,
|
|
3892
3929
|
height: parsed.height ?? DEFAULT_CANVAS_HEIGHT
|
|
3893
3930
|
});
|
|
3931
|
+
setSlideSizeEmu(
|
|
3932
|
+
typeof parsed.widthEmu === "number" && typeof parsed.heightEmu === "number" && parsed.widthEmu > 0 && parsed.heightEmu > 0 ? {
|
|
3933
|
+
widthEmu: parsed.widthEmu,
|
|
3934
|
+
heightEmu: parsed.heightEmu,
|
|
3935
|
+
type: parsed.slideSizeType ?? ""
|
|
3936
|
+
} : void 0
|
|
3937
|
+
);
|
|
3894
3938
|
setHeaderFooter(parsed.headerFooter ?? {});
|
|
3895
3939
|
setLayoutOptions(parsed.layoutOptions ?? []);
|
|
3896
3940
|
setSlideMasters(parsed.slideMasters ?? []);
|
|
@@ -3898,6 +3942,9 @@ function useLoadContent({
|
|
|
3898
3942
|
setTableStyleMap(parsed.tableStyleMap);
|
|
3899
3943
|
setThemeOptions(parsed.themeOptions ?? []);
|
|
3900
3944
|
setCustomShows(parsed.customShows ?? []);
|
|
3945
|
+
setActiveCustomShowId(
|
|
3946
|
+
resolveAuthoredCustomShowId(parsed.presentationProperties, parsed.customShows) ?? null
|
|
3947
|
+
);
|
|
3901
3948
|
setSections(parsed.sections ?? []);
|
|
3902
3949
|
setPresentationProperties(parsed.presentationProperties ?? {});
|
|
3903
3950
|
setNotesMaster(parsed.notesMaster);
|
|
@@ -3951,23 +3998,12 @@ function useLoadContent({
|
|
|
3951
3998
|
}, [content]);
|
|
3952
3999
|
return { handlerRef };
|
|
3953
4000
|
}
|
|
3954
|
-
|
|
3955
|
-
// src/viewer/hooks/useAutosave-helpers.ts
|
|
3956
|
-
var DEFAULT_AUTOSAVE_INTERVAL_SECONDS = 120;
|
|
3957
|
-
var MIN_AUTOSAVE_INTERVAL_SECONDS = 10;
|
|
3958
|
-
function computeAutosaveIntervalMs(intervalSeconds) {
|
|
3959
|
-
return Math.max(intervalSeconds, MIN_AUTOSAVE_INTERVAL_SECONDS) * 1e3;
|
|
3960
|
-
}
|
|
3961
|
-
|
|
3962
|
-
// src/viewer/hooks/useAutosave.ts
|
|
3963
4001
|
function useAutosave(input) {
|
|
3964
|
-
const {
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
enabled = true
|
|
3970
|
-
} = input;
|
|
4002
|
+
const { isDirty, filePath, serializeSlides, enabled = true, getChangeSources } = input;
|
|
4003
|
+
const intervalMs = resolveAutosaveIntervalMs({
|
|
4004
|
+
hostIntervalMs: input.intervalMs,
|
|
4005
|
+
optionsIntervalSeconds: input.intervalSeconds
|
|
4006
|
+
});
|
|
3971
4007
|
const [autosaveStatus, setAutosaveStatus] = useState({
|
|
3972
4008
|
state: "idle"
|
|
3973
4009
|
});
|
|
@@ -3975,6 +4011,8 @@ function useAutosave(input) {
|
|
|
3975
4011
|
const filePathRef = useRef(filePath);
|
|
3976
4012
|
const serializeRef = useRef(serializeSlides);
|
|
3977
4013
|
const isSavingRef = useRef(false);
|
|
4014
|
+
const changeSourcesRef = useRef(getChangeSources);
|
|
4015
|
+
const lastSnapshotRef = useRef(void 0);
|
|
3978
4016
|
useEffect(() => {
|
|
3979
4017
|
isDirtyRef.current = isDirty;
|
|
3980
4018
|
}, [isDirty]);
|
|
@@ -3984,14 +4022,22 @@ function useAutosave(input) {
|
|
|
3984
4022
|
useEffect(() => {
|
|
3985
4023
|
serializeRef.current = serializeSlides;
|
|
3986
4024
|
}, [serializeSlides]);
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
4025
|
+
useEffect(() => {
|
|
4026
|
+
changeSourcesRef.current = getChangeSources;
|
|
4027
|
+
}, [getChangeSources]);
|
|
4028
|
+
const doAutosave = useCallback(async (options) => {
|
|
4029
|
+
const path = filePathRef.current;
|
|
4030
|
+
if (!path) {
|
|
4031
|
+
return;
|
|
4032
|
+
}
|
|
4033
|
+
const sources = changeSourcesRef.current?.() ?? [];
|
|
4034
|
+
if (!shouldWriteAutosaveSnapshot({
|
|
4035
|
+
filePath: path,
|
|
4036
|
+
isDirty: isDirtyRef.current,
|
|
4037
|
+
saving: isSavingRef.current,
|
|
4038
|
+
sources: options?.polled === true ? sources : [],
|
|
4039
|
+
lastSnapshot: lastSnapshotRef.current
|
|
4040
|
+
})) {
|
|
3995
4041
|
return;
|
|
3996
4042
|
}
|
|
3997
4043
|
isSavingRef.current = true;
|
|
@@ -4003,7 +4049,8 @@ function useAutosave(input) {
|
|
|
4003
4049
|
isSavingRef.current = false;
|
|
4004
4050
|
return;
|
|
4005
4051
|
}
|
|
4006
|
-
await saveAutosaveSnapshot(
|
|
4052
|
+
await saveAutosaveSnapshot(path, data);
|
|
4053
|
+
lastSnapshotRef.current = autosaveSnapshotMark(path, sources);
|
|
4007
4054
|
setAutosaveStatus({ state: "saved", timestamp: Date.now() });
|
|
4008
4055
|
} catch (err) {
|
|
4009
4056
|
setAutosaveStatus({
|
|
@@ -4027,15 +4074,14 @@ function useAutosave(input) {
|
|
|
4027
4074
|
return;
|
|
4028
4075
|
}
|
|
4029
4076
|
setAutosaveStatus((prev) => prev.state === "disabled" ? { state: "idle" } : prev);
|
|
4030
|
-
const ms = computeAutosaveIntervalMs(intervalSeconds);
|
|
4031
4077
|
const id = setInterval(() => {
|
|
4032
|
-
void doAutosave();
|
|
4033
|
-
},
|
|
4078
|
+
void doAutosave({ polled: true });
|
|
4079
|
+
}, intervalMs);
|
|
4034
4080
|
return () => clearInterval(id);
|
|
4035
|
-
}, [enabled, filePath,
|
|
4081
|
+
}, [enabled, filePath, intervalMs, doAutosave]);
|
|
4036
4082
|
return {
|
|
4037
4083
|
autosaveStatus,
|
|
4038
|
-
triggerAutosave: doAutosave
|
|
4084
|
+
triggerAutosave: () => doAutosave()
|
|
4039
4085
|
};
|
|
4040
4086
|
}
|
|
4041
4087
|
function useElementOperations(input) {
|
|
@@ -4327,13 +4373,23 @@ function useSectionOperations(input) {
|
|
|
4327
4373
|
},
|
|
4328
4374
|
[sections, slides, setSlides, setSections, markDirty]
|
|
4329
4375
|
);
|
|
4376
|
+
const toggleSectionCollapse = useCallback(
|
|
4377
|
+
(sectionId) => {
|
|
4378
|
+
setSections(
|
|
4379
|
+
(prev) => prev.map((sec) => sec.id === sectionId ? { ...sec, collapsed: !sec.collapsed } : sec)
|
|
4380
|
+
);
|
|
4381
|
+
markDirty();
|
|
4382
|
+
},
|
|
4383
|
+
[setSections, markDirty]
|
|
4384
|
+
);
|
|
4330
4385
|
return {
|
|
4331
4386
|
addSection: addSection2,
|
|
4332
4387
|
renameSection: renameSection2,
|
|
4333
4388
|
deleteSection: deleteSection2,
|
|
4334
4389
|
moveSectionUp: moveSectionUp2,
|
|
4335
4390
|
moveSectionDown: moveSectionDown2,
|
|
4336
|
-
moveSlidesToSection: moveSlidesToSection2
|
|
4391
|
+
moveSlidesToSection: moveSlidesToSection2,
|
|
4392
|
+
toggleSectionCollapse
|
|
4337
4393
|
};
|
|
4338
4394
|
}
|
|
4339
4395
|
|
|
@@ -4551,13 +4607,14 @@ function processResizeMove(e, rs, editorScale, snapToGrid, gridSpacingPx, live)
|
|
|
4551
4607
|
}
|
|
4552
4608
|
function processAdjustmentMove(e, adj, editorScale, updateElementById) {
|
|
4553
4609
|
const dx = (e.clientX - adj.startClientX) / editorScale;
|
|
4554
|
-
const
|
|
4555
|
-
|
|
4610
|
+
const dy = (e.clientY - adj.startClientY) / editorScale;
|
|
4611
|
+
const adjustments = getDraggedShapeAdjustments(adj, dx, dy);
|
|
4612
|
+
if (!adj.moved && Math.hypot(dx, dy) > 2) {
|
|
4556
4613
|
adj.moved = true;
|
|
4557
4614
|
}
|
|
4558
4615
|
if (adj.moved) {
|
|
4559
4616
|
updateElementById(adj.elementId, {
|
|
4560
|
-
shapeAdjustments:
|
|
4617
|
+
shapeAdjustments: adjustments
|
|
4561
4618
|
});
|
|
4562
4619
|
}
|
|
4563
4620
|
}
|
|
@@ -5034,33 +5091,18 @@ function useCanvasInteractions(input) {
|
|
|
5034
5091
|
const handleFormatText = (updates) => {
|
|
5035
5092
|
ops.updateSelectedTextStyle(updates);
|
|
5036
5093
|
};
|
|
5037
|
-
const handleAdjustmentPointerDown = (elementId, e) => {
|
|
5094
|
+
const handleAdjustmentPointerDown = (elementId, e, descriptor) => {
|
|
5038
5095
|
e.stopPropagation();
|
|
5039
5096
|
const el = elementLookup.get(elementId);
|
|
5040
|
-
if (!el || !(
|
|
5041
|
-
return;
|
|
5042
|
-
}
|
|
5043
|
-
if (!canInteractWithElement(el, "adjustHandle")) {
|
|
5097
|
+
if (!el || !canInteractWithElement(el, "adjustHandle")) {
|
|
5044
5098
|
return;
|
|
5045
5099
|
}
|
|
5046
|
-
|
|
5047
|
-
el
|
|
5100
|
+
shapeAdjustmentDragStateRef.current = beginShapeAdjustment(
|
|
5101
|
+
el,
|
|
5102
|
+
descriptor,
|
|
5103
|
+
e.clientX,
|
|
5104
|
+
e.clientY
|
|
5048
5105
|
);
|
|
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
5106
|
};
|
|
5065
5107
|
return {
|
|
5066
5108
|
handleElementClick,
|
|
@@ -6975,12 +7017,14 @@ function useExportSaveAs(input) {
|
|
|
6975
7017
|
appProperties,
|
|
6976
7018
|
customProperties,
|
|
6977
7019
|
tagCollections,
|
|
7020
|
+
slideMasters,
|
|
6978
7021
|
notesMaster,
|
|
6979
7022
|
handoutMaster,
|
|
6980
7023
|
guides,
|
|
6981
7024
|
activeSlideIndexForGuides,
|
|
6982
7025
|
theme,
|
|
6983
7026
|
canvasSize,
|
|
7027
|
+
slideSizeEmu,
|
|
6984
7028
|
modalControls,
|
|
6985
7029
|
password
|
|
6986
7030
|
} = input;
|
|
@@ -7004,7 +7048,7 @@ function useExportSaveAs(input) {
|
|
|
7004
7048
|
setExportProgress(10);
|
|
7005
7049
|
setExportStatusMessage("Adding presentation...");
|
|
7006
7050
|
const pptxData = await serializeSlides();
|
|
7007
|
-
const pptxFilename = filePath
|
|
7051
|
+
const pptxFilename = savedPresentationFileName(filePath);
|
|
7008
7052
|
if (pptxData) {
|
|
7009
7053
|
pkgFolder.file(pptxFilename, pptxData);
|
|
7010
7054
|
}
|
|
@@ -7020,8 +7064,7 @@ function useExportSaveAs(input) {
|
|
|
7020
7064
|
const zipBlob = await zip.generateAsync({ type: "blob" });
|
|
7021
7065
|
setExportProgress(95);
|
|
7022
7066
|
setExportStatusMessage("Downloading...");
|
|
7023
|
-
|
|
7024
|
-
downloadBlob(zipBlob, `${baseName}-package.zip`);
|
|
7067
|
+
downloadBlob(zipBlob, `${presentationBaseName(pptxFilename)}-package.zip`);
|
|
7025
7068
|
setExportProgress(100);
|
|
7026
7069
|
} catch (err) {
|
|
7027
7070
|
if (err.name !== "AbortError") {
|
|
@@ -7037,16 +7080,15 @@ function useExportSaveAs(input) {
|
|
|
7037
7080
|
if (!handler) {
|
|
7038
7081
|
return;
|
|
7039
7082
|
}
|
|
7040
|
-
const
|
|
7041
|
-
const baseName = filePath ? filePath.replace(/\\/gu, "/").split("/").pop()?.replace(/\.[^.]+$/u, "") ?? "presentation" : "presentation";
|
|
7083
|
+
const downloadName = savedPresentationFileName(filePath, format);
|
|
7042
7084
|
try {
|
|
7043
7085
|
const data = await buildSaveAsData(handler, format);
|
|
7044
7086
|
const blob = new Blob([data], {
|
|
7045
7087
|
type: "application/vnd.openxmlformats-officedocument.presentationml.presentation"
|
|
7046
7088
|
});
|
|
7047
|
-
downloadBlob(blob,
|
|
7089
|
+
downloadBlob(blob, downloadName);
|
|
7048
7090
|
} catch (err) {
|
|
7049
|
-
console.error(`[PowerPointViewer] Save as .${
|
|
7091
|
+
console.error(`[PowerPointViewer] Save as .${format} failed:`, err);
|
|
7050
7092
|
}
|
|
7051
7093
|
};
|
|
7052
7094
|
const buildSaveAsData = async (handler, format) => {
|
|
@@ -7066,6 +7108,9 @@ function useExportSaveAs(input) {
|
|
|
7066
7108
|
});
|
|
7067
7109
|
const slidesToSave = buildSaveSlides(slidesWithGuides, templateElementsBySlideId);
|
|
7068
7110
|
const saveOptions = {
|
|
7111
|
+
// Save As shares Save's slide-size decision; leaving it out here is how
|
|
7112
|
+
// a preset picked in the inspector reached one save path and not the other.
|
|
7113
|
+
slideSize: resolveSlideSizeSelection({ current: slideSizeEmu, canvas: canvasSize }).size,
|
|
7069
7114
|
headerFooter,
|
|
7070
7115
|
presentationProperties,
|
|
7071
7116
|
customShows: customShows.length > 0 ? customShows : void 0,
|
|
@@ -7074,6 +7119,7 @@ function useExportSaveAs(input) {
|
|
|
7074
7119
|
appProperties: appProperties ?? void 0,
|
|
7075
7120
|
customProperties: customProperties.length > 0 ? customProperties : void 0,
|
|
7076
7121
|
tags: tagCollections.length > 0 ? tagCollections : void 0,
|
|
7122
|
+
slideMasters,
|
|
7077
7123
|
notesMaster,
|
|
7078
7124
|
handoutMaster,
|
|
7079
7125
|
outputFormat: format
|
|
@@ -7082,12 +7128,14 @@ function useExportSaveAs(input) {
|
|
|
7082
7128
|
};
|
|
7083
7129
|
const handleExportJson = () => {
|
|
7084
7130
|
const sourceName = filePath ? filePath.replace(/\\/gu, "/").split("/").pop() : void 0;
|
|
7131
|
+
const slideSize = resolveSlideSizeSelection({ current: slideSizeEmu, canvas: canvasSize }).size;
|
|
7085
7132
|
const data = {
|
|
7086
7133
|
slides: buildSaveSlides(slides, templateElementsBySlideId),
|
|
7087
7134
|
width: canvasSize.width,
|
|
7088
7135
|
height: canvasSize.height,
|
|
7089
|
-
widthEmu:
|
|
7090
|
-
heightEmu:
|
|
7136
|
+
widthEmu: slideSize.widthEmu,
|
|
7137
|
+
heightEmu: slideSize.heightEmu,
|
|
7138
|
+
slideSizeType: slideSize.type === "" ? void 0 : slideSize.type,
|
|
7091
7139
|
theme,
|
|
7092
7140
|
headerFooter,
|
|
7093
7141
|
presentationProperties,
|
|
@@ -7164,12 +7212,14 @@ function useExportHandlers(input) {
|
|
|
7164
7212
|
appProperties,
|
|
7165
7213
|
customProperties,
|
|
7166
7214
|
tagCollections,
|
|
7215
|
+
slideMasters,
|
|
7167
7216
|
notesMaster,
|
|
7168
7217
|
handoutMaster,
|
|
7169
7218
|
guides,
|
|
7170
7219
|
activeSlideIndexForGuides,
|
|
7171
7220
|
theme,
|
|
7172
7221
|
canvasSize,
|
|
7222
|
+
slideSizeEmu,
|
|
7173
7223
|
password
|
|
7174
7224
|
} = input;
|
|
7175
7225
|
const [exportModalOpen, setExportModalOpen] = useState(false);
|
|
@@ -7205,12 +7255,14 @@ function useExportHandlers(input) {
|
|
|
7205
7255
|
appProperties,
|
|
7206
7256
|
customProperties,
|
|
7207
7257
|
tagCollections,
|
|
7258
|
+
slideMasters,
|
|
7208
7259
|
notesMaster,
|
|
7209
7260
|
handoutMaster,
|
|
7210
7261
|
guides,
|
|
7211
7262
|
activeSlideIndexForGuides,
|
|
7212
7263
|
theme,
|
|
7213
7264
|
canvasSize,
|
|
7265
|
+
slideSizeEmu,
|
|
7214
7266
|
modalControls,
|
|
7215
7267
|
password
|
|
7216
7268
|
});
|
|
@@ -8380,7 +8432,7 @@ function computeVisibleSlideIndexes(slides, activeCustomShowId, customShows) {
|
|
|
8380
8432
|
}
|
|
8381
8433
|
function computeSlideSectionGroups(slides, sections) {
|
|
8382
8434
|
return groupSlidesBySection(sections, slides).map((group) => ({
|
|
8383
|
-
id: group.section?.id ?? (sections.length > 0 ? UNGROUPED_SECTION_ID :
|
|
8435
|
+
id: group.section?.id ?? (sections.length > 0 ? UNGROUPED_SECTION_ID : DEFAULT_SECTION_GROUP_ID),
|
|
8384
8436
|
label: group.section?.name ?? (sections.length > 0 ? "Ungrouped Slides" : "Slides"),
|
|
8385
8437
|
slideIndexes: group.slideIndexes,
|
|
8386
8438
|
...group.section?.color !== void 0 ? { color: group.section.color } : {},
|
|
@@ -8423,7 +8475,7 @@ function useDerivedSlideState(input) {
|
|
|
8423
8475
|
if (group.id === UNGROUPED_SECTION_ID && group.label === "Ungrouped Slides") {
|
|
8424
8476
|
return { ...group, label: t("pptx.slides.ungroupedSlides") };
|
|
8425
8477
|
}
|
|
8426
|
-
if (group.id ===
|
|
8478
|
+
if (group.id === DEFAULT_SECTION_GROUP_ID && group.label === "Slides") {
|
|
8427
8479
|
return { ...group, label: t("pptx.sections.slides") };
|
|
8428
8480
|
}
|
|
8429
8481
|
return group;
|
|
@@ -8577,6 +8629,8 @@ function useSerialize(input) {
|
|
|
8577
8629
|
slides,
|
|
8578
8630
|
templateElementsBySlideId,
|
|
8579
8631
|
activeSlideIndex,
|
|
8632
|
+
canvasSize,
|
|
8633
|
+
slideSizeEmu,
|
|
8580
8634
|
guides,
|
|
8581
8635
|
headerFooter,
|
|
8582
8636
|
presentationProperties,
|
|
@@ -8586,6 +8640,7 @@ function useSerialize(input) {
|
|
|
8586
8640
|
appProperties,
|
|
8587
8641
|
customProperties,
|
|
8588
8642
|
tagCollections,
|
|
8643
|
+
slideMasters,
|
|
8589
8644
|
notesMaster,
|
|
8590
8645
|
handoutMaster,
|
|
8591
8646
|
handlerRef,
|
|
@@ -8634,6 +8689,10 @@ function useSerialize(input) {
|
|
|
8634
8689
|
});
|
|
8635
8690
|
const slidesToSave = buildSaveSlides(slidesWithGuides, templateElementsBySlideId);
|
|
8636
8691
|
const saveOptions = {
|
|
8692
|
+
// Without this the Slide Size card edited a viewer-only pixel value and
|
|
8693
|
+
// the saved `p:sldSz` never moved: passing `slideSize` is the only way a
|
|
8694
|
+
// slide-size edit reaches the file.
|
|
8695
|
+
slideSize: resolveSlideSizeSelection({ current: slideSizeEmu, canvas: canvasSize }).size,
|
|
8637
8696
|
headerFooter,
|
|
8638
8697
|
presentationProperties,
|
|
8639
8698
|
customShows: customShows.length > 0 ? customShows : void 0,
|
|
@@ -8642,6 +8701,7 @@ function useSerialize(input) {
|
|
|
8642
8701
|
appProperties,
|
|
8643
8702
|
customProperties: customProperties.length > 0 ? customProperties : void 0,
|
|
8644
8703
|
tags: tagCollections.length > 0 ? tagCollections : void 0,
|
|
8704
|
+
slideMasters,
|
|
8645
8705
|
notesMaster,
|
|
8646
8706
|
handoutMaster,
|
|
8647
8707
|
...embeddedFontSaveOptions(embedFonts)
|
|
@@ -8650,6 +8710,8 @@ function useSerialize(input) {
|
|
|
8650
8710
|
}, [
|
|
8651
8711
|
slides,
|
|
8652
8712
|
templateElementsBySlideId,
|
|
8713
|
+
canvasSize,
|
|
8714
|
+
slideSizeEmu,
|
|
8653
8715
|
headerFooter,
|
|
8654
8716
|
presentationProperties,
|
|
8655
8717
|
customShows,
|
|
@@ -8658,6 +8720,7 @@ function useSerialize(input) {
|
|
|
8658
8720
|
appProperties,
|
|
8659
8721
|
customProperties,
|
|
8660
8722
|
tagCollections,
|
|
8723
|
+
slideMasters,
|
|
8661
8724
|
notesMaster,
|
|
8662
8725
|
handoutMaster,
|
|
8663
8726
|
guides,
|
|
@@ -8670,102 +8733,52 @@ function useSerialize(input) {
|
|
|
8670
8733
|
purpose
|
|
8671
8734
|
]);
|
|
8672
8735
|
}
|
|
8673
|
-
|
|
8674
|
-
// src/viewer/hooks/useRecoveryDetection-helpers.ts
|
|
8675
|
-
function shouldCheckRecovery(input) {
|
|
8676
|
-
const { alreadyChecked, filePath, loading, error, slideCount } = input;
|
|
8677
|
-
if (alreadyChecked) {
|
|
8678
|
-
return false;
|
|
8679
|
-
}
|
|
8680
|
-
if (!filePath) {
|
|
8681
|
-
return false;
|
|
8682
|
-
}
|
|
8683
|
-
if (loading) {
|
|
8684
|
-
return false;
|
|
8685
|
-
}
|
|
8686
|
-
if (error) {
|
|
8687
|
-
return false;
|
|
8688
|
-
}
|
|
8689
|
-
if (slideCount === 0) {
|
|
8690
|
-
return false;
|
|
8691
|
-
}
|
|
8692
|
-
return true;
|
|
8693
|
-
}
|
|
8694
|
-
var RECOVERY_WINDOW_MS = 24 * 60 * 60 * 1e3;
|
|
8695
|
-
function isRecentRecovery(timestamp, now) {
|
|
8696
|
-
return now - timestamp < RECOVERY_WINDOW_MS;
|
|
8697
|
-
}
|
|
8698
|
-
function hasRecentRecoveryVersion(versions, now) {
|
|
8699
|
-
if (versions.length === 0) {
|
|
8700
|
-
return false;
|
|
8701
|
-
}
|
|
8702
|
-
return isRecentRecovery(versions[0].timestamp, now);
|
|
8703
|
-
}
|
|
8704
|
-
|
|
8705
|
-
// src/viewer/hooks/useRecoveryDetection.ts
|
|
8706
|
-
var DB_NAME = "pptx-viewer-autosave";
|
|
8707
|
-
var DB_VERSION = 1;
|
|
8708
|
-
var STORE_NAME = "recoveryVersions";
|
|
8709
|
-
function openAutosaveDb() {
|
|
8710
|
-
return new Promise((resolve, reject) => {
|
|
8711
|
-
const req = indexedDB.open(DB_NAME, DB_VERSION);
|
|
8712
|
-
req.onupgradeneeded = () => {
|
|
8713
|
-
const db = req.result;
|
|
8714
|
-
if (!db.objectStoreNames.contains(STORE_NAME)) {
|
|
8715
|
-
db.createObjectStore(STORE_NAME, { keyPath: "key" });
|
|
8716
|
-
}
|
|
8717
|
-
};
|
|
8718
|
-
req.onsuccess = () => resolve(req.result);
|
|
8719
|
-
req.onerror = () => reject(req.error);
|
|
8720
|
-
});
|
|
8721
|
-
}
|
|
8722
|
-
async function getRecoveryVersion(filePath) {
|
|
8723
|
-
try {
|
|
8724
|
-
const db = await openAutosaveDb();
|
|
8725
|
-
return new Promise((resolve) => {
|
|
8726
|
-
const tx = db.transaction(STORE_NAME, "readonly");
|
|
8727
|
-
const store = tx.objectStore(STORE_NAME);
|
|
8728
|
-
const req = store.get(filePath);
|
|
8729
|
-
req.onsuccess = () => {
|
|
8730
|
-
db.close();
|
|
8731
|
-
resolve(req.result);
|
|
8732
|
-
};
|
|
8733
|
-
req.onerror = () => {
|
|
8734
|
-
db.close();
|
|
8735
|
-
resolve(void 0);
|
|
8736
|
-
};
|
|
8737
|
-
});
|
|
8738
|
-
} catch {
|
|
8739
|
-
return void 0;
|
|
8740
|
-
}
|
|
8741
|
-
}
|
|
8742
8736
|
function useRecoveryDetection(input) {
|
|
8743
|
-
const { filePath, loading, error, slideCount,
|
|
8737
|
+
const { filePath, loading, error, slideCount, autosaveAllowed = true } = input;
|
|
8744
8738
|
const recoveryCheckedRef = useRef(false);
|
|
8739
|
+
const recordRef = useRef(null);
|
|
8740
|
+
const [prompt, setPrompt] = useState(null);
|
|
8741
|
+
const onRestore = input.onRestore;
|
|
8742
|
+
const openVersionHistory = input.openVersionHistory;
|
|
8745
8743
|
useEffect(() => {
|
|
8746
|
-
if (!
|
|
8744
|
+
if (!shouldProbeAutosaveRecovery({
|
|
8747
8745
|
alreadyChecked: recoveryCheckedRef.current,
|
|
8748
8746
|
filePath,
|
|
8749
8747
|
loading,
|
|
8750
8748
|
error,
|
|
8751
|
-
slideCount
|
|
8749
|
+
slideCount,
|
|
8750
|
+
autosaveAllowed
|
|
8752
8751
|
})) {
|
|
8753
8752
|
return;
|
|
8754
8753
|
}
|
|
8755
8754
|
recoveryCheckedRef.current = true;
|
|
8756
|
-
if (typeof indexedDB === "undefined") {
|
|
8757
|
-
return;
|
|
8758
|
-
}
|
|
8759
8755
|
void (async () => {
|
|
8760
|
-
|
|
8761
|
-
|
|
8762
|
-
|
|
8763
|
-
openVersionHistory();
|
|
8764
|
-
}
|
|
8765
|
-
} catch {
|
|
8756
|
+
const offer = await probeAutosaveRecovery(filePath);
|
|
8757
|
+
if (!offer) {
|
|
8758
|
+
return;
|
|
8766
8759
|
}
|
|
8760
|
+
recordRef.current = offer.record;
|
|
8761
|
+
setPrompt(offer.prompt);
|
|
8762
|
+
openVersionHistory?.();
|
|
8767
8763
|
})();
|
|
8768
|
-
}, [filePath, loading, error, slideCount, openVersionHistory]);
|
|
8764
|
+
}, [filePath, loading, error, slideCount, autosaveAllowed, openVersionHistory]);
|
|
8765
|
+
const restore = useCallback(() => {
|
|
8766
|
+
const record = recordRef.current;
|
|
8767
|
+
setPrompt(null);
|
|
8768
|
+
if (record && onRestore) {
|
|
8769
|
+
onRestore(acceptAutosaveRecovery(record));
|
|
8770
|
+
}
|
|
8771
|
+
recordRef.current = null;
|
|
8772
|
+
}, [onRestore]);
|
|
8773
|
+
const discard = useCallback(() => {
|
|
8774
|
+
const record = recordRef.current;
|
|
8775
|
+
setPrompt(null);
|
|
8776
|
+
recordRef.current = null;
|
|
8777
|
+
if (record) {
|
|
8778
|
+
void discardAutosaveRecovery(record);
|
|
8779
|
+
}
|
|
8780
|
+
}, []);
|
|
8781
|
+
return { prompt, restore, discard };
|
|
8769
8782
|
}
|
|
8770
8783
|
function usePresentationSetup(input) {
|
|
8771
8784
|
const {
|
|
@@ -8783,7 +8796,8 @@ function usePresentationSetup(input) {
|
|
|
8783
8796
|
history,
|
|
8784
8797
|
endWithBlackSlide = true,
|
|
8785
8798
|
promptKeepInkAnnotations = true,
|
|
8786
|
-
popupToolbarEnabled = true
|
|
8799
|
+
popupToolbarEnabled = true,
|
|
8800
|
+
onToggleSubtitles
|
|
8787
8801
|
} = input;
|
|
8788
8802
|
const actionSoundHandlerRef = useRef(null);
|
|
8789
8803
|
const [, setShowKeepAnnotationsDialog] = useState(false);
|
|
@@ -8862,6 +8876,7 @@ function usePresentationSetup(input) {
|
|
|
8862
8876
|
onEraseAnnotations: () => annotations.clearAnnotations(),
|
|
8863
8877
|
onToggleInkMarkup: () => annotations.setInkMarkupVisible(!annotations.inkMarkupVisible),
|
|
8864
8878
|
onToggleToolbar: () => annotations.setToolbarVisible(!annotations.toolbarVisible),
|
|
8879
|
+
onToggleSubtitles,
|
|
8865
8880
|
onSaveRehearsalTimings: (timings) => {
|
|
8866
8881
|
setSlides((prev) => applyRehearsalTimings(prev, timings));
|
|
8867
8882
|
history.markDirty();
|
|
@@ -9161,12 +9176,14 @@ function useIOHandlers(input) {
|
|
|
9161
9176
|
appProperties: state.appProperties ?? null,
|
|
9162
9177
|
customProperties: state.customProperties,
|
|
9163
9178
|
tagCollections: state.tagCollections,
|
|
9179
|
+
slideMasters: state.slideMasters,
|
|
9164
9180
|
notesMaster: state.notesMaster,
|
|
9165
9181
|
handoutMaster: state.handoutMaster,
|
|
9166
9182
|
guides: state.guides,
|
|
9167
9183
|
activeSlideIndexForGuides: state.activeSlideIndex,
|
|
9168
9184
|
theme: state.theme,
|
|
9169
9185
|
canvasSize,
|
|
9186
|
+
slideSizeEmu: state.slideSizeEmu,
|
|
9170
9187
|
password
|
|
9171
9188
|
});
|
|
9172
9189
|
const printHandlers = usePrintHandlers({
|
|
@@ -9372,7 +9389,7 @@ function useContentLifecycle(input) {
|
|
|
9372
9389
|
content,
|
|
9373
9390
|
filePath,
|
|
9374
9391
|
autosaveEnabled = true,
|
|
9375
|
-
|
|
9392
|
+
autosaveIntervalMs,
|
|
9376
9393
|
embedFonts = true,
|
|
9377
9394
|
slides,
|
|
9378
9395
|
state,
|
|
@@ -9391,6 +9408,7 @@ function useContentLifecycle(input) {
|
|
|
9391
9408
|
setTemplateElementsBySlideId: state.setTemplateElementsBySlideId,
|
|
9392
9409
|
mediaDataUrls: state.mediaDataUrls,
|
|
9393
9410
|
setCanvasSize: state.setCanvasSize,
|
|
9411
|
+
setSlideSizeEmu: state.setSlideSizeEmu,
|
|
9394
9412
|
setHeaderFooter: state.setHeaderFooter,
|
|
9395
9413
|
setLayoutOptions: state.setLayoutOptions,
|
|
9396
9414
|
setSlideMasters: state.setSlideMasters,
|
|
@@ -9398,6 +9416,7 @@ function useContentLifecycle(input) {
|
|
|
9398
9416
|
setTableStyleMap: state.setTableStyleMap,
|
|
9399
9417
|
setThemeOptions: state.setThemeOptions,
|
|
9400
9418
|
setCustomShows: state.setCustomShows,
|
|
9419
|
+
setActiveCustomShowId: state.setActiveCustomShowId,
|
|
9401
9420
|
setSections: state.setSections,
|
|
9402
9421
|
setPresentationProperties: state.setPresentationProperties,
|
|
9403
9422
|
setNotesMaster: state.setNotesMaster,
|
|
@@ -9427,6 +9446,8 @@ function useContentLifecycle(input) {
|
|
|
9427
9446
|
slides,
|
|
9428
9447
|
templateElementsBySlideId: state.templateElementsBySlideId,
|
|
9429
9448
|
activeSlideIndex: state.activeSlideIndex,
|
|
9449
|
+
canvasSize: state.canvasSize,
|
|
9450
|
+
slideSizeEmu: state.slideSizeEmu,
|
|
9430
9451
|
guides: state.guides,
|
|
9431
9452
|
headerFooter: state.headerFooter,
|
|
9432
9453
|
presentationProperties: state.presentationProperties,
|
|
@@ -9436,6 +9457,7 @@ function useContentLifecycle(input) {
|
|
|
9436
9457
|
appProperties: state.appProperties,
|
|
9437
9458
|
customProperties: state.customProperties,
|
|
9438
9459
|
tagCollections: state.tagCollections,
|
|
9460
|
+
slideMasters: state.slideMasters,
|
|
9439
9461
|
notesMaster: state.notesMaster,
|
|
9440
9462
|
handoutMaster: state.handoutMaster,
|
|
9441
9463
|
handlerRef,
|
|
@@ -9451,7 +9473,31 @@ function useContentLifecycle(input) {
|
|
|
9451
9473
|
filePath,
|
|
9452
9474
|
serializeSlides: serializeForRecovery,
|
|
9453
9475
|
enabled: autosaveEnabled,
|
|
9454
|
-
...
|
|
9476
|
+
...autosaveIntervalMs === void 0 ? {} : { intervalMs: autosaveIntervalMs },
|
|
9477
|
+
// Everything `serializeForRecovery` reads that changes by REASSIGNMENT,
|
|
9478
|
+
// so a poll that finds all of them unchanged can skip re-serializing a
|
|
9479
|
+
// deck it has already snapshotted. The two refs are read by `.current`
|
|
9480
|
+
// because an inline edit in progress lives there and nowhere else yet.
|
|
9481
|
+
getChangeSources: () => [
|
|
9482
|
+
slides,
|
|
9483
|
+
state.templateElementsBySlideId,
|
|
9484
|
+
state.guides,
|
|
9485
|
+
state.headerFooter,
|
|
9486
|
+
state.presentationProperties,
|
|
9487
|
+
state.customShows,
|
|
9488
|
+
state.sections,
|
|
9489
|
+
state.coreProperties,
|
|
9490
|
+
state.appProperties,
|
|
9491
|
+
state.customProperties,
|
|
9492
|
+
state.tagCollections,
|
|
9493
|
+
state.notesMaster,
|
|
9494
|
+
state.handoutMaster,
|
|
9495
|
+
state.embeddedFonts,
|
|
9496
|
+
embedFonts,
|
|
9497
|
+
password,
|
|
9498
|
+
state.inlineEditingElementIdRef.current,
|
|
9499
|
+
state.inlineEditingTextRef.current
|
|
9500
|
+
]
|
|
9455
9501
|
});
|
|
9456
9502
|
return { handlerRef, serializeSlides, serializeForRecovery, autosaveStatus };
|
|
9457
9503
|
}
|
|
@@ -9462,7 +9508,14 @@ function useKeyboardShortcuts(input) {
|
|
|
9462
9508
|
const current = inputRef.current;
|
|
9463
9509
|
const { action, dx, dy } = mapEditorKey(e, {
|
|
9464
9510
|
canEdit: current.canEdit,
|
|
9465
|
-
|
|
9511
|
+
// The Slide Master view is an editing surface, not a viewing one.
|
|
9512
|
+
// Gating on `mode !== 'edit'` alone made `mapEditorKey` return
|
|
9513
|
+
// NO_ACTION there, so Delete, the arrow-key nudges and the clipboard
|
|
9514
|
+
// keys were all inert over a master shape even though the write path
|
|
9515
|
+
// behind them routes to the owning part correctly. Svelte and
|
|
9516
|
+
// vanilla, which render the master into their ordinary editable
|
|
9517
|
+
// stage, never had the gap.
|
|
9518
|
+
isPresenting: current.mode !== "edit" && current.mode !== "master",
|
|
9466
9519
|
hasSelection: current.hasSelection,
|
|
9467
9520
|
isEditingText: Boolean(current.inlineEditingElementId || current.tableEditorState?.isEditing),
|
|
9468
9521
|
isDrawing: current.activeTool !== "select",
|
|
@@ -9509,6 +9562,9 @@ function useKeyboardShortcuts(input) {
|
|
|
9509
9562
|
case "toggleShortcuts":
|
|
9510
9563
|
current.onToggleShortcuts?.();
|
|
9511
9564
|
break;
|
|
9565
|
+
case "find":
|
|
9566
|
+
current.onFind?.();
|
|
9567
|
+
break;
|
|
9512
9568
|
case "nudge":
|
|
9513
9569
|
current.onNudge(dx ?? 0, dy ?? 0);
|
|
9514
9570
|
break;
|
|
@@ -9617,7 +9673,8 @@ function useViewerIntegration(input) {
|
|
|
9617
9673
|
content,
|
|
9618
9674
|
filePath,
|
|
9619
9675
|
autosaveEnabled,
|
|
9620
|
-
|
|
9676
|
+
autosaveAllowed = true,
|
|
9677
|
+
autosaveIntervalMs,
|
|
9621
9678
|
canEdit,
|
|
9622
9679
|
mode,
|
|
9623
9680
|
slides,
|
|
@@ -9673,7 +9730,7 @@ function useViewerIntegration(input) {
|
|
|
9673
9730
|
content,
|
|
9674
9731
|
filePath,
|
|
9675
9732
|
autosaveEnabled,
|
|
9676
|
-
|
|
9733
|
+
autosaveIntervalMs,
|
|
9677
9734
|
// The File > Fonts toggle, finally reaching a save call.
|
|
9678
9735
|
embedFonts: dialogs.embedFontsEnabled,
|
|
9679
9736
|
slides,
|
|
@@ -9717,12 +9774,13 @@ function useViewerIntegration(input) {
|
|
|
9717
9774
|
setMode: state.setMode,
|
|
9718
9775
|
setSlides: state.setSlides
|
|
9719
9776
|
});
|
|
9720
|
-
useRecoveryDetection({
|
|
9777
|
+
const recovery = useRecoveryDetection({
|
|
9721
9778
|
filePath,
|
|
9722
9779
|
loading,
|
|
9723
9780
|
error,
|
|
9724
9781
|
slideCount: slides.length,
|
|
9725
|
-
|
|
9782
|
+
autosaveAllowed,
|
|
9783
|
+
onRestore: setContent
|
|
9726
9784
|
});
|
|
9727
9785
|
useImperativeHandle(
|
|
9728
9786
|
ref,
|
|
@@ -9930,6 +9988,7 @@ function useViewerIntegration(input) {
|
|
|
9930
9988
|
handleEnterPresenterView,
|
|
9931
9989
|
handleEnterRehearsalMode,
|
|
9932
9990
|
autosaveStatus,
|
|
9991
|
+
recovery,
|
|
9933
9992
|
isEncryptedDialogOpen,
|
|
9934
9993
|
setIsEncryptedDialogOpen,
|
|
9935
9994
|
handlerRef,
|
|
@@ -10855,6 +10914,15 @@ function buildToolbarProps(input) {
|
|
|
10855
10914
|
onToggleVersionHistory: () => propertyHandlers.setIsVersionHistoryOpen((p) => !p),
|
|
10856
10915
|
onOpenPasswordProtection: () => dialogs.setIsPasswordDialogOpen(true),
|
|
10857
10916
|
onOpenDocumentProperties: () => dialogs.setIsDocPropsDialogOpen(true),
|
|
10917
|
+
// Design > Slide Size: the size control is the inspector's SLIDE SIZE
|
|
10918
|
+
// card, which the deck (no-selection) panel renders. Drop the selection so
|
|
10919
|
+
// that panel is what the pane shows, then open it.
|
|
10920
|
+
onOpenSlideSize: () => {
|
|
10921
|
+
s.setSelectedElementId(null);
|
|
10922
|
+
s.setSelectedElementIds([]);
|
|
10923
|
+
s.setSidebarPanelMode("properties");
|
|
10924
|
+
s.setIsInspectorPaneOpen(true);
|
|
10925
|
+
},
|
|
10858
10926
|
onOpenFontEmbedding: () => dialogs.setIsFontEmbeddingOpen(true),
|
|
10859
10927
|
onOpenDigitalSignatures: () => dialogs.setIsDigitalSigDialogOpen(true),
|
|
10860
10928
|
onEnterPresenterView,
|
|
@@ -10981,7 +11049,12 @@ function useViewerBuildingBlocksCore(input) {
|
|
|
10981
11049
|
setMode: state.setMode,
|
|
10982
11050
|
setActiveSlideIndex: state.setActiveSlideIndex,
|
|
10983
11051
|
setSlides: state.setSlides,
|
|
10984
|
-
history
|
|
11052
|
+
history,
|
|
11053
|
+
// PowerPoint's bare `J` during a show toggles live captions.
|
|
11054
|
+
onToggleSubtitles: () => state.setPresentationProperties((prev) => ({
|
|
11055
|
+
...prev,
|
|
11056
|
+
showSubtitles: !prev.showSubtitles
|
|
11057
|
+
}))
|
|
10985
11058
|
});
|
|
10986
11059
|
return {
|
|
10987
11060
|
state,
|