pptx-react-viewer 2.16.10 → 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.
- package/CHANGELOG.md +4 -0
- package/README.md +14 -14
- package/dist/{AiChatPanel-XHKYPYPH.mjs → AiChatPanel-SSSBERWJ.mjs} +4 -4
- package/dist/AiChatPanel-SSSBERWJ.mjs.br +0 -0
- package/dist/AiChatPanel-SSSBERWJ.mjs.gz +0 -0
- package/dist/{AiChatPanel-EPMBL6EA.js → AiChatPanel-UN5DHPZY.js} +24 -24
- package/dist/AiChatPanel-UN5DHPZY.js.br +0 -0
- package/dist/AiChatPanel-UN5DHPZY.js.gz +0 -0
- package/dist/{Model3DScene-DUJOZA2B.js → Model3DScene-4RPYKC2I.js} +2 -2
- package/dist/Model3DScene-4RPYKC2I.js.br +0 -0
- package/dist/Model3DScene-4RPYKC2I.js.gz +0 -0
- package/dist/{Model3DScene-YMIAGRPG.mjs → Model3DScene-LYEESYAI.mjs} +1 -1
- package/dist/Model3DScene-LYEESYAI.mjs.br +0 -0
- package/dist/Model3DScene-LYEESYAI.mjs.gz +0 -0
- package/dist/{PowerPointViewer-Du7u4INi.d.ts → PowerPointViewer-Cf4YHjdF.d.ts} +2 -2
- package/dist/PowerPointViewer-Cf4YHjdF.d.ts.map +1 -0
- package/dist/{SurfaceChart3DScene-TNCHWQAK.js → SurfaceChart3DScene-ACPKCWLJ.js} +2 -2
- package/dist/SurfaceChart3DScene-ACPKCWLJ.js.br +0 -0
- package/dist/SurfaceChart3DScene-ACPKCWLJ.js.gz +0 -0
- package/dist/{SurfaceChart3DScene-Q47OEJXS.mjs → SurfaceChart3DScene-JR62SOYO.mjs} +1 -1
- package/dist/SurfaceChart3DScene-JR62SOYO.mjs.br +0 -0
- package/dist/SurfaceChart3DScene-JR62SOYO.mjs.gz +0 -0
- package/dist/{audience-content-store-BvqKy7Hf.d.ts → audience-content-store-CyS0oP6t.d.ts} +2 -2
- package/dist/{audience-content-store-BvqKy7Hf.d.ts.map → audience-content-store-CyS0oP6t.d.ts.map} +1 -1
- package/dist/{chunk-WK22Z7PK.js → chunk-4LWGAVAP.js} +526 -928
- package/dist/chunk-4LWGAVAP.js.br +0 -0
- package/dist/chunk-4LWGAVAP.js.gz +0 -0
- package/dist/{chunk-EL2YF26P.mjs → chunk-7XF6S4AM.mjs} +1 -1
- package/dist/chunk-7XF6S4AM.mjs.br +0 -0
- package/dist/chunk-7XF6S4AM.mjs.gz +0 -0
- package/dist/{chunk-FSVE6WUY.js → chunk-ASKYZ5ZY.js} +728 -523
- package/dist/chunk-ASKYZ5ZY.js.br +0 -0
- package/dist/chunk-ASKYZ5ZY.js.gz +0 -0
- package/dist/{chunk-VHME5BE6.mjs → chunk-BZOL6FXF.mjs} +326 -728
- package/dist/chunk-BZOL6FXF.mjs.br +0 -0
- package/dist/chunk-BZOL6FXF.mjs.gz +0 -0
- package/dist/{chunk-YWKUIUQX.mjs → chunk-GODW6RNR.mjs} +87648 -78804
- package/dist/chunk-GODW6RNR.mjs.br +0 -0
- package/dist/chunk-GODW6RNR.mjs.gz +0 -0
- package/dist/{chunk-ESC6IB2F.js → chunk-ICZDMFF2.js} +2147 -3399
- package/dist/chunk-ICZDMFF2.js.br +0 -0
- package/dist/chunk-ICZDMFF2.js.gz +0 -0
- package/dist/{chunk-PI5SFTDC.js → chunk-MAVLV56S.js} +3 -3
- package/dist/chunk-MAVLV56S.js.br +0 -0
- package/dist/chunk-MAVLV56S.js.gz +0 -0
- package/dist/{chunk-G3VAE7ZF.mjs → chunk-O7FTUUXP.mjs} +1212 -2464
- package/dist/chunk-O7FTUUXP.mjs.br +0 -0
- package/dist/chunk-O7FTUUXP.mjs.gz +0 -0
- package/dist/{chunk-J7EFC3GS.mjs → chunk-QUB5OSKY.mjs} +394 -189
- package/dist/chunk-QUB5OSKY.mjs.br +0 -0
- package/dist/chunk-QUB5OSKY.mjs.gz +0 -0
- package/dist/{chunk-DVZF4ARG.js → chunk-RTUGI4HQ.js} +49 -4
- package/dist/chunk-RTUGI4HQ.js.br +0 -0
- package/dist/chunk-RTUGI4HQ.js.gz +0 -0
- package/dist/{chunk-5IUEPQTK.mjs → chunk-SNL6LBRX.mjs} +49 -4
- package/dist/chunk-SNL6LBRX.mjs.br +0 -0
- package/dist/chunk-SNL6LBRX.mjs.gz +0 -0
- package/dist/{chunk-Y2KIB3QH.js → chunk-WVDM36ZM.js} +87730 -78843
- package/dist/chunk-WVDM36ZM.js.br +0 -0
- package/dist/chunk-WVDM36ZM.js.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 +702 -37
- 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 +923 -54
- 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-C_CTI-QE.d.ts} +3 -31
- package/dist/types-C_CTI-QE.d.ts.map +1 -0
- package/dist/{useViewerBuildingBlocks-Xddn6SFj.d.ts → useViewerBuildingBlocks-DItilDbP.d.ts} +47 -8
- package/dist/useViewerBuildingBlocks-DItilDbP.d.ts.map +1 -0
- package/dist/viewer/index.d.ts +593 -56
- 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-EPMBL6EA.js.br +0 -0
- package/dist/AiChatPanel-EPMBL6EA.js.gz +0 -0
- package/dist/AiChatPanel-XHKYPYPH.mjs.br +0 -0
- package/dist/AiChatPanel-XHKYPYPH.mjs.gz +0 -0
- package/dist/Model3DScene-DUJOZA2B.js.br +0 -0
- package/dist/Model3DScene-DUJOZA2B.js.gz +0 -0
- package/dist/Model3DScene-YMIAGRPG.mjs.br +0 -0
- package/dist/Model3DScene-YMIAGRPG.mjs.gz +0 -0
- package/dist/PowerPointViewer-Du7u4INi.d.ts.map +0 -1
- package/dist/SurfaceChart3DScene-Q47OEJXS.mjs.br +0 -0
- package/dist/SurfaceChart3DScene-Q47OEJXS.mjs.gz +0 -0
- package/dist/SurfaceChart3DScene-TNCHWQAK.js.br +0 -0
- package/dist/SurfaceChart3DScene-TNCHWQAK.js.gz +0 -0
- package/dist/chunk-5IUEPQTK.mjs.br +0 -0
- package/dist/chunk-5IUEPQTK.mjs.gz +0 -0
- package/dist/chunk-DVZF4ARG.js.br +0 -0
- package/dist/chunk-DVZF4ARG.js.gz +0 -0
- package/dist/chunk-EL2YF26P.mjs.br +0 -0
- package/dist/chunk-EL2YF26P.mjs.gz +0 -0
- package/dist/chunk-ESC6IB2F.js.br +0 -0
- package/dist/chunk-ESC6IB2F.js.gz +0 -0
- package/dist/chunk-FSVE6WUY.js.br +0 -0
- package/dist/chunk-FSVE6WUY.js.gz +0 -0
- package/dist/chunk-G3VAE7ZF.mjs.br +0 -0
- package/dist/chunk-G3VAE7ZF.mjs.gz +0 -0
- package/dist/chunk-J7EFC3GS.mjs.br +0 -0
- package/dist/chunk-J7EFC3GS.mjs.gz +0 -0
- package/dist/chunk-PI5SFTDC.js.br +0 -0
- package/dist/chunk-PI5SFTDC.js.gz +0 -0
- package/dist/chunk-VHME5BE6.mjs.br +0 -0
- package/dist/chunk-VHME5BE6.mjs.gz +0 -0
- package/dist/chunk-WK22Z7PK.js.br +0 -0
- package/dist/chunk-WK22Z7PK.js.gz +0 -0
- package/dist/chunk-Y2KIB3QH.js.br +0 -0
- package/dist/chunk-Y2KIB3QH.js.gz +0 -0
- package/dist/chunk-YWKUIUQX.mjs.br +0 -0
- package/dist/chunk-YWKUIUQX.mjs.gz +0 -0
- package/dist/types-DU35aAJK.d.ts.map +0 -1
- package/dist/useViewerBuildingBlocks-Xddn6SFj.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, isTemplateElementId, hasShapeProperties, hasTextProperties, getInlineEditorSelection, applyStyleToSelectedSegments, setPendingSelectionRestore, applyCaseTransformToSegments, transformTextCase, addSection, renameSection, deleteSection, moveSectionUp, moveSectionDown, moveSlidesToSection, normalizeColorsForCapture, preprocessCssForCapture, downloadBlob, sanitizeDownloadFilename, slideProgressPercent, slideStatusLabel, EXPORT_ASSEMBLING_PERCENT, EXPORT_DONE_PERCENT, isExportAbortError, recordProgressPercent, applyThemeToData, THEME_PRESETS, themeColorSchemesEqual, comparePresentation, applyAcceptSlide, applyAcceptAllSlides, collectUsedFonts, detectTouchDevice, detectOrientation, isMobileViewport, MOBILE_BREAKPOINT, TABLET_BREAKPOINT, mayLeaveSlideShow, stopAllPersistentAudio, remapTextToSegments, guidePxToEmu, buildSaveSlides, shouldLoopContinuously, applyRehearsalTimings, copyFormatFromElement, applyFormatToElement, mapEditorKey, isEditorTextInputTarget, createViewerOptionsStore, readSlidesFromYDoc, reconcileSlidesInYDoc, LOCAL_SYNC_ORIGIN, observeYDocSlides, shouldAutoFollowBroadcaster, createTouchGestureRecognizer, MAX_ZOOM_SCALE, MIN_ZOOM_SCALE, isKeyboardOpen, openPptxFile, readBackstageRecentFile, isActionHidden, buildElementClipboardPayload, generatePackageReadme, exportDeckJson, groupElements, generateElementId, makeCloneId, alignElements, distributeElements, bringForward, sendBackward, bringToFront, sendToBack, newTableElement, createDefaultChartElement, readViewportMetrics, computeKeyboardInset, mergeShapes, mapPresentationKey, lastShowSlideIndex, firstShowSlideIndex, 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, hasCopyableFormat, createBackstagePresentation, buildFieldSubstitutionContext, cloneElementForPaste, computeScrollDelta, getPresetShapeClipPath, svgPathToPolygons, polygonsToSvgPath, rerouteConnectorsForMovedElements, applyReroutedConnectors, SvgExporter, buildPrintHtmlDocument, deleteTableColumn, rebuildTableStructureInRawXml, insertTableColumn, deleteTableRow, insertTableRow, updateCellTextStyleInRawXml, updateCellTextInRawXml, splitCell, updateMergeAttrsInRawXml, mergeCells, isPpactionUrl, parsePpactionUrl, safeOpenUrl, ACTION_BUTTON_PRESETS, elementActionToPptxAction, buildSmartArtPresetData, computeSnapToShape, publishLiveGeometry, computeMarqueeHitIds, mergeAdditiveSelection, applyResize, snapBoxToGrid, applyMotionPathPreset } from './chunk-
|
|
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';
|
|
@@ -484,6 +484,7 @@ function useEditorHistory(input) {
|
|
|
484
484
|
maxHistoryEntries = DEFAULT_MAX_HISTORY_ENTRIES,
|
|
485
485
|
hasActivePointerInteraction,
|
|
486
486
|
pointerCommitNonce,
|
|
487
|
+
onDirty,
|
|
487
488
|
setSlides,
|
|
488
489
|
setCanvasSize,
|
|
489
490
|
setActiveSlideIndex,
|
|
@@ -556,8 +557,13 @@ function useEditorHistory(input) {
|
|
|
556
557
|
isApplyingHistoryRef.current = false;
|
|
557
558
|
}, 0);
|
|
558
559
|
}, []);
|
|
560
|
+
const onDirtyRef = useRef(onDirty);
|
|
561
|
+
useEffect(() => {
|
|
562
|
+
onDirtyRef.current = onDirty;
|
|
563
|
+
}, [onDirty]);
|
|
559
564
|
const markDirty = useCallback(() => {
|
|
560
565
|
setEditCommitNonce((previous) => previous + 1);
|
|
566
|
+
onDirtyRef.current?.();
|
|
561
567
|
}, []);
|
|
562
568
|
const handleUndo = useCallback(() => {
|
|
563
569
|
const previousSnapshot = historyPastRef.current.pop();
|
|
@@ -655,6 +661,7 @@ function useEditorHistory(input) {
|
|
|
655
661
|
updateHistoryAvailability();
|
|
656
662
|
return;
|
|
657
663
|
}
|
|
664
|
+
onDirtyRef.current?.();
|
|
658
665
|
historyPastRef.current.push(cloneHistorySnapshot(previousSnapshot));
|
|
659
666
|
while (historyPastRef.current.length > Math.max(1, maxHistoryEntries)) {
|
|
660
667
|
historyPastRef.current.shift();
|
|
@@ -1669,6 +1676,7 @@ function usePresentationKeyboard(input) {
|
|
|
1669
1676
|
onToggleInkMarkup,
|
|
1670
1677
|
onToggleToolbar,
|
|
1671
1678
|
onShowAllSlides,
|
|
1679
|
+
onToggleSubtitles,
|
|
1672
1680
|
onToggleBlackScreen,
|
|
1673
1681
|
onToggleWhiteScreen,
|
|
1674
1682
|
rehearsing,
|
|
@@ -1734,6 +1742,9 @@ function usePresentationKeyboard(input) {
|
|
|
1734
1742
|
case "showAllSlides":
|
|
1735
1743
|
onShowAllSlides?.();
|
|
1736
1744
|
return;
|
|
1745
|
+
case "toggleSubtitles":
|
|
1746
|
+
onToggleSubtitles?.();
|
|
1747
|
+
return;
|
|
1737
1748
|
case "toggleBlackScreen":
|
|
1738
1749
|
onToggleBlackScreen?.();
|
|
1739
1750
|
return;
|
|
@@ -1773,6 +1784,7 @@ function usePresentationKeyboard(input) {
|
|
|
1773
1784
|
onToggleInkMarkup,
|
|
1774
1785
|
onToggleToolbar,
|
|
1775
1786
|
onShowAllSlides,
|
|
1787
|
+
onToggleSubtitles,
|
|
1776
1788
|
onToggleBlackScreen,
|
|
1777
1789
|
onToggleWhiteScreen,
|
|
1778
1790
|
rehearsing,
|
|
@@ -2213,6 +2225,7 @@ function usePresentationMode(input) {
|
|
|
2213
2225
|
onEraseAnnotations,
|
|
2214
2226
|
onToggleInkMarkup,
|
|
2215
2227
|
onToggleToolbar,
|
|
2228
|
+
onToggleSubtitles,
|
|
2216
2229
|
onSaveRehearsalTimings,
|
|
2217
2230
|
loopContinuously,
|
|
2218
2231
|
showWithAnimation,
|
|
@@ -2420,6 +2433,7 @@ function usePresentationMode(input) {
|
|
|
2420
2433
|
onToggleInkMarkup,
|
|
2421
2434
|
onToggleToolbar,
|
|
2422
2435
|
onShowAllSlides: openAllSlides,
|
|
2436
|
+
onToggleSubtitles,
|
|
2423
2437
|
onToggleBlackScreen: () => presenterConsole.setBlackout(
|
|
2424
2438
|
presenterConsole.snapshot.blackout === "black" ? "none" : "black"
|
|
2425
2439
|
),
|
|
@@ -2902,13 +2916,15 @@ function useFindReplace({
|
|
|
2902
2916
|
}, [findResults, applyReplacements, performFind]);
|
|
2903
2917
|
useEffect(() => {
|
|
2904
2918
|
const handler = (event) => {
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2919
|
+
const { action } = mapEditorKey(event, {
|
|
2920
|
+
canEdit: mode === "edit",
|
|
2921
|
+
isTextInputTarget: isEditorTextInputTarget(event.target)
|
|
2922
|
+
});
|
|
2923
|
+
if (action !== "find") {
|
|
2924
|
+
return;
|
|
2911
2925
|
}
|
|
2926
|
+
event.preventDefault();
|
|
2927
|
+
setFindReplaceOpen((prev) => !prev);
|
|
2912
2928
|
};
|
|
2913
2929
|
window.addEventListener("keydown", handler);
|
|
2914
2930
|
return () => window.removeEventListener("keydown", handler);
|
|
@@ -3348,9 +3364,28 @@ function useDerivedElementState(input) {
|
|
|
3348
3364
|
}
|
|
3349
3365
|
return templateElementsBySlideId[activeSlide.id] ?? [];
|
|
3350
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]);
|
|
3351
3378
|
const elementLookup = useMemo(
|
|
3352
|
-
() => buildElementLookup(
|
|
3353
|
-
|
|
3379
|
+
() => buildElementLookup(
|
|
3380
|
+
[
|
|
3381
|
+
...templateElements,
|
|
3382
|
+
...masterViewElements2,
|
|
3383
|
+
...notesMasterElements,
|
|
3384
|
+
...handoutMasterElements
|
|
3385
|
+
],
|
|
3386
|
+
activeSlide?.elements ?? []
|
|
3387
|
+
),
|
|
3388
|
+
[activeSlide, templateElements, masterViewElements2, notesMasterElements, handoutMasterElements]
|
|
3354
3389
|
);
|
|
3355
3390
|
const selectedElement = useMemo(() => {
|
|
3356
3391
|
if (!selectedElementId) {
|
|
@@ -3367,17 +3402,6 @@ function useDerivedElementState(input) {
|
|
|
3367
3402
|
() => effectiveSelectedIds.map((id) => elementLookup.get(id)).filter(Boolean),
|
|
3368
3403
|
[effectiveSelectedIds, elementLookup]
|
|
3369
3404
|
);
|
|
3370
|
-
const activeMaster = slideMasters[activeMasterIndex];
|
|
3371
|
-
const activeLayout = useMemo(
|
|
3372
|
-
() => resolveActiveLayout(activeMaster, activeLayoutIndex),
|
|
3373
|
-
[activeMaster, activeLayoutIndex]
|
|
3374
|
-
);
|
|
3375
|
-
const masterViewElements = useMemo(
|
|
3376
|
-
() => computeMasterViewElements(activeMaster, activeLayout),
|
|
3377
|
-
[activeMaster, activeLayout]
|
|
3378
|
-
);
|
|
3379
|
-
const notesMasterElements = useMemo(() => notesMaster?.elements ?? [], [notesMaster]);
|
|
3380
|
-
const handoutMasterElements = useMemo(() => handoutMaster?.elements ?? [], [handoutMaster]);
|
|
3381
3405
|
return {
|
|
3382
3406
|
activeSlide,
|
|
3383
3407
|
templateElements,
|
|
@@ -3388,7 +3412,7 @@ function useDerivedElementState(input) {
|
|
|
3388
3412
|
selectedElements,
|
|
3389
3413
|
activeMaster,
|
|
3390
3414
|
activeLayout,
|
|
3391
|
-
masterViewElements,
|
|
3415
|
+
masterViewElements: masterViewElements2,
|
|
3392
3416
|
notesMasterElements,
|
|
3393
3417
|
handoutMasterElements
|
|
3394
3418
|
};
|
|
@@ -3416,6 +3440,7 @@ function useViewerCoreState(_input) {
|
|
|
3416
3440
|
width: DEFAULT_CANVAS_WIDTH,
|
|
3417
3441
|
height: DEFAULT_CANVAS_HEIGHT
|
|
3418
3442
|
});
|
|
3443
|
+
const [slideSizeEmu, setSlideSizeEmu] = useState();
|
|
3419
3444
|
const [activeSlideIndex, setActiveSlideIndex] = useState(0);
|
|
3420
3445
|
const [selectedElementId, setSelectedElementId] = useState(null);
|
|
3421
3446
|
const [selectedElementIds, setSelectedElementIds] = useState([]);
|
|
@@ -3514,6 +3539,8 @@ function useViewerCoreState(_input) {
|
|
|
3514
3539
|
setTemplateElementsBySlideId,
|
|
3515
3540
|
canvasSize,
|
|
3516
3541
|
setCanvasSize,
|
|
3542
|
+
slideSizeEmu,
|
|
3543
|
+
setSlideSizeEmu,
|
|
3517
3544
|
activeSlideIndex,
|
|
3518
3545
|
setActiveSlideIndex,
|
|
3519
3546
|
selectedElementId,
|
|
@@ -3718,6 +3745,7 @@ function useLoadContent({
|
|
|
3718
3745
|
setTemplateElementsBySlideId,
|
|
3719
3746
|
mediaDataUrls,
|
|
3720
3747
|
setCanvasSize,
|
|
3748
|
+
setSlideSizeEmu,
|
|
3721
3749
|
setHeaderFooter,
|
|
3722
3750
|
setLayoutOptions,
|
|
3723
3751
|
setSlideMasters,
|
|
@@ -3725,6 +3753,7 @@ function useLoadContent({
|
|
|
3725
3753
|
setTableStyleMap,
|
|
3726
3754
|
setThemeOptions,
|
|
3727
3755
|
setCustomShows,
|
|
3756
|
+
setActiveCustomShowId,
|
|
3728
3757
|
setSections,
|
|
3729
3758
|
setPresentationProperties,
|
|
3730
3759
|
setNotesMaster,
|
|
@@ -3884,6 +3913,13 @@ function useLoadContent({
|
|
|
3884
3913
|
width: parsed.width ?? DEFAULT_CANVAS_WIDTH,
|
|
3885
3914
|
height: parsed.height ?? DEFAULT_CANVAS_HEIGHT
|
|
3886
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
|
+
);
|
|
3887
3923
|
setHeaderFooter(parsed.headerFooter ?? {});
|
|
3888
3924
|
setLayoutOptions(parsed.layoutOptions ?? []);
|
|
3889
3925
|
setSlideMasters(parsed.slideMasters ?? []);
|
|
@@ -3891,6 +3927,9 @@ function useLoadContent({
|
|
|
3891
3927
|
setTableStyleMap(parsed.tableStyleMap);
|
|
3892
3928
|
setThemeOptions(parsed.themeOptions ?? []);
|
|
3893
3929
|
setCustomShows(parsed.customShows ?? []);
|
|
3930
|
+
setActiveCustomShowId(
|
|
3931
|
+
resolveAuthoredCustomShowId(parsed.presentationProperties, parsed.customShows) ?? null
|
|
3932
|
+
);
|
|
3894
3933
|
setSections(parsed.sections ?? []);
|
|
3895
3934
|
setPresentationProperties(parsed.presentationProperties ?? {});
|
|
3896
3935
|
setNotesMaster(parsed.notesMaster);
|
|
@@ -3959,7 +3998,8 @@ function useAutosave(input) {
|
|
|
3959
3998
|
filePath,
|
|
3960
3999
|
serializeSlides,
|
|
3961
4000
|
intervalSeconds = DEFAULT_AUTOSAVE_INTERVAL_SECONDS,
|
|
3962
|
-
enabled = true
|
|
4001
|
+
enabled = true,
|
|
4002
|
+
getChangeSources
|
|
3963
4003
|
} = input;
|
|
3964
4004
|
const [autosaveStatus, setAutosaveStatus] = useState({
|
|
3965
4005
|
state: "idle"
|
|
@@ -3968,6 +4008,8 @@ function useAutosave(input) {
|
|
|
3968
4008
|
const filePathRef = useRef(filePath);
|
|
3969
4009
|
const serializeRef = useRef(serializeSlides);
|
|
3970
4010
|
const isSavingRef = useRef(false);
|
|
4011
|
+
const changeSourcesRef = useRef(getChangeSources);
|
|
4012
|
+
const lastSnapshotRef = useRef(void 0);
|
|
3971
4013
|
useEffect(() => {
|
|
3972
4014
|
isDirtyRef.current = isDirty;
|
|
3973
4015
|
}, [isDirty]);
|
|
@@ -3977,14 +4019,22 @@ function useAutosave(input) {
|
|
|
3977
4019
|
useEffect(() => {
|
|
3978
4020
|
serializeRef.current = serializeSlides;
|
|
3979
4021
|
}, [serializeSlides]);
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
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
|
+
})) {
|
|
3988
4038
|
return;
|
|
3989
4039
|
}
|
|
3990
4040
|
isSavingRef.current = true;
|
|
@@ -3996,7 +4046,8 @@ function useAutosave(input) {
|
|
|
3996
4046
|
isSavingRef.current = false;
|
|
3997
4047
|
return;
|
|
3998
4048
|
}
|
|
3999
|
-
await saveAutosaveSnapshot(
|
|
4049
|
+
await saveAutosaveSnapshot(path, data);
|
|
4050
|
+
lastSnapshotRef.current = autosaveSnapshotMark(path, sources);
|
|
4000
4051
|
setAutosaveStatus({ state: "saved", timestamp: Date.now() });
|
|
4001
4052
|
} catch (err) {
|
|
4002
4053
|
setAutosaveStatus({
|
|
@@ -4022,13 +4073,13 @@ function useAutosave(input) {
|
|
|
4022
4073
|
setAutosaveStatus((prev) => prev.state === "disabled" ? { state: "idle" } : prev);
|
|
4023
4074
|
const ms = computeAutosaveIntervalMs(intervalSeconds);
|
|
4024
4075
|
const id = setInterval(() => {
|
|
4025
|
-
void doAutosave();
|
|
4076
|
+
void doAutosave({ polled: true });
|
|
4026
4077
|
}, ms);
|
|
4027
4078
|
return () => clearInterval(id);
|
|
4028
4079
|
}, [enabled, filePath, intervalSeconds, doAutosave]);
|
|
4029
4080
|
return {
|
|
4030
4081
|
autosaveStatus,
|
|
4031
|
-
triggerAutosave: doAutosave
|
|
4082
|
+
triggerAutosave: () => doAutosave()
|
|
4032
4083
|
};
|
|
4033
4084
|
}
|
|
4034
4085
|
function useElementOperations(input) {
|
|
@@ -4039,6 +4090,7 @@ function useElementOperations(input) {
|
|
|
4039
4090
|
selectedElementId,
|
|
4040
4091
|
editTemplateMode,
|
|
4041
4092
|
templateElements,
|
|
4093
|
+
masterView,
|
|
4042
4094
|
history,
|
|
4043
4095
|
setSlides,
|
|
4044
4096
|
setTemplateElementsBySlideId,
|
|
@@ -4059,8 +4111,33 @@ function useElementOperations(input) {
|
|
|
4059
4111
|
setInlineEditingElementId(null);
|
|
4060
4112
|
setContextMenuState(null);
|
|
4061
4113
|
}, [applySelection, setInlineEditingElementId, setContextMenuState]);
|
|
4114
|
+
const applyMasterViewWrite = useCallback(
|
|
4115
|
+
(write) => {
|
|
4116
|
+
if (!write || !masterView) {
|
|
4117
|
+
return false;
|
|
4118
|
+
}
|
|
4119
|
+
if (write.slideMasters) {
|
|
4120
|
+
masterView.setSlideMasters(write.slideMasters);
|
|
4121
|
+
}
|
|
4122
|
+
if (write.notesMaster) {
|
|
4123
|
+
masterView.setNotesMaster(write.notesMaster);
|
|
4124
|
+
}
|
|
4125
|
+
if (write.handoutMaster) {
|
|
4126
|
+
masterView.setHandoutMaster(write.handoutMaster);
|
|
4127
|
+
}
|
|
4128
|
+
history.markDirty();
|
|
4129
|
+
return true;
|
|
4130
|
+
},
|
|
4131
|
+
[history, masterView]
|
|
4132
|
+
);
|
|
4062
4133
|
const updateElementById = useCallback(
|
|
4063
4134
|
(elementId, updates) => {
|
|
4135
|
+
if (masterView?.target) {
|
|
4136
|
+
applyMasterViewWrite(
|
|
4137
|
+
updateMasterViewElement(masterView, masterView.target, elementId, updates)
|
|
4138
|
+
);
|
|
4139
|
+
return;
|
|
4140
|
+
}
|
|
4064
4141
|
if (isTemplateElementId(elementId)) {
|
|
4065
4142
|
const slideId = activeSlide?.id;
|
|
4066
4143
|
if (slideId) {
|
|
@@ -4088,7 +4165,15 @@ function useElementOperations(input) {
|
|
|
4088
4165
|
}
|
|
4089
4166
|
history.markDirty();
|
|
4090
4167
|
},
|
|
4091
|
-
[
|
|
4168
|
+
[
|
|
4169
|
+
activeSlide?.id,
|
|
4170
|
+
activeSlideIndex,
|
|
4171
|
+
applyMasterViewWrite,
|
|
4172
|
+
history,
|
|
4173
|
+
masterView,
|
|
4174
|
+
setSlides,
|
|
4175
|
+
setTemplateElementsBySlideId
|
|
4176
|
+
]
|
|
4092
4177
|
);
|
|
4093
4178
|
const updateSelectedElement = useCallback(
|
|
4094
4179
|
(updates) => {
|
|
@@ -4176,9 +4261,20 @@ function useElementOperations(input) {
|
|
|
4176
4261
|
},
|
|
4177
4262
|
[setSlides]
|
|
4178
4263
|
);
|
|
4179
|
-
const
|
|
4264
|
+
const masterViewTarget = masterView?.target ?? null;
|
|
4265
|
+
const activeElements = masterViewTarget ? masterViewElements(masterView, masterViewTarget) : editTemplateMode ? templateElements : activeSlide?.elements ?? [];
|
|
4180
4266
|
const updateActiveElements = useCallback(
|
|
4181
4267
|
(updater) => {
|
|
4268
|
+
if (masterView?.target) {
|
|
4269
|
+
applyMasterViewWrite(
|
|
4270
|
+
replaceMasterViewElements(
|
|
4271
|
+
masterView,
|
|
4272
|
+
masterView.target,
|
|
4273
|
+
updater(masterViewElements(masterView, masterView.target))
|
|
4274
|
+
)
|
|
4275
|
+
);
|
|
4276
|
+
return;
|
|
4277
|
+
}
|
|
4182
4278
|
if (editTemplateMode) {
|
|
4183
4279
|
const slideId = activeSlide?.id;
|
|
4184
4280
|
if (!slideId) {
|
|
@@ -4196,7 +4292,15 @@ function useElementOperations(input) {
|
|
|
4196
4292
|
);
|
|
4197
4293
|
}
|
|
4198
4294
|
},
|
|
4199
|
-
[
|
|
4295
|
+
[
|
|
4296
|
+
applyMasterViewWrite,
|
|
4297
|
+
editTemplateMode,
|
|
4298
|
+
masterView,
|
|
4299
|
+
activeSlide?.id,
|
|
4300
|
+
activeSlideIndex,
|
|
4301
|
+
setSlides,
|
|
4302
|
+
setTemplateElementsBySlideId
|
|
4303
|
+
]
|
|
4200
4304
|
);
|
|
4201
4305
|
const serializeSlides = useCallback(async () => {
|
|
4202
4306
|
return null;
|
|
@@ -4267,13 +4371,23 @@ function useSectionOperations(input) {
|
|
|
4267
4371
|
},
|
|
4268
4372
|
[sections, slides, setSlides, setSections, markDirty]
|
|
4269
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
|
+
);
|
|
4270
4383
|
return {
|
|
4271
4384
|
addSection: addSection2,
|
|
4272
4385
|
renameSection: renameSection2,
|
|
4273
4386
|
deleteSection: deleteSection2,
|
|
4274
4387
|
moveSectionUp: moveSectionUp2,
|
|
4275
4388
|
moveSectionDown: moveSectionDown2,
|
|
4276
|
-
moveSlidesToSection: moveSlidesToSection2
|
|
4389
|
+
moveSlidesToSection: moveSlidesToSection2,
|
|
4390
|
+
toggleSectionCollapse
|
|
4277
4391
|
};
|
|
4278
4392
|
}
|
|
4279
4393
|
|
|
@@ -4293,11 +4407,6 @@ function computeResizeGeometry(handle, startX, startY, startWidth, startHeight,
|
|
|
4293
4407
|
}
|
|
4294
4408
|
return snapBoxToGrid(box, handle, gridSpacingPx, MIN_ELEMENT_SIZE);
|
|
4295
4409
|
}
|
|
4296
|
-
function computeAdjustmentValue(startAdjustment, dx, startWidth) {
|
|
4297
|
-
const range = startWidth || 200;
|
|
4298
|
-
const delta = dx / range;
|
|
4299
|
-
return Math.max(0, Math.min(1, startAdjustment + delta));
|
|
4300
|
-
}
|
|
4301
4410
|
function resolveLiveTarget(input) {
|
|
4302
4411
|
const { livePatcher, editTemplateMode, activeSlide } = input;
|
|
4303
4412
|
if (!livePatcher || editTemplateMode || !livePatcher.isActive()) {
|
|
@@ -4496,13 +4605,14 @@ function processResizeMove(e, rs, editorScale, snapToGrid, gridSpacingPx, live)
|
|
|
4496
4605
|
}
|
|
4497
4606
|
function processAdjustmentMove(e, adj, editorScale, updateElementById) {
|
|
4498
4607
|
const dx = (e.clientX - adj.startClientX) / editorScale;
|
|
4499
|
-
const
|
|
4500
|
-
|
|
4608
|
+
const dy = (e.clientY - adj.startClientY) / editorScale;
|
|
4609
|
+
const adjustments = getDraggedShapeAdjustments(adj, dx, dy);
|
|
4610
|
+
if (!adj.moved && Math.hypot(dx, dy) > 2) {
|
|
4501
4611
|
adj.moved = true;
|
|
4502
4612
|
}
|
|
4503
4613
|
if (adj.moved) {
|
|
4504
4614
|
updateElementById(adj.elementId, {
|
|
4505
|
-
shapeAdjustments:
|
|
4615
|
+
shapeAdjustments: adjustments
|
|
4506
4616
|
});
|
|
4507
4617
|
}
|
|
4508
4618
|
}
|
|
@@ -4828,7 +4938,7 @@ function useCanvasInteractions(input) {
|
|
|
4828
4938
|
justInteractedRef.current = false;
|
|
4829
4939
|
} else {
|
|
4830
4940
|
const el = elementLookup.get(elementId);
|
|
4831
|
-
if (el && hasTextProperties(el) &&
|
|
4941
|
+
if (el && hasTextProperties(el) && canInteractWithElement(el, "textEdit")) {
|
|
4832
4942
|
if (!openEquationEditorForElement(el)) {
|
|
4833
4943
|
setInlineEditingElementId(elementId);
|
|
4834
4944
|
setInlineEditingText(el.text ?? "");
|
|
@@ -4847,7 +4957,7 @@ function useCanvasInteractions(input) {
|
|
|
4847
4957
|
if (openEquationEditorForElement(el)) {
|
|
4848
4958
|
return;
|
|
4849
4959
|
}
|
|
4850
|
-
if (hasTextProperties(el)) {
|
|
4960
|
+
if (hasTextProperties(el) && canInteractWithElement(el, "textEdit")) {
|
|
4851
4961
|
setInlineEditingElementId(elementId);
|
|
4852
4962
|
setInlineEditingText(el.text ?? "");
|
|
4853
4963
|
}
|
|
@@ -4870,9 +4980,13 @@ function useCanvasInteractions(input) {
|
|
|
4870
4980
|
justSelectedRef.current = false;
|
|
4871
4981
|
}
|
|
4872
4982
|
const ids = !wasSelected ? [elementId] : effectiveSelectedIds.length ? effectiveSelectedIds : [elementId];
|
|
4983
|
+
const movableIds = filterInteractableIds(ids, (id) => elementLookup.get(id), "move");
|
|
4984
|
+
if (movableIds.length === 0) {
|
|
4985
|
+
return;
|
|
4986
|
+
}
|
|
4873
4987
|
const startPositions = {};
|
|
4874
4988
|
const domEls = /* @__PURE__ */ new Map();
|
|
4875
|
-
for (const id of
|
|
4989
|
+
for (const id of movableIds) {
|
|
4876
4990
|
const el = elementLookup.get(id);
|
|
4877
4991
|
if (el) {
|
|
4878
4992
|
startPositions[id] = { x: el.x, y: el.y };
|
|
@@ -4936,7 +5050,7 @@ function useCanvasInteractions(input) {
|
|
|
4936
5050
|
const handleResizePointerDown = (elementId, e, handle) => {
|
|
4937
5051
|
e.stopPropagation();
|
|
4938
5052
|
const el = elementLookup.get(elementId);
|
|
4939
|
-
if (!el) {
|
|
5053
|
+
if (!el || !canInteractWithElement(el, "resize")) {
|
|
4940
5054
|
return;
|
|
4941
5055
|
}
|
|
4942
5056
|
resizeStateRef.current = {
|
|
@@ -4958,7 +5072,7 @@ function useCanvasInteractions(input) {
|
|
|
4958
5072
|
};
|
|
4959
5073
|
const handleRotate = (elementId, rotationDeg) => {
|
|
4960
5074
|
const el = elementLookup.get(elementId);
|
|
4961
|
-
if (!el || el
|
|
5075
|
+
if (!el || !canInteractWithElement(el, "rotate")) {
|
|
4962
5076
|
return;
|
|
4963
5077
|
}
|
|
4964
5078
|
ops.updateElementById(elementId, { rotation: rotationDeg });
|
|
@@ -4975,30 +5089,18 @@ function useCanvasInteractions(input) {
|
|
|
4975
5089
|
const handleFormatText = (updates) => {
|
|
4976
5090
|
ops.updateSelectedTextStyle(updates);
|
|
4977
5091
|
};
|
|
4978
|
-
const handleAdjustmentPointerDown = (elementId, e) => {
|
|
5092
|
+
const handleAdjustmentPointerDown = (elementId, e, descriptor) => {
|
|
4979
5093
|
e.stopPropagation();
|
|
4980
5094
|
const el = elementLookup.get(elementId);
|
|
4981
|
-
if (!el || !(
|
|
5095
|
+
if (!el || !canInteractWithElement(el, "adjustHandle")) {
|
|
4982
5096
|
return;
|
|
4983
5097
|
}
|
|
4984
|
-
|
|
4985
|
-
el
|
|
5098
|
+
shapeAdjustmentDragStateRef.current = beginShapeAdjustment(
|
|
5099
|
+
el,
|
|
5100
|
+
descriptor,
|
|
5101
|
+
e.clientX,
|
|
5102
|
+
e.clientY
|
|
4986
5103
|
);
|
|
4987
|
-
if (!adjEntries.length) {
|
|
4988
|
-
return;
|
|
4989
|
-
}
|
|
4990
|
-
const [key, value] = adjEntries[0];
|
|
4991
|
-
shapeAdjustmentDragStateRef.current = {
|
|
4992
|
-
elementId,
|
|
4993
|
-
key,
|
|
4994
|
-
shapeType: el.shapeType ?? "rect",
|
|
4995
|
-
startClientX: e.clientX,
|
|
4996
|
-
startClientY: e.clientY,
|
|
4997
|
-
startAdjustment: value,
|
|
4998
|
-
startWidth: el.width,
|
|
4999
|
-
startHeight: el.height,
|
|
5000
|
-
moved: false
|
|
5001
|
-
};
|
|
5002
5104
|
};
|
|
5003
5105
|
return {
|
|
5004
5106
|
handleElementClick,
|
|
@@ -5906,16 +6008,20 @@ function useGroupAlignLayerHandlers(input) {
|
|
|
5906
6008
|
}
|
|
5907
6009
|
const group = selectedElement;
|
|
5908
6010
|
const intoTemplate = isTemplateElementId(group.id);
|
|
5909
|
-
const
|
|
5910
|
-
|
|
5911
|
-
|
|
5912
|
-
|
|
5913
|
-
|
|
5914
|
-
|
|
5915
|
-
|
|
5916
|
-
|
|
5917
|
-
|
|
5918
|
-
|
|
6011
|
+
const childIds = group.children.map(
|
|
6012
|
+
(child) => intoTemplate ? makeCloneId(true, child.id || group.id) : child.id || generateElementId()
|
|
6013
|
+
);
|
|
6014
|
+
const { elements, childIds: usedIds } = ungroupElements(
|
|
6015
|
+
ops.activeElements,
|
|
6016
|
+
group.id,
|
|
6017
|
+
childIds,
|
|
6018
|
+
{ intoTemplate }
|
|
6019
|
+
);
|
|
6020
|
+
if (usedIds.length === 0) {
|
|
6021
|
+
return;
|
|
6022
|
+
}
|
|
6023
|
+
ops.updateActiveElements(() => elements);
|
|
6024
|
+
setSelectedElementIds(usedIds);
|
|
5919
6025
|
history.markDirty();
|
|
5920
6026
|
};
|
|
5921
6027
|
const handleFlip = (direction) => {
|
|
@@ -6909,12 +7015,14 @@ function useExportSaveAs(input) {
|
|
|
6909
7015
|
appProperties,
|
|
6910
7016
|
customProperties,
|
|
6911
7017
|
tagCollections,
|
|
7018
|
+
slideMasters,
|
|
6912
7019
|
notesMaster,
|
|
6913
7020
|
handoutMaster,
|
|
6914
7021
|
guides,
|
|
6915
7022
|
activeSlideIndexForGuides,
|
|
6916
7023
|
theme,
|
|
6917
7024
|
canvasSize,
|
|
7025
|
+
slideSizeEmu,
|
|
6918
7026
|
modalControls,
|
|
6919
7027
|
password
|
|
6920
7028
|
} = input;
|
|
@@ -6938,7 +7046,7 @@ function useExportSaveAs(input) {
|
|
|
6938
7046
|
setExportProgress(10);
|
|
6939
7047
|
setExportStatusMessage("Adding presentation...");
|
|
6940
7048
|
const pptxData = await serializeSlides();
|
|
6941
|
-
const pptxFilename = filePath
|
|
7049
|
+
const pptxFilename = savedPresentationFileName(filePath);
|
|
6942
7050
|
if (pptxData) {
|
|
6943
7051
|
pkgFolder.file(pptxFilename, pptxData);
|
|
6944
7052
|
}
|
|
@@ -6954,8 +7062,7 @@ function useExportSaveAs(input) {
|
|
|
6954
7062
|
const zipBlob = await zip.generateAsync({ type: "blob" });
|
|
6955
7063
|
setExportProgress(95);
|
|
6956
7064
|
setExportStatusMessage("Downloading...");
|
|
6957
|
-
|
|
6958
|
-
downloadBlob(zipBlob, `${baseName}-package.zip`);
|
|
7065
|
+
downloadBlob(zipBlob, `${presentationBaseName(pptxFilename)}-package.zip`);
|
|
6959
7066
|
setExportProgress(100);
|
|
6960
7067
|
} catch (err) {
|
|
6961
7068
|
if (err.name !== "AbortError") {
|
|
@@ -6971,16 +7078,15 @@ function useExportSaveAs(input) {
|
|
|
6971
7078
|
if (!handler) {
|
|
6972
7079
|
return;
|
|
6973
7080
|
}
|
|
6974
|
-
const
|
|
6975
|
-
const baseName = filePath ? filePath.replace(/\\/gu, "/").split("/").pop()?.replace(/\.[^.]+$/u, "") ?? "presentation" : "presentation";
|
|
7081
|
+
const downloadName = savedPresentationFileName(filePath, format);
|
|
6976
7082
|
try {
|
|
6977
7083
|
const data = await buildSaveAsData(handler, format);
|
|
6978
7084
|
const blob = new Blob([data], {
|
|
6979
7085
|
type: "application/vnd.openxmlformats-officedocument.presentationml.presentation"
|
|
6980
7086
|
});
|
|
6981
|
-
downloadBlob(blob,
|
|
7087
|
+
downloadBlob(blob, downloadName);
|
|
6982
7088
|
} catch (err) {
|
|
6983
|
-
console.error(`[PowerPointViewer] Save as .${
|
|
7089
|
+
console.error(`[PowerPointViewer] Save as .${format} failed:`, err);
|
|
6984
7090
|
}
|
|
6985
7091
|
};
|
|
6986
7092
|
const buildSaveAsData = async (handler, format) => {
|
|
@@ -7000,6 +7106,9 @@ function useExportSaveAs(input) {
|
|
|
7000
7106
|
});
|
|
7001
7107
|
const slidesToSave = buildSaveSlides(slidesWithGuides, templateElementsBySlideId);
|
|
7002
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,
|
|
7003
7112
|
headerFooter,
|
|
7004
7113
|
presentationProperties,
|
|
7005
7114
|
customShows: customShows.length > 0 ? customShows : void 0,
|
|
@@ -7008,27 +7117,23 @@ function useExportSaveAs(input) {
|
|
|
7008
7117
|
appProperties: appProperties ?? void 0,
|
|
7009
7118
|
customProperties: customProperties.length > 0 ? customProperties : void 0,
|
|
7010
7119
|
tags: tagCollections.length > 0 ? tagCollections : void 0,
|
|
7120
|
+
slideMasters,
|
|
7011
7121
|
notesMaster,
|
|
7012
7122
|
handoutMaster,
|
|
7013
7123
|
outputFormat: format
|
|
7014
7124
|
};
|
|
7015
|
-
|
|
7016
|
-
return handler.saveEncrypted(
|
|
7017
|
-
slidesToSave,
|
|
7018
|
-
password,
|
|
7019
|
-
saveOptions
|
|
7020
|
-
);
|
|
7021
|
-
}
|
|
7022
|
-
return handler.save(slidesToSave, saveOptions);
|
|
7125
|
+
return saveDeckWithPassword(handler, slidesToSave, saveOptions, password);
|
|
7023
7126
|
};
|
|
7024
7127
|
const handleExportJson = () => {
|
|
7025
7128
|
const sourceName = filePath ? filePath.replace(/\\/gu, "/").split("/").pop() : void 0;
|
|
7129
|
+
const slideSize = resolveSlideSizeSelection({ current: slideSizeEmu, canvas: canvasSize }).size;
|
|
7026
7130
|
const data = {
|
|
7027
7131
|
slides: buildSaveSlides(slides, templateElementsBySlideId),
|
|
7028
7132
|
width: canvasSize.width,
|
|
7029
7133
|
height: canvasSize.height,
|
|
7030
|
-
widthEmu:
|
|
7031
|
-
heightEmu:
|
|
7134
|
+
widthEmu: slideSize.widthEmu,
|
|
7135
|
+
heightEmu: slideSize.heightEmu,
|
|
7136
|
+
slideSizeType: slideSize.type === "" ? void 0 : slideSize.type,
|
|
7032
7137
|
theme,
|
|
7033
7138
|
headerFooter,
|
|
7034
7139
|
presentationProperties,
|
|
@@ -7105,12 +7210,14 @@ function useExportHandlers(input) {
|
|
|
7105
7210
|
appProperties,
|
|
7106
7211
|
customProperties,
|
|
7107
7212
|
tagCollections,
|
|
7213
|
+
slideMasters,
|
|
7108
7214
|
notesMaster,
|
|
7109
7215
|
handoutMaster,
|
|
7110
7216
|
guides,
|
|
7111
7217
|
activeSlideIndexForGuides,
|
|
7112
7218
|
theme,
|
|
7113
7219
|
canvasSize,
|
|
7220
|
+
slideSizeEmu,
|
|
7114
7221
|
password
|
|
7115
7222
|
} = input;
|
|
7116
7223
|
const [exportModalOpen, setExportModalOpen] = useState(false);
|
|
@@ -7146,12 +7253,14 @@ function useExportHandlers(input) {
|
|
|
7146
7253
|
appProperties,
|
|
7147
7254
|
customProperties,
|
|
7148
7255
|
tagCollections,
|
|
7256
|
+
slideMasters,
|
|
7149
7257
|
notesMaster,
|
|
7150
7258
|
handoutMaster,
|
|
7151
7259
|
guides,
|
|
7152
7260
|
activeSlideIndexForGuides,
|
|
7153
7261
|
theme,
|
|
7154
7262
|
canvasSize,
|
|
7263
|
+
slideSizeEmu,
|
|
7155
7264
|
modalControls,
|
|
7156
7265
|
password
|
|
7157
7266
|
});
|
|
@@ -8097,7 +8206,8 @@ function useViewerDialogs(input) {
|
|
|
8097
8206
|
preMasterMode,
|
|
8098
8207
|
hasDigitalSignatures,
|
|
8099
8208
|
isDirty,
|
|
8100
|
-
history
|
|
8209
|
+
history,
|
|
8210
|
+
embeddedFontFamilies
|
|
8101
8211
|
} = input;
|
|
8102
8212
|
const [isSmartArtDialogOpen, setIsSmartArtDialogOpen] = useState(false);
|
|
8103
8213
|
const [isEquationDialogOpen, setIsEquationDialogOpen] = useState(false);
|
|
@@ -8115,7 +8225,15 @@ function useViewerDialogs(input) {
|
|
|
8115
8225
|
const [editingEquationOmml, setEditingEquationOmml] = useState(
|
|
8116
8226
|
null
|
|
8117
8227
|
);
|
|
8118
|
-
const
|
|
8228
|
+
const embeddedFontKey = (embeddedFontFamilies ?? []).join("\0");
|
|
8229
|
+
const fontEmbedding = useMemo(
|
|
8230
|
+
() => describeFontEmbedding(embeddedFontKey ? embeddedFontKey.split("\0") : []),
|
|
8231
|
+
[embeddedFontKey]
|
|
8232
|
+
);
|
|
8233
|
+
const [embedFontsEnabled, setEmbedFontsEnabled] = useState(fontEmbedding.initialEnabled);
|
|
8234
|
+
useEffect(() => {
|
|
8235
|
+
setEmbedFontsEnabled(fontEmbedding.initialEnabled);
|
|
8236
|
+
}, [fontEmbedding]);
|
|
8119
8237
|
const [isNarrowViewport, setIsNarrowViewport] = useState(
|
|
8120
8238
|
() => typeof window !== "undefined" ? isMobileViewport(window.innerWidth, window.innerHeight, viewportIsTouch()) : false
|
|
8121
8239
|
);
|
|
@@ -8282,6 +8400,7 @@ function useViewerDialogs(input) {
|
|
|
8282
8400
|
setEditingEquationOmml,
|
|
8283
8401
|
embedFontsEnabled,
|
|
8284
8402
|
setEmbedFontsEnabled,
|
|
8403
|
+
fontEmbedding,
|
|
8285
8404
|
isNarrowViewport,
|
|
8286
8405
|
handleEnterMasterView,
|
|
8287
8406
|
handleCloseMasterView,
|
|
@@ -8311,7 +8430,7 @@ function computeVisibleSlideIndexes(slides, activeCustomShowId, customShows) {
|
|
|
8311
8430
|
}
|
|
8312
8431
|
function computeSlideSectionGroups(slides, sections) {
|
|
8313
8432
|
return groupSlidesBySection(sections, slides).map((group) => ({
|
|
8314
|
-
id: group.section?.id ?? (sections.length > 0 ? UNGROUPED_SECTION_ID :
|
|
8433
|
+
id: group.section?.id ?? (sections.length > 0 ? UNGROUPED_SECTION_ID : DEFAULT_SECTION_GROUP_ID),
|
|
8315
8434
|
label: group.section?.name ?? (sections.length > 0 ? "Ungrouped Slides" : "Slides"),
|
|
8316
8435
|
slideIndexes: group.slideIndexes,
|
|
8317
8436
|
...group.section?.color !== void 0 ? { color: group.section.color } : {},
|
|
@@ -8319,30 +8438,15 @@ function computeSlideSectionGroups(slides, sections) {
|
|
|
8319
8438
|
}));
|
|
8320
8439
|
}
|
|
8321
8440
|
function computeMasterPseudoSlide(mode, activeLayout, activeMaster) {
|
|
8322
|
-
if (mode !== "master") {
|
|
8441
|
+
if (mode !== "master" || !activeMaster) {
|
|
8323
8442
|
return void 0;
|
|
8324
8443
|
}
|
|
8325
|
-
|
|
8326
|
-
|
|
8327
|
-
|
|
8328
|
-
|
|
8329
|
-
|
|
8330
|
-
|
|
8331
|
-
backgroundColor: activeLayout.backgroundColor ?? activeMaster?.backgroundColor,
|
|
8332
|
-
backgroundImage: activeLayout.backgroundImage ?? activeMaster?.backgroundImage
|
|
8333
|
-
};
|
|
8334
|
-
}
|
|
8335
|
-
if (activeMaster) {
|
|
8336
|
-
return {
|
|
8337
|
-
id: activeMaster.path,
|
|
8338
|
-
rId: "",
|
|
8339
|
-
slideNumber: 0,
|
|
8340
|
-
elements: activeMaster.elements ?? [],
|
|
8341
|
-
backgroundColor: activeMaster.backgroundColor,
|
|
8342
|
-
backgroundImage: activeMaster.backgroundImage
|
|
8343
|
-
};
|
|
8344
|
-
}
|
|
8345
|
-
return void 0;
|
|
8444
|
+
const document2 = activeLayout ? { slideMasters: [{ ...activeMaster, layouts: [activeLayout] }] } : { slideMasters: [activeMaster] };
|
|
8445
|
+
return masterViewPseudoSlide(document2, {
|
|
8446
|
+
tab: "slides",
|
|
8447
|
+
masterIndex: 0,
|
|
8448
|
+
layoutIndex: activeLayout ? 0 : null
|
|
8449
|
+
});
|
|
8346
8450
|
}
|
|
8347
8451
|
function useDerivedSlideState(input) {
|
|
8348
8452
|
const { t } = useTranslation();
|
|
@@ -8369,7 +8473,7 @@ function useDerivedSlideState(input) {
|
|
|
8369
8473
|
if (group.id === UNGROUPED_SECTION_ID && group.label === "Ungrouped Slides") {
|
|
8370
8474
|
return { ...group, label: t("pptx.slides.ungroupedSlides") };
|
|
8371
8475
|
}
|
|
8372
|
-
if (group.id ===
|
|
8476
|
+
if (group.id === DEFAULT_SECTION_GROUP_ID && group.label === "Slides") {
|
|
8373
8477
|
return { ...group, label: t("pptx.sections.slides") };
|
|
8374
8478
|
}
|
|
8375
8479
|
return group;
|
|
@@ -8523,6 +8627,8 @@ function useSerialize(input) {
|
|
|
8523
8627
|
slides,
|
|
8524
8628
|
templateElementsBySlideId,
|
|
8525
8629
|
activeSlideIndex,
|
|
8630
|
+
canvasSize,
|
|
8631
|
+
slideSizeEmu,
|
|
8526
8632
|
guides,
|
|
8527
8633
|
headerFooter,
|
|
8528
8634
|
presentationProperties,
|
|
@@ -8532,12 +8638,15 @@ function useSerialize(input) {
|
|
|
8532
8638
|
appProperties,
|
|
8533
8639
|
customProperties,
|
|
8534
8640
|
tagCollections,
|
|
8641
|
+
slideMasters,
|
|
8535
8642
|
notesMaster,
|
|
8536
8643
|
handoutMaster,
|
|
8537
8644
|
handlerRef,
|
|
8538
8645
|
inlineEditingElementIdRef,
|
|
8539
8646
|
inlineEditingTextRef,
|
|
8540
|
-
password
|
|
8647
|
+
password,
|
|
8648
|
+
embedFonts = true,
|
|
8649
|
+
purpose
|
|
8541
8650
|
} = input;
|
|
8542
8651
|
return useCallback(async () => {
|
|
8543
8652
|
const handler = handlerRef.current;
|
|
@@ -8578,6 +8687,10 @@ function useSerialize(input) {
|
|
|
8578
8687
|
});
|
|
8579
8688
|
const slidesToSave = buildSaveSlides(slidesWithGuides, templateElementsBySlideId);
|
|
8580
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,
|
|
8581
8694
|
headerFooter,
|
|
8582
8695
|
presentationProperties,
|
|
8583
8696
|
customShows: customShows.length > 0 ? customShows : void 0,
|
|
@@ -8586,16 +8699,17 @@ function useSerialize(input) {
|
|
|
8586
8699
|
appProperties,
|
|
8587
8700
|
customProperties: customProperties.length > 0 ? customProperties : void 0,
|
|
8588
8701
|
tags: tagCollections.length > 0 ? tagCollections : void 0,
|
|
8702
|
+
slideMasters,
|
|
8589
8703
|
notesMaster,
|
|
8590
|
-
handoutMaster
|
|
8704
|
+
handoutMaster,
|
|
8705
|
+
...embeddedFontSaveOptions(embedFonts)
|
|
8591
8706
|
};
|
|
8592
|
-
|
|
8593
|
-
return handler.saveEncrypted(slidesToSave, password, saveOptions);
|
|
8594
|
-
}
|
|
8595
|
-
return handler.save(slidesToSave, saveOptions);
|
|
8707
|
+
return saveDeckWithPassword(handler, slidesToSave, saveOptions, { password, purpose });
|
|
8596
8708
|
}, [
|
|
8597
8709
|
slides,
|
|
8598
8710
|
templateElementsBySlideId,
|
|
8711
|
+
canvasSize,
|
|
8712
|
+
slideSizeEmu,
|
|
8599
8713
|
headerFooter,
|
|
8600
8714
|
presentationProperties,
|
|
8601
8715
|
customShows,
|
|
@@ -8604,6 +8718,7 @@ function useSerialize(input) {
|
|
|
8604
8718
|
appProperties,
|
|
8605
8719
|
customProperties,
|
|
8606
8720
|
tagCollections,
|
|
8721
|
+
slideMasters,
|
|
8607
8722
|
notesMaster,
|
|
8608
8723
|
handoutMaster,
|
|
8609
8724
|
guides,
|
|
@@ -8611,7 +8726,9 @@ function useSerialize(input) {
|
|
|
8611
8726
|
handlerRef,
|
|
8612
8727
|
inlineEditingElementIdRef,
|
|
8613
8728
|
inlineEditingTextRef,
|
|
8614
|
-
password
|
|
8729
|
+
password,
|
|
8730
|
+
embedFonts,
|
|
8731
|
+
purpose
|
|
8615
8732
|
]);
|
|
8616
8733
|
}
|
|
8617
8734
|
|
|
@@ -8727,7 +8844,8 @@ function usePresentationSetup(input) {
|
|
|
8727
8844
|
history,
|
|
8728
8845
|
endWithBlackSlide = true,
|
|
8729
8846
|
promptKeepInkAnnotations = true,
|
|
8730
|
-
popupToolbarEnabled = true
|
|
8847
|
+
popupToolbarEnabled = true,
|
|
8848
|
+
onToggleSubtitles
|
|
8731
8849
|
} = input;
|
|
8732
8850
|
const actionSoundHandlerRef = useRef(null);
|
|
8733
8851
|
const [, setShowKeepAnnotationsDialog] = useState(false);
|
|
@@ -8806,6 +8924,7 @@ function usePresentationSetup(input) {
|
|
|
8806
8924
|
onEraseAnnotations: () => annotations.clearAnnotations(),
|
|
8807
8925
|
onToggleInkMarkup: () => annotations.setInkMarkupVisible(!annotations.inkMarkupVisible),
|
|
8808
8926
|
onToggleToolbar: () => annotations.setToolbarVisible(!annotations.toolbarVisible),
|
|
8927
|
+
onToggleSubtitles,
|
|
8809
8928
|
onSaveRehearsalTimings: (timings) => {
|
|
8810
8929
|
setSlides((prev) => applyRehearsalTimings(prev, timings));
|
|
8811
8930
|
history.markDirty();
|
|
@@ -8837,6 +8956,33 @@ function useEditorOperations(input) {
|
|
|
8837
8956
|
handlerRef,
|
|
8838
8957
|
transformCommittedText
|
|
8839
8958
|
} = input;
|
|
8959
|
+
const masterView = useMemo(
|
|
8960
|
+
() => ({
|
|
8961
|
+
target: mode === "master" ? {
|
|
8962
|
+
tab: state.masterViewTab,
|
|
8963
|
+
masterIndex: state.activeMasterIndex,
|
|
8964
|
+
layoutIndex: state.activeLayoutIndex
|
|
8965
|
+
} : null,
|
|
8966
|
+
slideMasters: state.slideMasters,
|
|
8967
|
+
notesMaster: state.notesMaster,
|
|
8968
|
+
handoutMaster: state.handoutMaster,
|
|
8969
|
+
setSlideMasters: state.setSlideMasters,
|
|
8970
|
+
setNotesMaster: state.setNotesMaster,
|
|
8971
|
+
setHandoutMaster: state.setHandoutMaster
|
|
8972
|
+
}),
|
|
8973
|
+
[
|
|
8974
|
+
mode,
|
|
8975
|
+
state.masterViewTab,
|
|
8976
|
+
state.activeMasterIndex,
|
|
8977
|
+
state.activeLayoutIndex,
|
|
8978
|
+
state.slideMasters,
|
|
8979
|
+
state.notesMaster,
|
|
8980
|
+
state.handoutMaster,
|
|
8981
|
+
state.setSlideMasters,
|
|
8982
|
+
state.setNotesMaster,
|
|
8983
|
+
state.setHandoutMaster
|
|
8984
|
+
]
|
|
8985
|
+
);
|
|
8840
8986
|
const ops = useElementOperations({
|
|
8841
8987
|
activeSlide,
|
|
8842
8988
|
activeSlideIndex,
|
|
@@ -8844,6 +8990,7 @@ function useEditorOperations(input) {
|
|
|
8844
8990
|
selectedElementId,
|
|
8845
8991
|
editTemplateMode: state.editTemplateMode,
|
|
8846
8992
|
templateElements: state.templateElements,
|
|
8993
|
+
masterView,
|
|
8847
8994
|
history,
|
|
8848
8995
|
setSlides: state.setSlides,
|
|
8849
8996
|
setTemplateElementsBySlideId: state.setTemplateElementsBySlideId,
|
|
@@ -9054,6 +9201,7 @@ function useIOHandlers(input) {
|
|
|
9054
9201
|
zoom,
|
|
9055
9202
|
handlerRef,
|
|
9056
9203
|
serializeSlides,
|
|
9204
|
+
serializeForRecovery,
|
|
9057
9205
|
setContent,
|
|
9058
9206
|
onContentChange,
|
|
9059
9207
|
password
|
|
@@ -9076,12 +9224,14 @@ function useIOHandlers(input) {
|
|
|
9076
9224
|
appProperties: state.appProperties ?? null,
|
|
9077
9225
|
customProperties: state.customProperties,
|
|
9078
9226
|
tagCollections: state.tagCollections,
|
|
9227
|
+
slideMasters: state.slideMasters,
|
|
9079
9228
|
notesMaster: state.notesMaster,
|
|
9080
9229
|
handoutMaster: state.handoutMaster,
|
|
9081
9230
|
guides: state.guides,
|
|
9082
9231
|
activeSlideIndexForGuides: state.activeSlideIndex,
|
|
9083
9232
|
theme: state.theme,
|
|
9084
9233
|
canvasSize,
|
|
9234
|
+
slideSizeEmu: state.slideSizeEmu,
|
|
9085
9235
|
password
|
|
9086
9236
|
});
|
|
9087
9237
|
const printHandlers = usePrintHandlers({
|
|
@@ -9092,7 +9242,9 @@ function useIOHandlers(input) {
|
|
|
9092
9242
|
});
|
|
9093
9243
|
const themeHandlers = useThemeHandlers({
|
|
9094
9244
|
handlerRef,
|
|
9095
|
-
|
|
9245
|
+
// Theme apply re-serialises and re-parses through `setContent`, so these
|
|
9246
|
+
// bytes go back into our own loader: plaintext, never the protected save.
|
|
9247
|
+
serializeSlides: serializeForRecovery,
|
|
9096
9248
|
setContent,
|
|
9097
9249
|
onContentChange,
|
|
9098
9250
|
setTheme: state.setTheme,
|
|
@@ -9285,6 +9437,8 @@ function useContentLifecycle(input) {
|
|
|
9285
9437
|
content,
|
|
9286
9438
|
filePath,
|
|
9287
9439
|
autosaveEnabled = true,
|
|
9440
|
+
autosaveIntervalSeconds,
|
|
9441
|
+
embedFonts = true,
|
|
9288
9442
|
slides,
|
|
9289
9443
|
state,
|
|
9290
9444
|
history,
|
|
@@ -9302,6 +9456,7 @@ function useContentLifecycle(input) {
|
|
|
9302
9456
|
setTemplateElementsBySlideId: state.setTemplateElementsBySlideId,
|
|
9303
9457
|
mediaDataUrls: state.mediaDataUrls,
|
|
9304
9458
|
setCanvasSize: state.setCanvasSize,
|
|
9459
|
+
setSlideSizeEmu: state.setSlideSizeEmu,
|
|
9305
9460
|
setHeaderFooter: state.setHeaderFooter,
|
|
9306
9461
|
setLayoutOptions: state.setLayoutOptions,
|
|
9307
9462
|
setSlideMasters: state.setSlideMasters,
|
|
@@ -9309,6 +9464,7 @@ function useContentLifecycle(input) {
|
|
|
9309
9464
|
setTableStyleMap: state.setTableStyleMap,
|
|
9310
9465
|
setThemeOptions: state.setThemeOptions,
|
|
9311
9466
|
setCustomShows: state.setCustomShows,
|
|
9467
|
+
setActiveCustomShowId: state.setActiveCustomShowId,
|
|
9312
9468
|
setSections: state.setSections,
|
|
9313
9469
|
setPresentationProperties: state.setPresentationProperties,
|
|
9314
9470
|
setNotesMaster: state.setNotesMaster,
|
|
@@ -9334,10 +9490,12 @@ function useContentLifecycle(input) {
|
|
|
9334
9490
|
actionSoundHandlerRef.current = handlerRef.current;
|
|
9335
9491
|
}, [handlerRef, actionSoundHandlerRef, state.loading]);
|
|
9336
9492
|
useFontInjection({ embeddedFonts: state.embeddedFonts, slides });
|
|
9337
|
-
const
|
|
9493
|
+
const serializeInput = {
|
|
9338
9494
|
slides,
|
|
9339
9495
|
templateElementsBySlideId: state.templateElementsBySlideId,
|
|
9340
9496
|
activeSlideIndex: state.activeSlideIndex,
|
|
9497
|
+
canvasSize: state.canvasSize,
|
|
9498
|
+
slideSizeEmu: state.slideSizeEmu,
|
|
9341
9499
|
guides: state.guides,
|
|
9342
9500
|
headerFooter: state.headerFooter,
|
|
9343
9501
|
presentationProperties: state.presentationProperties,
|
|
@@ -9347,20 +9505,49 @@ function useContentLifecycle(input) {
|
|
|
9347
9505
|
appProperties: state.appProperties,
|
|
9348
9506
|
customProperties: state.customProperties,
|
|
9349
9507
|
tagCollections: state.tagCollections,
|
|
9508
|
+
slideMasters: state.slideMasters,
|
|
9350
9509
|
notesMaster: state.notesMaster,
|
|
9351
9510
|
handoutMaster: state.handoutMaster,
|
|
9352
9511
|
handlerRef,
|
|
9353
9512
|
inlineEditingElementIdRef: state.inlineEditingElementIdRef,
|
|
9354
9513
|
inlineEditingTextRef: state.inlineEditingTextRef,
|
|
9355
|
-
password
|
|
9356
|
-
|
|
9514
|
+
password,
|
|
9515
|
+
embedFonts
|
|
9516
|
+
};
|
|
9517
|
+
const serializeSlides = useSerialize(serializeInput);
|
|
9518
|
+
const serializeForRecovery = useSerialize({ ...serializeInput, purpose: "recovery-snapshot" });
|
|
9357
9519
|
const { autosaveStatus } = useAutosave({
|
|
9358
9520
|
isDirty: state.isDirty,
|
|
9359
9521
|
filePath,
|
|
9360
|
-
serializeSlides,
|
|
9361
|
-
enabled: autosaveEnabled
|
|
9522
|
+
serializeSlides: serializeForRecovery,
|
|
9523
|
+
enabled: autosaveEnabled,
|
|
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
|
+
]
|
|
9362
9549
|
});
|
|
9363
|
-
return { handlerRef, serializeSlides, autosaveStatus };
|
|
9550
|
+
return { handlerRef, serializeSlides, serializeForRecovery, autosaveStatus };
|
|
9364
9551
|
}
|
|
9365
9552
|
function useKeyboardShortcuts(input) {
|
|
9366
9553
|
const inputRef = useRef(input);
|
|
@@ -9369,7 +9556,14 @@ function useKeyboardShortcuts(input) {
|
|
|
9369
9556
|
const current = inputRef.current;
|
|
9370
9557
|
const { action, dx, dy } = mapEditorKey(e, {
|
|
9371
9558
|
canEdit: current.canEdit,
|
|
9372
|
-
|
|
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",
|
|
9373
9567
|
hasSelection: current.hasSelection,
|
|
9374
9568
|
isEditingText: Boolean(current.inlineEditingElementId || current.tableEditorState?.isEditing),
|
|
9375
9569
|
isDrawing: current.activeTool !== "select",
|
|
@@ -9416,6 +9610,9 @@ function useKeyboardShortcuts(input) {
|
|
|
9416
9610
|
case "toggleShortcuts":
|
|
9417
9611
|
current.onToggleShortcuts?.();
|
|
9418
9612
|
break;
|
|
9613
|
+
case "find":
|
|
9614
|
+
current.onFind?.();
|
|
9615
|
+
break;
|
|
9419
9616
|
case "nudge":
|
|
9420
9617
|
current.onNudge(dx ?? 0, dy ?? 0);
|
|
9421
9618
|
break;
|
|
@@ -9524,6 +9721,7 @@ function useViewerIntegration(input) {
|
|
|
9524
9721
|
content,
|
|
9525
9722
|
filePath,
|
|
9526
9723
|
autosaveEnabled,
|
|
9724
|
+
autosaveIntervalSeconds,
|
|
9527
9725
|
canEdit,
|
|
9528
9726
|
mode,
|
|
9529
9727
|
slides,
|
|
@@ -9574,19 +9772,24 @@ function useViewerIntegration(input) {
|
|
|
9574
9772
|
});
|
|
9575
9773
|
const [isEncryptedDialogOpen, setIsEncryptedDialogOpen] = useState(false);
|
|
9576
9774
|
const [loadVersion, setLoadVersion] = useState(0);
|
|
9577
|
-
const { handlerRef, serializeSlides, autosaveStatus } = useContentLifecycle(
|
|
9578
|
-
|
|
9579
|
-
|
|
9580
|
-
|
|
9581
|
-
|
|
9582
|
-
|
|
9583
|
-
|
|
9584
|
-
|
|
9585
|
-
|
|
9586
|
-
|
|
9587
|
-
|
|
9588
|
-
|
|
9589
|
-
|
|
9775
|
+
const { handlerRef, serializeSlides, serializeForRecovery, autosaveStatus } = useContentLifecycle(
|
|
9776
|
+
{
|
|
9777
|
+
content,
|
|
9778
|
+
filePath,
|
|
9779
|
+
autosaveEnabled,
|
|
9780
|
+
autosaveIntervalSeconds,
|
|
9781
|
+
// The File > Fonts toggle, finally reaching a save call.
|
|
9782
|
+
embedFonts: dialogs.embedFontsEnabled,
|
|
9783
|
+
slides,
|
|
9784
|
+
state,
|
|
9785
|
+
history,
|
|
9786
|
+
ops: editorOps.ops,
|
|
9787
|
+
actionSoundHandlerRef,
|
|
9788
|
+
setIsEncryptedDialogOpen,
|
|
9789
|
+
password: dialogs.presentationPassword ?? void 0,
|
|
9790
|
+
onContentApplied: () => setLoadVersion((v) => v + 1)
|
|
9791
|
+
}
|
|
9792
|
+
);
|
|
9590
9793
|
const { exportHandlers, printHandlers, themeHandlers, propertyHandlers } = useIOHandlers({
|
|
9591
9794
|
state,
|
|
9592
9795
|
slides,
|
|
@@ -9598,6 +9801,7 @@ function useViewerIntegration(input) {
|
|
|
9598
9801
|
zoom,
|
|
9599
9802
|
handlerRef,
|
|
9600
9803
|
serializeSlides,
|
|
9804
|
+
serializeForRecovery,
|
|
9601
9805
|
setContent,
|
|
9602
9806
|
onContentChange,
|
|
9603
9807
|
password: dialogs.presentationPassword ?? void 0
|
|
@@ -10236,11 +10440,16 @@ function useLayoutSwitching(input) {
|
|
|
10236
10440
|
},
|
|
10237
10441
|
[handler, activeSlideIndex, ops, history, onTemplateElementsChanged]
|
|
10238
10442
|
);
|
|
10443
|
+
const loadLayoutPreviews = useCallback(
|
|
10444
|
+
async () => handler ? handler.getLayoutPreviews() : [],
|
|
10445
|
+
[handler]
|
|
10446
|
+
);
|
|
10239
10447
|
return {
|
|
10240
10448
|
availableLayouts,
|
|
10241
10449
|
isLoading,
|
|
10242
10450
|
loadAvailableLayouts,
|
|
10243
10451
|
applyLayout,
|
|
10452
|
+
loadLayoutPreviews,
|
|
10244
10453
|
currentLayoutPath
|
|
10245
10454
|
};
|
|
10246
10455
|
}
|
|
@@ -10499,41 +10708,7 @@ function buildCanvasProps(input) {
|
|
|
10499
10708
|
|
|
10500
10709
|
// src/viewer/hooks/useScopedLayoutOptions.ts
|
|
10501
10710
|
function scopeLayoutOptionsToActiveSlide(options, activeSlide) {
|
|
10502
|
-
|
|
10503
|
-
return options;
|
|
10504
|
-
}
|
|
10505
|
-
const hasAnyMasterInfo = options.some((o) => o.masterPath);
|
|
10506
|
-
if (!hasAnyMasterInfo) {
|
|
10507
|
-
return options;
|
|
10508
|
-
}
|
|
10509
|
-
const activeOption = options.find((o) => o.path === activeSlide.layoutPath);
|
|
10510
|
-
const activeMaster = activeOption?.masterPath;
|
|
10511
|
-
if (!activeMaster) {
|
|
10512
|
-
return options;
|
|
10513
|
-
}
|
|
10514
|
-
const scoped = options.filter((o) => o.masterPath === activeMaster);
|
|
10515
|
-
const seen = /* @__PURE__ */ new Map();
|
|
10516
|
-
for (const opt of scoped) {
|
|
10517
|
-
const isActive = opt.path === activeSlide.layoutPath;
|
|
10518
|
-
const existing = seen.get(opt.name);
|
|
10519
|
-
if (!existing || isActive) {
|
|
10520
|
-
seen.set(opt.name, opt);
|
|
10521
|
-
}
|
|
10522
|
-
}
|
|
10523
|
-
const chosen = new Set(Array.from(seen.values()).map((o) => o.path));
|
|
10524
|
-
const result = [];
|
|
10525
|
-
const usedNames = /* @__PURE__ */ new Set();
|
|
10526
|
-
for (const opt of scoped) {
|
|
10527
|
-
if (!chosen.has(opt.path)) {
|
|
10528
|
-
continue;
|
|
10529
|
-
}
|
|
10530
|
-
if (usedNames.has(opt.name)) {
|
|
10531
|
-
continue;
|
|
10532
|
-
}
|
|
10533
|
-
usedNames.add(opt.name);
|
|
10534
|
-
result.push(opt);
|
|
10535
|
-
}
|
|
10536
|
-
return result;
|
|
10711
|
+
return scopeLayoutOptionsToSlide(options, activeSlide?.layoutPath);
|
|
10537
10712
|
}
|
|
10538
10713
|
|
|
10539
10714
|
// src/viewer/hooks/useViewerBuildingBlocks-toolbar-handlers.ts
|
|
@@ -10766,6 +10941,8 @@ function buildToolbarProps(input) {
|
|
|
10766
10941
|
isOverflowMenuOpen: s.isOverflowMenuOpen,
|
|
10767
10942
|
onSetOverflowMenuOpen: s.setIsOverflowMenuOpen,
|
|
10768
10943
|
layoutOptions: scopedLayoutOptions,
|
|
10944
|
+
currentLayoutPath: activeSlide?.layoutPath,
|
|
10945
|
+
loadLayoutPreviews: input.loadLayoutPreviews,
|
|
10769
10946
|
onInsertSlideFromLayout: slideOps.handleInsertSlideFromLayout,
|
|
10770
10947
|
onInsertSlideFromTemplate: slideOps.handleInsertSlideFromTemplate,
|
|
10771
10948
|
templateScheme: templateSchemeFromTheme(s.theme?.colorScheme),
|
|
@@ -10782,6 +10959,15 @@ function buildToolbarProps(input) {
|
|
|
10782
10959
|
onToggleVersionHistory: () => propertyHandlers.setIsVersionHistoryOpen((p) => !p),
|
|
10783
10960
|
onOpenPasswordProtection: () => dialogs.setIsPasswordDialogOpen(true),
|
|
10784
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
|
+
},
|
|
10785
10971
|
onOpenFontEmbedding: () => dialogs.setIsFontEmbeddingOpen(true),
|
|
10786
10972
|
onOpenDigitalSignatures: () => dialogs.setIsDigitalSigDialogOpen(true),
|
|
10787
10973
|
onEnterPresenterView,
|
|
@@ -10817,6 +11003,20 @@ function buildToolbarProps(input) {
|
|
|
10817
11003
|
activeSlide,
|
|
10818
11004
|
onTransitionChange: handleTransitionChange,
|
|
10819
11005
|
onApplyTransitionToAll: handleApplyTransitionToAll,
|
|
11006
|
+
// No `onResetSlide` here: this building-blocks surface supplies no
|
|
11007
|
+
// `onApplyLayout` either, so there is no layout to reset to. The mounted
|
|
11008
|
+
// viewer (`ViewerToolbarSection`) wires both.
|
|
11009
|
+
onSelectAll: () => {
|
|
11010
|
+
const allIds = activeSlide?.elements.map((element) => element.id) ?? [];
|
|
11011
|
+
if (allIds.length > 0) {
|
|
11012
|
+
ops.applySelection(allIds[0], allIds);
|
|
11013
|
+
}
|
|
11014
|
+
},
|
|
11015
|
+
presentationProperties: s.presentationProperties,
|
|
11016
|
+
onPresentationPropertiesChange: (updates) => {
|
|
11017
|
+
s.setPresentationProperties((prev) => ({ ...prev, ...updates }));
|
|
11018
|
+
history.markDirty();
|
|
11019
|
+
},
|
|
10820
11020
|
hiddenActions
|
|
10821
11021
|
};
|
|
10822
11022
|
}
|
|
@@ -10894,7 +11094,12 @@ function useViewerBuildingBlocksCore(input) {
|
|
|
10894
11094
|
setMode: state.setMode,
|
|
10895
11095
|
setActiveSlideIndex: state.setActiveSlideIndex,
|
|
10896
11096
|
setSlides: state.setSlides,
|
|
10897
|
-
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
|
+
}))
|
|
10898
11103
|
});
|
|
10899
11104
|
return {
|
|
10900
11105
|
state,
|