pptx-react-viewer 4.5.0 → 4.7.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 (137) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/README.md +34 -33
  3. package/dist/{AiChatPanel-P2N6X2KB.js → AiChatPanel-3YILWCBX.js} +28 -28
  4. package/dist/AiChatPanel-3YILWCBX.js.br +0 -0
  5. package/dist/AiChatPanel-3YILWCBX.js.gz +0 -0
  6. package/dist/{AiChatPanel-HXGCZPUX.mjs → AiChatPanel-X2MVL5UP.mjs} +4 -4
  7. package/dist/AiChatPanel-X2MVL5UP.mjs.br +0 -0
  8. package/dist/AiChatPanel-X2MVL5UP.mjs.gz +0 -0
  9. package/dist/{Model3DScene-PIFMH2TU.js → Model3DScene-G7P6ZAIO.js} +2 -2
  10. package/dist/Model3DScene-G7P6ZAIO.js.br +0 -0
  11. package/dist/Model3DScene-G7P6ZAIO.js.gz +0 -0
  12. package/dist/{Model3DScene-QXMMJRV3.mjs → Model3DScene-QFWI5CEE.mjs} +1 -1
  13. package/dist/Model3DScene-QFWI5CEE.mjs.br +0 -0
  14. package/dist/Model3DScene-QFWI5CEE.mjs.gz +0 -0
  15. package/dist/{chunk-T35BGKZG.js → chunk-2BM4GBFZ.js} +5 -5
  16. package/dist/chunk-2BM4GBFZ.js.br +0 -0
  17. package/dist/chunk-2BM4GBFZ.js.gz +0 -0
  18. package/dist/{chunk-ZF5S3HHW.mjs → chunk-5J6NW3YS.mjs} +55 -28
  19. package/dist/chunk-5J6NW3YS.mjs.br +0 -0
  20. package/dist/chunk-5J6NW3YS.mjs.gz +0 -0
  21. package/dist/{chunk-LYZQLV7R.js → chunk-AQIXKTAT.js} +13881 -8722
  22. package/dist/chunk-AQIXKTAT.js.br +0 -0
  23. package/dist/chunk-AQIXKTAT.js.gz +0 -0
  24. package/dist/{chunk-DX2JCSQ4.mjs → chunk-E5OIDWHO.mjs} +1 -1
  25. package/dist/chunk-E5OIDWHO.mjs.br +0 -0
  26. package/dist/chunk-E5OIDWHO.mjs.gz +0 -0
  27. package/dist/{chunk-6FVYG27J.js → chunk-FYAOOACZ.js} +241 -214
  28. package/dist/chunk-FYAOOACZ.js.br +0 -0
  29. package/dist/chunk-FYAOOACZ.js.gz +0 -0
  30. package/dist/{chunk-PRXJ3J5W.mjs → chunk-OECUSL2B.mjs} +129 -311
  31. package/dist/chunk-OECUSL2B.mjs.br +0 -0
  32. package/dist/chunk-OECUSL2B.mjs.gz +0 -0
  33. package/dist/{chunk-VZNIVS3X.mjs → chunk-QLDHUKH2.mjs} +13808 -8718
  34. package/dist/chunk-QLDHUKH2.mjs.br +0 -0
  35. package/dist/chunk-QLDHUKH2.mjs.gz +0 -0
  36. package/dist/{chunk-Y4VRYQQS.js → chunk-SR7ETIBF.js} +931 -1112
  37. package/dist/chunk-SR7ETIBF.js.br +0 -0
  38. package/dist/chunk-SR7ETIBF.js.gz +0 -0
  39. package/dist/{chunk-IDV2ITXM.mjs → chunk-UBYFLXAU.mjs} +1383 -208
  40. package/dist/chunk-UBYFLXAU.mjs.br +0 -0
  41. package/dist/chunk-UBYFLXAU.mjs.gz +0 -0
  42. package/dist/{chunk-UMQV2432.js → chunk-UIAU3NR2.js} +45 -0
  43. package/dist/chunk-UIAU3NR2.js.br +0 -0
  44. package/dist/chunk-UIAU3NR2.js.gz +0 -0
  45. package/dist/{chunk-UZFCFYK6.js → chunk-VF4RA27Q.js} +3245 -2070
  46. package/dist/chunk-VF4RA27Q.js.br +0 -0
  47. package/dist/chunk-VF4RA27Q.js.gz +0 -0
  48. package/dist/{chunk-APAVAD2A.mjs → chunk-WIEBQGQI.mjs} +45 -0
  49. package/dist/chunk-WIEBQGQI.mjs.br +0 -0
  50. package/dist/chunk-WIEBQGQI.mjs.gz +0 -0
  51. package/dist/i18n/de.cjs +71 -21
  52. package/dist/i18n/de.cjs.br +0 -0
  53. package/dist/i18n/de.cjs.gz +0 -0
  54. package/dist/i18n/de.mjs +71 -21
  55. package/dist/i18n/de.mjs.br +0 -0
  56. package/dist/i18n/de.mjs.gz +0 -0
  57. package/dist/i18n/es.cjs +71 -21
  58. package/dist/i18n/es.cjs.br +0 -0
  59. package/dist/i18n/es.cjs.gz +0 -0
  60. package/dist/i18n/es.mjs +71 -21
  61. package/dist/i18n/es.mjs.br +0 -0
  62. package/dist/i18n/es.mjs.gz +0 -0
  63. package/dist/i18n/fr.cjs +71 -21
  64. package/dist/i18n/fr.cjs.br +0 -0
  65. package/dist/i18n/fr.cjs.gz +0 -0
  66. package/dist/i18n/fr.mjs +71 -21
  67. package/dist/i18n/fr.mjs.br +0 -0
  68. package/dist/i18n/fr.mjs.gz +0 -0
  69. package/dist/i18n/zh-CN.cjs +49 -4
  70. package/dist/i18n/zh-CN.cjs.br +0 -0
  71. package/dist/i18n/zh-CN.cjs.gz +0 -0
  72. package/dist/i18n/zh-CN.mjs +49 -4
  73. package/dist/i18n/zh-CN.mjs.br +0 -0
  74. package/dist/i18n/zh-CN.mjs.gz +0 -0
  75. package/dist/i18n.js +4 -4
  76. package/dist/i18n.js.br +0 -0
  77. package/dist/i18n.js.gz +0 -0
  78. package/dist/i18n.mjs +1 -1
  79. package/dist/i18n.mjs.br +0 -0
  80. package/dist/i18n.mjs.gz +0 -0
  81. package/dist/index.d.ts +438 -13
  82. package/dist/index.js +105 -49
  83. package/dist/index.js.br +0 -0
  84. package/dist/index.js.gz +0 -0
  85. package/dist/index.mjs +6 -6
  86. package/dist/index.mjs.br +0 -0
  87. package/dist/index.mjs.gz +0 -0
  88. package/dist/internals.d.ts +501 -15
  89. package/dist/internals.js +105 -105
  90. package/dist/internals.js.br +0 -0
  91. package/dist/internals.js.gz +0 -0
  92. package/dist/internals.mjs +4 -4
  93. package/dist/internals.mjs.br +0 -0
  94. package/dist/internals.mjs.gz +0 -0
  95. package/dist/pptx-viewer.css +1 -1
  96. package/dist/pptx-viewer.css.br +0 -0
  97. package/dist/pptx-viewer.css.gz +0 -0
  98. package/dist/viewer/index.d.ts +515 -12
  99. package/dist/viewer/index.js +27 -27
  100. package/dist/viewer/index.js.br +0 -0
  101. package/dist/viewer/index.js.gz +0 -0
  102. package/dist/viewer/index.mjs +6 -6
  103. package/dist/viewer/index.mjs.br +3 -4
  104. package/dist/viewer/index.mjs.gz +0 -0
  105. package/package.json +1 -1
  106. package/dist/AiChatPanel-HXGCZPUX.mjs.br +0 -0
  107. package/dist/AiChatPanel-HXGCZPUX.mjs.gz +0 -0
  108. package/dist/AiChatPanel-P2N6X2KB.js.br +0 -0
  109. package/dist/AiChatPanel-P2N6X2KB.js.gz +0 -0
  110. package/dist/Model3DScene-PIFMH2TU.js.br +0 -0
  111. package/dist/Model3DScene-PIFMH2TU.js.gz +0 -0
  112. package/dist/Model3DScene-QXMMJRV3.mjs.br +0 -0
  113. package/dist/Model3DScene-QXMMJRV3.mjs.gz +0 -0
  114. package/dist/chunk-6FVYG27J.js.br +0 -0
  115. package/dist/chunk-6FVYG27J.js.gz +0 -0
  116. package/dist/chunk-APAVAD2A.mjs.br +0 -0
  117. package/dist/chunk-APAVAD2A.mjs.gz +0 -0
  118. package/dist/chunk-DX2JCSQ4.mjs.br +0 -0
  119. package/dist/chunk-DX2JCSQ4.mjs.gz +0 -0
  120. package/dist/chunk-IDV2ITXM.mjs.br +0 -0
  121. package/dist/chunk-IDV2ITXM.mjs.gz +0 -0
  122. package/dist/chunk-LYZQLV7R.js.br +0 -0
  123. package/dist/chunk-LYZQLV7R.js.gz +0 -0
  124. package/dist/chunk-PRXJ3J5W.mjs.br +0 -0
  125. package/dist/chunk-PRXJ3J5W.mjs.gz +0 -0
  126. package/dist/chunk-T35BGKZG.js.br +0 -0
  127. package/dist/chunk-T35BGKZG.js.gz +0 -0
  128. package/dist/chunk-UMQV2432.js.br +0 -0
  129. package/dist/chunk-UMQV2432.js.gz +0 -0
  130. package/dist/chunk-UZFCFYK6.js.br +0 -0
  131. package/dist/chunk-UZFCFYK6.js.gz +0 -0
  132. package/dist/chunk-VZNIVS3X.mjs.br +0 -0
  133. package/dist/chunk-VZNIVS3X.mjs.gz +0 -0
  134. package/dist/chunk-Y4VRYQQS.js.br +0 -0
  135. package/dist/chunk-Y4VRYQQS.js.gz +0 -0
  136. package/dist/chunk-ZF5S3HHW.mjs.br +0 -0
  137. package/dist/chunk-ZF5S3HHW.mjs.gz +0 -0
@@ -1,12 +1,12 @@
1
- import { computeFocusTargets, deckDataFieldChanged, aiChangeAnimationCss, changeGhostStyle, createChatHistoryStore, collectStoredChats, exportAiChatLogs, applyElementUpdate } from './chunk-DX2JCSQ4.mjs';
2
- import { useViewerOptions, useReadOnlyRecommendationState, useCompatibilityToastsState, useReducedMotion, useViewerState, useIsMobile, useResizablePanels, useDerivedSlideState, useZoomViewport, useEditorHistory, usePresentationSetup, useTouchGestures, useViewerDialogs, useEditorOperations, useViewerIntegration, useViewPreferencesSync, useLayoutSwitching, ViewerOptionsContext, Rendering3DFlagsContext, CollaborationProvider, useCollaboration, useCollaborationDocumentSync, useFollowMode, useBroadcastFollower, SlideBackgroundImageLayer, StaticElementRenderer, safePrompt, scopeLayoutOptionsToActiveSlide, ChartPartSelectionProvider, useToolbarVisibility, useKeyboardInsets, useModalDismissDrag, useViewerOptionsContext, useVirtualizedSlides, useSwipeNavigation, PresentationTransitionOverlay, RemoteSelectionOverlay, CollaborationCursorOverlay, useSheetDismissDrag, detectTargetType, parseEmailUrl, parseSlideFromUrl, ACTION_VERB_MAP, ElementRenderer, InlineCollaborationContext, SmartArtRenderer, playAnimationSound, ResizeHandles, renderStrokeView, useChartPartSelection, resolveSmartArtDataPalette } from './chunk-PRXJ3J5W.mjs';
3
- import { SHAPE_PRESETS, ANIMATION_PRESET_OPTIONS, cn, SLIDE_NAV_THUMBNAIL_WIDTH, TOOLBAR_SECTIONS, DEFAULT_SECTION_GROUP_ID, SHORTCUT_REFERENCE_ITEMS as SHORTCUT_REFERENCE_ITEMS$1, isConnectorOrLineElement, GRID_SIZE, MIN_ELEMENT_SIZE, CONNECTOR_ARROW_OPTIONS, ARROW_SIZE_OPTIONS, DEFAULT_FILL_COLOR, startMotionPathPreview, startPreviewAnimation, stopPreviewAnimation, DEFAULT_STROKE_COLOR, STROKE_DASH_OPTIONS } from './chunk-ZF5S3HHW.mjs';
4
- import { SWITCHABLE_LAYOUT_TYPES, compileEquationTemplateMathMl, buildUserFontFaceStyles, readStoredViewerPrefs, resolveThemeCatalogEntry, THEME_CATALOG, writeStoredViewerPrefs, openPptxFile, readBackstageRecentFile, resolveAutosaveActivation, buildThemeColorMap, viewerOptionsToPreferences, applyPreferenceToOptions, resolveHistoryDepth, applyAutoCorrect, resolveImageResolutionScale, resolveAutosaveIntervalMs, resolveAutosaveIntervalSeconds, shouldShowAutosaveRecoveryPrompt, resolveOptionRootClasses, resolve3DRenderingFlags, resolveSlideSizeSelection, RULER_THICKNESS, RULER_FONT_SIZE, buildPreviewElements, deriveSlideFieldContext, SLIDE_TRANSITION_OPTIONS, hiddenSlideCue, HIDDEN_SLIDE_SLASH_GRADIENT, HIDDEN_SLIDE_LABEL_KEY, visibleTemplateElements, normalizeHexColor, themeToCssVars, listAutosaveSnapshots, resolveExpiredAutosaveSnapshots, deleteAutosaveSnapshot, masterViewCrudActions, applyMasterViewCrudAction, masterViewCrudFailureKey, applyMotionPathPreset, resetSlideLayoutPath, DEFAULT_INSERT_CHART_KIND, hasCopyableFormat, templateSchemeFromTheme, createBackstagePresentation, playFeedbackSound, shouldDiscardAutosaveOnSuccessfulSave, setMasterViewBackgroundColor, canUseClipboard, runProgramNoticeStackStyle, compatToastStackStyle, printPropertiesFrameSlides, printPropertiesSlidesPerPage, PASTE_SPECIAL_OPTIONS, getDensePanelTouchTargetPx, shouldStickyActionRow, VIEWER_OPTIONS_TABS, DEFAULT_QUICK_ACCESS_COMMAND_IDS, isHeaderFooterDateTextVisible, isHeaderFooterHeaderTextVisible, isHeaderFooterFooterTextVisible, buildJoinCollaborationConfig, buildCreateCollaborationConfig, generateBroadcastRoomId, DEFAULT_BROADCAST_SERVER_URL, buildBroadcastViewerUrl, resolveTransportForServerUrl, getSlideBackgroundStyle, pushRecentColor, mruColorsPatch, shouldClearAutosaveCacheOnClose, filterCommands, resolveTitleBarStatusKey, TITLE_BAR_CLASSES, TITLE_BAR_DEFAULT_FILE_KEY, resolveScreenTip, masterViewBackgroundColor, buildFieldSubstitutionContext, shouldConfirmExternalHyperlink, safeOpenUrl, resolvePresentationAction, isPpactionUrl, parsePpactionUrl, isPresentationAdvanceClick, toggleBlackboard, PRESENT_TOOLBAR_CLASSES, buildContextMenuEntries, buildCanvasContextMenuEntries, isCurrentLayout, themeColorSchemesEqual, observeElementHeight, 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, extraQuickAccessCommands, TAB_ROW_ACTION_CLASSES, listBackstageRecentFiles, BACKSTAGE_NAV, BACKSTAGE_BACK_CLASSES, BACKSTAGE_NAV_CLASSES, hasTextProperties, COMMON_FONT_SIZES, textFontSizePtToPx, INSERT_CHART_TYPES, ACTION_BUTTON_PRESETS, CHARACTER_SPACING_OPTIONS, OFFICE_COLOR_SWATCHES, hasShapeProperties, shapeFillChange, shapeOutlineChange, readRibbonTransitionDraft, ribbonTransitionUpdates, playSlideTransitionPreview, RIBBON_TRANSITION_PRESETS, transitionSoundOptions, transitionSoundSelectedValue, DEFAULT_MOTION_PATH_PRESET_ID, SLIDE_SHOW_OPTIONS, slideShowOptionChange, readSlideShowOption, resolveSlidePaneClick, SLIDE_VIRTUALIZATION_THRESHOLD, buildSlidePaneContextMenuEntries, PRESENTATION_HIT_TEST_CSS, PRESENTATION_STAGE_ATTRIBUTE, buildStrokePathD, cursorForTool, annotationOverlayZIndex, presentationInkPath, resolveNotesSchematicBodyFontSizePx, PRESENTER_NAVIGATOR_LABEL_KEYS, PEN_COLORS, HIGHLIGHTER_COLORS, isBlackboardActive, buildLayoutPreviewGeometry, scaleSlidesForSizeChange, slideSizeToCanvasPx, resolveSelectionPaneRename, PRESET_THEMES, resolveNotesSegments, segmentsToEditorHtml, DEBOUNCE_MS, createPlainNotesSegments, parseSegmentsFromRichEditor, segmentsToPlainText, getCurrentParagraphIndex, segmentsToParagraphs, paragraphsToSegments, MAX_INDENT_LEVEL, INDENT_PX, isUrlSafe, buildNotesPrintHtml, MIN_TOUCH_TARGET_PX, 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, textFontSizePxToPt, buildFontCatalog, getSelectionTextStyleFlags, getInlineEditorSelectionResult, selectedParagraphBulletKind, elementBulletKind, selectionBulletKind, TEXT_DECORATION_FLAGS, nextToggleValue, buildThemeColorSwatchGrid, themeColorSwatchRows, findSelectedThemeSwatch, themeSwatchCommit, RIBBON_SHAPE_SWATCHES, canGroupSelection, canUngroupSelection, canSetStrokeWidth, strokeWidthOf, readSoundFileAsDataUrl, applyTransitionSoundFile, TRANSITION_SOUND_OTHER_VALUE, TRANSITION_SOUND_NONE_VALUE, clearTransitionSound, applyTransitionStockSound, transitionStockSoundId, getEffectSoundAsset, playAnimationRibbonPreview, ENTRANCE_PRESET_VALUES, EMPHASIS_PRESET_VALUES, EXIT_PRESET_VALUES, MOTION_PATH_FAMILIES, motionPathFamilyLabelKey, motionPathPresetsByFamily, motionPathPresetLabelKey, masterViewPseudoSlide, motionPathFor, setMotionPath, getShapeAdjustmentHandleDescriptors, shouldShowElementHandles, hasMultipleSelectedTableCells, computeAnchoredPopupPosition, applyTableStyleDelete, applyTableStyleMapChange, themeColorLabel, buildThemeColorGrid, THEME_COLOR_SCHEME_KEYS, COMMON_FONTS, handleReadingViewKey, getLocalStorageUsageSummary, saveViewerProfile, clearAllLocalViewerData, SLIDE_TEMPLATES, attachEditorImagePaste, authorConnectorBetweenSites, findEraserHitElementId, generateTicks, rulerDragToGuidePosition, resolveElementInteractivity, getElementTransformWithoutRotation, getElementTransform, buildChartQuickActionsDescriptor, applyChartElementToggle, CHART_QUICK_ACTION_BUTTON_SIZE, applyChartStylePreset, hideChartSeries, restoreFilteredSeries, getActiveXControlOverlayView, buildCommentMarkers, COMMENT_MARKER_SIZE, collectConnectorSiteCandidates, getConnectorEndpointHandles, findConnectorSiteNear, motionPathToSvgD, motionPathEndPixel, isEditableMotionPath, setMotionPathEnd, isElementLocked, isImageLikeElement, mergeSlideTransition, getElementLabel, TRIGGER_OPTIONS, mapSlideSorterKey, isEditorTextInputTarget, clampSorterZoom, buildSlideTemplateContent, buildFreeformShapeElement, buildLiveInkStrokeView, CONNECTOR_SITE_SNAP_PX, resolveConnectorEndpointUpdate, withConnectorEndpointUpdate, getShapeConnectionSites, elementLockTogglePatch, buildTableDataGrid, getDenseGridLayoutPlan, appendTableElementRow, removeLastTableElementRow, appendTableElementColumn, removeLastTableElementColumn, removeTableElementColumn, removeTableElementRow, setTableElementCellText, TABLE_STYLE_PRESETS, applyTableStylePreset, tableStyleAssignmentUpdate, evenColumnWidths, redistributeColumnWidth, evenRowHeights, patchChartData, collapseChartTitleRunsForEdit, chartGridlinesState, chartGridlinesPatch, seriesSecondaryAxisPatch, setChartCategoryLabel, setChartCellValue, addChartCategory, removeChartCategory, addChartSeries, removeChartSeries, setDataLabelsRangeCache, setChartAxisLogScale, setChartAxisTitleStyle, setChartAxisGridlineStyle, setChartSeriesMarker, setChartSeriesChartType, setChartDataPointFill, setChartDataPointExplosion, setChartDataPointMarker, setChartDataPointLabel, describeSmartArtBounds, canAddTopLevelNode, classifyExtraConnections, siblingIndex, siblingCount, canRemoveTopLevelNode, canInteractWithElement, buildOleObjectNamePatch, getOleObjectTypeLabel, sanitizeGradientStops, shouldShowAccessibilitySection, pptxActionToElementAction, withFrameSlides, withSlidesPerPage, applyThemeOverrideToSlide, COLOR_MAP_ALIAS_KEYS, DEFAULT_COLOR_MAP, schemaLabel, THEME_COLOR_SLOT_LABEL_KEYS, SLIDE_SIZE_PRESETS, TRANSITION_VALID_DIRECTIONS, TRANSITION_ORIENTATION_TYPES, TRANSITION_PATTERN_OPTIONS, TRANSITION_THRUBLK_TYPES, clampTransitionNumber, TRANSITION_SPEED_OPTIONS, TRANSITION_MORPH_OPTIONS, flattenTagCollections, resolveTemplateBackgroundRows, formatCommentTimestamp, commentMentionQuery, matchCommentMentionAuthors, buildAnimationTimelineRows, clearMotionPath, getEffectSoundState, setEffectSound, setEffectStockSound, setAfterAnimation, setAfterAnimationColor, DIRECTIONAL_PRESETS, buildAnimationTimelineBars, motionPathPresetIdForPath, EFFECT_SOUND_CATALOGUE, hasTiltData, normalizeTableStyleGuid, describeTableStyleEditor, TABLE_STYLE_EDITOR_PARTS, computeMergeCellRight, computeMergeCellDown, computeSplitCell, updateMergeAttrsInRawXml, resolveDisplayedChartType, CHART_TYPE_OPTIONS, chartDataLabelsTogglePatch, BAR3D_SHAPE_OPTIONS, bar3DShapePatch, RADAR_STYLE_OPTIONS, radarStylePatch, SURFACE_WIREFRAME_OPTIONS, surfaceWireframePatch, isSeriesUsingSecondaryAxis, listChartUserShapeRows, withChartUserShapeAdded, createDefaultChartUserShape, withChartUserShapeRowRemoved, withChartUserShapeRowTextUpdated, SMARTART_COLOR_SCHEME_LABEL_KEYS, SMARTART_STYLE_LABEL_KEYS, addSmartArtNodeAsChild, setSmartArtNodeStyle, removeSmartArtNode, addSiblingAfter, removeEmptyNode, demote, promote, updateSmartArtNodeText, reorder, clampCropValue, DUOTONE_PRESETS, ARTISTIC_EFFECTS, mediaTrimEndSeconds, trimmedMediaDurationMs, mediaTrimEndAbsoluteMs, mediaTrimEndMsFromAbsoluteMs, buildOleEditDialogDescriptor, buildOleContentUpdatePatch, applyOleSheetCellEdit, getOleSheetGrid, applyOleDocumentParagraphEdit, getOleDocumentParagraphs, applyOleNestedDeckElementTextEdit, getOleNestedDeckDetail, replaceOleFile, getNonVisualDescriptionFields, resolveActionType, ELEMENT_ACTION_TYPE_OPTIONS, elementActionToPptxAction, canCommitActionType, slideSizeFromPreset, withSlideSizeOrientation, TRANSITION_DIR_ARROWS, buildDirectionGrid, getSlideTransitionAnimations, SLIDE_TRANSITION_KEYFRAMES, updateTagInCollections, deleteTagFromCollections, addTagToCollections, commentTextSegments, COMMENT_MENTION_CLASS, COMMENT_MENTION_ATTRIBUTE, insertCommentMention, reorderAnimationTimelineRows, applyAnimationTimelineOrder, animationEffectLabel, TABLE_STYLE_BORDER_SIDES, applyTableStyleFieldEdit, createTableStyleEntry, addTableStyleToMap, deleteTableStyleFromMap, LBL, SEL, FILL_MODE_OPTIONS, SECTION_HEADING, NUM, getChartUserShapeGroupTransform, withChartUserShapeGroupChildAdded, createDefaultChartUserShapeGroupChild, withChartUserShapeRowUpdated, getChartUserShapeRowChartBox, withChartUserShapeRowFlipUpdated, withChartUserShapeRowRotationUpdated, withChartUserShapeRowChartBoxUpdated, switchSmartArtLayout, rebuildDrawingShapesIfCleared, mediaTrimEndMsFromSeconds, validateMediaTrimRange, 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, TABLE_STYLE_BORDER_SIDE_LABEL_KEYS, TABLE_STYLE_DASH_PRESETS, GRADIENT_TYPE_OPTIONS, PATTERN_OPTIONS, FILL_PATTERN_LABEL_KEYS, openNativeEyeDropper, toggleText3dExtrusion, BEVEL_PRESETS } from './chunk-VZNIVS3X.mjs';
5
- import { LOCALE_CATALOG, ALIGNMENT_LABEL_KEYS } from './chunk-APAVAD2A.mjs';
6
- import React4, { createContext, lazy, forwardRef, useEffect, useState, useCallback, useMemo, useRef, useId, Fragment as Fragment$1, useDeferredValue, useLayoutEffect, Suspense, useContext, useSyncExternalStore } from 'react';
1
+ import { computeFocusTargets, deckDataFieldChanged, aiChangeAnimationCss, changeGhostStyle, createChatHistoryStore, collectStoredChats, exportAiChatLogs, applyElementUpdate } from './chunk-E5OIDWHO.mjs';
2
+ import { useViewerOptions, useReadOnlyRecommendationState, useCompatibilityToastsState, useReducedMotion, useViewerState, useIsMobile, useResizablePanels, useDerivedSlideState, useZoomViewport, useEditorHistory, usePresentationSetup, useTouchGestures, useViewerDialogs, useEditorOperations, useViewerIntegration, useViewPreferencesSync, useLayoutSwitching, ViewerOptionsContext, Rendering3DFlagsContext, CollaborationProvider, useCollaboration, useCollaborationDocumentSync, useFollowMode, useBroadcastFollower, SlideBackgroundImageLayer, StaticElementRenderer, safePrompt, scopeLayoutOptionsToActiveSlide, ChartPartSelectionProvider, useToolbarVisibility, useKeyboardInsets, useModalDismissDrag, useViewerOptionsContext, useVirtualizedSlides, useSwipeNavigation, PresentationTransitionOverlay, RemoteSelectionOverlay, CollaborationCursorOverlay, useSheetDismissDrag, detectTargetType, parseEmailUrl, parseSlideFromUrl, ACTION_VERB_MAP, ElementRenderer, InlineCollaborationContext, SmartArtRenderer, playAnimationSound, ResizeHandles, imgSrc, renderStrokeView, useChartPartSelection, resolveSmartArtDataPalette } from './chunk-OECUSL2B.mjs';
3
+ import { SHAPE_PRESETS, ANIMATION_PRESET_OPTIONS, cn, SLIDE_NAV_THUMBNAIL_WIDTH, TOOLBAR_SECTIONS, DEFAULT_SECTION_GROUP_ID, SHORTCUT_REFERENCE_ITEMS as SHORTCUT_REFERENCE_ITEMS$1, isConnectorOrLineElement, GRID_SIZE, MIN_ELEMENT_SIZE, CONNECTOR_ARROW_OPTIONS, ARROW_SIZE_OPTIONS, DEFAULT_FILL_COLOR, startMotionPathPreview, startPreviewAnimation, stopPreviewAnimation, DEFAULT_STROKE_COLOR, STROKE_DASH_OPTIONS } from './chunk-5J6NW3YS.mjs';
4
+ import { EMPTY_RESOLVED_CUSTOMIZATION, SWITCHABLE_LAYOUT_TYPES, compileEquationTemplateMathMl, buildUserFontFaceStyles, readStoredViewerPrefs, resolveThemeCatalogEntry, THEME_CATALOG, writeStoredViewerPrefs, openPptxFile, readBackstageRecentFile, isFeatureEnabled, isDialogAvailable, resolveAutosaveActivation, buildThemeColorMap, viewerOptionsToPreferences, applyPreferenceToOptions, resolveHistoryDepth, applyAutoCorrect, resolveImageResolutionScale, resolveAutosaveIntervalMs, resolveAutosaveIntervalSeconds, isPanelVisible, shouldShowAutosaveRecoveryPrompt, resolveOptionRootClasses, resolve3DRenderingFlags, resolveSlideSizeSelection, RULER_THICKNESS, RULER_FONT_SIZE, buildPreviewElements, deriveSlideFieldContext, SLIDE_TRANSITION_OPTIONS, hiddenSlideCue, HIDDEN_SLIDE_SLASH_GRADIENT, HIDDEN_SLIDE_LABEL_KEY, visibleTemplateElements, normalizeHexColor, themeToCssVars, createCustomizationController, resolveEffectiveHiddenActions, listAutosaveSnapshots, resolveExpiredAutosaveSnapshots, deleteAutosaveSnapshot, masterViewCrudActions, applyMasterViewCrudAction, masterViewCrudFailureKey, applyMotionPathPreset, resetSlideLayoutPath, DEFAULT_INSERT_CHART_KIND, hasCopyableFormat, templateSchemeFromTheme, createBackstagePresentation, playFeedbackSound, shouldDiscardAutosaveOnSuccessfulSave, setMasterViewBackgroundColor, resolveEditPointsAvailability, canUseClipboard, runProgramNoticeStackStyle, compatToastStackStyle, printPropertiesFrameSlides, printPropertiesSlidesPerPage, PASTE_SPECIAL_OPTIONS, getDensePanelTouchTargetPx, shouldStickyActionRow, customizeOptionsTabs, VIEWER_OPTIONS_TABS, isOptionsPageVisible, DEFAULT_QUICK_ACCESS_COMMAND_IDS, isHeaderFooterDateTextVisible, isHeaderFooterHeaderTextVisible, isHeaderFooterFooterTextVisible, buildJoinCollaborationConfig, buildCreateCollaborationConfig, generateBroadcastRoomId, DEFAULT_BROADCAST_SERVER_URL, buildBroadcastViewerUrl, resolveTransportForServerUrl, getSlideBackgroundStyle, pushRecentColor, mruColorsPatch, shouldClearAutosaveCacheOnClose, canCropElement, cropSessionChanged, cancelCropUpdate, startCropSession, filterCommands, resolveTitleBarStatusKey, TITLE_BAR_CLASSES, TITLE_BAR_DEFAULT_FILE_KEY, resolveScreenTip, masterViewBackgroundColor, buildFieldSubstitutionContext, shouldConfirmExternalHyperlink, safeOpenUrl, resolvePresentationAction, isPpactionUrl, parsePpactionUrl, isPresentationAdvanceClick, toggleBlackboard, PRESENT_TOOLBAR_CLASSES, customizeContextMenuEntries, buildContextMenuEntries, customizeCanvasContextMenuEntries, buildCanvasContextMenuEntries, isCurrentLayout, themeColorSchemesEqual, observeElementHeight, 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, cropModeKeyAction, extraQuickAccessCommands, TAB_ROW_ACTION_CLASSES, customizeBackstageNav, BACKSTAGE_NAV, listBackstageRecentFiles, BACKSTAGE_BACK_CLASSES, BACKSTAGE_NAV_CLASSES, hasTextProperties, COMMON_FONT_SIZES, textFontSizePtToPx, INSERT_CHART_TYPES, ACTION_BUTTON_PRESETS, CHARACTER_SPACING_OPTIONS, OFFICE_COLOR_SWATCHES, hasShapeProperties, shapeFillChange, shapeOutlineChange, readRibbonTransitionDraft, ribbonTransitionUpdates, playSlideTransitionPreview, RIBBON_TRANSITION_PRESETS, transitionSoundOptions, transitionSoundSelectedValue, DEFAULT_MOTION_PATH_PRESET_ID, SLIDE_SHOW_OPTIONS, slideShowOptionChange, readSlideShowOption, resolveSlidePaneClick, SLIDE_VIRTUALIZATION_THRESHOLD, buildSlidePaneContextMenuEntries, isEditPointsEnabled, PRESENTATION_HIT_TEST_CSS, PRESENTATION_STAGE_ATTRIBUTE, buildStrokePathD, cursorForTool, annotationOverlayZIndex, presentationInkPath, resolveNotesSchematicBodyFontSizePx, PRESENTER_NAVIGATOR_LABEL_KEYS, PEN_COLORS, HIGHLIGHTER_COLORS, isBlackboardActive, clampFlyoutPosition, buildLayoutPreviewGeometry, scaleSlidesForSizeChange, slideSizeToCanvasPx, resolveSelectionPaneRename, PRESET_THEMES, resolveNotesSegments, segmentsToEditorHtml, DEBOUNCE_MS, createPlainNotesSegments, parseSegmentsFromRichEditor, segmentsToPlainText, getCurrentParagraphIndex, segmentsToParagraphs, paragraphsToSegments, MAX_INDENT_LEVEL, INDENT_PX, isUrlSafe, buildNotesPrintHtml, MIN_TOUCH_TARGET_PX, 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, customizeBackstageCards, backstageCardsFor, DEFAULT_VIEWER_PROFILE, resolveProfileInitial, AVATAR_COLOR_SWATCHES, resolveDefaultFontFamily, textFontSizePxToPt, buildFontCatalog, FREEFORM_TOOL_IDS, isDrawingToolVisible, FREEFORM_TOOL_LABEL_KEYS, getSelectionTextStyleFlags, getInlineEditorSelectionResult, selectedParagraphBulletKind, elementBulletKind, selectionBulletKind, TEXT_DECORATION_FLAGS, nextToggleValue, buildThemeColorSwatchGrid, themeColorSwatchRows, findSelectedThemeSwatch, themeSwatchCommit, RIBBON_SHAPE_SWATCHES, canGroupSelection, canUngroupSelection, canSetStrokeWidth, strokeWidthOf, readSoundFileAsDataUrl, applyTransitionSoundFile, TRANSITION_SOUND_OTHER_VALUE, TRANSITION_SOUND_NONE_VALUE, clearTransitionSound, applyTransitionStockSound, transitionStockSoundId, getEffectSoundAsset, playAnimationRibbonPreview, ENTRANCE_PRESET_VALUES, EMPHASIS_PRESET_VALUES, EXIT_PRESET_VALUES, MOTION_PATH_FAMILIES, motionPathFamilyLabelKey, motionPathPresetsByFamily, motionPathPresetLabelKey, masterViewPseudoSlide, motionPathFor, setMotionPath, getShapeAdjustmentHandleDescriptors, shouldShowElementHandles, MERGE_SHAPES_MENU_ITEMS, hasMultipleSelectedTableCells, computeAnchoredPopupPosition, applyTableStyleDelete, applyTableStyleMapChange, themeColorLabel, buildThemeColorGrid, THEME_COLOR_SCHEME_KEYS, COMMON_FONTS, handleReadingViewKey, getLocalStorageUsageSummary, saveViewerProfile, clearAllLocalViewerData, SLIDE_TEMPLATES, MERGE_SHAPES_LABEL_KEY, MERGE_SHAPES_HINT_KEY, CROP_LABEL_KEY, CROP_ASPECT_LABEL_KEY, CROP_ASPECT_GROUP_LABEL_KEYS, CROP_ASPECT_PRESETS, CROP_FILL_LABEL_KEY, CROP_FIT_LABEL_KEY, attachEditorImagePaste, authorConnectorBetweenSites, findEraserHitElementId, generateTicks, rulerDragToGuidePosition, resolveElementInteractivity, getElementTransformWithoutRotation, getElementTransform, buildChartQuickActionsDescriptor, applyChartElementToggle, CHART_QUICK_ACTION_BUTTON_SIZE, applyChartStylePreset, hideChartSeries, restoreFilteredSeries, buildCropOverlay, CROP_HANDLE_ARIA_KEY, getActiveXControlOverlayView, buildCommentMarkers, COMMENT_MARKER_SIZE, collectConnectorSiteCandidates, getConnectorEndpointHandles, findConnectorSiteNear, motionPathToSvgD, motionPathEndPixel, isEditableMotionPath, setMotionPathEnd, canEditElementPoints, isElementLocked, isImageLikeElement, mergeSlideTransition, getElementLabel, TRIGGER_OPTIONS, mapSlideSorterKey, isEditorTextInputTarget, clampSorterZoom, buildSlideTemplateContent, buildFreeformShapeElement, buildLiveInkStrokeView, beginCropDrag, CONNECTOR_SITE_SNAP_PX, resolveConnectorEndpointUpdate, withConnectorEndpointUpdate, getShapeConnectionSites, FreeformToolSession, attachOverlayKeyboard, EditPointsSession, EDIT_POINTS_STYLE, elementLockTogglePatch, buildTableDataGrid, getDenseGridLayoutPlan, appendTableElementRow, removeLastTableElementRow, appendTableElementColumn, removeLastTableElementColumn, removeTableElementColumn, removeTableElementRow, setTableElementCellText, TABLE_STYLE_PRESETS, applyTableStylePreset, tableStyleAssignmentUpdate, evenColumnWidths, redistributeColumnWidth, evenRowHeights, patchChartData, collapseChartTitleRunsForEdit, chartGridlinesState, chartGridlinesPatch, seriesSecondaryAxisPatch, setChartCategoryLabel, setChartCellValue, addChartCategory, removeChartCategory, addChartSeries, removeChartSeries, setDataLabelsRangeCache, setChartAxisLogScale, setChartAxisTitleStyle, setChartAxisGridlineStyle, setChartSeriesMarker, setChartSeriesChartType, setChartDataPointFill, setChartDataPointExplosion, setChartDataPointMarker, setChartDataPointLabel, describeSmartArtBounds, canAddTopLevelNode, classifyExtraConnections, siblingIndex, siblingCount, canRemoveTopLevelNode, canInteractWithElement, buildOleObjectNamePatch, getOleObjectTypeLabel, sanitizeGradientStops, shouldShowAccessibilitySection, pptxActionToElementAction, withFrameSlides, withSlidesPerPage, applyThemeOverrideToSlide, COLOR_MAP_ALIAS_KEYS, DEFAULT_COLOR_MAP, schemaLabel, THEME_COLOR_SLOT_LABEL_KEYS, SLIDE_SIZE_PRESETS, TRANSITION_VALID_DIRECTIONS, TRANSITION_ORIENTATION_TYPES, TRANSITION_PATTERN_OPTIONS, TRANSITION_THRUBLK_TYPES, clampTransitionNumber, TRANSITION_SPEED_OPTIONS, TRANSITION_MORPH_OPTIONS, flattenTagCollections, resolveTemplateBackgroundRows, formatCommentTimestamp, commentMentionQuery, matchCommentMentionAuthors, buildAnimationTimelineRows, clearMotionPath, setTrigger, setTriggerBookmark, getEffectSoundState, setEffectSound, setEffectStockSound, setAfterAnimation, setAfterAnimationColor, DIRECTIONAL_PRESETS, buildAnimationTimelineBars, motionPathPresetIdForPath, EFFECT_SOUND_CATALOGUE, listMediaBookmarkOptions, selectedBookmarkOptionValue, hasTiltData, toElementAxes, dragCropHandle, panCropImage, clientToSlidePoint, EDIT_POINTS_TARGET_ATTR, normalizeTableStyleGuid, describeTableStyleEditor, TABLE_STYLE_EDITOR_PARTS, computeMergeCellRight, computeMergeCellDown, computeSplitCell, updateMergeAttrsInRawXml, resolveDisplayedChartType, CHART_TYPE_OPTIONS, chartDataLabelsTogglePatch, BAR3D_SHAPE_OPTIONS, bar3DShapePatch, RADAR_STYLE_OPTIONS, radarStylePatch, SURFACE_WIREFRAME_OPTIONS, surfaceWireframePatch, isSeriesUsingSecondaryAxis, listChartUserShapeRows, withChartUserShapeAdded, createDefaultChartUserShape, withChartUserShapeRowRemoved, withChartUserShapeRowTextUpdated, SMARTART_COLOR_SCHEME_LABEL_KEYS, SMARTART_STYLE_LABEL_KEYS, addSmartArtNodeAsChild, setSmartArtNodeStyle, removeSmartArtNode, addSiblingAfter, removeEmptyNode, demote, promote, updateSmartArtNodeText, reorder, clampCropValue, DUOTONE_PRESETS, ARTISTIC_EFFECTS, mediaTrimEndSeconds, trimmedMediaDurationMs, mediaTrimEndAbsoluteMs, mediaTrimEndMsFromAbsoluteMs, buildOleEditDialogDescriptor, buildOleContentUpdatePatch, applyOleSheetCellEdit, getOleSheetGrid, applyOleDocumentParagraphEdit, getOleDocumentParagraphs, applyOleNestedDeckElementTextEdit, getOleNestedDeckDetail, replaceOleFile, getNonVisualDescriptionFields, resolveActionType, ELEMENT_ACTION_TYPE_OPTIONS, elementActionToPptxAction, canCommitActionType, slideSizeFromPreset, withSlideSizeOrientation, TRANSITION_DIR_ARROWS, buildDirectionGrid, getSlideTransitionAnimations, SLIDE_TRANSITION_KEYFRAMES, updateTagInCollections, deleteTagFromCollections, addTagToCollections, commentTextSegments, COMMENT_MENTION_CLASS, COMMENT_MENTION_ATTRIBUTE, insertCommentMention, reorderAnimationTimelineRows, applyAnimationTimelineOrder, animationEffectLabel, overlayPointerInput, TABLE_STYLE_BORDER_SIDES, applyTableStyleFieldEdit, createTableStyleEntry, addTableStyleToMap, deleteTableStyleFromMap, LBL, SEL, FILL_MODE_OPTIONS, SECTION_HEADING, NUM, getChartUserShapeGroupTransform, withChartUserShapeGroupChildAdded, createDefaultChartUserShapeGroupChild, withChartUserShapeRowUpdated, getChartUserShapeRowChartBox, withChartUserShapeRowFlipUpdated, withChartUserShapeRowRotationUpdated, withChartUserShapeRowChartBoxUpdated, switchSmartArtLayout, rebuildDrawingShapesIfCleared, mediaTrimEndMsFromSeconds, validateMediaTrimRange, 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, TABLE_STYLE_BORDER_SIDE_LABEL_KEYS, TABLE_STYLE_DASH_PRESETS, GRADIENT_TYPE_OPTIONS, PATTERN_OPTIONS, FILL_PATTERN_LABEL_KEYS, openNativeEyeDropper, toggleText3dExtrusion, BEVEL_PRESETS, cropFit, cropFill, cropToAspectRatio } from './chunk-QLDHUKH2.mjs';
5
+ import { LOCALE_CATALOG, ALIGNMENT_LABEL_KEYS } from './chunk-WIEBQGQI.mjs';
6
+ import React5, { createContext, lazy, forwardRef, useEffect, useState, useCallback, useMemo, useRef, useLayoutEffect, useSyncExternalStore, useId, useContext, Fragment as Fragment$1, useDeferredValue, Suspense, useReducer } from 'react';
7
7
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
8
8
  import { useTranslation } from 'react-i18next';
9
- import { 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, LuFilter, LuLockOpen, LuArrowDown, LuArrowUp, LuArrowRight, LuReply, LuRotateCw, LuBookmark } from 'react-icons/lu';
9
+ import { 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, LuSpline, LuAlignLeft, LuAlignCenter, LuAlignRight, LuAlignJustify, LuColumns3, LuAlignHorizontalSpaceAround, LuAlignVerticalSpaceAround, LuGroup, LuUngroup, LuMove, LuRadio, LuCombine, LuCrop, LuFilter, LuLockOpen, LuArrowDown, LuArrowUp, LuArrowRight, LuReply, LuRotateCw, LuBookmark } from 'react-icons/lu';
10
10
 
11
11
  var ViewerThemeContext = createContext(void 0);
12
12
  function ViewerThemeProvider({ theme, children }) {
@@ -806,6 +806,46 @@ function AnimationsSection(p) {
806
806
  ] }) })
807
807
  ] });
808
808
  }
809
+ var ShapeFormatContext = createContext(null);
810
+ function useShapeFormatContext() {
811
+ return useContext(ShapeFormatContext);
812
+ }
813
+ function RibbonMenu({
814
+ anchorRef,
815
+ className,
816
+ children
817
+ }) {
818
+ const [pos, setPos] = useState(null);
819
+ useEffect(() => {
820
+ const anchor = anchorRef.current;
821
+ if (!anchor) {
822
+ return;
823
+ }
824
+ const update = () => {
825
+ const { left, top } = computeAnchoredPopupPosition(anchor.getBoundingClientRect());
826
+ setPos(
827
+ (prev) => prev && prev.left === left && prev.top === top ? prev : { left: left ?? 0, top }
828
+ );
829
+ };
830
+ update();
831
+ anchor.addEventListener("mouseenter", update);
832
+ window.addEventListener("resize", update);
833
+ document.addEventListener("scroll", update, true);
834
+ return () => {
835
+ anchor.removeEventListener("mouseenter", update);
836
+ window.removeEventListener("resize", update);
837
+ document.removeEventListener("scroll", update, true);
838
+ };
839
+ }, [anchorRef]);
840
+ return /* @__PURE__ */ jsx(
841
+ "div",
842
+ {
843
+ className: cn("fixed z-50", className),
844
+ style: pos ? { left: pos.left, top: pos.top } : { visibility: "hidden" },
845
+ children
846
+ }
847
+ );
848
+ }
809
849
  var _b = "inline-flex items-center justify-center px-2.5 py-1.5 max-md:min-h-[44px] max-md:min-w-[44px] active:scale-95 active:opacity-80";
810
850
  var gB = `${_b} border-r border-border hover:bg-accent disabled:opacity-40 disabled:cursor-not-allowed`;
811
851
  var gL = `${_b} hover:bg-accent disabled:opacity-40 disabled:cursor-not-allowed`;
@@ -965,12 +1005,184 @@ var ATXT = [
965
1005
  { id: "right", i: /* @__PURE__ */ jsx(LuAlignRight, { className: ic }), labelKey: "pptx.ribbon.alignRight" },
966
1006
  { id: "justify", i: /* @__PURE__ */ jsx(LuAlignJustify, { className: ic }), labelKey: "pptx.ribbon.justify" }
967
1007
  ];
1008
+ function useRibbonDropdown() {
1009
+ const [open, setOpen] = useState(false);
1010
+ const ref = useRef(null);
1011
+ useEffect(() => {
1012
+ if (!open) {
1013
+ return;
1014
+ }
1015
+ const onMouseDown = (event) => {
1016
+ if (ref.current && !ref.current.contains(event.target)) {
1017
+ setOpen(false);
1018
+ }
1019
+ };
1020
+ const onKeyDown = (event) => {
1021
+ if (event.key === "Escape") {
1022
+ setOpen(false);
1023
+ }
1024
+ };
1025
+ document.addEventListener("mousedown", onMouseDown);
1026
+ document.addEventListener("keydown", onKeyDown);
1027
+ return () => {
1028
+ document.removeEventListener("mousedown", onMouseDown);
1029
+ document.removeEventListener("keydown", onKeyDown);
1030
+ };
1031
+ }, [open]);
1032
+ return { open, setOpen, ref };
1033
+ }
1034
+ var RIBBON_MENU_ITEM_CLASS = "flex items-center w-full px-3 py-1.5 text-xs text-left hover:bg-muted transition-colors";
1035
+ var RIBBON_MENU_SURFACE_CLASS = "rounded-lg border border-border bg-popover backdrop-blur-lg shadow-2xl py-1 min-w-36";
1036
+ var GROUPS = ["square", "portrait", "landscape"];
1037
+ function CropRibbonControls({ canEdit }) {
1038
+ const { t } = useTranslation();
1039
+ const crop = useShapeFormatContext()?.crop;
1040
+ const { open, setOpen, ref } = useRibbonDropdown();
1041
+ const enabled = canEdit && Boolean(crop?.canCrop);
1042
+ const active = Boolean(crop?.element);
1043
+ const label = t(CROP_LABEL_KEY);
1044
+ const hint = t("pptx.image.cropHint");
1045
+ const run = (action) => {
1046
+ setOpen(false);
1047
+ action();
1048
+ };
1049
+ return /* @__PURE__ */ jsxs("div", { className: "relative", ref, children: [
1050
+ /* @__PURE__ */ jsxs("div", { className: grp, children: [
1051
+ /* @__PURE__ */ jsx(
1052
+ "button",
1053
+ {
1054
+ type: "button",
1055
+ "data-pptx-ribbon-control": "crop",
1056
+ "aria-label": label,
1057
+ "aria-pressed": active,
1058
+ title: enabled ? label : hint,
1059
+ disabled: !enabled,
1060
+ className: cn(gB, active && "bg-accent text-accent-foreground"),
1061
+ onMouseDown: (e) => e.preventDefault(),
1062
+ onClick: () => crop?.toggle(),
1063
+ children: /* @__PURE__ */ jsx(LuCrop, { className: ic })
1064
+ }
1065
+ ),
1066
+ /* @__PURE__ */ jsx(
1067
+ "button",
1068
+ {
1069
+ type: "button",
1070
+ "data-pptx-ribbon-control": "crop-menu",
1071
+ "aria-label": t(CROP_ASPECT_LABEL_KEY),
1072
+ "aria-haspopup": "menu",
1073
+ "aria-expanded": open && enabled,
1074
+ title: enabled ? t(CROP_ASPECT_LABEL_KEY) : hint,
1075
+ disabled: !enabled,
1076
+ className: gL,
1077
+ onMouseDown: (e) => e.preventDefault(),
1078
+ onClick: () => setOpen((v) => !v),
1079
+ children: /* @__PURE__ */ jsx(LuChevronDown, { className: "w-3 h-3" })
1080
+ }
1081
+ )
1082
+ ] }),
1083
+ open && enabled && crop && /* @__PURE__ */ jsx(RibbonMenu, { anchorRef: ref, className: "pt-1", children: /* @__PURE__ */ jsxs("div", { role: "menu", "aria-label": label, className: RIBBON_MENU_SURFACE_CLASS, children: [
1084
+ GROUPS.map((group) => /* @__PURE__ */ jsxs("div", { role: "group", "aria-label": t(CROP_ASPECT_GROUP_LABEL_KEYS[group]), children: [
1085
+ /* @__PURE__ */ jsx(
1086
+ "div",
1087
+ {
1088
+ "aria-hidden": "true",
1089
+ className: "px-3 pt-1.5 pb-0.5 text-[10px] font-semibold text-muted-foreground",
1090
+ children: t(CROP_ASPECT_GROUP_LABEL_KEYS[group])
1091
+ }
1092
+ ),
1093
+ CROP_ASPECT_PRESETS.filter((preset) => preset.group === group).map((preset) => /* @__PURE__ */ jsx(
1094
+ "button",
1095
+ {
1096
+ type: "button",
1097
+ role: "menuitem",
1098
+ "data-pptx-crop-aspect": preset.id,
1099
+ className: RIBBON_MENU_ITEM_CLASS,
1100
+ onMouseDown: (e) => e.preventDefault(),
1101
+ onClick: () => run(() => crop.cropToAspect(preset.ratioWidth, preset.ratioHeight)),
1102
+ children: preset.id
1103
+ },
1104
+ preset.id
1105
+ ))
1106
+ ] }, group)),
1107
+ /* @__PURE__ */ jsx("hr", { className: "my-1 border-0 h-px bg-border" }),
1108
+ /* @__PURE__ */ jsx(
1109
+ "button",
1110
+ {
1111
+ type: "button",
1112
+ role: "menuitem",
1113
+ "data-pptx-crop-action": "fill",
1114
+ className: RIBBON_MENU_ITEM_CLASS,
1115
+ onMouseDown: (e) => e.preventDefault(),
1116
+ onClick: () => run(crop.fill),
1117
+ children: t(CROP_FILL_LABEL_KEY)
1118
+ }
1119
+ ),
1120
+ /* @__PURE__ */ jsx(
1121
+ "button",
1122
+ {
1123
+ type: "button",
1124
+ role: "menuitem",
1125
+ "data-pptx-crop-action": "fit",
1126
+ className: RIBBON_MENU_ITEM_CLASS,
1127
+ onMouseDown: (e) => e.preventDefault(),
1128
+ onClick: () => run(crop.fit),
1129
+ children: t(CROP_FIT_LABEL_KEY)
1130
+ }
1131
+ )
1132
+ ] }) })
1133
+ ] });
1134
+ }
1135
+ function MergeShapesMenu({ canEdit }) {
1136
+ const { t } = useTranslation();
1137
+ const commands = useShapeFormatContext();
1138
+ const { open, setOpen, ref } = useRibbonDropdown();
1139
+ const enabled = canEdit && Boolean(commands?.canMergeShapes);
1140
+ const label = t(MERGE_SHAPES_LABEL_KEY);
1141
+ return /* @__PURE__ */ jsxs("div", { className: "relative", ref, children: [
1142
+ /* @__PURE__ */ jsxs(
1143
+ "button",
1144
+ {
1145
+ type: "button",
1146
+ "data-pptx-ribbon-control": "merge-shapes",
1147
+ "aria-label": label,
1148
+ "aria-haspopup": "menu",
1149
+ "aria-expanded": open && enabled,
1150
+ title: enabled ? label : t(MERGE_SHAPES_HINT_KEY),
1151
+ disabled: !enabled,
1152
+ className: pill,
1153
+ onMouseDown: (e) => e.preventDefault(),
1154
+ onClick: () => setOpen((v) => !v),
1155
+ children: [
1156
+ /* @__PURE__ */ jsx(LuCombine, { className: ic }),
1157
+ /* @__PURE__ */ jsx(LuChevronDown, { className: "w-3 h-3" })
1158
+ ]
1159
+ }
1160
+ ),
1161
+ open && enabled && /* @__PURE__ */ jsx(RibbonMenu, { anchorRef: ref, className: "pt-1", children: /* @__PURE__ */ jsx("div", { role: "menu", "aria-label": label, className: RIBBON_MENU_SURFACE_CLASS, children: MERGE_SHAPES_MENU_ITEMS.map((item) => /* @__PURE__ */ jsx(
1162
+ "button",
1163
+ {
1164
+ type: "button",
1165
+ role: "menuitem",
1166
+ "data-pptx-merge-op": item.operation,
1167
+ className: RIBBON_MENU_ITEM_CLASS,
1168
+ onMouseDown: (e) => e.preventDefault(),
1169
+ onClick: () => {
1170
+ setOpen(false);
1171
+ commands?.mergeShapes(item.operation);
1172
+ },
1173
+ children: t(item.labelKey)
1174
+ },
1175
+ item.operation
1176
+ )) }) })
1177
+ ] });
1178
+ }
968
1179
  function ShapeArrangeExtras(p) {
969
1180
  const { t } = useTranslation();
970
1181
  const canGroup = canGroupSelection(p.canEdit, p.selectedCount, p.selectionGroupable);
971
1182
  const canUngroup = canUngroupSelection(p.canEdit, p.selectedElement);
972
1183
  const canStrokeWidth = canSetStrokeWidth(p.canEdit, p.selectedElement);
973
1184
  const strokeWidth = strokeWidthOf(p.selectedElement);
1185
+ const { isHidden } = useToolbarVisibility(p.hiddenActions);
974
1186
  return /* @__PURE__ */ jsxs(Fragment, { children: [
975
1187
  /* @__PURE__ */ jsxs("div", { className: grp, children: [
976
1188
  /* @__PURE__ */ jsx(
@@ -998,6 +1210,8 @@ function ShapeArrangeExtras(p) {
998
1210
  }
999
1211
  )
1000
1212
  ] }),
1213
+ !isHidden("mergeShapes") && /* @__PURE__ */ jsx(MergeShapesMenu, { canEdit: p.canEdit }),
1214
+ !isHidden("crop") && /* @__PURE__ */ jsx(CropRibbonControls, { canEdit: p.canEdit }),
1001
1215
  /* @__PURE__ */ jsx(
1002
1216
  "input",
1003
1217
  {
@@ -1102,7 +1316,8 @@ function ArrangeSection(p) {
1102
1316
  selectionGroupable: p.selectionGroupable,
1103
1317
  onGroupElements: p.onGroupElements,
1104
1318
  onUngroupElement: p.onUngroupElement,
1105
- onUpdateElementStyle: p.onUpdateElementStyle
1319
+ onUpdateElementStyle: p.onUpdateElementStyle,
1320
+ hiddenActions: p.hiddenActions
1106
1321
  }
1107
1322
  ),
1108
1323
  /* @__PURE__ */ jsxs("div", { className: grp, children: [
@@ -1178,8 +1393,8 @@ function ArrangeSection(p) {
1178
1393
  ] });
1179
1394
  }
1180
1395
  function useTransitionSoundPicker(activeSlide, onTransitionChange) {
1181
- const soundFileInputRef = React4.useRef(null);
1182
- const handleSoundFilePicked = React4.useCallback(
1396
+ const soundFileInputRef = React5.useRef(null);
1397
+ const handleSoundFilePicked = React5.useCallback(
1183
1398
  (file) => {
1184
1399
  void readSoundFileAsDataUrl(file).then((dataUrl) => {
1185
1400
  if (dataUrl) {
@@ -1190,7 +1405,7 @@ function useTransitionSoundPicker(activeSlide, onTransitionChange) {
1190
1405
  },
1191
1406
  [onTransitionChange]
1192
1407
  );
1193
- const handleSoundSelectChange = React4.useCallback(
1408
+ const handleSoundSelectChange = React5.useCallback(
1194
1409
  (event) => {
1195
1410
  const value = event.target.value;
1196
1411
  if (value === TRANSITION_SOUND_OTHER_VALUE) {
@@ -1209,7 +1424,7 @@ function useTransitionSoundPicker(activeSlide, onTransitionChange) {
1209
1424
  },
1210
1425
  [activeSlide, onTransitionChange]
1211
1426
  );
1212
- const handleSoundFileChange = React4.useCallback(
1427
+ const handleSoundFileChange = React5.useCallback(
1213
1428
  (event) => {
1214
1429
  const file = event.target.files?.[0];
1215
1430
  if (file) {
@@ -1220,7 +1435,7 @@ function useTransitionSoundPicker(activeSlide, onTransitionChange) {
1220
1435
  [handleSoundFilePicked]
1221
1436
  );
1222
1437
  const stockSoundId = transitionStockSoundId(activeSlide?.transition);
1223
- const handleSoundPreview = React4.useCallback(() => {
1438
+ const handleSoundPreview = React5.useCallback(() => {
1224
1439
  if (!stockSoundId) {
1225
1440
  return;
1226
1441
  }
@@ -1240,10 +1455,10 @@ function useTransitionSoundPicker(activeSlide, onTransitionChange) {
1240
1455
  function TransitionsSection(p) {
1241
1456
  const { t } = useTranslation();
1242
1457
  const canEdit = p.canEdit !== false;
1243
- const draft = React4.useMemo(() => readRibbonTransitionDraft(p.activeSlide), [p.activeSlide]);
1244
- const [durationBuffer, setDurationBuffer] = React4.useState(null);
1245
- const [advanceBuffer, setAdvanceBuffer] = React4.useState(null);
1246
- const commit = React4.useCallback(
1458
+ const draft = React5.useMemo(() => readRibbonTransitionDraft(p.activeSlide), [p.activeSlide]);
1459
+ const [durationBuffer, setDurationBuffer] = React5.useState(null);
1460
+ const [advanceBuffer, setAdvanceBuffer] = React5.useState(null);
1461
+ const commit = React5.useCallback(
1247
1462
  (changes) => {
1248
1463
  p.onTransitionChange(ribbonTransitionUpdates({ ...draft, ...changes }));
1249
1464
  },
@@ -1574,6 +1789,12 @@ function DrawSection(p) {
1574
1789
  ] })
1575
1790
  ] });
1576
1791
  }
1792
+ var ViewerCustomizationContext = createContext(
1793
+ EMPTY_RESOLVED_CUSTOMIZATION
1794
+ );
1795
+ function useViewerCustomizationContext() {
1796
+ return useContext(ViewerCustomizationContext);
1797
+ }
1577
1798
  function useHostEvent(ref, type, handler) {
1578
1799
  useEffect(() => {
1579
1800
  const host = ref.current;
@@ -1688,7 +1909,7 @@ function AccountPage() {
1688
1909
  return void 0;
1689
1910
  });
1690
1911
  };
1691
- const version = "4.4.0" ;
1912
+ const version = "4.6.0" ;
1692
1913
  return /* @__PURE__ */ jsxs("div", { className: "mt-8 max-w-[700px] space-y-6", children: [
1693
1914
  /* @__PURE__ */ jsxs("section", { className: cardClass, children: [
1694
1915
  /* @__PURE__ */ jsxs("h2", { className: "flex items-center gap-2 text-sm font-semibold", children: [
@@ -1902,8 +2123,10 @@ function BackstageCards({
1902
2123
  print: props.onPrint,
1903
2124
  share: props.onOpenShareDialog
1904
2125
  };
1905
- const cards = backstageCardsFor(page).filter(
1906
- (card) => card.id !== "saveAsPptm" || props.hasMacros
2126
+ const customization = useViewerCustomizationContext();
2127
+ const cards = customizeBackstageCards(
2128
+ backstageCardsFor(page).filter((card) => card.id !== "saveAsPptm" || props.hasMacros),
2129
+ customization
1907
2130
  );
1908
2131
  if (cards.length === 0) {
1909
2132
  return null;
@@ -1943,7 +2166,10 @@ function BackstageNavIcon({ page }) {
1943
2166
  }
1944
2167
  function FileSection(p) {
1945
2168
  const { t } = useTranslation();
1946
- const [page, setPage] = useState("home");
2169
+ const [requestedPage, setRequestedPage] = useState("home");
2170
+ const nav = customizeBackstageNav(BACKSTAGE_NAV, useViewerCustomizationContext());
2171
+ const offered = (id) => nav.some((item) => item.id === id);
2172
+ const page = offered(requestedPage) ? requestedPage : offered("home") ? "home" : nav.find((item) => item.id !== "save" && item.id !== "close")?.id ?? "home";
1947
2173
  const [query, setQuery] = useState("");
1948
2174
  const [recent, setRecent] = useState([]);
1949
2175
  const { isHidden } = useToolbarVisibility(p.hiddenActions);
@@ -1961,7 +2187,7 @@ function FileSection(p) {
1961
2187
  p.onClose();
1962
2188
  }
1963
2189
  };
1964
- const current = BACKSTAGE_NAV.find((item) => item.id === page);
2190
+ const current = nav.find((item) => item.id === page);
1965
2191
  const title = current ? t(current.labelKey, { defaultValue: current.label }) : t("pptx.backstage.nav.home");
1966
2192
  return /* @__PURE__ */ jsxs(
1967
2193
  "div",
@@ -1983,15 +2209,13 @@ function FileSection(p) {
1983
2209
  }
1984
2210
  ) }),
1985
2211
  /* @__PURE__ */ jsxs("nav", { className: "flex min-h-0 flex-1 flex-col overflow-y-auto pb-2 max-md:flex-row max-md:items-center max-md:overflow-y-visible max-md:pb-0", children: [
1986
- BACKSTAGE_NAV.filter(
1987
- (item) => !item.group && !(item.id === "export" && exportHidden)
1988
- ).map((item) => /* @__PURE__ */ jsxs(
2212
+ nav.filter((item) => !item.group && !(item.id === "export" && exportHidden)).map((item) => /* @__PURE__ */ jsxs(
1989
2213
  "button",
1990
2214
  {
1991
2215
  type: "button",
1992
2216
  "data-pptx-backstage-nav-item": true,
1993
2217
  "aria-current": page === item.id ? "page" : void 0,
1994
- onClick: () => item.id === "close" ? p.onClose() : item.id === "save" ? run(p.onSaveAsPptx) : setPage(item.id),
2218
+ onClick: () => item.id === "close" ? p.onClose() : item.id === "save" ? run(p.onSaveAsPptx) : setRequestedPage(item.id),
1995
2219
  className: `${BACKSTAGE_NAV_CLASSES.row} ${page === item.id ? BACKSTAGE_NAV_CLASSES.active : BACKSTAGE_NAV_CLASSES.inactive}`,
1996
2220
  children: [
1997
2221
  /* @__PURE__ */ jsx(BackstageNavIcon, { page: item.id }),
@@ -2001,13 +2225,13 @@ function FileSection(p) {
2001
2225
  item.id
2002
2226
  )),
2003
2227
  /* @__PURE__ */ jsx("div", { className: "flex-1 max-md:hidden" }),
2004
- BACKSTAGE_NAV.filter((item) => item.group).map((item) => /* @__PURE__ */ jsxs(
2228
+ nav.filter((item) => item.group).map((item) => /* @__PURE__ */ jsxs(
2005
2229
  "button",
2006
2230
  {
2007
2231
  type: "button",
2008
2232
  "data-pptx-backstage-nav-item": true,
2009
2233
  "aria-current": page === item.id ? "page" : void 0,
2010
- onClick: () => item.id === "options" && p.onOpenSettings ? run(p.onOpenSettings) : setPage(item.id),
2234
+ onClick: () => item.id === "options" && p.onOpenSettings ? run(p.onOpenSettings) : setRequestedPage(item.id),
2011
2235
  className: `${BACKSTAGE_NAV_CLASSES.row} ${page === item.id ? BACKSTAGE_NAV_CLASSES.active : BACKSTAGE_NAV_CLASSES.inactive}`,
2012
2236
  children: [
2013
2237
  /* @__PURE__ */ jsx(BackstageNavIcon, { page: item.id }),
@@ -2087,42 +2311,6 @@ function FileSection(p) {
2087
2311
  }
2088
2312
  );
2089
2313
  }
2090
- function RibbonMenu({
2091
- anchorRef,
2092
- className,
2093
- children
2094
- }) {
2095
- const [pos, setPos] = useState(null);
2096
- useEffect(() => {
2097
- const anchor = anchorRef.current;
2098
- if (!anchor) {
2099
- return;
2100
- }
2101
- const update = () => {
2102
- const { left, top } = computeAnchoredPopupPosition(anchor.getBoundingClientRect());
2103
- setPos(
2104
- (prev) => prev && prev.left === left && prev.top === top ? prev : { left: left ?? 0, top }
2105
- );
2106
- };
2107
- update();
2108
- anchor.addEventListener("mouseenter", update);
2109
- window.addEventListener("resize", update);
2110
- document.addEventListener("scroll", update, true);
2111
- return () => {
2112
- anchor.removeEventListener("mouseenter", update);
2113
- window.removeEventListener("resize", update);
2114
- document.removeEventListener("scroll", update, true);
2115
- };
2116
- }, [anchorRef]);
2117
- return /* @__PURE__ */ jsx(
2118
- "div",
2119
- {
2120
- className: cn("fixed z-50", className),
2121
- style: pos ? { left: pos.left, top: pos.top } : { visibility: "hidden" },
2122
- children
2123
- }
2124
- );
2125
- }
2126
2314
  function FontFamilyMenu(p) {
2127
2315
  const { t } = useTranslation();
2128
2316
  const groups = buildFontCatalog({
@@ -2130,7 +2318,7 @@ function FontFamilyMenu(p) {
2130
2318
  embeddedFonts: p.embeddedFonts,
2131
2319
  customFonts: p.customFonts
2132
2320
  });
2133
- return /* @__PURE__ */ jsx(RibbonMenu, { anchorRef: p.anchorRef, className: "flex flex-col w-64 pt-1", children: /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-border bg-popover backdrop-blur-lg shadow-2xl py-1 max-h-80 overflow-y-auto", children: groups.map((group, groupIndex) => /* @__PURE__ */ jsxs(React4.Fragment, { children: [
2321
+ return /* @__PURE__ */ jsx(RibbonMenu, { anchorRef: p.anchorRef, className: "flex flex-col w-64 pt-1", children: /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-border bg-popover backdrop-blur-lg shadow-2xl py-1 max-h-80 overflow-y-auto", children: groups.map((group, groupIndex) => /* @__PURE__ */ jsxs(React5.Fragment, { children: [
2134
2322
  /* @__PURE__ */ jsx(
2135
2323
  "div",
2136
2324
  {
@@ -2655,6 +2843,43 @@ function HomeSection(p) {
2655
2843
  sep
2656
2844
  ] });
2657
2845
  }
2846
+ var ICONS3 = {
2847
+ freeformShape: LuPenTool,
2848
+ curve: LuSpline
2849
+ };
2850
+ function FreeformToolButtons({
2851
+ canEdit,
2852
+ activeTool,
2853
+ onArm
2854
+ }) {
2855
+ const { t } = useTranslation();
2856
+ const customization = useViewerCustomizationContext();
2857
+ const tools = FREEFORM_TOOL_IDS.filter((tool) => isDrawingToolVisible(customization, tool));
2858
+ if (tools.length === 0) {
2859
+ return null;
2860
+ }
2861
+ return /* @__PURE__ */ jsx(Fragment, { children: tools.map((tool) => {
2862
+ const Icon = ICONS3[tool];
2863
+ const active = activeTool === tool;
2864
+ return /* @__PURE__ */ jsxs(
2865
+ "button",
2866
+ {
2867
+ type: "button",
2868
+ disabled: !canEdit,
2869
+ "aria-pressed": active,
2870
+ "data-pptx-drawing-tool": tool,
2871
+ className: cn(pill, active && "bg-primary/15 text-primary"),
2872
+ title: t(FREEFORM_TOOL_LABEL_KEYS[tool]),
2873
+ onClick: () => onArm(active ? null : tool),
2874
+ children: [
2875
+ /* @__PURE__ */ jsx(Icon, { className: ic }),
2876
+ t(FREEFORM_TOOL_LABEL_KEYS[tool])
2877
+ ]
2878
+ },
2879
+ tool
2880
+ );
2881
+ }) });
2882
+ }
2658
2883
  function InsertHyperlinkButton(p) {
2659
2884
  const { t } = useTranslation();
2660
2885
  return /* @__PURE__ */ jsxs(
@@ -2780,6 +3005,14 @@ function InsertSection(p) {
2780
3005
  }
2781
3006
  )
2782
3007
  ] }),
3008
+ p.onArmFreeformTool && /* @__PURE__ */ jsx(
3009
+ FreeformToolButtons,
3010
+ {
3011
+ canEdit,
3012
+ activeTool: p.activeFreeformTool,
3013
+ onArm: p.onArmFreeformTool
3014
+ }
3015
+ ),
2783
3016
  /* @__PURE__ */ jsxs(
2784
3017
  "button",
2785
3018
  {
@@ -3181,6 +3414,7 @@ function ReviewSection(p) {
3181
3414
  {
3182
3415
  label: t("pptx.review.language"),
3183
3416
  icon: /* @__PURE__ */ jsx(LuGlobe, {}),
3417
+ disabled: !p.onSetLanguage,
3184
3418
  onClick: p.onSetLanguage
3185
3419
  }
3186
3420
  )
@@ -4880,7 +5114,8 @@ function MobileSectionBody({
4880
5114
  onDelete: p.onDelete,
4881
5115
  formatPainterActive: p.formatPainterActive,
4882
5116
  onToggleFormatPainter: p.onToggleFormatPainter,
4883
- canActivateFormatPainter: p.canActivateFormatPainter
5117
+ canActivateFormatPainter: p.canActivateFormatPainter,
5118
+ hiddenActions: p.hiddenActions
4884
5119
  }
4885
5120
  ) });
4886
5121
  case "design":
@@ -5491,8 +5726,9 @@ function EditingSection(p) {
5491
5726
  }
5492
5727
  function HelpSection(p) {
5493
5728
  const { t } = useTranslation();
5729
+ const showSettings = isDialogAvailable(useViewerCustomizationContext(), "options");
5494
5730
  return /* @__PURE__ */ jsxs(Fragment, { children: [
5495
- /* @__PURE__ */ jsx(
5731
+ showSettings && /* @__PURE__ */ jsx(
5496
5732
  "button",
5497
5733
  {
5498
5734
  type: "button",
@@ -5823,8 +6059,23 @@ function ModeSwitcher({
5823
6059
  }
5824
6060
  );
5825
6061
  }
6062
+ var EXPORT_CARD_OF = {
6063
+ png: "png",
6064
+ pdf: "pdf",
6065
+ video: "video",
6066
+ gif: "gif",
6067
+ copyImg: "copyImage"
6068
+ };
5826
6069
  function OverflowMenu(p) {
5827
6070
  const { t } = useTranslation();
6071
+ const customization = useViewerCustomizationContext();
6072
+ const offered = (k) => {
6073
+ const card = EXPORT_CARD_OF[k];
6074
+ if (card) {
6075
+ return !customization.hiddenBackstageCards.has(card);
6076
+ }
6077
+ return k !== "print" || isDialogAvailable(customization, "print");
6078
+ };
5828
6079
  const ovAct = (k) => {
5829
6080
  p.onSetOverflowMenuOpen(false);
5830
6081
  ({
@@ -5872,7 +6123,7 @@ function OverflowMenu(p) {
5872
6123
  onClick: () => p.onSetOverflowMenuOpen(false)
5873
6124
  }
5874
6125
  ),
5875
- /* @__PURE__ */ jsx("div", { className: "absolute right-0 top-full mt-1 z-50 w-44 rounded-lg border border-border bg-popover backdrop-blur-lg shadow-2xl py-1", children: OV.filter((o) => o.k !== "pptm" || p.hasMacros).map(
6126
+ /* @__PURE__ */ jsx("div", { className: "absolute right-0 top-full mt-1 z-50 w-44 rounded-lg border border-border bg-popover backdrop-blur-lg shadow-2xl py-1", children: OV.filter((o) => (o.k !== "pptm" || p.hasMacros) && offered(o.k)).map(
5876
6127
  (o) => o.k.startsWith("---") ? /* @__PURE__ */ jsx("div", { className: "my-1 border-t border-border/60" }, o.k) : /* @__PURE__ */ jsxs(
5877
6128
  "button",
5878
6129
  {
@@ -5901,9 +6152,15 @@ function ToolbarPrimaryRow(p) {
5901
6152
  onToggleInspector
5902
6153
  } = p;
5903
6154
  const collab = useCollaboration();
6155
+ const customization = useViewerCustomizationContext();
6156
+ const showSlidesToggle = isPanelVisible(customization, "slidesPane");
6157
+ const showInspectorToggle = isPanelVisible(customization, "inspector");
6158
+ const showComments = isFeatureEnabled(customization, "comments");
6159
+ const showShare = isDialogAvailable(customization, "share");
6160
+ const showSettings = isDialogAvailable(customization, "options");
5904
6161
  const qab = "p-1 max-md:p-2 max-md:min-h-[40px] max-md:min-w-[40px] rounded-sm transition-colors hover:bg-accent/60 disabled:opacity-40 disabled:cursor-not-allowed active:scale-90 active:opacity-70";
5905
6162
  return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5 max-md:gap-0 px-1.5 py-0.5 max-md:px-1", children: [
5906
- mode !== "present" && /* @__PURE__ */ jsx(
6163
+ mode !== "present" && showSlidesToggle && /* @__PURE__ */ jsx(
5907
6164
  "button",
5908
6165
  {
5909
6166
  type: "button",
@@ -5915,7 +6172,7 @@ function ToolbarPrimaryRow(p) {
5915
6172
  }
5916
6173
  ),
5917
6174
  /* @__PURE__ */ jsx("div", { className: "flex-1 min-w-2 max-md:min-w-1" }),
5918
- (mode === "edit" || mode === "master") && /* @__PURE__ */ jsxs(
6175
+ (mode === "edit" || mode === "master") && showComments && /* @__PURE__ */ jsxs(
5919
6176
  "button",
5920
6177
  {
5921
6178
  type: "button",
@@ -5933,7 +6190,7 @@ function ToolbarPrimaryRow(p) {
5933
6190
  ]
5934
6191
  }
5935
6192
  ),
5936
- collab && (collab.status === "connected" || collab.status === "connecting") && collab.remoteUsers.length > 0 && /* @__PURE__ */ jsx(
6193
+ collab && showShare && (collab.status === "connected" || collab.status === "connecting") && collab.remoteUsers.length > 0 && /* @__PURE__ */ jsx(
5937
6194
  "button",
5938
6195
  {
5939
6196
  type: "button",
@@ -5982,7 +6239,7 @@ function ToolbarPrimaryRow(p) {
5982
6239
  }
5983
6240
  ),
5984
6241
  sep,
5985
- (mode === "edit" || mode === "master") && /* @__PURE__ */ jsx(
6242
+ (mode === "edit" || mode === "master") && showInspectorToggle && /* @__PURE__ */ jsx(
5986
6243
  "button",
5987
6244
  {
5988
6245
  type: "button",
@@ -6004,7 +6261,7 @@ function ToolbarPrimaryRow(p) {
6004
6261
  children: /* @__PURE__ */ jsx(LuSparkles, { className: ic })
6005
6262
  }
6006
6263
  ),
6007
- /* @__PURE__ */ jsx(
6264
+ showSettings && /* @__PURE__ */ jsx(
6008
6265
  "button",
6009
6266
  {
6010
6267
  type: "button",
@@ -6033,6 +6290,7 @@ function Toolbar(p) {
6033
6290
  const { t } = useTranslation();
6034
6291
  const { isTabVisible } = useToolbarVisibility(p.hiddenActions);
6035
6292
  const viewerOptions = useViewerOptionsContext();
6293
+ const customization = useViewerCustomizationContext();
6036
6294
  if (isNarrowViewport && mode !== "present") {
6037
6295
  return /* @__PURE__ */ jsx(MobileToolbar, { ...p });
6038
6296
  }
@@ -6108,7 +6366,7 @@ function Toolbar(p) {
6108
6366
  ]
6109
6367
  }
6110
6368
  ),
6111
- showRibbon && viewerOptions.quickAccess.position === "below" && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-0.5 border-b border-border/60 px-2 py-1", children: /* @__PURE__ */ jsx(
6369
+ showRibbon && viewerOptions.quickAccess.position === "below" && isPanelVisible(customization, "quickAccessToolbar") && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-0.5 border-b border-border/60 px-2 py-1", children: /* @__PURE__ */ jsx(
6112
6370
  TitleBarQuickExtras,
6113
6371
  {
6114
6372
  quickAccess: viewerOptions.quickAccess,
@@ -6189,6 +6447,8 @@ function Toolbar(p) {
6189
6447
  canEdit: p.canEdit,
6190
6448
  newShapeType: p.newShapeType,
6191
6449
  onSetNewShapeType: p.onSetNewShapeType,
6450
+ activeFreeformTool: p.activeFreeformTool,
6451
+ onArmFreeformTool: p.onArmFreeformTool,
6192
6452
  onAddTextBox: p.onAddTextBox,
6193
6453
  onAddShape: p.onAddShape,
6194
6454
  onAddTable: p.onAddTable,
@@ -6266,7 +6526,8 @@ function Toolbar(p) {
6266
6526
  onDelete: p.onDelete,
6267
6527
  formatPainterActive: p.formatPainterActive,
6268
6528
  onToggleFormatPainter: p.onToggleFormatPainter,
6269
- canActivateFormatPainter: p.canActivateFormatPainter
6529
+ canActivateFormatPainter: p.canActivateFormatPainter,
6530
+ hiddenActions: p.hiddenActions
6270
6531
  }
6271
6532
  ),
6272
6533
  sDes && /* @__PURE__ */ jsx(
@@ -6618,7 +6879,7 @@ var EXPLOSION_SUPPORTED_TYPES = /* @__PURE__ */ new Set([
6618
6879
  "doughnut",
6619
6880
  "ofPie"
6620
6881
  ]);
6621
- var ICONS3 = {
6882
+ var ICONS4 = {
6622
6883
  elements: LuPlus,
6623
6884
  styles: LuPaintbrush,
6624
6885
  filters: LuFilter
@@ -6661,7 +6922,7 @@ function ChartQuickActionsOverlay({
6661
6922
  "data-export-ignore": "true",
6662
6923
  style: { position: "absolute", left: 0, top: 0, zIndex: 59 },
6663
6924
  onMouseDown: (e) => e.stopPropagation(),
6664
- children: descriptor.buttons.map((button) => /* @__PURE__ */ jsxs(React4.Fragment, { children: [
6925
+ children: descriptor.buttons.map((button) => /* @__PURE__ */ jsxs(React5.Fragment, { children: [
6665
6926
  /* @__PURE__ */ jsx(
6666
6927
  "button",
6667
6928
  {
@@ -6681,7 +6942,7 @@ function ChartQuickActionsOverlay({
6681
6942
  transformOrigin: "top left"
6682
6943
  },
6683
6944
  className: "flex items-center justify-center rounded bg-white border border-gray-300 shadow-sm hover:bg-gray-100 text-gray-700",
6684
- children: React4.createElement(ICONS3[button.id], { className: "size-3.5" })
6945
+ children: React5.createElement(ICONS4[button.id], { className: "size-3.5" })
6685
6946
  }
6686
6947
  ),
6687
6948
  open === button.id && button.id === "elements" && /* @__PURE__ */ jsxs(
@@ -7232,6 +7493,542 @@ function MotionPathOverlay({
7232
7493
  }
7233
7494
  );
7234
7495
  }
7496
+ var ITEM_CLASS = "w-full px-3 py-1.5 text-left hover:bg-muted";
7497
+ var DANGER_ITEM_CLASS = "w-full px-3 py-1.5 text-left text-red-300 hover:bg-red-900/40";
7498
+ var DISABLED_CLASS = " opacity-40 pointer-events-none";
7499
+ function ContextMenuItem({
7500
+ onSelect,
7501
+ danger,
7502
+ disabled,
7503
+ checked,
7504
+ children
7505
+ }) {
7506
+ return /* @__PURE__ */ jsxs(
7507
+ "button",
7508
+ {
7509
+ type: "button",
7510
+ role: checked === void 0 ? "menuitem" : "menuitemcheckbox",
7511
+ "aria-checked": checked === void 0 ? void 0 : checked,
7512
+ disabled,
7513
+ className: `${danger ? DANGER_ITEM_CLASS : ITEM_CLASS}${disabled ? DISABLED_CLASS : ""}`,
7514
+ onClick: onSelect,
7515
+ children: [
7516
+ checked !== void 0 && /* @__PURE__ */ jsx("span", { className: "mr-1.5 inline-block w-3", "aria-hidden": "true", children: checked ? "\u2713" : "" }),
7517
+ children
7518
+ ]
7519
+ }
7520
+ );
7521
+ }
7522
+ function ContextMenuSeparator() {
7523
+ return /* @__PURE__ */ jsx("div", { role: "separator", "aria-orientation": "horizontal", className: "my-1 border-t border-border" });
7524
+ }
7525
+ function EditPointsMenu({ menu, onRun }) {
7526
+ const { t } = useTranslation();
7527
+ const stop2 = (event) => event.stopPropagation();
7528
+ return /* @__PURE__ */ jsx(
7529
+ "div",
7530
+ {
7531
+ role: "menu",
7532
+ tabIndex: -1,
7533
+ "aria-label": t("pptx.editPoints.menu"),
7534
+ "data-pptx-edit-points-menu": "true",
7535
+ className: "absolute z-[61] min-w-[180px] rounded border border-border bg-popover shadow-2xl py-1.5 text-xs text-foreground",
7536
+ style: {
7537
+ left: menu.x,
7538
+ top: menu.y,
7539
+ transform: `scale(${menu.inverseScale})`,
7540
+ transformOrigin: "0 0"
7541
+ },
7542
+ onPointerDown: stop2,
7543
+ onMouseDown: stop2,
7544
+ onClick: stop2,
7545
+ onContextMenu: (event) => {
7546
+ event.preventDefault();
7547
+ event.stopPropagation();
7548
+ },
7549
+ children: menu.entries.map((entry) => /* @__PURE__ */ jsxs(Fragment$1, { children: [
7550
+ entry.separatorBefore && /* @__PURE__ */ jsx(ContextMenuSeparator, {}),
7551
+ /* @__PURE__ */ jsx("div", { role: "none", "data-pptx-edit-points-command": entry.id, children: /* @__PURE__ */ jsx(
7552
+ ContextMenuItem,
7553
+ {
7554
+ disabled: entry.disabled,
7555
+ checked: entry.checked,
7556
+ onSelect: () => onRun(entry.id),
7557
+ children: t(entry.labelKey)
7558
+ }
7559
+ ) })
7560
+ ] }, entry.id))
7561
+ }
7562
+ );
7563
+ }
7564
+ function EditPointsOverlay({
7565
+ element,
7566
+ canvasSize,
7567
+ scale,
7568
+ hiddenCommands,
7569
+ onCommit,
7570
+ onExit
7571
+ }) {
7572
+ const { t } = useTranslation();
7573
+ const [, rerender] = useReducer((n) => n + 1, 0);
7574
+ const svgRef = useRef(null);
7575
+ const latest = useRef({ onCommit, onExit });
7576
+ latest.current = { onCommit, onExit };
7577
+ const elementId = element.id;
7578
+ const sessionRef = useRef(null);
7579
+ if (sessionRef.current?.id !== elementId) {
7580
+ sessionRef.current = {
7581
+ id: elementId,
7582
+ session: new EditPointsSession(element, {
7583
+ onCommit: (patch) => latest.current.onCommit(elementId, patch),
7584
+ onExit: () => latest.current.onExit(),
7585
+ onChange: rerender,
7586
+ hiddenCommands
7587
+ })
7588
+ };
7589
+ }
7590
+ const session = sessionRef.current.session;
7591
+ useEffect(() => {
7592
+ session.reconcile(element);
7593
+ }, [element, session]);
7594
+ useEffect(() => attachOverlayKeyboard(session), [session]);
7595
+ const view = session.view(scale);
7596
+ const input = (event) => overlayPointerInput(
7597
+ event.nativeEvent,
7598
+ svgRef.current ?? event.currentTarget,
7599
+ canvasSize.width,
7600
+ canvasSize.height
7601
+ );
7602
+ const onPointerDown = (event) => {
7603
+ event.stopPropagation();
7604
+ if (event.button !== 0) {
7605
+ return;
7606
+ }
7607
+ event.preventDefault();
7608
+ event.currentTarget.setPointerCapture?.(event.pointerId);
7609
+ session.pointerDown(input(event));
7610
+ };
7611
+ const onPointerMove = (event) => {
7612
+ session.pointerMove(input(event));
7613
+ };
7614
+ const onPointerUp = (event) => {
7615
+ event.currentTarget.releasePointerCapture?.(event.pointerId);
7616
+ session.pointerUp(input(event));
7617
+ };
7618
+ const onContextMenu = (event) => {
7619
+ event.preventDefault();
7620
+ event.stopPropagation();
7621
+ session.contextMenu(input(event));
7622
+ };
7623
+ const stop2 = (event) => event.stopPropagation();
7624
+ const target = (id) => ({ [EDIT_POINTS_TARGET_ATTR]: id });
7625
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
7626
+ /* @__PURE__ */ jsxs(
7627
+ "svg",
7628
+ {
7629
+ ref: svgRef,
7630
+ className: "absolute left-0 top-0 z-[60]",
7631
+ width: canvasSize.width,
7632
+ height: canvasSize.height,
7633
+ role: "application",
7634
+ "aria-label": t("pptx.editPoints.overlay"),
7635
+ "data-pptx-edit-points-overlay": "true",
7636
+ "data-pptx-edit-points-element": elementId,
7637
+ style: { touchAction: "none" },
7638
+ onPointerDown,
7639
+ onPointerMove,
7640
+ onPointerUp,
7641
+ onContextMenu,
7642
+ onMouseDown: stop2,
7643
+ onClick: stop2,
7644
+ onDoubleClick: stop2,
7645
+ children: [
7646
+ /* @__PURE__ */ jsx("rect", { width: canvasSize.width, height: canvasSize.height, fill: "transparent" }),
7647
+ view.segments.map((seg) => /* @__PURE__ */ jsx(
7648
+ "path",
7649
+ {
7650
+ d: seg.d,
7651
+ fill: "none",
7652
+ stroke: "transparent",
7653
+ strokeWidth: view.hitStrokeWidth,
7654
+ pointerEvents: "stroke",
7655
+ style: { cursor: "copy" },
7656
+ ...target(seg.target)
7657
+ },
7658
+ seg.target
7659
+ )),
7660
+ /* @__PURE__ */ jsx(
7661
+ "path",
7662
+ {
7663
+ d: view.outlineD,
7664
+ fill: "none",
7665
+ stroke: EDIT_POINTS_STYLE.outlineColor,
7666
+ strokeWidth: view.outlineWidth,
7667
+ pointerEvents: "none"
7668
+ }
7669
+ ),
7670
+ view.handles.map((h) => /* @__PURE__ */ jsxs("g", { children: [
7671
+ /* @__PURE__ */ jsx(
7672
+ "line",
7673
+ {
7674
+ x1: h.anchorX,
7675
+ y1: h.anchorY,
7676
+ x2: h.x,
7677
+ y2: h.y,
7678
+ stroke: EDIT_POINTS_STYLE.handleLineColor,
7679
+ strokeWidth: view.outlineWidth,
7680
+ pointerEvents: "none"
7681
+ }
7682
+ ),
7683
+ /* @__PURE__ */ jsx(
7684
+ "rect",
7685
+ {
7686
+ x: h.x - h.size / 2,
7687
+ y: h.y - h.size / 2,
7688
+ width: h.size,
7689
+ height: h.size,
7690
+ fill: EDIT_POINTS_STYLE.handleFill,
7691
+ stroke: EDIT_POINTS_STYLE.handleStroke,
7692
+ strokeWidth: view.outlineWidth,
7693
+ style: { cursor: "move" },
7694
+ ...target(h.target)
7695
+ }
7696
+ )
7697
+ ] }, h.target)),
7698
+ view.nodes.map((n) => /* @__PURE__ */ jsx(
7699
+ "rect",
7700
+ {
7701
+ x: n.x - n.size / 2,
7702
+ y: n.y - n.size / 2,
7703
+ width: n.size,
7704
+ height: n.size,
7705
+ fill: n.selected ? EDIT_POINTS_STYLE.selectedNodeFill : EDIT_POINTS_STYLE.nodeFill,
7706
+ stroke: n.selected ? EDIT_POINTS_STYLE.selectedNodeStroke : EDIT_POINTS_STYLE.nodeStroke,
7707
+ strokeWidth: view.outlineWidth,
7708
+ style: { cursor: "move" },
7709
+ "data-pptx-edit-points-node-type": n.type,
7710
+ "data-selected": n.selected ? "true" : void 0,
7711
+ ...target(n.target)
7712
+ },
7713
+ n.target
7714
+ ))
7715
+ ]
7716
+ }
7717
+ ),
7718
+ view.menu && /* @__PURE__ */ jsx(EditPointsMenu, { menu: view.menu, onRun: (id) => session.runCommand(id) })
7719
+ ] });
7720
+ }
7721
+ function FreeformToolOverlay({
7722
+ tool,
7723
+ canvasSize,
7724
+ scale,
7725
+ onCommit,
7726
+ onCancel
7727
+ }) {
7728
+ const { t } = useTranslation();
7729
+ const [, rerender] = useReducer((n) => n + 1, 0);
7730
+ const svgRef = useRef(null);
7731
+ const latest = useRef({ onCommit, onCancel });
7732
+ latest.current = { onCommit, onCancel };
7733
+ const sessionRef = useRef(null);
7734
+ if (sessionRef.current?.tool !== tool) {
7735
+ sessionRef.current = new FreeformToolSession({
7736
+ tool,
7737
+ onCommit: (element) => latest.current.onCommit(element),
7738
+ onCancel: () => latest.current.onCancel(),
7739
+ onChange: rerender
7740
+ });
7741
+ }
7742
+ const session = sessionRef.current;
7743
+ session.setScale(scale);
7744
+ useEffect(() => attachOverlayKeyboard(session), [session]);
7745
+ const point2 = (event) => clientToSlidePoint(
7746
+ svgRef.current ?? event.currentTarget,
7747
+ event.clientX,
7748
+ event.clientY,
7749
+ canvasSize.width,
7750
+ canvasSize.height
7751
+ );
7752
+ const view = session.view();
7753
+ const stop2 = (event) => event.stopPropagation();
7754
+ return (
7755
+ // oxlint-disable-next-line jsx-a11y/no-noninteractive-element-interactions -- a pointer-driven drawing surface; the keyboard is routed through attachOverlayKeyboard
7756
+ /* @__PURE__ */ jsxs(
7757
+ "svg",
7758
+ {
7759
+ ref: svgRef,
7760
+ className: "absolute left-0 top-0 z-[60]",
7761
+ width: canvasSize.width,
7762
+ height: canvasSize.height,
7763
+ role: "application",
7764
+ "aria-label": t("pptx.freeformTool.overlay"),
7765
+ "data-pptx-freeform-tool-overlay": tool,
7766
+ style: { cursor: "crosshair", touchAction: "none" },
7767
+ onPointerDown: (event) => {
7768
+ event.stopPropagation();
7769
+ event.preventDefault();
7770
+ event.currentTarget.setPointerCapture?.(event.pointerId);
7771
+ session.pointerDown({ ...point2(event), button: event.button });
7772
+ },
7773
+ onPointerMove: (event) => session.pointerMove(point2(event)),
7774
+ onPointerUp: (event) => {
7775
+ event.currentTarget.releasePointerCapture?.(event.pointerId);
7776
+ session.pointerUp();
7777
+ },
7778
+ onDoubleClick: (event) => {
7779
+ event.stopPropagation();
7780
+ session.doubleClick();
7781
+ },
7782
+ onContextMenu: (event) => {
7783
+ event.preventDefault();
7784
+ event.stopPropagation();
7785
+ },
7786
+ onMouseDown: stop2,
7787
+ onClick: stop2,
7788
+ children: [
7789
+ /* @__PURE__ */ jsx("rect", { width: canvasSize.width, height: canvasSize.height, fill: "transparent" }),
7790
+ view.previewD && /* @__PURE__ */ jsx(
7791
+ "path",
7792
+ {
7793
+ d: view.previewD,
7794
+ fill: "none",
7795
+ stroke: "#2f528f",
7796
+ strokeWidth: view.strokeWidth,
7797
+ pointerEvents: "none"
7798
+ }
7799
+ ),
7800
+ view.start && /* @__PURE__ */ jsx(
7801
+ "circle",
7802
+ {
7803
+ cx: view.start.x,
7804
+ cy: view.start.y,
7805
+ r: view.start.size / 2,
7806
+ fill: view.start.armed ? "#2f528f" : "#ffffff",
7807
+ stroke: "#2f528f",
7808
+ strokeWidth: view.strokeWidth,
7809
+ pointerEvents: "none",
7810
+ "data-pptx-freeform-start": view.start.armed ? "armed" : "idle"
7811
+ }
7812
+ )
7813
+ ]
7814
+ }
7815
+ )
7816
+ );
7817
+ }
7818
+ function OutlineAuthoringLayer({
7819
+ activeSlide,
7820
+ canvasSize,
7821
+ scale,
7822
+ editPointsElementId,
7823
+ hiddenEditPointsCommands,
7824
+ onCommitEditPoints,
7825
+ onExitEditPoints,
7826
+ freeformTool,
7827
+ onFreeformCommit,
7828
+ onFreeformCancel
7829
+ }) {
7830
+ const element = editPointsElementId ? activeSlide?.elements.find((candidate) => candidate.id === editPointsElementId) : void 0;
7831
+ const editable = Boolean(element && canEditElementPoints(element));
7832
+ useEffect(() => {
7833
+ if (editPointsElementId && !editable) {
7834
+ onExitEditPoints();
7835
+ }
7836
+ }, [editPointsElementId, editable, onExitEditPoints]);
7837
+ if (freeformTool) {
7838
+ return /* @__PURE__ */ jsx(
7839
+ FreeformToolOverlay,
7840
+ {
7841
+ tool: freeformTool,
7842
+ canvasSize,
7843
+ scale,
7844
+ onCommit: onFreeformCommit,
7845
+ onCancel: onFreeformCancel
7846
+ }
7847
+ );
7848
+ }
7849
+ if (element && editable) {
7850
+ return /* @__PURE__ */ jsx(
7851
+ EditPointsOverlay,
7852
+ {
7853
+ element,
7854
+ canvasSize,
7855
+ scale,
7856
+ hiddenCommands: hiddenEditPointsCommands,
7857
+ onCommit: onCommitEditPoints,
7858
+ onExit: onExitEditPoints
7859
+ }
7860
+ );
7861
+ }
7862
+ return null;
7863
+ }
7864
+ var stop = (e) => e.stopPropagation();
7865
+ function PictureCropOverlay({
7866
+ element,
7867
+ scale,
7868
+ onUpdate,
7869
+ onContextMenu
7870
+ }) {
7871
+ const { t } = useTranslation();
7872
+ const overlay = buildCropOverlay(element, scale);
7873
+ const dragRef = useRef(null);
7874
+ const latest = useRef({ scale, onUpdate });
7875
+ latest.current = { scale, onUpdate };
7876
+ const detachRef = useRef(null);
7877
+ useEffect(() => () => detachRef.current?.(), []);
7878
+ const beginDrag = (e, handle) => {
7879
+ if (e.button !== 0) {
7880
+ return;
7881
+ }
7882
+ e.preventDefault();
7883
+ e.stopPropagation();
7884
+ detachRef.current?.();
7885
+ dragRef.current = {
7886
+ start: beginCropDrag(element),
7887
+ handle,
7888
+ clientX: e.clientX,
7889
+ clientY: e.clientY
7890
+ };
7891
+ const onMove = (ev) => {
7892
+ const drag = dragRef.current;
7893
+ if (!drag) {
7894
+ return;
7895
+ }
7896
+ const zoom = latest.current.scale || 1;
7897
+ const { dx, dy } = toElementAxes(
7898
+ (ev.clientX - drag.clientX) / zoom,
7899
+ (ev.clientY - drag.clientY) / zoom,
7900
+ drag.start.rotation
7901
+ );
7902
+ latest.current.onUpdate(
7903
+ drag.handle ? dragCropHandle(drag.start, drag.handle, dx, dy) : panCropImage(drag.start, dx, dy)
7904
+ );
7905
+ };
7906
+ const onUp = () => detachRef.current?.();
7907
+ window.addEventListener("pointermove", onMove);
7908
+ window.addEventListener("pointerup", onUp);
7909
+ window.addEventListener("pointercancel", onUp);
7910
+ detachRef.current = () => {
7911
+ dragRef.current = null;
7912
+ window.removeEventListener("pointermove", onMove);
7913
+ window.removeEventListener("pointerup", onUp);
7914
+ window.removeEventListener("pointercancel", onUp);
7915
+ detachRef.current = null;
7916
+ };
7917
+ };
7918
+ const { ghost, frame, handles } = overlay;
7919
+ const src = imgSrc(element);
7920
+ return /* @__PURE__ */ jsxs(
7921
+ "div",
7922
+ {
7923
+ "data-pptx-crop-overlay": "true",
7924
+ "data-pptx-crop-for": element.id,
7925
+ "data-export-ignore": "true",
7926
+ style: {
7927
+ position: "absolute",
7928
+ left: element.x,
7929
+ top: element.y,
7930
+ width: element.width,
7931
+ height: element.height,
7932
+ transform: element.rotation ? `rotate(${element.rotation}deg)` : void 0,
7933
+ transformOrigin: "center",
7934
+ overflow: "visible",
7935
+ zIndex: 59,
7936
+ touchAction: "none"
7937
+ },
7938
+ onMouseDown: stop,
7939
+ onClick: stop,
7940
+ onDoubleClick: stop,
7941
+ onContextMenu: (e) => {
7942
+ e.stopPropagation();
7943
+ onContextMenu?.(element.id, e);
7944
+ },
7945
+ children: [
7946
+ /* @__PURE__ */ jsx(
7947
+ "div",
7948
+ {
7949
+ "data-pptx-crop-ghost": "true",
7950
+ style: {
7951
+ position: "absolute",
7952
+ left: ghost.left,
7953
+ top: ghost.top,
7954
+ width: ghost.width,
7955
+ height: ghost.height,
7956
+ clipPath: ghost.clipPath,
7957
+ opacity: ghost.opacity,
7958
+ cursor: "move"
7959
+ },
7960
+ onPointerDown: (e) => beginDrag(e, null),
7961
+ children: src && /* @__PURE__ */ jsx(
7962
+ "img",
7963
+ {
7964
+ src,
7965
+ alt: "",
7966
+ draggable: false,
7967
+ style: {
7968
+ display: "block",
7969
+ width: "100%",
7970
+ height: "100%",
7971
+ transform: ghost.transform || void 0,
7972
+ pointerEvents: "none",
7973
+ userSelect: "none"
7974
+ }
7975
+ }
7976
+ )
7977
+ }
7978
+ ),
7979
+ /* @__PURE__ */ jsx(
7980
+ "div",
7981
+ {
7982
+ "data-pptx-crop-frame": "true",
7983
+ style: {
7984
+ position: "absolute",
7985
+ left: frame.left,
7986
+ top: frame.top,
7987
+ width: frame.width,
7988
+ height: frame.height,
7989
+ boxSizing: "border-box",
7990
+ border: `${1 / (scale || 1)}px solid rgba(0, 0, 0, 0.75)`,
7991
+ outline: `${1 / (scale || 1)}px dashed rgba(255, 255, 255, 0.9)`,
7992
+ cursor: "move"
7993
+ },
7994
+ onPointerDown: (e) => beginDrag(e, null)
7995
+ }
7996
+ ),
7997
+ handles.map((handle) => /* @__PURE__ */ jsx(
7998
+ "div",
7999
+ {
8000
+ role: "button",
8001
+ tabIndex: -1,
8002
+ "aria-label": t(CROP_HANDLE_ARIA_KEY),
8003
+ "data-pptx-crop-handle": handle.id,
8004
+ style: {
8005
+ position: "absolute",
8006
+ left: handle.left,
8007
+ top: handle.top,
8008
+ width: handle.width,
8009
+ height: handle.height,
8010
+ cursor: handle.cursor
8011
+ },
8012
+ onPointerDown: (e) => beginDrag(e, handle.id),
8013
+ children: /* @__PURE__ */ jsx(
8014
+ "svg",
8015
+ {
8016
+ width: "100%",
8017
+ height: "100%",
8018
+ viewBox: `0 0 ${handle.width} ${handle.height}`,
8019
+ overflow: "visible",
8020
+ "aria-hidden": "true",
8021
+ style: { display: "block" },
8022
+ children: /* @__PURE__ */ jsx("path", { d: handle.path, fill: "#000", stroke: "#fff", strokeWidth: 1 / (scale || 1) })
8023
+ }
8024
+ )
8025
+ },
8026
+ handle.id
8027
+ ))
8028
+ ]
8029
+ }
8030
+ );
8031
+ }
7235
8032
  function HorizontalRulerView({ ticks, widthPx, highlight }) {
7236
8033
  return /* @__PURE__ */ jsxs(
7237
8034
  "svg",
@@ -7295,7 +8092,7 @@ function HorizontalRulerView({ ticks, widthPx, highlight }) {
7295
8092
  }
7296
8093
  );
7297
8094
  }
7298
- var HorizontalRuler = React4.memo(HorizontalRulerView);
8095
+ var HorizontalRuler = React5.memo(HorizontalRulerView);
7299
8096
  HorizontalRuler.displayName = "HorizontalRuler";
7300
8097
  function VerticalRulerView({ ticks, heightPx, highlight }) {
7301
8098
  return /* @__PURE__ */ jsxs(
@@ -7367,7 +8164,7 @@ function VerticalRulerView({ ticks, heightPx, highlight }) {
7367
8164
  }
7368
8165
  );
7369
8166
  }
7370
- var VerticalRuler = React4.memo(VerticalRulerView);
8167
+ var VerticalRuler = React5.memo(VerticalRulerView);
7371
8168
  VerticalRuler.displayName = "VerticalRuler";
7372
8169
  function Ruler({
7373
8170
  canvasSize,
@@ -8338,9 +9135,12 @@ function SlideCanvasContent({
8338
9135
  fieldContext,
8339
9136
  tableStyleContext,
8340
9137
  collaborationOverlay,
8341
- aiActive = false
9138
+ aiActive = false,
9139
+ outlineAuthoring
8342
9140
  }) {
8343
9141
  const isEditableCanvas = (mode === "edit" || mode === "master") && canEdit;
9142
+ const crop = useShapeFormatContext()?.crop;
9143
+ const cropElement = isEditableCanvas ? crop?.element ?? null : null;
8344
9144
  useSlideCanvasImagePaste({
8345
9145
  imagePaste,
8346
9146
  zoom,
@@ -8618,7 +9418,7 @@ function SlideCanvasContent({
8618
9418
  },
8619
9419
  element.id
8620
9420
  )),
8621
- selectedElement && shouldShowElementHandles(isEditableCanvas, true, selectedElementIdSet.size) && !isConnectorOrLineElement(selectedElement) && /* @__PURE__ */ jsx(
9421
+ selectedElement && selectedElement.id !== cropElement?.id && shouldShowElementHandles(isEditableCanvas, true, selectedElementIdSet.size) && !isConnectorOrLineElement(selectedElement) && outlineAuthoring?.editPointsElementId !== selectedElement.id && /* @__PURE__ */ jsx(
8622
9422
  SelectionHandleOverlay,
8623
9423
  {
8624
9424
  element: selectedElement,
@@ -8639,6 +9439,15 @@ function SlideCanvasContent({
8639
9439
  onUpdateElement: stableUpdateSmartArtElement
8640
9440
  }
8641
9441
  ),
9442
+ cropElement && crop && /* @__PURE__ */ jsx(
9443
+ PictureCropOverlay,
9444
+ {
9445
+ element: cropElement,
9446
+ scale: zoom.editorScale,
9447
+ onUpdate: crop.liveUpdate,
9448
+ onContextMenu
9449
+ }
9450
+ ),
8642
9451
  /* @__PURE__ */ jsx(MarqueeOverlay, { marqueeSelectionState }),
8643
9452
  activeSlide?.activeXControls && activeSlide.activeXControls.length > 0 && /* @__PURE__ */ jsx(ActiveXControlOverlay, { controls: activeSlide.activeXControls, canvasSize }),
8644
9453
  showCommentMarkers && comments && comments.length > 0 && /* @__PURE__ */ jsx(
@@ -8699,6 +9508,15 @@ function SlideCanvasContent({
8699
9508
  onPointerUp: handleDrawPointerUp
8700
9509
  }
8701
9510
  ),
9511
+ isEditableCanvas && outlineAuthoring && /* @__PURE__ */ jsx(
9512
+ OutlineAuthoringLayer,
9513
+ {
9514
+ ...outlineAuthoring,
9515
+ activeSlide,
9516
+ canvasSize,
9517
+ scale: zoom.editorScale
9518
+ }
9519
+ ),
8702
9520
  collaborationOverlay
8703
9521
  ]
8704
9522
  }
@@ -9267,7 +10085,7 @@ function slideThumbnailPropsEqual(prev, next) {
9267
10085
  }
9268
10086
  return true;
9269
10087
  }
9270
- var SlideThumbnail = React4.memo(SlideThumbnailImpl, slideThumbnailPropsEqual);
10088
+ var SlideThumbnail = React5.memo(SlideThumbnailImpl, slideThumbnailPropsEqual);
9271
10089
 
9272
10090
  // src/viewer/components/context-menu-dispatch.ts
9273
10091
  function tableCell(props) {
@@ -9282,18 +10100,32 @@ function tableCell(props) {
9282
10100
  isMergedCell: Boolean(cell && ((cell.gridSpan ?? 1) > 1 || (cell.rowSpan ?? 1) > 1))
9283
10101
  };
9284
10102
  }
9285
- function contextMenuContext(props) {
10103
+ function contextMenuContext(props, shapeFormat = null) {
9286
10104
  return {
9287
10105
  elementType: props.selectedElement?.type ?? null,
9288
10106
  table: tableCell(props),
9289
10107
  hasMultiSelection: Boolean(props.hasMultiSelection),
9290
10108
  selectionGroupable: props.selectionGroupable,
10109
+ hasClipboard: props.hasClipboard,
10110
+ editPoints: props.editPointsAvailability,
9291
10111
  // Both AI entries appear together or not at all, so a viewer that wired
9292
10112
  // only one of them does not produce a menu the other bindings cannot match.
9293
- aiEnabled: Boolean(props.onAskAi) && Boolean(props.onFixAi)
10113
+ aiEnabled: Boolean(props.onAskAi) && Boolean(props.onFixAi),
10114
+ canMergeShapes: Boolean(shapeFormat?.canMergeShapes),
10115
+ canCrop: canCropElement(props.selectedElement)
9294
10116
  };
9295
10117
  }
9296
- function contextMenuHandlers(props) {
10118
+ function shapeFormatHandlers(shapeFormat, andClose) {
10119
+ if (!shapeFormat) {
10120
+ return {};
10121
+ }
10122
+ const handlers = { crop: andClose(shapeFormat.crop.enter) };
10123
+ for (const item of MERGE_SHAPES_MENU_ITEMS) {
10124
+ handlers[item.commandId] = andClose(() => shapeFormat.mergeShapes(item.operation));
10125
+ }
10126
+ return handlers;
10127
+ }
10128
+ function contextMenuHandlers(props, shapeFormat = null) {
9297
10129
  const { onAction, onClose } = props;
9298
10130
  const andClose = (run) => run && (() => {
9299
10131
  run();
@@ -9325,46 +10157,46 @@ function contextMenuHandlers(props) {
9325
10157
  group: andClose(() => onAction("group")),
9326
10158
  ungroup: andClose(() => onAction("ungroup")),
9327
10159
  "edit-text": andClose(() => onAction("edit-text")),
10160
+ "edit-points": andClose(() => onAction("edit-points")),
9328
10161
  "save-as-picture": andClose(() => onAction("save-as-picture")),
9329
10162
  "edit-alt-text": andClose(() => onAction("edit-alt-text")),
9330
10163
  "size-and-position": andClose(() => onAction("size-and-position")),
9331
10164
  "format-shape": andClose(() => onAction("format-shape")),
9332
- delete: andClose(() => onAction("delete"))
10165
+ delete: andClose(() => onAction("delete")),
10166
+ ...shapeFormatHandlers(shapeFormat, andClose)
9333
10167
  };
9334
10168
  }
9335
- var ITEM_CLASS = "w-full px-3 py-1.5 text-left hover:bg-muted";
9336
- var DANGER_ITEM_CLASS = "w-full px-3 py-1.5 text-left text-red-300 hover:bg-red-900/40";
9337
- var DISABLED_CLASS = " opacity-40 pointer-events-none";
9338
- function ContextMenuItem({
9339
- onSelect,
9340
- danger,
9341
- disabled,
9342
- checked,
9343
- children
9344
- }) {
9345
- return /* @__PURE__ */ jsxs(
9346
- "button",
9347
- {
9348
- type: "button",
9349
- role: checked === void 0 ? "menuitem" : "menuitemcheckbox",
9350
- "aria-checked": checked === void 0 ? void 0 : checked,
9351
- disabled,
9352
- className: `${danger ? DANGER_ITEM_CLASS : ITEM_CLASS}${disabled ? DISABLED_CLASS : ""}`,
9353
- onClick: onSelect,
9354
- children: [
9355
- checked !== void 0 && /* @__PURE__ */ jsx("span", { className: "mr-1.5 inline-block w-3", "aria-hidden": "true", children: checked ? "\u2713" : "" }),
9356
- children
9357
- ]
10169
+ function useClampedMenuPosition(x, y) {
10170
+ const [size, setSize] = useState({ width: 0, height: 0 });
10171
+ const ref = useCallback((node) => {
10172
+ if (!node) {
10173
+ return;
9358
10174
  }
9359
- );
9360
- }
9361
- function ContextMenuSeparator() {
9362
- return /* @__PURE__ */ jsx("div", { role: "separator", "aria-orientation": "horizontal", className: "my-1 border-t border-border" });
10175
+ const rect = node.getBoundingClientRect();
10176
+ setSize(
10177
+ (previous) => previous.width === rect.width && previous.height === rect.height ? previous : { width: rect.width, height: rect.height }
10178
+ );
10179
+ }, []);
10180
+ const { left, top } = clampFlyoutPosition({
10181
+ x,
10182
+ y,
10183
+ width: size.width,
10184
+ height: size.height,
10185
+ viewportWidth: typeof window === "undefined" ? 0 : window.innerWidth,
10186
+ viewportHeight: typeof window === "undefined" ? 0 : window.innerHeight
10187
+ });
10188
+ return { ref, left, top };
9363
10189
  }
9364
10190
  function ContextMenu(props) {
9365
10191
  const { contextMenuState, mode, onClose } = props;
9366
10192
  const { t } = useTranslation();
10193
+ const customization = useViewerCustomizationContext();
10194
+ const shapeFormat = useShapeFormatContext();
9367
10195
  const open = Boolean(contextMenuState) && mode === "edit";
10196
+ const menuPosition = useClampedMenuPosition(
10197
+ contextMenuState?.x ?? 0,
10198
+ contextMenuState?.y ?? 0
10199
+ );
9368
10200
  useEffect(() => {
9369
10201
  if (!open) {
9370
10202
  return;
@@ -9381,8 +10213,14 @@ function ContextMenu(props) {
9381
10213
  if (!open) {
9382
10214
  return null;
9383
10215
  }
9384
- const handlers = contextMenuHandlers(props);
9385
- const entries = buildContextMenuEntries(contextMenuContext(props));
10216
+ const handlers = contextMenuHandlers(props, shapeFormat);
10217
+ const entries = customizeContextMenuEntries(
10218
+ buildContextMenuEntries(contextMenuContext(props, shapeFormat)),
10219
+ customization
10220
+ );
10221
+ if (entries.length === 0) {
10222
+ return null;
10223
+ }
9386
10224
  return /* @__PURE__ */ jsxs(Fragment, { children: [
9387
10225
  /* @__PURE__ */ jsx(
9388
10226
  "div",
@@ -9398,13 +10236,14 @@ function ContextMenu(props) {
9398
10236
  /* @__PURE__ */ jsx(
9399
10237
  "div",
9400
10238
  {
10239
+ ref: menuPosition.ref,
9401
10240
  "data-pptx-context-menu": "true",
9402
10241
  role: "menu",
9403
10242
  "aria-label": t("pptx.contextMenu.ariaLabel"),
9404
10243
  className: "fixed z-[120] min-w-[180px] rounded border border-border bg-popover shadow-2xl py-1.5 text-xs text-foreground",
9405
10244
  style: {
9406
- left: Math.max(contextMenuState.x, 8),
9407
- top: Math.max(contextMenuState.y, 8)
10245
+ left: menuPosition.left,
10246
+ top: menuPosition.top
9408
10247
  },
9409
10248
  children: entries.map((entry) => {
9410
10249
  const run = handlers[entry.id];
@@ -9452,7 +10291,12 @@ function canvasContextMenuHandlers(props) {
9452
10291
  function CanvasContextMenu(props) {
9453
10292
  const { canvasContextMenuState, mode, onClose } = props;
9454
10293
  const { t } = useTranslation();
10294
+ const customization = useViewerCustomizationContext();
9455
10295
  const open = Boolean(canvasContextMenuState) && mode === "edit";
10296
+ const menuPosition = useClampedMenuPosition(
10297
+ canvasContextMenuState?.x ?? 0,
10298
+ canvasContextMenuState?.y ?? 0
10299
+ );
9456
10300
  useEffect(() => {
9457
10301
  if (!open) {
9458
10302
  return;
@@ -9470,7 +10314,13 @@ function CanvasContextMenu(props) {
9470
10314
  return null;
9471
10315
  }
9472
10316
  const handlers = canvasContextMenuHandlers(props);
9473
- const entries = buildCanvasContextMenuEntries(canvasContextMenuContext(props));
10317
+ const entries = customizeCanvasContextMenuEntries(
10318
+ buildCanvasContextMenuEntries(canvasContextMenuContext(props)),
10319
+ customization
10320
+ );
10321
+ if (entries.length === 0) {
10322
+ return null;
10323
+ }
9474
10324
  return /* @__PURE__ */ jsxs(Fragment, { children: [
9475
10325
  /* @__PURE__ */ jsx(
9476
10326
  "div",
@@ -9486,13 +10336,14 @@ function CanvasContextMenu(props) {
9486
10336
  /* @__PURE__ */ jsx(
9487
10337
  "div",
9488
10338
  {
10339
+ ref: menuPosition.ref,
9489
10340
  "data-pptx-canvas-context-menu": "true",
9490
10341
  role: "menu",
9491
10342
  "aria-label": t("pptx.canvasContextMenu.ariaLabel"),
9492
10343
  className: "fixed z-[120] min-w-[180px] rounded border border-border bg-popover shadow-2xl py-1.5 text-xs text-foreground",
9493
10344
  style: {
9494
- left: Math.max(canvasContextMenuState.x, 8),
9495
- top: Math.max(canvasContextMenuState.y, 8)
10345
+ left: menuPosition.left,
10346
+ top: menuPosition.top
9496
10347
  },
9497
10348
  children: entries.map((entry) => {
9498
10349
  const run = handlers[entry.id];
@@ -9982,7 +10833,7 @@ function LazyThumbnailInner({
9982
10833
  }
9983
10834
  ) });
9984
10835
  }
9985
- var LazyThumbnail = React4.memo(LazyThumbnailInner);
10836
+ var LazyThumbnail = React5.memo(LazyThumbnailInner);
9986
10837
 
9987
10838
  // src/viewer/components/slides-pane/utils.ts
9988
10839
  function formatTimingMs(ms) {
@@ -10138,7 +10989,7 @@ function SlideItemInner({
10138
10989
  }
10139
10990
  );
10140
10991
  }
10141
- var SlideItem = React4.memo(SlideItemInner);
10992
+ var SlideItem = React5.memo(SlideItemInner);
10142
10993
  function useSlidePaneCallbacks(onMoveSlide, onRenameSection, onToggleSectionCollapse) {
10143
10994
  const [collapsedSections, setCollapsedSections] = useState({});
10144
10995
  const [renamingSectionId, setRenamingSectionId] = useState(null);
@@ -11535,7 +12386,7 @@ function arePropsEqual(prev, next) {
11535
12386
  }
11536
12387
  return true;
11537
12388
  }
11538
- var SlideCard = React4.memo(SlideCardImpl, arePropsEqual);
12389
+ var SlideCard = React5.memo(SlideCardImpl, arePropsEqual);
11539
12390
  function SorterContextMenu({
11540
12391
  x,
11541
12392
  y,
@@ -13094,15 +13945,15 @@ function SlideNotesPanel({
13094
13945
  onHeightChange
13095
13946
  }) {
13096
13947
  const { t } = useTranslation();
13097
- const rootRef = React4.useRef(null);
13098
- React4.useEffect(() => {
13948
+ const rootRef = React5.useRef(null);
13949
+ React5.useEffect(() => {
13099
13950
  const el = rootRef.current;
13100
13951
  if (!el || !onHeightChange) {
13101
13952
  return void 0;
13102
13953
  }
13103
- const stop = observeElementHeight(el, onHeightChange);
13954
+ const stop2 = observeElementHeight(el, onHeightChange);
13104
13955
  return () => {
13105
- stop();
13956
+ stop2();
13106
13957
  onHeightChange(0);
13107
13958
  };
13108
13959
  }, [onHeightChange]);
@@ -14993,9 +15844,9 @@ function PresentationSubtitleBar({
14993
15844
  function renderNotesSegments(segments) {
14994
15845
  return notesSegmentsToSpans(segments).map((span) => {
14995
15846
  if (span.kind === "break") {
14996
- return React4.createElement("br", { key: span.key });
15847
+ return React5.createElement("br", { key: span.key });
14997
15848
  }
14998
- return React4.createElement(
15849
+ return React5.createElement(
14999
15850
  "span",
15000
15851
  { key: span.key, style: span.style },
15001
15852
  span.text
@@ -15227,7 +16078,7 @@ function scaledSlidePreviewPropsEqual(prev, next) {
15227
16078
  }
15228
16079
  return true;
15229
16080
  }
15230
- var ScaledSlidePreview = React4.memo(ScaledSlidePreviewImpl, scaledSlidePreviewPropsEqual);
16081
+ var ScaledSlidePreview = React5.memo(ScaledSlidePreviewImpl, scaledSlidePreviewPropsEqual);
15231
16082
  function PresenterNotesRail({
15232
16083
  slides,
15233
16084
  current,
@@ -16403,6 +17254,37 @@ function AnimationTimelineSection({
16403
17254
  ] })
16404
17255
  ] });
16405
17256
  }
17257
+ function BookmarkTriggerRow({
17258
+ elements,
17259
+ animation,
17260
+ canEdit,
17261
+ style,
17262
+ onChange
17263
+ }) {
17264
+ const { t } = useTranslation();
17265
+ const options = listMediaBookmarkOptions(elements);
17266
+ return /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
17267
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-[11px]", children: t("pptx.animation.trigger.bookmarkLabel") }),
17268
+ /* @__PURE__ */ jsxs(
17269
+ WebSelect,
17270
+ {
17271
+ "aria-label": t("pptx.animation.trigger.bookmarkLabel"),
17272
+ "data-pptx-animation-bookmark-picker": true,
17273
+ value: selectedBookmarkOptionValue(animation),
17274
+ onChange: (event) => onChange(event.target.value),
17275
+ disabled: !canEdit || options.length === 0,
17276
+ className: SELECT_CLS,
17277
+ style,
17278
+ children: [
17279
+ /* @__PURE__ */ jsx("option", { value: "", children: t(
17280
+ options.length === 0 ? "pptx.animation.trigger.noBookmarks" : "pptx.animation.trigger.selectBookmark"
17281
+ ) }),
17282
+ options.map((option) => /* @__PURE__ */ jsx("option", { value: option.value, children: option.label }, option.value))
17283
+ ]
17284
+ }
17285
+ )
17286
+ ] });
17287
+ }
16406
17288
  var NONE_VALUE = "none";
16407
17289
  var CURRENT_VALUE = "current";
16408
17290
  var OTHER_VALUE = "other";
@@ -16413,7 +17295,7 @@ function EffectSoundRow({
16413
17295
  onPickStock
16414
17296
  }) {
16415
17297
  const { t } = useTranslation();
16416
- const fileInputRef = React4.useRef(null);
17298
+ const fileInputRef = React5.useRef(null);
16417
17299
  const selectedValue = soundState.catalogueId ?? (soundState.hasSound ? CURRENT_VALUE : NONE_VALUE);
16418
17300
  const handleSelectChange = (event) => {
16419
17301
  const value = event.target.value;
@@ -16796,12 +17678,13 @@ function useAnimationHandlers({
16796
17678
  const handleTriggerChange = useCallback(
16797
17679
  (event) => {
16798
17680
  const newTrigger = event.target.value;
16799
- updateAnimationField("trigger", newTrigger);
16800
- if (newTrigger !== "onShapeClick") {
16801
- updateAnimationField("triggerShapeId", void 0);
16802
- }
17681
+ updateAnimations((anims) => setTrigger(anims, selectedElement.id, newTrigger));
16803
17682
  },
16804
- [updateAnimationField]
17683
+ [updateAnimations, selectedElement.id]
17684
+ );
17685
+ const handleTriggerBookmarkChange = useCallback(
17686
+ (optionValue) => updateAnimations((anims) => setTriggerBookmark(anims, selectedElement.id, optionValue)),
17687
+ [updateAnimations, selectedElement.id]
16805
17688
  );
16806
17689
  const handleTriggerShapeChange = useCallback(
16807
17690
  (e) => updateAnimationField("triggerShapeId", e.target.value || void 0),
@@ -16932,6 +17815,7 @@ function useAnimationHandlers({
16932
17815
  handleEmphasisChange,
16933
17816
  handleTriggerChange,
16934
17817
  handleTriggerShapeChange,
17818
+ handleTriggerBookmarkChange,
16935
17819
  handleTimingCurveChange,
16936
17820
  handleDurationChange,
16937
17821
  handleDelayChange,
@@ -16976,6 +17860,7 @@ function AnimationPanel({
16976
17860
  handleEmphasisChange,
16977
17861
  handleTriggerChange,
16978
17862
  handleTriggerShapeChange,
17863
+ handleTriggerBookmarkChange,
16979
17864
  handleTimingCurveChange,
16980
17865
  handleDurationChange,
16981
17866
  handleDelayChange,
@@ -17165,6 +18050,16 @@ function AnimationPanel({
17165
18050
  }
17166
18051
  )
17167
18052
  ] }),
18053
+ selectedElementAnimation?.trigger === "onMediaBookmark" && /* @__PURE__ */ jsx(
18054
+ BookmarkTriggerRow,
18055
+ {
18056
+ elements: activeSlide.elements,
18057
+ animation: selectedElementAnimation,
18058
+ canEdit,
18059
+ style: fieldStyle,
18060
+ onChange: handleTriggerBookmarkChange
18061
+ }
18062
+ ),
17168
18063
  /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
17169
18064
  /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-[11px]", children: t("pptx.animation.duration") }),
17170
18065
  /* @__PURE__ */ jsx(
@@ -19981,7 +20876,7 @@ function ConnectorArrowsSection({
19981
20876
  ["Start", "End"].map((end) => {
19982
20877
  const widthKey = end === "Start" ? "connectorStartArrowWidth" : "connectorEndArrowWidth";
19983
20878
  const lengthKey = end === "Start" ? "connectorStartArrowLength" : "connectorEndArrowLength";
19984
- return /* @__PURE__ */ jsxs(React4.Fragment, { children: [
20879
+ return /* @__PURE__ */ jsxs(React5.Fragment, { children: [
19985
20880
  /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
19986
20881
  /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: t(END_LABEL_KEYS[end].width) }),
19987
20882
  /* @__PURE__ */ jsx(
@@ -20194,7 +21089,7 @@ function LayerOrderButtons({
20194
21089
  ] });
20195
21090
  }
20196
21091
  function ArtisticEffectsGallery({
20197
- imgSrc,
21092
+ imgSrc: imgSrc2,
20198
21093
  fx,
20199
21094
  canEdit,
20200
21095
  updateEffects
@@ -20224,7 +21119,7 @@ function ArtisticEffectsGallery({
20224
21119
  {
20225
21120
  className: "w-10 h-7 rounded overflow-hidden bg-muted",
20226
21121
  style: {
20227
- backgroundImage: imgSrc ? `url(${imgSrc})` : void 0,
21122
+ backgroundImage: imgSrc2 ? `url(${imgSrc2})` : void 0,
20228
21123
  backgroundSize: "cover",
20229
21124
  backgroundPosition: "center",
20230
21125
  filter: cssFilter || void 0
@@ -22464,7 +23359,7 @@ function ColorPickerRow({
22464
23359
  ] });
22465
23360
  }
22466
23361
  function GradientStopRow({
22467
- stop,
23362
+ stop: stop2,
22468
23363
  index,
22469
23364
  total,
22470
23365
  onUpdate,
@@ -22482,7 +23377,7 @@ function GradientStopRow({
22482
23377
  "input",
22483
23378
  {
22484
23379
  type: "color",
22485
- value: normalizeHexColor(stop.color, "#3b82f6"),
23380
+ value: normalizeHexColor(stop2.color, "#3b82f6"),
22486
23381
  onChange: (e) => {
22487
23382
  const hex = normalizeHexColor(e.target.value, "#3b82f6");
22488
23383
  patchStop({ color: hex, colorRef: void 0 });
@@ -22497,7 +23392,7 @@ function GradientStopRow({
22497
23392
  type: "range",
22498
23393
  min: 0,
22499
23394
  max: 100,
22500
- value: Math.round(stop.position),
23395
+ value: Math.round(stop2.position),
22501
23396
  onChange: (e) => patchStop({ position: Number(e.target.value) }),
22502
23397
  className: RNG
22503
23398
  }
@@ -22517,8 +23412,8 @@ function GradientStopRow({
22517
23412
  ThemeColorSwatchGrid,
22518
23413
  {
22519
23414
  prefix: `gradient-stop-${index}`,
22520
- selectedRef: stop.colorRef,
22521
- selectedHex: stop.color,
23415
+ selectedRef: stop2.colorRef,
23416
+ selectedHex: stop2.color,
22522
23417
  onPick: (c) => {
22523
23418
  patchStop({ color: c.hex, colorRef: c.ref });
22524
23419
  pushColor(c.hex);
@@ -22533,13 +23428,13 @@ function GradientStopRow({
22533
23428
  type: "range",
22534
23429
  min: 0,
22535
23430
  max: 100,
22536
- value: Math.round((stop.opacity ?? 1) * 100),
23431
+ value: Math.round((stop2.opacity ?? 1) * 100),
22537
23432
  onChange: (e) => patchStop({ opacity: Number(e.target.value) / 100 }),
22538
23433
  className: RNG
22539
23434
  }
22540
23435
  ),
22541
23436
  /* @__PURE__ */ jsxs("span", { className: "text-[10px] text-muted-foreground w-[52px] text-right", children: [
22542
- Math.round((stop.opacity ?? 1) * 100),
23437
+ Math.round((stop2.opacity ?? 1) * 100),
22543
23438
  "%"
22544
23439
  ] })
22545
23440
  ] })
@@ -22590,10 +23485,10 @@ function FillAdvancedControls({
22590
23485
  ] }),
22591
23486
  /* @__PURE__ */ jsxs("div", { className: `${COL2} space-y-1.5 rounded border border-border p-2`, children: [
22592
23487
  /* @__PURE__ */ jsx("div", { className: "text-[11px] uppercase tracking-wide text-muted-foreground", children: t("pptx.fillAdvanced.gradientStops") }),
22593
- gradientStops.map((stop, i) => /* @__PURE__ */ jsx(
23488
+ gradientStops.map((stop2, i) => /* @__PURE__ */ jsx(
22594
23489
  GradientStopRow,
22595
23490
  {
22596
- stop,
23491
+ stop: stop2,
22597
23492
  index: i,
22598
23493
  total: gradientStops.length,
22599
23494
  allStops: gradientStops,
@@ -22858,7 +23753,7 @@ function StrokeEffectsSection({
22858
23753
  ] }),
22859
23754
  EFFECT_CONFIGS.map((cfg) => {
22860
23755
  const on = cfg.isOn(style);
22861
- return /* @__PURE__ */ jsxs(React4.Fragment, { children: [
23756
+ return /* @__PURE__ */ jsxs(React5.Fragment, { children: [
22862
23757
  /* @__PURE__ */ jsxs("label", { className: `inline-flex items-center gap-2 text-foreground ${COL2}`, children: [
22863
23758
  /* @__PURE__ */ jsx(
22864
23759
  WebCheckbox,
@@ -23726,7 +24621,7 @@ function TextWarpGallery({
23726
24621
  onUpdateTextStyle
23727
24622
  }) {
23728
24623
  const { t } = useTranslation();
23729
- const [expanded, setExpanded] = React4.useState(false);
24624
+ const [expanded, setExpanded] = React5.useState(false);
23730
24625
  const currentPreset = ts?.textWarpPreset || "textNoShape";
23731
24626
  return /* @__PURE__ */ jsxs("div", { className: "mt-2 rounded border border-border bg-card p-2 space-y-2", children: [
23732
24627
  /* @__PURE__ */ jsxs(
@@ -24377,7 +25272,7 @@ function SmartArtStyleControls({
24377
25272
  onChangeStyle
24378
25273
  }) {
24379
25274
  const { t } = useTranslation();
24380
- const translate = React4.useCallback((key) => t(key), [t]);
25275
+ const translate = React5.useCallback((key) => t(key), [t]);
24381
25276
  return /* @__PURE__ */ jsxs(Fragment, { children: [
24382
25277
  /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1 text-[11px]", children: [
24383
25278
  /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: t("pptx.smartart.colorScheme") }),
@@ -24432,9 +25327,9 @@ function SmartArtPropertiesPanel({
24432
25327
  const nodes = smartArtData.nodes ?? [];
24433
25328
  const layout = smartArtData.resolvedLayoutType;
24434
25329
  const topLevelCount = nodes.filter((n) => !n.parentId).length;
24435
- const inputRefs = React4.useRef(/* @__PURE__ */ new Map());
24436
- const pendingFocusId = React4.useRef(null);
24437
- React4.useEffect(() => {
25330
+ const inputRefs = React5.useRef(/* @__PURE__ */ new Map());
25331
+ const pendingFocusId = React5.useRef(null);
25332
+ React5.useEffect(() => {
24438
25333
  const id = pendingFocusId.current;
24439
25334
  if (id) {
24440
25335
  inputRefs.current.get(id)?.focus();
@@ -24998,14 +25893,14 @@ function GradientControls({
24998
25893
  ] })
24999
25894
  ] }),
25000
25895
  /* @__PURE__ */ jsx("span", { className: LBL, children: t("pptx.table.gradientStops") }),
25001
- stops.map((stop, idx) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
25896
+ stops.map((stop2, idx) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
25002
25897
  /* @__PURE__ */ jsx(
25003
25898
  "input",
25004
25899
  {
25005
25900
  type: "color",
25006
25901
  disabled: !canEdit,
25007
25902
  className: "h-6 w-6 rounded border border-border cursor-pointer",
25008
- value: stop.color,
25903
+ value: stop2.color,
25009
25904
  onChange: (e) => {
25010
25905
  updateStop(idx, { color: e.target.value });
25011
25906
  pushColor(e.target.value);
@@ -25020,7 +25915,7 @@ function GradientControls({
25020
25915
  className: NUM,
25021
25916
  min: 0,
25022
25917
  max: 100,
25023
- value: Math.round(stop.position),
25918
+ value: Math.round(stop2.position),
25024
25919
  onChange: (e) => updateStop(idx, {
25025
25920
  position: Number(e.target.value)
25026
25921
  })
@@ -26048,7 +26943,7 @@ function CommentBody({ text, mentions, className }) {
26048
26943
  index
26049
26944
  ) : (
26050
26945
  // eslint-disable-next-line react/no-array-index-key -- segments are positional
26051
- /* @__PURE__ */ jsx(React4.Fragment, { children: segment.text }, index)
26946
+ /* @__PURE__ */ jsx(React5.Fragment, { children: segment.text }, index)
26052
26947
  )
26053
26948
  ) });
26054
26949
  }
@@ -27550,7 +28445,7 @@ function PresentationPropertiesPanel({
27550
28445
  onUpdateTagCollections
27551
28446
  }) {
27552
28447
  const { t } = useTranslation();
27553
- const handleTransitionChange = React4.useCallback(
28448
+ const handleTransitionChange = React5.useCallback(
27554
28449
  (updates) => {
27555
28450
  onUpdateSlide({
27556
28451
  transition: mergeSlideTransition(activeSlide?.transition, updates)
@@ -28591,7 +29486,7 @@ function PresentationTouchControls({
28591
29486
  return null;
28592
29487
  }
28593
29488
  const btnClass = "pointer-events-auto flex items-center justify-center w-11 h-11 min-w-11 min-h-11 rounded-full bg-black/55 text-white shadow-lg active:bg-black/75";
28594
- const stop = (e) => {
29489
+ const stop2 = (e) => {
28595
29490
  e.stopPropagation();
28596
29491
  };
28597
29492
  return /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -28606,7 +29501,7 @@ function PresentationTouchControls({
28606
29501
  touchAction: "manipulation"
28607
29502
  },
28608
29503
  onClick: (e) => {
28609
- stop(e);
29504
+ stop2(e);
28610
29505
  onEndPresentation();
28611
29506
  },
28612
29507
  "aria-label": t("pptx.presenter.endPresentation"),
@@ -28625,7 +29520,7 @@ function PresentationTouchControls({
28625
29520
  },
28626
29521
  disabled: currentSlideIndex <= 0,
28627
29522
  onClick: (e) => {
28628
- stop(e);
29523
+ stop2(e);
28629
29524
  onMovePresentationSlide(-1);
28630
29525
  },
28631
29526
  "aria-label": t("pptx.presenter.previousSlide"),
@@ -28643,7 +29538,7 @@ function PresentationTouchControls({
28643
29538
  },
28644
29539
  disabled: currentSlideIndex >= totalSlides - 1,
28645
29540
  onClick: (e) => {
28646
- stop(e);
29541
+ stop2(e);
28647
29542
  onMovePresentationSlide(1);
28648
29543
  },
28649
29544
  "aria-label": t("pptx.presenter.nextSlide"),
@@ -30982,9 +31877,11 @@ function ViewerBottomPanels({
30982
31877
  onNotesHeightChange
30983
31878
  }) {
30984
31879
  const { isHidden } = useToolbarVisibility(hiddenActions);
31880
+ const customization = useViewerCustomizationContext();
31881
+ const showNotes = isPanelVisible(customization, "notes");
30985
31882
  return /* @__PURE__ */ jsxs(Fragment, { children: [
30986
- onResizeBottom && !isSlideNotesCollapsed && /* @__PURE__ */ jsx(ResizeHandle, { direction: "vertical", onResize: onResizeBottom }),
30987
- /* @__PURE__ */ jsx(
31883
+ showNotes && onResizeBottom && !isSlideNotesCollapsed && /* @__PURE__ */ jsx(ResizeHandle, { direction: "vertical", onResize: onResizeBottom }),
31884
+ showNotes && /* @__PURE__ */ jsx(
30988
31885
  SlideNotesPanel,
30989
31886
  {
30990
31887
  activeSlide,
@@ -30998,7 +31895,7 @@ function ViewerBottomPanels({
30998
31895
  onHeightChange: onNotesHeightChange
30999
31896
  }
31000
31897
  ),
31001
- !hideStatusBar && /* @__PURE__ */ jsx(
31898
+ !hideStatusBar && isPanelVisible(customization, "statusBar") && /* @__PURE__ */ jsx(
31002
31899
  StatusBar,
31003
31900
  {
31004
31901
  slideCount,
@@ -31016,7 +31913,7 @@ function ViewerBottomPanels({
31016
31913
  onToggleSlideSorter,
31017
31914
  collaborationSlot,
31018
31915
  hideZoomControls: isHidden("zoom"),
31019
- hideNotesToggle: isHidden("notes"),
31916
+ hideNotesToggle: isHidden("notes") || !showNotes,
31020
31917
  hideFullscreenToggle: isHidden("fullscreen")
31021
31918
  }
31022
31919
  )
@@ -31177,6 +32074,7 @@ function TitleBar(p) {
31177
32074
  const editing = (p.mode === "edit" || p.mode === "master") && p.canEdit;
31178
32075
  const { isHidden } = useToolbarVisibility(p.hiddenActions);
31179
32076
  const quickAccess = useViewerOptionsContext().quickAccess;
32077
+ const showQuickAccess = isPanelVisible(useViewerCustomizationContext(), "quickAccessToolbar");
31180
32078
  const [searchQuery, setSearchQuery] = useState("");
31181
32079
  const [searchFocused, setSearchFocused] = useState(false);
31182
32080
  const searchRef = useRef(null);
@@ -31252,7 +32150,7 @@ function TitleBar(p) {
31252
32150
  /* @__PURE__ */ jsx("span", { className: TITLE_BAR_CLASSES.autosaveLabel, children: t(p.autosaveEnabled ? "pptx.titleBar.autoSaveOn" : "pptx.titleBar.autoSaveOff") })
31253
32151
  ] }),
31254
32152
  /* @__PURE__ */ jsx("div", { className: TITLE_BAR_CLASSES.separator }),
31255
- p.onSave && /* @__PURE__ */ jsx(
32153
+ showQuickAccess && p.onSave && /* @__PURE__ */ jsx(
31256
32154
  "button",
31257
32155
  {
31258
32156
  type: "button",
@@ -31263,7 +32161,7 @@ function TitleBar(p) {
31263
32161
  children: /* @__PURE__ */ jsx(LuSave, { className: "w-3.5 h-3.5" })
31264
32162
  }
31265
32163
  ),
31266
- !isHidden("undo") && /* @__PURE__ */ jsx(
32164
+ showQuickAccess && !isHidden("undo") && /* @__PURE__ */ jsx(
31267
32165
  "button",
31268
32166
  {
31269
32167
  type: "button",
@@ -31275,7 +32173,7 @@ function TitleBar(p) {
31275
32173
  children: /* @__PURE__ */ jsx(LuUndo, { className: "w-3.5 h-3.5" })
31276
32174
  }
31277
32175
  ),
31278
- !isHidden("redo") && /* @__PURE__ */ jsx(
32176
+ showQuickAccess && !isHidden("redo") && /* @__PURE__ */ jsx(
31279
32177
  "button",
31280
32178
  {
31281
32179
  type: "button",
@@ -31287,8 +32185,8 @@ function TitleBar(p) {
31287
32185
  children: /* @__PURE__ */ jsx(LuRedo, { className: "w-3.5 h-3.5" })
31288
32186
  }
31289
32187
  ),
31290
- quickAccess.position !== "below" && /* @__PURE__ */ jsx(TitleBarQuickExtras, { quickAccess, onCommand: p.onQuickCommand }),
31291
- /* @__PURE__ */ jsx("div", { className: TITLE_BAR_CLASSES.separator })
32188
+ showQuickAccess && quickAccess.position !== "below" && /* @__PURE__ */ jsx(TitleBarQuickExtras, { quickAccess, onCommand: p.onQuickCommand }),
32189
+ showQuickAccess && /* @__PURE__ */ jsx("div", { className: TITLE_BAR_CLASSES.separator })
31292
32190
  ] }),
31293
32191
  /* @__PURE__ */ jsxs("span", { className: TITLE_BAR_CLASSES.fileGroup, children: [
31294
32192
  /* @__PURE__ */ jsx("span", { className: TITLE_BAR_CLASSES.fileName, children: p.fileName || t(TITLE_BAR_DEFAULT_FILE_KEY) }),
@@ -31414,6 +32312,7 @@ function ViewerToolbarSection(props) {
31414
32312
  onSetShowGuides
31415
32313
  } = props;
31416
32314
  const { t } = useTranslation();
32315
+ const customization = useViewerCustomizationContext();
31417
32316
  const handleAddAnimation = useCallback(
31418
32317
  (preset, group) => {
31419
32318
  if (!selectedElement || !activeSlide) {
@@ -31464,7 +32363,7 @@ function ViewerToolbarSection(props) {
31464
32363
  },
31465
32364
  [activeSlide, propertyHandlers]
31466
32365
  );
31467
- const scopedLayoutOptions = React4.useMemo(
32366
+ const scopedLayoutOptions = React5.useMemo(
31468
32367
  () => scopeLayoutOptionsToActiveSlide(s.layoutOptions, activeSlide),
31469
32368
  [s.layoutOptions, activeSlide]
31470
32369
  );
@@ -31659,7 +32558,7 @@ function ViewerToolbarSection(props) {
31659
32558
  [onSetMode, onPresentFromBeginning, printHandlers, exportHandlers, slideOps, s, zoom]
31660
32559
  );
31661
32560
  return /* @__PURE__ */ jsxs(Fragment, { children: [
31662
- !dialogs.isNarrowViewport && /* @__PURE__ */ jsx(
32561
+ !dialogs.isNarrowViewport && isPanelVisible(customization, "titleBar") && /* @__PURE__ */ jsx(
31663
32562
  TitleBar,
31664
32563
  {
31665
32564
  mode,
@@ -31710,6 +32609,7 @@ function ViewerToolbarSection(props) {
31710
32609
  tableEditorState: s.tableEditorState,
31711
32610
  editTemplateMode: s.editTemplateMode,
31712
32611
  newShapeType: s.newShapeType,
32612
+ activeFreeformTool: s.activeFreeformTool,
31713
32613
  activeTool: s.activeTool,
31714
32614
  drawingColor: s.drawingColor,
31715
32615
  drawingWidth: s.drawingWidth,
@@ -31733,6 +32633,7 @@ function ViewerToolbarSection(props) {
31733
32633
  onRedo: history.handleRedo,
31734
32634
  onToggleFindReplace: () => findReplace.setFindReplaceOpen(!findReplace.findReplaceOpen),
31735
32635
  onSetNewShapeType: s.setNewShapeType,
32636
+ onArmFreeformTool: s.setActiveFreeformTool,
31736
32637
  onAddTextBox: insertHandlers.handleAddTextBox,
31737
32638
  onAddShape: insertHandlers.handleAddShape,
31738
32639
  onAddTable: insertHandlers.handleAddTable,
@@ -32340,6 +33241,7 @@ function ViewerDialogGroup(props) {
32340
33241
  onKeepAnnotations,
32341
33242
  onDiscardAnnotations
32342
33243
  } = props;
33244
+ const printAvailable = isDialogAvailable(useViewerCustomizationContext(), "print");
32343
33245
  return /* @__PURE__ */ jsxs(Fragment, { children: [
32344
33246
  /* @__PURE__ */ jsx(
32345
33247
  VersionHistoryPanel,
@@ -32480,7 +33382,7 @@ function ViewerDialogGroup(props) {
32480
33382
  /* @__PURE__ */ jsx(
32481
33383
  PrintDialog,
32482
33384
  {
32483
- open: printHandlers.isPrintDialogOpen,
33385
+ open: printHandlers.isPrintDialogOpen && printAvailable,
32484
33386
  onClose: () => printHandlers.setIsPrintDialogOpen(false),
32485
33387
  onPrint: printHandlers.handlePrintSvg,
32486
33388
  slides,
@@ -32584,6 +33486,45 @@ function ViewerPresentationLayer(props) {
32584
33486
  )
32585
33487
  ] });
32586
33488
  }
33489
+ function useOutlineAuthoring({
33490
+ state,
33491
+ updateElement,
33492
+ insertShape
33493
+ }) {
33494
+ const customization = useViewerCustomizationContext();
33495
+ const { editPointsElementId, setEditPointsElementId, activeFreeformTool, setActiveFreeformTool } = state;
33496
+ const enabled = isEditPointsEnabled(customization);
33497
+ const onExitEditPoints = useCallback(
33498
+ () => setEditPointsElementId(null),
33499
+ [setEditPointsElementId]
33500
+ );
33501
+ const onFreeformCancel = useCallback(() => setActiveFreeformTool(null), [setActiveFreeformTool]);
33502
+ return useMemo(
33503
+ () => ({
33504
+ editPointsElementId: enabled ? editPointsElementId : null,
33505
+ hiddenEditPointsCommands: customization.hiddenEditPointsCommands,
33506
+ onCommitEditPoints: (elementId, patch) => updateElement(elementId, patch),
33507
+ onExitEditPoints,
33508
+ freeformTool: activeFreeformTool,
33509
+ onFreeformCommit: (shape) => {
33510
+ setActiveFreeformTool(null);
33511
+ insertShape(shape);
33512
+ },
33513
+ onFreeformCancel
33514
+ }),
33515
+ [
33516
+ enabled,
33517
+ editPointsElementId,
33518
+ customization.hiddenEditPointsCommands,
33519
+ updateElement,
33520
+ onExitEditPoints,
33521
+ activeFreeformTool,
33522
+ setActiveFreeformTool,
33523
+ insertShape,
33524
+ onFreeformCancel
33525
+ ]
33526
+ );
33527
+ }
32587
33528
  function PresentationStage({
32588
33529
  activeSlide,
32589
33530
  templateElements,
@@ -32873,6 +33814,11 @@ function ViewerCanvasArea(props) {
32873
33814
  const { t } = useTranslation();
32874
33815
  const { isHidden } = useToolbarVisibility(hiddenActions);
32875
33816
  const viewerOptions = useViewerOptionsContext();
33817
+ const outlineAuthoring = useOutlineAuthoring({
33818
+ state: s,
33819
+ updateElement: canvasHandlers.handleUpdateSmartArtElement,
33820
+ insertShape: insertHandlers.handleAddFreeformShape
33821
+ });
32876
33822
  const effectiveSlide = mode === "master" ? masterPseudoSlide : activeSlide;
32877
33823
  const effectiveTemplateElements = mode === "master" ? [] : templateElements;
32878
33824
  const fieldContext = useMemo(
@@ -33157,6 +34103,7 @@ ${url}`)) {
33157
34103
  onMouseDown: handleElementMouseDown,
33158
34104
  onContextMenu: canvasHandlers.handleElementContextMenu,
33159
34105
  onCanvasMouseDown: canvasHandlers.handleCanvasMouseDown,
34106
+ onCanvasContextMenu: canvasHandlers.handleCanvasContextMenu,
33160
34107
  onResizePointerDown: canvasHandlers.handleResizePointerDown,
33161
34108
  onAdjustmentPointerDown: canvasHandlers.handleAdjustmentPointerDown,
33162
34109
  onRotate: canvasHandlers.handleRotate,
@@ -33184,6 +34131,7 @@ ${url}`)) {
33184
34131
  fieldContext,
33185
34132
  tableStyleContext,
33186
34133
  aiActive: aiCanvasActive,
34134
+ outlineAuthoring,
33187
34135
  collaborationOverlay: /* @__PURE__ */ jsxs(Fragment, { children: [
33188
34136
  /* @__PURE__ */ jsx(
33189
34137
  RemoteSelectionOverlay,
@@ -33335,7 +34283,7 @@ function useTableStyleMapHandlers(input) {
33335
34283
  var AiChatPanel = lazy(async () => {
33336
34284
  const [{ useChat }, { default: Panel }] = await Promise.all([
33337
34285
  import('@ai-sdk/react'),
33338
- import('./AiChatPanel-HXGCZPUX.mjs')
34286
+ import('./AiChatPanel-X2MVL5UP.mjs')
33339
34287
  ]);
33340
34288
  function BoundAiChatPanel(props) {
33341
34289
  return /* @__PURE__ */ jsx(Panel, { ...props, useChat });
@@ -34258,15 +35206,17 @@ function ViewerSidePanels(props) {
34258
35206
  setTableStylesToDelete: s.setTableStylesToDelete
34259
35207
  });
34260
35208
  const effectiveSlide = mode === "master" ? masterPseudoSlide : activeSlide;
35209
+ const customization = useViewerCustomizationContext();
35210
+ const inspectorOpen = (mode === "edit" || mode === "master") && s.isInspectorPaneOpen && isPanelVisible(customization, "inspector");
34261
35211
  const currentBuiltInTheme = BUILT_IN_THEMES.find(
34262
35212
  (candidate) => themeColorSchemesEqual(s.theme?.colorScheme, candidate.colorScheme)
34263
35213
  ) ?? null;
34264
35214
  return /* @__PURE__ */ jsxs(Fragment, { children: [
34265
- (mode === "edit" || mode === "master") && s.isInspectorPaneOpen && onResizeRight && /* @__PURE__ */ jsx(ResizeHandle, { direction: "horizontal", onResize: onResizeRight }),
35215
+ inspectorOpen && onResizeRight && /* @__PURE__ */ jsx(ResizeHandle, { direction: "horizontal", onResize: onResizeRight }),
34266
35216
  /* @__PURE__ */ jsx(
34267
35217
  ViewerInspector,
34268
35218
  {
34269
- isOpen: (mode === "edit" || mode === "master") && s.isInspectorPaneOpen,
35219
+ isOpen: inspectorOpen,
34270
35220
  canEdit,
34271
35221
  mode,
34272
35222
  activeSlide: effectiveSlide,
@@ -34611,6 +35561,8 @@ function ViewerMainContent(props) {
34611
35561
  tableEditorState: state.tableEditorState,
34612
35562
  hasMultiSelection: state.effectiveSelectedIds.length > 1,
34613
35563
  selectionGroupable: manipulation.selectionGroupable,
35564
+ hasClipboard: Boolean(state.clipboardPayload),
35565
+ editPointsAvailability: resolveEditPointsAvailability(selectedElement),
34614
35566
  onAction: manipulation.handleContextMenuAction,
34615
35567
  onInsertTableRow: tableOps.handleInsertTableRow,
34616
35568
  onDeleteTableRow: tableOps.handleDeleteTableRow,
@@ -35464,10 +36416,11 @@ function readValue(options, control) {
35464
36416
  function InfoTip({ text }) {
35465
36417
  return /* @__PURE__ */ jsx("span", { title: text, className: "inline-flex cursor-help align-middle", children: /* @__PURE__ */ jsx(LuInfo, { className: "ml-1 h-3.5 w-3.5 text-primary/70", "aria-label": text }) });
35466
36418
  }
36419
+ var IGNORE_CHANGE = () => void 0;
35467
36420
  function ControlRow({
35468
36421
  control,
35469
36422
  options,
35470
- onOptionChange
36423
+ onOptionChange: emitChange
35471
36424
  }) {
35472
36425
  const { t } = useTranslation();
35473
36426
  const { viewportWidth } = useIsMobile();
@@ -35477,6 +36430,9 @@ function ControlRow({
35477
36430
  const info = control.infoKey ? /* @__PURE__ */ jsx(InfoTip, { text: t(control.infoKey) }) : null;
35478
36431
  const rowClass = cn("flex items-center justify-between gap-3 py-1.5", control.indent && "pl-6");
35479
36432
  const rowStyle = { minHeight: fieldMinHeight };
36433
+ const locked = control.readOnly === true;
36434
+ const lockedTitle = locked ? t("pptx.options.lockedByHost") : void 0;
36435
+ const onOptionChange = locked ? IGNORE_CHANGE : emitChange;
35480
36436
  if (control.kind === "toggle") {
35481
36437
  return /* @__PURE__ */ jsxs("label", { className: cn(rowClass, "cursor-pointer select-none"), style: rowStyle, children: [
35482
36438
  /* @__PURE__ */ jsxs("span", { className: "text-sm text-foreground", children: [
@@ -35488,6 +36444,8 @@ function ControlRow({
35488
36444
  {
35489
36445
  checked: value === true,
35490
36446
  "aria-label": label,
36447
+ disabled: locked,
36448
+ title: lockedTitle,
35491
36449
  onChange: (event) => onOptionChange(
35492
36450
  control.group,
35493
36451
  control.key,
@@ -35507,6 +36465,8 @@ function ControlRow({
35507
36465
  WebSelect,
35508
36466
  {
35509
36467
  "aria-label": label,
36468
+ disabled: locked,
36469
+ title: lockedTitle,
35510
36470
  style: { minHeight: fieldMinHeight },
35511
36471
  value: typeof value === "string" ? value : "",
35512
36472
  onChange: (event) => onOptionChange(
@@ -35531,6 +36491,8 @@ function ControlRow({
35531
36491
  {
35532
36492
  type: "number",
35533
36493
  "aria-label": label,
36494
+ disabled: locked,
36495
+ title: lockedTitle,
35534
36496
  style: { minHeight: fieldMinHeight },
35535
36497
  className: "w-20 rounded border border-border bg-background px-2 py-1 text-right text-xs text-foreground",
35536
36498
  min: control.min,
@@ -35559,6 +36521,8 @@ function ControlRow({
35559
36521
  {
35560
36522
  type: "text",
35561
36523
  "aria-label": label,
36524
+ disabled: locked,
36525
+ title: lockedTitle,
35562
36526
  style: { minHeight: fieldMinHeight },
35563
36527
  className: "w-48 max-w-[55%] rounded border border-border bg-background px-2 py-1 text-xs text-foreground",
35564
36528
  maxLength: control.maxLength,
@@ -36070,6 +37034,7 @@ function SettingsDialog({
36070
37034
  }) {
36071
37035
  const [activeTabId, setActiveTabId] = useState("general");
36072
37036
  const { t } = useTranslation();
37037
+ const customization = useViewerCustomizationContext();
36073
37038
  const { panelStyle, handlers: dragHandlers } = useModalDismissDrag(onClose);
36074
37039
  const { viewportWidth, viewportHeight } = useIsMobile();
36075
37040
  const touchTargetPx = getDensePanelTouchTargetPx(viewportWidth);
@@ -36108,10 +37073,14 @@ function SettingsDialog({
36108
37073
  if (!isOpen) {
36109
37074
  return null;
36110
37075
  }
36111
- const activeTab = VIEWER_OPTIONS_TABS.find((tab) => tab.id === activeTabId) ?? VIEWER_OPTIONS_TABS[0];
37076
+ const tabs = customizeOptionsTabs(VIEWER_OPTIONS_TABS, customization);
37077
+ const showAiTab = Boolean(aiEnabled) && isOptionsPageVisible(customization, AI_TAB_ID);
37078
+ const activeTab = tabs.find((tab) => tab.id === activeTabId) ?? tabs[0];
37079
+ const aiActive = activeTabId === AI_TAB_ID && showAiTab;
36112
37080
  if (!activeTab) {
36113
37081
  return null;
36114
37082
  }
37083
+ const currentTabId = aiActive ? AI_TAB_ID : activeTab.id;
36115
37084
  return /* @__PURE__ */ jsxs(Fragment, { children: [
36116
37085
  /* @__PURE__ */ jsx(
36117
37086
  "button",
@@ -36168,31 +37137,31 @@ function SettingsDialog({
36168
37137
  "aria-label": t("pptx.options.title"),
36169
37138
  className: "w-44 shrink-0 space-y-0.5 overflow-y-auto border-r border-border/60 p-2 max-md:flex max-md:w-full max-md:space-y-0 max-md:gap-1 max-md:overflow-x-auto max-md:border-b max-md:border-r-0",
36170
37139
  children: [
36171
- VIEWER_OPTIONS_TABS.map((tab) => /* @__PURE__ */ jsx(
37140
+ tabs.map((tab) => /* @__PURE__ */ jsx(
36172
37141
  "button",
36173
37142
  {
36174
37143
  type: "button",
36175
37144
  onClick: () => setActiveTabId(tab.id),
36176
- "aria-current": activeTabId === tab.id,
37145
+ "aria-current": currentTabId === tab.id,
36177
37146
  style: navBtnStyle,
36178
37147
  className: cn(
36179
37148
  "flex w-full items-center whitespace-nowrap rounded px-3 py-2 text-left text-sm transition-colors max-md:w-auto",
36180
- activeTabId === tab.id ? "bg-primary/10 font-medium text-primary" : "text-foreground hover:bg-accent"
37149
+ currentTabId === tab.id ? "bg-primary/10 font-medium text-primary" : "text-foreground hover:bg-accent"
36181
37150
  ),
36182
37151
  children: t(tab.labelKey)
36183
37152
  },
36184
37153
  tab.id
36185
37154
  )),
36186
- aiEnabled && /* @__PURE__ */ jsx(
37155
+ showAiTab && /* @__PURE__ */ jsx(
36187
37156
  "button",
36188
37157
  {
36189
37158
  type: "button",
36190
37159
  onClick: () => setActiveTabId(AI_TAB_ID),
36191
- "aria-current": activeTabId === AI_TAB_ID,
37160
+ "aria-current": aiActive,
36192
37161
  style: navBtnStyle,
36193
37162
  className: cn(
36194
37163
  "flex w-full items-center whitespace-nowrap rounded px-3 py-2 text-left text-sm transition-colors max-md:w-auto",
36195
- activeTabId === AI_TAB_ID ? "bg-primary/10 font-medium text-primary" : "text-foreground hover:bg-accent"
37164
+ aiActive ? "bg-primary/10 font-medium text-primary" : "text-foreground hover:bg-accent"
36196
37165
  ),
36197
37166
  children: t("pptx.ai.settingsSectionTitle")
36198
37167
  }
@@ -36200,7 +37169,7 @@ function SettingsDialog({
36200
37169
  ]
36201
37170
  }
36202
37171
  ),
36203
- /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-y-auto px-5 py-4", children: activeTabId === AI_TAB_ID ? /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
37172
+ /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-y-auto px-5 py-4", children: aiActive ? /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
36204
37173
  /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-foreground", children: t("pptx.ai.settingsSectionTitle") }),
36205
37174
  /* @__PURE__ */ jsx(SettingsAiTab, { store: chatStore })
36206
37175
  ] }) : activeTab.custom === "language" ? /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
@@ -36733,6 +37702,201 @@ function useRunProgramNoticesState() {
36733
37702
  }, []);
36734
37703
  return { notices, addNotice, dismiss, dismissAll };
36735
37704
  }
37705
+ var CROP_KEEP_SELECTOR = [
37706
+ "[data-pptx-crop-overlay]",
37707
+ '[data-pptx-ribbon-control="crop"]',
37708
+ '[data-pptx-ribbon-control="crop-menu"]',
37709
+ "[data-pptx-crop-aspect]",
37710
+ "[data-pptx-crop-action]"
37711
+ ].join(",");
37712
+ function naturalSizeOf(elementId) {
37713
+ if (typeof document === "undefined" || typeof CSS === "undefined") {
37714
+ return void 0;
37715
+ }
37716
+ const img = document.querySelector(
37717
+ `[data-element-id="${CSS.escape(elementId)}"][data-pptx-element="true"] img`
37718
+ );
37719
+ return img && img.naturalWidth > 0 && img.naturalHeight > 0 ? { width: img.naturalWidth, height: img.naturalHeight } : void 0;
37720
+ }
37721
+ function isEditableTarget(target) {
37722
+ return target instanceof HTMLElement && (target.isContentEditable || target.tagName === "INPUT" || target.tagName === "TEXTAREA");
37723
+ }
37724
+ function usePictureCropMode(input) {
37725
+ const { cropSession, cropSessionRef, setCropSession, editable, selectedElement } = input;
37726
+ const { elementLookup, updateElementById, markDirty, activeSlideIndex } = input;
37727
+ const single = input.effectiveSelectedIds.length === 1 ? selectedElement : null;
37728
+ const canCrop = editable && canCropElement(single);
37729
+ const element = cropSession ? elementLookup.get(cropSession.elementId) ?? null : null;
37730
+ const lookupRef = useRef(elementLookup);
37731
+ lookupRef.current = elementLookup;
37732
+ const sessionSlideRef = useRef(activeSlideIndex);
37733
+ const commit = useCallback(() => {
37734
+ const session = cropSessionRef.current;
37735
+ if (!session) {
37736
+ return;
37737
+ }
37738
+ const current = lookupRef.current.get(session.elementId);
37739
+ setCropSession(null);
37740
+ if (current && cropSessionChanged(session, current)) {
37741
+ markDirty();
37742
+ }
37743
+ }, [cropSessionRef, markDirty, setCropSession]);
37744
+ const cancel = useCallback(() => {
37745
+ const session = cropSessionRef.current;
37746
+ if (!session) {
37747
+ return;
37748
+ }
37749
+ if (lookupRef.current.has(session.elementId)) {
37750
+ updateElementById(session.elementId, cancelCropUpdate(session));
37751
+ }
37752
+ setCropSession(null);
37753
+ }, [cropSessionRef, setCropSession, updateElementById]);
37754
+ const enter = useCallback(() => {
37755
+ if (cropSessionRef.current || !canCrop) {
37756
+ return;
37757
+ }
37758
+ sessionSlideRef.current = activeSlideIndex;
37759
+ setCropSession(startCropSession(single));
37760
+ }, [activeSlideIndex, canCrop, cropSessionRef, setCropSession, single]);
37761
+ const toggle = useCallback(() => {
37762
+ if (cropSessionRef.current) {
37763
+ commit();
37764
+ } else {
37765
+ enter();
37766
+ }
37767
+ }, [commit, cropSessionRef, enter]);
37768
+ const liveUpdate = useCallback(
37769
+ (update) => {
37770
+ const session = cropSessionRef.current;
37771
+ if (session) {
37772
+ updateElementById(session.elementId, update);
37773
+ }
37774
+ },
37775
+ [cropSessionRef, updateElementById]
37776
+ );
37777
+ const target = element ?? single;
37778
+ const applyOnce = (build) => {
37779
+ if (target && editable && canCropElement(target)) {
37780
+ updateElementById(target.id, build(target));
37781
+ }
37782
+ };
37783
+ const selectionKey = input.effectiveSelectedIds.join("|");
37784
+ useEffect(() => {
37785
+ const session = cropSessionRef.current;
37786
+ if (!session) {
37787
+ return;
37788
+ }
37789
+ if (selectionKey !== session.elementId || activeSlideIndex !== sessionSlideRef.current || !editable || !lookupRef.current.has(session.elementId)) {
37790
+ commit();
37791
+ }
37792
+ }, [activeSlideIndex, commit, cropSessionRef, editable, selectionKey]);
37793
+ const active = cropSession !== null;
37794
+ useEffect(() => {
37795
+ if (!active) {
37796
+ return;
37797
+ }
37798
+ const onKeyDown = (event) => {
37799
+ const action = cropModeKeyAction(event.key);
37800
+ if (!action || isEditableTarget(event.target)) {
37801
+ return;
37802
+ }
37803
+ event.preventDefault();
37804
+ event.stopImmediatePropagation();
37805
+ if (action === "commit") {
37806
+ commit();
37807
+ } else {
37808
+ cancel();
37809
+ }
37810
+ };
37811
+ const onPointerDown = (event) => {
37812
+ const node = event.target instanceof Element ? event.target : null;
37813
+ if (!node?.closest(CROP_KEEP_SELECTOR)) {
37814
+ commit();
37815
+ }
37816
+ };
37817
+ window.addEventListener("keydown", onKeyDown, true);
37818
+ window.addEventListener("pointerdown", onPointerDown, true);
37819
+ return () => {
37820
+ window.removeEventListener("keydown", onKeyDown, true);
37821
+ window.removeEventListener("pointerdown", onPointerDown, true);
37822
+ };
37823
+ }, [active, cancel, commit]);
37824
+ return {
37825
+ element,
37826
+ canCrop: canCrop || element !== null,
37827
+ toggle,
37828
+ enter,
37829
+ commit,
37830
+ cancel,
37831
+ liveUpdate,
37832
+ cropToAspect: (w, h) => applyOnce((el) => cropToAspectRatio(el, w, h)),
37833
+ fill: () => applyOnce((el) => cropFill(el, naturalSizeOf(el.id))),
37834
+ fit: () => applyOnce((el) => cropFit(el, naturalSizeOf(el.id)))
37835
+ };
37836
+ }
37837
+
37838
+ // src/viewer/hooks/useShapeFormatCommands.ts
37839
+ function useShapeFormatCommands(input) {
37840
+ const { state, editorOps, history, canEdit, mode } = input;
37841
+ const editable = canEdit && mode === "edit";
37842
+ const crop = usePictureCropMode({
37843
+ cropSession: state.cropSession,
37844
+ cropSessionRef: state.cropSessionRef,
37845
+ setCropSession: state.setCropSession,
37846
+ editable,
37847
+ selectedElement: state.selectedElement,
37848
+ effectiveSelectedIds: state.effectiveSelectedIds,
37849
+ elementLookup: state.elementLookup,
37850
+ activeSlideIndex: state.activeSlideIndex,
37851
+ updateElementById: editorOps.ops.updateElementById,
37852
+ markDirty: history.markDirty
37853
+ });
37854
+ const { canMergeShapes, handleMergeShapes } = editorOps.manipulation;
37855
+ return {
37856
+ canMergeShapes: editable && canMergeShapes,
37857
+ mergeShapes: (operation) => {
37858
+ if (editable) {
37859
+ handleMergeShapes(operation);
37860
+ }
37861
+ },
37862
+ crop
37863
+ };
37864
+ }
37865
+ function useViewerCustomization(customization, legacyHiddenActions, optionsStore) {
37866
+ const controllerRef = useRef(null);
37867
+ controllerRef.current ??= createCustomizationController(customization);
37868
+ const controller = controllerRef.current;
37869
+ const appliedRef = useRef(customization);
37870
+ useLayoutEffect(() => {
37871
+ if (appliedRef.current === customization) {
37872
+ return;
37873
+ }
37874
+ appliedRef.current = customization;
37875
+ controller.api.setCustomization(customization ?? {});
37876
+ }, [controller, customization]);
37877
+ const resolved = useSyncExternalStore(
37878
+ controller.subscribe,
37879
+ controller.getResolved,
37880
+ controller.getResolved
37881
+ );
37882
+ const appliedConstraintsRef = useRef(null);
37883
+ useLayoutEffect(() => {
37884
+ const key = JSON.stringify([resolved.lockedSettings, resolved.defaultSettings]);
37885
+ if (appliedConstraintsRef.current === key) {
37886
+ return;
37887
+ }
37888
+ appliedConstraintsRef.current = key;
37889
+ optionsStore.setConstraints({
37890
+ locked: resolved.lockedSettings,
37891
+ defaults: resolved.defaultSettings
37892
+ });
37893
+ }, [optionsStore, resolved]);
37894
+ const hiddenActions = useMemo(
37895
+ () => resolveEffectiveHiddenActions(resolved, legacyHiddenActions),
37896
+ [resolved, legacyHiddenActions]
37897
+ );
37898
+ return { resolved, api: controller.api, hiddenActions };
37899
+ }
36736
37900
  var PowerPointViewer = forwardRef(
36737
37901
  // oxlint-disable-next-line prefer-arrow-callback -- named fn gives the forwardRef component its displayName
36738
37902
  function PowerPointViewer2(props, ref) {
@@ -36771,8 +37935,9 @@ var PowerPointViewer = forwardRef(
36771
37935
  lineChart3D = false,
36772
37936
  areaChart3D = false,
36773
37937
  pieChart3D = false,
36774
- hiddenActions,
36775
- ai
37938
+ hiddenActions: legacyHiddenActions,
37939
+ ai,
37940
+ customization
36776
37941
  } = props;
36777
37942
  useEffect(() => {
36778
37943
  const css = buildUserFontFaceStyles(fonts);
@@ -36871,6 +38036,11 @@ var PowerPointViewer = forwardRef(
36871
38036
  })();
36872
38037
  }, []);
36873
38038
  const { optionsStore, options: viewerOptions } = useViewerOptions();
38039
+ const custom = useViewerCustomization(customization, legacyHiddenActions, optionsStore);
38040
+ const { resolved: customizationResolved, hiddenActions } = custom;
38041
+ const aiEnabled = Boolean(ai) && isFeatureEnabled(customizationResolved, "ai");
38042
+ const optionsAvailable = isDialogAvailable(customizationResolved, "options");
38043
+ const shareAvailable = isDialogAvailable(customizationResolved, "share");
36874
38044
  const [protectedViewOverridden, setProtectedViewOverridden] = useState(false);
36875
38045
  useEffect(() => {
36876
38046
  setProtectedViewOverridden(false);
@@ -37030,14 +38200,15 @@ var PowerPointViewer = forwardRef(
37030
38200
  const activeCustomShow = state.customShows.find((show) => show.id === state.activeCustomShowId) ?? null;
37031
38201
  const hasActivePointerInteraction = useCallback(
37032
38202
  () => Boolean(
37033
- state.dragStateRef.current || state.resizeStateRef.current || state.marqueeStateRef.current || state.shapeAdjustmentDragStateRef.current || state.isDrawingRef.current
38203
+ state.dragStateRef.current || state.resizeStateRef.current || state.marqueeStateRef.current || state.shapeAdjustmentDragStateRef.current || state.isDrawingRef.current || state.cropSessionRef.current
37034
38204
  ),
37035
38205
  [
37036
38206
  state.dragStateRef,
37037
38207
  state.resizeStateRef,
37038
38208
  state.marqueeStateRef,
37039
38209
  state.shapeAdjustmentDragStateRef,
37040
- state.isDrawingRef
38210
+ state.isDrawingRef,
38211
+ state.cropSessionRef
37041
38212
  ]
37042
38213
  );
37043
38214
  const zoom = useZoomViewport({
@@ -37204,8 +38375,10 @@ var PowerPointViewer = forwardRef(
37204
38375
  userName: authorName ?? collaboration?.userName ?? (viewerOptions.general.userName || void 0),
37205
38376
  handlerRef: actionSoundHandlerRef,
37206
38377
  // Options > Proofing > AutoCorrect, applied to committed inline-edit text.
37207
- transformCommittedText: (text) => applyAutoCorrect(text, viewerOptions.proofing)
38378
+ transformCommittedText: (text) => applyAutoCorrect(text, viewerOptions.proofing),
38379
+ keyboard: customizationResolved.keyboard
37208
38380
  });
38381
+ const shapeFormat = useShapeFormatCommands({ state, editorOps, history, canEdit, mode });
37209
38382
  const {
37210
38383
  exportHandlers: rawExportHandlers,
37211
38384
  printHandlers,
@@ -37281,7 +38454,9 @@ var PowerPointViewer = forwardRef(
37281
38454
  onModeChange,
37282
38455
  onZoomChange,
37283
38456
  onSelectionChange,
37284
- onSlideCountChange
38457
+ onSlideCountChange,
38458
+ customizationApi: custom.api,
38459
+ customization: customizationResolved
37285
38460
  });
37286
38461
  const viewPreferencesSync = useViewPreferencesSync({
37287
38462
  loadVersion,
@@ -37402,7 +38577,7 @@ var PowerPointViewer = forwardRef(
37402
38577
  markDirty: history.markDirty,
37403
38578
  applyThemeUpdates: applyAiTheme
37404
38579
  });
37405
- const showSlidesPane = mode === "edit" && !isMobile && !dialogs.isNarrowViewport && state.isSlidesPaneOpen;
38580
+ const showSlidesPane = mode === "edit" && !isMobile && !dialogs.isNarrowViewport && state.isSlidesPaneOpen && isPanelVisible(customizationResolved, "slidesPane");
37406
38581
  const showMasterPane = mode === "master" && !isMobile && state.isSlidesPaneOpen;
37407
38582
  const addinStatus = {
37408
38583
  smartArt3d: smartArt3D && !viewerOptions.advanced.disable3DRendering,
@@ -37455,7 +38630,7 @@ var PowerPointViewer = forwardRef(
37455
38630
  onPresentFromBeginning: presentation.enterPresentModeFromBeginning,
37456
38631
  onEnterPresenterView: handleEnterPresenterView,
37457
38632
  onEnterRehearsalMode: handleEnterRehearsalMode,
37458
- onOpenSettings: () => setIsSettingsOpen(true),
38633
+ onOpenSettings: optionsAvailable ? () => setIsSettingsOpen(true) : void 0,
37459
38634
  onOpenHeaderFooter: () => setIsHeaderFooterOpen(true),
37460
38635
  onOpenShareDialog: () => setIsShareDialogOpen(true),
37461
38636
  onOpenFile: handleOpenFile,
@@ -37470,7 +38645,7 @@ var PowerPointViewer = forwardRef(
37470
38645
  },
37471
38646
  hiddenActions,
37472
38647
  recentPresentationsCount: viewerOptions.advanced.recentPresentationsCount,
37473
- aiEnabled: Boolean(ai),
38648
+ aiEnabled,
37474
38649
  isAiPanelOpen: aiPanel.isOpen,
37475
38650
  onToggleAiPanel: aiPanel.toggle,
37476
38651
  isProtectedView,
@@ -37545,9 +38720,9 @@ var PowerPointViewer = forwardRef(
37545
38720
  rightPanelWidth: isMobile ? void 0 : resizablePanels.rightWidth,
37546
38721
  onResizeRight: isMobile ? void 0 : resizablePanels.onResizeRight,
37547
38722
  hiddenActions,
37548
- aiConfig: ai,
37549
- aiBridge: ai ? aiBridge : void 0,
37550
- aiPanel: ai ? aiPanel : void 0
38723
+ aiConfig: aiEnabled ? ai : void 0,
38724
+ aiBridge: aiEnabled ? aiBridge : void 0,
38725
+ aiPanel: aiEnabled ? aiPanel : void 0
37551
38726
  }
37552
38727
  ),
37553
38728
  mode !== "present" && (!isVirtualKeyboardOpen || !state.isSlideNotesCollapsed) && /* @__PURE__ */ jsx(
@@ -37563,7 +38738,7 @@ var PowerPointViewer = forwardRef(
37563
38738
  autosaveStatus,
37564
38739
  onToggleNotes: () => state.setIsSlideNotesCollapsed((p) => !p),
37565
38740
  onUpdateNotes: propertyHandlers.handleUpdateNotes,
37566
- collaborationSlot: collaboration ? /* @__PURE__ */ jsx(CollaborationStatusStrip, {}) : void 0,
38741
+ collaborationSlot: collaboration && shareAvailable ? /* @__PURE__ */ jsx(CollaborationStatusStrip, {}) : void 0,
37567
38742
  notesPanelHeight: isMobile ? void 0 : resizablePanels.bottomHeight,
37568
38743
  onResizeBottom: isMobile ? void 0 : resizablePanels.onResizeBottom,
37569
38744
  scale: zoom.scale,
@@ -37671,7 +38846,7 @@ var PowerPointViewer = forwardRef(
37671
38846
  /* @__PURE__ */ jsx(
37672
38847
  SettingsDialog,
37673
38848
  {
37674
- isOpen: isSettingsOpen,
38849
+ isOpen: isSettingsOpen && optionsAvailable,
37675
38850
  onClose: () => setIsSettingsOpen(false),
37676
38851
  options: viewerOptions,
37677
38852
  onOptionChange: (group, key, value) => optionsStore.setValue(group, key, value),
@@ -37687,7 +38862,7 @@ var PowerPointViewer = forwardRef(
37687
38862
  localeCode,
37688
38863
  availableLocales: resolvedLocales,
37689
38864
  onSelectLocale: handleLocaleChange,
37690
- aiEnabled: Boolean(ai),
38865
+ aiEnabled,
37691
38866
  customFontFamilies,
37692
38867
  onCustomFontRegistered: handleCustomFontRegistered
37693
38868
  }
@@ -37711,7 +38886,7 @@ var PowerPointViewer = forwardRef(
37711
38886
  /* @__PURE__ */ jsx(
37712
38887
  ShareDialog,
37713
38888
  {
37714
- open: isShareDialogOpen,
38889
+ open: isShareDialogOpen && shareAvailable,
37715
38890
  onClose: () => setIsShareDialogOpen(false),
37716
38891
  activeCollaboration: collaboration,
37717
38892
  onStartCollaboration,
@@ -37725,7 +38900,7 @@ var PowerPointViewer = forwardRef(
37725
38900
  /* @__PURE__ */ jsx(
37726
38901
  BroadcastDialog,
37727
38902
  {
37728
- open: dialogs.isBroadcastDialogOpen,
38903
+ open: dialogs.isBroadcastDialogOpen && isDialogAvailable(customizationResolved, "broadcast"),
37729
38904
  onClose: () => dialogs.setIsBroadcastDialogOpen(false),
37730
38905
  onStartBroadcast: onStartCollaboration,
37731
38906
  onStopBroadcast: onStopCollaboration,
@@ -37803,7 +38978,7 @@ var PowerPointViewer = forwardRef(
37803
38978
  // Nothing previously provided it, so every one of those consumers was
37804
38979
  // silently reading `DEFAULT_VIEWER_OPTIONS` forever, no matter what
37805
38980
  // the user changed in the Options dialog.
37806
- /* @__PURE__ */ jsx(ViewerOptionsContext.Provider, { value: viewerOptions, children: /* @__PURE__ */ jsx(AccountAuthContext.Provider, { value: accountAuth, children: /* @__PURE__ */ jsx(Rendering3DFlagsContext.Provider, { value: effective3D, children: /* @__PURE__ */ jsx(ViewerThemeProvider, { theme: effectiveTheme, children: /* @__PURE__ */ jsxs(
38981
+ /* @__PURE__ */ jsx(ViewerOptionsContext.Provider, { value: viewerOptions, children: /* @__PURE__ */ jsx(ViewerCustomizationContext.Provider, { value: customizationResolved, children: /* @__PURE__ */ jsx(AccountAuthContext.Provider, { value: accountAuth, children: /* @__PURE__ */ jsx(Rendering3DFlagsContext.Provider, { value: effective3D, children: /* @__PURE__ */ jsx(ViewerThemeProvider, { theme: effectiveTheme, children: /* @__PURE__ */ jsxs(
37807
38982
  CollaborationProvider,
37808
38983
  {
37809
38984
  config: collaboration,
@@ -37853,10 +39028,10 @@ var PowerPointViewer = forwardRef(
37853
39028
  slideCount: slides.length
37854
39029
  }
37855
39030
  ),
37856
- viewerContent
39031
+ /* @__PURE__ */ jsx(ShapeFormatContext.Provider, { value: shapeFormat, children: viewerContent })
37857
39032
  ]
37858
39033
  }
37859
- ) }) }) }) })
39034
+ ) }) }) }) }) })
37860
39035
  );
37861
39036
  }
37862
39037
  );