pptx-react-viewer 3.2.0 → 3.4.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 +53 -0
- package/dist/{AiChatPanel-TKBVSYD2.js → AiChatPanel-3Q4STA5E.js} +29 -28
- package/dist/AiChatPanel-3Q4STA5E.js.br +0 -0
- package/dist/AiChatPanel-3Q4STA5E.js.gz +0 -0
- package/dist/{AiChatPanel-C3E7NLX3.mjs → AiChatPanel-NQZBZIRM.mjs} +9 -8
- package/dist/AiChatPanel-NQZBZIRM.mjs.br +0 -0
- package/dist/AiChatPanel-NQZBZIRM.mjs.gz +0 -0
- package/dist/{Area3DChartScene-7YCFWEGX.mjs → Area3DChartScene-7PARQDOZ.mjs} +1 -1
- package/dist/Area3DChartScene-7PARQDOZ.mjs.br +3 -0
- package/dist/Area3DChartScene-7PARQDOZ.mjs.gz +0 -0
- package/dist/{Area3DChartScene-3A3CXKN3.js → Area3DChartScene-THLG74CM.js} +2 -2
- package/dist/Area3DChartScene-THLG74CM.js.br +0 -0
- package/dist/Area3DChartScene-THLG74CM.js.gz +0 -0
- package/dist/{Bar3DChartScene-BDUENAWJ.js → Bar3DChartScene-OLZ2V56I.js} +2 -2
- package/dist/Bar3DChartScene-OLZ2V56I.js.br +2 -0
- package/dist/Bar3DChartScene-OLZ2V56I.js.gz +0 -0
- package/dist/{Bar3DChartScene-7CNSJ35X.mjs → Bar3DChartScene-QUU6RUXM.mjs} +1 -1
- package/dist/Bar3DChartScene-QUU6RUXM.mjs.br +0 -0
- package/dist/Bar3DChartScene-QUU6RUXM.mjs.gz +0 -0
- package/dist/{Line3DChartScene-R352CZ5U.js → Line3DChartScene-2VZS52IB.js} +2 -2
- package/dist/Line3DChartScene-2VZS52IB.js.br +0 -0
- package/dist/Line3DChartScene-2VZS52IB.js.gz +0 -0
- package/dist/{Line3DChartScene-SMTHK6MD.mjs → Line3DChartScene-D77ORA4K.mjs} +1 -1
- package/dist/Line3DChartScene-D77ORA4K.mjs.br +3 -0
- package/dist/Line3DChartScene-D77ORA4K.mjs.gz +0 -0
- package/dist/{Model3DScene-Y4SGFQYW.js → Model3DScene-3WCALTXO.js} +2 -2
- package/dist/Model3DScene-3WCALTXO.js.br +0 -0
- package/dist/Model3DScene-3WCALTXO.js.gz +0 -0
- package/dist/{Model3DScene-AUVJXXPV.mjs → Model3DScene-ZEGWNILH.mjs} +1 -1
- package/dist/Model3DScene-ZEGWNILH.mjs.br +0 -0
- package/dist/Model3DScene-ZEGWNILH.mjs.gz +0 -0
- package/dist/{PieChart3DScene-TK2VT4RS.js → PieChart3DScene-7C3ACGKN.js} +2 -2
- package/dist/PieChart3DScene-7C3ACGKN.js.br +0 -0
- package/dist/PieChart3DScene-7C3ACGKN.js.gz +0 -0
- package/dist/{PieChart3DScene-UD7GRH55.mjs → PieChart3DScene-DGD4PZVV.mjs} +1 -1
- package/dist/PieChart3DScene-DGD4PZVV.mjs.br +0 -0
- package/dist/PieChart3DScene-DGD4PZVV.mjs.gz +0 -0
- package/dist/PowerPointViewer-Cl6jBPNw.d.ts.map +1 -1
- package/dist/{SurfaceChart3DScene-TXY6UZSW.mjs → SurfaceChart3DScene-QGH3OLJV.mjs} +1 -1
- package/dist/SurfaceChart3DScene-QGH3OLJV.mjs.br +0 -0
- package/dist/SurfaceChart3DScene-QGH3OLJV.mjs.gz +0 -0
- package/dist/{SurfaceChart3DScene-ERFXZW2O.js → SurfaceChart3DScene-SJPQGGGE.js} +2 -2
- package/dist/SurfaceChart3DScene-SJPQGGGE.js.br +0 -0
- package/dist/SurfaceChart3DScene-SJPQGGGE.js.gz +0 -0
- package/dist/{chunk-RRAL4Y7V.js → chunk-7E6SM42A.js} +2604 -2024
- package/dist/chunk-7E6SM42A.js.br +0 -0
- package/dist/chunk-7E6SM42A.js.gz +0 -0
- package/dist/{chunk-G7UBIKAG.mjs → chunk-B7WAGQW4.mjs} +5383 -873
- package/dist/chunk-B7WAGQW4.mjs.br +0 -0
- package/dist/chunk-B7WAGQW4.mjs.gz +0 -0
- package/dist/{chunk-RX6FE24O.mjs → chunk-C4WTQIC6.mjs} +302 -61
- package/dist/chunk-C4WTQIC6.mjs.br +0 -0
- package/dist/chunk-C4WTQIC6.mjs.gz +0 -0
- package/dist/{chunk-Q52HT4EZ.js → chunk-KY6JQJXK.js} +307 -63
- package/dist/chunk-KY6JQJXK.js.br +0 -0
- package/dist/chunk-KY6JQJXK.js.gz +0 -0
- package/dist/{chunk-PPNXPEEZ.mjs → chunk-L5MRKDRM.mjs} +1514 -934
- package/dist/chunk-L5MRKDRM.mjs.br +0 -0
- package/dist/chunk-L5MRKDRM.mjs.gz +0 -0
- package/dist/{chunk-UHR7EYFM.mjs → chunk-MSUUPLQ7.mjs} +718 -435
- package/dist/chunk-MSUUPLQ7.mjs.br +0 -0
- package/dist/chunk-MSUUPLQ7.mjs.gz +0 -0
- package/dist/{chunk-FJDZ7AEE.js → chunk-PCW2KT7Z.js} +5446 -879
- package/dist/chunk-PCW2KT7Z.js.br +0 -0
- package/dist/chunk-PCW2KT7Z.js.gz +0 -0
- package/dist/{chunk-FMEEIS6L.mjs → chunk-SFMATKNJ.mjs} +13 -114
- package/dist/chunk-SFMATKNJ.mjs.br +0 -0
- package/dist/chunk-SFMATKNJ.mjs.gz +0 -0
- package/dist/{chunk-ARQGUUYU.js → chunk-TJNG5VEK.js} +1114 -826
- package/dist/chunk-TJNG5VEK.js.br +0 -0
- package/dist/chunk-TJNG5VEK.js.gz +0 -0
- package/dist/{chunk-ALO4ZOHQ.js → chunk-UNIJUD5C.js} +45 -1
- package/dist/chunk-UNIJUD5C.js.br +0 -0
- package/dist/chunk-UNIJUD5C.js.gz +0 -0
- package/dist/{chunk-B6UIVRFA.js → chunk-XBTHWXNO.js} +177 -279
- package/dist/chunk-XBTHWXNO.js.br +0 -0
- package/dist/chunk-XBTHWXNO.js.gz +0 -0
- package/dist/{chunk-RHSA5BW5.mjs → chunk-XWUMM2TX.mjs} +45 -1
- package/dist/chunk-XWUMM2TX.mjs.br +0 -0
- package/dist/chunk-XWUMM2TX.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 +7 -0
- package/dist/index.js +47 -47
- 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 +176 -5
- 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/{useViewerBuildingBlocks-X1L8BjsQ.d.ts → useViewerBuildingBlocks-f6oNGKMX.d.ts} +8 -1
- package/dist/useViewerBuildingBlocks-f6oNGKMX.d.ts.map +1 -0
- 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 +1 -1
- package/dist/AiChatPanel-C3E7NLX3.mjs.br +0 -0
- package/dist/AiChatPanel-C3E7NLX3.mjs.gz +0 -0
- package/dist/AiChatPanel-TKBVSYD2.js.br +0 -0
- package/dist/AiChatPanel-TKBVSYD2.js.gz +0 -0
- package/dist/Area3DChartScene-3A3CXKN3.js.br +0 -0
- package/dist/Area3DChartScene-3A3CXKN3.js.gz +0 -0
- package/dist/Area3DChartScene-7YCFWEGX.mjs.br +0 -3
- package/dist/Area3DChartScene-7YCFWEGX.mjs.gz +0 -0
- package/dist/Bar3DChartScene-7CNSJ35X.mjs.br +0 -0
- package/dist/Bar3DChartScene-7CNSJ35X.mjs.gz +0 -0
- package/dist/Bar3DChartScene-BDUENAWJ.js.br +0 -0
- package/dist/Bar3DChartScene-BDUENAWJ.js.gz +0 -0
- package/dist/Line3DChartScene-R352CZ5U.js.br +0 -0
- package/dist/Line3DChartScene-R352CZ5U.js.gz +0 -0
- package/dist/Line3DChartScene-SMTHK6MD.mjs.br +0 -3
- package/dist/Line3DChartScene-SMTHK6MD.mjs.gz +0 -0
- package/dist/Model3DScene-AUVJXXPV.mjs.br +0 -0
- package/dist/Model3DScene-AUVJXXPV.mjs.gz +0 -0
- package/dist/Model3DScene-Y4SGFQYW.js.br +0 -0
- package/dist/Model3DScene-Y4SGFQYW.js.gz +0 -0
- package/dist/PieChart3DScene-TK2VT4RS.js.br +0 -0
- package/dist/PieChart3DScene-TK2VT4RS.js.gz +0 -0
- package/dist/PieChart3DScene-UD7GRH55.mjs.br +0 -0
- package/dist/PieChart3DScene-UD7GRH55.mjs.gz +0 -0
- package/dist/SurfaceChart3DScene-ERFXZW2O.js.br +0 -0
- package/dist/SurfaceChart3DScene-ERFXZW2O.js.gz +0 -0
- package/dist/SurfaceChart3DScene-TXY6UZSW.mjs.br +0 -0
- package/dist/SurfaceChart3DScene-TXY6UZSW.mjs.gz +0 -0
- package/dist/chunk-ALO4ZOHQ.js.br +0 -0
- package/dist/chunk-ALO4ZOHQ.js.gz +0 -0
- package/dist/chunk-ARQGUUYU.js.br +0 -0
- package/dist/chunk-ARQGUUYU.js.gz +0 -0
- package/dist/chunk-B6UIVRFA.js.br +0 -0
- package/dist/chunk-B6UIVRFA.js.gz +0 -0
- package/dist/chunk-FJDZ7AEE.js.br +0 -0
- package/dist/chunk-FJDZ7AEE.js.gz +0 -0
- package/dist/chunk-FMEEIS6L.mjs.br +0 -0
- package/dist/chunk-FMEEIS6L.mjs.gz +0 -0
- package/dist/chunk-G7UBIKAG.mjs.br +0 -0
- package/dist/chunk-G7UBIKAG.mjs.gz +0 -0
- package/dist/chunk-PPNXPEEZ.mjs.br +0 -0
- package/dist/chunk-PPNXPEEZ.mjs.gz +0 -0
- package/dist/chunk-Q52HT4EZ.js.br +0 -0
- package/dist/chunk-Q52HT4EZ.js.gz +0 -0
- package/dist/chunk-RHSA5BW5.mjs.br +0 -0
- package/dist/chunk-RHSA5BW5.mjs.gz +0 -0
- package/dist/chunk-RRAL4Y7V.js.br +0 -0
- package/dist/chunk-RRAL4Y7V.js.gz +0 -0
- package/dist/chunk-RX6FE24O.mjs.br +0 -0
- package/dist/chunk-RX6FE24O.mjs.gz +0 -0
- package/dist/chunk-UHR7EYFM.mjs.br +0 -0
- package/dist/chunk-UHR7EYFM.mjs.gz +0 -0
- package/dist/useViewerBuildingBlocks-X1L8BjsQ.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_SECTION_GROUP_ID, DEFAULT_TABLE_ROWS, DEFAULT_TABLE_COLUMNS,
|
|
2
|
-
import { DEFAULT_VIEWER_OPTIONS, 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,
|
|
3
|
-
import { translationsEn } 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, buildPdfFromImageData, buildNotesPdf, GRID_SIZE, DEFAULT_TEXT_FONT_SIZE } from './chunk-SFMATKNJ.mjs';
|
|
2
|
+
import { DEFAULT_VIEWER_OPTIONS, 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, cancelBuildReveal, PresentationAnimationController, scheduleAutoAdvanceChain, playGroup, 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, firstShowSlideIndex, attachPresentationVisibilityPause, presentationEntrySlideIndex, buildMorphTransitionPlan, morphOptionToMode, buildMorphAnimationRules, findInSlides, applyFindReplacements, createCollaborationLivePatcher, publishLiveInlineText, PptxHandler, collectMediaElements, collectImagePaths, applyImagePathPatches, resolveTableCellImageUrls, resolveTableStyleImageUrls, partitionTemplateElements, seedRecentColors, resolveAuthoredCustomShowId, buildInitialGuides, readOnlyRecommendation, compatibilityWarningToasts, EncryptedFileError, resolveAutosaveIntervalMs, shouldWriteAutosaveSnapshot, saveAutosaveSnapshot, autosaveSnapshotMark, updateMasterViewElement, isTemplateElementId, updateElement, hasShapeProperties, hasTextProperties, getInlineEditorSelection, applyStyleToSelectedSegments, setPendingSelectionRestore, applyCaseTransformToSegments, transformTextCase, masterViewElements, replaceMasterViewElements, addSection, renameSection, deleteSection, moveSectionUp, moveSectionDown, moveSlidesToSection, normalizeColorsForCapture, preprocessCssForCapture, slideProgressPercent, slideStatusLabel, EXPORT_ASSEMBLING_PERCENT, EXPORT_DONE_PERCENT, isExportAbortError, recordProgressPercent, downloadBlob, resolveImageResolutionScale, applyThemeToData, THEME_PRESETS, themeColorSchemesEqual, comparePresentation, applyAcceptSlide, applyAcceptAllSlides, collectUsedFonts, describeFontEmbedding, isMobileViewport, resolveAuthoredSlideRange, mayLeaveSlideShow, stopAllPersistentAudio, remapTextToSegments, guidePxToEmu, buildSaveSlides, embeddedFontSaveOptions, resolveSlideSizeSelection, saveDeckWithPassword, shouldProbeAutosaveRecovery, probeAutosaveRecovery, acceptAutosaveRecovery, discardAutosaveRecovery, shouldLoopContinuously, applyRehearsalTimings, copyFormatFromElement, applyFormatToElement, collectReferencedFontFamilies, resolveGoogleWebfontHref, mapSlideShowStartKey, mapEditorKey, isEditorTextInputTarget, createViewerOptionsStore, readSlidesFromYDoc, shouldRoomSlidesReplaceLoad, reconcileSlidesInYDoc, LOCAL_SYNC_ORIGIN, observeYDocSlides, shouldAutoFollowBroadcaster, detectTouchDevice, detectOrientation, deriveViewportBreakpoints, createTouchGestureRecognizer, MAX_ZOOM_SCALE, MIN_ZOOM_SCALE, isKeyboardOpen, scopeLayoutOptionsToSlide, viewerPreferencesFromViewProperties, DEFAULT_VIEWER_PREFERENCES, viewPropertiesPatchFromPreferences, openPptxFile, readBackstageRecentFile, isActionHidden, resolveInlineEditAutoFitHeight, canInteractWithElement, filterInteractableIds, beginShapeAdjustment, buildElementClipboardPayload, savedPresentationFileName, exportDeckJson, groupElements, generateElementId, makeCloneId, ungroupElements, alignElements, distributeElements, bringForward, sendBackward, bringToFront, sendToBack, newTableElement, createDefaultChartElement, readViewportMetrics, computeKeyboardInset, mergeShapes, mapPresentationKey, lastShowSlideIndex, mapPresentationWheel, openPendingPrintWindow, computeColorFilter, filterHiddenSlideIndices, computeSlideIndices, buildPrintDocument, finishPrintWindow, buildPrintHtmlDocument, buildOutlineHtml, buildSlidesHtml, buildNotesHtml, buildHandoutsHtml, createBlankSlide, makeSlideId, buildSlideTemplateSlide, templateSchemeFromTheme, buildThemeColorMap, reResolveSlideColors, computeEntranceAnimationDelay, createPresentationSessionId, resolveTransitionDurationMs, runPresentationAction, safeOpenUrl, toggleStageElementMedia, resolveOleVerbTarget, openUrlInNewTab, createPresenterTimer, createInitialPresentationSnapshot, mergePresentationSnapshot, resetPresenterTimer, presenterElapsed, stepPresenterZoom, togglePresenterTimer, addCommentToList, removeCommentFromList, editCommentInList, toggleCommentResolvedInList, canvasToJpegData, downloadDataUrl, pickSupportedMimeType, WEBM_MIME_CANDIDATES, fpsToFrameIntervalMs, segmentFrameCount, encodeGif, computeGridSpacingPx, resolveShowSlideIndexes, groupSlidesBySection, masterViewPseudoSlide, resolveHistoryDepth, hasCopyableFormat, createBackstagePresentation, buildFieldSubstitutionContext, cloneElementForPaste, computeScrollDelta, getPresetShapeClipPath, svgPathToPolygons, polygonsToSvgPath, rerouteConnectorsForMovedElements, applyReroutedConnectors, SvgExporter, replyToCommentInList, deleteTableColumn, rebuildTableStructureInRawXml, insertTableColumn, deleteTableRow, insertTableRow, updateCellTextStyleInRawXml, setCellText, updateCellTextInRawXml, splitCell, updateMergeAttrsInRawXml, mergeCells, isPpactionUrl, parsePpactionUrl, resolvePresentationAction, ACTION_BUTTON_PRESETS, elementActionToPptxAction, isUrlSafe, buildSmartArtPresetData, classifyMediaType, computeSnapToShape, publishLiveGeometry, getDraggedShapeAdjustments, computeMarqueeHitIds, mergeAdditiveSelection, shouldConfirmExternalHyperlink, applyResize, lockResizeAspect, snapBoxToGrid, applyMotionPathPreset } from './chunk-B7WAGQW4.mjs';
|
|
3
|
+
import { translationsEn } from './chunk-XWUMM2TX.mjs';
|
|
4
4
|
import { createContext, useRef, useState, useEffect, useCallback, useMemo, useLayoutEffect, useContext, useImperativeHandle, useSyncExternalStore } from 'react';
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
6
|
|
|
@@ -969,67 +969,6 @@ function stopAnimationSound() {
|
|
|
969
969
|
}
|
|
970
970
|
|
|
971
971
|
// src/viewer/hooks/presentation-mode/animation-helpers.ts
|
|
972
|
-
function applyAnimationGroupSteps(group, onPlayActionSound, setPresentationElementStates, presentationTimersRef) {
|
|
973
|
-
for (const step of group.steps) {
|
|
974
|
-
if (step.command) {
|
|
975
|
-
const command = step.command;
|
|
976
|
-
const timer = window.setTimeout(
|
|
977
|
-
() => {
|
|
978
|
-
executeMediaCommand(command);
|
|
979
|
-
},
|
|
980
|
-
Math.max(0, step.delayMs)
|
|
981
|
-
);
|
|
982
|
-
presentationTimersRef.current.push(timer);
|
|
983
|
-
continue;
|
|
984
|
-
}
|
|
985
|
-
if (step.stopSound) {
|
|
986
|
-
stopAnimationSound();
|
|
987
|
-
} else if (step.soundPath && onPlayActionSound) {
|
|
988
|
-
onPlayActionSound(step.soundPath);
|
|
989
|
-
}
|
|
990
|
-
}
|
|
991
|
-
setPresentationElementStates((previousStates) => {
|
|
992
|
-
const nextStates = new Map(previousStates);
|
|
993
|
-
for (const step of group.steps) {
|
|
994
|
-
if (step.command) {
|
|
995
|
-
continue;
|
|
996
|
-
}
|
|
997
|
-
const currentState = nextStates.get(step.elementId) ?? {
|
|
998
|
-
visible: true};
|
|
999
|
-
const shouldBeVisible = step.presetClass === "exit" ? currentState.visible : true;
|
|
1000
|
-
const colorTargets = step.colorTargets;
|
|
1001
|
-
nextStates.set(step.elementId, {
|
|
1002
|
-
visible: shouldBeVisible,
|
|
1003
|
-
cssAnimation: step.cssAnimation,
|
|
1004
|
-
animatesFill: colorTargets?.includes("fill") ? true : void 0,
|
|
1005
|
-
animatesStroke: colorTargets?.includes("stroke") ? true : void 0
|
|
1006
|
-
});
|
|
1007
|
-
}
|
|
1008
|
-
return nextStates;
|
|
1009
|
-
});
|
|
1010
|
-
for (const step of group.steps) {
|
|
1011
|
-
if (step.command) {
|
|
1012
|
-
continue;
|
|
1013
|
-
}
|
|
1014
|
-
const timer = window.setTimeout(
|
|
1015
|
-
() => {
|
|
1016
|
-
setPresentationElementStates((previousStates) => {
|
|
1017
|
-
const nextStates = new Map(previousStates);
|
|
1018
|
-
const currentState = nextStates.get(step.elementId) ?? {
|
|
1019
|
-
visible: true};
|
|
1020
|
-
const visibleAfterStep = step.presetClass === "exit" || step.hideAfterEffect ? false : currentState.visible;
|
|
1021
|
-
nextStates.set(step.elementId, {
|
|
1022
|
-
visible: visibleAfterStep,
|
|
1023
|
-
cssAnimation: step.holdEndState ? step.cssAnimation : void 0
|
|
1024
|
-
});
|
|
1025
|
-
return nextStates;
|
|
1026
|
-
});
|
|
1027
|
-
},
|
|
1028
|
-
Math.max(0, step.delayMs + step.durationMs + 8)
|
|
1029
|
-
);
|
|
1030
|
-
presentationTimersRef.current.push(timer);
|
|
1031
|
-
}
|
|
1032
|
-
}
|
|
1033
972
|
function shouldSeekAnimationGroup(group, endAtMs, nowMs) {
|
|
1034
973
|
return group?.seqNextAction === "seek" && nowMs < endAtMs;
|
|
1035
974
|
}
|
|
@@ -1102,49 +1041,8 @@ function finishAnimationGroupSteps(group, setPresentationElementStates, complete
|
|
|
1102
1041
|
});
|
|
1103
1042
|
}
|
|
1104
1043
|
|
|
1105
|
-
// src/viewer/hooks/presentation-mode/build-playback.ts
|
|
1106
|
-
function cancelBuildReveal(handle) {
|
|
1107
|
-
if (handle.current !== null) {
|
|
1108
|
-
cancelAnimationFrame(handle.current);
|
|
1109
|
-
handle.current = null;
|
|
1110
|
-
}
|
|
1111
|
-
}
|
|
1112
|
-
function driveBuildReveal(controller, buildIds, setStates, handle) {
|
|
1113
|
-
cancelBuildReveal(handle);
|
|
1114
|
-
if (buildIds.length === 0 || typeof requestAnimationFrame !== "function") {
|
|
1115
|
-
return;
|
|
1116
|
-
}
|
|
1117
|
-
const start = performance.now();
|
|
1118
|
-
const tick = () => {
|
|
1119
|
-
const elapsedMs = performance.now() - start;
|
|
1120
|
-
const states = controller.computeStatesFor(buildIds, { elapsedMs });
|
|
1121
|
-
setStates((prev) => {
|
|
1122
|
-
const next = new Map(prev);
|
|
1123
|
-
for (const id of buildIds) {
|
|
1124
|
-
const build = states.get(id)?.build;
|
|
1125
|
-
if (!build) {
|
|
1126
|
-
continue;
|
|
1127
|
-
}
|
|
1128
|
-
const existing = next.get(id) ?? { visible: true, cssAnimation: void 0 };
|
|
1129
|
-
next.set(id, { ...existing, build });
|
|
1130
|
-
}
|
|
1131
|
-
return next;
|
|
1132
|
-
});
|
|
1133
|
-
let pending = false;
|
|
1134
|
-
for (const id of buildIds) {
|
|
1135
|
-
const build = states.get(id)?.build;
|
|
1136
|
-
if (build && build.progress < 1) {
|
|
1137
|
-
pending = true;
|
|
1138
|
-
break;
|
|
1139
|
-
}
|
|
1140
|
-
}
|
|
1141
|
-
handle.current = pending ? requestAnimationFrame(tick) : null;
|
|
1142
|
-
};
|
|
1143
|
-
tick();
|
|
1144
|
-
}
|
|
1145
|
-
|
|
1146
1044
|
// src/viewer/hooks/presentation-mode/entrance-animation-timers.ts
|
|
1147
|
-
function scheduleOpeningAutoPlayGroup(controller,
|
|
1045
|
+
function scheduleOpeningAutoPlayGroup(controller, ctx) {
|
|
1148
1046
|
if (!controller.hasMoreSteps()) {
|
|
1149
1047
|
return;
|
|
1150
1048
|
}
|
|
@@ -1157,17 +1055,10 @@ function scheduleOpeningAutoPlayGroup(controller, deps) {
|
|
|
1157
1055
|
if (!group) {
|
|
1158
1056
|
return;
|
|
1159
1057
|
}
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
deps.onPlayActionSound,
|
|
1163
|
-
deps.setPresentationElementStates,
|
|
1164
|
-
deps.presentationTimersRef
|
|
1165
|
-
);
|
|
1166
|
-
deps.markAnimationGroupActive(group);
|
|
1167
|
-
deps.startBuildReveal(controller, group);
|
|
1168
|
-
deps.scheduleAutoAdvanceChain(controller);
|
|
1058
|
+
playGroup(controller, group, ctx);
|
|
1059
|
+
scheduleAutoAdvanceChain(controller, ctx);
|
|
1169
1060
|
}, firstGroup.autoAdvanceDelayMs ?? 0);
|
|
1170
|
-
|
|
1061
|
+
ctx.timers.push(timer);
|
|
1171
1062
|
}
|
|
1172
1063
|
function scheduleEntranceAnimationTimers(slide, setPresentationAnimations, presentationTimersRef) {
|
|
1173
1064
|
const entranceAnimations = [...slide.animations || []].filter((animation) => Boolean(animation.entrance)).sort(
|
|
@@ -1214,17 +1105,16 @@ function useAnimationPlayback(input) {
|
|
|
1214
1105
|
const activeAnimationEndAtRef = useRef(0);
|
|
1215
1106
|
const seededCompletedRef = useRef(false);
|
|
1216
1107
|
const lastSeedCompletedRef = useRef(false);
|
|
1217
|
-
const
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
}
|
|
1226
|
-
|
|
1227
|
-
);
|
|
1108
|
+
const buildPlaybackContext = useCallback(() => {
|
|
1109
|
+
return {
|
|
1110
|
+
setStates: setPresentationElementStates,
|
|
1111
|
+
timers: presentationTimersRef.current,
|
|
1112
|
+
buildHandle: buildRafRef,
|
|
1113
|
+
onPlayActionSound,
|
|
1114
|
+
playSound: playAnimationSound,
|
|
1115
|
+
stopSound: stopAnimationSound
|
|
1116
|
+
};
|
|
1117
|
+
}, [onPlayActionSound]);
|
|
1228
1118
|
useEffect(() => {
|
|
1229
1119
|
return () => {
|
|
1230
1120
|
cancelBuildReveal(buildRafRef);
|
|
@@ -1243,45 +1133,6 @@ function useAnimationPlayback(input) {
|
|
|
1243
1133
|
activeAnimationGroupRef.current = group;
|
|
1244
1134
|
activeAnimationEndAtRef.current = performance.now() + Math.max(0, group.totalDurationMs);
|
|
1245
1135
|
}, []);
|
|
1246
|
-
const scheduleAutoAdvanceChain = useCallback(
|
|
1247
|
-
(controller) => {
|
|
1248
|
-
if (!controller.shouldAutoAdvance()) {
|
|
1249
|
-
return;
|
|
1250
|
-
}
|
|
1251
|
-
const delay = controller.getAutoAdvanceDelay();
|
|
1252
|
-
const previousGroup = controller.peekNext();
|
|
1253
|
-
if (!previousGroup) {
|
|
1254
|
-
return;
|
|
1255
|
-
}
|
|
1256
|
-
const totalDelay = delay + (previousGroup.autoAdvanceDelayMs ?? 0);
|
|
1257
|
-
const timer = window.setTimeout(
|
|
1258
|
-
() => {
|
|
1259
|
-
const group = controller.advance();
|
|
1260
|
-
if (!group) {
|
|
1261
|
-
return;
|
|
1262
|
-
}
|
|
1263
|
-
applyAnimationGroupSteps(
|
|
1264
|
-
group,
|
|
1265
|
-
onPlayActionSound,
|
|
1266
|
-
setPresentationElementStates,
|
|
1267
|
-
presentationTimersRef
|
|
1268
|
-
);
|
|
1269
|
-
markAnimationGroupActive(group);
|
|
1270
|
-
startBuildReveal(controller, group);
|
|
1271
|
-
scheduleAutoAdvanceChain(controller);
|
|
1272
|
-
},
|
|
1273
|
-
Math.max(0, totalDelay)
|
|
1274
|
-
);
|
|
1275
|
-
presentationTimersRef.current.push(timer);
|
|
1276
|
-
},
|
|
1277
|
-
// `scheduleAutoAdvanceChain` recursively calls itself (line 190) to walk the
|
|
1278
|
-
// auto-advance chain; it can't list itself as its own dependency (the const
|
|
1279
|
-
// isn't assigned yet when the array is evaluated). The recursive call still
|
|
1280
|
-
// resolves correctly because the setTimeout callback only reads the binding
|
|
1281
|
-
// once the outer const has been assigned.
|
|
1282
|
-
// oxlint-disable-next-line react/memo-dependencies -- see comment above
|
|
1283
|
-
[markAnimationGroupActive, onPlayActionSound, startBuildReveal]
|
|
1284
|
-
);
|
|
1285
1136
|
const resetSlideTimeline = useCallback(
|
|
1286
1137
|
(slideIndex) => {
|
|
1287
1138
|
cancelBuildReveal(buildRafRef);
|
|
@@ -1315,7 +1166,7 @@ function useAnimationPlayback(input) {
|
|
|
1315
1166
|
const completedStates = controller.computeStatesFor(buildIds);
|
|
1316
1167
|
clearPresentationTimers();
|
|
1317
1168
|
finishAnimationGroupSteps(activeGroup, setPresentationElementStates, completedStates);
|
|
1318
|
-
scheduleAutoAdvanceChain(controller);
|
|
1169
|
+
scheduleAutoAdvanceChain(controller, buildPlaybackContext());
|
|
1319
1170
|
return true;
|
|
1320
1171
|
}
|
|
1321
1172
|
if (!controller || !controller.hasMoreSteps()) {
|
|
@@ -1325,24 +1176,12 @@ function useAnimationPlayback(input) {
|
|
|
1325
1176
|
if (!group) {
|
|
1326
1177
|
return false;
|
|
1327
1178
|
}
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
onPlayActionSound,
|
|
1331
|
-
setPresentationElementStates,
|
|
1332
|
-
presentationTimersRef
|
|
1333
|
-
);
|
|
1179
|
+
const ctx = buildPlaybackContext();
|
|
1180
|
+
playGroup(controller, group, ctx);
|
|
1334
1181
|
markAnimationGroupActive(group);
|
|
1335
|
-
|
|
1336
|
-
scheduleAutoAdvanceChain(controller);
|
|
1182
|
+
scheduleAutoAdvanceChain(controller, ctx);
|
|
1337
1183
|
return true;
|
|
1338
|
-
}, [
|
|
1339
|
-
animationsEnabled,
|
|
1340
|
-
clearPresentationTimers,
|
|
1341
|
-
markAnimationGroupActive,
|
|
1342
|
-
onPlayActionSound,
|
|
1343
|
-
scheduleAutoAdvanceChain,
|
|
1344
|
-
startBuildReveal
|
|
1345
|
-
]);
|
|
1184
|
+
}, [animationsEnabled, buildPlaybackContext, clearPresentationTimers, markAnimationGroupActive]);
|
|
1346
1185
|
const handleInteractiveShapeClick = useCallback(
|
|
1347
1186
|
(shapeId) => {
|
|
1348
1187
|
const controller = controllerRef.current;
|
|
@@ -1353,16 +1192,10 @@ function useAnimationPlayback(input) {
|
|
|
1353
1192
|
if (!group) {
|
|
1354
1193
|
return false;
|
|
1355
1194
|
}
|
|
1356
|
-
|
|
1357
|
-
group,
|
|
1358
|
-
onPlayActionSound,
|
|
1359
|
-
setPresentationElementStates,
|
|
1360
|
-
presentationTimersRef
|
|
1361
|
-
);
|
|
1362
|
-
startBuildReveal(controller, group);
|
|
1195
|
+
playGroup(controller, group, buildPlaybackContext());
|
|
1363
1196
|
return true;
|
|
1364
1197
|
},
|
|
1365
|
-
[
|
|
1198
|
+
[buildPlaybackContext]
|
|
1366
1199
|
);
|
|
1367
1200
|
const handleHoverStart = useCallback(
|
|
1368
1201
|
(shapeId) => {
|
|
@@ -1378,16 +1211,10 @@ function useAnimationPlayback(input) {
|
|
|
1378
1211
|
if (!group) {
|
|
1379
1212
|
return false;
|
|
1380
1213
|
}
|
|
1381
|
-
|
|
1382
|
-
group,
|
|
1383
|
-
onPlayActionSound,
|
|
1384
|
-
setPresentationElementStates,
|
|
1385
|
-
presentationTimersRef
|
|
1386
|
-
);
|
|
1387
|
-
startBuildReveal(controller, group);
|
|
1214
|
+
playGroup(controller, group, buildPlaybackContext());
|
|
1388
1215
|
return true;
|
|
1389
1216
|
},
|
|
1390
|
-
[animationsEnabled,
|
|
1217
|
+
[animationsEnabled, buildPlaybackContext]
|
|
1391
1218
|
);
|
|
1392
1219
|
const handleHoverEnd = useCallback((shapeId) => {
|
|
1393
1220
|
const controller = controllerRef.current;
|
|
@@ -1433,25 +1260,12 @@ function useAnimationPlayback(input) {
|
|
|
1433
1260
|
}
|
|
1434
1261
|
const controller = controllerRef.current;
|
|
1435
1262
|
if (controller) {
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
setPresentationElementStates,
|
|
1439
|
-
presentationTimersRef,
|
|
1440
|
-
startBuildReveal,
|
|
1441
|
-
scheduleAutoAdvanceChain,
|
|
1442
|
-
markAnimationGroupActive
|
|
1443
|
-
});
|
|
1263
|
+
const ctx = buildPlaybackContext();
|
|
1264
|
+
scheduleOpeningAutoPlayGroup(controller, ctx);
|
|
1444
1265
|
}
|
|
1445
1266
|
scheduleEntranceAnimationTimers(slide, setPresentationAnimations, presentationTimersRef);
|
|
1446
1267
|
},
|
|
1447
|
-
[
|
|
1448
|
-
animationsEnabled,
|
|
1449
|
-
slides,
|
|
1450
|
-
onPlayActionSound,
|
|
1451
|
-
markAnimationGroupActive,
|
|
1452
|
-
scheduleAutoAdvanceChain,
|
|
1453
|
-
startBuildReveal
|
|
1454
|
-
]
|
|
1268
|
+
[animationsEnabled, slides, buildPlaybackContext]
|
|
1455
1269
|
);
|
|
1456
1270
|
const runPresentationEntranceAnimations = useCallback(
|
|
1457
1271
|
(slideIndex, options) => {
|
|
@@ -2019,7 +1833,7 @@ function useRehearsalTimings(input) {
|
|
|
2019
1833
|
function handlePresentationActionImpl(action, deps) {
|
|
2020
1834
|
runPresentationAction(
|
|
2021
1835
|
action,
|
|
2022
|
-
{ slideCount: deps.slidesLength },
|
|
1836
|
+
{ slideCount: deps.slidesLength, ...deps.elementId ? { elementId: deps.elementId } : {} },
|
|
2023
1837
|
{
|
|
2024
1838
|
goToSlide: (slideIndex) => {
|
|
2025
1839
|
deps.navigateToSlide(slideIndex);
|
|
@@ -2030,7 +1844,13 @@ function handlePresentationActionImpl(action, deps) {
|
|
|
2030
1844
|
endShow: () => {
|
|
2031
1845
|
deps.onSetMode("edit");
|
|
2032
1846
|
},
|
|
2033
|
-
playSound: deps.onPlayActionSound ? (soundPath) => deps.onPlayActionSound?.(soundPath) : void 0
|
|
1847
|
+
playSound: deps.onPlayActionSound ? (soundPath) => deps.onPlayActionSound?.(soundPath) : void 0,
|
|
1848
|
+
lastViewed: deps.onLastViewed,
|
|
1849
|
+
customShow: deps.onCustomShow,
|
|
1850
|
+
openFile: deps.onOpenFile,
|
|
1851
|
+
openPresentation: deps.onOpenPresentation,
|
|
1852
|
+
playMedia: deps.onPlayMedia,
|
|
1853
|
+
oleVerb: deps.onOleVerb
|
|
2034
1854
|
}
|
|
2035
1855
|
);
|
|
2036
1856
|
}
|
|
@@ -2038,7 +1858,7 @@ function handlePresentationActionImpl(action, deps) {
|
|
|
2038
1858
|
// src/viewer/hooks/presentation-mode/slide-transition.ts
|
|
2039
1859
|
function executeSlideTransition(nextSlideIndex, deps) {
|
|
2040
1860
|
const incomingSlide = deps.slides[nextSlideIndex];
|
|
2041
|
-
const transition = incomingSlide?.transition;
|
|
1861
|
+
const transition = deps.reverse ? deps.slides[deps.currentSlideIndex]?.transition : incomingSlide?.transition;
|
|
2042
1862
|
const durationMs = deps.playTransition ? resolveTransitionDurationMs(transition) : 0;
|
|
2043
1863
|
deps.clearPresentationTimers();
|
|
2044
1864
|
deps.setPresentationSlideIndex(nextSlideIndex);
|
|
@@ -2092,7 +1912,13 @@ function useSlideNavigation(input) {
|
|
|
2092
1912
|
presentationTimersRef,
|
|
2093
1913
|
rehearsing,
|
|
2094
1914
|
recordCurrentSlideTime,
|
|
2095
|
-
setShowRehearsalSummary
|
|
1915
|
+
setShowRehearsalSummary,
|
|
1916
|
+
onLastViewed,
|
|
1917
|
+
onCustomShow,
|
|
1918
|
+
onOpenFile,
|
|
1919
|
+
onOpenPresentation,
|
|
1920
|
+
onPlayMedia,
|
|
1921
|
+
onOleVerb
|
|
2096
1922
|
} = input;
|
|
2097
1923
|
const movePresentationSlideRef = useRef(() => {
|
|
2098
1924
|
});
|
|
@@ -2161,8 +1987,11 @@ function useSlideNavigation(input) {
|
|
|
2161
1987
|
scheduleAutoAdvanceForSlide: rehearsing ? void 0 : scheduleAutoAdvanceForSlide,
|
|
2162
1988
|
presentationTimersRef,
|
|
2163
1989
|
setTransitionOverlay,
|
|
2164
|
-
// PowerPoint plays a slide's transition only when advancing into it
|
|
2165
|
-
|
|
1990
|
+
// PowerPoint plays a slide's transition only when advancing into it,
|
|
1991
|
+
// and replays the LEAVING slide's transition in reverse when stepping
|
|
1992
|
+
// back (a morph glides its shapes back to where they came from).
|
|
1993
|
+
playTransition: true,
|
|
1994
|
+
reverse: direction === -1,
|
|
2166
1995
|
// Stepping back onto a slide shows it with its builds already played.
|
|
2167
1996
|
seedCompleted: direction === -1
|
|
2168
1997
|
});
|
|
@@ -2238,16 +2067,35 @@ function useSlideNavigation(input) {
|
|
|
2238
2067
|
]
|
|
2239
2068
|
);
|
|
2240
2069
|
const handlePresentationAction = useCallback(
|
|
2241
|
-
(action) => {
|
|
2070
|
+
(action, elementId) => {
|
|
2242
2071
|
handlePresentationActionImpl(action, {
|
|
2072
|
+
elementId,
|
|
2243
2073
|
movePresentationSlide,
|
|
2244
2074
|
navigateToSlide,
|
|
2245
2075
|
onPlayActionSound,
|
|
2246
2076
|
onSetMode,
|
|
2247
|
-
slidesLength: slides.length
|
|
2077
|
+
slidesLength: slides.length,
|
|
2078
|
+
onLastViewed,
|
|
2079
|
+
onCustomShow,
|
|
2080
|
+
onOpenFile,
|
|
2081
|
+
onOpenPresentation,
|
|
2082
|
+
onPlayMedia,
|
|
2083
|
+
onOleVerb
|
|
2248
2084
|
});
|
|
2249
2085
|
},
|
|
2250
|
-
[
|
|
2086
|
+
[
|
|
2087
|
+
movePresentationSlide,
|
|
2088
|
+
navigateToSlide,
|
|
2089
|
+
onPlayActionSound,
|
|
2090
|
+
onSetMode,
|
|
2091
|
+
slides.length,
|
|
2092
|
+
onLastViewed,
|
|
2093
|
+
onCustomShow,
|
|
2094
|
+
onOpenFile,
|
|
2095
|
+
onOpenPresentation,
|
|
2096
|
+
onPlayMedia,
|
|
2097
|
+
onOleVerb
|
|
2098
|
+
]
|
|
2251
2099
|
);
|
|
2252
2100
|
return {
|
|
2253
2101
|
movePresentationSlide,
|
|
@@ -2285,6 +2133,136 @@ function useZoomNavigation(input) {
|
|
|
2285
2133
|
clearZoomReturn
|
|
2286
2134
|
};
|
|
2287
2135
|
}
|
|
2136
|
+
function createCustomShowRunner(deps) {
|
|
2137
|
+
let origin = null;
|
|
2138
|
+
return {
|
|
2139
|
+
runCustomShow(customShowId, returnAfter) {
|
|
2140
|
+
const target = deps.getCustomShows().find((show) => show.id === customShowId);
|
|
2141
|
+
if (!target) {
|
|
2142
|
+
return;
|
|
2143
|
+
}
|
|
2144
|
+
origin = returnAfter ? { showId: deps.getActiveCustomShowId(), slideIndex: deps.getPresentationSlideIndex() } : null;
|
|
2145
|
+
const first = firstShowSlideIndex(resolveShowSlideIndexes(deps.getSlides(), target));
|
|
2146
|
+
deps.setActiveCustomShowId(customShowId);
|
|
2147
|
+
if (first !== void 0) {
|
|
2148
|
+
deps.navigateToSlide(first);
|
|
2149
|
+
}
|
|
2150
|
+
},
|
|
2151
|
+
tryReturnFromCustomShow() {
|
|
2152
|
+
if (!origin) {
|
|
2153
|
+
return false;
|
|
2154
|
+
}
|
|
2155
|
+
const { showId, slideIndex } = origin;
|
|
2156
|
+
origin = null;
|
|
2157
|
+
deps.setActiveCustomShowId(showId);
|
|
2158
|
+
deps.navigateToSlide(slideIndex);
|
|
2159
|
+
return true;
|
|
2160
|
+
}
|
|
2161
|
+
};
|
|
2162
|
+
}
|
|
2163
|
+
function useCustomShowRunner(deps) {
|
|
2164
|
+
const depsRef = useRef(deps);
|
|
2165
|
+
depsRef.current = deps;
|
|
2166
|
+
const runnerRef = useRef(null);
|
|
2167
|
+
runnerRef.current ??= createCustomShowRunner({
|
|
2168
|
+
getSlides: () => depsRef.current.getSlides(),
|
|
2169
|
+
getCustomShows: () => depsRef.current.getCustomShows(),
|
|
2170
|
+
getActiveCustomShowId: () => depsRef.current.getActiveCustomShowId(),
|
|
2171
|
+
setActiveCustomShowId: (id) => depsRef.current.setActiveCustomShowId(id),
|
|
2172
|
+
navigateToSlide: (index) => depsRef.current.navigateToSlide(index),
|
|
2173
|
+
getPresentationSlideIndex: () => depsRef.current.getPresentationSlideIndex()
|
|
2174
|
+
});
|
|
2175
|
+
return runnerRef.current;
|
|
2176
|
+
}
|
|
2177
|
+
|
|
2178
|
+
// src/viewer/hooks/presentation-mode/usePresentationActionExtensions.ts
|
|
2179
|
+
function usePresentationActionExtensions(input) {
|
|
2180
|
+
const {
|
|
2181
|
+
slides,
|
|
2182
|
+
customShows,
|
|
2183
|
+
activeCustomShowId,
|
|
2184
|
+
onSetActiveCustomShowId,
|
|
2185
|
+
presentationSlideIndex,
|
|
2186
|
+
containerRef,
|
|
2187
|
+
endWithBlackSlide,
|
|
2188
|
+
onSetMode,
|
|
2189
|
+
setEndOfShowVisible
|
|
2190
|
+
} = input;
|
|
2191
|
+
const navigateToSlideRef = useRef(null);
|
|
2192
|
+
const navigateToSlideViaRef = useCallback((index) => {
|
|
2193
|
+
navigateToSlideRef.current?.(index);
|
|
2194
|
+
}, []);
|
|
2195
|
+
const customShowRunner = useCustomShowRunner({
|
|
2196
|
+
getSlides: () => slides,
|
|
2197
|
+
getCustomShows: () => customShows,
|
|
2198
|
+
getActiveCustomShowId: () => activeCustomShowId,
|
|
2199
|
+
setActiveCustomShowId: (id) => onSetActiveCustomShowId?.(id),
|
|
2200
|
+
navigateToSlide: navigateToSlideViaRef,
|
|
2201
|
+
getPresentationSlideIndex: () => presentationSlideIndex
|
|
2202
|
+
});
|
|
2203
|
+
const previousSlideRef = useRef(presentationSlideIndex);
|
|
2204
|
+
const lastViewedSlideRef = useRef(null);
|
|
2205
|
+
useEffect(() => {
|
|
2206
|
+
lastViewedSlideRef.current = previousSlideRef.current;
|
|
2207
|
+
previousSlideRef.current = presentationSlideIndex;
|
|
2208
|
+
}, [presentationSlideIndex]);
|
|
2209
|
+
const onCustomShow = useCallback(
|
|
2210
|
+
(customShowId, returnAfter) => {
|
|
2211
|
+
customShowRunner.runCustomShow(customShowId, returnAfter);
|
|
2212
|
+
},
|
|
2213
|
+
[customShowRunner]
|
|
2214
|
+
);
|
|
2215
|
+
const onLastViewed = useCallback(() => {
|
|
2216
|
+
const previous = lastViewedSlideRef.current;
|
|
2217
|
+
if (previous !== null) {
|
|
2218
|
+
navigateToSlideViaRef(previous);
|
|
2219
|
+
}
|
|
2220
|
+
}, [navigateToSlideViaRef]);
|
|
2221
|
+
const onOpenFile = useCallback((target) => {
|
|
2222
|
+
safeOpenUrl(target);
|
|
2223
|
+
}, []);
|
|
2224
|
+
const onOpenPresentation = useCallback((target) => {
|
|
2225
|
+
safeOpenUrl(target);
|
|
2226
|
+
}, []);
|
|
2227
|
+
const onPlayMedia = useCallback(
|
|
2228
|
+
(elementId) => {
|
|
2229
|
+
toggleStageElementMedia(containerRef.current, elementId);
|
|
2230
|
+
},
|
|
2231
|
+
[containerRef]
|
|
2232
|
+
);
|
|
2233
|
+
const onOleVerb = useCallback(
|
|
2234
|
+
(verb, elementId) => {
|
|
2235
|
+
const target = resolveOleVerbTarget(slides[presentationSlideIndex], elementId, verb);
|
|
2236
|
+
if (target) {
|
|
2237
|
+
openUrlInNewTab(target.url);
|
|
2238
|
+
}
|
|
2239
|
+
},
|
|
2240
|
+
[slides, presentationSlideIndex]
|
|
2241
|
+
);
|
|
2242
|
+
const handleAdvancePastLastSlide = useCallback(() => {
|
|
2243
|
+
if (customShowRunner.tryReturnFromCustomShow()) {
|
|
2244
|
+
return;
|
|
2245
|
+
}
|
|
2246
|
+
if (endWithBlackSlide) {
|
|
2247
|
+
setEndOfShowVisible(true);
|
|
2248
|
+
} else {
|
|
2249
|
+
onSetMode("edit");
|
|
2250
|
+
}
|
|
2251
|
+
}, [customShowRunner, endWithBlackSlide, onSetMode, setEndOfShowVisible]);
|
|
2252
|
+
const bindNavigateToSlide = useCallback((navigateToSlide) => {
|
|
2253
|
+
navigateToSlideRef.current = navigateToSlide;
|
|
2254
|
+
}, []);
|
|
2255
|
+
return {
|
|
2256
|
+
onLastViewed,
|
|
2257
|
+
onCustomShow,
|
|
2258
|
+
onOpenFile,
|
|
2259
|
+
onOpenPresentation,
|
|
2260
|
+
onPlayMedia,
|
|
2261
|
+
onOleVerb,
|
|
2262
|
+
handleAdvancePastLastSlide,
|
|
2263
|
+
bindNavigateToSlide
|
|
2264
|
+
};
|
|
2265
|
+
}
|
|
2288
2266
|
function usePresenterConsole(slideIndex, active) {
|
|
2289
2267
|
const timerRef = useRef(createPresenterTimer());
|
|
2290
2268
|
const [snapshot, setSnapshot] = useState(() => createInitialPresentationSnapshot(slideIndex));
|
|
@@ -2341,6 +2319,7 @@ function usePresentationMode(input) {
|
|
|
2341
2319
|
const {
|
|
2342
2320
|
mode,
|
|
2343
2321
|
slides,
|
|
2322
|
+
templateElementsBySlideId,
|
|
2344
2323
|
visibleSlideIndexes,
|
|
2345
2324
|
activeSlideIndex,
|
|
2346
2325
|
containerRef,
|
|
@@ -2357,7 +2336,10 @@ function usePresentationMode(input) {
|
|
|
2357
2336
|
loopContinuously,
|
|
2358
2337
|
showWithAnimation,
|
|
2359
2338
|
useTimings,
|
|
2360
|
-
endWithBlackSlide = true
|
|
2339
|
+
endWithBlackSlide = true,
|
|
2340
|
+
customShows = [],
|
|
2341
|
+
activeCustomShowId = null,
|
|
2342
|
+
onSetActiveCustomShowId
|
|
2361
2343
|
} = input;
|
|
2362
2344
|
const [presentationSlideIndex, setPresentationSlideIndex] = useState(0);
|
|
2363
2345
|
const [presentationSlideVisible, setPresentationSlideVisible] = useState(true);
|
|
@@ -2412,13 +2394,17 @@ function usePresentationMode(input) {
|
|
|
2412
2394
|
setPresenterMode(false);
|
|
2413
2395
|
}
|
|
2414
2396
|
}, [mode]);
|
|
2415
|
-
const
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2397
|
+
const actionExtensions = usePresentationActionExtensions({
|
|
2398
|
+
slides,
|
|
2399
|
+
customShows,
|
|
2400
|
+
activeCustomShowId,
|
|
2401
|
+
onSetActiveCustomShowId,
|
|
2402
|
+
presentationSlideIndex,
|
|
2403
|
+
containerRef,
|
|
2404
|
+
endWithBlackSlide,
|
|
2405
|
+
onSetMode,
|
|
2406
|
+
setEndOfShowVisible
|
|
2407
|
+
});
|
|
2422
2408
|
const {
|
|
2423
2409
|
movePresentationSlide: moveNavigationSlide,
|
|
2424
2410
|
navigateToSlide,
|
|
@@ -2436,7 +2422,7 @@ function usePresentationMode(input) {
|
|
|
2436
2422
|
onPlayActionSound,
|
|
2437
2423
|
loopContinuously,
|
|
2438
2424
|
useTimings,
|
|
2439
|
-
onAdvancePastLastSlide: handleAdvancePastLastSlide,
|
|
2425
|
+
onAdvancePastLastSlide: actionExtensions.handleAdvancePastLastSlide,
|
|
2440
2426
|
playNextAnimationGroup,
|
|
2441
2427
|
clearPresentationTimers,
|
|
2442
2428
|
seedSlideAnimations,
|
|
@@ -2444,8 +2430,15 @@ function usePresentationMode(input) {
|
|
|
2444
2430
|
presentationTimersRef,
|
|
2445
2431
|
rehearsing,
|
|
2446
2432
|
recordCurrentSlideTime,
|
|
2447
|
-
setShowRehearsalSummary
|
|
2433
|
+
setShowRehearsalSummary,
|
|
2434
|
+
onLastViewed: actionExtensions.onLastViewed,
|
|
2435
|
+
onCustomShow: actionExtensions.onCustomShow,
|
|
2436
|
+
onOpenFile: actionExtensions.onOpenFile,
|
|
2437
|
+
onOpenPresentation: actionExtensions.onOpenPresentation,
|
|
2438
|
+
onPlayMedia: actionExtensions.onPlayMedia,
|
|
2439
|
+
onOleVerb: actionExtensions.onOleVerb
|
|
2448
2440
|
});
|
|
2441
|
+
actionExtensions.bindNavigateToSlide(navigateToSlide);
|
|
2449
2442
|
const movePresentationSlide = useCallback(
|
|
2450
2443
|
(direction, trigger = "explicit") => {
|
|
2451
2444
|
if (!acceptsPresentationInput()) {
|
|
@@ -2516,6 +2509,13 @@ function usePresentationMode(input) {
|
|
|
2516
2509
|
}
|
|
2517
2510
|
onSetMode("present");
|
|
2518
2511
|
}, [containerRef, onSetMode, setRehearsing]);
|
|
2512
|
+
const enterPresentModeFromBeginning = useCallback(() => {
|
|
2513
|
+
const first = firstShowSlideIndex(visibleSlideIndexes);
|
|
2514
|
+
if (first !== void 0) {
|
|
2515
|
+
onSetActiveSlideIndex(first);
|
|
2516
|
+
}
|
|
2517
|
+
enterPresentMode();
|
|
2518
|
+
}, [visibleSlideIndexes, onSetActiveSlideIndex, enterPresentMode]);
|
|
2519
2519
|
const enterPresenterView = useCallback(() => {
|
|
2520
2520
|
setPresenterMode(true);
|
|
2521
2521
|
setRehearsing(false);
|
|
@@ -2578,6 +2578,10 @@ function usePresentationMode(input) {
|
|
|
2578
2578
|
scheduleAutoAdvanceRef.current = scheduleAutoAdvanceForSlide;
|
|
2579
2579
|
const activeSlideIndexRef = useRef(activeSlideIndex);
|
|
2580
2580
|
activeSlideIndexRef.current = activeSlideIndex;
|
|
2581
|
+
const visibleSlideIndexesRef = useRef(visibleSlideIndexes);
|
|
2582
|
+
visibleSlideIndexesRef.current = visibleSlideIndexes;
|
|
2583
|
+
const onSetActiveSlideIndexRef = useRef(onSetActiveSlideIndex);
|
|
2584
|
+
onSetActiveSlideIndexRef.current = onSetActiveSlideIndex;
|
|
2581
2585
|
const presentationSlideIndexRef = useRef(presentationSlideIndex);
|
|
2582
2586
|
presentationSlideIndexRef.current = presentationSlideIndex;
|
|
2583
2587
|
const clearPresentationTimersRef = useRef(clearPresentationTimers);
|
|
@@ -2594,8 +2598,14 @@ function usePresentationMode(input) {
|
|
|
2594
2598
|
}, [mode, containerRef]);
|
|
2595
2599
|
useLayoutEffect(() => {
|
|
2596
2600
|
if (mode === "present") {
|
|
2597
|
-
const idx =
|
|
2601
|
+
const idx = presentationEntrySlideIndex(
|
|
2602
|
+
activeSlideIndexRef.current,
|
|
2603
|
+
visibleSlideIndexesRef.current
|
|
2604
|
+
);
|
|
2598
2605
|
setPresentationSlideIndex(idx);
|
|
2606
|
+
if (idx !== activeSlideIndexRef.current) {
|
|
2607
|
+
onSetActiveSlideIndexRef.current(idx);
|
|
2608
|
+
}
|
|
2599
2609
|
runEntranceAnimationsRef.current(idx);
|
|
2600
2610
|
scheduleAutoAdvanceRef.current(idx);
|
|
2601
2611
|
} else {
|
|
@@ -2666,13 +2676,18 @@ function usePresentationMode(input) {
|
|
|
2666
2676
|
if (!transitionOverlay || transitionOverlay.transition.type !== "morph") {
|
|
2667
2677
|
return void 0;
|
|
2668
2678
|
}
|
|
2679
|
+
const incoming = slides[transitionOverlay.incomingSlideIndex];
|
|
2669
2680
|
return buildMorphTransitionPlan(
|
|
2670
2681
|
slides[transitionOverlay.outgoingSlideIndex],
|
|
2671
|
-
|
|
2682
|
+
incoming,
|
|
2672
2683
|
transitionOverlay.durationMs,
|
|
2673
|
-
morphOptionToMode(transitionOverlay.transition.morphOption)
|
|
2684
|
+
morphOptionToMode(transitionOverlay.transition.morphOption),
|
|
2685
|
+
// `PresentationStage` stacks the incoming slide's elements above its
|
|
2686
|
+
// template shapes (`zIndex = templateElements.length + index`), so a
|
|
2687
|
+
// z-index journey has to start counting where the stage does.
|
|
2688
|
+
{ zIndexBase: incoming ? templateElementsBySlideId?.[incoming.id]?.length ?? 0 : 0 }
|
|
2674
2689
|
);
|
|
2675
|
-
}, [transitionOverlay, slides]);
|
|
2690
|
+
}, [transitionOverlay, slides, templateElementsBySlideId]);
|
|
2676
2691
|
const morphedElementStates = useMemo(() => {
|
|
2677
2692
|
if (!morphPlan || morphPlan.incomingAnimations.size === 0) {
|
|
2678
2693
|
return presentationElementStates;
|
|
@@ -2721,6 +2736,7 @@ ${imageRules}`;
|
|
|
2721
2736
|
handleHoverStart,
|
|
2722
2737
|
handleHoverEnd,
|
|
2723
2738
|
enterPresentMode,
|
|
2739
|
+
enterPresentModeFromBeginning,
|
|
2724
2740
|
presenterMode,
|
|
2725
2741
|
enterPresenterView,
|
|
2726
2742
|
togglePresenterView,
|
|
@@ -3112,6 +3128,38 @@ function useModalDismissDrag(onClose, threshold = 120) {
|
|
|
3112
3128
|
handlers: { onPointerDown, onPointerMove, onPointerUp, onPointerCancel: onPointerUp }
|
|
3113
3129
|
};
|
|
3114
3130
|
}
|
|
3131
|
+
function withoutKey(map, key) {
|
|
3132
|
+
if (!(key in map)) {
|
|
3133
|
+
return map;
|
|
3134
|
+
}
|
|
3135
|
+
const next = { ...map };
|
|
3136
|
+
delete next[key];
|
|
3137
|
+
return next;
|
|
3138
|
+
}
|
|
3139
|
+
function useCommentMentionDrafts() {
|
|
3140
|
+
const [commentDraftMentionsBySlideId, setCommentDraftMentionsBySlideId] = useState({});
|
|
3141
|
+
const [replyDraftMentionsByCommentId, setReplyDraftMentionsByCommentId] = useState({});
|
|
3142
|
+
const setCommentDraftMentions = useCallback((slideId, mentions) => {
|
|
3143
|
+
setCommentDraftMentionsBySlideId((prev) => ({ ...prev, [slideId]: mentions }));
|
|
3144
|
+
}, []);
|
|
3145
|
+
const setReplyDraftMentions = useCallback((commentId, mentions) => {
|
|
3146
|
+
setReplyDraftMentionsByCommentId((prev) => ({ ...prev, [commentId]: mentions }));
|
|
3147
|
+
}, []);
|
|
3148
|
+
const clearCommentDraftMentions = useCallback((slideId) => {
|
|
3149
|
+
setCommentDraftMentionsBySlideId((prev) => withoutKey(prev, slideId));
|
|
3150
|
+
}, []);
|
|
3151
|
+
const clearReplyDraftMentions = useCallback((commentId) => {
|
|
3152
|
+
setReplyDraftMentionsByCommentId((prev) => withoutKey(prev, commentId));
|
|
3153
|
+
}, []);
|
|
3154
|
+
return {
|
|
3155
|
+
commentDraftMentionsBySlideId,
|
|
3156
|
+
replyDraftMentionsByCommentId,
|
|
3157
|
+
setCommentDraftMentions,
|
|
3158
|
+
setReplyDraftMentions,
|
|
3159
|
+
clearCommentDraftMentions,
|
|
3160
|
+
clearReplyDraftMentions
|
|
3161
|
+
};
|
|
3162
|
+
}
|
|
3115
3163
|
|
|
3116
3164
|
// src/viewer/hooks/useComments-helpers.ts
|
|
3117
3165
|
function replaceCommentsOnSlide(slides, slideIndex, next) {
|
|
@@ -3119,7 +3167,7 @@ function replaceCommentsOnSlide(slides, slideIndex, next) {
|
|
|
3119
3167
|
(entry, index) => index === slideIndex ? { ...entry, comments: next } : entry
|
|
3120
3168
|
);
|
|
3121
3169
|
}
|
|
3122
|
-
function addCommentToSlide(slides, slideIndex, text, authorName, elementId) {
|
|
3170
|
+
function addCommentToSlide(slides, slideIndex, text, authorName, elementId, mentions) {
|
|
3123
3171
|
const slide = slides[slideIndex];
|
|
3124
3172
|
if (!slide) {
|
|
3125
3173
|
return { slides, didAdd: false };
|
|
@@ -3135,7 +3183,10 @@ function addCommentToSlide(slides, slideIndex, text, authorName, elementId) {
|
|
|
3135
3183
|
if (!next) {
|
|
3136
3184
|
return { slides, didAdd: false };
|
|
3137
3185
|
}
|
|
3138
|
-
|
|
3186
|
+
const withMentions = mentions && mentions.length > 0 ? next.map(
|
|
3187
|
+
(comment, index) => index === next.length - 1 ? { ...comment, mentions } : comment
|
|
3188
|
+
) : next;
|
|
3189
|
+
return { slides: replaceCommentsOnSlide(slides, slideIndex, withMentions), didAdd: true };
|
|
3139
3190
|
}
|
|
3140
3191
|
function removeCommentFromSlide(slides, slideIndex, commentId) {
|
|
3141
3192
|
const slide = slides[slideIndex];
|
|
@@ -3170,7 +3221,7 @@ function toggleResolvedInSlide(slides, slideIndex, commentId) {
|
|
|
3170
3221
|
}
|
|
3171
3222
|
return { slides: replaceCommentsOnSlide(slides, slideIndex, next), didUpdate: true };
|
|
3172
3223
|
}
|
|
3173
|
-
function addReplyToSlide(slides, slideIndex, parentId, text, authorName) {
|
|
3224
|
+
function addReplyToSlide(slides, slideIndex, parentId, text, authorName, mentions) {
|
|
3174
3225
|
const slide = slides[slideIndex];
|
|
3175
3226
|
if (!slide) {
|
|
3176
3227
|
return { slides, didAdd: false };
|
|
@@ -3179,7 +3230,15 @@ function addReplyToSlide(slides, slideIndex, parentId, text, authorName) {
|
|
|
3179
3230
|
if (!next) {
|
|
3180
3231
|
return { slides, didAdd: false };
|
|
3181
3232
|
}
|
|
3182
|
-
|
|
3233
|
+
const withMentions = mentions && mentions.length > 0 ? next.map(
|
|
3234
|
+
(comment) => comment.id === parentId && comment.replies && comment.replies.length > 0 ? {
|
|
3235
|
+
...comment,
|
|
3236
|
+
replies: comment.replies.map(
|
|
3237
|
+
(reply, index) => index === comment.replies.length - 1 ? { ...reply, mentions } : reply
|
|
3238
|
+
)
|
|
3239
|
+
} : comment
|
|
3240
|
+
) : next;
|
|
3241
|
+
return { slides: replaceCommentsOnSlide(slides, slideIndex, withMentions), didAdd: true };
|
|
3183
3242
|
}
|
|
3184
3243
|
function pruneSlideDrafts(drafts, slideIds) {
|
|
3185
3244
|
const next = {};
|
|
@@ -3194,6 +3253,95 @@ function pruneSlideDrafts(drafts, slideIds) {
|
|
|
3194
3253
|
return changed ? next : null;
|
|
3195
3254
|
}
|
|
3196
3255
|
|
|
3256
|
+
// src/viewer/hooks/useCommentReplyHandlers.ts
|
|
3257
|
+
function useCommentReplyHandlers(input) {
|
|
3258
|
+
const {
|
|
3259
|
+
slides,
|
|
3260
|
+
canEdit,
|
|
3261
|
+
userName,
|
|
3262
|
+
onUpdateSlides,
|
|
3263
|
+
onMarkDirty,
|
|
3264
|
+
replyDraftMentionsByCommentId,
|
|
3265
|
+
setReplyDraftMentions,
|
|
3266
|
+
clearReplyDraftMentions
|
|
3267
|
+
} = input;
|
|
3268
|
+
const [replyDraftByCommentId, setReplyDraftByCommentId] = useState({});
|
|
3269
|
+
const [replyingToCommentId, setReplyingToCommentId] = useState(null);
|
|
3270
|
+
const handleStartReply = useCallback((_slideIndex, commentId) => {
|
|
3271
|
+
setReplyingToCommentId(commentId);
|
|
3272
|
+
setReplyDraftByCommentId((prev) => ({ ...prev, [commentId]: "" }));
|
|
3273
|
+
}, []);
|
|
3274
|
+
const handleCancelReply = useCallback(() => {
|
|
3275
|
+
setReplyingToCommentId(null);
|
|
3276
|
+
}, []);
|
|
3277
|
+
const handleReplyDraftChange = useCallback(
|
|
3278
|
+
(commentId, draft, mentions) => {
|
|
3279
|
+
setReplyDraftByCommentId((prev) => ({ ...prev, [commentId]: draft }));
|
|
3280
|
+
if (mentions) {
|
|
3281
|
+
setReplyDraftMentions(commentId, mentions);
|
|
3282
|
+
}
|
|
3283
|
+
},
|
|
3284
|
+
[setReplyDraftMentions]
|
|
3285
|
+
);
|
|
3286
|
+
const handleSubmitReply = useCallback(
|
|
3287
|
+
(slideIndex, commentId) => {
|
|
3288
|
+
if (!canEdit) {
|
|
3289
|
+
return;
|
|
3290
|
+
}
|
|
3291
|
+
const slide = slides[slideIndex];
|
|
3292
|
+
if (!slide) {
|
|
3293
|
+
return;
|
|
3294
|
+
}
|
|
3295
|
+
const replyText = String(replyDraftByCommentId[commentId] || "").trim();
|
|
3296
|
+
if (replyText.length === 0) {
|
|
3297
|
+
return;
|
|
3298
|
+
}
|
|
3299
|
+
let didAdd = false;
|
|
3300
|
+
onUpdateSlides((prev) => {
|
|
3301
|
+
const result = addReplyToSlide(
|
|
3302
|
+
prev,
|
|
3303
|
+
slideIndex,
|
|
3304
|
+
commentId,
|
|
3305
|
+
replyText,
|
|
3306
|
+
userName,
|
|
3307
|
+
replyDraftMentionsByCommentId[commentId]
|
|
3308
|
+
);
|
|
3309
|
+
didAdd = result.didAdd;
|
|
3310
|
+
return result.slides;
|
|
3311
|
+
});
|
|
3312
|
+
if (!didAdd) {
|
|
3313
|
+
return;
|
|
3314
|
+
}
|
|
3315
|
+
setReplyingToCommentId(null);
|
|
3316
|
+
setReplyDraftByCommentId((prev) => {
|
|
3317
|
+
const next = { ...prev };
|
|
3318
|
+
delete next[commentId];
|
|
3319
|
+
return next;
|
|
3320
|
+
});
|
|
3321
|
+
clearReplyDraftMentions(commentId);
|
|
3322
|
+
onMarkDirty();
|
|
3323
|
+
},
|
|
3324
|
+
[
|
|
3325
|
+
canEdit,
|
|
3326
|
+
onMarkDirty,
|
|
3327
|
+
onUpdateSlides,
|
|
3328
|
+
replyDraftByCommentId,
|
|
3329
|
+
replyDraftMentionsByCommentId,
|
|
3330
|
+
clearReplyDraftMentions,
|
|
3331
|
+
slides,
|
|
3332
|
+
userName
|
|
3333
|
+
]
|
|
3334
|
+
);
|
|
3335
|
+
return {
|
|
3336
|
+
replyingToCommentId,
|
|
3337
|
+
replyDraftByCommentId,
|
|
3338
|
+
handleStartReply,
|
|
3339
|
+
handleCancelReply,
|
|
3340
|
+
handleReplyDraftChange,
|
|
3341
|
+
handleSubmitReply
|
|
3342
|
+
};
|
|
3343
|
+
}
|
|
3344
|
+
|
|
3197
3345
|
// src/viewer/hooks/useComments.ts
|
|
3198
3346
|
function useComments({
|
|
3199
3347
|
slides,
|
|
@@ -3206,11 +3354,33 @@ function useComments({
|
|
|
3206
3354
|
const [commentDraftBySlideId, setCommentDraftBySlideId] = useState({});
|
|
3207
3355
|
const [editingCommentIdBySlideId, setEditingCommentIdBySlideId] = useState({});
|
|
3208
3356
|
const [commentEditDraftByCommentId, setCommentEditDraftByCommentId] = useState({});
|
|
3209
|
-
const
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3357
|
+
const {
|
|
3358
|
+
commentDraftMentionsBySlideId,
|
|
3359
|
+
replyDraftMentionsByCommentId,
|
|
3360
|
+
setCommentDraftMentions,
|
|
3361
|
+
setReplyDraftMentions,
|
|
3362
|
+
clearCommentDraftMentions,
|
|
3363
|
+
clearReplyDraftMentions
|
|
3364
|
+
} = useCommentMentionDrafts();
|
|
3365
|
+
const reply = useCommentReplyHandlers({
|
|
3366
|
+
slides,
|
|
3367
|
+
canEdit,
|
|
3368
|
+
userName,
|
|
3369
|
+
onUpdateSlides,
|
|
3370
|
+
onMarkDirty,
|
|
3371
|
+
replyDraftMentionsByCommentId,
|
|
3372
|
+
setReplyDraftMentions,
|
|
3373
|
+
clearReplyDraftMentions
|
|
3374
|
+
});
|
|
3375
|
+
const handleCommentDraftChange = useCallback(
|
|
3376
|
+
(slideId, draft, mentions) => {
|
|
3377
|
+
setCommentDraftBySlideId((prev) => ({ ...prev, [slideId]: draft }));
|
|
3378
|
+
if (mentions) {
|
|
3379
|
+
setCommentDraftMentions(slideId, mentions);
|
|
3380
|
+
}
|
|
3381
|
+
},
|
|
3382
|
+
[setCommentDraftMentions]
|
|
3383
|
+
);
|
|
3214
3384
|
const handleSetCommentEditDraft = useCallback((commentId, draft) => {
|
|
3215
3385
|
setCommentEditDraftByCommentId((prev) => ({
|
|
3216
3386
|
...prev,
|
|
@@ -3237,7 +3407,8 @@ function useComments({
|
|
|
3237
3407
|
slideIndex,
|
|
3238
3408
|
draft,
|
|
3239
3409
|
userName,
|
|
3240
|
-
selectedElementId ?? void 0
|
|
3410
|
+
selectedElementId ?? void 0,
|
|
3411
|
+
commentDraftMentionsBySlideId[slide.id]
|
|
3241
3412
|
);
|
|
3242
3413
|
didAdd = result.didAdd;
|
|
3243
3414
|
return result.slides;
|
|
@@ -3249,11 +3420,14 @@ function useComments({
|
|
|
3249
3420
|
...prev,
|
|
3250
3421
|
[slide.id]: ""
|
|
3251
3422
|
}));
|
|
3423
|
+
clearCommentDraftMentions(slide.id);
|
|
3252
3424
|
onMarkDirty();
|
|
3253
3425
|
},
|
|
3254
3426
|
[
|
|
3255
3427
|
canEdit,
|
|
3256
3428
|
commentDraftBySlideId,
|
|
3429
|
+
commentDraftMentionsBySlideId,
|
|
3430
|
+
clearCommentDraftMentions,
|
|
3257
3431
|
onMarkDirty,
|
|
3258
3432
|
onUpdateSlides,
|
|
3259
3433
|
selectedElementId,
|
|
@@ -3365,48 +3539,6 @@ function useComments({
|
|
|
3365
3539
|
},
|
|
3366
3540
|
[canEdit, onMarkDirty, onUpdateSlides, slides]
|
|
3367
3541
|
);
|
|
3368
|
-
const handleStartReply = useCallback((_slideIndex, commentId) => {
|
|
3369
|
-
setReplyingToCommentId(commentId);
|
|
3370
|
-
setReplyDraftByCommentId((prev) => ({ ...prev, [commentId]: "" }));
|
|
3371
|
-
}, []);
|
|
3372
|
-
const handleCancelReply = useCallback(() => {
|
|
3373
|
-
setReplyingToCommentId(null);
|
|
3374
|
-
}, []);
|
|
3375
|
-
const handleReplyDraftChange = useCallback((commentId, draft) => {
|
|
3376
|
-
setReplyDraftByCommentId((prev) => ({ ...prev, [commentId]: draft }));
|
|
3377
|
-
}, []);
|
|
3378
|
-
const handleSubmitReply = useCallback(
|
|
3379
|
-
(slideIndex, commentId) => {
|
|
3380
|
-
if (!canEdit) {
|
|
3381
|
-
return;
|
|
3382
|
-
}
|
|
3383
|
-
const slide = slides[slideIndex];
|
|
3384
|
-
if (!slide) {
|
|
3385
|
-
return;
|
|
3386
|
-
}
|
|
3387
|
-
const replyText = String(replyDraftByCommentId[commentId] || "").trim();
|
|
3388
|
-
if (replyText.length === 0) {
|
|
3389
|
-
return;
|
|
3390
|
-
}
|
|
3391
|
-
let didAdd = false;
|
|
3392
|
-
onUpdateSlides((prev) => {
|
|
3393
|
-
const result = addReplyToSlide(prev, slideIndex, commentId, replyText, userName);
|
|
3394
|
-
didAdd = result.didAdd;
|
|
3395
|
-
return result.slides;
|
|
3396
|
-
});
|
|
3397
|
-
if (!didAdd) {
|
|
3398
|
-
return;
|
|
3399
|
-
}
|
|
3400
|
-
setReplyingToCommentId(null);
|
|
3401
|
-
setReplyDraftByCommentId((prev) => {
|
|
3402
|
-
const next = { ...prev };
|
|
3403
|
-
delete next[commentId];
|
|
3404
|
-
return next;
|
|
3405
|
-
});
|
|
3406
|
-
onMarkDirty();
|
|
3407
|
-
},
|
|
3408
|
-
[canEdit, onMarkDirty, onUpdateSlides, replyDraftByCommentId, slides, userName]
|
|
3409
|
-
);
|
|
3410
3542
|
useEffect(() => {
|
|
3411
3543
|
const slideIds = new Set(slides.map((slide) => slide.id));
|
|
3412
3544
|
setCommentDraftBySlideId((prev) => {
|
|
@@ -3418,8 +3550,8 @@ function useComments({
|
|
|
3418
3550
|
commentDraftBySlideId,
|
|
3419
3551
|
editingCommentIdBySlideId,
|
|
3420
3552
|
commentEditDraftByCommentId,
|
|
3421
|
-
|
|
3422
|
-
|
|
3553
|
+
commentDraftMentionsBySlideId,
|
|
3554
|
+
replyDraftMentionsByCommentId,
|
|
3423
3555
|
handleCommentDraftChange,
|
|
3424
3556
|
handleAddSlideComment,
|
|
3425
3557
|
handleDeleteSlideComment,
|
|
@@ -3428,10 +3560,7 @@ function useComments({
|
|
|
3428
3560
|
handleSaveCommentEdit,
|
|
3429
3561
|
handleSetCommentEditDraft,
|
|
3430
3562
|
handleToggleCommentResolved,
|
|
3431
|
-
|
|
3432
|
-
handleCancelReply,
|
|
3433
|
-
handleReplyDraftChange,
|
|
3434
|
-
handleSubmitReply
|
|
3563
|
+
...reply
|
|
3435
3564
|
};
|
|
3436
3565
|
}
|
|
3437
3566
|
function buildElementLookup(templateElements, slideElements) {
|
|
@@ -3596,6 +3725,8 @@ function useViewerCoreState(_input) {
|
|
|
3596
3725
|
const [headerFooter, setHeaderFooter] = useState({});
|
|
3597
3726
|
const [layoutOptions, setLayoutOptions] = useState([]);
|
|
3598
3727
|
const [slideMasters, setSlideMasters] = useState([]);
|
|
3728
|
+
const [modernCommentAuthors, setModernCommentAuthors] = useState([]);
|
|
3729
|
+
const [recentColors, setRecentColors] = useState([]);
|
|
3599
3730
|
const [theme, setTheme] = useState();
|
|
3600
3731
|
const [tableStyleMap, setTableStyleMap] = useState();
|
|
3601
3732
|
const [themeOptions, setThemeOptions] = useState([]);
|
|
@@ -3689,6 +3820,10 @@ function useViewerCoreState(_input) {
|
|
|
3689
3820
|
setLayoutOptions,
|
|
3690
3821
|
slideMasters,
|
|
3691
3822
|
setSlideMasters,
|
|
3823
|
+
modernCommentAuthors,
|
|
3824
|
+
setModernCommentAuthors,
|
|
3825
|
+
recentColors,
|
|
3826
|
+
setRecentColors,
|
|
3692
3827
|
theme,
|
|
3693
3828
|
setTheme,
|
|
3694
3829
|
tableStyleMap,
|
|
@@ -3873,6 +4008,8 @@ function useLoadContent({
|
|
|
3873
4008
|
setHeaderFooter,
|
|
3874
4009
|
setLayoutOptions,
|
|
3875
4010
|
setSlideMasters,
|
|
4011
|
+
setModernCommentAuthors,
|
|
4012
|
+
setRecentColors,
|
|
3876
4013
|
setTheme,
|
|
3877
4014
|
setTableStyleMap,
|
|
3878
4015
|
setThemeOptions,
|
|
@@ -3894,6 +4031,8 @@ function useLoadContent({
|
|
|
3894
4031
|
setHasDigitalSignatures,
|
|
3895
4032
|
setDigitalSignatureCount,
|
|
3896
4033
|
setGuides,
|
|
4034
|
+
setReadOnlyRecommendation,
|
|
4035
|
+
setCompatToasts,
|
|
3897
4036
|
setLoading,
|
|
3898
4037
|
setError,
|
|
3899
4038
|
setIsDirty,
|
|
@@ -3992,93 +4131,19 @@ function useLoadContent({
|
|
|
3992
4131
|
}
|
|
3993
4132
|
})
|
|
3994
4133
|
);
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
continue;
|
|
4000
|
-
}
|
|
4001
|
-
const id = ref.element.id;
|
|
4002
|
-
const existing = elementPatches.get(id) ?? {};
|
|
4003
|
-
existing[ref.field] = url;
|
|
4004
|
-
elementPatches.set(id, existing);
|
|
4005
|
-
}
|
|
4006
|
-
if (elementPatches.size > 0) {
|
|
4007
|
-
const patchElements = (elements) => {
|
|
4008
|
-
let mutated = false;
|
|
4009
|
-
const next = elements.map((el) => {
|
|
4010
|
-
let updated = el;
|
|
4011
|
-
const patch = elementPatches.get(el.id);
|
|
4012
|
-
if (patch) {
|
|
4013
|
-
updated = { ...el, ...patch };
|
|
4014
|
-
}
|
|
4015
|
-
if (updated.type === "group" && updated.children?.length) {
|
|
4016
|
-
const newChildren = patchElements(updated.children);
|
|
4017
|
-
if (newChildren !== updated.children) {
|
|
4018
|
-
updated = { ...updated, children: newChildren };
|
|
4019
|
-
}
|
|
4020
|
-
}
|
|
4021
|
-
if (updated !== el) {
|
|
4022
|
-
mutated = true;
|
|
4023
|
-
}
|
|
4024
|
-
return updated;
|
|
4025
|
-
});
|
|
4026
|
-
return mutated ? next : elements;
|
|
4027
|
-
};
|
|
4028
|
-
nextSlides = parsed.slides.map((s) => {
|
|
4029
|
-
const newElements = patchElements(s.elements);
|
|
4030
|
-
return newElements === s.elements ? s : { ...s, elements: newElements };
|
|
4031
|
-
});
|
|
4032
|
-
}
|
|
4033
|
-
}
|
|
4034
|
-
const { paths: tableImagePaths, refs: tableImageRefs } = collectTableCellImagePaths(nextSlides);
|
|
4035
|
-
if (tableImagePaths.size > 0) {
|
|
4036
|
-
const resolvedTableMap = /* @__PURE__ */ new Map();
|
|
4037
|
-
await Promise.all(
|
|
4038
|
-
Array.from(tableImagePaths).map(async (path) => {
|
|
4039
|
-
try {
|
|
4040
|
-
const url = await handler.getImageData(path);
|
|
4041
|
-
if (url) {
|
|
4042
|
-
resolvedTableMap.set(path, url);
|
|
4043
|
-
}
|
|
4044
|
-
} catch {
|
|
4045
|
-
}
|
|
4046
|
-
})
|
|
4047
|
-
);
|
|
4048
|
-
if (resolvedTableMap.size > 0) {
|
|
4049
|
-
nextSlides = nextSlides.map((s) => {
|
|
4050
|
-
const newElements = applyTableCellImagePatches(
|
|
4051
|
-
s.elements,
|
|
4052
|
-
resolvedTableMap,
|
|
4053
|
-
tableImageRefs
|
|
4054
|
-
);
|
|
4055
|
-
return newElements === s.elements ? s : { ...s, elements: newElements };
|
|
4056
|
-
});
|
|
4057
|
-
}
|
|
4058
|
-
}
|
|
4059
|
-
let nextTableStyleMap = parsed.tableStyleMap;
|
|
4060
|
-
const { paths: tableStyleImagePaths, refs: tableStyleImageRefs } = collectTableStyleImagePaths(nextTableStyleMap);
|
|
4061
|
-
if (tableStyleImagePaths.size > 0) {
|
|
4062
|
-
const resolvedStyleMap = /* @__PURE__ */ new Map();
|
|
4063
|
-
await Promise.all(
|
|
4064
|
-
Array.from(tableStyleImagePaths).map(async (path) => {
|
|
4065
|
-
try {
|
|
4066
|
-
const url = await handler.getImageData(path);
|
|
4067
|
-
if (url) {
|
|
4068
|
-
resolvedStyleMap.set(path, url);
|
|
4069
|
-
}
|
|
4070
|
-
} catch {
|
|
4071
|
-
}
|
|
4072
|
-
})
|
|
4073
|
-
);
|
|
4074
|
-
if (resolvedStyleMap.size > 0 && nextTableStyleMap) {
|
|
4075
|
-
nextTableStyleMap = applyTableStyleImagePatches(
|
|
4076
|
-
nextTableStyleMap,
|
|
4077
|
-
resolvedStyleMap,
|
|
4078
|
-
tableStyleImageRefs
|
|
4079
|
-
);
|
|
4080
|
-
}
|
|
4134
|
+
nextSlides = parsed.slides.map((s) => {
|
|
4135
|
+
const newElements = applyImagePathPatches(s.elements, resolvedMap, imageRefs);
|
|
4136
|
+
return newElements === s.elements ? s : { ...s, elements: newElements };
|
|
4137
|
+
});
|
|
4081
4138
|
}
|
|
4139
|
+
nextSlides = await resolveTableCellImageUrls(
|
|
4140
|
+
nextSlides,
|
|
4141
|
+
(path) => handler.getImageData(path)
|
|
4142
|
+
);
|
|
4143
|
+
const nextTableStyleMap = await resolveTableStyleImageUrls(
|
|
4144
|
+
parsed.tableStyleMap,
|
|
4145
|
+
(path) => handler.getImageData(path)
|
|
4146
|
+
);
|
|
4082
4147
|
handlerRef.current = handler;
|
|
4083
4148
|
const partition = partitionTemplateElements(nextSlides);
|
|
4084
4149
|
setSlides(partition.slides);
|
|
@@ -4097,6 +4162,8 @@ function useLoadContent({
|
|
|
4097
4162
|
setHeaderFooter(parsed.headerFooter ?? {});
|
|
4098
4163
|
setLayoutOptions(parsed.layoutOptions ?? []);
|
|
4099
4164
|
setSlideMasters(parsed.slideMasters ?? []);
|
|
4165
|
+
setModernCommentAuthors(parsed.modernCommentAuthors ?? []);
|
|
4166
|
+
setRecentColors(seedRecentColors({ mruColors: parsed.mruColors }));
|
|
4100
4167
|
setTheme(parsed.theme);
|
|
4101
4168
|
setTableStyleMap(nextTableStyleMap);
|
|
4102
4169
|
setThemeOptions(parsed.themeOptions ?? []);
|
|
@@ -4126,6 +4193,13 @@ function useLoadContent({
|
|
|
4126
4193
|
setHasDigitalSignatures(parsed.hasDigitalSignatures === true);
|
|
4127
4194
|
setDigitalSignatureCount(parsed.digitalSignatureCount ?? 0);
|
|
4128
4195
|
setGuides(buildInitialGuides(parsed.presentationGuides, parsed.slides[0]?.guides));
|
|
4196
|
+
setReadOnlyRecommendation(readOnlyRecommendation(parsed));
|
|
4197
|
+
setCompatToasts(
|
|
4198
|
+
compatibilityWarningToasts([
|
|
4199
|
+
...parsed.warnings ?? [],
|
|
4200
|
+
...parsed.slides.flatMap((slide) => slide.warnings ?? [])
|
|
4201
|
+
])
|
|
4202
|
+
);
|
|
4129
4203
|
setActiveSlideIndex(0);
|
|
4130
4204
|
clearSelection();
|
|
4131
4205
|
setIsDirty(false);
|
|
@@ -4312,19 +4386,7 @@ function useElementOperations(input) {
|
|
|
4312
4386
|
}));
|
|
4313
4387
|
}
|
|
4314
4388
|
} else {
|
|
4315
|
-
setSlides(
|
|
4316
|
-
(prev) => prev.map(
|
|
4317
|
-
(s, i) => i !== activeSlideIndex ? s : {
|
|
4318
|
-
...s,
|
|
4319
|
-
elements: s.elements.map(
|
|
4320
|
-
(el) => el.id === elementId ? {
|
|
4321
|
-
...el,
|
|
4322
|
-
...updates
|
|
4323
|
-
} : el
|
|
4324
|
-
)
|
|
4325
|
-
}
|
|
4326
|
-
)
|
|
4327
|
-
);
|
|
4389
|
+
setSlides((prev) => updateElement(prev, activeSlideIndex, elementId, updates));
|
|
4328
4390
|
}
|
|
4329
4391
|
history.markDirty();
|
|
4330
4392
|
},
|
|
@@ -4554,16 +4616,49 @@ function useSectionOperations(input) {
|
|
|
4554
4616
|
};
|
|
4555
4617
|
}
|
|
4556
4618
|
|
|
4619
|
+
// src/viewer/utils/selection-handle-overlay.ts
|
|
4620
|
+
var VIEWPORT_SELECTOR = "[data-pptx-viewport]";
|
|
4621
|
+
function findSelectionHandleHost(elementNode, elementId) {
|
|
4622
|
+
const scope = elementNode.closest(VIEWPORT_SELECTOR) ?? elementNode.parentElement;
|
|
4623
|
+
if (!scope) {
|
|
4624
|
+
return null;
|
|
4625
|
+
}
|
|
4626
|
+
for (const candidate of scope.querySelectorAll("[data-pptx-handle-for]")) {
|
|
4627
|
+
if (candidate.getAttribute("data-pptx-handle-for") === elementId) {
|
|
4628
|
+
return candidate;
|
|
4629
|
+
}
|
|
4630
|
+
}
|
|
4631
|
+
return null;
|
|
4632
|
+
}
|
|
4633
|
+
function syncSelectionHandleOverlay(elementNode, elementId, geometry) {
|
|
4634
|
+
const host = findSelectionHandleHost(elementNode, elementId);
|
|
4635
|
+
if (!host) {
|
|
4636
|
+
return;
|
|
4637
|
+
}
|
|
4638
|
+
if (geometry.x !== void 0) {
|
|
4639
|
+
host.style.left = `${geometry.x}px`;
|
|
4640
|
+
}
|
|
4641
|
+
if (geometry.y !== void 0) {
|
|
4642
|
+
host.style.top = `${geometry.y}px`;
|
|
4643
|
+
}
|
|
4644
|
+
if (geometry.width !== void 0) {
|
|
4645
|
+
host.style.width = `${geometry.width}px`;
|
|
4646
|
+
}
|
|
4647
|
+
if (geometry.height !== void 0) {
|
|
4648
|
+
host.style.height = `${geometry.height}px`;
|
|
4649
|
+
}
|
|
4650
|
+
if (geometry.transform !== void 0) {
|
|
4651
|
+
host.style.transform = geometry.transform;
|
|
4652
|
+
}
|
|
4653
|
+
}
|
|
4654
|
+
|
|
4557
4655
|
// src/viewer/hooks/pointer-move-handlers.ts
|
|
4558
|
-
function computeResizeGeometry(handle, startX, startY, startWidth, startHeight, dx, dy, snapToGrid, gridSpacingPx) {
|
|
4559
|
-
const
|
|
4560
|
-
|
|
4561
|
-
|
|
4562
|
-
|
|
4563
|
-
|
|
4564
|
-
1,
|
|
4565
|
-
{ minSize: MIN_ELEMENT_SIZE }
|
|
4566
|
-
);
|
|
4656
|
+
function computeResizeGeometry(handle, startX, startY, startWidth, startHeight, dx, dy, snapToGrid, gridSpacingPx, lockAspect = false) {
|
|
4657
|
+
const startBox = { x: startX, y: startY, width: startWidth, height: startHeight };
|
|
4658
|
+
let resized = applyResize(startBox, handle, dx, dy, 1, { minSize: MIN_ELEMENT_SIZE });
|
|
4659
|
+
if (lockAspect) {
|
|
4660
|
+
resized = lockResizeAspect(resized, startBox, handle, MIN_ELEMENT_SIZE);
|
|
4661
|
+
}
|
|
4567
4662
|
const box = { x: resized.x, y: resized.y, width: resized.width, height: resized.height };
|
|
4568
4663
|
if (!snapToGrid) {
|
|
4569
4664
|
return box;
|
|
@@ -4713,8 +4808,11 @@ function processDragMove(e, drag, editorScale, snapToGrid, snapToShape, gridSpac
|
|
|
4713
4808
|
for (const [id, domEl] of drag.domEls) {
|
|
4714
4809
|
const start = drag.startPositionsById[id];
|
|
4715
4810
|
if (start) {
|
|
4716
|
-
|
|
4717
|
-
|
|
4811
|
+
const x = start.x + appliedDx;
|
|
4812
|
+
const y = start.y + appliedDy;
|
|
4813
|
+
domEl.style.left = `${x}px`;
|
|
4814
|
+
domEl.style.top = `${y}px`;
|
|
4815
|
+
syncSelectionHandleOverlay(domEl, id, { x, y });
|
|
4718
4816
|
}
|
|
4719
4817
|
}
|
|
4720
4818
|
if (live) {
|
|
@@ -4745,24 +4843,28 @@ function processResizeMove(e, rs, editorScale, snapToGrid, gridSpacingPx, live)
|
|
|
4745
4843
|
dx,
|
|
4746
4844
|
dy,
|
|
4747
4845
|
snapToGrid,
|
|
4748
|
-
gridSpacingPx
|
|
4846
|
+
gridSpacingPx,
|
|
4847
|
+
e.shiftKey
|
|
4749
4848
|
);
|
|
4750
4849
|
rs.lastX = geo.x;
|
|
4751
4850
|
rs.lastY = geo.y;
|
|
4752
4851
|
rs.lastWidth = geo.width;
|
|
4753
4852
|
rs.lastHeight = geo.height;
|
|
4853
|
+
const width = Math.max(geo.width, MIN_ELEMENT_SIZE);
|
|
4854
|
+
const height = Math.max(geo.height, MIN_ELEMENT_SIZE);
|
|
4754
4855
|
if (rs.domEl) {
|
|
4755
4856
|
rs.domEl.style.left = `${geo.x}px`;
|
|
4756
4857
|
rs.domEl.style.top = `${geo.y}px`;
|
|
4757
|
-
rs.domEl.style.width = `${
|
|
4758
|
-
rs.domEl.style.height = `${
|
|
4858
|
+
rs.domEl.style.width = `${width}px`;
|
|
4859
|
+
rs.domEl.style.height = `${height}px`;
|
|
4860
|
+
syncSelectionHandleOverlay(rs.domEl, rs.elementId, { x: geo.x, y: geo.y, width, height });
|
|
4759
4861
|
}
|
|
4760
4862
|
if (live) {
|
|
4761
4863
|
publishLiveGeometry(live.patcher, live.slideId, rs.elementId, {
|
|
4762
4864
|
x: geo.x,
|
|
4763
4865
|
y: geo.y,
|
|
4764
|
-
width
|
|
4765
|
-
height
|
|
4866
|
+
width,
|
|
4867
|
+
height
|
|
4766
4868
|
});
|
|
4767
4869
|
}
|
|
4768
4870
|
}
|
|
@@ -7721,7 +7823,7 @@ function usePrintHandlers(input) {
|
|
|
7721
7823
|
printWindow,
|
|
7722
7824
|
buildPrintHtmlDocument({
|
|
7723
7825
|
title: `Handout ${spp} per page`,
|
|
7724
|
-
bodyHtml: buildHandoutsHtml(slideImages, slideIndices, spp),
|
|
7826
|
+
bodyHtml: buildHandoutsHtml(slideImages, slideIndices, spp, pptxData?.handoutMaster),
|
|
7725
7827
|
orientation: "portrait",
|
|
7726
7828
|
colorFilter,
|
|
7727
7829
|
frameSlides: settings.frameSlides,
|
|
@@ -8378,9 +8480,10 @@ function useViewerDialogs(input) {
|
|
|
8378
8480
|
function computeGridSpacingPx2(documentGridSpacing) {
|
|
8379
8481
|
return computeGridSpacingPx(documentGridSpacing, GRID_SIZE);
|
|
8380
8482
|
}
|
|
8381
|
-
function computeVisibleSlideIndexes(slides, activeCustomShowId, customShows) {
|
|
8483
|
+
function computeVisibleSlideIndexes(slides, activeCustomShowId, customShows, presentationProperties) {
|
|
8382
8484
|
const activeShow = activeCustomShowId ? customShows.find((show) => show.id === activeCustomShowId) : void 0;
|
|
8383
|
-
|
|
8485
|
+
const authoredRange = resolveAuthoredSlideRange(presentationProperties, slides.length);
|
|
8486
|
+
return resolveShowSlideIndexes(slides, activeShow, authoredRange);
|
|
8384
8487
|
}
|
|
8385
8488
|
function computeSlideSectionGroups(slides, sections) {
|
|
8386
8489
|
return groupSlidesBySection(sections, slides).map((group) => ({
|
|
@@ -8409,6 +8512,7 @@ function useDerivedSlideState(input) {
|
|
|
8409
8512
|
sections,
|
|
8410
8513
|
customShows,
|
|
8411
8514
|
activeCustomShowId,
|
|
8515
|
+
presentationProperties,
|
|
8412
8516
|
mode,
|
|
8413
8517
|
activeLayout,
|
|
8414
8518
|
activeMaster,
|
|
@@ -8419,8 +8523,12 @@ function useDerivedSlideState(input) {
|
|
|
8419
8523
|
[documentGridSpacing]
|
|
8420
8524
|
);
|
|
8421
8525
|
const visibleSlideIndexes = useMemo(
|
|
8422
|
-
() => computeVisibleSlideIndexes(slides, activeCustomShowId, customShows),
|
|
8423
|
-
[slides, activeCustomShowId, customShows]
|
|
8526
|
+
() => computeVisibleSlideIndexes(slides, activeCustomShowId, customShows, presentationProperties),
|
|
8527
|
+
[slides, activeCustomShowId, customShows, presentationProperties]
|
|
8528
|
+
);
|
|
8529
|
+
const authoredRange = useMemo(
|
|
8530
|
+
() => resolveAuthoredSlideRange(presentationProperties, slides.length),
|
|
8531
|
+
[presentationProperties, slides.length]
|
|
8424
8532
|
);
|
|
8425
8533
|
const slideSectionGroups = useMemo(
|
|
8426
8534
|
() => computeSlideSectionGroups(slides, sections).map((group) => {
|
|
@@ -8442,7 +8550,8 @@ function useDerivedSlideState(input) {
|
|
|
8442
8550
|
gridSpacingPx,
|
|
8443
8551
|
visibleSlideIndexes,
|
|
8444
8552
|
slideSectionGroups,
|
|
8445
|
-
masterPseudoSlide
|
|
8553
|
+
masterPseudoSlide,
|
|
8554
|
+
authoredRange
|
|
8446
8555
|
};
|
|
8447
8556
|
}
|
|
8448
8557
|
function useAnnotationHandlers(input) {
|
|
@@ -8580,6 +8689,7 @@ function useSerialize(input) {
|
|
|
8580
8689
|
guides,
|
|
8581
8690
|
headerFooter,
|
|
8582
8691
|
presentationProperties,
|
|
8692
|
+
viewProperties,
|
|
8583
8693
|
customShows,
|
|
8584
8694
|
sections,
|
|
8585
8695
|
coreProperties,
|
|
@@ -8641,6 +8751,7 @@ function useSerialize(input) {
|
|
|
8641
8751
|
slideSize: resolveSlideSizeSelection({ current: slideSizeEmu, canvas: canvasSize }).size,
|
|
8642
8752
|
headerFooter,
|
|
8643
8753
|
presentationProperties,
|
|
8754
|
+
viewProperties,
|
|
8644
8755
|
customShows: customShows.length > 0 ? customShows : void 0,
|
|
8645
8756
|
sections: sections.length > 0 ? sections : void 0,
|
|
8646
8757
|
coreProperties,
|
|
@@ -8660,6 +8771,7 @@ function useSerialize(input) {
|
|
|
8660
8771
|
slideSizeEmu,
|
|
8661
8772
|
headerFooter,
|
|
8662
8773
|
presentationProperties,
|
|
8774
|
+
viewProperties,
|
|
8663
8775
|
customShows,
|
|
8664
8776
|
sections,
|
|
8665
8777
|
coreProperties,
|
|
@@ -8730,6 +8842,7 @@ function usePresentationSetup(input) {
|
|
|
8730
8842
|
const {
|
|
8731
8843
|
mode,
|
|
8732
8844
|
slides,
|
|
8845
|
+
templateElementsBySlideId,
|
|
8733
8846
|
visibleSlideIndexes,
|
|
8734
8847
|
activeSlideIndex,
|
|
8735
8848
|
containerRef,
|
|
@@ -8743,7 +8856,10 @@ function usePresentationSetup(input) {
|
|
|
8743
8856
|
endWithBlackSlide = true,
|
|
8744
8857
|
promptKeepInkAnnotations = true,
|
|
8745
8858
|
popupToolbarEnabled = true,
|
|
8746
|
-
onToggleSubtitles
|
|
8859
|
+
onToggleSubtitles,
|
|
8860
|
+
customShows = [],
|
|
8861
|
+
activeCustomShowId = null,
|
|
8862
|
+
onSetActiveCustomShowId
|
|
8747
8863
|
} = input;
|
|
8748
8864
|
const actionSoundHandlerRef = useRef(null);
|
|
8749
8865
|
const exitModeHandlerRef = useRef(null);
|
|
@@ -8755,6 +8871,7 @@ function usePresentationSetup(input) {
|
|
|
8755
8871
|
const presentation = usePresentationMode({
|
|
8756
8872
|
mode,
|
|
8757
8873
|
slides,
|
|
8874
|
+
templateElementsBySlideId,
|
|
8758
8875
|
visibleSlideIndexes,
|
|
8759
8876
|
activeSlideIndex,
|
|
8760
8877
|
containerRef,
|
|
@@ -8832,7 +8949,10 @@ function usePresentationSetup(input) {
|
|
|
8832
8949
|
loopContinuously: shouldLoopContinuously(presentationProperties),
|
|
8833
8950
|
showWithAnimation: presentationProperties.showWithAnimation,
|
|
8834
8951
|
useTimings: presentationProperties.advanceMode !== "manual",
|
|
8835
|
-
endWithBlackSlide
|
|
8952
|
+
endWithBlackSlide,
|
|
8953
|
+
customShows,
|
|
8954
|
+
activeCustomShowId,
|
|
8955
|
+
onSetActiveCustomShowId
|
|
8836
8956
|
});
|
|
8837
8957
|
return {
|
|
8838
8958
|
presentation,
|
|
@@ -9316,7 +9436,9 @@ function useContentLifecycle(input) {
|
|
|
9316
9436
|
setIsEncryptedDialogOpen,
|
|
9317
9437
|
password,
|
|
9318
9438
|
onContentApplied,
|
|
9319
|
-
allowExternalImages
|
|
9439
|
+
allowExternalImages,
|
|
9440
|
+
setReadOnlyRecommendation,
|
|
9441
|
+
setCompatToasts
|
|
9320
9442
|
} = input;
|
|
9321
9443
|
const { handlerRef } = useLoadContent({
|
|
9322
9444
|
content,
|
|
@@ -9330,6 +9452,8 @@ function useContentLifecycle(input) {
|
|
|
9330
9452
|
setHeaderFooter: state.setHeaderFooter,
|
|
9331
9453
|
setLayoutOptions: state.setLayoutOptions,
|
|
9332
9454
|
setSlideMasters: state.setSlideMasters,
|
|
9455
|
+
setModernCommentAuthors: state.setModernCommentAuthors,
|
|
9456
|
+
setRecentColors: state.setRecentColors,
|
|
9333
9457
|
setTheme: state.setTheme,
|
|
9334
9458
|
setTableStyleMap: state.setTableStyleMap,
|
|
9335
9459
|
setThemeOptions: state.setThemeOptions,
|
|
@@ -9351,6 +9475,8 @@ function useContentLifecycle(input) {
|
|
|
9351
9475
|
setHasDigitalSignatures: state.setHasDigitalSignatures,
|
|
9352
9476
|
setDigitalSignatureCount: state.setDigitalSignatureCount,
|
|
9353
9477
|
setGuides: state.setGuides,
|
|
9478
|
+
setReadOnlyRecommendation,
|
|
9479
|
+
setCompatToasts,
|
|
9354
9480
|
setLoading: state.setLoading,
|
|
9355
9481
|
setError: state.setError,
|
|
9356
9482
|
setIsDirty: state.setIsDirty,
|
|
@@ -9371,6 +9497,7 @@ function useContentLifecycle(input) {
|
|
|
9371
9497
|
guides: state.guides,
|
|
9372
9498
|
headerFooter: state.headerFooter,
|
|
9373
9499
|
presentationProperties: state.presentationProperties,
|
|
9500
|
+
viewProperties: state.viewProperties,
|
|
9374
9501
|
customShows: state.customShows,
|
|
9375
9502
|
sections: state.sections,
|
|
9376
9503
|
coreProperties: state.coreProperties,
|
|
@@ -9426,6 +9553,16 @@ function useKeyboardShortcuts(input) {
|
|
|
9426
9553
|
inputRef.current = input;
|
|
9427
9554
|
const handleKeyDown = useCallback((e) => {
|
|
9428
9555
|
const current = inputRef.current;
|
|
9556
|
+
const startAction = mapSlideShowStartKey(e, { isPresenting: current.mode === "present" });
|
|
9557
|
+
if (startAction !== null) {
|
|
9558
|
+
e.preventDefault();
|
|
9559
|
+
if (startAction === "fromBeginning") {
|
|
9560
|
+
current.onStartShowFromBeginning();
|
|
9561
|
+
} else {
|
|
9562
|
+
current.onStartShowFromCurrent();
|
|
9563
|
+
}
|
|
9564
|
+
return;
|
|
9565
|
+
}
|
|
9429
9566
|
const { action, dx, dy } = mapEditorKey(e, {
|
|
9430
9567
|
canEdit: current.canEdit,
|
|
9431
9568
|
// The Slide Master view is an editing surface, not a viewing one.
|
|
@@ -9506,7 +9643,18 @@ function useKeyboardShortcuts(input) {
|
|
|
9506
9643
|
|
|
9507
9644
|
// src/viewer/hooks/useKeyboardShortcutWiring.ts
|
|
9508
9645
|
function useKeyboardShortcutWiring(input) {
|
|
9509
|
-
const {
|
|
9646
|
+
const {
|
|
9647
|
+
state,
|
|
9648
|
+
mode,
|
|
9649
|
+
canEdit,
|
|
9650
|
+
slides,
|
|
9651
|
+
activeSlide,
|
|
9652
|
+
ops,
|
|
9653
|
+
manipulation,
|
|
9654
|
+
history,
|
|
9655
|
+
onEnterPresentModeFromBeginning,
|
|
9656
|
+
onSetMode
|
|
9657
|
+
} = input;
|
|
9510
9658
|
useKeyboardShortcuts({
|
|
9511
9659
|
containerRef: state.containerRef,
|
|
9512
9660
|
mode,
|
|
@@ -9576,7 +9724,9 @@ function useKeyboardShortcutWiring(input) {
|
|
|
9576
9724
|
return;
|
|
9577
9725
|
}
|
|
9578
9726
|
state.setActiveSlideIndex((prev) => Math.min(slides.length - 1, prev + 1));
|
|
9579
|
-
}
|
|
9727
|
+
},
|
|
9728
|
+
onStartShowFromBeginning: onEnterPresentModeFromBeginning,
|
|
9729
|
+
onStartShowFromCurrent: () => onSetMode("present")
|
|
9580
9730
|
});
|
|
9581
9731
|
}
|
|
9582
9732
|
function useViewerIntegration(input) {
|
|
@@ -9596,6 +9746,8 @@ function useViewerIntegration(input) {
|
|
|
9596
9746
|
autosaveAllowed = true,
|
|
9597
9747
|
autosaveIntervalMs,
|
|
9598
9748
|
allowExternalImages,
|
|
9749
|
+
setReadOnlyRecommendation,
|
|
9750
|
+
setCompatToasts,
|
|
9599
9751
|
canEdit,
|
|
9600
9752
|
promptKeepInkAnnotations,
|
|
9601
9753
|
imageExportScale,
|
|
@@ -9664,7 +9816,9 @@ function useViewerIntegration(input) {
|
|
|
9664
9816
|
setIsEncryptedDialogOpen,
|
|
9665
9817
|
password: dialogs.presentationPassword ?? void 0,
|
|
9666
9818
|
onContentApplied: () => setLoadVersion((v) => v + 1),
|
|
9667
|
-
allowExternalImages
|
|
9819
|
+
allowExternalImages,
|
|
9820
|
+
setReadOnlyRecommendation,
|
|
9821
|
+
setCompatToasts
|
|
9668
9822
|
}
|
|
9669
9823
|
);
|
|
9670
9824
|
const { exportHandlers, printHandlers, themeHandlers, propertyHandlers } = useIOHandlers({
|
|
@@ -9899,7 +10053,9 @@ function useViewerIntegration(input) {
|
|
|
9899
10053
|
activeSlide,
|
|
9900
10054
|
ops: editorOps.ops,
|
|
9901
10055
|
manipulation: editorOps.manipulation,
|
|
9902
|
-
history
|
|
10056
|
+
history,
|
|
10057
|
+
onEnterPresentModeFromBeginning: presentation.enterPresentModeFromBeginning,
|
|
10058
|
+
onSetMode: handleSetMode
|
|
9903
10059
|
});
|
|
9904
10060
|
return {
|
|
9905
10061
|
exportHandlers,
|
|
@@ -10579,14 +10735,14 @@ function buildCanvasProps(input) {
|
|
|
10579
10735
|
}
|
|
10580
10736
|
safeOpenUrl(url);
|
|
10581
10737
|
};
|
|
10582
|
-
const handleActionClick = (
|
|
10738
|
+
const handleActionClick = (elementId, action) => {
|
|
10583
10739
|
if (mode === "present") {
|
|
10584
10740
|
const resolved = resolvePresentationAction(action, { slideCount: slides.length });
|
|
10585
10741
|
if (resolved.intent.kind === "openUrl") {
|
|
10586
10742
|
openExternalUrl(resolved.intent.url);
|
|
10587
10743
|
return;
|
|
10588
10744
|
}
|
|
10589
|
-
presentation.handlePresentationAction(action);
|
|
10745
|
+
presentation.handlePresentationAction(action, elementId);
|
|
10590
10746
|
} else if (action.url) {
|
|
10591
10747
|
openExternalUrl(action.url);
|
|
10592
10748
|
}
|
|
@@ -10795,7 +10951,8 @@ function buildToolbarProps(input) {
|
|
|
10795
10951
|
onOpenFile,
|
|
10796
10952
|
onOpenRecentFile,
|
|
10797
10953
|
fileName,
|
|
10798
|
-
hiddenActions
|
|
10954
|
+
hiddenActions,
|
|
10955
|
+
viewPreferencesSync
|
|
10799
10956
|
} = input;
|
|
10800
10957
|
const {
|
|
10801
10958
|
handleAddAnimation,
|
|
@@ -10879,9 +11036,9 @@ function buildToolbarProps(input) {
|
|
|
10879
11036
|
onSetSpellCheckEnabled: s.setSpellCheckEnabled,
|
|
10880
11037
|
onSetShowGrid: s.setShowGrid,
|
|
10881
11038
|
onSetShowRulers: s.setShowRulers,
|
|
10882
|
-
onSetShowGuides: s.setShowGuides,
|
|
10883
|
-
onSetSnapToGrid: s.setSnapToGrid,
|
|
10884
|
-
onSetSnapToShape: s.setSnapToShape,
|
|
11039
|
+
onSetShowGuides: viewPreferencesSync?.handleSetShowGuides ?? s.setShowGuides,
|
|
11040
|
+
onSetSnapToGrid: viewPreferencesSync?.handleSetSnapToGrid ?? s.setSnapToGrid,
|
|
11041
|
+
onSetSnapToShape: viewPreferencesSync?.handleSetSnapToShape ?? s.setSnapToShape,
|
|
10885
11042
|
onAddGuide: dialogs.handleAddGuide,
|
|
10886
11043
|
onAlignElements: manipulation.handleAlignElements,
|
|
10887
11044
|
onDistributeElements: manipulation.handleDistributeElements,
|
|
@@ -11068,6 +11225,7 @@ function useViewerBuildingBlocksCore(input) {
|
|
|
11068
11225
|
sections: state.sections,
|
|
11069
11226
|
customShows: state.customShows,
|
|
11070
11227
|
activeCustomShowId: state.activeCustomShowId,
|
|
11228
|
+
presentationProperties: state.presentationProperties,
|
|
11071
11229
|
mode,
|
|
11072
11230
|
activeLayout: state.activeLayout,
|
|
11073
11231
|
activeMaster: state.activeMaster,
|
|
@@ -11076,6 +11234,7 @@ function useViewerBuildingBlocksCore(input) {
|
|
|
11076
11234
|
const { presentation, annotations, actionSoundHandlerRef, setExitModeHandler } = usePresentationSetup({
|
|
11077
11235
|
mode,
|
|
11078
11236
|
slides,
|
|
11237
|
+
templateElementsBySlideId,
|
|
11079
11238
|
visibleSlideIndexes,
|
|
11080
11239
|
endWithBlackSlide: viewerOptions.advanced.slideShowEndWithBlackSlide,
|
|
11081
11240
|
// File > Options > Advanced > "Prompt to keep ink annotations when
|
|
@@ -11120,6 +11279,111 @@ function useViewerBuildingBlocksCore(input) {
|
|
|
11120
11279
|
viewerOptions
|
|
11121
11280
|
};
|
|
11122
11281
|
}
|
|
11282
|
+
function useCompatibilityToastsState() {
|
|
11283
|
+
const [toasts, setToasts] = useState([]);
|
|
11284
|
+
const dismiss = useCallback((id) => {
|
|
11285
|
+
setToasts((prev) => prev.filter((toast) => toast.id !== id));
|
|
11286
|
+
}, []);
|
|
11287
|
+
const dismissAll = useCallback(() => {
|
|
11288
|
+
setToasts([]);
|
|
11289
|
+
}, []);
|
|
11290
|
+
return { toasts, setToasts, dismiss, dismissAll };
|
|
11291
|
+
}
|
|
11292
|
+
function useReadOnlyRecommendationState(content) {
|
|
11293
|
+
const [recommendation, setRecommendation] = useState(
|
|
11294
|
+
() => readOnlyRecommendation(void 0)
|
|
11295
|
+
);
|
|
11296
|
+
const [bannerHidden, setBannerHidden] = useState(false);
|
|
11297
|
+
const [editAnywayActive, setEditAnywayActive] = useState(false);
|
|
11298
|
+
useEffect(() => {
|
|
11299
|
+
setBannerHidden(false);
|
|
11300
|
+
setEditAnywayActive(false);
|
|
11301
|
+
}, [content]);
|
|
11302
|
+
const editAnyway = useCallback(() => {
|
|
11303
|
+
setEditAnywayActive(true);
|
|
11304
|
+
setBannerHidden(true);
|
|
11305
|
+
}, []);
|
|
11306
|
+
const dismiss = useCallback(() => {
|
|
11307
|
+
setBannerHidden(true);
|
|
11308
|
+
}, []);
|
|
11309
|
+
return {
|
|
11310
|
+
recommendation,
|
|
11311
|
+
setRecommendation,
|
|
11312
|
+
/** Whether the viewer's `canEdit` should be forced off. */
|
|
11313
|
+
locked: recommendation.defaultReadOnly && !editAnywayActive,
|
|
11314
|
+
bannerVisible: recommendation.kind !== null && !bannerHidden,
|
|
11315
|
+
editAnyway,
|
|
11316
|
+
dismiss
|
|
11317
|
+
};
|
|
11318
|
+
}
|
|
11319
|
+
function useViewPreferencesSync(input) {
|
|
11320
|
+
const {
|
|
11321
|
+
loadVersion,
|
|
11322
|
+
viewProperties,
|
|
11323
|
+
setViewProperties,
|
|
11324
|
+
snapToGrid,
|
|
11325
|
+
setSnapToGrid,
|
|
11326
|
+
snapToShape,
|
|
11327
|
+
setSnapToShape,
|
|
11328
|
+
showGuides,
|
|
11329
|
+
setShowGuides
|
|
11330
|
+
} = input;
|
|
11331
|
+
useEffect(() => {
|
|
11332
|
+
const seeded = viewerPreferencesFromViewProperties(
|
|
11333
|
+
{ viewProperties },
|
|
11334
|
+
{ ...DEFAULT_VIEWER_PREFERENCES, snapToGrid, snapToObjects: snapToShape, showGuides }
|
|
11335
|
+
);
|
|
11336
|
+
setSnapToGrid(seeded.snapToGrid);
|
|
11337
|
+
setSnapToShape(seeded.snapToObjects ?? snapToShape);
|
|
11338
|
+
setShowGuides(seeded.showGuides ?? showGuides);
|
|
11339
|
+
}, [loadVersion]);
|
|
11340
|
+
const patchViewProperties = useCallback(
|
|
11341
|
+
(prefsOverride) => {
|
|
11342
|
+
setViewProperties((prev) => {
|
|
11343
|
+
const merged = {
|
|
11344
|
+
...DEFAULT_VIEWER_PREFERENCES,
|
|
11345
|
+
snapToGrid,
|
|
11346
|
+
snapToObjects: snapToShape,
|
|
11347
|
+
showGuides,
|
|
11348
|
+
gridSpacingCx: prev?.gridSpacing?.cx,
|
|
11349
|
+
gridSpacingCy: prev?.gridSpacing?.cy,
|
|
11350
|
+
...prefsOverride
|
|
11351
|
+
};
|
|
11352
|
+
const patch = viewPropertiesPatchFromPreferences(merged);
|
|
11353
|
+
return {
|
|
11354
|
+
...prev,
|
|
11355
|
+
slideViewPr: { ...prev?.slideViewPr, ...patch.slideViewPr },
|
|
11356
|
+
...patch.gridSpacing ? { gridSpacing: patch.gridSpacing } : {}
|
|
11357
|
+
};
|
|
11358
|
+
});
|
|
11359
|
+
},
|
|
11360
|
+
[setViewProperties, snapToGrid, snapToShape, showGuides]
|
|
11361
|
+
);
|
|
11362
|
+
const handleSetSnapToGrid = useCallback(
|
|
11363
|
+
(value) => {
|
|
11364
|
+
setSnapToGrid(value);
|
|
11365
|
+
patchViewProperties({ snapToGrid: value });
|
|
11366
|
+
},
|
|
11367
|
+
[setSnapToGrid, patchViewProperties]
|
|
11368
|
+
);
|
|
11369
|
+
const handleSetSnapToShape = useCallback(
|
|
11370
|
+
(value) => {
|
|
11371
|
+
setSnapToShape(value);
|
|
11372
|
+
patchViewProperties({ snapToObjects: value });
|
|
11373
|
+
},
|
|
11374
|
+
[setSnapToShape, patchViewProperties]
|
|
11375
|
+
);
|
|
11376
|
+
const handleSetShowGuides = useCallback(
|
|
11377
|
+
(value) => {
|
|
11378
|
+
setShowGuides(value);
|
|
11379
|
+
patchViewProperties({ showGuides: value });
|
|
11380
|
+
},
|
|
11381
|
+
[setShowGuides, patchViewProperties]
|
|
11382
|
+
);
|
|
11383
|
+
return { handleSetSnapToGrid, handleSetSnapToShape, handleSetShowGuides };
|
|
11384
|
+
}
|
|
11385
|
+
|
|
11386
|
+
// src/viewer/hooks/useViewerBuildingBlocksState.ts
|
|
11123
11387
|
function useViewerBuildingBlocksState(input) {
|
|
11124
11388
|
const { core, content, canEdit, filePath, autosaveEnabled, userName, handle, setContent } = input;
|
|
11125
11389
|
const {
|
|
@@ -11175,6 +11439,8 @@ function useViewerBuildingBlocksState(input) {
|
|
|
11175
11439
|
isDirty: state.isDirty,
|
|
11176
11440
|
history
|
|
11177
11441
|
});
|
|
11442
|
+
const readOnlyRec = useReadOnlyRecommendationState(content);
|
|
11443
|
+
const compatToastsState = useCompatibilityToastsState();
|
|
11178
11444
|
useEffect(() => {
|
|
11179
11445
|
state.setSelectedElementId(null);
|
|
11180
11446
|
state.setSelectedElementIds([]);
|
|
@@ -11205,7 +11471,8 @@ function useViewerBuildingBlocksState(input) {
|
|
|
11205
11471
|
handleSetMode,
|
|
11206
11472
|
handleEnterPresenterView,
|
|
11207
11473
|
handleEnterRehearsalMode,
|
|
11208
|
-
autosaveStatus
|
|
11474
|
+
autosaveStatus,
|
|
11475
|
+
loadVersion
|
|
11209
11476
|
} = useViewerIntegration({
|
|
11210
11477
|
state,
|
|
11211
11478
|
zoom,
|
|
@@ -11223,6 +11490,8 @@ function useViewerBuildingBlocksState(input) {
|
|
|
11223
11490
|
// applies, so the headless building-blocks API loads http(s) images
|
|
11224
11491
|
// under the same default-off, core-side SSRF/privacy guard.
|
|
11225
11492
|
allowExternalImages: viewerOptions.trust.allowExternalContent,
|
|
11493
|
+
setReadOnlyRecommendation: readOnlyRec.setRecommendation,
|
|
11494
|
+
setCompatToasts: compatToastsState.setToasts,
|
|
11226
11495
|
canEdit,
|
|
11227
11496
|
promptKeepInkAnnotations: viewerOptions.advanced.slideShowPromptKeepInkAnnotations,
|
|
11228
11497
|
imageExportScale,
|
|
@@ -11244,6 +11513,17 @@ function useViewerBuildingBlocksState(input) {
|
|
|
11244
11513
|
onSlideCountChange
|
|
11245
11514
|
});
|
|
11246
11515
|
setExitModeHandler(handleSetMode);
|
|
11516
|
+
const viewPreferencesSync = useViewPreferencesSync({
|
|
11517
|
+
loadVersion,
|
|
11518
|
+
viewProperties: state.viewProperties,
|
|
11519
|
+
setViewProperties: state.setViewProperties,
|
|
11520
|
+
snapToGrid: state.snapToGrid,
|
|
11521
|
+
setSnapToGrid: state.setSnapToGrid,
|
|
11522
|
+
snapToShape: state.snapToShape,
|
|
11523
|
+
setSnapToShape: state.setSnapToShape,
|
|
11524
|
+
showGuides: state.showGuides,
|
|
11525
|
+
setShowGuides: state.setShowGuides
|
|
11526
|
+
});
|
|
11247
11527
|
return {
|
|
11248
11528
|
dialogs,
|
|
11249
11529
|
editorOps,
|
|
@@ -11253,7 +11533,8 @@ function useViewerBuildingBlocksState(input) {
|
|
|
11253
11533
|
handleSetMode,
|
|
11254
11534
|
handleEnterPresenterView,
|
|
11255
11535
|
handleEnterRehearsalMode,
|
|
11256
|
-
autosaveStatus
|
|
11536
|
+
autosaveStatus,
|
|
11537
|
+
viewPreferencesSync
|
|
11257
11538
|
};
|
|
11258
11539
|
}
|
|
11259
11540
|
|
|
@@ -11326,7 +11607,8 @@ function useViewerBuildingBlocks(input) {
|
|
|
11326
11607
|
handleSetMode,
|
|
11327
11608
|
handleEnterPresenterView,
|
|
11328
11609
|
handleEnterRehearsalMode,
|
|
11329
|
-
autosaveStatus
|
|
11610
|
+
autosaveStatus,
|
|
11611
|
+
viewPreferencesSync
|
|
11330
11612
|
} = useViewerBuildingBlocksState({
|
|
11331
11613
|
core,
|
|
11332
11614
|
content,
|
|
@@ -11371,7 +11653,8 @@ function useViewerBuildingBlocks(input) {
|
|
|
11371
11653
|
onOpenFile,
|
|
11372
11654
|
onOpenRecentFile,
|
|
11373
11655
|
fileName,
|
|
11374
|
-
hiddenActions
|
|
11656
|
+
hiddenActions,
|
|
11657
|
+
viewPreferencesSync
|
|
11375
11658
|
});
|
|
11376
11659
|
const canvasProps = buildCanvasProps({
|
|
11377
11660
|
mode,
|
|
@@ -11469,4 +11752,4 @@ function useResizablePanels() {
|
|
|
11469
11752
|
};
|
|
11470
11753
|
}
|
|
11471
11754
|
|
|
11472
|
-
export { ACTION_VERB_MAP, MIN_TOUCH_TARGET, ViewerOptionsContext, computeToolbarVisibility, detectTargetType, isAudienceTab, parseAudienceNonce, parseEmailUrl, parseSlideFromUrl, renderToCanvas, scopeLayoutOptionsToActiveSlide, useAnimationPlayback, useAnnotationHandlers, useAudienceMode, useAutosave, useBroadcastFollower, useCanvasInteractions, useClipboardHandlers, useCollaborationLivePatch, useCollaborativeHistory, useCollaborativeState, useComments, useContentLifecycle, useDerivedElementState, useDerivedSlideState, useDialogCustomShows, useEditorHistory, useEditorOperations, useElementManipulation, useElementOperations, useExportHandlers, useExportSaveAs, useFindReplace, useFollowMode, useFontInjection, useGroupAlignLayerHandlers, useIOHandlers, useInsertElements, useIsMobile, useKeyboardInsets, useKeyboardShortcutWiring, useKeyboardShortcuts, useLayoutSwitching, useLoadContent, useMergeShapesHandler, useModalDismissDrag, usePointerHandlers, usePresenceTracking, usePresentationAnnotations, usePresentationKeyboard, usePresentationMode, usePresentationSetup, usePresenterWindow, usePrintHandlers, usePropertyHandlers, useRecoveryDetection, useReducedMotion, useRehearsalTimings, useResizablePanels, useSectionOperations, useSerialize, useSheetDismissDrag, useSlideManagement, useSlideNavigation, useSwipeNavigation, useTableOperations, useThemeHandlers, useThemeSwitching, useToolbarVisibility, useTouchGestures, useViewerBuildingBlocks, useViewerCoreState, useViewerDialogs, useViewerIntegration, useViewerOptions, useViewerOptionsContext, useViewerState, useViewerUIState, useVirtualizedSlides, useYjsDocumentSync, useYjsProvider, useZoomNavigation, useZoomViewport };
|
|
11755
|
+
export { ACTION_VERB_MAP, MIN_TOUCH_TARGET, ViewerOptionsContext, computeToolbarVisibility, detectTargetType, isAudienceTab, parseAudienceNonce, parseEmailUrl, parseSlideFromUrl, renderToCanvas, safePrompt, scopeLayoutOptionsToActiveSlide, syncSelectionHandleOverlay, useAnimationPlayback, useAnnotationHandlers, useAudienceMode, useAutosave, useBroadcastFollower, useCanvasInteractions, useClipboardHandlers, useCollaborationLivePatch, useCollaborativeHistory, useCollaborativeState, useComments, useCompatibilityToastsState, useContentLifecycle, useDerivedElementState, useDerivedSlideState, useDialogCustomShows, useEditorHistory, useEditorOperations, useElementManipulation, useElementOperations, useExportHandlers, useExportSaveAs, useFindReplace, useFollowMode, useFontInjection, useGroupAlignLayerHandlers, useIOHandlers, useInsertElements, useIsMobile, useKeyboardInsets, useKeyboardShortcutWiring, useKeyboardShortcuts, useLayoutSwitching, useLoadContent, useMergeShapesHandler, useModalDismissDrag, usePointerHandlers, usePresenceTracking, usePresentationAnnotations, usePresentationKeyboard, usePresentationMode, usePresentationSetup, usePresenterWindow, usePrintHandlers, usePropertyHandlers, useReadOnlyRecommendationState, useRecoveryDetection, useReducedMotion, useRehearsalTimings, useResizablePanels, useSectionOperations, useSerialize, useSheetDismissDrag, useSlideManagement, useSlideNavigation, useSwipeNavigation, useTableOperations, useThemeHandlers, useThemeSwitching, useToolbarVisibility, useTouchGestures, useViewPreferencesSync, useViewerBuildingBlocks, useViewerCoreState, useViewerDialogs, useViewerIntegration, useViewerOptions, useViewerOptionsContext, useViewerState, useViewerUIState, useVirtualizedSlides, useYjsDocumentSync, useYjsProvider, useZoomNavigation, useZoomViewport };
|