pptx-svelte-viewer 2.7.1 → 2.9.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 (112) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/AiChatPanel-CWB7jYUa.js +1108 -0
  3. package/dist/{export-Dggu1blu.js → export-CAW_l1TQ.js} +44625 -39074
  4. package/dist/i18n.js +1 -1
  5. package/dist/index.d.ts +21 -0
  6. package/dist/index.js +20 -20
  7. package/dist/pptx-svelte-viewer.css +1 -1
  8. package/dist/{translator-DL83W_OP.js → translator-0iRuc5gX.js} +240 -19
  9. package/dist/viewer/ai/ai-chat-persistence.svelte.d.ts +23 -0
  10. package/dist/viewer/ai/ai-chat-persistence.svelte.d.ts.map +1 -0
  11. package/dist/viewer/components/inspector/theme-editor-state.svelte.d.ts +47 -0
  12. package/dist/viewer/components/inspector/theme-editor-state.svelte.d.ts.map +1 -0
  13. package/dist/viewer/components/props-chrome.d.ts +104 -0
  14. package/dist/viewer/components/props-chrome.d.ts.map +1 -0
  15. package/dist/viewer/components/props-editing.d.ts +86 -0
  16. package/dist/viewer/components/props-editing.d.ts.map +1 -0
  17. package/dist/viewer/components/props-elements.d.ts +65 -0
  18. package/dist/viewer/components/props-elements.d.ts.map +1 -0
  19. package/dist/viewer/components/props-stage.d.ts +84 -0
  20. package/dist/viewer/components/props-stage.d.ts.map +1 -0
  21. package/dist/viewer/components/props.d.ts +10 -283
  22. package/dist/viewer/components/props.d.ts.map +1 -1
  23. package/dist/viewer/components/ribbon/insert/equation-latex-preview.d.ts +23 -0
  24. package/dist/viewer/components/ribbon/insert/equation-latex-preview.d.ts.map +1 -0
  25. package/dist/viewer/components/ribbon/ribbon-types.d.ts +2 -0
  26. package/dist/viewer/components/ribbon/ribbon-types.d.ts.map +1 -1
  27. package/dist/viewer/components/viewer-body-commits.d.ts +18 -0
  28. package/dist/viewer/components/viewer-body-commits.d.ts.map +1 -0
  29. package/dist/viewer/components/viewer-body-props.d.ts +125 -0
  30. package/dist/viewer/components/viewer-body-props.d.ts.map +1 -0
  31. package/dist/viewer/editor/context-menu-dispatch.d.ts +45 -0
  32. package/dist/viewer/editor/context-menu-dispatch.d.ts.map +1 -0
  33. package/dist/viewer/editor/deck-api.d.ts +31 -0
  34. package/dist/viewer/editor/deck-api.d.ts.map +1 -0
  35. package/dist/viewer/editor/editor-controller-deps.d.ts +21 -1
  36. package/dist/viewer/editor/editor-controller-deps.d.ts.map +1 -1
  37. package/dist/viewer/editor/editor-controller-wiring.d.ts +35 -0
  38. package/dist/viewer/editor/editor-controller-wiring.d.ts.map +1 -0
  39. package/dist/viewer/editor/editor-controller.svelte.d.ts.map +1 -1
  40. package/dist/viewer/editor/editor-document-lifecycle.d.ts +68 -0
  41. package/dist/viewer/editor/editor-document-lifecycle.d.ts.map +1 -0
  42. package/dist/viewer/editor/editor-document-state.d.ts +3 -1
  43. package/dist/viewer/editor/editor-document-state.d.ts.map +1 -1
  44. package/dist/viewer/editor/editor-freeform.d.ts +4 -0
  45. package/dist/viewer/editor/editor-freeform.d.ts.map +1 -0
  46. package/dist/viewer/editor/editor-history-state.svelte.d.ts +31 -0
  47. package/dist/viewer/editor/editor-history-state.svelte.d.ts.map +1 -0
  48. package/dist/viewer/editor/editor-ink-controller.svelte.d.ts +10 -6
  49. package/dist/viewer/editor/editor-ink-controller.svelte.d.ts.map +1 -1
  50. package/dist/viewer/editor/editor-keyboard.d.ts +18 -11
  51. package/dist/viewer/editor/editor-keyboard.d.ts.map +1 -1
  52. package/dist/viewer/editor/editor-selection.svelte.d.ts +10 -10
  53. package/dist/viewer/editor/editor-selection.svelte.d.ts.map +1 -1
  54. package/dist/viewer/editor/editor-state.svelte.d.ts +26 -19
  55. package/dist/viewer/editor/editor-state.svelte.d.ts.map +1 -1
  56. package/dist/viewer/editor/editor-text-body-mutations.d.ts +17 -0
  57. package/dist/viewer/editor/editor-text-body-mutations.d.ts.map +1 -0
  58. package/dist/viewer/editor/element-hit.d.ts +8 -26
  59. package/dist/viewer/editor/element-hit.d.ts.map +1 -1
  60. package/dist/viewer/editor/index.d.ts +2 -0
  61. package/dist/viewer/editor/index.d.ts.map +1 -1
  62. package/dist/viewer/export/export-wiring.svelte.d.ts +8 -1
  63. package/dist/viewer/export/export-wiring.svelte.d.ts.map +1 -1
  64. package/dist/viewer/export/rasterize-slide.d.ts +8 -1
  65. package/dist/viewer/export/rasterize-slide.d.ts.map +1 -1
  66. package/dist/viewer/index.d.ts +897 -342
  67. package/dist/viewer/index.js +20 -398
  68. package/dist/viewer/presentation/animation-media-commands.d.ts +4 -0
  69. package/dist/viewer/presentation/animation-media-commands.d.ts.map +1 -0
  70. package/dist/viewer/presentation/animation-playback-helpers.d.ts.map +1 -1
  71. package/dist/viewer/state/create-viewer-state-ai.svelte.d.ts +42 -0
  72. package/dist/viewer/state/create-viewer-state-ai.svelte.d.ts.map +1 -0
  73. package/dist/viewer/state/create-viewer-state-collab.svelte.d.ts +13 -0
  74. package/dist/viewer/state/create-viewer-state-collab.svelte.d.ts.map +1 -1
  75. package/dist/viewer/state/create-viewer-state-derived.svelte.d.ts +38 -0
  76. package/dist/viewer/state/create-viewer-state-derived.svelte.d.ts.map +1 -0
  77. package/dist/viewer/state/create-viewer-state-editor-ui.svelte.d.ts +21 -13
  78. package/dist/viewer/state/create-viewer-state-editor-ui.svelte.d.ts.map +1 -1
  79. package/dist/viewer/state/create-viewer-state-export-notes.svelte.d.ts +6 -1
  80. package/dist/viewer/state/create-viewer-state-export-notes.svelte.d.ts.map +1 -1
  81. package/dist/viewer/state/create-viewer-state-presentation.svelte.d.ts +3 -1
  82. package/dist/viewer/state/create-viewer-state-presentation.svelte.d.ts.map +1 -1
  83. package/dist/viewer/state/create-viewer-state-presenter.svelte.d.ts +31 -0
  84. package/dist/viewer/state/create-viewer-state-presenter.svelte.d.ts.map +1 -0
  85. package/dist/viewer/state/create-viewer-state-types.d.ts +43 -6
  86. package/dist/viewer/state/create-viewer-state-types.d.ts.map +1 -1
  87. package/dist/viewer/state/create-viewer-state.svelte.d.ts +17 -16
  88. package/dist/viewer/state/create-viewer-state.svelte.d.ts.map +1 -1
  89. package/dist/viewer/state/field-context.d.ts +38 -0
  90. package/dist/viewer/state/field-context.d.ts.map +1 -0
  91. package/dist/viewer/state/index.d.ts +4 -0
  92. package/dist/viewer/state/index.d.ts.map +1 -1
  93. package/dist/viewer/state/navigation.d.ts +9 -7
  94. package/dist/viewer/state/navigation.d.ts.map +1 -1
  95. package/dist/viewer/state/open-file.d.ts +15 -0
  96. package/dist/viewer/state/open-file.d.ts.map +1 -0
  97. package/dist/viewer/state/presentation-loader.svelte.d.ts +3 -1
  98. package/dist/viewer/state/presentation-loader.svelte.d.ts.map +1 -1
  99. package/dist/viewer/state/quick-access-commands.d.ts +19 -0
  100. package/dist/viewer/state/quick-access-commands.d.ts.map +1 -0
  101. package/dist/viewer/state/slide-elements.d.ts +51 -0
  102. package/dist/viewer/state/slide-elements.d.ts.map +1 -0
  103. package/dist/viewer/state/theme-locale.svelte.d.ts +68 -0
  104. package/dist/viewer/state/theme-locale.svelte.d.ts.map +1 -0
  105. package/dist/viewer/state/viewer-effects.svelte.d.ts.map +1 -1
  106. package/dist/viewer/state/viewer-state-options.d.ts +31 -0
  107. package/dist/viewer/state/viewer-state-options.d.ts.map +1 -0
  108. package/dist/viewer/style/element-style.d.ts.map +1 -1
  109. package/dist/viewer/style/text-style.d.ts +15 -0
  110. package/dist/viewer/style/text-style.d.ts.map +1 -1
  111. package/package.json +1 -1
  112. package/dist/AiChatPanel-BbVtEzOo.js +0 -1082
@@ -910,6 +910,27 @@ interface ShapeStyle {
910
910
  /** Raw `a:ln/a:pattFill` XML preserved for round-trip when the outline is
911
911
  * pattern-filled. Re-emitted verbatim as the line's single fill on save. */
912
912
  strokePatternXml?: XmlObject;
913
+ /**
914
+ * Structured stops of a gradient outline (`a:ln/a:gradFill/a:gsLst`), in the
915
+ * same shape as {@link fillGradientStops}.
916
+ *
917
+ * The raw XML above round-trips a gradient outline on save, but a renderer
918
+ * cannot paint from it: it needs resolved colours and positions. Without
919
+ * these, every binding fell back to {@link strokeColor} - a single averaged
920
+ * colour - so a two-tone outline painted flat and a fade-to-transparent
921
+ * outline painted fully opaque.
922
+ */
923
+ strokeGradientStops?: ShapeStyle['fillGradientStops'];
924
+ /** Gradient outline angle in OOXML degrees (`a:lin/@ang`), 0 = left to right. */
925
+ strokeGradientAngle?: number;
926
+ /** Gradient outline kind: `linear` (`a:lin`) or `radial` (`a:path`). */
927
+ strokeGradientType?: ShapeStyle['fillGradientType'];
928
+ /** Path-gradient shape for a radial outline (`a:path/@path`). */
929
+ strokeGradientPathType?: ShapeStyle['fillGradientPathType'];
930
+ /** Preset name of a pattern outline (`a:ln/a:pattFill/@prst`). */
931
+ strokePatternPreset?: string;
932
+ /** Background colour of a pattern outline (`a:ln/a:pattFill/a:bgClr`). */
933
+ strokePatternBackgroundColor?: string;
913
934
  strokeWidth?: number;
914
935
  strokeOpacity?: number;
915
936
  strokeDash?: StrokeDashType;
@@ -8607,6 +8628,37 @@ interface SnapLine {
8607
8628
  position: number;
8608
8629
  }
8609
8630
  //#endregion
8631
+ //#region src/render/text-field-substitution.d.ts
8632
+ /**
8633
+ * Text-field placeholder substitution, shared by every binding's text
8634
+ * renderer.
8635
+ *
8636
+ * Pure string logic: resolves OOXML field runs (slide number, date/time,
8637
+ * header/footer, document properties, slide title) into their display text.
8638
+ * Extracted from the React `viewer/utils/text-field-substitution` module so
8639
+ * every binding substitutes identically.
8640
+ */
8641
+ /** Context for substituting field placeholders (slide number, date/time, header/footer, etc.). */
8642
+ interface FieldSubstitutionContext {
8643
+ slideNumber?: number;
8644
+ dateTimeText?: string;
8645
+ /** OOXML date-format pattern from header/footer settings (e.g. "M/d/yyyy"). */
8646
+ dateFormat?: string;
8647
+ /** Footer text from PptxHeaderFooter settings. */
8648
+ footerText?: string;
8649
+ /** Header text from PptxHeaderFooter settings. */
8650
+ headerText?: string;
8651
+ /** Custom document properties for `docproperty` field substitution (keyed by property name). */
8652
+ customProperties?: ReadonlyArray<{
8653
+ name: string;
8654
+ value: string;
8655
+ }>;
8656
+ /** Locale string for date/time formatting (e.g. "en-US"). Falls back to browser default. */
8657
+ locale?: string;
8658
+ /** Title text extracted from the first title placeholder on the slide. */
8659
+ slideTitle?: string;
8660
+ }
8661
+ //#endregion
8610
8662
  //#region src/render/collaboration-presence.d.ts
8611
8663
  /** Connection lifecycle states for the Yjs WebSocket provider. */
8612
8664
  type ConnectionStatus = 'disconnected' | 'connecting' | 'connected' | 'error';
@@ -8879,6 +8931,10 @@ interface ElementClipboardPayload {
8879
8931
  //#endregion
8880
8932
  //#region src/render/template-editing.d.ts
8881
8933
  type TemplateElementMap = Record<string, PptxElement[]>;
8934
+ /** The percentage one zoom-in press moves to, clamped. */
8935
+ declare function zoomInPercent(percent: number): number;
8936
+ /** The percentage one zoom-out press moves to, clamped. */
8937
+ declare function zoomOutPercent(percent: number): number;
8882
8938
  //#endregion
8883
8939
  //#region src/render/viewer-preferences.d.ts
8884
8940
  /** Framework-neutral viewer preferences surfaced by Settings dialogs. */
@@ -8932,6 +8988,125 @@ type ToolbarButtonId = 'share' | 'broadcast' | 'export' | 'undo' | 'redo' | 'rec
8932
8988
  type ToolbarTabId = 'file' | 'home' | 'insert' | 'draw' | 'design' | 'transitions' | 'animations' | 'slideShow' | 'record' | 'review' | 'view' | 'help';
8933
8989
  type ToolbarActionId = ToolbarButtonId | ToolbarTabId;
8934
8990
  //#endregion
8991
+ //#region src/render/options/viewer-options.d.ts
8992
+ /**
8993
+ * Full PowerPoint "File > Options" parity model.
8994
+ *
8995
+ * Groups mirror the ten categories of PowerPoint's Options dialog. Values are
8996
+ * flat primitives per group so the dialog panes can be rendered generically
8997
+ * from `VIEWER_OPTIONS_SCHEMA` in every binding. The legacy six-toggle
8998
+ * `ViewerPreferences` surface stays supported via the mapping helpers below.
8999
+ */
9000
+ type ScreenTipStyle = 'descriptions' | 'plain' | 'off';
9001
+ type DisplayOptimization = 'appearance' | 'compatibility';
9002
+ type ImageResolutionPreset = 'highFidelity' | 'ppi330' | 'ppi220' | 'ppi150' | 'ppi96';
9003
+ type OpenDocumentsView = 'savedView' | 'normal' | 'outline' | 'slideSorter' | 'notes';
9004
+ type DefaultExportFormat = 'pptx' | 'pdf' | 'png';
9005
+ type QuickAccessPosition = 'above' | 'below';
9006
+ type FeedbackSoundScheme = 'modern' | 'classic';
9007
+ type OptionsPrintWhat = 'slides' | 'handouts' | 'notes' | 'outline';
9008
+ type OptionsPrintColorMode = 'color' | 'grayscale' | 'blackAndWhite';
9009
+ interface ViewerGeneralOptions {
9010
+ displayOptimization: DisplayOptimization;
9011
+ showMiniToolbar: boolean;
9012
+ enableLivePreview: boolean;
9013
+ collapseRibbonAutomatically: boolean;
9014
+ collapseSearchByDefault: boolean;
9015
+ screenTipStyle: ScreenTipStyle;
9016
+ userName: string;
9017
+ userInitials: string;
9018
+ showStartScreen: boolean;
9019
+ }
9020
+ interface ViewerProofingOptions {
9021
+ autoCorrectTwoInitialCapitals: boolean;
9022
+ autoCorrectCapitalizeFirstLetter: boolean;
9023
+ autoCorrectCapitalizeDayNames: boolean;
9024
+ autoCorrectSmartQuotes: boolean;
9025
+ autoCorrectHyphensToDash: boolean;
9026
+ autoCorrectFractions: boolean;
9027
+ autoCorrectOrdinals: boolean;
9028
+ ignoreUppercase: boolean;
9029
+ ignoreWordsWithNumbers: boolean;
9030
+ ignoreInternetAddresses: boolean;
9031
+ flagRepeatedWords: boolean;
9032
+ checkSpellingAsYouType: boolean;
9033
+ hideSpellingErrors: boolean;
9034
+ }
9035
+ interface ViewerSaveOptions {
9036
+ autoSave: boolean;
9037
+ autoRecoverIntervalMinutes: number;
9038
+ keepLastAutoRecoveredVersion: boolean;
9039
+ defaultExportFormat: DefaultExportFormat;
9040
+ embedFonts: boolean;
9041
+ embedAllFontCharacters: boolean;
9042
+ cacheRetentionDays: number;
9043
+ clearCacheOnClose: boolean;
9044
+ }
9045
+ interface ViewerAccessibilityOptions {
9046
+ showAccessibilityStatus: boolean;
9047
+ feedbackWithSound: boolean;
9048
+ soundScheme: FeedbackSoundScheme;
9049
+ showShortcutKeysInScreenTips: boolean;
9050
+ reducedMotion: boolean;
9051
+ }
9052
+ interface ViewerAdvancedOptions {
9053
+ autoSelectEntireWord: boolean;
9054
+ allowTextDragAndDrop: boolean;
9055
+ maximumUndoSteps: number;
9056
+ useSmartCutAndPaste: boolean;
9057
+ showPasteOptionsButton: boolean;
9058
+ imageDefaultResolution: ImageResolutionPreset;
9059
+ doNotCompressImages: boolean;
9060
+ chartPropertiesFollowDataPoint: boolean;
9061
+ recentPresentationsCount: number;
9062
+ showVerticalRuler: boolean;
9063
+ showGrid: boolean;
9064
+ snapToGrid: boolean;
9065
+ disableHardwareAcceleration: boolean;
9066
+ openDocumentsView: OpenDocumentsView;
9067
+ slideShowShowMenuOnRightClick: boolean;
9068
+ slideShowShowPopupToolbar: boolean;
9069
+ slideShowPromptKeepInkAnnotations: boolean;
9070
+ slideShowEndWithBlackSlide: boolean;
9071
+ printInBackground: boolean;
9072
+ printHighQuality: boolean;
9073
+ printUseMostRecentSettings: boolean;
9074
+ printWhat: OptionsPrintWhat;
9075
+ printColorMode: OptionsPrintColorMode;
9076
+ printHiddenSlides: boolean;
9077
+ printScaleToFit: boolean;
9078
+ printFrameSlides: boolean;
9079
+ }
9080
+ interface ViewerRibbonOptions {
9081
+ /** Ribbon tabs unticked in Customize Ribbon. The File tab can never be hidden. */
9082
+ hiddenTabIds: ToolbarTabId[];
9083
+ }
9084
+ interface ViewerQuickAccessOptions {
9085
+ visible: boolean;
9086
+ position: QuickAccessPosition;
9087
+ showCommandLabels: boolean;
9088
+ /** Ordered ids from `QUICK_ACCESS_COMMAND_CATALOG`. */
9089
+ commandIds: string[];
9090
+ }
9091
+ interface ViewerTrustOptions {
9092
+ openInProtectedView: boolean;
9093
+ allowExternalContent: boolean;
9094
+ confirmExternalHyperlinks: boolean;
9095
+ }
9096
+ interface ViewerOptions {
9097
+ general: ViewerGeneralOptions;
9098
+ proofing: ViewerProofingOptions;
9099
+ save: ViewerSaveOptions;
9100
+ accessibility: ViewerAccessibilityOptions;
9101
+ advanced: ViewerAdvancedOptions;
9102
+ ribbon: ViewerRibbonOptions;
9103
+ quickAccess: ViewerQuickAccessOptions;
9104
+ trust: ViewerTrustOptions;
9105
+ }
9106
+ type ViewerOptionsGroupId = keyof ViewerOptions;
9107
+ type ViewerOptionPrimitive = boolean | number | string;
9108
+ type StoredViewerOptions = { [G in ViewerOptionsGroupId]?: Partial<ViewerOptions[G]>; };
9109
+ //#endregion
8935
9110
  //#region src/export/handout-layout.d.ts
8936
9111
  /**
8937
9112
  * Pure handout layout calculations, shared by every binding's print path.
@@ -8963,7 +9138,34 @@ interface PrintSettings {
8963
9138
  customRangeFrom: number;
8964
9139
  customRangeTo: number;
8965
9140
  }
9141
+ interface ViewerOptionsStoreInit {
9142
+ /** Seed values layered over defaults before persisted values are applied. */
9143
+ initial?: StoredViewerOptions;
9144
+ /** Skip localStorage entirely (hosts that own persistence themselves). */
9145
+ persist?: boolean;
9146
+ }
8966
9147
 
9148
+ //#endregion
9149
+ //#region src/ai/change-diff.d.ts
9150
+ /** What kind of change an element underwent. */
9151
+ type AiChangeKind = 'added' | 'removed' | 'moved' | 'resized' | 'restyled' | 'text';
9152
+ /** Axis-aligned bounds in slide (CSS pixel) coordinates. */
9153
+ interface AiChangeBounds {
9154
+ x: number;
9155
+ y: number;
9156
+ width: number;
9157
+ height: number;
9158
+ }
9159
+ /** One element's change, with old/new bounds for motion. */
9160
+ interface AiElementChange {
9161
+ slideIndex: number;
9162
+ elementId: string;
9163
+ kind: AiChangeKind;
9164
+ /** Bounds before the edit (present for removed / moved / resized). */
9165
+ from?: AiChangeBounds;
9166
+ /** Bounds after the edit (present for added / moved / resized / restyled / text). */
9167
+ to?: AiChangeBounds;
9168
+ }
8967
9169
  //#endregion
8968
9170
  //#region src/ai/change-animator.d.ts
8969
9171
  /** Host-tunable options for how AI edits are animated on the canvas. */
@@ -8979,6 +9181,23 @@ interface AiChangeAnimationConfig {
8979
9181
  /** Accent colour (any CSS colour) for the glow/ghosts. Default a blue. */
8980
9182
  color?: string;
8981
9183
  }
9184
+ /** Config with every field resolved to a concrete value. */
9185
+ interface ResolvedAiChangeAnimationConfig {
9186
+ enabled: boolean;
9187
+ durationMs: number;
9188
+ glow: boolean;
9189
+ tween: boolean;
9190
+ color: string;
9191
+ }
9192
+ /** One batch of changes to animate, plus the slide to reveal for it. */
9193
+ interface AiChangeBatch {
9194
+ changes: AiElementChange[];
9195
+ /** Slide index the first change lives on (reveal this to show the edit). */
9196
+ slideIndex: number;
9197
+ /** Monotonic id so a binding can restart its animation on each new batch. */
9198
+ nonce: number;
9199
+ config: ResolvedAiChangeAnimationConfig;
9200
+ }
8982
9201
  //#endregion
8983
9202
  //#region src/ai/config.d.ts
8984
9203
  /** The UI message shape exchanged with the assistant. Alias of the SDK type. */
@@ -9184,6 +9403,26 @@ interface PptxAiBridge {
9184
9403
  /** Surface a transient message in the host UI (toast / status line). */
9185
9404
  notify?(message: string, level?: PptxAiNotifyLevel): void;
9186
9405
  }
9406
+ //#endregion
9407
+ //#region src/ai/tool-target.d.ts
9408
+ /**
9409
+ * Pure derivation of the on-canvas focus target a running tool refers to, so
9410
+ * the viewer can behave like a live collaborator: as the assistant reads or
9411
+ * edits the deck, the canvas navigates to the relevant slide and highlights the
9412
+ * element(s) the tool is touching.
9413
+ *
9414
+ * The mapping is intentionally structural (it reads well-known input fields:
9415
+ * `slideIndex`, `elementId`, `elementIdA/B`, `elementIds`, `slideIndexes`,
9416
+ * `newOrder`) and framework-agnostic, so every binding drives the same live
9417
+ * focus. It NEVER performs navigation itself; it only says "what to look at".
9418
+ */
9419
+ /** The slide / element(s) a tool invocation is focused on. */
9420
+ interface ToolCanvasTarget {
9421
+ /** Zero-based slide index to navigate to, when the tool names one. */
9422
+ slideIndex?: number;
9423
+ /** Element ids on that slide to highlight (may be empty for slide-level tools). */
9424
+ elementIds: string[];
9425
+ }
9187
9426
 
9188
9427
  //#endregion
9189
9428
  //#region src/i18n/locale-catalog.d.ts
@@ -9654,101 +9893,256 @@ interface PowerPointViewerApi extends PowerPointViewerAPI {
9654
9893
  */
9655
9894
  declare const PowerPointViewer: Component<PowerPointViewerProps, PowerPointViewerApi>;
9656
9895
 
9657
- /**
9658
- * Shared value types for the Svelte editing layer.
9659
- */
9660
- /** Box geometry in element (unscaled slide) px. */
9661
- interface OverlayBox {
9662
- x: number;
9663
- y: number;
9664
- width: number;
9665
- height: number;
9666
- rotation: number;
9667
- }
9668
-
9669
- interface EditorControllerDeps {
9670
- getScale(): number;
9671
- getCurrent(): number;
9672
- getPresenting(): boolean;
9673
- getStageRoot(): Element | null;
9674
- getHolderEl(): HTMLElement | null;
9675
- onCursorMove?(x: number, y: number): void;
9676
- onContextMenu?(x: number, y: number): void;
9677
- getSnapToGrid?(): boolean;
9678
- getSnapToShape?(): boolean;
9679
- getGuides?(): readonly {
9680
- axis: 'h' | 'v';
9681
- position: number;
9682
- }[];
9896
+ interface SlideCanvasProps {
9897
+ slide: PptxSlide | undefined;
9898
+ canvasSize: CanvasSize;
9899
+ mediaDataUrls: Map<string, string>;
9900
+ /** Effective scale (fit-to-viewport x user zoom), pre-computed by the host. */
9901
+ scale: number;
9902
+ /** True only on the live presentation stage; see `SlideStageProps.presenting`. */
9903
+ presenting?: boolean;
9904
+ /** True while in-place editing is available; gates the pointer handlers and the editing cursor/class. */
9905
+ editingActive?: boolean;
9906
+ editTemplateMode?: boolean;
9907
+ ontablecellcommit?: (elementId: string, rowIndex: number, cellIndex: number, text: string) => void;
9908
+ onsmartartnodecommit?: (elementId: string, nodeId: string, text: string) => void;
9909
+ onsmartartnodefill?: (elementId: string, nodeId: string, fill: string) => void;
9910
+ /** Reports the stage-holder node to the host on mount/teardown (editing hit-surface, export capture anchor). */
9911
+ onstageholder?: (el: HTMLDivElement | null) => void;
9912
+ onstagepointerdown?: (event: PointerEvent) => void;
9913
+ onstagepointermove?: (event: PointerEvent) => void;
9914
+ onstagedblclick?: (event: MouseEvent) => void;
9915
+ onstagecontextmenu?: (event: MouseEvent) => void;
9916
+ /** Fired on any stage click; the host wires this to advance presentation playback. */
9917
+ onstageclick?: (event: MouseEvent) => void;
9683
9918
  /**
9684
- * Transform inline-editor text at commit time (File > Options > Proofing
9685
- * AutoCorrect); identity when unset.
9919
+ * True while the AI panel is picking an element: the next element click(s)
9920
+ * become the assistant's focus (highlighted) instead of selecting / editing.
9686
9921
  */
9687
- transformCommittedText?(text: string): string;
9922
+ aiPickMode?: boolean;
9688
9923
  /**
9689
- * Collaboration live-preview channel. Inline text only reaches the slides
9690
- * state on commit, so peers saw nothing while a peer typed; each keystroke is
9691
- * published through this instead. Omit outside a collaborative viewer.
9924
+ * True while a running AI tool is active: the stage marks itself
9925
+ * `data-pptx-ai-active` so element colour changes tween while the assistant
9926
+ * works (see AiFocusHighlightOverlay's tween rule).
9692
9927
  */
9693
- getLivePatcher?(): CollaborationLivePatcher | undefined;
9694
- /** The slide the inline-edited element belongs to (live-preview lookup). */
9695
- getActiveSlide?(): PptxSlide | undefined;
9928
+ aiActive?: boolean;
9929
+ /** Route a picked canvas element to the AI focus (pick mode only). */
9930
+ onaipickelement?: (elementId: string) => void;
9931
+ /**
9932
+ * Overlay content layered above the slide (selection/editor layer, ink
9933
+ * drawing, alignment guides, presentation annotations, collaboration
9934
+ * cursors, transition overlay, ...). Rendered inside the same
9935
+ * fixed-size, scaled stage-holder as the slide itself. Kept out of this
9936
+ * component's own props (rather than a fixed list of overlay slots) so it
9937
+ * stays free of the live editor/controller instances those overlays need.
9938
+ */
9939
+ children?: svelte.Snippet;
9696
9940
  }
9697
9941
 
9698
9942
  /**
9699
- * Pure, immutable slide-array mutations for the Svelte editor.
9943
+ * ExportUiState: reactive state behind the toolbar `ExportMenu` and the
9944
+ * `ExportProgressModal`. Svelte port of Vue's `useExportProgress` composable:
9945
+ * it owns the modal state (open / title / progress / status), the
9946
+ * `AbortController` the export loops check between slides, and wraps each
9947
+ * multi-slide export (PDF / GIF / WebM) in a `begin -> run -> end` envelope.
9948
+ * All percentage maths + status labels come from `pptx-viewer-shared`
9949
+ * (`export-progress.ts`) so every binding shows identical progress.
9700
9950
  *
9701
- * Mirrors the vanilla binding's `editor-mutations` (in turn the Vue binding's
9702
- * `useEditorOperations` commit helpers), minus the reactivity: every function
9703
- * takes the current `PptxSlide[]` and returns a brand-new array (untouched
9704
- * slides are reused by reference so the render layer can cheaply detect
9705
- * changes). All cloning defers to the core helpers (`cloneSlide`,
9706
- * `cloneElement`, `duplicateElement`); nothing is mutated in place.
9951
+ * PNG (single slide, fast) and print (opens its own surface) run without the
9952
+ * modal; the menu trigger still disables via {@link exporting} while they run.
9707
9953
  */
9708
- /** Geometry patch applied by drag / resize / rotate / nudge. */
9709
- interface ElementBoxPatch {
9710
- x: number;
9711
- y: number;
9712
- width: number;
9713
- height: number;
9714
- rotation: number;
9954
+ interface ExportUiDeps {
9955
+ controller: ExportController;
9956
+ getTranslator(): Translator;
9957
+ /**
9958
+ * Fired after an export completes successfully (Options > Accessibility
9959
+ * "feedback with sound" hook); not called on abort or failure.
9960
+ */
9961
+ onComplete?(): void;
9715
9962
  }
9716
-
9717
- interface EditorMarqueeRect extends MarqueeRect {
9718
- additive: boolean;
9963
+ declare class ExportUiState {
9964
+ #private;
9965
+ /** Whether the progress modal is visible. */
9966
+ open: boolean;
9967
+ /** Modal heading (e.g. "Export as PDF"). */
9968
+ title: string;
9969
+ /** Current progress, 0-100. */
9970
+ progress: number;
9971
+ /** Status line under the bar (e.g. "Rendering slide 3 of 10..."). */
9972
+ status: string;
9973
+ constructor(deps: ExportUiDeps);
9974
+ /** True while any export runs (disables the menu trigger). */
9975
+ get exporting(): boolean;
9976
+ /** Export the current slide as PNG (no modal; quick single capture). */
9977
+ runPng(): void;
9978
+ /** Copy the current slide to the system image clipboard. */
9979
+ runCopyImage(): void;
9980
+ /** Run the PDF export with the progress modal wired. */
9981
+ runPdf(): Promise<void>;
9982
+ /** Run the animated-GIF export with the progress modal wired. */
9983
+ runGif(): Promise<void>;
9984
+ /** Run the WebM video export with the progress modal wired. */
9985
+ runVideo(): Promise<void>;
9986
+ /** Run the print flow (no modal; the print surface takes over). */
9987
+ runPrint(options?: PrintOptions): void;
9988
+ /** Cancel the in-flight export (aborts the loop, closes the modal). */
9989
+ cancel(): void;
9719
9990
  }
9720
9991
 
9721
9992
  /**
9722
- * Element-animation actions for the ribbon's Animations tab, split out of
9723
- * `EditorState` to keep it under the repo's 300-LOC budget.
9993
+ * autosave.svelte.ts: debounced crash-recovery autosave for the Svelte viewer.
9724
9994
  *
9725
- * Animation data lives on the SLIDE (`PptxSlide.animations`, keyed by
9726
- * `elementId`), not on the element itself, matching how the presentation
9727
- * playback state machine reads it (`buildClickGroups` in
9728
- * `presentation/animation-playback.svelte.ts`). Both actions target the
9729
- * currently selected element and route through the shared
9730
- * `animation-authoring.ts` "coarse group preset" model (`applyAnimationPreset`
9731
- * / `removeElementAnimation`), the same one the Vue/vanilla ribbons use:
9732
- * applying a preset sets one of entrance/emphasis/exit without touching the
9733
- * others; remove drops the whole entry. Both mutations go through
9734
- * `EditorState.commitSlides`, so they are history-integrated (undoable).
9995
+ * A runes port that fuses the two shared semantics the other bindings use:
9996
+ * - React's persistence target: each successful save writes the serialized
9997
+ * `.pptx` bytes to the shared IndexedDB recovery store
9998
+ * (`saveAutosaveSnapshot`, keyed by `filePath`), so a host can offer
9999
+ * restore-on-load with `getAutosaveSnapshot` / `listAutosaveSnapshots`
10000
+ * (both re-exported from this package). This binding does NOT auto-restore;
10001
+ * matching React/Vue, recovery is a host concern.
10002
+ * - Vue's debounce-on-edit trigger: an edit marks the document dirty and
10003
+ * (re)arms a debounce timer instead of polling on a fixed interval.
10004
+ *
10005
+ * The controller registers its own edit-watching `$effect` in the constructor,
10006
+ * so the SFC only has to construct it once during setup and read its reactive
10007
+ * `status` / `isDirty` for the toolbar indicator.
9735
10008
  */
9736
- declare class EditorAnimationController {
10009
+ /**
10010
+ * Autosave status, surfaced for the toolbar status pill.
10011
+ *
10012
+ * - `idle` : nothing has been saved yet (or no edits since mount).
10013
+ * - `disabled` : autosave is inactive (off, not editable, or no file path).
10014
+ * - `saving` : a save is currently in flight.
10015
+ * - `saved` : the most recent save succeeded.
10016
+ * - `error` : the most recent save threw.
10017
+ */
10018
+ type AutosaveStatus = 'idle' | 'disabled' | 'saving' | 'saved' | 'error';
10019
+ interface AutosaveDeps {
10020
+ /** Master on/off: host `autosave` prop AND editing allowed. */
10021
+ getEnabled: () => boolean;
10022
+ /** Debounce window in milliseconds. */
10023
+ getIntervalMs: () => number;
10024
+ /** IndexedDB record key (host `filePath`); autosave is disabled without one. */
10025
+ getFilePath: () => string | undefined;
10026
+ /** The current editable slides (watched for edits). */
10027
+ getSlides: () => PptxSlide[];
10028
+ getSlideMasters?: () => PptxSlideMaster[];
10029
+ getNotesMaster?: () => PptxNotesMaster | undefined;
10030
+ getHandoutMaster?: () => PptxHandoutMaster | undefined;
10031
+ getSections?: () => PptxSection[];
10032
+ /** The live core handler used to serialize slides to `.pptx` bytes. */
10033
+ getHandler: () => PptxHandler | null;
10034
+ /**
10035
+ * Monotonic load counter: a change means a fresh presentation was seeded (not
10036
+ * a user edit), so the watcher clears dirty instead of arming a save.
10037
+ */
10038
+ getLoadCount: () => number;
10039
+ /** Host callback with the freshly-serialized bytes on each successful save. */
10040
+ onSaved?: (bytes: Uint8Array) => void;
10041
+ }
10042
+ declare class AutosaveController {
9737
10043
  #private;
9738
- constructor(editor: EditorState);
9739
- addAnimation(group: AnimationGroup, preset: PptxAnimationPreset): void;
9740
- removeAnimation(): void;
10044
+ /** Current autosave lifecycle status (reactive). */
10045
+ status: AutosaveStatus;
10046
+ /** Whether there are unsaved edits pending (reactive). */
10047
+ isDirty: boolean;
10048
+ /** Epoch ms of the last successful save, or null (reactive). */
10049
+ lastSavedAt: number | null;
10050
+ constructor(deps: AutosaveDeps);
10051
+ /** Force an immediate save, bypassing the debounce window. */
10052
+ save(): Promise<void>;
9741
10053
  }
9742
10054
 
9743
10055
  /**
9744
- * The Home tab's multi-select-aware Arrange group (align / distribute /
9745
- * flip / group / ungroup), split out of `EditorState` to keep it under the
9746
- * repo's 300-LOC budget. Reads `editor.selection.ids` (the ordered
9747
- * multi-selection) rather than just the primary id, matching React's
9748
- * `selectedElementIds` semantics.
10056
+ * Prop contracts for the viewer chrome around the canvas: the compact
10057
+ * toolbar, the thumbnail rail, and the speaker-notes panel. Split out of
10058
+ * `props.ts` for the repo's file-size budget; import them from `./props`,
10059
+ * which re-exports this module.
9749
10060
  */
9750
- declare class EditorArrangeController {
9751
- #private;
10061
+ interface ViewerToolbarProps {
10062
+ /** Active slide (0-based). */
10063
+ current: number;
10064
+ total: number;
10065
+ /** Currently-effective zoom percent (rounded). */
10066
+ zoomPercent: number;
10067
+ isFullscreen: boolean;
10068
+ onprev: () => void;
10069
+ onnext: () => void;
10070
+ onzoomin: () => void;
10071
+ onzoomout: () => void;
10072
+ onzoomfit: () => void;
10073
+ onfullscreen: () => void;
10074
+ /** Whether the Notes toggle button is shown (host has a notes panel). */
10075
+ showNotes?: boolean;
10076
+ /** Whether the notes panel is currently expanded (drives the pressed state). */
10077
+ notesExpanded?: boolean;
10078
+ onnotestoggle?: () => void;
10079
+ /** Show the editing action group (Undo / Redo / Save). Default false. */
10080
+ editable?: boolean;
10081
+ /** Whether an undo step is available (drives the Undo button's disabled state). */
10082
+ canUndo?: boolean;
10083
+ /** Whether a redo step is available (drives the Redo button's disabled state). */
10084
+ canRedo?: boolean;
10085
+ /** Whether there are unsaved edits (drives the Save button's emphasis). */
10086
+ dirty?: boolean;
10087
+ onundo?: () => void;
10088
+ onredo?: () => void;
10089
+ onsave?: () => void;
10090
+ ondownload?: () => void;
10091
+ /**
10092
+ * Autosave lifecycle status; when set (host opted into `autosave`) a small
10093
+ * status pill renders in the editing group. Omit to hide the pill entirely.
10094
+ */
10095
+ autosaveStatus?: AutosaveStatus;
10096
+ /** Whether there are unsaved autosave edits (drives the pill's "dirty" tone). */
10097
+ autosaveDirty?: boolean;
10098
+ /**
10099
+ * Export menu state (PNG / PDF / GIF / video / print). When set, the
10100
+ * toolbar renders the `ExportMenu` dropdown in its right-hand group,
10101
+ * matching the export affordance the React/Vue/Angular chrome exposes.
10102
+ * Omit to hide the menu (e.g. while no presentation is loaded).
10103
+ */
10104
+ exportUi?: ExportUiState;
10105
+ /** Opens the Share (collaboration) dialog. Omit to hide the button. */
10106
+ onshare?: () => void;
10107
+ /** Opens the Broadcast dialog. Omit to hide the button. */
10108
+ onbroadcast?: () => void;
10109
+ /** Whether a collaboration session is currently active (highlights the Share button). */
10110
+ collabActive?: boolean;
10111
+ /** Toolbar buttons to hide; see `PowerPointViewerProps.hiddenActions`. Default undefined: nothing hidden. */
10112
+ hiddenActions?: ToolbarActionId[];
10113
+ }
10114
+
10115
+ /**
10116
+ * Element-animation actions for the ribbon's Animations tab, split out of
10117
+ * `EditorState` to keep it under the repo's 300-LOC budget.
10118
+ *
10119
+ * Animation data lives on the SLIDE (`PptxSlide.animations`, keyed by
10120
+ * `elementId`), not on the element itself, matching how the presentation
10121
+ * playback state machine reads it (`buildClickGroups` in
10122
+ * `presentation/animation-playback.svelte.ts`). Both actions target the
10123
+ * currently selected element and route through the shared
10124
+ * `animation-authoring.ts` "coarse group preset" model (`applyAnimationPreset`
10125
+ * / `removeElementAnimation`), the same one the Vue/vanilla ribbons use:
10126
+ * applying a preset sets one of entrance/emphasis/exit without touching the
10127
+ * others; remove drops the whole entry. Both mutations go through
10128
+ * `EditorState.commitSlides`, so they are history-integrated (undoable).
10129
+ */
10130
+ declare class EditorAnimationController {
10131
+ #private;
10132
+ constructor(editor: EditorState);
10133
+ addAnimation(group: AnimationGroup, preset: PptxAnimationPreset): void;
10134
+ removeAnimation(): void;
10135
+ }
10136
+
10137
+ /**
10138
+ * The Home tab's multi-select-aware Arrange group (align / distribute /
10139
+ * flip / group / ungroup), split out of `EditorState` to keep it under the
10140
+ * repo's 300-LOC budget. Reads `editor.selection.ids` (the ordered
10141
+ * multi-selection) rather than just the primary id, matching React's
10142
+ * `selectedElementIds` semantics.
10143
+ */
10144
+ declare class EditorArrangeController {
10145
+ #private;
9752
10146
  constructor(editor: EditorState);
9753
10147
  /** Align every selected element to `edge` (needs >= 2 selected). */
9754
10148
  alignSelected(edge: AlignEdge): void;
@@ -9799,6 +10193,71 @@ declare class EditorClipboardController {
9799
10193
  pasteClipboard(): string | null;
9800
10194
  }
9801
10195
 
10196
+ interface EditorSnapshot {
10197
+ slides: PptxSlide[];
10198
+ templateElementsBySlideId: TemplateElementMap;
10199
+ slideMasters: PptxSlideMaster[];
10200
+ notesMaster: PptxNotesMaster | undefined;
10201
+ handoutMaster: PptxHandoutMaster | undefined;
10202
+ sections: PptxSection[];
10203
+ headerFooter: PptxHeaderFooter;
10204
+ presentationProperties: PptxPresentationProperties;
10205
+ customShows: PptxCustomShow[];
10206
+ coreProperties: PptxCoreProperties | undefined;
10207
+ appProperties: PptxAppProperties | undefined;
10208
+ customProperties: PptxCustomProperty[];
10209
+ /** `ppt/tags/*.xml` name/value metadata, editable in the inspector. */
10210
+ tagCollections: PptxTagCollection[];
10211
+ }
10212
+
10213
+ /**
10214
+ * Deck-level lifecycle for {@link EditorState}: adopting a freshly loaded
10215
+ * document, resetting, taking a remote (collaboration) snapshot, restoring an
10216
+ * undo snapshot, editing document metadata, and serialising back to bytes.
10217
+ *
10218
+ * These are free functions over the state rather than methods because
10219
+ * `EditorState` is already a facade over thirteen focused controllers, and
10220
+ * document lifecycle is simply the fourteenth concern; keeping it here is what
10221
+ * holds that file within the repo's file-size budget.
10222
+ */
10223
+ /**
10224
+ * Everything a load hands the editor, in the order `PptxHandler` produces it.
10225
+ * Declared once here as a labelled tuple so `EditorState.setSlides` can forward
10226
+ * it verbatim without restating eleven parameters (and their defaults).
10227
+ */
10228
+ type LoadDocumentArgs = [
10229
+ slides: PptxSlide[],
10230
+ slideMasters?: PptxSlideMaster[],
10231
+ notesMaster?: PptxNotesMaster,
10232
+ handoutMaster?: PptxHandoutMaster,
10233
+ sections?: PptxSection[],
10234
+ coreProperties?: PptxCoreProperties,
10235
+ appProperties?: PptxAppProperties,
10236
+ customProperties?: PptxCustomProperty[],
10237
+ headerFooter?: PptxHeaderFooter,
10238
+ presentationProperties?: PptxPresentationProperties,
10239
+ customShows?: PptxCustomShow[]
10240
+ ];
10241
+
10242
+ /**
10243
+ * Pure, immutable slide-array mutations for the Svelte editor.
10244
+ *
10245
+ * Mirrors the vanilla binding's `editor-mutations` (in turn the Vue binding's
10246
+ * `useEditorOperations` commit helpers), minus the reactivity: every function
10247
+ * takes the current `PptxSlide[]` and returns a brand-new array (untouched
10248
+ * slides are reused by reference so the render layer can cheaply detect
10249
+ * changes). All cloning defers to the core helpers (`cloneSlide`,
10250
+ * `cloneElement`, `duplicateElement`); nothing is mutated in place.
10251
+ */
10252
+ /** Geometry patch applied by drag / resize / rotate / nudge. */
10253
+ interface ElementBoxPatch {
10254
+ x: number;
10255
+ y: number;
10256
+ width: number;
10257
+ height: number;
10258
+ rotation: number;
10259
+ }
10260
+
9802
10261
  /**
9803
10262
  * Z-order (paint-order) reordering for the Svelte editor.
9804
10263
  *
@@ -9852,13 +10311,44 @@ declare class EditorFormatPainterController {
9852
10311
  cancel(): void;
9853
10312
  }
9854
10313
 
10314
+ /**
10315
+ * The editor's undo/redo stack, wrapped so `canUndo` / `canRedo` are runes the
10316
+ * chrome can read directly.
10317
+ *
10318
+ * The shared {@link EditorHistory} is a plain (non-reactive) structure, so
10319
+ * every mutation has to be followed by a flag re-read; doing that in one place
10320
+ * here is what stops a missed `#syncHistoryFlags()` call leaving the ribbon's
10321
+ * Undo button greyed out after a real edit. Extracted from `EditorState` to
10322
+ * keep that file within the repo's file-size budget.
10323
+ */
10324
+ declare class EditorHistoryState {
10325
+ #private;
10326
+ get canUndo(): boolean;
10327
+ get canRedo(): boolean;
10328
+ /** Re-read the stack's availability flags onto the reactive mirrors. */
10329
+ sync(): void;
10330
+ /**
10331
+ * Apply the File > Options "maximum number of undos" value. Recreates the
10332
+ * stack when the depth changes (PowerPoint likewise applies the new maximum
10333
+ * going forward; existing entries are dropped).
10334
+ */
10335
+ setDepth(depth: number): void;
10336
+ record(snapshot: EditorSnapshot): void;
10337
+ clear(): void;
10338
+ undo(current: EditorSnapshot): EditorSnapshot | undefined;
10339
+ redo(current: EditorSnapshot): EditorSnapshot | undefined;
10340
+ }
10341
+
9855
10342
  /**
9856
10343
  * The ribbon Draw tab's active tool. `'select'` means "not drawing": the
9857
10344
  * stage's normal selection/drag/resize gestures own the pointer, matching
9858
- * React's `DrawingTool` / Angular's `DrawTool` conventions (minus `freeform`,
9859
- * out of scope for this wave; see the Draw tab's JSDoc).
10345
+ * React's `DrawingTool` / Angular's `DrawTool`.
10346
+ *
10347
+ * `freeform` shares the pen's gesture but commits a closed custom-geometry
10348
+ * SHAPE rather than an ink stroke, so the result is editable/fillable like any
10349
+ * other shape; see `editor-freeform.ts`.
9860
10350
  */
9861
- type InkDrawTool = 'select' | 'pen' | 'highlighter' | 'eraser';
10351
+ type InkDrawTool = 'select' | 'pen' | 'highlighter' | 'eraser' | 'freeform';
9862
10352
  /**
9863
10353
  * EditorInkController: the ribbon Draw tab's tool/colour/width state plus the
9864
10354
  * pure element-factory / erase mutations, split out of `EditorState` to keep
@@ -9897,9 +10387,10 @@ declare class EditorInkController {
9897
10387
  /** Update the live preview path while a pen/highlighter stroke is in progress. */
9898
10388
  previewStroke(points: readonly InkPoint[]): void;
9899
10389
  /**
9900
- * Finalise the in-progress stroke into a new `ink` element (undoable via
9901
- * `EditorState.insertElement`), or discard it silently when too short (a
9902
- * plain tap) or the tool changed mid-gesture.
10390
+ * Finalise the in-progress stroke (undoable via `EditorState.insertElement`),
10391
+ * or discard it silently when too short (a plain tap) or the tool changed
10392
+ * mid-gesture. Pen/highlighter commit an `ink` element; freeform commits a
10393
+ * closed custom-geometry `shape`.
9903
10394
  */
9904
10395
  commitStroke(points: readonly InkPoint[]): void;
9905
10396
  /**
@@ -9964,16 +10455,6 @@ declare class EditorSectionController {
9964
10455
  private commit;
9965
10456
  }
9966
10457
 
9967
- /**
9968
- * EditorSelection: the reactive multi-element selection for the Svelte editor.
9969
- *
9970
- * Holds an ordered list of selected element ids; the LAST id is the primary
9971
- * selection (the one the overlay handles, gestures, and inline editing act
9972
- * on), matching the React binding's `selectedElementIds` + primary convention.
9973
- * Plain clicks call {@link set} (single selection), shift/ctrl clicks call
9974
- * {@link toggle} (additive), and mutations that invalidate ids call
9975
- * {@link prune}.
9976
- */
9977
10458
  declare class EditorSelection {
9978
10459
  #private;
9979
10460
  /** All selected ids in selection order (primary last). */
@@ -10078,6 +10559,12 @@ declare class EditorState {
10078
10559
  coreProperties: PptxCoreProperties | undefined;
10079
10560
  appProperties: PptxAppProperties | undefined;
10080
10561
  customProperties: PptxCustomProperty[];
10562
+ /**
10563
+ * The deck's `ppt/tags/*.xml` name/value metadata. Seeded from the load via
10564
+ * {@link adoptTagCollections} and edited by the inspector's Tags section;
10565
+ * carried through the undo snapshot and re-emitted on save.
10566
+ */
10567
+ tagCollections: PptxTagCollection[];
10081
10568
  masterViewTarget: MasterViewTarget | null;
10082
10569
  readonly selection: EditorSelection;
10083
10570
  editable: boolean;
@@ -10085,6 +10572,8 @@ declare class EditorState {
10085
10572
  editTemplateMode: boolean;
10086
10573
  interactionActive: boolean;
10087
10574
  clipboard: ElementClipboardPayload | null;
10575
+ /** Undo/redo stack; the `canUndo` / `canRedo` getters below mirror it. */
10576
+ readonly history: EditorHistoryState;
10088
10577
  readonly clipboardOps: EditorClipboardController;
10089
10578
  readonly elementOps: EditorElementController;
10090
10579
  readonly templateOps: EditorTemplateController;
@@ -10114,29 +10603,15 @@ declare class EditorState {
10114
10603
  /** The loaded core handler, or null before a deck is open. Used by the
10115
10604
  * Slides group for layout switching (`applyLayoutToSlide`). */
10116
10605
  getHandler(): PptxHandler | null;
10117
- setSlides(slides: PptxSlide[], slideMasters?: PptxSlideMaster[], notesMaster?: PptxNotesMaster, handoutMaster?: PptxHandoutMaster, sections?: PptxSection[], coreProperties?: PptxCoreProperties, appProperties?: PptxAppProperties, customProperties?: PptxCustomProperty[], headerFooter?: PptxHeaderFooter, presentationProperties?: PptxPresentationProperties, customShows?: PptxCustomShow[]): void;
10118
- /**
10119
- * Replace the working slides with a remote (collaboration) snapshot without
10120
- * recording an undo step or touching the dirty flag: the granular reconcile
10121
- * already merged the peer's change, and treating an incoming remote edit as
10122
- * a local mutation would both pollute the undo stack and re-broadcast it.
10123
- *
10124
- * Selection is preserved when the selected element still exists so a remote
10125
- * edit does not yank the local user's selection out from under them. Local
10126
- * undo history is intentionally kept (see the collaboration module JSDoc):
10127
- * shared defines no collaborative-undo semantics, so, matching React/Vue,
10128
- * local undo may fight a concurrent remote edit.
10129
- */
10606
+ /** Adopt a freshly loaded deck as the working document (see `loadEditorDocument`). */
10607
+ setSlides(...args: LoadDocumentArgs): void;
10608
+ /** Adopt a remote (collaboration) snapshot; see `applyRemoteEditorSlides`. */
10130
10609
  applyRemoteSlides(slides: PptxSlide[]): void;
10131
10610
  reset(): void;
10132
10611
  select(id: string | null): void;
10133
10612
  isElementInteractive(id: string): boolean;
10134
10613
  setTemplateEditing(enabled: boolean): void;
10135
- /**
10136
- * Apply the File > Options "maximum number of undos" value. Recreates the
10137
- * history stack when the depth changes (PowerPoint likewise applies the new
10138
- * maximum going forward; existing entries are dropped).
10139
- */
10614
+ /** Apply the File > Options "maximum number of undos" value. */
10140
10615
  setHistoryDepth(depth: number): void;
10141
10616
  pushHistory(): void;
10142
10617
  commitChange(): void;
@@ -10152,6 +10627,8 @@ declare class EditorState {
10152
10627
  * undoable step). No-op when not editable.
10153
10628
  */
10154
10629
  commitSlides(next: PptxSlide[]): void;
10630
+ /** A deep clone of the whole editable document (one undo entry, or save input). */
10631
+ snapshot(): EditorSnapshot;
10155
10632
  deleteSelected: () => void;
10156
10633
  duplicateSelected: () => string | null;
10157
10634
  applyElementPatch: (id: string, patch: Partial<PptxElement>) => void;
@@ -10162,11 +10639,107 @@ declare class EditorState {
10162
10639
  commitInlineText: (id: string, text: string) => void;
10163
10640
  commitNotes: (notes: string, notesSegments?: TextSegment[]) => void;
10164
10641
  updateDocumentProperties(core: PptxCoreProperties, app: PptxAppProperties, custom: PptxCustomProperty[]): void;
10642
+ /**
10643
+ * Seed the deck's tag parts straight after a load. Deliberately NOT an undo
10644
+ * step: the load already cleared history, and treating the parsed value as
10645
+ * a user edit would mark a pristine deck dirty.
10646
+ */
10647
+ adoptTagCollections(tags: readonly PptxTagCollection[]): void;
10648
+ /** Replace the tag collections as one undoable edit (inspector Tags section). */
10649
+ updateTagCollections(next: readonly PptxTagCollection[]): void;
10165
10650
  undo(): void;
10166
10651
  redo(): void;
10167
10652
  save(format?: PptxSaveFormat): Promise<Uint8Array>;
10168
10653
  }
10169
10654
 
10655
+ /**
10656
+ * What the canvas context menu offers, and what each command does.
10657
+ *
10658
+ * The item list is deliberately NOT decided here: `buildContextMenuEntries` in
10659
+ * `pptx-viewer-shared` owns the command ids, labels, order and separators for
10660
+ * all five bindings, so a command added there appears in all five at once. This
10661
+ * module only supplies the context (what is selected, which table cell was
10662
+ * right-clicked) and routes the chosen id at the editor's existing operations.
10663
+ * Svelte's menu used to hand-write its own items, which is exactly how it ended
10664
+ * up shipping without Group, Ungroup, Add Comment, Edit Hyperlink, or a single
10665
+ * table command.
10666
+ *
10667
+ * It lives in a plain `.ts` module rather than inside `ElementContextMenu.svelte`
10668
+ * so the SFC stays thin presentation (repo convention) and so the dispatch is
10669
+ * unit-testable without mounting a component.
10670
+ *
10671
+ * @module editor/context-menu-dispatch
10672
+ */
10673
+ /** The table cell a right-click landed on, in model (unmerged) coordinates. */
10674
+ interface ContextMenuCellTarget {
10675
+ rowIndex: number;
10676
+ columnIndex: number;
10677
+ }
10678
+
10679
+ /**
10680
+ * Shared value types for the Svelte editing layer.
10681
+ */
10682
+ /** Box geometry in element (unscaled slide) px. */
10683
+ interface OverlayBox {
10684
+ x: number;
10685
+ y: number;
10686
+ width: number;
10687
+ height: number;
10688
+ rotation: number;
10689
+ }
10690
+
10691
+ interface EditorControllerDeps {
10692
+ getScale(): number;
10693
+ getCurrent(): number;
10694
+ getPresenting(): boolean;
10695
+ getStageRoot(): Element | null;
10696
+ getHolderEl(): HTMLElement | null;
10697
+ /**
10698
+ * The focusable viewer root. The stage gesture preventDefault()s the click, so
10699
+ * focus has to be put back here or the root's keydown listener stops seeing
10700
+ * anything (see `armEditorKeyboard`).
10701
+ */
10702
+ getRootEl?(): HTMLElement | null;
10703
+ onCursorMove?(x: number, y: number): void;
10704
+ /**
10705
+ * Open the canvas context menu at viewport `x`/`y`. `cell` is the table cell
10706
+ * the right-click landed on (null elsewhere): the menu's row / column /
10707
+ * merge commands need a target, and this binding has no cell-selection
10708
+ * model, so the cell under the pointer is the target.
10709
+ */
10710
+ onContextMenu?(x: number, y: number, cell: ContextMenuCellTarget | null): void;
10711
+ getSnapToGrid?(): boolean;
10712
+ getSnapToShape?(): boolean;
10713
+ getGuides?(): readonly {
10714
+ axis: 'h' | 'v';
10715
+ position: number;
10716
+ }[];
10717
+ /**
10718
+ * Transform inline-editor text at commit time (File > Options > Proofing
10719
+ * AutoCorrect); identity when unset.
10720
+ */
10721
+ transformCommittedText?(text: string): string;
10722
+ /**
10723
+ * Collaboration live-preview channel. Inline text only reaches the slides
10724
+ * state on commit, so peers saw nothing while a peer typed; each keystroke is
10725
+ * published through this instead. Omit outside a collaborative viewer.
10726
+ */
10727
+ getLivePatcher?(): CollaborationLivePatcher | undefined;
10728
+ /** The slide the inline-edited element belongs to (live-preview lookup). */
10729
+ getActiveSlide?(): PptxSlide | undefined;
10730
+ /**
10731
+ * Show or hide the keyboard-shortcut cheat sheet ("?"). The panel is parity
10732
+ * UI state owned by the shell, so the controller only signals the intent.
10733
+ */
10734
+ toggleShortcuts?(): void;
10735
+ /** Close the cheat sheet on Escape; true when it was open (Escape consumed). */
10736
+ closeShortcuts?(): boolean;
10737
+ }
10738
+
10739
+ interface EditorMarqueeRect extends MarqueeRect {
10740
+ additive: boolean;
10741
+ }
10742
+
10170
10743
  declare class EditorController {
10171
10744
  #private;
10172
10745
  snapLines: readonly SnapLine[];
@@ -10203,215 +10776,15 @@ declare class EditorController {
10203
10776
  }
10204
10777
 
10205
10778
  /**
10206
- * ExportUiState: reactive state behind the toolbar `ExportMenu` and the
10207
- * `ExportProgressModal`. Svelte port of Vue's `useExportProgress` composable:
10208
- * it owns the modal state (open / title / progress / status), the
10209
- * `AbortController` the export loops check between slides, and wraps each
10210
- * multi-slide export (PDF / GIF / WebM) in a `begin -> run -> end` envelope.
10211
- * All percentage maths + status labels come from `pptx-viewer-shared`
10212
- * (`export-progress.ts`) so every binding shows identical progress.
10213
- *
10214
- * PNG (single slide, fast) and print (opens its own surface) run without the
10215
- * modal; the menu trigger still disables via {@link exporting} while they run.
10216
- */
10217
- interface ExportUiDeps {
10218
- controller: ExportController;
10219
- getTranslator(): Translator;
10220
- /**
10221
- * Fired after an export completes successfully (Options > Accessibility
10222
- * "feedback with sound" hook); not called on abort or failure.
10223
- */
10224
- onComplete?(): void;
10225
- }
10226
- declare class ExportUiState {
10227
- #private;
10228
- /** Whether the progress modal is visible. */
10229
- open: boolean;
10230
- /** Modal heading (e.g. "Export as PDF"). */
10231
- title: string;
10232
- /** Current progress, 0-100. */
10233
- progress: number;
10234
- /** Status line under the bar (e.g. "Rendering slide 3 of 10..."). */
10235
- status: string;
10236
- constructor(deps: ExportUiDeps);
10237
- /** True while any export runs (disables the menu trigger). */
10238
- get exporting(): boolean;
10239
- /** Export the current slide as PNG (no modal; quick single capture). */
10240
- runPng(): void;
10241
- /** Copy the current slide to the system image clipboard. */
10242
- runCopyImage(): void;
10243
- /** Run the PDF export with the progress modal wired. */
10244
- runPdf(): Promise<void>;
10245
- /** Run the animated-GIF export with the progress modal wired. */
10246
- runGif(): Promise<void>;
10247
- /** Run the WebM video export with the progress modal wired. */
10248
- runVideo(): Promise<void>;
10249
- /** Run the print flow (no modal; the print surface takes over). */
10250
- runPrint(options?: PrintOptions): void;
10251
- /** Cancel the in-flight export (aborts the loop, closes the modal). */
10252
- cancel(): void;
10253
- }
10254
-
10255
- /**
10256
- * autosave.svelte.ts: debounced crash-recovery autosave for the Svelte viewer.
10779
+ * Where the canvas context menu opened, and on which table cell.
10257
10780
  *
10258
- * A runes port that fuses the two shared semantics the other bindings use:
10259
- * - React's persistence target: each successful save writes the serialized
10260
- * `.pptx` bytes to the shared IndexedDB recovery store
10261
- * (`saveAutosaveSnapshot`, keyed by `filePath`), so a host can offer
10262
- * restore-on-load with `getAutosaveSnapshot` / `listAutosaveSnapshots`
10263
- * (both re-exported from this package). This binding does NOT auto-restore;
10264
- * matching React/Vue, recovery is a host concern.
10265
- * - Vue's debounce-on-edit trigger: an edit marks the document dirty and
10266
- * (re)arms a debounce timer instead of polling on a fixed interval.
10267
- *
10268
- * The controller registers its own edit-watching `$effect` in the constructor,
10269
- * so the SFC only has to construct it once during setup and read its reactive
10270
- * `status` / `isDirty` for the toolbar indicator.
10271
- */
10272
- /**
10273
- * Autosave status, surfaced for the toolbar status pill.
10274
- *
10275
- * - `idle` : nothing has been saved yet (or no edits since mount).
10276
- * - `disabled` : autosave is inactive (off, not editable, or no file path).
10277
- * - `saving` : a save is currently in flight.
10278
- * - `saved` : the most recent save succeeded.
10279
- * - `error` : the most recent save threw.
10781
+ * Owned by the viewer shell and handed straight to `ElementContextMenu`; the
10782
+ * cell is what turns the shared menu's table block on and gives it a target.
10280
10783
  */
10281
- type AutosaveStatus = 'idle' | 'disabled' | 'saving' | 'saved' | 'error';
10282
- interface AutosaveDeps {
10283
- /** Master on/off: host `autosave` prop AND editing allowed. */
10284
- getEnabled: () => boolean;
10285
- /** Debounce window in milliseconds. */
10286
- getIntervalMs: () => number;
10287
- /** IndexedDB record key (host `filePath`); autosave is disabled without one. */
10288
- getFilePath: () => string | undefined;
10289
- /** The current editable slides (watched for edits). */
10290
- getSlides: () => PptxSlide[];
10291
- getSlideMasters?: () => PptxSlideMaster[];
10292
- getNotesMaster?: () => PptxNotesMaster | undefined;
10293
- getHandoutMaster?: () => PptxHandoutMaster | undefined;
10294
- getSections?: () => PptxSection[];
10295
- /** The live core handler used to serialize slides to `.pptx` bytes. */
10296
- getHandler: () => PptxHandler | null;
10297
- /**
10298
- * Monotonic load counter: a change means a fresh presentation was seeded (not
10299
- * a user edit), so the watcher clears dirty instead of arming a save.
10300
- */
10301
- getLoadCount: () => number;
10302
- /** Host callback with the freshly-serialized bytes on each successful save. */
10303
- onSaved?: (bytes: Uint8Array) => void;
10304
- }
10305
- declare class AutosaveController {
10306
- #private;
10307
- /** Current autosave lifecycle status (reactive). */
10308
- status: AutosaveStatus;
10309
- /** Whether there are unsaved edits pending (reactive). */
10310
- isDirty: boolean;
10311
- /** Epoch ms of the last successful save, or null (reactive). */
10312
- lastSavedAt: number | null;
10313
- constructor(deps: AutosaveDeps);
10314
- /** Force an immediate save, bypassing the debounce window. */
10315
- save(): Promise<void>;
10316
- }
10317
-
10318
- interface SlideCanvasProps {
10319
- slide: PptxSlide | undefined;
10320
- canvasSize: CanvasSize;
10321
- mediaDataUrls: Map<string, string>;
10322
- /** Effective scale (fit-to-viewport x user zoom), pre-computed by the host. */
10323
- scale: number;
10324
- /** True only on the live presentation stage; see `SlideStageProps.presenting`. */
10325
- presenting?: boolean;
10326
- /** True while in-place editing is available; gates the pointer handlers and the editing cursor/class. */
10327
- editingActive?: boolean;
10328
- editTemplateMode?: boolean;
10329
- ontablecellcommit?: (elementId: string, rowIndex: number, cellIndex: number, text: string) => void;
10330
- onsmartartnodecommit?: (elementId: string, nodeId: string, text: string) => void;
10331
- onsmartartnodefill?: (elementId: string, nodeId: string, fill: string) => void;
10332
- /** Reports the stage-holder node to the host on mount/teardown (editing hit-surface, export capture anchor). */
10333
- onstageholder?: (el: HTMLDivElement | null) => void;
10334
- onstagepointerdown?: (event: PointerEvent) => void;
10335
- onstagepointermove?: (event: PointerEvent) => void;
10336
- onstagedblclick?: (event: MouseEvent) => void;
10337
- onstagecontextmenu?: (event: MouseEvent) => void;
10338
- /** Fired on any stage click; the host wires this to advance presentation playback. */
10339
- onstageclick?: (event: MouseEvent) => void;
10340
- /**
10341
- * True while the AI panel is picking an element: the next element click(s)
10342
- * become the assistant's focus (highlighted) instead of selecting / editing.
10343
- */
10344
- aiPickMode?: boolean;
10345
- /**
10346
- * True while a running AI tool is active: the stage marks itself
10347
- * `data-pptx-ai-active` so element colour changes tween while the assistant
10348
- * works (see AiFocusHighlightOverlay's tween rule).
10349
- */
10350
- aiActive?: boolean;
10351
- /** Route a picked canvas element to the AI focus (pick mode only). */
10352
- onaipickelement?: (elementId: string) => void;
10353
- /**
10354
- * Overlay content layered above the slide (selection/editor layer, ink
10355
- * drawing, alignment guides, presentation annotations, collaboration
10356
- * cursors, transition overlay, ...). Rendered inside the same
10357
- * fixed-size, scaled stage-holder as the slide itself. Kept out of this
10358
- * component's own props (rather than a fixed list of overlay slots) so it
10359
- * stays free of the live editor/controller instances those overlays need.
10360
- */
10361
- children?: svelte.Snippet;
10362
- }
10363
- interface ViewerToolbarProps {
10364
- /** Active slide (0-based). */
10365
- current: number;
10366
- total: number;
10367
- /** Currently-effective zoom percent (rounded). */
10368
- zoomPercent: number;
10369
- isFullscreen: boolean;
10370
- onprev: () => void;
10371
- onnext: () => void;
10372
- onzoomin: () => void;
10373
- onzoomout: () => void;
10374
- onzoomfit: () => void;
10375
- onfullscreen: () => void;
10376
- /** Whether the Notes toggle button is shown (host has a notes panel). */
10377
- showNotes?: boolean;
10378
- /** Whether the notes panel is currently expanded (drives the pressed state). */
10379
- notesExpanded?: boolean;
10380
- onnotestoggle?: () => void;
10381
- /** Show the editing action group (Undo / Redo / Save). Default false. */
10382
- editable?: boolean;
10383
- /** Whether an undo step is available (drives the Undo button's disabled state). */
10384
- canUndo?: boolean;
10385
- /** Whether a redo step is available (drives the Redo button's disabled state). */
10386
- canRedo?: boolean;
10387
- /** Whether there are unsaved edits (drives the Save button's emphasis). */
10388
- dirty?: boolean;
10389
- onundo?: () => void;
10390
- onredo?: () => void;
10391
- onsave?: () => void;
10392
- ondownload?: () => void;
10393
- /**
10394
- * Autosave lifecycle status; when set (host opted into `autosave`) a small
10395
- * status pill renders in the editing group. Omit to hide the pill entirely.
10396
- */
10397
- autosaveStatus?: AutosaveStatus;
10398
- /** Whether there are unsaved autosave edits (drives the pill's "dirty" tone). */
10399
- autosaveDirty?: boolean;
10400
- /**
10401
- * Export menu state (PNG / PDF / GIF / video / print). When set, the
10402
- * toolbar renders the `ExportMenu` dropdown in its right-hand group,
10403
- * matching the export affordance the React/Vue/Angular chrome exposes.
10404
- * Omit to hide the menu (e.g. while no presentation is loaded).
10405
- */
10406
- exportUi?: ExportUiState;
10407
- /** Opens the Share (collaboration) dialog. Omit to hide the button. */
10408
- onshare?: () => void;
10409
- /** Opens the Broadcast dialog. Omit to hide the button. */
10410
- onbroadcast?: () => void;
10411
- /** Whether a collaboration session is currently active (highlights the Share button). */
10412
- collabActive?: boolean;
10413
- /** Toolbar buttons to hide; see `PowerPointViewerProps.hiddenActions`. Default undefined: nothing hidden. */
10414
- hiddenActions?: ToolbarActionId[];
10784
+ interface StageContextMenu {
10785
+ x: number;
10786
+ y: number;
10787
+ cell: ContextMenuCellTarget | null;
10415
10788
  }
10416
10789
 
10417
10790
  /**
@@ -10549,6 +10922,8 @@ interface RibbonProps {
10549
10922
  oncustomshows: () => void;
10550
10923
  onselectionpane: () => void;
10551
10924
  onslidesorter: () => void;
10925
+ /** View tab > Normal: leave slide sorter / slide show for the editing view. */
10926
+ onnormal?: () => void;
10552
10927
  preferences: ViewerPreferences;
10553
10928
  onpreferenceschange: (preferences: ViewerPreferences) => void;
10554
10929
  showGuides: boolean;
@@ -10673,10 +11048,7 @@ type NavigationAction = 'next' | 'prev' | 'first' | 'last';
10673
11048
  * conventions used by the other bindings (arrows, paging keys, space, Home/End).
10674
11049
  */
10675
11050
  declare function resolveNavigationKey(key: string): NavigationAction | undefined;
10676
- /** Next zoom level up from `current` percent, clamped. */
10677
- declare function zoomInPercent(current: number): number;
10678
- /** Next zoom level down from `current` percent, clamped. */
10679
- declare function zoomOutPercent(current: number): number;
11051
+
10680
11052
  /**
10681
11053
  * Fit-to-viewport scale for a canvas inside a viewport, with breathing room.
10682
11054
  * Returns a strictly positive scale (falls back to 1 while unmeasured).
@@ -10707,6 +11079,8 @@ declare class PresentationLoader {
10707
11079
  coreProperties: PptxCoreProperties | undefined;
10708
11080
  appProperties: PptxAppProperties | undefined;
10709
11081
  customProperties: PptxCustomProperty[];
11082
+ /** Parsed `ppt/tags/*.xml` collections, editable in the inspector's Tags section. */
11083
+ tagCollections: PptxTagCollection[];
10710
11084
  embeddedFonts: PptxEmbeddedFont[];
10711
11085
  hasDigitalSignatures: boolean;
10712
11086
  digitalSignatureCount: number;
@@ -10911,6 +11285,13 @@ declare class CollaborationDialogsState {
10911
11285
  retry(propConfig: CollaborationConfig | undefined): void;
10912
11286
  }
10913
11287
 
11288
+ /**
11289
+ * The navigation / zoom / mode / slide / element half of the imperative
11290
+ * `PowerPointViewer` instance API. The undo/redo/save half lives in
11291
+ * `editing-api.ts` and the export half in `export/exporting-api.ts`.
11292
+ */
11293
+ type DeckApi = Omit<PowerPointViewerAPI, 'getContent' | 'undo' | 'redo' | 'canUndo' | 'canRedo'>;
11294
+
10914
11295
  /** The imperative editing API exposed on the `PowerPointViewer` instance. */
10915
11296
  interface EditingApi {
10916
11297
  undo(): void;
@@ -11133,6 +11514,146 @@ declare class PresenterSession {
11133
11514
  private getChannel;
11134
11515
  }
11135
11516
 
11517
+ /** One element ring to draw on the canvas: an explicit pick or a live-tool focus. */
11518
+ interface AiCanvasHighlight {
11519
+ slideIndex: number;
11520
+ elementId: string;
11521
+ /** `pick` = persistent user pick; `active` = transient AI-is-working ring. */
11522
+ variant: 'pick' | 'active';
11523
+ }
11524
+ /** Live viewer accessors + the panel-open hook the controller closes over. */
11525
+ interface AiPanelControllerDeps {
11526
+ getActiveSlideIndex(): number;
11527
+ getSelectedElementId(): string | null;
11528
+ getSelectedElementIds(): readonly string[];
11529
+ /** The primary selected element, for building the "Fix with AI" directive. */
11530
+ getSelectedElement(): PptxElement | undefined;
11531
+ /** Open the panel (askAboutSelection / fixSelection / startPicking need it). */
11532
+ openPanel(): void;
11533
+ }
11534
+ declare class AiPanelController {
11535
+ #private;
11536
+ /** Pinned focus override (null follows the live selection). */
11537
+ pinnedFocus: PptxAiFocusedTarget[] | null;
11538
+ /** One-shot composer prefill. `nonce` bumps on every ask/fix. */
11539
+ prefill: {
11540
+ text: string;
11541
+ nonce: number;
11542
+ };
11543
+ /** True while the user is picking element(s) on the canvas for the assistant. */
11544
+ pickMode: boolean;
11545
+ /** The elements the user has explicitly handed to the assistant. */
11546
+ pickTargets: PptxAiFocusedTarget[];
11547
+ /** The batch of just-applied element changes the canvas should animate. */
11548
+ changeBatch: AiChangeBatch | null;
11549
+ constructor(deps: AiPanelControllerDeps);
11550
+ /** Focused targets derived live from the current canvas selection. */
11551
+ get liveFocusTargets(): PptxAiFocusedTarget[];
11552
+ /** True when there are explicit picks (they win over a pin / live selection). */
11553
+ get hasPicks(): boolean;
11554
+ /** The targets the assistant should scope to: picks > pin > live selection. */
11555
+ get effectiveTargets(): PptxAiFocusedTarget[];
11556
+ /** Whether a pin is currently the active focus (no picks override it). */
11557
+ get isPinned(): boolean;
11558
+ /** Element rings the canvas should draw (picks + the live tool focus). */
11559
+ get canvasHighlights(): AiCanvasHighlight[];
11560
+ /** True while the canvas should tween colour changes (AI is active). */
11561
+ get canvasAnimating(): boolean;
11562
+ pinFocus(): void;
11563
+ clearPinnedFocus(): void;
11564
+ /** Open the panel scoped to the current selection, empty composer (focused). */
11565
+ askAboutSelection(): void;
11566
+ /** Open the panel scoped to the current selection, prefilled fix directive. */
11567
+ fixSelection(): void;
11568
+ /** Enter pick mode (the next canvas element clicks become picks). */
11569
+ startPicking(): void;
11570
+ /** Leave pick mode without clearing the accumulated picks. */
11571
+ stopPicking(): void;
11572
+ /** Add one clicked canvas element to the pick set (and highlight it). */
11573
+ addPick(slideIndex: number, elementId: string): void;
11574
+ /** Empty the pick set and leave pick mode. */
11575
+ clearPicks(): void;
11576
+ /**
11577
+ * Flash a transient "the AI is working on this" highlight for a running tool,
11578
+ * and enable colour tweening for a short settle window. Pass `null` to just
11579
+ * enable tweening (e.g. a theme-colour edit with no single element target).
11580
+ */
11581
+ flashToolTarget(target: ToolCanvasTarget | null): void;
11582
+ /**
11583
+ * Push (or clear) the change batch the AI apply path published, so the canvas
11584
+ * overlay animates the just-applied edit (glide old->new, fade/scale in-out,
11585
+ * glow). Pass `null` to clear once the animation has settled.
11586
+ */
11587
+ showChangeBatch(batch: AiChangeBatch | null): void;
11588
+ /** Cancel the pending flash timer (call on teardown). */
11589
+ dispose(): void;
11590
+ }
11591
+
11592
+ interface AiCluster {
11593
+ /** The SDK-free bridge handed to the (lazily imported) chat panel. */
11594
+ readonly bridge: PptxAiBridge;
11595
+ /** On-canvas scope: focus targets, pick mode, live tool-focus highlights. */
11596
+ readonly panel: AiPanelController;
11597
+ /** Whether the right-side chat panel is open (ribbon Sparkles toggle). */
11598
+ panelOpen: boolean;
11599
+ /** Element rings to draw on the active slide; empty when AI is disabled. */
11600
+ readonly canvasHighlights: readonly AiCanvasHighlight[];
11601
+ }
11602
+
11603
+ /**
11604
+ * ViewerOptionsState: the runes wrapper around the shared File > Options
11605
+ * store. Owns the reactive `options` snapshot (updated via the store's
11606
+ * subscribe callback, persisted by the store to the shared
11607
+ * `pptx-viewer-prefs` localStorage entry) plus the derived behavior values
11608
+ * the viewer wires: history depth, ribbon visibility, print defaults,
11609
+ * screen tips, root classes, trust gates, and feedback sounds.
11610
+ */
11611
+ declare class ViewerOptionsState {
11612
+ #private;
11613
+ /** Reactive File > Options snapshot; a new object per change. */
11614
+ options: ViewerOptions;
11615
+ constructor(init?: ViewerOptionsStoreInit);
11616
+ /** The legacy six-toggle projection of the current options. */
11617
+ get preferences(): ViewerPreferences;
11618
+ /** Undo depth for the editor history (Advanced > maximum undos). */
11619
+ get historyDepth(): number;
11620
+ /** Ribbon tabs unticked in Customize Ribbon (File never hides). */
11621
+ get hiddenRibbonTabIds(): readonly ToolbarTabId[];
11622
+ /** Print dialog seed, or undefined for "use most recent settings". */
11623
+ get printDefaults(): Partial<PrintSettings> | undefined;
11624
+ /** Viewer-root CSS classes reflecting display-affecting options. */
11625
+ get rootClasses(): string[];
11626
+ setValue(group: ViewerOptionsGroupId, key: string, value: ViewerOptionPrimitive): void;
11627
+ /** Restore a snapshot wholesale (the dialog's Cancel semantics). */
11628
+ restore(snapshot: ViewerOptions): void;
11629
+ setRibbonTabHidden(tabId: ToolbarTabId, hidden: boolean): void;
11630
+ setQuickAccessCommands(commandIds: readonly string[]): void;
11631
+ reset(group?: ViewerOptionsGroupId): void;
11632
+ /**
11633
+ * Push the legacy preference toggles (ribbon View tab, title-bar autosave)
11634
+ * back into the options model. Only writes when a value actually differs,
11635
+ * so the bidirectional sync with `preferences` cannot loop.
11636
+ */
11637
+ applyPreferences(prefs: ViewerPreferences): void;
11638
+ /** Tooltip text under the current ScreenTip style, or undefined for none. */
11639
+ screenTip(label: string, description?: string, shortcut?: string): string | undefined;
11640
+ /**
11641
+ * Trust Center gate for following an external hyperlink. Returns true when
11642
+ * navigation may proceed (gate off, non-http(s) target, or confirmed).
11643
+ */
11644
+ confirmHyperlink(href: string, message: string): boolean;
11645
+ /** Accessibility > "feedback with sound" cue for a completed action. */
11646
+ playFeedback(): void;
11647
+ /**
11648
+ * Autosave debounce in ms: the host prop until the user picks a custom
11649
+ * AutoRecover cadence in Options > Save, which then takes over.
11650
+ */
11651
+ autosaveDebounceMs(hostIntervalMs: number, defaultMinutes: number): number;
11652
+ /** Options > Save > "Delete cached files": drop all recovery snapshots. */
11653
+ clearCache(): Promise<void>;
11654
+ dispose(): void;
11655
+ }
11656
+
11136
11657
  declare class CompareController {
11137
11658
  #private;
11138
11659
  result: CompareResult | null;
@@ -11238,8 +11759,16 @@ interface CreateViewerStateOptions {
11238
11759
  /** Already locale-bound translator; propagated to descendants via context. */
11239
11760
  t: Translator;
11240
11761
  getSmartArt3D: () => boolean;
11241
- /** Whether in-place editing is enabled (host `editable` prop, post-effect value). */
11762
+ /**
11763
+ * The host `editable` prop. The factory mirrors it into its own
11764
+ * {@link ViewerStateBag.editable} flag, which the AI seam, `setMode()` and
11765
+ * Trust Center's Protected View can then flip without the host round-trip.
11766
+ */
11242
11767
  getEditable: () => boolean;
11768
+ /** Display file name, used by the AI seam as a friendly deck title. */
11769
+ getFileName?: () => string | undefined;
11770
+ /** Whether the host enabled the AI assistant (the `ai` prop). */
11771
+ getAiEnabled?: () => boolean;
11243
11772
  onload?: (detail: ViewerLoadDetail) => void;
11244
11773
  onerror?: (message: string) => void;
11245
11774
  onslidechange?: (index: number) => void;
@@ -11256,6 +11785,12 @@ interface CreateViewerStateOptions {
11256
11785
  onautosavetoggle?: (enabled: boolean) => void;
11257
11786
  onstartcollaboration?: (config: CollaborationConfig) => void;
11258
11787
  onstopcollaboration?: () => void;
11788
+ /**
11789
+ * Host override for File > Open > "Browse this device". Without it
11790
+ * {@link ViewerStateBag.openFile} falls back to the built-in native picker
11791
+ * and loads the chosen deck in place, so the control is never inert.
11792
+ */
11793
+ onopenfile?: () => void;
11259
11794
  /** DOM-bound getters, supplied by the component that owns the markup. */
11260
11795
  getStageHolderEl: () => HTMLDivElement | undefined;
11261
11796
  getRootEl: () => HTMLDivElement | undefined;
@@ -11285,11 +11820,17 @@ interface ViewerStateBag {
11285
11820
  readonly presenterSession: PresenterSession;
11286
11821
  readonly exportWiring: ExportWiring;
11287
11822
  readonly exportUi: ExportUiState;
11823
+ /** The full PowerPoint File > Options model (persisted), provided via context. */
11824
+ readonly optionsState: ViewerOptionsState;
11825
+ /** AI assistant bridge + on-canvas focus controller + panel open flag. */
11826
+ readonly ai: AiCluster;
11288
11827
  readonly t: Translator;
11289
11828
  /** Imperative undo/redo/save/download API, matching `PowerPointViewerApi`'s editing subset. */
11290
11829
  readonly editingApi: EditingApi;
11291
11830
  /** Imperative PNG/PDF/GIF/video/print API, matching `PowerPointViewerApi`'s export subset. */
11292
11831
  readonly exportingApi: ExportingApi;
11832
+ /** Imperative navigation/zoom/mode/slide/element API (the rest of `PowerPointViewerApi`). */
11833
+ readonly deck: DeckApi;
11293
11834
  /** Effective scale (fit-to-viewport x user zoom), matching the main canvas. */
11294
11835
  readonly scale: number;
11295
11836
  /** User-facing zoom percent (rounded, never below 1). */
@@ -11304,16 +11845,19 @@ interface ViewerStateBag {
11304
11845
  readonly viewerMode: ViewerMode;
11305
11846
  /** True while the autosave debounce/write cycle is armed. */
11306
11847
  readonly autosaveActive: boolean;
11848
+ /**
11849
+ * The live editable flag: seeded from the host `editable` prop, then
11850
+ * writable so an AI edit, `deck.setMode()` or Trust Center's Protected View
11851
+ * can flip it without waiting on the host.
11852
+ */
11853
+ editable: boolean;
11307
11854
  /** Read-only: mutate via {@link setAutosaveEnabled}, which also fires `onautosavetoggle`. */
11308
11855
  readonly autosaveEnabled: boolean;
11309
11856
  setAutosaveEnabled(enabled: boolean): void;
11310
11857
  presenterMode: boolean;
11311
11858
  /** `Date.now()` timestamp of the last `enterPresenterView()` call; the presenter view's elapsed-time display. */
11312
11859
  readonly presenterStartedAt: number;
11313
- stageContextMenu: {
11314
- x: number;
11315
- y: number;
11316
- } | null;
11860
+ stageContextMenu: StageContextMenu | null;
11317
11861
  readonly activeMobileSheet: MobileSheetKey;
11318
11862
  setActiveMobileSheet(next: MobileSheetKey): void;
11319
11863
  readonly notesExpanded: boolean;
@@ -11321,6 +11865,16 @@ interface ViewerStateBag {
11321
11865
  readonly signatureWarningOpen: boolean;
11322
11866
  enterPresenterView(): void;
11323
11867
  closeSignatureWarning(): void;
11868
+ /** File > Open > "Browse this device" (host override, else the native picker). */
11869
+ openFile(): void;
11870
+ /** Run a Quick Access Toolbar command by catalog id (unknown ids no-op). */
11871
+ runQuickAccessCommand(id: string): void;
11872
+ /**
11873
+ * Deck-level OOXML field-substitution context (date/time, header/footer,
11874
+ * document properties, plus the active slide's number and title), also
11875
+ * published to descendants via `provideFieldContext`.
11876
+ */
11877
+ fieldContext(): FieldSubstitutionContext;
11324
11878
  onNotesToggle(): void;
11325
11879
  onNotesCommit(notes: string, segments?: TextSegment[]): void;
11326
11880
  onFullscreenToggle(): void;
@@ -11334,28 +11888,29 @@ interface ViewerStateBag {
11334
11888
 
11335
11889
  /**
11336
11890
  * Builds every reactive controller the ribbon, toolbar, and slide canvas
11337
- * need: the runes port of `PowerPointViewer.svelte`'s own construction block
11338
- * (originally inlined at the top of its `<script>`), extracted so a host can
11339
- * compose its own viewer shell out of `Ribbon` / `ViewerToolbar` / the state
11340
- * classes without pulling in the whole `PowerPointViewer` component.
11891
+ * need. This is `PowerPointViewer.svelte`'s entire construction block,
11892
+ * extracted so that SFC stays thin composition and so a host can build its
11893
+ * own viewer shell out of `Ribbon` / `ViewerToolbar` / the state classes
11894
+ * without pulling in the whole `PowerPointViewer` component.
11341
11895
  *
11342
11896
  * MUST be called synchronously from a `.svelte` component's own script body
11343
11897
  * (top level, not inside a callback or after an `await`): it registers
11344
11898
  * `onMount` / `onDestroy` hooks and Svelte context (`setContext`) via
11345
11899
  * `provideTranslator` / `provideSmartArt3D` / `provideRenderContext` /
11346
- * `provideZoomNavigation` (inside the editor-ui cluster) / `provideInspectorDeck`,
11347
- * all of which require an active component-initialisation context. Svelte's
11348
- * lifecycle context stays active for the whole synchronous execution of a
11349
- * component's script, not just its top-level statements, so calling this
11350
- * from a component's script works exactly like inlining the same code would.
11351
- *
11352
- * Construction is split across a few `create-viewer-state-*.svelte.ts`
11353
- * helpers purely to stay under the repo's file-size budget; the ORDER those
11354
- * helpers are invoked in below mirrors the original inline code (later
11355
- * clusters close over earlier ones), with one deliberate reordering: the
11356
- * collaboration cluster is now built right after `editor` (it doesn't need
11357
- * the editing-chrome cluster), which lets `controller` close over the real
11358
- * `collab.setCursor` instead of a forward reference.
11900
+ * `provideInspectorDeck` / `provideFieldContext` (plus more inside the
11901
+ * clusters), all of which require an active component-initialisation
11902
+ * context. Svelte's lifecycle context stays active for the whole synchronous
11903
+ * execution of a component's script, not just its top-level statements, so
11904
+ * calling this from a component's script works exactly like inlining the
11905
+ * same code would.
11906
+ *
11907
+ * Construction is split across the `create-viewer-state-*.svelte.ts` helpers
11908
+ * purely to stay under the repo's file-size budget; the ORDER they are
11909
+ * invoked in below mirrors the original inline code (later clusters close
11910
+ * over earlier ones), with one deliberate reordering: the collaboration
11911
+ * cluster is built right after `editor` (it doesn't need the editing-chrome
11912
+ * cluster), which lets `controller` close over the real `collab.setCursor`
11913
+ * instead of a forward reference.
11359
11914
  *
11360
11915
  * Call the returned `destroy()` from the host component's own `onDestroy`.
11361
11916
  */