pptx-react-viewer 2.0.0 → 2.2.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 (112) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +1 -1
  3. package/dist/{AiChatPanel-BRGQCYZM.mjs → AiChatPanel-JFCJCR3O.mjs} +3 -3
  4. package/dist/AiChatPanel-JFCJCR3O.mjs.br +0 -0
  5. package/dist/AiChatPanel-JFCJCR3O.mjs.gz +0 -0
  6. package/dist/{AiChatPanel-PW5OT25Z.js → AiChatPanel-S3FWARWG.js} +11 -11
  7. package/dist/AiChatPanel-S3FWARWG.js.br +0 -0
  8. package/dist/AiChatPanel-S3FWARWG.js.gz +0 -0
  9. package/dist/{Model3DScene-JCGYRKXM.js → Model3DScene-BZK4UHL4.js} +2 -2
  10. package/dist/Model3DScene-BZK4UHL4.js.br +0 -0
  11. package/dist/Model3DScene-BZK4UHL4.js.gz +0 -0
  12. package/dist/{Model3DScene-TEF362W2.mjs → Model3DScene-RCZCBW52.mjs} +1 -1
  13. package/dist/{Model3DScene-TEF362W2.mjs.br → Model3DScene-RCZCBW52.mjs.br} +0 -0
  14. package/dist/Model3DScene-RCZCBW52.mjs.gz +0 -0
  15. package/dist/PowerPointViewer-gmU5rc7K.d.ts.map +1 -1
  16. package/dist/{SurfaceChart3DScene-2SHCYZVC.js → SurfaceChart3DScene-EGPAMPX4.js} +2 -2
  17. package/dist/SurfaceChart3DScene-EGPAMPX4.js.br +0 -0
  18. package/dist/SurfaceChart3DScene-EGPAMPX4.js.gz +0 -0
  19. package/dist/{SurfaceChart3DScene-UPDCIMJM.mjs → SurfaceChart3DScene-IRLH4ADG.mjs} +1 -1
  20. package/dist/{SurfaceChart3DScene-UPDCIMJM.mjs.br → SurfaceChart3DScene-IRLH4ADG.mjs.br} +0 -0
  21. package/dist/SurfaceChart3DScene-IRLH4ADG.mjs.gz +0 -0
  22. package/dist/{chunk-LFXG7SGG.js → chunk-3KD6S6VM.js} +1111 -830
  23. package/dist/chunk-3KD6S6VM.js.br +0 -0
  24. package/dist/chunk-3KD6S6VM.js.gz +0 -0
  25. package/dist/{chunk-L63RAVM7.mjs → chunk-6BUR4MJO.mjs} +358 -77
  26. package/dist/chunk-6BUR4MJO.mjs.br +0 -0
  27. package/dist/chunk-6BUR4MJO.mjs.gz +0 -0
  28. package/dist/{chunk-ZB4NZRCI.js → chunk-JPJBOVU7.js} +423 -332
  29. package/dist/chunk-JPJBOVU7.js.br +0 -0
  30. package/dist/chunk-JPJBOVU7.js.gz +0 -0
  31. package/dist/{chunk-5XLLRPMV.mjs → chunk-L4ETDT4F.mjs} +174 -84
  32. package/dist/chunk-L4ETDT4F.mjs.br +0 -0
  33. package/dist/chunk-L4ETDT4F.mjs.gz +0 -0
  34. package/dist/{chunk-2X72MOPZ.mjs → chunk-PZTPX3HK.mjs} +10 -1
  35. package/dist/chunk-PZTPX3HK.mjs.br +0 -0
  36. package/dist/chunk-PZTPX3HK.mjs.gz +0 -0
  37. package/dist/{chunk-R2N2UYT7.mjs → chunk-RLK72AOU.mjs} +403 -3
  38. package/dist/chunk-RLK72AOU.mjs.br +0 -0
  39. package/dist/{chunk-R2N2UYT7.mjs.gz → chunk-RLK72AOU.mjs.gz} +0 -0
  40. package/dist/{chunk-ZKDE3HJI.js → chunk-RNZJKGA7.js} +219 -219
  41. package/dist/chunk-RNZJKGA7.js.br +0 -0
  42. package/dist/chunk-RNZJKGA7.js.gz +0 -0
  43. package/dist/{chunk-B6NRDUHJ.mjs → chunk-SOHIKHL4.mjs} +3 -3
  44. package/dist/chunk-SOHIKHL4.mjs.br +0 -0
  45. package/dist/chunk-SOHIKHL4.mjs.gz +0 -0
  46. package/dist/{chunk-OKOJVSKJ.js → chunk-UTTXH3GH.js} +410 -2
  47. package/dist/chunk-UTTXH3GH.js.br +0 -0
  48. package/dist/{chunk-OKOJVSKJ.js.gz → chunk-UTTXH3GH.js.gz} +0 -0
  49. package/dist/{chunk-CUUYYYC5.js → chunk-YIFO3WQO.js} +10 -1
  50. package/dist/chunk-YIFO3WQO.js.br +0 -0
  51. package/dist/chunk-YIFO3WQO.js.gz +0 -0
  52. package/dist/i18n.js +4 -4
  53. package/dist/i18n.js.br +0 -0
  54. package/dist/i18n.js.gz +0 -0
  55. package/dist/i18n.mjs +1 -1
  56. package/dist/i18n.mjs.br +0 -0
  57. package/dist/i18n.mjs.gz +0 -0
  58. package/dist/{index-a8wcFjRJ.d.ts → index-CDCSXtK3.d.ts} +32 -16
  59. package/dist/index-CDCSXtK3.d.ts.map +1 -0
  60. package/dist/index.js +35 -35
  61. package/dist/index.js.br +0 -0
  62. package/dist/index.js.gz +0 -0
  63. package/dist/index.mjs +5 -5
  64. package/dist/index.mjs.br +0 -0
  65. package/dist/index.mjs.gz +0 -0
  66. package/dist/internals.d.ts +142 -14
  67. package/dist/internals.d.ts.map +1 -1
  68. package/dist/internals.js +79 -79
  69. package/dist/internals.js.br +0 -0
  70. package/dist/internals.js.gz +0 -0
  71. package/dist/internals.mjs +4 -4
  72. package/dist/internals.mjs.br +0 -0
  73. package/dist/internals.mjs.gz +0 -0
  74. package/dist/pptx-viewer.css +1 -1
  75. package/dist/pptx-viewer.css.br +0 -0
  76. package/dist/pptx-viewer.css.gz +0 -0
  77. package/dist/viewer/index.js +21 -21
  78. package/dist/viewer/index.js.br +0 -0
  79. package/dist/viewer/index.js.gz +0 -0
  80. package/dist/viewer/index.mjs +5 -5
  81. package/dist/viewer/index.mjs.br +0 -0
  82. package/dist/viewer/index.mjs.gz +0 -0
  83. package/package.json +5 -3
  84. package/dist/AiChatPanel-BRGQCYZM.mjs.br +0 -0
  85. package/dist/AiChatPanel-BRGQCYZM.mjs.gz +0 -0
  86. package/dist/AiChatPanel-PW5OT25Z.js.br +0 -0
  87. package/dist/AiChatPanel-PW5OT25Z.js.gz +0 -0
  88. package/dist/Model3DScene-JCGYRKXM.js.br +0 -0
  89. package/dist/Model3DScene-JCGYRKXM.js.gz +0 -0
  90. package/dist/Model3DScene-TEF362W2.mjs.gz +0 -0
  91. package/dist/SurfaceChart3DScene-2SHCYZVC.js.br +0 -0
  92. package/dist/SurfaceChart3DScene-2SHCYZVC.js.gz +0 -0
  93. package/dist/SurfaceChart3DScene-UPDCIMJM.mjs.gz +0 -0
  94. package/dist/chunk-2X72MOPZ.mjs.br +0 -0
  95. package/dist/chunk-2X72MOPZ.mjs.gz +0 -0
  96. package/dist/chunk-5XLLRPMV.mjs.br +0 -0
  97. package/dist/chunk-5XLLRPMV.mjs.gz +0 -0
  98. package/dist/chunk-B6NRDUHJ.mjs.br +0 -0
  99. package/dist/chunk-B6NRDUHJ.mjs.gz +0 -0
  100. package/dist/chunk-CUUYYYC5.js.br +0 -0
  101. package/dist/chunk-CUUYYYC5.js.gz +0 -0
  102. package/dist/chunk-L63RAVM7.mjs.br +0 -0
  103. package/dist/chunk-L63RAVM7.mjs.gz +0 -0
  104. package/dist/chunk-LFXG7SGG.js.br +0 -0
  105. package/dist/chunk-LFXG7SGG.js.gz +0 -0
  106. package/dist/chunk-OKOJVSKJ.js.br +0 -0
  107. package/dist/chunk-R2N2UYT7.mjs.br +0 -0
  108. package/dist/chunk-ZB4NZRCI.js.br +0 -0
  109. package/dist/chunk-ZB4NZRCI.js.gz +0 -0
  110. package/dist/chunk-ZKDE3HJI.js.br +0 -0
  111. package/dist/chunk-ZKDE3HJI.js.gz +0 -0
  112. package/dist/index-a8wcFjRJ.d.ts.map +0 -1
Binary file
Binary file
@@ -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-B6NRDUHJ.mjs';
2
- import { TOOLBAR_TABS, computeVirtualRange, DEFAULT_VIRTUAL_OVERSCAN, BROADCAST_THROTTLE_MS, createSyncGate, validateRoomId, resolveTransportForServerUrl, isMixedContentBlocked, CONNECTION_TIMEOUT_MS, sanitizeColor, cloneTemplateElementsBySlideId, cloneSlide, PresentationAnimationController, computeEntranceAnimationDelay, PRESENTATION_HASH, PRESENTATION_NONCE_KEY, PRESENTATION_CHANNEL_NAME, swapPresentationWindows, PRESENTATION_MESSAGE_ORIGIN, clearAudienceContent, buildPresentationAudienceUrl, resolveAudienceScreenPlacement, placeAudienceWindow, storeAudienceContent, isPresentationSessionMessage, collectMediaElements, collectImagePaths, buildInitialGuides, saveAutosaveSnapshot, isTemplateElementId, 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, comparePresentation, applyAcceptSlide, applyAcceptAllSlides, collectUsedFonts, detectTouchDevice, detectOrientation, isMobileViewport, MOBILE_BREAKPOINT, TABLET_BREAKPOINT, remapTextToSegments, 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, derivePresenceList, buildPrintDocument, buildOutlineHtml, buildSlidesHtml, buildNotesHtml, buildHandoutsHtml, createBlankSlide, makeSlideId, createPresentationSessionId, resolveTransitionDurationMs, isUrlSafe, createPresenterTimer, createInitialPresentationSnapshot, mergePresentationSnapshot, presenterElapsed, stepPresenterZoom, resetPresenterTimer, togglePresenterTimer, canvasToJpegData, downloadDataUrl, pickSupportedMimeType, WEBM_MIME_CANDIDATES, fpsToFrameIntervalMs, segmentFrameCount, encodeGif, groupSlidesBySection, hasCopyableFormat, createBackstagePresentation, cloneElementForPaste, computeScrollDelta, rerouteConnectorsForMovedElements, applyReroutedConnectors, buildPrintHtmlDocument, deleteTableColumn, insertTableColumn, deleteTableRow, insertTableRow, splitCell, mergeCells, isPpactionUrl, parsePpactionUrl, safeOpenUrl, ACTION_BUTTON_PRESETS, buildSmartArtPresetData, computeSnapToShape, computeMarqueeHitIds, mergeAdditiveSelection, applyResize, snapBoxToGrid } from './chunk-R2N2UYT7.mjs';
3
- import { translationsEn } from './chunk-2X72MOPZ.mjs';
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-SOHIKHL4.mjs';
2
+ 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, createPresentationKeyBuffer, createCollaborationLivePatcher, publishLiveInlineText, collectMediaElements, collectImagePaths, buildInitialGuides, saveAutosaveSnapshot, isTemplateElementId, 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, comparePresentation, applyAcceptSlide, applyAcceptAllSlides, collectUsedFonts, detectTouchDevice, detectOrientation, isMobileViewport, MOBILE_BREAKPOINT, TABLET_BREAKPOINT, remapTextToSegments, 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, derivePresenceList, mapPresentationKey, buildPrintDocument, buildOutlineHtml, buildSlidesHtml, buildNotesHtml, buildHandoutsHtml, createBlankSlide, makeSlideId, createPresentationSessionId, resolveTransitionDurationMs, isUrlSafe, createPresenterTimer, createInitialPresentationSnapshot, mergePresentationSnapshot, presenterElapsed, stepPresenterZoom, resetPresenterTimer, togglePresenterTimer, canvasToJpegData, downloadDataUrl, pickSupportedMimeType, WEBM_MIME_CANDIDATES, fpsToFrameIntervalMs, segmentFrameCount, encodeGif, groupSlidesBySection, hasCopyableFormat, createBackstagePresentation, cloneElementForPaste, computeScrollDelta, rerouteConnectorsForMovedElements, applyReroutedConnectors, buildPrintHtmlDocument, deleteTableColumn, insertTableColumn, deleteTableRow, insertTableRow, splitCell, mergeCells, isPpactionUrl, parsePpactionUrl, safeOpenUrl, ACTION_BUTTON_PRESETS, buildSmartArtPresetData, computeSnapToShape, publishLiveGeometry, computeMarqueeHitIds, mergeAdditiveSelection, applyResize, snapBoxToGrid } from './chunk-RLK72AOU.mjs';
3
+ import { translationsEn } from './chunk-PZTPX3HK.mjs';
4
4
  import { PptxHandler, EncryptedFileError, hasShapeProperties, hasTextProperties, applyThemeToData, THEME_PRESETS, themeColorSchemesEqual, guidePxToEmu, mergeShapes, buildThemeColorMap, reResolveSlideColors, getPresetShapeClipPath, svgPathToPolygons, polygonsToSvgPath, SvgExporter, rebuildTableStructureInRawXml, updateCellTextStyleInRawXml, updateCellTextInRawXml, updateMergeAttrsInRawXml, elementActionToPptxAction } from './chunk-6YXLGMTN.mjs';
5
5
  import { useRef, useState, useEffect, useCallback, useMemo, useSyncExternalStore, useImperativeHandle } from 'react';
6
6
  import JSZip from 'jszip';
@@ -186,6 +186,7 @@ function useYjsProvider({ config }) {
186
186
  const [synced, setSynced] = useState(false);
187
187
  const cleanupRef = useRef(null);
188
188
  const timeoutRef = useRef(null);
189
+ const departureRef = useRef(null);
189
190
  const gateRef = useRef(null);
190
191
  if (!gateRef.current) {
191
192
  gateRef.current = createSyncGate(() => setSynced(true));
@@ -200,8 +201,15 @@ function useYjsProvider({ config }) {
200
201
  cleanupRef.current?.();
201
202
  cleanupRef.current = null;
202
203
  }, []);
204
+ const announceDeparture = useCallback(() => {
205
+ departureRef.current?.announce();
206
+ departureRef.current?.dispose();
207
+ departureRef.current = null;
208
+ }, []);
203
209
  const buildCleanup = useCallback(
204
210
  (provider, yDoc) => () => {
211
+ announceDeparture();
212
+ clearLocalAwareness(provider.awareness);
205
213
  provider.destroy();
206
214
  yDoc.destroy();
207
215
  setDoc(null);
@@ -209,7 +217,7 @@ function useYjsProvider({ config }) {
209
217
  setClientId(null);
210
218
  setStatus("disconnected");
211
219
  },
212
- []
220
+ [announceDeparture]
213
221
  );
214
222
  const initWebrtc = useCallback(async () => {
215
223
  if (!config) {
@@ -226,7 +234,9 @@ function useYjsProvider({ config }) {
226
234
  if (config.authToken) {
227
235
  opts.password = config.authToken;
228
236
  }
229
- const provider = new WebrtcProvider(validateRoomId(config.roomId), yDoc, opts);
237
+ const roomId = validateRoomId(config.roomId);
238
+ const provider = new WebrtcProvider(roomId, yDoc, opts);
239
+ departureRef.current = createDepartureChannel(roomId, provider.awareness);
230
240
  setDoc(yDoc);
231
241
  setAwareness(provider.awareness);
232
242
  setClientId(provider.awareness.clientID);
@@ -288,6 +298,7 @@ function useYjsProvider({ config }) {
288
298
  const provider = new WebsocketProvider(config.serverUrl, roomId, yDoc, {
289
299
  params: config.authToken ? { token: config.authToken } : void 0
290
300
  });
301
+ departureRef.current = createDepartureChannel(roomId, provider.awareness);
291
302
  let connected = false;
292
303
  const handleStatus = (event) => {
293
304
  if (event.status === "connected") {
@@ -326,6 +337,8 @@ function useYjsProvider({ config }) {
326
337
  if (!connected) {
327
338
  provider.off("status", handleStatus);
328
339
  provider.off("sync", handleSynced);
340
+ announceDeparture();
341
+ clearLocalAwareness(provider.awareness);
329
342
  provider.destroy();
330
343
  yDoc.destroy();
331
344
  setDoc(null);
@@ -342,6 +355,8 @@ function useYjsProvider({ config }) {
342
355
  cleanupRef.current = () => {
343
356
  provider.off("status", handleStatus);
344
357
  provider.off("sync", handleSynced);
358
+ announceDeparture();
359
+ clearLocalAwareness(provider.awareness);
345
360
  provider.destroy();
346
361
  yDoc.destroy();
347
362
  setDoc(null);
@@ -361,12 +376,20 @@ function useYjsProvider({ config }) {
361
376
  config?.serverUrl,
362
377
  config?.authToken,
363
378
  config?.transport,
379
+ announceDeparture,
364
380
  initWebrtc,
365
381
  teardown
366
382
  ]);
367
383
  useEffect(() => {
368
384
  init();
369
- return teardown;
385
+ const disposeTeardown = registerCollaborationTeardown({
386
+ leave: teardown,
387
+ rejoin: init
388
+ });
389
+ return () => {
390
+ disposeTeardown();
391
+ teardown();
392
+ };
370
393
  }, [init, teardown]);
371
394
  const retry = useCallback(() => {
372
395
  init();
@@ -1536,53 +1559,18 @@ function useAudienceMode(input) {
1536
1559
  };
1537
1560
  }, [onSetMode, onSetActiveSlideIndex, onSnapshot]);
1538
1561
  }
1539
-
1540
- // src/viewer/hooks/presentation-mode/keyboard-helpers.ts
1541
- function mapKeyToPresentationAction(key, ctrlKey) {
1542
- if (key === "Escape") {
1543
- return { action: "exit" };
1544
- }
1545
- if (key === "ArrowRight" || key === "PageDown" || key === " ") {
1546
- return { action: "next" };
1547
- }
1548
- if (key === "ArrowLeft" || key === "PageUp") {
1549
- return { action: "prev" };
1550
- }
1551
- if (key === "l" || key === "L") {
1552
- return { action: "toggleLaser" };
1553
- }
1554
- if (key === "p" || key === "P") {
1555
- return { action: "togglePen" };
1556
- }
1557
- if (key === "e" || key === "E") {
1558
- return { action: "toggleEraser" };
1559
- }
1560
- if (key === "b" || key === "B") {
1561
- return { action: "toggleBlackScreen" };
1562
- }
1563
- if (key === "w" || key === "W") {
1564
- return { action: "toggleWhiteScreen" };
1565
- }
1566
- if (key === "m" && ctrlKey) {
1567
- return { action: "toggleToolbar" };
1568
- }
1569
- if (key === "n" || key === "N") {
1570
- return { action: "togglePresenterView" };
1571
- }
1572
- return { action: "none" };
1573
- }
1574
-
1575
- // src/viewer/hooks/presentation-mode/usePresentationKeyboard.ts
1576
1562
  function usePresentationKeyboard(input) {
1577
1563
  const {
1578
1564
  mode,
1579
1565
  movePresentationSlide,
1566
+ navigateToSlide,
1567
+ slideCount,
1580
1568
  onSetMode,
1581
- onToggleLaser,
1582
- onTogglePen,
1583
- onToggleEraser,
1569
+ onSetPointerTool,
1570
+ onEraseAnnotations,
1571
+ onToggleInkMarkup,
1584
1572
  onToggleToolbar,
1585
- onTogglePresenterView,
1573
+ onShowAllSlides,
1586
1574
  onToggleBlackScreen,
1587
1575
  onToggleWhiteScreen,
1588
1576
  rehearsing,
@@ -1590,18 +1578,20 @@ function usePresentationKeyboard(input) {
1590
1578
  presentationSlideIndex,
1591
1579
  setShowRehearsalSummary
1592
1580
  } = input;
1581
+ const keyBufferRef = useRef(createPresentationKeyBuffer());
1593
1582
  useEffect(() => {
1594
1583
  if (mode !== "present") {
1584
+ keyBufferRef.current = createPresentationKeyBuffer();
1595
1585
  return;
1596
1586
  }
1597
1587
  const handleKeyDown = (event) => {
1598
- const mapped = mapKeyToPresentationAction(event.key, event.ctrlKey);
1588
+ const mapped = mapPresentationKey(event, keyBufferRef.current);
1599
1589
  if (mapped.action === "none") {
1600
1590
  return;
1601
1591
  }
1602
1592
  event.preventDefault();
1603
1593
  switch (mapped.action) {
1604
- case "exit":
1594
+ case "end":
1605
1595
  if (rehearsing) {
1606
1596
  recordCurrentSlideTime(presentationSlideIndex);
1607
1597
  setShowRehearsalSummary(true);
@@ -1611,27 +1601,40 @@ function usePresentationKeyboard(input) {
1611
1601
  case "next":
1612
1602
  movePresentationSlide(1);
1613
1603
  return;
1614
- case "prev":
1604
+ case "previous":
1615
1605
  movePresentationSlide(-1);
1616
1606
  return;
1617
- case "toggleLaser":
1618
- onToggleLaser?.();
1607
+ case "first":
1608
+ navigateToSlide(0);
1609
+ return;
1610
+ case "last":
1611
+ navigateToSlide(Math.max(0, slideCount - 1));
1612
+ return;
1613
+ case "goto": {
1614
+ const index = mapped.slideNumber - 1;
1615
+ if (index >= 0 && index < slideCount) {
1616
+ navigateToSlide(index);
1617
+ }
1618
+ return;
1619
+ }
1620
+ case "pointerTool":
1621
+ onSetPointerTool?.(mapped.tool);
1619
1622
  return;
1620
- case "togglePen":
1621
- onTogglePen?.();
1623
+ case "eraseAnnotations":
1624
+ onEraseAnnotations?.();
1622
1625
  return;
1623
- case "toggleEraser":
1624
- onToggleEraser?.();
1626
+ case "toggleInkMarkup":
1627
+ onToggleInkMarkup?.();
1625
1628
  return;
1626
- case "toggleToolbar":
1629
+ case "toggleChrome":
1627
1630
  onToggleToolbar?.();
1628
1631
  return;
1629
- case "togglePresenterView":
1630
- onTogglePresenterView?.();
1631
- break;
1632
+ case "showAllSlides":
1633
+ onShowAllSlides?.();
1634
+ return;
1632
1635
  case "toggleBlackScreen":
1633
1636
  onToggleBlackScreen?.();
1634
- break;
1637
+ return;
1635
1638
  case "toggleWhiteScreen":
1636
1639
  onToggleWhiteScreen?.();
1637
1640
  break;
@@ -1644,12 +1647,14 @@ function usePresentationKeyboard(input) {
1644
1647
  }, [
1645
1648
  mode,
1646
1649
  movePresentationSlide,
1650
+ navigateToSlide,
1651
+ slideCount,
1647
1652
  onSetMode,
1648
- onToggleLaser,
1649
- onTogglePen,
1650
- onToggleEraser,
1653
+ onSetPointerTool,
1654
+ onEraseAnnotations,
1655
+ onToggleInkMarkup,
1651
1656
  onToggleToolbar,
1652
- onTogglePresenterView,
1657
+ onShowAllSlides,
1653
1658
  onToggleBlackScreen,
1654
1659
  onToggleWhiteScreen,
1655
1660
  rehearsing,
@@ -2101,9 +2106,9 @@ function usePresentationMode(input) {
2101
2106
  onSetMode,
2102
2107
  onSetActiveSlideIndex,
2103
2108
  onPlayActionSound,
2104
- onToggleLaser,
2105
- onTogglePen,
2106
- onToggleEraser,
2109
+ onSetPointerTool,
2110
+ onEraseAnnotations,
2111
+ onToggleInkMarkup,
2107
2112
  onToggleToolbar,
2108
2113
  onSaveRehearsalTimings,
2109
2114
  loopContinuously,
@@ -2118,6 +2123,7 @@ function usePresentationMode(input) {
2118
2123
  setTransitionOverlay(null);
2119
2124
  }, []);
2120
2125
  const [presenterMode, setPresenterMode] = useState(false);
2126
+ const [allSlidesOpen, setAllSlidesOpen] = useState(false);
2121
2127
  const [endOfShowVisible, setEndOfShowVisible] = useState(false);
2122
2128
  const [presentationStartTime, setPresentationStartTime] = useState(null);
2123
2129
  const switchingToPresenterRef = useRef(false);
@@ -2202,6 +2208,8 @@ function usePresentationMode(input) {
2202
2208
  [endOfShowVisible, moveNavigationSlide, onSetMode]
2203
2209
  );
2204
2210
  const { handleZoomClick, zoomReturnSlideIndex, returnToZoomSlide, clearZoomReturn } = useZoomNavigation({ navigateToSlide });
2211
+ const openAllSlides = useCallback(() => setAllSlidesOpen(true), []);
2212
+ const closeAllSlides = useCallback(() => setAllSlidesOpen(false), []);
2205
2213
  const presenterConsole = usePresenterConsole(presentationSlideIndex);
2206
2214
  const {
2207
2215
  openAudienceWindow,
@@ -2274,12 +2282,14 @@ function usePresentationMode(input) {
2274
2282
  usePresentationKeyboard({
2275
2283
  mode,
2276
2284
  movePresentationSlide,
2285
+ navigateToSlide,
2286
+ slideCount: slides.length,
2277
2287
  onSetMode,
2278
- onToggleLaser,
2279
- onTogglePen,
2280
- onToggleEraser,
2288
+ onSetPointerTool,
2289
+ onEraseAnnotations,
2290
+ onToggleInkMarkup,
2281
2291
  onToggleToolbar,
2282
- onTogglePresenterView: togglePresenterView,
2292
+ onShowAllSlides: openAllSlides,
2283
2293
  onToggleBlackScreen: () => presenterConsole.setBlackout(
2284
2294
  presenterConsole.snapshot.blackout === "black" ? "none" : "black"
2285
2295
  ),
@@ -2379,6 +2389,9 @@ function usePresentationMode(input) {
2379
2389
  clearPresentationTimers,
2380
2390
  runPresentationEntranceAnimations,
2381
2391
  endOfShowVisible,
2392
+ allSlidesOpen,
2393
+ openAllSlides,
2394
+ closeAllSlides,
2382
2395
  movePresentationSlide,
2383
2396
  navigateToSlide,
2384
2397
  handlePresentationAction,
@@ -2439,6 +2452,7 @@ function usePresentationAnnotations(input) {
2439
2452
  const [currentStroke, setCurrentStroke] = useState(null);
2440
2453
  const [laserPosition, setLaserPosition] = useState(null);
2441
2454
  const [toolbarVisible, setToolbarVisible] = useState(false);
2455
+ const [inkMarkupVisible, setInkMarkupVisible] = useState(true);
2442
2456
  const slideAnnotationsRef = useRef(/* @__PURE__ */ new Map());
2443
2457
  const [annotationStrokes, setAnnotationStrokes] = useState([]);
2444
2458
  const [annotationVersion, setAnnotationVersion] = useState(0);
@@ -2624,6 +2638,8 @@ function usePresentationAnnotations(input) {
2624
2638
  laserPosition,
2625
2639
  toolbarVisible,
2626
2640
  setToolbarVisible,
2641
+ inkMarkupVisible,
2642
+ setInkMarkupVisible,
2627
2643
  handlePointerDown,
2628
2644
  handlePointerMove,
2629
2645
  handlePointerUp,
@@ -3293,6 +3309,9 @@ function useViewerCoreState(_input) {
3293
3309
  const shapeAdjustmentDragStateRef = useRef(null);
3294
3310
  const marqueeStateRef = useRef(null);
3295
3311
  const isDrawingRef = useRef(false);
3312
+ const livePatcher = useMemo(() => createCollaborationLivePatcher(), []);
3313
+ useEffect(() => () => livePatcher.dispose(), [livePatcher]);
3314
+ const slidesRef = useRef([]);
3296
3315
  const [mode, setMode] = useState("edit");
3297
3316
  const [loading, setLoading] = useState(true);
3298
3317
  const [error, setError] = useState(null);
@@ -3320,8 +3339,14 @@ function useViewerCoreState(_input) {
3320
3339
  const resolved = typeof value === "function" ? value(inlineEditingTextRef.current) : value;
3321
3340
  inlineEditingTextRef.current = resolved;
3322
3341
  setInlineEditingTextBase(value);
3342
+ publishLiveInlineText(
3343
+ livePatcher,
3344
+ slidesRef.current[activeSlideIndexRef.current],
3345
+ inlineEditingElementIdRef.current,
3346
+ resolved
3347
+ );
3323
3348
  },
3324
- []
3349
+ [livePatcher]
3325
3350
  );
3326
3351
  const [editTemplateMode, setEditTemplateMode] = useState(false);
3327
3352
  const [newShapeType, setNewShapeType] = useState("rect");
@@ -3355,6 +3380,7 @@ function useViewerCoreState(_input) {
3355
3380
  const [preMasterMode, setPreMasterMode] = useState("edit");
3356
3381
  const [masterViewTab, setMasterViewTab] = useState("slides");
3357
3382
  const [handoutSlidesPerPage, setHandoutSlidesPerPage] = useState(4);
3383
+ slidesRef.current = slides;
3358
3384
  const derived = useDerivedElementState({
3359
3385
  slides,
3360
3386
  activeSlideIndex,
@@ -3379,6 +3405,7 @@ function useViewerCoreState(_input) {
3379
3405
  shapeAdjustmentDragStateRef,
3380
3406
  marqueeStateRef,
3381
3407
  isDrawingRef,
3408
+ livePatcher,
3382
3409
  mode,
3383
3410
  setMode,
3384
3411
  loading,
@@ -4166,6 +4193,13 @@ function computeAdjustmentValue(startAdjustment, dx, startWidth) {
4166
4193
  const delta = dx / range;
4167
4194
  return Math.max(0, Math.min(1, startAdjustment + delta));
4168
4195
  }
4196
+ function resolveLiveTarget(input) {
4197
+ const { livePatcher, editTemplateMode, activeSlide } = input;
4198
+ if (!livePatcher || editTemplateMode || !livePatcher.isActive()) {
4199
+ return void 0;
4200
+ }
4201
+ return { patcher: livePatcher, slideId: activeSlide?.id };
4202
+ }
4169
4203
  function processPointerMove(e, input, tracker) {
4170
4204
  const {
4171
4205
  editorScale,
@@ -4214,13 +4248,14 @@ function processPointerMove(e, input, tracker) {
4214
4248
  guides,
4215
4249
  elementLookup,
4216
4250
  tracker,
4217
- setSnapLines
4251
+ setSnapLines,
4252
+ resolveLiveTarget(input)
4218
4253
  );
4219
4254
  return;
4220
4255
  }
4221
4256
  const rs = resizeStateRef.current;
4222
4257
  if (rs) {
4223
- processResizeMove(e, rs, editorScale, snapToGrid, gridSpacingPx);
4258
+ processResizeMove(e, rs, editorScale, snapToGrid, gridSpacingPx, resolveLiveTarget(input));
4224
4259
  return;
4225
4260
  }
4226
4261
  const adj = shapeAdjustmentDragStateRef.current;
@@ -4238,7 +4273,7 @@ function processMarqueeMove(e, marquee, canvasStageRef, canvasSize, editorScale,
4238
4273
  marquee.currentY = Math.max(0, Math.min(canvasSize.height, (e.clientY - rect.top) / editorScale));
4239
4274
  setMarqueeSelectionState({ ...marquee });
4240
4275
  }
4241
- function processDragMove(e, drag, editorScale, snapToGrid, snapToShape, gridSpacingPx, editTemplateMode, templateElements, activeSlide, guides, elementLookup, tracker, setSnapLines) {
4276
+ function processDragMove(e, drag, editorScale, snapToGrid, snapToShape, gridSpacingPx, editTemplateMode, templateElements, activeSlide, guides, elementLookup, tracker, setSnapLines, live) {
4242
4277
  const dx = (e.clientX - drag.startClientX) / editorScale;
4243
4278
  const dy = (e.clientY - drag.startClientY) / editorScale;
4244
4279
  if (!drag.moved && (Math.abs(dx) > 2 || Math.abs(dy) > 2)) {
@@ -4305,8 +4340,17 @@ function processDragMove(e, drag, editorScale, snapToGrid, snapToShape, gridSpac
4305
4340
  domEl.style.top = `${start.y + appliedDy}px`;
4306
4341
  }
4307
4342
  }
4343
+ if (live) {
4344
+ for (const id of Object.keys(drag.startPositionsById)) {
4345
+ const start = drag.startPositionsById[id];
4346
+ publishLiveGeometry(live.patcher, live.slideId, id, {
4347
+ x: start.x + appliedDx,
4348
+ y: start.y + appliedDy
4349
+ });
4350
+ }
4351
+ }
4308
4352
  }
4309
- function processResizeMove(e, rs, editorScale, snapToGrid, gridSpacingPx) {
4353
+ function processResizeMove(e, rs, editorScale, snapToGrid, gridSpacingPx, live) {
4310
4354
  const dx = (e.clientX - rs.startClientX) / editorScale;
4311
4355
  const dy = (e.clientY - rs.startClientY) / editorScale;
4312
4356
  if (!rs.moved && (Math.abs(dx) > 2 || Math.abs(dy) > 2)) {
@@ -4336,6 +4380,14 @@ function processResizeMove(e, rs, editorScale, snapToGrid, gridSpacingPx) {
4336
4380
  rs.domEl.style.width = `${Math.max(geo.width, MIN_ELEMENT_SIZE)}px`;
4337
4381
  rs.domEl.style.height = `${Math.max(geo.height, MIN_ELEMENT_SIZE)}px`;
4338
4382
  }
4383
+ if (live) {
4384
+ publishLiveGeometry(live.patcher, live.slideId, rs.elementId, {
4385
+ x: geo.x,
4386
+ y: geo.y,
4387
+ width: Math.max(geo.width, MIN_ELEMENT_SIZE),
4388
+ height: Math.max(geo.height, MIN_ELEMENT_SIZE)
4389
+ });
4390
+ }
4339
4391
  }
4340
4392
  function processAdjustmentMove(e, adj, editorScale, updateElementById) {
4341
4393
  const dx = (e.clientX - adj.startClientX) / editorScale;
@@ -4369,7 +4421,8 @@ function processPointerUp(input) {
4369
4421
  clearSelection,
4370
4422
  updateSlides,
4371
4423
  updateElementById,
4372
- markDirty
4424
+ markDirty,
4425
+ livePatcher
4373
4426
  } = input;
4374
4427
  const marquee = marqueeStateRef.current;
4375
4428
  const drag = dragStateRef.current;
@@ -4424,6 +4477,9 @@ function processPointerUp(input) {
4424
4477
  );
4425
4478
  }
4426
4479
  const wasMoved = drag?.moved || rs?.moved || adj?.moved;
4480
+ if (wasMoved) {
4481
+ livePatcher?.flush();
4482
+ }
4427
4483
  marqueeStateRef.current = null;
4428
4484
  dragStateRef.current = null;
4429
4485
  resizeStateRef.current = null;
@@ -4508,7 +4564,8 @@ function usePointerHandlers(input) {
4508
4564
  clearSelection,
4509
4565
  updateSlides,
4510
4566
  updateElementById,
4511
- markDirty
4567
+ markDirty,
4568
+ livePatcher
4512
4569
  } = input;
4513
4570
  useEffect(() => {
4514
4571
  const tracker = {
@@ -4572,6 +4629,7 @@ function usePointerHandlers(input) {
4572
4629
  updateSlides,
4573
4630
  updateElementById,
4574
4631
  markDirty,
4632
+ livePatcher,
4575
4633
  input
4576
4634
  ]);
4577
4635
  }
@@ -8572,9 +8630,10 @@ function usePresentationSetup(input) {
8572
8630
  }
8573
8631
  })();
8574
8632
  },
8575
- onToggleLaser: () => annotations.setPresentationTool("laser"),
8576
- onTogglePen: () => annotations.setPresentationTool("pen"),
8577
- onToggleEraser: () => annotations.setPresentationTool("eraser"),
8633
+ // PowerPoint's Ctrl+A "arrow" is the plain pointer, i.e. no active tool.
8634
+ onSetPointerTool: (tool) => annotations.setPresentationTool(tool === "arrow" ? "none" : tool),
8635
+ onEraseAnnotations: () => annotations.clearAnnotations(),
8636
+ onToggleInkMarkup: () => annotations.setInkMarkupVisible(!annotations.inkMarkupVisible),
8578
8637
  onToggleToolbar: () => annotations.setToolbarVisible(!annotations.toolbarVisible),
8579
8638
  onSaveRehearsalTimings: (timings) => {
8580
8639
  setSlides((prev) => applyRehearsalTimings(prev, timings));
@@ -9391,7 +9450,8 @@ function useViewerIntegration(input) {
9391
9450
  clearSelection: editorOps.ops.clearSelection,
9392
9451
  updateSlides: editorOps.ops.updateSlides,
9393
9452
  updateElementById: editorOps.ops.updateElementById,
9394
- markDirty: history.markDirty
9453
+ markDirty: history.markDirty,
9454
+ livePatcher: state.livePatcher
9395
9455
  });
9396
9456
  const [isEncryptedDialogOpen, setIsEncryptedDialogOpen] = useState(false);
9397
9457
  const [loadVersion, setLoadVersion] = useState(0);
@@ -9976,6 +10036,36 @@ function useFollowMode({
9976
10036
  }, [activeSlideIndex, followedClientId]);
9977
10037
  return { followedClientId, followUser };
9978
10038
  }
10039
+ function useCollaborationLivePatch({
10040
+ patcher,
10041
+ doc,
10042
+ isConnected,
10043
+ isSynced = true
10044
+ }) {
10045
+ useEffect(() => {
10046
+ if (!doc || !isConnected || !isSynced) {
10047
+ patcher.configure(null, null);
10048
+ return;
10049
+ }
10050
+ let cancelled = false;
10051
+ void (async () => {
10052
+ const Y = await import('./yjs-FKGX4QHS.mjs');
10053
+ if (cancelled) {
10054
+ return;
10055
+ }
10056
+ const factories = {
10057
+ createMap: () => new Y.Map(),
10058
+ createArray: () => new Y.Array(),
10059
+ createText: () => new Y.Text()
10060
+ };
10061
+ patcher.configure(doc, factories);
10062
+ })();
10063
+ return () => {
10064
+ cancelled = true;
10065
+ patcher.configure(null, null);
10066
+ };
10067
+ }, [patcher, doc, isConnected, isSynced]);
10068
+ }
9979
10069
  function useLayoutSwitching(input) {
9980
10070
  const { handler, slides, activeSlideIndex, ops, history } = input;
9981
10071
  const [availableLayouts, setAvailableLayouts] = useState([]);
@@ -11022,4 +11112,4 @@ function useResizablePanels() {
11022
11112
  };
11023
11113
  }
11024
11114
 
11025
- export { ACTION_VERB_MAP, MIN_TOUCH_TARGET, computeToolbarVisibility, detectTargetType, downloadBlob2 as downloadBlob, isAudienceTab, parseAudienceNonce, parseEmailUrl, parseSlideFromUrl, renderToCanvas, scopeLayoutOptionsToActiveSlide, useAnimationPlayback, useAnnotationHandlers, useAudienceMode, useAutosave, useBroadcastFollower, useCanvasInteractions, useClipboardHandlers, 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, useViewerState, useViewerUIState, useVirtualizedSlides, useYjsDocumentSync, useYjsProvider, useZoomNavigation, useZoomViewport };
11115
+ export { ACTION_VERB_MAP, MIN_TOUCH_TARGET, computeToolbarVisibility, detectTargetType, downloadBlob2 as downloadBlob, 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, useViewerState, useViewerUIState, useVirtualizedSlides, useYjsDocumentSync, useYjsProvider, useZoomNavigation, useZoomViewport };
Binary file
Binary file
@@ -375,6 +375,7 @@ var translationsEn = {
375
375
  "pptx.presentation.highlighter": "Highlighter",
376
376
  "pptx.presentation.eraser": "Eraser",
377
377
  "pptx.presentation.laserPointer": "Laser Pointer",
378
+ "pptx.presentation.pointerTools": "Pointer Options",
378
379
  // Selection pane
379
380
  "pptx.selectionPane.title": "Selection Pane",
380
381
  "pptx.selectionPane.empty": "No elements",
@@ -1101,9 +1102,17 @@ var translationsEn = {
1101
1102
  "pptx.presenter.nextSlide": "Next Slide",
1102
1103
  "pptx.presenter.noSlides": "No slides",
1103
1104
  "pptx.presenter.openAudienceWindow": "Open Audience Window",
1104
- "pptx.presenter.presenterView": "Presenter View (N)",
1105
+ "pptx.presenter.presenterView": "Presenter View",
1105
1106
  "pptx.presenter.prev": "Prev",
1106
1107
  "pptx.presenter.previousSlide": "Previous Slide",
1108
+ "pptx.presenter.seeAllSlides": "See All Slides",
1109
+ "pptx.presenter.screen": "Screen",
1110
+ "pptx.presenter.blackScreen": "Black Screen",
1111
+ "pptx.presenter.whiteScreen": "White Screen",
1112
+ "pptx.presenter.pointerArrow": "Arrow",
1113
+ "pptx.presenter.pointerPen": "Pen",
1114
+ "pptx.presenter.pointerHighlighter": "Highlighter",
1115
+ "pptx.presenter.eraseAllInk": "Erase All Ink on Slide",
1107
1116
  "pptx.presenter.slideLabel": "Slide {{current}} of {{total}}",
1108
1117
  "pptx.presenter.timerProgress": "Timer Progress",
1109
1118
  // Print dialog
Binary file
Binary file