pptx-svelte-viewer 2.18.0 → 2.20.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 (75) hide show
  1. package/CHANGELOG.md +450 -0
  2. package/dist/{AiChatPanel-D6dfMwnT.js → AiChatPanel-DPXM1HsP.js} +190 -206
  3. package/dist/{export-DbSAFc8m.js → export-Cp97qZ_g.js} +29893 -26847
  4. package/dist/i18n.js +1 -1
  5. package/dist/index.d.ts +488 -22
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +35 -28
  8. package/dist/pptx-svelte-viewer.css +1 -1
  9. package/dist/{translator-CZ12ZvlE.js → translator-Cs5ewuZ4.js} +32 -4
  10. package/dist/viewer/components/chart-drag.svelte.d.ts +39 -0
  11. package/dist/viewer/components/chart-drag.svelte.d.ts.map +1 -0
  12. package/dist/viewer/components/presentation-toolbar.svelte.d.ts +6 -0
  13. package/dist/viewer/components/presentation-toolbar.svelte.d.ts.map +1 -1
  14. package/dist/viewer/components/props-editing.d.ts +2 -2
  15. package/dist/viewer/components/props-editing.d.ts.map +1 -1
  16. package/dist/viewer/components/props-elements.d.ts +8 -1
  17. package/dist/viewer/components/props-elements.d.ts.map +1 -1
  18. package/dist/viewer/components/props-stage.d.ts +5 -1
  19. package/dist/viewer/components/props-stage.d.ts.map +1 -1
  20. package/dist/viewer/components/viewer-body-commits.d.ts +6 -0
  21. package/dist/viewer/components/viewer-body-commits.d.ts.map +1 -1
  22. package/dist/viewer/editor/editing-api.d.ts.map +1 -1
  23. package/dist/viewer/editor/editor-adjust-gesture.d.ts.map +1 -1
  24. package/dist/viewer/editor/editor-controller-deps.d.ts +5 -0
  25. package/dist/viewer/editor/editor-controller-deps.d.ts.map +1 -1
  26. package/dist/viewer/editor/editor-controller-wiring.d.ts.map +1 -1
  27. package/dist/viewer/editor/editor-controller.svelte.d.ts +13 -2
  28. package/dist/viewer/editor/editor-controller.svelte.d.ts.map +1 -1
  29. package/dist/viewer/editor/editor-document-lifecycle.d.ts.map +1 -1
  30. package/dist/viewer/editor/editor-document-state.d.ts +6 -2
  31. package/dist/viewer/editor/editor-document-state.d.ts.map +1 -1
  32. package/dist/viewer/editor/editor-handle-handlers.d.ts +2 -2
  33. package/dist/viewer/editor/editor-handle-handlers.d.ts.map +1 -1
  34. package/dist/viewer/editor/editor-keyboard.d.ts +7 -0
  35. package/dist/viewer/editor/editor-keyboard.d.ts.map +1 -1
  36. package/dist/viewer/editor/editor-presentation-metadata.svelte.d.ts +11 -0
  37. package/dist/viewer/editor/editor-presentation-metadata.svelte.d.ts.map +1 -1
  38. package/dist/viewer/editor/editor-selection-interactivity.d.ts +7 -2
  39. package/dist/viewer/editor/editor-selection-interactivity.d.ts.map +1 -1
  40. package/dist/viewer/editor/editor-state.svelte.d.ts +29 -1
  41. package/dist/viewer/editor/editor-state.svelte.d.ts.map +1 -1
  42. package/dist/viewer/editor/table-cell-pointer.d.ts +5 -0
  43. package/dist/viewer/editor/table-cell-pointer.d.ts.map +1 -1
  44. package/dist/viewer/index.d.ts +779 -35
  45. package/dist/viewer/index.js +14 -14
  46. package/dist/viewer/render/contentpart-view.d.ts +8 -21
  47. package/dist/viewer/render/contentpart-view.d.ts.map +1 -1
  48. package/dist/viewer/render/table-view.d.ts.map +1 -1
  49. package/dist/viewer/state/autosave-recovery.svelte.d.ts +48 -0
  50. package/dist/viewer/state/autosave-recovery.svelte.d.ts.map +1 -0
  51. package/dist/viewer/state/autosave.svelte.d.ts +26 -2
  52. package/dist/viewer/state/autosave.svelte.d.ts.map +1 -1
  53. package/dist/viewer/state/create-viewer-state-collab.svelte.d.ts +23 -0
  54. package/dist/viewer/state/create-viewer-state-collab.svelte.d.ts.map +1 -1
  55. package/dist/viewer/state/create-viewer-state-editor-ui.svelte.d.ts.map +1 -1
  56. package/dist/viewer/state/create-viewer-state-presentation.svelte.d.ts.map +1 -1
  57. package/dist/viewer/state/create-viewer-state-types.d.ts +21 -4
  58. package/dist/viewer/state/create-viewer-state-types.d.ts.map +1 -1
  59. package/dist/viewer/state/create-viewer-state.svelte.d.ts.map +1 -1
  60. package/dist/viewer/state/inspector-deck.d.ts +10 -2
  61. package/dist/viewer/state/inspector-deck.d.ts.map +1 -1
  62. package/dist/viewer/state/presentation-loader.svelte.d.ts +12 -1
  63. package/dist/viewer/state/presentation-loader.svelte.d.ts.map +1 -1
  64. package/dist/viewer/state/viewer-effects.svelte.d.ts +2 -1
  65. package/dist/viewer/state/viewer-effects.svelte.d.ts.map +1 -1
  66. package/dist/viewer/state/viewer-options.svelte.d.ts +5 -3
  67. package/dist/viewer/state/viewer-options.svelte.d.ts.map +1 -1
  68. package/dist/viewer/state/viewer-parity-ui.svelte.d.ts +11 -0
  69. package/dist/viewer/state/viewer-parity-ui.svelte.d.ts.map +1 -1
  70. package/dist/viewer/state/viewer-state-options.d.ts.map +1 -1
  71. package/dist/viewer/state/viewport-handlers.d.ts +6 -0
  72. package/dist/viewer/state/viewport-handlers.d.ts.map +1 -1
  73. package/dist/viewer/types.d.ts +32 -8
  74. package/dist/viewer/types.d.ts.map +1 -1
  75. package/package.json +2 -2
@@ -183,11 +183,18 @@ interface XmlObject {
183
183
  [child: string]: XmlObject | XmlObject[] | string | undefined;
184
184
  }
185
185
  /**
186
- * Shape lock attributes from `p:cNvSpPr / a:spLocks`.
186
+ * Lock attributes from an element's non-visual properties node.
187
187
  *
188
188
  * When a flag is `true` the corresponding user interaction is disabled
189
189
  * in the editor (e.g. `noRotation` prevents free rotation of the shape).
190
190
  *
191
+ * One bag covers every family, but the families are NOT interchangeable in
192
+ * the file: `a:spLocks` (`CT_ShapeLocking`), `a:picLocks`, `a:cxnSpLocks`,
193
+ * `a:grpSpLocks` (`CT_GroupLocking`) and `a:graphicFrameLocks`
194
+ * (`CT_GraphicalObjectFrameLocking`) each declare their own attribute subset.
195
+ * `runtime/shape-lock-containers` holds that table and is what decides which
196
+ * of these fields may be written for a given element.
197
+ *
191
198
  * @example
192
199
  * ```ts
193
200
  * const locks: PptxShapeLocks = { noMove: true, noResize: true };
@@ -206,6 +213,14 @@ interface PptxShapeLocks {
206
213
  noAdjustHandles?: boolean;
207
214
  noChangeArrowheads?: boolean;
208
215
  noChangeShapeType?: boolean;
216
+ /**
217
+ * `a:graphicFrameLocks/@noDrilldown`: forbids selecting the individual
218
+ * parts inside a graphic frame (a chart series, a SmartArt node). Declared
219
+ * ONLY by `CT_GraphicalObjectFrameLocking`, so it is written for tables,
220
+ * charts, SmartArt, OLE objects and graphic-frame media, and never onto
221
+ * `a:spLocks` / `a:picLocks` / `a:cxnSpLocks` / `a:grpSpLocks`.
222
+ */
223
+ noDrilldown?: boolean;
209
224
  /**
210
225
  * Text-box flag from `p:cNvSpPr/@txBox`. Not a lock in the strict sense,
211
226
  * but it lives on the same non-visual-properties node as `a:spLocks`, so
@@ -1145,6 +1160,22 @@ interface ShapeStyle {
1145
1160
  fontRefIdx?: string;
1146
1161
  /** Raw XML colour child of `<a:fontRef>`. */
1147
1162
  fontRefColorXml?: XmlObject;
1163
+ /**
1164
+ * The fill `<a:fillRef>` resolved to, recorded ONLY when the shape's own
1165
+ * `spPr` authored no fill at all, so the reference is what paints it.
1166
+ *
1167
+ * Its absence therefore means "the fill is the shape's own", and its
1168
+ * presence plus an unchanged flat fill means "still purely inherited": see
1169
+ * `authored-shape-style.ts`, the shape-scope twin of `TextStyle`'s
1170
+ * `inheritedRunStyle`.
1171
+ */
1172
+ inheritedFillStyle?: ShapeStyle;
1173
+ /**
1174
+ * The outline `<a:lnRef>` resolved to, recorded before `spPr/a:ln` was
1175
+ * layered on top. A property that still equals this baseline was never
1176
+ * authored on the shape and must not be written back as if it were.
1177
+ */
1178
+ inheritedLineStyle?: ShapeStyle;
1148
1179
  }
1149
1180
  //#endregion
1150
1181
  //#region src/core/types/text.d.ts
@@ -1185,6 +1216,60 @@ interface ShapeStyle {
1185
1216
  interface TextStyle {
1186
1217
  /** Original `a:rPr` XML retained by projections that share the shape-text model. */
1187
1218
  runPropertiesXml?: XmlObject;
1219
+ /**
1220
+ * The properties this run's OWN `a:rPr` authored, and nothing else.
1221
+ *
1222
+ * A run style is assembled as
1223
+ * `{...inheritedRunStyle, ...authoredRunStyle}`, so the flat style is a
1224
+ * fully RESOLVED view: it cannot say whether `fontSize: 60` came from the
1225
+ * run, from the shape's `a:lstStyle`, from the layout placeholder, from the
1226
+ * master `p:txStyles` or from the theme. Omission is meaningful in OOXML
1227
+ * (§21.1.2.3), so a writer that re-emits the resolved view converts every
1228
+ * inherited value into an authored one and the deck stops being
1229
+ * theme-driven after one save.
1230
+ *
1231
+ * This is the run-scope twin of {@link TextSegment.paragraphProperties},
1232
+ * which is parsed strictly from the paragraph's own `a:pPr` for the same
1233
+ * reason. Present only for runs that came from a parsed deck; absent for
1234
+ * SDK-built text, where the flat style IS the only description and must be
1235
+ * written out in full.
1236
+ */
1237
+ authoredRunStyle?: TextStyle;
1238
+ /**
1239
+ * The resolved inheritance baseline {@link authoredRunStyle} was layered
1240
+ * on top of (shape `a:lstStyle` -> placeholder -> layout -> master
1241
+ * `p:txStyles` -> theme -> `p:defaultTextStyle`).
1242
+ *
1243
+ * Kept alongside the authored half because the two answer different
1244
+ * questions. The authored half says "the source pinned this"; the baseline
1245
+ * says "this value is what inheritance already produces", which is how an
1246
+ * EDIT is told apart from an inherited value: an editor mutates the flat
1247
+ * style without knowing about either field, so a property that now differs
1248
+ * from the baseline was either authored or edited and must be written,
1249
+ * while one that still matches can be left to inherit.
1250
+ *
1251
+ * Holds a reference to the per-paragraph baseline object rather than a
1252
+ * copy, so carrying it costs one pointer per run.
1253
+ */
1254
+ inheritedRunStyle?: TextStyle;
1255
+ /**
1256
+ * Snapshot of the ELEMENT-scope paragraph geometry (alignment, margins,
1257
+ * indent, line and paragraph spacing, tab stops, rtl, line-break flags) as
1258
+ * the load pipeline resolved it.
1259
+ *
1260
+ * Present only on an `element.textStyle` that came from a parsed deck, and
1261
+ * populated only with the geometry keys. It exists so the save path can
1262
+ * answer one question it otherwise cannot: has the user CHANGED the body's
1263
+ * alignment or indent, or is the value simply what the shape's
1264
+ * `a:lstStyle`, its layout placeholder and the master already produce?
1265
+ * Element-level text panels (`textAdvancedPatch`, `alignPatch` and friends
1266
+ * in `pptx-viewer-shared`) write `element.textStyle` and never touch
1267
+ * `segment.paragraphProperties`, so a diff against this snapshot is the
1268
+ * only way to tell an edit from an inheritance artefact.
1269
+ *
1270
+ * @see element-paragraph-geometry.ts
1271
+ */
1272
+ resolvedParagraphGeometry?: TextStyle;
1188
1273
  fontFamily?: string;
1189
1274
  fontSize?: number;
1190
1275
  /** When true, renderer should shrink text to fit the shape bounds. */
@@ -1849,6 +1934,15 @@ interface PptxElementBase {
1849
1934
  shapeId?: string;
1850
1935
  /** Element name from `cNvPr/@name`. Used for morph transition matching via the `!!` naming convention. */
1851
1936
  name?: string;
1937
+ /**
1938
+ * `p:nvSpPr/p:nvPr/p:ph/@type` (lower-cased) when the shape is a placeholder:
1939
+ * `title`, `ctrtitle`, `body`, `subtitle`, `ftr`, `dt`, `sldnum`, ...
1940
+ *
1941
+ * Captured on load so consumers can tell a footer placeholder from a text box
1942
+ * without re-walking `rawXml`. Absent on non-placeholder shapes and on
1943
+ * SDK-created elements.
1944
+ */
1945
+ placeholderType?: string;
1852
1946
  x: number;
1853
1947
  y: number;
1854
1948
  width: number;
@@ -1909,6 +2003,19 @@ interface PptxTextProperties {
1909
2003
  }>;
1910
2004
  /** Placeholder prompt text inherited from layout/master (e.g. "Click to add title"). Shown as a greyed-out hint when the shape has no user-entered text. */
1911
2005
  promptText?: string;
2006
+ /**
2007
+ * The string {@link text} was INHERITED from, when this is a header / footer /
2008
+ * date / slide-number placeholder whose own body the file leaves empty.
2009
+ *
2010
+ * PowerPoint keeps the footer string on the slide master and writes each
2011
+ * slide's copy of the `ftr` placeholder empty, so the empty body means
2012
+ * "render the master's footer here". Rendering needs the resolved string, but
2013
+ * SAVING it into the slide would pin that slide to today's master text and
2014
+ * silently detach it from the Header & Footer dialog. The save writer
2015
+ * therefore leaves the authored empty body alone while `text` still equals
2016
+ * this value, and writes a genuine per-slide override once it does not.
2017
+ */
2018
+ inheritedPlaceholderText?: string;
1912
2019
  /** Linked text box chain ID from `a:bodyPr > a:linkedTxbx/@id` or `a:txbx > a:linkedTxbx/@id`. Text overflows from one linked frame to the next. */
1913
2020
  linkedTxbxId?: number;
1914
2021
  /** Sequence number within a linked text box chain (0-based). */
@@ -2319,6 +2426,12 @@ interface PptxChartLineStyle {
2319
2426
  }
2320
2427
  /** Marker symbol types for line/scatter chart data points. */
2321
2428
  type PptxChartMarkerSymbol = 'circle' | 'dash' | 'diamond' | 'dot' | 'none' | 'picture' | 'plus' | 'square' | 'star' | 'triangle' | 'x' | 'auto';
2429
+ /**
2430
+ * `ST_ScatterStyle` (ECMA-376 §21.2.3.40): how a scatter chart joins its points.
2431
+ * `line`/`lineMarker` connect them with straight segments, `smooth`/
2432
+ * `smoothMarker` with a bezier, `marker`/`none` not at all.
2433
+ */
2434
+ type PptxChartScatterStyle = 'none' | 'line' | 'lineMarker' | 'marker' | 'smooth' | 'smoothMarker';
2322
2435
  /** Shape properties extracted from c:spPr for chart formatting. */
2323
2436
  interface PptxChartShapeProps {
2324
2437
  fillColor?: string;
@@ -2520,6 +2633,42 @@ interface PptxChartTreemapOptions {
2520
2633
  interface PptxChartSeries {
2521
2634
  name: string;
2522
2635
  values: number[];
2636
+ /**
2637
+ * Per-series x values from `c:ser/c:xVal` (scatter and bubble series only).
2638
+ *
2639
+ * Every `CT_ScatterSer` / `CT_BubbleSer` carries its OWN `c:xVal`, so two
2640
+ * series in one scatter chart routinely plot against different x ranges (the
2641
+ * normal case for measurement data). Reading the x values off the first
2642
+ * series and reusing them everywhere plotted every series against series 1's
2643
+ * x axis. Absent for category-axis chart kinds, where
2644
+ * {@link PptxChartData.categories} is the x axis.
2645
+ */
2646
+ xValues?: number[];
2647
+ /**
2648
+ * Per-series bubble sizes from `c:ser/c:bubbleSize` (bubble series only),
2649
+ * aligned index-for-index with {@link values}.
2650
+ *
2651
+ * `CT_BubbleSer` carries x, y AND size, so a one-series bubble chart is fully
2652
+ * specified. Absent when the source omits `c:bubbleSize`.
2653
+ */
2654
+ bubbleSizes?: number[];
2655
+ /**
2656
+ * Series-level data-label content flags from `c:ser/c:dLbls`.
2657
+ *
2658
+ * PowerPoint writes the flags a user picks in "Format Data Labels" onto the
2659
+ * SERIES, and leaves the chart-type-level `c:dLbls` all-zero, so reading only
2660
+ * the chart-level group reports "show nothing" for a chart that visibly shows
2661
+ * percentages. These override {@link PptxChartStyle.dataLabels}.
2662
+ */
2663
+ dataLabelOptions?: PptxChartDataLabelOptions;
2664
+ /**
2665
+ * Whether the series line is explicitly suppressed
2666
+ * (`c:ser/c:spPr/a:ln/a:noFill`). Line-drawn kinds (line, scatter, radar)
2667
+ * use this to decide whether to draw a connecting line at all; a marker-only
2668
+ * scatter is authored as `scatterStyle="lineMarker"` PLUS this flag, never by
2669
+ * changing the scatter style.
2670
+ */
2671
+ lineNoFill?: boolean;
2523
2672
  /**
2524
2673
  * Blank-value mask aligned index-for-index with {@link values}: `true` marks
2525
2674
  * a category whose numeric cache point (`c:numCache/c:pt`) was absent or
@@ -2863,6 +3012,17 @@ interface PptxChartData {
2863
3012
  * default), so only horizontal bar charts need to carry the field.
2864
3013
  */
2865
3014
  barDirection?: PptxChartBarDirection;
3015
+ /**
3016
+ * Scatter presentation mode (`c:scatterChart/c:scatterStyle/@val`).
3017
+ *
3018
+ * `lineMarker` (PowerPoint's own default for every scatter it writes) and
3019
+ * `smoothMarker` draw a connecting line; `marker` and `none` do not. Whether
3020
+ * the MARKERS appear is decided separately by `c:marker/c:symbol`, and
3021
+ * whether the LINE appears is further gated by
3022
+ * {@link PptxChartSeries.lineNoFill} - PowerPoint expresses "markers only" as
3023
+ * `lineMarker` plus an `a:ln/a:noFill`, not as `marker`.
3024
+ */
3025
+ scatterStyle?: PptxChartScatterStyle;
2866
3026
  /**
2867
3027
  * Bar/column gap between category clusters as a percentage of bar width
2868
3028
  * (`c:gapWidth/@val`, 0 through 500). Absent uses the renderer default.
@@ -3016,6 +3176,53 @@ interface PptxChartData {
3016
3176
  * // => { brightness: 20, contrast: -10, grayscale: true } satisfies PptxImageEffects
3017
3177
  * ```
3018
3178
  */
3179
+ /**
3180
+ * One `a14:foregroundMark` / `a14:backgroundMark` polyline hint recorded while
3181
+ * the user painted over the picture in PowerPoint's "Remove Background" mode.
3182
+ * Coordinates are 0..1 fractions of the image.
3183
+ */
3184
+ interface PptxBackgroundRemovalMark {
3185
+ x1: number;
3186
+ y1: number;
3187
+ x2: number;
3188
+ y2: number;
3189
+ }
3190
+ /**
3191
+ * PowerPoint "Remove Background" state (`a14:backgroundRemoval`).
3192
+ *
3193
+ * The four edges are the RETAINED rectangle as 0..1 fractions of the image
3194
+ * (OOXML stores them as per-100000 relative units), and the mark lists are the
3195
+ * segmentation hints the user painted.
3196
+ *
3197
+ * **This is edit-time metadata, not a render instruction.** PowerPoint bakes the
3198
+ * removal into the bitmap referenced by the main `a:blip/@r:embed` and keeps the
3199
+ * pristine original in `a14:imgLayer/@r:embed`. Verified against PowerPoint COM:
3200
+ * a slide exported with and without this element is byte-identical. A renderer
3201
+ * that clips to the retained rectangle would clip an image whose background has
3202
+ * already been removed.
3203
+ *
3204
+ * @example
3205
+ * ```ts
3206
+ * const removal: PptxBackgroundRemoval = { top: 0.12, bottom: 0.88, left: 0.07, right: 0.93 };
3207
+ * // => retains the middle of the image; the marks list stays empty
3208
+ * ```
3209
+ */
3210
+ interface PptxBackgroundRemoval {
3211
+ /** Top edge of the retained rectangle (0..1 fraction of the image height). */
3212
+ top: number;
3213
+ /** Bottom edge of the retained rectangle (0..1 fraction of the image height). */
3214
+ bottom: number;
3215
+ /** Left edge of the retained rectangle (0..1 fraction of the image width). */
3216
+ left: number;
3217
+ /** Right edge of the retained rectangle (0..1 fraction of the image width). */
3218
+ right: number;
3219
+ /** Strokes marking regions the user forced to be foreground. */
3220
+ foregroundMarks?: PptxBackgroundRemovalMark[];
3221
+ /** Strokes marking regions the user forced to be background. */
3222
+ backgroundMarks?: PptxBackgroundRemovalMark[];
3223
+ /** Original effect XML, retained for lossless re-emission. */
3224
+ rawXml?: XmlObject;
3225
+ }
3019
3226
  interface PptxImageEffects {
3020
3227
  /** Brightness adjustment (-100 to 100). */
3021
3228
  brightness?: number;
@@ -3039,8 +3246,38 @@ interface PptxImageEffects {
3039
3246
  };
3040
3247
  /** Artistic effect name (blur, pencilGrayscale, paintStrokes, etc.). */
3041
3248
  artisticEffect?: string;
3042
- /** Artistic effect radius/amount. */
3249
+ /** Artistic effect radius/amount, normalised to 0..100. */
3043
3250
  artisticRadius?: number;
3251
+ /**
3252
+ * Every numeric attribute of the source `a14:artistic*` element, raw and
3253
+ * un-normalised (`trans`, `pencilSize`, `crackSpacing`, …). The attribute set
3254
+ * differs per effect, so this is the lossless companion to the single
3255
+ * {@link PptxImageEffects.artisticRadius} number.
3256
+ */
3257
+ artisticParams?: Record<string, number>;
3258
+ /**
3259
+ * Name of the artistic effect ALREADY baked into the image data, which a
3260
+ * renderer must not apply a second time. Set from the `a14` blip extension,
3261
+ * which PowerPoint writes alongside a pre-rendered bitmap (see
3262
+ * {@link PptxBackgroundRemoval}), and normally equal to
3263
+ * {@link PptxImageEffects.artisticEffect}.
3264
+ *
3265
+ * It records the NAME rather than a boolean so that picking a different
3266
+ * effect in this library's inspector (which patches `artisticEffect` alone)
3267
+ * still renders: the two names then differ.
3268
+ */
3269
+ artisticPrerenderedEffect?: string;
3270
+ /**
3271
+ * PowerPoint "Remove Background" state (`a14:backgroundRemoval`). Edit-time
3272
+ * metadata: the removal is already baked into the image data.
3273
+ */
3274
+ backgroundRemoval?: PptxBackgroundRemoval;
3275
+ /**
3276
+ * `a14:imgLayer/@r:embed` — relationship id of the PRISTINE original image
3277
+ * the baked effects were derived from (PowerPoint stores it as an HD Photo
3278
+ * `.wdp` part, which browsers cannot decode).
3279
+ */
3280
+ originalImageRelId?: string;
3044
3281
  /** Alpha modulation fixed: non-negative percentage (100 means unchanged opacity). */
3045
3282
  alphaModFix?: number;
3046
3283
  /** Original alpha modulation fixed node, including foreign attributes. */
@@ -4952,7 +5189,7 @@ interface UnknownPptxElement extends PptxElementBase {
4952
5189
  /**
4953
5190
  * A single element on a PPTX slide.
4954
5191
  *
4955
- * This is a **discriminated union** — narrow on `element.type` to access
5192
+ * This is a **discriminated union**: narrow on `element.type` to access
4956
5193
  * variant-specific properties like `imageData` (image/picture), `pathData`
4957
5194
  * (shape), or `textSegments` (text/shape).
4958
5195
  */
@@ -5695,6 +5932,54 @@ interface PptxEmbeddedFontList {
5695
5932
  rawXml?: XmlObject;
5696
5933
  }
5697
5934
  //#endregion
5935
+ //#region src/core/types/comment-mentions.d.ts
5936
+ /**
5937
+ * A single `@`-mention inside a modern comment body.
5938
+ *
5939
+ * Offsets index into the comment's FLATTENED plain text: every `a:t` value
5940
+ * below `p188:txBody` concatenated, with paragraphs joined by `\n`. That is the
5941
+ * same string `PptxComment.text` carries, so an edit to `text` invalidates
5942
+ * every offset after the edit point and the serializer re-bases them.
5943
+ *
5944
+ * The markup Office uses for a mention is `CT_Mention` (documented for the
5945
+ * SpreadsheetML `2018/threadedcomments` part): `mentionpersonId`, `mentionId`,
5946
+ * `startIndex` and `length`. The PowerPoint `2018/8/main` schema does not
5947
+ * publish a mention element at all, so `rawXml` is retained and re-emitted
5948
+ * attribute-for-attribute: a producer that spells the attributes differently
5949
+ * still round-trips.
5950
+ *
5951
+ * @example
5952
+ * ```ts
5953
+ * const mention: PptxCommentMention = {
5954
+ * personId: "{2CB2E9D0-D392-EB21-5D46-FBA34C1295E6}",
5955
+ * authorName: "Bob Example",
5956
+ * startIndex: 3,
5957
+ * length: 11,
5958
+ * };
5959
+ * // => "Hi Bob Example can you check this".slice(3, 14) === "Bob Example"
5960
+ * ```
5961
+ */
5962
+ interface PptxCommentMention {
5963
+ /** `mentionId`: GUID identifying this mention instance. */
5964
+ id?: string;
5965
+ /** `mentionpersonId`: the `p188:author` id of the mentioned person. */
5966
+ personId: string;
5967
+ /** Display name resolved from the author list at parse time, when known. */
5968
+ authorName?: string;
5969
+ /** Character offset of the mentioned span in the flattened plain text. */
5970
+ startIndex: number;
5971
+ /** Character length of the mentioned span. */
5972
+ length: number;
5973
+ /**
5974
+ * `uri` of the `p188:ext` this mention list was read from. Undefined means
5975
+ * the list is a direct child of `p188:cm`, which is where it is written for
5976
+ * newly authored mentions.
5977
+ */
5978
+ containerUri?: string;
5979
+ /** Original `p188:mention` node, retained for unknown-attribute preservation. */
5980
+ rawXml?: XmlObject;
5981
+ }
5982
+ //#endregion
5698
5983
  //#region src/core/types/metadata.d.ts
5699
5984
  /**
5700
5985
  * A slide comment — may be a legacy positional comment or a modern
@@ -5741,6 +6026,8 @@ interface PptxComment {
5741
6026
  title?: string;
5742
6027
  /** Modern threaded comment support (p15:threadingInfo). */
5743
6028
  threadId?: string;
6029
+ /** `@`-mentions, indexed into `text` (see {@link PptxCommentMention}). */
6030
+ mentions?: PptxCommentMention[];
5744
6031
  /** Replies to this comment (for modern threaded comments). */
5745
6032
  replies?: PptxComment[];
5746
6033
  /** ID of the element this comment is associated with (if any). */
@@ -6260,7 +6547,7 @@ interface PptxTheme {
6260
6547
  * // => "morph" — one of 40+ transition effects
6261
6548
  * ```
6262
6549
  */
6263
- type PptxTransitionType = 'none' | 'cut' | 'fade' | 'push' | 'wipe' | 'split' | 'randomBar' | 'blinds' | 'checker' | 'circle' | 'comb' | 'cover' | 'diamond' | 'dissolve' | 'plus' | 'pull' | 'random' | 'strips' | 'uncover' | 'wedge' | 'wheel' | 'zoom' | 'newsflash' | 'morph' | 'conveyor' | 'doors' | 'ferris' | 'flash' | 'flythrough' | 'gallery' | 'glitter' | 'honeycomb' | 'pan' | 'prism' | 'reveal' | 'ripple' | 'shred' | 'switch' | 'vortex' | 'warp' | 'wheelReverse' | 'window' | 'cube' | 'flip' | 'rotate' | 'orbit' | 'fallOver' | 'drape' | 'curtains' | 'wind' | 'prestige' | 'fracture' | 'crush' | 'peelOff' | 'pageCurlDouble' | 'pageCurlSingle' | 'airplane' | 'origami';
6550
+ type PptxTransitionType = 'none' | 'cut' | 'fade' | 'push' | 'wipe' | 'split' | 'randomBar' | 'blinds' | 'checker' | 'circle' | 'comb' | 'cover' | 'diamond' | 'dissolve' | 'plus' | 'pull' | 'random' | 'strips' | 'uncover' | 'wedge' | 'wheel' | 'zoom' | 'newsflash' | 'morph' | 'conveyor' | 'doors' | 'ferris' | 'flash' | 'flythrough' | 'gallery' | 'glitter' | 'honeycomb' | 'pan' | 'prism' | 'reveal' | 'ripple' | 'shred' | 'switch' | 'vortex' | 'warp' | 'wheelReverse' | 'window' | 'cube' | 'flip' | 'rotate' | 'box' | 'orbit' | 'fallOver' | 'drape' | 'curtains' | 'wind' | 'prestige' | 'fracture' | 'crush' | 'peelOff' | 'pageCurlDouble' | 'pageCurlSingle' | 'airplane' | 'origami';
6264
6551
  /** Split orientation from OOXML `@_orient`. */
6265
6552
  type PptxSplitOrientation = 'horz' | 'vert';
6266
6553
  /** Schema-defined `ST_TransitionSpeed` values. */
@@ -6555,6 +6842,18 @@ interface PptxSlideBackgroundPattern {
6555
6842
  interface PptxSlide {
6556
6843
  id: string;
6557
6844
  rId: string;
6845
+ /**
6846
+ * `p:sldIdLst/p:sldId/@id` (ST_SlideId, 256..2147483647): the numeric key
6847
+ * that sections (`p14:sldIdLst/p14:sldId/@id`) and section/summary zooms
6848
+ * name slides by.
6849
+ *
6850
+ * It lives in `presentation.xml`, NOT in the slide part, so it cannot be
6851
+ * recovered from `rawXml`. Without it on the model, code that writes a
6852
+ * section's membership has nothing correct to write and falls back to the
6853
+ * slide NUMBER, which is 1-based and therefore never matches a real deck's
6854
+ * ids: the section reloads with no slides in it.
6855
+ */
6856
+ slideId?: string;
6558
6857
  sourceSlideId?: string;
6559
6858
  /** Optional author-supplied slide name (set via `SlideBuilder.setName`). */
6560
6859
  name?: string;
@@ -6757,6 +7056,26 @@ interface PptxPresentationProperties {
6757
7056
  /** Kiosk auto-restart interval in milliseconds (from `p:kiosk/@restart`). Only meaningful when showType is "kiosk". */
6758
7057
  kioskRestartTime?: number;
6759
7058
  }
7059
+ /**
7060
+ * Slide dimensions from `p:sldSz` (CT_SlideSize, ECMA-376 §19.2.1.39).
7061
+ *
7062
+ * @example
7063
+ * ```ts
7064
+ * const size: PptxSlideSize = { widthEmu: 9144000, heightEmu: 6858000, type: 'screen4x3' };
7065
+ * // => satisfies PptxSlideSize
7066
+ * ```
7067
+ */
7068
+ interface PptxSlideSize {
7069
+ /** `@cx` in EMU. Omitted or non-positive values leave the loaded width alone. */
7070
+ widthEmu?: number;
7071
+ /** `@cy` in EMU. Omitted or non-positive values leave the loaded height alone. */
7072
+ heightEmu?: number;
7073
+ /**
7074
+ * `@type` (ST_SlideSizeType). The schema default is `custom`, which is
7075
+ * why PowerPoint omits the attribute for a non-preset size.
7076
+ */
7077
+ type?: string;
7078
+ }
6760
7079
  /**
6761
7080
  * A named custom slide show (`p:custShowLst / p:custShow`).
6762
7081
  *
@@ -7771,6 +8090,19 @@ interface PptxHandlerSaveOptions {
7771
8090
  customerData?: PptxCustomerData[];
7772
8091
  /** Photo album metadata to save back to `p:photoAlbum`. */
7773
8092
  photoAlbum?: PptxPhotoAlbum;
8093
+ /**
8094
+ * Slide dimensions to write back to `p:sldSz`.
8095
+ *
8096
+ * Omitting the option preserves the load-time dimensions verbatim, which
8097
+ * is why an edit made through a viewer's Slide Size control has to reach
8098
+ * the save call: nothing else in the pipeline can observe it.
8099
+ *
8100
+ * PowerPoint derives `Presentation.PageSetup.SlideSize` from `@cx`/`@cy`
8101
+ * alone (verified by COM: an A4-typed `p:sldSz` carrying 4:3 dimensions
8102
+ * still reports `ppSlideSizeCustom`), so `type` is written for fidelity
8103
+ * but the dimensions are what actually decide the reported preset.
8104
+ */
8105
+ slideSize?: PptxSlideSize;
7774
8106
  /** East Asian line-break settings to save back to `p:kinsoku`. */
7775
8107
  kinsoku?: PptxKinsoku | null;
7776
8108
  /** Write-protection verifier. Set to `null` to remove, `undefined` to preserve existing. */
@@ -8362,24 +8694,38 @@ declare class PptxHandlerCore {
8362
8694
  name?: string;
8363
8695
  }>>;
8364
8696
  /**
8365
- * Export selected slides as individual PPTX files.
8697
+ * Export selected slides to a vector or raster format, keyed by slide index.
8698
+ *
8699
+ * **This does not produce PPTX files.** The previous version of this comment
8700
+ * said each entry was "a standalone PPTX with only that slide", named the
8701
+ * option `slideIndexes` (the real field is `slideIndices`), and wrote the
8702
+ * bytes to `slide_N.pptx`. None of that was ever true: the runtime has
8703
+ * always taken a `format` of `svg` / `png` / `pdf`. Per-slide PPTX
8704
+ * extraction is a different operation and is not implemented here.
8366
8705
  *
8367
- * Each entry in the returned map is keyed by slide index and contains a
8368
- * standalone `Uint8Array` PPTX with only that slide.
8706
+ * Only `svg` works without a host-supplied backend, and it works fully:
8707
+ * the headless {@link SvgExporter} renders it with no DOM. `png` and `pdf`
8708
+ * THROW, because this package carries no rasteriser; use a viewer binding's
8709
+ * browser export pipeline, or override `exportSlides` on the runtime with
8710
+ * your own backend.
8369
8711
  *
8370
8712
  * @param slides - Full slide array.
8371
- * @param options - Export options (slide indexes, format, etc.).
8372
- * @returns A `Map<slideIndex, Uint8Array>` of exported files.
8713
+ * @param options - Export options (`format`, `slideIndices`, `width`, ...).
8714
+ * @returns A `Map<slideIndex, Uint8Array>` of exported files. Hidden slides
8715
+ * are omitted unless `options.includeHidden` is set, so the map can be
8716
+ * smaller than `options.slideIndices`.
8717
+ * @throws {Error} when `options.format` is `png` or `pdf`.
8373
8718
  *
8374
8719
  * @example
8375
8720
  * ```ts
8376
8721
  * const exports = await handler.exportSlides(data.slides, {
8377
- * slideIndexes: [0, 2],
8722
+ * format: 'svg',
8723
+ * slideIndices: [0, 2],
8378
8724
  * });
8379
8725
  * for (const [idx, bytes] of exports) {
8380
- * await fs.writeFile(`slide_${idx}.pptx`, Buffer.from(bytes));
8726
+ * await fs.writeFile(`slide_${idx}.svg`, Buffer.from(bytes));
8381
8727
  * }
8382
- * // => Map<number, Uint8Array> — one standalone .pptx per exported slide
8728
+ * // => Map<number, Uint8Array>: one SVG document per exported slide
8383
8729
  * ```
8384
8730
  */
8385
8731
  exportSlides(slides: PptxSlide[], options: PptxExportOptions): Promise<Map<number, Uint8Array>>;
@@ -8939,16 +9285,71 @@ interface FieldSubstitutionContext {
8939
9285
  /** Title text extracted from the first title placeholder on the slide. */
8940
9286
  slideTitle?: string;
8941
9287
  }
8942
- /** Descriptor for the draggable adjustment handle (the amber diamond). */
9288
+ //#endregion
9289
+ //#region src/render/connector-endpoints.d.ts
9290
+ /** Which end of a connector a gesture is moving. */
9291
+ type ConnectorEndpointKind = 'start' | 'end';
9292
+ //#endregion
9293
+ //#region src/render/shape-adjustment-model.d.ts
9294
+ /**
9295
+ * `shape-adjustment-model`: the vocabulary the adjust-handle modules share.
9296
+ *
9297
+ * The `a:ahLst` work is split three ways for the repo's file-size budget:
9298
+ * `shape-adjustment-probe` measures the geometry, `shape-adjustment-handles`
9299
+ * derives the handles from those measurements, and `shape-adjustment-solver`
9300
+ * turns a pointer position back into guide values. All three need these types
9301
+ * and the one rule that operates purely on them, so they live here and the
9302
+ * dependency graph stays a DAG rather than a cycle.
9303
+ *
9304
+ * @module render/shape-adjustment-model
9305
+ */
9306
+ /**
9307
+ * How a pointer position becomes a guide value, captured once when the gesture
9308
+ * starts so `pointermove` stays pure arithmetic.
9309
+ */
9310
+ interface ShapeAdjustmentSolver {
9311
+ /** `linear`: the handle slides. `angular`: it swings about {@link centerX}. */
9312
+ kind: 'linear' | 'angular';
9313
+ /** Handle position in element-local px at {@link startValue}. */
9314
+ anchorX: number;
9315
+ anchorY: number;
9316
+ /** Element-local px the handle travels per ONE unit of guide value. */
9317
+ dirX: number;
9318
+ dirY: number;
9319
+ /** Pivot for an angular handle (the shape centre). */
9320
+ centerX: number;
9321
+ centerY: number;
9322
+ /** The guide value the anchor was measured at. */
9323
+ startValue: number;
9324
+ /** Guide-space bounds, taken from the preset's own `pin` clamp. */
9325
+ min: number;
9326
+ max: number;
9327
+ }
9328
+ /** One guide a handle drives. */
9329
+ interface AdjustmentAxisSolver {
9330
+ key: string;
9331
+ solver: ShapeAdjustmentSolver;
9332
+ }
9333
+ /** Descriptor for one draggable adjustment handle (the amber diamond). */
8943
9334
  interface ShapeAdjustmentHandleDescriptor {
9335
+ /** The `a:avLst` guide name this handle writes (`adj`, `adj1`, ...). */
8944
9336
  key: string;
8945
9337
  /** Handle x offset in element-local px (origin = element top-left). */
8946
9338
  left: number;
8947
9339
  /** Handle y offset in element-local px. */
8948
9340
  top: number;
8949
- /** Current adjustment value (0–50000). */
9341
+ /**
9342
+ * Current adjustment value in GUIDE units, not a 0-1 fraction. Most presets
9343
+ * range 0..50000 or 0..100000 and the angular ones run to 21,600,000.
9344
+ */
8950
9345
  value: number;
8951
9346
  cursor: string;
9347
+ /**
9348
+ * How this handle's drag resolves, measured off the preset geometry: one
9349
+ * entry per `a:avLst` guide it drives (callouts drive two). Absent only for
9350
+ * a caller that built a descriptor by hand.
9351
+ */
9352
+ solvers?: AdjustmentAxisSolver[];
8952
9353
  }
8953
9354
  //#endregion
8954
9355
  //#region src/render/collaboration-presence.d.ts
@@ -9142,6 +9543,12 @@ interface ViewerFontSource {
9142
9543
  weight?: string | number;
9143
9544
  style?: 'normal' | 'italic';
9144
9545
  }
9546
+ interface SlideSizeEmu {
9547
+ widthEmu: number;
9548
+ heightEmu: number;
9549
+ /** ST_SlideSizeType token, or `''` for a size with no preset. */
9550
+ type: string;
9551
+ }
9145
9552
  /** The configuration emitted when a broadcast starts. */
9146
9553
  interface BroadcastConfig {
9147
9554
  roomId: string;
@@ -9259,6 +9666,93 @@ interface FontEmbeddingDescriptor {
9259
9666
  declare function zoomInPercent(percent: number): number;
9260
9667
  /** The percentage one zoom-out press moves to, clamped. */
9261
9668
  declare function zoomOutPercent(percent: number): number;
9669
+ //#endregion
9670
+ //#region src/render/autosave-policy.d.ts
9671
+ /**
9672
+ * @fileoverview Who decides whether recovery autosave runs, and how often.
9673
+ *
9674
+ * ## The rule: the host prop is a ceiling, the toggle is a preference
9675
+ *
9676
+ * Two things can speak about autosave, and until now each binding invented its
9677
+ * own answer for what happens when both do:
9678
+ *
9679
+ * - the **host** passes an `autosave` prop. That is a POLICY: the embedder is
9680
+ * stating what its application permits.
9681
+ * - the **user** flips the title-bar AutoSave switch, or File > Options > Save
9682
+ * > AutoSave. That is a PREFERENCE, expressed inside whatever the host allows.
9683
+ *
9684
+ * A preference can never exceed a policy, so:
9685
+ *
9686
+ * - `autosave={false}` turns recovery autosave OFF and takes the toggle away
9687
+ * (`toggleAvailable: false`). A user cannot switch on what the application
9688
+ * forbade, and a switch that silently does nothing is worse than no switch.
9689
+ * - `autosave={true}`, or the prop omitted entirely, PERMITS autosave. The
9690
+ * user's toggle then decides, and it defaults to on.
9691
+ *
9692
+ * The prop is therefore only load-bearing when it is `false`. That is
9693
+ * deliberate: crash recovery that is off by default is crash recovery nobody
9694
+ * has, and the shared options schema already declares `save.autoSave: true` as
9695
+ * the user default, so any other prop default would contradict it. Vue, Svelte
9696
+ * and Vanilla previously defaulted to `false` and React and Angular to `true`;
9697
+ * `true` is the answer, and the three that defaulted off now write recovery
9698
+ * snapshots for hosts that never opted in. Pass `autosave={false}` to opt out.
9699
+ *
9700
+ * Two further gates are not negotiable by anyone, because without them there is
9701
+ * nothing to write or nowhere to write it: editing must be possible at all, and
9702
+ * a `filePath` must be set to key the IndexedDB record.
9703
+ *
9704
+ * ## Cadence follows the same rule
9705
+ *
9706
+ * An explicit `autosaveIntervalMs` prop is a policy and is honoured as given.
9707
+ * Otherwise the cadence is the user's own File > Options > Save > "Save
9708
+ * AutoRecover information every N minutes" (default two minutes), which React
9709
+ * and Angular already respected and the other three ignored.
9710
+ *
9711
+ * ## What the two engine shapes must agree on
9712
+ *
9713
+ * React and Angular POLL on a fixed interval; Vue, Svelte and Vanilla DEBOUNCE
9714
+ * on the edit. Both are legitimate, but a plain debounce has a failure mode a
9715
+ * poll does not: a user who keeps editing keeps re-arming the timer, so it can
9716
+ * defer a snapshot forever, and at the two-minute cadence that is an entire
9717
+ * session of lost work. {@link nextAutosaveDelayMs} caps the debounce so both
9718
+ * shapes make the same promise:
9719
+ *
9720
+ * **a snapshot lands no later than one interval after the first unsaved edit,
9721
+ * and no more often than once per interval.**
9722
+ *
9723
+ * @module render/autosave-policy
9724
+ */
9725
+ /**
9726
+ * Why autosave is not running. `autosave_toggle_off` and `no_file_path` are the
9727
+ * codes the title bar has always understood; the other two are new and fall
9728
+ * back to the generic message in bindings that do not map them.
9729
+ */
9730
+ type AutosaveDisabledReason = 'autosave_host_off' | 'autosave_toggle_off' | 'no_file_path' | 'read_only';
9731
+ /** Everything a binding needs to render the recovery dialog, and nothing else. */
9732
+ interface AutosaveRecoveryPrompt {
9733
+ /** IndexedDB key the snapshot is stored under (the deck's file path/name). */
9734
+ readonly filePath: string;
9735
+ /** When the snapshot was written (epoch ms). */
9736
+ readonly timestamp: number;
9737
+ /** Snapshot size in bytes. */
9738
+ readonly size: number;
9739
+ /** Whole minutes since it was written, floored at 0. */
9740
+ readonly ageMinutes: number;
9741
+ readonly titleKey: string;
9742
+ readonly messageKey: string;
9743
+ /** `size` is pre-formatted here because byte units are not translated. */
9744
+ readonly messageParams: {
9745
+ readonly file: string;
9746
+ readonly size: string;
9747
+ };
9748
+ /** Relative age, reusing the existing autosave age keys. */
9749
+ readonly ageKey: string;
9750
+ readonly ageParams: {
9751
+ readonly count: number;
9752
+ };
9753
+ readonly restoreKey: string;
9754
+ readonly discardKey: string;
9755
+ }
9262
9756
  /**
9263
9757
  * Why the deck is being serialised, which is a separate question from whether
9264
9758
  * the user protected it.
@@ -9425,13 +9919,25 @@ interface ViewerProofingOptions {
9425
9919
  checkSpellingAsYouType: boolean;
9426
9920
  hideSpellingErrors: boolean;
9427
9921
  }
9922
+ /**
9923
+ * File > Options > Save.
9924
+ *
9925
+ * Font embedding deliberately has NO entry here. It is owned by the File >
9926
+ * Fonts panel, whose toggle is the one the save path reads (see
9927
+ * `render/font-embedding`: `describeFontEmbedding` decides the toggle's start
9928
+ * position and whether it can do anything at all, `embeddedFontSaveOptions`
9929
+ * turns it into the `PptxHandler.save()` slice). This group used to carry a
9930
+ * second `embedFonts` boolean, plus an `embedAllFontCharacters` companion, and
9931
+ * neither was read by anything: the pane moved a switch that changed no saved
9932
+ * byte, while the panel next door moved the real one. Two switches for one
9933
+ * setting, one of them lying, is worse than one switch in a less
9934
+ * PowerPoint-shaped place.
9935
+ */
9428
9936
  interface ViewerSaveOptions {
9429
9937
  autoSave: boolean;
9430
9938
  autoRecoverIntervalMinutes: number;
9431
9939
  keepLastAutoRecoveredVersion: boolean;
9432
9940
  defaultExportFormat: DefaultExportFormat;
9433
- embedFonts: boolean;
9434
- embedAllFontCharacters: boolean;
9435
9941
  cacheRetentionDays: number;
9436
9942
  clearCacheOnClose: boolean;
9437
9943
  }
@@ -10168,13 +10674,28 @@ interface PowerPointViewerProps {
10168
10674
  /** Host override for the File > Open action. */
10169
10675
  onopenfile?: () => void;
10170
10676
  /**
10171
- * Enable debounced crash-recovery autosave. On each edit (when `editable`)
10172
- * the current slides are serialized to `.pptx` bytes and written to the
10173
- * shared IndexedDB recovery store (keyed by {@link filePath}), and
10174
- * `onautosave` is fired with the bytes. Requires `filePath`; without one the
10175
- * autosave indicator reads "disabled". This binding does not auto-restore on
10176
- * load; recovery is a host concern (see the re-exported `getAutosaveSnapshot`
10177
- * / `listAutosaveSnapshots` helpers). Default false.
10677
+ * POLICY CEILING for crash-recovery autosave. Not a switch the host flips on
10678
+ * the user's behalf: it states what this application permits, and the
10679
+ * title-bar AutoSave toggle (and File > Options > Save > AutoSave) is the
10680
+ * user's preference inside it.
10681
+ *
10682
+ * - `false` turns autosave off AND renders the toggle off and inert; a user
10683
+ * cannot switch on what the application forbade.
10684
+ * - `true`, or omitted, PERMITS autosave and lets the toggle decide.
10685
+ *
10686
+ * While active, each edit serializes the current slides to `.pptx` bytes,
10687
+ * writes them to the shared IndexedDB recovery store (keyed by
10688
+ * {@link filePath}) and fires `onautosave`. A snapshot lands no later than
10689
+ * one interval after the first unsaved edit, and no more often than once per
10690
+ * interval. Requires `filePath`; without one the indicator reads "disabled".
10691
+ *
10692
+ * On the next load of the same `filePath` the viewer OFFERS the snapshot back
10693
+ * in a "Recover unsaved changes?" dialog (Restore loads it in place, Discard
10694
+ * deletes it), unless this prop is `false`. The store is also reachable
10695
+ * directly through the re-exported `getAutosaveSnapshot` /
10696
+ * `listAutosaveSnapshots` helpers.
10697
+ *
10698
+ * @default true
10178
10699
  */
10179
10700
  autosave?: boolean;
10180
10701
  /** Fired when the desktop title bar toggles AutoSave for this viewer instance. */
@@ -10184,7 +10705,16 @@ interface PowerPointViewerProps {
10184
10705
  * Autosave is inert until this is set.
10185
10706
  */
10186
10707
  filePath?: string;
10187
- /** Autosave debounce window in milliseconds. Default 2000. */
10708
+ /**
10709
+ * Autosave cadence in milliseconds: the debounce window, and the ceiling on
10710
+ * how long an unbroken stream of edits may defer a snapshot.
10711
+ *
10712
+ * Optional, and a policy like {@link autosave}: pass it and it wins. Leave it
10713
+ * out and the cadence is the user's own File > Options > Save > "Save
10714
+ * AutoRecover information every N minutes", which defaults to two minutes.
10715
+ *
10716
+ * @default 120000 (Options > Save, "every 2 minutes")
10717
+ */
10188
10718
  autosaveIntervalMs?: number;
10189
10719
  /** Fired with the serialized `.pptx` bytes after each successful autosave. */
10190
10720
  onautosave?: (bytes: Uint8Array) => void;
@@ -10310,6 +10840,8 @@ interface SlideCanvasProps {
10310
10840
  ontablecellcommit?: (elementId: string, rowIndex: number, cellIndex: number, text: string) => void;
10311
10841
  onsmartartnodecommit?: (elementId: string, nodeId: string, text: string) => void;
10312
10842
  onsmartartnodefill?: (elementId: string, nodeId: string, fill: string) => void;
10843
+ /** See `ElementRendererProps.onchartpointcommit`. */
10844
+ onchartpointcommit?: (elementId: string, chartData: PptxChartData) => void;
10313
10845
  /** Passed through to `SlideStage`; see {@link SlideStageProps.comments}. */
10314
10846
  comments?: readonly PptxComment[];
10315
10847
  /** Passed through to `SlideStage`; see {@link SlideStageProps.oncommentmarkerclick}. */
@@ -10414,6 +10946,13 @@ declare class ExportUiState {
10414
10946
  * - Vue's debounce-on-edit trigger: an edit marks the document dirty and
10415
10947
  * (re)arms a debounce timer instead of polling on a fixed interval.
10416
10948
  *
10949
+ * The debounce is CAPPED by the shared `nextAutosaveDelayMs`, so it keeps the
10950
+ * same promise React's and Angular's polling engines do: a snapshot lands no
10951
+ * later than one interval after the FIRST unsaved edit, and no more often than
10952
+ * once per interval. Without that cap a user who keeps typing keeps re-arming
10953
+ * the timer, and at the two-minute AutoRecover cadence that is a whole session
10954
+ * of work that never reaches the recovery store.
10955
+ *
10417
10956
  * The controller registers its own edit-watching `$effect` in the constructor,
10418
10957
  * so the SFC only has to construct it once during setup and read its reactive
10419
10958
  * `status` / `isDirty` for the toolbar indicator.
@@ -10429,9 +10968,13 @@ declare class ExportUiState {
10429
10968
  */
10430
10969
  type AutosaveStatus = 'idle' | 'disabled' | 'saving' | 'saved' | 'error';
10431
10970
  interface AutosaveDeps {
10432
- /** Master on/off: host `autosave` prop AND editing allowed. */
10971
+ /**
10972
+ * Master on/off: the resolved activation (`resolveAutosaveActivation` in
10973
+ * shared), which folds the host policy, the user's toggle, editability and
10974
+ * the collaboration read-only veto into one answer.
10975
+ */
10433
10976
  getEnabled: () => boolean;
10434
- /** Debounce window in milliseconds. */
10977
+ /** Debounce window in milliseconds, and the ceiling on deferring a save. */
10435
10978
  getIntervalMs: () => number;
10436
10979
  /** IndexedDB record key (host `filePath`); autosave is disabled without one. */
10437
10980
  getFilePath: () => string | undefined;
@@ -10456,6 +10999,19 @@ interface AutosaveDeps {
10456
10999
  * a user edit), so the watcher clears dirty instead of arming a save.
10457
11000
  */
10458
11001
  getLoadCount: () => number;
11002
+ /**
11003
+ * Monotonic SEED counter, bumped in the same synchronous block that installs
11004
+ * the loaded slides (`EditorState.seedNonce`).
11005
+ *
11006
+ * `getLoadCount` alone is not enough, because the loader bumps it in an
11007
+ * earlier flush than the effect that copies its slides into the editor: this
11008
+ * watcher ran once on the count change (old slides, so nothing to do) and
11009
+ * then a second time on the slide reassignment, with the count already
11010
+ * settled - indistinguishable from an edit. Merely OPENING a deck therefore
11011
+ * marked it dirty and wrote a crash-recovery snapshot, so the next visit
11012
+ * offered to recover unsaved changes that never existed.
11013
+ */
11014
+ getSeedNonce?: () => number;
10459
11015
  /** Host callback with the freshly-serialized bytes on each successful save. */
10460
11016
  onSaved?: (bytes: Uint8Array) => void;
10461
11017
  }
@@ -10870,6 +11426,17 @@ declare class EditorPresentationMetadata {
10870
11426
  presentationProperties: PptxPresentationProperties;
10871
11427
  customShows: PptxCustomShow[];
10872
11428
  constructor(host: PresentationMetadataHost);
11429
+ /**
11430
+ * Deep-copy a value that may be a rune PROXY.
11431
+ *
11432
+ * The dialogs build their edits in `$state`, so what reaches these setters is
11433
+ * a reactive proxy, and `structuredClone` throws `DataCloneError` on one. The
11434
+ * Header & Footer panel hit exactly that: "Apply to All" threw before it ever
11435
+ * assigned, so setting a footer silently did nothing and the canvas kept the
11436
+ * string the deck was loaded with. `$state.snapshot` is a pass-through for a
11437
+ * plain object, so this is safe for every caller.
11438
+ */
11439
+ private static clone;
10873
11440
  set(headerFooter?: PptxHeaderFooter, presentationProperties?: PptxPresentationProperties, customShows?: PptxCustomShow[]): void;
10874
11441
  updatePresentationProperties(next: PptxPresentationProperties): void;
10875
11442
  updateHeaderFooter(next: PptxHeaderFooter): void;
@@ -11058,6 +11625,13 @@ declare class TableCellSelection {
11058
11625
  interface EditorStateDeps {
11059
11626
  getCurrent(): number;
11060
11627
  getHandler(): PptxHandler | null;
11628
+ /**
11629
+ * The `p:sldSz` a save should write, resolved from the viewer's EMU slide
11630
+ * size and its pixel canvas by the shared `resolveSlideSizeSelection`.
11631
+ * Optional so out-of-tree mounts (and the unit tests) can omit it, in which
11632
+ * case core re-emits the load-time dimensions verbatim.
11633
+ */
11634
+ getSlideSize?: () => PptxSlideSize | undefined;
11061
11635
  onChange?: () => void;
11062
11636
  }
11063
11637
  declare class EditorState {
@@ -11112,6 +11686,20 @@ declare class EditorState {
11112
11686
  readonly tableCells: TableCellSelection;
11113
11687
  editable: boolean;
11114
11688
  dirty: boolean;
11689
+ /**
11690
+ * Monotonic counter bumped by {@link setSlides}, i.e. every time a freshly
11691
+ * loaded deck is installed as the working document.
11692
+ *
11693
+ * It exists because the loader's own `loadCount` is bumped in an EARLIER
11694
+ * flush than the one that writes these slides: the seeding effect
11695
+ * (`viewer-effects.svelte.ts`) reacts to `loadCount`, so by the time it calls
11696
+ * `setSlides` the autosave effect has already run once, seen the new count
11697
+ * against the old slides, and settled. The slide reassignment that followed
11698
+ * then looked exactly like a user edit, and merely OPENING a deck wrote a
11699
+ * crash-recovery snapshot. This counter changes in the SAME synchronous block
11700
+ * as the slides it describes, so the reseed can never be misread again.
11701
+ */
11702
+ seedNonce: number;
11115
11703
  editTemplateMode: boolean;
11116
11704
  interactionActive: boolean;
11117
11705
  clipboard: ElementClipboardPayload | null;
@@ -11155,6 +11743,13 @@ declare class EditorState {
11155
11743
  /** The loaded core handler, or null before a deck is open. Used by the
11156
11744
  * Slides group for layout switching (`applyLayoutToSlide`). */
11157
11745
  getHandler(): PptxHandler | null;
11746
+ /**
11747
+ * The `p:sldSz` the next save should write, or undefined to leave the
11748
+ * load-time dimensions alone. Slide size lives on the loader (it is not
11749
+ * content the undo stack owns), so it reaches the save through this dep the
11750
+ * same way the handler does.
11751
+ */
11752
+ getSlideSize(): PptxSlideSize | undefined;
11158
11753
  /** Adopt a freshly loaded deck as the working document (see `loadEditorDocument`). */
11159
11754
  setSlides(...args: LoadDocumentArgs): void;
11160
11755
  /** Adopt a remote (collaboration) snapshot; see `applyRemoteEditorSlides`. */
@@ -11310,6 +11905,11 @@ interface EditorControllerDeps {
11310
11905
  toggleShortcuts?(): void;
11311
11906
  /** Close the cheat sheet on Escape; true when it was open (Escape consumed). */
11312
11907
  closeShortcuts?(): boolean;
11908
+ /**
11909
+ * Open or close the find bar (Ctrl/Cmd+F). Like the cheat sheet, the panel is
11910
+ * shell-owned UI state, so the controller only signals the intent.
11911
+ */
11912
+ toggleFind?(): void;
11313
11913
  }
11314
11914
 
11315
11915
  interface EditorMarqueeRect extends MarqueeRect {
@@ -11336,8 +11936,13 @@ interface SelectionInteractivity {
11336
11936
  resizable: boolean;
11337
11937
  /** Draw (and honour) the rotate stem + knob. */
11338
11938
  rotatable: boolean;
11339
- /** The amber adjustment diamond, or null when there is none to draw. */
11340
- adjust: ShapeAdjustmentHandleDescriptor | null;
11939
+ /**
11940
+ * The amber adjustment diamonds, one per `a:avLst` guide. Empty when there
11941
+ * is none to draw; PowerPoint shows several on most presets (`quadArrow`
11942
+ * three, `callout3` four), and offering only the first left the rest
11943
+ * unreachable.
11944
+ */
11945
+ adjust: ShapeAdjustmentHandleDescriptor[];
11341
11946
  }
11342
11947
 
11343
11948
  declare class EditorController {
@@ -11346,6 +11951,8 @@ declare class EditorController {
11346
11951
  editingId: string | null;
11347
11952
  marquee: EditorMarqueeRect | null;
11348
11953
  constructor(editor: EditorState, deps: EditorControllerDeps);
11954
+ /** The elements the pointer acts on (slide, or master/layout), for overlays. */
11955
+ get activeElements(): PptxElement[];
11349
11956
  get overlayBox(): OverlayBox | null;
11350
11957
  /**
11351
11958
  * Which selection chrome the authored `a:spLocks` still permit, plus the
@@ -11365,7 +11972,16 @@ declare class EditorController {
11365
11972
  onStageContextMenu: (event: MouseEvent) => void;
11366
11973
  onHandlePointerDown: (handle: ResizeHandleId, event: PointerEvent) => void;
11367
11974
  onRotatePointerDown: (event: PointerEvent) => void;
11368
- onAdjustPointerDown: (event: PointerEvent) => void;
11975
+ onAdjustPointerDown: (event: PointerEvent, descriptor: ShapeAdjustmentHandleDescriptor) => void;
11976
+ /** Live connector-endpoint drag position in SLIDE px, or null when idle. */
11977
+ connectorEndpointDrag: {
11978
+ kind: ConnectorEndpointKind;
11979
+ x: number;
11980
+ y: number;
11981
+ } | null;
11982
+ /** The selected connector, when exactly one connector is selected. */
11983
+ get selectedConnector(): PptxElement | null;
11984
+ onConnectorEndpointPointerDown: (kind: ConnectorEndpointKind, event: PointerEvent) => void;
11369
11985
  onKeyDown: (event: KeyboardEvent) => void;
11370
11986
  /** Open the inline text editor over `id` when the element carries text. */
11371
11987
  enterInlineEdit(id: string): void;
@@ -11708,6 +12324,17 @@ declare class PresentationLoader {
11708
12324
  themeOptions: PptxThemeOption[];
11709
12325
  /** Slide canvas size in pixels. */
11710
12326
  canvasSize: CanvasSize;
12327
+ /**
12328
+ * The deck's `p:sldSz` in EMU, seeded from the parse and re-written by the
12329
+ * inspector's Slide Size preset / orientation controls.
12330
+ *
12331
+ * Held alongside {@link canvasSize} rather than derived from it because the
12332
+ * pixel size is lossy: Ledger is 12179300 EMU (1278.5px), so a round-trip
12333
+ * through an integer pixel would move it 6350 EMU and cost the deck its
12334
+ * `ppSlideSizeLedgerPaper` identity. `resolveSlideSizeSelection` decides
12335
+ * which of the two wins at save time.
12336
+ */
12337
+ slideSize: SlideSizeEmu | undefined;
11711
12338
  /** Archive-path -> displayable URL map for media + poster frames. */
11712
12339
  mediaDataUrls: Map<string, string>;
11713
12340
  /** Presentation theme colours used to resolve scheme-based table styles. */
@@ -12168,6 +12795,53 @@ declare class PresenterSession {
12168
12795
  private getChannel;
12169
12796
  }
12170
12797
 
12798
+ /**
12799
+ * autosave-recovery.svelte.ts: offer the crash-recovery snapshot back.
12800
+ *
12801
+ * This binding has always WRITTEN recovery snapshots (see `autosave.svelte.ts`)
12802
+ * and never once offered one back, so the whole feature was invisible: the user
12803
+ * lost a tab mid-edit, reopened the deck, and silently got the pre-crash work
12804
+ * thrown away. Every decision (is it worth probing, is the snapshot fresh
12805
+ * enough, has this tab already taken delivery of it, what should the prompt
12806
+ * say) lives in `pptx-viewer-shared`'s `render/autosave-recovery` so all five
12807
+ * bindings ask the same questions in the same order; this class is only the
12808
+ * runes wiring plus the two actions.
12809
+ *
12810
+ * It registers its own probing `$effect` in the constructor, exactly like
12811
+ * {@link AutosaveController}, so a caller only has to construct it during
12812
+ * component initialisation and render `prompt` when it is non-null.
12813
+ */
12814
+ interface AutosaveRecoveryDeps {
12815
+ /** IndexedDB record key (host `filePath`). Nothing to look up without one. */
12816
+ getFilePath: () => string | undefined;
12817
+ /**
12818
+ * Whether recovery snapshots are permitted at all, which is the HOST prop
12819
+ * (`autosave !== false`) and not the user's toggle: someone who merely
12820
+ * switched AutoSave off should still be offered the pre-crash snapshot that
12821
+ * was written while it was on.
12822
+ */
12823
+ getAutosaveAllowed: () => boolean;
12824
+ getLoading: () => boolean;
12825
+ getError: () => string | null;
12826
+ getSlideCount: () => number;
12827
+ /** Monotonic load counter: the probe runs once per loaded deck. */
12828
+ getLoadCount: () => number;
12829
+ /** The loader's own load path, the same one the backstage recent list uses. */
12830
+ load: (bytes: Uint8Array) => Promise<void> | void;
12831
+ }
12832
+ declare class AutosaveRecoveryController {
12833
+ #private;
12834
+ /** The prompt to render, or null when there is nothing to recover. */
12835
+ prompt: AutosaveRecoveryPrompt | null;
12836
+ constructor(deps: AutosaveRecoveryDeps);
12837
+ /** Take the snapshot: mark it consumed, then load its bytes in place. */
12838
+ restore(): Promise<void>;
12839
+ /** Decline the snapshot: delete it, and never load it. */
12840
+ discard(): Promise<void>;
12841
+ /** Close the prompt without touching the stored snapshot. */
12842
+ dismiss(): void;
12843
+ }
12844
+
12171
12845
  /** One element ring to draw on the canvas: an explicit pick or a live-tool focus. */
12172
12846
  interface AiCanvasHighlight {
12173
12847
  slideIndex: number;
@@ -12299,10 +12973,12 @@ declare class ViewerOptionsState {
12299
12973
  /** Accessibility > "feedback with sound" cue for a completed action. */
12300
12974
  playFeedback(): void;
12301
12975
  /**
12302
- * Autosave debounce in ms: the host prop until the user picks a custom
12303
- * AutoRecover cadence in Options > Save, which then takes over.
12976
+ * Options > Save > "Save AutoRecover information every N minutes", in
12977
+ * seconds. The autosave cadence whenever the host passed no explicit
12978
+ * `autosaveIntervalMs`; the host-vs-user precedence itself is decided by
12979
+ * `resolveAutosaveIntervalMs` in shared, not re-invented here.
12304
12980
  */
12305
- autosaveDebounceMs(hostIntervalMs: number, defaultMinutes: number): number;
12981
+ get autosaveIntervalSeconds(): number;
12306
12982
  /** Options > Save > "Delete cached files": drop all recovery snapshots. */
12307
12983
  clearCache(): Promise<void>;
12308
12984
  dispose(): void;
@@ -12321,6 +12997,48 @@ declare class CompareController {
12321
12997
  acceptAll(): void;
12322
12998
  }
12323
12999
 
13000
+ /** Which tool's colour palette is currently open, if any. */
13001
+ type PresentPaletteKey = 'pen' | 'highlighter';
13002
+ /** DOM getters {@link PresentToolbarChrome.attach} needs from the component. */
13003
+ interface PresentToolbarChromeTargets {
13004
+ /**
13005
+ * The positioned show surface the bar floats over. Used only for the
13006
+ * bottom-trigger-zone fast path; a missing container still shows the bar on
13007
+ * any movement, exactly as React's wrapper does.
13008
+ */
13009
+ getContainer: () => HTMLElement | null;
13010
+ /** The bar itself, so a mousedown outside it can close an open palette. */
13011
+ getToolbar: () => HTMLElement | null;
13012
+ }
13013
+ declare class PresentToolbarChrome {
13014
+ #private;
13015
+ /** Whether the bar is currently faded in and accepting pointer events. */
13016
+ visible: boolean;
13017
+ /** Milliseconds since the show started, refreshed once a second. */
13018
+ elapsedMs: number;
13019
+ /** The open colour palette, or `null` when both are closed. */
13020
+ palette: PresentPaletteKey | null;
13021
+ /**
13022
+ * Wire the document listeners and the one-second tick. Returns a teardown,
13023
+ * so a component can hand it straight to `$effect`.
13024
+ */
13025
+ attach(targets: PresentToolbarChromeTargets): () => void;
13026
+ /** Pointer entered the bar: pin it open until the pointer leaves again. */
13027
+ enter(): void;
13028
+ /** Pointer left the bar: restart the auto-hide countdown. */
13029
+ leave(): void;
13030
+ /**
13031
+ * PowerPoint's Ctrl+H: flip the show chrome. Deliberately the same `visible`
13032
+ * flag auto-hide writes, and it re-arms the countdown when it reveals the bar,
13033
+ * so the shortcut leaves the toolbar in a state the pointer can still govern.
13034
+ */
13035
+ toggleVisible(): void;
13036
+ /** Open `key`'s palette, or close it when it is already the open one. */
13037
+ togglePalette(key: PresentPaletteKey): void;
13038
+ /** Close both palettes (after picking a colour or choosing a tool). */
13039
+ closePalettes(): void;
13040
+ }
13041
+
12324
13042
  type PresentationInkTool = 'none' | 'pen' | 'highlighter' | 'eraser' | 'laser';
12325
13043
  interface PresentationStroke {
12326
13044
  id: string;
@@ -12378,6 +13096,16 @@ declare class RehearseState {
12378
13096
  declare class ViewerParityUiState {
12379
13097
  readonly compare: CompareController;
12380
13098
  readonly annotations: PresentationAnnotations;
13099
+ /**
13100
+ * The show toolbar's fade/auto-hide state. It lives here, not inside
13101
+ * `PresentationToolbar.svelte`, because PowerPoint's Ctrl+H toggles the show
13102
+ * chrome from the keyboard handler, which is nowhere near that component: a
13103
+ * second visibility flag over there would be overwritten by the next mouse
13104
+ * move, so the shortcut and the countdown share this one.
13105
+ */
13106
+ readonly showChrome: PresentToolbarChrome;
13107
+ /** PowerPoint's Ctrl+S "See All Slides" grid, over the running show. */
13108
+ allSlidesOpen: boolean;
12381
13109
  readonly rehearse: RehearseState;
12382
13110
  setupSlideShowOpen: boolean;
12383
13111
  headerFooterOpen: boolean;
@@ -12427,8 +13155,13 @@ interface CreateViewerStateOptions {
12427
13155
  getSource: () => Uint8Array | ArrayBuffer | null | undefined;
12428
13156
  collaboration?: CollaborationConfig;
12429
13157
  shareDefaults?: ShareDefaultsInput;
12430
- /** Host `autosave` prop (post-effect value the caller keeps in sync). */
12431
- getAutosave: () => boolean;
13158
+ /**
13159
+ * Host `autosave` prop, verbatim. `undefined` means the host said nothing,
13160
+ * which PERMITS autosave (the user's toggle then decides); only an explicit
13161
+ * `false` vetoes it and makes the toggle inert. See
13162
+ * `resolveAutosaveActivation` in `pptx-viewer-shared`.
13163
+ */
13164
+ getAutosave: () => boolean | undefined;
12432
13165
  autosaveIntervalMs?: number;
12433
13166
  getFilePath: () => string | undefined;
12434
13167
  getInitialSlide: () => number;
@@ -12492,6 +13225,8 @@ interface ViewerStateBag {
12492
13225
  readonly collab: CollaborationController;
12493
13226
  readonly dialogs: CollaborationDialogsState;
12494
13227
  readonly autosaveCtl: AutosaveController;
13228
+ /** The "recover unsaved changes?" probe + prompt for the loaded deck. */
13229
+ readonly autosaveRecovery: AutosaveRecoveryController;
12495
13230
  readonly presentation: PresentationController;
12496
13231
  readonly presenterSession: PresenterSession;
12497
13232
  readonly exportWiring: ExportWiring;
@@ -12527,8 +13262,17 @@ interface ViewerStateBag {
12527
13262
  * can flip it without waiting on the host.
12528
13263
  */
12529
13264
  editable: boolean;
12530
- /** Read-only: mutate via {@link setAutosaveEnabled}, which also fires `onautosavetoggle`. */
13265
+ /**
13266
+ * The EFFECTIVE title-bar AutoSave state: the user's preference, or false
13267
+ * when the host vetoed autosave (the switch renders off and inert rather
13268
+ * than pretending to work). Mutate via {@link setAutosaveEnabled}, which
13269
+ * also fires `onautosavetoggle`.
13270
+ */
12531
13271
  readonly autosaveEnabled: boolean;
13272
+ /** False only when the host passed `autosave={false}`; the toggle is then inert. */
13273
+ readonly autosaveToggleAvailable: boolean;
13274
+ /** Why autosave is not running, for a host that wants to explain it. */
13275
+ readonly autosaveDisabledReason: AutosaveDisabledReason | undefined;
12532
13276
  setAutosaveEnabled(enabled: boolean): void;
12533
13277
  presenterMode: boolean;
12534
13278
  /** `Date.now()` timestamp of the last `enterPresenterView()` call; the presenter view's elapsed-time display. */