pptx-react-viewer 1.17.1 → 1.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +1 -1
  3. package/dist/{Model3DScene-YA4F63DT.js → Model3DScene-CQP7JLKK.js} +3 -3
  4. package/dist/Model3DScene-CQP7JLKK.js.br +0 -0
  5. package/dist/Model3DScene-CQP7JLKK.js.gz +0 -0
  6. package/dist/{Model3DScene-QHDYQXL2.mjs → Model3DScene-J2KBVMEZ.mjs} +2 -2
  7. package/dist/Model3DScene-J2KBVMEZ.mjs.br +0 -0
  8. package/dist/Model3DScene-J2KBVMEZ.mjs.gz +0 -0
  9. package/dist/PowerPointViewer-C4d7SKZf.d.ts.map +1 -1
  10. package/dist/{SurfaceChart3DScene-GUAS2NWQ.mjs → SurfaceChart3DScene-52VUVZSC.mjs} +2 -2
  11. package/dist/SurfaceChart3DScene-52VUVZSC.mjs.br +0 -0
  12. package/dist/SurfaceChart3DScene-52VUVZSC.mjs.gz +0 -0
  13. package/dist/{SurfaceChart3DScene-TGNJHTJQ.js → SurfaceChart3DScene-U6LVKSKR.js} +3 -3
  14. package/dist/SurfaceChart3DScene-U6LVKSKR.js.br +0 -0
  15. package/dist/SurfaceChart3DScene-U6LVKSKR.js.gz +0 -0
  16. package/dist/{chunk-XRYREYXC.mjs → chunk-3ZGCM6RC.mjs} +39271 -20532
  17. package/dist/chunk-3ZGCM6RC.mjs.br +0 -0
  18. package/dist/chunk-3ZGCM6RC.mjs.gz +0 -0
  19. package/dist/{chunk-IZXN663G.js → chunk-AALZCSY4.js} +7 -0
  20. package/dist/chunk-AALZCSY4.js.br +0 -0
  21. package/dist/chunk-AALZCSY4.js.gz +0 -0
  22. package/dist/{chunk-MGLRKGCH.js → chunk-AD3EAEY6.js} +39323 -20531
  23. package/dist/chunk-AD3EAEY6.js.br +0 -0
  24. package/dist/chunk-AD3EAEY6.js.gz +0 -0
  25. package/dist/{chunk-WH7YXV3I.js → chunk-DBZLZMED.js} +24152 -23261
  26. package/dist/chunk-DBZLZMED.js.br +0 -0
  27. package/dist/chunk-DBZLZMED.js.gz +0 -0
  28. package/dist/{chunk-JWS3RQKN.js → chunk-P3T4E6JQ.js} +3573 -907
  29. package/dist/chunk-P3T4E6JQ.js.br +0 -0
  30. package/dist/chunk-P3T4E6JQ.js.gz +0 -0
  31. package/dist/{chunk-G22EWPLH.mjs → chunk-R7FTNSSP.mjs} +3498 -882
  32. package/dist/chunk-R7FTNSSP.mjs.br +0 -0
  33. package/dist/chunk-R7FTNSSP.mjs.gz +0 -0
  34. package/dist/{chunk-5CD34U2V.mjs → chunk-RIRK64DM.mjs} +7 -0
  35. package/dist/chunk-RIRK64DM.mjs.br +0 -0
  36. package/dist/chunk-RIRK64DM.mjs.gz +0 -0
  37. package/dist/{chunk-PCQH2UBR.mjs → chunk-SLJXGFZS.mjs} +24109 -23218
  38. package/dist/chunk-SLJXGFZS.mjs.br +0 -0
  39. package/dist/chunk-SLJXGFZS.mjs.gz +0 -0
  40. package/dist/{chunk-HN7CPQUG.mjs → chunk-XGTMHQR7.mjs} +244 -785
  41. package/dist/chunk-XGTMHQR7.mjs.br +0 -0
  42. package/dist/chunk-XGTMHQR7.mjs.gz +0 -0
  43. package/dist/{chunk-SXCO5HHN.js → chunk-YF6JD4DO.js} +679 -1231
  44. package/dist/chunk-YF6JD4DO.js.br +0 -0
  45. package/dist/chunk-YF6JD4DO.js.gz +0 -0
  46. package/dist/dist-3YRZ26TL.mjs +2 -0
  47. package/dist/dist-3YRZ26TL.mjs.br +0 -0
  48. package/dist/dist-3YRZ26TL.mjs.gz +0 -0
  49. package/dist/{dist-2ZAH7U6U.js → dist-M2P6HBG4.js} +719 -507
  50. package/dist/dist-M2P6HBG4.js.br +0 -0
  51. package/dist/dist-M2P6HBG4.js.gz +0 -0
  52. package/dist/hooks-unstable.d.ts +1006 -165
  53. package/dist/hooks-unstable.d.ts.map +1 -1
  54. package/dist/hooks-unstable.js +78 -78
  55. package/dist/hooks-unstable.js.br +0 -0
  56. package/dist/hooks-unstable.js.gz +0 -0
  57. package/dist/hooks-unstable.mjs +4 -4
  58. package/dist/hooks-unstable.mjs.br +0 -0
  59. package/dist/hooks-unstable.mjs.gz +0 -0
  60. package/dist/i18n.js +3 -3
  61. package/dist/i18n.js.br +0 -0
  62. package/dist/i18n.js.gz +0 -0
  63. package/dist/i18n.mjs +1 -1
  64. package/dist/i18n.mjs.br +0 -0
  65. package/dist/i18n.mjs.gz +0 -0
  66. package/dist/{index-XGt7MZpa.d.ts → index-DmHVR48M.d.ts} +25 -3
  67. package/dist/index-DmHVR48M.d.ts.map +1 -0
  68. package/dist/index.d.ts +828 -137
  69. package/dist/index.d.ts.map +1 -1
  70. package/dist/index.js +19 -19
  71. package/dist/index.js.br +0 -0
  72. package/dist/index.js.gz +0 -0
  73. package/dist/index.mjs +5 -5
  74. package/dist/index.mjs.br +0 -0
  75. package/dist/index.mjs.gz +0 -0
  76. package/dist/pptx-viewer.css +1 -1
  77. package/dist/pptx-viewer.css.br +0 -0
  78. package/dist/pptx-viewer.css.gz +0 -0
  79. package/dist/viewer/index.d.ts +946 -147
  80. package/dist/viewer/index.d.ts.map +1 -1
  81. package/dist/viewer/index.js +24 -20
  82. package/dist/viewer/index.js.br +0 -0
  83. package/dist/viewer/index.js.gz +0 -0
  84. package/dist/viewer/index.mjs +5 -5
  85. package/dist/viewer/index.mjs.br +0 -0
  86. package/dist/viewer/index.mjs.gz +0 -0
  87. package/package.json +1 -1
  88. package/dist/Model3DScene-QHDYQXL2.mjs.br +0 -0
  89. package/dist/Model3DScene-QHDYQXL2.mjs.gz +0 -0
  90. package/dist/Model3DScene-YA4F63DT.js.br +0 -0
  91. package/dist/Model3DScene-YA4F63DT.js.gz +0 -0
  92. package/dist/SurfaceChart3DScene-GUAS2NWQ.mjs.br +0 -0
  93. package/dist/SurfaceChart3DScene-GUAS2NWQ.mjs.gz +0 -0
  94. package/dist/SurfaceChart3DScene-TGNJHTJQ.js.br +0 -0
  95. package/dist/SurfaceChart3DScene-TGNJHTJQ.js.gz +0 -0
  96. package/dist/chunk-5CD34U2V.mjs.br +0 -0
  97. package/dist/chunk-5CD34U2V.mjs.gz +0 -0
  98. package/dist/chunk-G22EWPLH.mjs.br +0 -0
  99. package/dist/chunk-G22EWPLH.mjs.gz +0 -0
  100. package/dist/chunk-HN7CPQUG.mjs.br +0 -0
  101. package/dist/chunk-HN7CPQUG.mjs.gz +0 -0
  102. package/dist/chunk-IZXN663G.js.br +0 -0
  103. package/dist/chunk-IZXN663G.js.gz +0 -0
  104. package/dist/chunk-JWS3RQKN.js.br +0 -0
  105. package/dist/chunk-JWS3RQKN.js.gz +0 -0
  106. package/dist/chunk-MGLRKGCH.js.br +0 -0
  107. package/dist/chunk-MGLRKGCH.js.gz +0 -0
  108. package/dist/chunk-PCQH2UBR.mjs.br +0 -0
  109. package/dist/chunk-PCQH2UBR.mjs.gz +0 -0
  110. package/dist/chunk-SXCO5HHN.js.br +0 -0
  111. package/dist/chunk-SXCO5HHN.js.gz +0 -0
  112. package/dist/chunk-WH7YXV3I.js.br +0 -0
  113. package/dist/chunk-WH7YXV3I.js.gz +0 -0
  114. package/dist/chunk-XRYREYXC.mjs.br +0 -0
  115. package/dist/chunk-XRYREYXC.mjs.gz +0 -0
  116. package/dist/dist-2ZAH7U6U.js.br +0 -0
  117. package/dist/dist-2ZAH7U6U.js.gz +0 -0
  118. package/dist/dist-MXDC6YTS.mjs +0 -2
  119. package/dist/dist-MXDC6YTS.mjs.br +0 -0
  120. package/dist/dist-MXDC6YTS.mjs.gz +0 -0
  121. package/dist/index-XGt7MZpa.d.ts.map +0 -1
@@ -1,13 +1,12 @@
1
- import { SHAPE_PRESET_DEFS, computeValueRangeForChart, cloneTemplateElementsBySlideId, cloneSlide, countTextSegments, expandTextBuildAnimations, TimelineEngine, TEXT_BUILD_ID_SEP, collectMediaElements, collectImagePaths, buildInitialGuides, saveAutosaveSnapshot, getAnimationInitialStyle, normalizeHexColor, toCssWritingMode, toCssTextOrientation, toCssVerticalDirection, computeAutoFitTextStyle, resolveLineHeight, getKinsokuLineBreakStyles, buildTextBody3DSceneStyle, resolveParagraphRtl, resolveParagraphAlign, resolveCssTextAlign, colorWithOpacity, build3DExtrusionData, getResolvedShapeClipPath, normalizeStrokeDashType, buildCssGradientFromShapeStyle, buildShadowCssFromShapeStyle, buildInnerShadowCssFromShapeStyle, buildMultiLayerShadowCss, buildGlowBoxShadow, getCompoundLineBoxShadow, getEffectDagFilter, buildPatternFillCss, buildReflectionCss, getCssBorderDashStyle, getCompoundLineBorderWidth, getSvgStrokeDasharray, getCompoundLineOffsets, getCompoundLineWidths, clampCropValue, parseDrawingColor, parseDrawingColorOpacity, getPatternSvg, ooxmlDashToCssBorderStyle, computeSelectionRect, rectToCells, isCellInRect, buildChartViewModel, buildPreviewAnimation, isTemplateElementId, getInlineEditorSelection, applyStyleToSelectedSegments, setPendingSelectionRestore, applyCaseTransformToSegments, transformTextCase, addSection, renameSection, deleteSection, moveSectionUp, moveSectionDown, moveSlidesToSection, normalizeColorsForCapture, preprocessCssForCapture, slideProgressPercent, slideStatusLabel, EXPORT_ASSEMBLING_PERCENT, EXPORT_DONE_PERCENT, isExportAbortError, recordProgressPercent, comparePresentation, detectTouchDevice, detectOrientation, isMobileViewport, MOBILE_BREAKPOINT, TABLET_BREAKPOINT, remapTextToSegments, copyFormatFromElement, applyFormatToElement, createSyncGate, validateRoomId, resolveTransportForServerUrl, isMixedContentBlocked, CONNECTION_TIMEOUT_MS, BROADCAST_THROTTLE_MS, sanitizeColor, readSlidesFromYDoc, reconcileSlidesInYDoc, LOCAL_SYNC_ORIGIN, observeYDocSlides, createTouchGestureRecognizer, isKeyboardOpen, buildElementClipboardPayload, downloadBlob, groupElements, generateElementId, makeCloneId, alignElements, distributeElements, bringForward, sendBackward, bringToFront, sendToBack, newTableElement, createDefaultChartElement, readViewportMetrics, computeKeyboardInset, derivePresenceList, buildPrintDocument, buildOutlineHtml, buildSlidesHtml, buildNotesHtml, buildHandoutsHtml, createBlankSlide, makeSlideId, cloneHistorySnapshot, secureRandomUuid, resolveTransitionDurationMs, isUrlSafe, isTemplateElement, substituteFieldText, resolveUnderlineDecorationStyle, hasDistinctScriptFonts, buildTextReflectionCss, getTextAlphaOpacity, buildTextRunFilterChain, buildTextShadowCss, apply3dEffects, clampUnitInterval, getRoundRectRadiusPx, tintColor2, shadeColor2, computeColumnBoundaries, getChartStylePalette, computeLayout, valueToY, formatAxisValue, computeLayoutOptions, splitSeriesByAxis, computeValueRange, getSecondaryValueAxis, seriesColor, paletteColor, resolveRegionCode, normalizeValue, sequentialColorScale, canvasToJpegData, downloadDataUrl, pickSupportedMimeType, WEBM_MIME_CANDIDATES, fpsToFrameIntervalMs, segmentFrameCount, sanitizeDownloadFilename, encodeGif, cloneElementForPaste, computeScrollDelta, rerouteConnectorsForMovedElements, applyReroutedConnectors, buildPrintHtmlDocument, convertOmmlToMathMl, sanitizeMathMl, buildTextFillCss, computeResizedColumnWidths, computeResizedRowHeight, DEFAULT_ROW_HEIGHT, deleteTableColumn, insertTableColumn, deleteTableRow, insertTableRow, splitCell, mergeCells, buildSlidesPdfBytes, buildNotesPdfBytes, ACTION_BUTTON_PRESETS, buildSmartArtPresetData, computeSnapToShape, computeMarqueeHitIds, mergeAdditiveSelection, segmentByScript, resolveFontForScript, generateLogTicks, formatAxisValueWithUnits, getDisplayUnitLabel, applyResize, snapBoxToGrid, chartPartToAttrs } from './chunk-G22EWPLH.mjs';
2
- import { translationsEn } from './chunk-5CD34U2V.mjs';
3
- import { hasTextProperties, PptxHandler, EncryptedFileError, hasShapeProperties, isImageLikeElement, isCalloutShape, getCalloutLeaderLineGeometry, buildCalloutLeaderLineSvgPath, getCalloutViewBoxBounds, applyThemeToData, THEME_PRESETS, guidePxToEmu, mergeShapes, getSubstituteFontFamily, getPresetShapeClipPath, svgPathToPolygons, polygonsToSvgPath, SvgExporter, rebuildTableStructureInRawXml, updateCellTextStyleInRawXml, updateCellTextInRawXml, updateMergeAttrsInRawXml, elementActionToPptxAction } from './chunk-XRYREYXC.mjs';
1
+ import { SHAPE_PRESET_DEFS, computeValueRangeForChart, cloneTemplateElementsBySlideId, cloneSlide, countTextSegments, expandTextBuildAnimations, TimelineEngine, TEXT_BUILD_ID_SEP, computeEntranceAnimationDelay, storePresentationDeck, loadPresentationDeck, clearPresentationDeck, PRESENTATION_HASH, PRESENTATION_NONCE_KEY, PRESENTATION_CHANNEL_NAME, swapPresentationWindows, PRESENTATION_MESSAGE_ORIGIN, buildPresentationAudienceUrl, resolveAudienceScreenPlacement, placeAudienceWindow, isPresentationSessionMessage, collectMediaElements, collectImagePaths, buildInitialGuides, saveAutosaveSnapshot, getAnimationInitialStyle, normalizeHexColor, toCssWritingMode, toCssTextOrientation, toCssVerticalDirection, computeAutoFitTextStyle, resolveLineHeight, getKinsokuLineBreakStyles, buildTextBody3DSceneStyle, resolveParagraphRtl, resolveParagraphAlign, resolveCssTextAlign, colorWithOpacity, build3DExtrusionData, getResolvedShapeClipPath, normalizeStrokeDashType, buildCssGradientFromShapeStyle, buildShadowCssFromShapeStyle, buildInnerShadowCssFromShapeStyle, buildMultiLayerShadowCss, buildGlowBoxShadow, getCompoundLineBoxShadow, getEffectDagFilter, buildPatternFillCss, buildReflectionCss, getCssBorderDashStyle, getCompoundLineBorderWidth, getSvgStrokeDasharray, getCompoundLineOffsets, getCompoundLineWidths, clampCropValue, computeSelectionRect, rectToCells, isCellInRect, buildChartViewModel, buildPreviewAnimation, isTemplateElementId, getInlineEditorSelection, applyStyleToSelectedSegments, setPendingSelectionRestore, applyCaseTransformToSegments, transformTextCase, addSection, renameSection, deleteSection, moveSectionUp, moveSectionDown, moveSlidesToSection, normalizeColorsForCapture, preprocessCssForCapture, 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, createSyncGate, validateRoomId, resolveTransportForServerUrl, isMixedContentBlocked, CONNECTION_TIMEOUT_MS, BROADCAST_THROTTLE_MS, sanitizeColor, readSlidesFromYDoc, reconcileSlidesInYDoc, LOCAL_SYNC_ORIGIN, observeYDocSlides, computeVirtualRange, DEFAULT_VIRTUAL_OVERSCAN, createTouchGestureRecognizer, isKeyboardOpen, buildElementClipboardPayload, generatePackageReadme, downloadBlob, groupElements, generateElementId, makeCloneId, alignElements, distributeElements, bringForward, sendBackward, bringToFront, sendToBack, newTableElement, createDefaultChartElement, readViewportMetrics, computeKeyboardInset, derivePresenceList, buildPrintDocument, buildOutlineHtml, buildSlidesHtml, buildNotesHtml, buildHandoutsHtml, createBlankSlide, makeSlideId, cloneHistorySnapshot, createPresentationSessionId, resolveTransitionDurationMs, isUrlSafe, createPresenterTimer, createInitialPresentationSnapshot, mergePresentationSnapshot, presenterElapsed, stepPresenterZoom, resetPresenterTimer, togglePresenterTimer, isTemplateElement, substituteFieldText, resolveUnderlineDecorationStyle, hasDistinctScriptFonts, buildTextReflectionCss, getTextAlphaOpacity, buildTextRunFilterChain, buildTextShadowCss, apply3dEffects, clampUnitInterval, getRoundRectRadiusPx, computeColumnBoundaries, parseDrawingColor, parseDrawingColorOpacity, getPatternSvg, ooxmlDashToCssBorderStyle, getChartStylePalette, computeLayout, valueToY, formatAxisValue, computeLayoutOptions, splitSeriesByAxis, computeValueRange, getSecondaryValueAxis, seriesColor, paletteColor, resolveRegionCode, normalizeValue, sequentialColorScale, canvasToJpegData, downloadDataUrl, pickSupportedMimeType, WEBM_MIME_CANDIDATES, fpsToFrameIntervalMs, segmentFrameCount, sanitizeDownloadFilename, encodeGif, groupSlidesBySection, cloneElementForPaste, computeScrollDelta, rerouteConnectorsForMovedElements, applyReroutedConnectors, buildPrintHtmlDocument, convertOmmlToMathMl, sanitizeMathMl, buildTextFillCss, resolvePictureBullet, computeResizedColumnWidths, computeResizedRowHeight, DEFAULT_ROW_HEIGHT, tintColor2, shadeColor2, deleteTableColumn, insertTableColumn, deleteTableRow, insertTableRow, splitCell, mergeCells, buildSlidesPdfBytes, buildNotesPdfBytes, ACTION_BUTTON_PRESETS, buildSmartArtPresetData, computeSnapToShape, computeMarqueeHitIds, mergeAdditiveSelection, segmentByScript, resolveFontForScript, generateLogTicks, formatAxisValueWithUnits, getDisplayUnitLabel, applyResize, snapBoxToGrid, chartPartToAttrs } from './chunk-R7FTNSSP.mjs';
2
+ import { translationsEn } from './chunk-RIRK64DM.mjs';
3
+ import { hasTextProperties, PptxHandler, EncryptedFileError, hasShapeProperties, isImageLikeElement, isCalloutShape, getCalloutLeaderLineGeometry, buildCalloutLeaderLineSvgPath, getCalloutViewBoxBounds, applyThemeToData, THEME_PRESETS, themeColorSchemesEqual, guidePxToEmu, mergeShapes, getSubstituteFontFamily, getPresetShapeClipPath, svgPathToPolygons, polygonsToSvgPath, SvgExporter, rebuildTableStructureInRawXml, updateCellTextStyleInRawXml, updateCellTextInRawXml, updateMergeAttrsInRawXml, elementActionToPptxAction } from './chunk-3ZGCM6RC.mjs';
4
4
  import React3, { useState, useEffect, useMemo, Suspense, useRef, useCallback, useSyncExternalStore, useImperativeHandle, useLayoutEffect } from 'react';
5
5
  import { LuTriangle, LuPlus, LuMoveRight, LuMinus, LuDiamond, LuDatabase, LuCircle, LuSquare } from 'react-icons/lu';
6
6
  import { clsx } from 'clsx';
7
7
  import { twMerge } from 'tailwind-merge';
8
8
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
9
9
  import { useTranslation } from 'react-i18next';
10
- import html2canvasPro from 'html2canvas-pro';
11
10
  import JSZip from 'jszip';
12
11
 
13
12
  // src/viewer/utils/clone.ts
@@ -548,30 +547,6 @@ function useZoomViewport({
548
547
  };
549
548
  }
550
549
 
551
- // src/viewer/hooks/usePresentationSetup-helpers.ts
552
- function shouldLoopContinuously(input) {
553
- return Boolean(input.loopContinuously) || input.showType === "kiosk";
554
- }
555
- function applyRehearsalTimings(slides, timings) {
556
- return slides.map((slide, idx) => {
557
- const ms = timings[idx];
558
- if (typeof ms !== "number") {
559
- return slide;
560
- }
561
- return {
562
- ...slide,
563
- transition: {
564
- ...slide.transition,
565
- type: slide.transition?.type ?? "none",
566
- advanceAfterMs: ms
567
- }
568
- };
569
- });
570
- }
571
- function computeEntranceAnimationDelay(delayMs, animationIndex) {
572
- return Math.max(0, delayMs || 0) + animationIndex * 60;
573
- }
574
-
575
550
  // src/viewer/hooks/presentation-mode/animation-helpers.ts
576
551
  function applyAnimationGroupSteps(group, onPlayActionSound, setPresentationElementStates, presentationTimersRef) {
577
552
  for (const step of group.steps) {
@@ -879,7 +854,10 @@ function openDb() {
879
854
  request.onerror = () => reject(request.error);
880
855
  });
881
856
  }
882
- async function storeAudienceContent(content) {
857
+ async function storeAudienceContent(content, sessionId) {
858
+ if (sessionId) {
859
+ return storePresentationDeck(sessionId, content);
860
+ }
883
861
  const db = await openDb();
884
862
  return new Promise((resolve, reject) => {
885
863
  const tx = db.transaction(STORE_NAME, "readwrite");
@@ -897,7 +875,10 @@ async function storeAudienceContent(content) {
897
875
  };
898
876
  });
899
877
  }
900
- async function loadAudienceContent() {
878
+ async function loadAudienceContent(sessionId) {
879
+ if (sessionId) {
880
+ return loadPresentationDeck(sessionId);
881
+ }
901
882
  try {
902
883
  const db = await openDb();
903
884
  return new Promise((resolve, reject) => {
@@ -935,7 +916,10 @@ async function loadAudienceContent() {
935
916
  return null;
936
917
  }
937
918
  }
938
- async function clearAudienceContent() {
919
+ async function clearAudienceContent(sessionId) {
920
+ if (sessionId) {
921
+ return clearPresentationDeck(sessionId);
922
+ }
939
923
  try {
940
924
  const db = await openDb();
941
925
  return new Promise((resolve) => {
@@ -954,12 +938,12 @@ async function clearAudienceContent() {
954
938
  } catch {
955
939
  }
956
940
  }
957
- var PRESENTER_CHANNEL_NAME = "pptx-viewer-presenter";
958
- var AUDIENCE_HASH = "#pptx-audience";
959
- var PRESENTER_MSG_ORIGIN = "pptx-viewer-presenter";
960
- var AUDIENCE_NONCE_KEY = "nonce";
941
+ var PRESENTER_CHANNEL_NAME = PRESENTATION_CHANNEL_NAME;
942
+ var AUDIENCE_HASH = PRESENTATION_HASH;
943
+ var PRESENTER_MSG_ORIGIN = PRESENTATION_MESSAGE_ORIGIN;
944
+ var AUDIENCE_NONCE_KEY = PRESENTATION_NONCE_KEY;
961
945
  function generateSessionId() {
962
- return secureRandomUuid();
946
+ return createPresentationSessionId();
963
947
  }
964
948
  function parseAudienceNonce() {
965
949
  const hash = window.location.hash;
@@ -977,11 +961,13 @@ function isAudienceTab() {
977
961
  return window.location.hash.startsWith(AUDIENCE_HASH);
978
962
  }
979
963
  function usePresenterWindow(input) {
980
- const { currentSlideIndex, isPresenterMode, content } = input;
964
+ const { isPresenterMode, content, snapshot } = input;
981
965
  const audienceWindowRef = useRef(null);
982
966
  const channelRef = useRef(null);
983
967
  const pollTimerRef = useRef(null);
984
968
  const sessionIdRef = useRef("");
969
+ const snapshotRef = useRef(snapshot);
970
+ snapshotRef.current = snapshot;
985
971
  const getChannel = useCallback(() => {
986
972
  if (!channelRef.current) {
987
973
  channelRef.current = new BroadcastChannel(PRESENTER_CHANNEL_NAME);
@@ -991,6 +977,10 @@ function usePresenterWindow(input) {
991
977
  const isAudienceWindowOpen = useCallback(() => {
992
978
  return audienceWindowRef.current !== null && !audienceWindowRef.current.closed;
993
979
  }, []);
980
+ const swapDisplays = useCallback(async () => {
981
+ const audience = audienceWindowRef.current;
982
+ return audience && !audience.closed ? swapPresentationWindows(window, audience) : false;
983
+ }, []);
994
984
  const syncSlideToAudience = useCallback(
995
985
  (slideIndex) => {
996
986
  if (!sessionIdRef.current) {
@@ -1009,7 +999,25 @@ function usePresenterWindow(input) {
1009
999
  },
1010
1000
  [getChannel]
1011
1001
  );
1002
+ const syncStateToAudience = useCallback(
1003
+ (nextSnapshot) => {
1004
+ if (!sessionIdRef.current) {
1005
+ return;
1006
+ }
1007
+ try {
1008
+ getChannel().postMessage({
1009
+ origin: PRESENTER_MSG_ORIGIN,
1010
+ type: "presenter-state",
1011
+ sessionId: sessionIdRef.current,
1012
+ snapshot: nextSnapshot
1013
+ });
1014
+ } catch {
1015
+ }
1016
+ },
1017
+ [getChannel]
1018
+ );
1012
1019
  const closeAudienceWindow = useCallback(() => {
1020
+ const closingSessionId = sessionIdRef.current;
1013
1021
  if (sessionIdRef.current) {
1014
1022
  try {
1015
1023
  const exitMsg = {
@@ -1034,23 +1042,32 @@ function usePresenterWindow(input) {
1034
1042
  clearInterval(pollTimerRef.current);
1035
1043
  pollTimerRef.current = null;
1036
1044
  }
1037
- void clearAudienceContent();
1045
+ if (closingSessionId) {
1046
+ void clearAudienceContent(closingSessionId);
1047
+ }
1038
1048
  }, [getChannel]);
1039
1049
  const openAudienceWindow = useCallback(() => {
1040
1050
  if (isAudienceWindowOpen()) {
1041
1051
  closeAudienceWindow();
1042
1052
  }
1043
- const blankWin = window.open("about:blank", "_blank");
1053
+ const blankWin = window.open(
1054
+ "about:blank",
1055
+ "pptx-viewer-audience",
1056
+ "popup=yes,width=1280,height=720"
1057
+ );
1044
1058
  if (!blankWin) {
1045
1059
  return false;
1046
1060
  }
1047
1061
  audienceWindowRef.current = blankWin;
1048
1062
  const sessionId = generateSessionId();
1049
1063
  sessionIdRef.current = sessionId;
1050
- const audienceUrl = new URL(window.location.href);
1051
- const params = new URLSearchParams();
1052
- params.set(AUDIENCE_NONCE_KEY, sessionId);
1053
- audienceUrl.hash = `${AUDIENCE_HASH}&${params.toString()}`;
1064
+ const audienceUrl = buildPresentationAudienceUrl(window.location.href, sessionId);
1065
+ void resolveAudienceScreenPlacement(window).then((placement) => {
1066
+ if (placement && audienceWindowRef.current === blankWin && !blankWin.closed) {
1067
+ placeAudienceWindow(blankWin, placement);
1068
+ }
1069
+ return void 0;
1070
+ });
1054
1071
  const navigateOrClose = (ok) => {
1055
1072
  const win = audienceWindowRef.current;
1056
1073
  if (!win || win.closed) {
@@ -1066,7 +1083,7 @@ function usePresenterWindow(input) {
1066
1083
  return;
1067
1084
  }
1068
1085
  try {
1069
- win.location.replace(audienceUrl.toString());
1086
+ win.location.replace(audienceUrl);
1070
1087
  } catch {
1071
1088
  try {
1072
1089
  win.close();
@@ -1077,11 +1094,10 @@ function usePresenterWindow(input) {
1077
1094
  }
1078
1095
  };
1079
1096
  if (content) {
1080
- void storeAudienceContent(content).then(() => navigateOrClose(true)).catch(() => navigateOrClose(false));
1097
+ void storeAudienceContent(content, sessionId).then(() => navigateOrClose(true)).catch(() => navigateOrClose(false));
1081
1098
  } else {
1082
1099
  navigateOrClose(true);
1083
1100
  }
1084
- window.setTimeout(() => syncSlideToAudience(currentSlideIndex), 1500);
1085
1101
  pollTimerRef.current = setInterval(() => {
1086
1102
  const win = audienceWindowRef.current;
1087
1103
  if (!win || win.closed) {
@@ -1094,12 +1110,28 @@ function usePresenterWindow(input) {
1094
1110
  }
1095
1111
  }, 1e3);
1096
1112
  return true;
1097
- }, [isAudienceWindowOpen, closeAudienceWindow, syncSlideToAudience, currentSlideIndex, content]);
1113
+ }, [isAudienceWindowOpen, closeAudienceWindow, content]);
1114
+ useEffect(() => {
1115
+ let channel;
1116
+ try {
1117
+ channel = getChannel();
1118
+ } catch {
1119
+ return;
1120
+ }
1121
+ const handleMessage = (event) => {
1122
+ const message = event.data;
1123
+ if (isPresentationSessionMessage(message) && message.type === "audience-ready" && message.sessionId === sessionIdRef.current) {
1124
+ syncStateToAudience(snapshotRef.current);
1125
+ }
1126
+ };
1127
+ channel.addEventListener("message", handleMessage);
1128
+ return () => channel.removeEventListener("message", handleMessage);
1129
+ }, [getChannel, syncStateToAudience]);
1098
1130
  useEffect(() => {
1099
1131
  if (isPresenterMode && isAudienceWindowOpen()) {
1100
- syncSlideToAudience(currentSlideIndex);
1132
+ syncStateToAudience(snapshot);
1101
1133
  }
1102
- }, [currentSlideIndex, isPresenterMode, isAudienceWindowOpen, syncSlideToAudience]);
1134
+ }, [snapshot, isPresenterMode, isAudienceWindowOpen, syncStateToAudience]);
1103
1135
  useEffect(() => {
1104
1136
  return () => {
1105
1137
  closeAudienceWindow();
@@ -1116,7 +1148,9 @@ function usePresenterWindow(input) {
1116
1148
  }, [isPresenterMode, closeAudienceWindow]);
1117
1149
  useEffect(() => {
1118
1150
  const handleBeforeUnload = () => {
1119
- void clearAudienceContent();
1151
+ if (sessionIdRef.current) {
1152
+ void clearAudienceContent(sessionIdRef.current);
1153
+ }
1120
1154
  };
1121
1155
  window.addEventListener("beforeunload", handleBeforeUnload);
1122
1156
  return () => window.removeEventListener("beforeunload", handleBeforeUnload);
@@ -1125,11 +1159,13 @@ function usePresenterWindow(input) {
1125
1159
  openAudienceWindow,
1126
1160
  closeAudienceWindow,
1127
1161
  isAudienceWindowOpen,
1128
- syncSlideToAudience
1162
+ syncSlideToAudience,
1163
+ syncStateToAudience,
1164
+ swapDisplays
1129
1165
  };
1130
1166
  }
1131
1167
  function useAudienceMode(input) {
1132
- const { mode: _mode, onSetMode, onSetActiveSlideIndex, containerRef } = input;
1168
+ const { mode: _mode, onSetMode, onSetActiveSlideIndex, containerRef, onSnapshot } = input;
1133
1169
  const initialised = useRef(false);
1134
1170
  useEffect(() => {
1135
1171
  if (!isAudienceTab()) {
@@ -1139,18 +1175,19 @@ function useAudienceMode(input) {
1139
1175
  return;
1140
1176
  }
1141
1177
  initialised.current = true;
1142
- const timer = window.setTimeout(() => {
1143
- try {
1144
- const wrapper = containerRef.current;
1145
- if (wrapper && typeof wrapper.requestFullscreen === "function") {
1146
- void wrapper.requestFullscreen().catch(() => {
1147
- });
1148
- }
1149
- } catch {
1178
+ onSetMode("present");
1179
+ const requestAudienceFullscreen = () => {
1180
+ const wrapper = containerRef.current;
1181
+ if (!document.fullscreenElement && wrapper?.requestFullscreen) {
1182
+ void wrapper.requestFullscreen().catch(() => void 0);
1150
1183
  }
1151
- onSetMode("present");
1152
- }, 800);
1153
- return () => window.clearTimeout(timer);
1184
+ };
1185
+ document.addEventListener("pointerdown", requestAudienceFullscreen, { once: true });
1186
+ document.addEventListener("keydown", requestAudienceFullscreen, { once: true });
1187
+ return () => {
1188
+ document.removeEventListener("pointerdown", requestAudienceFullscreen);
1189
+ document.removeEventListener("keydown", requestAudienceFullscreen);
1190
+ };
1154
1191
  }, [containerRef, onSetMode]);
1155
1192
  useEffect(() => {
1156
1193
  if (!isAudienceTab()) {
@@ -1165,7 +1202,7 @@ function useAudienceMode(input) {
1165
1202
  }
1166
1203
  channel.onmessage = (event) => {
1167
1204
  const data = event.data;
1168
- if (!data || data.origin !== PRESENTER_MSG_ORIGIN) {
1205
+ if (!isPresentationSessionMessage(data) || data.origin !== PRESENTER_MSG_ORIGIN) {
1169
1206
  return;
1170
1207
  }
1171
1208
  if (expectedSessionId && data.sessionId !== expectedSessionId) {
@@ -1174,8 +1211,14 @@ function useAudienceMode(input) {
1174
1211
  if (data.type === "presenter-slide-change") {
1175
1212
  onSetActiveSlideIndex(data.slideIndex);
1176
1213
  }
1214
+ if (data.type === "presenter-state") {
1215
+ onSetActiveSlideIndex(data.snapshot.slideIndex);
1216
+ onSnapshot?.(data.snapshot);
1217
+ }
1177
1218
  if (data.type === "presenter-exit") {
1178
- void clearAudienceContent();
1219
+ if (expectedSessionId) {
1220
+ void clearAudienceContent(expectedSessionId);
1221
+ }
1179
1222
  onSetMode("edit");
1180
1223
  try {
1181
1224
  window.close();
@@ -1183,13 +1226,20 @@ function useAudienceMode(input) {
1183
1226
  }
1184
1227
  }
1185
1228
  };
1229
+ if (expectedSessionId) {
1230
+ channel.postMessage({
1231
+ origin: PRESENTATION_MESSAGE_ORIGIN,
1232
+ type: "audience-ready",
1233
+ sessionId: expectedSessionId
1234
+ });
1235
+ }
1186
1236
  return () => {
1187
1237
  try {
1188
1238
  channel.close();
1189
1239
  } catch {
1190
1240
  }
1191
1241
  };
1192
- }, [onSetMode, onSetActiveSlideIndex]);
1242
+ }, [onSetMode, onSetActiveSlideIndex, onSnapshot]);
1193
1243
  }
1194
1244
 
1195
1245
  // src/viewer/hooks/presentation-mode/keyboard-helpers.ts
@@ -1212,6 +1262,12 @@ function mapKeyToPresentationAction(key, ctrlKey) {
1212
1262
  if (key === "e" || key === "E") {
1213
1263
  return { action: "toggleEraser" };
1214
1264
  }
1265
+ if (key === "b" || key === "B") {
1266
+ return { action: "toggleBlackScreen" };
1267
+ }
1268
+ if (key === "w" || key === "W") {
1269
+ return { action: "toggleWhiteScreen" };
1270
+ }
1215
1271
  if (key === "m" && ctrlKey) {
1216
1272
  return { action: "toggleToolbar" };
1217
1273
  }
@@ -1232,6 +1288,8 @@ function usePresentationKeyboard(input) {
1232
1288
  onToggleEraser,
1233
1289
  onToggleToolbar,
1234
1290
  onTogglePresenterView,
1291
+ onToggleBlackScreen,
1292
+ onToggleWhiteScreen,
1235
1293
  rehearsing,
1236
1294
  recordCurrentSlideTime,
1237
1295
  presentationSlideIndex,
@@ -1276,6 +1334,12 @@ function usePresentationKeyboard(input) {
1276
1334
  case "togglePresenterView":
1277
1335
  onTogglePresenterView?.();
1278
1336
  break;
1337
+ case "toggleBlackScreen":
1338
+ onToggleBlackScreen?.();
1339
+ break;
1340
+ case "toggleWhiteScreen":
1341
+ onToggleWhiteScreen?.();
1342
+ break;
1279
1343
  }
1280
1344
  };
1281
1345
  window.addEventListener("keydown", handleKeyDown);
@@ -1291,6 +1355,8 @@ function usePresentationKeyboard(input) {
1291
1355
  onToggleEraser,
1292
1356
  onToggleToolbar,
1293
1357
  onTogglePresenterView,
1358
+ onToggleBlackScreen,
1359
+ onToggleWhiteScreen,
1294
1360
  rehearsing,
1295
1361
  recordCurrentSlideTime,
1296
1362
  presentationSlideIndex,
@@ -1670,6 +1736,53 @@ function useZoomNavigation(input) {
1670
1736
  clearZoomReturn
1671
1737
  };
1672
1738
  }
1739
+ function usePresenterConsole(slideIndex) {
1740
+ const timerRef = useRef(createPresenterTimer());
1741
+ const [snapshot, setSnapshot] = useState(() => createInitialPresentationSnapshot(slideIndex));
1742
+ const patch = useCallback((value) => {
1743
+ setSnapshot((current) => mergePresentationSnapshot(current, value));
1744
+ }, []);
1745
+ useEffect(() => patch({ slideIndex }), [patch, slideIndex]);
1746
+ useEffect(() => {
1747
+ const timer = window.setInterval(() => {
1748
+ patch({
1749
+ paused: timerRef.current.paused,
1750
+ elapsedMs: presenterElapsed(timerRef.current)
1751
+ });
1752
+ }, 1e3);
1753
+ return () => window.clearInterval(timer);
1754
+ }, [patch]);
1755
+ return {
1756
+ snapshot,
1757
+ applyAudienceSnapshot: setSnapshot,
1758
+ setBlackout: (blackout) => patch({ blackout }),
1759
+ toggleTimer: () => {
1760
+ timerRef.current = togglePresenterTimer(timerRef.current);
1761
+ patch({
1762
+ paused: timerRef.current.paused,
1763
+ elapsedMs: presenterElapsed(timerRef.current)
1764
+ });
1765
+ },
1766
+ resetTimer: () => {
1767
+ timerRef.current = resetPresenterTimer();
1768
+ patch({ paused: false, elapsedMs: 0 });
1769
+ },
1770
+ stepZoom: (direction) => setSnapshot(
1771
+ (current) => mergePresentationSnapshot(current, {
1772
+ zoom: stepPresenterZoom(
1773
+ current.zoom ?? { scale: 1, originX: 0.5, originY: 0.5 },
1774
+ direction
1775
+ )
1776
+ })
1777
+ ),
1778
+ resetZoom: () => patch({ zoom: { scale: 1, originX: 0.5, originY: 0.5 } }),
1779
+ setCaption: (caption) => patch({ caption }),
1780
+ setSubtitlesVisible: (subtitlesVisible) => patch({ subtitlesVisible }),
1781
+ updateSnapshot: patch
1782
+ };
1783
+ }
1784
+
1785
+ // src/viewer/hooks/usePresentationMode.ts
1673
1786
  function usePresentationMode(input) {
1674
1787
  const {
1675
1788
  mode,
@@ -1759,16 +1872,28 @@ function usePresentationMode(input) {
1759
1872
  setShowRehearsalSummary
1760
1873
  });
1761
1874
  const { handleZoomClick, zoomReturnSlideIndex, returnToZoomSlide, clearZoomReturn } = useZoomNavigation({ navigateToSlide });
1762
- const { openAudienceWindow, closeAudienceWindow, isAudienceWindowOpen, syncSlideToAudience } = usePresenterWindow({
1763
- currentSlideIndex: presentationSlideIndex,
1875
+ const presenterConsole = usePresenterConsole(presentationSlideIndex);
1876
+ const {
1877
+ openAudienceWindow,
1878
+ closeAudienceWindow,
1879
+ isAudienceWindowOpen,
1880
+ syncSlideToAudience,
1881
+ syncStateToAudience,
1882
+ swapDisplays
1883
+ } = usePresenterWindow({
1764
1884
  isPresenterMode: presenterMode,
1765
- content
1885
+ content,
1886
+ snapshot: presenterConsole.snapshot
1766
1887
  });
1767
1888
  useAudienceMode({
1768
1889
  mode,
1769
1890
  onSetMode,
1770
- onSetActiveSlideIndex,
1771
- containerRef
1891
+ onSetActiveSlideIndex: (index) => {
1892
+ onSetActiveSlideIndex(index);
1893
+ setPresentationSlideIndex(index);
1894
+ },
1895
+ containerRef,
1896
+ onSnapshot: presenterConsole.applyAudienceSnapshot
1772
1897
  });
1773
1898
  const enterPresentMode = useCallback(() => {
1774
1899
  setPresenterMode(false);
@@ -1825,6 +1950,12 @@ function usePresentationMode(input) {
1825
1950
  onToggleEraser,
1826
1951
  onToggleToolbar,
1827
1952
  onTogglePresenterView: togglePresenterView,
1953
+ onToggleBlackScreen: () => presenterConsole.setBlackout(
1954
+ presenterConsole.snapshot.blackout === "black" ? "none" : "black"
1955
+ ),
1956
+ onToggleWhiteScreen: () => presenterConsole.setBlackout(
1957
+ presenterConsole.snapshot.blackout === "white" ? "none" : "white"
1958
+ ),
1828
1959
  rehearsing,
1829
1960
  recordCurrentSlideTime,
1830
1961
  presentationSlideIndex,
@@ -1945,7 +2076,18 @@ function usePresentationMode(input) {
1945
2076
  openAudienceWindow,
1946
2077
  closeAudienceWindow,
1947
2078
  isAudienceWindowOpen,
1948
- syncSlideToAudience
2079
+ syncSlideToAudience,
2080
+ syncStateToAudience,
2081
+ swapPresenterDisplays: swapDisplays,
2082
+ presenterSnapshot: presenterConsole.snapshot,
2083
+ setPresenterBlackout: presenterConsole.setBlackout,
2084
+ togglePresenterTimer: presenterConsole.toggleTimer,
2085
+ resetPresenterTimer: presenterConsole.resetTimer,
2086
+ stepPresenterZoom: presenterConsole.stepZoom,
2087
+ resetPresenterZoom: presenterConsole.resetZoom,
2088
+ setPresenterCaption: presenterConsole.setCaption,
2089
+ setPresenterSubtitlesVisible: presenterConsole.setSubtitlesVisible,
2090
+ updatePresenterSnapshot: presenterConsole.updateSnapshot
1949
2091
  };
1950
2092
  }
1951
2093
  var PEN_WIDTH = 2.5;
@@ -4030,21 +4172,25 @@ function renderEquationSegment(elementId, segmentIndex, equationXml, equationNum
4030
4172
  return /* @__PURE__ */ jsx("span", { children: equationContent }, `${elementId}-seg-${segmentIndex}`);
4031
4173
  }
4032
4174
  function renderPictureBullet(elementId, segmentIndex, bulletInfo, baseFontSize) {
4033
- const bulletSize = typeof bulletInfo.sizePts === "number" ? bulletInfo.sizePts : typeof bulletInfo.sizePercent === "number" ? baseFontSize * (bulletInfo.sizePercent / 100) : baseFontSize;
4034
- if (!bulletInfo.imageDataUrl) {
4175
+ const picture = resolvePictureBullet(bulletInfo, baseFontSize) ?? {
4176
+ sizePx: baseFontSize,
4177
+ fallbackMarker: "\u2022",
4178
+ accessibleLabel: "Bullet"
4179
+ };
4180
+ if (!picture.src) {
4035
4181
  return /* @__PURE__ */ jsx(
4036
4182
  "span",
4037
4183
  {
4038
4184
  style: {
4039
- fontSize: bulletSize,
4185
+ fontSize: picture.sizePx,
4040
4186
  display: "inline-block",
4041
4187
  verticalAlign: "middle",
4042
4188
  marginInlineEnd: 4,
4043
4189
  color: bulletInfo.color || void 0,
4044
4190
  fontFamily: bulletInfo.fontFamily || void 0
4045
4191
  },
4046
- "aria-label": translationsEn["pptx.textSegment.bulletAria"],
4047
- children: "\u2022 "
4192
+ "aria-label": picture.accessibleLabel,
4193
+ children: `${picture.fallbackMarker} `
4048
4194
  },
4049
4195
  `${elementId}-seg-${segmentIndex}-bullet-fallback`
4050
4196
  );
@@ -4052,11 +4198,11 @@ function renderPictureBullet(elementId, segmentIndex, bulletInfo, baseFontSize)
4052
4198
  return /* @__PURE__ */ jsx(
4053
4199
  "img",
4054
4200
  {
4055
- src: bulletInfo.imageDataUrl,
4056
- alt: translationsEn["pptx.textSegment.bulletAria"],
4201
+ src: picture.src,
4202
+ alt: picture.accessibleLabel,
4057
4203
  style: {
4058
- width: bulletSize,
4059
- height: bulletSize,
4204
+ width: picture.sizePx,
4205
+ height: picture.sizePx,
4060
4206
  display: "inline-block",
4061
4207
  verticalAlign: "middle",
4062
4208
  marginInlineEnd: 4,
@@ -4466,9 +4612,6 @@ function isConnectorOrLineElement(element) {
4466
4612
  const st = getShapeType(element.shapeType);
4467
4613
  return st === "connector" || st === "line" || element.shapeType === "line";
4468
4614
  }
4469
- function getDuotoneFilterId(elementId) {
4470
- return `duotone-${elementId}`;
4471
- }
4472
4615
  function hexToRgbUnit(hex) {
4473
4616
  const clean = hex.replace("#", "");
4474
4617
  const r = parseInt(clean.substring(0, 2), 16) / 255;
@@ -4480,50 +4623,6 @@ function hexToRgbUnit(hex) {
4480
4623
  b: Number.isFinite(b) ? b : 0
4481
4624
  };
4482
4625
  }
4483
- function renderDuotoneSvgFilter(elementId, color1, color2) {
4484
- const filterId = getDuotoneFilterId(elementId);
4485
- const c1 = hexToRgbUnit(color1);
4486
- const c2 = hexToRgbUnit(color2);
4487
- const grayscaleMatrix = [
4488
- 0.2126,
4489
- 0.7152,
4490
- 0.0722,
4491
- 0,
4492
- 0,
4493
- 0.2126,
4494
- 0.7152,
4495
- 0.0722,
4496
- 0,
4497
- 0,
4498
- 0.2126,
4499
- 0.7152,
4500
- 0.0722,
4501
- 0,
4502
- 0,
4503
- 0,
4504
- 0,
4505
- 0,
4506
- 1,
4507
- 0
4508
- ].join(" ");
4509
- return /* @__PURE__ */ jsx(
4510
- "svg",
4511
- {
4512
- width: 0,
4513
- height: 0,
4514
- style: { position: "absolute", overflow: "hidden" },
4515
- "aria-hidden": "true",
4516
- children: /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs("filter", { id: filterId, colorInterpolationFilters: "sRGB", children: [
4517
- /* @__PURE__ */ jsx("feColorMatrix", { type: "matrix", values: grayscaleMatrix }),
4518
- /* @__PURE__ */ jsxs("feComponentTransfer", { children: [
4519
- /* @__PURE__ */ jsx("feFuncR", { type: "linear", slope: c2.r - c1.r, intercept: c1.r }),
4520
- /* @__PURE__ */ jsx("feFuncG", { type: "linear", slope: c2.g - c1.g, intercept: c1.g }),
4521
- /* @__PURE__ */ jsx("feFuncB", { type: "linear", slope: c2.b - c1.b, intercept: c1.b })
4522
- ] })
4523
- ] }) })
4524
- }
4525
- );
4526
- }
4527
4626
  function getDuotoneColors(element) {
4528
4627
  if (!isImageLikeElement(element)) {
4529
4628
  return void 0;
@@ -4577,128 +4676,6 @@ function mapDagBlendModeToCss(blend) {
4577
4676
  return void 0;
4578
4677
  }
4579
4678
  }
4580
- function getImageAlphaFilterId(elementId) {
4581
- return `imgalpha-${elementId}`;
4582
- }
4583
- function hasAdvancedImageAlphaEffects(element) {
4584
- if (!isImageLikeElement(element)) {
4585
- return false;
4586
- }
4587
- const e = element.imageEffects;
4588
- if (!e) {
4589
- return false;
4590
- }
4591
- return Boolean(
4592
- typeof e.alphaModFix === "number" || e.alphaInv || e.alphaCeiling || e.alphaFloor || typeof e.alphaRepl === "number" || typeof e.alphaBiLevel === "number" || typeof e.biLevel === "number" || e.lum && (typeof e.lum.bright === "number" || typeof e.lum.contrast === "number") || e.hsl && (typeof e.hsl.sat === "number" || typeof e.hsl.lum === "number") || e.tint && typeof e.tint.amt === "number" || e.clrRepl
4593
- );
4594
- }
4595
- function renderImageAlphaSvgFilter(element) {
4596
- if (!isImageLikeElement(element)) {
4597
- return null;
4598
- }
4599
- const e = element.imageEffects;
4600
- if (!e || !hasAdvancedImageAlphaEffects(element)) {
4601
- return null;
4602
- }
4603
- const filterId = getImageAlphaFilterId(element.id);
4604
- const primitives = [];
4605
- let resultIdx = 0;
4606
- let inputRef = "SourceGraphic";
4607
- const next = (jsx42) => {
4608
- const result = `r${resultIdx++}`;
4609
- primitives.push(jsx42(inputRef, result));
4610
- inputRef = result;
4611
- };
4612
- if (typeof e.alphaModFix === "number") {
4613
- const mul = clamp(e.alphaModFix / 100, 0, 1);
4614
- next((inp, out) => /* @__PURE__ */ jsx(
4615
- "feColorMatrix",
4616
- {
4617
- in: inp,
4618
- result: out,
4619
- type: "matrix",
4620
- values: `1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 ${mul} 0`
4621
- },
4622
- out
4623
- ));
4624
- }
4625
- if (e.alphaInv) {
4626
- next((inp, out) => /* @__PURE__ */ jsx("feComponentTransfer", { in: inp, result: out, children: /* @__PURE__ */ jsx("feFuncA", { type: "linear", slope: -1, intercept: 1 }) }, out));
4627
- }
4628
- if (e.alphaCeiling) {
4629
- next((inp, out) => /* @__PURE__ */ jsx("feComponentTransfer", { in: inp, result: out, children: /* @__PURE__ */ jsx("feFuncA", { type: "discrete", tableValues: "0 1 1 1 1 1 1 1 1 1" }) }, out));
4630
- }
4631
- if (e.alphaFloor) {
4632
- next((inp, out) => /* @__PURE__ */ jsx("feComponentTransfer", { in: inp, result: out, children: /* @__PURE__ */ jsx("feFuncA", { type: "discrete", tableValues: "0 0 0 0 0 0 0 0 0 1" }) }, out));
4633
- }
4634
- if (typeof e.alphaRepl === "number") {
4635
- const a = clamp(e.alphaRepl / 100, 0, 1);
4636
- next((inp, out) => /* @__PURE__ */ jsx("feComponentTransfer", { in: inp, result: out, children: /* @__PURE__ */ jsx("feFuncA", { type: "linear", slope: 0, intercept: a }) }, out));
4637
- }
4638
- if (typeof e.alphaBiLevel === "number") {
4639
- const t = clamp(e.alphaBiLevel / 100, 0, 1);
4640
- const table = Array.from({ length: 10 }, (_, i) => i / 10 >= t ? "1" : "0").join(" ");
4641
- next((inp, out) => /* @__PURE__ */ jsx("feComponentTransfer", { in: inp, result: out, children: /* @__PURE__ */ jsx("feFuncA", { type: "discrete", tableValues: table }) }, out));
4642
- }
4643
- if (typeof e.biLevel === "number") {
4644
- next((inp, out) => /* @__PURE__ */ jsx("feColorMatrix", { in: inp, result: out, type: "saturate", values: "0" }, out));
4645
- const t = clamp(e.biLevel / 100, 0, 1);
4646
- const tbl = t < 0.5 ? "0 1" : "0 1";
4647
- next((inp, out) => /* @__PURE__ */ jsxs("feComponentTransfer", { in: inp, result: out, children: [
4648
- /* @__PURE__ */ jsx("feFuncR", { type: "discrete", tableValues: tbl }),
4649
- /* @__PURE__ */ jsx("feFuncG", { type: "discrete", tableValues: tbl }),
4650
- /* @__PURE__ */ jsx("feFuncB", { type: "discrete", tableValues: tbl })
4651
- ] }, out));
4652
- }
4653
- if (e.lum && (typeof e.lum.bright === "number" || typeof e.lum.contrast === "number")) {
4654
- const b = (e.lum.bright ?? 0) / 100;
4655
- const c = 1 + (e.lum.contrast ?? 0) / 100;
4656
- const slope = c;
4657
- const intercept = b + (1 - c) / 2;
4658
- next((inp, out) => /* @__PURE__ */ jsxs("feComponentTransfer", { in: inp, result: out, children: [
4659
- /* @__PURE__ */ jsx("feFuncR", { type: "linear", slope, intercept }),
4660
- /* @__PURE__ */ jsx("feFuncG", { type: "linear", slope, intercept }),
4661
- /* @__PURE__ */ jsx("feFuncB", { type: "linear", slope, intercept })
4662
- ] }, out));
4663
- }
4664
- if (e.hsl && typeof e.hsl.sat === "number") {
4665
- const v = clamp(1 + e.hsl.sat / 100, 0, 2);
4666
- next((inp, out) => /* @__PURE__ */ jsx("feColorMatrix", { in: inp, result: out, type: "saturate", values: String(v) }, out));
4667
- }
4668
- if (e.tint && typeof e.tint.amt === "number" && e.tint.amt < 0) {
4669
- const v = clamp(1 + e.tint.amt / 100, 0, 1);
4670
- next((inp, out) => /* @__PURE__ */ jsx("feColorMatrix", { in: inp, result: out, type: "saturate", values: String(v) }, out));
4671
- }
4672
- if (e.clrRepl) {
4673
- const c = hexToRgbUnit(e.clrRepl.color);
4674
- next((inp, out) => /* @__PURE__ */ jsx(
4675
- "feColorMatrix",
4676
- {
4677
- in: inp,
4678
- result: out,
4679
- type: "matrix",
4680
- values: `0 0 0 0 ${c.r} 0 0 0 0 ${c.g} 0 0 0 0 ${c.b} 0 0 0 1 0`
4681
- },
4682
- out
4683
- ));
4684
- }
4685
- if (primitives.length === 0) {
4686
- return null;
4687
- }
4688
- return /* @__PURE__ */ jsx(
4689
- "svg",
4690
- {
4691
- width: 0,
4692
- height: 0,
4693
- style: { position: "absolute", overflow: "hidden" },
4694
- "aria-hidden": "true",
4695
- children: /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx("filter", { id: filterId, colorInterpolationFilters: "sRGB", children: primitives }) })
4696
- }
4697
- );
4698
- }
4699
- function clamp(v, lo, hi) {
4700
- return v < lo ? lo : v > hi ? hi : v;
4701
- }
4702
4679
  function getDagDuotoneFilterId(elementId) {
4703
4680
  return `dag-duotone-${elementId}`;
4704
4681
  }
@@ -8487,7 +8464,7 @@ function FailedToLoad() {
8487
8464
  var LazySurfaceChart3DScene = React3.lazy(
8488
8465
  async () => {
8489
8466
  try {
8490
- return await import('./SurfaceChart3DScene-GUAS2NWQ.mjs');
8467
+ return await import('./SurfaceChart3DScene-52VUVZSC.mjs');
8491
8468
  } catch {
8492
8469
  return { default: FailedToLoad };
8493
8470
  }
@@ -10870,366 +10847,6 @@ function stopPreviewAnimation() {
10870
10847
  }
10871
10848
  activePreview = null;
10872
10849
  }
10873
- var SVG_FILTER_EFFECTS = /* @__PURE__ */ new Set([
10874
- "artisticFilmGrain",
10875
- "filmGrain",
10876
- "artisticCutout",
10877
- "cutout",
10878
- "artisticCement",
10879
- "cement",
10880
- "artisticTexturizer",
10881
- "texturizer",
10882
- "artisticCrisscrossEtching",
10883
- "crisscrossEtching",
10884
- "artisticMosaic",
10885
- "artisticMosaicBubbles",
10886
- "mosaicBubbles",
10887
- "mosaic",
10888
- "artisticGlowEdges",
10889
- "glowEdges",
10890
- "glow_edges",
10891
- "artisticChalkSketch",
10892
- "chalkSketch",
10893
- "chalk",
10894
- "artisticPencilSketch",
10895
- "pencilSketch",
10896
- "artisticPencilGrayscale",
10897
- "pencilGrayscale",
10898
- "grayPencil"
10899
- ]);
10900
- function getArtisticFilterId(elementId) {
10901
- return `artistic-fx-${elementId}`;
10902
- }
10903
- function needsSvgArtisticFilter(effectName) {
10904
- if (!effectName) {
10905
- return false;
10906
- }
10907
- return SVG_FILTER_EFFECTS.has(effectName);
10908
- }
10909
- function renderArtisticEffectSvgFilter(elementId, effectName, radius) {
10910
- if (!effectName || !needsSvgArtisticFilter(effectName)) {
10911
- return null;
10912
- }
10913
- const filterId = getArtisticFilterId(elementId);
10914
- const filterContent = buildFilterPrimitives(effectName, radius);
10915
- if (!filterContent) {
10916
- return null;
10917
- }
10918
- return /* @__PURE__ */ jsx(
10919
- "svg",
10920
- {
10921
- width: 0,
10922
- height: 0,
10923
- style: { position: "absolute", overflow: "hidden" },
10924
- "aria-hidden": "true",
10925
- children: /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx(
10926
- "filter",
10927
- {
10928
- id: filterId,
10929
- x: "0%",
10930
- y: "0%",
10931
- width: "100%",
10932
- height: "100%",
10933
- colorInterpolationFilters: "sRGB",
10934
- children: filterContent
10935
- }
10936
- ) })
10937
- }
10938
- );
10939
- }
10940
- function buildFilterPrimitives(effectName, radius) {
10941
- const normalizedRadius = Math.max(0, Math.min(100, radius)) / 100;
10942
- switch (effectName) {
10943
- // ── Film Grain ──────────────────────────────────────────────────────
10944
- // Subtle noise overlay using feTurbulence blended with the source.
10945
- case "artisticFilmGrain":
10946
- case "filmGrain": {
10947
- const freq = 0.5 + normalizedRadius * 0.5;
10948
- const opacity = 0.15 + normalizedRadius * 0.25;
10949
- return /* @__PURE__ */ jsxs(Fragment, { children: [
10950
- /* @__PURE__ */ jsx(
10951
- "feTurbulence",
10952
- {
10953
- type: "fractalNoise",
10954
- baseFrequency: freq,
10955
- numOctaves: 4,
10956
- seed: 1,
10957
- stitchTiles: "stitch",
10958
- result: "grain"
10959
- }
10960
- ),
10961
- /* @__PURE__ */ jsx("feColorMatrix", { in: "grain", type: "saturate", values: "0", result: "grainGray" }),
10962
- /* @__PURE__ */ jsx("feBlend", { in: "SourceGraphic", in2: "grainGray", mode: "overlay" }),
10963
- /* @__PURE__ */ jsxs("feComponentTransfer", { children: [
10964
- /* @__PURE__ */ jsx("feFuncR", { type: "linear", slope: 1 + opacity * 0.3, intercept: opacity * 0.02 }),
10965
- /* @__PURE__ */ jsx("feFuncG", { type: "linear", slope: 1 + opacity * 0.3, intercept: opacity * 0.02 }),
10966
- /* @__PURE__ */ jsx("feFuncB", { type: "linear", slope: 1 + opacity * 0.3, intercept: opacity * 0.02 })
10967
- ] })
10968
- ] });
10969
- }
10970
- // ── Cutout ──────────────────────────────────────────────────────────
10971
- // Posterization: reduce colours to discrete steps using feComponentTransfer
10972
- // with `discrete` table values.
10973
- case "artisticCutout":
10974
- case "cutout": {
10975
- const steps = Math.max(2, Math.round(4 + normalizedRadius * 4));
10976
- const tableValues = buildDiscreteTable(steps);
10977
- return /* @__PURE__ */ jsxs("feComponentTransfer", { children: [
10978
- /* @__PURE__ */ jsx("feFuncR", { type: "discrete", tableValues }),
10979
- /* @__PURE__ */ jsx("feFuncG", { type: "discrete", tableValues }),
10980
- /* @__PURE__ */ jsx("feFuncB", { type: "discrete", tableValues })
10981
- ] });
10982
- }
10983
- // ── Cement ──────────────────────────────────────────────────────────
10984
- // Desaturated image with a fine noise texture overlay.
10985
- case "artisticCement":
10986
- case "cement": {
10987
- const freq = 1.5 + normalizedRadius * 2.5;
10988
- return /* @__PURE__ */ jsxs(Fragment, { children: [
10989
- /* @__PURE__ */ jsx(
10990
- "feColorMatrix",
10991
- {
10992
- type: "saturate",
10993
- values: `${Math.max(0, 0.4 - normalizedRadius * 0.3)}`,
10994
- result: "desat"
10995
- }
10996
- ),
10997
- /* @__PURE__ */ jsx(
10998
- "feTurbulence",
10999
- {
11000
- type: "fractalNoise",
11001
- baseFrequency: freq,
11002
- numOctaves: 5,
11003
- seed: 2,
11004
- stitchTiles: "stitch",
11005
- result: "cementNoise"
11006
- }
11007
- ),
11008
- /* @__PURE__ */ jsx("feColorMatrix", { in: "cementNoise", type: "saturate", values: "0", result: "cementGray" }),
11009
- /* @__PURE__ */ jsx("feBlend", { in: "desat", in2: "cementGray", mode: "multiply" }),
11010
- /* @__PURE__ */ jsxs("feComponentTransfer", { children: [
11011
- /* @__PURE__ */ jsx("feFuncR", { type: "linear", slope: 1.2, intercept: 0 }),
11012
- /* @__PURE__ */ jsx("feFuncG", { type: "linear", slope: 1.2, intercept: 0 }),
11013
- /* @__PURE__ */ jsx("feFuncB", { type: "linear", slope: 1.2, intercept: 0 })
11014
- ] })
11015
- ] });
11016
- }
11017
- // ── Texturizer ─────────────────────────────────────────────────────
11018
- // Fine noise texture overlay on the original image.
11019
- case "artisticTexturizer":
11020
- case "texturizer": {
11021
- const freq = 2 + normalizedRadius * 3;
11022
- return /* @__PURE__ */ jsxs(Fragment, { children: [
11023
- /* @__PURE__ */ jsx(
11024
- "feTurbulence",
11025
- {
11026
- type: "fractalNoise",
11027
- baseFrequency: freq,
11028
- numOctaves: 3,
11029
- seed: 3,
11030
- stitchTiles: "stitch",
11031
- result: "texNoise"
11032
- }
11033
- ),
11034
- /* @__PURE__ */ jsx("feColorMatrix", { in: "texNoise", type: "saturate", values: "0", result: "texGray" }),
11035
- /* @__PURE__ */ jsx("feBlend", { in: "SourceGraphic", in2: "texGray", mode: "overlay" }),
11036
- /* @__PURE__ */ jsxs("feComponentTransfer", { children: [
11037
- /* @__PURE__ */ jsx("feFuncR", { type: "linear", slope: 1.1, intercept: 0.02 }),
11038
- /* @__PURE__ */ jsx("feFuncG", { type: "linear", slope: 1.1, intercept: 0.02 }),
11039
- /* @__PURE__ */ jsx("feFuncB", { type: "linear", slope: 1.1, intercept: 0.02 })
11040
- ] })
11041
- ] });
11042
- }
11043
- // ── Crisscross Etching ─────────────────────────────────────────────
11044
- // Grayscale image with a hatching-like line pattern overlay.
11045
- case "artisticCrisscrossEtching":
11046
- case "crisscrossEtching": {
11047
- const freq = 0.08 + normalizedRadius * 0.12;
11048
- return /* @__PURE__ */ jsxs(Fragment, { children: [
11049
- /* @__PURE__ */ jsx("feColorMatrix", { type: "saturate", values: "0", result: "gray" }),
11050
- /* @__PURE__ */ jsx(
11051
- "feTurbulence",
11052
- {
11053
- type: "turbulence",
11054
- baseFrequency: `${freq} ${freq * 3}`,
11055
- numOctaves: 1,
11056
- seed: 7,
11057
- result: "lines"
11058
- }
11059
- ),
11060
- /* @__PURE__ */ jsx("feColorMatrix", { in: "lines", type: "saturate", values: "0", result: "linesGray" }),
11061
- /* @__PURE__ */ jsx("feBlend", { in: "gray", in2: "linesGray", mode: "multiply" }),
11062
- /* @__PURE__ */ jsxs("feComponentTransfer", { children: [
11063
- /* @__PURE__ */ jsx("feFuncR", { type: "linear", slope: 1.3, intercept: -0.05 }),
11064
- /* @__PURE__ */ jsx("feFuncG", { type: "linear", slope: 1.3, intercept: -0.05 }),
11065
- /* @__PURE__ */ jsx("feFuncB", { type: "linear", slope: 1.3, intercept: -0.05 })
11066
- ] })
11067
- ] });
11068
- }
11069
- // ── Mosaic / Mosaic Bubbles ─────────────────────────────────────────
11070
- // Pixelation effect: achieved via heavy blur + displacement noise.
11071
- // True pixelation requires image-rendering: pixelated + downscale
11072
- // but SVG filter gives a reasonable approximation.
11073
- case "artisticMosaic":
11074
- case "artisticMosaicBubbles":
11075
- case "mosaicBubbles":
11076
- case "mosaic": {
11077
- const blurAmount = Math.max(2, Math.round(radius * 0.8));
11078
- const freq = 0.02 + normalizedRadius * 0.03;
11079
- return /* @__PURE__ */ jsxs(Fragment, { children: [
11080
- /* @__PURE__ */ jsx("feGaussianBlur", { in: "SourceGraphic", stdDeviation: blurAmount, result: "blurred" }),
11081
- /* @__PURE__ */ jsx(
11082
- "feTurbulence",
11083
- {
11084
- type: "turbulence",
11085
- baseFrequency: freq,
11086
- numOctaves: 1,
11087
- seed: 4,
11088
- result: "cells"
11089
- }
11090
- ),
11091
- /* @__PURE__ */ jsx(
11092
- "feDisplacementMap",
11093
- {
11094
- in: "blurred",
11095
- in2: "cells",
11096
- scale: blurAmount * 0.5,
11097
- xChannelSelector: "R",
11098
- yChannelSelector: "G",
11099
- result: "mosaic"
11100
- }
11101
- ),
11102
- /* @__PURE__ */ jsxs("feComponentTransfer", { in: "mosaic", children: [
11103
- /* @__PURE__ */ jsx("feFuncR", { type: "linear", slope: 1.05, intercept: 0 }),
11104
- /* @__PURE__ */ jsx("feFuncG", { type: "linear", slope: 1.05, intercept: 0 }),
11105
- /* @__PURE__ */ jsx("feFuncB", { type: "linear", slope: 1.05, intercept: 0 })
11106
- ] })
11107
- ] });
11108
- }
11109
- // ── Glow Edges ─────────────────────────────────────────────────────
11110
- // Edge detection with glow: invert, blur slightly, overlay to
11111
- // create edge-glowing effect.
11112
- case "artisticGlowEdges":
11113
- case "glowEdges":
11114
- case "glow_edges": {
11115
- const edgeBlur = Math.max(1, Math.round(normalizedRadius * 3));
11116
- return /* @__PURE__ */ jsxs(Fragment, { children: [
11117
- /* @__PURE__ */ jsx(
11118
- "feColorMatrix",
11119
- {
11120
- type: "matrix",
11121
- values: "-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0",
11122
- result: "inverted"
11123
- }
11124
- ),
11125
- /* @__PURE__ */ jsx("feGaussianBlur", { in: "inverted", stdDeviation: edgeBlur, result: "blurredInv" }),
11126
- /* @__PURE__ */ jsx("feBlend", { in: "SourceGraphic", in2: "blurredInv", mode: "screen" }),
11127
- /* @__PURE__ */ jsxs("feComponentTransfer", { children: [
11128
- /* @__PURE__ */ jsx("feFuncR", { type: "linear", slope: 2, intercept: -0.3 }),
11129
- /* @__PURE__ */ jsx("feFuncG", { type: "linear", slope: 2, intercept: -0.3 }),
11130
- /* @__PURE__ */ jsx("feFuncB", { type: "linear", slope: 2, intercept: -0.3 })
11131
- ] })
11132
- ] });
11133
- }
11134
- // ── Chalk Sketch ───────────────────────────────────────────────────
11135
- // Grayscale with high contrast and chalk-like noise texture.
11136
- case "artisticChalkSketch":
11137
- case "chalkSketch":
11138
- case "chalk": {
11139
- const freq = 1 + normalizedRadius * 2;
11140
- return /* @__PURE__ */ jsxs(Fragment, { children: [
11141
- /* @__PURE__ */ jsx(
11142
- "feColorMatrix",
11143
- {
11144
- type: "saturate",
11145
- values: `${Math.max(0, 0.2 - normalizedRadius * 0.2)}`,
11146
- result: "gray"
11147
- }
11148
- ),
11149
- /* @__PURE__ */ jsx(
11150
- "feTurbulence",
11151
- {
11152
- type: "fractalNoise",
11153
- baseFrequency: freq,
11154
- numOctaves: 4,
11155
- seed: 5,
11156
- stitchTiles: "stitch",
11157
- result: "chalkTex"
11158
- }
11159
- ),
11160
- /* @__PURE__ */ jsx("feColorMatrix", { in: "chalkTex", type: "saturate", values: "0", result: "chalkGray" }),
11161
- /* @__PURE__ */ jsx("feBlend", { in: "gray", in2: "chalkGray", mode: "overlay" }),
11162
- /* @__PURE__ */ jsxs("feComponentTransfer", { children: [
11163
- /* @__PURE__ */ jsx("feFuncR", { type: "linear", slope: 1.5, intercept: 0.05 }),
11164
- /* @__PURE__ */ jsx("feFuncG", { type: "linear", slope: 1.5, intercept: 0.05 }),
11165
- /* @__PURE__ */ jsx("feFuncB", { type: "linear", slope: 1.5, intercept: 0.05 })
11166
- ] })
11167
- ] });
11168
- }
11169
- // ── Pencil Sketch ──────────────────────────────────────────────────
11170
- // Grayscale with edge enhancement: invert + blur + blend (multiply)
11171
- // to create pencil-drawing look.
11172
- case "artisticPencilSketch":
11173
- case "pencilSketch": {
11174
- const blurAmt = Math.max(3, Math.round(4 + normalizedRadius * 8));
11175
- return /* @__PURE__ */ jsxs(Fragment, { children: [
11176
- /* @__PURE__ */ jsx("feColorMatrix", { type: "saturate", values: "0", result: "gray" }),
11177
- /* @__PURE__ */ jsx(
11178
- "feColorMatrix",
11179
- {
11180
- in: "gray",
11181
- type: "matrix",
11182
- values: "-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0",
11183
- result: "invGray"
11184
- }
11185
- ),
11186
- /* @__PURE__ */ jsx("feGaussianBlur", { in: "invGray", stdDeviation: blurAmt, result: "blurInv" }),
11187
- /* @__PURE__ */ jsx("feBlend", { in: "blurInv", in2: "gray", mode: "screen", result: "sketch" }),
11188
- /* @__PURE__ */ jsxs("feComponentTransfer", { in: "sketch", children: [
11189
- /* @__PURE__ */ jsx("feFuncR", { type: "linear", slope: 1.6, intercept: -0.15 }),
11190
- /* @__PURE__ */ jsx("feFuncG", { type: "linear", slope: 1.6, intercept: -0.15 }),
11191
- /* @__PURE__ */ jsx("feFuncB", { type: "linear", slope: 1.6, intercept: -0.15 })
11192
- ] })
11193
- ] });
11194
- }
11195
- // ── Pencil Grayscale ───────────────────────────────────────────────
11196
- // Desaturated image with enhanced edge contrast (sharpen effect).
11197
- case "artisticPencilGrayscale":
11198
- case "pencilGrayscale":
11199
- case "grayPencil": {
11200
- const sharpenBlur = Math.max(0.5, 1 + normalizedRadius * 2);
11201
- return /* @__PURE__ */ jsxs(Fragment, { children: [
11202
- /* @__PURE__ */ jsx("feColorMatrix", { type: "saturate", values: "0", result: "gray" }),
11203
- /* @__PURE__ */ jsx("feGaussianBlur", { in: "gray", stdDeviation: sharpenBlur, result: "grayBlur" }),
11204
- /* @__PURE__ */ jsx(
11205
- "feComposite",
11206
- {
11207
- in: "gray",
11208
- in2: "grayBlur",
11209
- operator: "arithmetic",
11210
- k1: 0,
11211
- k2: 1.5,
11212
- k3: -0.5,
11213
- k4: 0
11214
- }
11215
- )
11216
- ] });
11217
- }
11218
- default:
11219
- return null;
11220
- }
11221
- }
11222
- function buildDiscreteTable(steps) {
11223
- const values = [];
11224
- for (let i = 0; i < steps; i++) {
11225
- const v = Math.round(i / (steps - 1) * 100) / 100;
11226
- const count = Math.ceil(256 / steps);
11227
- for (let j = 0; j < count; j++) {
11228
- values.push(v);
11229
- }
11230
- }
11231
- return values.slice(0, 256).join(" ");
11232
- }
11233
10850
 
11234
10851
  // src/viewer/hooks/useElementOperations.ts
11235
10852
  function useElementOperations(input) {
@@ -13700,8 +13317,11 @@ function useTableOperations(input) {
13700
13317
  ...mergeHandlers
13701
13318
  };
13702
13319
  }
13320
+
13321
+ // src/lib/canvas-export.ts
13703
13322
  async function renderToCanvas(element, options = {}) {
13704
13323
  const userOnClone = options.onclone;
13324
+ const { default: html2canvasPro } = await import('html2canvas-pro');
13705
13325
  return html2canvasPro(element, {
13706
13326
  ...options,
13707
13327
  onclone: async (doc, clonedEl) => {
@@ -13965,24 +13585,6 @@ async function exportAllSlidesAsGif(slideStageRef, totalSlides, setActiveSlide,
13965
13585
  return new Blob([buf], { type: "image/gif" });
13966
13586
  }
13967
13587
 
13968
- // src/viewer/utils/export-package.ts
13969
- function generatePackageReadme(presentationFilename) {
13970
- return [
13971
- "Presentation Package",
13972
- "====================",
13973
- "",
13974
- `This folder contains the presentation "${presentationFilename}" along with`,
13975
- "all linked media files (images, audio, video) in the /media subfolder.",
13976
- "",
13977
- "To view this presentation:",
13978
- "1. Open the .pptx file with any compatible presentation software",
13979
- "2. Ensure the /media folder remains alongside the .pptx file",
13980
- "",
13981
- `Packaged on ${(/* @__PURE__ */ new Date()).toLocaleDateString()}`,
13982
- ""
13983
- ].join("\n");
13984
- }
13985
-
13986
13588
  // src/viewer/utils/export-svg.ts
13987
13589
  function injectFontFaces(svg, fontFaces) {
13988
13590
  if (!fontFaces.length) {
@@ -14788,13 +14390,6 @@ function useThemeHandlers(input) {
14788
14390
  handleSwitchTheme
14789
14391
  };
14790
14392
  }
14791
- function colorSchemesMatch(a, b) {
14792
- if (!a) {
14793
- return false;
14794
- }
14795
- const normalize = (hex) => hex.replace(/^#/u, "").toUpperCase().slice(0, 6);
14796
- return normalize(a.dk1) === normalize(b.dk1) && normalize(a.lt1) === normalize(b.lt1) && normalize(a.dk2) === normalize(b.dk2) && normalize(a.lt2) === normalize(b.lt2) && normalize(a.accent1) === normalize(b.accent1) && normalize(a.accent2) === normalize(b.accent2) && normalize(a.accent3) === normalize(b.accent3) && normalize(a.accent4) === normalize(b.accent4) && normalize(a.accent5) === normalize(b.accent5) && normalize(a.accent6) === normalize(b.accent6) && normalize(a.hlink) === normalize(b.hlink) && normalize(a.folHlink) === normalize(b.folHlink);
14797
- }
14798
14393
  function useThemeSwitching(input) {
14799
14394
  const { handlerRef, data, onDataChange, onThemeChanged } = input;
14800
14395
  const switchToPreset = useCallback(
@@ -14834,7 +14429,9 @@ function useThemeSwitching(input) {
14834
14429
  if (!data?.theme?.colorScheme) {
14835
14430
  return void 0;
14836
14431
  }
14837
- return THEME_PRESETS.find((p) => colorSchemesMatch(data.theme?.colorScheme, p.colorScheme));
14432
+ return THEME_PRESETS.find(
14433
+ (p) => themeColorSchemesEqual(data.theme?.colorScheme, p.colorScheme)
14434
+ );
14838
14435
  }, [data?.theme?.colorScheme]);
14839
14436
  return {
14840
14437
  presets: THEME_PRESETS,
@@ -14843,74 +14440,6 @@ function useThemeSwitching(input) {
14843
14440
  currentPreset
14844
14441
  };
14845
14442
  }
14846
-
14847
- // src/viewer/hooks/usePropertyHandlers-helpers.ts
14848
- function collectUsedFonts(slides) {
14849
- const fonts = /* @__PURE__ */ new Set();
14850
- for (const slide of slides) {
14851
- for (const el of slide.elements ?? []) {
14852
- collectFontsFromElement(el, fonts);
14853
- }
14854
- }
14855
- return Array.from(fonts).sort();
14856
- }
14857
- function collectFontsFromElement(el, fonts) {
14858
- if (hasTextProperties(el)) {
14859
- if (el.textStyle?.fontFamily) {
14860
- fonts.add(el.textStyle.fontFamily);
14861
- }
14862
- if (el.textSegments) {
14863
- for (const seg of el.textSegments) {
14864
- if (seg.style?.fontFamily) {
14865
- fonts.add(seg.style.fontFamily);
14866
- }
14867
- }
14868
- }
14869
- }
14870
- if (el.type === "group" && el.children) {
14871
- for (const child of el.children) {
14872
- collectFontsFromElement(child, fonts);
14873
- }
14874
- }
14875
- }
14876
- function applyAcceptSlide(slides, diff) {
14877
- const n = [...slides];
14878
- if (diff.status === "added" && diff.compareSlide) {
14879
- n.splice(Math.min(diff.compareIndex, n.length), 0, {
14880
- ...diff.compareSlide
14881
- });
14882
- } else if (diff.status === "changed" && diff.compareSlide && diff.baseIndex >= 0) {
14883
- n[diff.baseIndex] = { ...diff.compareSlide };
14884
- } else if (diff.status === "removed" && diff.baseIndex >= 0) {
14885
- n.splice(diff.baseIndex, 1);
14886
- }
14887
- return n;
14888
- }
14889
- function applyAcceptAllSlides(slides, compareResult) {
14890
- const n = [...slides];
14891
- const dd = [...compareResult.diffs];
14892
- for (let i = dd.length - 1; i >= 0; i--) {
14893
- const x = dd[i];
14894
- if (x.status === "removed" && x.baseIndex >= 0 && x.baseIndex < n.length) {
14895
- n.splice(x.baseIndex, 1);
14896
- }
14897
- }
14898
- for (const x of dd) {
14899
- if (x.status === "changed" && x.compareSlide && x.baseIndex >= 0 && x.baseIndex < n.length) {
14900
- n[x.baseIndex] = { ...x.compareSlide };
14901
- }
14902
- }
14903
- for (const x of dd) {
14904
- if (x.status === "added" && x.compareSlide) {
14905
- n.splice(Math.min(x.compareIndex, n.length), 0, {
14906
- ...x.compareSlide
14907
- });
14908
- }
14909
- }
14910
- return n;
14911
- }
14912
-
14913
- // src/viewer/hooks/usePropertyHandlers.ts
14914
14443
  function usePropertyHandlers(input) {
14915
14444
  const {
14916
14445
  slides,
@@ -15493,54 +15022,13 @@ function computeVisibleSlideIndexes(slides, activeCustomShowId, customShows) {
15493
15022
  return slides.map((_, i) => i).filter((i) => !slides[i]?.hidden);
15494
15023
  }
15495
15024
  function computeSlideSectionGroups(slides, sections) {
15496
- if (slides.length === 0) {
15497
- return [];
15498
- }
15499
- if (sections.length > 0) {
15500
- const sectionSlideMap = /* @__PURE__ */ new Map();
15501
- const ungroupedIndexes = [];
15502
- for (let i = 0; i < slides.length; i++) {
15503
- const sid = slides[i].sectionId;
15504
- if (sid) {
15505
- const arr = sectionSlideMap.get(sid);
15506
- if (arr) {
15507
- arr.push(i);
15508
- } else {
15509
- sectionSlideMap.set(sid, [i]);
15510
- }
15511
- } else {
15512
- ungroupedIndexes.push(i);
15513
- }
15514
- }
15515
- const groups = sections.map((sec) => ({
15516
- id: sec.id,
15517
- label: sec.name,
15518
- slideIndexes: sectionSlideMap.get(sec.id) ?? [],
15519
- color: sec.color,
15520
- defaultCollapsed: sec.collapsed
15521
- })).filter((g) => g.slideIndexes.length > 0);
15522
- if (ungroupedIndexes.length > 0) {
15523
- groups.push({
15524
- id: UNGROUPED_SECTION_ID,
15525
- label: "Ungrouped Slides",
15526
- slideIndexes: ungroupedIndexes
15527
- });
15528
- }
15529
- return groups.length > 0 ? groups : [
15530
- {
15531
- id: "default",
15532
- label: "Slides",
15533
- slideIndexes: slides.map((_s, i) => i)
15534
- }
15535
- ];
15536
- }
15537
- return [
15538
- {
15539
- id: "default",
15540
- label: "Slides",
15541
- slideIndexes: slides.map((_s, i) => i)
15542
- }
15543
- ];
15025
+ return groupSlidesBySection(sections, slides).map((group) => ({
15026
+ id: group.section?.id ?? (sections.length > 0 ? UNGROUPED_SECTION_ID : "default"),
15027
+ label: group.section?.name ?? (sections.length > 0 ? "Ungrouped Slides" : "Slides"),
15028
+ slideIndexes: group.slideIndexes,
15029
+ ...group.section?.color !== void 0 ? { color: group.section.color } : {},
15030
+ ...group.section?.collapsed !== void 0 ? { defaultCollapsed: group.section.collapsed } : {}
15031
+ }));
15544
15032
  }
15545
15033
  function computeMasterPseudoSlide(mode, activeLayout, activeMaster) {
15546
15034
  if (mode !== "master") {
@@ -17513,7 +17001,7 @@ function useYjsDocumentSync({
17513
17001
  return;
17514
17002
  }
17515
17003
  try {
17516
- const { PptxHandler: PptxHandler2 } = await import('./dist-MXDC6YTS.mjs');
17004
+ const { PptxHandler: PptxHandler2 } = await import('./dist-3YRZ26TL.mjs');
17517
17005
  const handler = new PptxHandler2();
17518
17006
  await handler.load(sourceBytes.buffer);
17519
17007
  const currentSlides = readSlidesFromYDoc(
@@ -17720,39 +17208,10 @@ function useLayoutSwitching(input) {
17720
17208
  currentLayoutPath
17721
17209
  };
17722
17210
  }
17723
- var DEFAULT_OVERSCAN = 5;
17724
- function computeVirtualRange(totalItems, itemHeight, scrollTop, viewportHeight, overscan = DEFAULT_OVERSCAN) {
17725
- const safeItemHeight = Math.max(itemHeight, 1);
17726
- const totalHeight = totalItems * safeItemHeight;
17727
- if (totalItems === 0) {
17728
- return {
17729
- startIndex: 0,
17730
- endIndex: -1,
17731
- totalHeight: 0,
17732
- offsetY: 0,
17733
- visibleRange: { start: 0, end: -1 }
17734
- };
17735
- }
17736
- const visibleStart = Math.floor(scrollTop / safeItemHeight);
17737
- const visibleEnd = Math.min(
17738
- totalItems - 1,
17739
- Math.floor((scrollTop + viewportHeight) / safeItemHeight)
17740
- );
17741
- const startIndex = Math.max(0, visibleStart - overscan);
17742
- const endIndex = Math.min(totalItems - 1, visibleEnd + overscan);
17743
- const offsetY = startIndex * safeItemHeight;
17744
- return {
17745
- startIndex,
17746
- endIndex,
17747
- totalHeight,
17748
- offsetY,
17749
- visibleRange: { start: visibleStart, end: visibleEnd }
17750
- };
17751
- }
17752
17211
  function useVirtualizedSlides({
17753
17212
  totalItems,
17754
17213
  itemHeight,
17755
- overscan = DEFAULT_OVERSCAN
17214
+ overscan = DEFAULT_VIRTUAL_OVERSCAN
17756
17215
  }) {
17757
17216
  const scrollContainerRef = useRef(null);
17758
17217
  const [scrollTop, setScrollTop] = useState(0);
@@ -17989,4 +17448,4 @@ function useSwipeNavigation(input) {
17989
17448
  return { onTouchStart, onTouchEnd };
17990
17449
  }
17991
17450
 
17992
- export { ACTION_VERB_MAP, ANIMATION_PRESET_OPTIONS, DEFAULT_FILL_COLOR, DEFAULT_FONT_FAMILY, DEFAULT_STROKE_COLOR, DEFAULT_TEXT_COLOR, DEFAULT_TEXT_FONT_SIZE, EMU_PER_PX, GRID_SIZE, HYPERLINK_COLOR, MIN_ELEMENT_SIZE, MIN_TOUCH_TARGET, SHAPE_PRESETS, SHORTCUT_REFERENCE_ITEMS, SLIDE_NAV_THUMBNAIL_WIDTH, SLIDE_TRANSITION_OPTIONS, SmartArtNodeText, TOOLBAR_SECTIONS, build3DExtrusionData2 as build3DExtrusionData, buildLineGlowFilter, buildLineShadowCss, buildReactChartViewModel, buildTextBody3DSceneStyle2 as buildTextBody3DSceneStyle, buildTree, cellStyleToCss, chevronPoints, clearAudienceContent, cn, colour, computeVirtualRange, detectTargetType, ensureArrayValue, extractCellText, extractTableCellStyle, fitFontSize, gearPath, getAnimationInitialStyle2 as getAnimationInitialStyle, getConnectorPathGeometry, getCropShapeClipPath, getDuotoneColors, getImageRenderStyle, getImageTilingStyle, getShapeVisualStyle, getTableCellBandStyle, getTextLayoutStyle, getTextStyleForElement, getTextWarpStyle, hasDagDuotoneEffect, isAudienceTab, isConnectorOrLineElement, isImageTiled, layoutToCategory, loadAudienceContent, nodeOpacity, parseEmailUrl, parseSlideFromUrl, parseTableElementData, renderAccentProcess, renderAlternatingFlow, renderArtisticEffectSvgFilter, renderChartElement, renderConnectorMarker, renderDagDuotoneSvgFilter, renderDescendingProcess, renderDuotoneSvgFilter, renderGroupedList, renderHorizontalPictureList, renderImageAlphaSvgFilter, renderMediaElement, renderPictureAccentList, renderPyramidList, renderStepDownProcess, renderTableElement, renderTextSegments, renderToCanvas, renderVectorShape, renderVerticalBlockList, renderVerticalChevronList, resolvePalette, resolveSmartArtDataPalette, resolveStyle, shouldRenderFallbackLabel, smartArtNodeGroupProps, startPreviewAnimation, stopPreviewAnimation, storeAudienceContent, styleShadow, styleStroke, treeDepth, treeWidth, truncate, 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, useTouchGestures, useViewerCoreState, useViewerDialogs, useViewerIntegration, useViewerState, useViewerUIState, useVirtualizedSlides, useYjsDocumentSync, useYjsProvider, useZoomNavigation, useZoomViewport, wrapChrome };
17451
+ export { ACTION_VERB_MAP, ANIMATION_PRESET_OPTIONS, DEFAULT_FILL_COLOR, DEFAULT_FONT_FAMILY, DEFAULT_STROKE_COLOR, DEFAULT_TEXT_COLOR, DEFAULT_TEXT_FONT_SIZE, GRID_SIZE, HYPERLINK_COLOR, MIN_ELEMENT_SIZE, MIN_TOUCH_TARGET, SHAPE_PRESETS, SHORTCUT_REFERENCE_ITEMS, SLIDE_NAV_THUMBNAIL_WIDTH, SLIDE_TRANSITION_OPTIONS, SmartArtNodeText, TOOLBAR_SECTIONS, build3DExtrusionData2 as build3DExtrusionData, buildLineGlowFilter, buildLineShadowCss, buildReactChartViewModel, buildTextBody3DSceneStyle2 as buildTextBody3DSceneStyle, buildTree, chevronPoints, clearAudienceContent, cn, colour, detectTargetType, fitFontSize, gearPath, getAnimationInitialStyle2 as getAnimationInitialStyle, getConnectorPathGeometry, getCropShapeClipPath, getDuotoneColors, getImageRenderStyle, getImageTilingStyle, getShapeVisualStyle, getTextLayoutStyle, getTextStyleForElement, getTextWarpStyle, hasDagDuotoneEffect, isAudienceTab, isConnectorOrLineElement, isImageTiled, layoutToCategory, loadAudienceContent, nodeOpacity, parseAudienceNonce, parseEmailUrl, parseSlideFromUrl, renderAccentProcess, renderAlternatingFlow, renderChartElement, renderConnectorMarker, renderDagDuotoneSvgFilter, renderDescendingProcess, renderGroupedList, renderHorizontalPictureList, renderMediaElement, renderPictureAccentList, renderPyramidList, renderStepDownProcess, renderTableElement, renderTextSegments, renderToCanvas, renderVectorShape, renderVerticalBlockList, renderVerticalChevronList, resolvePalette, resolveSmartArtDataPalette, resolveStyle, shouldRenderFallbackLabel, smartArtNodeGroupProps, startPreviewAnimation, stopPreviewAnimation, storeAudienceContent, styleShadow, styleStroke, treeDepth, treeWidth, truncate, 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, useTouchGestures, useViewerCoreState, useViewerDialogs, useViewerIntegration, useViewerState, useViewerUIState, useVirtualizedSlides, useYjsDocumentSync, useYjsProvider, useZoomNavigation, useZoomViewport, wrapChrome };