pptx-react-viewer 2.8.0 → 2.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/{AiChatPanel-UXPHPUQV.mjs → AiChatPanel-35CHYS5N.mjs} +4 -4
  3. package/dist/AiChatPanel-35CHYS5N.mjs.br +0 -0
  4. package/dist/AiChatPanel-35CHYS5N.mjs.gz +0 -0
  5. package/dist/{AiChatPanel-GTCK35EI.js → AiChatPanel-KTMWRUD5.js} +23 -23
  6. package/dist/AiChatPanel-KTMWRUD5.js.br +0 -0
  7. package/dist/AiChatPanel-KTMWRUD5.js.gz +0 -0
  8. package/dist/{Model3DScene-HDUHTKPF.mjs → Model3DScene-2VMN3B65.mjs} +1 -1
  9. package/dist/Model3DScene-2VMN3B65.mjs.br +0 -0
  10. package/dist/Model3DScene-2VMN3B65.mjs.gz +0 -0
  11. package/dist/{Model3DScene-USPBP3KE.js → Model3DScene-TMNUKCL6.js} +2 -2
  12. package/dist/Model3DScene-TMNUKCL6.js.br +0 -0
  13. package/dist/Model3DScene-TMNUKCL6.js.gz +0 -0
  14. package/dist/{SurfaceChart3DScene-7SLM73XC.mjs → SurfaceChart3DScene-GKRDDN2U.mjs} +1 -1
  15. package/dist/{SurfaceChart3DScene-7SLM73XC.mjs.br → SurfaceChart3DScene-GKRDDN2U.mjs.br} +0 -0
  16. package/dist/SurfaceChart3DScene-GKRDDN2U.mjs.gz +0 -0
  17. package/dist/{SurfaceChart3DScene-NZ3K5CC6.js → SurfaceChart3DScene-KPNP3QD5.js} +2 -2
  18. package/dist/SurfaceChart3DScene-KPNP3QD5.js.br +0 -0
  19. package/dist/SurfaceChart3DScene-KPNP3QD5.js.gz +0 -0
  20. package/dist/{chunk-KGXDCDA5.js → chunk-A7HLINZU.js} +414 -472
  21. package/dist/chunk-A7HLINZU.js.br +0 -0
  22. package/dist/chunk-A7HLINZU.js.gz +0 -0
  23. package/dist/{chunk-AHPZGUL7.mjs → chunk-FY2AFXKP.mjs} +140 -174
  24. package/dist/chunk-FY2AFXKP.mjs.br +0 -0
  25. package/dist/chunk-FY2AFXKP.mjs.gz +0 -0
  26. package/dist/{chunk-MZJMOEEX.js → chunk-H74UXL4Q.js} +2914 -832
  27. package/dist/chunk-H74UXL4Q.js.br +0 -0
  28. package/dist/chunk-H74UXL4Q.js.gz +0 -0
  29. package/dist/{chunk-SMW4QYGK.js → chunk-IJVDNQLG.js} +374 -407
  30. package/dist/chunk-IJVDNQLG.js.br +0 -0
  31. package/dist/chunk-IJVDNQLG.js.gz +0 -0
  32. package/dist/{chunk-SOBKYMMR.js → chunk-JWMXOYSX.js} +5739 -3092
  33. package/dist/chunk-JWMXOYSX.js.br +0 -0
  34. package/dist/chunk-JWMXOYSX.js.gz +0 -0
  35. package/dist/{chunk-TJ5QMUUJ.mjs → chunk-LCG7WBAG.mjs} +4245 -1598
  36. package/dist/chunk-LCG7WBAG.mjs.br +0 -0
  37. package/dist/chunk-LCG7WBAG.mjs.gz +0 -0
  38. package/dist/{chunk-PVCUYPU7.mjs → chunk-LXTKPSIG.mjs} +1 -1
  39. package/dist/chunk-LXTKPSIG.mjs.br +0 -0
  40. package/dist/chunk-LXTKPSIG.mjs.gz +0 -0
  41. package/dist/{chunk-25VSL2BB.js → chunk-MMK4K3QI.js} +260 -17
  42. package/dist/chunk-MMK4K3QI.js.br +0 -0
  43. package/dist/chunk-MMK4K3QI.js.gz +0 -0
  44. package/dist/{chunk-OIH753PJ.mjs → chunk-OHPF2HTP.mjs} +102 -160
  45. package/dist/chunk-OHPF2HTP.mjs.br +0 -0
  46. package/dist/chunk-OHPF2HTP.mjs.gz +0 -0
  47. package/dist/{chunk-Z6HIZWIQ.mjs → chunk-SL3XPERE.mjs} +260 -17
  48. package/dist/chunk-SL3XPERE.mjs.br +0 -0
  49. package/dist/chunk-SL3XPERE.mjs.gz +0 -0
  50. package/dist/{chunk-VFLBLJ4G.js → chunk-SPJR6MPI.js} +3 -3
  51. package/dist/chunk-SPJR6MPI.js.br +0 -0
  52. package/dist/chunk-SPJR6MPI.js.gz +0 -0
  53. package/dist/{chunk-VH2QF5CT.mjs → chunk-TJ55KUWH.mjs} +2829 -824
  54. package/dist/chunk-TJ55KUWH.mjs.br +0 -0
  55. package/dist/chunk-TJ55KUWH.mjs.gz +0 -0
  56. package/dist/i18n.js +4 -4
  57. package/dist/i18n.js.br +0 -0
  58. package/dist/i18n.js.gz +0 -0
  59. package/dist/i18n.mjs +1 -1
  60. package/dist/i18n.mjs.br +0 -0
  61. package/dist/i18n.mjs.gz +0 -0
  62. package/dist/index.d.ts +36 -0
  63. package/dist/index.js +36 -36
  64. package/dist/index.js.br +0 -0
  65. package/dist/index.js.gz +0 -0
  66. package/dist/index.mjs +6 -6
  67. package/dist/index.mjs.br +0 -0
  68. package/dist/index.mjs.gz +0 -0
  69. package/dist/internals.d.ts +48 -1
  70. package/dist/internals.d.ts.map +1 -1
  71. package/dist/internals.js +79 -79
  72. package/dist/internals.js.br +0 -0
  73. package/dist/internals.js.gz +0 -0
  74. package/dist/internals.mjs +4 -4
  75. package/dist/internals.mjs.br +0 -0
  76. package/dist/internals.mjs.gz +0 -0
  77. package/dist/pptx-viewer.css +1 -1
  78. package/dist/pptx-viewer.css.br +0 -0
  79. package/dist/pptx-viewer.css.gz +0 -0
  80. package/dist/{useViewerBuildingBlocks-DMDZRawe.d.ts → useViewerBuildingBlocks-CpUwhBD5.d.ts} +17 -2
  81. package/dist/useViewerBuildingBlocks-CpUwhBD5.d.ts.map +1 -0
  82. package/dist/viewer/index.d.ts +21 -0
  83. package/dist/viewer/index.js +22 -22
  84. package/dist/viewer/index.js.br +0 -0
  85. package/dist/viewer/index.js.gz +0 -0
  86. package/dist/viewer/index.mjs +6 -6
  87. package/dist/viewer/index.mjs.br +0 -0
  88. package/dist/viewer/index.mjs.gz +0 -0
  89. package/package.json +1 -1
  90. package/dist/AiChatPanel-GTCK35EI.js.br +0 -0
  91. package/dist/AiChatPanel-GTCK35EI.js.gz +0 -0
  92. package/dist/AiChatPanel-UXPHPUQV.mjs.br +0 -0
  93. package/dist/AiChatPanel-UXPHPUQV.mjs.gz +0 -0
  94. package/dist/Model3DScene-HDUHTKPF.mjs.br +0 -0
  95. package/dist/Model3DScene-HDUHTKPF.mjs.gz +0 -0
  96. package/dist/Model3DScene-USPBP3KE.js.br +0 -0
  97. package/dist/Model3DScene-USPBP3KE.js.gz +0 -0
  98. package/dist/SurfaceChart3DScene-7SLM73XC.mjs.gz +0 -0
  99. package/dist/SurfaceChart3DScene-NZ3K5CC6.js.br +0 -0
  100. package/dist/SurfaceChart3DScene-NZ3K5CC6.js.gz +0 -0
  101. package/dist/chunk-25VSL2BB.js.br +0 -0
  102. package/dist/chunk-25VSL2BB.js.gz +0 -0
  103. package/dist/chunk-AHPZGUL7.mjs.br +0 -0
  104. package/dist/chunk-AHPZGUL7.mjs.gz +0 -0
  105. package/dist/chunk-KGXDCDA5.js.br +0 -0
  106. package/dist/chunk-KGXDCDA5.js.gz +0 -0
  107. package/dist/chunk-MZJMOEEX.js.br +0 -0
  108. package/dist/chunk-MZJMOEEX.js.gz +0 -0
  109. package/dist/chunk-OIH753PJ.mjs.br +0 -0
  110. package/dist/chunk-OIH753PJ.mjs.gz +0 -0
  111. package/dist/chunk-PVCUYPU7.mjs.br +0 -0
  112. package/dist/chunk-PVCUYPU7.mjs.gz +0 -0
  113. package/dist/chunk-SMW4QYGK.js.br +0 -0
  114. package/dist/chunk-SMW4QYGK.js.gz +0 -0
  115. package/dist/chunk-SOBKYMMR.js.br +0 -0
  116. package/dist/chunk-SOBKYMMR.js.gz +0 -0
  117. package/dist/chunk-TJ5QMUUJ.mjs.br +0 -0
  118. package/dist/chunk-TJ5QMUUJ.mjs.gz +0 -0
  119. package/dist/chunk-VFLBLJ4G.js.br +0 -0
  120. package/dist/chunk-VFLBLJ4G.js.gz +0 -0
  121. package/dist/chunk-VH2QF5CT.mjs.br +0 -0
  122. package/dist/chunk-VH2QF5CT.mjs.gz +0 -0
  123. package/dist/chunk-Z6HIZWIQ.mjs.br +0 -0
  124. package/dist/chunk-Z6HIZWIQ.mjs.gz +0 -0
  125. package/dist/useViewerBuildingBlocks-DMDZRawe.d.ts.map +0 -1
@@ -1,6 +1,6 @@
1
- import { cloneHistorySnapshot, MAX_ZOOM_SCALE, MIN_ZOOM_SCALE, MIN_ELEMENT_SIZE, ZOOM_TO_SELECTION_PADDING, DEFAULT_CANVAS_HEIGHT, DEFAULT_CANVAS_WIDTH, partitionTemplateElements, UNGROUPED_SECTION_ID, stopAllPersistentAudio, buildSaveSlides, DEFAULT_TABLE_ROWS, DEFAULT_TABLE_COLUMNS, executeMediaCommand, buildPdfFromImageData, buildNotesPdf, EMU_PER_PX, GRID_SIZE, DEFAULT_TEXT_FONT_SIZE } from './chunk-AHPZGUL7.mjs';
2
- import { translationsEn } from './chunk-Z6HIZWIQ.mjs';
3
- import { TOOLBAR_TABS, computeVirtualRange, DEFAULT_VIRTUAL_OVERSCAN, BROADCAST_THROTTLE_MS, createSyncGate, clearLocalAwareness, validateRoomId, createDepartureChannel, resolveTransportForServerUrl, isMixedContentBlocked, CONNECTION_TIMEOUT_MS, registerCollaborationTeardown, sanitizeColor, cloneTemplateElementsBySlideId, cloneSlide, PresentationAnimationController, computeEntranceAnimationDelay, PRESENTATION_HASH, PRESENTATION_NONCE_KEY, PRESENTATION_CHANNEL_NAME, swapPresentationWindows, PRESENTATION_MESSAGE_ORIGIN, clearAudienceContent, buildPresentationAudienceUrl, resolveAudienceScreenPlacement, placeAudienceWindow, storeAudienceContent, isPresentationSessionMessage, endAudienceDisplay, createPresentationKeyBuffer, acceptsPresentationInput, resolveAutoAdvanceDelayMs, buildMorphTransitionPlan, morphOptionToMode, createCollaborationLivePatcher, publishLiveInlineText, PptxHandler, collectMediaElements, collectImagePaths, buildInitialGuides, EncryptedFileError, saveAutosaveSnapshot, isTemplateElementId, hasShapeProperties, hasTextProperties, getInlineEditorSelection, applyStyleToSelectedSegments, setPendingSelectionRestore, applyCaseTransformToSegments, transformTextCase, addSection, renameSection, deleteSection, moveSectionUp, moveSectionDown, moveSlidesToSection, normalizeColorsForCapture, preprocessCssForCapture, downloadBlob, sanitizeDownloadFilename, slideProgressPercent, slideStatusLabel, EXPORT_ASSEMBLING_PERCENT, EXPORT_DONE_PERCENT, isExportAbortError, recordProgressPercent, applyThemeToData, THEME_PRESETS, themeColorSchemesEqual, comparePresentation, applyAcceptSlide, applyAcceptAllSlides, collectUsedFonts, detectTouchDevice, detectOrientation, isMobileViewport, MOBILE_BREAKPOINT, TABLET_BREAKPOINT, mayLeaveSlideShow, remapTextToSegments, guidePxToEmu, shouldLoopContinuously, applyRehearsalTimings, copyFormatFromElement, applyFormatToElement, createViewerOptionsStore, readSlidesFromYDoc, reconcileSlidesInYDoc, LOCAL_SYNC_ORIGIN, observeYDocSlides, shouldAutoFollowBroadcaster, createTouchGestureRecognizer, isKeyboardOpen, openPptxFile, readBackstageRecentFile, isActionHidden, buildElementClipboardPayload, generatePackageReadme, groupElements, generateElementId, makeCloneId, alignElements, distributeElements, bringForward, sendBackward, bringToFront, sendToBack, newTableElement, createDefaultChartElement, readViewportMetrics, computeKeyboardInset, mergeShapes, derivePresenceList, mapPresentationKey, buildPrintDocument, buildOutlineHtml, buildSlidesHtml, buildNotesHtml, buildHandoutsHtml, createBlankSlide, makeSlideId, buildThemeColorMap, reResolveSlideColors, createPresentationSessionId, resolveTransitionDurationMs, isUrlSafe, createPresenterTimer, createInitialPresentationSnapshot, mergePresentationSnapshot, presenterElapsed, stepPresenterZoom, resetPresenterTimer, togglePresenterTimer, canvasToJpegData, downloadDataUrl, pickSupportedMimeType, WEBM_MIME_CANDIDATES, fpsToFrameIntervalMs, segmentFrameCount, encodeGif, groupSlidesBySection, hasCopyableFormat, createBackstagePresentation, cloneElementForPaste, computeScrollDelta, getPresetShapeClipPath, svgPathToPolygons, polygonsToSvgPath, rerouteConnectorsForMovedElements, applyReroutedConnectors, SvgExporter, buildPrintHtmlDocument, deleteTableColumn, rebuildTableStructureInRawXml, insertTableColumn, deleteTableRow, insertTableRow, updateCellTextStyleInRawXml, updateCellTextInRawXml, splitCell, updateMergeAttrsInRawXml, mergeCells, isPpactionUrl, parsePpactionUrl, safeOpenUrl, ACTION_BUTTON_PRESETS, elementActionToPptxAction, buildSmartArtPresetData, computeSnapToShape, publishLiveGeometry, computeMarqueeHitIds, mergeAdditiveSelection, applyResize, snapBoxToGrid } from './chunk-VH2QF5CT.mjs';
1
+ import { cloneHistorySnapshot, MIN_ELEMENT_SIZE, ZOOM_TO_SELECTION_PADDING, DEFAULT_CANVAS_HEIGHT, DEFAULT_CANVAS_WIDTH, partitionTemplateElements, UNGROUPED_SECTION_ID, stopAllPersistentAudio, buildSaveSlides, DEFAULT_TABLE_ROWS, DEFAULT_TABLE_COLUMNS, executeMediaCommand, buildPdfFromImageData, buildNotesPdf, EMU_PER_PX, GRID_SIZE, DEFAULT_TEXT_FONT_SIZE } from './chunk-FY2AFXKP.mjs';
2
+ import { translationsEn } from './chunk-SL3XPERE.mjs';
3
+ import { TOOLBAR_TABS, computeVirtualRange, DEFAULT_VIRTUAL_OVERSCAN, BROADCAST_THROTTLE_MS, createSyncGate, clearLocalAwareness, validateRoomId, createDepartureChannel, resolveTransportForServerUrl, isMixedContentBlocked, CONNECTION_TIMEOUT_MS, registerCollaborationTeardown, sanitizeColor, cloneTemplateElementsBySlideId, cloneSlide, clampZoomScale, zoomInScale, zoomOutScale, PresentationAnimationController, computeEntranceAnimationDelay, PRESENTATION_HASH, PRESENTATION_NONCE_KEY, PRESENTATION_CHANNEL_NAME, swapPresentationWindows, PRESENTATION_MESSAGE_ORIGIN, clearAudienceContent, buildPresentationAudienceUrl, resolveAudienceScreenPlacement, placeAudienceWindow, storeAudienceContent, isPresentationSessionMessage, endAudienceDisplay, createPresentationKeyBuffer, acceptsPresentationInput, resolveAutoAdvanceDelayMs, buildMorphTransitionPlan, morphOptionToMode, createCollaborationLivePatcher, publishLiveInlineText, PptxHandler, collectMediaElements, collectImagePaths, buildInitialGuides, EncryptedFileError, saveAutosaveSnapshot, isTemplateElementId, hasShapeProperties, hasTextProperties, getInlineEditorSelection, applyStyleToSelectedSegments, setPendingSelectionRestore, applyCaseTransformToSegments, transformTextCase, addSection, renameSection, deleteSection, moveSectionUp, moveSectionDown, moveSlidesToSection, normalizeColorsForCapture, preprocessCssForCapture, downloadBlob, sanitizeDownloadFilename, slideProgressPercent, slideStatusLabel, EXPORT_ASSEMBLING_PERCENT, EXPORT_DONE_PERCENT, isExportAbortError, recordProgressPercent, applyThemeToData, THEME_PRESETS, themeColorSchemesEqual, comparePresentation, applyAcceptSlide, applyAcceptAllSlides, collectUsedFonts, detectTouchDevice, detectOrientation, isMobileViewport, MOBILE_BREAKPOINT, TABLET_BREAKPOINT, mayLeaveSlideShow, remapTextToSegments, guidePxToEmu, shouldLoopContinuously, applyRehearsalTimings, copyFormatFromElement, applyFormatToElement, mapEditorKey, isEditorTextInputTarget, createViewerOptionsStore, readSlidesFromYDoc, reconcileSlidesInYDoc, LOCAL_SYNC_ORIGIN, observeYDocSlides, shouldAutoFollowBroadcaster, createTouchGestureRecognizer, MAX_ZOOM_SCALE, MIN_ZOOM_SCALE, isKeyboardOpen, openPptxFile, readBackstageRecentFile, isActionHidden, buildElementClipboardPayload, generatePackageReadme, groupElements, generateElementId, makeCloneId, alignElements, distributeElements, bringForward, sendBackward, bringToFront, sendToBack, newTableElement, createDefaultChartElement, readViewportMetrics, computeKeyboardInset, mergeShapes, derivePresenceList, mapPresentationKey, buildPrintDocument, buildOutlineHtml, buildSlidesHtml, buildNotesHtml, buildHandoutsHtml, createBlankSlide, makeSlideId, buildThemeColorMap, reResolveSlideColors, createPresentationSessionId, resolveTransitionDurationMs, isUrlSafe, createPresenterTimer, createInitialPresentationSnapshot, mergePresentationSnapshot, presenterElapsed, stepPresenterZoom, resetPresenterTimer, togglePresenterTimer, canvasToJpegData, downloadDataUrl, pickSupportedMimeType, WEBM_MIME_CANDIDATES, fpsToFrameIntervalMs, segmentFrameCount, encodeGif, groupSlidesBySection, hasCopyableFormat, createBackstagePresentation, buildFieldSubstitutionContext, cloneElementForPaste, computeScrollDelta, getPresetShapeClipPath, svgPathToPolygons, polygonsToSvgPath, rerouteConnectorsForMovedElements, applyReroutedConnectors, SvgExporter, buildPrintHtmlDocument, deleteTableColumn, rebuildTableStructureInRawXml, insertTableColumn, deleteTableRow, insertTableRow, updateCellTextStyleInRawXml, updateCellTextInRawXml, splitCell, updateMergeAttrsInRawXml, mergeCells, isPpactionUrl, parsePpactionUrl, safeOpenUrl, ACTION_BUTTON_PRESETS, elementActionToPptxAction, buildSmartArtPresetData, computeSnapToShape, publishLiveGeometry, computeMarqueeHitIds, mergeAdditiveSelection, applyResize, snapBoxToGrid } from './chunk-TJ55KUWH.mjs';
4
4
  import { useRef, useState, useEffect, useCallback, useMemo, useSyncExternalStore, useImperativeHandle } from 'react';
5
5
  import JSZip from 'jszip';
6
6
  import { useTranslation } from 'react-i18next';
@@ -743,7 +743,7 @@ function useZoomViewport({
743
743
  if (!wrapper || !canvasViewport) {
744
744
  return;
745
745
  }
746
- const boundedScale = Math.min(Math.max(nextScale, MIN_ZOOM_SCALE), MAX_ZOOM_SCALE);
746
+ const boundedScale = clampZoomScale(nextScale);
747
747
  const nextEditorScale = fitScale * boundedScale;
748
748
  const centerX = (bounds.minX + bounds.maxX) / 2;
749
749
  const centerY = (bounds.minY + bounds.maxY) / 2;
@@ -758,10 +758,10 @@ function useZoomViewport({
758
758
  [fitScale]
759
759
  );
760
760
  const handleZoomIn = useCallback(() => {
761
- setScale((currentScale) => Math.min(currentScale + 0.1, MAX_ZOOM_SCALE));
761
+ setScale((currentScale) => zoomInScale(currentScale));
762
762
  }, []);
763
763
  const handleZoomOut = useCallback(() => {
764
- setScale((currentScale) => Math.max(currentScale - 0.1, MIN_ZOOM_SCALE));
764
+ setScale((currentScale) => zoomOutScale(currentScale));
765
765
  }, []);
766
766
  const handleResetZoom = useCallback(() => {
767
767
  setScale(1);
@@ -802,10 +802,7 @@ function useZoomViewport({
802
802
  availableHeight / boundsHeight
803
803
  );
804
804
  const safeFitScale = fitScale > Number.EPSILON ? fitScale : Number.EPSILON;
805
- const nextScale = Math.min(
806
- Math.max(targetEditorScale / safeFitScale, MIN_ZOOM_SCALE),
807
- MAX_ZOOM_SCALE
808
- );
805
+ const nextScale = clampZoomScale(targetEditorScale / safeFitScale);
809
806
  setScale(nextScale);
810
807
  window.requestAnimationFrame(() => {
811
808
  window.requestAnimationFrame(() => {
@@ -825,9 +822,7 @@ function useZoomViewport({
825
822
  }
826
823
  event.preventDefault();
827
824
  const delta = event.deltaY * -1e-3;
828
- setScale(
829
- (currentScale) => Math.min(Math.max(currentScale + delta, MIN_ZOOM_SCALE), MAX_ZOOM_SCALE)
830
- );
825
+ setScale((currentScale) => clampZoomScale(currentScale + delta));
831
826
  }, []);
832
827
  useEffect(() => {
833
828
  const viewport = canvasViewportRef.current;
@@ -3584,6 +3579,7 @@ function useViewerUIState() {
3584
3579
  const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(false);
3585
3580
  const [sidebarPanelMode, setSidebarPanelMode] = useState("properties");
3586
3581
  const [showSlideSorter, setShowSlideSorter] = useState(false);
3582
+ const [showReadingView, setShowReadingView] = useState(false);
3587
3583
  const [isShortcutHelpOpen, setIsShortcutHelpOpen] = useState(false);
3588
3584
  const [isAccessibilityPanelOpen, setIsAccessibilityPanelOpen] = useState(false);
3589
3585
  const [accessibilityIssues, setAccessibilityIssues] = useState([]);
@@ -3592,6 +3588,7 @@ function useViewerUIState() {
3592
3588
  const [spellCheckEnabled, setSpellCheckEnabled] = useState(true);
3593
3589
  const [showGrid, setShowGrid] = useState(false);
3594
3590
  const [showRulers, setShowRulers] = useState(false);
3591
+ const [showGuides, setShowGuides] = useState(true);
3595
3592
  const [snapToGrid, setSnapToGrid] = useState(true);
3596
3593
  const [snapToShape, setSnapToShape] = useState(true);
3597
3594
  const [guides, setGuides] = useState(
@@ -3629,6 +3626,8 @@ function useViewerUIState() {
3629
3626
  setSidebarPanelMode,
3630
3627
  showSlideSorter,
3631
3628
  setShowSlideSorter,
3629
+ showReadingView,
3630
+ setShowReadingView,
3632
3631
  isShortcutHelpOpen,
3633
3632
  setIsShortcutHelpOpen,
3634
3633
  isAccessibilityPanelOpen,
@@ -3645,6 +3644,8 @@ function useViewerUIState() {
3645
3644
  setShowGrid,
3646
3645
  showRulers,
3647
3646
  setShowRulers,
3647
+ showGuides,
3648
+ setShowGuides,
3648
3649
  snapToGrid,
3649
3650
  setSnapToGrid,
3650
3651
  snapToShape,
@@ -4710,6 +4711,9 @@ function usePointerHandlers(input) {
4710
4711
  input
4711
4712
  ]);
4712
4713
  }
4714
+ function mouseDownStartsSelectionDrag(event) {
4715
+ return !event.shiftKey && !event.metaKey;
4716
+ }
4713
4717
  function useCanvasInteractions(input) {
4714
4718
  const {
4715
4719
  mode,
@@ -4822,6 +4826,9 @@ function useCanvasInteractions(input) {
4822
4826
  if (inlineEditingElementId && inlineEditingElementId !== elementId) {
4823
4827
  handleInlineEditCommit();
4824
4828
  }
4829
+ if (!mouseDownStartsSelectionDrag(e)) {
4830
+ return;
4831
+ }
4825
4832
  const wasSelected = selectedElementIdSet.has(elementId);
4826
4833
  if (!wasSelected) {
4827
4834
  ops.applySelection(elementId);
@@ -9269,140 +9276,77 @@ function useContentLifecycle(input) {
9269
9276
  });
9270
9277
  return { handlerRef, serializeSlides, autosaveStatus };
9271
9278
  }
9272
- var NUDGE_SMALL = 2;
9273
- var NUDGE_LARGE = 20;
9274
9279
  function useKeyboardShortcuts(input) {
9275
9280
  const inputRef = useRef(input);
9276
9281
  inputRef.current = input;
9277
9282
  const handleKeyDown = useCallback((e) => {
9278
- const {
9279
- mode,
9280
- canEdit,
9281
- inlineEditingElementId,
9282
- tableEditorState,
9283
- activeTool,
9284
- hasSelection,
9285
- onDelete,
9286
- onCopy,
9287
- onCut,
9288
- onPaste,
9289
- onDuplicate,
9290
- onUndo,
9291
- onRedo,
9292
- onSelectAll,
9293
- onEscape,
9294
- onNudge,
9295
- onPrevSlide,
9296
- onNextSlide
9297
- } = inputRef.current;
9298
- if (mode !== "edit" || !canEdit) {
9299
- return;
9300
- }
9301
- const target = e.target;
9302
- const isTextInput = target?.tagName === "INPUT" || target?.tagName === "TEXTAREA" || target?.isContentEditable;
9303
- if (e.key === "Escape") {
9304
- e.preventDefault();
9305
- onEscape();
9306
- return;
9307
- }
9308
- if (inlineEditingElementId || tableEditorState?.isEditing || activeTool !== "select") {
9309
- return;
9310
- }
9311
- if (isTextInput) {
9312
- return;
9313
- }
9314
- const isMod = e.metaKey || e.ctrlKey;
9315
- if ((e.key === "Delete" || e.key === "Backspace") && hasSelection) {
9316
- e.preventDefault();
9317
- onDelete();
9318
- return;
9319
- }
9320
- if (isMod) {
9321
- switch (e.key.toLowerCase()) {
9322
- case "z":
9323
- e.preventDefault();
9324
- if (e.shiftKey) {
9325
- onRedo();
9326
- } else {
9327
- onUndo();
9328
- }
9329
- return;
9330
- case "y":
9331
- e.preventDefault();
9332
- onRedo();
9333
- return;
9334
- case "c":
9335
- if (hasSelection) {
9336
- e.preventDefault();
9337
- onCopy();
9338
- }
9339
- return;
9340
- case "x":
9341
- if (hasSelection) {
9342
- e.preventDefault();
9343
- onCut();
9344
- }
9345
- return;
9346
- case "v":
9347
- e.preventDefault();
9348
- onPaste();
9349
- return;
9350
- case "d":
9351
- if (hasSelection) {
9352
- e.preventDefault();
9353
- onDuplicate();
9354
- }
9355
- return;
9356
- case "a":
9357
- e.preventDefault();
9358
- onSelectAll();
9359
- return;
9360
- }
9361
- }
9362
- if (hasSelection && (e.key === "ArrowUp" || e.key === "ArrowDown" || e.key === "ArrowLeft" || e.key === "ArrowRight")) {
9363
- e.preventDefault();
9364
- const step = e.shiftKey ? NUDGE_LARGE : NUDGE_SMALL;
9365
- let dx = 0;
9366
- let dy = 0;
9367
- switch (e.key) {
9368
- case "ArrowUp":
9369
- dy = -step;
9370
- break;
9371
- case "ArrowDown":
9372
- dy = step;
9373
- break;
9374
- case "ArrowLeft":
9375
- dx = -step;
9376
- break;
9377
- case "ArrowRight":
9378
- dx = step;
9379
- break;
9380
- }
9381
- onNudge(dx, dy);
9283
+ const current = inputRef.current;
9284
+ const { action, dx, dy } = mapEditorKey(e, {
9285
+ canEdit: current.canEdit,
9286
+ isPresenting: current.mode !== "edit",
9287
+ hasSelection: current.hasSelection,
9288
+ isEditingText: Boolean(current.inlineEditingElementId || current.tableEditorState?.isEditing),
9289
+ isDrawing: current.activeTool !== "select",
9290
+ isTextInputTarget: isEditorTextInputTarget(e.target)
9291
+ });
9292
+ if (action === null) {
9382
9293
  return;
9383
9294
  }
9384
- if (!hasSelection && (e.key === "ArrowLeft" || e.key === "ArrowRight")) {
9385
- e.preventDefault();
9386
- if (e.key === "ArrowLeft") {
9387
- onPrevSlide?.();
9388
- } else {
9389
- onNextSlide?.();
9390
- }
9295
+ e.preventDefault();
9296
+ switch (action) {
9297
+ case "escape":
9298
+ current.onEscape();
9299
+ break;
9300
+ case "delete":
9301
+ current.onDelete();
9302
+ break;
9303
+ case "undo":
9304
+ current.onUndo();
9305
+ break;
9306
+ case "redo":
9307
+ current.onRedo();
9308
+ break;
9309
+ case "copy":
9310
+ current.onCopy();
9311
+ break;
9312
+ case "cut":
9313
+ current.onCut();
9314
+ break;
9315
+ case "paste":
9316
+ current.onPaste();
9317
+ break;
9318
+ case "duplicate":
9319
+ current.onDuplicate();
9320
+ break;
9321
+ case "selectAll":
9322
+ current.onSelectAll();
9323
+ break;
9324
+ case "group":
9325
+ current.onGroup?.();
9326
+ break;
9327
+ case "ungroup":
9328
+ current.onUngroup?.();
9329
+ break;
9330
+ case "toggleShortcuts":
9331
+ current.onToggleShortcuts?.();
9332
+ break;
9333
+ case "nudge":
9334
+ current.onNudge(dx ?? 0, dy ?? 0);
9335
+ break;
9336
+ case "prevSlide":
9337
+ current.onPrevSlide?.();
9338
+ break;
9339
+ case "nextSlide":
9340
+ current.onNextSlide?.();
9341
+ break;
9391
9342
  }
9392
9343
  }, []);
9393
9344
  useEffect(() => {
9394
- const container = input.containerRef.current;
9395
- if (container) {
9396
- container.addEventListener("keydown", handleKeyDown);
9397
- }
9398
9345
  window.addEventListener("keydown", handleKeyDown);
9399
9346
  return () => {
9400
- if (container) {
9401
- container.removeEventListener("keydown", handleKeyDown);
9402
- }
9403
9347
  window.removeEventListener("keydown", handleKeyDown);
9404
9348
  };
9405
- }, [input.containerRef, handleKeyDown]);
9349
+ }, [handleKeyDown]);
9406
9350
  }
9407
9351
 
9408
9352
  // src/viewer/hooks/useKeyboardShortcutWiring.ts
@@ -9433,8 +9377,13 @@ function useKeyboardShortcutWiring(input) {
9433
9377
  ops.applySelection(allIds[0], allIds);
9434
9378
  }
9435
9379
  },
9380
+ onGroup: manipulation.handleGroupElements,
9381
+ onUngroup: manipulation.handleUngroupElement,
9382
+ onToggleShortcuts: () => state.setIsShortcutHelpOpen((prev) => !prev),
9436
9383
  onEscape: () => {
9437
- if (state.inlineEditingElementId) {
9384
+ if (state.isShortcutHelpOpen) {
9385
+ state.setIsShortcutHelpOpen(false);
9386
+ } else if (state.inlineEditingElementId) {
9438
9387
  state.setInlineEditingElementId(null);
9439
9388
  state.setInlineEditingText("");
9440
9389
  } else if (state.contextMenuState) {
@@ -9631,7 +9580,7 @@ function useViewerIntegration(input) {
9631
9580
  return zoom.scale;
9632
9581
  },
9633
9582
  setZoom(level) {
9634
- zoom.setScale(Math.min(Math.max(level, MIN_ZOOM_SCALE), MAX_ZOOM_SCALE));
9583
+ zoom.setScale(clampZoomScale(level));
9635
9584
  },
9636
9585
  zoomIn() {
9637
9586
  zoom.handleZoomIn();
@@ -10335,29 +10284,11 @@ function buildCanvasProps(input) {
10335
10284
  } = input;
10336
10285
  const effectiveSlide = mode === "master" ? masterPseudoSlide : activeSlide;
10337
10286
  const effectiveTemplateElements = mode === "master" ? s.activeLayout ? s.activeMaster?.elements ?? [] : [] : templateElements;
10338
- let slideTitle;
10339
- if (activeSlide) {
10340
- for (const el of activeSlide.elements) {
10341
- const phType = el.placeholderType;
10342
- if (phType === "title" || phType === "ctrTitle") {
10343
- const txt = el.text;
10344
- if (txt) {
10345
- slideTitle = txt;
10346
- break;
10347
- }
10348
- }
10349
- }
10350
- }
10351
- const hf = s.headerFooter;
10352
- const fieldContext = {
10353
- slideNumber: activeSlide?.slideNumber,
10354
- dateTimeText: hf.dateTimeText,
10355
- dateFormat: hf.dateFormat,
10356
- footerText: hf.footerText,
10357
- headerText: hf.headerText,
10358
- slideTitle,
10359
- customProperties: s.customProperties.map((p) => ({ name: p.name, value: p.value }))
10360
- };
10287
+ const fieldContext = buildFieldSubstitutionContext({
10288
+ headerFooter: s.headerFooter,
10289
+ customProperties: s.customProperties,
10290
+ slide: activeSlide
10291
+ });
10361
10292
  const tableStyleContext = s.theme || s.tableStyleMap ? { theme: s.theme, tableStyleMap: s.tableStyleMap } : void 0;
10362
10293
  const handleActionClick = (_elementId, action) => {
10363
10294
  if (mode === "present") {
@@ -10401,7 +10332,9 @@ function buildCanvasProps(input) {
10401
10332
  showGrid: s.showGrid,
10402
10333
  gridSpacingPx,
10403
10334
  showRulers: s.showRulers,
10404
- guides: s.guides,
10335
+ // View ▸ Guides hides the overlay without discarding the guides: they are
10336
+ // still snapped to while dragging and still round-trip on save.
10337
+ guides: s.showGuides ? s.guides : [],
10405
10338
  presentationElementStates: mode === "present" ? presentation.presentationElementStates : void 0,
10406
10339
  presentationKeyframesCss: mode === "present" ? presentation.presentationKeyframesCss : void 0,
10407
10340
  onClick: canvasHandlers.handleElementClick,
@@ -10610,6 +10543,7 @@ function buildToolbarProps(input) {
10610
10543
  history
10611
10544
  });
10612
10545
  const scopedLayoutOptions = scopeLayoutOptionsToActiveSlide(s.layoutOptions, activeSlide);
10546
+ const selectionSize = selectedElement === null ? 0 : 1;
10613
10547
  return {
10614
10548
  fileName,
10615
10549
  mode,
@@ -10672,11 +10606,13 @@ function buildToolbarProps(input) {
10672
10606
  spellCheckEnabled: s.spellCheckEnabled,
10673
10607
  showGrid: s.showGrid,
10674
10608
  showRulers: s.showRulers,
10609
+ showGuides: s.showGuides,
10675
10610
  snapToGrid: s.snapToGrid,
10676
10611
  snapToShape: s.snapToShape,
10677
10612
  onSetSpellCheckEnabled: s.setSpellCheckEnabled,
10678
10613
  onSetShowGrid: s.setShowGrid,
10679
10614
  onSetShowRulers: s.setShowRulers,
10615
+ onSetShowGuides: s.setShowGuides,
10680
10616
  onSetSnapToGrid: s.setSnapToGrid,
10681
10617
  onSetSnapToShape: s.setSnapToShape,
10682
10618
  onAddGuide: dialogs.handleAddGuide,
@@ -10689,6 +10625,11 @@ function buildToolbarProps(input) {
10689
10625
  onFlip: manipulation.handleFlip,
10690
10626
  onMoveLayer: manipulation.handleMoveLayer,
10691
10627
  onMoveLayerToEdge: manipulation.handleMoveLayerToEdge,
10628
+ onGroupElements: manipulation.handleGroupElements,
10629
+ onUngroupElement: manipulation.handleUngroupElement,
10630
+ onUpdateElementStyle: ops.updateSelectedShapeStyle,
10631
+ selectedCount: s.selectedElementIds.length > 0 ? s.selectedElementIds.length : selectionSize,
10632
+ onOpenHyperlinkDialog: () => dialogs.setIsHyperlinkDialogOpen(true),
10692
10633
  onDuplicate: manipulation.handleDuplicate,
10693
10634
  onDelete: manipulation.handleDelete,
10694
10635
  onExportPng: exportHandlers.handleExportPng,
@@ -10717,6 +10658,7 @@ function buildToolbarProps(input) {
10717
10658
  onOpenSettings,
10718
10659
  onRunAccessibilityCheck: dialogs.handleRunAccessibilityCheck,
10719
10660
  onToggleSlideSorter: () => s.setShowSlideSorter((p) => !p),
10661
+ onOpenReadingView: () => s.setShowReadingView(true),
10720
10662
  onUpdateTextStyle: ops.updateSelectedTextStyle,
10721
10663
  onTransformTextCase: ops.updateSelectedTextCase,
10722
10664
  isOverflowMenuOpen: s.isOverflowMenuOpen,
Binary file
Binary file