pptx-react-viewer 4.6.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 (135) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/{AiChatPanel-3C7GM6ZF.js → AiChatPanel-3YILWCBX.js} +28 -28
  3. package/dist/AiChatPanel-3YILWCBX.js.br +0 -0
  4. package/dist/AiChatPanel-3YILWCBX.js.gz +0 -0
  5. package/dist/{AiChatPanel-L7DBCWE3.mjs → AiChatPanel-X2MVL5UP.mjs} +4 -4
  6. package/dist/AiChatPanel-X2MVL5UP.mjs.br +0 -0
  7. package/dist/AiChatPanel-X2MVL5UP.mjs.gz +0 -0
  8. package/dist/{Model3DScene-USKNPWWH.js → Model3DScene-G7P6ZAIO.js} +2 -2
  9. package/dist/{Model3DScene-USKNPWWH.js.br → Model3DScene-G7P6ZAIO.js.br} +0 -0
  10. package/dist/Model3DScene-G7P6ZAIO.js.gz +0 -0
  11. package/dist/{Model3DScene-IJ7YYTYU.mjs → Model3DScene-QFWI5CEE.mjs} +1 -1
  12. package/dist/Model3DScene-QFWI5CEE.mjs.br +0 -0
  13. package/dist/Model3DScene-QFWI5CEE.mjs.gz +0 -0
  14. package/dist/{chunk-5V5SMT5A.js → chunk-2BM4GBFZ.js} +5 -5
  15. package/dist/chunk-2BM4GBFZ.js.br +0 -0
  16. package/dist/chunk-2BM4GBFZ.js.gz +0 -0
  17. package/dist/{chunk-K6QHGABT.mjs → chunk-5J6NW3YS.mjs} +55 -28
  18. package/dist/chunk-5J6NW3YS.mjs.br +0 -0
  19. package/dist/chunk-5J6NW3YS.mjs.gz +0 -0
  20. package/dist/{chunk-FZSYLXJT.js → chunk-AQIXKTAT.js} +13118 -8704
  21. package/dist/chunk-AQIXKTAT.js.br +0 -0
  22. package/dist/chunk-AQIXKTAT.js.gz +0 -0
  23. package/dist/{chunk-VCAQSSGD.mjs → chunk-E5OIDWHO.mjs} +1 -1
  24. package/dist/chunk-E5OIDWHO.mjs.br +0 -0
  25. package/dist/chunk-E5OIDWHO.mjs.gz +0 -0
  26. package/dist/{chunk-Y4QUVWZC.js → chunk-FYAOOACZ.js} +241 -214
  27. package/dist/chunk-FYAOOACZ.js.br +0 -0
  28. package/dist/chunk-FYAOOACZ.js.gz +0 -0
  29. package/dist/{chunk-INX3E37P.mjs → chunk-OECUSL2B.mjs} +80 -283
  30. package/dist/chunk-OECUSL2B.mjs.br +0 -0
  31. package/dist/chunk-OECUSL2B.mjs.gz +0 -0
  32. package/dist/{chunk-ICEZL4TM.mjs → chunk-QLDHUKH2.mjs} +13074 -8701
  33. package/dist/chunk-QLDHUKH2.mjs.br +0 -0
  34. package/dist/chunk-QLDHUKH2.mjs.gz +0 -0
  35. package/dist/{chunk-IBHIXBC5.js → chunk-SR7ETIBF.js} +889 -1091
  36. package/dist/chunk-SR7ETIBF.js.br +0 -0
  37. package/dist/chunk-SR7ETIBF.js.gz +0 -0
  38. package/dist/{chunk-ZAQFTO4P.mjs → chunk-UBYFLXAU.mjs} +1174 -148
  39. package/dist/chunk-UBYFLXAU.mjs.br +0 -0
  40. package/dist/chunk-UBYFLXAU.mjs.gz +0 -0
  41. package/dist/{chunk-3JUZOKFI.js → chunk-UIAU3NR2.js} +44 -0
  42. package/dist/chunk-UIAU3NR2.js.br +0 -0
  43. package/dist/chunk-UIAU3NR2.js.gz +0 -0
  44. package/dist/{chunk-DFSWCVRW.js → chunk-VF4RA27Q.js} +3082 -2056
  45. package/dist/chunk-VF4RA27Q.js.br +0 -0
  46. package/dist/chunk-VF4RA27Q.js.gz +0 -0
  47. package/dist/{chunk-OOO4JL2N.mjs → chunk-WIEBQGQI.mjs} +44 -0
  48. package/dist/chunk-WIEBQGQI.mjs.br +0 -0
  49. package/dist/chunk-WIEBQGQI.mjs.gz +0 -0
  50. package/dist/i18n/de.cjs +70 -21
  51. package/dist/i18n/de.cjs.br +0 -0
  52. package/dist/i18n/de.cjs.gz +0 -0
  53. package/dist/i18n/de.mjs +70 -21
  54. package/dist/i18n/de.mjs.br +0 -0
  55. package/dist/i18n/de.mjs.gz +0 -0
  56. package/dist/i18n/es.cjs +70 -21
  57. package/dist/i18n/es.cjs.br +0 -0
  58. package/dist/i18n/es.cjs.gz +0 -0
  59. package/dist/i18n/es.mjs +70 -21
  60. package/dist/i18n/es.mjs.br +0 -0
  61. package/dist/i18n/es.mjs.gz +0 -0
  62. package/dist/i18n/fr.cjs +70 -21
  63. package/dist/i18n/fr.cjs.br +0 -0
  64. package/dist/i18n/fr.cjs.gz +0 -0
  65. package/dist/i18n/fr.mjs +70 -21
  66. package/dist/i18n/fr.mjs.br +0 -0
  67. package/dist/i18n/fr.mjs.gz +0 -0
  68. package/dist/i18n/zh-CN.cjs +48 -4
  69. package/dist/i18n/zh-CN.cjs.br +0 -0
  70. package/dist/i18n/zh-CN.cjs.gz +0 -0
  71. package/dist/i18n/zh-CN.mjs +48 -4
  72. package/dist/i18n/zh-CN.mjs.br +0 -0
  73. package/dist/i18n/zh-CN.mjs.gz +0 -0
  74. package/dist/i18n.js +4 -4
  75. package/dist/i18n.js.br +0 -0
  76. package/dist/i18n.js.gz +0 -0
  77. package/dist/i18n.mjs +1 -1
  78. package/dist/i18n.mjs.br +0 -0
  79. package/dist/i18n.mjs.gz +0 -0
  80. package/dist/index.d.ts +177 -15
  81. package/dist/index.js +63 -63
  82. package/dist/index.js.br +0 -0
  83. package/dist/index.js.gz +0 -0
  84. package/dist/index.mjs +6 -6
  85. package/dist/index.mjs.br +0 -0
  86. package/dist/index.mjs.gz +0 -0
  87. package/dist/internals.d.ts +230 -15
  88. package/dist/internals.js +105 -105
  89. package/dist/internals.js.br +0 -0
  90. package/dist/internals.js.gz +0 -0
  91. package/dist/internals.mjs +4 -4
  92. package/dist/internals.mjs.br +0 -0
  93. package/dist/internals.mjs.gz +0 -0
  94. package/dist/pptx-viewer.css +1 -1
  95. package/dist/pptx-viewer.css.br +0 -0
  96. package/dist/pptx-viewer.css.gz +0 -0
  97. package/dist/viewer/index.d.ts +149 -13
  98. package/dist/viewer/index.js +27 -27
  99. package/dist/viewer/index.js.br +0 -0
  100. package/dist/viewer/index.js.gz +0 -0
  101. package/dist/viewer/index.mjs +6 -6
  102. package/dist/viewer/index.mjs.br +3 -3
  103. package/dist/viewer/index.mjs.gz +0 -0
  104. package/package.json +1 -1
  105. package/dist/AiChatPanel-3C7GM6ZF.js.br +0 -0
  106. package/dist/AiChatPanel-3C7GM6ZF.js.gz +0 -0
  107. package/dist/AiChatPanel-L7DBCWE3.mjs.br +0 -0
  108. package/dist/AiChatPanel-L7DBCWE3.mjs.gz +0 -0
  109. package/dist/Model3DScene-IJ7YYTYU.mjs.br +0 -0
  110. package/dist/Model3DScene-IJ7YYTYU.mjs.gz +0 -0
  111. package/dist/Model3DScene-USKNPWWH.js.gz +0 -0
  112. package/dist/chunk-3JUZOKFI.js.br +0 -0
  113. package/dist/chunk-3JUZOKFI.js.gz +0 -0
  114. package/dist/chunk-5V5SMT5A.js.br +0 -0
  115. package/dist/chunk-5V5SMT5A.js.gz +0 -0
  116. package/dist/chunk-DFSWCVRW.js.br +0 -0
  117. package/dist/chunk-DFSWCVRW.js.gz +0 -0
  118. package/dist/chunk-FZSYLXJT.js.br +0 -0
  119. package/dist/chunk-FZSYLXJT.js.gz +0 -0
  120. package/dist/chunk-IBHIXBC5.js.br +0 -0
  121. package/dist/chunk-IBHIXBC5.js.gz +0 -0
  122. package/dist/chunk-ICEZL4TM.mjs.br +0 -0
  123. package/dist/chunk-ICEZL4TM.mjs.gz +0 -0
  124. package/dist/chunk-INX3E37P.mjs.br +0 -0
  125. package/dist/chunk-INX3E37P.mjs.gz +0 -0
  126. package/dist/chunk-K6QHGABT.mjs.br +0 -0
  127. package/dist/chunk-K6QHGABT.mjs.gz +0 -0
  128. package/dist/chunk-OOO4JL2N.mjs.br +0 -0
  129. package/dist/chunk-OOO4JL2N.mjs.gz +0 -0
  130. package/dist/chunk-VCAQSSGD.mjs.br +0 -0
  131. package/dist/chunk-VCAQSSGD.mjs.gz +0 -0
  132. package/dist/chunk-Y4QUVWZC.js.br +0 -0
  133. package/dist/chunk-Y4QUVWZC.js.gz +0 -0
  134. package/dist/chunk-ZAQFTO4P.mjs.br +0 -0
  135. package/dist/chunk-ZAQFTO4P.mjs.gz +0 -0
@@ -1,12 +1,12 @@
1
- import { computeFocusTargets, deckDataFieldChanged, aiChangeAnimationCss, changeGhostStyle, createChatHistoryStore, collectStoredChats, exportAiChatLogs, applyElementUpdate } from './chunk-VCAQSSGD.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-INX3E37P.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-K6QHGABT.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, 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, 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, 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, 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, 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-ICEZL4TM.mjs';
5
- import { LOCALE_CATALOG, ALIGNMENT_LABEL_KEYS } from './chunk-OOO4JL2N.mjs';
6
- import React4, { createContext, lazy, forwardRef, useEffect, useState, useCallback, useMemo, useRef, useLayoutEffect, useSyncExternalStore, useId, useContext, Fragment as Fragment$1, useDeferredValue, Suspense } 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
  },
@@ -1694,7 +1909,7 @@ function AccountPage() {
1694
1909
  return void 0;
1695
1910
  });
1696
1911
  };
1697
- const version = "4.5.0" ;
1912
+ const version = "4.6.0" ;
1698
1913
  return /* @__PURE__ */ jsxs("div", { className: "mt-8 max-w-[700px] space-y-6", children: [
1699
1914
  /* @__PURE__ */ jsxs("section", { className: cardClass, children: [
1700
1915
  /* @__PURE__ */ jsxs("h2", { className: "flex items-center gap-2 text-sm font-semibold", children: [
@@ -2096,42 +2311,6 @@ function FileSection(p) {
2096
2311
  }
2097
2312
  );
2098
2313
  }
2099
- function RibbonMenu({
2100
- anchorRef,
2101
- className,
2102
- children
2103
- }) {
2104
- const [pos, setPos] = useState(null);
2105
- useEffect(() => {
2106
- const anchor = anchorRef.current;
2107
- if (!anchor) {
2108
- return;
2109
- }
2110
- const update = () => {
2111
- const { left, top } = computeAnchoredPopupPosition(anchor.getBoundingClientRect());
2112
- setPos(
2113
- (prev) => prev && prev.left === left && prev.top === top ? prev : { left: left ?? 0, top }
2114
- );
2115
- };
2116
- update();
2117
- anchor.addEventListener("mouseenter", update);
2118
- window.addEventListener("resize", update);
2119
- document.addEventListener("scroll", update, true);
2120
- return () => {
2121
- anchor.removeEventListener("mouseenter", update);
2122
- window.removeEventListener("resize", update);
2123
- document.removeEventListener("scroll", update, true);
2124
- };
2125
- }, [anchorRef]);
2126
- return /* @__PURE__ */ jsx(
2127
- "div",
2128
- {
2129
- className: cn("fixed z-50", className),
2130
- style: pos ? { left: pos.left, top: pos.top } : { visibility: "hidden" },
2131
- children
2132
- }
2133
- );
2134
- }
2135
2314
  function FontFamilyMenu(p) {
2136
2315
  const { t } = useTranslation();
2137
2316
  const groups = buildFontCatalog({
@@ -2139,7 +2318,7 @@ function FontFamilyMenu(p) {
2139
2318
  embeddedFonts: p.embeddedFonts,
2140
2319
  customFonts: p.customFonts
2141
2320
  });
2142
- 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: [
2143
2322
  /* @__PURE__ */ jsx(
2144
2323
  "div",
2145
2324
  {
@@ -2664,6 +2843,43 @@ function HomeSection(p) {
2664
2843
  sep
2665
2844
  ] });
2666
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
+ }
2667
2883
  function InsertHyperlinkButton(p) {
2668
2884
  const { t } = useTranslation();
2669
2885
  return /* @__PURE__ */ jsxs(
@@ -2789,6 +3005,14 @@ function InsertSection(p) {
2789
3005
  }
2790
3006
  )
2791
3007
  ] }),
3008
+ p.onArmFreeformTool && /* @__PURE__ */ jsx(
3009
+ FreeformToolButtons,
3010
+ {
3011
+ canEdit,
3012
+ activeTool: p.activeFreeformTool,
3013
+ onArm: p.onArmFreeformTool
3014
+ }
3015
+ ),
2792
3016
  /* @__PURE__ */ jsxs(
2793
3017
  "button",
2794
3018
  {
@@ -4890,7 +5114,8 @@ function MobileSectionBody({
4890
5114
  onDelete: p.onDelete,
4891
5115
  formatPainterActive: p.formatPainterActive,
4892
5116
  onToggleFormatPainter: p.onToggleFormatPainter,
4893
- canActivateFormatPainter: p.canActivateFormatPainter
5117
+ canActivateFormatPainter: p.canActivateFormatPainter,
5118
+ hiddenActions: p.hiddenActions
4894
5119
  }
4895
5120
  ) });
4896
5121
  case "design":
@@ -6222,6 +6447,8 @@ function Toolbar(p) {
6222
6447
  canEdit: p.canEdit,
6223
6448
  newShapeType: p.newShapeType,
6224
6449
  onSetNewShapeType: p.onSetNewShapeType,
6450
+ activeFreeformTool: p.activeFreeformTool,
6451
+ onArmFreeformTool: p.onArmFreeformTool,
6225
6452
  onAddTextBox: p.onAddTextBox,
6226
6453
  onAddShape: p.onAddShape,
6227
6454
  onAddTable: p.onAddTable,
@@ -6299,7 +6526,8 @@ function Toolbar(p) {
6299
6526
  onDelete: p.onDelete,
6300
6527
  formatPainterActive: p.formatPainterActive,
6301
6528
  onToggleFormatPainter: p.onToggleFormatPainter,
6302
- canActivateFormatPainter: p.canActivateFormatPainter
6529
+ canActivateFormatPainter: p.canActivateFormatPainter,
6530
+ hiddenActions: p.hiddenActions
6303
6531
  }
6304
6532
  ),
6305
6533
  sDes && /* @__PURE__ */ jsx(
@@ -6651,7 +6879,7 @@ var EXPLOSION_SUPPORTED_TYPES = /* @__PURE__ */ new Set([
6651
6879
  "doughnut",
6652
6880
  "ofPie"
6653
6881
  ]);
6654
- var ICONS3 = {
6882
+ var ICONS4 = {
6655
6883
  elements: LuPlus,
6656
6884
  styles: LuPaintbrush,
6657
6885
  filters: LuFilter
@@ -6694,7 +6922,7 @@ function ChartQuickActionsOverlay({
6694
6922
  "data-export-ignore": "true",
6695
6923
  style: { position: "absolute", left: 0, top: 0, zIndex: 59 },
6696
6924
  onMouseDown: (e) => e.stopPropagation(),
6697
- children: descriptor.buttons.map((button) => /* @__PURE__ */ jsxs(React4.Fragment, { children: [
6925
+ children: descriptor.buttons.map((button) => /* @__PURE__ */ jsxs(React5.Fragment, { children: [
6698
6926
  /* @__PURE__ */ jsx(
6699
6927
  "button",
6700
6928
  {
@@ -6714,7 +6942,7 @@ function ChartQuickActionsOverlay({
6714
6942
  transformOrigin: "top left"
6715
6943
  },
6716
6944
  className: "flex items-center justify-center rounded bg-white border border-gray-300 shadow-sm hover:bg-gray-100 text-gray-700",
6717
- children: React4.createElement(ICONS3[button.id], { className: "size-3.5" })
6945
+ children: React5.createElement(ICONS4[button.id], { className: "size-3.5" })
6718
6946
  }
6719
6947
  ),
6720
6948
  open === button.id && button.id === "elements" && /* @__PURE__ */ jsxs(
@@ -7265,6 +7493,542 @@ function MotionPathOverlay({
7265
7493
  }
7266
7494
  );
7267
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
+ }
7268
8032
  function HorizontalRulerView({ ticks, widthPx, highlight }) {
7269
8033
  return /* @__PURE__ */ jsxs(
7270
8034
  "svg",
@@ -7328,7 +8092,7 @@ function HorizontalRulerView({ ticks, widthPx, highlight }) {
7328
8092
  }
7329
8093
  );
7330
8094
  }
7331
- var HorizontalRuler = React4.memo(HorizontalRulerView);
8095
+ var HorizontalRuler = React5.memo(HorizontalRulerView);
7332
8096
  HorizontalRuler.displayName = "HorizontalRuler";
7333
8097
  function VerticalRulerView({ ticks, heightPx, highlight }) {
7334
8098
  return /* @__PURE__ */ jsxs(
@@ -7400,7 +8164,7 @@ function VerticalRulerView({ ticks, heightPx, highlight }) {
7400
8164
  }
7401
8165
  );
7402
8166
  }
7403
- var VerticalRuler = React4.memo(VerticalRulerView);
8167
+ var VerticalRuler = React5.memo(VerticalRulerView);
7404
8168
  VerticalRuler.displayName = "VerticalRuler";
7405
8169
  function Ruler({
7406
8170
  canvasSize,
@@ -8371,9 +9135,12 @@ function SlideCanvasContent({
8371
9135
  fieldContext,
8372
9136
  tableStyleContext,
8373
9137
  collaborationOverlay,
8374
- aiActive = false
9138
+ aiActive = false,
9139
+ outlineAuthoring
8375
9140
  }) {
8376
9141
  const isEditableCanvas = (mode === "edit" || mode === "master") && canEdit;
9142
+ const crop = useShapeFormatContext()?.crop;
9143
+ const cropElement = isEditableCanvas ? crop?.element ?? null : null;
8377
9144
  useSlideCanvasImagePaste({
8378
9145
  imagePaste,
8379
9146
  zoom,
@@ -8651,7 +9418,7 @@ function SlideCanvasContent({
8651
9418
  },
8652
9419
  element.id
8653
9420
  )),
8654
- 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(
8655
9422
  SelectionHandleOverlay,
8656
9423
  {
8657
9424
  element: selectedElement,
@@ -8672,6 +9439,15 @@ function SlideCanvasContent({
8672
9439
  onUpdateElement: stableUpdateSmartArtElement
8673
9440
  }
8674
9441
  ),
9442
+ cropElement && crop && /* @__PURE__ */ jsx(
9443
+ PictureCropOverlay,
9444
+ {
9445
+ element: cropElement,
9446
+ scale: zoom.editorScale,
9447
+ onUpdate: crop.liveUpdate,
9448
+ onContextMenu
9449
+ }
9450
+ ),
8675
9451
  /* @__PURE__ */ jsx(MarqueeOverlay, { marqueeSelectionState }),
8676
9452
  activeSlide?.activeXControls && activeSlide.activeXControls.length > 0 && /* @__PURE__ */ jsx(ActiveXControlOverlay, { controls: activeSlide.activeXControls, canvasSize }),
8677
9453
  showCommentMarkers && comments && comments.length > 0 && /* @__PURE__ */ jsx(
@@ -8732,6 +9508,15 @@ function SlideCanvasContent({
8732
9508
  onPointerUp: handleDrawPointerUp
8733
9509
  }
8734
9510
  ),
9511
+ isEditableCanvas && outlineAuthoring && /* @__PURE__ */ jsx(
9512
+ OutlineAuthoringLayer,
9513
+ {
9514
+ ...outlineAuthoring,
9515
+ activeSlide,
9516
+ canvasSize,
9517
+ scale: zoom.editorScale
9518
+ }
9519
+ ),
8735
9520
  collaborationOverlay
8736
9521
  ]
8737
9522
  }
@@ -9300,7 +10085,7 @@ function slideThumbnailPropsEqual(prev, next) {
9300
10085
  }
9301
10086
  return true;
9302
10087
  }
9303
- var SlideThumbnail = React4.memo(SlideThumbnailImpl, slideThumbnailPropsEqual);
10088
+ var SlideThumbnail = React5.memo(SlideThumbnailImpl, slideThumbnailPropsEqual);
9304
10089
 
9305
10090
  // src/viewer/components/context-menu-dispatch.ts
9306
10091
  function tableCell(props) {
@@ -9315,19 +10100,32 @@ function tableCell(props) {
9315
10100
  isMergedCell: Boolean(cell && ((cell.gridSpan ?? 1) > 1 || (cell.rowSpan ?? 1) > 1))
9316
10101
  };
9317
10102
  }
9318
- function contextMenuContext(props) {
10103
+ function contextMenuContext(props, shapeFormat = null) {
9319
10104
  return {
9320
10105
  elementType: props.selectedElement?.type ?? null,
9321
10106
  table: tableCell(props),
9322
10107
  hasMultiSelection: Boolean(props.hasMultiSelection),
9323
10108
  selectionGroupable: props.selectionGroupable,
9324
10109
  hasClipboard: props.hasClipboard,
10110
+ editPoints: props.editPointsAvailability,
9325
10111
  // Both AI entries appear together or not at all, so a viewer that wired
9326
10112
  // only one of them does not produce a menu the other bindings cannot match.
9327
- 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)
9328
10116
  };
9329
10117
  }
9330
- 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) {
9331
10129
  const { onAction, onClose } = props;
9332
10130
  const andClose = (run) => run && (() => {
9333
10131
  run();
@@ -9359,42 +10157,15 @@ function contextMenuHandlers(props) {
9359
10157
  group: andClose(() => onAction("group")),
9360
10158
  ungroup: andClose(() => onAction("ungroup")),
9361
10159
  "edit-text": andClose(() => onAction("edit-text")),
10160
+ "edit-points": andClose(() => onAction("edit-points")),
9362
10161
  "save-as-picture": andClose(() => onAction("save-as-picture")),
9363
10162
  "edit-alt-text": andClose(() => onAction("edit-alt-text")),
9364
10163
  "size-and-position": andClose(() => onAction("size-and-position")),
9365
10164
  "format-shape": andClose(() => onAction("format-shape")),
9366
- delete: andClose(() => onAction("delete"))
10165
+ delete: andClose(() => onAction("delete")),
10166
+ ...shapeFormatHandlers(shapeFormat, andClose)
9367
10167
  };
9368
10168
  }
9369
- var ITEM_CLASS = "w-full px-3 py-1.5 text-left hover:bg-muted";
9370
- var DANGER_ITEM_CLASS = "w-full px-3 py-1.5 text-left text-red-300 hover:bg-red-900/40";
9371
- var DISABLED_CLASS = " opacity-40 pointer-events-none";
9372
- function ContextMenuItem({
9373
- onSelect,
9374
- danger,
9375
- disabled,
9376
- checked,
9377
- children
9378
- }) {
9379
- return /* @__PURE__ */ jsxs(
9380
- "button",
9381
- {
9382
- type: "button",
9383
- role: checked === void 0 ? "menuitem" : "menuitemcheckbox",
9384
- "aria-checked": checked === void 0 ? void 0 : checked,
9385
- disabled,
9386
- className: `${danger ? DANGER_ITEM_CLASS : ITEM_CLASS}${disabled ? DISABLED_CLASS : ""}`,
9387
- onClick: onSelect,
9388
- children: [
9389
- checked !== void 0 && /* @__PURE__ */ jsx("span", { className: "mr-1.5 inline-block w-3", "aria-hidden": "true", children: checked ? "\u2713" : "" }),
9390
- children
9391
- ]
9392
- }
9393
- );
9394
- }
9395
- function ContextMenuSeparator() {
9396
- return /* @__PURE__ */ jsx("div", { role: "separator", "aria-orientation": "horizontal", className: "my-1 border-t border-border" });
9397
- }
9398
10169
  function useClampedMenuPosition(x, y) {
9399
10170
  const [size, setSize] = useState({ width: 0, height: 0 });
9400
10171
  const ref = useCallback((node) => {
@@ -9420,6 +10191,7 @@ function ContextMenu(props) {
9420
10191
  const { contextMenuState, mode, onClose } = props;
9421
10192
  const { t } = useTranslation();
9422
10193
  const customization = useViewerCustomizationContext();
10194
+ const shapeFormat = useShapeFormatContext();
9423
10195
  const open = Boolean(contextMenuState) && mode === "edit";
9424
10196
  const menuPosition = useClampedMenuPosition(
9425
10197
  contextMenuState?.x ?? 0,
@@ -9441,9 +10213,9 @@ function ContextMenu(props) {
9441
10213
  if (!open) {
9442
10214
  return null;
9443
10215
  }
9444
- const handlers = contextMenuHandlers(props);
10216
+ const handlers = contextMenuHandlers(props, shapeFormat);
9445
10217
  const entries = customizeContextMenuEntries(
9446
- buildContextMenuEntries(contextMenuContext(props)),
10218
+ buildContextMenuEntries(contextMenuContext(props, shapeFormat)),
9447
10219
  customization
9448
10220
  );
9449
10221
  if (entries.length === 0) {
@@ -10061,7 +10833,7 @@ function LazyThumbnailInner({
10061
10833
  }
10062
10834
  ) });
10063
10835
  }
10064
- var LazyThumbnail = React4.memo(LazyThumbnailInner);
10836
+ var LazyThumbnail = React5.memo(LazyThumbnailInner);
10065
10837
 
10066
10838
  // src/viewer/components/slides-pane/utils.ts
10067
10839
  function formatTimingMs(ms) {
@@ -10217,7 +10989,7 @@ function SlideItemInner({
10217
10989
  }
10218
10990
  );
10219
10991
  }
10220
- var SlideItem = React4.memo(SlideItemInner);
10992
+ var SlideItem = React5.memo(SlideItemInner);
10221
10993
  function useSlidePaneCallbacks(onMoveSlide, onRenameSection, onToggleSectionCollapse) {
10222
10994
  const [collapsedSections, setCollapsedSections] = useState({});
10223
10995
  const [renamingSectionId, setRenamingSectionId] = useState(null);
@@ -11614,7 +12386,7 @@ function arePropsEqual(prev, next) {
11614
12386
  }
11615
12387
  return true;
11616
12388
  }
11617
- var SlideCard = React4.memo(SlideCardImpl, arePropsEqual);
12389
+ var SlideCard = React5.memo(SlideCardImpl, arePropsEqual);
11618
12390
  function SorterContextMenu({
11619
12391
  x,
11620
12392
  y,
@@ -13173,15 +13945,15 @@ function SlideNotesPanel({
13173
13945
  onHeightChange
13174
13946
  }) {
13175
13947
  const { t } = useTranslation();
13176
- const rootRef = React4.useRef(null);
13177
- React4.useEffect(() => {
13948
+ const rootRef = React5.useRef(null);
13949
+ React5.useEffect(() => {
13178
13950
  const el = rootRef.current;
13179
13951
  if (!el || !onHeightChange) {
13180
13952
  return void 0;
13181
13953
  }
13182
- const stop = observeElementHeight(el, onHeightChange);
13954
+ const stop2 = observeElementHeight(el, onHeightChange);
13183
13955
  return () => {
13184
- stop();
13956
+ stop2();
13185
13957
  onHeightChange(0);
13186
13958
  };
13187
13959
  }, [onHeightChange]);
@@ -15072,9 +15844,9 @@ function PresentationSubtitleBar({
15072
15844
  function renderNotesSegments(segments) {
15073
15845
  return notesSegmentsToSpans(segments).map((span) => {
15074
15846
  if (span.kind === "break") {
15075
- return React4.createElement("br", { key: span.key });
15847
+ return React5.createElement("br", { key: span.key });
15076
15848
  }
15077
- return React4.createElement(
15849
+ return React5.createElement(
15078
15850
  "span",
15079
15851
  { key: span.key, style: span.style },
15080
15852
  span.text
@@ -15306,7 +16078,7 @@ function scaledSlidePreviewPropsEqual(prev, next) {
15306
16078
  }
15307
16079
  return true;
15308
16080
  }
15309
- var ScaledSlidePreview = React4.memo(ScaledSlidePreviewImpl, scaledSlidePreviewPropsEqual);
16081
+ var ScaledSlidePreview = React5.memo(ScaledSlidePreviewImpl, scaledSlidePreviewPropsEqual);
15310
16082
  function PresenterNotesRail({
15311
16083
  slides,
15312
16084
  current,
@@ -16482,6 +17254,37 @@ function AnimationTimelineSection({
16482
17254
  ] })
16483
17255
  ] });
16484
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
+ }
16485
17288
  var NONE_VALUE = "none";
16486
17289
  var CURRENT_VALUE = "current";
16487
17290
  var OTHER_VALUE = "other";
@@ -16492,7 +17295,7 @@ function EffectSoundRow({
16492
17295
  onPickStock
16493
17296
  }) {
16494
17297
  const { t } = useTranslation();
16495
- const fileInputRef = React4.useRef(null);
17298
+ const fileInputRef = React5.useRef(null);
16496
17299
  const selectedValue = soundState.catalogueId ?? (soundState.hasSound ? CURRENT_VALUE : NONE_VALUE);
16497
17300
  const handleSelectChange = (event) => {
16498
17301
  const value = event.target.value;
@@ -16875,12 +17678,13 @@ function useAnimationHandlers({
16875
17678
  const handleTriggerChange = useCallback(
16876
17679
  (event) => {
16877
17680
  const newTrigger = event.target.value;
16878
- updateAnimationField("trigger", newTrigger);
16879
- if (newTrigger !== "onShapeClick") {
16880
- updateAnimationField("triggerShapeId", void 0);
16881
- }
17681
+ updateAnimations((anims) => setTrigger(anims, selectedElement.id, newTrigger));
16882
17682
  },
16883
- [updateAnimationField]
17683
+ [updateAnimations, selectedElement.id]
17684
+ );
17685
+ const handleTriggerBookmarkChange = useCallback(
17686
+ (optionValue) => updateAnimations((anims) => setTriggerBookmark(anims, selectedElement.id, optionValue)),
17687
+ [updateAnimations, selectedElement.id]
16884
17688
  );
16885
17689
  const handleTriggerShapeChange = useCallback(
16886
17690
  (e) => updateAnimationField("triggerShapeId", e.target.value || void 0),
@@ -17011,6 +17815,7 @@ function useAnimationHandlers({
17011
17815
  handleEmphasisChange,
17012
17816
  handleTriggerChange,
17013
17817
  handleTriggerShapeChange,
17818
+ handleTriggerBookmarkChange,
17014
17819
  handleTimingCurveChange,
17015
17820
  handleDurationChange,
17016
17821
  handleDelayChange,
@@ -17055,6 +17860,7 @@ function AnimationPanel({
17055
17860
  handleEmphasisChange,
17056
17861
  handleTriggerChange,
17057
17862
  handleTriggerShapeChange,
17863
+ handleTriggerBookmarkChange,
17058
17864
  handleTimingCurveChange,
17059
17865
  handleDurationChange,
17060
17866
  handleDelayChange,
@@ -17244,6 +18050,16 @@ function AnimationPanel({
17244
18050
  }
17245
18051
  )
17246
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
+ ),
17247
18063
  /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
17248
18064
  /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-[11px]", children: t("pptx.animation.duration") }),
17249
18065
  /* @__PURE__ */ jsx(
@@ -20060,7 +20876,7 @@ function ConnectorArrowsSection({
20060
20876
  ["Start", "End"].map((end) => {
20061
20877
  const widthKey = end === "Start" ? "connectorStartArrowWidth" : "connectorEndArrowWidth";
20062
20878
  const lengthKey = end === "Start" ? "connectorStartArrowLength" : "connectorEndArrowLength";
20063
- return /* @__PURE__ */ jsxs(React4.Fragment, { children: [
20879
+ return /* @__PURE__ */ jsxs(React5.Fragment, { children: [
20064
20880
  /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
20065
20881
  /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: t(END_LABEL_KEYS[end].width) }),
20066
20882
  /* @__PURE__ */ jsx(
@@ -20273,7 +21089,7 @@ function LayerOrderButtons({
20273
21089
  ] });
20274
21090
  }
20275
21091
  function ArtisticEffectsGallery({
20276
- imgSrc,
21092
+ imgSrc: imgSrc2,
20277
21093
  fx,
20278
21094
  canEdit,
20279
21095
  updateEffects
@@ -20303,7 +21119,7 @@ function ArtisticEffectsGallery({
20303
21119
  {
20304
21120
  className: "w-10 h-7 rounded overflow-hidden bg-muted",
20305
21121
  style: {
20306
- backgroundImage: imgSrc ? `url(${imgSrc})` : void 0,
21122
+ backgroundImage: imgSrc2 ? `url(${imgSrc2})` : void 0,
20307
21123
  backgroundSize: "cover",
20308
21124
  backgroundPosition: "center",
20309
21125
  filter: cssFilter || void 0
@@ -22543,7 +23359,7 @@ function ColorPickerRow({
22543
23359
  ] });
22544
23360
  }
22545
23361
  function GradientStopRow({
22546
- stop,
23362
+ stop: stop2,
22547
23363
  index,
22548
23364
  total,
22549
23365
  onUpdate,
@@ -22561,7 +23377,7 @@ function GradientStopRow({
22561
23377
  "input",
22562
23378
  {
22563
23379
  type: "color",
22564
- value: normalizeHexColor(stop.color, "#3b82f6"),
23380
+ value: normalizeHexColor(stop2.color, "#3b82f6"),
22565
23381
  onChange: (e) => {
22566
23382
  const hex = normalizeHexColor(e.target.value, "#3b82f6");
22567
23383
  patchStop({ color: hex, colorRef: void 0 });
@@ -22576,7 +23392,7 @@ function GradientStopRow({
22576
23392
  type: "range",
22577
23393
  min: 0,
22578
23394
  max: 100,
22579
- value: Math.round(stop.position),
23395
+ value: Math.round(stop2.position),
22580
23396
  onChange: (e) => patchStop({ position: Number(e.target.value) }),
22581
23397
  className: RNG
22582
23398
  }
@@ -22596,8 +23412,8 @@ function GradientStopRow({
22596
23412
  ThemeColorSwatchGrid,
22597
23413
  {
22598
23414
  prefix: `gradient-stop-${index}`,
22599
- selectedRef: stop.colorRef,
22600
- selectedHex: stop.color,
23415
+ selectedRef: stop2.colorRef,
23416
+ selectedHex: stop2.color,
22601
23417
  onPick: (c) => {
22602
23418
  patchStop({ color: c.hex, colorRef: c.ref });
22603
23419
  pushColor(c.hex);
@@ -22612,13 +23428,13 @@ function GradientStopRow({
22612
23428
  type: "range",
22613
23429
  min: 0,
22614
23430
  max: 100,
22615
- value: Math.round((stop.opacity ?? 1) * 100),
23431
+ value: Math.round((stop2.opacity ?? 1) * 100),
22616
23432
  onChange: (e) => patchStop({ opacity: Number(e.target.value) / 100 }),
22617
23433
  className: RNG
22618
23434
  }
22619
23435
  ),
22620
23436
  /* @__PURE__ */ jsxs("span", { className: "text-[10px] text-muted-foreground w-[52px] text-right", children: [
22621
- Math.round((stop.opacity ?? 1) * 100),
23437
+ Math.round((stop2.opacity ?? 1) * 100),
22622
23438
  "%"
22623
23439
  ] })
22624
23440
  ] })
@@ -22669,10 +23485,10 @@ function FillAdvancedControls({
22669
23485
  ] }),
22670
23486
  /* @__PURE__ */ jsxs("div", { className: `${COL2} space-y-1.5 rounded border border-border p-2`, children: [
22671
23487
  /* @__PURE__ */ jsx("div", { className: "text-[11px] uppercase tracking-wide text-muted-foreground", children: t("pptx.fillAdvanced.gradientStops") }),
22672
- gradientStops.map((stop, i) => /* @__PURE__ */ jsx(
23488
+ gradientStops.map((stop2, i) => /* @__PURE__ */ jsx(
22673
23489
  GradientStopRow,
22674
23490
  {
22675
- stop,
23491
+ stop: stop2,
22676
23492
  index: i,
22677
23493
  total: gradientStops.length,
22678
23494
  allStops: gradientStops,
@@ -22937,7 +23753,7 @@ function StrokeEffectsSection({
22937
23753
  ] }),
22938
23754
  EFFECT_CONFIGS.map((cfg) => {
22939
23755
  const on = cfg.isOn(style);
22940
- return /* @__PURE__ */ jsxs(React4.Fragment, { children: [
23756
+ return /* @__PURE__ */ jsxs(React5.Fragment, { children: [
22941
23757
  /* @__PURE__ */ jsxs("label", { className: `inline-flex items-center gap-2 text-foreground ${COL2}`, children: [
22942
23758
  /* @__PURE__ */ jsx(
22943
23759
  WebCheckbox,
@@ -23805,7 +24621,7 @@ function TextWarpGallery({
23805
24621
  onUpdateTextStyle
23806
24622
  }) {
23807
24623
  const { t } = useTranslation();
23808
- const [expanded, setExpanded] = React4.useState(false);
24624
+ const [expanded, setExpanded] = React5.useState(false);
23809
24625
  const currentPreset = ts?.textWarpPreset || "textNoShape";
23810
24626
  return /* @__PURE__ */ jsxs("div", { className: "mt-2 rounded border border-border bg-card p-2 space-y-2", children: [
23811
24627
  /* @__PURE__ */ jsxs(
@@ -24456,7 +25272,7 @@ function SmartArtStyleControls({
24456
25272
  onChangeStyle
24457
25273
  }) {
24458
25274
  const { t } = useTranslation();
24459
- const translate = React4.useCallback((key) => t(key), [t]);
25275
+ const translate = React5.useCallback((key) => t(key), [t]);
24460
25276
  return /* @__PURE__ */ jsxs(Fragment, { children: [
24461
25277
  /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1 text-[11px]", children: [
24462
25278
  /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: t("pptx.smartart.colorScheme") }),
@@ -24511,9 +25327,9 @@ function SmartArtPropertiesPanel({
24511
25327
  const nodes = smartArtData.nodes ?? [];
24512
25328
  const layout = smartArtData.resolvedLayoutType;
24513
25329
  const topLevelCount = nodes.filter((n) => !n.parentId).length;
24514
- const inputRefs = React4.useRef(/* @__PURE__ */ new Map());
24515
- const pendingFocusId = React4.useRef(null);
24516
- React4.useEffect(() => {
25330
+ const inputRefs = React5.useRef(/* @__PURE__ */ new Map());
25331
+ const pendingFocusId = React5.useRef(null);
25332
+ React5.useEffect(() => {
24517
25333
  const id = pendingFocusId.current;
24518
25334
  if (id) {
24519
25335
  inputRefs.current.get(id)?.focus();
@@ -25077,14 +25893,14 @@ function GradientControls({
25077
25893
  ] })
25078
25894
  ] }),
25079
25895
  /* @__PURE__ */ jsx("span", { className: LBL, children: t("pptx.table.gradientStops") }),
25080
- 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: [
25081
25897
  /* @__PURE__ */ jsx(
25082
25898
  "input",
25083
25899
  {
25084
25900
  type: "color",
25085
25901
  disabled: !canEdit,
25086
25902
  className: "h-6 w-6 rounded border border-border cursor-pointer",
25087
- value: stop.color,
25903
+ value: stop2.color,
25088
25904
  onChange: (e) => {
25089
25905
  updateStop(idx, { color: e.target.value });
25090
25906
  pushColor(e.target.value);
@@ -25099,7 +25915,7 @@ function GradientControls({
25099
25915
  className: NUM,
25100
25916
  min: 0,
25101
25917
  max: 100,
25102
- value: Math.round(stop.position),
25918
+ value: Math.round(stop2.position),
25103
25919
  onChange: (e) => updateStop(idx, {
25104
25920
  position: Number(e.target.value)
25105
25921
  })
@@ -26127,7 +26943,7 @@ function CommentBody({ text, mentions, className }) {
26127
26943
  index
26128
26944
  ) : (
26129
26945
  // eslint-disable-next-line react/no-array-index-key -- segments are positional
26130
- /* @__PURE__ */ jsx(React4.Fragment, { children: segment.text }, index)
26946
+ /* @__PURE__ */ jsx(React5.Fragment, { children: segment.text }, index)
26131
26947
  )
26132
26948
  ) });
26133
26949
  }
@@ -27629,7 +28445,7 @@ function PresentationPropertiesPanel({
27629
28445
  onUpdateTagCollections
27630
28446
  }) {
27631
28447
  const { t } = useTranslation();
27632
- const handleTransitionChange = React4.useCallback(
28448
+ const handleTransitionChange = React5.useCallback(
27633
28449
  (updates) => {
27634
28450
  onUpdateSlide({
27635
28451
  transition: mergeSlideTransition(activeSlide?.transition, updates)
@@ -28670,7 +29486,7 @@ function PresentationTouchControls({
28670
29486
  return null;
28671
29487
  }
28672
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";
28673
- const stop = (e) => {
29489
+ const stop2 = (e) => {
28674
29490
  e.stopPropagation();
28675
29491
  };
28676
29492
  return /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -28685,7 +29501,7 @@ function PresentationTouchControls({
28685
29501
  touchAction: "manipulation"
28686
29502
  },
28687
29503
  onClick: (e) => {
28688
- stop(e);
29504
+ stop2(e);
28689
29505
  onEndPresentation();
28690
29506
  },
28691
29507
  "aria-label": t("pptx.presenter.endPresentation"),
@@ -28704,7 +29520,7 @@ function PresentationTouchControls({
28704
29520
  },
28705
29521
  disabled: currentSlideIndex <= 0,
28706
29522
  onClick: (e) => {
28707
- stop(e);
29523
+ stop2(e);
28708
29524
  onMovePresentationSlide(-1);
28709
29525
  },
28710
29526
  "aria-label": t("pptx.presenter.previousSlide"),
@@ -28722,7 +29538,7 @@ function PresentationTouchControls({
28722
29538
  },
28723
29539
  disabled: currentSlideIndex >= totalSlides - 1,
28724
29540
  onClick: (e) => {
28725
- stop(e);
29541
+ stop2(e);
28726
29542
  onMovePresentationSlide(1);
28727
29543
  },
28728
29544
  "aria-label": t("pptx.presenter.nextSlide"),
@@ -31547,7 +32363,7 @@ function ViewerToolbarSection(props) {
31547
32363
  },
31548
32364
  [activeSlide, propertyHandlers]
31549
32365
  );
31550
- const scopedLayoutOptions = React4.useMemo(
32366
+ const scopedLayoutOptions = React5.useMemo(
31551
32367
  () => scopeLayoutOptionsToActiveSlide(s.layoutOptions, activeSlide),
31552
32368
  [s.layoutOptions, activeSlide]
31553
32369
  );
@@ -31793,6 +32609,7 @@ function ViewerToolbarSection(props) {
31793
32609
  tableEditorState: s.tableEditorState,
31794
32610
  editTemplateMode: s.editTemplateMode,
31795
32611
  newShapeType: s.newShapeType,
32612
+ activeFreeformTool: s.activeFreeformTool,
31796
32613
  activeTool: s.activeTool,
31797
32614
  drawingColor: s.drawingColor,
31798
32615
  drawingWidth: s.drawingWidth,
@@ -31816,6 +32633,7 @@ function ViewerToolbarSection(props) {
31816
32633
  onRedo: history.handleRedo,
31817
32634
  onToggleFindReplace: () => findReplace.setFindReplaceOpen(!findReplace.findReplaceOpen),
31818
32635
  onSetNewShapeType: s.setNewShapeType,
32636
+ onArmFreeformTool: s.setActiveFreeformTool,
31819
32637
  onAddTextBox: insertHandlers.handleAddTextBox,
31820
32638
  onAddShape: insertHandlers.handleAddShape,
31821
32639
  onAddTable: insertHandlers.handleAddTable,
@@ -32668,6 +33486,45 @@ function ViewerPresentationLayer(props) {
32668
33486
  )
32669
33487
  ] });
32670
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
+ }
32671
33528
  function PresentationStage({
32672
33529
  activeSlide,
32673
33530
  templateElements,
@@ -32957,6 +33814,11 @@ function ViewerCanvasArea(props) {
32957
33814
  const { t } = useTranslation();
32958
33815
  const { isHidden } = useToolbarVisibility(hiddenActions);
32959
33816
  const viewerOptions = useViewerOptionsContext();
33817
+ const outlineAuthoring = useOutlineAuthoring({
33818
+ state: s,
33819
+ updateElement: canvasHandlers.handleUpdateSmartArtElement,
33820
+ insertShape: insertHandlers.handleAddFreeformShape
33821
+ });
32960
33822
  const effectiveSlide = mode === "master" ? masterPseudoSlide : activeSlide;
32961
33823
  const effectiveTemplateElements = mode === "master" ? [] : templateElements;
32962
33824
  const fieldContext = useMemo(
@@ -33269,6 +34131,7 @@ ${url}`)) {
33269
34131
  fieldContext,
33270
34132
  tableStyleContext,
33271
34133
  aiActive: aiCanvasActive,
34134
+ outlineAuthoring,
33272
34135
  collaborationOverlay: /* @__PURE__ */ jsxs(Fragment, { children: [
33273
34136
  /* @__PURE__ */ jsx(
33274
34137
  RemoteSelectionOverlay,
@@ -33420,7 +34283,7 @@ function useTableStyleMapHandlers(input) {
33420
34283
  var AiChatPanel = lazy(async () => {
33421
34284
  const [{ useChat }, { default: Panel }] = await Promise.all([
33422
34285
  import('@ai-sdk/react'),
33423
- import('./AiChatPanel-L7DBCWE3.mjs')
34286
+ import('./AiChatPanel-X2MVL5UP.mjs')
33424
34287
  ]);
33425
34288
  function BoundAiChatPanel(props) {
33426
34289
  return /* @__PURE__ */ jsx(Panel, { ...props, useChat });
@@ -34699,6 +35562,7 @@ function ViewerMainContent(props) {
34699
35562
  hasMultiSelection: state.effectiveSelectedIds.length > 1,
34700
35563
  selectionGroupable: manipulation.selectionGroupable,
34701
35564
  hasClipboard: Boolean(state.clipboardPayload),
35565
+ editPointsAvailability: resolveEditPointsAvailability(selectedElement),
34702
35566
  onAction: manipulation.handleContextMenuAction,
34703
35567
  onInsertTableRow: tableOps.handleInsertTableRow,
34704
35568
  onDeleteTableRow: tableOps.handleDeleteTableRow,
@@ -36838,6 +37702,166 @@ function useRunProgramNoticesState() {
36838
37702
  }, []);
36839
37703
  return { notices, addNotice, dismiss, dismissAll };
36840
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
+ }
36841
37865
  function useViewerCustomization(customization, legacyHiddenActions, optionsStore) {
36842
37866
  const controllerRef = useRef(null);
36843
37867
  controllerRef.current ??= createCustomizationController(customization);
@@ -37176,14 +38200,15 @@ var PowerPointViewer = forwardRef(
37176
38200
  const activeCustomShow = state.customShows.find((show) => show.id === state.activeCustomShowId) ?? null;
37177
38201
  const hasActivePointerInteraction = useCallback(
37178
38202
  () => Boolean(
37179
- 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
37180
38204
  ),
37181
38205
  [
37182
38206
  state.dragStateRef,
37183
38207
  state.resizeStateRef,
37184
38208
  state.marqueeStateRef,
37185
38209
  state.shapeAdjustmentDragStateRef,
37186
- state.isDrawingRef
38210
+ state.isDrawingRef,
38211
+ state.cropSessionRef
37187
38212
  ]
37188
38213
  );
37189
38214
  const zoom = useZoomViewport({
@@ -37353,6 +38378,7 @@ var PowerPointViewer = forwardRef(
37353
38378
  transformCommittedText: (text) => applyAutoCorrect(text, viewerOptions.proofing),
37354
38379
  keyboard: customizationResolved.keyboard
37355
38380
  });
38381
+ const shapeFormat = useShapeFormatCommands({ state, editorOps, history, canEdit, mode });
37356
38382
  const {
37357
38383
  exportHandlers: rawExportHandlers,
37358
38384
  printHandlers,
@@ -38002,7 +39028,7 @@ var PowerPointViewer = forwardRef(
38002
39028
  slideCount: slides.length
38003
39029
  }
38004
39030
  ),
38005
- viewerContent
39031
+ /* @__PURE__ */ jsx(ShapeFormatContext.Provider, { value: shapeFormat, children: viewerContent })
38006
39032
  ]
38007
39033
  }
38008
39034
  ) }) }) }) }) })