pptx-react-viewer 3.2.0 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/dist/{AiChatPanel-TKBVSYD2.js → AiChatPanel-3Q4STA5E.js} +29 -28
  3. package/dist/AiChatPanel-3Q4STA5E.js.br +0 -0
  4. package/dist/AiChatPanel-3Q4STA5E.js.gz +0 -0
  5. package/dist/{AiChatPanel-C3E7NLX3.mjs → AiChatPanel-NQZBZIRM.mjs} +9 -8
  6. package/dist/AiChatPanel-NQZBZIRM.mjs.br +0 -0
  7. package/dist/AiChatPanel-NQZBZIRM.mjs.gz +0 -0
  8. package/dist/{Area3DChartScene-7YCFWEGX.mjs → Area3DChartScene-7PARQDOZ.mjs} +1 -1
  9. package/dist/Area3DChartScene-7PARQDOZ.mjs.br +3 -0
  10. package/dist/Area3DChartScene-7PARQDOZ.mjs.gz +0 -0
  11. package/dist/{Area3DChartScene-3A3CXKN3.js → Area3DChartScene-THLG74CM.js} +2 -2
  12. package/dist/Area3DChartScene-THLG74CM.js.br +0 -0
  13. package/dist/Area3DChartScene-THLG74CM.js.gz +0 -0
  14. package/dist/{Bar3DChartScene-BDUENAWJ.js → Bar3DChartScene-OLZ2V56I.js} +2 -2
  15. package/dist/Bar3DChartScene-OLZ2V56I.js.br +2 -0
  16. package/dist/Bar3DChartScene-OLZ2V56I.js.gz +0 -0
  17. package/dist/{Bar3DChartScene-7CNSJ35X.mjs → Bar3DChartScene-QUU6RUXM.mjs} +1 -1
  18. package/dist/Bar3DChartScene-QUU6RUXM.mjs.br +0 -0
  19. package/dist/Bar3DChartScene-QUU6RUXM.mjs.gz +0 -0
  20. package/dist/{Line3DChartScene-R352CZ5U.js → Line3DChartScene-2VZS52IB.js} +2 -2
  21. package/dist/Line3DChartScene-2VZS52IB.js.br +0 -0
  22. package/dist/Line3DChartScene-2VZS52IB.js.gz +0 -0
  23. package/dist/{Line3DChartScene-SMTHK6MD.mjs → Line3DChartScene-D77ORA4K.mjs} +1 -1
  24. package/dist/Line3DChartScene-D77ORA4K.mjs.br +3 -0
  25. package/dist/Line3DChartScene-D77ORA4K.mjs.gz +0 -0
  26. package/dist/{Model3DScene-Y4SGFQYW.js → Model3DScene-3WCALTXO.js} +2 -2
  27. package/dist/Model3DScene-3WCALTXO.js.br +0 -0
  28. package/dist/Model3DScene-3WCALTXO.js.gz +0 -0
  29. package/dist/{Model3DScene-AUVJXXPV.mjs → Model3DScene-ZEGWNILH.mjs} +1 -1
  30. package/dist/Model3DScene-ZEGWNILH.mjs.br +0 -0
  31. package/dist/Model3DScene-ZEGWNILH.mjs.gz +0 -0
  32. package/dist/{PieChart3DScene-TK2VT4RS.js → PieChart3DScene-7C3ACGKN.js} +2 -2
  33. package/dist/PieChart3DScene-7C3ACGKN.js.br +0 -0
  34. package/dist/PieChart3DScene-7C3ACGKN.js.gz +0 -0
  35. package/dist/{PieChart3DScene-UD7GRH55.mjs → PieChart3DScene-DGD4PZVV.mjs} +1 -1
  36. package/dist/PieChart3DScene-DGD4PZVV.mjs.br +0 -0
  37. package/dist/PieChart3DScene-DGD4PZVV.mjs.gz +0 -0
  38. package/dist/PowerPointViewer-Cl6jBPNw.d.ts.map +1 -1
  39. package/dist/{SurfaceChart3DScene-TXY6UZSW.mjs → SurfaceChart3DScene-QGH3OLJV.mjs} +1 -1
  40. package/dist/SurfaceChart3DScene-QGH3OLJV.mjs.br +0 -0
  41. package/dist/SurfaceChart3DScene-QGH3OLJV.mjs.gz +0 -0
  42. package/dist/{SurfaceChart3DScene-ERFXZW2O.js → SurfaceChart3DScene-SJPQGGGE.js} +2 -2
  43. package/dist/SurfaceChart3DScene-SJPQGGGE.js.br +0 -0
  44. package/dist/SurfaceChart3DScene-SJPQGGGE.js.gz +0 -0
  45. package/dist/{chunk-RRAL4Y7V.js → chunk-7E6SM42A.js} +2604 -2024
  46. package/dist/chunk-7E6SM42A.js.br +0 -0
  47. package/dist/chunk-7E6SM42A.js.gz +0 -0
  48. package/dist/{chunk-G7UBIKAG.mjs → chunk-B7WAGQW4.mjs} +5383 -873
  49. package/dist/chunk-B7WAGQW4.mjs.br +0 -0
  50. package/dist/chunk-B7WAGQW4.mjs.gz +0 -0
  51. package/dist/{chunk-RX6FE24O.mjs → chunk-C4WTQIC6.mjs} +302 -61
  52. package/dist/chunk-C4WTQIC6.mjs.br +0 -0
  53. package/dist/chunk-C4WTQIC6.mjs.gz +0 -0
  54. package/dist/{chunk-Q52HT4EZ.js → chunk-KY6JQJXK.js} +307 -63
  55. package/dist/chunk-KY6JQJXK.js.br +0 -0
  56. package/dist/chunk-KY6JQJXK.js.gz +0 -0
  57. package/dist/{chunk-PPNXPEEZ.mjs → chunk-L5MRKDRM.mjs} +1514 -934
  58. package/dist/chunk-L5MRKDRM.mjs.br +0 -0
  59. package/dist/chunk-L5MRKDRM.mjs.gz +0 -0
  60. package/dist/{chunk-UHR7EYFM.mjs → chunk-MSUUPLQ7.mjs} +718 -435
  61. package/dist/chunk-MSUUPLQ7.mjs.br +0 -0
  62. package/dist/chunk-MSUUPLQ7.mjs.gz +0 -0
  63. package/dist/{chunk-FJDZ7AEE.js → chunk-PCW2KT7Z.js} +5446 -879
  64. package/dist/chunk-PCW2KT7Z.js.br +0 -0
  65. package/dist/chunk-PCW2KT7Z.js.gz +0 -0
  66. package/dist/{chunk-FMEEIS6L.mjs → chunk-SFMATKNJ.mjs} +13 -114
  67. package/dist/chunk-SFMATKNJ.mjs.br +0 -0
  68. package/dist/chunk-SFMATKNJ.mjs.gz +0 -0
  69. package/dist/{chunk-ARQGUUYU.js → chunk-TJNG5VEK.js} +1114 -826
  70. package/dist/chunk-TJNG5VEK.js.br +0 -0
  71. package/dist/chunk-TJNG5VEK.js.gz +0 -0
  72. package/dist/{chunk-ALO4ZOHQ.js → chunk-UNIJUD5C.js} +45 -1
  73. package/dist/chunk-UNIJUD5C.js.br +0 -0
  74. package/dist/chunk-UNIJUD5C.js.gz +0 -0
  75. package/dist/{chunk-B6UIVRFA.js → chunk-XBTHWXNO.js} +177 -279
  76. package/dist/chunk-XBTHWXNO.js.br +0 -0
  77. package/dist/chunk-XBTHWXNO.js.gz +0 -0
  78. package/dist/{chunk-RHSA5BW5.mjs → chunk-XWUMM2TX.mjs} +45 -1
  79. package/dist/chunk-XWUMM2TX.mjs.br +0 -0
  80. package/dist/chunk-XWUMM2TX.mjs.gz +0 -0
  81. package/dist/i18n.js +4 -4
  82. package/dist/i18n.js.br +0 -0
  83. package/dist/i18n.js.gz +0 -0
  84. package/dist/i18n.mjs +1 -1
  85. package/dist/i18n.mjs.br +0 -0
  86. package/dist/i18n.mjs.gz +0 -0
  87. package/dist/index.d.ts +7 -0
  88. package/dist/index.js +47 -47
  89. package/dist/index.js.br +0 -0
  90. package/dist/index.js.gz +0 -0
  91. package/dist/index.mjs +6 -6
  92. package/dist/index.mjs.br +0 -0
  93. package/dist/index.mjs.gz +0 -0
  94. package/dist/internals.d.ts +176 -5
  95. package/dist/internals.d.ts.map +1 -1
  96. package/dist/internals.js +79 -79
  97. package/dist/internals.js.br +0 -0
  98. package/dist/internals.js.gz +0 -0
  99. package/dist/internals.mjs +4 -4
  100. package/dist/internals.mjs.br +0 -0
  101. package/dist/internals.mjs.gz +0 -0
  102. package/dist/pptx-viewer.css +1 -1
  103. package/dist/pptx-viewer.css.br +0 -0
  104. package/dist/pptx-viewer.css.gz +0 -0
  105. package/dist/{useViewerBuildingBlocks-X1L8BjsQ.d.ts → useViewerBuildingBlocks-f6oNGKMX.d.ts} +8 -1
  106. package/dist/useViewerBuildingBlocks-f6oNGKMX.d.ts.map +1 -0
  107. package/dist/viewer/index.js +27 -27
  108. package/dist/viewer/index.js.br +0 -0
  109. package/dist/viewer/index.js.gz +0 -0
  110. package/dist/viewer/index.mjs +6 -6
  111. package/dist/viewer/index.mjs.br +0 -0
  112. package/dist/viewer/index.mjs.gz +0 -0
  113. package/package.json +1 -1
  114. package/dist/AiChatPanel-C3E7NLX3.mjs.br +0 -0
  115. package/dist/AiChatPanel-C3E7NLX3.mjs.gz +0 -0
  116. package/dist/AiChatPanel-TKBVSYD2.js.br +0 -0
  117. package/dist/AiChatPanel-TKBVSYD2.js.gz +0 -0
  118. package/dist/Area3DChartScene-3A3CXKN3.js.br +0 -0
  119. package/dist/Area3DChartScene-3A3CXKN3.js.gz +0 -0
  120. package/dist/Area3DChartScene-7YCFWEGX.mjs.br +0 -3
  121. package/dist/Area3DChartScene-7YCFWEGX.mjs.gz +0 -0
  122. package/dist/Bar3DChartScene-7CNSJ35X.mjs.br +0 -0
  123. package/dist/Bar3DChartScene-7CNSJ35X.mjs.gz +0 -0
  124. package/dist/Bar3DChartScene-BDUENAWJ.js.br +0 -0
  125. package/dist/Bar3DChartScene-BDUENAWJ.js.gz +0 -0
  126. package/dist/Line3DChartScene-R352CZ5U.js.br +0 -0
  127. package/dist/Line3DChartScene-R352CZ5U.js.gz +0 -0
  128. package/dist/Line3DChartScene-SMTHK6MD.mjs.br +0 -3
  129. package/dist/Line3DChartScene-SMTHK6MD.mjs.gz +0 -0
  130. package/dist/Model3DScene-AUVJXXPV.mjs.br +0 -0
  131. package/dist/Model3DScene-AUVJXXPV.mjs.gz +0 -0
  132. package/dist/Model3DScene-Y4SGFQYW.js.br +0 -0
  133. package/dist/Model3DScene-Y4SGFQYW.js.gz +0 -0
  134. package/dist/PieChart3DScene-TK2VT4RS.js.br +0 -0
  135. package/dist/PieChart3DScene-TK2VT4RS.js.gz +0 -0
  136. package/dist/PieChart3DScene-UD7GRH55.mjs.br +0 -0
  137. package/dist/PieChart3DScene-UD7GRH55.mjs.gz +0 -0
  138. package/dist/SurfaceChart3DScene-ERFXZW2O.js.br +0 -0
  139. package/dist/SurfaceChart3DScene-ERFXZW2O.js.gz +0 -0
  140. package/dist/SurfaceChart3DScene-TXY6UZSW.mjs.br +0 -0
  141. package/dist/SurfaceChart3DScene-TXY6UZSW.mjs.gz +0 -0
  142. package/dist/chunk-ALO4ZOHQ.js.br +0 -0
  143. package/dist/chunk-ALO4ZOHQ.js.gz +0 -0
  144. package/dist/chunk-ARQGUUYU.js.br +0 -0
  145. package/dist/chunk-ARQGUUYU.js.gz +0 -0
  146. package/dist/chunk-B6UIVRFA.js.br +0 -0
  147. package/dist/chunk-B6UIVRFA.js.gz +0 -0
  148. package/dist/chunk-FJDZ7AEE.js.br +0 -0
  149. package/dist/chunk-FJDZ7AEE.js.gz +0 -0
  150. package/dist/chunk-FMEEIS6L.mjs.br +0 -0
  151. package/dist/chunk-FMEEIS6L.mjs.gz +0 -0
  152. package/dist/chunk-G7UBIKAG.mjs.br +0 -0
  153. package/dist/chunk-G7UBIKAG.mjs.gz +0 -0
  154. package/dist/chunk-PPNXPEEZ.mjs.br +0 -0
  155. package/dist/chunk-PPNXPEEZ.mjs.gz +0 -0
  156. package/dist/chunk-Q52HT4EZ.js.br +0 -0
  157. package/dist/chunk-Q52HT4EZ.js.gz +0 -0
  158. package/dist/chunk-RHSA5BW5.mjs.br +0 -0
  159. package/dist/chunk-RHSA5BW5.mjs.gz +0 -0
  160. package/dist/chunk-RRAL4Y7V.js.br +0 -0
  161. package/dist/chunk-RRAL4Y7V.js.gz +0 -0
  162. package/dist/chunk-RX6FE24O.mjs.br +0 -0
  163. package/dist/chunk-RX6FE24O.mjs.gz +0 -0
  164. package/dist/chunk-UHR7EYFM.mjs.br +0 -0
  165. package/dist/chunk-UHR7EYFM.mjs.gz +0 -0
  166. package/dist/useViewerBuildingBlocks-X1L8BjsQ.d.ts.map +0 -1
@@ -1,12 +1,12 @@
1
- import { computeFocusTargets, aiChangeAnimationCss, changeGhostStyle, createChatHistoryStore, toRenderableParts } from './chunk-RX6FE24O.mjs';
2
- import { useViewerOptions, useReducedMotion, useViewerState, useIsMobile, useResizablePanels, useDerivedSlideState, useZoomViewport, useEditorHistory, usePresentationSetup, useTouchGestures, useViewerDialogs, useEditorOperations, useViewerIntegration, useLayoutSwitching, ViewerOptionsContext, useYjsDocumentSync, useCollaborationLivePatch, useFollowMode, useBroadcastFollower, scopeLayoutOptionsToActiveSlide, useToolbarVisibility, useKeyboardInsets, useModalDismissDrag, useCollaborativeState, useViewerOptionsContext, useVirtualizedSlides, useSwipeNavigation, useSheetDismissDrag, detectTargetType, parseEmailUrl, parseSlideFromUrl, ACTION_VERB_MAP } from './chunk-UHR7EYFM.mjs';
3
- import { MIN_ELEMENT_SIZE, DEFAULT_STROKE_COLOR, getConnectorPathGeometry, buildLineShadowCss, buildLineGlowFilter, renderConnectorMarker, getShapeVisualStyle, getTextStyleForElement, DEFAULT_TEXT_COLOR, renderVectorShape, isConnectorOrLineElement, build3DExtrusionData, getImageRenderStyle, cn, getImageSurfaceStyle, getTextLayoutStyle, renderTableElement, renderMediaElement, shouldRenderFallbackLabel, SHAPE_PRESETS, ANIMATION_PRESET_OPTIONS, DEFAULT_FILL_COLOR, hasDagDuotoneEffect, renderDagDuotoneSvgFilter, getImageSurfaceMaskStyle, getCropShapeClipPath, getImageTilingStyle, getDuotoneColors, getTextWarpStyle, renderTextSegments, buildReactChartViewModel, renderChartElement, buildTextBody3DSceneStyle, SLIDE_NAV_THUMBNAIL_WIDTH, DEFAULT_TEXT_FONT_SIZE, DEFAULT_FONT_FAMILY, TOOLBAR_SECTIONS, DEFAULT_SECTION_GROUP_ID, SHORTCUT_REFERENCE_ITEMS as SHORTCUT_REFERENCE_ITEMS$1, HYPERLINK_COLOR, GRID_SIZE, CONNECTOR_ARROW_OPTIONS, ARROW_SIZE_OPTIONS, startMotionPathPreview, startPreviewAnimation, stopPreviewAnimation, THEME_COLOR_SWATCHES, STROKE_DASH_OPTIONS } from './chunk-FMEEIS6L.mjs';
4
- import { hasShapeProperties, normalizeHexColor, colorWithOpacity, normalizeStrokeDashType, getSvgStrokeDasharray, getCompoundLineOffsets, getCompoundLineWidths, svgLineCap, hasTextProperties, getElementTransform, getAriaRoleDescription, getAriaLabel, getAriaRole, resolveElementInteractivity, isEditableTextElement, isElementRendered, isElementActionable, getImageEffectsOpacity, getImageEffectsFilter, inlineElementPointerEvents, isHollowShapeElement, LINK_TOOLTIP_HOST_CLASS, ACTION_BUTTON_PRESETS, mediaTransportVisible, isInkElement, getGroupChildParentFill, getElementLabel, SWITCHABLE_LAYOUT_TYPES, compileEquationTemplateMathMl, buildUserFontFaceStyles, readStoredViewerPrefs, resolveThemeCatalogEntry, THEME_CATALOG, writeStoredViewerPrefs, openPptxFile, readBackstageRecentFile, resolveAutosaveActivation, viewerOptionsToPreferences, applyPreferenceToOptions, listAutosaveSnapshots, deleteAutosaveSnapshot, resolveExpiredAutosaveSnapshots, resolveHistoryDepth, applyAutoCorrect, resolveImageResolutionScale, resolveAutosaveIntervalMs, resolveAutosaveIntervalSeconds, shouldShowAutosaveRecoveryPrompt, resolveOptionRootClasses, resolve3DRenderingFlags, paintedStrokeWidth, buildCssGradientFromShapeStyle, ensureActionAffordanceStyles, resolveElementActionAffordance, actionAffordanceLabels, getComputedEffectStyle, getSoftEdgeSvgFilter, buildStrokeOutline, buildHollowHitOutline, buildSubpathFillOverlay, isImageLikeElement, getComputedFillStyle, strokeOutlineViewBox, revealedSmartArtNodeCount, buildSmartArtA11y, computeSmartArtElementLayout, flattenNodes, buildSummaryZoomView, isImageTiled, getImageColorWashStyle, placeCaretAtEnd, getPendingSelectionRestore, restoreSegmentSelection, getTextCompensationTransform, resolveChartKind, ensureChartInteractionStyles, applyChartPartHighlight, applyChartBuildReveal, formatAxisValue, hasPressureVariation, getInkReplayStyles, INK_REPLAY_KEYFRAMES, resolveInkColor, resolveInkWidth, resolveInkOpacity, pressuresToWidths, getContentPartReplayStyles, resolveOleType, getOleAriaLabel, getOleTypeColor, getOleTypeLabel, filterRenderedElements, resolveGroupChildFill, isLinkedTextBox, getOverflowSegments, shouldUseSvgWarp, getTextBodyRotationTransform, isWedgeCalloutPresetShape, RULER_THICKNESS, RULER_FONT_SIZE, buildPreviewElements, deriveSlideFieldContext, SLIDE_TRANSITION_OPTIONS, hiddenSlideCue, HIDDEN_SLIDE_SLASH_GRADIENT, HIDDEN_SLIDE_LABEL_KEY, themeToCssVars, shouldClearAutosaveCacheOnClose, applyMotionPathPreset, resetSlideLayoutPath, DEFAULT_INSERT_CHART_KIND, hasCopyableFormat, templateSchemeFromTheme, createBackstagePresentation, playFeedbackSound, shouldDiscardAutosaveOnSuccessfulSave, setMasterViewBackgroundColor, printPropertiesFrameSlides, printPropertiesSlidesPerPage, VIEWER_OPTIONS_TABS, DEFAULT_QUICK_ACCESS_COMMAND_IDS, buildJoinCollaborationConfig, buildCreateCollaborationConfig, generateBroadcastRoomId, DEFAULT_BROADCAST_SERVER_URL, buildBroadcastViewerUrl, resolveTransportForServerUrl, ACTION_INDICATOR_CLASS, ACTION_INDICATOR_ICON_PATH, LINK_TOOLTIP_CLASS, LINK_TOOLTIP_PANEL_CLASS, LINK_TOOLTIP_LABEL_CLASS, LINK_TOOLTIP_HINT_CLASS, DEFAULT_PALETTE2, resolvePalette, computeDrawingViewBox, projectDrawingShapes, styleShadowFilter, resolveDrawingShapeNodeId, buildChromeStyle, getImageSvgFilters, buildDuotoneCacheKey, getDuotoneCachedResult, applyDuotone, setDuotoneCachedResult, buildCacheKey, DEFAULT_COLOR_CHANGE_TOLERANCE, getCachedResult, applyColorChange, setCachedResult, findChartPartTarget, advanceChartValueDrag, beginChartValueDrag, buildSurfaceChart3DDataForElement, buildBarChart3DDataForElement, buildLineChart3DDataForElement, buildAreaChart3DDataForElement, buildPieChart3DDataForElement, withChartTitle, buildSmartArt3DModel, extractPathPoints, generatePressureCircles, generateNibMarks, isBrowserOpenableMime, formatBytes, getOleDisplayName, getOleBadgeLabel, openUrlInNewTab, getSubstituteFontFamily, getWarpPath, getSlideBackgroundStyle, filterCommands, resolveTitleBarStatusKey, TITLE_BAR_CLASSES, TITLE_BAR_DEFAULT_FILE_KEY, resolveScreenTip, masterViewBackgroundColor, buildFieldSubstitutionContext, shouldConfirmExternalHyperlink, safeOpenUrl, resolvePresentationAction, isPpactionUrl, parsePpactionUrl, isPresentationAdvanceClick, toggleBlackboard, PRESENT_TOOLBAR_CLASSES, buildContextMenuEntries, themeColorSchemesEqual, EXPANDED_MAX_HEIGHT, STATUS_BAR_CLASSES, buildBarActions, formatVersionTimestamp, formatRelativeTime, scanAvailableFontFamilies, PRESETS, CATEGORIES, convertOmmlToLatex, compileLatexEquation, convertLatexToOmml, EQUATION_TEMPLATES, clampPercent2, resolveDefaultPrintSettings, HANDOUT_OPTIONS, TOOLBAR_TABS, SHORTCUT_REFERENCE_ITEMS, resolveViewerAddinRows, availableQuickAccessCommands, addQuickAccessCommand, removeQuickAccessCommand, moveQuickAccessCommand, CUSTOM_FONT_ACCEPT, activateModalFocus, buildCollaborationShareUrl, buildActiveSessionUsers, SORTER_MIN_ZOOM, SORTER_ZOOM_STEP, SORTER_MAX_ZOOM, canGoPrevious, formatSlideCounter, READING_VIEW_COUNTER_ATTR, canGoNext, READING_VIEW_ATTR, OUTLINE_LEVEL_ATTR, OUTLINE_SLIDE_ATTR, OUTLINE_ROW_ATTR, OUTLINE_VIEW_ATTR, mobileElapsedSince, nextPresentedSlide, presenterPrevDisabled, presenterNextDisabled, formatMobileElapsed, mobileSlideCounter, presenterPaneAdvancesOnClick, presenterTimerProgress, PRESENTER_CONSOLE_CLASSES, formatElapsed, centeredSvgTextLines, computeInlineEditorRect, findSmartArtNodeText, setSmartArtNodeStyle, rebuildDrawingShapesIfCleared, shouldCommitSmartArtNodeText, updateSmartArtNodeText, groupIntoParagraphs, substituteFieldText, extraQuickAccessCommands, TAB_ROW_ACTION_CLASSES, listBackstageRecentFiles, BACKSTAGE_NAV, INSERT_CHART_TYPES, CHARACTER_SPACING_OPTIONS, RIBBON_SHAPE_SWATCHES, shapeFillChange, shapeOutlineChange, readRibbonTransitionDraft, ribbonTransitionUpdates, readSoundFileAsDataUrl, applyTransitionSoundFile, playSlideTransitionPreview, RIBBON_TRANSITION_PRESETS, transitionSoundOptions, transitionSoundSelectedValue, DEFAULT_MOTION_PATH_PRESET_ID, SLIDE_SHOW_OPTIONS, slideShowOptionChange, readSlideShowOption, SLIDE_VIRTUALIZATION_THRESHOLD, PRESENTATION_HIT_TEST_CSS, PRESENTATION_STAGE_ATTRIBUTE, getSlideTransitionAnimations, MORPH_CROSSFADE_GROUP_STYLE, MORPH_CROSSFADE_HALF_STYLE, SLIDE_TRANSITION_KEYFRAMES, annotationOverlayZIndex, presentationInkPath, resolveNotesSchematicBodyFontSizePx, motionPathFor, setMotionPath, getShapeAdjustmentHandleDescriptors, PRESENTER_NAVIGATOR_LABEL_KEYS, PEN_COLORS, HIGHLIGHTER_COLORS, isBlackboardActive, slideSizeToCanvasPx, resolveSelectionPaneRename, PRESET_THEMES, resolveNotesSegments, segmentsToEditorHtml, DEBOUNCE_MS, createPlainNotesSegments, parseSegmentsFromRichEditor, segmentsToPlainText, getCurrentParagraphIndex, segmentsToParagraphs, paragraphsToSegments, MAX_INDENT_LEVEL, INDENT_PX, isUrlSafe, buildNotesPrintHtml, toggleSheet, sanitizeMathMl, computeHandoutLayout, getPrintableArea, generateNoteLineCount, computeAllNotesPages, getNotesPrintableArea, downloadBlob, clampOptionNumber, QUICK_ACCESS_COMMAND_CATALOG, registerCustomFont, openReadingView, applyReadingViewCommand, createPresentationKeyBuffer, readingViewFitScale, READING_VIEW_STAGE_ATTR, buildOutline, applyOutlineEdit, mapOutlineKey, notesSegmentsToSpans, erasePresentationInkAt, movePresenterPointer, appendPresentationInkPoint, PRESENTER_CONSOLE_CONTROLS, NOTES_FONT_SIZE_DEFAULT, formatTime, NOTES_FONT_SIZE_MIN, clampNotesFontSize, NOTES_FONT_SIZE_STEP, NOTES_FONT_SIZE_MAX, BACKSTAGE_TEMPLATES, formatBackstageDate, formatBackstageSize, backstageCardsFor, DEFAULT_VIEWER_PROFILE, resolveProfileInitial, AVATAR_COLOR_SWATCHES, resolveDefaultFontFamily, buildFontCatalog, TRANSITION_SOUND_OTHER_VALUE, TRANSITION_SOUND_NONE_VALUE, clearTransitionSound, ENTRANCE_PRESET_VALUES, EMPHASIS_PRESET_VALUES, EXIT_PRESET_VALUES, MOTION_PATH_FAMILIES, motionPathFamilyLabelKey, motionPathPresetsByFamily, motionPathPresetLabelKey, masterViewPseudoSlide, authorConnectorBetweenSites, findEraserHitElementId, generateTicks, rulerDragToGuidePosition, getElementTransformWithoutRotation, buildCommentMarkers, COMMENT_MARKER_SIZE, collectConnectorSiteCandidates, getConnectorEndpointHandles, findConnectorSiteNear, motionPathToSvgD, motionPathEndPixel, isEditableMotionPath, setMotionPathEnd, themeColorLabel, buildThemeColorGrid, THEME_COLOR_SCHEME_KEYS, COMMON_FONTS, buildSmartArtPresetData, handleReadingViewKey, getLocalStorageUsageSummary, saveViewerProfile, clearAllLocalViewerData, isCurrentLayout, SLIDE_TEMPLATES, computeAnchoredPopupPosition, CONNECTOR_SITE_SNAP_PX, resolveConnectorEndpointUpdate, withConnectorEndpointUpdate, getShapeConnectionSites, isElementLocked, mergeSlideTransition, mapSlideSorterKey, isEditorTextInputTarget, clampSorterZoom, buildLayoutPreviewGeometry, buildSlideTemplateContent, elementLockTogglePatch, buildTableDataGrid, appendTableElementRow, removeLastTableElementRow, appendTableElementColumn, removeLastTableElementColumn, removeTableElementColumn, removeTableElementRow, setTableElementCellText, TABLE_STYLE_PRESETS, applyTableStylePreset, evenColumnWidths, redistributeColumnWidth, evenRowHeights, patchChartData, setChartCategoryLabel, setChartCellValue, addChartCategory, removeChartCategory, addChartSeries, removeChartSeries, setChartAxisLogScale, setChartAxisTitleStyle, setChartAxisGridlineStyle, setChartSeriesMarker, setChartSeriesChartType, setChartDataPointFill, setChartDataPointExplosion, setChartDataPointMarker, setChartDataPointLabel, describeSmartArtBounds, canAddTopLevelNode, classifyExtraConnections, siblingIndex, siblingCount, canRemoveTopLevelNode, buildOleObjectNamePatch, getOleObjectTypeLabel, sanitizeGradientStops, pptxActionToElementAction, withFrameSlides, withSlidesPerPage, applyThemeOverrideToSlide, COLOR_MAP_ALIAS_KEYS, DEFAULT_COLOR_MAP, schemaLabel, THEME_COLOR_SLOT_LABEL_KEYS, resolveSlideSizeSelection, SLIDE_SIZE_PRESETS, TRANSITION_VALID_DIRECTIONS, TRANSITION_ORIENTATION_TYPES, clampTransitionNumber, TRANSITION_SPEED_OPTIONS, TRANSITION_MORPH_OPTIONS, flattenTagCollections, resolveTemplateBackgroundRows, formatCommentTimestamp, buildAnimationTimelineRows, clearMotionPath, getEffectSoundState, setEffectSound, setAfterAnimation, setAfterAnimationColor, DIRECTIONAL_PRESETS, buildAnimationTimelineBars, motionPathPresetIdForPath, computeMergeCellRight, computeMergeCellDown, computeSplitCell, CHART_TYPE_OPTIONS, SMARTART_COLOR_SCHEME_LABEL_KEYS, SMARTART_STYLE_LABEL_KEYS, addSmartArtNodeAsChild, removeSmartArtNode, addSiblingAfter, removeEmptyNode, demote, promote, reorder, clampCropValue, DUOTONE_PRESETS, ARTISTIC_EFFECTS, resolveActionType, ELEMENT_ACTION_TYPE_OPTIONS, toSlideIndex, elementActionToPptxAction, canCommitActionType, slideSizeFromPreset, withSlideSizeOrientation, TRANSITION_DIR_ARROWS, buildDirectionGrid, updateTagInCollections, deleteTagFromCollections, addTagToCollections, commentTextSegments, COMMENT_MENTION_CLASS, COMMENT_MENTION_ATTRIBUTE, reorderAnimationTimelineRows, applyAnimationTimelineOrder, animationEffectLabel, LBL, SEL, FILL_MODE_OPTIONS, SECTION_HEADING, NUM, switchSmartArtLayout, SHAPE_QUICK_STYLES, quickStyleSwatchCss, getPatternSvg, TEXT_WARP_PRESETS, warpPreviewPath, text3dPtToEmu, text3dEmuToPt, MATERIAL_PRESETS, GRADIENT_TYPE_OPTIONS, PATTERN_OPTIONS, FILL_PATTERN_LABEL_KEYS, openNativeEyeDropper, toggleText3dExtrusion, BEVEL_PRESETS } from './chunk-G7UBIKAG.mjs';
5
- import { LOCALE_CATALOG, translationsEn } from './chunk-RHSA5BW5.mjs';
1
+ import { computeFocusTargets, aiChangeAnimationCss, changeGhostStyle, createChatHistoryStore, collectStoredChats, exportAiChatLogs, applyElementUpdate } from './chunk-C4WTQIC6.mjs';
2
+ import { useViewerOptions, useReadOnlyRecommendationState, useCompatibilityToastsState, useReducedMotion, useViewerState, useIsMobile, useResizablePanels, useDerivedSlideState, useZoomViewport, useEditorHistory, usePresentationSetup, useTouchGestures, useViewerDialogs, useEditorOperations, useViewerIntegration, useViewPreferencesSync, useLayoutSwitching, ViewerOptionsContext, useYjsDocumentSync, useCollaborationLivePatch, useFollowMode, useBroadcastFollower, safePrompt, scopeLayoutOptionsToActiveSlide, useToolbarVisibility, useKeyboardInsets, useModalDismissDrag, useCollaborativeState, useViewerOptionsContext, useVirtualizedSlides, useSwipeNavigation, useSheetDismissDrag, detectTargetType, parseEmailUrl, parseSlideFromUrl, ACTION_VERB_MAP, syncSelectionHandleOverlay } from './chunk-MSUUPLQ7.mjs';
3
+ import { MIN_ELEMENT_SIZE, DEFAULT_STROKE_COLOR, getConnectorPathGeometry, buildLineShadowCss, buildLineGlowFilter, renderConnectorMarker, getShapeVisualStyle, getTextStyleForElement, DEFAULT_TEXT_COLOR, renderVectorShape, isConnectorOrLineElement, build3DExtrusionData, getImageRenderStyle, cn, getImageSurfaceStyle, getTextLayoutStyle, renderTableElement, renderMediaElement, shouldRenderFallbackLabel, SHAPE_PRESETS, ANIMATION_PRESET_OPTIONS, DEFAULT_FILL_COLOR, hasDagDuotoneEffect, renderDagDuotoneSvgFilter, getImageSurfaceMaskStyle, getCropShapeClipPath, getImageTilingStyle, getDuotoneColors, getTextWarpStyle, renderTextSegments, buildReactChartViewModel, renderChartElement, buildTextBody3DSceneStyle, SLIDE_NAV_THUMBNAIL_WIDTH, DEFAULT_TEXT_FONT_SIZE, DEFAULT_FONT_FAMILY, TOOLBAR_SECTIONS, DEFAULT_SECTION_GROUP_ID, SHORTCUT_REFERENCE_ITEMS as SHORTCUT_REFERENCE_ITEMS$1, HYPERLINK_COLOR, GRID_SIZE, CONNECTOR_ARROW_OPTIONS, ARROW_SIZE_OPTIONS, startMotionPathPreview, startPreviewAnimation, stopPreviewAnimation, THEME_COLOR_SWATCHES, STROKE_DASH_OPTIONS } from './chunk-SFMATKNJ.mjs';
4
+ import { hasShapeProperties, normalizeHexColor, colorWithOpacity, normalizeStrokeDashType, getSvgStrokeDasharray, getCompoundLineOffsets, getCompoundLineWidths, svgLineCap, hasTextProperties, getElementTransform, getAriaRoleDescription, getAriaLabel, getAriaRole, resolveElementInteractivity, isEditableTextElement, isElementRendered, isElementActionable, getImageEffectsOpacity, getImageEffectsFilter, inlineElementPointerEvents, isHollowShapeElement, LINK_TOOLTIP_HOST_CLASS, ACTION_BUTTON_PRESETS, mediaTransportVisible, isInkElement, getGroupChildParentFill, getElementLabel, SWITCHABLE_LAYOUT_TYPES, compileEquationTemplateMathMl, buildUserFontFaceStyles, readStoredViewerPrefs, resolveThemeCatalogEntry, THEME_CATALOG, writeStoredViewerPrefs, openPptxFile, readBackstageRecentFile, resolveAutosaveActivation, viewerOptionsToPreferences, applyPreferenceToOptions, listAutosaveSnapshots, deleteAutosaveSnapshot, resolveExpiredAutosaveSnapshots, resolveHistoryDepth, applyAutoCorrect, resolveImageResolutionScale, resolveAutosaveIntervalMs, resolveAutosaveIntervalSeconds, shouldShowAutosaveRecoveryPrompt, resolveOptionRootClasses, resolve3DRenderingFlags, paintedStrokeWidth, buildCssGradientFromShapeStyle, ensureActionAffordanceStyles, resolveElementActionAffordance, actionAffordanceLabels, getComputedEffectStyle, getSoftEdgeSvgFilter, buildStrokeOutline, buildHollowHitOutline, buildSubpathFillOverlay, isImageLikeElement, getComputedFillStyle, strokeOutlineViewBox, revealedSmartArtNodeCount, buildSmartArtA11y, computeSmartArtElementLayout, flattenNodes, buildSummaryZoomView, isImageTiled, getImageColorWashStyle, placeCaretAtEnd, getPendingSelectionRestore, restoreSegmentSelection, getTextCompensationTransform, resolveChartKind, ensureChartInteractionStyles, applyChartPartHighlight, applyChartBuildReveal, formatAxisValue, hasPressureVariation, getInkReplayStyles, INK_REPLAY_KEYFRAMES, resolveInkColor, resolveInkWidth, resolveInkOpacity, pressuresToWidths, getContentPartReplayStyles, resolveOleType, getOleAriaLabel, getOleTypeColor, getOleTypeLabel, filterRenderedElements, resolveGroupChildFill, isLinkedTextBox, getOverflowSegments, shouldUseSvgWarp, getTextBodyRotationTransform, placeholderPromptDescriptor, isWedgeCalloutPresetShape, RULER_THICKNESS, RULER_FONT_SIZE, buildPreviewElements, deriveSlideFieldContext, SLIDE_TRANSITION_OPTIONS, hiddenSlideCue, HIDDEN_SLIDE_SLASH_GRADIENT, HIDDEN_SLIDE_LABEL_KEY, themeToCssVars, shouldClearAutosaveCacheOnClose, masterViewCrudActions, applyMasterViewCrudAction, masterViewCrudFailureKey, applyMotionPathPreset, resetSlideLayoutPath, DEFAULT_INSERT_CHART_KIND, hasCopyableFormat, templateSchemeFromTheme, createBackstagePresentation, playFeedbackSound, shouldDiscardAutosaveOnSuccessfulSave, setMasterViewBackgroundColor, compatToastStackStyle, printPropertiesFrameSlides, printPropertiesSlidesPerPage, VIEWER_OPTIONS_TABS, DEFAULT_QUICK_ACCESS_COMMAND_IDS, isHeaderFooterDateTextVisible, isHeaderFooterHeaderTextVisible, isHeaderFooterFooterTextVisible, buildJoinCollaborationConfig, buildCreateCollaborationConfig, generateBroadcastRoomId, DEFAULT_BROADCAST_SERVER_URL, buildBroadcastViewerUrl, resolveTransportForServerUrl, elementIdSelector, ACTION_INDICATOR_CLASS, ACTION_INDICATOR_ICON_PATH, LINK_TOOLTIP_CLASS, LINK_TOOLTIP_PANEL_CLASS, LINK_TOOLTIP_LABEL_CLASS, LINK_TOOLTIP_HINT_CLASS, DEFAULT_PALETTE2, resolvePalette, computeDrawingViewBox, projectDrawingShapes, styleShadowFilter, resolveDrawingShapeNodeId, buildChromeStyle, modelDataToBlobUrl, getImageSvgFilters, buildDuotoneCacheKey, getDuotoneCachedResult, applyDuotone, setDuotoneCachedResult, buildCacheKey, DEFAULT_COLOR_CHANGE_TOLERANCE, getCachedResult, applyColorChange, setCachedResult, findChartPartTarget, advanceChartValueDrag, beginChartValueDrag, buildSurfaceChart3DDataForElement, buildBarChart3DDataForElement, buildLineChart3DDataForElement, buildAreaChart3DDataForElement, buildPieChart3DDataForElement, withChartTitle, buildSmartArt3DModel, extractPathPoints, generatePressureCircles, generateNibMarks, isBrowserOpenableMime, formatBytes, getOleDisplayName, getOleBadgeLabel, openUrlInNewTab, getSubstituteFontFamily, getWarpPath, getSlideBackgroundStyle, pushRecentColor, mruColorsPatch, filterCommands, resolveTitleBarStatusKey, TITLE_BAR_CLASSES, TITLE_BAR_DEFAULT_FILE_KEY, resolveScreenTip, masterViewBackgroundColor, buildFieldSubstitutionContext, shouldConfirmExternalHyperlink, safeOpenUrl, resolvePresentationAction, isPpactionUrl, parsePpactionUrl, isPresentationAdvanceClick, toggleBlackboard, PRESENT_TOOLBAR_CLASSES, buildContextMenuEntries, themeColorSchemesEqual, EXPANDED_MAX_HEIGHT, STATUS_BAR_CLASSES, buildBarActions, formatVersionTimestamp, formatRelativeTime, scanAvailableFontFamilies, PRESETS, CATEGORIES, convertOmmlToLatex, compileLatexEquation, convertLatexToOmml, EQUATION_TEMPLATES, clampPercent2, resolveDefaultPrintSettings, HANDOUT_OPTIONS, TOOLBAR_TABS, SHORTCUT_REFERENCE_ITEMS, resolveViewerAddinRows, availableQuickAccessCommands, addQuickAccessCommand, removeQuickAccessCommand, moveQuickAccessCommand, CUSTOM_FONT_ACCEPT, activateModalFocus, buildCollaborationShareUrl, buildActiveSessionUsers, SORTER_MIN_ZOOM, SORTER_ZOOM_STEP, SORTER_MAX_ZOOM, canGoPrevious, formatSlideCounter, READING_VIEW_COUNTER_ATTR, canGoNext, READING_VIEW_ATTR, OUTLINE_LEVEL_ATTR, OUTLINE_SLIDE_ATTR, OUTLINE_ROW_ATTR, OUTLINE_VIEW_ATTR, mobileElapsedSince, nextPresentedSlide, presenterPrevDisabled, presenterNextDisabled, formatMobileElapsed, mobileSlideCounter, presenterPaneAdvancesOnClick, presenterTimerProgress, PRESENTER_CONSOLE_CLASSES, formatElapsed, centeredSvgTextLines, computeInlineEditorRect, findSmartArtNodeText, setSmartArtNodeStyle, rebuildDrawingShapesIfCleared, shouldCommitSmartArtNodeText, updateSmartArtNodeText, groupIntoParagraphs, substituteFieldText, extraQuickAccessCommands, TAB_ROW_ACTION_CLASSES, listBackstageRecentFiles, BACKSTAGE_NAV, COMMON_FONT_SIZES, INSERT_CHART_TYPES, CHARACTER_SPACING_OPTIONS, shapeFillChange, shapeOutlineChange, readRibbonTransitionDraft, ribbonTransitionUpdates, readSoundFileAsDataUrl, applyTransitionSoundFile, playSlideTransitionPreview, RIBBON_TRANSITION_PRESETS, transitionSoundOptions, transitionSoundSelectedValue, DEFAULT_MOTION_PATH_PRESET_ID, SLIDE_SHOW_OPTIONS, slideShowOptionChange, readSlideShowOption, SLIDE_VIRTUALIZATION_THRESHOLD, PRESENTATION_HIT_TEST_CSS, PRESENTATION_STAGE_ATTRIBUTE, getSlideTransitionAnimations, MORPH_CROSSFADE_GROUP_STYLE, MORPH_CROSSFADE_HALF_STYLE, SLIDE_TRANSITION_KEYFRAMES, buildStrokePathD, cursorForTool, annotationOverlayZIndex, presentationInkPath, resolveNotesSchematicBodyFontSizePx, motionPathFor, setMotionPath, getShapeAdjustmentHandleDescriptors, PRESENTER_NAVIGATOR_LABEL_KEYS, PEN_COLORS, HIGHLIGHTER_COLORS, isBlackboardActive, scaleSlidesForSizeChange, slideSizeToCanvasPx, resolveSelectionPaneRename, PRESET_THEMES, resolveNotesSegments, segmentsToEditorHtml, DEBOUNCE_MS, createPlainNotesSegments, parseSegmentsFromRichEditor, segmentsToPlainText, getCurrentParagraphIndex, segmentsToParagraphs, paragraphsToSegments, MAX_INDENT_LEVEL, INDENT_PX, isUrlSafe, buildNotesPrintHtml, toggleSheet, SMARTART_PREVIEW_ELEMENT_HEIGHT, SMARTART_PREVIEW_ELEMENT_WIDTH, buildSmartArtPreviewElement, sanitizeMathMl, computeHandoutLayout, getPrintableArea, generateNoteLineCount, computeAllNotesPages, getNotesPrintableArea, downloadBlob, clampOptionNumber, QUICK_ACCESS_COMMAND_CATALOG, registerCustomFont, openReadingView, applyReadingViewCommand, createPresentationKeyBuffer, readingViewFitScale, READING_VIEW_STAGE_ATTR, buildOutline, applyOutlineEdit, mapOutlineKey, notesSegmentsToSpans, erasePresentationInkAt, movePresenterPointer, appendPresentationInkPoint, PRESENTER_CONSOLE_CONTROLS, NOTES_FONT_SIZE_DEFAULT, formatTime, NOTES_FONT_SIZE_MIN, clampNotesFontSize, NOTES_FONT_SIZE_STEP, NOTES_FONT_SIZE_MAX, BACKSTAGE_TEMPLATES, formatBackstageDate, formatBackstageSize, backstageCardsFor, DEFAULT_VIEWER_PROFILE, resolveProfileInitial, AVATAR_COLOR_SWATCHES, resolveDefaultFontFamily, buildFontCatalog, RIBBON_SHAPE_SWATCHES, canGroupSelection, canUngroupSelection, canSetStrokeWidth, strokeWidthOf, TRANSITION_SOUND_OTHER_VALUE, TRANSITION_SOUND_NONE_VALUE, clearTransitionSound, ENTRANCE_PRESET_VALUES, EMPHASIS_PRESET_VALUES, EXIT_PRESET_VALUES, MOTION_PATH_FAMILIES, motionPathFamilyLabelKey, motionPathPresetsByFamily, motionPathPresetLabelKey, masterViewPseudoSlide, authorConnectorBetweenSites, findEraserHitElementId, generateTicks, rulerDragToGuidePosition, getElementTransformWithoutRotation, getActiveXControlOverlayView, buildCommentMarkers, COMMENT_MARKER_SIZE, collectConnectorSiteCandidates, getConnectorEndpointHandles, findConnectorSiteNear, motionPathToSvgD, motionPathEndPixel, isEditableMotionPath, setMotionPathEnd, themeColorLabel, buildThemeColorGrid, THEME_COLOR_SCHEME_KEYS, COMMON_FONTS, handleReadingViewKey, getLocalStorageUsageSummary, saveViewerProfile, clearAllLocalViewerData, isCurrentLayout, SLIDE_TEMPLATES, computeAnchoredPopupPosition, CONNECTOR_SITE_SNAP_PX, resolveConnectorEndpointUpdate, withConnectorEndpointUpdate, getShapeConnectionSites, isElementLocked, mergeSlideTransition, mapSlideSorterKey, isEditorTextInputTarget, clampSorterZoom, buildLayoutPreviewGeometry, buildSlideTemplateContent, elementLockTogglePatch, buildTableDataGrid, appendTableElementRow, removeLastTableElementRow, appendTableElementColumn, removeLastTableElementColumn, removeTableElementColumn, removeTableElementRow, setTableElementCellText, TABLE_STYLE_PRESETS, applyTableStylePreset, evenColumnWidths, redistributeColumnWidth, evenRowHeights, patchChartData, chartGridlinesState, chartGridlinesPatch, seriesSecondaryAxisPatch, setChartCategoryLabel, setChartCellValue, addChartCategory, removeChartCategory, addChartSeries, removeChartSeries, setChartAxisLogScale, setChartAxisTitleStyle, setChartAxisGridlineStyle, setChartSeriesMarker, setChartSeriesChartType, setChartDataPointFill, setChartDataPointExplosion, setChartDataPointMarker, setChartDataPointLabel, describeSmartArtBounds, canAddTopLevelNode, classifyExtraConnections, siblingIndex, siblingCount, canRemoveTopLevelNode, buildOleObjectNamePatch, getOleObjectTypeLabel, sanitizeGradientStops, pptxActionToElementAction, withFrameSlides, withSlidesPerPage, applyThemeOverrideToSlide, COLOR_MAP_ALIAS_KEYS, DEFAULT_COLOR_MAP, schemaLabel, THEME_COLOR_SLOT_LABEL_KEYS, resolveSlideSizeSelection, SLIDE_SIZE_PRESETS, TRANSITION_VALID_DIRECTIONS, TRANSITION_ORIENTATION_TYPES, clampTransitionNumber, TRANSITION_SPEED_OPTIONS, TRANSITION_MORPH_OPTIONS, flattenTagCollections, resolveTemplateBackgroundRows, formatCommentTimestamp, commentMentionQuery, matchCommentMentionAuthors, buildAnimationTimelineRows, clearMotionPath, getEffectSoundState, setEffectSound, setAfterAnimation, setAfterAnimationColor, DIRECTIONAL_PRESETS, buildAnimationTimelineBars, motionPathPresetIdForPath, computeMergeCellRight, computeMergeCellDown, computeSplitCell, CHART_TYPE_OPTIONS, BAR3D_SHAPE_OPTIONS, bar3DShapePatch, RADAR_STYLE_OPTIONS, radarStylePatch, SURFACE_WIREFRAME_OPTIONS, surfaceWireframePatch, isSeriesUsingSecondaryAxis, SMARTART_COLOR_SCHEME_LABEL_KEYS, SMARTART_STYLE_LABEL_KEYS, addSmartArtNodeAsChild, removeSmartArtNode, addSiblingAfter, removeEmptyNode, demote, promote, reorder, clampCropValue, DUOTONE_PRESETS, ARTISTIC_EFFECTS, resolveActionType, ELEMENT_ACTION_TYPE_OPTIONS, elementActionToPptxAction, canCommitActionType, slideSizeFromPreset, withSlideSizeOrientation, TRANSITION_DIR_ARROWS, buildDirectionGrid, updateTagInCollections, deleteTagFromCollections, addTagToCollections, commentTextSegments, COMMENT_MENTION_CLASS, COMMENT_MENTION_ATTRIBUTE, insertCommentMention, reorderAnimationTimelineRows, applyAnimationTimelineOrder, animationEffectLabel, LBL, SEL, FILL_MODE_OPTIONS, SECTION_HEADING, NUM, switchSmartArtLayout, SHAPE_QUICK_STYLES, quickStyleSwatchCss, PATTERN_PRESET_OPTIONS, getPatternSvg, COMPOUND_LINE_OPTIONS, LINE_JOIN_OPTIONS, LINE_CAP_OPTIONS, TEXT_WARP_PRESETS, warpPreviewPath, text3dPtToEmu, text3dEmuToPt, MATERIAL_PRESETS, toSlideIndex, GRADIENT_TYPE_OPTIONS, PATTERN_OPTIONS, FILL_PATTERN_LABEL_KEYS, openNativeEyeDropper, toggleText3dExtrusion, BEVEL_PRESETS } from './chunk-B7WAGQW4.mjs';
5
+ import { LOCALE_CATALOG, translationsEn } from './chunk-XWUMM2TX.mjs';
6
6
  import React19, { createContext, useMemo, useState, useCallback, lazy, forwardRef, useEffect, useRef, Suspense, useLayoutEffect, useContext, Fragment as Fragment$1, useDeferredValue } from 'react';
7
7
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
8
8
  import { useTranslation } from 'react-i18next';
9
- import { LuRotateCw, LuMessageSquare, LuEyeOff, LuHistory, LuTrash2, LuSettings, LuX, LuCalendarDays, LuHash, LuText, LuCast, LuSave, LuUndo, LuRedo, LuSearch, LuShieldCheck, LuPlus, LuPanelLeftClose, LuStickyNote, LuMonitor, LuColumns2, LuPresentation, LuMinus, LuSettings2, LuLayers, LuClock, LuDownload, LuCheck, LuLock, LuEye, LuFileText, LuType, LuLoader, LuShieldAlert, LuSignature, LuInfo, LuTriangleAlert, LuPrinter, LuPenTool, LuBug, LuChevronUp, LuChevronDown, LuUpload, LuWifi, LuWifiOff, LuUsers, LuCopy, LuChevronLeft, LuChevronRight, LuPlay, LuPause, LuZoomOut, LuZoomIn, LuSpellCheck, LuFileDown, LuMenu, LuSparkles, LuShare2, LuPanelLeft, LuPanelRight, LuArrowLeft, LuFolderOpen, LuClipboardPaste, LuScissors, LuPaintbrush, LuSquare, LuImage, LuVideo, LuDatabase, LuAArrowUp, LuAArrowDown, LuRemoveFormatting, LuHighlighter, LuList, LuListOrdered, LuIndentDecrease, LuIndentIncrease, LuReplace, LuMousePointer2, LuShapes, LuPaintBucket, LuPenLine, LuPalette, LuPencil, LuStar, LuMoveRight, LuMousePointerClick, LuClock3, LuMonitorPlay, LuListVideo, LuCaptions, LuCamera, LuEraser, LuRotateCcw, LuCircleHelp, LuBookOpen, LuLanguages, LuGlobe, LuGitCompare, LuMessageSquarePlus, LuLockKeyhole, LuPanelTop, LuLayoutGrid, LuGrid3X3, LuPipette, LuRuler, LuMaximize2, LuCode, LuCaseSensitive, LuTimer, LuGripVertical, LuLoaderCircle, LuBold, LuItalic, LuUnderline, LuStrikethrough, LuLink, LuGrid2X2, LuCopyPlus, LuScan, LuMonitorOff, LuCirclePlay, LuCirclePause, LuArrowLeftRight, LuClipboardCopy, LuWand, LuTextCursorInput, LuFile, LuEllipsis, LuUserRound, LuFilePlus2, LuHouse, LuFileJson, LuBox, LuFileImage, LuUser, LuHardDrive, LuLogIn, LuLayoutTemplate, LuFolderPlus, LuAlignLeft, LuAlignCenter, LuAlignRight, LuAlignJustify, LuColumns3, LuSpline, LuAlignHorizontalSpaceAround, LuAlignVerticalSpaceAround, LuGroup, LuUngroup, LuMove, LuRadio, LuLockOpen, LuArrowDown, LuArrowUp, LuArrowRight, LuReply, LuBookmark } from 'react-icons/lu';
9
+ import { LuRotateCw, LuMessageSquare, LuEyeOff, LuHistory, LuTrash2, LuSettings, LuX, LuCalendarDays, LuClock, LuHash, LuFileText, LuText, LuCast, LuSave, LuUndo, LuRedo, LuSearch, LuShieldCheck, LuPlus, LuPanelLeftClose, LuStickyNote, LuMonitor, LuColumns2, LuPresentation, LuMinus, LuSettings2, LuLayers, LuDownload, LuCheck, LuLock, LuEye, LuType, LuLoader, LuShieldAlert, LuSignature, LuInfo, LuTriangleAlert, LuPrinter, LuPenTool, LuBug, LuChevronUp, LuChevronDown, LuUpload, LuWifi, LuWifiOff, LuUsers, LuCopy, LuChevronLeft, LuChevronRight, LuPlay, LuPause, LuZoomOut, LuZoomIn, LuSpellCheck, LuFileDown, LuMenu, LuSparkles, LuShare2, LuPanelLeft, LuPanelRight, LuArrowLeft, LuFolderOpen, LuClipboardPaste, LuScissors, LuPaintbrush, LuSquare, LuImage, LuVideo, LuDatabase, LuAArrowUp, LuAArrowDown, LuRemoveFormatting, LuHighlighter, LuList, LuListOrdered, LuIndentDecrease, LuIndentIncrease, LuReplace, LuMousePointer2, LuShapes, LuPaintBucket, LuPenLine, LuPalette, LuPencil, LuStar, LuMoveRight, LuMousePointerClick, LuClock3, LuMonitorPlay, LuListVideo, LuCaptions, LuCamera, LuEraser, LuRotateCcw, LuCircleHelp, LuBookOpen, LuLanguages, LuGlobe, LuGitCompare, LuMessageSquarePlus, LuLockKeyhole, LuPanelTop, LuLayoutGrid, LuGrid3X3, LuPipette, LuRuler, LuMaximize2, LuCode, LuCaseSensitive, LuTimer, LuGripVertical, LuLoaderCircle, LuBold, LuItalic, LuUnderline, LuStrikethrough, LuLink, LuGrid2X2, LuCopyPlus, LuScan, LuMonitorOff, LuCirclePlay, LuCirclePause, LuArrowLeftRight, LuClipboardCopy, LuWand, LuTextCursorInput, LuFile, LuEllipsis, LuUserRound, LuFilePlus2, LuHouse, LuFileJson, LuBox, LuFileImage, LuUser, LuHardDrive, LuLogIn, LuLayoutTemplate, LuFolderPlus, LuAlignLeft, LuAlignCenter, LuAlignRight, LuAlignJustify, LuColumns3, LuSpline, LuAlignHorizontalSpaceAround, LuAlignVerticalSpaceAround, LuGroup, LuUngroup, LuMove, LuRadio, LuLockOpen, LuArrowDown, LuArrowUp, LuArrowRight, LuReply, LuBookmark } from 'react-icons/lu';
10
10
 
11
11
  var ViewerThemeContext = createContext(void 0);
12
12
  function ViewerThemeProvider({ theme, children }) {
@@ -514,7 +514,7 @@ function FailedToLoad() {
514
514
  var LazyArea3DChartScene = React19.lazy(
515
515
  async () => {
516
516
  try {
517
- return await import('./Area3DChartScene-7YCFWEGX.mjs');
517
+ return await import('./Area3DChartScene-7PARQDOZ.mjs');
518
518
  } catch {
519
519
  return { default: FailedToLoad };
520
520
  }
@@ -570,7 +570,7 @@ function FailedToLoad2() {
570
570
  var LazyBar3DChartScene = React19.lazy(
571
571
  async () => {
572
572
  try {
573
- return await import('./Bar3DChartScene-7CNSJ35X.mjs');
573
+ return await import('./Bar3DChartScene-QUU6RUXM.mjs');
574
574
  } catch {
575
575
  return { default: FailedToLoad2 };
576
576
  }
@@ -626,7 +626,7 @@ function FailedToLoad3() {
626
626
  var LazyLine3DChartScene = React19.lazy(
627
627
  async () => {
628
628
  try {
629
- return await import('./Line3DChartScene-SMTHK6MD.mjs');
629
+ return await import('./Line3DChartScene-D77ORA4K.mjs');
630
630
  } catch {
631
631
  return { default: FailedToLoad3 };
632
632
  }
@@ -682,7 +682,7 @@ function FailedToLoad4() {
682
682
  var LazyPieChart3DScene = React19.lazy(
683
683
  async () => {
684
684
  try {
685
- return await import('./PieChart3DScene-UD7GRH55.mjs');
685
+ return await import('./PieChart3DScene-DGD4PZVV.mjs');
686
686
  } catch {
687
687
  return { default: FailedToLoad4 };
688
688
  }
@@ -738,7 +738,7 @@ function FailedToLoad5() {
738
738
  var LazySurfaceChart3DScene = React19.lazy(
739
739
  async () => {
740
740
  try {
741
- return await import('./SurfaceChart3DScene-TXY6UZSW.mjs');
741
+ return await import('./SurfaceChart3DScene-QGH3OLJV.mjs');
742
742
  } catch {
743
743
  return { default: FailedToLoad5 };
744
744
  }
@@ -1355,9 +1355,8 @@ function ResizeHandles({
1355
1355
  onResizePointerDown(elementId, e, handle);
1356
1356
  };
1357
1357
  const startRotate = (btn, pointerId) => {
1358
- const wrapper = document.querySelector(
1359
- `[data-element-id="${elementId}"]`
1360
- );
1358
+ const scope = btn.closest("[data-pptx-viewport]") ?? document;
1359
+ const wrapper = scope.querySelector(elementIdSelector(elementId));
1361
1360
  if (!wrapper) {
1362
1361
  return;
1363
1362
  }
@@ -1377,7 +1376,9 @@ function ResizeHandles({
1377
1376
  }
1378
1377
  deg = Math.round((deg % 360 + 360) % 360);
1379
1378
  last = deg;
1380
- wrapper.style.transform = `rotate(${deg}deg)${base}`;
1379
+ const transform = `rotate(${deg}deg)${base}`;
1380
+ wrapper.style.transform = transform;
1381
+ syncSelectionHandleOverlay(wrapper, elementId, { transform });
1381
1382
  };
1382
1383
  const onPointerMove = (ev) => apply(ev.clientX, ev.clientY, ev.shiftKey);
1383
1384
  const end = () => {
@@ -2402,6 +2403,9 @@ var ElementRenderer = React19.memo(
2402
2403
  findHl: findHighlights,
2403
2404
  onHyperlinkClick,
2404
2405
  isPresentationPassive,
2406
+ // Same rule as the other four bindings: the hint belongs to the
2407
+ // editable canvas, not to a read-only viewer or the show stage.
2408
+ placeholderPromptMode: canInteract && !isPresentationPassive ? "edit" : "present",
2405
2409
  handleMediaPlayStateChange,
2406
2410
  presentationElementStates,
2407
2411
  slideElements: activeSlide?.elements,
@@ -3018,35 +3022,14 @@ function FailedToLoad6() {
3018
3022
  var LazyModel3DScene = React19.lazy(
3019
3023
  async () => {
3020
3024
  try {
3021
- return await import('./Model3DScene-AUVJXXPV.mjs');
3025
+ return await import('./Model3DScene-ZEGWNILH.mjs');
3022
3026
  } catch {
3023
3027
  return { default: FailedToLoad6 };
3024
3028
  }
3025
3029
  }
3026
3030
  );
3027
- function dataUrlToBlobUrl(dataUrl) {
3028
- if (!dataUrl) {
3029
- return void 0;
3030
- }
3031
- try {
3032
- const commaIdx = dataUrl.indexOf(",");
3033
- if (commaIdx === -1) {
3034
- return void 0;
3035
- }
3036
- const meta = dataUrl.slice(0, commaIdx);
3037
- const base64 = dataUrl.slice(commaIdx + 1);
3038
- const mimeMatch = meta.match(/data:(?<mime>[^;]+)/u);
3039
- const mime = mimeMatch?.groups?.mime ?? "application/octet-stream";
3040
- const binary = atob(base64);
3041
- const bytes = new Uint8Array(binary.length);
3042
- for (let i = 0; i < binary.length; i++) {
3043
- bytes[i] = binary.charCodeAt(i);
3044
- }
3045
- const blob = new Blob([bytes], { type: mime });
3046
- return URL.createObjectURL(blob);
3047
- } catch {
3048
- return void 0;
3049
- }
3031
+ function dataUrlToBlobUrl(dataUrl, mimeType) {
3032
+ return modelDataToBlobUrl(dataUrl, mimeType);
3050
3033
  }
3051
3034
  function PosterFallback({
3052
3035
  element,
@@ -3134,7 +3117,10 @@ function Model3DRenderer({ element, width, height, interactive }) {
3134
3117
  cancelled = true;
3135
3118
  };
3136
3119
  }, []);
3137
- const blobUrl = useMemo(() => dataUrlToBlobUrl(element.modelData), [element.modelData]);
3120
+ const blobUrl = useMemo(
3121
+ () => dataUrlToBlobUrl(element.modelData, element.modelMimeType),
3122
+ [element.modelData, element.modelMimeType]
3123
+ );
3138
3124
  useEffect(() => {
3139
3125
  return () => {
3140
3126
  if (blobUrl) {
@@ -4389,6 +4375,7 @@ function renderTextElementBody(options) {
4389
4375
  fieldContext,
4390
4376
  presentationElementStates,
4391
4377
  isPresentationPassive,
4378
+ placeholderPromptMode = "present",
4392
4379
  slideElements
4393
4380
  } = options;
4394
4381
  const isLinkedTextBox2 = isLinkedTextBox(el);
@@ -4407,7 +4394,8 @@ function renderTextElementBody(options) {
4407
4394
  ...isLinkedTextBox2 ? { overflow: "hidden" } : {}
4408
4395
  };
4409
4396
  const shapeType = "shapeType" in el ? el.shapeType : void 0;
4410
- const shouldRenderText = isTxtEl || hasTextProperties(el) && Boolean(el.promptText);
4397
+ const placeholderPrompt = placeholderPromptDescriptor(el, placeholderPromptMode);
4398
+ const shouldRenderText = isTxtEl || placeholderPrompt !== null;
4411
4399
  return /* @__PURE__ */ jsxs(Fragment, { children: [
4412
4400
  vecShape,
4413
4401
  isActionButtonShape(shapeType) && /* @__PURE__ */ jsx(ActionButtonGlyphOverlay, { element: el }),
@@ -4453,7 +4441,8 @@ function renderTextElementBody(options) {
4453
4441
  fieldContext,
4454
4442
  presentationElementStates,
4455
4443
  linkedSegments ?? void 0,
4456
- !isPresentationPassive
4444
+ !isPresentationPassive,
4445
+ placeholderPrompt
4457
4446
  )
4458
4447
  }
4459
4448
  ))
@@ -5009,6 +4998,7 @@ function StaticElementRendererImpl({
5009
4998
  // mode, so without saying so a video here would carry Chrome's
5010
4999
  // scrubber over a slide nobody can play.
5011
5000
  isStaticSurface: true,
5001
+ placeholderPromptMode: "thumbnail",
5012
5002
  slideElements: activeSlide?.elements,
5013
5003
  allSlides,
5014
5004
  sourceSlideIndex,
@@ -5723,13 +5713,12 @@ var ATXT = [
5723
5713
  { id: "right", i: /* @__PURE__ */ jsx(LuAlignRight, { className: ic }), labelKey: "pptx.ribbon.alignRight" },
5724
5714
  { id: "justify", i: /* @__PURE__ */ jsx(LuAlignJustify, { className: ic }), labelKey: "pptx.ribbon.justify" }
5725
5715
  ];
5726
- var DEFAULT_STROKE_WIDTH = 1;
5727
5716
  function ShapeArrangeExtras(p) {
5728
5717
  const { t } = useTranslation();
5729
- const canGroup = p.canEdit && p.selectedCount >= 2;
5730
- const canUngroup = p.canEdit && p.selectedElement?.type === "group";
5731
- const shape = p.selectedElement !== null && hasShapeProperties(p.selectedElement);
5732
- const strokeWidth = p.selectedElement !== null && hasShapeProperties(p.selectedElement) ? p.selectedElement.shapeStyle?.strokeWidth ?? DEFAULT_STROKE_WIDTH : DEFAULT_STROKE_WIDTH;
5718
+ const canGroup = canGroupSelection(p.canEdit, p.selectedCount);
5719
+ const canUngroup = canUngroupSelection(p.canEdit, p.selectedElement);
5720
+ const canStrokeWidth = canSetStrokeWidth(p.canEdit, p.selectedElement);
5721
+ const strokeWidth = strokeWidthOf(p.selectedElement);
5733
5722
  return /* @__PURE__ */ jsxs(Fragment, { children: [
5734
5723
  /* @__PURE__ */ jsxs("div", { className: grp, children: [
5735
5724
  /* @__PURE__ */ jsx(
@@ -5764,7 +5753,7 @@ function ShapeArrangeExtras(p) {
5764
5753
  min: "0",
5765
5754
  max: "120",
5766
5755
  step: "0.5",
5767
- disabled: !p.canEdit || !shape,
5756
+ disabled: !canStrokeWidth,
5768
5757
  "aria-label": t("pptx.ribbon.strokeWidth"),
5769
5758
  title: t("pptx.ribbon.strokeWidth"),
5770
5759
  value: strokeWidth,
@@ -6199,8 +6188,29 @@ function DesignSection(p) {
6199
6188
  )
6200
6189
  ] });
6201
6190
  }
6191
+ var DEFAULT_VALUE = {
6192
+ recentColors: [],
6193
+ pushColor: () => {
6194
+ }
6195
+ };
6196
+ var RecentColorsContext = createContext(DEFAULT_VALUE);
6197
+ var RecentColorsProvider = RecentColorsContext.Provider;
6198
+ function useRecentColors() {
6199
+ return useContext(RecentColorsContext);
6200
+ }
6202
6201
  function DrawSection(p) {
6203
6202
  const { t } = useTranslation();
6203
+ const { pushColor } = useRecentColors();
6204
+ const colorRef = useRef(null);
6205
+ useEffect(() => {
6206
+ const el = colorRef.current;
6207
+ if (!el) {
6208
+ return;
6209
+ }
6210
+ const handler = () => pushColor(el.value);
6211
+ el.addEventListener("change", handler);
6212
+ return () => el.removeEventListener("change", handler);
6213
+ }, [pushColor]);
6204
6214
  return /* @__PURE__ */ jsxs(Fragment, { children: [
6205
6215
  /* @__PURE__ */ jsx("div", { className: grp, children: DRAW_TOOLS.map((tool, i, a) => /* @__PURE__ */ jsx(
6206
6216
  "button",
@@ -6227,6 +6237,7 @@ function DrawSection(p) {
6227
6237
  /* @__PURE__ */ jsx(
6228
6238
  "input",
6229
6239
  {
6240
+ ref: colorRef,
6230
6241
  type: "color",
6231
6242
  value: p.drawingColor,
6232
6243
  onChange: (e) => p.onSetDrawingColor(e.target.value),
@@ -6291,7 +6302,7 @@ function AccountPage() {
6291
6302
  return void 0;
6292
6303
  });
6293
6304
  };
6294
- const version = "3.1.5" ;
6305
+ const version = "3.3.0" ;
6295
6306
  return /* @__PURE__ */ jsxs("div", { className: "mt-8 max-w-[700px] space-y-6", children: [
6296
6307
  /* @__PURE__ */ jsxs("section", { className: cardClass, children: [
6297
6308
  /* @__PURE__ */ jsxs("h2", { className: "flex items-center gap-2 text-sm font-semibold", children: [
@@ -7062,7 +7073,6 @@ function extractFontInfo(element, themeFonts) {
7062
7073
  fontSize: fontSize !== void 0 && fontSize !== null ? String(fontSize) : defaults.fontSize
7063
7074
  };
7064
7075
  }
7065
- var COMMON_SIZES = [8, 9, 10, 11, 12, 14, 16, 18, 20, 24, 28, 32, 36, 40, 44, 48, 54, 60, 72, 96];
7066
7076
  function HomeSection(p) {
7067
7077
  const { t } = useTranslation();
7068
7078
  const [fontMenuOpen, setFontMenuOpen] = useState(false);
@@ -7220,7 +7230,7 @@ function HomeSection(p) {
7220
7230
  ]
7221
7231
  }
7222
7232
  ),
7223
- sizeMenuOpen && /* @__PURE__ */ jsx(RibbonMenu, { anchorRef: sizeMenuRef, className: "flex flex-col w-48 pt-1", children: /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-border bg-popover backdrop-blur-lg shadow-2xl py-1 max-h-60 overflow-y-auto", children: COMMON_SIZES.map((s) => /* @__PURE__ */ jsx(
7233
+ sizeMenuOpen && /* @__PURE__ */ jsx(RibbonMenu, { anchorRef: sizeMenuRef, className: "flex flex-col w-48 pt-1", children: /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-border bg-popover backdrop-blur-lg shadow-2xl py-1 max-h-60 overflow-y-auto", children: COMMON_FONT_SIZES.map((s) => /* @__PURE__ */ jsx(
7224
7234
  "button",
7225
7235
  {
7226
7236
  type: "button",
@@ -7992,7 +8002,7 @@ function SlideShowSection(p) {
7992
8002
  {
7993
8003
  label: t("pptx.slideShow.fromBeginning"),
7994
8004
  icon: /* @__PURE__ */ jsx(LuPlay, {}),
7995
- onClick: () => p.onSetMode("present"),
8005
+ onClick: p.onPresentFromBeginning ?? (() => p.onSetMode("present")),
7996
8006
  title: t("pptx.slideShow.fromBeginningTooltip")
7997
8007
  }
7998
8008
  ),
@@ -8132,6 +8142,45 @@ function SlideShowSection(p) {
8132
8142
  ] })
8133
8143
  ] });
8134
8144
  }
8145
+ function RecentColorsRow({
8146
+ prefix,
8147
+ disabled,
8148
+ onCommit
8149
+ }) {
8150
+ const { t } = useTranslation();
8151
+ const { recentColors, pushColor } = useRecentColors();
8152
+ if (recentColors.length === 0) {
8153
+ return null;
8154
+ }
8155
+ return /* @__PURE__ */ jsxs(
8156
+ "div",
8157
+ {
8158
+ "data-testid": "pptx-color-recent",
8159
+ "aria-label": t("pptx.colorPicker.recentColors"),
8160
+ className: "mt-1 flex flex-wrap items-center gap-1",
8161
+ children: [
8162
+ /* @__PURE__ */ jsx("span", { className: "text-[9px] text-muted-foreground", children: t("pptx.colorPicker.recentColors") }),
8163
+ recentColors.map((c) => /* @__PURE__ */ jsx(
8164
+ "button",
8165
+ {
8166
+ type: "button",
8167
+ "data-pptx-compact": true,
8168
+ className: "h-4 w-4 rounded border border-primary",
8169
+ style: { backgroundColor: c },
8170
+ title: c,
8171
+ "aria-label": `Recent ${c}`,
8172
+ disabled,
8173
+ onClick: () => {
8174
+ onCommit(c);
8175
+ pushColor(c);
8176
+ }
8177
+ },
8178
+ `${prefix}-recent-${c}`
8179
+ ))
8180
+ ]
8181
+ }
8182
+ );
8183
+ }
8135
8184
  var LINE_SPACING_OPTIONS = [
8136
8185
  { label: "1.0", value: 1 },
8137
8186
  { label: "1.15", value: 1.15 },
@@ -8344,14 +8393,16 @@ function TextSection(p) {
8344
8393
  const changeCaseRef = useRef(null);
8345
8394
  const fontColorRef = useRef(null);
8346
8395
  const highlightMenuRef = useRef(null);
8396
+ const { pushColor } = useRecentColors();
8347
8397
  const handleColorChange = useCallback(
8348
8398
  (color) => {
8349
8399
  if (!canFormat) {
8350
8400
  return;
8351
8401
  }
8352
8402
  p.onUpdateTextStyle({ color });
8403
+ pushColor(color);
8353
8404
  },
8354
- [canFormat, p]
8405
+ [canFormat, p, pushColor]
8355
8406
  );
8356
8407
  const handleHighlightChange = useCallback(
8357
8408
  (highlightColor) => {
@@ -8359,8 +8410,9 @@ function TextSection(p) {
8359
8410
  return;
8360
8411
  }
8361
8412
  p.onUpdateTextStyle({ highlightColor });
8413
+ pushColor(highlightColor);
8362
8414
  },
8363
- [canFormat, p]
8415
+ [canFormat, p, pushColor]
8364
8416
  );
8365
8417
  return /* @__PURE__ */ jsxs(Fragment, { children: [
8366
8418
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-0.5", children: [
@@ -8708,6 +8760,14 @@ function TextSection(p) {
8708
8760
  value: currentColor,
8709
8761
  onChange: (e) => handleColorChange(e.target.value)
8710
8762
  }
8763
+ ),
8764
+ /* @__PURE__ */ jsx(
8765
+ RecentColorsRow,
8766
+ {
8767
+ prefix: "font-color",
8768
+ disabled: !canMut,
8769
+ onCommit: handleColorChange
8770
+ }
8711
8771
  )
8712
8772
  ] }) })
8713
8773
  ] }),
@@ -9356,6 +9416,7 @@ function MobileSectionBody({
9356
9416
  SlideShowSection,
9357
9417
  {
9358
9418
  onPresent: () => p.onSetMode("present"),
9419
+ onPresentFromBeginning: p.onPresentFromBeginning,
9359
9420
  onEnterPresenterView: p.onEnterPresenterView ?? (() => {
9360
9421
  }),
9361
9422
  onEnterRehearsalMode: p.onEnterRehearsalMode ?? (() => {
@@ -9554,9 +9615,55 @@ function MobileToolbar(props) {
9554
9615
  }
9555
9616
  );
9556
9617
  }
9618
+ function ShapeColorPopover({
9619
+ icon,
9620
+ title,
9621
+ prefix,
9622
+ anchorRef,
9623
+ open,
9624
+ onToggle,
9625
+ disabled,
9626
+ swatchAriaLabel,
9627
+ onApply,
9628
+ onClose
9629
+ }) {
9630
+ return /* @__PURE__ */ jsxs("div", { className: "relative", ref: anchorRef, children: [
9631
+ /* @__PURE__ */ jsx("button", { type: "button", disabled, className: pill, title, onClick: onToggle, children: icon }),
9632
+ open && /* @__PURE__ */ jsx(RibbonMenu, { anchorRef, className: "pt-1", children: /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-border bg-popover backdrop-blur-lg shadow-2xl p-2", children: [
9633
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-6 gap-1", children: RIBBON_SHAPE_SWATCHES.map((c) => /* @__PURE__ */ jsx(
9634
+ "button",
9635
+ {
9636
+ type: "button",
9637
+ "aria-label": `${swatchAriaLabel} ${c}`,
9638
+ "data-pptx-compact": true,
9639
+ className: "w-5 h-5 rounded border border-border/60 hover:scale-110 transition-transform",
9640
+ style: { backgroundColor: c },
9641
+ title: c,
9642
+ onClick: () => {
9643
+ onApply(c);
9644
+ onClose();
9645
+ }
9646
+ },
9647
+ c
9648
+ )) }),
9649
+ /* @__PURE__ */ jsx(
9650
+ RecentColorsRow,
9651
+ {
9652
+ prefix,
9653
+ disabled,
9654
+ onCommit: (c) => {
9655
+ onApply(c);
9656
+ onClose();
9657
+ }
9658
+ }
9659
+ )
9660
+ ] }) })
9661
+ ] });
9662
+ }
9557
9663
  var TOP_SHAPES = SHAPE_PRESETS.slice(0, 12);
9558
9664
  function DrawingGroup(p) {
9559
9665
  const { t } = useTranslation();
9666
+ const { pushColor } = useRecentColors();
9560
9667
  const [shapesOpen, setShapesOpen] = useState(false);
9561
9668
  const [arrangeOpen, setArrangeOpen] = useState(false);
9562
9669
  const [fillOpen, setFillOpen] = useState(false);
@@ -9718,64 +9825,42 @@ function DrawingGroup(p) {
9718
9825
  )
9719
9826
  ] }) })
9720
9827
  ] }),
9721
- /* @__PURE__ */ jsxs("div", { className: "relative", ref: fillRef, children: [
9722
- /* @__PURE__ */ jsx(
9723
- "button",
9724
- {
9725
- type: "button",
9726
- disabled: !p.canEdit || !p.selectedElement,
9727
- className: pill,
9728
- title: t("pptx.drawing.shapeFill"),
9729
- onClick: () => setFillOpen((v) => !v),
9730
- children: /* @__PURE__ */ jsx(LuPaintBucket, { className: ic })
9731
- }
9732
- ),
9733
- fillOpen && /* @__PURE__ */ jsx(RibbonMenu, { anchorRef: fillRef, className: "pt-1", children: /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-border bg-popover backdrop-blur-lg shadow-2xl p-2 grid grid-cols-6 gap-1", children: RIBBON_SHAPE_SWATCHES.map((c) => /* @__PURE__ */ jsx(
9734
- "button",
9735
- {
9736
- type: "button",
9737
- "aria-label": `Fill colour ${c}`,
9738
- "data-pptx-compact": true,
9739
- className: "w-5 h-5 rounded border border-border/60 hover:scale-110 transition-transform",
9740
- style: { backgroundColor: c },
9741
- title: c,
9742
- onClick: () => {
9743
- p.onUpdateElementStyle?.(shapeFillChange(c));
9744
- setFillOpen(false);
9745
- }
9828
+ /* @__PURE__ */ jsx(
9829
+ ShapeColorPopover,
9830
+ {
9831
+ icon: /* @__PURE__ */ jsx(LuPaintBucket, { className: ic }),
9832
+ title: t("pptx.drawing.shapeFill"),
9833
+ prefix: "shape-fill",
9834
+ anchorRef: fillRef,
9835
+ open: fillOpen,
9836
+ onToggle: () => setFillOpen((v) => !v),
9837
+ disabled: !p.canEdit || !p.selectedElement,
9838
+ swatchAriaLabel: "Fill colour",
9839
+ onApply: (c) => {
9840
+ p.onUpdateElementStyle?.(shapeFillChange(c));
9841
+ pushColor(c);
9746
9842
  },
9747
- c
9748
- )) }) })
9749
- ] }),
9750
- /* @__PURE__ */ jsxs("div", { className: "relative", ref: outlineRef, children: [
9751
- /* @__PURE__ */ jsx(
9752
- "button",
9753
- {
9754
- type: "button",
9755
- disabled: !p.canEdit || !p.selectedElement,
9756
- className: pill,
9757
- title: t("pptx.drawing.shapeOutline"),
9758
- onClick: () => setOutlineOpen((v) => !v),
9759
- children: /* @__PURE__ */ jsx(LuPenLine, { className: ic })
9760
- }
9761
- ),
9762
- outlineOpen && /* @__PURE__ */ jsx(RibbonMenu, { anchorRef: outlineRef, className: "pt-1", children: /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-border bg-popover backdrop-blur-lg shadow-2xl p-2 grid grid-cols-6 gap-1", children: RIBBON_SHAPE_SWATCHES.map((c) => /* @__PURE__ */ jsx(
9763
- "button",
9764
- {
9765
- type: "button",
9766
- "aria-label": `Outline colour ${c}`,
9767
- "data-pptx-compact": true,
9768
- className: "w-5 h-5 rounded border border-border/60 hover:scale-110 transition-transform",
9769
- style: { backgroundColor: c },
9770
- title: c,
9771
- onClick: () => {
9772
- p.onUpdateElementStyle?.(shapeOutlineChange(c));
9773
- setOutlineOpen(false);
9774
- }
9843
+ onClose: () => setFillOpen(false)
9844
+ }
9845
+ ),
9846
+ /* @__PURE__ */ jsx(
9847
+ ShapeColorPopover,
9848
+ {
9849
+ icon: /* @__PURE__ */ jsx(LuPenLine, { className: ic }),
9850
+ title: t("pptx.drawing.shapeOutline"),
9851
+ prefix: "shape-outline",
9852
+ anchorRef: outlineRef,
9853
+ open: outlineOpen,
9854
+ onToggle: () => setOutlineOpen((v) => !v),
9855
+ disabled: !p.canEdit || !p.selectedElement,
9856
+ swatchAriaLabel: "Outline colour",
9857
+ onApply: (c) => {
9858
+ p.onUpdateElementStyle?.(shapeOutlineChange(c));
9859
+ pushColor(c);
9775
9860
  },
9776
- c
9777
- )) }) })
9778
- ] }),
9861
+ onClose: () => setOutlineOpen(false)
9862
+ }
9863
+ ),
9779
9864
  /* @__PURE__ */ jsx(
9780
9865
  "button",
9781
9866
  {
@@ -10679,6 +10764,7 @@ function Toolbar(p) {
10679
10764
  SlideShowSection,
10680
10765
  {
10681
10766
  onPresent: () => p.onSetMode("present"),
10767
+ onPresentFromBeginning: p.onPresentFromBeginning,
10682
10768
  onEnterPresenterView: p.onEnterPresenterView ?? (() => {
10683
10769
  }),
10684
10770
  onEnterRehearsalMode: p.onEnterRehearsalMode ?? (() => {
@@ -11927,7 +12013,7 @@ function useDrawingOverlay({
11927
12013
  },
11928
12014
  [zoom.canvasStageRef, zoom.editorScale]
11929
12015
  );
11930
- const buildPathD2 = useCallback((pts) => {
12016
+ const buildPathD = useCallback((pts) => {
11931
12017
  if (pts.length === 0) {
11932
12018
  return "";
11933
12019
  }
@@ -12056,7 +12142,7 @@ function useDrawingOverlay({
12056
12142
  };
12057
12143
  onAddFreeformShape?.(freeformShape);
12058
12144
  } else {
12059
- const pathD = buildPathD2(relPoints);
12145
+ const pathD = buildPathD(relPoints);
12060
12146
  const isHighlighter = activeTool === "highlighter";
12061
12147
  const hasPressure = currentStrokePressures.length >= 2 && currentStrokePressures.some((p) => Math.abs(p - currentStrokePressures[0]) > 0.01);
12062
12148
  const ink = {
@@ -12087,13 +12173,13 @@ function useDrawingOverlay({
12087
12173
  isDrawingRef,
12088
12174
  onAddInkElement,
12089
12175
  onAddFreeformShape,
12090
- buildPathD2,
12176
+ buildPathD,
12091
12177
  currentStrokePressures
12092
12178
  ]
12093
12179
  );
12094
12180
  const liveStrokeD = useMemo(
12095
- () => isStrokeActive ? buildPathD2(currentStrokePoints) : "",
12096
- [isStrokeActive, currentStrokePoints, buildPathD2]
12181
+ () => isStrokeActive ? buildPathD(currentStrokePoints) : "",
12182
+ [isStrokeActive, currentStrokePoints, buildPathD]
12097
12183
  );
12098
12184
  return {
12099
12185
  isDrawing,
@@ -12166,8 +12252,6 @@ function useStableCallbacks(callbacks) {
12166
12252
  stableResizeTableRow
12167
12253
  };
12168
12254
  }
12169
- var PLACEHOLDER_WIDTH = 120;
12170
- var PLACEHOLDER_HEIGHT = 40;
12171
12255
  function ActiveXControlOverlay({
12172
12256
  controls,
12173
12257
  canvasSize,
@@ -12176,24 +12260,17 @@ function ActiveXControlOverlay({
12176
12260
  if (controls.length === 0) {
12177
12261
  return null;
12178
12262
  }
12179
- return /* @__PURE__ */ jsx("div", { className: "absolute inset-0 pointer-events-none z-[40]", children: controls.map((control, idx) => {
12180
- const width = control.width ?? PLACEHOLDER_WIDTH;
12181
- const height = control.height ?? PLACEHOLDER_HEIGHT;
12182
- const left = control.x ?? 8;
12183
- const top = control.y ?? 8 + idx * (PLACEHOLDER_HEIGHT + 6);
12184
- const clampedWidth = Math.min(width, canvasSize.width);
12185
- const clampedHeight = Math.min(height, canvasSize.height);
12186
- const imageUrl = control.fallbackImageRelId ? resolveFallbackImage?.(control.fallbackImageRelId) : void 0;
12187
- const label = control.name || "ActiveX control";
12188
- if (imageUrl) {
12263
+ return /* @__PURE__ */ jsx("div", { className: "absolute inset-0 pointer-events-none z-[40]", "data-testid": "pptx-activex-overlay", children: controls.map((control, idx) => {
12264
+ const view = getActiveXControlOverlayView(control, canvasSize, idx, resolveFallbackImage);
12265
+ if (view.className === "image" && view.imageUrl) {
12189
12266
  return /* @__PURE__ */ jsx(
12190
12267
  "img",
12191
12268
  {
12192
- src: imageUrl,
12193
- alt: label,
12194
- title: `ActiveX control: ${label}`,
12269
+ src: view.imageUrl,
12270
+ alt: view.label,
12271
+ title: `ActiveX control: ${view.label}`,
12195
12272
  className: "absolute",
12196
- style: { left, top, width: clampedWidth, height: clampedHeight }
12273
+ style: { left: view.left, top: view.top, width: view.width, height: view.height }
12197
12274
  },
12198
12275
  `${control.relId}-${idx}`
12199
12276
  );
@@ -12202,12 +12279,12 @@ function ActiveXControlOverlay({
12202
12279
  "div",
12203
12280
  {
12204
12281
  className: "absolute",
12205
- title: `ActiveX control: ${label} (interactive controls are not supported in the viewer)`,
12282
+ title: `ActiveX control: ${view.label} (interactive controls are not supported in the viewer)`,
12206
12283
  style: {
12207
- left,
12208
- top,
12209
- width: clampedWidth,
12210
- height: clampedHeight,
12284
+ left: view.left,
12285
+ top: view.top,
12286
+ width: view.width,
12287
+ height: view.height,
12211
12288
  display: "flex",
12212
12289
  alignItems: "center",
12213
12290
  justifyContent: "center",
@@ -12227,7 +12304,7 @@ function ActiveXControlOverlay({
12227
12304
  },
12228
12305
  children: [
12229
12306
  /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u2699" }),
12230
- /* @__PURE__ */ jsx("span", { style: { overflow: "hidden", textOverflow: "ellipsis" }, children: label })
12307
+ /* @__PURE__ */ jsx("span", { style: { overflow: "hidden", textOverflow: "ellipsis" }, children: view.label })
12231
12308
  ]
12232
12309
  },
12233
12310
  `${control.relId}-${idx}`
@@ -14541,6 +14618,8 @@ function MasterViewSidebar({
14541
14618
  onSelectLayout,
14542
14619
  onCollapse,
14543
14620
  onTabChange,
14621
+ crudActions,
14622
+ onCrudAction,
14544
14623
  onHandoutSlidesPerPageChange,
14545
14624
  onNotesMasterBackgroundChange,
14546
14625
  onHandoutMasterBackgroundChange,
@@ -14620,6 +14699,19 @@ function MasterViewSidebar({
14620
14699
  }
14621
14700
  )
14622
14701
  ] }),
14702
+ masterViewTab === "slides" && canEdit && crudActions.length > 0 && /* @__PURE__ */ jsx("section", { className: "grid grid-cols-2 gap-1 rounded-md border border-border/60 p-2", children: crudActions.map((action) => /* @__PURE__ */ jsx(
14703
+ "button",
14704
+ {
14705
+ type: "button",
14706
+ "data-testid": `pptx-master-crud-${action.id}`,
14707
+ disabled: !action.enabled,
14708
+ title: action.disabledReasonKey ? t(action.disabledReasonKey) : void 0,
14709
+ onClick: () => onCrudAction(action.id),
14710
+ className: "rounded border border-border/60 px-1.5 py-1 text-[10px] hover:bg-accent/60 disabled:cursor-not-allowed disabled:opacity-40",
14711
+ children: t(action.labelKey)
14712
+ },
14713
+ action.id
14714
+ )) }),
14623
14715
  masterViewTab === "slides" && /* @__PURE__ */ jsx(
14624
14716
  SlideMastersList,
14625
14717
  {
@@ -18896,12 +18988,13 @@ function PresenterNotesRail({
18896
18988
  now,
18897
18989
  elapsed,
18898
18990
  activeCustomShow,
18991
+ authoredRange,
18899
18992
  onMove,
18900
18993
  onUpdateNotes
18901
18994
  }) {
18902
18995
  const { t } = useTranslation();
18903
18996
  const slide = slides[current];
18904
- const nextSlide = nextPresentedSlide(slides, current, activeCustomShow);
18997
+ const nextSlide = nextPresentedSlide(slides, current, activeCustomShow, authoredRange);
18905
18998
  const notesText = slide?.notes ?? "";
18906
18999
  const notesSegments = slide?.notesSegments;
18907
19000
  const [notesDraft, setNotesDraft] = useState(notesText);
@@ -19147,6 +19240,7 @@ function PresenterView({
19147
19240
  templateElements,
19148
19241
  presentationStartTime,
19149
19242
  activeCustomShow,
19243
+ authoredRange,
19150
19244
  onMovePresentationSlide,
19151
19245
  onExit,
19152
19246
  onOpenAudienceWindow,
@@ -19258,6 +19352,7 @@ function PresenterView({
19258
19352
  canvasSize,
19259
19353
  templateElements,
19260
19354
  activeCustomShow,
19355
+ authoredRange,
19261
19356
  now,
19262
19357
  elapsed,
19263
19358
  onMove: onMovePresentationSlide,
@@ -19315,6 +19410,8 @@ function MobilePresenterView({
19315
19410
  currentSlideIndex,
19316
19411
  canvasSize,
19317
19412
  templateElements,
19413
+ activeCustomShow,
19414
+ authoredRange,
19318
19415
  presentationStartTime,
19319
19416
  onMovePresentationSlide,
19320
19417
  onExit
@@ -19327,7 +19424,7 @@ function MobilePresenterView({
19327
19424
  }, []);
19328
19425
  const elapsed = mobileElapsedSince(presentationStartTime, now);
19329
19426
  const currentSlide = slides[currentSlideIndex];
19330
- const nextSlide = nextPresentedSlide(slides, currentSlideIndex);
19427
+ const nextSlide = nextPresentedSlide(slides, currentSlideIndex, activeCustomShow, authoredRange);
19331
19428
  if (!currentSlide) {
19332
19429
  return /* @__PURE__ */ jsx("div", { className: "absolute inset-0 z-50 flex items-center justify-center bg-card text-muted-foreground", children: t("pptx.presenter.noSlides") });
19333
19430
  }
@@ -19860,6 +19957,7 @@ function AfterAnimationRow({
19860
19957
  onColorChange
19861
19958
  }) {
19862
19959
  const { t } = useTranslation();
19960
+ const { pushColor } = useRecentColors();
19863
19961
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
19864
19962
  /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
19865
19963
  /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-[11px]", children: t("pptx.animation.afterAnimation") }),
@@ -19883,7 +19981,10 @@ function AfterAnimationRow({
19883
19981
  type: "color",
19884
19982
  "aria-label": t("pptx.animation.afterAnimation.color"),
19885
19983
  value: color ?? "#808080",
19886
- onChange: (event) => onColorChange(event.target.value),
19984
+ onChange: (event) => {
19985
+ onColorChange(event.target.value);
19986
+ pushColor(event.target.value);
19987
+ },
19887
19988
  disabled: !canEdit,
19888
19989
  className: "h-6 w-10 rounded border border-border bg-transparent p-0"
19889
19990
  }
@@ -20865,17 +20966,105 @@ var POS_FIELDS = [
20865
20966
  ["W", "width"],
20866
20967
  ["H", "height"]
20867
20968
  ];
20969
+ var URL_LABEL_KEY = {
20970
+ url: "pptx.action.gotoUrl",
20971
+ openFile: "pptx.hyperlink.actionOpenFile",
20972
+ openPresentation: "pptx.hyperlink.actionOpenPresentation"
20973
+ };
20974
+ function ActionTargetFields({
20975
+ type,
20976
+ canEdit,
20977
+ slideCount,
20978
+ customShows,
20979
+ url,
20980
+ slideIndex,
20981
+ customShowId,
20982
+ returnAfter,
20983
+ onChange
20984
+ }) {
20985
+ const { t } = useTranslation();
20986
+ const urlLabelKey = URL_LABEL_KEY[type];
20987
+ if (urlLabelKey) {
20988
+ return /* @__PURE__ */ jsx(
20989
+ "input",
20990
+ {
20991
+ type: "text",
20992
+ disabled: !canEdit,
20993
+ "aria-label": t(urlLabelKey),
20994
+ className: cn(INPUT, "w-full"),
20995
+ placeholder: "https://...",
20996
+ value: url ?? "",
20997
+ onChange: (e) => onChange({ url: e.target.value })
20998
+ }
20999
+ );
21000
+ }
21001
+ if (type === "slide") {
21002
+ return /* @__PURE__ */ jsx(
21003
+ "input",
21004
+ {
21005
+ type: "number",
21006
+ disabled: !canEdit,
21007
+ "aria-label": t("pptx.action.gotoSlide"),
21008
+ className: cn(INPUT, "w-full"),
21009
+ placeholder: t("pptx.action.slideNumberPlaceholder"),
21010
+ min: 1,
21011
+ max: slideCount,
21012
+ value: (slideIndex ?? 0) + 1,
21013
+ onChange: (e) => {
21014
+ const idx = toSlideIndex(Number(e.target.value), slideCount);
21015
+ if (idx !== void 0) {
21016
+ onChange({ slideIndex: idx });
21017
+ }
21018
+ }
21019
+ }
21020
+ );
21021
+ }
21022
+ if (type === "customShow") {
21023
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
21024
+ /* @__PURE__ */ jsxs(
21025
+ "select",
21026
+ {
21027
+ "data-testid": "pptx-action-custom-show",
21028
+ disabled: !canEdit,
21029
+ "aria-label": t("pptx.hyperlink.customShowLabel"),
21030
+ className: cn(INPUT, "w-full"),
21031
+ value: customShowId ?? "",
21032
+ onChange: (e) => onChange({ customShowId: e.target.value, returnAfter }),
21033
+ children: [
21034
+ /* @__PURE__ */ jsx("option", { value: "", children: t("pptx.hyperlink.customShowLabel") }),
21035
+ customShows.map((show) => /* @__PURE__ */ jsx("option", { value: show.id, children: show.name }, show.id))
21036
+ ]
21037
+ }
21038
+ ),
21039
+ /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-1.5 text-muted-foreground", children: [
21040
+ /* @__PURE__ */ jsx(
21041
+ "input",
21042
+ {
21043
+ type: "checkbox",
21044
+ "data-testid": "pptx-action-custom-show-return",
21045
+ disabled: !canEdit,
21046
+ checked: returnAfter ?? false,
21047
+ onChange: (e) => onChange({ customShowId, returnAfter: e.target.checked })
21048
+ }
21049
+ ),
21050
+ t("pptx.hyperlink.customShowReturn")
21051
+ ] })
21052
+ ] });
21053
+ }
21054
+ return null;
21055
+ }
20868
21056
  function ActionSettingsPanel({
20869
21057
  selectedElement,
20870
21058
  slides,
20871
21059
  canEdit,
21060
+ customShows,
20872
21061
  onUpdateElement
20873
21062
  }) {
20874
21063
  const { t } = useTranslation();
20875
21064
  const clickAction = selectedElement.actionClick ? pptxActionToElementAction(selectedElement.actionClick, "click") : void 0;
20876
21065
  const hoverAction = selectedElement.actionHover ? pptxActionToElementAction(selectedElement.actionHover, "hover") : void 0;
20877
- const updateAction = (trigger, type, url, slideIndex) => {
20878
- const ea = { trigger, type, url, slideIndex };
21066
+ const updateAction = (trigger, type, patch) => {
21067
+ const ea = { trigger, type, ...patch };
20879
21068
  const pa = elementActionToPptxAction(ea);
20880
21069
  if (trigger === "click") {
20881
21070
  onUpdateElement({ actionClick: pa });
@@ -20885,9 +21074,13 @@ function ActionSettingsPanel({
20885
21074
  };
20886
21075
  const changeType = (trigger, type) => {
20887
21076
  const current = trigger === "click" ? clickAction : hoverAction;
20888
- const target = { url: current?.url, slideIndex: current?.slideIndex };
21077
+ const target = {
21078
+ url: current?.url,
21079
+ slideIndex: current?.slideIndex,
21080
+ customShowId: current?.customShowId
21081
+ };
20889
21082
  if (canCommitActionType(type, target)) {
20890
- updateAction(trigger, type, target.url, target.slideIndex);
21083
+ updateAction(trigger, type, target);
20891
21084
  }
20892
21085
  };
20893
21086
  return /* @__PURE__ */ jsxs("div", { className: CARD, "data-pptx-action-settings": true, children: [
@@ -20904,9 +21097,9 @@ function ActionSettingsPanel({
20904
21097
  fallbackSlideIndex: selectedElement.actionClick?.targetSlideIndex,
20905
21098
  canEdit,
20906
21099
  slideCount: slides.length,
21100
+ customShows,
20907
21101
  onChangeType: (type) => changeType("click", type),
20908
- onChangeUrl: (url) => updateAction("click", "url", url),
20909
- onChangeSlide: (idx) => updateAction("click", "slide", void 0, idx)
21102
+ onChangeTarget: (type, patch) => updateAction("click", type, patch)
20910
21103
  },
20911
21104
  `click-${selectedElement.id}`
20912
21105
  ),
@@ -20921,9 +21114,9 @@ function ActionSettingsPanel({
20921
21114
  fallbackSlideIndex: selectedElement.actionHover?.targetSlideIndex,
20922
21115
  canEdit,
20923
21116
  slideCount: slides.length,
21117
+ customShows,
20924
21118
  onChangeType: (type) => changeType("hover", type),
20925
- onChangeUrl: (url) => updateAction("hover", "url", url),
20926
- onChangeSlide: (idx) => updateAction("hover", "slide", void 0, idx)
21119
+ onChangeTarget: (type, patch) => updateAction("hover", type, patch)
20927
21120
  },
20928
21121
  `hover-${selectedElement.id}`
20929
21122
  )
@@ -20939,9 +21132,9 @@ function ActionTriggerSection({
20939
21132
  fallbackSlideIndex,
20940
21133
  canEdit,
20941
21134
  slideCount,
21135
+ customShows,
20942
21136
  onChangeType,
20943
- onChangeUrl,
20944
- onChangeSlide
21137
+ onChangeTarget
20945
21138
  }) {
20946
21139
  const { t } = useTranslation();
20947
21140
  const [pendingType, setPendingType] = useState(void 0);
@@ -20963,35 +21156,18 @@ function ActionTriggerSection({
20963
21156
  children: ELEMENT_ACTION_TYPE_OPTIONS.map((o) => /* @__PURE__ */ jsx("option", { value: o.value, children: t(o.labelKey) }, o.value))
20964
21157
  }
20965
21158
  ),
20966
- effectiveType === "url" && /* @__PURE__ */ jsx(
20967
- "input",
20968
- {
20969
- type: "text",
20970
- disabled: !canEdit,
20971
- "aria-label": t("pptx.action.gotoUrl"),
20972
- className: cn(INPUT, "w-full"),
20973
- placeholder: "https://...",
20974
- value: action?.url ?? fallbackUrl ?? "",
20975
- onChange: (e) => onChangeUrl(e.target.value)
20976
- }
20977
- ),
20978
- effectiveType === "slide" && /* @__PURE__ */ jsx(
20979
- "input",
21159
+ /* @__PURE__ */ jsx(
21160
+ ActionTargetFields,
20980
21161
  {
20981
- type: "number",
20982
- disabled: !canEdit,
20983
- "aria-label": t("pptx.action.gotoSlide"),
20984
- className: cn(INPUT, "w-full"),
20985
- placeholder: t("pptx.action.slideNumberPlaceholder"),
20986
- min: 1,
20987
- max: slideCount,
20988
- value: (action?.slideIndex ?? fallbackSlideIndex ?? 0) + 1,
20989
- onChange: (e) => {
20990
- const idx = toSlideIndex(Number(e.target.value), slideCount);
20991
- if (idx !== void 0) {
20992
- onChangeSlide(idx);
20993
- }
20994
- }
21162
+ type: effectiveType,
21163
+ canEdit,
21164
+ slideCount,
21165
+ customShows,
21166
+ url: action?.url ?? fallbackUrl,
21167
+ slideIndex: action?.slideIndex ?? fallbackSlideIndex,
21168
+ customShowId: action?.customShowId,
21169
+ returnAfter: action?.returnAfter,
21170
+ onChange: (patch) => onChangeTarget(effectiveType, patch)
20995
21171
  }
20996
21172
  )
20997
21173
  ] });
@@ -21279,6 +21455,7 @@ function ChartAxisStyleOptions({
21279
21455
  onSetGridlineStyle
21280
21456
  }) {
21281
21457
  const { t } = useTranslation();
21458
+ const { pushColor } = useRecentColors();
21282
21459
  const rows = SCALE_AXES.map((row) => ({
21283
21460
  ...row,
21284
21461
  axis: axes?.find((a) => a.axisType === row.type)
@@ -21380,7 +21557,10 @@ function ChartAxisStyleOptions({
21380
21557
  disabled: !canEdit,
21381
21558
  className: "h-6 w-8 cursor-pointer rounded border border-border bg-transparent",
21382
21559
  value: axis.fontColor ?? "#000000",
21383
- onChange: (e) => onSetTitleStyle(type, { fontColor: e.target.value })
21560
+ onChange: (e) => {
21561
+ onSetTitleStyle(type, { fontColor: e.target.value });
21562
+ pushColor(e.target.value);
21563
+ }
21384
21564
  }
21385
21565
  )
21386
21566
  ] })
@@ -21403,7 +21583,10 @@ function ChartAxisStyleOptions({
21403
21583
  title: t("pptx.chart.gridlineColor"),
21404
21584
  className: "h-6 w-8 cursor-pointer rounded border border-border bg-transparent",
21405
21585
  value: spPr?.strokeColor ?? "#d9d9d9",
21406
- onChange: (e) => onSetGridlineStyle(type, which, { color: e.target.value })
21586
+ onChange: (e) => {
21587
+ onSetGridlineStyle(type, which, { color: e.target.value });
21588
+ pushColor(e.target.value);
21589
+ }
21407
21590
  }
21408
21591
  ),
21409
21592
  /* @__PURE__ */ jsx(
@@ -21653,6 +21836,7 @@ function ChartDataPointMarkerOptions({
21653
21836
  onSetPointMarker
21654
21837
  }) {
21655
21838
  const { t } = useTranslation();
21839
+ const { pushColor } = useRecentColors();
21656
21840
  const [seriesIndex, setSeriesIndex] = useState(0);
21657
21841
  if (!MARKER_SUPPORTED_TYPES.has(chartType) || series.length === 0 || categories.length === 0) {
21658
21842
  return null;
@@ -21740,7 +21924,10 @@ function ChartDataPointMarkerOptions({
21740
21924
  title: t("pptx.chart.markerFill"),
21741
21925
  className: "h-6 w-8 cursor-pointer rounded border border-border bg-transparent",
21742
21926
  value: point2.marker.spPr?.fillColor ?? "#4472c4",
21743
- onChange: (e) => onSetPointMarker(seriesIndex, idx, { fillColor: e.target.value })
21927
+ onChange: (e) => {
21928
+ onSetPointMarker(seriesIndex, idx, { fillColor: e.target.value });
21929
+ pushColor(e.target.value);
21930
+ }
21744
21931
  }
21745
21932
  )
21746
21933
  ] })
@@ -21758,6 +21945,7 @@ function ChartDataPointOptions({
21758
21945
  onSetPointLabel
21759
21946
  }) {
21760
21947
  const { t } = useTranslation();
21948
+ const { pushColor } = useRecentColors();
21761
21949
  const [seriesIndex, setSeriesIndex] = useState(0);
21762
21950
  if (series.length === 0 || categories.length === 0) {
21763
21951
  return null;
@@ -21808,7 +21996,10 @@ function ChartDataPointOptions({
21808
21996
  title: t("pptx.chart.pointFill"),
21809
21997
  className: "h-6 w-8 cursor-pointer rounded border border-border bg-transparent",
21810
21998
  value: point2?.spPr?.fillColor ?? activeSeries.color ?? "#4472c4",
21811
- onChange: (e) => onSetPointFill(seriesIndex, idx, e.target.value)
21999
+ onChange: (e) => {
22000
+ onSetPointFill(seriesIndex, idx, e.target.value);
22001
+ pushColor(e.target.value);
22002
+ }
21812
22003
  }
21813
22004
  ),
21814
22005
  point2?.spPr?.fillColor && /* @__PURE__ */ jsx(
@@ -21850,7 +22041,13 @@ function ChartDataPointOptions({
21850
22041
  }) })
21851
22042
  ] });
21852
22043
  }
21853
- function ChartDisplayOptions({ style, canEdit, onUpdateStyle }) {
22044
+ function ChartDisplayOptions({
22045
+ style,
22046
+ canEdit,
22047
+ onUpdateStyle,
22048
+ hasGridlines,
22049
+ onToggleGridlines
22050
+ }) {
21854
22051
  const { t } = useTranslation();
21855
22052
  return /* @__PURE__ */ jsxs("div", { className: CARD2, children: [
21856
22053
  /* @__PURE__ */ jsx("div", { className: HEADING2, children: t("pptx.chart.display") }),
@@ -21903,8 +22100,8 @@ function ChartDisplayOptions({ style, canEdit, onUpdateStyle }) {
21903
22100
  {
21904
22101
  type: "checkbox",
21905
22102
  disabled: !canEdit,
21906
- checked: style?.hasGridlines ?? false,
21907
- onChange: (e) => onUpdateStyle({ hasGridlines: e.target.checked }),
22103
+ checked: hasGridlines,
22104
+ onChange: (e) => onToggleGridlines(e.target.checked),
21908
22105
  className: "accent-primary"
21909
22106
  }
21910
22107
  ),
@@ -22014,6 +22211,7 @@ function ChartMarkerOptions({
22014
22211
  onSetMarker
22015
22212
  }) {
22016
22213
  const { t } = useTranslation();
22214
+ const { pushColor } = useRecentColors();
22017
22215
  if (!MARKER_SUPPORTED_TYPES.has(chartType) || series.length === 0) {
22018
22216
  return null;
22019
22217
  }
@@ -22072,7 +22270,10 @@ function ChartMarkerOptions({
22072
22270
  disabled: !canEdit,
22073
22271
  className: "h-6 w-8 cursor-pointer rounded border border-border bg-transparent",
22074
22272
  value: marker.spPr?.fillColor ?? "#4472c4",
22075
- onChange: (e) => onSetMarker(i, { fillColor: e.target.value })
22273
+ onChange: (e) => {
22274
+ onSetMarker(i, { fillColor: e.target.value });
22275
+ pushColor(e.target.value);
22276
+ }
22076
22277
  }
22077
22278
  )
22078
22279
  ] })
@@ -22091,14 +22292,19 @@ function DebouncedColorInput({
22091
22292
  const [local, setLocal] = useState(value);
22092
22293
  const commitRef = useRef(onCommit);
22093
22294
  commitRef.current = onCommit;
22295
+ const { pushColor } = useRecentColors();
22094
22296
  useEffect(() => {
22095
22297
  setLocal(value);
22096
22298
  }, [value]);
22097
- const handleChange = useCallback((e) => {
22098
- const next = e.target.value;
22099
- setLocal(next);
22100
- commitRef.current(next);
22101
- }, []);
22299
+ const handleChange = useCallback(
22300
+ (e) => {
22301
+ const next = e.target.value;
22302
+ setLocal(next);
22303
+ commitRef.current(next);
22304
+ pushColor(next);
22305
+ },
22306
+ [pushColor]
22307
+ );
22102
22308
  return /* @__PURE__ */ jsx(
22103
22309
  "input",
22104
22310
  {
@@ -22113,11 +22319,13 @@ function DebouncedColorInput({
22113
22319
  }
22114
22320
  var DEFAULT_SWATCH = "#4472c4";
22115
22321
  function ChartSeriesColorOptions({
22116
- series,
22322
+ chartData,
22117
22323
  canEdit,
22118
- onSetColor
22324
+ onSetColor,
22325
+ onToggleSecondaryAxis
22119
22326
  }) {
22120
22327
  const { t } = useTranslation();
22328
+ const series = chartData.series;
22121
22329
  if (series.length === 0) {
22122
22330
  return null;
22123
22331
  }
@@ -22125,6 +22333,19 @@ function ChartSeriesColorOptions({
22125
22333
  /* @__PURE__ */ jsx("div", { className: HEADING2, children: t("pptx.chart.seriesColors") }),
22126
22334
  /* @__PURE__ */ jsx("div", { className: "space-y-1", children: series.map((s, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-[11px]", children: [
22127
22335
  /* @__PURE__ */ jsx("span", { className: "flex-1 truncate", title: s.name, children: s.name }),
22336
+ /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-1 text-muted-foreground shrink-0", children: [
22337
+ /* @__PURE__ */ jsx(
22338
+ "input",
22339
+ {
22340
+ type: "checkbox",
22341
+ disabled: !canEdit,
22342
+ checked: isSeriesUsingSecondaryAxis(chartData, i),
22343
+ onChange: (e) => onToggleSecondaryAxis(i, e.target.checked),
22344
+ className: "accent-primary"
22345
+ }
22346
+ ),
22347
+ t("pptx.chart.secondaryAxis")
22348
+ ] }),
22128
22349
  /* @__PURE__ */ jsx(
22129
22350
  DebouncedColorInput,
22130
22351
  {
@@ -22148,6 +22369,71 @@ function ChartSeriesColorOptions({
22148
22369
  ] }, `${s.name}-${i}`)) })
22149
22370
  ] });
22150
22371
  }
22372
+ function ChartSubtypeOptions({
22373
+ chartData,
22374
+ canEdit,
22375
+ onUpdateChartData
22376
+ }) {
22377
+ const { t } = useTranslation();
22378
+ if (chartData.chartType !== "bar3D" && chartData.chartType !== "radar" && chartData.chartType !== "surface") {
22379
+ return null;
22380
+ }
22381
+ return /* @__PURE__ */ jsxs("div", { className: CARD2, children: [
22382
+ /* @__PURE__ */ jsx("div", { className: HEADING2, children: t("pptx.chart.display") }),
22383
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
22384
+ chartData.chartType === "bar3D" && /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-[11px]", children: [
22385
+ /* @__PURE__ */ jsx("span", { className: "w-16 text-muted-foreground shrink-0", children: t("pptx.chart.bar3DShapeLabel") }),
22386
+ /* @__PURE__ */ jsx(
22387
+ "select",
22388
+ {
22389
+ "data-testid": "pptx-chart-bar3d-shape",
22390
+ "aria-label": t("pptx.chart.bar3DShapeLabel"),
22391
+ disabled: !canEdit,
22392
+ className: INPUT2,
22393
+ value: chartData.barShape ?? "box",
22394
+ onChange: (e) => onUpdateChartData(bar3DShapePatch(chartData, e.target.value)),
22395
+ children: BAR3D_SHAPE_OPTIONS.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value, children: t(opt.labelKey) }, opt.value))
22396
+ }
22397
+ )
22398
+ ] }),
22399
+ chartData.chartType === "radar" && /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-[11px]", children: [
22400
+ /* @__PURE__ */ jsx("span", { className: "w-16 text-muted-foreground shrink-0", children: t("pptx.chart.radarStyleLabel") }),
22401
+ /* @__PURE__ */ jsx(
22402
+ "select",
22403
+ {
22404
+ "data-testid": "pptx-chart-radar-style",
22405
+ "aria-label": t("pptx.chart.radarStyleLabel"),
22406
+ disabled: !canEdit,
22407
+ className: INPUT2,
22408
+ value: chartData.radarStyle ?? "standard",
22409
+ onChange: (e) => onUpdateChartData(
22410
+ radarStylePatch(
22411
+ chartData,
22412
+ e.target.value
22413
+ )
22414
+ ),
22415
+ children: RADAR_STYLE_OPTIONS.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value, children: t(opt.labelKey) }, opt.value))
22416
+ }
22417
+ )
22418
+ ] }),
22419
+ chartData.chartType === "surface" && /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-[11px]", children: [
22420
+ /* @__PURE__ */ jsx("span", { className: "w-16 text-muted-foreground shrink-0", children: t("pptx.chart.surfaceWireframeLabel") }),
22421
+ /* @__PURE__ */ jsx(
22422
+ "select",
22423
+ {
22424
+ "data-testid": "pptx-chart-surface-wireframe",
22425
+ "aria-label": t("pptx.chart.surfaceWireframeLabel"),
22426
+ disabled: !canEdit,
22427
+ className: INPUT2,
22428
+ value: chartData.wireframe ? "true" : "false",
22429
+ onChange: (e) => onUpdateChartData(surfaceWireframePatch(chartData, e.target.value === "true")),
22430
+ children: SURFACE_WIREFRAME_OPTIONS.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value, children: t(opt.labelKey) }, opt.value))
22431
+ }
22432
+ )
22433
+ ] })
22434
+ ] })
22435
+ ] });
22436
+ }
22151
22437
  function ChartTrendlineOptions({
22152
22438
  chartType,
22153
22439
  series,
@@ -22329,6 +22615,25 @@ function ChartDataPanel({ selectedElement, canEdit, onUpdateElement }) {
22329
22615
  },
22330
22616
  [chartData, style, onUpdateElement]
22331
22617
  );
22618
+ const hasGridlines = chartData ? chartGridlinesState(chartData) : false;
22619
+ const toggleGridlines = useCallback(
22620
+ (show) => {
22621
+ if (!chartData) {
22622
+ return;
22623
+ }
22624
+ updateChartData(chartGridlinesPatch(chartData, show));
22625
+ },
22626
+ [chartData, updateChartData]
22627
+ );
22628
+ const toggleSecondaryAxis = useCallback(
22629
+ (seriesIndex, useSecondary) => {
22630
+ if (!chartData) {
22631
+ return;
22632
+ }
22633
+ updateChartData(seriesSecondaryAxisPatch(chartData, seriesIndex, useSecondary));
22634
+ },
22635
+ [chartData, updateChartData]
22636
+ );
22332
22637
  const updateAxis = useCallback(
22333
22638
  (axisType, patch) => {
22334
22639
  if (!chartData) {
@@ -22499,7 +22804,24 @@ function ChartDataPanel({ selectedElement, canEdit, onUpdateElement }) {
22499
22804
  onUpdateChartData: updateChartData
22500
22805
  }
22501
22806
  ),
22502
- /* @__PURE__ */ jsx(ChartDisplayOptions, { style, canEdit, onUpdateStyle: updateStyle }),
22807
+ /* @__PURE__ */ jsx(
22808
+ ChartDisplayOptions,
22809
+ {
22810
+ style,
22811
+ canEdit,
22812
+ onUpdateStyle: updateStyle,
22813
+ hasGridlines,
22814
+ onToggleGridlines: toggleGridlines
22815
+ }
22816
+ ),
22817
+ /* @__PURE__ */ jsx(
22818
+ ChartSubtypeOptions,
22819
+ {
22820
+ chartData,
22821
+ canEdit,
22822
+ onUpdateChartData: updateChartData
22823
+ }
22824
+ ),
22503
22825
  /* @__PURE__ */ jsx(ChartDataLabelOptions, { style, canEdit, onUpdateStyle: updateStyle }),
22504
22826
  /* @__PURE__ */ jsx(ChartAxisOptions, { axes: chartData.axes, canEdit, onUpdateAxis: updateAxis }),
22505
22827
  /* @__PURE__ */ jsx(
@@ -22570,7 +22892,15 @@ function ChartDataPanel({ selectedElement, canEdit, onUpdateElement }) {
22570
22892
  onSetErrorBars: setSeriesErrorBars
22571
22893
  }
22572
22894
  ),
22573
- /* @__PURE__ */ jsx(ChartSeriesColorOptions, { series, canEdit, onSetColor: setSeriesColor }),
22895
+ /* @__PURE__ */ jsx(
22896
+ ChartSeriesColorOptions,
22897
+ {
22898
+ chartData,
22899
+ canEdit,
22900
+ onSetColor: setSeriesColor,
22901
+ onToggleSecondaryAxis: toggleSecondaryAxis
22902
+ }
22903
+ ),
22574
22904
  /* @__PURE__ */ jsx(
22575
22905
  ChartDataGrid,
22576
22906
  {
@@ -23030,6 +23360,7 @@ function DebouncedColorInput2({
23030
23360
  const [local, setLocal] = useState(value);
23031
23361
  const commitRef = useRef(onCommit);
23032
23362
  commitRef.current = onCommit;
23363
+ const { pushColor } = useRecentColors();
23033
23364
  useEffect(() => {
23034
23365
  setLocal(value);
23035
23366
  }, [value]);
@@ -23038,7 +23369,8 @@ function DebouncedColorInput2({
23038
23369
  }, []);
23039
23370
  const handleBlur = useCallback(() => {
23040
23371
  commitRef.current(local);
23041
- }, [local]);
23372
+ pushColor(local);
23373
+ }, [local, pushColor]);
23042
23374
  const inputRef = useRef(null);
23043
23375
  useEffect(() => {
23044
23376
  const el = inputRef.current;
@@ -23047,10 +23379,11 @@ function DebouncedColorInput2({
23047
23379
  }
23048
23380
  const handler = () => {
23049
23381
  commitRef.current(el.value);
23382
+ pushColor(el.value);
23050
23383
  };
23051
23384
  el.addEventListener("change", handler);
23052
23385
  return () => el.removeEventListener("change", handler);
23053
- }, []);
23386
+ }, [pushColor]);
23054
23387
  return /* @__PURE__ */ jsx(
23055
23388
  "input",
23056
23389
  {
@@ -24303,23 +24636,10 @@ function MediaPropertiesPanel({
24303
24636
  }
24304
24637
 
24305
24638
  // src/viewer/components/inspector/fill-stroke-options.ts
24306
- var COMPOUND_LINE_OPTIONS = [
24307
- { value: "sng", label: "Single", i18nKey: "pptx.strokeOptions.compoundSingle" },
24308
- { value: "dbl", label: "Double", i18nKey: "pptx.strokeOptions.compoundDouble" },
24309
- { value: "thickThin", label: "Thick-Thin", i18nKey: "pptx.strokeOptions.compoundThickThin" },
24310
- { value: "thinThick", label: "Thin-Thick", i18nKey: "pptx.strokeOptions.compoundThinThick" },
24311
- { value: "tri", label: "Triple", i18nKey: "pptx.strokeOptions.compoundTriple" }
24312
- ];
24313
- var LINE_JOIN_OPTIONS = [
24314
- { value: "round", label: "Round", i18nKey: "pptx.strokeOptions.joinRound" },
24315
- { value: "bevel", label: "Bevel", i18nKey: "pptx.strokeOptions.joinBevel" },
24316
- { value: "miter", label: "Miter", i18nKey: "pptx.strokeOptions.joinMiter" }
24317
- ];
24318
- var LINE_CAP_OPTIONS = [
24319
- { value: "flat", label: "Flat", i18nKey: "pptx.strokeOptions.capFlat" },
24320
- { value: "rnd", label: "Round", i18nKey: "pptx.strokeOptions.capRound" },
24321
- { value: "sq", label: "Square", i18nKey: "pptx.strokeOptions.capSquare" }
24322
- ];
24639
+ var COMPOUND_LINE_OPTIONS2 = COMPOUND_LINE_OPTIONS;
24640
+ var LINE_JOIN_OPTIONS2 = LINE_JOIN_OPTIONS;
24641
+ var LINE_CAP_OPTIONS2 = LINE_CAP_OPTIONS;
24642
+ var PATTERN_PRESET_OPTIONS2 = PATTERN_PRESET_OPTIONS;
24323
24643
  var FILL_MODE_OPTIONS2 = [
24324
24644
  { value: "solid", label: "Solid", i18nKey: "pptx.fill.solid" },
24325
24645
  { value: "gradient", label: "Gradient", i18nKey: "pptx.fill.gradient" },
@@ -24327,76 +24647,6 @@ var FILL_MODE_OPTIONS2 = [
24327
24647
  { value: "image", label: "Image", i18nKey: "pptx.inspector.image" },
24328
24648
  { value: "none", label: "None", i18nKey: "pptx.fill.none" }
24329
24649
  ];
24330
- var PATTERN_PRESET_OPTIONS = [
24331
- { value: "pct5", label: "5%", i18nKey: "pptx.fillPatterns.pct5" },
24332
- { value: "pct10", label: "10%", i18nKey: "pptx.fillPatterns.pct10" },
24333
- { value: "pct20", label: "20%", i18nKey: "pptx.fillPatterns.pct20" },
24334
- { value: "pct25", label: "25%", i18nKey: "pptx.fillPatterns.pct25" },
24335
- { value: "pct30", label: "30%", i18nKey: "pptx.fillPatterns.pct30" },
24336
- { value: "pct40", label: "40%", i18nKey: "pptx.fillPatterns.pct40" },
24337
- { value: "pct50", label: "50%", i18nKey: "pptx.fillPatterns.pct50" },
24338
- { value: "pct60", label: "60%", i18nKey: "pptx.fillPatterns.pct60" },
24339
- { value: "pct70", label: "70%", i18nKey: "pptx.fillPatterns.pct70" },
24340
- { value: "pct75", label: "75%", i18nKey: "pptx.fillPatterns.pct75" },
24341
- { value: "pct80", label: "80%", i18nKey: "pptx.fillPatterns.pct80" },
24342
- { value: "pct90", label: "90%", i18nKey: "pptx.fillPatterns.pct90" },
24343
- { value: "horz", label: "Horizontal", i18nKey: "pptx.fillPatterns.horizontal" },
24344
- { value: "vert", label: "Vertical", i18nKey: "pptx.fillPatterns.vertical" },
24345
- { value: "ltHorz", label: "Light Horizontal", i18nKey: "pptx.fillPatterns.lightHorizontal" },
24346
- { value: "ltVert", label: "Light Vertical", i18nKey: "pptx.fillPatterns.lightVertical" },
24347
- { value: "dkHorz", label: "Dark Horizontal", i18nKey: "pptx.fillPatterns.darkHorizontal" },
24348
- { value: "dkVert", label: "Dark Vertical", i18nKey: "pptx.fillPatterns.darkVertical" },
24349
- { value: "narHorz", label: "Narrow Horizontal", i18nKey: "pptx.fillPatterns.narrowHorizontal" },
24350
- { value: "narVert", label: "Narrow Vertical", i18nKey: "pptx.fillPatterns.narrowVertical" },
24351
- { value: "wdHorz", label: "Wide Horizontal", i18nKey: "pptx.fillPatterns.wideHorizontal" },
24352
- { value: "wdVert", label: "Wide Vertical", i18nKey: "pptx.fillPatterns.wideVertical" },
24353
- { value: "dashHorz", label: "Dashed Horizontal", i18nKey: "pptx.fillPatterns.dashedHorizontal" },
24354
- { value: "dashVert", label: "Dashed Vertical", i18nKey: "pptx.fillPatterns.dashedVertical" },
24355
- { value: "cross", label: "Cross", i18nKey: "pptx.fillPatterns.cross" },
24356
- { value: "dnDiag", label: "Down Diagonal", i18nKey: "pptx.fillPatterns.downDiagonal" },
24357
- { value: "upDiag", label: "Up Diagonal", i18nKey: "pptx.fillPatterns.upDiagonal" },
24358
- {
24359
- value: "ltDnDiag",
24360
- label: "Light Down Diagonal",
24361
- i18nKey: "pptx.fillPatterns.lightDownDiagonal"
24362
- },
24363
- { value: "ltUpDiag", label: "Light Up Diagonal", i18nKey: "pptx.fillPatterns.lightUpDiagonal" },
24364
- { value: "dkDnDiag", label: "Dark Down Diagonal", i18nKey: "pptx.fillPatterns.darkDownDiagonal" },
24365
- { value: "dkUpDiag", label: "Dark Up Diagonal", i18nKey: "pptx.fillPatterns.darkUpDiagonal" },
24366
- { value: "wdDnDiag", label: "Wide Down Diagonal", i18nKey: "pptx.fillPatterns.wideDownDiagonal" },
24367
- { value: "wdUpDiag", label: "Wide Up Diagonal", i18nKey: "pptx.fillPatterns.wideUpDiagonal" },
24368
- {
24369
- value: "dashDnDiag",
24370
- label: "Dashed Down Diagonal",
24371
- i18nKey: "pptx.fillPatterns.dashedDownDiagonal"
24372
- },
24373
- {
24374
- value: "dashUpDiag",
24375
- label: "Dashed Up Diagonal",
24376
- i18nKey: "pptx.fillPatterns.dashedUpDiagonal"
24377
- },
24378
- { value: "diagCross", label: "Diagonal Cross", i18nKey: "pptx.fillPatterns.diagonalCross" },
24379
- { value: "smCheck", label: "Small Check", i18nKey: "pptx.fillPatterns.smallCheck" },
24380
- { value: "lgCheck", label: "Large Check", i18nKey: "pptx.fillPatterns.largeCheck" },
24381
- { value: "smGrid", label: "Small Grid", i18nKey: "pptx.fillPatterns.smallGrid" },
24382
- { value: "lgGrid", label: "Large Grid", i18nKey: "pptx.fillPatterns.largeGrid" },
24383
- { value: "dotGrid", label: "Dot Grid", i18nKey: "pptx.fillPatterns.dotGrid" },
24384
- { value: "smConfetti", label: "Small Confetti", i18nKey: "pptx.fillPatterns.smallConfetti" },
24385
- { value: "lgConfetti", label: "Large Confetti", i18nKey: "pptx.fillPatterns.largeConfetti" },
24386
- { value: "horzBrick", label: "Horizontal Brick", i18nKey: "pptx.fillPatterns.horizontalBrick" },
24387
- { value: "diagBrick", label: "Diagonal Brick", i18nKey: "pptx.fillPatterns.diagonalBrick" },
24388
- { value: "solidDmnd", label: "Solid Diamond", i18nKey: "pptx.fillPatterns.solidDiamond" },
24389
- { value: "openDmnd", label: "Open Diamond", i18nKey: "pptx.fillPatterns.openDiamond" },
24390
- { value: "dotDmnd", label: "Dotted Diamond", i18nKey: "pptx.fillPatterns.dottedDiamond" },
24391
- { value: "plaid", label: "Plaid", i18nKey: "pptx.fillPatterns.plaid" },
24392
- { value: "sphere", label: "Sphere", i18nKey: "pptx.fillPatterns.sphere" },
24393
- { value: "weave", label: "Weave", i18nKey: "pptx.fillPatterns.weave" },
24394
- { value: "divot", label: "Divot", i18nKey: "pptx.fillPatterns.divot" },
24395
- { value: "shingle", label: "Shingle", i18nKey: "pptx.fillPatterns.shingle" },
24396
- { value: "wave", label: "Wave", i18nKey: "pptx.fillPatterns.wave" },
24397
- { value: "trellis", label: "Trellis", i18nKey: "pptx.fillPatterns.trellis" },
24398
- { value: "zigZag", label: "Zig Zag", i18nKey: "pptx.fillPatterns.zigZag" }
24399
- ];
24400
24650
  var GRADIENT_TYPE_OPTIONS2 = [
24401
24651
  { value: "linear", label: "Linear", i18nKey: "pptx.gradient.linear" },
24402
24652
  { value: "radial", label: "Radial", i18nKey: "pptx.gradient.radial" }
@@ -24591,6 +24841,7 @@ var SHADOW_EFFECT_CONFIGS = [
24591
24841
  {
24592
24842
  key: "sr",
24593
24843
  label: "Rotate with Shape",
24844
+ i18nKey: "pptx.effects.rotateWithShape",
24594
24845
  type: "checkbox",
24595
24846
  read: (s) => s?.shadowRotateWithShape ?? true,
24596
24847
  write: (v) => ({ shadowRotateWithShape: Boolean(v) })
@@ -24949,6 +25200,108 @@ var safeNum = (raw, fallback) => {
24949
25200
  const n = Number(raw);
24950
25201
  return Number.isFinite(n) ? n : fallback;
24951
25202
  };
25203
+ function EffectField({
25204
+ field,
25205
+ style,
25206
+ onUpdate
25207
+ }) {
25208
+ const { t } = useTranslation();
25209
+ const { pushColor } = useRecentColors();
25210
+ const fieldLabel = field.i18nKey ? t(field.i18nKey) : field.label;
25211
+ const val = field.read(style);
25212
+ const cls = `flex flex-col gap-1 ${field.span2 ? COL2 : ""}`;
25213
+ if (field.type === "select" && field.options) {
25214
+ return /* @__PURE__ */ jsxs("label", { className: cls, children: [
25215
+ /* @__PURE__ */ jsx("span", { className: LBL2, children: fieldLabel }),
25216
+ /* @__PURE__ */ jsx(
25217
+ "select",
25218
+ {
25219
+ "aria-label": fieldLabel,
25220
+ value: String(val),
25221
+ onChange: (e) => {
25222
+ const result = field.write(e.target.value, style);
25223
+ onUpdate(typeof result === "function" ? result(style) : result);
25224
+ },
25225
+ className: SEL2,
25226
+ children: field.options.map((o) => /* @__PURE__ */ jsx("option", { value: o.value, children: o.label }, o.value))
25227
+ }
25228
+ )
25229
+ ] });
25230
+ }
25231
+ if (field.type === "color") {
25232
+ return /* @__PURE__ */ jsxs("label", { className: cls, children: [
25233
+ /* @__PURE__ */ jsx("span", { className: LBL2, children: fieldLabel }),
25234
+ /* @__PURE__ */ jsx(
25235
+ "input",
25236
+ {
25237
+ type: "color",
25238
+ value: String(val),
25239
+ onChange: (e) => {
25240
+ const result = field.write(e.target.value, style);
25241
+ onUpdate(typeof result === "function" ? result(style) : result);
25242
+ pushColor(e.target.value);
25243
+ },
25244
+ className: `h-8 ${SEL2} px-1`
25245
+ }
25246
+ )
25247
+ ] });
25248
+ }
25249
+ if (field.type === "checkbox") {
25250
+ return /* @__PURE__ */ jsxs("label", { className: `flex items-center gap-2 ${field.span2 ? COL2 : ""}`, children: [
25251
+ /* @__PURE__ */ jsx(
25252
+ "input",
25253
+ {
25254
+ type: "checkbox",
25255
+ checked: Boolean(val),
25256
+ onChange: (e) => {
25257
+ const result = field.write(e.target.checked, style);
25258
+ onUpdate(typeof result === "function" ? result(style) : result);
25259
+ },
25260
+ className: "h-4 w-4"
25261
+ }
25262
+ ),
25263
+ /* @__PURE__ */ jsx("span", { className: LBL2, children: fieldLabel })
25264
+ ] });
25265
+ }
25266
+ if (field.type === "range") {
25267
+ return /* @__PURE__ */ jsxs("label", { className: cls, children: [
25268
+ /* @__PURE__ */ jsx("span", { className: LBL2, children: fieldLabel }),
25269
+ /* @__PURE__ */ jsx(
25270
+ "input",
25271
+ {
25272
+ type: "range",
25273
+ min: field.min ?? 0,
25274
+ max: field.max ?? 100,
25275
+ value: Number(val),
25276
+ onChange: (e) => {
25277
+ const result = field.write(Number(e.target.value), style);
25278
+ onUpdate(typeof result === "function" ? result(style) : result);
25279
+ },
25280
+ className: RNG
25281
+ }
25282
+ )
25283
+ ] });
25284
+ }
25285
+ return /* @__PURE__ */ jsxs("label", { className: cls, children: [
25286
+ /* @__PURE__ */ jsx("span", { className: LBL2, children: fieldLabel }),
25287
+ /* @__PURE__ */ jsx(
25288
+ "input",
25289
+ {
25290
+ type: "number",
25291
+ min: field.min,
25292
+ max: field.max,
25293
+ step: field.step,
25294
+ value: Number(val),
25295
+ onChange: (e) => {
25296
+ const n = safeNum(e.target.value, Number(val));
25297
+ const result = field.write(n, style);
25298
+ onUpdate(typeof result === "function" ? result(style) : result);
25299
+ },
25300
+ className: NUM2
25301
+ }
25302
+ )
25303
+ ] });
25304
+ }
24952
25305
  function SelectRow({
24953
25306
  label,
24954
25307
  value,
@@ -24976,14 +25329,18 @@ function ColorPickerRow({
24976
25329
  value,
24977
25330
  disabled,
24978
25331
  prefix,
24979
- recentColors,
24980
25332
  onChange
24981
25333
  }) {
24982
25334
  const { t } = useTranslation();
25335
+ const { pushColor } = useRecentColors();
25336
+ const commit = (color) => {
25337
+ onChange(color);
25338
+ pushColor(color);
25339
+ };
24983
25340
  const handleEyedropper = async () => {
24984
25341
  const color = await openNativeEyeDropper();
24985
25342
  if (color) {
24986
- onChange(color);
25343
+ commit(color);
24987
25344
  }
24988
25345
  };
24989
25346
  return /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
@@ -24995,7 +25352,7 @@ function ColorPickerRow({
24995
25352
  type: "color",
24996
25353
  value,
24997
25354
  disabled,
24998
- onChange: (e) => onChange(e.target.value),
25355
+ onChange: (e) => commit(e.target.value),
24999
25356
  className: `h-8 flex-1 ${SEL2} px-1 ${DIS}`
25000
25357
  }
25001
25358
  ),
@@ -25014,35 +25371,21 @@ function ColorPickerRow({
25014
25371
  }
25015
25372
  )
25016
25373
  ] }),
25017
- /* @__PURE__ */ jsxs("div", { className: "mt-1 flex flex-wrap gap-1", children: [
25018
- THEME_COLOR_SWATCHES.map((c) => /* @__PURE__ */ jsx(
25019
- "button",
25020
- {
25021
- type: "button",
25022
- className: `${SWATCH} ${DIS}`,
25023
- style: { backgroundColor: c },
25024
- title: `${label} ${c}`,
25025
- "aria-label": `${label} ${c}`,
25026
- "data-pptx-compact": true,
25027
- disabled,
25028
- onClick: () => onChange(c)
25029
- },
25030
- `${prefix}-theme-${c}`
25031
- )),
25032
- recentColors?.map((c) => /* @__PURE__ */ jsx(
25033
- "button",
25034
- {
25035
- type: "button",
25036
- "data-pptx-compact": true,
25037
- className: "h-4 w-4 rounded border border-primary",
25038
- style: { backgroundColor: c },
25039
- title: `Recent ${c}`,
25040
- "aria-label": `Recent ${c}`,
25041
- onClick: () => onChange(c)
25042
- },
25043
- `${prefix}-recent-${c}`
25044
- ))
25045
- ] })
25374
+ /* @__PURE__ */ jsx("div", { className: "mt-1 flex flex-wrap gap-1", children: THEME_COLOR_SWATCHES.map((c) => /* @__PURE__ */ jsx(
25375
+ "button",
25376
+ {
25377
+ type: "button",
25378
+ className: `${SWATCH} ${DIS}`,
25379
+ style: { backgroundColor: c },
25380
+ title: `${label} ${c}`,
25381
+ "aria-label": `${label} ${c}`,
25382
+ "data-pptx-compact": true,
25383
+ disabled,
25384
+ onClick: () => commit(c)
25385
+ },
25386
+ `${prefix}-theme-${c}`
25387
+ )) }),
25388
+ /* @__PURE__ */ jsx(RecentColorsRow, { prefix, disabled, onCommit: commit })
25046
25389
  ] });
25047
25390
  }
25048
25391
  function GradientStopRow({
@@ -25053,6 +25396,7 @@ function GradientStopRow({
25053
25396
  allStops
25054
25397
  }) {
25055
25398
  const { t } = useTranslation();
25399
+ const { pushColor } = useRecentColors();
25056
25400
  const patchStop = (patch) => {
25057
25401
  const next = allStops.map((s, i) => i === index ? { ...s, ...patch } : s);
25058
25402
  onUpdate(next);
@@ -25064,7 +25408,11 @@ function GradientStopRow({
25064
25408
  {
25065
25409
  type: "color",
25066
25410
  value: normalizeHexColor(stop.color, "#3b82f6"),
25067
- onChange: (e) => patchStop({ color: normalizeHexColor(e.target.value, "#3b82f6") }),
25411
+ onChange: (e) => {
25412
+ const hex = normalizeHexColor(e.target.value, "#3b82f6");
25413
+ patchStop({ color: hex });
25414
+ pushColor(hex);
25415
+ },
25068
25416
  className: "h-7 w-10 rounded border border-border bg-muted"
25069
25417
  }
25070
25418
  ),
@@ -25110,106 +25458,6 @@ function GradientStopRow({
25110
25458
  ] })
25111
25459
  ] });
25112
25460
  }
25113
- function EffectField({
25114
- field,
25115
- style,
25116
- onUpdate
25117
- }) {
25118
- const { t } = useTranslation();
25119
- const fieldLabel = field.i18nKey ? t(field.i18nKey) : field.label;
25120
- const val = field.read(style);
25121
- const cls = `flex flex-col gap-1 ${field.span2 ? COL2 : ""}`;
25122
- if (field.type === "select" && field.options) {
25123
- return /* @__PURE__ */ jsxs("label", { className: cls, children: [
25124
- /* @__PURE__ */ jsx("span", { className: LBL2, children: fieldLabel }),
25125
- /* @__PURE__ */ jsx(
25126
- "select",
25127
- {
25128
- "aria-label": fieldLabel,
25129
- value: String(val),
25130
- onChange: (e) => {
25131
- const result = field.write(e.target.value, style);
25132
- onUpdate(typeof result === "function" ? result(style) : result);
25133
- },
25134
- className: SEL2,
25135
- children: field.options.map((o) => /* @__PURE__ */ jsx("option", { value: o.value, children: o.label }, o.value))
25136
- }
25137
- )
25138
- ] });
25139
- }
25140
- if (field.type === "color") {
25141
- return /* @__PURE__ */ jsxs("label", { className: cls, children: [
25142
- /* @__PURE__ */ jsx("span", { className: LBL2, children: fieldLabel }),
25143
- /* @__PURE__ */ jsx(
25144
- "input",
25145
- {
25146
- type: "color",
25147
- value: String(val),
25148
- onChange: (e) => {
25149
- const result = field.write(e.target.value, style);
25150
- onUpdate(typeof result === "function" ? result(style) : result);
25151
- },
25152
- className: `h-8 ${SEL2} px-1`
25153
- }
25154
- )
25155
- ] });
25156
- }
25157
- if (field.type === "checkbox") {
25158
- return /* @__PURE__ */ jsxs("label", { className: `flex items-center gap-2 ${field.span2 ? COL2 : ""}`, children: [
25159
- /* @__PURE__ */ jsx(
25160
- "input",
25161
- {
25162
- type: "checkbox",
25163
- checked: Boolean(val),
25164
- onChange: (e) => {
25165
- const result = field.write(e.target.checked, style);
25166
- onUpdate(typeof result === "function" ? result(style) : result);
25167
- },
25168
- className: "h-4 w-4"
25169
- }
25170
- ),
25171
- /* @__PURE__ */ jsx("span", { className: LBL2, children: fieldLabel })
25172
- ] });
25173
- }
25174
- if (field.type === "range") {
25175
- return /* @__PURE__ */ jsxs("label", { className: cls, children: [
25176
- /* @__PURE__ */ jsx("span", { className: LBL2, children: fieldLabel }),
25177
- /* @__PURE__ */ jsx(
25178
- "input",
25179
- {
25180
- type: "range",
25181
- min: field.min ?? 0,
25182
- max: field.max ?? 100,
25183
- value: Number(val),
25184
- onChange: (e) => {
25185
- const result = field.write(Number(e.target.value), style);
25186
- onUpdate(typeof result === "function" ? result(style) : result);
25187
- },
25188
- className: RNG
25189
- }
25190
- )
25191
- ] });
25192
- }
25193
- return /* @__PURE__ */ jsxs("label", { className: cls, children: [
25194
- /* @__PURE__ */ jsx("span", { className: LBL2, children: fieldLabel }),
25195
- /* @__PURE__ */ jsx(
25196
- "input",
25197
- {
25198
- type: "number",
25199
- min: field.min,
25200
- max: field.max,
25201
- step: field.step,
25202
- value: Number(val),
25203
- onChange: (e) => {
25204
- const n = safeNum(e.target.value, Number(val));
25205
- const result = field.write(n, style);
25206
- onUpdate(typeof result === "function" ? result(style) : result);
25207
- },
25208
- className: NUM2
25209
- }
25210
- )
25211
- ] });
25212
- }
25213
25461
  function FillAdvancedControls({
25214
25462
  style,
25215
25463
  gradientStops,
@@ -25287,7 +25535,7 @@ function FillAdvancedControls({
25287
25535
  style?.fillMode === "pattern" && /* @__PURE__ */ jsxs(Fragment, { children: [
25288
25536
  /* @__PURE__ */ jsxs("div", { className: `${COL2} flex flex-col gap-2`, children: [
25289
25537
  /* @__PURE__ */ jsx("span", { className: LBL2, children: "Pattern" }),
25290
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-8 gap-1 max-h-48 overflow-y-auto rounded border border-border p-2", children: PATTERN_PRESET_OPTIONS.map((opt) => {
25538
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-8 gap-1 max-h-48 overflow-y-auto rounded border border-border p-2", children: PATTERN_PRESET_OPTIONS2.map((opt) => {
25291
25539
  const fgColor = normalizeHexColor(style?.fillColor, DEFAULT_FILL_COLOR);
25292
25540
  const bgColor = normalizeHexColor(style?.fillPatternBackgroundColor, "#ffffff");
25293
25541
  const svgPattern = getPatternSvg(opt.value, fgColor, bgColor);
@@ -25296,7 +25544,7 @@ function FillAdvancedControls({
25296
25544
  "button",
25297
25545
  {
25298
25546
  type: "button",
25299
- title: opt.label,
25547
+ title: t(opt.labelKey),
25300
25548
  className: `h-8 w-8 rounded border transition-all ${isSelected ? "border-primary border-2 ring-2 ring-primary/20" : "border-border hover:border-primary/50"}`,
25301
25549
  onClick: () => onUpdateShapeStyle({
25302
25550
  fillMode: "pattern",
@@ -25419,7 +25667,6 @@ function QuickStylesGallery({
25419
25667
  function StrokeEffectsSection({
25420
25668
  style,
25421
25669
  isLine,
25422
- recentColors,
25423
25670
  onUpdateShapeStyle,
25424
25671
  onSetStrokeColor
25425
25672
  }) {
@@ -25431,7 +25678,6 @@ function StrokeEffectsSection({
25431
25678
  label: t("pptx.inspector.stroke"),
25432
25679
  prefix: "stroke",
25433
25680
  value: normalizeHexColor(style?.strokeColor, DEFAULT_STROKE_COLOR),
25434
- recentColors,
25435
25681
  onChange: onSetStrokeColor
25436
25682
  }
25437
25683
  ),
@@ -25499,7 +25745,7 @@ function StrokeEffectsSection({
25499
25745
  ] }),
25500
25746
  /* @__PURE__ */ jsxs("label", { className: `flex flex-col gap-1 ${COL2}`, children: [
25501
25747
  /* @__PURE__ */ jsx("span", { className: LBL2, children: t("pptx.strokeEffects.compoundLine") }),
25502
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-5 gap-1", children: COMPOUND_LINE_OPTIONS.map((opt) => /* @__PURE__ */ jsx(
25748
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-5 gap-1", children: COMPOUND_LINE_OPTIONS2.map((opt) => /* @__PURE__ */ jsx(
25503
25749
  "button",
25504
25750
  {
25505
25751
  type: "button",
@@ -25544,7 +25790,7 @@ function StrokeEffectsSection({
25544
25790
  {
25545
25791
  label: t("pptx.strokeEffects.lineJoin"),
25546
25792
  value: style?.lineJoin || "round",
25547
- options: LINE_JOIN_OPTIONS,
25793
+ options: LINE_JOIN_OPTIONS2,
25548
25794
  onChange: (v) => onUpdateShapeStyle({ lineJoin: v })
25549
25795
  }
25550
25796
  ),
@@ -25553,7 +25799,7 @@ function StrokeEffectsSection({
25553
25799
  {
25554
25800
  label: t("pptx.strokeEffects.lineCap"),
25555
25801
  value: style?.lineCap || "flat",
25556
- options: LINE_CAP_OPTIONS,
25802
+ options: LINE_CAP_OPTIONS2,
25557
25803
  onChange: (v) => onUpdateShapeStyle({ lineCap: v })
25558
25804
  }
25559
25805
  )
@@ -25564,7 +25810,6 @@ function FillStrokeProperties({
25564
25810
  selectedShapeStyle,
25565
25811
  selectedShapeType,
25566
25812
  selectedGradientStops,
25567
- recentColors,
25568
25813
  onUpdateShapeStyle,
25569
25814
  onSetFillColor,
25570
25815
  onSetStrokeColor
@@ -25663,7 +25908,6 @@ function FillStrokeProperties({
25663
25908
  {
25664
25909
  style,
25665
25910
  isLine: line,
25666
- recentColors,
25667
25911
  onUpdateShapeStyle,
25668
25912
  onSetStrokeColor
25669
25913
  }
@@ -25678,6 +25922,7 @@ function Text3DProperties({
25678
25922
  onUpdateTextStyle
25679
25923
  }) {
25680
25924
  const { t } = useTranslation();
25925
+ const { pushColor } = useRecentColors();
25681
25926
  const t3d = ts?.text3d;
25682
25927
  const hasExtrusion = Boolean(t3d?.extrusionHeight && t3d.extrusionHeight > 0);
25683
25928
  const update3d = (partial) => {
@@ -25731,7 +25976,10 @@ function Text3DProperties({
25731
25976
  {
25732
25977
  type: "color",
25733
25978
  value: normalizeHexColor(t3d?.extrusionColor, "#888888"),
25734
- onChange: (e) => update3d({ extrusionColor: e.target.value }),
25979
+ onChange: (e) => {
25980
+ update3d({ extrusionColor: e.target.value });
25981
+ pushColor(e.target.value);
25982
+ },
25735
25983
  className: COLOR_CLS
25736
25984
  }
25737
25985
  )
@@ -25897,6 +26145,7 @@ function AdvancedTextFormatting({
25897
26145
  numChange
25898
26146
  }) {
25899
26147
  const { t } = useTranslation();
26148
+ const { pushColor } = useRecentColors();
25900
26149
  return /* @__PURE__ */ jsxs("div", { className: "mt-2 rounded border border-border bg-card p-2 space-y-2", children: [
25901
26150
  /* @__PURE__ */ jsx("div", { className: "text-[11px] uppercase tracking-wide text-muted-foreground", children: t("pptx.textProperties.advancedTextHeading") }),
25902
26151
  /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-2", children: BASELINE_TOGGLES.map(([label, baseline]) => /* @__PURE__ */ jsxs("label", { className: "inline-flex items-center gap-2 text-foreground", children: [
@@ -25919,7 +26168,10 @@ function AdvancedTextFormatting({
25919
26168
  {
25920
26169
  type: "color",
25921
26170
  value: normalizeHexColor(ts?.highlightColor, "#ffff00"),
25922
- onChange: (e) => onUpdateTextStyle({ highlightColor: e.target.value }),
26171
+ onChange: (e) => {
26172
+ onUpdateTextStyle({ highlightColor: e.target.value });
26173
+ pushColor(e.target.value);
26174
+ },
25923
26175
  disabled: !canEdit,
25924
26176
  className: COLOR_CLS2
25925
26177
  }
@@ -25950,7 +26202,10 @@ function AdvancedTextFormatting({
25950
26202
  {
25951
26203
  type: "color",
25952
26204
  value: ts?.underlineColor || ts?.color || "#000000",
25953
- onChange: (e) => onUpdateTextStyle({ underlineColor: e.target.value }),
26205
+ onChange: (e) => {
26206
+ onUpdateTextStyle({ underlineColor: e.target.value });
26207
+ pushColor(e.target.value);
26208
+ },
25954
26209
  className: COLOR_CLS2
25955
26210
  }
25956
26211
  )
@@ -25981,7 +26236,10 @@ function AdvancedTextFormatting({
25981
26236
  {
25982
26237
  type: "color",
25983
26238
  value: ts?.textOutlineColor || "#000000",
25984
- onChange: (e) => onUpdateTextStyle({ textOutlineColor: e.target.value }),
26239
+ onChange: (e) => {
26240
+ onUpdateTextStyle({ textOutlineColor: e.target.value });
26241
+ pushColor(e.target.value);
26242
+ },
25985
26243
  className: COLOR_CLS2
25986
26244
  }
25987
26245
  )
@@ -26055,19 +26313,128 @@ function AdvancedTextFormatting({
26055
26313
  ] })
26056
26314
  ] });
26057
26315
  }
26316
+ function TextReflectionSection({
26317
+ ts,
26318
+ onUpdateTextStyle,
26319
+ numChange
26320
+ }) {
26321
+ const { t } = useTranslation();
26322
+ const hasReflection = Boolean(ts?.textReflection);
26323
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
26324
+ /* @__PURE__ */ jsxs("label", { className: "inline-flex items-center gap-2 text-foreground", children: [
26325
+ /* @__PURE__ */ jsx(
26326
+ "input",
26327
+ {
26328
+ type: "checkbox",
26329
+ checked: hasReflection,
26330
+ onChange: (e) => {
26331
+ if (e.target.checked) {
26332
+ onUpdateTextStyle({
26333
+ textReflection: true,
26334
+ textReflectionBlur: 1,
26335
+ textReflectionStartOpacity: 0.5,
26336
+ textReflectionEndOpacity: 0,
26337
+ textReflectionOffset: 3
26338
+ });
26339
+ } else {
26340
+ onUpdateTextStyle({
26341
+ textReflection: void 0,
26342
+ textReflectionBlur: void 0,
26343
+ textReflectionStartOpacity: void 0,
26344
+ textReflectionEndOpacity: void 0,
26345
+ textReflectionOffset: void 0
26346
+ });
26347
+ }
26348
+ }
26349
+ }
26350
+ ),
26351
+ t("pptx.textEffects.reflection")
26352
+ ] }),
26353
+ hasReflection && /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2 pl-4", children: [
26354
+ /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
26355
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Blur" }),
26356
+ /* @__PURE__ */ jsx(
26357
+ "input",
26358
+ {
26359
+ type: "number",
26360
+ min: 0,
26361
+ max: 20,
26362
+ step: 0.5,
26363
+ value: Number(ts?.textReflectionBlur ?? 1).toFixed(1),
26364
+ onChange: numChange((v) => ({
26365
+ textReflectionBlur: Math.max(0, Math.min(20, v))
26366
+ })),
26367
+ className: INPUT_CLS3
26368
+ }
26369
+ )
26370
+ ] }),
26371
+ /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
26372
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Offset" }),
26373
+ /* @__PURE__ */ jsx(
26374
+ "input",
26375
+ {
26376
+ type: "number",
26377
+ min: 0,
26378
+ max: 20,
26379
+ step: 1,
26380
+ value: Math.round(ts?.textReflectionOffset ?? 3),
26381
+ onChange: numChange((v) => ({
26382
+ textReflectionOffset: Math.max(0, Math.min(20, v))
26383
+ })),
26384
+ className: INPUT_CLS3
26385
+ }
26386
+ )
26387
+ ] }),
26388
+ /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
26389
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: t("pptx.textEffects.startOpacity") }),
26390
+ /* @__PURE__ */ jsx(
26391
+ "input",
26392
+ {
26393
+ type: "number",
26394
+ min: 0,
26395
+ max: 1,
26396
+ step: 0.05,
26397
+ value: Number(ts?.textReflectionStartOpacity ?? 0.5).toFixed(2),
26398
+ onChange: numChange((v) => ({
26399
+ textReflectionStartOpacity: Math.max(0, Math.min(1, v))
26400
+ })),
26401
+ className: INPUT_CLS3
26402
+ }
26403
+ )
26404
+ ] }),
26405
+ /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
26406
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: t("pptx.textEffects.endOpacity") }),
26407
+ /* @__PURE__ */ jsx(
26408
+ "input",
26409
+ {
26410
+ type: "number",
26411
+ min: 0,
26412
+ max: 1,
26413
+ step: 0.05,
26414
+ value: Number(ts?.textReflectionEndOpacity ?? 0).toFixed(2),
26415
+ onChange: numChange((v) => ({
26416
+ textReflectionEndOpacity: Math.max(0, Math.min(1, v))
26417
+ })),
26418
+ className: INPUT_CLS3
26419
+ }
26420
+ )
26421
+ ] })
26422
+ ] })
26423
+ ] });
26424
+ }
26058
26425
  function TextEffectsPanel({
26059
26426
  ts,
26060
26427
  onUpdateTextStyle,
26061
26428
  numChange
26062
26429
  }) {
26063
26430
  const { t } = useTranslation();
26431
+ const { pushColor } = useRecentColors();
26064
26432
  const hasShadow = Boolean(
26065
26433
  ts?.textShadowColor || typeof ts?.textShadowBlur === "number" && ts.textShadowBlur > 0
26066
26434
  );
26067
26435
  const hasGlow = Boolean(
26068
26436
  ts?.textGlowColor || typeof ts?.textGlowRadius === "number" && ts.textGlowRadius > 0
26069
26437
  );
26070
- const hasReflection = Boolean(ts?.textReflection);
26071
26438
  return /* @__PURE__ */ jsxs("div", { className: "mt-2 rounded border border-border bg-card p-2 space-y-2", children: [
26072
26439
  /* @__PURE__ */ jsx("div", { className: "text-[11px] uppercase tracking-wide text-muted-foreground", children: t("pptx.textEffects.title") }),
26073
26440
  /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
@@ -26108,7 +26475,10 @@ function TextEffectsPanel({
26108
26475
  {
26109
26476
  type: "color",
26110
26477
  value: normalizeHexColor(ts?.textShadowColor, "#000000"),
26111
- onChange: (e) => onUpdateTextStyle({ textShadowColor: e.target.value }),
26478
+ onChange: (e) => {
26479
+ onUpdateTextStyle({ textShadowColor: e.target.value });
26480
+ pushColor(e.target.value);
26481
+ },
26112
26482
  className: COLOR_CLS2
26113
26483
  }
26114
26484
  )
@@ -26213,7 +26583,10 @@ function TextEffectsPanel({
26213
26583
  {
26214
26584
  type: "color",
26215
26585
  value: normalizeHexColor(ts?.textGlowColor, "#ffff00"),
26216
- onChange: (e) => onUpdateTextStyle({ textGlowColor: e.target.value }),
26586
+ onChange: (e) => {
26587
+ onUpdateTextStyle({ textGlowColor: e.target.value });
26588
+ pushColor(e.target.value);
26589
+ },
26217
26590
  className: COLOR_CLS2
26218
26591
  }
26219
26592
  )
@@ -26254,107 +26627,7 @@ function TextEffectsPanel({
26254
26627
  ] })
26255
26628
  ] })
26256
26629
  ] }),
26257
- /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
26258
- /* @__PURE__ */ jsxs("label", { className: "inline-flex items-center gap-2 text-foreground", children: [
26259
- /* @__PURE__ */ jsx(
26260
- "input",
26261
- {
26262
- type: "checkbox",
26263
- checked: hasReflection,
26264
- onChange: (e) => {
26265
- if (e.target.checked) {
26266
- onUpdateTextStyle({
26267
- textReflection: true,
26268
- textReflectionBlur: 1,
26269
- textReflectionStartOpacity: 0.5,
26270
- textReflectionEndOpacity: 0,
26271
- textReflectionOffset: 3
26272
- });
26273
- } else {
26274
- onUpdateTextStyle({
26275
- textReflection: void 0,
26276
- textReflectionBlur: void 0,
26277
- textReflectionStartOpacity: void 0,
26278
- textReflectionEndOpacity: void 0,
26279
- textReflectionOffset: void 0
26280
- });
26281
- }
26282
- }
26283
- }
26284
- ),
26285
- t("pptx.textEffects.reflection")
26286
- ] }),
26287
- hasReflection && /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2 pl-4", children: [
26288
- /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
26289
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Blur" }),
26290
- /* @__PURE__ */ jsx(
26291
- "input",
26292
- {
26293
- type: "number",
26294
- min: 0,
26295
- max: 20,
26296
- step: 0.5,
26297
- value: Number(ts?.textReflectionBlur ?? 1).toFixed(1),
26298
- onChange: numChange((v) => ({
26299
- textReflectionBlur: Math.max(0, Math.min(20, v))
26300
- })),
26301
- className: INPUT_CLS3
26302
- }
26303
- )
26304
- ] }),
26305
- /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
26306
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Offset" }),
26307
- /* @__PURE__ */ jsx(
26308
- "input",
26309
- {
26310
- type: "number",
26311
- min: 0,
26312
- max: 20,
26313
- step: 1,
26314
- value: Math.round(ts?.textReflectionOffset ?? 3),
26315
- onChange: numChange((v) => ({
26316
- textReflectionOffset: Math.max(0, Math.min(20, v))
26317
- })),
26318
- className: INPUT_CLS3
26319
- }
26320
- )
26321
- ] }),
26322
- /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
26323
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: t("pptx.textEffects.startOpacity") }),
26324
- /* @__PURE__ */ jsx(
26325
- "input",
26326
- {
26327
- type: "number",
26328
- min: 0,
26329
- max: 1,
26330
- step: 0.05,
26331
- value: Number(ts?.textReflectionStartOpacity ?? 0.5).toFixed(2),
26332
- onChange: numChange((v) => ({
26333
- textReflectionStartOpacity: Math.max(0, Math.min(1, v))
26334
- })),
26335
- className: INPUT_CLS3
26336
- }
26337
- )
26338
- ] }),
26339
- /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
26340
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: t("pptx.textEffects.endOpacity") }),
26341
- /* @__PURE__ */ jsx(
26342
- "input",
26343
- {
26344
- type: "number",
26345
- min: 0,
26346
- max: 1,
26347
- step: 0.05,
26348
- value: Number(ts?.textReflectionEndOpacity ?? 0).toFixed(2),
26349
- onChange: numChange((v) => ({
26350
- textReflectionEndOpacity: Math.max(0, Math.min(1, v))
26351
- })),
26352
- className: INPUT_CLS3
26353
- }
26354
- )
26355
- ] })
26356
- ] })
26357
- ] })
26630
+ /* @__PURE__ */ jsx(TextReflectionSection, { ts, onUpdateTextStyle, numChange })
26358
26631
  ] });
26359
26632
  }
26360
26633
  function TextWarpGallery({
@@ -26428,7 +26701,6 @@ function TextAdvancedSections({
26428
26701
  /* @__PURE__ */ jsx(Text3DProperties, { ts, onUpdateTextStyle })
26429
26702
  ] });
26430
26703
  }
26431
- var EMPTY_RECENT_COLORS = [];
26432
26704
  function ShapeTextPanels({
26433
26705
  selectedElement,
26434
26706
  canEdit,
@@ -26464,7 +26736,6 @@ function ShapeTextPanels({
26464
26736
  selectedGradientStops: sanitizeGradientStops(
26465
26737
  selectedElement.shapeStyle?.fillGradientStops
26466
26738
  ),
26467
- recentColors: EMPTY_RECENT_COLORS,
26468
26739
  canEdit,
26469
26740
  onUpdateShapeStyle: onUpdateElementStyle,
26470
26741
  onSetFillColor: (hex) => onUpdateElementStyle({ fillColor: hex, fillMode: "solid" }),
@@ -26472,7 +26743,7 @@ function ShapeTextPanels({
26472
26743
  }
26473
26744
  )
26474
26745
  ] }),
26475
- hasTextProperties(selectedElement) && /* @__PURE__ */ jsxs("div", { className: CARD, children: [
26746
+ hasTextProperties(selectedElement) && /* @__PURE__ */ jsxs("div", { className: CARD, "data-pptx-text-card": true, children: [
26476
26747
  /* @__PURE__ */ jsx("div", { className: HEADING, children: t("pptx.text.title", "Text") }),
26477
26748
  /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-1.5 text-[11px]", children: [
26478
26749
  /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
@@ -26496,12 +26767,21 @@ function ShapeTextPanels({
26496
26767
  DebouncedColorInput,
26497
26768
  {
26498
26769
  disabled: !canEdit,
26770
+ ariaLabel: "Text Color",
26499
26771
  value: normalizeHexColor(selectedElement.textStyle?.color, "#000000"),
26500
26772
  className: "w-full h-7 rounded border border-border bg-transparent cursor-pointer",
26501
26773
  onCommit: (hex) => onUpdateTextStyle({ color: hex })
26502
26774
  }
26503
26775
  )
26504
26776
  ] }),
26777
+ /* @__PURE__ */ jsx("div", { className: "col-span-2", children: /* @__PURE__ */ jsx(
26778
+ RecentColorsRow,
26779
+ {
26780
+ prefix: "text-color",
26781
+ disabled: !canEdit,
26782
+ onCommit: (hex) => onUpdateTextStyle({ color: hex })
26783
+ }
26784
+ ) }),
26505
26785
  /* @__PURE__ */ jsxs("div", { className: "flex gap-1 col-span-2", children: [
26506
26786
  /* @__PURE__ */ jsx(
26507
26787
  TextFormatToggle,
@@ -26784,6 +27064,7 @@ function SmartArtNodeStyleControls({
26784
27064
  canEdit,
26785
27065
  onChangeStyle
26786
27066
  }) {
27067
+ const { pushColor } = useRecentColors();
26787
27068
  const bold = Boolean(style?.bold);
26788
27069
  const italic = Boolean(style?.italic);
26789
27070
  return /* @__PURE__ */ jsxs(
@@ -26803,7 +27084,10 @@ function SmartArtNodeStyleControls({
26803
27084
  "aria-label": `Fill colour for ${label}`,
26804
27085
  className: "h-4 w-5 cursor-pointer rounded border border-border bg-transparent p-0 disabled:cursor-not-allowed",
26805
27086
  value: style?.fillColor ?? DEFAULT_FILL,
26806
- onChange: (e) => onChangeStyle(nodeId, { fillColor: e.target.value })
27087
+ onChange: (e) => {
27088
+ onChangeStyle(nodeId, { fillColor: e.target.value });
27089
+ pushColor(e.target.value);
27090
+ }
26807
27091
  }
26808
27092
  )
26809
27093
  ] }),
@@ -26817,7 +27101,10 @@ function SmartArtNodeStyleControls({
26817
27101
  "aria-label": `Font colour for ${label}`,
26818
27102
  className: "h-4 w-5 cursor-pointer rounded border border-border bg-transparent p-0 disabled:cursor-not-allowed",
26819
27103
  value: style?.fontColor ?? DEFAULT_FONT,
26820
- onChange: (e) => onChangeStyle(nodeId, { fontColor: e.target.value })
27104
+ onChange: (e) => {
27105
+ onChangeStyle(nodeId, { fontColor: e.target.value });
27106
+ pushColor(e.target.value);
27107
+ }
26821
27108
  }
26822
27109
  )
26823
27110
  ] }),
@@ -27381,6 +27668,7 @@ function TableCellPatternFill({
27381
27668
  onUpdateCellStyle
27382
27669
  }) {
27383
27670
  const { t } = useTranslation();
27671
+ const { pushColor } = useRecentColors();
27384
27672
  const translate = (key) => t(key);
27385
27673
  return /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
27386
27674
  /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-0.5", children: [
@@ -27407,7 +27695,10 @@ function TableCellPatternFill({
27407
27695
  disabled: !canEdit,
27408
27696
  className: "w-full h-7 rounded border border-border bg-transparent cursor-pointer",
27409
27697
  value: cellStyle.patternFillForeground ?? "#000000",
27410
- onChange: (e) => onUpdateCellStyle({ patternFillForeground: e.target.value })
27698
+ onChange: (e) => {
27699
+ onUpdateCellStyle({ patternFillForeground: e.target.value });
27700
+ pushColor(e.target.value);
27701
+ }
27411
27702
  }
27412
27703
  )
27413
27704
  ] }),
@@ -27420,7 +27711,10 @@ function TableCellPatternFill({
27420
27711
  disabled: !canEdit,
27421
27712
  className: "w-full h-7 rounded border border-border bg-transparent cursor-pointer",
27422
27713
  value: cellStyle.patternFillBackground ?? "#FFFFFF",
27423
- onChange: (e) => onUpdateCellStyle({ patternFillBackground: e.target.value })
27714
+ onChange: (e) => {
27715
+ onUpdateCellStyle({ patternFillBackground: e.target.value });
27716
+ pushColor(e.target.value);
27717
+ }
27424
27718
  }
27425
27719
  )
27426
27720
  ] })
@@ -27521,6 +27815,7 @@ function GradientControls({
27521
27815
  onUpdateCellStyle
27522
27816
  }) {
27523
27817
  const { t } = useTranslation();
27818
+ const { pushColor } = useRecentColors();
27524
27819
  const stops = cellStyle.gradientFillStops ?? [];
27525
27820
  const gradType = cellStyle.gradientFillType ?? "linear";
27526
27821
  const updateStop = (index, patch) => {
@@ -27577,7 +27872,10 @@ function GradientControls({
27577
27872
  disabled: !canEdit,
27578
27873
  className: "h-6 w-6 rounded border border-border cursor-pointer",
27579
27874
  value: stop.color,
27580
- onChange: (e) => updateStop(idx, { color: e.target.value })
27875
+ onChange: (e) => {
27876
+ updateStop(idx, { color: e.target.value });
27877
+ pushColor(e.target.value);
27878
+ }
27581
27879
  }
27582
27880
  ),
27583
27881
  /* @__PURE__ */ jsx(
@@ -28022,6 +28320,7 @@ function ElementInspectorBody({
28022
28320
  selectedElement,
28023
28321
  canEdit,
28024
28322
  slides,
28323
+ customShows,
28025
28324
  tableEditorState,
28026
28325
  mediaDataUrls,
28027
28326
  onUpdateElement,
@@ -28156,6 +28455,7 @@ function ElementInspectorBody({
28156
28455
  selectedElement,
28157
28456
  slides,
28158
28457
  canEdit,
28458
+ customShows,
28159
28459
  onUpdateElement
28160
28460
  }
28161
28461
  ),
@@ -28170,6 +28470,122 @@ function ElementInspectorBody({
28170
28470
  /* @__PURE__ */ jsx(LayerOrderButtons, { canEdit, onMoveLayer })
28171
28471
  ] });
28172
28472
  }
28473
+ function CommentMentionTextarea({
28474
+ value,
28475
+ mentions,
28476
+ authors,
28477
+ onChange,
28478
+ onSubmitShortcut,
28479
+ placeholder,
28480
+ rows = 2,
28481
+ className,
28482
+ ariaLabel
28483
+ }) {
28484
+ const { t } = useTranslation();
28485
+ const textareaRef = useRef(null);
28486
+ const [caret, setCaret] = useState(value.length);
28487
+ const [highlighted, setHighlighted] = useState(0);
28488
+ const [dismissedAt, setDismissedAt] = useState(null);
28489
+ const query = useMemo(() => commentMentionQuery(value, caret), [value, caret]);
28490
+ const activeQuery = query && query.start !== dismissedAt ? query : null;
28491
+ const matches = useMemo(
28492
+ () => activeQuery ? matchCommentMentionAuthors(authors, activeQuery.query) : [],
28493
+ [activeQuery, authors]
28494
+ );
28495
+ const safeHighlighted = matches.length > 0 ? highlighted % matches.length : 0;
28496
+ const syncCaret = (target) => {
28497
+ setCaret(target.selectionStart ?? target.value.length);
28498
+ setHighlighted(0);
28499
+ };
28500
+ const acceptAuthor = (author) => {
28501
+ const result = insertCommentMention(value, mentions, caret, author);
28502
+ onChange(result.text, result.mentions);
28503
+ setCaret(result.caret);
28504
+ setDismissedAt(null);
28505
+ requestAnimationFrame(() => {
28506
+ textareaRef.current?.setSelectionRange(result.caret, result.caret);
28507
+ textareaRef.current?.focus();
28508
+ });
28509
+ };
28510
+ const handleChange = (event) => {
28511
+ onChange(event.target.value, mentions);
28512
+ syncCaret(event.target);
28513
+ };
28514
+ const handleKeyDown = (event) => {
28515
+ if (matches.length > 0) {
28516
+ if (event.key === "ArrowDown") {
28517
+ event.preventDefault();
28518
+ setHighlighted((index) => (index + 1) % matches.length);
28519
+ return;
28520
+ }
28521
+ if (event.key === "ArrowUp") {
28522
+ event.preventDefault();
28523
+ setHighlighted((index) => (index - 1 + matches.length) % matches.length);
28524
+ return;
28525
+ }
28526
+ if (event.key === "Enter" || event.key === "Tab") {
28527
+ event.preventDefault();
28528
+ acceptAuthor(matches[safeHighlighted]);
28529
+ return;
28530
+ }
28531
+ if (event.key === "Escape") {
28532
+ event.preventDefault();
28533
+ setDismissedAt(activeQuery?.start ?? null);
28534
+ return;
28535
+ }
28536
+ }
28537
+ if (onSubmitShortcut && event.key === "Enter" && (event.metaKey || event.ctrlKey)) {
28538
+ event.preventDefault();
28539
+ onSubmitShortcut();
28540
+ }
28541
+ };
28542
+ return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
28543
+ /* @__PURE__ */ jsx(
28544
+ "textarea",
28545
+ {
28546
+ ref: textareaRef,
28547
+ "aria-label": ariaLabel,
28548
+ rows,
28549
+ placeholder: placeholder ?? t("pptx.comments.mentionPlaceholder"),
28550
+ value,
28551
+ className,
28552
+ onChange: handleChange,
28553
+ onSelect: (event) => syncCaret(event.currentTarget),
28554
+ onClick: (event) => syncCaret(event.currentTarget),
28555
+ onKeyDown: handleKeyDown,
28556
+ onKeyUp: (event) => syncCaret(event.currentTarget)
28557
+ }
28558
+ ),
28559
+ activeQuery && matches.length > 0 && /* @__PURE__ */ jsx(
28560
+ "div",
28561
+ {
28562
+ "data-testid": "pptx-comment-mention-suggestions",
28563
+ role: "listbox",
28564
+ "aria-label": t("pptx.comments.mentionSuggestions"),
28565
+ className: "absolute z-10 mt-0.5 max-h-40 w-full overflow-y-auto rounded border border-border bg-popover shadow-lg",
28566
+ children: matches.map((author, index) => /* @__PURE__ */ jsx(
28567
+ "button",
28568
+ {
28569
+ type: "button",
28570
+ "data-testid": "pptx-comment-mention-option",
28571
+ role: "option",
28572
+ "aria-selected": index === safeHighlighted,
28573
+ className: cn(
28574
+ "block w-full px-2 py-1 text-left text-[11px] hover:bg-accent",
28575
+ index === safeHighlighted && "bg-accent"
28576
+ ),
28577
+ onMouseDown: (event) => {
28578
+ event.preventDefault();
28579
+ acceptAuthor(author);
28580
+ },
28581
+ children: author.name
28582
+ },
28583
+ author.id
28584
+ ))
28585
+ }
28586
+ )
28587
+ ] });
28588
+ }
28173
28589
  function CommentBody({ text, mentions, className }) {
28174
28590
  const segments = commentTextSegments(text, mentions);
28175
28591
  if (!segments.some((segment) => segment.kind === "mention")) {
@@ -28191,6 +28607,59 @@ function CommentBody({ text, mentions, className }) {
28191
28607
  )
28192
28608
  ) });
28193
28609
  }
28610
+ function InspectorCommentReplyForm({
28611
+ commentId,
28612
+ authorName,
28613
+ draft,
28614
+ mentions,
28615
+ authors,
28616
+ onDraftChange,
28617
+ onSubmit,
28618
+ onCancel
28619
+ }) {
28620
+ const { t } = useTranslation();
28621
+ return /* @__PURE__ */ jsxs("div", { className: "mt-2 space-y-1.5 pl-3 border-l-2 border-l-primary/40", children: [
28622
+ /* @__PURE__ */ jsx(
28623
+ CommentMentionTextarea,
28624
+ {
28625
+ value: draft,
28626
+ mentions,
28627
+ authors,
28628
+ rows: 2,
28629
+ placeholder: t("pptx.comments.replyPlaceholder", { author: authorName || "Author" }),
28630
+ className: "w-full rounded border border-border bg-background px-2 py-1.5 text-xs text-foreground outline-none focus:border-primary resize-y",
28631
+ onChange: (text, next) => onDraftChange(commentId, text, next),
28632
+ onSubmitShortcut: () => onSubmit(commentId)
28633
+ }
28634
+ ),
28635
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
28636
+ /* @__PURE__ */ jsxs(
28637
+ "button",
28638
+ {
28639
+ type: "button",
28640
+ className: "inline-flex items-center gap-1 rounded bg-primary px-2 py-1 text-[11px] text-white hover:bg-primary/80 disabled:opacity-40 disabled:cursor-not-allowed",
28641
+ onClick: () => onSubmit(commentId),
28642
+ disabled: draft.trim().length === 0,
28643
+ children: [
28644
+ /* @__PURE__ */ jsx(LuReply, { className: "h-3 w-3" }),
28645
+ t("pptx.comments.addReply")
28646
+ ]
28647
+ }
28648
+ ),
28649
+ /* @__PURE__ */ jsx(
28650
+ "button",
28651
+ {
28652
+ type: "button",
28653
+ className: "inline-flex items-center gap-1 rounded bg-muted px-2 py-1 text-[11px] text-foreground hover:bg-accent",
28654
+ onClick: onCancel,
28655
+ children: t("pptx.comments.cancel")
28656
+ }
28657
+ )
28658
+ ] })
28659
+ ] });
28660
+ }
28661
+ var EMPTY_REPLY_MENTIONS = {};
28662
+ var EMPTY_AUTHORS = [];
28194
28663
  function InspectorCommentRow({
28195
28664
  comment,
28196
28665
  canEdit,
@@ -28199,6 +28668,8 @@ function InspectorCommentRow({
28199
28668
  commentEditDraft,
28200
28669
  replyingToCommentId,
28201
28670
  replyDraftByCommentId,
28671
+ replyDraftMentionsByCommentId = EMPTY_REPLY_MENTIONS,
28672
+ commentAuthors = EMPTY_AUTHORS,
28202
28673
  onStartEditComment,
28203
28674
  onSaveEditComment,
28204
28675
  onCancelEditComment,
@@ -28361,6 +28832,8 @@ function InspectorCommentRow({
28361
28832
  commentEditDraft,
28362
28833
  replyingToCommentId,
28363
28834
  replyDraftByCommentId,
28835
+ replyDraftMentionsByCommentId,
28836
+ commentAuthors,
28364
28837
  onStartEditComment,
28365
28838
  onSaveEditComment,
28366
28839
  onCancelEditComment,
@@ -28377,50 +28850,19 @@ function InspectorCommentRow({
28377
28850
  `${reply.id}-${ri}`
28378
28851
  )) })
28379
28852
  ] }),
28380
- isReplying && onCancelReply && onReplyDraftChange && onSubmitReply && /* @__PURE__ */ jsxs("div", { className: "mt-2 space-y-1.5 pl-3 border-l-2 border-l-primary/40", children: [
28381
- /* @__PURE__ */ jsx(
28382
- "textarea",
28383
- {
28384
- value: replyDraft,
28385
- onChange: (e) => onReplyDraftChange(comment.id, e.target.value),
28386
- rows: 2,
28387
- placeholder: t("pptx.comments.replyPlaceholder", {
28388
- author: comment.author || "Author"
28389
- }),
28390
- className: "w-full rounded border border-border bg-background px-2 py-1.5 text-xs text-foreground outline-none focus:border-primary resize-y",
28391
- onKeyDown: (e) => {
28392
- if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
28393
- e.preventDefault();
28394
- onSubmitReply(comment.id);
28395
- }
28396
- }
28397
- }
28398
- ),
28399
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
28400
- /* @__PURE__ */ jsxs(
28401
- "button",
28402
- {
28403
- type: "button",
28404
- className: "inline-flex items-center gap-1 rounded bg-primary px-2 py-1 text-[11px] text-white hover:bg-primary/80 disabled:opacity-40 disabled:cursor-not-allowed",
28405
- onClick: () => onSubmitReply(comment.id),
28406
- disabled: replyDraft.trim().length === 0,
28407
- children: [
28408
- /* @__PURE__ */ jsx(LuReply, { className: "h-3 w-3" }),
28409
- t("pptx.comments.addReply")
28410
- ]
28411
- }
28412
- ),
28413
- /* @__PURE__ */ jsx(
28414
- "button",
28415
- {
28416
- type: "button",
28417
- className: "inline-flex items-center gap-1 rounded bg-muted px-2 py-1 text-[11px] text-foreground hover:bg-accent",
28418
- onClick: onCancelReply,
28419
- children: t("pptx.comments.cancel")
28420
- }
28421
- )
28422
- ] })
28423
- ] })
28853
+ isReplying && onCancelReply && onReplyDraftChange && onSubmitReply && /* @__PURE__ */ jsx(
28854
+ InspectorCommentReplyForm,
28855
+ {
28856
+ commentId: comment.id,
28857
+ authorName: comment.author ?? "",
28858
+ draft: replyDraft,
28859
+ mentions: replyDraftMentionsByCommentId[comment.id] ?? [],
28860
+ authors: commentAuthors,
28861
+ onDraftChange: onReplyDraftChange,
28862
+ onSubmit: onSubmitReply,
28863
+ onCancel: onCancelReply
28864
+ }
28865
+ )
28424
28866
  ]
28425
28867
  }
28426
28868
  );
@@ -28433,8 +28875,11 @@ function InspectorCommentsSection({
28433
28875
  editingCommentId,
28434
28876
  commentEditDraft,
28435
28877
  commentDraft,
28878
+ commentDraftMentions,
28879
+ commentAuthors,
28436
28880
  replyingToCommentId,
28437
28881
  replyDraftByCommentId,
28882
+ replyDraftMentionsByCommentId,
28438
28883
  onSetCommentDraft,
28439
28884
  onAddComment,
28440
28885
  onDeleteComment,
@@ -28466,6 +28911,8 @@ function InspectorCommentsSection({
28466
28911
  commentEditDraft,
28467
28912
  replyingToCommentId,
28468
28913
  replyDraftByCommentId,
28914
+ replyDraftMentionsByCommentId,
28915
+ commentAuthors,
28469
28916
  onStartEditComment,
28470
28917
  onSaveEditComment,
28471
28918
  onCancelEditComment,
@@ -28488,21 +28935,18 @@ function InspectorCommentsSection({
28488
28935
  })
28489
28936
  ] }),
28490
28937
  /* @__PURE__ */ jsx(
28491
- "textarea",
28938
+ CommentMentionTextarea,
28492
28939
  {
28940
+ value: commentDraft,
28941
+ mentions: commentDraftMentions,
28942
+ authors: commentAuthors,
28493
28943
  rows: 2,
28494
28944
  placeholder: selectedElement ? t("pptx.comments.addOnElement", {
28495
28945
  element: getElementLabel(selectedElement)
28496
28946
  }) : t("pptx.comments.addPlaceholder"),
28497
- value: commentDraft,
28498
28947
  className: "w-full bg-muted border border-border rounded px-2 py-1 text-xs resize-y outline-none focus:border-primary",
28499
- onChange: (e) => onSetCommentDraft(e.target.value),
28500
- onKeyDown: (e) => {
28501
- if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
28502
- e.preventDefault();
28503
- onAddComment();
28504
- }
28505
- }
28948
+ onChange: onSetCommentDraft,
28949
+ onSubmitShortcut: onAddComment
28506
28950
  }
28507
28951
  ),
28508
28952
  /* @__PURE__ */ jsxs(
@@ -28819,26 +29263,78 @@ function DocumentPropertiesCard({
28819
29263
  ] })
28820
29264
  ] });
28821
29265
  }
29266
+ function SlideSizeRescalePrompt({
29267
+ onChoose
29268
+ }) {
29269
+ const { t } = useTranslation();
29270
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-1.5 rounded border border-border bg-muted/40 p-2 text-[11px]", children: [
29271
+ /* @__PURE__ */ jsx("div", { className: "font-medium", children: t("pptx.slideSize.rescaleTitle") }),
29272
+ /* @__PURE__ */ jsx("div", { className: "text-muted-foreground", children: t("pptx.slideSize.rescaleDescription") }),
29273
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-1.5 pt-1", children: [
29274
+ /* @__PURE__ */ jsx(
29275
+ "button",
29276
+ {
29277
+ type: "button",
29278
+ "data-testid": "pptx-slide-size-rescale-maximize",
29279
+ title: t("pptx.slideSize.rescaleMaximizeHint"),
29280
+ className: "rounded bg-primary px-2 py-1 text-primary-foreground transition-colors hover:opacity-90",
29281
+ onClick: () => onChoose("maximize"),
29282
+ children: t("pptx.slideSize.rescaleMaximize")
29283
+ }
29284
+ ),
29285
+ /* @__PURE__ */ jsx(
29286
+ "button",
29287
+ {
29288
+ type: "button",
29289
+ "data-testid": "pptx-slide-size-rescale-ensure-fit",
29290
+ title: t("pptx.slideSize.rescaleEnsureFitHint"),
29291
+ className: "rounded bg-muted px-2 py-1 transition-colors hover:bg-accent",
29292
+ onClick: () => onChoose("ensureFit"),
29293
+ children: t("pptx.slideSize.rescaleEnsureFit")
29294
+ }
29295
+ )
29296
+ ] })
29297
+ ] });
29298
+ }
28822
29299
  var CUSTOM_PRESET_VALUE = "";
29300
+ function sizesDiffer(a, b) {
29301
+ return a.widthEmu !== b.widthEmu || a.heightEmu !== b.heightEmu;
29302
+ }
28823
29303
  function SlideSizeCard({
28824
29304
  canvasSize,
28825
29305
  slideSizeEmu,
28826
29306
  canEdit,
28827
29307
  onUpdate,
28828
- onUpdateSlideSize
29308
+ onUpdateSlideSize,
29309
+ hasContent
28829
29310
  }) {
28830
29311
  const { t } = useTranslation();
28831
29312
  const selection = resolveSlideSizeSelection({ current: slideSizeEmu, canvas: canvasSize });
28832
29313
  const presetDisabled = !canEdit || !onUpdateSlideSize;
29314
+ const [pendingSize, setPendingSize] = useState(null);
29315
+ const applyOrPromptSize = (nextSize) => {
29316
+ if (hasContent && sizesDiffer(selection.size, nextSize)) {
29317
+ setPendingSize(nextSize);
29318
+ return;
29319
+ }
29320
+ onUpdateSlideSize?.(nextSize);
29321
+ };
28833
29322
  const handlePreset = (labelKey) => {
28834
29323
  const preset = SLIDE_SIZE_PRESETS.find((candidate) => candidate.labelKey === labelKey);
28835
29324
  if (!preset) {
28836
29325
  return;
28837
29326
  }
28838
- onUpdateSlideSize?.(slideSizeFromPreset(preset, selection.orientation));
29327
+ applyOrPromptSize(slideSizeFromPreset(preset, selection.orientation));
28839
29328
  };
28840
29329
  const handleOrientation = (orientation) => {
28841
- onUpdateSlideSize?.(withSlideSizeOrientation(selection.size, orientation));
29330
+ applyOrPromptSize(withSlideSizeOrientation(selection.size, orientation));
29331
+ };
29332
+ const handleRescale = (mode) => {
29333
+ if (!pendingSize) {
29334
+ return;
29335
+ }
29336
+ onUpdateSlideSize?.(pendingSize, mode);
29337
+ setPendingSize(null);
28842
29338
  };
28843
29339
  return /* @__PURE__ */ jsxs("div", { className: CARD, children: [
28844
29340
  /* @__PURE__ */ jsx("div", { className: HEADING, children: t("pptx.slideSize.title") }),
@@ -28894,7 +29390,8 @@ function SlideSizeCard({
28894
29390
  onChange: (e) => onUpdate({ ...canvasSize, [key]: Number(e.target.value) })
28895
29391
  }
28896
29392
  )
28897
- ] }, key)) })
29393
+ ] }, key)) }),
29394
+ pendingSize && /* @__PURE__ */ jsx(SlideSizeRescalePrompt, { onChoose: handleRescale })
28898
29395
  ] })
28899
29396
  ] });
28900
29397
  }
@@ -29553,6 +30050,7 @@ function PresentationPropertiesPanel({
29553
30050
  onUpdateCanvasSize,
29554
30051
  slideSizeEmu,
29555
30052
  onUpdateSlideSize,
30053
+ hasContent,
29556
30054
  notesCanvasSize,
29557
30055
  notesMaster,
29558
30056
  handoutMaster,
@@ -29612,7 +30110,8 @@ function PresentationPropertiesPanel({
29612
30110
  slideSizeEmu,
29613
30111
  canEdit,
29614
30112
  onUpdate: onUpdateCanvasSize,
29615
- onUpdateSlideSize
30113
+ onUpdateSlideSize,
30114
+ hasContent
29616
30115
  }
29617
30116
  ),
29618
30117
  /* @__PURE__ */ jsx(
@@ -29853,6 +30352,7 @@ function InspectorPane(props) {
29853
30352
  canEdit,
29854
30353
  activeSlide,
29855
30354
  slides,
30355
+ customShows,
29856
30356
  canvasSize,
29857
30357
  selectedElement,
29858
30358
  selectedElementIds,
@@ -29880,6 +30380,8 @@ function InspectorPane(props) {
29880
30380
  onApplyTheme,
29881
30381
  comments,
29882
30382
  commentDraft,
30383
+ commentDraftMentions,
30384
+ commentAuthors,
29883
30385
  editingCommentId,
29884
30386
  commentEditDraft,
29885
30387
  onSetCommentDraft,
@@ -29896,6 +30398,7 @@ function InspectorPane(props) {
29896
30398
  onSubmitReply,
29897
30399
  replyingToCommentId,
29898
30400
  replyDraftByCommentId,
30401
+ replyDraftMentionsByCommentId,
29899
30402
  onUpdateCanvasSize,
29900
30403
  slideSizeEmu,
29901
30404
  onUpdateSlideSize,
@@ -29987,6 +30490,7 @@ function InspectorPane(props) {
29987
30490
  selectedElement,
29988
30491
  canEdit,
29989
30492
  slides,
30493
+ customShows,
29990
30494
  tableEditorState,
29991
30495
  mediaDataUrls,
29992
30496
  onUpdateElement,
@@ -30020,6 +30524,7 @@ function InspectorPane(props) {
30020
30524
  onUpdateCanvasSize,
30021
30525
  slideSizeEmu,
30022
30526
  onUpdateSlideSize,
30527
+ hasContent: slides.some((slide) => slide.elements.length > 0),
30023
30528
  activeSlide,
30024
30529
  theme,
30025
30530
  onUpdateSlide
@@ -30048,8 +30553,11 @@ function InspectorPane(props) {
30048
30553
  editingCommentId,
30049
30554
  commentEditDraft,
30050
30555
  commentDraft,
30556
+ commentDraftMentions: commentDraftMentions ?? [],
30557
+ commentAuthors: commentAuthors ?? [],
30051
30558
  replyingToCommentId: replyingToCommentId ?? null,
30052
30559
  replyDraftByCommentId: replyDraftByCommentId ?? {},
30560
+ replyDraftMentionsByCommentId: replyDraftMentionsByCommentId ?? {},
30053
30561
  onSetCommentDraft,
30054
30562
  onAddComment,
30055
30563
  onDeleteComment,
@@ -30090,32 +30598,6 @@ function InspectorPane(props) {
30090
30598
  )
30091
30599
  ] });
30092
30600
  }
30093
- function buildPathD(points) {
30094
- if (points.length === 0) {
30095
- return "";
30096
- }
30097
- const first = points[0];
30098
- let d = `M ${first.x} ${first.y}`;
30099
- for (let i = 1; i < points.length; i++) {
30100
- const pt = points[i];
30101
- d += ` L ${pt.x} ${pt.y}`;
30102
- }
30103
- return d;
30104
- }
30105
- function getCursorForTool(tool) {
30106
- switch (tool) {
30107
- case "laser":
30108
- return "none";
30109
- case "pen":
30110
- return "crosshair";
30111
- case "highlighter":
30112
- return "crosshair";
30113
- case "eraser":
30114
- return "crosshair";
30115
- default:
30116
- return "default";
30117
- }
30118
- }
30119
30601
  function PresentationAnnotationOverlay({
30120
30602
  canvasSize,
30121
30603
  editorScale,
@@ -30226,7 +30708,7 @@ function PresentationAnnotationOverlay({
30226
30708
  className: "absolute inset-0",
30227
30709
  style: {
30228
30710
  zIndex: annotationOverlayZIndex(blackout),
30229
- cursor: getCursorForTool(presentationTool),
30711
+ cursor: cursorForTool(presentationTool),
30230
30712
  pointerEvents: isCapturing ? "auto" : "none"
30231
30713
  },
30232
30714
  children: [
@@ -30249,7 +30731,7 @@ function PresentationAnnotationOverlay({
30249
30731
  children: allStrokes.map((stroke) => /* @__PURE__ */ jsx(
30250
30732
  "path",
30251
30733
  {
30252
- d: buildPathD(stroke.points),
30734
+ d: buildStrokePathD(stroke.points),
30253
30735
  fill: "none",
30254
30736
  stroke: stroke.color,
30255
30737
  strokeWidth: stroke.width,
@@ -33127,6 +33609,7 @@ function ViewerInspector({
33127
33609
  mode,
33128
33610
  activeSlide,
33129
33611
  slides,
33612
+ customShows,
33130
33613
  canvasSize,
33131
33614
  selectedElement,
33132
33615
  effectiveSelectedIds,
@@ -33134,6 +33617,7 @@ function ViewerInspector({
33134
33617
  sidebarPanelMode,
33135
33618
  activeSlideIndex,
33136
33619
  comments,
33620
+ commentAuthors,
33137
33621
  onSetSidebarPanelMode,
33138
33622
  onClose,
33139
33623
  onUpdateElementStyle,
@@ -33193,6 +33677,7 @@ function ViewerInspector({
33193
33677
  mode,
33194
33678
  activeSlide,
33195
33679
  slides,
33680
+ customShows,
33196
33681
  canvasSize,
33197
33682
  selectedElement,
33198
33683
  selectedElementIds: effectiveSelectedIds,
@@ -33225,9 +33710,11 @@ function ViewerInspector({
33225
33710
  onUpdateTagCollections,
33226
33711
  onApplyTheme,
33227
33712
  commentDraft,
33713
+ commentDraftMentions: comments.commentDraftMentionsBySlideId?.[slideId] ?? [],
33714
+ commentAuthors: commentAuthors ?? [],
33228
33715
  editingCommentId,
33229
33716
  commentEditDraft: editingCommentId ? comments.commentEditDraftByCommentId[editingCommentId] ?? "" : "",
33230
- onSetCommentDraft: (draft) => comments.handleCommentDraftChange(slideId, draft),
33717
+ onSetCommentDraft: (draft, mentions) => comments.handleCommentDraftChange(slideId, draft, mentions),
33231
33718
  onAddComment: () => comments.handleAddSlideComment(activeSlideIndex),
33232
33719
  onDeleteComment: (id) => comments.handleDeleteSlideComment(activeSlideIndex, id),
33233
33720
  onStartEditComment: (id) => comments.handleStartCommentEdit(slideId, id),
@@ -33240,10 +33727,11 @@ function ViewerInspector({
33240
33727
  onToggleCommentResolved: (id) => comments.handleToggleCommentResolved(activeSlideIndex, id),
33241
33728
  onStartReply: (id) => comments.handleStartReply(activeSlideIndex, id),
33242
33729
  onCancelReply: comments.handleCancelReply,
33243
- onReplyDraftChange: (commentId, draft) => comments.handleReplyDraftChange(commentId, draft),
33730
+ onReplyDraftChange: (commentId, draft, mentions) => comments.handleReplyDraftChange(commentId, draft, mentions),
33244
33731
  onSubmitReply: (commentId) => comments.handleSubmitReply(activeSlideIndex, commentId),
33245
33732
  replyingToCommentId: comments.replyingToCommentId,
33246
33733
  replyDraftByCommentId: comments.replyDraftByCommentId,
33734
+ replyDraftMentionsByCommentId: comments.replyDraftMentionsByCommentId,
33247
33735
  onUpdateCanvasSize: onSetCanvasSize,
33248
33736
  slideSizeEmu,
33249
33737
  onUpdateSlideSize: onSetSlideSize,
@@ -33487,6 +33975,7 @@ function ViewerToolbarSection(props) {
33487
33975
  customFontFamilies,
33488
33976
  ops,
33489
33977
  onSetMode,
33978
+ onPresentFromBeginning,
33490
33979
  onEnterPresenterView,
33491
33980
  onEnterRehearsalMode,
33492
33981
  onOpenSettings,
@@ -33505,7 +33994,10 @@ function ViewerToolbarSection(props) {
33505
33994
  isAiPanelOpen,
33506
33995
  onToggleAiPanel,
33507
33996
  isProtectedView,
33508
- onEnableEditing
33997
+ onEnableEditing,
33998
+ onSetSnapToGrid,
33999
+ onSetSnapToShape,
34000
+ onSetShowGuides
33509
34001
  } = props;
33510
34002
  const { t } = useTranslation();
33511
34003
  const handleAddAnimation = useCallback(
@@ -33682,7 +34174,7 @@ function ViewerToolbarSection(props) {
33682
34174
  case "slideShow":
33683
34175
  switch (action) {
33684
34176
  case "fromBeginning":
33685
- onSetMode("present");
34177
+ (onPresentFromBeginning ?? (() => onSetMode("present")))();
33686
34178
  break;
33687
34179
  case "presenterView":
33688
34180
  onEnterPresenterView();
@@ -33731,6 +34223,7 @@ function ViewerToolbarSection(props) {
33731
34223
  dialogs,
33732
34224
  zoom,
33733
34225
  onSetMode,
34226
+ onPresentFromBeginning,
33734
34227
  onEnterPresenterView,
33735
34228
  manipulation,
33736
34229
  handleOpenSlideSize
@@ -33739,7 +34232,7 @@ function ViewerToolbarSection(props) {
33739
34232
  const handleQuickAccessCommand = useCallback(
33740
34233
  (id) => {
33741
34234
  const handlers = {
33742
- presentFromStart: () => onSetMode("present"),
34235
+ presentFromStart: onPresentFromBeginning ?? (() => onSetMode("present")),
33743
34236
  print: printHandlers.handlePrint,
33744
34237
  exportPdf: exportHandlers.handleExportPdf,
33745
34238
  newSlide: slideOps.handleAddSlide,
@@ -33749,7 +34242,7 @@ function ViewerToolbarSection(props) {
33749
34242
  };
33750
34243
  handlers[id]?.();
33751
34244
  },
33752
- [onSetMode, printHandlers, exportHandlers, slideOps, s, zoom]
34245
+ [onSetMode, onPresentFromBeginning, printHandlers, exportHandlers, slideOps, s, zoom]
33753
34246
  );
33754
34247
  return /* @__PURE__ */ jsxs(Fragment, { children: [
33755
34248
  !dialogs.isNarrowViewport && /* @__PURE__ */ jsx(
@@ -33808,6 +34301,7 @@ function ViewerToolbarSection(props) {
33808
34301
  drawingWidth: s.drawingWidth,
33809
34302
  clipboardPayload: s.clipboardPayload,
33810
34303
  onSetMode,
34304
+ onPresentFromBeginning,
33811
34305
  onToggleSidebar: () => s.setIsSlidesPaneOpen((p) => !p),
33812
34306
  onToggleInspector: () => s.setIsInspectorPaneOpen((p) => !p),
33813
34307
  onOpenAnimationPanel: () => {
@@ -33852,9 +34346,9 @@ function ViewerToolbarSection(props) {
33852
34346
  onSetSpellCheckEnabled: s.setSpellCheckEnabled,
33853
34347
  onSetShowGrid: s.setShowGrid,
33854
34348
  onSetShowRulers: s.setShowRulers,
33855
- onSetShowGuides: s.setShowGuides,
33856
- onSetSnapToGrid: s.setSnapToGrid,
33857
- onSetSnapToShape: s.setSnapToShape,
34349
+ onSetShowGuides: onSetShowGuides ?? s.setShowGuides,
34350
+ onSetSnapToGrid: onSetSnapToGrid ?? s.setSnapToGrid,
34351
+ onSetSnapToShape: onSetSnapToShape ?? s.setSnapToShape,
33858
34352
  onAddGuide: dialogs.handleAddGuide,
33859
34353
  onAlignElements: manipulation.handleAlignElements,
33860
34354
  onDistributeElements: manipulation.handleDistributeElements,
@@ -34209,24 +34703,9 @@ function EquationEditorDialog({
34209
34703
  }
34210
34704
  );
34211
34705
  }
34212
- var PREVIEW_ELEMENT_WIDTH = 600;
34213
- var PREVIEW_ELEMENT_HEIGHT = 340;
34214
34706
  var PREVIEW_TILE_WIDTH2 = 64;
34215
- var FALLBACK_ITEMS = ["1", "2", "3"];
34216
- function buildPreviewElement(layout) {
34217
- const preset = PRESETS.find((p) => p.layout === layout);
34218
- return {
34219
- id: `smartart-preview-${layout}`,
34220
- type: "smartArt",
34221
- x: 0,
34222
- y: 0,
34223
- width: PREVIEW_ELEMENT_WIDTH,
34224
- height: PREVIEW_ELEMENT_HEIGHT,
34225
- smartArtData: buildSmartArtPresetData(layout, preset?.defaultItems ?? FALLBACK_ITEMS)
34226
- };
34227
- }
34228
34707
  function getPreviewForLayout(layout) {
34229
- const scale = PREVIEW_TILE_WIDTH2 / PREVIEW_ELEMENT_WIDTH;
34708
+ const scale = PREVIEW_TILE_WIDTH2 / SMARTART_PREVIEW_ELEMENT_WIDTH;
34230
34709
  return /* @__PURE__ */ jsx(
34231
34710
  "div",
34232
34711
  {
@@ -34234,18 +34713,18 @@ function getPreviewForLayout(layout) {
34234
34713
  className: "overflow-hidden pointer-events-none",
34235
34714
  style: {
34236
34715
  width: PREVIEW_TILE_WIDTH2,
34237
- height: Math.round(PREVIEW_ELEMENT_HEIGHT * scale)
34716
+ height: Math.round(SMARTART_PREVIEW_ELEMENT_HEIGHT * scale)
34238
34717
  },
34239
34718
  children: /* @__PURE__ */ jsx(
34240
34719
  "div",
34241
34720
  {
34242
34721
  style: {
34243
- width: PREVIEW_ELEMENT_WIDTH,
34244
- height: PREVIEW_ELEMENT_HEIGHT,
34722
+ width: SMARTART_PREVIEW_ELEMENT_WIDTH,
34723
+ height: SMARTART_PREVIEW_ELEMENT_HEIGHT,
34245
34724
  transform: `scale(${scale})`,
34246
34725
  transformOrigin: "top left"
34247
34726
  },
34248
- children: /* @__PURE__ */ jsx(SmartArtRenderer, { element: buildPreviewElement(layout) })
34727
+ children: /* @__PURE__ */ jsx(SmartArtRenderer, { element: buildSmartArtPreviewElement(layout) })
34249
34728
  }
34250
34729
  )
34251
34730
  }
@@ -34610,6 +35089,7 @@ function ViewerPresentationLayer(props) {
34610
35089
  templateElements,
34611
35090
  presentation,
34612
35091
  activeCustomShow,
35092
+ authoredRange,
34613
35093
  onExitPresentation,
34614
35094
  isMobile,
34615
35095
  onUpdateNotes
@@ -34623,6 +35103,8 @@ function ViewerPresentationLayer(props) {
34623
35103
  currentSlideIndex: presentation.presentationSlideIndex,
34624
35104
  canvasSize,
34625
35105
  templateElements,
35106
+ activeCustomShow,
35107
+ authoredRange,
34626
35108
  presentationStartTime: presentation.presentationStartTime,
34627
35109
  onMovePresentationSlide: presentation.movePresentationSlide,
34628
35110
  onExit: onExitPresentation
@@ -34635,6 +35117,7 @@ function ViewerPresentationLayer(props) {
34635
35117
  canvasSize,
34636
35118
  templateElements,
34637
35119
  activeCustomShow,
35120
+ authoredRange,
34638
35121
  presentationStartTime: presentation.presentationStartTime,
34639
35122
  onMovePresentationSlide: presentation.movePresentationSlide,
34640
35123
  onExit: onExitPresentation,
@@ -34991,14 +35474,14 @@ ${url}`)) {
34991
35474
  [viewerOptions, t]
34992
35475
  );
34993
35476
  const handleActionClick = useCallback(
34994
- (_elementId, action) => {
35477
+ (elementId, action) => {
34995
35478
  if (mode === "present") {
34996
35479
  const resolved = resolvePresentationAction(action, { slideCount: slides.length });
34997
35480
  if (resolved.intent.kind === "openUrl") {
34998
35481
  openExternalUrl(resolved.intent.url);
34999
35482
  return;
35000
35483
  }
35001
- presentation.handlePresentationAction(action);
35484
+ presentation.handlePresentationAction(action, elementId);
35002
35485
  } else if (action.url) {
35003
35486
  openExternalUrl(action.url);
35004
35487
  }
@@ -35402,7 +35885,7 @@ ${url}`)) {
35402
35885
  var AiChatPanel = lazy(async () => {
35403
35886
  const [{ useChat }, { default: Panel }] = await Promise.all([
35404
35887
  import('@ai-sdk/react'),
35405
- import('./AiChatPanel-C3E7NLX3.mjs')
35888
+ import('./AiChatPanel-NQZBZIRM.mjs')
35406
35889
  ]);
35407
35890
  function BoundAiChatPanel(props) {
35408
35891
  return /* @__PURE__ */ jsx(Panel, { ...props, useChat });
@@ -36309,7 +36792,10 @@ function ViewerSidePanels(props) {
36309
36792
  aiBridge,
36310
36793
  aiPanel
36311
36794
  } = props;
36312
- const handleSetSlideSize = (size) => {
36795
+ const handleSetSlideSize = (size, rescaleMode) => {
36796
+ if (rescaleMode && s.slideSizeEmu) {
36797
+ s.setSlides(scaleSlidesForSizeChange(slides, s.slideSizeEmu, size, rescaleMode));
36798
+ }
36313
36799
  s.setSlideSizeEmu(size);
36314
36800
  s.setCanvasSize(slideSizeToCanvasPx(size));
36315
36801
  history.markDirty();
@@ -36328,6 +36814,7 @@ function ViewerSidePanels(props) {
36328
36814
  mode,
36329
36815
  activeSlide: effectiveSlide,
36330
36816
  slides,
36817
+ customShows: s.customShows,
36331
36818
  canvasSize,
36332
36819
  selectedElement,
36333
36820
  effectiveSelectedIds: s.effectiveSelectedIds,
@@ -36335,6 +36822,7 @@ function ViewerSidePanels(props) {
36335
36822
  sidebarPanelMode: s.sidebarPanelMode,
36336
36823
  activeSlideIndex,
36337
36824
  comments,
36825
+ commentAuthors: s.modernCommentAuthors,
36338
36826
  onSetSidebarPanelMode: s.setSidebarPanelMode,
36339
36827
  onClose: () => s.setIsInspectorPaneOpen(false),
36340
36828
  onUpdateElementStyle: ops.updateSelectedShapeStyle,
@@ -36475,6 +36963,7 @@ function ViewerMainContent(props) {
36475
36963
  themeHandlers,
36476
36964
  history,
36477
36965
  comments,
36966
+ masterViewCrud,
36478
36967
  zoom,
36479
36968
  isMobile: _isMobile = false,
36480
36969
  isTouchDevice: _isTouchDevice = false,
@@ -36559,6 +37048,8 @@ function ViewerMainContent(props) {
36559
37048
  onSelectLayout: dialogs.handleSelectLayout,
36560
37049
  onCollapse: dialogs.handleCloseMasterView,
36561
37050
  onTabChange: state.setMasterViewTab,
37051
+ crudActions: masterViewCrud.crudActions,
37052
+ onCrudAction: masterViewCrud.handleCrudAction,
36562
37053
  onHandoutSlidesPerPageChange: (count) => {
36563
37054
  state.setHandoutSlidesPerPage(count);
36564
37055
  state.setHandoutMaster(
@@ -36752,7 +37243,61 @@ function AutosaveRecoveryDialog({
36752
37243
  }
36753
37244
  );
36754
37245
  }
36755
- function ToggleRow({ checked, onChange, icon, label }) {
37246
+ function CompatibilityToasts({ toasts, onDismiss, onDismissAll }) {
37247
+ const { t } = useTranslation();
37248
+ if (toasts.length === 0) {
37249
+ return null;
37250
+ }
37251
+ return /* @__PURE__ */ jsxs(
37252
+ "div",
37253
+ {
37254
+ "data-testid": "pptx-compat-toasts",
37255
+ className: "max-h-[60%] overflow-y-auto",
37256
+ style: compatToastStackStyle(),
37257
+ children: [
37258
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-1", style: { pointerEvents: "auto" }, children: [
37259
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: t("pptx.compatibility.toastTitle") }),
37260
+ /* @__PURE__ */ jsx(
37261
+ "button",
37262
+ {
37263
+ type: "button",
37264
+ "data-testid": "pptx-compat-toasts-dismiss-all",
37265
+ onClick: onDismissAll,
37266
+ className: "text-[11px] text-muted-foreground underline-offset-2 hover:underline",
37267
+ children: t("pptx.compatibility.dismissAll")
37268
+ }
37269
+ )
37270
+ ] }),
37271
+ toasts.map((toast) => /* @__PURE__ */ jsxs(
37272
+ "div",
37273
+ {
37274
+ "data-testid": "pptx-compat-toast",
37275
+ "data-code": toast.code,
37276
+ "data-severity": toast.severity,
37277
+ className: "flex items-start gap-2 rounded border border-border bg-card p-2 text-[11px] shadow-md",
37278
+ style: { pointerEvents: "auto" },
37279
+ children: [
37280
+ /* @__PURE__ */ jsx("span", { className: "flex-1 min-w-0", children: t(toast.messageKey, toast.params) }),
37281
+ /* @__PURE__ */ jsx(
37282
+ "button",
37283
+ {
37284
+ type: "button",
37285
+ "data-testid": "pptx-compat-toast-dismiss",
37286
+ onClick: () => onDismiss(toast.id),
37287
+ "aria-label": t("pptx.compatibility.dismiss"),
37288
+ className: "shrink-0 text-muted-foreground hover:text-foreground",
37289
+ children: "\xD7"
37290
+ }
37291
+ )
37292
+ ]
37293
+ },
37294
+ toast.id
37295
+ ))
37296
+ ]
37297
+ }
37298
+ );
37299
+ }
37300
+ function ToggleRow({ checked, onChange, icon, label, testId }) {
36756
37301
  return /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2.5 cursor-pointer group select-none", children: [
36757
37302
  /* @__PURE__ */ jsxs("span", { className: "relative flex items-center justify-center w-4 h-4", children: [
36758
37303
  /* @__PURE__ */ jsx(
@@ -36761,6 +37306,7 @@ function ToggleRow({ checked, onChange, icon, label }) {
36761
37306
  type: "checkbox",
36762
37307
  checked,
36763
37308
  onChange: (e) => onChange(e.target.checked),
37309
+ "data-testid": testId,
36764
37310
  className: "peer sr-only"
36765
37311
  }
36766
37312
  ),
@@ -36774,25 +37320,33 @@ function ToggleRow({ checked, onChange, icon, label }) {
36774
37320
  ] });
36775
37321
  }
36776
37322
  function HeaderFooterPanel({
36777
- showDateTime,
36778
- showSlideNumber,
36779
- showFooter,
36780
- footerText,
36781
- onSetShowDateTime,
36782
- onSetShowSlideNumber,
36783
- onSetShowFooter,
36784
- onSetFooterText,
37323
+ headerFooter,
37324
+ onUpdate,
36785
37325
  onApplyToAll,
36786
37326
  onApplyToCurrent,
36787
37327
  onClose
36788
37328
  }) {
37329
+ const { t } = useTranslation();
37330
+ const showDateTime = headerFooter.hasDateTime ?? false;
37331
+ const dateTimeAuto = headerFooter.dateTimeAuto ?? false;
37332
+ const showDateText = isHeaderFooterDateTextVisible(headerFooter);
37333
+ const showSlideNumber = headerFooter.hasSlideNumber ?? false;
37334
+ const showHeader = headerFooter.hasHeader ?? false;
37335
+ const showHeaderText = isHeaderFooterHeaderTextVisible(headerFooter);
37336
+ const showFooter = headerFooter.hasFooter ?? false;
37337
+ const showFooterText = isHeaderFooterFooterTextVisible(headerFooter);
37338
+ const handleDateTextChange = useCallback(
37339
+ (e) => onUpdate({ dateTimeText: e.target.value }),
37340
+ [onUpdate]
37341
+ );
37342
+ const handleHeaderTextChange = useCallback(
37343
+ (e) => onUpdate({ headerText: e.target.value }),
37344
+ [onUpdate]
37345
+ );
36789
37346
  const handleFooterTextChange = useCallback(
36790
- (e) => {
36791
- onSetFooterText(e.target.value);
36792
- },
36793
- [onSetFooterText]
37347
+ (e) => onUpdate({ footerText: e.target.value }),
37348
+ [onUpdate]
36794
37349
  );
36795
- const { t } = useTranslation();
36796
37350
  return /* @__PURE__ */ jsx("div", { className: "absolute inset-0 z-50 flex items-center justify-center bg-black/40 backdrop-blur-sm", children: /* @__PURE__ */ jsxs("div", { className: "w-full max-w-sm rounded-lg border border-border bg-background shadow-2xl", children: [
36797
37351
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-b border-border px-4 py-3", children: [
36798
37352
  /* @__PURE__ */ jsx("h2", { className: "text-sm font-semibold text-foreground", children: t("pptx.headerFooter.title") }),
@@ -36803,6 +37357,7 @@ function HeaderFooterPanel({
36803
37357
  onClick: onClose,
36804
37358
  className: "rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground transition-colors",
36805
37359
  "aria-label": t("pptx.headerFooter.close"),
37360
+ "data-testid": "header-footer-close",
36806
37361
  children: /* @__PURE__ */ jsx(LuX, { className: "w-4 h-4" })
36807
37362
  }
36808
37363
  )
@@ -36812,36 +37367,84 @@ function HeaderFooterPanel({
36812
37367
  ToggleRow,
36813
37368
  {
36814
37369
  checked: showDateTime,
36815
- onChange: onSetShowDateTime,
37370
+ onChange: (hasDateTime) => onUpdate({ hasDateTime }),
36816
37371
  icon: /* @__PURE__ */ jsx(LuCalendarDays, { className: "w-3.5 h-3.5" }),
36817
- label: t("pptx.headerFooter.dateAndTime")
37372
+ label: t("pptx.headerFooter.dateAndTime"),
37373
+ testId: "hf-date-time"
36818
37374
  }
36819
37375
  ),
37376
+ showDateTime && /* @__PURE__ */ jsxs("div", { className: "pl-6 space-y-2", children: [
37377
+ /* @__PURE__ */ jsx(
37378
+ ToggleRow,
37379
+ {
37380
+ checked: dateTimeAuto,
37381
+ onChange: (auto) => onUpdate({ dateTimeAuto: auto }),
37382
+ icon: /* @__PURE__ */ jsx(LuClock, { className: "w-3.5 h-3.5" }),
37383
+ label: t("pptx.headerFooter.updateAutomatically"),
37384
+ testId: "hf-date-auto"
37385
+ }
37386
+ ),
37387
+ showDateText && /* @__PURE__ */ jsx(
37388
+ "input",
37389
+ {
37390
+ type: "text",
37391
+ value: headerFooter.dateTimeText ?? "",
37392
+ onChange: handleDateTextChange,
37393
+ placeholder: t("pptx.headerFooter.fixedDate"),
37394
+ "data-testid": "hf-date-text",
37395
+ className: "w-full rounded border border-border bg-muted px-2.5 py-1.5 text-xs text-foreground placeholder-muted-foreground outline-none transition-colors focus:border-primary focus:ring-1 focus:ring-primary/30"
37396
+ }
37397
+ )
37398
+ ] }),
36820
37399
  /* @__PURE__ */ jsx(
36821
37400
  ToggleRow,
36822
37401
  {
36823
37402
  checked: showSlideNumber,
36824
- onChange: onSetShowSlideNumber,
37403
+ onChange: (hasSlideNumber) => onUpdate({ hasSlideNumber }),
36825
37404
  icon: /* @__PURE__ */ jsx(LuHash, { className: "w-3.5 h-3.5" }),
36826
- label: t("pptx.headerFooter.slideNumber")
37405
+ label: t("pptx.headerFooter.slideNumber"),
37406
+ testId: "hf-slide-number"
37407
+ }
37408
+ ),
37409
+ /* @__PURE__ */ jsx(
37410
+ ToggleRow,
37411
+ {
37412
+ checked: showHeader,
37413
+ onChange: (hasHeader) => onUpdate({ hasHeader }),
37414
+ icon: /* @__PURE__ */ jsx(LuFileText, { className: "w-3.5 h-3.5" }),
37415
+ label: t("pptx.field.header"),
37416
+ testId: "hf-header"
36827
37417
  }
36828
37418
  ),
37419
+ showHeaderText && /* @__PURE__ */ jsx("div", { className: "pl-6", children: /* @__PURE__ */ jsx(
37420
+ "input",
37421
+ {
37422
+ type: "text",
37423
+ value: headerFooter.headerText ?? "",
37424
+ onChange: handleHeaderTextChange,
37425
+ placeholder: t("pptx.headerFooter.headerText"),
37426
+ "data-testid": "hf-header-text",
37427
+ className: "w-full rounded border border-border bg-muted px-2.5 py-1.5 text-xs text-foreground placeholder-muted-foreground outline-none transition-colors focus:border-primary focus:ring-1 focus:ring-primary/30"
37428
+ }
37429
+ ) }),
36829
37430
  /* @__PURE__ */ jsx(
36830
37431
  ToggleRow,
36831
37432
  {
36832
37433
  checked: showFooter,
36833
- onChange: onSetShowFooter,
37434
+ onChange: (hasFooter) => onUpdate({ hasFooter }),
36834
37435
  icon: /* @__PURE__ */ jsx(LuText, { className: "w-3.5 h-3.5" }),
36835
- label: t("pptx.headerFooter.footer")
37436
+ label: t("pptx.headerFooter.footer"),
37437
+ testId: "hf-footer"
36836
37438
  }
36837
37439
  ),
36838
- showFooter && /* @__PURE__ */ jsx("div", { className: "pl-6", children: /* @__PURE__ */ jsx(
37440
+ showFooterText && /* @__PURE__ */ jsx("div", { className: "pl-6", children: /* @__PURE__ */ jsx(
36839
37441
  "input",
36840
37442
  {
36841
37443
  type: "text",
36842
- value: footerText,
37444
+ value: headerFooter.footerText ?? "",
36843
37445
  onChange: handleFooterTextChange,
36844
37446
  placeholder: t("pptx.headerFooter.footerPlaceholder"),
37447
+ "data-testid": "hf-footer-text",
36845
37448
  className: "w-full rounded border border-border bg-muted px-2.5 py-1.5 text-xs text-foreground placeholder-muted-foreground outline-none transition-colors focus:border-primary focus:ring-1 focus:ring-primary/30"
36846
37449
  }
36847
37450
  ) })
@@ -36852,6 +37455,7 @@ function HeaderFooterPanel({
36852
37455
  {
36853
37456
  type: "button",
36854
37457
  onClick: onApplyToAll,
37458
+ "data-testid": "hf-apply-all",
36855
37459
  className: "rounded bg-accent px-3 py-1.5 text-xs font-medium text-foreground hover:bg-accent/80 transition-colors",
36856
37460
  children: t("pptx.headerFooter.applyToAll")
36857
37461
  }
@@ -36861,6 +37465,7 @@ function HeaderFooterPanel({
36861
37465
  {
36862
37466
  type: "button",
36863
37467
  onClick: onApplyToCurrent,
37468
+ "data-testid": "hf-apply-current",
36864
37469
  className: "rounded bg-primary px-3 py-1.5 text-xs font-medium text-white hover:bg-primary/80 transition-colors",
36865
37470
  children: t("pptx.headerFooter.applyToCurrent")
36866
37471
  }
@@ -37065,6 +37670,41 @@ function MobileChromeOverlay(props) {
37065
37670
  )
37066
37671
  ] });
37067
37672
  }
37673
+ function ReadOnlyBanner({ recommendation, onEditAnyway, onDismiss }) {
37674
+ const { t } = useTranslation();
37675
+ return /* @__PURE__ */ jsxs(
37676
+ "div",
37677
+ {
37678
+ "data-testid": "pptx-readonly-banner",
37679
+ "data-kind": recommendation.kind ?? void 0,
37680
+ className: "flex items-center gap-3 px-3 py-1.5 bg-amber-600/10 border-b border-amber-600/30 text-[12px] text-amber-900 dark:text-amber-200",
37681
+ children: [
37682
+ /* @__PURE__ */ jsx("span", { className: "flex-1 min-w-0", children: t(recommendation.messageKey) }),
37683
+ /* @__PURE__ */ jsx(
37684
+ "button",
37685
+ {
37686
+ type: "button",
37687
+ "data-testid": "pptx-readonly-edit-anyway",
37688
+ onClick: onEditAnyway,
37689
+ className: "shrink-0 rounded-sm bg-amber-600/90 px-2 py-0.5 text-[11px] text-amber-50 transition-colors hover:bg-amber-600",
37690
+ children: t("pptx.readOnly.editAnyway")
37691
+ }
37692
+ ),
37693
+ /* @__PURE__ */ jsx(
37694
+ "button",
37695
+ {
37696
+ type: "button",
37697
+ "data-testid": "pptx-readonly-dismiss",
37698
+ onClick: onDismiss,
37699
+ "aria-label": t("pptx.readOnly.dismiss"),
37700
+ className: "shrink-0 rounded-sm px-1.5 py-0.5 text-[11px] text-amber-900/80 transition-colors hover:bg-amber-600/20 dark:text-amber-200/80",
37701
+ children: t("pptx.readOnly.dismiss")
37702
+ }
37703
+ )
37704
+ ]
37705
+ }
37706
+ );
37707
+ }
37068
37708
  function AddinTable({
37069
37709
  title,
37070
37710
  rows,
@@ -37480,144 +38120,16 @@ function OptionsRibbonPane({
37480
38120
  }
37481
38121
 
37482
38122
  // src/viewer/utils/ai-log-export.ts
37483
- function isoOf(ms) {
37484
- const n = Number.isFinite(ms) ? ms : 0;
37485
- return new Date(n).toISOString();
37486
- }
37487
- function toLogChat(chat, detailed) {
37488
- const messages = chat.messages.map((message) => {
37489
- const parts = toRenderableParts(message);
37490
- const textRuns = [];
37491
- const toolCalls = [];
37492
- for (const part of parts) {
37493
- if (part.kind === "text") {
37494
- textRuns.push(part.text);
37495
- continue;
37496
- }
37497
- toolCalls.push({
37498
- toolName: part.toolName,
37499
- toolCallId: part.toolCallId,
37500
- state: part.state,
37501
- input: detailed ? part.input : void 0,
37502
- output: detailed ? part.output : void 0,
37503
- errorText: part.errorText
37504
- });
37505
- }
37506
- return {
37507
- role: message.role,
37508
- text: textRuns.join("\n\n"),
37509
- toolCalls
37510
- };
37511
- });
37512
- return {
37513
- id: chat.id,
37514
- title: chat.title,
37515
- deckId: chat.deckId,
37516
- createdAt: chat.createdAt,
37517
- updatedAt: chat.updatedAt,
37518
- createdAtIso: isoOf(chat.createdAt),
37519
- updatedAtIso: isoOf(chat.updatedAt),
37520
- messageCount: chat.messages.length,
37521
- messages
37522
- };
37523
- }
37524
- function buildChatLogExport(chats, options) {
37525
- const detailed = options?.detailed ?? true;
37526
- const now = options?.now ?? Date.now();
37527
- return {
37528
- format: "pptx-ai-chat-log",
37529
- version: 1,
37530
- exportedAt: isoOf(now),
37531
- detailed,
37532
- chatCount: chats.length,
37533
- chats: chats.map((chat) => toLogChat(chat, detailed))
37534
- };
37535
- }
37536
- function toolCallLine(call, detailed) {
37537
- const lines = [`- Tool \`${call.toolName}\` (${call.state})`];
37538
- if (call.errorText) {
37539
- lines.push(` - error: ${call.errorText}`);
37540
- }
37541
- if (detailed) {
37542
- lines.push(" - input:");
37543
- lines.push(" ```json");
37544
- lines.push(JSON.stringify(call.input ?? null, null, 2));
37545
- lines.push(" ```");
37546
- lines.push(" - output:");
37547
- lines.push(" ```json");
37548
- lines.push(JSON.stringify(call.output ?? null, null, 2));
37549
- lines.push(" ```");
37550
- }
37551
- return lines.join("\n");
37552
- }
37553
- function buildChatLogMarkdown(doc) {
37554
- const out = [
37555
- `# AI chat logs`,
37556
- "",
37557
- `Exported: ${doc.exportedAt}`,
37558
- `Chats: ${doc.chatCount}`,
37559
- ""
37560
- ];
37561
- for (const chat of doc.chats) {
37562
- out.push(`## ${chat.title || chat.id}`);
37563
- out.push("");
37564
- out.push(`- id: ${chat.id}`);
37565
- if (chat.deckId) {
37566
- out.push(`- deck: ${chat.deckId}`);
37567
- }
37568
- out.push(`- created: ${chat.createdAtIso}`);
37569
- out.push(`- updated: ${chat.updatedAtIso}`);
37570
- out.push(`- messages: ${chat.messageCount}`);
37571
- out.push("");
37572
- for (const message of chat.messages) {
37573
- out.push(`### ${message.role}`);
37574
- out.push("");
37575
- if (message.text) {
37576
- out.push(message.text);
37577
- out.push("");
37578
- }
37579
- for (const call of message.toolCalls) {
37580
- out.push(toolCallLine(call, doc.detailed));
37581
- out.push("");
37582
- }
37583
- }
37584
- }
37585
- return out.join("\n");
37586
- }
37587
- async function collectStoredChats(store) {
37588
- const summaries = await store.listChats();
37589
- const chats = [];
37590
- for (const summary of summaries) {
37591
- const chat = await store.loadChat(summary.id);
37592
- if (chat) {
37593
- chats.push(chat);
37594
- }
37595
- }
37596
- return chats;
37597
- }
37598
- function timestampSlug(now) {
37599
- const d = new Date(now);
37600
- const p = (n) => String(n).padStart(2, "0");
37601
- return `${d.getFullYear()}${p(d.getMonth() + 1)}${p(d.getDate())}-${p(d.getHours())}${p(d.getMinutes())}${p(d.getSeconds())}`;
37602
- }
37603
- async function exportAiChatLogs(options) {
38123
+ async function exportAiChatLogs2(options) {
37604
38124
  const store = options?.store ?? createChatHistoryStore();
37605
- const format = options?.format ?? "json";
37606
- const now = options?.now ?? Date.now();
37607
38125
  const chats = await collectStoredChats(store);
37608
- if (chats.length === 0) {
37609
- return 0;
37610
- }
37611
- const doc = buildChatLogExport(chats, { detailed: options?.detailed ?? true, now });
37612
- const slug = timestampSlug(now);
37613
- if (format === "markdown") {
37614
- const blob = new Blob([buildChatLogMarkdown(doc)], { type: "text/markdown" });
37615
- downloadBlob(blob, `pptx-ai-chats-${slug}.md`);
37616
- } else {
37617
- const blob = new Blob([JSON.stringify(doc, null, 2)], { type: "application/json" });
37618
- downloadBlob(blob, `pptx-ai-chats-${slug}.json`);
37619
- }
37620
- return chats.length;
38126
+ return exportAiChatLogs(
38127
+ chats,
38128
+ { format: options?.format, detailed: options?.detailed, now: options?.now },
38129
+ (filename, content, mime) => {
38130
+ downloadBlob(new Blob([content], { type: mime }), filename);
38131
+ }
38132
+ );
37621
38133
  }
37622
38134
  function SettingsAiTab({ store }) {
37623
38135
  const { t } = useTranslation();
@@ -37648,7 +38160,7 @@ function SettingsAiTab({ store }) {
37648
38160
  async (format) => {
37649
38161
  setStatus({ kind: "busy" });
37650
38162
  try {
37651
- const count = await exportAiChatLogs({ store: activeStore, format, detailed });
38163
+ const count = await exportAiChatLogs2({ store: activeStore, format, detailed });
37652
38164
  setStatus({ kind: "done", count });
37653
38165
  } catch {
37654
38166
  setStatus({ kind: "done", count: 0 });
@@ -38103,106 +38615,6 @@ function SettingsDialog({
38103
38615
  )
38104
38616
  ] });
38105
38617
  }
38106
-
38107
- // src/viewer/hooks/ai/ai-element-update.ts
38108
- function applyGeometry(el, u) {
38109
- if (u.x !== void 0) {
38110
- el.x = u.x;
38111
- }
38112
- if (u.y !== void 0) {
38113
- el.y = u.y;
38114
- }
38115
- if (u.width !== void 0) {
38116
- el.width = u.width;
38117
- }
38118
- if (u.height !== void 0) {
38119
- el.height = u.height;
38120
- }
38121
- if (u.rotation !== void 0) {
38122
- el.rotation = u.rotation;
38123
- }
38124
- if (u.opacity !== void 0) {
38125
- el.opacity = u.opacity;
38126
- }
38127
- if (u.hidden !== void 0) {
38128
- el.hidden = u.hidden;
38129
- }
38130
- if (u.flipHorizontal !== void 0) {
38131
- el.flipHorizontal = u.flipHorizontal;
38132
- }
38133
- if (u.flipVertical !== void 0) {
38134
- el.flipVertical = u.flipVertical;
38135
- }
38136
- }
38137
- function applyText(el, u) {
38138
- if (!hasTextProperties(el)) {
38139
- return;
38140
- }
38141
- if (typeof u.text === "string") {
38142
- el.text = u.text;
38143
- if (el.textSegments && el.textSegments.length > 0) {
38144
- el.textSegments = [{ text: u.text, style: el.textSegments[0].style }];
38145
- } else {
38146
- el.textSegments = [{ text: u.text, style: {} }];
38147
- }
38148
- }
38149
- const textStyle = {};
38150
- if (u.fontSize !== void 0) {
38151
- textStyle.fontSize = u.fontSize;
38152
- }
38153
- if (u.fontFamily !== void 0) {
38154
- textStyle.fontFamily = u.fontFamily;
38155
- }
38156
- if (u.fontColor !== void 0) {
38157
- textStyle.color = u.fontColor;
38158
- }
38159
- if (u.bold !== void 0) {
38160
- textStyle.bold = u.bold;
38161
- }
38162
- if (u.italic !== void 0) {
38163
- textStyle.italic = u.italic;
38164
- }
38165
- if (u.underline !== void 0) {
38166
- textStyle.underline = u.underline;
38167
- }
38168
- if (u.align !== void 0) {
38169
- textStyle.align = u.align;
38170
- }
38171
- if (Object.keys(textStyle).length === 0) {
38172
- return;
38173
- }
38174
- el.textStyle = { ...el.textStyle, ...textStyle };
38175
- el.textSegments = el.textSegments?.map((seg) => ({
38176
- ...seg,
38177
- style: { ...seg.style, ...textStyle }
38178
- }));
38179
- }
38180
- function applyShapeStyle(el, u) {
38181
- if (!hasShapeProperties(el)) {
38182
- return;
38183
- }
38184
- const shapeStyle = {};
38185
- if (u.fillColor !== void 0) {
38186
- shapeStyle.fillColor = u.fillColor;
38187
- }
38188
- if (u.strokeColor !== void 0) {
38189
- shapeStyle.strokeColor = u.strokeColor;
38190
- }
38191
- if (u.strokeWidth !== void 0) {
38192
- shapeStyle.strokeWidth = u.strokeWidth;
38193
- }
38194
- if (Object.keys(shapeStyle).length === 0) {
38195
- return;
38196
- }
38197
- el.shapeStyle = { ...el.shapeStyle, ...shapeStyle };
38198
- }
38199
- function applyAiElementUpdate(el, updates) {
38200
- applyGeometry(el, updates);
38201
- applyText(el, updates);
38202
- applyShapeStyle(el, updates);
38203
- }
38204
-
38205
- // src/viewer/hooks/ai/useAiBridge.ts
38206
38618
  function useAiBridge(input) {
38207
38619
  const ref = useRef(input);
38208
38620
  ref.current = input;
@@ -38258,7 +38670,7 @@ function useAiBridge(input) {
38258
38670
  applySlidesUpdate((slides) => {
38259
38671
  const el = slides[slideIndex]?.elements.find((e) => e.id === elementId);
38260
38672
  if (el) {
38261
- applyAiElementUpdate(el, updates);
38673
+ applyElementUpdate(el, updates);
38262
38674
  }
38263
38675
  return slides;
38264
38676
  });
@@ -38438,6 +38850,109 @@ function useAiPanelController(input) {
38438
38850
  showChangeBatch
38439
38851
  };
38440
38852
  }
38853
+ function useMasterViewCrud(input) {
38854
+ const {
38855
+ handlerRef,
38856
+ slides,
38857
+ slideMasters,
38858
+ target,
38859
+ setSlides,
38860
+ setSlideMasters,
38861
+ setActiveMasterIndex,
38862
+ setActiveLayoutIndex,
38863
+ markDirty,
38864
+ pushToast
38865
+ } = input;
38866
+ const { t } = useTranslation();
38867
+ const data = useMemo(
38868
+ () => ({ slides, slideMasters }),
38869
+ [slides, slideMasters]
38870
+ );
38871
+ const crudActions = useMemo(() => masterViewCrudActions(data, target), [data, target]);
38872
+ const handleCrudAction = useCallback(
38873
+ async (id) => {
38874
+ const handler = handlerRef.current;
38875
+ if (!handler || !target) {
38876
+ return;
38877
+ }
38878
+ const action = crudActions.find((candidate) => candidate.id === id);
38879
+ if (!action?.enabled) {
38880
+ return;
38881
+ }
38882
+ let name;
38883
+ if (id === "renameLayout" || id === "renameMaster") {
38884
+ const master = slideMasters[target.masterIndex];
38885
+ const current = id === "renameLayout" ? master?.layouts?.[target.layoutIndex ?? -1]?.name ?? "" : master?.name ?? "";
38886
+ const next = safePrompt(t("pptx.masterView.renamePrompt"), current)?.trim();
38887
+ if (!next) {
38888
+ return;
38889
+ }
38890
+ name = next;
38891
+ }
38892
+ const result = await applyMasterViewCrudAction(
38893
+ handler,
38894
+ data,
38895
+ id,
38896
+ target,
38897
+ name !== void 0 ? { name } : void 0
38898
+ );
38899
+ if (!result.ok) {
38900
+ pushToast({
38901
+ id: `master-crud-${Date.now()}`,
38902
+ code: `masterViewCrud:${result.reason}`,
38903
+ severity: "warning",
38904
+ messageKey: masterViewCrudFailureKey(id, result.reason)
38905
+ });
38906
+ return;
38907
+ }
38908
+ handlerRef.current = result.handler;
38909
+ setSlides(result.data.slides);
38910
+ setSlideMasters(result.data.slideMasters ?? []);
38911
+ setActiveMasterIndex(result.target.masterIndex);
38912
+ setActiveLayoutIndex(result.target.layoutIndex);
38913
+ markDirty();
38914
+ },
38915
+ [
38916
+ handlerRef,
38917
+ target,
38918
+ crudActions,
38919
+ slideMasters,
38920
+ t,
38921
+ data,
38922
+ pushToast,
38923
+ setSlides,
38924
+ setSlideMasters,
38925
+ setActiveMasterIndex,
38926
+ setActiveLayoutIndex,
38927
+ markDirty
38928
+ ]
38929
+ );
38930
+ return { crudActions, handleCrudAction };
38931
+ }
38932
+ function applyRecentColorPick(recent, hex) {
38933
+ const next = pushRecentColor(recent, hex);
38934
+ if (next === recent) {
38935
+ return null;
38936
+ }
38937
+ return { recentColors: next, patch: mruColorsPatch(next) };
38938
+ }
38939
+ function useRecentColorsSync(input) {
38940
+ const { setRecentColors, setPresentationProperties } = input;
38941
+ const pushColor = useCallback(
38942
+ (hex) => {
38943
+ setRecentColors((prev) => {
38944
+ const applied = applyRecentColorPick(prev, hex);
38945
+ if (!applied) {
38946
+ return prev;
38947
+ }
38948
+ setPresentationProperties((properties) => ({ ...properties, ...applied.patch }));
38949
+ return applied.recentColors;
38950
+ });
38951
+ },
38952
+ [setRecentColors, setPresentationProperties]
38953
+ );
38954
+ return { pushColor };
38955
+ }
38441
38956
  var PowerPointViewer = forwardRef(
38442
38957
  // oxlint-disable-next-line prefer-arrow-callback -- named fn gives the forwardRef component its displayName
38443
38958
  function PowerPointViewer2(props, ref) {
@@ -38584,7 +39099,9 @@ var PowerPointViewer = forwardRef(
38584
39099
  const handleEnableEditing = useCallback(() => {
38585
39100
  setProtectedViewOverridden(true);
38586
39101
  }, []);
38587
- const canEdit = hostCanEdit && !isProtectedView;
39102
+ const readOnlyRec = useReadOnlyRecommendationState(content);
39103
+ const compatToastsState = useCompatibilityToastsState();
39104
+ const canEdit = hostCanEdit && !isProtectedView && !readOnlyRec.locked;
38588
39105
  const [isSettingsOpen, setIsSettingsOpen] = useState(false);
38589
39106
  const [isHeaderFooterOpen, setIsHeaderFooterOpen] = useState(false);
38590
39107
  const [autosaveEnabled, setAutosaveEnabled] = useState(true);
@@ -38611,6 +39128,14 @@ var PowerPointViewer = forwardRef(
38611
39128
  activeSlide,
38612
39129
  selectedElement
38613
39130
  } = state;
39131
+ const { pushColor } = useRecentColorsSync({
39132
+ setRecentColors: state.setRecentColors,
39133
+ setPresentationProperties: state.setPresentationProperties
39134
+ });
39135
+ const recentColorsValue = useMemo(
39136
+ () => ({ recentColors: state.recentColors, pushColor }),
39137
+ [state.recentColors, pushColor]
39138
+ );
38614
39139
  const settings = useMemo(
38615
39140
  () => ({
38616
39141
  autoSave: autosaveEnabled,
@@ -38725,11 +39250,18 @@ var PowerPointViewer = forwardRef(
38725
39250
  const mobile = useIsMobile();
38726
39251
  const { isMobile, isTouchDevice, isVirtualKeyboardOpen } = mobile;
38727
39252
  const resizablePanels = useResizablePanels();
38728
- const { gridSpacingPx, visibleSlideIndexes, slideSectionGroups, masterPseudoSlide } = useDerivedSlideState({
39253
+ const {
39254
+ gridSpacingPx,
39255
+ visibleSlideIndexes,
39256
+ slideSectionGroups,
39257
+ masterPseudoSlide,
39258
+ authoredRange
39259
+ } = useDerivedSlideState({
38729
39260
  slides,
38730
39261
  sections: state.sections,
38731
39262
  customShows: state.customShows,
38732
39263
  activeCustomShowId: state.activeCustomShowId,
39264
+ presentationProperties: state.presentationProperties,
38733
39265
  mode,
38734
39266
  activeLayout: state.activeLayout,
38735
39267
  activeMaster: state.activeMaster,
@@ -38808,7 +39340,10 @@ var PowerPointViewer = forwardRef(
38808
39340
  onToggleSubtitles: () => state.setPresentationProperties((prev) => ({
38809
39341
  ...prev,
38810
39342
  showSubtitles: !prev.showSubtitles
38811
- }))
39343
+ })),
39344
+ customShows: state.customShows,
39345
+ activeCustomShowId: state.activeCustomShowId,
39346
+ onSetActiveCustomShowId: state.setActiveCustomShowId
38812
39347
  });
38813
39348
  useTouchGestures({
38814
39349
  targetRef: zoom.canvasViewportRef,
@@ -38938,6 +39473,8 @@ var PowerPointViewer = forwardRef(
38938
39473
  // (SSRF/privacy-safe), so only an explicit `true` here lets remote
38939
39474
  // http(s) image sources actually load.
38940
39475
  allowExternalImages: viewerOptions.trust.allowExternalContent,
39476
+ setReadOnlyRecommendation: readOnlyRec.setRecommendation,
39477
+ setCompatToasts: compatToastsState.setToasts,
38941
39478
  canEdit,
38942
39479
  promptKeepInkAnnotations: viewerOptions.advanced.slideShowPromptKeepInkAnnotations,
38943
39480
  // File > Options > Advanced > "Image Size and Quality" (do-not-compress /
@@ -38965,6 +39502,17 @@ var PowerPointViewer = forwardRef(
38965
39502
  onSelectionChange,
38966
39503
  onSlideCountChange
38967
39504
  });
39505
+ const viewPreferencesSync = useViewPreferencesSync({
39506
+ loadVersion,
39507
+ viewProperties: state.viewProperties,
39508
+ setViewProperties: state.setViewProperties,
39509
+ snapToGrid: state.snapToGrid,
39510
+ setSnapToGrid: state.setSnapToGrid,
39511
+ snapToShape: state.snapToShape,
39512
+ setSnapToShape: state.setSnapToShape,
39513
+ showGuides: state.showGuides,
39514
+ setShowGuides: state.setShowGuides
39515
+ });
38968
39516
  const exportHandlers = useMemo(() => {
38969
39517
  const afterSuccessfulSave = (format) => {
38970
39518
  playFeedbackSound(viewerOptions);
@@ -38999,6 +39547,22 @@ var PowerPointViewer = forwardRef(
38999
39547
  history,
39000
39548
  onTemplateElementsChanged: handleTemplateElementsChanged
39001
39549
  });
39550
+ const masterViewCrud = useMasterViewCrud({
39551
+ handlerRef,
39552
+ slides,
39553
+ slideMasters: state.slideMasters,
39554
+ target: {
39555
+ tab: state.masterViewTab,
39556
+ masterIndex: state.activeMasterIndex,
39557
+ layoutIndex: state.activeLayoutIndex
39558
+ },
39559
+ setSlides: state.setSlides,
39560
+ setSlideMasters: state.setSlideMasters,
39561
+ setActiveMasterIndex: state.setActiveMasterIndex,
39562
+ setActiveLayoutIndex: state.setActiveLayoutIndex,
39563
+ markDirty: history.markDirty,
39564
+ pushToast: (toast) => compatToastsState.setToasts((prev) => [...prev, toast])
39565
+ });
39002
39566
  const applyAiTheme = useCallback(
39003
39567
  (updates) => {
39004
39568
  if (updates.colorScheme) {
@@ -39072,7 +39636,7 @@ var PowerPointViewer = forwardRef(
39072
39636
  ref: containerRef,
39073
39637
  tabIndex: 0,
39074
39638
  className: "h-full w-full flex flex-col overflow-hidden outline-none",
39075
- children: loading ? /* @__PURE__ */ jsx(LoadingState, {}) : error ? /* @__PURE__ */ jsx(ErrorState, { error }) : /* @__PURE__ */ jsxs(Fragment, { children: [
39639
+ children: loading ? /* @__PURE__ */ jsx(LoadingState, {}) : error ? /* @__PURE__ */ jsx(ErrorState, { error }) : /* @__PURE__ */ jsxs(RecentColorsProvider, { value: recentColorsValue, children: [
39076
39640
  mode !== "present" && /* @__PURE__ */ jsx(
39077
39641
  ViewerToolbarSection,
39078
39642
  {
@@ -39098,6 +39662,7 @@ var PowerPointViewer = forwardRef(
39098
39662
  customFontFamilies,
39099
39663
  ops: editorOps.ops,
39100
39664
  onSetMode: handleSetMode,
39665
+ onPresentFromBeginning: presentation.enterPresentModeFromBeginning,
39101
39666
  onEnterPresenterView: handleEnterPresenterView,
39102
39667
  onEnterRehearsalMode: handleEnterRehearsalMode,
39103
39668
  onOpenSettings: () => setIsSettingsOpen(true),
@@ -39119,7 +39684,18 @@ var PowerPointViewer = forwardRef(
39119
39684
  isAiPanelOpen: aiPanel.isOpen,
39120
39685
  onToggleAiPanel: aiPanel.toggle,
39121
39686
  isProtectedView,
39122
- onEnableEditing: hostCanEdit ? handleEnableEditing : void 0
39687
+ onEnableEditing: hostCanEdit ? handleEnableEditing : void 0,
39688
+ onSetSnapToGrid: viewPreferencesSync.handleSetSnapToGrid,
39689
+ onSetSnapToShape: viewPreferencesSync.handleSetSnapToShape,
39690
+ onSetShowGuides: viewPreferencesSync.handleSetShowGuides
39691
+ }
39692
+ ),
39693
+ mode !== "present" && readOnlyRec.bannerVisible && /* @__PURE__ */ jsx(
39694
+ ReadOnlyBanner,
39695
+ {
39696
+ recommendation: readOnlyRec.recommendation,
39697
+ onEditAnyway: readOnlyRec.editAnyway,
39698
+ onDismiss: readOnlyRec.dismiss
39123
39699
  }
39124
39700
  ),
39125
39701
  /* @__PURE__ */ jsx(
@@ -39146,6 +39722,7 @@ var PowerPointViewer = forwardRef(
39146
39722
  themeHandlers,
39147
39723
  history,
39148
39724
  comments: editorOps.comments,
39725
+ masterViewCrud,
39149
39726
  zoom,
39150
39727
  isMobile,
39151
39728
  isTouchDevice,
@@ -39205,6 +39782,14 @@ var PowerPointViewer = forwardRef(
39205
39782
  ] })
39206
39783
  }
39207
39784
  ),
39785
+ mode !== "present" && /* @__PURE__ */ jsx(
39786
+ CompatibilityToasts,
39787
+ {
39788
+ toasts: compatToastsState.toasts,
39789
+ onDismiss: compatToastsState.dismiss,
39790
+ onDismissAll: compatToastsState.dismissAll
39791
+ }
39792
+ ),
39208
39793
  /* @__PURE__ */ jsx(
39209
39794
  ViewerDialogGroup,
39210
39795
  {
@@ -39272,14 +39857,8 @@ var PowerPointViewer = forwardRef(
39272
39857
  isHeaderFooterOpen && /* @__PURE__ */ jsx(
39273
39858
  HeaderFooterPanel,
39274
39859
  {
39275
- showDateTime: state.headerFooter.hasDateTime ?? false,
39276
- showSlideNumber: state.headerFooter.hasSlideNumber ?? false,
39277
- showFooter: state.headerFooter.hasFooter ?? false,
39278
- footerText: state.headerFooter.footerText ?? "",
39279
- onSetShowDateTime: (hasDateTime) => state.setHeaderFooter((current) => ({ ...current, hasDateTime })),
39280
- onSetShowSlideNumber: (hasSlideNumber) => state.setHeaderFooter((current) => ({ ...current, hasSlideNumber })),
39281
- onSetShowFooter: (hasFooter) => state.setHeaderFooter((current) => ({ ...current, hasFooter })),
39282
- onSetFooterText: (footerText) => state.setHeaderFooter((current) => ({ ...current, footerText })),
39860
+ headerFooter: state.headerFooter,
39861
+ onUpdate: (patch) => state.setHeaderFooter((current) => ({ ...current, ...patch })),
39283
39862
  onApplyToAll: () => {
39284
39863
  history.markDirty();
39285
39864
  setIsHeaderFooterOpen(false);
@@ -39365,6 +39944,7 @@ var PowerPointViewer = forwardRef(
39365
39944
  templateElements: state.templateElements,
39366
39945
  presentation,
39367
39946
  activeCustomShow,
39947
+ authoredRange,
39368
39948
  onExitPresentation: () => handleSetMode("edit"),
39369
39949
  onUpdateNotes: propertyHandlers.handleUpdateNotes,
39370
39950
  isMobile