pptx-react-viewer 2.16.10 → 2.17.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 (127) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/dist/{AiChatPanel-EPMBL6EA.js → AiChatPanel-HCHCVQN2.js} +24 -24
  3. package/dist/AiChatPanel-HCHCVQN2.js.br +0 -0
  4. package/dist/AiChatPanel-HCHCVQN2.js.gz +0 -0
  5. package/dist/{AiChatPanel-XHKYPYPH.mjs → AiChatPanel-RZ4A7P4H.mjs} +4 -4
  6. package/dist/AiChatPanel-RZ4A7P4H.mjs.br +0 -0
  7. package/dist/AiChatPanel-RZ4A7P4H.mjs.gz +0 -0
  8. package/dist/{Model3DScene-YMIAGRPG.mjs → Model3DScene-I7FR74AD.mjs} +1 -1
  9. package/dist/Model3DScene-I7FR74AD.mjs.br +0 -0
  10. package/dist/Model3DScene-I7FR74AD.mjs.gz +0 -0
  11. package/dist/{Model3DScene-DUJOZA2B.js → Model3DScene-LK7LSQNH.js} +2 -2
  12. package/dist/Model3DScene-LK7LSQNH.js.br +0 -0
  13. package/dist/Model3DScene-LK7LSQNH.js.gz +0 -0
  14. package/dist/PowerPointViewer-Du7u4INi.d.ts.map +1 -1
  15. package/dist/{SurfaceChart3DScene-Q47OEJXS.mjs → SurfaceChart3DScene-DEQP5O3U.mjs} +1 -1
  16. package/dist/SurfaceChart3DScene-DEQP5O3U.mjs.br +0 -0
  17. package/dist/SurfaceChart3DScene-DEQP5O3U.mjs.gz +0 -0
  18. package/dist/{SurfaceChart3DScene-TNCHWQAK.js → SurfaceChart3DScene-ODQY77SZ.js} +2 -2
  19. package/dist/SurfaceChart3DScene-ODQY77SZ.js.br +0 -0
  20. package/dist/SurfaceChart3DScene-ODQY77SZ.js.gz +0 -0
  21. package/dist/{chunk-G3VAE7ZF.mjs → chunk-422DF424.mjs} +729 -2294
  22. package/dist/chunk-422DF424.mjs.br +0 -0
  23. package/dist/chunk-422DF424.mjs.gz +0 -0
  24. package/dist/{chunk-WK22Z7PK.js → chunk-5BXATG54.js} +520 -868
  25. package/dist/chunk-5BXATG54.js.br +0 -0
  26. package/dist/chunk-5BXATG54.js.gz +0 -0
  27. package/dist/{chunk-Y2KIB3QH.js → chunk-7JPLVECA.js} +44829 -39322
  28. package/dist/chunk-7JPLVECA.js.br +0 -0
  29. package/dist/chunk-7JPLVECA.js.gz +0 -0
  30. package/dist/{chunk-DVZF4ARG.js → chunk-AONFHTTJ.js} +22 -0
  31. package/dist/chunk-AONFHTTJ.js.br +0 -0
  32. package/dist/chunk-AONFHTTJ.js.gz +0 -0
  33. package/dist/{chunk-PI5SFTDC.js → chunk-ATOUVRRQ.js} +3 -3
  34. package/dist/chunk-ATOUVRRQ.js.br +0 -0
  35. package/dist/chunk-ATOUVRRQ.js.gz +0 -0
  36. package/dist/{chunk-EL2YF26P.mjs → chunk-FXJOTEPO.mjs} +1 -1
  37. package/dist/chunk-FXJOTEPO.mjs.br +0 -0
  38. package/dist/chunk-FXJOTEPO.mjs.gz +0 -0
  39. package/dist/{chunk-YWKUIUQX.mjs → chunk-K2QU73KB.mjs} +44784 -39286
  40. package/dist/chunk-K2QU73KB.mjs.br +0 -0
  41. package/dist/chunk-K2QU73KB.mjs.gz +0 -0
  42. package/dist/{chunk-VHME5BE6.mjs → chunk-MQHC5TXI.mjs} +318 -665
  43. package/dist/chunk-MQHC5TXI.mjs.br +0 -0
  44. package/dist/chunk-MQHC5TXI.mjs.gz +0 -0
  45. package/dist/{chunk-ESC6IB2F.js → chunk-NQJPPIVH.js} +1668 -3233
  46. package/dist/chunk-NQJPPIVH.js.br +0 -0
  47. package/dist/chunk-NQJPPIVH.js.gz +0 -0
  48. package/dist/{chunk-5IUEPQTK.mjs → chunk-S64T7C4V.mjs} +22 -0
  49. package/dist/chunk-S64T7C4V.mjs.br +0 -0
  50. package/dist/chunk-S64T7C4V.mjs.gz +0 -0
  51. package/dist/{chunk-FSVE6WUY.js → chunk-TCGXGD6E.js} +550 -463
  52. package/dist/chunk-TCGXGD6E.js.br +0 -0
  53. package/dist/chunk-TCGXGD6E.js.gz +0 -0
  54. package/dist/{chunk-J7EFC3GS.mjs → chunk-ZA5JONCW.mjs} +210 -123
  55. package/dist/chunk-ZA5JONCW.mjs.br +0 -0
  56. package/dist/chunk-ZA5JONCW.mjs.gz +0 -0
  57. package/dist/i18n.js +4 -4
  58. package/dist/i18n.js.br +0 -0
  59. package/dist/i18n.js.gz +0 -0
  60. package/dist/i18n.mjs +1 -1
  61. package/dist/i18n.mjs.br +0 -0
  62. package/dist/i18n.mjs.gz +0 -0
  63. package/dist/index.d.ts +205 -21
  64. package/dist/index.js +41 -41
  65. package/dist/index.js.br +0 -0
  66. package/dist/index.js.gz +0 -0
  67. package/dist/index.mjs +6 -6
  68. package/dist/index.mjs.br +0 -0
  69. package/dist/index.mjs.gz +0 -0
  70. package/dist/internals.d.ts +380 -22
  71. package/dist/internals.d.ts.map +1 -1
  72. package/dist/internals.js +79 -79
  73. package/dist/internals.js.br +0 -0
  74. package/dist/internals.js.gz +0 -0
  75. package/dist/internals.mjs +4 -4
  76. package/dist/internals.mjs.br +0 -0
  77. package/dist/internals.mjs.gz +0 -0
  78. package/dist/pptx-viewer.css +1 -1
  79. package/dist/pptx-viewer.css.br +0 -0
  80. package/dist/pptx-viewer.css.gz +0 -0
  81. package/dist/{useViewerBuildingBlocks-Xddn6SFj.d.ts → useViewerBuildingBlocks-C9-prKYB.d.ts} +32 -6
  82. package/dist/useViewerBuildingBlocks-C9-prKYB.d.ts.map +1 -0
  83. package/dist/viewer/index.d.ts +166 -17
  84. package/dist/viewer/index.js +27 -27
  85. package/dist/viewer/index.js.br +0 -0
  86. package/dist/viewer/index.js.gz +0 -0
  87. package/dist/viewer/index.mjs +6 -6
  88. package/dist/viewer/index.mjs.br +0 -0
  89. package/dist/viewer/index.mjs.gz +0 -0
  90. package/package.json +1 -1
  91. package/dist/AiChatPanel-EPMBL6EA.js.br +0 -0
  92. package/dist/AiChatPanel-EPMBL6EA.js.gz +0 -0
  93. package/dist/AiChatPanel-XHKYPYPH.mjs.br +0 -0
  94. package/dist/AiChatPanel-XHKYPYPH.mjs.gz +0 -0
  95. package/dist/Model3DScene-DUJOZA2B.js.br +0 -0
  96. package/dist/Model3DScene-DUJOZA2B.js.gz +0 -0
  97. package/dist/Model3DScene-YMIAGRPG.mjs.br +0 -0
  98. package/dist/Model3DScene-YMIAGRPG.mjs.gz +0 -0
  99. package/dist/SurfaceChart3DScene-Q47OEJXS.mjs.br +0 -0
  100. package/dist/SurfaceChart3DScene-Q47OEJXS.mjs.gz +0 -0
  101. package/dist/SurfaceChart3DScene-TNCHWQAK.js.br +0 -0
  102. package/dist/SurfaceChart3DScene-TNCHWQAK.js.gz +0 -0
  103. package/dist/chunk-5IUEPQTK.mjs.br +0 -0
  104. package/dist/chunk-5IUEPQTK.mjs.gz +0 -0
  105. package/dist/chunk-DVZF4ARG.js.br +0 -0
  106. package/dist/chunk-DVZF4ARG.js.gz +0 -0
  107. package/dist/chunk-EL2YF26P.mjs.br +0 -0
  108. package/dist/chunk-EL2YF26P.mjs.gz +0 -0
  109. package/dist/chunk-ESC6IB2F.js.br +0 -0
  110. package/dist/chunk-ESC6IB2F.js.gz +0 -0
  111. package/dist/chunk-FSVE6WUY.js.br +0 -0
  112. package/dist/chunk-FSVE6WUY.js.gz +0 -0
  113. package/dist/chunk-G3VAE7ZF.mjs.br +0 -0
  114. package/dist/chunk-G3VAE7ZF.mjs.gz +0 -0
  115. package/dist/chunk-J7EFC3GS.mjs.br +0 -0
  116. package/dist/chunk-J7EFC3GS.mjs.gz +0 -0
  117. package/dist/chunk-PI5SFTDC.js.br +0 -0
  118. package/dist/chunk-PI5SFTDC.js.gz +0 -0
  119. package/dist/chunk-VHME5BE6.mjs.br +0 -0
  120. package/dist/chunk-VHME5BE6.mjs.gz +0 -0
  121. package/dist/chunk-WK22Z7PK.js.br +0 -0
  122. package/dist/chunk-WK22Z7PK.js.gz +0 -0
  123. package/dist/chunk-Y2KIB3QH.js.br +0 -0
  124. package/dist/chunk-Y2KIB3QH.js.gz +0 -0
  125. package/dist/chunk-YWKUIUQX.mjs.br +0 -0
  126. package/dist/chunk-YWKUIUQX.mjs.gz +0 -0
  127. package/dist/useViewerBuildingBlocks-Xddn6SFj.d.ts.map +0 -1
@@ -1,12 +1,12 @@
1
- import { computeFocusTargets, aiChangeAnimationCss, changeGhostStyle, createChatHistoryStore, toRenderableParts } from './chunk-EL2YF26P.mjs';
2
- import { useReducedMotion, useViewerState, useViewerOptions, useIsMobile, useResizablePanels, useDerivedSlideState, useZoomViewport, useEditorHistory, usePresentationSetup, useTouchGestures, useViewerDialogs, useEditorOperations, useViewerIntegration, useLayoutSwitching, useYjsDocumentSync, useCollaborationLivePatch, useFollowMode, useBroadcastFollower, scopeLayoutOptionsToActiveSlide, useToolbarVisibility, useKeyboardInsets, useModalDismissDrag, useCollaborativeState, useVirtualizedSlides, useSwipeNavigation, useSheetDismissDrag, detectTargetType, parseEmailUrl, parseSlideFromUrl, ACTION_VERB_MAP, downloadBlob } from './chunk-J7EFC3GS.mjs';
3
- import { MIN_ELEMENT_SIZE, DEFAULT_STROKE_COLOR, getConnectorPathGeometry, buildLineShadowCss, buildLineGlowFilter, renderConnectorMarker, getShapeVisualStyle, getTextStyleForElement, DEFAULT_TEXT_COLOR, renderVectorShape, isConnectorOrLineElement, build3DExtrusionData, getImageRenderStyle, cn, getTextLayoutStyle, renderTableElement, renderMediaElement, shouldRenderFallbackLabel, SHAPE_PRESETS, ANIMATION_PRESET_OPTIONS, DEFAULT_FILL_COLOR, hasDagDuotoneEffect, renderDagDuotoneSvgFilter, getCropShapeClipPath, isImageTiled, getImageTilingStyle, getDuotoneColors, getTextWarpStyle, renderTextSegments, buildReactChartViewModel, renderChartElement, buildTextBody3DSceneStyle, SLIDE_NAV_THUMBNAIL_WIDTH, DEFAULT_TEXT_FONT_SIZE, DEFAULT_FONT_FAMILY, TOOLBAR_SECTIONS, SHORTCUT_REFERENCE_ITEMS as SHORTCUT_REFERENCE_ITEMS$1, HYPERLINK_COLOR, GRID_SIZE, CONNECTOR_ARROW_OPTIONS, ARROW_SIZE_OPTIONS, startMotionPathPreview, startPreviewAnimation, stopPreviewAnimation, THEME_COLOR_SWATCHES, STROKE_DASH_OPTIONS } from './chunk-VHME5BE6.mjs';
4
- import { LOCALE_CATALOG, translationsEn } from './chunk-5IUEPQTK.mjs';
5
- import { hasShapeProperties, normalizeHexColor, colorWithOpacity, normalizeStrokeDashType, getSvgStrokeDasharray, getCompoundLineOffsets, getCompoundLineWidths, svgLineCap, hasTextProperties, getElementTransform, isEditableTextElement, isElementRendered, isElementActionable, getAriaRole, getAriaLabel, getAriaRoleDescription, getImageEffectsOpacity, getImageEffectsFilter, getElementTransformWithoutRotation, isHollowShapeElement, LINK_TOOLTIP_HOST_CLASS, ACTION_BUTTON_PRESETS, mediaTransportVisible, isInkElement, getElementLabel, SWITCHABLE_LAYOUT_TYPES, DEFAULT_VIEWER_OPTIONS, compileEquationTemplateMathMl, buildUserFontFaceStyles, readStoredViewerPrefs, resolveThemeCatalogEntry, THEME_CATALOG, writeStoredViewerPrefs, openPptxFile, readBackstageRecentFile, viewerOptionsToPreferences, applyPreferenceToOptions, listAutosaveSnapshots, deleteAutosaveSnapshot, paintedStrokeWidth, buildCssGradientFromShapeStyle, ensureActionAffordanceStyles, resolveElementActionAffordance, actionAffordanceLabels, getComputedEffectStyle, getSoftEdgeSvgFilter, buildStrokeOutline, buildHollowHitOutline, strokeOutlineViewBox, getGroupChildParentFill, revealedSmartArtNodeCount, buildSmartArtA11y, buildSummaryZoomView, getImageColorWashStyle, isImageLikeElement, placeCaretAtEnd, getPendingSelectionRestore, restoreSegmentSelection, getTextCompensationTransform, applyChartBuildReveal, formatAxisValue, hasPressureVariation, getInkReplayStyles, INK_REPLAY_KEYFRAMES, resolveInkColor, resolveInkWidth, resolveInkOpacity, pressuresToWidths, getContentPartReplayStyles, resolveOleType, getOleTypeColor, getOleTypeLabel, filterRenderedElements, resolveGroupChildFill, isLinkedTextBox, getOverflowSegments, shouldUseSvgWarp, RULER_THICKNESS, RULER_FONT_SIZE, buildPreviewElements, deriveSlideFieldContext, SLIDE_TRANSITION_OPTIONS, hiddenSlideCue, HIDDEN_SLIDE_SLASH_GRADIENT, HIDDEN_SLIDE_LABEL_KEY, themeToCssVars, applyMotionPathPreset, DEFAULT_INSERT_CHART_KIND, hasCopyableFormat, templateSchemeFromTheme, createBackstagePresentation, printPropertiesFrameSlides, printPropertiesSlidesPerPage, VIEWER_OPTIONS_TABS, DEFAULT_QUICK_ACCESS_COMMAND_IDS, buildJoinCollaborationConfig, buildCreateCollaborationConfig, generateBroadcastRoomId, DEFAULT_BROADCAST_SERVER_URL, buildBroadcastViewerUrl, resolveTransportForServerUrl, ACTION_INDICATOR_CLASS, ACTION_INDICATOR_ICON_PATH, LINK_TOOLTIP_CLASS, LINK_TOOLTIP_PANEL_CLASS, LINK_TOOLTIP_LABEL_CLASS, LINK_TOOLTIP_HINT_CLASS, DEFAULT_PALETTE2, resolvePalette, computeDrawingViewBox, projectDrawingShapes, styleShadowFilter, resolveDrawingShapeNodeId, getImageSvgFilters, buildDuotoneCacheKey, getDuotoneCachedResult, applyDuotone, setDuotoneCachedResult, buildCacheKey, DEFAULT_COLOR_CHANGE_TOLERANCE, getCachedResult, applyColorChange, setCachedResult, findChartPartTarget, dragValueForPart, withChartPointValue, dragAnchorViewY, withChartTitle, computeSmartArtLayout, buildSmartArt3DModel, extractPathPoints, generatePressureCircles, isBrowserOpenableMime, formatBytes, getOleBadgeLabel, openUrlInNewTab, getSubstituteFontFamily, getWarpPath, getSlideBackgroundStyle, filterCommands, resolveTitleBarStatusKey, TITLE_BAR_CLASSES, TITLE_BAR_DEFAULT_FILE_KEY, buildFieldSubstitutionContext, shouldConfirmExternalHyperlink, safeOpenUrl, isPpactionUrl, parsePpactionUrl, isPresentationAdvanceClick, toggleBlackboard, PRESENT_TOOLBAR_CLASSES, buildContextMenuEntries, themeColorSchemesEqual, EXPANDED_MAX_HEIGHT, STATUS_BAR_CLASSES, formatVersionTimestamp, formatRelativeTime, scanAvailableFontFamilies, PRESETS, CATEGORIES, convertOmmlToLatex, compileLatexEquation, convertLatexToOmml, EQUATION_TEMPLATES, clampPercent, HANDOUT_OPTIONS, TOOLBAR_TABS, SHORTCUT_REFERENCE_ITEMS, resolveViewerAddinRows, availableQuickAccessCommands, addQuickAccessCommand, removeQuickAccessCommand, moveQuickAccessCommand, activateModalFocus, buildCollaborationShareUrl, canGoPrevious, formatSlideCounter, READING_VIEW_COUNTER_ATTR, canGoNext, READING_VIEW_ATTR, OUTLINE_LEVEL_ATTR, OUTLINE_SLIDE_ATTR, OUTLINE_ROW_ATTR, OUTLINE_VIEW_ATTR, mobileElapsedSince, nextPresentedSlide, presenterPrevDisabled, presenterNextDisabled, formatMobileElapsed, mobileSlideCounter, presenterPaneAdvancesOnClick, presenterTimerProgress, PRESENTER_CONSOLE_CLASSES, formatElapsed, centeredSvgTextLines, buildTree, treeWidth, treeDepth, fitFontSize, computeInlineEditorRect, findSmartArtNodeText, setSmartArtNodeStyle, rebuildDrawingShapesIfCleared, shouldCommitSmartArtNodeText, updateSmartArtNodeText, groupIntoParagraphs, substituteFieldText, extraQuickAccessCommands, TAB_ROW_ACTION_CLASSES, listBackstageRecentFiles, BACKSTAGE_NAV, INSERT_CHART_TYPES, CHARACTER_SPACING_OPTIONS, DEFAULT_MOTION_PATH_PRESET_ID, SLIDE_VIRTUALIZATION_THRESHOLD, PRESENTATION_STAGE_ATTRIBUTE, getSlideTransitionAnimations, SLIDE_TRANSITION_KEYFRAMES, annotationOverlayZIndex, presentationInkPath, motionPathFor, setMotionPath, getShapeAdjustmentHandleDescriptor, PRESENTER_NAVIGATOR_LABEL_KEYS, PEN_COLORS, HIGHLIGHTER_COLORS, isBlackboardActive, PRESET_THEMES, normalizeSegments, createPlainNotesSegments, segmentsToEditorHtml, DEBOUNCE_MS, parseSegmentsFromRichEditor, segmentsToPlainText, getCurrentParagraphIndex, segmentsToParagraphs, paragraphsToSegments, MAX_INDENT_LEVEL, INDENT_PX, isUrlSafe, escapeHtml2, sanitizeMathMl, computeHandoutLayout, getPrintableArea, generateNoteLineCount, computeAllNotesPages, getNotesPrintableArea, QUICK_ACCESS_COMMAND_CATALOG, 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, styleShadow, styleStroke, nodeOpacity, truncate, paletteColour, BACKSTAGE_TEMPLATES, formatBackstageDate, formatBackstageSize, backstageCardsFor, DEFAULT_VIEWER_PROFILE, resolveProfileInitial, AVATAR_COLOR_SWATCHES, ENTRANCE_PRESET_VALUES, EMPHASIS_PRESET_VALUES, EXIT_PRESET_VALUES, MOTION_PATH_FAMILIES, motionPathFamilyLabelKey, motionPathPresetsByFamily, motionPathPresetLabelKey, getConnectionSites, generateTicks, rulerDragToGuidePosition, getCommentMarkerPosition, motionPathToSvgD, motionPathEndPixel, isEditableMotionPath, setMotionPathEnd, themeColorLabel, buildThemeColorGrid, THEME_COLOR_SCHEME_KEYS, COMMON_FONTS, buildSmartArtPresetData, handleReadingViewKey, getLocalStorageUsageSummary, saveViewerProfile, clearAllLocalViewerData, SLIDE_TEMPLATES, mergeSlideTransition, buildSlideTemplateContent, buildTableDataGrid, appendTableElementRow, removeLastTableElementRow, appendTableElementColumn, removeLastTableElementColumn, removeTableElementColumn, removeTableElementRow, setTableElementCellText, TABLE_STYLE_PRESETS, chartDataChangeType, setChartCategoryLabel, setChartCellValue, addChartCategory, removeChartCategory, addChartSeries, removeChartSeries, setChartAxisLogScale, setChartAxisTitleStyle, setChartAxisGridlineStyle, setChartSeriesMarker, setChartSeriesChartType, setChartDataPointFill, setChartDataPointExplosion, setChartDataPointMarker, setChartDataPointLabel, getOleObjectTypeLabel, sanitizeGradientStops, pptxActionToElementAction, withFrameSlides, withSlidesPerPage, applyThemeOverrideToSlide, COLOR_MAP_ALIAS_KEYS, DEFAULT_COLOR_MAP, schemaLabel, THEME_COLOR_SLOT_LABEL_KEYS, TRANSITION_VALID_DIRECTIONS, TRANSITION_ORIENTATION_TYPES, clampTransitionNumber, flattenTagCollections, formatCommentTimestamp, clearMotionPath, DIRECTIONAL_PRESETS, motionPathPresetIdForPath, computeMergeCellRight, computeMergeCellDown, computeSplitCell, SMARTART_COLOR_SCHEME_LABEL_KEYS, SMARTART_STYLE_LABEL_KEYS, addSmartArtNodeAsChild, removeSmartArtNode, clampCropValue, DUOTONE_PRESETS, ARTISTIC_EFFECTS, resolveActionType, ELEMENT_ACTION_TYPE_OPTIONS, toSlideIndex, elementActionToPptxAction, canCommitActionType, TRANSITION_DIR_ARROWS, buildDirectionGrid, updateTagInCollections, deleteTagFromCollections, addTagToCollections, animationEffectLabel, LBL, SEL, FILL_MODE_OPTIONS, SECTION_HEADING, NUM, switchSmartArtLayout, addSmartArtNode, demoteSmartArtNode, promoteSmartArtNode, reorderSmartArtNode, SHAPE_QUICK_STYLES, quickStyleSwatchCss, getPatternSvg, TEXT_WARP_PRESETS, warpPreviewPath, text3dPtToEmu, text3dEmuToPt, MATERIAL_PRESETS, GRADIENT_TYPE_OPTIONS, PATTERN_OPTIONS, FILL_PATTERN_LABEL_KEYS, openNativeEyeDropper, toggleText3dExtrusion, BEVEL_PRESETS } from './chunk-YWKUIUQX.mjs';
1
+ import { computeFocusTargets, aiChangeAnimationCss, changeGhostStyle, createChatHistoryStore, toRenderableParts } from './chunk-FXJOTEPO.mjs';
2
+ import { useReducedMotion, useViewerState, useViewerOptions, useIsMobile, useResizablePanels, useDerivedSlideState, useZoomViewport, useEditorHistory, usePresentationSetup, useTouchGestures, useViewerDialogs, useEditorOperations, useViewerIntegration, useLayoutSwitching, useYjsDocumentSync, useCollaborationLivePatch, useFollowMode, useBroadcastFollower, scopeLayoutOptionsToActiveSlide, useToolbarVisibility, useKeyboardInsets, useModalDismissDrag, useCollaborativeState, useVirtualizedSlides, useSwipeNavigation, useSheetDismissDrag, detectTargetType, parseEmailUrl, parseSlideFromUrl, ACTION_VERB_MAP, downloadBlob } from './chunk-ZA5JONCW.mjs';
3
+ import { MIN_ELEMENT_SIZE, DEFAULT_STROKE_COLOR, getConnectorPathGeometry, buildLineShadowCss, buildLineGlowFilter, renderConnectorMarker, getShapeVisualStyle, getTextStyleForElement, DEFAULT_TEXT_COLOR, renderVectorShape, isConnectorOrLineElement, build3DExtrusionData, getImageRenderStyle, cn, getTextLayoutStyle, renderTableElement, renderMediaElement, shouldRenderFallbackLabel, SHAPE_PRESETS, ANIMATION_PRESET_OPTIONS, DEFAULT_FILL_COLOR, hasDagDuotoneEffect, renderDagDuotoneSvgFilter, getCropShapeClipPath, getImageTilingStyle, getDuotoneColors, getTextWarpStyle, renderTextSegments, buildReactChartViewModel, renderChartElement, buildTextBody3DSceneStyle, SLIDE_NAV_THUMBNAIL_WIDTH, DEFAULT_TEXT_FONT_SIZE, DEFAULT_FONT_FAMILY, TOOLBAR_SECTIONS, SHORTCUT_REFERENCE_ITEMS as SHORTCUT_REFERENCE_ITEMS$1, HYPERLINK_COLOR, GRID_SIZE, CONNECTOR_ARROW_OPTIONS, ARROW_SIZE_OPTIONS, startMotionPathPreview, startPreviewAnimation, stopPreviewAnimation, THEME_COLOR_SWATCHES, STROKE_DASH_OPTIONS } from './chunk-MQHC5TXI.mjs';
4
+ import { LOCALE_CATALOG, translationsEn } from './chunk-S64T7C4V.mjs';
5
+ import { hasShapeProperties, normalizeHexColor, colorWithOpacity, normalizeStrokeDashType, getSvgStrokeDasharray, getCompoundLineOffsets, getCompoundLineWidths, svgLineCap, hasTextProperties, getElementTransform, getAriaRoleDescription, getAriaLabel, getAriaRole, resolveElementInteractivity, isEditableTextElement, isElementRendered, isElementActionable, getImageEffectsOpacity, getImageEffectsFilter, getElementTransformWithoutRotation, inlineElementPointerEvents, isHollowShapeElement, LINK_TOOLTIP_HOST_CLASS, ACTION_BUTTON_PRESETS, mediaTransportVisible, isInkElement, getGroupChildParentFill, getElementLabel, SWITCHABLE_LAYOUT_TYPES, DEFAULT_VIEWER_OPTIONS, compileEquationTemplateMathMl, buildUserFontFaceStyles, readStoredViewerPrefs, resolveThemeCatalogEntry, THEME_CATALOG, writeStoredViewerPrefs, openPptxFile, readBackstageRecentFile, viewerOptionsToPreferences, applyPreferenceToOptions, listAutosaveSnapshots, deleteAutosaveSnapshot, resolveAutosaveIntervalSeconds, paintedStrokeWidth, buildCssGradientFromShapeStyle, ensureActionAffordanceStyles, resolveElementActionAffordance, actionAffordanceLabels, getComputedEffectStyle, getSoftEdgeSvgFilter, buildStrokeOutline, buildHollowHitOutline, strokeOutlineViewBox, revealedSmartArtNodeCount, buildSmartArtA11y, computeSmartArtLayout, flattenNodes, buildSummaryZoomView, isImageTiled, getImageColorWashStyle, isImageLikeElement, placeCaretAtEnd, getPendingSelectionRestore, restoreSegmentSelection, getTextCompensationTransform, applyChartBuildReveal, formatAxisValue, hasPressureVariation, getInkReplayStyles, INK_REPLAY_KEYFRAMES, resolveInkColor, resolveInkWidth, resolveInkOpacity, pressuresToWidths, getContentPartReplayStyles, resolveOleType, getOleTypeColor, getOleTypeLabel, filterRenderedElements, resolveGroupChildFill, isLinkedTextBox, getOverflowSegments, shouldUseSvgWarp, RULER_THICKNESS, RULER_FONT_SIZE, buildPreviewElements, deriveSlideFieldContext, SLIDE_TRANSITION_OPTIONS, hiddenSlideCue, HIDDEN_SLIDE_SLASH_GRADIENT, HIDDEN_SLIDE_LABEL_KEY, themeToCssVars, applyMotionPathPreset, resetSlideLayoutPath, DEFAULT_INSERT_CHART_KIND, hasCopyableFormat, templateSchemeFromTheme, createBackstagePresentation, printPropertiesFrameSlides, printPropertiesSlidesPerPage, VIEWER_OPTIONS_TABS, DEFAULT_QUICK_ACCESS_COMMAND_IDS, buildJoinCollaborationConfig, buildCreateCollaborationConfig, generateBroadcastRoomId, DEFAULT_BROADCAST_SERVER_URL, buildBroadcastViewerUrl, resolveTransportForServerUrl, ACTION_INDICATOR_CLASS, ACTION_INDICATOR_ICON_PATH, LINK_TOOLTIP_CLASS, LINK_TOOLTIP_PANEL_CLASS, LINK_TOOLTIP_LABEL_CLASS, LINK_TOOLTIP_HINT_CLASS, DEFAULT_PALETTE2, resolvePalette, computeDrawingViewBox, projectDrawingShapes, styleShadowFilter, resolveDrawingShapeNodeId, getImageSvgFilters, buildDuotoneCacheKey, getDuotoneCachedResult, applyDuotone, setDuotoneCachedResult, buildCacheKey, DEFAULT_COLOR_CHANGE_TOLERANCE, getCachedResult, applyColorChange, setCachedResult, findChartPartTarget, dragValueForPart, withChartPointValue, dragAnchorViewY, withChartTitle, buildSmartArt3DModel, extractPathPoints, generatePressureCircles, isBrowserOpenableMime, formatBytes, getOleBadgeLabel, openUrlInNewTab, getSubstituteFontFamily, getWarpPath, getSlideBackgroundStyle, filterCommands, resolveTitleBarStatusKey, TITLE_BAR_CLASSES, TITLE_BAR_DEFAULT_FILE_KEY, buildFieldSubstitutionContext, shouldConfirmExternalHyperlink, safeOpenUrl, isPpactionUrl, parsePpactionUrl, isPresentationAdvanceClick, toggleBlackboard, PRESENT_TOOLBAR_CLASSES, buildContextMenuEntries, themeColorSchemesEqual, EXPANDED_MAX_HEIGHT, STATUS_BAR_CLASSES, formatVersionTimestamp, formatRelativeTime, scanAvailableFontFamilies, PRESETS, CATEGORIES, convertOmmlToLatex, compileLatexEquation, convertLatexToOmml, EQUATION_TEMPLATES, clampPercent, HANDOUT_OPTIONS, TOOLBAR_TABS, SHORTCUT_REFERENCE_ITEMS, resolveViewerAddinRows, availableQuickAccessCommands, addQuickAccessCommand, removeQuickAccessCommand, moveQuickAccessCommand, CUSTOM_FONT_ACCEPT, activateModalFocus, buildCollaborationShareUrl, canGoPrevious, formatSlideCounter, READING_VIEW_COUNTER_ATTR, canGoNext, READING_VIEW_ATTR, OUTLINE_LEVEL_ATTR, OUTLINE_SLIDE_ATTR, OUTLINE_ROW_ATTR, OUTLINE_VIEW_ATTR, mobileElapsedSince, nextPresentedSlide, presenterPrevDisabled, presenterNextDisabled, formatMobileElapsed, mobileSlideCounter, presenterPaneAdvancesOnClick, presenterTimerProgress, PRESENTER_CONSOLE_CLASSES, formatElapsed, centeredSvgTextLines, computeInlineEditorRect, findSmartArtNodeText, setSmartArtNodeStyle, rebuildDrawingShapesIfCleared, shouldCommitSmartArtNodeText, updateSmartArtNodeText, groupIntoParagraphs, substituteFieldText, extraQuickAccessCommands, TAB_ROW_ACTION_CLASSES, listBackstageRecentFiles, BACKSTAGE_NAV, INSERT_CHART_TYPES, CHARACTER_SPACING_OPTIONS, RIBBON_SHAPE_SWATCHES, shapeFillChange, shapeOutlineChange, readRibbonTransitionDraft, ribbonTransitionUpdates, RIBBON_TRANSITION_PRESETS, DEFAULT_MOTION_PATH_PRESET_ID, SLIDE_SHOW_OPTIONS, slideShowOptionChange, readSlideShowOption, SLIDE_VIRTUALIZATION_THRESHOLD, PRESENTATION_HIT_TEST_CSS, PRESENTATION_STAGE_ATTRIBUTE, getSlideTransitionAnimations, SLIDE_TRANSITION_KEYFRAMES, annotationOverlayZIndex, presentationInkPath, motionPathFor, setMotionPath, getShapeAdjustmentHandleDescriptor, PRESENTER_NAVIGATOR_LABEL_KEYS, PEN_COLORS, HIGHLIGHTER_COLORS, isBlackboardActive, resolveSelectionPaneRename, PRESET_THEMES, normalizeSegments, createPlainNotesSegments, segmentsToEditorHtml, DEBOUNCE_MS, parseSegmentsFromRichEditor, segmentsToPlainText, getCurrentParagraphIndex, segmentsToParagraphs, paragraphsToSegments, MAX_INDENT_LEVEL, INDENT_PX, isUrlSafe, escapeHtml2, sanitizeMathMl, computeHandoutLayout, getPrintableArea, generateNoteLineCount, computeAllNotesPages, getNotesPrintableArea, QUICK_ACCESS_COMMAND_CATALOG, registerCustomFont, openReadingView, applyReadingViewCommand, createPresentationKeyBuffer, readingViewFitScale, READING_VIEW_STAGE_ATTR, buildOutline, applyOutlineEdit, mapOutlineKey, notesSegmentsToSpans, erasePresentationInkAt, movePresenterPointer, appendPresentationInkPoint, PRESENTER_CONSOLE_CONTROLS, NOTES_FONT_SIZE_DEFAULT, formatTime, NOTES_FONT_SIZE_MIN, clampNotesFontSize, NOTES_FONT_SIZE_STEP, NOTES_FONT_SIZE_MAX, BACKSTAGE_TEMPLATES, formatBackstageDate, formatBackstageSize, backstageCardsFor, DEFAULT_VIEWER_PROFILE, resolveProfileInitial, AVATAR_COLOR_SWATCHES, resolveDefaultFontFamily, buildFontCatalog, ENTRANCE_PRESET_VALUES, EMPHASIS_PRESET_VALUES, EXIT_PRESET_VALUES, MOTION_PATH_FAMILIES, motionPathFamilyLabelKey, motionPathPresetsByFamily, motionPathPresetLabelKey, masterViewPseudoSlide, authorConnectorBetweenSites, generateTicks, rulerDragToGuidePosition, getCommentMarkerPosition, getConnectionSites, motionPathToSvgD, motionPathEndPixel, isEditableMotionPath, setMotionPathEnd, themeColorLabel, buildThemeColorGrid, THEME_COLOR_SCHEME_KEYS, COMMON_FONTS, buildSmartArtPresetData, handleReadingViewKey, getLocalStorageUsageSummary, saveViewerProfile, clearAllLocalViewerData, isCurrentLayout, SLIDE_TEMPLATES, isElementLocked, mergeSlideTransition, buildLayoutPreviewGeometry, buildSlideTemplateContent, elementLockTogglePatch, buildTableDataGrid, appendTableElementRow, removeLastTableElementRow, appendTableElementColumn, removeLastTableElementColumn, removeTableElementColumn, removeTableElementRow, setTableElementCellText, TABLE_STYLE_PRESETS, chartDataChangeType, setChartCategoryLabel, setChartCellValue, addChartCategory, removeChartCategory, addChartSeries, removeChartSeries, setChartAxisLogScale, setChartAxisTitleStyle, setChartAxisGridlineStyle, setChartSeriesMarker, setChartSeriesChartType, setChartDataPointFill, setChartDataPointExplosion, setChartDataPointMarker, setChartDataPointLabel, getOleObjectTypeLabel, sanitizeGradientStops, pptxActionToElementAction, withFrameSlides, withSlidesPerPage, applyThemeOverrideToSlide, COLOR_MAP_ALIAS_KEYS, DEFAULT_COLOR_MAP, schemaLabel, THEME_COLOR_SLOT_LABEL_KEYS, TRANSITION_VALID_DIRECTIONS, TRANSITION_ORIENTATION_TYPES, clampTransitionNumber, flattenTagCollections, formatCommentTimestamp, clearMotionPath, DIRECTIONAL_PRESETS, motionPathPresetIdForPath, computeMergeCellRight, computeMergeCellDown, computeSplitCell, SMARTART_COLOR_SCHEME_LABEL_KEYS, SMARTART_STYLE_LABEL_KEYS, addSmartArtNodeAsChild, removeSmartArtNode, clampCropValue, DUOTONE_PRESETS, ARTISTIC_EFFECTS, resolveActionType, ELEMENT_ACTION_TYPE_OPTIONS, toSlideIndex, elementActionToPptxAction, canCommitActionType, TRANSITION_DIR_ARROWS, buildDirectionGrid, updateTagInCollections, deleteTagFromCollections, addTagToCollections, animationEffectLabel, LBL, SEL, FILL_MODE_OPTIONS, SECTION_HEADING, NUM, switchSmartArtLayout, addSmartArtNode, demoteSmartArtNode, promoteSmartArtNode, reorderSmartArtNode, SHAPE_QUICK_STYLES, quickStyleSwatchCss, getPatternSvg, TEXT_WARP_PRESETS, warpPreviewPath, text3dPtToEmu, text3dEmuToPt, MATERIAL_PRESETS, GRADIENT_TYPE_OPTIONS, PATTERN_OPTIONS, FILL_PATTERN_LABEL_KEYS, openNativeEyeDropper, toggleText3dExtrusion, BEVEL_PRESETS } from './chunk-K2QU73KB.mjs';
6
6
  import React14, { createContext, useMemo, useState, useCallback, lazy, forwardRef, useEffect, useRef, Suspense, useLayoutEffect, useContext, Fragment as Fragment$1, useDeferredValue } from 'react';
7
7
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
8
8
  import { useTranslation } from 'react-i18next';
9
- import { LuRotateCw, LuMessageSquare, LuEyeOff, LuSettings, LuX, LuCalendarDays, LuHash, LuText, LuCast, LuSave, LuUndo, LuRedo, LuSearch, LuShieldCheck, LuPlus, LuPanelLeftClose, LuStickyNote, LuMonitor, LuColumns2, LuPresentation, LuMinus, LuLayers, LuSettings2, LuClock, LuDownload, LuTrash2, LuCheck, LuLock, LuEye, LuFileText, LuType, LuLoader, LuShieldAlert, LuSignature, LuInfo, LuTriangleAlert, LuPrinter, LuPenTool, LuBug, LuChevronUp, LuChevronDown, 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, LuUpload, LuBold, LuItalic, LuUnderline, LuStrikethrough, LuLink, LuGrid2X2, LuCopyPlus, LuScan, LuMonitorOff, LuCirclePlay, LuCirclePause, LuArrowLeftRight, LuClipboardCopy, LuWand, LuTextCursorInput, LuFile, LuEllipsis, LuUserRound, LuFilePlus2, LuHouse, LuPackage, LuFileJson, LuBox, LuFileImage, LuUser, LuHardDrive, LuLogIn, LuLayoutTemplate, LuFolderPlus, LuAlignLeft, LuAlignCenter, LuAlignRight, LuAlignJustify, LuColumns3, LuSpline, LuAlignHorizontalSpaceAround, LuAlignVerticalSpaceAround, LuGroup, LuUngroup, LuMove, LuRadio, LuLockOpen, LuArrowDown, LuArrowUp, LuArrowRight, LuReply, LuBookmark } from 'react-icons/lu';
9
+ import { LuRotateCw, LuMessageSquare, LuEyeOff, LuSettings, LuX, LuCalendarDays, LuHash, LuText, LuCast, LuSave, LuUndo, LuRedo, LuSearch, LuShieldCheck, LuPlus, LuPanelLeftClose, LuStickyNote, LuMonitor, LuColumns2, LuPresentation, LuMinus, LuLayers, LuSettings2, LuClock, LuDownload, LuTrash2, LuCheck, LuLock, LuEye, LuFileText, LuType, LuLoader, LuShieldAlert, LuSignature, LuInfo, LuTriangleAlert, LuPrinter, LuPenTool, LuBug, LuChevronUp, LuChevronDown, LuUpload, LuWifi, LuWifiOff, LuUsers, LuCopy, LuChevronLeft, LuChevronRight, LuPlay, LuPause, LuZoomOut, LuZoomIn, LuSpellCheck, LuFileDown, LuMenu, LuSparkles, LuShare2, LuPanelLeft, LuPanelRight, LuArrowLeft, LuFolderOpen, LuClipboardPaste, LuScissors, LuPaintbrush, LuSquare, LuImage, LuVideo, LuDatabase, LuAArrowUp, LuAArrowDown, LuRemoveFormatting, LuHighlighter, LuList, LuListOrdered, LuIndentDecrease, LuIndentIncrease, LuReplace, LuMousePointer2, LuShapes, LuPaintBucket, LuPenLine, LuPalette, LuPencil, LuStar, LuMoveRight, LuMousePointerClick, LuClock3, LuMonitorPlay, LuListVideo, LuCaptions, LuCamera, LuEraser, LuRotateCcw, LuCircleHelp, LuBookOpen, LuLanguages, LuGlobe, LuGitCompare, LuMessageSquarePlus, LuLockKeyhole, LuPanelTop, LuLayoutGrid, LuGrid3X3, LuPipette, LuRuler, LuMaximize2, LuCode, LuCaseSensitive, LuTimer, LuGripVertical, LuLoaderCircle, LuBold, LuItalic, LuUnderline, LuStrikethrough, LuLink, LuGrid2X2, LuCopyPlus, LuScan, LuMonitorOff, LuCirclePlay, LuCirclePause, LuArrowLeftRight, LuClipboardCopy, LuWand, LuTextCursorInput, LuFile, LuEllipsis, LuUserRound, LuFilePlus2, LuHouse, LuPackage, LuFileJson, LuBox, LuFileImage, LuUser, LuHardDrive, LuLogIn, LuLayoutTemplate, LuFolderPlus, LuAlignLeft, LuAlignCenter, LuAlignRight, LuAlignJustify, LuColumns3, LuSpline, LuAlignHorizontalSpaceAround, LuAlignVerticalSpaceAround, LuGroup, LuUngroup, LuMove, LuRadio, LuLockOpen, LuArrowDown, LuArrowUp, LuArrowRight, LuReply, LuBookmark } from 'react-icons/lu';
10
10
 
11
11
  var ViewerThemeContext = createContext(void 0);
12
12
  function ViewerThemeProvider({ theme, children }) {
@@ -1268,6 +1268,10 @@ var ConnectorElementRenderer = React14.memo(
1268
1268
  {
1269
1269
  "data-pptx-element": "true",
1270
1270
  "data-element-id": el.id,
1271
+ role: getAriaRole(el, { actionable: false }),
1272
+ "aria-label": getAriaLabel(el),
1273
+ "aria-roledescription": getAriaRoleDescription(el),
1274
+ "aria-selected": isSelected ? true : void 0,
1271
1275
  className: "absolute",
1272
1276
  style: {
1273
1277
  left: el.x,
@@ -1545,13 +1549,18 @@ function getContainerStyle({
1545
1549
  overflow: overflowValue,
1546
1550
  clipPath: isImg && !has3DExtrusion ? getCropShapeClipPath(el) : void 0,
1547
1551
  zIndex: isFullscreenMedia ? 20 : zIndex,
1548
- opacity,
1549
1552
  visibility: animationState?.visible === false ? "hidden" : "visible",
1550
1553
  animation: animationState?.cssAnimation,
1551
1554
  background: isFullscreenMedia ? "#000" : void 0,
1552
1555
  transition: isFullscreenMedia ? "left 0.3s ease, top 0.3s ease, width 0.3s ease, height 0.3s ease" : void 0,
1553
1556
  borderColor: isFullscreenMedia ? "transparent" : void 0,
1554
1557
  ...shapeVisualStyle,
1558
+ // COMPOSE the effect alpha (`a:alphaModFix` on the effect DAG) with the
1559
+ // element opacity instead of letting the spread clobber it. The other four
1560
+ // bindings multiply the two; React spread the shape style over its own
1561
+ // `opacity` key, so a half-transparent element carrying a DAG alpha
1562
+ // rendered at the DAG's alpha alone.
1563
+ opacity: typeof shapeVisualStyle.opacity === "number" ? (opacity ?? 1) * shapeVisualStyle.opacity : opacity,
1555
1564
  // Editable-template affordance: a distinct amber dashed ring + slight
1556
1565
  // transparency so inherited master/layout shapes read as "template" while
1557
1566
  // edit-template mode is on. Applied after the shape style so it wins; never
@@ -1748,6 +1757,7 @@ var ElementRenderer = React14.memo(
1748
1757
  isInlineEditing,
1749
1758
  inlineEditingText,
1750
1759
  canInteract,
1760
+ presenting,
1751
1761
  spellCheckEnabled,
1752
1762
  mediaDataUrls,
1753
1763
  tableEditorState,
@@ -1799,8 +1809,8 @@ var ElementRenderer = React14.memo(
1799
1809
  });
1800
1810
  const chartUpdateHandler = smartArtUpdateHandler;
1801
1811
  const { hf, fc, sw, sc } = shapeParams(el);
1802
- const elementLocks = el.locks;
1803
- const isTxt = isEditableTextElement(el) && !elementLocks?.noTextEdit;
1812
+ const allow = resolveElementInteractivity(el);
1813
+ const isTxt = isEditableTextElement(el) && allow.textEditable;
1804
1814
  const txtSE = hasTextProperties(el) ? el.textStyle : void 0;
1805
1815
  const ss = getShapeVisualStyle(
1806
1816
  el,
@@ -1844,7 +1854,7 @@ var ElementRenderer = React14.memo(
1844
1854
  el,
1845
1855
  isSelected,
1846
1856
  canInteract,
1847
- showResizeHandles: showResizeHandles && !elementLocks?.noResize,
1857
+ showResizeHandles: showResizeHandles && allow.resizable,
1848
1858
  showHoverBorder,
1849
1859
  selectionColorClass: selClr,
1850
1860
  opacity,
@@ -1856,10 +1866,10 @@ var ElementRenderer = React14.memo(
1856
1866
  }
1857
1867
  );
1858
1868
  }
1859
- const effectiveCanInteract = canInteract && !elementLocks?.noSelect;
1860
- const effectiveShowResizeHandles = showResizeHandles && !elementLocks?.noResize;
1861
- const effectiveIsInlineEditing = isInlineEditing && !elementLocks?.noTextEdit;
1862
- const canEditSmartArt = effectiveCanInteract && !elementLocks?.noTextEdit;
1869
+ const effectiveCanInteract = canInteract && allow.selectable;
1870
+ const effectiveShowResizeHandles = showResizeHandles && allow.resizable;
1871
+ const effectiveIsInlineEditing = isInlineEditing && allow.textEditable;
1872
+ const canEditSmartArt = effectiveCanInteract && allow.textEditable;
1863
1873
  const canEditChart = effectiveCanInteract;
1864
1874
  const hasAction = Boolean(el.actionClick && onActionClick);
1865
1875
  const isZoom = el.type === "zoom" && Boolean(onZoomClick);
@@ -1869,7 +1879,7 @@ var ElementRenderer = React14.memo(
1869
1879
  hasZoomHandler: Boolean(onZoomClick)
1870
1880
  });
1871
1881
  const selB = isSelected ? `outline-1 -outline-offset-1 outline-${selClr} ring-2 ring-${selClr}/50` : showHoverBorder ? "outline-1 -outline-offset-1 outline-transparent hover:outline-primary/40" : "";
1872
- const cur = effectiveIsInlineEditing ? "cursor-text" : effectiveCanInteract ? elementLocks?.noMove ? "cursor-default" : "cursor-move" : hasAction || isZoom ? "cursor-pointer" : "";
1882
+ const cur = effectiveIsInlineEditing ? "cursor-text" : effectiveCanInteract ? !allow.movable ? "cursor-default" : "cursor-move" : hasAction || isZoom ? "cursor-pointer" : "";
1873
1883
  const isPresentationPassive = !effectiveCanInteract;
1874
1884
  const isFullscreenMedia = el.type === "media" && Boolean(el.fullScreen) && isPresentationPassive && isMediaPlaying;
1875
1885
  const ariaRole = getAriaRole(el, { actionable: isActionable });
@@ -1901,7 +1911,16 @@ var ElementRenderer = React14.memo(
1901
1911
  "absolute",
1902
1912
  "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500",
1903
1913
  cur,
1904
- effectiveCanInteract || isActionable ? "" : "pointer-events-none",
1914
+ // During a show this must stay EMPTY: `PRESENTATION_HIT_TEST_CSS`
1915
+ // (injected by `PresentationStage`) owns hit-testing there, because
1916
+ // it is the only form that can re-enable an action shape nested
1917
+ // inside inert scenery - an inline `pointer-events: none` on the
1918
+ // group could never do that, and React was the one binding that
1919
+ // wrote it. Off the show stage the inline rule still applies.
1920
+ inlineElementPointerEvents({
1921
+ interactive: effectiveCanInteract || isActionable,
1922
+ presenting: presenting === true
1923
+ }) === "none" ? "pointer-events-none" : "",
1905
1924
  // An unfilled, textless shape is a FRAME: PowerPoint hit-tests it on its
1906
1925
  // outline only, so its interior must not swallow clicks meant for what it
1907
1926
  // is drawn over. ShapeEffectOverlay paints a transparent
@@ -2000,7 +2019,7 @@ var ElementRenderer = React14.memo(
2000
2019
  onAdjustmentPointerDown,
2001
2020
  rotation: el.rotation,
2002
2021
  nonRotationTransform: getElementTransformWithoutRotation(el),
2003
- onRotate: elementLocks?.noRotation ? void 0 : onRotate
2022
+ onRotate: allow.rotatable ? onRotate : void 0
2004
2023
  }
2005
2024
  )
2006
2025
  ]
@@ -2112,7 +2131,11 @@ function renderGroup(children, parentGroupFill) {
2112
2131
  },
2113
2132
  children: [
2114
2133
  /* @__PURE__ */ jsx(ShapeEffectOverlay, { element: c }),
2115
- isI && ("svgData" in c && c.svgData || "imageData" in c && c.imageData) ? isImageTiled(c) ? /* @__PURE__ */ jsx(
2134
+ c.type === "group" ? (
2135
+ // A nested group: recurse, chaining the inherited fill so a
2136
+ // `grpFill` shape under a fill-less sub-group still paints.
2137
+ renderGroup(c.children, getGroupChildParentFill(c, parentGroupFill))
2138
+ ) : isI && ("svgData" in c && c.svgData || "imageData" in c && c.imageData) ? isImageTiled(c) ? /* @__PURE__ */ jsx(
2116
2139
  "div",
2117
2140
  {
2118
2141
  className: "pointer-events-none select-none w-full h-full",
@@ -2563,7 +2586,7 @@ function FailedToLoad() {
2563
2586
  var LazyModel3DScene = React14.lazy(
2564
2587
  async () => {
2565
2588
  try {
2566
- return await import('./Model3DScene-YMIAGRPG.mjs');
2589
+ return await import('./Model3DScene-I7FR74AD.mjs');
2567
2590
  } catch {
2568
2591
  return { default: FailedToLoad };
2569
2592
  }
@@ -2827,24 +2850,10 @@ function OleRenderer({ element: el }) {
2827
2850
  );
2828
2851
  }
2829
2852
  var SmartArt3DContext = createContext(false);
2830
- var DEFAULT_PALETTE = DEFAULT_PALETTE2;
2831
- function colour(index, palette = DEFAULT_PALETTE) {
2832
- return paletteColour(index, palette);
2833
- }
2834
- function nodeOpacity2(index, total, style) {
2835
- return nodeOpacity(index, total, style ?? "flat");
2836
- }
2837
- function styleShadow2(style) {
2838
- return styleShadow(style ?? "flat");
2839
- }
2840
- function styleStroke2(style) {
2841
- return styleStroke(style ?? "flat");
2842
- }
2843
- function truncate2(text, max) {
2844
- return truncate(text, max);
2845
- }
2853
+
2854
+ // src/viewer/utils/smartart-helpers.tsx
2846
2855
  function resolvePalette2(el) {
2847
- return el.type === "smartArt" ? resolvePalette(el.smartArtData) : DEFAULT_PALETTE;
2856
+ return el.type === "smartArt" ? resolvePalette(el.smartArtData) : DEFAULT_PALETTE2;
2848
2857
  }
2849
2858
  function resolveStyle(el) {
2850
2859
  if (el.type !== "smartArt" || !el.smartArtData) {
@@ -2855,49 +2864,6 @@ function resolveStyle(el) {
2855
2864
  function resolveSmartArtDataPalette(data) {
2856
2865
  return resolvePalette(data);
2857
2866
  }
2858
- function layoutToCategory(layout) {
2859
- if (!layout) {
2860
- return "list";
2861
- }
2862
- const map = {
2863
- basicBlockList: "list",
2864
- alternatingHexagons: "list",
2865
- basicChevronProcess: "process",
2866
- basicCycle: "cycle",
2867
- basicPie: "cycle",
2868
- basicRadial: "radial",
2869
- basicVenn: "venn",
2870
- continuousBlockProcess: "process",
2871
- convergingRadial: "radial",
2872
- hierarchy: "hierarchy",
2873
- horizontalBulletList: "list",
2874
- linearVenn: "venn",
2875
- segmentedProcess: "process",
2876
- stackedList: "list",
2877
- tableList: "list",
2878
- trapezoidList: "list",
2879
- upwardArrow: "process",
2880
- basicFunnel: "funnel",
2881
- basicTarget: "radial",
2882
- interlockingGears: "radial",
2883
- basicTimeline: "process",
2884
- basicMatrix: "matrix",
2885
- basicPyramid: "pyramid",
2886
- invertedPyramid: "pyramid",
2887
- bendingProcess: "process",
2888
- stepDownProcess: "stepdown",
2889
- alternatingFlow: "alternatingflow",
2890
- descendingProcess: "descending",
2891
- pictureAccentList: "pictureaccent",
2892
- verticalBlockList: "verticalblock",
2893
- groupedList: "grouped",
2894
- pyramidList: "pyramidlist",
2895
- horizontalPictureList: "horizontalpicture",
2896
- accentProcess: "accentprocess",
2897
- verticalChevronList: "verticalchevron"
2898
- };
2899
- return map[layout] ?? "list";
2900
- }
2901
2867
  var LINE_HEIGHT_RATIO = 1.2;
2902
2868
  var DEFAULT_FONT_SIZE = 12;
2903
2869
  function SmartArtInlineNodeEditor({
@@ -3179,19 +3145,6 @@ function smartArtNodeGroupProps(nodeId, shadow, label) {
3179
3145
  }
3180
3146
  return props;
3181
3147
  }
3182
- function gearPath(cx, cy, outerR, innerR, teeth) {
3183
- const segments = [];
3184
- const step = Math.PI * 2 / (teeth * 2);
3185
- for (let i = 0; i < teeth * 2; i++) {
3186
- const angle = i * step - Math.PI / 2;
3187
- const r = i % 2 === 0 ? outerR : innerR;
3188
- const x = cx + r * Math.cos(angle);
3189
- const y = cy + r * Math.sin(angle);
3190
- segments.push(i === 0 ? `M${x},${y}` : `L${x},${y}`);
3191
- }
3192
- segments.push("Z");
3193
- return segments.join(" ");
3194
- }
3195
3148
  function SmartArtGradient({ gradient }) {
3196
3149
  const stops = gradient.stops.map((stop, i) => /* @__PURE__ */ jsx(
3197
3150
  "stop",
@@ -3224,6 +3177,7 @@ function SmartArtNodeText({
3224
3177
  fontWeight,
3225
3178
  fontStyle,
3226
3179
  className,
3180
+ textAnchor = "middle",
3227
3181
  anchor = "middle",
3228
3182
  maxWidth
3229
3183
  }) {
@@ -3232,7 +3186,7 @@ function SmartArtNodeText({
3232
3186
  "text",
3233
3187
  {
3234
3188
  x,
3235
- textAnchor: "middle",
3189
+ textAnchor,
3236
3190
  dominantBaseline: "central",
3237
3191
  fill,
3238
3192
  fontSize,
@@ -3265,7 +3219,7 @@ function SmartArtNodeText({
3265
3219
  "text",
3266
3220
  {
3267
3221
  x,
3268
- textAnchor: "middle",
3222
+ textAnchor,
3269
3223
  dominantBaseline,
3270
3224
  fill,
3271
3225
  fontSize,
@@ -3295,795 +3249,6 @@ function wrapChrome(chrome, content, className, a11y) {
3295
3249
  }
3296
3250
  );
3297
3251
  }
3298
- function renderStepDownProcess(element, nodes, palette, style) {
3299
- const w = element.width;
3300
- const h = element.height;
3301
- const pad = 8;
3302
- const usableW = w - pad * 2;
3303
- const usableH = h - pad * 2;
3304
- const stepW = usableW / nodes.length;
3305
- const stepH = usableH / nodes.length;
3306
- const boxW = stepW * 0.85;
3307
- const boxH = stepH * 0.6;
3308
- const shadow = styleShadow2(style);
3309
- const sw = styleStroke2(style);
3310
- return /* @__PURE__ */ jsx(
3311
- "svg",
3312
- {
3313
- className: "w-full h-full pointer-events-none",
3314
- viewBox: `0 0 ${w} ${h}`,
3315
- preserveAspectRatio: "xMidYMid meet",
3316
- style: { filter: shadow },
3317
- children: nodes.map((node, i) => {
3318
- const x = pad + i * stepW;
3319
- const y = pad + i * stepH;
3320
- const fontSize = Math.max(7, Math.min(10, boxW * 0.1));
3321
- return /* @__PURE__ */ jsxs("g", { children: [
3322
- i < nodes.length - 1 && /* @__PURE__ */ jsx(
3323
- "line",
3324
- {
3325
- x1: x + boxW,
3326
- y1: y + boxH / 2,
3327
- x2: x + stepW,
3328
- y2: y + stepH + boxH / 2,
3329
- stroke: "#94a3b8",
3330
- strokeWidth: 1.5,
3331
- opacity: 0.5
3332
- }
3333
- ),
3334
- /* @__PURE__ */ jsx(
3335
- "rect",
3336
- {
3337
- x,
3338
- y,
3339
- width: boxW,
3340
- height: boxH,
3341
- rx: 5,
3342
- fill: colour(i, palette),
3343
- opacity: nodeOpacity2(i, nodes.length, style),
3344
- stroke: sw > 0 ? "rgba(255,255,255,0.3)" : "none",
3345
- strokeWidth: sw
3346
- }
3347
- ),
3348
- /* @__PURE__ */ jsx(
3349
- SmartArtNodeText,
3350
- {
3351
- x: x + boxW / 2,
3352
- y: y + boxH / 2,
3353
- text: truncate2(node.text, 20),
3354
- fill: "white",
3355
- fontSize,
3356
- className: "pointer-events-none"
3357
- }
3358
- )
3359
- ] }, `${element.id}-stepdown-${node.id}-${i}`);
3360
- })
3361
- }
3362
- );
3363
- }
3364
- function renderAlternatingFlow(element, nodes, palette, style) {
3365
- const w = element.width;
3366
- const h = element.height;
3367
- const pad = 8;
3368
- const usableH = h - pad * 2;
3369
- const rowH = usableH / nodes.length;
3370
- const halfW = (w - pad * 2) / 2;
3371
- const boxW = halfW * 0.8;
3372
- const boxH = Math.min(rowH * 0.7, 40);
3373
- const centerX = w / 2;
3374
- const shadow = styleShadow2(style);
3375
- const sw = styleStroke2(style);
3376
- return /* @__PURE__ */ jsxs(
3377
- "svg",
3378
- {
3379
- className: "w-full h-full pointer-events-none",
3380
- viewBox: `0 0 ${w} ${h}`,
3381
- preserveAspectRatio: "xMidYMid meet",
3382
- style: { filter: shadow },
3383
- children: [
3384
- /* @__PURE__ */ jsx(
3385
- "line",
3386
- {
3387
- x1: centerX,
3388
- y1: pad,
3389
- x2: centerX,
3390
- y2: h - pad,
3391
- stroke: "#94a3b8",
3392
- strokeWidth: 2,
3393
- opacity: 0.3
3394
- }
3395
- ),
3396
- nodes.map((node, i) => {
3397
- const isLeft = i % 2 === 0;
3398
- const y = pad + i * rowH + (rowH - boxH) / 2;
3399
- const x = isLeft ? centerX - boxW - 12 : centerX + 12;
3400
- const fontSize = Math.max(7, Math.min(10, boxW * 0.1));
3401
- return /* @__PURE__ */ jsxs("g", { children: [
3402
- /* @__PURE__ */ jsx(
3403
- "line",
3404
- {
3405
- x1: isLeft ? x + boxW : x,
3406
- y1: y + boxH / 2,
3407
- x2: centerX,
3408
- y2: y + boxH / 2,
3409
- stroke: colour(i, palette),
3410
- strokeWidth: 1.5,
3411
- opacity: 0.5
3412
- }
3413
- ),
3414
- /* @__PURE__ */ jsx("circle", { cx: centerX, cy: y + boxH / 2, r: 3, fill: colour(i, palette), opacity: 0.8 }),
3415
- /* @__PURE__ */ jsx(
3416
- "rect",
3417
- {
3418
- x,
3419
- y,
3420
- width: boxW,
3421
- height: boxH,
3422
- rx: 5,
3423
- fill: colour(i, palette),
3424
- opacity: nodeOpacity2(i, nodes.length, style),
3425
- stroke: sw > 0 ? "rgba(255,255,255,0.3)" : "none",
3426
- strokeWidth: sw
3427
- }
3428
- ),
3429
- /* @__PURE__ */ jsx(
3430
- SmartArtNodeText,
3431
- {
3432
- x: x + boxW / 2,
3433
- y: y + boxH / 2,
3434
- text: truncate2(node.text, 20),
3435
- fill: "white",
3436
- fontSize,
3437
- className: "pointer-events-none"
3438
- }
3439
- )
3440
- ] }, `${element.id}-altflow-${node.id}-${i}`);
3441
- })
3442
- ]
3443
- }
3444
- );
3445
- }
3446
- function renderDescendingProcess(element, nodes, palette, style) {
3447
- const w = element.width;
3448
- const h = element.height;
3449
- const pad = 8;
3450
- const gap = 4;
3451
- const usableH = h - pad * 2;
3452
- const maxW = w - pad * 2;
3453
- const itemH = (usableH - gap * (nodes.length - 1)) / nodes.length;
3454
- const shadow = styleShadow2(style);
3455
- const sw = styleStroke2(style);
3456
- return /* @__PURE__ */ jsx(
3457
- "svg",
3458
- {
3459
- className: "w-full h-full pointer-events-none",
3460
- viewBox: `0 0 ${w} ${h}`,
3461
- preserveAspectRatio: "xMidYMid meet",
3462
- style: { filter: shadow },
3463
- children: nodes.map((node, i) => {
3464
- const widthFraction = 1 - i / Math.max(nodes.length, 1) * 0.5;
3465
- const bw = maxW * widthFraction;
3466
- const x = (w - bw) / 2;
3467
- const y = pad + i * (itemH + gap);
3468
- const fontSize = Math.max(7, Math.min(11, itemH * 0.4));
3469
- return /* @__PURE__ */ jsxs("g", { children: [
3470
- i < nodes.length - 1 && /* @__PURE__ */ jsxs(Fragment, { children: [
3471
- /* @__PURE__ */ jsx(
3472
- "line",
3473
- {
3474
- x1: w / 2,
3475
- y1: y + itemH,
3476
- x2: w / 2,
3477
- y2: y + itemH + gap,
3478
- stroke: "#94a3b8",
3479
- strokeWidth: 1.5,
3480
- opacity: 0.5
3481
- }
3482
- ),
3483
- /* @__PURE__ */ jsx(
3484
- "polygon",
3485
- {
3486
- points: `${w / 2 - 3},${y + itemH + gap - 4} ${w / 2},${y + itemH + gap} ${w / 2 + 3},${y + itemH + gap - 4}`,
3487
- fill: "#94a3b8",
3488
- opacity: 0.5
3489
- }
3490
- )
3491
- ] }),
3492
- /* @__PURE__ */ jsx(
3493
- "rect",
3494
- {
3495
- x,
3496
- y,
3497
- width: bw,
3498
- height: itemH,
3499
- rx: 5,
3500
- fill: colour(i, palette),
3501
- opacity: nodeOpacity2(i, nodes.length, style),
3502
- stroke: sw > 0 ? "rgba(255,255,255,0.3)" : "none",
3503
- strokeWidth: sw
3504
- }
3505
- ),
3506
- /* @__PURE__ */ jsx(
3507
- SmartArtNodeText,
3508
- {
3509
- x: w / 2,
3510
- y: y + itemH / 2,
3511
- text: truncate2(node.text, 30),
3512
- fill: "white",
3513
- fontSize,
3514
- className: "pointer-events-none"
3515
- }
3516
- )
3517
- ] }, `${element.id}-desc-${node.id}-${i}`);
3518
- })
3519
- }
3520
- );
3521
- }
3522
- function renderPictureAccentList(element, nodes, palette, style) {
3523
- const w = element.width;
3524
- const h = element.height;
3525
- const pad = 8;
3526
- const gap = 6;
3527
- const usableH = h - pad * 2;
3528
- const usableW = w - pad * 2;
3529
- const itemH = (usableH - gap * (nodes.length - 1)) / nodes.length;
3530
- const circleR = Math.min(itemH * 0.38, 18);
3531
- const textX = pad + circleR * 2 + 12;
3532
- const textW = usableW - circleR * 2 - 16;
3533
- const shadow = styleShadow2(style);
3534
- const sw = styleStroke2(style);
3535
- return /* @__PURE__ */ jsx(
3536
- "svg",
3537
- {
3538
- className: "w-full h-full pointer-events-none",
3539
- viewBox: `0 0 ${w} ${h}`,
3540
- preserveAspectRatio: "xMidYMid meet",
3541
- style: { filter: shadow },
3542
- children: nodes.map((node, i) => {
3543
- const y = pad + i * (itemH + gap);
3544
- const cy = y + itemH / 2;
3545
- const col = colour(i, palette);
3546
- const fontSize = Math.max(7, Math.min(11, itemH * 0.35));
3547
- return /* @__PURE__ */ jsxs("g", { children: [
3548
- /* @__PURE__ */ jsx(
3549
- "circle",
3550
- {
3551
- cx: pad + circleR,
3552
- cy,
3553
- r: circleR,
3554
- fill: col,
3555
- opacity: nodeOpacity2(i, nodes.length, style)
3556
- }
3557
- ),
3558
- /* @__PURE__ */ jsx(
3559
- "text",
3560
- {
3561
- x: pad + circleR,
3562
- y: cy,
3563
- textAnchor: "middle",
3564
- dominantBaseline: "central",
3565
- fill: "white",
3566
- fontSize: Math.max(7, circleR * 0.7),
3567
- fontWeight: "bold",
3568
- className: "pointer-events-none",
3569
- children: i + 1
3570
- }
3571
- ),
3572
- /* @__PURE__ */ jsx(
3573
- "rect",
3574
- {
3575
- x: textX,
3576
- y: y + 2,
3577
- width: textW,
3578
- height: itemH - 4,
3579
- rx: 4,
3580
- fill: col,
3581
- opacity: 0.12,
3582
- stroke: col,
3583
- strokeWidth: sw > 0 ? sw : 1,
3584
- strokeOpacity: 0.3
3585
- }
3586
- ),
3587
- /* @__PURE__ */ jsx(
3588
- "text",
3589
- {
3590
- x: textX + 8,
3591
- y: cy,
3592
- textAnchor: "start",
3593
- dominantBaseline: "central",
3594
- fill: col,
3595
- fontSize,
3596
- className: "pointer-events-none",
3597
- children: truncate2(node.text, 40)
3598
- }
3599
- )
3600
- ] }, `${element.id}-picacc-${node.id}-${i}`);
3601
- })
3602
- }
3603
- );
3604
- }
3605
- function renderVerticalBlockList(element, nodes, palette, style) {
3606
- const w = element.width;
3607
- const h = element.height;
3608
- const pad = 8;
3609
- const gap = 4;
3610
- const usableH = h - pad * 2;
3611
- const usableW = w - pad * 2;
3612
- const itemH = (usableH - gap * (nodes.length - 1)) / nodes.length;
3613
- const headerW = usableW * 0.22;
3614
- const bodyW = usableW - headerW - 4;
3615
- const shadow = styleShadow2(style);
3616
- const sw = styleStroke2(style);
3617
- return /* @__PURE__ */ jsx(
3618
- "svg",
3619
- {
3620
- className: "w-full h-full pointer-events-none",
3621
- viewBox: `0 0 ${w} ${h}`,
3622
- preserveAspectRatio: "xMidYMid meet",
3623
- style: { filter: shadow },
3624
- children: nodes.map((node, i) => {
3625
- const y = pad + i * (itemH + gap);
3626
- const col = colour(i, palette);
3627
- const fontSize = Math.max(7, Math.min(11, itemH * 0.35));
3628
- return /* @__PURE__ */ jsxs("g", { children: [
3629
- /* @__PURE__ */ jsx(
3630
- "rect",
3631
- {
3632
- x: pad,
3633
- y,
3634
- width: headerW,
3635
- height: itemH,
3636
- rx: 3,
3637
- fill: col,
3638
- opacity: nodeOpacity2(i, nodes.length, style),
3639
- stroke: sw > 0 ? "rgba(255,255,255,0.3)" : "none",
3640
- strokeWidth: sw
3641
- }
3642
- ),
3643
- /* @__PURE__ */ jsx(
3644
- "text",
3645
- {
3646
- x: pad + headerW / 2,
3647
- y: y + itemH / 2,
3648
- textAnchor: "middle",
3649
- dominantBaseline: "central",
3650
- fill: "white",
3651
- fontSize: Math.max(8, itemH * 0.4),
3652
- fontWeight: "bold",
3653
- className: "pointer-events-none",
3654
- children: i + 1
3655
- }
3656
- ),
3657
- /* @__PURE__ */ jsx(
3658
- "rect",
3659
- {
3660
- x: pad + headerW + 4,
3661
- y,
3662
- width: bodyW,
3663
- height: itemH,
3664
- rx: 3,
3665
- fill: col,
3666
- opacity: 0.1,
3667
- stroke: col,
3668
- strokeWidth: 1,
3669
- strokeOpacity: 0.3
3670
- }
3671
- ),
3672
- /* @__PURE__ */ jsx(
3673
- "text",
3674
- {
3675
- x: pad + headerW + 12,
3676
- y: y + itemH / 2,
3677
- textAnchor: "start",
3678
- dominantBaseline: "central",
3679
- fill: col,
3680
- fontSize,
3681
- className: "pointer-events-none",
3682
- children: truncate2(node.text, 40)
3683
- }
3684
- )
3685
- ] }, `${element.id}-vblk-${node.id}-${i}`);
3686
- })
3687
- }
3688
- );
3689
- }
3690
- function renderGroupedList(element, nodes, palette, style) {
3691
- const w = element.width;
3692
- const h = element.height;
3693
- const pad = 8;
3694
- const gap = 8;
3695
- const shadow = styleShadow2(style);
3696
- const sw = styleStroke2(style);
3697
- const groupSize = nodes.length <= 4 ? 2 : 3;
3698
- const groups = [];
3699
- for (let i = 0; i < nodes.length; i += groupSize) {
3700
- groups.push(nodes.slice(i, i + groupSize));
3701
- }
3702
- const usableW = w - pad * 2;
3703
- const groupW = (usableW - gap * (groups.length - 1)) / groups.length;
3704
- const usableH = h - pad * 2;
3705
- const headerH = usableH * 0.18;
3706
- return /* @__PURE__ */ jsx(
3707
- "svg",
3708
- {
3709
- className: "w-full h-full pointer-events-none",
3710
- viewBox: `0 0 ${w} ${h}`,
3711
- preserveAspectRatio: "xMidYMid meet",
3712
- style: { filter: shadow },
3713
- children: groups.map((group, gi) => {
3714
- const gx = pad + gi * (groupW + gap);
3715
- const col = colour(gi, palette);
3716
- const subItemGap = 3;
3717
- const subItemH = (usableH - headerH - 4 - subItemGap * (group.length - 1)) / group.length;
3718
- return /* @__PURE__ */ jsxs("g", { children: [
3719
- /* @__PURE__ */ jsx(
3720
- "rect",
3721
- {
3722
- x: gx,
3723
- y: pad,
3724
- width: groupW,
3725
- height: headerH,
3726
- rx: 4,
3727
- fill: col,
3728
- opacity: nodeOpacity2(gi, groups.length, style),
3729
- stroke: sw > 0 ? "rgba(255,255,255,0.3)" : "none",
3730
- strokeWidth: sw
3731
- }
3732
- ),
3733
- /* @__PURE__ */ jsx(
3734
- "text",
3735
- {
3736
- x: gx + groupW / 2,
3737
- y: pad + headerH / 2,
3738
- textAnchor: "middle",
3739
- dominantBaseline: "central",
3740
- fill: "white",
3741
- fontSize: Math.max(7, Math.min(10, groupW * 0.08)),
3742
- fontWeight: "bold",
3743
- className: "pointer-events-none",
3744
- children: `Group ${gi + 1}`
3745
- }
3746
- ),
3747
- group.map((node, si) => {
3748
- const sy = pad + headerH + 4 + si * (subItemH + subItemGap);
3749
- const fontSize = Math.max(7, Math.min(10, subItemH * 0.35));
3750
- return /* @__PURE__ */ jsxs("g", { children: [
3751
- /* @__PURE__ */ jsx(
3752
- "rect",
3753
- {
3754
- x: gx + 4,
3755
- y: sy,
3756
- width: groupW - 8,
3757
- height: subItemH,
3758
- rx: 3,
3759
- fill: col,
3760
- opacity: 0.15,
3761
- stroke: col,
3762
- strokeWidth: 1,
3763
- strokeOpacity: 0.3
3764
- }
3765
- ),
3766
- /* @__PURE__ */ jsx(
3767
- SmartArtNodeText,
3768
- {
3769
- x: gx + groupW / 2,
3770
- y: sy + subItemH / 2,
3771
- text: truncate2(node.text, 20),
3772
- fill: col,
3773
- fontSize,
3774
- className: "pointer-events-none"
3775
- }
3776
- )
3777
- ] }, `${element.id}-grp-${gi}-item-${node.id}-${si}`);
3778
- })
3779
- ] }, `${element.id}-grp-${gi}`);
3780
- })
3781
- }
3782
- );
3783
- }
3784
- function renderPyramidList(element, nodes, palette, style) {
3785
- const w = element.width;
3786
- const h = element.height;
3787
- const pad = 8;
3788
- const gap = 4;
3789
- const usableH = h - pad * 2;
3790
- const pyramidW = w * 0.35;
3791
- const labelStartX = pyramidW + pad + 16;
3792
- const labelW = w - labelStartX - pad;
3793
- const bandH = (usableH - gap * (nodes.length - 1)) / nodes.length;
3794
- const shadow = styleShadow2(style);
3795
- return /* @__PURE__ */ jsx(
3796
- "svg",
3797
- {
3798
- className: "w-full h-full pointer-events-none",
3799
- viewBox: `0 0 ${w} ${h}`,
3800
- preserveAspectRatio: "xMidYMid meet",
3801
- style: { filter: shadow },
3802
- children: nodes.map((node, i) => {
3803
- const y = pad + i * (bandH + gap);
3804
- const col = colour(i, palette);
3805
- const topFrac = 0.3 + i / Math.max(nodes.length - 1, 1) * 0.7;
3806
- const segW = pyramidW * topFrac;
3807
- const segX = pad + (pyramidW - segW) / 2;
3808
- const fontSize = Math.max(7, Math.min(11, bandH * 0.35));
3809
- return /* @__PURE__ */ jsxs("g", { children: [
3810
- /* @__PURE__ */ jsx(
3811
- "rect",
3812
- {
3813
- x: segX,
3814
- y,
3815
- width: segW,
3816
- height: bandH,
3817
- rx: 2,
3818
- fill: col,
3819
- opacity: nodeOpacity2(i, nodes.length, style)
3820
- }
3821
- ),
3822
- /* @__PURE__ */ jsx(
3823
- "line",
3824
- {
3825
- x1: segX + segW,
3826
- y1: y + bandH / 2,
3827
- x2: labelStartX - 4,
3828
- y2: y + bandH / 2,
3829
- stroke: col,
3830
- strokeWidth: 1,
3831
- opacity: 0.5,
3832
- strokeDasharray: "3,2"
3833
- }
3834
- ),
3835
- /* @__PURE__ */ jsx(
3836
- "rect",
3837
- {
3838
- x: labelStartX,
3839
- y: y + 2,
3840
- width: labelW,
3841
- height: bandH - 4,
3842
- rx: 3,
3843
- fill: col,
3844
- opacity: 0.1,
3845
- stroke: col,
3846
- strokeWidth: 1,
3847
- strokeOpacity: 0.25
3848
- }
3849
- ),
3850
- /* @__PURE__ */ jsx(
3851
- "text",
3852
- {
3853
- x: labelStartX + 8,
3854
- y: y + bandH / 2,
3855
- textAnchor: "start",
3856
- dominantBaseline: "central",
3857
- fill: col,
3858
- fontSize,
3859
- className: "pointer-events-none",
3860
- children: truncate2(node.text, 30)
3861
- }
3862
- )
3863
- ] }, `${element.id}-pyrlist-${node.id}-${i}`);
3864
- })
3865
- }
3866
- );
3867
- }
3868
- function renderHorizontalPictureList(element, nodes, palette, style) {
3869
- const w = element.width;
3870
- const h = element.height;
3871
- const pad = 8;
3872
- const gap = 8;
3873
- const usableW = w - pad * 2;
3874
- const colW = (usableW - gap * (nodes.length - 1)) / nodes.length;
3875
- const usableH = h - pad * 2;
3876
- const circleR = Math.min(colW * 0.38, usableH * 0.28);
3877
- const shadow = styleShadow2(style);
3878
- const sw = styleStroke2(style);
3879
- return /* @__PURE__ */ jsx(
3880
- "svg",
3881
- {
3882
- className: "w-full h-full pointer-events-none",
3883
- viewBox: `0 0 ${w} ${h}`,
3884
- preserveAspectRatio: "xMidYMid meet",
3885
- style: { filter: shadow },
3886
- children: nodes.map((node, i) => {
3887
- const cx = pad + i * (colW + gap) + colW / 2;
3888
- const cy = pad + circleR + 4;
3889
- const col = colour(i, palette);
3890
- const labelY = cy + circleR + 10;
3891
- const fontSize = Math.max(7, Math.min(10, colW * 0.1));
3892
- return /* @__PURE__ */ jsxs("g", { children: [
3893
- /* @__PURE__ */ jsx(
3894
- "circle",
3895
- {
3896
- cx,
3897
- cy,
3898
- r: circleR,
3899
- fill: col,
3900
- opacity: nodeOpacity2(i, nodes.length, style),
3901
- stroke: sw > 0 ? "rgba(255,255,255,0.3)" : "none",
3902
- strokeWidth: sw
3903
- }
3904
- ),
3905
- /* @__PURE__ */ jsx(
3906
- "text",
3907
- {
3908
- x: cx,
3909
- y: cy,
3910
- textAnchor: "middle",
3911
- dominantBaseline: "central",
3912
- fill: "white",
3913
- fontSize: Math.max(8, circleR * 0.5),
3914
- fontWeight: "bold",
3915
- className: "pointer-events-none",
3916
- children: i + 1
3917
- }
3918
- ),
3919
- /* @__PURE__ */ jsx(
3920
- "text",
3921
- {
3922
- x: cx,
3923
- y: labelY,
3924
- textAnchor: "middle",
3925
- dominantBaseline: "hanging",
3926
- fill: col,
3927
- fontSize,
3928
- className: "pointer-events-none",
3929
- children: truncate2(node.text, 15)
3930
- }
3931
- )
3932
- ] }, `${element.id}-hpic-${node.id}-${i}`);
3933
- })
3934
- }
3935
- );
3936
- }
3937
- function renderAccentProcess(element, nodes, palette, style) {
3938
- const w = element.width;
3939
- const h = element.height;
3940
- const pad = 8;
3941
- const arrowGap = 16;
3942
- const usableW = w - pad * 2;
3943
- const nodeW = (usableW - arrowGap * (nodes.length - 1)) / nodes.length;
3944
- const nodeH = h * 0.45;
3945
- const yMid = h / 2;
3946
- const circleR = Math.min(nodeW, nodeH) * 0.55;
3947
- const shadow = styleShadow2(style);
3948
- const sw = styleStroke2(style);
3949
- return /* @__PURE__ */ jsx(
3950
- "svg",
3951
- {
3952
- className: "w-full h-full pointer-events-none",
3953
- viewBox: `0 0 ${w} ${h}`,
3954
- preserveAspectRatio: "xMidYMid meet",
3955
- style: { filter: shadow },
3956
- children: nodes.map((node, i) => {
3957
- const x = pad + i * (nodeW + arrowGap);
3958
- const cx = x + nodeW / 2;
3959
- const col = colour(i, palette);
3960
- const fontSize = Math.max(7, Math.min(11, nodeW * 0.1));
3961
- return /* @__PURE__ */ jsxs("g", { children: [
3962
- /* @__PURE__ */ jsx("circle", { cx, cy: yMid, r: circleR, fill: col, opacity: 0.15 }),
3963
- /* @__PURE__ */ jsx(
3964
- "rect",
3965
- {
3966
- x,
3967
- y: yMid - nodeH / 2,
3968
- width: nodeW,
3969
- height: nodeH,
3970
- rx: 5,
3971
- fill: col,
3972
- opacity: nodeOpacity2(i, nodes.length, style),
3973
- stroke: sw > 0 ? "rgba(255,255,255,0.3)" : "none",
3974
- strokeWidth: sw
3975
- }
3976
- ),
3977
- /* @__PURE__ */ jsx(
3978
- SmartArtNodeText,
3979
- {
3980
- x: cx,
3981
- y: yMid,
3982
- text: truncate2(node.text, 20),
3983
- fill: "white",
3984
- fontSize,
3985
- className: "pointer-events-none"
3986
- }
3987
- ),
3988
- i < nodes.length - 1 && /* @__PURE__ */ jsxs(Fragment, { children: [
3989
- /* @__PURE__ */ jsx(
3990
- "line",
3991
- {
3992
- x1: x + nodeW + 2,
3993
- y1: yMid,
3994
- x2: x + nodeW + arrowGap - 2,
3995
- y2: yMid,
3996
- stroke: "#94a3b8",
3997
- strokeWidth: 1.5,
3998
- opacity: 0.5
3999
- }
4000
- ),
4001
- /* @__PURE__ */ jsx(
4002
- "polygon",
4003
- {
4004
- points: `${x + nodeW + arrowGap - 6},${yMid - 3} ${x + nodeW + arrowGap - 2},${yMid} ${x + nodeW + arrowGap - 6},${yMid + 3}`,
4005
- fill: "#94a3b8",
4006
- opacity: 0.5
4007
- }
4008
- )
4009
- ] })
4010
- ] }, `${element.id}-accproc-${node.id}-${i}`);
4011
- })
4012
- }
4013
- );
4014
- }
4015
- function renderVerticalChevronList(element, nodes, palette, style) {
4016
- const w = element.width;
4017
- const h = element.height;
4018
- const pad = 8;
4019
- const gap = 2;
4020
- const usableW = w - pad * 2;
4021
- const usableH = h - pad * 2;
4022
- const itemH = (usableH - gap * (nodes.length - 1)) / nodes.length;
4023
- const chevDepth = Math.min(12, itemH * 0.3);
4024
- const shadow = styleShadow2(style);
4025
- const sw = styleStroke2(style);
4026
- return /* @__PURE__ */ jsx(
4027
- "svg",
4028
- {
4029
- className: "w-full h-full pointer-events-none",
4030
- viewBox: `0 0 ${w} ${h}`,
4031
- preserveAspectRatio: "xMidYMid meet",
4032
- style: { filter: shadow },
4033
- children: nodes.map((node, i) => {
4034
- const x = pad;
4035
- const y = pad + i * (itemH + gap);
4036
- const col = colour(i, palette);
4037
- const fontSize = Math.max(7, Math.min(11, itemH * 0.4));
4038
- const isFirst = i === 0;
4039
- const isLast = i === nodes.length - 1;
4040
- const points = isFirst ? [
4041
- `${x},${y}`,
4042
- `${x + usableW},${y}`,
4043
- `${x + usableW},${y + itemH - chevDepth}`,
4044
- `${x + usableW / 2},${y + itemH}`,
4045
- `${x},${y + itemH - chevDepth}`
4046
- ].join(" ") : isLast ? [
4047
- `${x},${y + chevDepth}`,
4048
- `${x + usableW / 2},${y}`,
4049
- `${x + usableW},${y + chevDepth}`,
4050
- `${x + usableW},${y + itemH}`,
4051
- `${x},${y + itemH}`
4052
- ].join(" ") : [
4053
- `${x},${y + chevDepth}`,
4054
- `${x + usableW / 2},${y}`,
4055
- `${x + usableW},${y + chevDepth}`,
4056
- `${x + usableW},${y + itemH - chevDepth}`,
4057
- `${x + usableW / 2},${y + itemH}`,
4058
- `${x},${y + itemH - chevDepth}`
4059
- ].join(" ");
4060
- return /* @__PURE__ */ jsxs("g", { children: [
4061
- /* @__PURE__ */ jsx(
4062
- "polygon",
4063
- {
4064
- points,
4065
- fill: col,
4066
- opacity: nodeOpacity2(i, nodes.length, style),
4067
- stroke: sw > 0 ? "rgba(255,255,255,0.3)" : "none",
4068
- strokeWidth: sw
4069
- }
4070
- ),
4071
- /* @__PURE__ */ jsx(
4072
- SmartArtNodeText,
4073
- {
4074
- x: x + usableW / 2,
4075
- y: y + itemH / 2,
4076
- text: truncate2(node.text, 30),
4077
- fill: "white",
4078
- fontSize,
4079
- className: "pointer-events-none"
4080
- }
4081
- )
4082
- ] }, `${element.id}-vchev-${node.id}-${i}`);
4083
- })
4084
- }
4085
- );
4086
- }
4087
3252
  function shapeBody(shape) {
4088
3253
  switch (shape.kind) {
4089
3254
  case "image":
@@ -4183,1056 +3348,126 @@ function DrawingShapeRenderer({
4183
3348
  }
4184
3349
  );
4185
3350
  }
4186
-
4187
- // src/viewer/components/elements/smartart-node-style.tsx
4188
- function resolveNodeStyle(node, index, palette) {
4189
- const style = node.style;
4190
- return {
4191
- fill: style?.fillColor ?? colour(index, palette),
4192
- fontColor: style?.fontColor ?? "white",
4193
- fontWeight: style?.bold ? 700 : void 0,
4194
- fontStyle: style?.italic ? "italic" : void 0,
4195
- strokeColor: style?.lineColor
4196
- };
4197
- }
4198
- function ListRenderer({
4199
- element,
4200
- nodes,
4201
- palette,
4202
- style,
4203
- nodeLabels
4204
- }) {
4205
- const w = element.width;
4206
- const h = element.height;
4207
- const pad = 8;
4208
- const gap = 4;
4209
- const usableH = h - pad * 2;
4210
- const itemH = (usableH - gap * (nodes.length - 1)) / nodes.length;
4211
- const itemW = w - pad * 2;
4212
- const rx = Math.min(6, itemH * 0.15);
4213
- const shadow = styleShadow2(style);
4214
- const sw = styleStroke2(style);
4215
- return /* @__PURE__ */ jsx(
4216
- "svg",
4217
- {
4218
- className: "w-full h-full pointer-events-none",
4219
- viewBox: `0 0 ${w} ${h}`,
4220
- preserveAspectRatio: "xMidYMid meet",
4221
- "data-testid": "smartart-list",
4222
- children: nodes.map((node, i) => {
4223
- const y = pad + i * (itemH + gap);
4224
- const fontSize = fitFontSize(node.text, itemW * 0.9, itemH, 12);
4225
- const ns = resolveNodeStyle(node, i, palette);
4226
- const label = nodeLabels?.get(node.id);
4227
- return /* @__PURE__ */ jsxs(
4228
- "g",
4229
- {
4230
- ...smartArtNodeGroupProps(node.id, shadow, label),
4231
- children: [
4232
- label ? /* @__PURE__ */ jsx("title", { children: label }) : null,
4233
- /* @__PURE__ */ jsx(
4234
- "rect",
4235
- {
4236
- x: pad,
4237
- y,
4238
- width: itemW,
4239
- height: itemH,
4240
- rx,
4241
- fill: ns.fill,
4242
- opacity: nodeOpacity2(i, nodes.length, style),
4243
- stroke: ns.strokeColor ?? (sw > 0 ? "rgba(255,255,255,0.3)" : "none"),
4244
- strokeWidth: sw
4245
- }
4246
- ),
4247
- /* @__PURE__ */ jsx(
4248
- SmartArtNodeText,
4249
- {
4250
- x: pad + itemW / 2,
4251
- y: y + itemH / 2,
4252
- text: truncate2(node.text, 40),
4253
- fill: ns.fontColor,
4254
- fontWeight: ns.fontWeight,
4255
- fontStyle: ns.fontStyle,
4256
- fontSize,
4257
- className: "pointer-events-none"
4258
- }
4259
- )
4260
- ]
4261
- },
4262
- `${element.id}-list-${node.id}-${i}`
4263
- );
4264
- })
4265
- }
4266
- );
4267
- }
4268
- function ProcessRenderer({
4269
- element,
4270
- nodes,
4271
- palette,
4272
- style,
4273
- nodeLabels
4274
- }) {
4275
- const w = element.width;
4276
- const h = element.height;
4277
- const pad = 8;
4278
- const gap = 4;
4279
- const chevronDepth = Math.min(16, w * 0.04);
4280
- const usableW = w - pad * 2;
4281
- const itemW = (usableW - gap * (nodes.length - 1)) / nodes.length;
4282
- const itemH = Math.min(h - pad * 2, h * 0.6);
4283
- const yMid = h / 2;
4284
- const shadow = styleShadow2(style);
4285
- const sw = styleStroke2(style);
4286
- return /* @__PURE__ */ jsx(
4287
- "svg",
4288
- {
4289
- className: "w-full h-full pointer-events-none",
4290
- viewBox: `0 0 ${w} ${h}`,
4291
- preserveAspectRatio: "xMidYMid meet",
4292
- "data-testid": "smartart-process",
4293
- children: nodes.map((node, i) => {
4294
- const x = pad + i * (itemW + gap);
4295
- const halfH = itemH / 2;
4296
- const isFirst = i === 0;
4297
- const isLast = i === nodes.length - 1;
4298
- const points = isFirst ? `${x},${yMid - halfH} ${x + itemW - chevronDepth},${yMid - halfH} ${x + itemW},${yMid} ${x + itemW - chevronDepth},${yMid + halfH} ${x},${yMid + halfH}` : isLast ? `${x},${yMid - halfH} ${x + itemW},${yMid - halfH} ${x + itemW},${yMid + halfH} ${x},${yMid + halfH} ${x + chevronDepth},${yMid}` : `${x},${yMid - halfH} ${x + itemW - chevronDepth},${yMid - halfH} ${x + itemW},${yMid} ${x + itemW - chevronDepth},${yMid + halfH} ${x},${yMid + halfH} ${x + chevronDepth},${yMid}`;
4299
- const fontSize = fitFontSize(node.text, itemW * 0.7, itemH, 12);
4300
- const ns = resolveNodeStyle(node, i, palette);
4301
- const label = nodeLabels?.get(node.id);
4302
- return /* @__PURE__ */ jsxs(
4303
- "g",
4304
- {
4305
- ...smartArtNodeGroupProps(node.id, shadow, label),
4306
- children: [
4307
- label ? /* @__PURE__ */ jsx("title", { children: label }) : null,
4308
- /* @__PURE__ */ jsx(
4309
- "polygon",
4310
- {
4311
- points,
4312
- fill: ns.fill,
4313
- opacity: nodeOpacity2(i, nodes.length, style),
4314
- stroke: ns.strokeColor ?? (sw > 0 ? "rgba(255,255,255,0.3)" : "none"),
4315
- strokeWidth: sw
4316
- }
4317
- ),
4318
- /* @__PURE__ */ jsx(
4319
- SmartArtNodeText,
4320
- {
4321
- x: x + itemW / 2,
4322
- y: yMid,
4323
- text: truncate2(node.text, 25),
4324
- fill: ns.fontColor,
4325
- fontWeight: ns.fontWeight,
4326
- fontStyle: ns.fontStyle,
4327
- fontSize,
4328
- className: "pointer-events-none"
4329
- }
4330
- )
4331
- ]
4332
- },
4333
- `${element.id}-process-${node.id}-${i}`
4334
- );
4335
- })
4336
- }
4337
- );
4338
- }
4339
- function CycleRenderer({
4340
- element,
4341
- nodes,
4342
- palette,
4343
- style,
4344
- nodeLabels
4345
- }) {
4346
- const w = element.width;
4347
- const h = element.height;
4348
- const size = Math.min(w, h);
4349
- const cx = w / 2;
4350
- const cy = h / 2;
4351
- const radius = size * 0.35;
4352
- const nodeR = Math.max(size * 0.06, Math.min(size * 0.12, 200 / nodes.length));
4353
- const shadow = styleShadow2(style);
4354
- const sw = styleStroke2(style);
4355
- return /* @__PURE__ */ jsxs(
4356
- "svg",
4357
- {
4358
- className: "w-full h-full pointer-events-none",
4359
- viewBox: `0 0 ${w} ${h}`,
4360
- preserveAspectRatio: "xMidYMid meet",
4361
- "data-testid": "smartart-cycle",
4362
- children: [
4363
- nodes.map((_node, i) => {
4364
- const angle = i / nodes.length * Math.PI * 2 - Math.PI / 2;
4365
- const nx = cx + radius * Math.cos(angle);
4366
- const ny = cy + radius * Math.sin(angle);
4367
- const nextI = (i + 1) % nodes.length;
4368
- const nextAngle = nextI / nodes.length * Math.PI * 2 - Math.PI / 2;
4369
- const nextX = cx + radius * Math.cos(nextAngle);
4370
- const nextY = cy + radius * Math.sin(nextAngle);
4371
- const midAngle = (angle + nextAngle) / 2;
4372
- const adjustedMidAngle = i === nodes.length - 1 ? (angle + nextAngle + Math.PI * 2) / 2 : midAngle;
4373
- const arcBulge = radius * 0.15;
4374
- const controlX = cx + (radius + arcBulge) * Math.cos(adjustedMidAngle);
4375
- const controlY = cy + (radius + arcBulge) * Math.sin(adjustedMidAngle);
4376
- return /* @__PURE__ */ jsx(
4377
- "path",
4378
- {
4379
- d: `M${nx},${ny} Q${controlX},${controlY} ${nextX},${nextY}`,
4380
- fill: "none",
4381
- stroke: "#94a3b8",
4382
- strokeWidth: 1.5,
4383
- opacity: 0.5,
4384
- markerEnd: void 0
4385
- },
4386
- `${element.id}-cycle-conn-${i}`
4387
- );
4388
- }),
4389
- nodes.map((node, i) => {
4390
- const angle = i / nodes.length * Math.PI * 2 - Math.PI / 2;
4391
- const nx = cx + radius * Math.cos(angle);
4392
- const ny = cy + radius * Math.sin(angle);
4393
- const fontSize = fitFontSize(node.text, nodeR * 1.4, nodeR * 2, 11);
4394
- const ns = resolveNodeStyle(node, i, palette);
4395
- const label = nodeLabels?.get(node.id);
4396
- return /* @__PURE__ */ jsxs(
4397
- "g",
4398
- {
4399
- ...smartArtNodeGroupProps(node.id, shadow, label),
4400
- children: [
4401
- label ? /* @__PURE__ */ jsx("title", { children: label }) : null,
4402
- /* @__PURE__ */ jsx(
4403
- "circle",
4404
- {
4405
- cx: nx,
4406
- cy: ny,
4407
- r: nodeR,
4408
- fill: ns.fill,
4409
- opacity: nodeOpacity2(i, nodes.length, style),
4410
- stroke: ns.strokeColor ?? (sw > 0 ? "rgba(255,255,255,0.3)" : "none"),
4411
- strokeWidth: sw
4412
- }
4413
- ),
4414
- /* @__PURE__ */ jsx(
4415
- SmartArtNodeText,
4416
- {
4417
- x: nx,
4418
- y: ny,
4419
- text: truncate2(node.text, 20),
4420
- fill: ns.fontColor,
4421
- fontWeight: ns.fontWeight,
4422
- fontStyle: ns.fontStyle,
4423
- fontSize,
4424
- className: "pointer-events-none"
4425
- }
4426
- )
4427
- ]
4428
- },
4429
- `${element.id}-cycle-${node.id}-${i}`
4430
- );
4431
- })
4432
- ]
4433
- }
4434
- );
4435
- }
4436
- function MatrixRenderer({
4437
- element,
4438
- nodes,
4439
- palette,
4440
- style,
4441
- nodeLabels
4442
- }) {
4443
- const w = element.width;
4444
- const h = element.height;
4445
- const cols = Math.ceil(Math.sqrt(nodes.length));
4446
- const rows = Math.ceil(nodes.length / cols);
4447
- const pad = 8;
4448
- const gap = 6;
4449
- const usableW = w - pad * 2;
4450
- const usableH = h - pad * 2;
4451
- const cellW = (usableW - gap * (cols - 1)) / cols;
4452
- const cellH = (usableH - gap * (rows - 1)) / rows;
4453
- const rx = Math.min(6, Math.min(cellW, cellH) * 0.1);
4454
- const shadow = styleShadow2(style);
4455
- const sw = styleStroke2(style);
4456
- return /* @__PURE__ */ jsx(
4457
- "svg",
4458
- {
4459
- className: "w-full h-full pointer-events-none",
4460
- viewBox: `0 0 ${w} ${h}`,
4461
- preserveAspectRatio: "xMidYMid meet",
4462
- "data-testid": "smartart-matrix",
4463
- children: nodes.map((node, i) => {
4464
- const col = i % cols;
4465
- const row = Math.floor(i / cols);
4466
- const x = pad + col * (cellW + gap);
4467
- const y = pad + row * (cellH + gap);
4468
- const fontSize = fitFontSize(node.text, cellW * 0.85, cellH, 12);
4469
- const ns = resolveNodeStyle(node, i, palette);
4470
- const label = nodeLabels?.get(node.id);
4471
- return /* @__PURE__ */ jsxs(
4472
- "g",
4473
- {
4474
- ...smartArtNodeGroupProps(node.id, shadow, label),
4475
- children: [
4476
- label ? /* @__PURE__ */ jsx("title", { children: label }) : null,
4477
- /* @__PURE__ */ jsx(
4478
- "rect",
4479
- {
4480
- x,
4481
- y,
4482
- width: cellW,
4483
- height: cellH,
4484
- rx,
4485
- fill: ns.fill,
4486
- opacity: nodeOpacity2(i, nodes.length, style),
4487
- stroke: ns.strokeColor ?? (sw > 0 ? "rgba(255,255,255,0.3)" : "none"),
4488
- strokeWidth: sw
4489
- }
4490
- ),
4491
- /* @__PURE__ */ jsx(
4492
- SmartArtNodeText,
4493
- {
4494
- x: x + cellW / 2,
4495
- y: y + cellH / 2,
4496
- text: truncate2(node.text, 30),
4497
- fill: ns.fontColor,
4498
- fontWeight: ns.fontWeight ?? 500,
4499
- fontStyle: ns.fontStyle,
4500
- fontSize,
4501
- className: "pointer-events-none"
4502
- }
4503
- )
4504
- ]
4505
- },
4506
- `${element.id}-matrix-${node.id}-${i}`
4507
- );
4508
- })
4509
- }
4510
- );
4511
- }
4512
- function PyramidRenderer({
4513
- element,
4514
- nodes,
4515
- palette,
4516
- style
4517
- }) {
4518
- const w = element.width;
4519
- const h = element.height;
4520
- const pad = 8;
4521
- const gap = 3;
4522
- const usableH = h - pad * 2;
4523
- const bandH = (usableH - gap * (nodes.length - 1)) / nodes.length;
4524
- const maxW = w - pad * 2;
4525
- const shadow = styleShadow2(style);
4526
- const sw = styleStroke2(style);
3351
+ var CONNECTOR_STROKE = "#94a3b8";
3352
+ var CONNECTOR_WIDTH = 1.5;
3353
+ var CONNECTOR_OPACITY = 0.5;
3354
+ var DEFAULT_LABEL_COLOR = "white";
3355
+ function ConnectorPath({ connector }) {
4527
3356
  return /* @__PURE__ */ jsx(
4528
- "svg",
3357
+ "path",
4529
3358
  {
4530
- className: "w-full h-full pointer-events-none",
4531
- viewBox: `0 0 ${w} ${h}`,
4532
- preserveAspectRatio: "xMidYMid meet",
4533
- "data-testid": "smartart-pyramid",
4534
- children: nodes.map((node, i) => {
4535
- const topWidthFrac = 0.3 + i / Math.max(nodes.length - 1, 1) * 0.7;
4536
- const bottomWidthFrac = i < nodes.length - 1 ? 0.3 + (i + 1) / Math.max(nodes.length - 1, 1) * 0.7 : 1;
4537
- const topW = maxW * topWidthFrac;
4538
- const bottomW = maxW * bottomWidthFrac;
4539
- const y = pad + i * (bandH + gap);
4540
- const topLeft = (w - topW) / 2;
4541
- const topRight = topLeft + topW;
4542
- const bottomLeft = (w - bottomW) / 2;
4543
- const bottomRight = bottomLeft + bottomW;
4544
- const points = [
4545
- `${topLeft},${y}`,
4546
- `${topRight},${y}`,
4547
- `${bottomRight},${y + bandH}`,
4548
- `${bottomLeft},${y + bandH}`
4549
- ].join(" ");
4550
- const fontSize = fitFontSize(node.text, topW * 0.85, bandH, 12);
4551
- return /* @__PURE__ */ jsxs(
4552
- "g",
4553
- {
4554
- ...smartArtNodeGroupProps(node.id, shadow),
4555
- children: [
4556
- /* @__PURE__ */ jsx(
4557
- "polygon",
4558
- {
4559
- points,
4560
- fill: colour(i, palette),
4561
- opacity: nodeOpacity2(i, nodes.length, style),
4562
- stroke: sw > 0 ? "rgba(255,255,255,0.3)" : "none",
4563
- strokeWidth: sw
4564
- }
4565
- ),
4566
- /* @__PURE__ */ jsx(
4567
- SmartArtNodeText,
4568
- {
4569
- x: w / 2,
4570
- y: y + bandH / 2,
4571
- text: truncate2(node.text, 30),
4572
- fill: "white",
4573
- fontSize,
4574
- className: "pointer-events-none"
4575
- }
4576
- )
4577
- ]
4578
- },
4579
- `${element.id}-pyramid-${node.id}-${i}`
4580
- );
4581
- })
3359
+ d: connector.d,
3360
+ fill: "none",
3361
+ stroke: connector.stroke ?? CONNECTOR_STROKE,
3362
+ strokeWidth: connector.strokeWidth ?? CONNECTOR_WIDTH,
3363
+ opacity: connector.opacity ?? CONNECTOR_OPACITY,
3364
+ strokeDasharray: connector.dash
4582
3365
  }
4583
3366
  );
4584
3367
  }
4585
- function VennRenderer({
4586
- element,
4587
- nodes,
4588
- palette,
4589
- style
4590
- }) {
4591
- const w = element.width;
4592
- const h = element.height;
4593
- const shadow = styleShadow2(style);
4594
- if (nodes.length <= 4) {
4595
- const cx = w / 2;
4596
- const cy2 = h / 2;
4597
- const r2 = Math.min(w, h) * 0.28;
4598
- const spread = r2 * 0.55;
3368
+ function NodeShape({ node }) {
3369
+ if (node.kind === "circle") {
4599
3370
  return /* @__PURE__ */ jsx(
4600
- "svg",
3371
+ "circle",
4601
3372
  {
4602
- className: "w-full h-full pointer-events-none",
4603
- viewBox: `0 0 ${w} ${h}`,
4604
- preserveAspectRatio: "xMidYMid meet",
4605
- "data-testid": "smartart-venn",
4606
- children: nodes.map((node, i) => {
4607
- const angle = i / nodes.length * Math.PI * 2 - Math.PI / 2;
4608
- const nx = cx + spread * Math.cos(angle);
4609
- const ny = cy2 + spread * Math.sin(angle);
4610
- const fontSize = fitFontSize(node.text, r2 * 1.2, r2 * 2, 11);
4611
- return /* @__PURE__ */ jsxs(
4612
- "g",
4613
- {
4614
- ...smartArtNodeGroupProps(node.id, shadow),
4615
- children: [
4616
- /* @__PURE__ */ jsx("circle", { cx: nx, cy: ny, r: r2, fill: colour(i, palette), opacity: 0.35 }),
4617
- /* @__PURE__ */ jsx(
4618
- SmartArtNodeText,
4619
- {
4620
- x: nx,
4621
- y: ny,
4622
- text: truncate2(node.text, 20),
4623
- fill: "white",
4624
- fontSize,
4625
- fontWeight: "bold",
4626
- className: "pointer-events-none"
4627
- }
4628
- )
4629
- ]
4630
- },
4631
- `${element.id}-venn-${node.id}-${i}`
4632
- );
4633
- })
3373
+ cx: node.cx,
3374
+ cy: node.cy,
3375
+ r: node.r,
3376
+ fill: node.fill,
3377
+ stroke: node.stroke,
3378
+ strokeWidth: node.strokeWidth,
3379
+ opacity: node.opacity
4634
3380
  }
4635
3381
  );
4636
3382
  }
4637
- const r = Math.min(h * 0.38, w / (nodes.length * 0.9));
4638
- const overlap = r * 0.5;
4639
- const totalW = nodes.length * (r * 2 - overlap) + overlap;
4640
- const offsetX = (w - totalW) / 2 + r;
4641
- const cy = h / 2;
4642
- return /* @__PURE__ */ jsx(
4643
- "svg",
4644
- {
4645
- className: "w-full h-full pointer-events-none",
4646
- viewBox: `0 0 ${w} ${h}`,
4647
- preserveAspectRatio: "xMidYMid meet",
4648
- "data-testid": "smartart-venn",
4649
- children: nodes.map((node, i) => {
4650
- const nx = offsetX + i * (r * 2 - overlap);
4651
- const fontSize = fitFontSize(node.text, r * 1.2, r * 2, 10);
4652
- return /* @__PURE__ */ jsxs(
4653
- "g",
4654
- {
4655
- ...smartArtNodeGroupProps(node.id, shadow),
4656
- children: [
4657
- /* @__PURE__ */ jsx("circle", { cx: nx, cy, r, fill: colour(i, palette), opacity: 0.35 }),
4658
- /* @__PURE__ */ jsx(
4659
- SmartArtNodeText,
4660
- {
4661
- x: nx,
4662
- y: cy,
4663
- text: truncate2(node.text, 20),
4664
- fill: "white",
4665
- fontSize,
4666
- fontWeight: "bold",
4667
- className: "pointer-events-none"
4668
- }
4669
- )
4670
- ]
4671
- },
4672
- `${element.id}-venn-${node.id}-${i}`
4673
- );
4674
- })
4675
- }
4676
- );
4677
- }
4678
- function FunnelRenderer({
4679
- element,
4680
- nodes,
4681
- palette,
4682
- style
4683
- }) {
4684
- const w = element.width;
4685
- const h = element.height;
4686
- const pad = 8;
4687
- const usableW = w - pad * 2;
4688
- const stageH = (h - pad * 2) / nodes.length;
4689
- const shadow = styleShadow2(style);
4690
- return /* @__PURE__ */ jsx(
4691
- "svg",
4692
- {
4693
- className: "w-full h-full pointer-events-none",
4694
- viewBox: `0 0 ${w} ${h}`,
4695
- preserveAspectRatio: "xMidYMid meet",
4696
- "data-testid": "smartart-funnel",
4697
- children: nodes.map((node, i) => {
4698
- const topWidth = usableW * (1 - i / nodes.length);
4699
- const bottomWidth = usableW * (1 - (i + 1) / nodes.length);
4700
- const y = pad + i * stageH;
4701
- const topLeft = (w - topWidth) / 2;
4702
- const topRight = topLeft + topWidth;
4703
- const bottomLeft = (w - bottomWidth) / 2;
4704
- const bottomRight = bottomLeft + bottomWidth;
4705
- const points = [
4706
- `${topLeft},${y}`,
4707
- `${topRight},${y}`,
4708
- `${bottomRight},${y + stageH}`,
4709
- `${bottomLeft},${y + stageH}`
4710
- ].join(" ");
4711
- const fontSize = fitFontSize(node.text, topWidth * 0.85, stageH, 11);
4712
- return /* @__PURE__ */ jsxs(
4713
- "g",
4714
- {
4715
- ...smartArtNodeGroupProps(node.id, shadow),
4716
- children: [
4717
- /* @__PURE__ */ jsx(
4718
- "polygon",
4719
- {
4720
- points,
4721
- fill: colour(i, palette),
4722
- opacity: nodeOpacity2(i, nodes.length, style)
4723
- }
4724
- ),
4725
- /* @__PURE__ */ jsx(
4726
- SmartArtNodeText,
4727
- {
4728
- x: w / 2,
4729
- y: y + stageH / 2,
4730
- text: truncate2(node.text, 30),
4731
- fill: "white",
4732
- fontSize,
4733
- className: "pointer-events-none"
4734
- }
4735
- )
4736
- ]
4737
- },
4738
- `${element.id}-funnel-${node.id}-${i}`
4739
- );
4740
- })
4741
- }
4742
- );
4743
- }
4744
- function TargetRenderer({
4745
- element,
4746
- nodes,
4747
- palette,
4748
- style
4749
- }) {
4750
- const w = element.width;
4751
- const h = element.height;
4752
- const cx = w * 0.4;
4753
- const cy = h / 2;
4754
- const maxR = Math.min(cx - 8, cy - 8);
4755
- const fontSize = Math.max(7, Math.min(10, maxR / (nodes.length + 1)));
4756
- const labelX = cx + maxR + 8;
4757
- const shadow = styleShadow2(style);
4758
- return /* @__PURE__ */ jsx(
4759
- "svg",
4760
- {
4761
- className: "w-full h-full pointer-events-none",
4762
- viewBox: `0 0 ${w} ${h}`,
4763
- preserveAspectRatio: "xMidYMid meet",
4764
- "data-testid": "smartart-target",
4765
- children: nodes.map((node, i) => {
4766
- const r = maxR * ((nodes.length - i) / nodes.length);
4767
- return /* @__PURE__ */ jsxs(
4768
- "g",
4769
- {
4770
- ...smartArtNodeGroupProps(node.id, shadow),
4771
- children: [
4772
- /* @__PURE__ */ jsx(
4773
- "circle",
4774
- {
4775
- cx,
4776
- cy,
4777
- r: Math.max(r, 4),
4778
- fill: colour(i, palette),
4779
- opacity: nodeOpacity2(i, nodes.length, style)
4780
- }
4781
- ),
4782
- /* @__PURE__ */ jsx(
4783
- "line",
4784
- {
4785
- x1: cx + Math.max(r, 4),
4786
- y1: cy,
4787
- x2: labelX - 2,
4788
- y2: 8 + i * (fontSize + 6),
4789
- stroke: colour(i, palette),
4790
- strokeWidth: 1,
4791
- opacity: 0.6
4792
- }
4793
- ),
4794
- /* @__PURE__ */ jsx(
4795
- "text",
4796
- {
4797
- x: labelX,
4798
- y: 8 + i * (fontSize + 6) + fontSize / 2,
4799
- textAnchor: "start",
4800
- dominantBaseline: "central",
4801
- fill: colour(i, palette),
4802
- fontSize,
4803
- className: "pointer-events-none",
4804
- children: truncate2(node.text, 30)
4805
- }
4806
- )
4807
- ]
4808
- },
4809
- `${element.id}-target-${node.id}-${i}`
4810
- );
4811
- })
4812
- }
4813
- );
4814
- }
4815
- function HierarchyRenderer({
4816
- element,
4817
- nodes,
4818
- palette,
4819
- style
4820
- }) {
4821
- const roots = buildTree(nodes);
4822
- if (roots.length === 0) {
4823
- return /* @__PURE__ */ jsx(ListRenderer, { element, nodes, palette, style });
4824
- }
4825
- const totalLeaves = roots.reduce((s, r) => s + treeWidth(r), 0);
4826
- const depth = Math.max(...roots.map(treeDepth));
4827
- const svgW = element.width;
4828
- const svgH = element.height;
4829
- const cellW = svgW / totalLeaves;
4830
- const cellH = svgH / Math.max(depth, 1);
4831
- const boxW = Math.min(cellW * 0.8, 140);
4832
- const boxH = Math.min(cellH * 0.4, 36);
4833
- const rx = Math.min(6, boxH * 0.15);
4834
- const shadow = styleShadow2(style);
4835
- const sw = styleStroke2(style);
4836
- const elements = [];
4837
- let colourIdx = 0;
4838
- function renderTreeNode(t, xOffset, level) {
4839
- const w = treeWidth(t);
4840
- const nodeCx = (xOffset + w / 2) * cellW;
4841
- const nodeCy = level * cellH + cellH / 2;
4842
- const ci = colourIdx++;
4843
- const fontSize = fitFontSize(t.node.text, boxW * 0.9, boxH, 11);
4844
- for (const child of t.children) {
4845
- const childW = treeWidth(child);
4846
- let childOffset2 = xOffset;
4847
- for (const c of t.children) {
4848
- if (c === child) {
4849
- break;
4850
- }
4851
- childOffset2 += treeWidth(c);
3383
+ if (node.kind === "polygon") {
3384
+ return /* @__PURE__ */ jsx(
3385
+ "polygon",
3386
+ {
3387
+ points: node.points,
3388
+ fill: node.fill,
3389
+ stroke: node.stroke,
3390
+ strokeWidth: node.strokeWidth,
3391
+ opacity: node.opacity
4852
3392
  }
4853
- const childCx = (childOffset2 + childW / 2) * cellW;
4854
- const childCy = (level + 1) * cellH + cellH / 2;
4855
- const midY = nodeCy + boxH / 2 + (childCy - boxH / 2 - (nodeCy + boxH / 2)) / 2;
4856
- elements.push(
4857
- /* @__PURE__ */ jsx(
4858
- "path",
4859
- {
4860
- d: `M${nodeCx},${nodeCy + boxH / 2} L${nodeCx},${midY} L${childCx},${midY} L${childCx},${childCy - boxH / 2}`,
4861
- fill: "none",
4862
- stroke: "#94a3b8",
4863
- strokeWidth: 1.5,
4864
- opacity: 0.5
4865
- },
4866
- `${element.id}-hier-conn-${t.node.id}-${child.node.id}`
4867
- )
4868
- );
4869
- }
4870
- elements.push(
4871
- /* @__PURE__ */ jsxs(
4872
- "g",
4873
- {
4874
- ...smartArtNodeGroupProps(t.node.id, shadow),
4875
- children: [
4876
- /* @__PURE__ */ jsx(
4877
- "rect",
4878
- {
4879
- x: nodeCx - boxW / 2,
4880
- y: nodeCy - boxH / 2,
4881
- width: boxW,
4882
- height: boxH,
4883
- rx,
4884
- fill: colour(ci, palette),
4885
- opacity: nodeOpacity2(ci, nodes.length, style),
4886
- stroke: sw > 0 ? "rgba(255,255,255,0.3)" : "none",
4887
- strokeWidth: sw
4888
- }
4889
- ),
4890
- /* @__PURE__ */ jsx(
4891
- SmartArtNodeText,
4892
- {
4893
- x: nodeCx,
4894
- y: nodeCy,
4895
- text: truncate2(t.node.text, 40),
4896
- fill: "white",
4897
- fontSize,
4898
- className: "pointer-events-none"
4899
- }
4900
- )
4901
- ]
4902
- },
4903
- `${element.id}-hier-group-${t.node.id}`
4904
- )
4905
3393
  );
4906
- let childOffset = xOffset;
4907
- for (const child of t.children) {
4908
- renderTreeNode(child, childOffset, level + 1);
4909
- childOffset += treeWidth(child);
4910
- }
4911
- return w;
4912
- }
4913
- let offset = 0;
4914
- for (const root of roots) {
4915
- offset += renderTreeNode(root, offset, 0);
4916
3394
  }
4917
3395
  return /* @__PURE__ */ jsx(
4918
- "svg",
3396
+ "rect",
4919
3397
  {
4920
- className: "w-full h-full pointer-events-none",
4921
- viewBox: `0 0 ${svgW} ${svgH}`,
4922
- preserveAspectRatio: "xMidYMid meet",
4923
- "data-testid": "smartart-hierarchy",
4924
- children: elements
3398
+ x: node.x,
3399
+ y: node.y,
3400
+ width: node.width,
3401
+ height: node.height,
3402
+ rx: node.rx,
3403
+ fill: node.fill,
3404
+ stroke: node.stroke,
3405
+ strokeWidth: node.strokeWidth,
3406
+ opacity: node.opacity
4925
3407
  }
4926
3408
  );
4927
3409
  }
4928
- function GearRenderer({
4929
- element,
4930
- nodes,
4931
- palette,
4932
- style
4933
- }) {
4934
- const w = element.width;
4935
- const h = element.height;
4936
- const gearNodes = nodes.slice(0, 3);
4937
- const extraNodes = nodes.slice(3);
4938
- const gearCount = gearNodes.length;
4939
- const gearAreaW = extraNodes.length > 0 ? w * 0.7 : w;
4940
- const spacing = gearAreaW / (gearCount + 1);
4941
- const gearR = Math.min(spacing * 0.4, h * 0.35);
4942
- const innerR = gearR * 0.7;
4943
- const teethCount = 8;
4944
- const shadow = styleShadow2(style);
4945
- return /* @__PURE__ */ jsxs(
4946
- "svg",
4947
- {
4948
- className: "w-full h-full pointer-events-none",
4949
- viewBox: `0 0 ${w} ${h}`,
4950
- preserveAspectRatio: "xMidYMid meet",
4951
- "data-testid": "smartart-gear",
4952
- children: [
4953
- gearNodes.map((node, i) => {
4954
- const gx = spacing * (i + 1);
4955
- const gy = h / 2 + (i % 2 === 0 ? 0 : gearR * 0.35);
4956
- const fontSize = fitFontSize(node.text, innerR * 1.2, innerR * 2, 11);
4957
- return /* @__PURE__ */ jsxs(
4958
- "g",
4959
- {
4960
- ...smartArtNodeGroupProps(node.id, shadow),
4961
- children: [
4962
- /* @__PURE__ */ jsx(
4963
- "path",
4964
- {
4965
- d: gearPath(gx, gy, gearR, innerR, teethCount),
4966
- fill: colour(i, palette),
4967
- opacity: nodeOpacity2(i, nodes.length, style)
4968
- }
4969
- ),
4970
- /* @__PURE__ */ jsx("circle", { cx: gx, cy: gy, r: innerR * 0.5, fill: "white", opacity: 0.25 }),
4971
- /* @__PURE__ */ jsx(
4972
- SmartArtNodeText,
4973
- {
4974
- x: gx,
4975
- y: gy,
4976
- text: truncate2(node.text, 20),
4977
- fill: "white",
4978
- fontSize,
4979
- fontWeight: "bold",
4980
- className: "pointer-events-none"
4981
- }
4982
- )
4983
- ]
4984
- },
4985
- `${element.id}-gear-${node.id}-${i}`
4986
- );
4987
- }),
4988
- extraNodes.map((node, i) => {
4989
- const lx = gearAreaW + 10;
4990
- const ly = 14 + i * 18;
4991
- return /* @__PURE__ */ jsxs("g", { children: [
4992
- /* @__PURE__ */ jsx(
4993
- "circle",
4994
- {
4995
- cx: lx,
4996
- cy: ly,
4997
- r: 3,
4998
- fill: colour(gearCount + i, palette),
4999
- opacity: nodeOpacity2(gearCount + i, nodes.length, style)
5000
- }
5001
- ),
5002
- /* @__PURE__ */ jsx(
5003
- "text",
5004
- {
5005
- x: lx + 8,
5006
- y: ly,
5007
- textAnchor: "start",
5008
- dominantBaseline: "central",
5009
- fill: colour(gearCount + i, palette),
5010
- fontSize: 10,
5011
- className: "pointer-events-none",
5012
- children: truncate2(node.text, 30)
5013
- }
5014
- )
5015
- ] }, `${element.id}-gear-extra-${node.id}-${i}`);
5016
- })
5017
- ]
5018
- }
5019
- );
3410
+ function labelAnchor(node) {
3411
+ if (node.kind === "circle") {
3412
+ return {
3413
+ x: node.textX ?? node.cx,
3414
+ y: node.textY ?? node.cy,
3415
+ textAnchor: node.textAnchor ?? "middle",
3416
+ baseline: node.textBaseline ?? "middle"
3417
+ };
3418
+ }
3419
+ return { x: node.textX, y: node.textY, textAnchor: "middle", baseline: "middle" };
5020
3420
  }
5021
- function TimelineRenderer({
5022
- element,
5023
- nodes,
5024
- palette,
5025
- style
3421
+ function SmartArtLayoutSvg({
3422
+ layout,
3423
+ nodeIds,
3424
+ nodeLabels
5026
3425
  }) {
5027
- const w = element.width;
5028
- const h = element.height;
5029
- const padX = 24;
5030
- const lineY = h / 2;
5031
- const lineStartX = padX;
5032
- const lineEndX = w - padX;
5033
- const lineLen = lineEndX - lineStartX;
5034
- const dotR = Math.max(4, Math.min(8, lineLen / (nodes.length * 4)));
5035
- const labelOffset = Math.min(h * 0.28, 40);
5036
- const shadow = styleShadow2(style);
5037
3426
  return /* @__PURE__ */ jsxs(
5038
3427
  "svg",
5039
3428
  {
5040
3429
  className: "w-full h-full pointer-events-none",
5041
- viewBox: `0 0 ${w} ${h}`,
3430
+ viewBox: layout.viewBox,
5042
3431
  preserveAspectRatio: "xMidYMid meet",
5043
- "data-testid": "smartart-timeline",
3432
+ "data-testid": `smartart-${layout.family}`,
3433
+ "data-layout-family": layout.family,
5044
3434
  children: [
5045
- /* @__PURE__ */ jsx("line", { x1: lineStartX, y1: lineY, x2: lineEndX, y2: lineY, stroke: "#94a3b8", strokeWidth: 2 }),
5046
- /* @__PURE__ */ jsx(
5047
- "polygon",
5048
- {
5049
- points: `${lineEndX - 6},${lineY - 4} ${lineEndX},${lineY} ${lineEndX - 6},${lineY + 4}`,
5050
- fill: "#94a3b8"
5051
- }
5052
- ),
5053
- nodes.map((node, i) => {
5054
- const x = nodes.length === 1 ? (lineStartX + lineEndX) / 2 : lineStartX + i / (nodes.length - 1) * lineLen;
5055
- const above = i % 2 === 0;
5056
- const textY = above ? lineY - labelOffset : lineY + labelOffset;
5057
- const stemEndY = above ? lineY - dotR - 2 : lineY + dotR + 2;
5058
- const fontSize = fitFontSize(node.text, lineLen / nodes.length * 0.9, labelOffset, 10);
3435
+ layout.connectors.map((connector) => /* @__PURE__ */ jsx(ConnectorPath, { connector }, connector.key)),
3436
+ layout.nodes.map((node, i) => {
3437
+ const nodeId = nodeIds[i];
3438
+ const label = nodeId ? nodeLabels?.get(nodeId) : void 0;
3439
+ const anchor = labelAnchor(node);
5059
3440
  return /* @__PURE__ */ jsxs(
5060
3441
  "g",
5061
3442
  {
5062
- ...smartArtNodeGroupProps(node.id, shadow),
3443
+ ...smartArtNodeGroupProps(nodeId ?? node.key, layout.shadowFilter, label),
5063
3444
  children: [
5064
- /* @__PURE__ */ jsx(
5065
- "line",
5066
- {
5067
- x1: x,
5068
- y1: stemEndY,
5069
- x2: x,
5070
- y2: textY + (above ? fontSize : -fontSize),
5071
- stroke: colour(i, palette),
5072
- strokeWidth: 1,
5073
- opacity: 0.5
5074
- }
5075
- ),
5076
- /* @__PURE__ */ jsx(
5077
- "circle",
5078
- {
5079
- cx: x,
5080
- cy: lineY,
5081
- r: dotR,
5082
- fill: colour(i, palette),
5083
- opacity: nodeOpacity2(i, nodes.length, style)
5084
- }
5085
- ),
5086
- /* @__PURE__ */ jsx(
3445
+ label ? /* @__PURE__ */ jsx("title", { children: label }) : null,
3446
+ /* @__PURE__ */ jsx(NodeShape, { node }),
3447
+ node.text.length > 0 ? /* @__PURE__ */ jsx(
5087
3448
  SmartArtNodeText,
5088
3449
  {
5089
- text: truncate2(node.text, 20) ?? "",
5090
- x,
5091
- y: textY,
5092
- fill: colour(i, palette),
5093
- fontSize,
5094
- anchor: above ? "bottom" : "top",
3450
+ x: anchor.x,
3451
+ y: anchor.y,
3452
+ text: node.text,
3453
+ fill: node.fontColor ?? DEFAULT_LABEL_COLOR,
3454
+ fontSize: node.fontSize,
3455
+ fontWeight: node.fontWeight,
3456
+ fontStyle: node.fontStyle,
3457
+ textAnchor: anchor.textAnchor,
3458
+ anchor: anchor.baseline,
5095
3459
  className: "pointer-events-none"
5096
3460
  }
5097
- )
3461
+ ) : null
5098
3462
  ]
5099
3463
  },
5100
- `${element.id}-timeline-${node.id}-${i}`
3464
+ node.key
5101
3465
  );
5102
3466
  })
5103
3467
  ]
5104
3468
  }
5105
3469
  );
5106
3470
  }
5107
- function BendingProcessRenderer({
5108
- element,
5109
- nodes,
5110
- palette,
5111
- style
5112
- }) {
5113
- const COLS = 4;
5114
- const w = element.width;
5115
- const h = element.height;
5116
- const rowsCount = Math.ceil(nodes.length / COLS);
5117
- const padX = 8;
5118
- const padY = 8;
5119
- const cellW = (w - padX * 2) / COLS;
5120
- const cellH = (h - padY * 2) / Math.max(rowsCount, 1);
5121
- const boxW = cellW * 0.8;
5122
- const boxH = Math.min(cellH * 0.6, 32);
5123
- const rx = Math.min(5, boxH * 0.15);
5124
- const arrowSize = 6;
5125
- const shadow = styleShadow2(style);
5126
- const sw = styleStroke2(style);
5127
- return /* @__PURE__ */ jsx(
5128
- "svg",
5129
- {
5130
- className: "w-full h-full pointer-events-none",
5131
- viewBox: `0 0 ${w} ${h}`,
5132
- preserveAspectRatio: "xMidYMid meet",
5133
- "data-testid": "smartart-bending",
5134
- children: nodes.map((node, i) => {
5135
- const row = Math.floor(i / COLS);
5136
- const colInRow = i % COLS;
5137
- const col = row % 2 === 0 ? colInRow : COLS - 1 - colInRow;
5138
- const nodeCx = padX + col * cellW + cellW / 2;
5139
- const nodeCy = padY + row * cellH + cellH / 2;
5140
- const fontSize = fitFontSize(node.text, boxW * 0.85, boxH, 10);
5141
- let arrow = null;
5142
- if (i < nodes.length - 1) {
5143
- const nextRow = Math.floor((i + 1) / COLS);
5144
- const nextColInRow = (i + 1) % COLS;
5145
- const nextCol = nextRow % 2 === 0 ? nextColInRow : COLS - 1 - nextColInRow;
5146
- const nextCx = padX + nextCol * cellW + cellW / 2;
5147
- const nextCy = padY + nextRow * cellH + cellH / 2;
5148
- if (nextRow === row) {
5149
- const dir = nextCx > nodeCx ? 1 : -1;
5150
- const startX = nodeCx + dir * (boxW / 2 + 2);
5151
- const endX = nextCx - dir * (boxW / 2 + 2);
5152
- arrow = /* @__PURE__ */ jsxs("g", { children: [
5153
- /* @__PURE__ */ jsx(
5154
- "line",
5155
- {
5156
- x1: startX,
5157
- y1: nodeCy,
5158
- x2: endX,
5159
- y2: nodeCy,
5160
- stroke: "#94a3b8",
5161
- strokeWidth: 1.5
5162
- }
5163
- ),
5164
- /* @__PURE__ */ jsx(
5165
- "polygon",
5166
- {
5167
- points: `${endX},${nodeCy - arrowSize / 2} ${endX + dir * arrowSize},${nodeCy} ${endX},${nodeCy + arrowSize / 2}`,
5168
- fill: "#94a3b8"
5169
- }
5170
- )
5171
- ] }, `${element.id}-snake-arrow-${i}`);
5172
- } else {
5173
- const startY = nodeCy + boxH / 2 + 2;
5174
- const endY = nextCy - boxH / 2 - 2;
5175
- arrow = /* @__PURE__ */ jsxs("g", { children: [
5176
- /* @__PURE__ */ jsx(
5177
- "line",
5178
- {
5179
- x1: nodeCx,
5180
- y1: startY,
5181
- x2: nextCx,
5182
- y2: endY,
5183
- stroke: "#94a3b8",
5184
- strokeWidth: 1.5
5185
- }
5186
- ),
5187
- /* @__PURE__ */ jsx(
5188
- "polygon",
5189
- {
5190
- points: `${nextCx - arrowSize / 2},${endY} ${nextCx},${endY + arrowSize} ${nextCx + arrowSize / 2},${endY}`,
5191
- fill: "#94a3b8"
5192
- }
5193
- )
5194
- ] }, `${element.id}-snake-arrow-${i}`);
5195
- }
5196
- }
5197
- return /* @__PURE__ */ jsxs(
5198
- "g",
5199
- {
5200
- ...smartArtNodeGroupProps(node.id, shadow),
5201
- children: [
5202
- arrow,
5203
- /* @__PURE__ */ jsx(
5204
- "rect",
5205
- {
5206
- x: nodeCx - boxW / 2,
5207
- y: nodeCy - boxH / 2,
5208
- width: boxW,
5209
- height: boxH,
5210
- rx,
5211
- fill: colour(i, palette),
5212
- opacity: nodeOpacity2(i, nodes.length, style),
5213
- stroke: sw > 0 ? "rgba(255,255,255,0.3)" : "none",
5214
- strokeWidth: sw
5215
- }
5216
- ),
5217
- /* @__PURE__ */ jsx(
5218
- SmartArtNodeText,
5219
- {
5220
- x: nodeCx,
5221
- y: nodeCy,
5222
- text: truncate2(node.text, 20),
5223
- fill: "white",
5224
- fontSize,
5225
- className: "pointer-events-none"
5226
- }
5227
- )
5228
- ]
5229
- },
5230
- `${element.id}-snake-${node.id}-${i}`
5231
- );
5232
- })
5233
- }
5234
- );
5235
- }
5236
3471
  function SmartArtRendererImpl({
5237
3472
  element,
5238
3473
  className = "",
@@ -5322,9 +3557,20 @@ function SmartArtRendererImpl({
5322
3557
  }
5323
3558
  );
5324
3559
  } else {
5325
- const namedLayout = smartArtData.layout;
5326
- const layoutType = namedLayout ? layoutToCategory(namedLayout) : (smartArtData.resolvedLayoutType ?? smartArtData.layoutType ?? "list").toLowerCase();
5327
- content = renderLayout(layoutType, element, revealedNodes, palette, style, nodeLabels);
3560
+ const layout = computeSmartArtLayout(
3561
+ revealedNodes,
3562
+ { width: element.width, height: element.height },
3563
+ palette,
3564
+ style,
3565
+ element.id,
3566
+ smartArtData.resolvedLayoutType,
3567
+ smartArtData.layout,
3568
+ void 0,
3569
+ smartArtData.layoutDefinition,
3570
+ smartArtData.presLayoutVars
3571
+ );
3572
+ const nodeIds = flattenNodes(revealedNodes).map((n) => n.id);
3573
+ content = /* @__PURE__ */ jsx(SmartArtLayoutSvg, { layout, nodeIds, nodeLabels });
5328
3574
  }
5329
3575
  const body = editable ? /* @__PURE__ */ jsx(
5330
3576
  SmartArtEditableLayer,
@@ -5339,108 +3585,6 @@ function SmartArtRendererImpl({
5339
3585
  ) : content;
5340
3586
  return wrapChrome(chrome, body, className, { role: a11y.role, label: a11y.label });
5341
3587
  }
5342
- function renderLayout(layoutType, element, nodes, palette, style, nodeLabels) {
5343
- if (layoutType.includes("hierarchy") || layoutType.includes("org")) {
5344
- return /* @__PURE__ */ jsx(HierarchyRenderer, { element, nodes, palette, style });
5345
- }
5346
- if (layoutType.includes("process") || layoutType.includes("chevron") || layoutType.includes("arrow")) {
5347
- return /* @__PURE__ */ jsx(
5348
- ProcessRenderer,
5349
- {
5350
- element,
5351
- nodes,
5352
- palette,
5353
- style,
5354
- nodeLabels
5355
- }
5356
- );
5357
- }
5358
- if (layoutType.includes("cycle") || layoutType.includes("radial")) {
5359
- return /* @__PURE__ */ jsx(
5360
- CycleRenderer,
5361
- {
5362
- element,
5363
- nodes,
5364
- palette,
5365
- style,
5366
- nodeLabels
5367
- }
5368
- );
5369
- }
5370
- if (layoutType.includes("matrix")) {
5371
- return /* @__PURE__ */ jsx(
5372
- MatrixRenderer,
5373
- {
5374
- element,
5375
- nodes,
5376
- palette,
5377
- style,
5378
- nodeLabels
5379
- }
5380
- );
5381
- }
5382
- if (layoutType.includes("pyramid")) {
5383
- return /* @__PURE__ */ jsx(PyramidRenderer, { element, nodes, palette, style });
5384
- }
5385
- if (layoutType.includes("venn")) {
5386
- return /* @__PURE__ */ jsx(VennRenderer, { element, nodes, palette, style });
5387
- }
5388
- if (layoutType.includes("funnel")) {
5389
- return /* @__PURE__ */ jsx(FunnelRenderer, { element, nodes, palette, style });
5390
- }
5391
- if (layoutType.includes("target") || layoutType.includes("bullseye")) {
5392
- return /* @__PURE__ */ jsx(TargetRenderer, { element, nodes, palette, style });
5393
- }
5394
- if (layoutType.includes("gear")) {
5395
- return /* @__PURE__ */ jsx(GearRenderer, { element, nodes, palette, style });
5396
- }
5397
- if (layoutType.includes("timeline") || layoutType.includes("linear")) {
5398
- return /* @__PURE__ */ jsx(TimelineRenderer, { element, nodes, palette, style });
5399
- }
5400
- if (layoutType.includes("bending") || layoutType.includes("snake")) {
5401
- return /* @__PURE__ */ jsx(BendingProcessRenderer, { element, nodes, palette, style });
5402
- }
5403
- if (layoutType.includes("stepdown")) {
5404
- return /* @__PURE__ */ jsx(Fragment, { children: renderStepDownProcess(element, nodes, palette, style) });
5405
- }
5406
- if (layoutType.includes("alternatingflow") || layoutType.includes("alternating")) {
5407
- return /* @__PURE__ */ jsx(Fragment, { children: renderAlternatingFlow(element, nodes, palette, style) });
5408
- }
5409
- if (layoutType.includes("descending")) {
5410
- return /* @__PURE__ */ jsx(Fragment, { children: renderDescendingProcess(element, nodes, palette, style) });
5411
- }
5412
- if (layoutType.includes("pictureaccent")) {
5413
- return /* @__PURE__ */ jsx(Fragment, { children: renderPictureAccentList(element, nodes, palette, style) });
5414
- }
5415
- if (layoutType.includes("verticalblock")) {
5416
- return /* @__PURE__ */ jsx(Fragment, { children: renderVerticalBlockList(element, nodes, palette, style) });
5417
- }
5418
- if (layoutType.includes("grouped")) {
5419
- return /* @__PURE__ */ jsx(Fragment, { children: renderGroupedList(element, nodes, palette, style) });
5420
- }
5421
- if (layoutType.includes("pyramidlist")) {
5422
- return /* @__PURE__ */ jsx(Fragment, { children: renderPyramidList(element, nodes, palette, style) });
5423
- }
5424
- if (layoutType.includes("horizontalpicture")) {
5425
- return /* @__PURE__ */ jsx(Fragment, { children: renderHorizontalPictureList(element, nodes, palette, style) });
5426
- }
5427
- if (layoutType.includes("accentprocess")) {
5428
- return /* @__PURE__ */ jsx(Fragment, { children: renderAccentProcess(element, nodes, palette, style) });
5429
- }
5430
- if (layoutType.includes("verticalchevron")) {
5431
- return /* @__PURE__ */ jsx(Fragment, { children: renderVerticalChevronList(element, nodes, palette, style) });
5432
- }
5433
- return /* @__PURE__ */ jsx(
5434
- ListRenderer,
5435
- {
5436
- element,
5437
- nodes,
5438
- palette,
5439
- style,
5440
- nodeLabels
5441
- }
5442
- );
5443
- }
5444
3588
  function arePropsEqual(prev, next) {
5445
3589
  if (prev.className !== next.className) {
5446
3590
  return false;
@@ -6257,7 +4401,7 @@ function renderBody(options) {
6257
4401
  if (renderGroupChild) {
6258
4402
  return /* @__PURE__ */ jsx("div", { className: "relative w-full h-full pointer-events-none", children: el.children.map(renderGroupChild) });
6259
4403
  }
6260
- return renderGroup(el.children, el.groupFill);
4404
+ return renderGroup(el.children, getGroupChildParentFill(el));
6261
4405
  }
6262
4406
  if (shouldRenderFallbackLabel(el, isTxtEl)) {
6263
4407
  return /* @__PURE__ */ jsx("div", { className: "w-full h-full flex items-center justify-center text-[11px] text-white/80 pointer-events-none", children: getElementLabel(el) });
@@ -6363,7 +4507,7 @@ function StaticElementRendererImpl({
6363
4507
  zIndex: index,
6364
4508
  fieldContext,
6365
4509
  tableStyleContext,
6366
- parentGroupFill: getGroupChildParentFill(element),
4510
+ parentGroupFill: getGroupChildParentFill(element, parentGroupFill),
6367
4511
  onActionClick,
6368
4512
  actionRequiresModifier,
6369
4513
  exposeElementId
@@ -7328,105 +5472,51 @@ function ArrangeSection(p) {
7328
5472
  /* @__PURE__ */ jsx("span", { className: "text-[9px] text-muted-foreground leading-none", children: t("pptx.arrange.groupLabel") })
7329
5473
  ] });
7330
5474
  }
7331
- function DesignSection(p) {
5475
+ function TransitionsSection(p) {
7332
5476
  const { t } = useTranslation();
5477
+ const canEdit = p.canEdit !== false;
5478
+ const draft = React14.useMemo(() => readRibbonTransitionDraft(p.activeSlide), [p.activeSlide]);
5479
+ const [durationBuffer, setDurationBuffer] = React14.useState(null);
5480
+ const [advanceBuffer, setAdvanceBuffer] = React14.useState(null);
5481
+ const commit = React14.useCallback(
5482
+ (changes) => {
5483
+ p.onTransitionChange(ribbonTransitionUpdates({ ...draft, ...changes }));
5484
+ },
5485
+ [draft, p]
5486
+ );
7333
5487
  return /* @__PURE__ */ jsxs(Fragment, { children: [
7334
5488
  /* @__PURE__ */ jsxs(
7335
5489
  "button",
7336
5490
  {
7337
- onClick: p.onToggleThemeGallery,
7338
- disabled: !p.canEdit,
7339
- className: cn(
7340
- pill,
7341
- p.isThemeGalleryOpen ? "bg-primary hover:bg-primary/80 text-white" : ""
7342
- ),
7343
- title: t("pptx.ribbon.browseThemesTitle"),
7344
- children: [
7345
- /* @__PURE__ */ jsx(LuPalette, { className: ics }),
7346
- t("pptx.ribbon.browseThemes")
7347
- ]
7348
- }
7349
- ),
7350
- /* @__PURE__ */ jsxs(
7351
- "button",
7352
- {
7353
- onClick: p.onToggleThemeEditor,
7354
- disabled: !p.canEdit,
7355
- className: cn(pill, p.isThemeEditorOpen ? "bg-primary hover:bg-primary/80 text-white" : ""),
7356
- title: t("pptx.ribbon.editThemeTitle"),
7357
- children: [
7358
- /* @__PURE__ */ jsx(LuPencil, { className: ics }),
7359
- t("pptx.ribbon.editTheme")
7360
- ]
7361
- }
7362
- ),
7363
- sep,
7364
- p.onOpenDocumentProperties && /* @__PURE__ */ jsxs(
7365
- "button",
7366
- {
7367
- onClick: p.onOpenDocumentProperties,
5491
+ type: "button",
7368
5492
  className: pill,
7369
- title: t("pptx.ribbon.slideSizeTitle"),
5493
+ title: t("pptx.ribbon.previewTransition"),
5494
+ onClick: () => {
5495
+ if (p.activeSlide?.transition) {
5496
+ commit({});
5497
+ }
5498
+ },
7370
5499
  children: [
7371
- /* @__PURE__ */ jsx(LuMonitor, { className: ics }),
7372
- t("pptx.ribbon.slideSize")
5500
+ /* @__PURE__ */ jsx(LuPlay, { className: ics }),
5501
+ t("pptx.ribbon.preview")
7373
5502
  ]
7374
5503
  }
7375
5504
  ),
7376
- p.onToggleInspector && /* @__PURE__ */ jsxs(
7377
- "button",
7378
- {
7379
- onClick: p.onToggleInspector,
7380
- className: cn(
7381
- pill,
7382
- p.isInspectorPaneOpen ? "bg-primary hover:bg-primary/80 text-white" : ""
7383
- ),
7384
- title: t("pptx.ribbon.formatBackgroundTitle"),
7385
- children: [
7386
- /* @__PURE__ */ jsx(LuPaintBucket, { className: ics }),
7387
- t("pptx.ribbon.formatBackground")
7388
- ]
7389
- }
7390
- )
7391
- ] });
7392
- }
7393
- var TRANSITION_PRESETS = [
7394
- { value: "none", labelKey: "pptx.ribbon.transition.none" },
7395
- { value: "fade", labelKey: "pptx.ribbon.transition.fade" },
7396
- { value: "push", labelKey: "pptx.ribbon.transition.push" },
7397
- { value: "wipe", labelKey: "pptx.ribbon.transition.wipe" },
7398
- { value: "split", labelKey: "pptx.ribbon.transition.split" },
7399
- { value: "reveal", labelKey: "pptx.ribbon.transition.reveal" },
7400
- { value: "cut", labelKey: "pptx.ribbon.transition.cut" },
7401
- { value: "cover", labelKey: "pptx.ribbon.transition.cover" },
7402
- { value: "uncover", labelKey: "pptx.ribbon.transition.uncover" }
7403
- ];
7404
- function TransitionsSection(p) {
7405
- const { t } = useTranslation();
7406
- const [selected, setSelected] = React14.useState("none");
7407
- const [duration, setDuration] = React14.useState("00.50");
7408
- const [advanceOnClick, setAdvanceOnClick] = React14.useState(true);
7409
- const [advanceAfter, setAdvanceAfter] = React14.useState(false);
7410
- const [advanceAfterSeconds, setAdvanceAfterSeconds] = React14.useState("00:00.00");
7411
- return /* @__PURE__ */ jsxs(Fragment, { children: [
7412
- /* @__PURE__ */ jsxs("button", { type: "button", className: pill, title: t("pptx.ribbon.previewTransition"), children: [
7413
- /* @__PURE__ */ jsx(LuPlay, { className: ics }),
7414
- t("pptx.ribbon.preview")
7415
- ] }),
7416
5505
  sep,
7417
- /* @__PURE__ */ jsx("div", { className: "inline-flex items-center gap-0.5 overflow-x-auto max-w-[420px]", children: TRANSITION_PRESETS.map((preset) => /* @__PURE__ */ jsx(
5506
+ /* @__PURE__ */ jsx("div", { className: "inline-flex items-center gap-0.5 overflow-x-auto max-w-[420px]", children: RIBBON_TRANSITION_PRESETS.map((preset) => /* @__PURE__ */ jsx(
7418
5507
  "button",
7419
5508
  {
7420
5509
  type: "button",
7421
- onClick: () => setSelected(preset.value),
5510
+ disabled: !canEdit,
5511
+ onClick: () => commit({ type: preset.type }),
7422
5512
  className: cn(
7423
5513
  "flex-shrink-0 px-2 py-1 max-md:min-h-[44px] rounded border text-[11px] leading-tight transition-colors",
7424
- selected === preset.value ? "border-primary bg-primary/10 text-primary font-medium" : "border-border bg-muted hover:bg-accent text-foreground"
5514
+ draft.type === preset.type ? "border-primary bg-primary/10 text-primary font-medium" : "border-border bg-muted hover:bg-accent text-foreground"
7425
5515
  ),
7426
5516
  title: t("pptx.ribbon.transitionTitle", { name: t(preset.labelKey) }),
7427
5517
  children: t(preset.labelKey)
7428
5518
  },
7429
- preset.value
5519
+ preset.type
7430
5520
  )) }),
7431
5521
  sep,
7432
5522
  /* @__PURE__ */ jsxs("label", { className: "inline-flex items-center gap-1.5 text-xs text-muted-foreground", children: [
@@ -7434,10 +5524,21 @@ function TransitionsSection(p) {
7434
5524
  /* @__PURE__ */ jsx(
7435
5525
  "input",
7436
5526
  {
7437
- type: "text",
7438
- value: duration,
7439
- onChange: (e) => setDuration(e.target.value),
7440
- className: "w-14 px-1.5 py-1 rounded border border-border bg-muted text-xs text-foreground text-center",
5527
+ type: "number",
5528
+ min: 0,
5529
+ max: 20,
5530
+ step: 0.25,
5531
+ disabled: !canEdit,
5532
+ value: durationBuffer ?? String(draft.durationSec),
5533
+ onChange: (e) => {
5534
+ setDurationBuffer(e.target.value);
5535
+ const seconds = Number(e.target.value);
5536
+ if (Number.isFinite(seconds) && e.target.value !== "") {
5537
+ commit({ durationSec: seconds });
5538
+ }
5539
+ },
5540
+ onBlur: () => setDurationBuffer(null),
5541
+ className: "w-16 px-1.5 py-1 rounded border border-border bg-muted text-xs text-foreground text-center",
7441
5542
  title: t("pptx.ribbon.transitionDurationTitle")
7442
5543
  }
7443
5544
  )
@@ -7448,17 +5549,28 @@ function TransitionsSection(p) {
7448
5549
  /* @__PURE__ */ jsx(
7449
5550
  "select",
7450
5551
  {
7451
- className: "w-24 px-1.5 py-1 rounded border border-border bg-muted text-xs text-foreground",
5552
+ className: "w-24 px-1.5 py-1 rounded border border-border bg-muted text-xs text-foreground disabled:opacity-50",
7452
5553
  defaultValue: "none",
5554
+ disabled: true,
7453
5555
  children: /* @__PURE__ */ jsx("option", { value: "none", children: t("pptx.ribbon.soundNone") })
7454
5556
  }
7455
5557
  )
7456
5558
  ] }),
7457
5559
  sep,
7458
- /* @__PURE__ */ jsxs("button", { type: "button", className: pill, title: t("pptx.ribbon.applyTransitionToAll"), children: [
7459
- /* @__PURE__ */ jsx(LuCopy, { className: ics }),
7460
- t("pptx.headerFooter.applyToAll")
7461
- ] }),
5560
+ /* @__PURE__ */ jsxs(
5561
+ "button",
5562
+ {
5563
+ type: "button",
5564
+ disabled: !canEdit,
5565
+ className: pill,
5566
+ title: t("pptx.ribbon.applyTransitionToAll"),
5567
+ onClick: p.onApplyTransitionToAll,
5568
+ children: [
5569
+ /* @__PURE__ */ jsx(LuCopy, { className: ics }),
5570
+ t("pptx.headerFooter.applyToAll")
5571
+ ]
5572
+ }
5573
+ ),
7462
5574
  sep,
7463
5575
  /* @__PURE__ */ jsxs("div", { className: "inline-flex flex-col gap-1 text-xs text-muted-foreground", children: [
7464
5576
  /* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium text-foreground", children: t("pptx.ribbon.advanceSlide") }),
@@ -7467,8 +5579,9 @@ function TransitionsSection(p) {
7467
5579
  "input",
7468
5580
  {
7469
5581
  type: "checkbox",
7470
- checked: advanceOnClick,
7471
- onChange: (e) => setAdvanceOnClick(e.target.checked),
5582
+ disabled: !canEdit,
5583
+ checked: draft.advanceOnClick,
5584
+ onChange: (e) => commit({ advanceOnClick: e.target.checked }),
7472
5585
  className: "accent-primary h-3 w-3"
7473
5586
  }
7474
5587
  ),
@@ -7479,8 +5592,9 @@ function TransitionsSection(p) {
7479
5592
  "input",
7480
5593
  {
7481
5594
  type: "checkbox",
7482
- checked: advanceAfter,
7483
- onChange: (e) => setAdvanceAfter(e.target.checked),
5595
+ disabled: !canEdit,
5596
+ checked: draft.advanceAfter,
5597
+ onChange: (e) => commit({ advanceAfter: e.target.checked }),
7484
5598
  className: "accent-primary h-3 w-3"
7485
5599
  }
7486
5600
  ),
@@ -7489,9 +5603,13 @@ function TransitionsSection(p) {
7489
5603
  "input",
7490
5604
  {
7491
5605
  type: "text",
7492
- value: advanceAfterSeconds,
7493
- onChange: (e) => setAdvanceAfterSeconds(e.target.value),
7494
- disabled: !advanceAfter,
5606
+ value: advanceBuffer ?? draft.advanceAfterText,
5607
+ onChange: (e) => {
5608
+ setAdvanceBuffer(e.target.value);
5609
+ commit({ advanceAfter: true, advanceAfterText: e.target.value });
5610
+ },
5611
+ onBlur: () => setAdvanceBuffer(null),
5612
+ disabled: !canEdit || !draft.advanceAfter,
7495
5613
  className: "w-16 px-1 py-0.5 rounded border border-border bg-muted text-xs text-foreground text-center disabled:opacity-50",
7496
5614
  title: t("pptx.ribbon.advanceAfterSeconds")
7497
5615
  }
@@ -7517,6 +5635,68 @@ function TransitionsSection(p) {
7517
5635
  )
7518
5636
  ] });
7519
5637
  }
5638
+ function DesignSection(p) {
5639
+ const { t } = useTranslation();
5640
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
5641
+ /* @__PURE__ */ jsxs(
5642
+ "button",
5643
+ {
5644
+ onClick: p.onToggleThemeGallery,
5645
+ disabled: !p.canEdit,
5646
+ className: cn(
5647
+ pill,
5648
+ p.isThemeGalleryOpen ? "bg-primary hover:bg-primary/80 text-white" : ""
5649
+ ),
5650
+ title: t("pptx.ribbon.browseThemesTitle"),
5651
+ children: [
5652
+ /* @__PURE__ */ jsx(LuPalette, { className: ics }),
5653
+ t("pptx.ribbon.browseThemes")
5654
+ ]
5655
+ }
5656
+ ),
5657
+ /* @__PURE__ */ jsxs(
5658
+ "button",
5659
+ {
5660
+ onClick: p.onToggleThemeEditor,
5661
+ disabled: !p.canEdit,
5662
+ className: cn(pill, p.isThemeEditorOpen ? "bg-primary hover:bg-primary/80 text-white" : ""),
5663
+ title: t("pptx.ribbon.editThemeTitle"),
5664
+ children: [
5665
+ /* @__PURE__ */ jsx(LuPencil, { className: ics }),
5666
+ t("pptx.ribbon.editTheme")
5667
+ ]
5668
+ }
5669
+ ),
5670
+ sep,
5671
+ p.onOpenDocumentProperties && /* @__PURE__ */ jsxs(
5672
+ "button",
5673
+ {
5674
+ onClick: p.onOpenDocumentProperties,
5675
+ className: pill,
5676
+ title: t("pptx.ribbon.slideSizeTitle"),
5677
+ children: [
5678
+ /* @__PURE__ */ jsx(LuMonitor, { className: ics }),
5679
+ t("pptx.ribbon.slideSize")
5680
+ ]
5681
+ }
5682
+ ),
5683
+ p.onToggleInspector && /* @__PURE__ */ jsxs(
5684
+ "button",
5685
+ {
5686
+ onClick: p.onToggleInspector,
5687
+ className: cn(
5688
+ pill,
5689
+ p.isInspectorPaneOpen ? "bg-primary hover:bg-primary/80 text-white" : ""
5690
+ ),
5691
+ title: t("pptx.ribbon.formatBackgroundTitle"),
5692
+ children: [
5693
+ /* @__PURE__ */ jsx(LuPaintBucket, { className: ics }),
5694
+ t("pptx.ribbon.formatBackground")
5695
+ ]
5696
+ }
5697
+ )
5698
+ ] });
5699
+ }
7520
5700
  function DrawSection(p) {
7521
5701
  const { t } = useTranslation();
7522
5702
  return /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -7609,7 +5789,7 @@ function AccountPage() {
7609
5789
  return void 0;
7610
5790
  });
7611
5791
  };
7612
- const version = "2.16.9" ;
5792
+ const version = "2.16.10" ;
7613
5793
  return /* @__PURE__ */ jsxs("div", { className: "mt-8 max-w-[700px] space-y-6", children: [
7614
5794
  /* @__PURE__ */ jsxs("section", { className: cardClass, children: [
7615
5795
  /* @__PURE__ */ jsxs("h2", { className: "flex items-center gap-2 text-sm font-semibold", children: [
@@ -8042,6 +6222,160 @@ function RibbonMenu({
8042
6222
  }
8043
6223
  );
8044
6224
  }
6225
+ function FontFamilyMenu(p) {
6226
+ const { t } = useTranslation();
6227
+ const groups = buildFontCatalog({
6228
+ themeFonts: p.themeFonts,
6229
+ embeddedFonts: p.embeddedFonts,
6230
+ customFonts: p.customFonts
6231
+ });
6232
+ 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(React14.Fragment, { children: [
6233
+ /* @__PURE__ */ jsx(
6234
+ "div",
6235
+ {
6236
+ className: `px-3 pb-1 pt-2 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground${groupIndex > 0 ? " border-t border-border/60 mt-1" : ""}`,
6237
+ children: t(group.labelKey)
6238
+ }
6239
+ ),
6240
+ group.entries.map((entry) => /* @__PURE__ */ jsx(FontRow, { entry, onSelect: p.onSelect }, `${group.id}-${entry.family}`))
6241
+ ] }, group.id)) }) });
6242
+ }
6243
+ function FontRow({
6244
+ entry,
6245
+ onSelect
6246
+ }) {
6247
+ const { t } = useTranslation();
6248
+ return /* @__PURE__ */ jsxs(
6249
+ "button",
6250
+ {
6251
+ type: "button",
6252
+ className: "flex w-full items-center justify-between gap-3 px-3 py-1.5 text-xs text-foreground hover:bg-muted transition-colors",
6253
+ style: { fontFamily: entry.family },
6254
+ onClick: () => onSelect(entry.family),
6255
+ children: [
6256
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: entry.family }),
6257
+ entry.themeRole && /* @__PURE__ */ jsx("span", { className: "shrink-0 text-[10px] text-muted-foreground", children: t(`pptx.font.role.${entry.themeRole}`) })
6258
+ ]
6259
+ }
6260
+ );
6261
+ }
6262
+ function useLayoutPreviews(loadPreviews, enabled) {
6263
+ const [previews, setPreviews] = useState(/* @__PURE__ */ new Map());
6264
+ useEffect(() => {
6265
+ if (!enabled || !loadPreviews) {
6266
+ return;
6267
+ }
6268
+ let cancelled = false;
6269
+ void loadPreviews().then((loaded) => {
6270
+ if (!cancelled) {
6271
+ setPreviews(new Map(loaded.map((preview) => [preview.path, preview])));
6272
+ }
6273
+ return void 0;
6274
+ }).catch(() => {
6275
+ });
6276
+ return () => {
6277
+ cancelled = true;
6278
+ };
6279
+ }, [enabled, loadPreviews]);
6280
+ return previews;
6281
+ }
6282
+ var THUMB_WIDTH = 128;
6283
+ var THUMB_HEIGHT = 72;
6284
+ var MAX_PREVIEW_ELEMENTS = 100;
6285
+ function LayoutGalleryMenu(p) {
6286
+ const { t } = useTranslation();
6287
+ return /* @__PURE__ */ jsx(RibbonMenu, { anchorRef: p.anchorRef, className: "flex flex-col w-[620px] pt-1", children: /* @__PURE__ */ jsxs(
6288
+ "div",
6289
+ {
6290
+ "data-testid": "layout-gallery-menu",
6291
+ className: "grid grid-cols-4 gap-2 rounded-lg border border-border bg-popover backdrop-blur-lg shadow-2xl p-3 max-h-[520px] overflow-y-auto",
6292
+ children: [
6293
+ p.layoutOptions.length === 0 && /* @__PURE__ */ jsx("p", { className: "col-span-4 px-2 py-3 text-xs text-muted-foreground", children: t("pptx.layoutGallery.empty") }),
6294
+ p.layoutOptions.map((layout) => {
6295
+ const isCurrent = isCurrentLayout(layout, p.currentLayoutPath);
6296
+ return /* @__PURE__ */ jsxs(
6297
+ "button",
6298
+ {
6299
+ type: "button",
6300
+ "aria-current": isCurrent ? "true" : void 0,
6301
+ title: isCurrent ? `${layout.name} (${t("pptx.layoutGallery.current")})` : layout.name,
6302
+ className: cn(
6303
+ "relative flex min-w-0 flex-col items-center gap-1 rounded border-2 p-1 text-xs text-foreground transition-colors hover:bg-muted",
6304
+ isCurrent ? "border-primary bg-primary/10" : "border-transparent"
6305
+ ),
6306
+ onClick: () => p.onSelect(layout),
6307
+ children: [
6308
+ /* @__PURE__ */ jsx(LayoutThumbnail, { preview: p.previews.get(layout.path), name: layout.name }),
6309
+ /* @__PURE__ */ jsx("span", { className: "w-full truncate text-center", children: layout.name })
6310
+ ]
6311
+ },
6312
+ layout.path
6313
+ );
6314
+ })
6315
+ ]
6316
+ }
6317
+ ) });
6318
+ }
6319
+ function LayoutThumbnail({ preview, name }) {
6320
+ const geometry = buildLayoutPreviewGeometry(preview, THUMB_WIDTH, THUMB_HEIGHT);
6321
+ const slide = {
6322
+ id: `layout-preview-${preview?.path ?? name}`,
6323
+ rId: "",
6324
+ slideNumber: 0,
6325
+ elements: preview?.elements ?? [],
6326
+ backgroundColor: geometry.backgroundColor
6327
+ };
6328
+ return /* @__PURE__ */ jsx(
6329
+ "div",
6330
+ {
6331
+ className: "relative shrink-0 overflow-hidden rounded-sm border border-border/70 shadow-sm",
6332
+ style: {
6333
+ width: geometry.boxWidth,
6334
+ height: geometry.boxHeight,
6335
+ backgroundColor: geometry.backgroundColor
6336
+ },
6337
+ children: /* @__PURE__ */ jsxs(
6338
+ "div",
6339
+ {
6340
+ className: "absolute left-0 top-0 origin-top-left overflow-hidden",
6341
+ style: {
6342
+ width: geometry.surfaceWidth,
6343
+ height: geometry.surfaceHeight,
6344
+ transform: `scale(${geometry.scale})`,
6345
+ backgroundColor: geometry.backgroundColor
6346
+ },
6347
+ children: [
6348
+ (preview?.elements ?? []).slice(0, MAX_PREVIEW_ELEMENTS).map((element, index) => /* @__PURE__ */ jsx(
6349
+ StaticElementRenderer,
6350
+ {
6351
+ element,
6352
+ activeSlide: slide,
6353
+ allSlides: [slide],
6354
+ zIndex: index
6355
+ },
6356
+ element.id
6357
+ )),
6358
+ geometry.frames.map((frame) => /* @__PURE__ */ jsx(
6359
+ "div",
6360
+ {
6361
+ className: "absolute border-dashed border-muted-foreground/70 bg-background/20",
6362
+ style: {
6363
+ left: frame.left,
6364
+ top: frame.top,
6365
+ width: frame.width,
6366
+ height: frame.height,
6367
+ borderWidth: geometry.frameBorderWidth,
6368
+ borderStyle: "dashed"
6369
+ }
6370
+ },
6371
+ frame.key
6372
+ ))
6373
+ ]
6374
+ }
6375
+ )
6376
+ }
6377
+ );
6378
+ }
8045
6379
  function SlidesGroup(p) {
8046
6380
  const { t } = useTranslation();
8047
6381
  const [newSlideMenuOpen, setNewSlideMenuOpen] = useState(false);
@@ -8049,6 +6383,7 @@ function SlidesGroup(p) {
8049
6383
  const [templateGalleryOpen, setTemplateGalleryOpen] = useState(false);
8050
6384
  const newSlideMenuRef = useRef(null);
8051
6385
  const layoutMenuRef = useRef(null);
6386
+ const previews = useLayoutPreviews(p.loadLayoutPreviews, newSlideMenuOpen || layoutMenuOpen);
8052
6387
  const handleNewSlide = useCallback(() => {
8053
6388
  if (p.layoutOptions.length > 0) {
8054
6389
  const first = p.layoutOptions[0];
@@ -8112,19 +6447,18 @@ function SlidesGroup(p) {
8112
6447
  children: /* @__PURE__ */ jsx(LuChevronDown, { className: "w-3 h-3" })
8113
6448
  }
8114
6449
  ),
8115
- newSlideMenuOpen && /* @__PURE__ */ jsx(RibbonMenu, { anchorRef: newSlideMenuRef, className: "flex flex-col w-48 pt-1", children: /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-border bg-popover backdrop-blur-lg shadow-2xl py-1 max-h-60 overflow-y-auto", children: p.layoutOptions.map((lo) => /* @__PURE__ */ jsx(
8116
- "button",
8117
- {
8118
- type: "button",
8119
- className: "flex items-center gap-2 w-full px-3 py-1.5 text-xs text-foreground hover:bg-muted transition-colors",
8120
- onClick: () => {
8121
- p.onInsertSlideFromLayout(lo.path, lo.name);
6450
+ newSlideMenuOpen && /* @__PURE__ */ jsx(
6451
+ LayoutGalleryMenu,
6452
+ {
6453
+ anchorRef: newSlideMenuRef,
6454
+ layoutOptions: p.layoutOptions,
6455
+ previews,
6456
+ onSelect: (layout) => {
6457
+ p.onInsertSlideFromLayout(layout.path, layout.name);
8122
6458
  setNewSlideMenuOpen(false);
8123
- },
8124
- children: lo.name
8125
- },
8126
- lo.path
8127
- )) }) })
6459
+ }
6460
+ }
6461
+ )
8128
6462
  ] }),
8129
6463
  p.onInsertSlideFromTemplate && /* @__PURE__ */ jsxs(
8130
6464
  "button",
@@ -8155,19 +6489,19 @@ function SlidesGroup(p) {
8155
6489
  ]
8156
6490
  }
8157
6491
  ),
8158
- layoutMenuOpen && /* @__PURE__ */ jsx(RibbonMenu, { anchorRef: layoutMenuRef, className: "flex flex-col w-48 pt-1", children: /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-border bg-popover backdrop-blur-lg shadow-2xl py-1 max-h-60 overflow-y-auto", children: p.layoutOptions.map((lo) => /* @__PURE__ */ jsx(
8159
- "button",
8160
- {
8161
- type: "button",
8162
- className: "flex items-center gap-2 w-full px-3 py-1.5 text-xs text-foreground hover:bg-muted transition-colors",
8163
- onClick: () => {
8164
- p.onApplyLayout?.(lo.path);
6492
+ layoutMenuOpen && /* @__PURE__ */ jsx(
6493
+ LayoutGalleryMenu,
6494
+ {
6495
+ anchorRef: layoutMenuRef,
6496
+ layoutOptions: p.layoutOptions,
6497
+ previews,
6498
+ currentLayoutPath: p.currentLayoutPath,
6499
+ onSelect: (layout) => {
6500
+ p.onApplyLayout?.(layout.path);
8165
6501
  setLayoutMenuOpen(false);
8166
- },
8167
- children: lo.name
8168
- },
8169
- lo.path
8170
- )) }) })
6502
+ }
6503
+ }
6504
+ )
8171
6505
  ] }),
8172
6506
  /* @__PURE__ */ jsxs(
8173
6507
  "button",
@@ -8212,12 +6546,13 @@ function SlidesGroup(p) {
8212
6546
  )
8213
6547
  ] });
8214
6548
  }
8215
- function extractFontInfo(element) {
8216
- const defaults = { fontFamily: "Segoe UI", fontSize: "24" };
8217
- if (!element) {
8218
- return defaults;
8219
- }
8220
- if (!hasTextProperties(element)) {
6549
+ function extractFontInfo(element, themeFonts) {
6550
+ const placeholderType = element?.placeholderType;
6551
+ const defaults = {
6552
+ fontFamily: resolveDefaultFontFamily(placeholderType, themeFonts),
6553
+ fontSize: "24"
6554
+ };
6555
+ if (!element || !hasTextProperties(element)) {
8221
6556
  return defaults;
8222
6557
  }
8223
6558
  const segStyle = element.textSegments?.[0]?.style;
@@ -8229,21 +6564,6 @@ function extractFontInfo(element) {
8229
6564
  fontSize: fontSize !== void 0 && fontSize !== null ? String(fontSize) : defaults.fontSize
8230
6565
  };
8231
6566
  }
8232
- var COMMON_FONTS2 = [
8233
- "Arial",
8234
- "Calibri",
8235
- "Cambria",
8236
- "Comic Sans MS",
8237
- "Courier New",
8238
- "Georgia",
8239
- "Helvetica",
8240
- "Impact",
8241
- "Segoe UI",
8242
- "Tahoma",
8243
- "Times New Roman",
8244
- "Trebuchet MS",
8245
- "Verdana"
8246
- ];
8247
6567
  var COMMON_SIZES = [8, 9, 10, 11, 12, 14, 16, 18, 20, 24, 28, 32, 36, 40, 44, 48, 54, 60, 72, 96];
8248
6568
  function HomeSection(p) {
8249
6569
  const { t } = useTranslation();
@@ -8253,7 +6573,7 @@ function HomeSection(p) {
8253
6573
  const [cutFeedback, setCutFeedback] = useState(false);
8254
6574
  const fontMenuRef = useRef(null);
8255
6575
  const sizeMenuRef = useRef(null);
8256
- const { fontFamily, fontSize } = extractFontInfo(p.selectedElement);
6576
+ const { fontFamily, fontSize } = extractFontInfo(p.selectedElement, p.themeFonts);
8257
6577
  const hasSelection = Boolean(p.selectedElement);
8258
6578
  useEffect(() => {
8259
6579
  if (!fontMenuOpen) {
@@ -8348,6 +6668,8 @@ function HomeSection(p) {
8348
6668
  {
8349
6669
  canEdit: p.canEdit,
8350
6670
  layoutOptions: p.layoutOptions,
6671
+ currentLayoutPath: p.currentLayoutPath,
6672
+ loadLayoutPreviews: p.loadLayoutPreviews,
8351
6673
  onInsertSlideFromLayout: p.onInsertSlideFromLayout,
8352
6674
  onInsertSlideFromTemplate: p.onInsertSlideFromTemplate,
8353
6675
  templateScheme: p.templateScheme,
@@ -8372,20 +6694,19 @@ function HomeSection(p) {
8372
6694
  ]
8373
6695
  }
8374
6696
  ),
8375
- fontMenuOpen && /* @__PURE__ */ jsx(RibbonMenu, { anchorRef: fontMenuRef, className: "flex flex-col w-48 pt-1", children: /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-border bg-popover backdrop-blur-lg shadow-2xl py-1 max-h-60 overflow-y-auto", children: COMMON_FONTS2.map((f) => /* @__PURE__ */ jsx(
8376
- "button",
8377
- {
8378
- type: "button",
8379
- className: "flex items-center gap-2 w-full px-3 py-1.5 text-xs text-foreground hover:bg-muted transition-colors",
8380
- style: { fontFamily: f },
8381
- onClick: () => {
8382
- p.onUpdateTextStyle?.({ fontFamily: f });
6697
+ fontMenuOpen && /* @__PURE__ */ jsx(
6698
+ FontFamilyMenu,
6699
+ {
6700
+ anchorRef: fontMenuRef,
6701
+ themeFonts: p.themeFonts,
6702
+ embeddedFonts: p.embeddedFontFamilies,
6703
+ customFonts: p.customFontFamilies,
6704
+ onSelect: (family) => {
6705
+ p.onUpdateTextStyle?.({ fontFamily: family });
8383
6706
  setFontMenuOpen(false);
8384
- },
8385
- children: f
8386
- },
8387
- f
8388
- )) }) })
6707
+ }
6708
+ }
6709
+ )
8389
6710
  ] }),
8390
6711
  /* @__PURE__ */ jsxs("div", { className: "relative", ref: sizeMenuRef, children: [
8391
6712
  /* @__PURE__ */ jsxs(
@@ -9267,36 +7588,28 @@ function SlideShowSection(p) {
9267
7588
  )
9268
7589
  ] }),
9269
7590
  /* @__PURE__ */ jsxs(RibbonGroup, { label: t("pptx.slideShow.options", { defaultValue: "Options" }), children: [
9270
- /* @__PURE__ */ jsxs(RibbonCommandStack, { children: [
9271
- /* @__PURE__ */ jsx(
9272
- RibbonToggle,
9273
- {
9274
- label: t("pptx.slideShow.keepUpdated", { defaultValue: "Keep Slides Updated" }),
9275
- checked: false,
9276
- disabled: true
9277
- }
9278
- ),
9279
- /* @__PURE__ */ jsx(
9280
- RibbonToggle,
9281
- {
9282
- label: t("pptx.slideShow.useTimings", { defaultValue: "Use Timings" }),
9283
- checked: true
9284
- }
9285
- ),
9286
- /* @__PURE__ */ jsx(
9287
- RibbonToggle,
9288
- {
9289
- label: t("pptx.slideShow.playNarrations", { defaultValue: "Play Narrations" }),
9290
- checked: true
7591
+ /* @__PURE__ */ jsx(RibbonCommandStack, { children: SLIDE_SHOW_OPTIONS.slice(0, 3).map((option) => /* @__PURE__ */ jsx(
7592
+ RibbonToggle,
7593
+ {
7594
+ label: t(option.labelKey),
7595
+ checked: readSlideShowOption(p.presentationProperties, option.id),
7596
+ disabled: option.unsupported,
7597
+ onChange: option.unsupported ? void 0 : (next) => {
7598
+ const change = slideShowOptionChange(option.id, next);
7599
+ if (change) {
7600
+ p.onPresentationPropertiesChange?.(change);
7601
+ }
9291
7602
  }
9292
- )
9293
- ] }),
7603
+ },
7604
+ option.id
7605
+ )) }),
9294
7606
  /* @__PURE__ */ jsxs(RibbonCommandStack, { children: [
9295
7607
  /* @__PURE__ */ jsx(
9296
7608
  RibbonToggle,
9297
7609
  {
9298
- label: t("pptx.slideShow.mediaControls", { defaultValue: "Show Media Controls" }),
9299
- checked: true
7610
+ label: t(SLIDE_SHOW_OPTIONS[3].labelKey),
7611
+ checked: readSlideShowOption(p.presentationProperties, SLIDE_SHOW_OPTIONS[3].id),
7612
+ disabled: SLIDE_SHOW_OPTIONS[3].unsupported
9300
7613
  }
9301
7614
  ),
9302
7615
  /* @__PURE__ */ jsx(
@@ -10519,7 +8832,11 @@ function MobileSectionBody({
10519
8832
  TransitionsSection,
10520
8833
  {
10521
8834
  isInspectorPaneOpen: p.isInspectorPaneOpen,
10522
- onToggleInspector: p.onToggleInspector
8835
+ onToggleInspector: p.onToggleInspector,
8836
+ canEdit: p.canEdit,
8837
+ activeSlide: p.activeSlide,
8838
+ onTransitionChange: p.onTransitionChange,
8839
+ onApplyTransitionToAll: p.onApplyTransitionToAll
10523
8840
  }
10524
8841
  ) });
10525
8842
  case "animations":
@@ -10738,20 +9055,6 @@ function MobileToolbar(props) {
10738
9055
  }
10739
9056
  );
10740
9057
  }
10741
- var FILL_COLORS = [
10742
- "#ffffff",
10743
- "#000000",
10744
- "#ff0000",
10745
- "#00ff00",
10746
- "#0000ff",
10747
- "#ffff00",
10748
- "#ff00ff",
10749
- "#00ffff",
10750
- "#ff8800",
10751
- "#8800ff",
10752
- "#008888",
10753
- "#888888"
10754
- ];
10755
9058
  var TOP_SHAPES = SHAPE_PRESETS.slice(0, 12);
10756
9059
  function DrawingGroup(p) {
10757
9060
  const { t } = useTranslation();
@@ -10928,7 +9231,7 @@ function DrawingGroup(p) {
10928
9231
  children: /* @__PURE__ */ jsx(LuPaintBucket, { className: ic })
10929
9232
  }
10930
9233
  ),
10931
- fillOpen && /* @__PURE__ */ jsx(RibbonMenu, { anchorRef: fillRef, className: "pt-1", children: /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-border bg-popover backdrop-blur-lg shadow-2xl p-2 grid grid-cols-6 gap-1", children: FILL_COLORS.map((c) => /* @__PURE__ */ jsx(
9234
+ fillOpen && /* @__PURE__ */ jsx(RibbonMenu, { anchorRef: fillRef, className: "pt-1", children: /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-border bg-popover backdrop-blur-lg shadow-2xl p-2 grid grid-cols-6 gap-1", children: RIBBON_SHAPE_SWATCHES.map((c) => /* @__PURE__ */ jsx(
10932
9235
  "button",
10933
9236
  {
10934
9237
  type: "button",
@@ -10938,7 +9241,7 @@ function DrawingGroup(p) {
10938
9241
  style: { backgroundColor: c },
10939
9242
  title: c,
10940
9243
  onClick: () => {
10941
- p.onUpdateElementStyle?.({ fill: c });
9244
+ p.onUpdateElementStyle?.(shapeFillChange(c));
10942
9245
  setFillOpen(false);
10943
9246
  }
10944
9247
  },
@@ -10957,7 +9260,7 @@ function DrawingGroup(p) {
10957
9260
  children: /* @__PURE__ */ jsx(LuPenLine, { className: ic })
10958
9261
  }
10959
9262
  ),
10960
- outlineOpen && /* @__PURE__ */ jsx(RibbonMenu, { anchorRef: outlineRef, className: "pt-1", children: /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-border bg-popover backdrop-blur-lg shadow-2xl p-2 grid grid-cols-6 gap-1", children: FILL_COLORS.map((c) => /* @__PURE__ */ jsx(
9263
+ outlineOpen && /* @__PURE__ */ jsx(RibbonMenu, { anchorRef: outlineRef, className: "pt-1", children: /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-border bg-popover backdrop-blur-lg shadow-2xl p-2 grid grid-cols-6 gap-1", children: RIBBON_SHAPE_SWATCHES.map((c) => /* @__PURE__ */ jsx(
10961
9264
  "button",
10962
9265
  {
10963
9266
  type: "button",
@@ -10967,7 +9270,7 @@ function DrawingGroup(p) {
10967
9270
  style: { backgroundColor: c },
10968
9271
  title: c,
10969
9272
  onClick: () => {
10970
- p.onUpdateElementStyle?.({ outlineColor: c });
9273
+ p.onUpdateElementStyle?.(shapeOutlineChange(c));
10971
9274
  setOutlineOpen(false);
10972
9275
  }
10973
9276
  },
@@ -11671,12 +9974,19 @@ function Toolbar(p) {
11671
9974
  onPaste: p.onPaste,
11672
9975
  onToggleFormatPainter: p.onToggleFormatPainter,
11673
9976
  layoutOptions: p.layoutOptions,
9977
+ currentLayoutPath: p.currentLayoutPath,
9978
+ loadLayoutPreviews: p.loadLayoutPreviews,
9979
+ themeFonts: p.themeFonts,
9980
+ embeddedFontFamilies: p.embeddedFontFamilies,
9981
+ customFontFamilies: p.customFontFamilies,
11674
9982
  onInsertSlideFromLayout: p.onInsertSlideFromLayout,
11675
9983
  onApplyLayout: p.onApplyLayout,
11676
9984
  onInsertSlideFromTemplate: p.onInsertSlideFromTemplate,
11677
9985
  templateScheme: p.templateScheme,
11678
9986
  selectedElement: p.selectedElement,
11679
- onUpdateTextStyle: p.onUpdateTextStyle
9987
+ onUpdateTextStyle: p.onUpdateTextStyle,
9988
+ onResetSlide: p.onResetSlide,
9989
+ onAddSection: p.onAddSection
11680
9990
  }
11681
9991
  ),
11682
9992
  sIns && /* @__PURE__ */ jsx(
@@ -11710,7 +10020,13 @@ function Toolbar(p) {
11710
10020
  onTransformTextCase: p.onTransformTextCase
11711
10021
  }
11712
10022
  ),
11713
- sHome && /* @__PURE__ */ jsx(EditingSection, { onToggleFindReplace: p.onToggleFindReplace }),
10023
+ sHome && /* @__PURE__ */ jsx(
10024
+ EditingSection,
10025
+ {
10026
+ onToggleFindReplace: p.onToggleFindReplace,
10027
+ onSelectAll: p.onSelectAll
10028
+ }
10029
+ ),
11714
10030
  sHome && /* @__PURE__ */ jsx(
11715
10031
  DrawingGroup,
11716
10032
  {
@@ -11720,7 +10036,8 @@ function Toolbar(p) {
11720
10036
  onSetNewShapeType: p.onSetNewShapeType,
11721
10037
  onAddShape: p.onAddShape,
11722
10038
  onMoveLayer: p.onMoveLayer,
11723
- onMoveLayerToEdge: p.onMoveLayerToEdge
10039
+ onMoveLayerToEdge: p.onMoveLayerToEdge,
10040
+ onUpdateElementStyle: p.onUpdateElementStyle
11724
10041
  }
11725
10042
  ),
11726
10043
  sDrw && /* @__PURE__ */ jsx(
@@ -11773,7 +10090,11 @@ function Toolbar(p) {
11773
10090
  TransitionsSection,
11774
10091
  {
11775
10092
  isInspectorPaneOpen: p.isInspectorPaneOpen,
11776
- onToggleInspector: p.onToggleInspector
10093
+ onToggleInspector: p.onToggleInspector,
10094
+ canEdit: p.canEdit,
10095
+ activeSlide: p.activeSlide,
10096
+ onTransitionChange: p.onTransitionChange,
10097
+ onApplyTransitionToAll: p.onApplyTransitionToAll
11777
10098
  }
11778
10099
  ),
11779
10100
  sAni && /* @__PURE__ */ jsx(
@@ -11808,7 +10129,9 @@ function Toolbar(p) {
11808
10129
  showSubtitles: p.showSubtitles ?? false,
11809
10130
  onSetMode: p.onSetMode,
11810
10131
  customShowControls: p,
11811
- hiddenActions: p.hiddenActions
10132
+ hiddenActions: p.hiddenActions,
10133
+ presentationProperties: p.presentationProperties,
10134
+ onPresentationPropertiesChange: p.onPresentationPropertiesChange
11812
10135
  }
11813
10136
  ),
11814
10137
  sRec && /* @__PURE__ */ jsx(
@@ -12786,10 +11109,6 @@ function useConnectorCreation({
12786
11109
  if (!connectorDragState || !onCreateConnector) {
12787
11110
  return;
12788
11111
  }
12789
- if (connectorDragState.startElementId === targetElementId) {
12790
- setConnectorDragState(null);
12791
- return;
12792
- }
12793
11112
  const startEl = activeSlide?.elements.find(
12794
11113
  (el) => el.id === connectorDragState.startElementId
12795
11114
  );
@@ -12798,37 +11117,27 @@ function useConnectorCreation({
12798
11117
  setConnectorDragState(null);
12799
11118
  return;
12800
11119
  }
12801
- const startSites = getConnectionSites(startEl.width, startEl.height);
12802
- const endSites = getConnectionSites(endEl.width, endEl.height);
12803
- const startSite = startSites[connectorDragState.startSiteIndex] ?? startSites[0];
12804
- const endSite = endSites[targetSiteIndex] ?? endSites[0];
12805
- const sx = startEl.x + startSite.x;
12806
- const sy = startEl.y + startSite.y;
12807
- const ex = endEl.x + endSite.x;
12808
- const ey = endEl.y + endSite.y;
12809
- const dx = Math.abs(ex - sx);
12810
- const dy = Math.abs(ey - sy);
12811
- const dist = Math.sqrt(dx * dx + dy * dy);
12812
- const shapeType = dist < 100 ? "straightConnector1" : dist < 300 ? "bentConnector3" : "curvedConnector3";
11120
+ const authored = authorConnectorBetweenSites(
11121
+ { element: startEl, siteIndex: connectorDragState.startSiteIndex },
11122
+ { element: endEl, siteIndex: targetSiteIndex }
11123
+ );
11124
+ if (!authored) {
11125
+ setConnectorDragState(null);
11126
+ return;
11127
+ }
12813
11128
  const newConnector = {
12814
11129
  id: `conn-new-${Date.now()}`,
12815
11130
  type: "connector",
12816
- x: Math.min(sx, ex),
12817
- y: Math.min(sy, ey),
12818
- width: Math.abs(ex - sx) || 1,
12819
- height: Math.abs(ey - sy) || 1,
12820
- shapeType,
11131
+ x: authored.x,
11132
+ y: authored.y,
11133
+ width: authored.width,
11134
+ height: authored.height,
11135
+ shapeType: authored.shapeType,
12821
11136
  shapeStyle: {
12822
11137
  strokeColor: "#4472C4",
12823
11138
  strokeWidth: 2,
12824
- connectorStartConnection: {
12825
- shapeId: connectorDragState.startElementId,
12826
- connectionSiteIndex: connectorDragState.startSiteIndex
12827
- },
12828
- connectorEndConnection: {
12829
- shapeId: targetElementId,
12830
- connectionSiteIndex: targetSiteIndex
12831
- }
11139
+ connectorStartConnection: authored.startConnection,
11140
+ connectorEndConnection: authored.endConnection
12832
11141
  }
12833
11142
  };
12834
11143
  onCreateConnector(newConnector);
@@ -15323,26 +13632,13 @@ function NotesMasterPanel({
15323
13632
  ] })
15324
13633
  ] });
15325
13634
  }
15326
- function masterToSlide(master) {
15327
- return {
15328
- id: master.path,
15329
- rId: "",
15330
- slideNumber: 0,
15331
- elements: master.elements ?? [],
15332
- backgroundColor: master.backgroundColor,
15333
- backgroundImage: master.backgroundImage
15334
- };
15335
- }
15336
- function layoutToSlide(layout) {
15337
- return {
15338
- id: layout.path,
15339
- rId: "",
15340
- slideNumber: 0,
15341
- elements: layout.elements ?? [],
15342
- backgroundColor: layout.backgroundColor,
15343
- backgroundImage: layout.backgroundImage
15344
- };
13635
+ function partToSlide(master, layoutIndex) {
13636
+ return masterViewPseudoSlide(
13637
+ { slideMasters: [master] },
13638
+ { tab: "slides", masterIndex: 0, layoutIndex }
13639
+ );
15345
13640
  }
13641
+ var EMPTY_SLIDE = { id: "", rId: "", slideNumber: 0, elements: [] };
15346
13642
  function SlideMastersList({
15347
13643
  slideMasters,
15348
13644
  activeMasterIndex,
@@ -15374,7 +13670,7 @@ function SlideMastersList({
15374
13670
  /* @__PURE__ */ jsx("div", { className: "relative overflow-hidden rounded bg-white", children: /* @__PURE__ */ jsx(
15375
13671
  SlideThumbnail,
15376
13672
  {
15377
- slide: masterToSlide(master),
13673
+ slide: partToSlide(master, null) ?? EMPTY_SLIDE,
15378
13674
  templateElements: [],
15379
13675
  canvasSize
15380
13676
  }
@@ -15407,8 +13703,8 @@ function SlideMastersList({
15407
13703
  /* @__PURE__ */ jsx("div", { className: "relative overflow-hidden rounded bg-white", children: /* @__PURE__ */ jsx(
15408
13704
  SlideThumbnail,
15409
13705
  {
15410
- slide: layoutToSlide(layout),
15411
- templateElements: master.elements ?? [],
13706
+ slide: partToSlide(master, layoutIdx) ?? EMPTY_SLIDE,
13707
+ templateElements: [],
15412
13708
  canvasSize
15413
13709
  }
15414
13710
  ) }),
@@ -19030,6 +17326,8 @@ function FontEmbeddingPanel({
19030
17326
  embedFontsEnabled,
19031
17327
  usedFontFamilies,
19032
17328
  embeddedFonts,
17329
+ canEmbedFonts = true,
17330
+ embedUnavailableKey,
19033
17331
  onClose,
19034
17332
  onToggleEmbedFonts
19035
17333
  }) {
@@ -19092,32 +17390,40 @@ function FontEmbeddingPanel({
19092
17390
  ] }),
19093
17391
  /* @__PURE__ */ jsxs("div", { className: "px-5 py-4 space-y-4 overflow-y-auto flex-1", children: [
19094
17392
  /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: t("pptx.fonts.embedDescription") }),
19095
- /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-3 cursor-pointer", children: [
19096
- /* @__PURE__ */ jsxs("div", { className: "relative", children: [
19097
- /* @__PURE__ */ jsx(
19098
- "input",
19099
- {
19100
- type: "checkbox",
19101
- className: "sr-only",
19102
- checked: embedFontsEnabled,
19103
- onChange: (e) => onToggleEmbedFonts(e.target.checked)
19104
- }
19105
- ),
19106
- /* @__PURE__ */ jsx(
19107
- "div",
19108
- {
19109
- className: `w-9 h-5 rounded-full transition-colors ${embedFontsEnabled ? "bg-primary" : "bg-muted-foreground"}`
19110
- }
19111
- ),
19112
- /* @__PURE__ */ jsx(
19113
- "div",
19114
- {
19115
- className: `absolute top-0.5 left-0.5 w-4 h-4 rounded-full bg-white transition-transform ${embedFontsEnabled ? "translate-x-4" : ""}`
19116
- }
19117
- )
19118
- ] }),
19119
- /* @__PURE__ */ jsx("span", { className: "text-xs text-foreground", children: t("pptx.fonts.enableEmbedding") })
19120
- ] }),
17393
+ /* @__PURE__ */ jsxs(
17394
+ "label",
17395
+ {
17396
+ className: `flex items-center gap-3 ${canEmbedFonts ? "cursor-pointer" : "cursor-not-allowed opacity-60"}`,
17397
+ children: [
17398
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
17399
+ /* @__PURE__ */ jsx(
17400
+ "input",
17401
+ {
17402
+ type: "checkbox",
17403
+ className: "sr-only",
17404
+ checked: embedFontsEnabled,
17405
+ disabled: !canEmbedFonts,
17406
+ onChange: (e) => onToggleEmbedFonts(e.target.checked)
17407
+ }
17408
+ ),
17409
+ /* @__PURE__ */ jsx(
17410
+ "div",
17411
+ {
17412
+ className: `w-9 h-5 rounded-full transition-colors ${embedFontsEnabled ? "bg-primary" : "bg-muted-foreground"}`
17413
+ }
17414
+ ),
17415
+ /* @__PURE__ */ jsx(
17416
+ "div",
17417
+ {
17418
+ className: `absolute top-0.5 left-0.5 w-4 h-4 rounded-full bg-white transition-transform ${embedFontsEnabled ? "translate-x-4" : ""}`
17419
+ }
17420
+ )
17421
+ ] }),
17422
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-foreground", children: t("pptx.fonts.enableEmbedding") })
17423
+ ]
17424
+ }
17425
+ ),
17426
+ /* @__PURE__ */ jsx("p", { className: "text-[11px] text-muted-foreground", children: canEmbedFonts ? t("pptx.fonts.embedKeepsExisting") : t(embedUnavailableKey ?? "pptx.fonts.embedUnavailable") }),
19121
17427
  /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
19122
17428
  /* @__PURE__ */ jsxs("h3", { className: "text-xs font-medium text-foreground", children: [
19123
17429
  t("pptx.fonts.usedFonts"),
@@ -20560,8 +18866,8 @@ function SelectionPane({
20560
18866
  if (elementId === null) {
20561
18867
  return;
20562
18868
  }
20563
- const trimmed = editingName.trim();
20564
- if (trimmed === editSeedRef.current.trim()) {
18869
+ const commit = resolveSelectionPaneRename(editSeedRef.current, editingName);
18870
+ if (!commit) {
20565
18871
  return;
20566
18872
  }
20567
18873
  setSlides((prevSlides) => {
@@ -20577,7 +18883,7 @@ function SelectionPane({
20577
18883
  }
20578
18884
  nextElements[idx] = {
20579
18885
  ...nextElements[idx],
20580
- name: trimmed.length > 0 ? trimmed : void 0
18886
+ name: commit.name
20581
18887
  };
20582
18888
  nextSlides[activeSlideIndex] = { ...slide, elements: nextElements };
20583
18889
  return nextSlides;
@@ -28834,17 +27140,12 @@ function ElementInspectorBody({
28834
27140
  onMoveLayer
28835
27141
  }) {
28836
27142
  const { t } = useTranslation();
28837
- const isLocked = Boolean(selectedElement.locks?.noMove || selectedElement.locks?.noSelect);
27143
+ const isLocked = isElementLocked(selectedElement);
28838
27144
  const handleToggleLock = () => {
28839
27145
  if (!canEdit) {
28840
27146
  return;
28841
27147
  }
28842
- if (isLocked) {
28843
- onUpdateElement({ locks: void 0 });
28844
- } else {
28845
- const locks = { noMove: true, noResize: true, noSelect: true };
28846
- onUpdateElement({ locks });
28847
- }
27148
+ onUpdateElement({ locks: elementLockTogglePatch(!isLocked) });
28848
27149
  };
28849
27150
  return /* @__PURE__ */ jsxs(Fragment, { children: [
28850
27151
  /* @__PURE__ */ jsxs("div", { className: CARD, children: [
@@ -34165,7 +32466,10 @@ function ViewerToolbarSection(props) {
34165
32466
  propertyHandlers,
34166
32467
  dialogs,
34167
32468
  slideOps,
32469
+ sectionOps,
34168
32470
  onApplyLayout,
32471
+ loadLayoutPreviews,
32472
+ customFontFamilies,
34169
32473
  ops,
34170
32474
  onSetMode,
34171
32475
  onEnterPresenterView,
@@ -34185,6 +32489,7 @@ function ViewerToolbarSection(props) {
34185
32489
  isAiPanelOpen,
34186
32490
  onToggleAiPanel
34187
32491
  } = props;
32492
+ const { t } = useTranslation();
34188
32493
  const handleAddAnimation = useCallback(
34189
32494
  (preset, group) => {
34190
32495
  if (!selectedElement || !activeSlide) {
@@ -34239,6 +32544,28 @@ function ViewerToolbarSection(props) {
34239
32544
  () => scopeLayoutOptionsToActiveSlide(s.layoutOptions, activeSlide),
34240
32545
  [s.layoutOptions, activeSlide]
34241
32546
  );
32547
+ const handleResetSlide = useCallback(() => {
32548
+ const path = resetSlideLayoutPath(activeSlide);
32549
+ if (path) {
32550
+ onApplyLayout?.(path);
32551
+ }
32552
+ }, [activeSlide, onApplyLayout]);
32553
+ const handleAddSection = useCallback(() => {
32554
+ sectionOps?.addSection(t("pptx.sections.defaultName"), activeSlideIndex);
32555
+ }, [sectionOps, activeSlideIndex, t]);
32556
+ const handleSelectAll = useCallback(() => {
32557
+ const allIds = activeSlide?.elements.map((element) => element.id) ?? [];
32558
+ if (allIds.length > 0) {
32559
+ ops.applySelection(allIds[0], allIds);
32560
+ }
32561
+ }, [activeSlide, ops]);
32562
+ const handlePresentationPropertiesChange = useCallback(
32563
+ (updates) => {
32564
+ s.setPresentationProperties((prev) => ({ ...prev, ...updates }));
32565
+ history.markDirty();
32566
+ },
32567
+ [s, history]
32568
+ );
34242
32569
  const handleApplyTransitionToAll = useCallback(() => {
34243
32570
  const transition = activeSlide?.transition;
34244
32571
  if (!transition) {
@@ -34541,6 +32868,14 @@ function ViewerToolbarSection(props) {
34541
32868
  isOverflowMenuOpen: s.isOverflowMenuOpen,
34542
32869
  onSetOverflowMenuOpen: s.setIsOverflowMenuOpen,
34543
32870
  layoutOptions: scopedLayoutOptions,
32871
+ currentLayoutPath: activeSlide?.layoutPath,
32872
+ loadLayoutPreviews,
32873
+ themeFonts: {
32874
+ heading: s.theme?.fontScheme?.majorFont?.latin,
32875
+ body: s.theme?.fontScheme?.minorFont?.latin
32876
+ },
32877
+ embeddedFontFamilies: s.embeddedFonts.map((font) => font.name),
32878
+ customFontFamilies,
34544
32879
  onInsertSlideFromLayout: slideOps.handleInsertSlideFromLayout,
34545
32880
  onApplyLayout,
34546
32881
  onInsertSlideFromTemplate: slideOps.handleInsertSlideFromTemplate,
@@ -34591,6 +32926,11 @@ function ViewerToolbarSection(props) {
34591
32926
  activeSlide,
34592
32927
  onTransitionChange: handleTransitionChange,
34593
32928
  onApplyTransitionToAll: handleApplyTransitionToAll,
32929
+ onResetSlide: handleResetSlide,
32930
+ onAddSection: sectionOps ? handleAddSection : void 0,
32931
+ onSelectAll: handleSelectAll,
32932
+ presentationProperties: s.presentationProperties,
32933
+ onPresentationPropertiesChange: handlePresentationPropertiesChange,
34594
32934
  aiEnabled,
34595
32935
  isAiPanelOpen,
34596
32936
  onToggleAiPanel
@@ -35116,6 +33456,8 @@ function ViewerDialogGroup(props) {
35116
33456
  embedFontsEnabled: dialogs.embedFontsEnabled,
35117
33457
  usedFontFamilies: propertyHandlers.usedFontFamilies,
35118
33458
  embeddedFonts: embeddedFonts.map((f) => f.name),
33459
+ canEmbedFonts: dialogs.fontEmbedding.interactive,
33460
+ embedUnavailableKey: dialogs.fontEmbedding.disabledReasonKey,
35119
33461
  onClose: () => dialogs.setIsFontEmbeddingOpen(false),
35120
33462
  onToggleEmbedFonts: dialogs.setEmbedFontsEnabled
35121
33463
  }
@@ -35390,6 +33732,7 @@ function PresentationStage({
35390
33732
  ...getReactSlideBackgroundStyle(activeSlide)
35391
33733
  },
35392
33734
  children: [
33735
+ /* @__PURE__ */ jsx("style", { children: PRESENTATION_HIT_TEST_CSS }),
35393
33736
  presentationKeyframesCss && /* @__PURE__ */ jsx("style", { children: presentationKeyframesCss }),
35394
33737
  templateElements.map((element, index) => /* @__PURE__ */ jsx(
35395
33738
  ElementRenderer,
@@ -35400,6 +33743,7 @@ function PresentationStage({
35400
33743
  isInlineEditing: false,
35401
33744
  inlineEditingText: "",
35402
33745
  canInteract: false,
33746
+ presenting: true,
35403
33747
  spellCheckEnabled: false,
35404
33748
  mediaDataUrls,
35405
33749
  selectionColorClass: "blue-400",
@@ -35436,6 +33780,7 @@ function PresentationStage({
35436
33780
  isInlineEditing: false,
35437
33781
  inlineEditingText: "",
35438
33782
  canInteract: false,
33783
+ presenting: true,
35439
33784
  spellCheckEnabled: false,
35440
33785
  mediaDataUrls,
35441
33786
  selectionColorClass: "blue-500",
@@ -35578,7 +33923,7 @@ function ViewerCanvasArea(props) {
35578
33923
  const { isHidden } = useToolbarVisibility(hiddenActions);
35579
33924
  const viewerOptions = useViewerOptionsContext();
35580
33925
  const effectiveSlide = mode === "master" ? masterPseudoSlide : activeSlide;
35581
- const effectiveTemplateElements = mode === "master" ? s.activeLayout ? s.activeMaster?.elements ?? [] : [] : templateElements;
33926
+ const effectiveTemplateElements = mode === "master" ? [] : templateElements;
35582
33927
  const fieldContext = useMemo(
35583
33928
  () => buildFieldSubstitutionContext({
35584
33929
  headerFooter: s.headerFooter,
@@ -36011,7 +34356,7 @@ ${url}`)) {
36011
34356
  var AiChatPanel = lazy(async () => {
36012
34357
  const [{ useChat }, { default: Panel }] = await Promise.all([
36013
34358
  import('@ai-sdk/react'),
36014
- import('./AiChatPanel-XHKYPYPH.mjs')
34359
+ import('./AiChatPanel-RZ4A7P4H.mjs')
36015
34360
  ]);
36016
34361
  function BoundAiChatPanel(props) {
36017
34362
  return /* @__PURE__ */ jsx(Panel, { ...props, useChat });
@@ -38263,6 +36608,63 @@ function SettingsAppearanceTab({
38263
36608
  );
38264
36609
  }) });
38265
36610
  }
36611
+ function SettingsCustomFontsSection({
36612
+ enabled,
36613
+ families,
36614
+ onRegistered
36615
+ }) {
36616
+ const { t } = useTranslation();
36617
+ const inputRef = useRef(null);
36618
+ const [error, setError] = useState(false);
36619
+ const handleFile = async (file) => {
36620
+ setError(false);
36621
+ try {
36622
+ const registration = await registerCustomFont(file);
36623
+ if (registration) {
36624
+ onRegistered(registration.family);
36625
+ } else {
36626
+ setError(true);
36627
+ }
36628
+ } catch {
36629
+ setError(true);
36630
+ }
36631
+ };
36632
+ return /* @__PURE__ */ jsxs("div", { className: "mt-2", children: [
36633
+ /* @__PURE__ */ jsxs(
36634
+ "button",
36635
+ {
36636
+ type: "button",
36637
+ disabled: !enabled,
36638
+ onClick: () => inputRef.current?.click(),
36639
+ className: "inline-flex items-center gap-2 rounded border border-border px-3 py-1.5 text-xs text-foreground transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50",
36640
+ children: [
36641
+ /* @__PURE__ */ jsx(LuUpload, { className: "h-3.5 w-3.5" }),
36642
+ t("pptx.options.general.addFontFile")
36643
+ ]
36644
+ }
36645
+ ),
36646
+ /* @__PURE__ */ jsx(
36647
+ "input",
36648
+ {
36649
+ ref: inputRef,
36650
+ type: "file",
36651
+ accept: CUSTOM_FONT_ACCEPT,
36652
+ className: "hidden",
36653
+ onChange: (event) => {
36654
+ const file = event.currentTarget.files?.[0];
36655
+ event.currentTarget.value = "";
36656
+ if (file) {
36657
+ void handleFile(file);
36658
+ }
36659
+ }
36660
+ }
36661
+ ),
36662
+ !enabled && /* @__PURE__ */ jsx("p", { className: "mt-2 text-xs text-muted-foreground", children: t("pptx.options.general.customFontsDisabled") }),
36663
+ error && /* @__PURE__ */ jsx("p", { role: "alert", className: "mt-2 text-xs text-destructive", children: t("pptx.options.general.customFontError") }),
36664
+ /* @__PURE__ */ jsx("p", { className: "mt-3 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground", children: t("pptx.options.general.customFontsAdded") }),
36665
+ families.length === 0 ? /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: t("pptx.options.general.customFontsEmpty") }) : /* @__PURE__ */ jsx("ul", { className: "mt-1 flex flex-col gap-0.5", children: families.map((family) => /* @__PURE__ */ jsx("li", { className: "text-xs text-foreground", style: { fontFamily: family }, children: family }, family)) })
36666
+ ] });
36667
+ }
38266
36668
  function SettingsLanguageTab({
38267
36669
  activeLocale,
38268
36670
  locales,
@@ -38290,6 +36692,7 @@ function SettingsLanguageTab({
38290
36692
  }) });
38291
36693
  }
38292
36694
  var AI_TAB_ID = "ai";
36695
+ var NO_CUSTOM_FONT_FAMILIES = [];
38293
36696
  function SettingsDialog({
38294
36697
  isOpen,
38295
36698
  onClose,
@@ -38308,7 +36711,9 @@ function SettingsDialog({
38308
36711
  availableLocales,
38309
36712
  onSelectLocale,
38310
36713
  aiEnabled,
38311
- chatStore
36714
+ chatStore,
36715
+ customFontFamilies = NO_CUSTOM_FONT_FAMILIES,
36716
+ onCustomFontRegistered
38312
36717
  }) {
38313
36718
  const [activeTabId, setActiveTabId] = useState("general");
38314
36719
  const { t } = useTranslation();
@@ -38480,6 +36885,16 @@ function SettingsDialog({
38480
36885
  }
38481
36886
  ) });
38482
36887
  }
36888
+ if (section.special === "customFonts") {
36889
+ return /* @__PURE__ */ jsx(
36890
+ SettingsCustomFontsSection,
36891
+ {
36892
+ enabled: options.general.enableCustomFontUpload,
36893
+ families: customFontFamilies,
36894
+ onRegistered: (family) => onCustomFontRegistered?.(family)
36895
+ }
36896
+ );
36897
+ }
38483
36898
  if (section.special === "clearCache") {
38484
36899
  return /* @__PURE__ */ jsxs("div", { className: "mt-2", children: [
38485
36900
  /* @__PURE__ */ jsx("p", { className: "mb-2 text-xs text-muted-foreground", children: t("pptx.options.save.clearCacheDescription") }),
@@ -38942,6 +37357,12 @@ var PowerPointViewer = forwardRef(
38942
37357
  [onThemeChange]
38943
37358
  );
38944
37359
  const themeStyle = useThemeStyle(effectiveTheme);
37360
+ const [customFontFamilies, setCustomFontFamilies] = useState([]);
37361
+ const handleCustomFontRegistered = useCallback((family) => {
37362
+ setCustomFontFamilies(
37363
+ (current) => current.includes(family) ? current : [...current, family]
37364
+ );
37365
+ }, []);
38945
37366
  const { i18n } = useTranslation();
38946
37367
  const [localeCode, setLocaleCode] = useState(
38947
37368
  () => defaultLocale ?? readStoredViewerPrefs().localeCode ?? "en"
@@ -39139,6 +37560,10 @@ var PowerPointViewer = forwardRef(
39139
37560
  canvasSize,
39140
37561
  selectedElements: state.selectedElements
39141
37562
  });
37563
+ const { setIsDirty } = state;
37564
+ const markDocumentDirty = useCallback(() => {
37565
+ setIsDirty(true);
37566
+ }, [setIsDirty]);
39142
37567
  const history = useEditorHistory({
39143
37568
  slides,
39144
37569
  canvasSize,
@@ -39152,6 +37577,7 @@ var PowerPointViewer = forwardRef(
39152
37577
  error,
39153
37578
  hasActivePointerInteraction,
39154
37579
  pointerCommitNonce: state.pointerCommitNonce,
37580
+ onDirty: markDocumentDirty,
39155
37581
  setSlides: state.setSlides,
39156
37582
  setCanvasSize: state.setCanvasSize,
39157
37583
  setActiveSlideIndex: state.setActiveSlideIndex,
@@ -39224,7 +37650,8 @@ var PowerPointViewer = forwardRef(
39224
37650
  preMasterMode: state.preMasterMode,
39225
37651
  hasDigitalSignatures: state.hasDigitalSignatures,
39226
37652
  isDirty: state.isDirty,
39227
- history
37653
+ history,
37654
+ embeddedFontFamilies: state.embeddedFonts.map((font) => font.name)
39228
37655
  });
39229
37656
  useEffect(() => {
39230
37657
  state.setSelectedElementId(null);
@@ -39288,6 +37715,9 @@ var PowerPointViewer = forwardRef(
39288
37715
  content,
39289
37716
  filePath,
39290
37717
  autosaveEnabled,
37718
+ // File > Options > Save > "Save AutoRecover information every N
37719
+ // minutes". React alone ignored it and stayed on the 120s default.
37720
+ autosaveIntervalSeconds: resolveAutosaveIntervalSeconds(viewerOptions),
39291
37721
  canEdit,
39292
37722
  mode,
39293
37723
  slides,
@@ -39405,7 +37835,10 @@ var PowerPointViewer = forwardRef(
39405
37835
  propertyHandlers,
39406
37836
  dialogs,
39407
37837
  slideOps: editorOps.slideOps,
37838
+ sectionOps: editorOps.sectionOps,
39408
37839
  onApplyLayout: (path) => void layoutSwitching.applyLayout(path),
37840
+ loadLayoutPreviews: layoutSwitching.loadLayoutPreviews,
37841
+ customFontFamilies,
39409
37842
  ops: editorOps.ops,
39410
37843
  onSetMode: handleSetMode,
39411
37844
  onEnterPresenterView: handleEnterPresenterView,
@@ -39554,7 +37987,9 @@ var PowerPointViewer = forwardRef(
39554
37987
  localeCode,
39555
37988
  availableLocales: resolvedLocales,
39556
37989
  onSelectLocale: handleLocaleChange,
39557
- aiEnabled: Boolean(ai)
37990
+ aiEnabled: Boolean(ai),
37991
+ customFontFamilies,
37992
+ onCustomFontRegistered: handleCustomFontRegistered
39558
37993
  }
39559
37994
  ),
39560
37995
  isHeaderFooterOpen && /* @__PURE__ */ jsx(