pptx-react-viewer 3.3.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 (164) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/{AiChatPanel-WNQCTQB5.js → AiChatPanel-3Q4STA5E.js} +25 -25
  3. package/dist/AiChatPanel-3Q4STA5E.js.br +0 -0
  4. package/dist/AiChatPanel-3Q4STA5E.js.gz +0 -0
  5. package/dist/{AiChatPanel-BNFDBP4S.mjs → AiChatPanel-NQZBZIRM.mjs} +4 -4
  6. package/dist/AiChatPanel-NQZBZIRM.mjs.br +0 -0
  7. package/dist/AiChatPanel-NQZBZIRM.mjs.gz +0 -0
  8. package/dist/{Area3DChartScene-SAQVRYOH.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-FXBSLIGX.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-7HVUTP2E.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-LUA6E2K6.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-OVPULUTF.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-IW4JGH57.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-5KP6BVCV.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-BERTZYCJ.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-3R2ETTGA.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-O6FFK5L7.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-OCR26R5D.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-TGFAOLHL.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-QKSYKQEL.js → chunk-7E6SM42A.js} +2513 -1626
  46. package/dist/chunk-7E6SM42A.js.br +0 -0
  47. package/dist/chunk-7E6SM42A.js.gz +0 -0
  48. package/dist/{chunk-DM2IZCSD.mjs → chunk-B7WAGQW4.mjs} +2955 -835
  49. package/dist/chunk-B7WAGQW4.mjs.br +0 -0
  50. package/dist/chunk-B7WAGQW4.mjs.gz +0 -0
  51. package/dist/{chunk-2FTJAMFA.mjs → chunk-C4WTQIC6.mjs} +13 -5
  52. package/dist/chunk-C4WTQIC6.mjs.br +0 -0
  53. package/dist/chunk-C4WTQIC6.mjs.gz +0 -0
  54. package/dist/{chunk-FSQCEAMG.js → chunk-KY6JQJXK.js} +17 -9
  55. package/dist/chunk-KY6JQJXK.js.br +0 -0
  56. package/dist/chunk-KY6JQJXK.js.gz +0 -0
  57. package/dist/{chunk-3B5FRKYU.mjs → chunk-L5MRKDRM.mjs} +1397 -510
  58. package/dist/chunk-L5MRKDRM.mjs.br +0 -0
  59. package/dist/chunk-L5MRKDRM.mjs.gz +0 -0
  60. package/dist/{chunk-QEEU4S4Z.mjs → chunk-MSUUPLQ7.mjs} +671 -114
  61. package/dist/chunk-MSUUPLQ7.mjs.br +0 -0
  62. package/dist/chunk-MSUUPLQ7.mjs.gz +0 -0
  63. package/dist/{chunk-K6R2JNCK.js → chunk-PCW2KT7Z.js} +2987 -834
  64. package/dist/chunk-PCW2KT7Z.js.br +0 -0
  65. package/dist/chunk-PCW2KT7Z.js.gz +0 -0
  66. package/dist/{chunk-ITN5NYYM.mjs → chunk-SFMATKNJ.mjs} +6 -19
  67. package/dist/chunk-SFMATKNJ.mjs.br +0 -0
  68. package/dist/chunk-SFMATKNJ.mjs.gz +0 -0
  69. package/dist/{chunk-GR6SJJIT.js → chunk-TJNG5VEK.js} +1080 -518
  70. package/dist/chunk-TJNG5VEK.js.br +0 -0
  71. package/dist/chunk-TJNG5VEK.js.gz +0 -0
  72. package/dist/{chunk-3P7FYHJH.js → chunk-UNIJUD5C.js} +44 -1
  73. package/dist/chunk-UNIJUD5C.js.br +0 -0
  74. package/dist/{chunk-3P7FYHJH.js.gz → chunk-UNIJUD5C.js.gz} +0 -0
  75. package/dist/{chunk-44CQ67GQ.js → chunk-XBTHWXNO.js} +172 -185
  76. package/dist/chunk-XBTHWXNO.js.br +0 -0
  77. package/dist/chunk-XBTHWXNO.js.gz +0 -0
  78. package/dist/{chunk-AMRT3AE4.mjs → chunk-XWUMM2TX.mjs} +44 -1
  79. package/dist/chunk-XWUMM2TX.mjs.br +0 -0
  80. package/dist/{chunk-AMRT3AE4.mjs.gz → 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-BNFDBP4S.mjs.br +0 -0
  115. package/dist/AiChatPanel-BNFDBP4S.mjs.gz +0 -0
  116. package/dist/AiChatPanel-WNQCTQB5.js.br +0 -0
  117. package/dist/AiChatPanel-WNQCTQB5.js.gz +0 -0
  118. package/dist/Area3DChartScene-FXBSLIGX.js.br +0 -0
  119. package/dist/Area3DChartScene-FXBSLIGX.js.gz +0 -0
  120. package/dist/Area3DChartScene-SAQVRYOH.mjs.br +0 -0
  121. package/dist/Area3DChartScene-SAQVRYOH.mjs.gz +0 -0
  122. package/dist/Bar3DChartScene-7HVUTP2E.js.br +0 -0
  123. package/dist/Bar3DChartScene-7HVUTP2E.js.gz +0 -0
  124. package/dist/Bar3DChartScene-LUA6E2K6.mjs.br +0 -3
  125. package/dist/Bar3DChartScene-LUA6E2K6.mjs.gz +0 -0
  126. package/dist/Line3DChartScene-IW4JGH57.mjs.br +0 -0
  127. package/dist/Line3DChartScene-IW4JGH57.mjs.gz +0 -0
  128. package/dist/Line3DChartScene-OVPULUTF.js.br +0 -0
  129. package/dist/Line3DChartScene-OVPULUTF.js.gz +0 -0
  130. package/dist/Model3DScene-5KP6BVCV.js.br +0 -0
  131. package/dist/Model3DScene-5KP6BVCV.js.gz +0 -0
  132. package/dist/Model3DScene-BERTZYCJ.mjs.br +0 -0
  133. package/dist/Model3DScene-BERTZYCJ.mjs.gz +0 -0
  134. package/dist/PieChart3DScene-3R2ETTGA.js.br +0 -0
  135. package/dist/PieChart3DScene-3R2ETTGA.js.gz +0 -0
  136. package/dist/PieChart3DScene-O6FFK5L7.mjs.br +0 -0
  137. package/dist/PieChart3DScene-O6FFK5L7.mjs.gz +0 -0
  138. package/dist/SurfaceChart3DScene-OCR26R5D.mjs.br +0 -0
  139. package/dist/SurfaceChart3DScene-OCR26R5D.mjs.gz +0 -0
  140. package/dist/SurfaceChart3DScene-TGFAOLHL.js.br +0 -0
  141. package/dist/SurfaceChart3DScene-TGFAOLHL.js.gz +0 -0
  142. package/dist/chunk-2FTJAMFA.mjs.br +0 -0
  143. package/dist/chunk-2FTJAMFA.mjs.gz +0 -0
  144. package/dist/chunk-3B5FRKYU.mjs.br +0 -0
  145. package/dist/chunk-3B5FRKYU.mjs.gz +0 -0
  146. package/dist/chunk-3P7FYHJH.js.br +0 -0
  147. package/dist/chunk-44CQ67GQ.js.br +0 -0
  148. package/dist/chunk-44CQ67GQ.js.gz +0 -0
  149. package/dist/chunk-AMRT3AE4.mjs.br +0 -0
  150. package/dist/chunk-DM2IZCSD.mjs.br +0 -0
  151. package/dist/chunk-DM2IZCSD.mjs.gz +0 -0
  152. package/dist/chunk-FSQCEAMG.js.br +0 -0
  153. package/dist/chunk-FSQCEAMG.js.gz +0 -0
  154. package/dist/chunk-GR6SJJIT.js.br +0 -0
  155. package/dist/chunk-GR6SJJIT.js.gz +0 -0
  156. package/dist/chunk-ITN5NYYM.mjs.br +0 -0
  157. package/dist/chunk-ITN5NYYM.mjs.gz +0 -0
  158. package/dist/chunk-K6R2JNCK.js.br +0 -0
  159. package/dist/chunk-K6R2JNCK.js.gz +0 -0
  160. package/dist/chunk-QEEU4S4Z.mjs.br +0 -0
  161. package/dist/chunk-QEEU4S4Z.mjs.gz +0 -0
  162. package/dist/chunk-QKSYKQEL.js.br +0 -0
  163. package/dist/chunk-QKSYKQEL.js.gz +0 -0
  164. package/dist/useViewerBuildingBlocks-X1L8BjsQ.d.ts.map +0 -1
@@ -1,12 +1,12 @@
1
- import { computeFocusTargets, aiChangeAnimationCss, changeGhostStyle, createChatHistoryStore, collectStoredChats, exportAiChatLogs, applyElementUpdate } from './chunk-2FTJAMFA.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-QEEU4S4Z.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-ITN5NYYM.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, 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, 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, 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, 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, buildStrokePathD, cursorForTool, 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, 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, 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, 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, buildAnimationTimelineRows, clearMotionPath, getEffectSoundState, setEffectSound, setAfterAnimation, setAfterAnimationColor, DIRECTIONAL_PRESETS, buildAnimationTimelineBars, motionPathPresetIdForPath, computeMergeCellRight, computeMergeCellDown, computeSplitCell, CHART_TYPE_OPTIONS, 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, 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, PATTERN_PRESET_OPTIONS, getPatternSvg, COMPOUND_LINE_OPTIONS, LINE_JOIN_OPTIONS, LINE_CAP_OPTIONS, TEXT_WARP_PRESETS, warpPreviewPath, text3dPtToEmu, text3dEmuToPt, MATERIAL_PRESETS, GRADIENT_TYPE_OPTIONS, PATTERN_OPTIONS, FILL_PATTERN_LABEL_KEYS, openNativeEyeDropper, toggleText3dExtrusion, BEVEL_PRESETS } from './chunk-DM2IZCSD.mjs';
5
- import { LOCALE_CATALOG, translationsEn } from './chunk-AMRT3AE4.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-SAQVRYOH.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-LUA6E2K6.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-IW4JGH57.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-O6FFK5L7.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-OCR26R5D.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 = () => {
@@ -3021,7 +3022,7 @@ function FailedToLoad6() {
3021
3022
  var LazyModel3DScene = React19.lazy(
3022
3023
  async () => {
3023
3024
  try {
3024
- return await import('./Model3DScene-BERTZYCJ.mjs');
3025
+ return await import('./Model3DScene-ZEGWNILH.mjs');
3025
3026
  } catch {
3026
3027
  return { default: FailedToLoad6 };
3027
3028
  }
@@ -6187,8 +6188,29 @@ function DesignSection(p) {
6187
6188
  )
6188
6189
  ] });
6189
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
+ }
6190
6201
  function DrawSection(p) {
6191
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]);
6192
6214
  return /* @__PURE__ */ jsxs(Fragment, { children: [
6193
6215
  /* @__PURE__ */ jsx("div", { className: grp, children: DRAW_TOOLS.map((tool, i, a) => /* @__PURE__ */ jsx(
6194
6216
  "button",
@@ -6215,6 +6237,7 @@ function DrawSection(p) {
6215
6237
  /* @__PURE__ */ jsx(
6216
6238
  "input",
6217
6239
  {
6240
+ ref: colorRef,
6218
6241
  type: "color",
6219
6242
  value: p.drawingColor,
6220
6243
  onChange: (e) => p.onSetDrawingColor(e.target.value),
@@ -6279,7 +6302,7 @@ function AccountPage() {
6279
6302
  return void 0;
6280
6303
  });
6281
6304
  };
6282
- const version = "3.2.0" ;
6305
+ const version = "3.3.0" ;
6283
6306
  return /* @__PURE__ */ jsxs("div", { className: "mt-8 max-w-[700px] space-y-6", children: [
6284
6307
  /* @__PURE__ */ jsxs("section", { className: cardClass, children: [
6285
6308
  /* @__PURE__ */ jsxs("h2", { className: "flex items-center gap-2 text-sm font-semibold", children: [
@@ -7979,7 +8002,7 @@ function SlideShowSection(p) {
7979
8002
  {
7980
8003
  label: t("pptx.slideShow.fromBeginning"),
7981
8004
  icon: /* @__PURE__ */ jsx(LuPlay, {}),
7982
- onClick: () => p.onSetMode("present"),
8005
+ onClick: p.onPresentFromBeginning ?? (() => p.onSetMode("present")),
7983
8006
  title: t("pptx.slideShow.fromBeginningTooltip")
7984
8007
  }
7985
8008
  ),
@@ -8119,6 +8142,45 @@ function SlideShowSection(p) {
8119
8142
  ] })
8120
8143
  ] });
8121
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
+ }
8122
8184
  var LINE_SPACING_OPTIONS = [
8123
8185
  { label: "1.0", value: 1 },
8124
8186
  { label: "1.15", value: 1.15 },
@@ -8331,14 +8393,16 @@ function TextSection(p) {
8331
8393
  const changeCaseRef = useRef(null);
8332
8394
  const fontColorRef = useRef(null);
8333
8395
  const highlightMenuRef = useRef(null);
8396
+ const { pushColor } = useRecentColors();
8334
8397
  const handleColorChange = useCallback(
8335
8398
  (color) => {
8336
8399
  if (!canFormat) {
8337
8400
  return;
8338
8401
  }
8339
8402
  p.onUpdateTextStyle({ color });
8403
+ pushColor(color);
8340
8404
  },
8341
- [canFormat, p]
8405
+ [canFormat, p, pushColor]
8342
8406
  );
8343
8407
  const handleHighlightChange = useCallback(
8344
8408
  (highlightColor) => {
@@ -8346,8 +8410,9 @@ function TextSection(p) {
8346
8410
  return;
8347
8411
  }
8348
8412
  p.onUpdateTextStyle({ highlightColor });
8413
+ pushColor(highlightColor);
8349
8414
  },
8350
- [canFormat, p]
8415
+ [canFormat, p, pushColor]
8351
8416
  );
8352
8417
  return /* @__PURE__ */ jsxs(Fragment, { children: [
8353
8418
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-0.5", children: [
@@ -8695,6 +8760,14 @@ function TextSection(p) {
8695
8760
  value: currentColor,
8696
8761
  onChange: (e) => handleColorChange(e.target.value)
8697
8762
  }
8763
+ ),
8764
+ /* @__PURE__ */ jsx(
8765
+ RecentColorsRow,
8766
+ {
8767
+ prefix: "font-color",
8768
+ disabled: !canMut,
8769
+ onCommit: handleColorChange
8770
+ }
8698
8771
  )
8699
8772
  ] }) })
8700
8773
  ] }),
@@ -9343,6 +9416,7 @@ function MobileSectionBody({
9343
9416
  SlideShowSection,
9344
9417
  {
9345
9418
  onPresent: () => p.onSetMode("present"),
9419
+ onPresentFromBeginning: p.onPresentFromBeginning,
9346
9420
  onEnterPresenterView: p.onEnterPresenterView ?? (() => {
9347
9421
  }),
9348
9422
  onEnterRehearsalMode: p.onEnterRehearsalMode ?? (() => {
@@ -9541,9 +9615,55 @@ function MobileToolbar(props) {
9541
9615
  }
9542
9616
  );
9543
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
+ }
9544
9663
  var TOP_SHAPES = SHAPE_PRESETS.slice(0, 12);
9545
9664
  function DrawingGroup(p) {
9546
9665
  const { t } = useTranslation();
9666
+ const { pushColor } = useRecentColors();
9547
9667
  const [shapesOpen, setShapesOpen] = useState(false);
9548
9668
  const [arrangeOpen, setArrangeOpen] = useState(false);
9549
9669
  const [fillOpen, setFillOpen] = useState(false);
@@ -9705,64 +9825,42 @@ function DrawingGroup(p) {
9705
9825
  )
9706
9826
  ] }) })
9707
9827
  ] }),
9708
- /* @__PURE__ */ jsxs("div", { className: "relative", ref: fillRef, children: [
9709
- /* @__PURE__ */ jsx(
9710
- "button",
9711
- {
9712
- type: "button",
9713
- disabled: !p.canEdit || !p.selectedElement,
9714
- className: pill,
9715
- title: t("pptx.drawing.shapeFill"),
9716
- onClick: () => setFillOpen((v) => !v),
9717
- children: /* @__PURE__ */ jsx(LuPaintBucket, { className: ic })
9718
- }
9719
- ),
9720
- 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(
9721
- "button",
9722
- {
9723
- type: "button",
9724
- "aria-label": `Fill colour ${c}`,
9725
- "data-pptx-compact": true,
9726
- className: "w-5 h-5 rounded border border-border/60 hover:scale-110 transition-transform",
9727
- style: { backgroundColor: c },
9728
- title: c,
9729
- onClick: () => {
9730
- p.onUpdateElementStyle?.(shapeFillChange(c));
9731
- setFillOpen(false);
9732
- }
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);
9733
9842
  },
9734
- c
9735
- )) }) })
9736
- ] }),
9737
- /* @__PURE__ */ jsxs("div", { className: "relative", ref: outlineRef, children: [
9738
- /* @__PURE__ */ jsx(
9739
- "button",
9740
- {
9741
- type: "button",
9742
- disabled: !p.canEdit || !p.selectedElement,
9743
- className: pill,
9744
- title: t("pptx.drawing.shapeOutline"),
9745
- onClick: () => setOutlineOpen((v) => !v),
9746
- children: /* @__PURE__ */ jsx(LuPenLine, { className: ic })
9747
- }
9748
- ),
9749
- 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(
9750
- "button",
9751
- {
9752
- type: "button",
9753
- "aria-label": `Outline colour ${c}`,
9754
- "data-pptx-compact": true,
9755
- className: "w-5 h-5 rounded border border-border/60 hover:scale-110 transition-transform",
9756
- style: { backgroundColor: c },
9757
- title: c,
9758
- onClick: () => {
9759
- p.onUpdateElementStyle?.(shapeOutlineChange(c));
9760
- setOutlineOpen(false);
9761
- }
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);
9762
9860
  },
9763
- c
9764
- )) }) })
9765
- ] }),
9861
+ onClose: () => setOutlineOpen(false)
9862
+ }
9863
+ ),
9766
9864
  /* @__PURE__ */ jsx(
9767
9865
  "button",
9768
9866
  {
@@ -10666,6 +10764,7 @@ function Toolbar(p) {
10666
10764
  SlideShowSection,
10667
10765
  {
10668
10766
  onPresent: () => p.onSetMode("present"),
10767
+ onPresentFromBeginning: p.onPresentFromBeginning,
10669
10768
  onEnterPresenterView: p.onEnterPresenterView ?? (() => {
10670
10769
  }),
10671
10770
  onEnterRehearsalMode: p.onEnterRehearsalMode ?? (() => {
@@ -12153,8 +12252,6 @@ function useStableCallbacks(callbacks) {
12153
12252
  stableResizeTableRow
12154
12253
  };
12155
12254
  }
12156
- var PLACEHOLDER_WIDTH = 120;
12157
- var PLACEHOLDER_HEIGHT = 40;
12158
12255
  function ActiveXControlOverlay({
12159
12256
  controls,
12160
12257
  canvasSize,
@@ -12163,24 +12260,17 @@ function ActiveXControlOverlay({
12163
12260
  if (controls.length === 0) {
12164
12261
  return null;
12165
12262
  }
12166
- return /* @__PURE__ */ jsx("div", { className: "absolute inset-0 pointer-events-none z-[40]", children: controls.map((control, idx) => {
12167
- const width = control.width ?? PLACEHOLDER_WIDTH;
12168
- const height = control.height ?? PLACEHOLDER_HEIGHT;
12169
- const left = control.x ?? 8;
12170
- const top = control.y ?? 8 + idx * (PLACEHOLDER_HEIGHT + 6);
12171
- const clampedWidth = Math.min(width, canvasSize.width);
12172
- const clampedHeight = Math.min(height, canvasSize.height);
12173
- const imageUrl = control.fallbackImageRelId ? resolveFallbackImage?.(control.fallbackImageRelId) : void 0;
12174
- const label = control.name || "ActiveX control";
12175
- 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) {
12176
12266
  return /* @__PURE__ */ jsx(
12177
12267
  "img",
12178
12268
  {
12179
- src: imageUrl,
12180
- alt: label,
12181
- title: `ActiveX control: ${label}`,
12269
+ src: view.imageUrl,
12270
+ alt: view.label,
12271
+ title: `ActiveX control: ${view.label}`,
12182
12272
  className: "absolute",
12183
- style: { left, top, width: clampedWidth, height: clampedHeight }
12273
+ style: { left: view.left, top: view.top, width: view.width, height: view.height }
12184
12274
  },
12185
12275
  `${control.relId}-${idx}`
12186
12276
  );
@@ -12189,12 +12279,12 @@ function ActiveXControlOverlay({
12189
12279
  "div",
12190
12280
  {
12191
12281
  className: "absolute",
12192
- 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)`,
12193
12283
  style: {
12194
- left,
12195
- top,
12196
- width: clampedWidth,
12197
- height: clampedHeight,
12284
+ left: view.left,
12285
+ top: view.top,
12286
+ width: view.width,
12287
+ height: view.height,
12198
12288
  display: "flex",
12199
12289
  alignItems: "center",
12200
12290
  justifyContent: "center",
@@ -12214,7 +12304,7 @@ function ActiveXControlOverlay({
12214
12304
  },
12215
12305
  children: [
12216
12306
  /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u2699" }),
12217
- /* @__PURE__ */ jsx("span", { style: { overflow: "hidden", textOverflow: "ellipsis" }, children: label })
12307
+ /* @__PURE__ */ jsx("span", { style: { overflow: "hidden", textOverflow: "ellipsis" }, children: view.label })
12218
12308
  ]
12219
12309
  },
12220
12310
  `${control.relId}-${idx}`
@@ -14528,6 +14618,8 @@ function MasterViewSidebar({
14528
14618
  onSelectLayout,
14529
14619
  onCollapse,
14530
14620
  onTabChange,
14621
+ crudActions,
14622
+ onCrudAction,
14531
14623
  onHandoutSlidesPerPageChange,
14532
14624
  onNotesMasterBackgroundChange,
14533
14625
  onHandoutMasterBackgroundChange,
@@ -14607,6 +14699,19 @@ function MasterViewSidebar({
14607
14699
  }
14608
14700
  )
14609
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
+ )) }),
14610
14715
  masterViewTab === "slides" && /* @__PURE__ */ jsx(
14611
14716
  SlideMastersList,
14612
14717
  {
@@ -18883,12 +18988,13 @@ function PresenterNotesRail({
18883
18988
  now,
18884
18989
  elapsed,
18885
18990
  activeCustomShow,
18991
+ authoredRange,
18886
18992
  onMove,
18887
18993
  onUpdateNotes
18888
18994
  }) {
18889
18995
  const { t } = useTranslation();
18890
18996
  const slide = slides[current];
18891
- const nextSlide = nextPresentedSlide(slides, current, activeCustomShow);
18997
+ const nextSlide = nextPresentedSlide(slides, current, activeCustomShow, authoredRange);
18892
18998
  const notesText = slide?.notes ?? "";
18893
18999
  const notesSegments = slide?.notesSegments;
18894
19000
  const [notesDraft, setNotesDraft] = useState(notesText);
@@ -19134,6 +19240,7 @@ function PresenterView({
19134
19240
  templateElements,
19135
19241
  presentationStartTime,
19136
19242
  activeCustomShow,
19243
+ authoredRange,
19137
19244
  onMovePresentationSlide,
19138
19245
  onExit,
19139
19246
  onOpenAudienceWindow,
@@ -19245,6 +19352,7 @@ function PresenterView({
19245
19352
  canvasSize,
19246
19353
  templateElements,
19247
19354
  activeCustomShow,
19355
+ authoredRange,
19248
19356
  now,
19249
19357
  elapsed,
19250
19358
  onMove: onMovePresentationSlide,
@@ -19302,6 +19410,8 @@ function MobilePresenterView({
19302
19410
  currentSlideIndex,
19303
19411
  canvasSize,
19304
19412
  templateElements,
19413
+ activeCustomShow,
19414
+ authoredRange,
19305
19415
  presentationStartTime,
19306
19416
  onMovePresentationSlide,
19307
19417
  onExit
@@ -19314,7 +19424,7 @@ function MobilePresenterView({
19314
19424
  }, []);
19315
19425
  const elapsed = mobileElapsedSince(presentationStartTime, now);
19316
19426
  const currentSlide = slides[currentSlideIndex];
19317
- const nextSlide = nextPresentedSlide(slides, currentSlideIndex);
19427
+ const nextSlide = nextPresentedSlide(slides, currentSlideIndex, activeCustomShow, authoredRange);
19318
19428
  if (!currentSlide) {
19319
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") });
19320
19430
  }
@@ -19847,6 +19957,7 @@ function AfterAnimationRow({
19847
19957
  onColorChange
19848
19958
  }) {
19849
19959
  const { t } = useTranslation();
19960
+ const { pushColor } = useRecentColors();
19850
19961
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
19851
19962
  /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
19852
19963
  /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-[11px]", children: t("pptx.animation.afterAnimation") }),
@@ -19870,7 +19981,10 @@ function AfterAnimationRow({
19870
19981
  type: "color",
19871
19982
  "aria-label": t("pptx.animation.afterAnimation.color"),
19872
19983
  value: color ?? "#808080",
19873
- onChange: (event) => onColorChange(event.target.value),
19984
+ onChange: (event) => {
19985
+ onColorChange(event.target.value);
19986
+ pushColor(event.target.value);
19987
+ },
19874
19988
  disabled: !canEdit,
19875
19989
  className: "h-6 w-10 rounded border border-border bg-transparent p-0"
19876
19990
  }
@@ -20852,17 +20966,105 @@ var POS_FIELDS = [
20852
20966
  ["W", "width"],
20853
20967
  ["H", "height"]
20854
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
+ }
20855
21056
  function ActionSettingsPanel({
20856
21057
  selectedElement,
20857
21058
  slides,
20858
21059
  canEdit,
21060
+ customShows,
20859
21061
  onUpdateElement
20860
21062
  }) {
20861
21063
  const { t } = useTranslation();
20862
21064
  const clickAction = selectedElement.actionClick ? pptxActionToElementAction(selectedElement.actionClick, "click") : void 0;
20863
21065
  const hoverAction = selectedElement.actionHover ? pptxActionToElementAction(selectedElement.actionHover, "hover") : void 0;
20864
- const updateAction = (trigger, type, url, slideIndex) => {
20865
- const ea = { trigger, type, url, slideIndex };
21066
+ const updateAction = (trigger, type, patch) => {
21067
+ const ea = { trigger, type, ...patch };
20866
21068
  const pa = elementActionToPptxAction(ea);
20867
21069
  if (trigger === "click") {
20868
21070
  onUpdateElement({ actionClick: pa });
@@ -20872,9 +21074,13 @@ function ActionSettingsPanel({
20872
21074
  };
20873
21075
  const changeType = (trigger, type) => {
20874
21076
  const current = trigger === "click" ? clickAction : hoverAction;
20875
- const target = { url: current?.url, slideIndex: current?.slideIndex };
21077
+ const target = {
21078
+ url: current?.url,
21079
+ slideIndex: current?.slideIndex,
21080
+ customShowId: current?.customShowId
21081
+ };
20876
21082
  if (canCommitActionType(type, target)) {
20877
- updateAction(trigger, type, target.url, target.slideIndex);
21083
+ updateAction(trigger, type, target);
20878
21084
  }
20879
21085
  };
20880
21086
  return /* @__PURE__ */ jsxs("div", { className: CARD, "data-pptx-action-settings": true, children: [
@@ -20891,9 +21097,9 @@ function ActionSettingsPanel({
20891
21097
  fallbackSlideIndex: selectedElement.actionClick?.targetSlideIndex,
20892
21098
  canEdit,
20893
21099
  slideCount: slides.length,
21100
+ customShows,
20894
21101
  onChangeType: (type) => changeType("click", type),
20895
- onChangeUrl: (url) => updateAction("click", "url", url),
20896
- onChangeSlide: (idx) => updateAction("click", "slide", void 0, idx)
21102
+ onChangeTarget: (type, patch) => updateAction("click", type, patch)
20897
21103
  },
20898
21104
  `click-${selectedElement.id}`
20899
21105
  ),
@@ -20908,9 +21114,9 @@ function ActionSettingsPanel({
20908
21114
  fallbackSlideIndex: selectedElement.actionHover?.targetSlideIndex,
20909
21115
  canEdit,
20910
21116
  slideCount: slides.length,
21117
+ customShows,
20911
21118
  onChangeType: (type) => changeType("hover", type),
20912
- onChangeUrl: (url) => updateAction("hover", "url", url),
20913
- onChangeSlide: (idx) => updateAction("hover", "slide", void 0, idx)
21119
+ onChangeTarget: (type, patch) => updateAction("hover", type, patch)
20914
21120
  },
20915
21121
  `hover-${selectedElement.id}`
20916
21122
  )
@@ -20926,9 +21132,9 @@ function ActionTriggerSection({
20926
21132
  fallbackSlideIndex,
20927
21133
  canEdit,
20928
21134
  slideCount,
21135
+ customShows,
20929
21136
  onChangeType,
20930
- onChangeUrl,
20931
- onChangeSlide
21137
+ onChangeTarget
20932
21138
  }) {
20933
21139
  const { t } = useTranslation();
20934
21140
  const [pendingType, setPendingType] = useState(void 0);
@@ -20950,35 +21156,18 @@ function ActionTriggerSection({
20950
21156
  children: ELEMENT_ACTION_TYPE_OPTIONS.map((o) => /* @__PURE__ */ jsx("option", { value: o.value, children: t(o.labelKey) }, o.value))
20951
21157
  }
20952
21158
  ),
20953
- effectiveType === "url" && /* @__PURE__ */ jsx(
20954
- "input",
20955
- {
20956
- type: "text",
20957
- disabled: !canEdit,
20958
- "aria-label": t("pptx.action.gotoUrl"),
20959
- className: cn(INPUT, "w-full"),
20960
- placeholder: "https://...",
20961
- value: action?.url ?? fallbackUrl ?? "",
20962
- onChange: (e) => onChangeUrl(e.target.value)
20963
- }
20964
- ),
20965
- effectiveType === "slide" && /* @__PURE__ */ jsx(
20966
- "input",
21159
+ /* @__PURE__ */ jsx(
21160
+ ActionTargetFields,
20967
21161
  {
20968
- type: "number",
20969
- disabled: !canEdit,
20970
- "aria-label": t("pptx.action.gotoSlide"),
20971
- className: cn(INPUT, "w-full"),
20972
- placeholder: t("pptx.action.slideNumberPlaceholder"),
20973
- min: 1,
20974
- max: slideCount,
20975
- value: (action?.slideIndex ?? fallbackSlideIndex ?? 0) + 1,
20976
- onChange: (e) => {
20977
- const idx = toSlideIndex(Number(e.target.value), slideCount);
20978
- if (idx !== void 0) {
20979
- onChangeSlide(idx);
20980
- }
20981
- }
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)
20982
21171
  }
20983
21172
  )
20984
21173
  ] });
@@ -21266,6 +21455,7 @@ function ChartAxisStyleOptions({
21266
21455
  onSetGridlineStyle
21267
21456
  }) {
21268
21457
  const { t } = useTranslation();
21458
+ const { pushColor } = useRecentColors();
21269
21459
  const rows = SCALE_AXES.map((row) => ({
21270
21460
  ...row,
21271
21461
  axis: axes?.find((a) => a.axisType === row.type)
@@ -21367,7 +21557,10 @@ function ChartAxisStyleOptions({
21367
21557
  disabled: !canEdit,
21368
21558
  className: "h-6 w-8 cursor-pointer rounded border border-border bg-transparent",
21369
21559
  value: axis.fontColor ?? "#000000",
21370
- onChange: (e) => onSetTitleStyle(type, { fontColor: e.target.value })
21560
+ onChange: (e) => {
21561
+ onSetTitleStyle(type, { fontColor: e.target.value });
21562
+ pushColor(e.target.value);
21563
+ }
21371
21564
  }
21372
21565
  )
21373
21566
  ] })
@@ -21390,7 +21583,10 @@ function ChartAxisStyleOptions({
21390
21583
  title: t("pptx.chart.gridlineColor"),
21391
21584
  className: "h-6 w-8 cursor-pointer rounded border border-border bg-transparent",
21392
21585
  value: spPr?.strokeColor ?? "#d9d9d9",
21393
- 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
+ }
21394
21590
  }
21395
21591
  ),
21396
21592
  /* @__PURE__ */ jsx(
@@ -21640,6 +21836,7 @@ function ChartDataPointMarkerOptions({
21640
21836
  onSetPointMarker
21641
21837
  }) {
21642
21838
  const { t } = useTranslation();
21839
+ const { pushColor } = useRecentColors();
21643
21840
  const [seriesIndex, setSeriesIndex] = useState(0);
21644
21841
  if (!MARKER_SUPPORTED_TYPES.has(chartType) || series.length === 0 || categories.length === 0) {
21645
21842
  return null;
@@ -21727,7 +21924,10 @@ function ChartDataPointMarkerOptions({
21727
21924
  title: t("pptx.chart.markerFill"),
21728
21925
  className: "h-6 w-8 cursor-pointer rounded border border-border bg-transparent",
21729
21926
  value: point2.marker.spPr?.fillColor ?? "#4472c4",
21730
- 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
+ }
21731
21931
  }
21732
21932
  )
21733
21933
  ] })
@@ -21745,6 +21945,7 @@ function ChartDataPointOptions({
21745
21945
  onSetPointLabel
21746
21946
  }) {
21747
21947
  const { t } = useTranslation();
21948
+ const { pushColor } = useRecentColors();
21748
21949
  const [seriesIndex, setSeriesIndex] = useState(0);
21749
21950
  if (series.length === 0 || categories.length === 0) {
21750
21951
  return null;
@@ -21795,7 +21996,10 @@ function ChartDataPointOptions({
21795
21996
  title: t("pptx.chart.pointFill"),
21796
21997
  className: "h-6 w-8 cursor-pointer rounded border border-border bg-transparent",
21797
21998
  value: point2?.spPr?.fillColor ?? activeSeries.color ?? "#4472c4",
21798
- onChange: (e) => onSetPointFill(seriesIndex, idx, e.target.value)
21999
+ onChange: (e) => {
22000
+ onSetPointFill(seriesIndex, idx, e.target.value);
22001
+ pushColor(e.target.value);
22002
+ }
21799
22003
  }
21800
22004
  ),
21801
22005
  point2?.spPr?.fillColor && /* @__PURE__ */ jsx(
@@ -22007,6 +22211,7 @@ function ChartMarkerOptions({
22007
22211
  onSetMarker
22008
22212
  }) {
22009
22213
  const { t } = useTranslation();
22214
+ const { pushColor } = useRecentColors();
22010
22215
  if (!MARKER_SUPPORTED_TYPES.has(chartType) || series.length === 0) {
22011
22216
  return null;
22012
22217
  }
@@ -22065,7 +22270,10 @@ function ChartMarkerOptions({
22065
22270
  disabled: !canEdit,
22066
22271
  className: "h-6 w-8 cursor-pointer rounded border border-border bg-transparent",
22067
22272
  value: marker.spPr?.fillColor ?? "#4472c4",
22068
- onChange: (e) => onSetMarker(i, { fillColor: e.target.value })
22273
+ onChange: (e) => {
22274
+ onSetMarker(i, { fillColor: e.target.value });
22275
+ pushColor(e.target.value);
22276
+ }
22069
22277
  }
22070
22278
  )
22071
22279
  ] })
@@ -22084,14 +22292,19 @@ function DebouncedColorInput({
22084
22292
  const [local, setLocal] = useState(value);
22085
22293
  const commitRef = useRef(onCommit);
22086
22294
  commitRef.current = onCommit;
22295
+ const { pushColor } = useRecentColors();
22087
22296
  useEffect(() => {
22088
22297
  setLocal(value);
22089
22298
  }, [value]);
22090
- const handleChange = useCallback((e) => {
22091
- const next = e.target.value;
22092
- setLocal(next);
22093
- commitRef.current(next);
22094
- }, []);
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
+ );
22095
22308
  return /* @__PURE__ */ jsx(
22096
22309
  "input",
22097
22310
  {
@@ -22156,6 +22369,71 @@ function ChartSeriesColorOptions({
22156
22369
  ] }, `${s.name}-${i}`)) })
22157
22370
  ] });
22158
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
+ }
22159
22437
  function ChartTrendlineOptions({
22160
22438
  chartType,
22161
22439
  series,
@@ -22536,6 +22814,14 @@ function ChartDataPanel({ selectedElement, canEdit, onUpdateElement }) {
22536
22814
  onToggleGridlines: toggleGridlines
22537
22815
  }
22538
22816
  ),
22817
+ /* @__PURE__ */ jsx(
22818
+ ChartSubtypeOptions,
22819
+ {
22820
+ chartData,
22821
+ canEdit,
22822
+ onUpdateChartData: updateChartData
22823
+ }
22824
+ ),
22539
22825
  /* @__PURE__ */ jsx(ChartDataLabelOptions, { style, canEdit, onUpdateStyle: updateStyle }),
22540
22826
  /* @__PURE__ */ jsx(ChartAxisOptions, { axes: chartData.axes, canEdit, onUpdateAxis: updateAxis }),
22541
22827
  /* @__PURE__ */ jsx(
@@ -23074,6 +23360,7 @@ function DebouncedColorInput2({
23074
23360
  const [local, setLocal] = useState(value);
23075
23361
  const commitRef = useRef(onCommit);
23076
23362
  commitRef.current = onCommit;
23363
+ const { pushColor } = useRecentColors();
23077
23364
  useEffect(() => {
23078
23365
  setLocal(value);
23079
23366
  }, [value]);
@@ -23082,7 +23369,8 @@ function DebouncedColorInput2({
23082
23369
  }, []);
23083
23370
  const handleBlur = useCallback(() => {
23084
23371
  commitRef.current(local);
23085
- }, [local]);
23372
+ pushColor(local);
23373
+ }, [local, pushColor]);
23086
23374
  const inputRef = useRef(null);
23087
23375
  useEffect(() => {
23088
23376
  const el = inputRef.current;
@@ -23091,10 +23379,11 @@ function DebouncedColorInput2({
23091
23379
  }
23092
23380
  const handler = () => {
23093
23381
  commitRef.current(el.value);
23382
+ pushColor(el.value);
23094
23383
  };
23095
23384
  el.addEventListener("change", handler);
23096
23385
  return () => el.removeEventListener("change", handler);
23097
- }, []);
23386
+ }, [pushColor]);
23098
23387
  return /* @__PURE__ */ jsx(
23099
23388
  "input",
23100
23389
  {
@@ -24911,6 +25200,108 @@ var safeNum = (raw, fallback) => {
24911
25200
  const n = Number(raw);
24912
25201
  return Number.isFinite(n) ? n : fallback;
24913
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
+ }
24914
25305
  function SelectRow({
24915
25306
  label,
24916
25307
  value,
@@ -24938,14 +25329,18 @@ function ColorPickerRow({
24938
25329
  value,
24939
25330
  disabled,
24940
25331
  prefix,
24941
- recentColors,
24942
25332
  onChange
24943
25333
  }) {
24944
25334
  const { t } = useTranslation();
25335
+ const { pushColor } = useRecentColors();
25336
+ const commit = (color) => {
25337
+ onChange(color);
25338
+ pushColor(color);
25339
+ };
24945
25340
  const handleEyedropper = async () => {
24946
25341
  const color = await openNativeEyeDropper();
24947
25342
  if (color) {
24948
- onChange(color);
25343
+ commit(color);
24949
25344
  }
24950
25345
  };
24951
25346
  return /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
@@ -24957,7 +25352,7 @@ function ColorPickerRow({
24957
25352
  type: "color",
24958
25353
  value,
24959
25354
  disabled,
24960
- onChange: (e) => onChange(e.target.value),
25355
+ onChange: (e) => commit(e.target.value),
24961
25356
  className: `h-8 flex-1 ${SEL2} px-1 ${DIS}`
24962
25357
  }
24963
25358
  ),
@@ -24976,35 +25371,21 @@ function ColorPickerRow({
24976
25371
  }
24977
25372
  )
24978
25373
  ] }),
24979
- /* @__PURE__ */ jsxs("div", { className: "mt-1 flex flex-wrap gap-1", children: [
24980
- THEME_COLOR_SWATCHES.map((c) => /* @__PURE__ */ jsx(
24981
- "button",
24982
- {
24983
- type: "button",
24984
- className: `${SWATCH} ${DIS}`,
24985
- style: { backgroundColor: c },
24986
- title: `${label} ${c}`,
24987
- "aria-label": `${label} ${c}`,
24988
- "data-pptx-compact": true,
24989
- disabled,
24990
- onClick: () => onChange(c)
24991
- },
24992
- `${prefix}-theme-${c}`
24993
- )),
24994
- recentColors?.map((c) => /* @__PURE__ */ jsx(
24995
- "button",
24996
- {
24997
- type: "button",
24998
- "data-pptx-compact": true,
24999
- className: "h-4 w-4 rounded border border-primary",
25000
- style: { backgroundColor: c },
25001
- title: `Recent ${c}`,
25002
- "aria-label": `Recent ${c}`,
25003
- onClick: () => onChange(c)
25004
- },
25005
- `${prefix}-recent-${c}`
25006
- ))
25007
- ] })
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 })
25008
25389
  ] });
25009
25390
  }
25010
25391
  function GradientStopRow({
@@ -25015,6 +25396,7 @@ function GradientStopRow({
25015
25396
  allStops
25016
25397
  }) {
25017
25398
  const { t } = useTranslation();
25399
+ const { pushColor } = useRecentColors();
25018
25400
  const patchStop = (patch) => {
25019
25401
  const next = allStops.map((s, i) => i === index ? { ...s, ...patch } : s);
25020
25402
  onUpdate(next);
@@ -25026,7 +25408,11 @@ function GradientStopRow({
25026
25408
  {
25027
25409
  type: "color",
25028
25410
  value: normalizeHexColor(stop.color, "#3b82f6"),
25029
- 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
+ },
25030
25416
  className: "h-7 w-10 rounded border border-border bg-muted"
25031
25417
  }
25032
25418
  ),
@@ -25072,106 +25458,6 @@ function GradientStopRow({
25072
25458
  ] })
25073
25459
  ] });
25074
25460
  }
25075
- function EffectField({
25076
- field,
25077
- style,
25078
- onUpdate
25079
- }) {
25080
- const { t } = useTranslation();
25081
- const fieldLabel = field.i18nKey ? t(field.i18nKey) : field.label;
25082
- const val = field.read(style);
25083
- const cls = `flex flex-col gap-1 ${field.span2 ? COL2 : ""}`;
25084
- if (field.type === "select" && field.options) {
25085
- return /* @__PURE__ */ jsxs("label", { className: cls, children: [
25086
- /* @__PURE__ */ jsx("span", { className: LBL2, children: fieldLabel }),
25087
- /* @__PURE__ */ jsx(
25088
- "select",
25089
- {
25090
- "aria-label": fieldLabel,
25091
- value: String(val),
25092
- onChange: (e) => {
25093
- const result = field.write(e.target.value, style);
25094
- onUpdate(typeof result === "function" ? result(style) : result);
25095
- },
25096
- className: SEL2,
25097
- children: field.options.map((o) => /* @__PURE__ */ jsx("option", { value: o.value, children: o.label }, o.value))
25098
- }
25099
- )
25100
- ] });
25101
- }
25102
- if (field.type === "color") {
25103
- return /* @__PURE__ */ jsxs("label", { className: cls, children: [
25104
- /* @__PURE__ */ jsx("span", { className: LBL2, children: fieldLabel }),
25105
- /* @__PURE__ */ jsx(
25106
- "input",
25107
- {
25108
- type: "color",
25109
- value: String(val),
25110
- onChange: (e) => {
25111
- const result = field.write(e.target.value, style);
25112
- onUpdate(typeof result === "function" ? result(style) : result);
25113
- },
25114
- className: `h-8 ${SEL2} px-1`
25115
- }
25116
- )
25117
- ] });
25118
- }
25119
- if (field.type === "checkbox") {
25120
- return /* @__PURE__ */ jsxs("label", { className: `flex items-center gap-2 ${field.span2 ? COL2 : ""}`, children: [
25121
- /* @__PURE__ */ jsx(
25122
- "input",
25123
- {
25124
- type: "checkbox",
25125
- checked: Boolean(val),
25126
- onChange: (e) => {
25127
- const result = field.write(e.target.checked, style);
25128
- onUpdate(typeof result === "function" ? result(style) : result);
25129
- },
25130
- className: "h-4 w-4"
25131
- }
25132
- ),
25133
- /* @__PURE__ */ jsx("span", { className: LBL2, children: fieldLabel })
25134
- ] });
25135
- }
25136
- if (field.type === "range") {
25137
- return /* @__PURE__ */ jsxs("label", { className: cls, children: [
25138
- /* @__PURE__ */ jsx("span", { className: LBL2, children: fieldLabel }),
25139
- /* @__PURE__ */ jsx(
25140
- "input",
25141
- {
25142
- type: "range",
25143
- min: field.min ?? 0,
25144
- max: field.max ?? 100,
25145
- value: Number(val),
25146
- onChange: (e) => {
25147
- const result = field.write(Number(e.target.value), style);
25148
- onUpdate(typeof result === "function" ? result(style) : result);
25149
- },
25150
- className: RNG
25151
- }
25152
- )
25153
- ] });
25154
- }
25155
- return /* @__PURE__ */ jsxs("label", { className: cls, children: [
25156
- /* @__PURE__ */ jsx("span", { className: LBL2, children: fieldLabel }),
25157
- /* @__PURE__ */ jsx(
25158
- "input",
25159
- {
25160
- type: "number",
25161
- min: field.min,
25162
- max: field.max,
25163
- step: field.step,
25164
- value: Number(val),
25165
- onChange: (e) => {
25166
- const n = safeNum(e.target.value, Number(val));
25167
- const result = field.write(n, style);
25168
- onUpdate(typeof result === "function" ? result(style) : result);
25169
- },
25170
- className: NUM2
25171
- }
25172
- )
25173
- ] });
25174
- }
25175
25461
  function FillAdvancedControls({
25176
25462
  style,
25177
25463
  gradientStops,
@@ -25381,7 +25667,6 @@ function QuickStylesGallery({
25381
25667
  function StrokeEffectsSection({
25382
25668
  style,
25383
25669
  isLine,
25384
- recentColors,
25385
25670
  onUpdateShapeStyle,
25386
25671
  onSetStrokeColor
25387
25672
  }) {
@@ -25393,7 +25678,6 @@ function StrokeEffectsSection({
25393
25678
  label: t("pptx.inspector.stroke"),
25394
25679
  prefix: "stroke",
25395
25680
  value: normalizeHexColor(style?.strokeColor, DEFAULT_STROKE_COLOR),
25396
- recentColors,
25397
25681
  onChange: onSetStrokeColor
25398
25682
  }
25399
25683
  ),
@@ -25526,7 +25810,6 @@ function FillStrokeProperties({
25526
25810
  selectedShapeStyle,
25527
25811
  selectedShapeType,
25528
25812
  selectedGradientStops,
25529
- recentColors,
25530
25813
  onUpdateShapeStyle,
25531
25814
  onSetFillColor,
25532
25815
  onSetStrokeColor
@@ -25625,7 +25908,6 @@ function FillStrokeProperties({
25625
25908
  {
25626
25909
  style,
25627
25910
  isLine: line,
25628
- recentColors,
25629
25911
  onUpdateShapeStyle,
25630
25912
  onSetStrokeColor
25631
25913
  }
@@ -25640,6 +25922,7 @@ function Text3DProperties({
25640
25922
  onUpdateTextStyle
25641
25923
  }) {
25642
25924
  const { t } = useTranslation();
25925
+ const { pushColor } = useRecentColors();
25643
25926
  const t3d = ts?.text3d;
25644
25927
  const hasExtrusion = Boolean(t3d?.extrusionHeight && t3d.extrusionHeight > 0);
25645
25928
  const update3d = (partial) => {
@@ -25693,7 +25976,10 @@ function Text3DProperties({
25693
25976
  {
25694
25977
  type: "color",
25695
25978
  value: normalizeHexColor(t3d?.extrusionColor, "#888888"),
25696
- onChange: (e) => update3d({ extrusionColor: e.target.value }),
25979
+ onChange: (e) => {
25980
+ update3d({ extrusionColor: e.target.value });
25981
+ pushColor(e.target.value);
25982
+ },
25697
25983
  className: COLOR_CLS
25698
25984
  }
25699
25985
  )
@@ -25859,6 +26145,7 @@ function AdvancedTextFormatting({
25859
26145
  numChange
25860
26146
  }) {
25861
26147
  const { t } = useTranslation();
26148
+ const { pushColor } = useRecentColors();
25862
26149
  return /* @__PURE__ */ jsxs("div", { className: "mt-2 rounded border border-border bg-card p-2 space-y-2", children: [
25863
26150
  /* @__PURE__ */ jsx("div", { className: "text-[11px] uppercase tracking-wide text-muted-foreground", children: t("pptx.textProperties.advancedTextHeading") }),
25864
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: [
@@ -25881,7 +26168,10 @@ function AdvancedTextFormatting({
25881
26168
  {
25882
26169
  type: "color",
25883
26170
  value: normalizeHexColor(ts?.highlightColor, "#ffff00"),
25884
- onChange: (e) => onUpdateTextStyle({ highlightColor: e.target.value }),
26171
+ onChange: (e) => {
26172
+ onUpdateTextStyle({ highlightColor: e.target.value });
26173
+ pushColor(e.target.value);
26174
+ },
25885
26175
  disabled: !canEdit,
25886
26176
  className: COLOR_CLS2
25887
26177
  }
@@ -25912,7 +26202,10 @@ function AdvancedTextFormatting({
25912
26202
  {
25913
26203
  type: "color",
25914
26204
  value: ts?.underlineColor || ts?.color || "#000000",
25915
- onChange: (e) => onUpdateTextStyle({ underlineColor: e.target.value }),
26205
+ onChange: (e) => {
26206
+ onUpdateTextStyle({ underlineColor: e.target.value });
26207
+ pushColor(e.target.value);
26208
+ },
25916
26209
  className: COLOR_CLS2
25917
26210
  }
25918
26211
  )
@@ -25943,7 +26236,10 @@ function AdvancedTextFormatting({
25943
26236
  {
25944
26237
  type: "color",
25945
26238
  value: ts?.textOutlineColor || "#000000",
25946
- onChange: (e) => onUpdateTextStyle({ textOutlineColor: e.target.value }),
26239
+ onChange: (e) => {
26240
+ onUpdateTextStyle({ textOutlineColor: e.target.value });
26241
+ pushColor(e.target.value);
26242
+ },
25947
26243
  className: COLOR_CLS2
25948
26244
  }
25949
26245
  )
@@ -26017,19 +26313,128 @@ function AdvancedTextFormatting({
26017
26313
  ] })
26018
26314
  ] });
26019
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
+ }
26020
26425
  function TextEffectsPanel({
26021
26426
  ts,
26022
26427
  onUpdateTextStyle,
26023
26428
  numChange
26024
26429
  }) {
26025
26430
  const { t } = useTranslation();
26431
+ const { pushColor } = useRecentColors();
26026
26432
  const hasShadow = Boolean(
26027
26433
  ts?.textShadowColor || typeof ts?.textShadowBlur === "number" && ts.textShadowBlur > 0
26028
26434
  );
26029
26435
  const hasGlow = Boolean(
26030
26436
  ts?.textGlowColor || typeof ts?.textGlowRadius === "number" && ts.textGlowRadius > 0
26031
26437
  );
26032
- const hasReflection = Boolean(ts?.textReflection);
26033
26438
  return /* @__PURE__ */ jsxs("div", { className: "mt-2 rounded border border-border bg-card p-2 space-y-2", children: [
26034
26439
  /* @__PURE__ */ jsx("div", { className: "text-[11px] uppercase tracking-wide text-muted-foreground", children: t("pptx.textEffects.title") }),
26035
26440
  /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
@@ -26070,7 +26475,10 @@ function TextEffectsPanel({
26070
26475
  {
26071
26476
  type: "color",
26072
26477
  value: normalizeHexColor(ts?.textShadowColor, "#000000"),
26073
- onChange: (e) => onUpdateTextStyle({ textShadowColor: e.target.value }),
26478
+ onChange: (e) => {
26479
+ onUpdateTextStyle({ textShadowColor: e.target.value });
26480
+ pushColor(e.target.value);
26481
+ },
26074
26482
  className: COLOR_CLS2
26075
26483
  }
26076
26484
  )
@@ -26175,7 +26583,10 @@ function TextEffectsPanel({
26175
26583
  {
26176
26584
  type: "color",
26177
26585
  value: normalizeHexColor(ts?.textGlowColor, "#ffff00"),
26178
- onChange: (e) => onUpdateTextStyle({ textGlowColor: e.target.value }),
26586
+ onChange: (e) => {
26587
+ onUpdateTextStyle({ textGlowColor: e.target.value });
26588
+ pushColor(e.target.value);
26589
+ },
26179
26590
  className: COLOR_CLS2
26180
26591
  }
26181
26592
  )
@@ -26216,107 +26627,7 @@ function TextEffectsPanel({
26216
26627
  ] })
26217
26628
  ] })
26218
26629
  ] }),
26219
- /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
26220
- /* @__PURE__ */ jsxs("label", { className: "inline-flex items-center gap-2 text-foreground", children: [
26221
- /* @__PURE__ */ jsx(
26222
- "input",
26223
- {
26224
- type: "checkbox",
26225
- checked: hasReflection,
26226
- onChange: (e) => {
26227
- if (e.target.checked) {
26228
- onUpdateTextStyle({
26229
- textReflection: true,
26230
- textReflectionBlur: 1,
26231
- textReflectionStartOpacity: 0.5,
26232
- textReflectionEndOpacity: 0,
26233
- textReflectionOffset: 3
26234
- });
26235
- } else {
26236
- onUpdateTextStyle({
26237
- textReflection: void 0,
26238
- textReflectionBlur: void 0,
26239
- textReflectionStartOpacity: void 0,
26240
- textReflectionEndOpacity: void 0,
26241
- textReflectionOffset: void 0
26242
- });
26243
- }
26244
- }
26245
- }
26246
- ),
26247
- t("pptx.textEffects.reflection")
26248
- ] }),
26249
- hasReflection && /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2 pl-4", children: [
26250
- /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
26251
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Blur" }),
26252
- /* @__PURE__ */ jsx(
26253
- "input",
26254
- {
26255
- type: "number",
26256
- min: 0,
26257
- max: 20,
26258
- step: 0.5,
26259
- value: Number(ts?.textReflectionBlur ?? 1).toFixed(1),
26260
- onChange: numChange((v) => ({
26261
- textReflectionBlur: Math.max(0, Math.min(20, v))
26262
- })),
26263
- className: INPUT_CLS3
26264
- }
26265
- )
26266
- ] }),
26267
- /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
26268
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Offset" }),
26269
- /* @__PURE__ */ jsx(
26270
- "input",
26271
- {
26272
- type: "number",
26273
- min: 0,
26274
- max: 20,
26275
- step: 1,
26276
- value: Math.round(ts?.textReflectionOffset ?? 3),
26277
- onChange: numChange((v) => ({
26278
- textReflectionOffset: Math.max(0, Math.min(20, v))
26279
- })),
26280
- className: INPUT_CLS3
26281
- }
26282
- )
26283
- ] }),
26284
- /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
26285
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: t("pptx.textEffects.startOpacity") }),
26286
- /* @__PURE__ */ jsx(
26287
- "input",
26288
- {
26289
- type: "number",
26290
- min: 0,
26291
- max: 1,
26292
- step: 0.05,
26293
- value: Number(ts?.textReflectionStartOpacity ?? 0.5).toFixed(2),
26294
- onChange: numChange((v) => ({
26295
- textReflectionStartOpacity: Math.max(0, Math.min(1, v))
26296
- })),
26297
- className: INPUT_CLS3
26298
- }
26299
- )
26300
- ] }),
26301
- /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
26302
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: t("pptx.textEffects.endOpacity") }),
26303
- /* @__PURE__ */ jsx(
26304
- "input",
26305
- {
26306
- type: "number",
26307
- min: 0,
26308
- max: 1,
26309
- step: 0.05,
26310
- value: Number(ts?.textReflectionEndOpacity ?? 0).toFixed(2),
26311
- onChange: numChange((v) => ({
26312
- textReflectionEndOpacity: Math.max(0, Math.min(1, v))
26313
- })),
26314
- className: INPUT_CLS3
26315
- }
26316
- )
26317
- ] })
26318
- ] })
26319
- ] })
26630
+ /* @__PURE__ */ jsx(TextReflectionSection, { ts, onUpdateTextStyle, numChange })
26320
26631
  ] });
26321
26632
  }
26322
26633
  function TextWarpGallery({
@@ -26390,7 +26701,6 @@ function TextAdvancedSections({
26390
26701
  /* @__PURE__ */ jsx(Text3DProperties, { ts, onUpdateTextStyle })
26391
26702
  ] });
26392
26703
  }
26393
- var EMPTY_RECENT_COLORS = [];
26394
26704
  function ShapeTextPanels({
26395
26705
  selectedElement,
26396
26706
  canEdit,
@@ -26426,7 +26736,6 @@ function ShapeTextPanels({
26426
26736
  selectedGradientStops: sanitizeGradientStops(
26427
26737
  selectedElement.shapeStyle?.fillGradientStops
26428
26738
  ),
26429
- recentColors: EMPTY_RECENT_COLORS,
26430
26739
  canEdit,
26431
26740
  onUpdateShapeStyle: onUpdateElementStyle,
26432
26741
  onSetFillColor: (hex) => onUpdateElementStyle({ fillColor: hex, fillMode: "solid" }),
@@ -26434,7 +26743,7 @@ function ShapeTextPanels({
26434
26743
  }
26435
26744
  )
26436
26745
  ] }),
26437
- hasTextProperties(selectedElement) && /* @__PURE__ */ jsxs("div", { className: CARD, children: [
26746
+ hasTextProperties(selectedElement) && /* @__PURE__ */ jsxs("div", { className: CARD, "data-pptx-text-card": true, children: [
26438
26747
  /* @__PURE__ */ jsx("div", { className: HEADING, children: t("pptx.text.title", "Text") }),
26439
26748
  /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-1.5 text-[11px]", children: [
26440
26749
  /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
@@ -26458,12 +26767,21 @@ function ShapeTextPanels({
26458
26767
  DebouncedColorInput,
26459
26768
  {
26460
26769
  disabled: !canEdit,
26770
+ ariaLabel: "Text Color",
26461
26771
  value: normalizeHexColor(selectedElement.textStyle?.color, "#000000"),
26462
26772
  className: "w-full h-7 rounded border border-border bg-transparent cursor-pointer",
26463
26773
  onCommit: (hex) => onUpdateTextStyle({ color: hex })
26464
26774
  }
26465
26775
  )
26466
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
+ ) }),
26467
26785
  /* @__PURE__ */ jsxs("div", { className: "flex gap-1 col-span-2", children: [
26468
26786
  /* @__PURE__ */ jsx(
26469
26787
  TextFormatToggle,
@@ -26746,6 +27064,7 @@ function SmartArtNodeStyleControls({
26746
27064
  canEdit,
26747
27065
  onChangeStyle
26748
27066
  }) {
27067
+ const { pushColor } = useRecentColors();
26749
27068
  const bold = Boolean(style?.bold);
26750
27069
  const italic = Boolean(style?.italic);
26751
27070
  return /* @__PURE__ */ jsxs(
@@ -26765,7 +27084,10 @@ function SmartArtNodeStyleControls({
26765
27084
  "aria-label": `Fill colour for ${label}`,
26766
27085
  className: "h-4 w-5 cursor-pointer rounded border border-border bg-transparent p-0 disabled:cursor-not-allowed",
26767
27086
  value: style?.fillColor ?? DEFAULT_FILL,
26768
- onChange: (e) => onChangeStyle(nodeId, { fillColor: e.target.value })
27087
+ onChange: (e) => {
27088
+ onChangeStyle(nodeId, { fillColor: e.target.value });
27089
+ pushColor(e.target.value);
27090
+ }
26769
27091
  }
26770
27092
  )
26771
27093
  ] }),
@@ -26779,7 +27101,10 @@ function SmartArtNodeStyleControls({
26779
27101
  "aria-label": `Font colour for ${label}`,
26780
27102
  className: "h-4 w-5 cursor-pointer rounded border border-border bg-transparent p-0 disabled:cursor-not-allowed",
26781
27103
  value: style?.fontColor ?? DEFAULT_FONT,
26782
- onChange: (e) => onChangeStyle(nodeId, { fontColor: e.target.value })
27104
+ onChange: (e) => {
27105
+ onChangeStyle(nodeId, { fontColor: e.target.value });
27106
+ pushColor(e.target.value);
27107
+ }
26783
27108
  }
26784
27109
  )
26785
27110
  ] }),
@@ -27343,6 +27668,7 @@ function TableCellPatternFill({
27343
27668
  onUpdateCellStyle
27344
27669
  }) {
27345
27670
  const { t } = useTranslation();
27671
+ const { pushColor } = useRecentColors();
27346
27672
  const translate = (key) => t(key);
27347
27673
  return /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
27348
27674
  /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-0.5", children: [
@@ -27369,7 +27695,10 @@ function TableCellPatternFill({
27369
27695
  disabled: !canEdit,
27370
27696
  className: "w-full h-7 rounded border border-border bg-transparent cursor-pointer",
27371
27697
  value: cellStyle.patternFillForeground ?? "#000000",
27372
- onChange: (e) => onUpdateCellStyle({ patternFillForeground: e.target.value })
27698
+ onChange: (e) => {
27699
+ onUpdateCellStyle({ patternFillForeground: e.target.value });
27700
+ pushColor(e.target.value);
27701
+ }
27373
27702
  }
27374
27703
  )
27375
27704
  ] }),
@@ -27382,7 +27711,10 @@ function TableCellPatternFill({
27382
27711
  disabled: !canEdit,
27383
27712
  className: "w-full h-7 rounded border border-border bg-transparent cursor-pointer",
27384
27713
  value: cellStyle.patternFillBackground ?? "#FFFFFF",
27385
- onChange: (e) => onUpdateCellStyle({ patternFillBackground: e.target.value })
27714
+ onChange: (e) => {
27715
+ onUpdateCellStyle({ patternFillBackground: e.target.value });
27716
+ pushColor(e.target.value);
27717
+ }
27386
27718
  }
27387
27719
  )
27388
27720
  ] })
@@ -27483,6 +27815,7 @@ function GradientControls({
27483
27815
  onUpdateCellStyle
27484
27816
  }) {
27485
27817
  const { t } = useTranslation();
27818
+ const { pushColor } = useRecentColors();
27486
27819
  const stops = cellStyle.gradientFillStops ?? [];
27487
27820
  const gradType = cellStyle.gradientFillType ?? "linear";
27488
27821
  const updateStop = (index, patch) => {
@@ -27539,7 +27872,10 @@ function GradientControls({
27539
27872
  disabled: !canEdit,
27540
27873
  className: "h-6 w-6 rounded border border-border cursor-pointer",
27541
27874
  value: stop.color,
27542
- onChange: (e) => updateStop(idx, { color: e.target.value })
27875
+ onChange: (e) => {
27876
+ updateStop(idx, { color: e.target.value });
27877
+ pushColor(e.target.value);
27878
+ }
27543
27879
  }
27544
27880
  ),
27545
27881
  /* @__PURE__ */ jsx(
@@ -27984,6 +28320,7 @@ function ElementInspectorBody({
27984
28320
  selectedElement,
27985
28321
  canEdit,
27986
28322
  slides,
28323
+ customShows,
27987
28324
  tableEditorState,
27988
28325
  mediaDataUrls,
27989
28326
  onUpdateElement,
@@ -28118,6 +28455,7 @@ function ElementInspectorBody({
28118
28455
  selectedElement,
28119
28456
  slides,
28120
28457
  canEdit,
28458
+ customShows,
28121
28459
  onUpdateElement
28122
28460
  }
28123
28461
  ),
@@ -28132,6 +28470,122 @@ function ElementInspectorBody({
28132
28470
  /* @__PURE__ */ jsx(LayerOrderButtons, { canEdit, onMoveLayer })
28133
28471
  ] });
28134
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
+ }
28135
28589
  function CommentBody({ text, mentions, className }) {
28136
28590
  const segments = commentTextSegments(text, mentions);
28137
28591
  if (!segments.some((segment) => segment.kind === "mention")) {
@@ -28153,6 +28607,59 @@ function CommentBody({ text, mentions, className }) {
28153
28607
  )
28154
28608
  ) });
28155
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 = [];
28156
28663
  function InspectorCommentRow({
28157
28664
  comment,
28158
28665
  canEdit,
@@ -28161,6 +28668,8 @@ function InspectorCommentRow({
28161
28668
  commentEditDraft,
28162
28669
  replyingToCommentId,
28163
28670
  replyDraftByCommentId,
28671
+ replyDraftMentionsByCommentId = EMPTY_REPLY_MENTIONS,
28672
+ commentAuthors = EMPTY_AUTHORS,
28164
28673
  onStartEditComment,
28165
28674
  onSaveEditComment,
28166
28675
  onCancelEditComment,
@@ -28323,6 +28832,8 @@ function InspectorCommentRow({
28323
28832
  commentEditDraft,
28324
28833
  replyingToCommentId,
28325
28834
  replyDraftByCommentId,
28835
+ replyDraftMentionsByCommentId,
28836
+ commentAuthors,
28326
28837
  onStartEditComment,
28327
28838
  onSaveEditComment,
28328
28839
  onCancelEditComment,
@@ -28339,50 +28850,19 @@ function InspectorCommentRow({
28339
28850
  `${reply.id}-${ri}`
28340
28851
  )) })
28341
28852
  ] }),
28342
- isReplying && onCancelReply && onReplyDraftChange && onSubmitReply && /* @__PURE__ */ jsxs("div", { className: "mt-2 space-y-1.5 pl-3 border-l-2 border-l-primary/40", children: [
28343
- /* @__PURE__ */ jsx(
28344
- "textarea",
28345
- {
28346
- value: replyDraft,
28347
- onChange: (e) => onReplyDraftChange(comment.id, e.target.value),
28348
- rows: 2,
28349
- placeholder: t("pptx.comments.replyPlaceholder", {
28350
- author: comment.author || "Author"
28351
- }),
28352
- 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",
28353
- onKeyDown: (e) => {
28354
- if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
28355
- e.preventDefault();
28356
- onSubmitReply(comment.id);
28357
- }
28358
- }
28359
- }
28360
- ),
28361
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
28362
- /* @__PURE__ */ jsxs(
28363
- "button",
28364
- {
28365
- type: "button",
28366
- 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",
28367
- onClick: () => onSubmitReply(comment.id),
28368
- disabled: replyDraft.trim().length === 0,
28369
- children: [
28370
- /* @__PURE__ */ jsx(LuReply, { className: "h-3 w-3" }),
28371
- t("pptx.comments.addReply")
28372
- ]
28373
- }
28374
- ),
28375
- /* @__PURE__ */ jsx(
28376
- "button",
28377
- {
28378
- type: "button",
28379
- className: "inline-flex items-center gap-1 rounded bg-muted px-2 py-1 text-[11px] text-foreground hover:bg-accent",
28380
- onClick: onCancelReply,
28381
- children: t("pptx.comments.cancel")
28382
- }
28383
- )
28384
- ] })
28385
- ] })
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
+ )
28386
28866
  ]
28387
28867
  }
28388
28868
  );
@@ -28395,8 +28875,11 @@ function InspectorCommentsSection({
28395
28875
  editingCommentId,
28396
28876
  commentEditDraft,
28397
28877
  commentDraft,
28878
+ commentDraftMentions,
28879
+ commentAuthors,
28398
28880
  replyingToCommentId,
28399
28881
  replyDraftByCommentId,
28882
+ replyDraftMentionsByCommentId,
28400
28883
  onSetCommentDraft,
28401
28884
  onAddComment,
28402
28885
  onDeleteComment,
@@ -28428,6 +28911,8 @@ function InspectorCommentsSection({
28428
28911
  commentEditDraft,
28429
28912
  replyingToCommentId,
28430
28913
  replyDraftByCommentId,
28914
+ replyDraftMentionsByCommentId,
28915
+ commentAuthors,
28431
28916
  onStartEditComment,
28432
28917
  onSaveEditComment,
28433
28918
  onCancelEditComment,
@@ -28450,21 +28935,18 @@ function InspectorCommentsSection({
28450
28935
  })
28451
28936
  ] }),
28452
28937
  /* @__PURE__ */ jsx(
28453
- "textarea",
28938
+ CommentMentionTextarea,
28454
28939
  {
28940
+ value: commentDraft,
28941
+ mentions: commentDraftMentions,
28942
+ authors: commentAuthors,
28455
28943
  rows: 2,
28456
28944
  placeholder: selectedElement ? t("pptx.comments.addOnElement", {
28457
28945
  element: getElementLabel(selectedElement)
28458
28946
  }) : t("pptx.comments.addPlaceholder"),
28459
- value: commentDraft,
28460
28947
  className: "w-full bg-muted border border-border rounded px-2 py-1 text-xs resize-y outline-none focus:border-primary",
28461
- onChange: (e) => onSetCommentDraft(e.target.value),
28462
- onKeyDown: (e) => {
28463
- if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
28464
- e.preventDefault();
28465
- onAddComment();
28466
- }
28467
- }
28948
+ onChange: onSetCommentDraft,
28949
+ onSubmitShortcut: onAddComment
28468
28950
  }
28469
28951
  ),
28470
28952
  /* @__PURE__ */ jsxs(
@@ -28781,26 +29263,78 @@ function DocumentPropertiesCard({
28781
29263
  ] })
28782
29264
  ] });
28783
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
+ }
28784
29299
  var CUSTOM_PRESET_VALUE = "";
29300
+ function sizesDiffer(a, b) {
29301
+ return a.widthEmu !== b.widthEmu || a.heightEmu !== b.heightEmu;
29302
+ }
28785
29303
  function SlideSizeCard({
28786
29304
  canvasSize,
28787
29305
  slideSizeEmu,
28788
29306
  canEdit,
28789
29307
  onUpdate,
28790
- onUpdateSlideSize
29308
+ onUpdateSlideSize,
29309
+ hasContent
28791
29310
  }) {
28792
29311
  const { t } = useTranslation();
28793
29312
  const selection = resolveSlideSizeSelection({ current: slideSizeEmu, canvas: canvasSize });
28794
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
+ };
28795
29322
  const handlePreset = (labelKey) => {
28796
29323
  const preset = SLIDE_SIZE_PRESETS.find((candidate) => candidate.labelKey === labelKey);
28797
29324
  if (!preset) {
28798
29325
  return;
28799
29326
  }
28800
- onUpdateSlideSize?.(slideSizeFromPreset(preset, selection.orientation));
29327
+ applyOrPromptSize(slideSizeFromPreset(preset, selection.orientation));
28801
29328
  };
28802
29329
  const handleOrientation = (orientation) => {
28803
- 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);
28804
29338
  };
28805
29339
  return /* @__PURE__ */ jsxs("div", { className: CARD, children: [
28806
29340
  /* @__PURE__ */ jsx("div", { className: HEADING, children: t("pptx.slideSize.title") }),
@@ -28856,7 +29390,8 @@ function SlideSizeCard({
28856
29390
  onChange: (e) => onUpdate({ ...canvasSize, [key]: Number(e.target.value) })
28857
29391
  }
28858
29392
  )
28859
- ] }, key)) })
29393
+ ] }, key)) }),
29394
+ pendingSize && /* @__PURE__ */ jsx(SlideSizeRescalePrompt, { onChoose: handleRescale })
28860
29395
  ] })
28861
29396
  ] });
28862
29397
  }
@@ -29515,6 +30050,7 @@ function PresentationPropertiesPanel({
29515
30050
  onUpdateCanvasSize,
29516
30051
  slideSizeEmu,
29517
30052
  onUpdateSlideSize,
30053
+ hasContent,
29518
30054
  notesCanvasSize,
29519
30055
  notesMaster,
29520
30056
  handoutMaster,
@@ -29574,7 +30110,8 @@ function PresentationPropertiesPanel({
29574
30110
  slideSizeEmu,
29575
30111
  canEdit,
29576
30112
  onUpdate: onUpdateCanvasSize,
29577
- onUpdateSlideSize
30113
+ onUpdateSlideSize,
30114
+ hasContent
29578
30115
  }
29579
30116
  ),
29580
30117
  /* @__PURE__ */ jsx(
@@ -29815,6 +30352,7 @@ function InspectorPane(props) {
29815
30352
  canEdit,
29816
30353
  activeSlide,
29817
30354
  slides,
30355
+ customShows,
29818
30356
  canvasSize,
29819
30357
  selectedElement,
29820
30358
  selectedElementIds,
@@ -29842,6 +30380,8 @@ function InspectorPane(props) {
29842
30380
  onApplyTheme,
29843
30381
  comments,
29844
30382
  commentDraft,
30383
+ commentDraftMentions,
30384
+ commentAuthors,
29845
30385
  editingCommentId,
29846
30386
  commentEditDraft,
29847
30387
  onSetCommentDraft,
@@ -29858,6 +30398,7 @@ function InspectorPane(props) {
29858
30398
  onSubmitReply,
29859
30399
  replyingToCommentId,
29860
30400
  replyDraftByCommentId,
30401
+ replyDraftMentionsByCommentId,
29861
30402
  onUpdateCanvasSize,
29862
30403
  slideSizeEmu,
29863
30404
  onUpdateSlideSize,
@@ -29949,6 +30490,7 @@ function InspectorPane(props) {
29949
30490
  selectedElement,
29950
30491
  canEdit,
29951
30492
  slides,
30493
+ customShows,
29952
30494
  tableEditorState,
29953
30495
  mediaDataUrls,
29954
30496
  onUpdateElement,
@@ -29982,6 +30524,7 @@ function InspectorPane(props) {
29982
30524
  onUpdateCanvasSize,
29983
30525
  slideSizeEmu,
29984
30526
  onUpdateSlideSize,
30527
+ hasContent: slides.some((slide) => slide.elements.length > 0),
29985
30528
  activeSlide,
29986
30529
  theme,
29987
30530
  onUpdateSlide
@@ -30010,8 +30553,11 @@ function InspectorPane(props) {
30010
30553
  editingCommentId,
30011
30554
  commentEditDraft,
30012
30555
  commentDraft,
30556
+ commentDraftMentions: commentDraftMentions ?? [],
30557
+ commentAuthors: commentAuthors ?? [],
30013
30558
  replyingToCommentId: replyingToCommentId ?? null,
30014
30559
  replyDraftByCommentId: replyDraftByCommentId ?? {},
30560
+ replyDraftMentionsByCommentId: replyDraftMentionsByCommentId ?? {},
30015
30561
  onSetCommentDraft,
30016
30562
  onAddComment,
30017
30563
  onDeleteComment,
@@ -33063,6 +33609,7 @@ function ViewerInspector({
33063
33609
  mode,
33064
33610
  activeSlide,
33065
33611
  slides,
33612
+ customShows,
33066
33613
  canvasSize,
33067
33614
  selectedElement,
33068
33615
  effectiveSelectedIds,
@@ -33070,6 +33617,7 @@ function ViewerInspector({
33070
33617
  sidebarPanelMode,
33071
33618
  activeSlideIndex,
33072
33619
  comments,
33620
+ commentAuthors,
33073
33621
  onSetSidebarPanelMode,
33074
33622
  onClose,
33075
33623
  onUpdateElementStyle,
@@ -33129,6 +33677,7 @@ function ViewerInspector({
33129
33677
  mode,
33130
33678
  activeSlide,
33131
33679
  slides,
33680
+ customShows,
33132
33681
  canvasSize,
33133
33682
  selectedElement,
33134
33683
  selectedElementIds: effectiveSelectedIds,
@@ -33161,9 +33710,11 @@ function ViewerInspector({
33161
33710
  onUpdateTagCollections,
33162
33711
  onApplyTheme,
33163
33712
  commentDraft,
33713
+ commentDraftMentions: comments.commentDraftMentionsBySlideId?.[slideId] ?? [],
33714
+ commentAuthors: commentAuthors ?? [],
33164
33715
  editingCommentId,
33165
33716
  commentEditDraft: editingCommentId ? comments.commentEditDraftByCommentId[editingCommentId] ?? "" : "",
33166
- onSetCommentDraft: (draft) => comments.handleCommentDraftChange(slideId, draft),
33717
+ onSetCommentDraft: (draft, mentions) => comments.handleCommentDraftChange(slideId, draft, mentions),
33167
33718
  onAddComment: () => comments.handleAddSlideComment(activeSlideIndex),
33168
33719
  onDeleteComment: (id) => comments.handleDeleteSlideComment(activeSlideIndex, id),
33169
33720
  onStartEditComment: (id) => comments.handleStartCommentEdit(slideId, id),
@@ -33176,10 +33727,11 @@ function ViewerInspector({
33176
33727
  onToggleCommentResolved: (id) => comments.handleToggleCommentResolved(activeSlideIndex, id),
33177
33728
  onStartReply: (id) => comments.handleStartReply(activeSlideIndex, id),
33178
33729
  onCancelReply: comments.handleCancelReply,
33179
- onReplyDraftChange: (commentId, draft) => comments.handleReplyDraftChange(commentId, draft),
33730
+ onReplyDraftChange: (commentId, draft, mentions) => comments.handleReplyDraftChange(commentId, draft, mentions),
33180
33731
  onSubmitReply: (commentId) => comments.handleSubmitReply(activeSlideIndex, commentId),
33181
33732
  replyingToCommentId: comments.replyingToCommentId,
33182
33733
  replyDraftByCommentId: comments.replyDraftByCommentId,
33734
+ replyDraftMentionsByCommentId: comments.replyDraftMentionsByCommentId,
33183
33735
  onUpdateCanvasSize: onSetCanvasSize,
33184
33736
  slideSizeEmu,
33185
33737
  onUpdateSlideSize: onSetSlideSize,
@@ -33423,6 +33975,7 @@ function ViewerToolbarSection(props) {
33423
33975
  customFontFamilies,
33424
33976
  ops,
33425
33977
  onSetMode,
33978
+ onPresentFromBeginning,
33426
33979
  onEnterPresenterView,
33427
33980
  onEnterRehearsalMode,
33428
33981
  onOpenSettings,
@@ -33441,7 +33994,10 @@ function ViewerToolbarSection(props) {
33441
33994
  isAiPanelOpen,
33442
33995
  onToggleAiPanel,
33443
33996
  isProtectedView,
33444
- onEnableEditing
33997
+ onEnableEditing,
33998
+ onSetSnapToGrid,
33999
+ onSetSnapToShape,
34000
+ onSetShowGuides
33445
34001
  } = props;
33446
34002
  const { t } = useTranslation();
33447
34003
  const handleAddAnimation = useCallback(
@@ -33618,7 +34174,7 @@ function ViewerToolbarSection(props) {
33618
34174
  case "slideShow":
33619
34175
  switch (action) {
33620
34176
  case "fromBeginning":
33621
- onSetMode("present");
34177
+ (onPresentFromBeginning ?? (() => onSetMode("present")))();
33622
34178
  break;
33623
34179
  case "presenterView":
33624
34180
  onEnterPresenterView();
@@ -33667,6 +34223,7 @@ function ViewerToolbarSection(props) {
33667
34223
  dialogs,
33668
34224
  zoom,
33669
34225
  onSetMode,
34226
+ onPresentFromBeginning,
33670
34227
  onEnterPresenterView,
33671
34228
  manipulation,
33672
34229
  handleOpenSlideSize
@@ -33675,7 +34232,7 @@ function ViewerToolbarSection(props) {
33675
34232
  const handleQuickAccessCommand = useCallback(
33676
34233
  (id) => {
33677
34234
  const handlers = {
33678
- presentFromStart: () => onSetMode("present"),
34235
+ presentFromStart: onPresentFromBeginning ?? (() => onSetMode("present")),
33679
34236
  print: printHandlers.handlePrint,
33680
34237
  exportPdf: exportHandlers.handleExportPdf,
33681
34238
  newSlide: slideOps.handleAddSlide,
@@ -33685,7 +34242,7 @@ function ViewerToolbarSection(props) {
33685
34242
  };
33686
34243
  handlers[id]?.();
33687
34244
  },
33688
- [onSetMode, printHandlers, exportHandlers, slideOps, s, zoom]
34245
+ [onSetMode, onPresentFromBeginning, printHandlers, exportHandlers, slideOps, s, zoom]
33689
34246
  );
33690
34247
  return /* @__PURE__ */ jsxs(Fragment, { children: [
33691
34248
  !dialogs.isNarrowViewport && /* @__PURE__ */ jsx(
@@ -33744,6 +34301,7 @@ function ViewerToolbarSection(props) {
33744
34301
  drawingWidth: s.drawingWidth,
33745
34302
  clipboardPayload: s.clipboardPayload,
33746
34303
  onSetMode,
34304
+ onPresentFromBeginning,
33747
34305
  onToggleSidebar: () => s.setIsSlidesPaneOpen((p) => !p),
33748
34306
  onToggleInspector: () => s.setIsInspectorPaneOpen((p) => !p),
33749
34307
  onOpenAnimationPanel: () => {
@@ -33788,9 +34346,9 @@ function ViewerToolbarSection(props) {
33788
34346
  onSetSpellCheckEnabled: s.setSpellCheckEnabled,
33789
34347
  onSetShowGrid: s.setShowGrid,
33790
34348
  onSetShowRulers: s.setShowRulers,
33791
- onSetShowGuides: s.setShowGuides,
33792
- onSetSnapToGrid: s.setSnapToGrid,
33793
- onSetSnapToShape: s.setSnapToShape,
34349
+ onSetShowGuides: onSetShowGuides ?? s.setShowGuides,
34350
+ onSetSnapToGrid: onSetSnapToGrid ?? s.setSnapToGrid,
34351
+ onSetSnapToShape: onSetSnapToShape ?? s.setSnapToShape,
33794
34352
  onAddGuide: dialogs.handleAddGuide,
33795
34353
  onAlignElements: manipulation.handleAlignElements,
33796
34354
  onDistributeElements: manipulation.handleDistributeElements,
@@ -34531,6 +35089,7 @@ function ViewerPresentationLayer(props) {
34531
35089
  templateElements,
34532
35090
  presentation,
34533
35091
  activeCustomShow,
35092
+ authoredRange,
34534
35093
  onExitPresentation,
34535
35094
  isMobile,
34536
35095
  onUpdateNotes
@@ -34544,6 +35103,8 @@ function ViewerPresentationLayer(props) {
34544
35103
  currentSlideIndex: presentation.presentationSlideIndex,
34545
35104
  canvasSize,
34546
35105
  templateElements,
35106
+ activeCustomShow,
35107
+ authoredRange,
34547
35108
  presentationStartTime: presentation.presentationStartTime,
34548
35109
  onMovePresentationSlide: presentation.movePresentationSlide,
34549
35110
  onExit: onExitPresentation
@@ -34556,6 +35117,7 @@ function ViewerPresentationLayer(props) {
34556
35117
  canvasSize,
34557
35118
  templateElements,
34558
35119
  activeCustomShow,
35120
+ authoredRange,
34559
35121
  presentationStartTime: presentation.presentationStartTime,
34560
35122
  onMovePresentationSlide: presentation.movePresentationSlide,
34561
35123
  onExit: onExitPresentation,
@@ -34912,14 +35474,14 @@ ${url}`)) {
34912
35474
  [viewerOptions, t]
34913
35475
  );
34914
35476
  const handleActionClick = useCallback(
34915
- (_elementId, action) => {
35477
+ (elementId, action) => {
34916
35478
  if (mode === "present") {
34917
35479
  const resolved = resolvePresentationAction(action, { slideCount: slides.length });
34918
35480
  if (resolved.intent.kind === "openUrl") {
34919
35481
  openExternalUrl(resolved.intent.url);
34920
35482
  return;
34921
35483
  }
34922
- presentation.handlePresentationAction(action);
35484
+ presentation.handlePresentationAction(action, elementId);
34923
35485
  } else if (action.url) {
34924
35486
  openExternalUrl(action.url);
34925
35487
  }
@@ -35323,7 +35885,7 @@ ${url}`)) {
35323
35885
  var AiChatPanel = lazy(async () => {
35324
35886
  const [{ useChat }, { default: Panel }] = await Promise.all([
35325
35887
  import('@ai-sdk/react'),
35326
- import('./AiChatPanel-BNFDBP4S.mjs')
35888
+ import('./AiChatPanel-NQZBZIRM.mjs')
35327
35889
  ]);
35328
35890
  function BoundAiChatPanel(props) {
35329
35891
  return /* @__PURE__ */ jsx(Panel, { ...props, useChat });
@@ -36230,7 +36792,10 @@ function ViewerSidePanels(props) {
36230
36792
  aiBridge,
36231
36793
  aiPanel
36232
36794
  } = props;
36233
- const handleSetSlideSize = (size) => {
36795
+ const handleSetSlideSize = (size, rescaleMode) => {
36796
+ if (rescaleMode && s.slideSizeEmu) {
36797
+ s.setSlides(scaleSlidesForSizeChange(slides, s.slideSizeEmu, size, rescaleMode));
36798
+ }
36234
36799
  s.setSlideSizeEmu(size);
36235
36800
  s.setCanvasSize(slideSizeToCanvasPx(size));
36236
36801
  history.markDirty();
@@ -36249,6 +36814,7 @@ function ViewerSidePanels(props) {
36249
36814
  mode,
36250
36815
  activeSlide: effectiveSlide,
36251
36816
  slides,
36817
+ customShows: s.customShows,
36252
36818
  canvasSize,
36253
36819
  selectedElement,
36254
36820
  effectiveSelectedIds: s.effectiveSelectedIds,
@@ -36256,6 +36822,7 @@ function ViewerSidePanels(props) {
36256
36822
  sidebarPanelMode: s.sidebarPanelMode,
36257
36823
  activeSlideIndex,
36258
36824
  comments,
36825
+ commentAuthors: s.modernCommentAuthors,
36259
36826
  onSetSidebarPanelMode: s.setSidebarPanelMode,
36260
36827
  onClose: () => s.setIsInspectorPaneOpen(false),
36261
36828
  onUpdateElementStyle: ops.updateSelectedShapeStyle,
@@ -36396,6 +36963,7 @@ function ViewerMainContent(props) {
36396
36963
  themeHandlers,
36397
36964
  history,
36398
36965
  comments,
36966
+ masterViewCrud,
36399
36967
  zoom,
36400
36968
  isMobile: _isMobile = false,
36401
36969
  isTouchDevice: _isTouchDevice = false,
@@ -36480,6 +37048,8 @@ function ViewerMainContent(props) {
36480
37048
  onSelectLayout: dialogs.handleSelectLayout,
36481
37049
  onCollapse: dialogs.handleCloseMasterView,
36482
37050
  onTabChange: state.setMasterViewTab,
37051
+ crudActions: masterViewCrud.crudActions,
37052
+ onCrudAction: masterViewCrud.handleCrudAction,
36483
37053
  onHandoutSlidesPerPageChange: (count) => {
36484
37054
  state.setHandoutSlidesPerPage(count);
36485
37055
  state.setHandoutMaster(
@@ -36673,7 +37243,61 @@ function AutosaveRecoveryDialog({
36673
37243
  }
36674
37244
  );
36675
37245
  }
36676
- 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 }) {
36677
37301
  return /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2.5 cursor-pointer group select-none", children: [
36678
37302
  /* @__PURE__ */ jsxs("span", { className: "relative flex items-center justify-center w-4 h-4", children: [
36679
37303
  /* @__PURE__ */ jsx(
@@ -36682,6 +37306,7 @@ function ToggleRow({ checked, onChange, icon, label }) {
36682
37306
  type: "checkbox",
36683
37307
  checked,
36684
37308
  onChange: (e) => onChange(e.target.checked),
37309
+ "data-testid": testId,
36685
37310
  className: "peer sr-only"
36686
37311
  }
36687
37312
  ),
@@ -36695,25 +37320,33 @@ function ToggleRow({ checked, onChange, icon, label }) {
36695
37320
  ] });
36696
37321
  }
36697
37322
  function HeaderFooterPanel({
36698
- showDateTime,
36699
- showSlideNumber,
36700
- showFooter,
36701
- footerText,
36702
- onSetShowDateTime,
36703
- onSetShowSlideNumber,
36704
- onSetShowFooter,
36705
- onSetFooterText,
37323
+ headerFooter,
37324
+ onUpdate,
36706
37325
  onApplyToAll,
36707
37326
  onApplyToCurrent,
36708
37327
  onClose
36709
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
+ );
36710
37346
  const handleFooterTextChange = useCallback(
36711
- (e) => {
36712
- onSetFooterText(e.target.value);
36713
- },
36714
- [onSetFooterText]
37347
+ (e) => onUpdate({ footerText: e.target.value }),
37348
+ [onUpdate]
36715
37349
  );
36716
- const { t } = useTranslation();
36717
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: [
36718
37351
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-b border-border px-4 py-3", children: [
36719
37352
  /* @__PURE__ */ jsx("h2", { className: "text-sm font-semibold text-foreground", children: t("pptx.headerFooter.title") }),
@@ -36724,6 +37357,7 @@ function HeaderFooterPanel({
36724
37357
  onClick: onClose,
36725
37358
  className: "rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground transition-colors",
36726
37359
  "aria-label": t("pptx.headerFooter.close"),
37360
+ "data-testid": "header-footer-close",
36727
37361
  children: /* @__PURE__ */ jsx(LuX, { className: "w-4 h-4" })
36728
37362
  }
36729
37363
  )
@@ -36733,36 +37367,84 @@ function HeaderFooterPanel({
36733
37367
  ToggleRow,
36734
37368
  {
36735
37369
  checked: showDateTime,
36736
- onChange: onSetShowDateTime,
37370
+ onChange: (hasDateTime) => onUpdate({ hasDateTime }),
36737
37371
  icon: /* @__PURE__ */ jsx(LuCalendarDays, { className: "w-3.5 h-3.5" }),
36738
- label: t("pptx.headerFooter.dateAndTime")
37372
+ label: t("pptx.headerFooter.dateAndTime"),
37373
+ testId: "hf-date-time"
36739
37374
  }
36740
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
+ ] }),
36741
37399
  /* @__PURE__ */ jsx(
36742
37400
  ToggleRow,
36743
37401
  {
36744
37402
  checked: showSlideNumber,
36745
- onChange: onSetShowSlideNumber,
37403
+ onChange: (hasSlideNumber) => onUpdate({ hasSlideNumber }),
36746
37404
  icon: /* @__PURE__ */ jsx(LuHash, { className: "w-3.5 h-3.5" }),
36747
- label: t("pptx.headerFooter.slideNumber")
37405
+ label: t("pptx.headerFooter.slideNumber"),
37406
+ testId: "hf-slide-number"
36748
37407
  }
36749
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"
37417
+ }
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
+ ) }),
36750
37430
  /* @__PURE__ */ jsx(
36751
37431
  ToggleRow,
36752
37432
  {
36753
37433
  checked: showFooter,
36754
- onChange: onSetShowFooter,
37434
+ onChange: (hasFooter) => onUpdate({ hasFooter }),
36755
37435
  icon: /* @__PURE__ */ jsx(LuText, { className: "w-3.5 h-3.5" }),
36756
- label: t("pptx.headerFooter.footer")
37436
+ label: t("pptx.headerFooter.footer"),
37437
+ testId: "hf-footer"
36757
37438
  }
36758
37439
  ),
36759
- showFooter && /* @__PURE__ */ jsx("div", { className: "pl-6", children: /* @__PURE__ */ jsx(
37440
+ showFooterText && /* @__PURE__ */ jsx("div", { className: "pl-6", children: /* @__PURE__ */ jsx(
36760
37441
  "input",
36761
37442
  {
36762
37443
  type: "text",
36763
- value: footerText,
37444
+ value: headerFooter.footerText ?? "",
36764
37445
  onChange: handleFooterTextChange,
36765
37446
  placeholder: t("pptx.headerFooter.footerPlaceholder"),
37447
+ "data-testid": "hf-footer-text",
36766
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"
36767
37449
  }
36768
37450
  ) })
@@ -36773,6 +37455,7 @@ function HeaderFooterPanel({
36773
37455
  {
36774
37456
  type: "button",
36775
37457
  onClick: onApplyToAll,
37458
+ "data-testid": "hf-apply-all",
36776
37459
  className: "rounded bg-accent px-3 py-1.5 text-xs font-medium text-foreground hover:bg-accent/80 transition-colors",
36777
37460
  children: t("pptx.headerFooter.applyToAll")
36778
37461
  }
@@ -36782,6 +37465,7 @@ function HeaderFooterPanel({
36782
37465
  {
36783
37466
  type: "button",
36784
37467
  onClick: onApplyToCurrent,
37468
+ "data-testid": "hf-apply-current",
36785
37469
  className: "rounded bg-primary px-3 py-1.5 text-xs font-medium text-white hover:bg-primary/80 transition-colors",
36786
37470
  children: t("pptx.headerFooter.applyToCurrent")
36787
37471
  }
@@ -36986,6 +37670,41 @@ function MobileChromeOverlay(props) {
36986
37670
  )
36987
37671
  ] });
36988
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
+ }
36989
37708
  function AddinTable({
36990
37709
  title,
36991
37710
  rows,
@@ -38131,6 +38850,109 @@ function useAiPanelController(input) {
38131
38850
  showChangeBatch
38132
38851
  };
38133
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
+ }
38134
38956
  var PowerPointViewer = forwardRef(
38135
38957
  // oxlint-disable-next-line prefer-arrow-callback -- named fn gives the forwardRef component its displayName
38136
38958
  function PowerPointViewer2(props, ref) {
@@ -38277,7 +39099,9 @@ var PowerPointViewer = forwardRef(
38277
39099
  const handleEnableEditing = useCallback(() => {
38278
39100
  setProtectedViewOverridden(true);
38279
39101
  }, []);
38280
- const canEdit = hostCanEdit && !isProtectedView;
39102
+ const readOnlyRec = useReadOnlyRecommendationState(content);
39103
+ const compatToastsState = useCompatibilityToastsState();
39104
+ const canEdit = hostCanEdit && !isProtectedView && !readOnlyRec.locked;
38281
39105
  const [isSettingsOpen, setIsSettingsOpen] = useState(false);
38282
39106
  const [isHeaderFooterOpen, setIsHeaderFooterOpen] = useState(false);
38283
39107
  const [autosaveEnabled, setAutosaveEnabled] = useState(true);
@@ -38304,6 +39128,14 @@ var PowerPointViewer = forwardRef(
38304
39128
  activeSlide,
38305
39129
  selectedElement
38306
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
+ );
38307
39139
  const settings = useMemo(
38308
39140
  () => ({
38309
39141
  autoSave: autosaveEnabled,
@@ -38418,11 +39250,18 @@ var PowerPointViewer = forwardRef(
38418
39250
  const mobile = useIsMobile();
38419
39251
  const { isMobile, isTouchDevice, isVirtualKeyboardOpen } = mobile;
38420
39252
  const resizablePanels = useResizablePanels();
38421
- const { gridSpacingPx, visibleSlideIndexes, slideSectionGroups, masterPseudoSlide } = useDerivedSlideState({
39253
+ const {
39254
+ gridSpacingPx,
39255
+ visibleSlideIndexes,
39256
+ slideSectionGroups,
39257
+ masterPseudoSlide,
39258
+ authoredRange
39259
+ } = useDerivedSlideState({
38422
39260
  slides,
38423
39261
  sections: state.sections,
38424
39262
  customShows: state.customShows,
38425
39263
  activeCustomShowId: state.activeCustomShowId,
39264
+ presentationProperties: state.presentationProperties,
38426
39265
  mode,
38427
39266
  activeLayout: state.activeLayout,
38428
39267
  activeMaster: state.activeMaster,
@@ -38501,7 +39340,10 @@ var PowerPointViewer = forwardRef(
38501
39340
  onToggleSubtitles: () => state.setPresentationProperties((prev) => ({
38502
39341
  ...prev,
38503
39342
  showSubtitles: !prev.showSubtitles
38504
- }))
39343
+ })),
39344
+ customShows: state.customShows,
39345
+ activeCustomShowId: state.activeCustomShowId,
39346
+ onSetActiveCustomShowId: state.setActiveCustomShowId
38505
39347
  });
38506
39348
  useTouchGestures({
38507
39349
  targetRef: zoom.canvasViewportRef,
@@ -38631,6 +39473,8 @@ var PowerPointViewer = forwardRef(
38631
39473
  // (SSRF/privacy-safe), so only an explicit `true` here lets remote
38632
39474
  // http(s) image sources actually load.
38633
39475
  allowExternalImages: viewerOptions.trust.allowExternalContent,
39476
+ setReadOnlyRecommendation: readOnlyRec.setRecommendation,
39477
+ setCompatToasts: compatToastsState.setToasts,
38634
39478
  canEdit,
38635
39479
  promptKeepInkAnnotations: viewerOptions.advanced.slideShowPromptKeepInkAnnotations,
38636
39480
  // File > Options > Advanced > "Image Size and Quality" (do-not-compress /
@@ -38658,6 +39502,17 @@ var PowerPointViewer = forwardRef(
38658
39502
  onSelectionChange,
38659
39503
  onSlideCountChange
38660
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
+ });
38661
39516
  const exportHandlers = useMemo(() => {
38662
39517
  const afterSuccessfulSave = (format) => {
38663
39518
  playFeedbackSound(viewerOptions);
@@ -38692,6 +39547,22 @@ var PowerPointViewer = forwardRef(
38692
39547
  history,
38693
39548
  onTemplateElementsChanged: handleTemplateElementsChanged
38694
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
+ });
38695
39566
  const applyAiTheme = useCallback(
38696
39567
  (updates) => {
38697
39568
  if (updates.colorScheme) {
@@ -38765,7 +39636,7 @@ var PowerPointViewer = forwardRef(
38765
39636
  ref: containerRef,
38766
39637
  tabIndex: 0,
38767
39638
  className: "h-full w-full flex flex-col overflow-hidden outline-none",
38768
- 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: [
38769
39640
  mode !== "present" && /* @__PURE__ */ jsx(
38770
39641
  ViewerToolbarSection,
38771
39642
  {
@@ -38791,6 +39662,7 @@ var PowerPointViewer = forwardRef(
38791
39662
  customFontFamilies,
38792
39663
  ops: editorOps.ops,
38793
39664
  onSetMode: handleSetMode,
39665
+ onPresentFromBeginning: presentation.enterPresentModeFromBeginning,
38794
39666
  onEnterPresenterView: handleEnterPresenterView,
38795
39667
  onEnterRehearsalMode: handleEnterRehearsalMode,
38796
39668
  onOpenSettings: () => setIsSettingsOpen(true),
@@ -38812,7 +39684,18 @@ var PowerPointViewer = forwardRef(
38812
39684
  isAiPanelOpen: aiPanel.isOpen,
38813
39685
  onToggleAiPanel: aiPanel.toggle,
38814
39686
  isProtectedView,
38815
- 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
38816
39699
  }
38817
39700
  ),
38818
39701
  /* @__PURE__ */ jsx(
@@ -38839,6 +39722,7 @@ var PowerPointViewer = forwardRef(
38839
39722
  themeHandlers,
38840
39723
  history,
38841
39724
  comments: editorOps.comments,
39725
+ masterViewCrud,
38842
39726
  zoom,
38843
39727
  isMobile,
38844
39728
  isTouchDevice,
@@ -38898,6 +39782,14 @@ var PowerPointViewer = forwardRef(
38898
39782
  ] })
38899
39783
  }
38900
39784
  ),
39785
+ mode !== "present" && /* @__PURE__ */ jsx(
39786
+ CompatibilityToasts,
39787
+ {
39788
+ toasts: compatToastsState.toasts,
39789
+ onDismiss: compatToastsState.dismiss,
39790
+ onDismissAll: compatToastsState.dismissAll
39791
+ }
39792
+ ),
38901
39793
  /* @__PURE__ */ jsx(
38902
39794
  ViewerDialogGroup,
38903
39795
  {
@@ -38965,14 +39857,8 @@ var PowerPointViewer = forwardRef(
38965
39857
  isHeaderFooterOpen && /* @__PURE__ */ jsx(
38966
39858
  HeaderFooterPanel,
38967
39859
  {
38968
- showDateTime: state.headerFooter.hasDateTime ?? false,
38969
- showSlideNumber: state.headerFooter.hasSlideNumber ?? false,
38970
- showFooter: state.headerFooter.hasFooter ?? false,
38971
- footerText: state.headerFooter.footerText ?? "",
38972
- onSetShowDateTime: (hasDateTime) => state.setHeaderFooter((current) => ({ ...current, hasDateTime })),
38973
- onSetShowSlideNumber: (hasSlideNumber) => state.setHeaderFooter((current) => ({ ...current, hasSlideNumber })),
38974
- onSetShowFooter: (hasFooter) => state.setHeaderFooter((current) => ({ ...current, hasFooter })),
38975
- onSetFooterText: (footerText) => state.setHeaderFooter((current) => ({ ...current, footerText })),
39860
+ headerFooter: state.headerFooter,
39861
+ onUpdate: (patch) => state.setHeaderFooter((current) => ({ ...current, ...patch })),
38976
39862
  onApplyToAll: () => {
38977
39863
  history.markDirty();
38978
39864
  setIsHeaderFooterOpen(false);
@@ -39058,6 +39944,7 @@ var PowerPointViewer = forwardRef(
39058
39944
  templateElements: state.templateElements,
39059
39945
  presentation,
39060
39946
  activeCustomShow,
39947
+ authoredRange,
39061
39948
  onExitPresentation: () => handleSetMode("edit"),
39062
39949
  onUpdateNotes: propertyHandlers.handleUpdateNotes,
39063
39950
  isMobile