@shbernal/ts-pptx 2.0.0 → 3.1.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 (85) hide show
  1. package/README.md +31 -2
  2. package/dist/{autopage-tmfjRzL4.js → autopage-QQyfRtoK.js} +4 -5
  3. package/dist/{autopage-tmfjRzL4.js.map → autopage-QQyfRtoK.js.map} +1 -1
  4. package/dist/browser.d.ts +14 -6
  5. package/dist/browser.d.ts.map +1 -1
  6. package/dist/browser.js +14 -6
  7. package/dist/browser.js.map +1 -1
  8. package/dist/{diagnostics-CQ0JWc9m.d.ts → diagnostics-PMINsVP6.d.ts} +97 -8
  9. package/dist/diagnostics-PMINsVP6.d.ts.map +1 -0
  10. package/dist/{enums-D3aF4QGb.d.ts → enums-CoXnxiCI.d.ts} +6 -5
  11. package/dist/{enums-D3aF4QGb.d.ts.map → enums-CoXnxiCI.d.ts.map} +1 -1
  12. package/dist/{errors-B22h8Qd0.d.ts → errors-BeUEkNWL.d.ts} +26 -4
  13. package/dist/errors-BeUEkNWL.d.ts.map +1 -0
  14. package/dist/{errors-DGE9zh3U.js → errors-Bvln0H-7.js} +21 -2
  15. package/dist/errors-Bvln0H-7.js.map +1 -0
  16. package/dist/{fit-BSWY0AYt.js → fit-DhMbQG5O.js} +0 -0
  17. package/dist/fit-DhMbQG5O.js.map +1 -0
  18. package/dist/{html-dom-BQLUntho.js → html-dom-DajBuobe.js} +20 -6
  19. package/dist/html-dom-DajBuobe.js.map +1 -0
  20. package/dist/html.d.ts +3 -3
  21. package/dist/html.d.ts.map +1 -1
  22. package/dist/html.js +7 -4
  23. package/dist/html.js.map +1 -1
  24. package/dist/index.d.ts +6 -6
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +6 -6
  27. package/dist/index.js.map +1 -1
  28. package/dist/inspect.d.ts +1 -1
  29. package/dist/inspect.js +4 -4
  30. package/dist/inspect.js.map +1 -1
  31. package/dist/math.d.ts +1 -1
  32. package/dist/math.d.ts.map +1 -1
  33. package/dist/math.js +98 -2
  34. package/dist/math.js.map +1 -1
  35. package/dist/measure.d.ts +3 -3
  36. package/dist/measure.js +2 -2
  37. package/dist/node.d.ts +14 -6
  38. package/dist/node.d.ts.map +1 -1
  39. package/dist/node.js +13 -5
  40. package/dist/node.js.map +1 -1
  41. package/dist/package-CaOLXSNi.d.ts.map +1 -1
  42. package/dist/{pres-GU-jjBEx.d.ts → pres-BgvxhQ_m.d.ts} +3 -3
  43. package/dist/{pres-GU-jjBEx.d.ts.map → pres-BgvxhQ_m.d.ts.map} +1 -1
  44. package/dist/{presentation-MJe9WDi4.js → presentation-BP1B8PCF.js} +863 -343
  45. package/dist/presentation-BP1B8PCF.js.map +1 -0
  46. package/dist/{presentation-CVaTZw1V.d.ts → presentation-DyIRDKkp.d.ts} +742 -595
  47. package/dist/presentation-DyIRDKkp.d.ts.map +1 -0
  48. package/dist/{presentation-types-BVw0EknS.d.ts → presentation-types-Dj4riuDs.d.ts} +2 -2
  49. package/dist/{presentation-types-BVw0EknS.d.ts.map → presentation-types-Dj4riuDs.d.ts.map} +1 -1
  50. package/dist/read.d.ts +5 -5
  51. package/dist/read.d.ts.map +1 -1
  52. package/dist/read.js +3 -3
  53. package/dist/script.d.ts +2 -2
  54. package/dist/script.d.ts.map +1 -1
  55. package/dist/script.js +0 -0
  56. package/dist/script.js.map +1 -1
  57. package/dist/{shapes-CaOgR0i1.js → shapes-DMThLsZN.js} +689 -1032
  58. package/dist/shapes-DMThLsZN.js.map +1 -0
  59. package/dist/{slide-BBlElWr9.d.ts → slide-BRAtT8Dl.d.ts} +197 -22
  60. package/dist/slide-BRAtT8Dl.d.ts.map +1 -0
  61. package/dist/{image-size-C8uYE8GJ.js → st-enums-evQG2A7Z.js} +233 -2
  62. package/dist/st-enums-evQG2A7Z.js.map +1 -0
  63. package/dist/{text-B1ZrPEeK.js → text-B6PbMFih.js} +725 -319
  64. package/dist/text-B6PbMFih.js.map +1 -0
  65. package/dist/{units-B-JUKwCS.js → units-C7QM1KgH.js} +2 -2
  66. package/dist/{units-B-JUKwCS.js.map → units-C7QM1KgH.js.map} +1 -1
  67. package/dist/{units-internal-7JcMfYti.js → units-internal-CR8s8YQa.js} +4 -3
  68. package/dist/units-internal-CR8s8YQa.js.map +1 -0
  69. package/dist/zip.d.ts +2 -2
  70. package/dist/zip.js +1 -1
  71. package/dist/zip.js.map +1 -1
  72. package/package.json +40 -29
  73. package/skills/ts-pptx-upstream/SKILL.md +247 -0
  74. package/dist/diagnostics-CQ0JWc9m.d.ts.map +0 -1
  75. package/dist/errors-B22h8Qd0.d.ts.map +0 -1
  76. package/dist/errors-DGE9zh3U.js.map +0 -1
  77. package/dist/fit-BSWY0AYt.js.map +0 -1
  78. package/dist/html-dom-BQLUntho.js.map +0 -1
  79. package/dist/image-size-C8uYE8GJ.js.map +0 -1
  80. package/dist/presentation-CVaTZw1V.d.ts.map +0 -1
  81. package/dist/presentation-MJe9WDi4.js.map +0 -1
  82. package/dist/shapes-CaOgR0i1.js.map +0 -1
  83. package/dist/slide-BBlElWr9.d.ts.map +0 -1
  84. package/dist/text-B1ZrPEeK.js.map +0 -1
  85. package/dist/units-internal-7JcMfYti.js.map +0 -1
@@ -1,42 +1,36 @@
1
- import { t as CustomPropertyValue } from "./pres-GU-jjBEx.js";
2
- import { c as ImportSlideMastersOptions, d as LayoutHandle, f as SlideSize, l as ImportSlideOptions, o as FromTemplateOptions, p as SlideSource, r as EmbeddedFontInfo, s as ImportShapeOptions, t as AppendSlidesOptions, u as ImportedSlideMaster } from "./presentation-types-BVw0EknS.js";
1
+ import { t as CustomPropertyValue } from "./pres-BgvxhQ_m.js";
2
+ import { c as ImportSlideMastersOptions, d as LayoutHandle, f as SlideSize, l as ImportSlideOptions, o as FromTemplateOptions, p as SlideSource, r as EmbeddedFontInfo, s as ImportShapeOptions, t as AppendSlidesOptions, u as ImportedSlideMaster } from "./presentation-types-Dj4riuDs.js";
3
3
  import { a as Part, i as Relationships, n as OpcPackage, o as Element, t as OpcInput } from "./package-CaOLXSNi.js";
4
4
  //#region src/read/oxml/theme.d.ts
5
5
  /**
6
6
  * The colour-resolution context: the two maps that turn a DrawingML colour
7
7
  * reference into a literal hex — the effective colour map (token → `clrScheme`
8
8
  * slot, honouring any slide `clrMapOvr`) and the resolved colour scheme (slot →
9
- * 6-hex RGB). Shared by the read-model colour getters and {@link FlattenContext}.
9
+ * 6-hex RGB). Shared by the read-model colour getters and {@link ThemeContext}.
10
10
  */
11
11
  interface ColorContext {
12
12
  clrMap: Map<string, string>;
13
13
  clrScheme: Map<string, string>;
14
14
  }
15
15
  /**
16
- * Everything {@link flattenSlide} needs from the slide's source theme subgraph:
17
- * the {@link ColorContext} maps plus the live `a:fmtScheme` element (for
18
- * style-matrix resolution).
16
+ * The source theme subgraph a slide, notes slide, layout or master resolves against: the
17
+ * {@link ColorContext} maps, the live `a:fmtScheme` for style-matrix resolution, and the roots
18
+ * of the inheritance chain a placeholder reads through.
19
+ *
20
+ * Every root here is **read-only** — nothing in this module or in `placeholder-inherit.ts`
21
+ * mutates one. The import-time flatten pass extends this with the one field it needs to write
22
+ * from (see `FlattenContext` in `read/api/ops/flatten.ts`).
19
23
  */
20
- interface FlattenContext extends ColorContext {
24
+ interface ThemeContext extends ColorContext {
21
25
  fmtScheme: Element | null;
22
26
  /**
23
- * The slide's effective background inherited from the *source*
24
- * `slideLayout`/`slideMaster` (the raw `p:bg` element), or `null` when the
25
- * slide carries its own. Applied onto the slide before flattening so the
26
- * background survives rebinding to the destination master. See
27
- * {@link flattenSlide}.
28
- */
29
- inheritedBackground?: Element | null;
30
- /**
31
- * The source `slideLayout` root element, for resolving placeholder-inherited
32
- * run colours (gap 1). Read-only — never mutated. `null`/absent disables the
33
- * placeholder run-colour pass for the layout tier.
27
+ * The source `slideLayout` root element, for resolving what a placeholder inherits.
28
+ * `null`/absent disables the layout tier.
34
29
  */
35
30
  layoutRoot?: Element | null;
36
31
  /**
37
- * The source `slideMaster` root element, for resolving placeholder-inherited
38
- * run colours via its placeholder `a:lstStyle` and `p:txStyles`. Read-only —
39
- * never mutated.
32
+ * The source `slideMaster` root element, for resolving placeholder inheritance via its
33
+ * placeholder `a:lstStyle` and `p:txStyles`.
40
34
  */
41
35
  masterRoot?: Element | null;
42
36
  /**
@@ -304,89 +298,436 @@ interface ShapeProperties {
304
298
  lnAfter: string[] | null;
305
299
  }
306
300
  //#endregion
307
- //#region src/read/api/text.d.ts
301
+ //#region src/read/api/pattern-fill.d.ts
308
302
  /**
309
- * What a {@link Run}'s text body needs to resolve an *inherited* run
310
- * colour/size/face/bold: which placeholder the text lives in (or `null` for a
311
- * non-placeholder shape, which still resolves its `p:style/a:fontRef` and the
312
- * presentation `p:defaultTextStyle`), the slide theme context (with the
313
- * layout/master roots) to resolve against, and the shape's resolved
314
- * `p:style/a:fontRef` text tier. The owning slide's text body `a:lstStyle` is added
315
- * per text frame. Absent only for text reached without a theme context (table cells).
303
+ * A pattern fill (`a:pattFill`) — a two-colour preset hatch. The write-side
304
+ * `fill: { type: 'pattern', pattern: { preset, fgColor, bgColor } }` emits the same element,
305
+ * so the {@link preset} name and both colours round-trip. Colours resolve against the theme
306
+ * (a scheme token → literal hex) the same way a solid fill does.
316
307
  */
317
- interface PlaceholderTextContext {
318
- ph: PlaceholderRef | null;
319
- flatten: FlattenContext;
320
- /** The shape's resolved `p:style/a:fontRef` colour + face tier, or `null` when it has none. */
321
- fontRef?: StyleFontRef | null;
308
+ interface PatternFill {
309
+ /** Preset pattern name (`@prst`, e.g. `pct50`/`diagCross`/`ltUpDiag`), or `null` when unset. */
310
+ preset: string | null;
311
+ /** Foreground colour (`a:fgClr`) resolved against the theme, or `null`. */
312
+ foreground: ResolvedColor | null;
313
+ /** Background colour (`a:bgClr`) resolved against the theme, or `null`. */
314
+ background: ResolvedColor | null;
315
+ }
316
+ //#endregion
317
+ //#region src/read/api/shapes/types.d.ts
318
+ /** Discriminator for the concrete `Shape` subclass. */
319
+ type ShapeType = 'autoShape' | 'picture' | 'connector' | 'graphicFrame' | 'group';
320
+ /** One end of a connector/line (`a:ln/a:headEnd` or `a:tailEnd`), as read from a shape. */
321
+ interface LineEnd {
322
+ /** Arrowhead type (`@type`: `none`/`triangle`/`stealth`/`diamond`/`oval`/`arrow`). */
323
+ type: string;
324
+ /** Width class (`@w`: `sm`/`med`/`lg`), or `null` when unset. */
325
+ width: string | null;
326
+ /** Length class (`@len`: `sm`/`med`/`lg`), or `null` when unset. */
327
+ length: string | null;
328
+ }
329
+ /** Both ends of a shape's line/border, when either carries an arrowhead. */
330
+ interface LineEnds {
331
+ head: LineEnd | null;
332
+ tail: LineEnd | null;
322
333
  }
323
334
  /**
324
- * A run's click hyperlink (`a:rPr/a:hlinkClick`): a link on a span of text. A URL
325
- * link carries an external {@link url}; a slide jump carries the internal
326
- * {@link targetPartName} (the linked slide's part) alongside its `hlinksldjump`
327
- * {@link action}. `tooltip` and `relId` are surfaced when present.
335
+ * One bound end of a connector (`p:nvCxnSpPr/p:cNvCxnSpPr/a:stCxn` or `a:endCxn`),
336
+ * as read. A connector authored with `startShape`/`endShape` attaches each end to
337
+ * a shape by that shape's `p:cNvPr/@id` plus a connection-site index; an unbound
338
+ * end (the writer emits a bare `p:cNvCxnSpPr`) reports no site at all — see
339
+ * {@link Connector.startConnection}. This is the read counterpart of the write
340
+ * API's `startShape`/`startShapeIdx` split, which binds by `objectName` and
341
+ * resolves the name → id at serialize time.
328
342
  */
329
- interface RunHyperlink {
330
- /** External URL target (its `@r:id` resolves to a `TargetMode="External"` rel), or `null` for an internal/action-only link. */
331
- url: string | null;
332
- /** Absolute partname of an internal target (e.g. the slide a jump points at), or `null`. */
333
- targetPartName: string | null;
334
- /** Navigation action token (`@action`, e.g. `ppaction://hlinksldjump`), or `null` when absent/empty. */
335
- action: string | null;
336
- /** Tooltip text (`@tooltip`), or `null` when absent/empty. */
337
- tooltip: string | null;
338
- /** The relationship id (`@r:id`) backing the link, or `null` when the link is action-only. */
339
- relId: string | null;
343
+ interface ConnectionSite {
344
+ /** The bound shape's drawing id (`@id`, i.e. its `p:cNvPr/@id`). */
345
+ shapeId: number;
346
+ /** Connection-site index on the bound shape (`@idx`; 0-based, preset-dependent). */
347
+ siteIndex: number;
348
+ /**
349
+ * The bound shape resolved to a read-model shape via {@link Slide.shapeByIdDeep},
350
+ * which descends into groups — so a connector bound to a shape nested in a group
351
+ * resolves the same as one bound to a top-level shape. `null` only when no shape
352
+ * anywhere on the slide carries that id (a genuinely dangling binding), which is
353
+ * faithful degradation and does not throw.
354
+ */
355
+ boundShape: AnyShape | null;
340
356
  }
341
357
  /**
342
- * A paragraph's line spacing (`a:pPr/a:lnSpc`), in whichever of the two OOXML
343
- * forms the file uses: an exact point height (`a:spcPts`) or a percentage of the
344
- * single-line height (`a:spcPct` — e.g. `percent: 150` for 1.5× spacing).
358
+ * A shape's outer drop shadow (`spPr/a:effectLst/a:outerShdw`), as read from a
359
+ * shape and resolved against the slide theme. Distances are in points (the EMU
360
+ * source ÷ 12700) and the direction in degrees (the `60000`ths source ÷ 60000),
361
+ * matching the write-side {@link ShadowProps} convention so it round-trips.
345
362
  */
346
- type LineSpacing = {
347
- type: 'points';
348
- valuePt: number;
363
+ interface OuterShadow {
364
+ /** Effective shadow colour as 6-hex (theme-resolved, transforms applied), or `null`. */
365
+ color: string | null;
366
+ /** Theme colour token when the shadow colour was a scheme colour (e.g. `accent1`), else `undefined`. */
367
+ colorToken?: string;
368
+ /** Shadow opacity 0–1 (from the colour's `a:alpha`), or `undefined` when fully opaque. */
369
+ alpha?: number;
370
+ /** Blur radius in points (`@blurRad` ÷ 12700), or `undefined` when unset. */
371
+ blurPt?: number;
372
+ /** Offset distance in points (`@dist` ÷ 12700), or `undefined` when unset. */
373
+ offsetPt?: number;
374
+ /** Offset direction in degrees, clockwise from 3 o'clock (`@dir` ÷ 60000), or `undefined` when unset. */
375
+ angleDeg?: number;
376
+ }
377
+ /**
378
+ * A shape's inner shadow (`spPr/a:effectLst/a:innerShdw`), resolved against the
379
+ * slide theme. Identical fields to {@link OuterShadow} — CT_InnerShadowEffect
380
+ * carries the same `blurRad`/`dist`/`dir` + colour — but a distinct type so a
381
+ * consumer can tell an inset shadow from a drop shadow. Distances in points,
382
+ * direction in degrees, matching the write-side `shadow: { type: 'inner' }`.
383
+ */
384
+ interface InnerShadow {
385
+ /** Effective shadow colour as 6-hex (theme-resolved, transforms applied), or `null`. */
386
+ color: string | null;
387
+ /** Theme colour token when the shadow colour was a scheme colour (e.g. `accent1`), else `undefined`. */
388
+ colorToken?: string;
389
+ /** Shadow opacity 0–1 (from the colour's `a:alpha`), or `undefined` when fully opaque. */
390
+ alpha?: number;
391
+ /** Blur radius in points (`@blurRad` ÷ 12700), or `undefined` when unset. */
392
+ blurPt?: number;
393
+ /** Offset distance in points (`@dist` ÷ 12700), or `undefined` when unset. */
394
+ offsetPt?: number;
395
+ /** Offset direction in degrees, clockwise from 3 o'clock (`@dir` ÷ 60000), or `undefined` when unset. */
396
+ angleDeg?: number;
397
+ }
398
+ /**
399
+ * A shape's glow effect (`spPr/a:effectLst/a:glow`) — a coloured halo — resolved
400
+ * against the slide theme. The write-side text glow (`glow: { size, color,
401
+ * opacity }`) emits the same element, so {@link radiusPt} (`@rad` ÷ 12700) and the
402
+ * colour round-trip.
403
+ */
404
+ interface Glow {
405
+ /** Effective glow colour as 6-hex (theme-resolved, transforms applied), or `null`. */
406
+ color: string | null;
407
+ /** Theme colour token when the glow colour was a scheme colour (e.g. `accent1`), else `undefined`. */
408
+ colorToken?: string;
409
+ /** Glow opacity 0–1 (from the colour's `a:alpha`), or `undefined` when fully opaque. */
410
+ alpha?: number;
411
+ /** Glow radius in points (`@rad` ÷ 12700), or `undefined` when unset. */
412
+ radiusPt?: number;
413
+ }
414
+ /**
415
+ * A shape's reflection effect (`spPr/a:effectLst/a:reflection`) — a mirrored fade
416
+ * beneath the shape. This library's writer authors none, so this is a **read-only**
417
+ * surface: a consumer that finds one should carry the part verbatim rather than
418
+ * regenerate it. Only the attributes a faithful replica needs are decoded —
419
+ * distances in points (÷ 12700), directions in degrees (÷ 60000), and the start/end
420
+ * alpha and position pairs as 0–1 fractions (the `1000`ths-of-a-percent source
421
+ * ÷ 100000). All fields are optional; an attribute absent from the source is omitted.
422
+ */
423
+ interface Reflection {
424
+ /** Blur radius in points (`@blurRad` ÷ 12700). */
425
+ blurPt?: number;
426
+ /** Start opacity 0–1 (`@stA` ÷ 100000). */
427
+ startAlpha?: number;
428
+ /** Start position along the reflection 0–1 (`@stPos` ÷ 100000). */
429
+ startPos?: number;
430
+ /** End opacity 0–1 (`@endA` ÷ 100000). */
431
+ endAlpha?: number;
432
+ /** End position along the reflection 0–1 (`@endPos` ÷ 100000). */
433
+ endPos?: number;
434
+ /** Offset distance in points (`@dist` ÷ 12700). */
435
+ distPt?: number;
436
+ /** Offset direction in degrees (`@dir` ÷ 60000). */
437
+ angleDeg?: number;
438
+ /** Fade direction in degrees (`@fadeDir` ÷ 60000). */
439
+ fadeAngleDeg?: number;
440
+ }
441
+ /**
442
+ * A shape's soft-edge effect (`spPr/a:effectLst/a:softEdge`) — a feathered border.
443
+ * Like {@link Reflection}, the writer authors none, so carry it verbatim. `@rad`
444
+ * (the feather radius) ÷ 12700 → points.
445
+ */
446
+ interface SoftEdge {
447
+ /** Feather radius in points (`@rad` ÷ 12700). */
448
+ radiusPt: number;
449
+ }
450
+ /**
451
+ * One segment of a custom-geometry path (`a:path`), as read from a shape. The
452
+ * command verbs mirror the write-side `GeometryPoint` DSL (`src/types/`)
453
+ * so a consumer can map a `GeometryCommand[]` to `GeometryPoint[]` one-to-one.
454
+ *
455
+ * Coordinates (`x`/`y`/`x1`…) are raw path-unit integers in the path's own
456
+ * `0..w` / `0..h` space (see {@link CustomGeometryPath.w}); they are not EMU and
457
+ * must be scaled by the consumer against the shape's box. `arcTo` angles are in
458
+ * **degrees** (the raw `60000`ths-of-a-degree values divided by 60000), matching
459
+ * the write DSL's degree input.
460
+ */
461
+ type GeometryCommand = {
462
+ cmd: 'moveTo';
463
+ x: number;
464
+ y: number;
349
465
  } | {
350
- type: 'percent';
351
- percent: number;
466
+ cmd: 'lnTo';
467
+ x: number;
468
+ y: number;
469
+ } | {
470
+ cmd: 'cubicBezTo';
471
+ x1: number;
472
+ y1: number;
473
+ x2: number;
474
+ y2: number;
475
+ x: number;
476
+ y: number;
477
+ } | {
478
+ cmd: 'quadBezTo';
479
+ x1: number;
480
+ y1: number;
481
+ x: number;
482
+ y: number;
483
+ } | {
484
+ cmd: 'arcTo';
485
+ wR: number;
486
+ hR: number;
487
+ stAng: number;
488
+ swAng: number;
489
+ } | {
490
+ cmd: 'close';
352
491
  };
353
- /** One text run (`a:r`): a span of text with uniform character formatting. */
354
- declare class Run {
355
- #private;
356
- private readonly element;
357
- private readonly part;
358
- /** The owning slide's theme context (colour maps + `fontScheme`), for the `resolved*` getters; absent when the run was reached without one. */
359
- private readonly themeContext?;
360
- /**
361
- * Resolves the colour this run inherits from its placeholder/list-style chain
362
- * when it sets none of its own (item A). Built by the owning {@link Paragraph}
363
- * for placeholder text; absent for non-placeholder runs. Called lazily.
364
- */
365
- private readonly inheritedColor?;
366
- /**
367
- * Resolves the point size this run inherits from the same chain when it sets no
368
- * own `@sz`. Built by the owning {@link Paragraph} for placeholder text; absent
369
- * for non-placeholder runs. Called lazily.
370
- */
371
- private readonly inheritedSize?;
372
- /**
373
- * Resolves the typeface this run inherits from the same chain (a `+mj-*`/`+mn-*`
374
- * theme token already resolved to a literal face) when it sets no own `a:latin`.
375
- * Built by the owning {@link Paragraph} for placeholder text; absent otherwise.
376
- * Called lazily.
377
- */
378
- private readonly inheritedFace?;
379
- /**
380
- * Resolves whether this run inherits bold from the same chain when it sets no
381
- * own `@b`. Built by the owning {@link Paragraph} for placeholder text; absent
382
- * for non-placeholder runs. Called lazily.
383
- */
384
- private readonly inheritedBold?;
385
- /**
386
- * The owning part's relationships, used to resolve a run hyperlink's `@r:id`
387
- * to its external URL or internal target partname. Absent when the run was
388
- * reached without them (e.g. table-cell or notes text), in which case
389
- * {@link hyperlink} still reports the raw `@r:id`/`@action`/`@tooltip`.
492
+ /** One `<a:path>` of a custom geometry, with its path-unit viewport and render attrs. */
493
+ interface CustomGeometryPath {
494
+ /** Path-unit width (`a:path/@w`); the `x` denominator for this path's coords. Default `0`. */
495
+ w: number;
496
+ /** Path-unit height (`a:path/@h`); the `y` denominator for this path's coords. Default `0`. */
497
+ h: number;
498
+ /** Fill mode (`a:path/@fill`, `ST_PathFillMode`, e.g. `norm`/`none`/`lighten`). Default `norm`. */
499
+ fill: string;
500
+ /** Whether the path is stroked (`a:path/@stroke`). Default `true`. */
501
+ stroke: boolean;
502
+ /** The path's segments in document order — order *is* the geometry. */
503
+ commands: GeometryCommand[];
504
+ }
505
+ /**
506
+ * Custom freeform geometry (`spPr/a:custGeom/a:pathLst`), as read from a shape.
507
+ * Faithfully exposes every `a:path` rather than flattening to a single command
508
+ * list: the schema allows repeatable `a:path`, each with independent
509
+ * `fill`/`stroke`. Desktop PowerPoint's own freeforms only ever emit one
510
+ * `a:path` (a hole is one path with two `moveTo`…`close` contours), but
511
+ * multi-`a:path` input is schema-legal (e.g. SVG import) and preserved here.
512
+ */
513
+ interface CustomGeometry {
514
+ paths: CustomGeometryPath[];
515
+ }
516
+ /** A shape's resolved position and size in slide-absolute EMU. */
517
+ interface AbsoluteFrame {
518
+ left: number;
519
+ top: number;
520
+ width: number;
521
+ height: number;
522
+ /** Effective clockwise rotation in degrees after composing enclosing group rotations. */
523
+ rotation: number;
524
+ /** Effective horizontal flip after XOR-composing enclosing group flips. */
525
+ flipH: boolean;
526
+ /** Effective vertical flip after XOR-composing enclosing group flips. */
527
+ flipV: boolean;
528
+ }
529
+ /**
530
+ * A group shape's own child coordinate space (`p:grpSpPr/a:xfrm/a:chOff` and
531
+ * `a:chExt`) in EMU — the space its children's `a:off`/`a:ext` are authored in.
532
+ *
533
+ * Named after the OOXML attributes rather than in the `left`/`top`/`width`/
534
+ * `height` vocabulary the rest of the read model uses, because this is not a
535
+ * frame on the slide: it is the source rectangle of the
536
+ * `off + (p - chOff) * (ext / chExt)` mapping, and nothing about it is
537
+ * positional. A consumer reaching for it is rebuilding that mapping, so the
538
+ * names it needs are the ones the mapping is written in.
539
+ */
540
+ interface ChildFrame {
541
+ /** `a:chOff/@x`. */
542
+ offsetX: number;
543
+ /** `a:chOff/@y`. */
544
+ offsetY: number;
545
+ /** `a:chExt/@cx`. */
546
+ extentX: number;
547
+ /** `a:chExt/@cy`. */
548
+ extentY: number;
549
+ }
550
+ /**
551
+ * A colour reference inside a picture recolour effect, split by colour model
552
+ * (mirrors {@link GradientStop}). At most one field is non-`null`.
553
+ */
554
+ interface RecolorColor {
555
+ /** Explicit RGB as 6-hex (`a:srgbClr/@val`), or `null`. */
556
+ color: string | null;
557
+ /** Theme colour token (`a:schemeClr/@val`, e.g. `accent1`), or `null`. */
558
+ schemeColor: string | null;
559
+ /** Preset colour name (`a:prstClr/@val`, e.g. `black`/`white` — the duotone icon-tint stops), or `null`. */
560
+ presetColor: string | null;
561
+ }
562
+ /**
563
+ * A picture's blip recolour effect (`p:blipFill/a:blip` recolour child), as read.
564
+ * A small discriminated union over the effects a faithful reader needs to
565
+ * reproduce a recoloured image. Colours use the same `color`/`schemeColor`/
566
+ * `presetColor` split as {@link GradientStop}, so theme tokens can resolve through
567
+ * {@link Slide.themeContext}. `threshold`/`amount` are 0–1 fractions.
568
+ */
569
+ type Recolor = {
570
+ kind: 'duotone';
571
+ stops: RecolorColor[];
572
+ } | {
573
+ kind: 'clrChange';
574
+ from: RecolorColor | null;
575
+ to: RecolorColor | null;
576
+ } | {
577
+ kind: 'grayscale';
578
+ } | {
579
+ kind: 'biLevel';
580
+ threshold: number | null;
581
+ } | {
582
+ kind: 'alphaModFix';
583
+ amount: number;
584
+ };
585
+ //#endregion
586
+ //#region src/read/api/text.d.ts
587
+ /**
588
+ * What a {@link Run}'s text body needs to resolve an *inherited* run
589
+ * colour/size/face/bold: which placeholder the text lives in (or `null` for a
590
+ * non-placeholder shape, which still resolves its `p:style/a:fontRef` and the
591
+ * presentation `p:defaultTextStyle`), the slide theme context (with the
592
+ * layout/master roots) to resolve against, and the shape's resolved
593
+ * `p:style/a:fontRef` text tier. The owning slide's text body `a:lstStyle` is added
594
+ * per text frame. Absent only for text reached without a theme context (table cells).
595
+ */
596
+ interface PlaceholderTextContext {
597
+ ph: PlaceholderRef | null;
598
+ flatten: ThemeContext;
599
+ /** The shape's resolved `p:style/a:fontRef` colour + face tier, or `null` when it has none. */
600
+ fontRef?: StyleFontRef | null;
601
+ }
602
+ /**
603
+ * A run's click hyperlink (`a:rPr/a:hlinkClick`): a link on a span of text. A URL
604
+ * link carries an external {@link url}; a slide jump carries the internal
605
+ * {@link targetPartName} (the linked slide's part) alongside its `hlinksldjump`
606
+ * {@link action}. `tooltip` and `relId` are surfaced when present.
607
+ */
608
+ interface RunHyperlink {
609
+ /** External URL target (its `@r:id` resolves to a `TargetMode="External"` rel), or `null` for an internal/action-only link. */
610
+ url: string | null;
611
+ /** Absolute partname of an internal target (e.g. the slide a jump points at), or `null`. */
612
+ targetPartName: string | null;
613
+ /** Navigation action token (`@action`, e.g. `ppaction://hlinksldjump`), or `null` when absent/empty. */
614
+ action: string | null;
615
+ /** Tooltip text (`@tooltip`), or `null` when absent/empty. */
616
+ tooltip: string | null;
617
+ /** The relationship id (`@r:id`) backing the link, or `null` when the link is action-only. */
618
+ relId: string | null;
619
+ }
620
+ /**
621
+ * A paragraph's line spacing (`a:pPr/a:lnSpc`), in whichever of the two OOXML
622
+ * forms the file uses: an exact point height (`a:spcPts`) or a percentage of the
623
+ * single-line height (`a:spcPct` — e.g. `percent: 150` for 1.5× spacing).
624
+ */
625
+ type LineSpacing = {
626
+ type: 'points';
627
+ valuePt: number;
628
+ } | {
629
+ type: 'percent';
630
+ percent: number;
631
+ };
632
+ /**
633
+ * The bullet's own font, size and colour (`a:buFont` / `a:buSzPct` / `a:buSzPts` /
634
+ * `a:buClr`) — the properties that style the glyph or number itself rather than
635
+ * the text after it. Every field is `null` when the paragraph leaves it to be
636
+ * inherited from the list style.
637
+ *
638
+ * These are siblings of the bullet kind in `a:pPr`, not children of it, so they
639
+ * are carried alongside each kind rather than inside it.
640
+ */
641
+ interface BulletStyle {
642
+ /** `a:buFont/@typeface` — the face the glyph is drawn in (a symbol font such as `Wingdings`), or `null`. */
643
+ font: string | null;
644
+ /** `a:buSzPct/@val` as a percentage of the run size (e.g. `80`; the raw attribute is thousandths of a percent), or `null`. */
645
+ sizePct: number | null;
646
+ /** `a:buSzPts/@val` as an absolute point size (the raw attribute is hundredths of a point), or `null`. The alternative to {@link sizePct}; at most one is set. */
647
+ sizePt: number | null;
648
+ /** Explicit RGB bullet colour as 6-hex (`a:buClr/a:srgbClr/@val`), or `null`. */
649
+ color: string | null;
650
+ /** Theme colour token when the bullet colour is a scheme colour (`a:buClr/a:schemeClr/@val`), or `null`. */
651
+ schemeColor: string | null;
652
+ /** The bullet colour resolved against the slide theme with its transforms applied, or `null` when unset or not resolvable to a literal. */
653
+ resolvedColor: ResolvedColor | null;
654
+ }
655
+ /**
656
+ * A paragraph's bullet, as the structured counterpart of the `a:pPr` bullet
657
+ * children. Discriminated on {@link kind}, which is one of the four mutually
658
+ * exclusive choices the schema allows:
659
+ *
660
+ * - `'none'` — `a:buNone`, the bullet explicitly suppressed. Carries no style,
661
+ * because there is no glyph to style.
662
+ * - `'char'` — `a:buChar`, a literal glyph.
663
+ * - `'autoNum'` — `a:buAutoNum`, an auto-numbered list.
664
+ * - `'picture'` — `a:buBlip`, an image used as the glyph.
665
+ *
666
+ * A paragraph that names none of them inherits its bullet from the list style and
667
+ * reports `null` rather than a member of this union.
668
+ */
669
+ type BulletDetail = {
670
+ kind: 'none';
671
+ } | ({
672
+ kind: 'char';
673
+ /** The glyph itself (`a:buChar/@char`) — a bare character, never a tagged string. */
674
+ char: string;
675
+ } & BulletStyle) | ({
676
+ kind: 'autoNum';
677
+ /** The numbering scheme (`a:buAutoNum/@type`, e.g. `arabicPeriod`). */
678
+ scheme: string;
679
+ /**
680
+ * The number this list starts at (`a:buAutoNum/@startAt`), or `null` when
681
+ * unset (the schema default is 1). Content rather than styling: a list
682
+ * continuing "5. Deploy" that restarts at 1 is a different slide.
683
+ */
684
+ startAt: number | null;
685
+ } & BulletStyle) | ({
686
+ kind: 'picture';
687
+ /**
688
+ * Absolute partname of the image used as the glyph (`a:buBlip/a:blip/@r:embed`,
689
+ * resolved through the owning part's relationships), or `null` when the
690
+ * paragraph was reached without them or the blip carries no `r:embed`.
691
+ */
692
+ imagePartName: string | null;
693
+ } & BulletStyle);
694
+ /** One text run (`a:r`): a span of text with uniform character formatting. */
695
+ declare class Run {
696
+ #private;
697
+ private readonly element;
698
+ private readonly part;
699
+ /** The owning slide's theme context (colour maps + `fontScheme`), for the `resolved*` getters; absent when the run was reached without one. */
700
+ private readonly themeContext?;
701
+ /**
702
+ * Resolves the colour this run inherits from its placeholder/list-style chain
703
+ * when it sets none of its own (item A). Built by the owning {@link Paragraph}
704
+ * for placeholder text; absent for non-placeholder runs. Called lazily.
705
+ */
706
+ private readonly inheritedColor?;
707
+ /**
708
+ * Resolves the point size this run inherits from the same chain when it sets no
709
+ * own `@sz`. Built by the owning {@link Paragraph} for placeholder text; absent
710
+ * for non-placeholder runs. Called lazily.
711
+ */
712
+ private readonly inheritedSize?;
713
+ /**
714
+ * Resolves the typeface this run inherits from the same chain (a `+mj-*`/`+mn-*`
715
+ * theme token already resolved to a literal face) when it sets no own `a:latin`.
716
+ * Built by the owning {@link Paragraph} for placeholder text; absent otherwise.
717
+ * Called lazily.
718
+ */
719
+ private readonly inheritedFace?;
720
+ /**
721
+ * Resolves whether this run inherits bold from the same chain when it sets no
722
+ * own `@b`. Built by the owning {@link Paragraph} for placeholder text; absent
723
+ * for non-placeholder runs. Called lazily.
724
+ */
725
+ private readonly inheritedBold?;
726
+ /**
727
+ * The owning part's relationships, used to resolve a run hyperlink's `@r:id`
728
+ * to its external URL or internal target partname. Absent when the run was
729
+ * reached without them (e.g. table-cell or notes text), in which case
730
+ * {@link hyperlink} still reports the raw `@r:id`/`@action`/`@tooltip`.
390
731
  */
391
732
  private readonly relationships?;
392
733
  /**
@@ -398,7 +739,7 @@ declare class Run {
398
739
  private readonly fontRef?;
399
740
  constructor(element: Element, part: Part,
400
741
  /** The owning slide's theme context (colour maps + `fontScheme`), for the `resolved*` getters; absent when the run was reached without one. */
401
- themeContext?: FlattenContext | undefined,
742
+ themeContext?: ThemeContext | undefined,
402
743
  /**
403
744
  * Resolves the colour this run inherits from its placeholder/list-style chain
404
745
  * when it sets none of its own (item A). Built by the owning {@link Paragraph}
@@ -437,7 +778,7 @@ declare class Run {
437
778
  * below the run's own `a:rPr` and above the placeholder/`p:defaultTextStyle`
438
779
  * chain. Absent when the shape has no `p:style/a:fontRef`.
439
780
  */
440
- fontRef?: (StyleFontRef | null) | undefined);
781
+ fontRef?: StyleFontRef | null | undefined);
441
782
  /** The run's text (`a:t`), verbatim — whitespace is not normalized. */
442
783
  get text(): string;
443
784
  set text(value: string);
@@ -520,487 +861,228 @@ declare class Run {
520
861
  * The point size this run effectively renders. It is the run's own `@sz`
521
862
  * ({@link fontSizePt}) when set; otherwise, for a run inside a placeholder, the
522
863
  * size it inherits from the placeholder/list-style chain (paragraph `a:defRPr` →
523
- * slide `a:lstStyle` → layout → master placeholder `a:lstStyle` → master
524
- * `p:txStyles`). `null` when the run sets no size and inherits none — the
525
- * resolved counterpart of {@link fontSizePt}, which reports only the run's own value.
526
- */
527
- get resolvedSizePt(): number | null;
528
- /**
529
- * The typeface this run effectively renders, resolved to a literal face name. It
530
- * is the run's own `a:latin` ({@link fontName}) when set; otherwise the face named
531
- * by the shape's `p:style/a:fontRef` (`idx` → theme major/minor font), then — for a
532
- * run inside a placeholder — the face it inherits from the placeholder/list-style
533
- * chain, then the presentation's `p:defaultTextStyle`. A `+mj-*`/`+mn-*`
534
- * major/minor theme-font token — on the run itself or reached through the chain —
535
- * is resolved through the theme `fontScheme` to its concrete face. `null` when the
536
- * run names no face and inherits none, or a token cannot be resolved — the resolved
537
- * counterpart of {@link fontName}, which reports the raw `@typeface` (possibly a token).
538
- */
539
- get resolvedFontFace(): string | null;
540
- /**
541
- * Whether this run effectively renders bold. It is the run's own `@b`
542
- * ({@link bold}) when set; otherwise, for a run inside a placeholder, the bold
543
- * state it inherits from the placeholder/list-style chain (paragraph `a:defRPr` →
544
- * slide `a:lstStyle` → layout → master placeholder `a:lstStyle` → master
545
- * `p:txStyles`). `null` when the run sets no `@b` and inherits none — the
546
- * resolved counterpart of {@link bold}, which reports only the run's own value.
547
- */
548
- get resolvedBold(): boolean | null;
549
- /** Escape hatch: the underlying `a:r` element. After mutating it call {@link markDirty}, or `save()` writes the original bytes. */
550
- get element_(): Element;
551
- /** Mark the owning part dirty so `save()` reserializes it. Call after mutating {@link element_}. */
552
- markDirty(): void;
553
- }
554
- /** One paragraph (`a:p`) of a text frame. */
555
- declare class Paragraph {
556
- #private;
557
- private readonly element;
558
- private readonly part;
559
- /** The owning slide's theme context (colour maps + `fontScheme`), threaded to each {@link Run} for the `resolved*` getters. */
560
- private readonly themeContext?;
561
- /**
562
- * Placeholder + slide-list-style context for resolving a placeholder-inherited
563
- * run colour/size/face; absent for non-placeholder text. The owning
564
- * {@link TextFrame} supplies the placeholder identity and the text body's
565
- * `a:lstStyle`.
566
- */
567
- private readonly inherit?;
568
- /** The owning part's relationships, threaded to each {@link Run} for hyperlink `@r:id` resolution; absent when reached without them. */
569
- private readonly relationships?;
570
- constructor(element: Element, part: Part,
571
- /** The owning slide's theme context (colour maps + `fontScheme`), threaded to each {@link Run} for the `resolved*` getters. */
572
- themeContext?: FlattenContext | undefined,
573
- /**
574
- * Placeholder + slide-list-style context for resolving a placeholder-inherited
575
- * run colour/size/face; absent for non-placeholder text. The owning
576
- * {@link TextFrame} supplies the placeholder identity and the text body's
577
- * `a:lstStyle`.
578
- */
579
- inherit?: {
580
- placeholder: PlaceholderTextContext;
581
- slideLstStyle: Element | null;
582
- } | undefined,
583
- /** The owning part's relationships, threaded to each {@link Run} for hyperlink `@r:id` resolution; absent when reached without them. */
584
- relationships?: Relationships | undefined);
585
- /** The runs (`a:r`) in document order. Fields (`a:fld`) and breaks are not runs; see `text`. */
586
- get runs(): Run[];
587
- /** Indent level (`a:pPr/@lvl`), 0 when unset. */
588
- get level(): number;
589
- /**
590
- * Horizontal alignment token (`a:pPr/@algn`: `l` | `ctr` | `r` | `just` |
591
- * `dist` | `thaiDist`), or `null` when unset (inherited from the list style).
592
- */
593
- get align(): string | null;
594
- /**
595
- * Space before the paragraph in points (`a:pPr/a:spcBef/a:spcPts/@val` is
596
- * hundredths of a point), or `null` when unset or expressed as a percentage
597
- * (`a:spcPct`, which has no fixed point value).
598
- */
599
- get spaceBeforePt(): number | null;
600
- /** Space after the paragraph in points; see {@link spaceBeforePt} for the percentage caveat. */
601
- get spaceAfterPt(): number | null;
602
- /**
603
- * The paragraph's line spacing (`a:pPr/a:lnSpc`), as an exact point height
604
- * (`a:spcPts`) or a percentage of the single-line height (`a:spcPct`), or
605
- * `null` when unset (inherited from the list style). See {@link LineSpacing}.
606
- */
607
- get lineSpacing(): LineSpacing | null;
608
- /** Left margin of the paragraph in points (`a:pPr/@marL` is EMU; 12700 EMU = 1pt), or `null` when unset. */
609
- get marginLeftPt(): number | null;
610
- /** First-line indent in points (`a:pPr/@indent` is EMU; negative for a hanging indent), or `null` when unset. */
611
- get indentPt(): number | null;
612
- /**
613
- * Bullet description for this paragraph, derived from the `a:pPr` bullet
614
- * children, or `null` when unset (inherited from the list style):
615
- * - `'none'` — explicit `a:buNone` (bullet suppressed)
616
- * - `'char:•'` — `a:buChar/@char` (the literal glyph follows the colon)
617
- * - `'autoNum:arabicPeriod'` — `a:buAutoNum/@type` (auto-numbered)
618
- */
619
- get bullet(): string | null;
620
- /**
621
- * The paragraph's text: run (`a:r`) and field (`a:fld`) text concatenated in
622
- * document order, with each line break (`a:br`) rendered as `\n`.
623
- */
624
- get text(): string;
625
- /** Escape hatch: the underlying `a:p` element. After mutating it call {@link markDirty}, or `save()` writes the original bytes. */
626
- get element_(): Element;
627
- /** Mark the owning part dirty so `save()` reserializes it. Call after mutating {@link element_}. */
628
- markDirty(): void;
629
- }
630
- /** A shape's text frame (`p:txBody`): an ordered list of paragraphs. */
631
- /**
632
- * A text frame's body properties (`a:bodyPr`), as read from a shape. Carries the
633
- * inset/anchor/vertical-text settings that govern where text sits inside its box
634
- * — the difference between a label that clears a left rail and one that overlaps
635
- * it. Only **explicitly set** attributes are reported; an absent inset means the
636
- * PowerPoint default (`lIns`/`rIns` = 0.1", `tIns`/`bIns` = 0.05").
637
- */
638
- interface BodyProperties {
639
- /** Text direction (`@vert`: `horz`/`vert`/`vert270`/`eaVert`/`wordArtVert`…), or `null` when horizontal/unset. */
640
- vert: string | null;
641
- /** Vertical anchor (`@anchor`: `t`/`ctr`/`b`), or `null` when unset (defaults to top). */
642
- anchor: string | null;
643
- /** Wrap mode (`@wrap`: `square`/`none`), or `null` when unset. */
644
- wrap: string | null;
645
- /** Explicitly-set text insets in points (`@lIns`/`@rIns`/`@tIns`/`@bIns` ÷ 12700); a missing side uses the PowerPoint default. */
646
- insetsPt: {
647
- left?: number;
648
- right?: number;
649
- top?: number;
650
- bottom?: number;
651
- };
652
- }
653
- /**
654
- * A text frame's vertical-autofit mode, read from its `a:bodyPr` autofit child:
655
- * - `'none'` — `a:noAutofit`, or no autofit child at all (the box has a fixed
656
- * size and text can overflow); write-side `fit: 'none'`.
657
- * - `'normAutofit'`— `a:normAutofit` (shrink text to fit); write-side `fit: 'shrink'`.
658
- * - `'spAutoFit'` — `a:spAutoFit` (resize the shape to fit text); write-side `fit: 'resize'`.
659
- */
660
- type AutofitMode = 'none' | 'normAutofit' | 'spAutoFit';
661
- declare class TextFrame {
662
- #private;
663
- private readonly txBody;
664
- private readonly part;
665
- /** The owning slide's theme context (colour maps + `fontScheme`), threaded to each {@link Paragraph}/{@link Run} for the `resolved*` getters. */
666
- private readonly themeContext?;
667
- /**
668
- * The placeholder this text body lives in, when any — enables
669
- * placeholder-inherited run colour/size/face resolution. Absent for ordinary
670
- * text boxes and table cells.
671
- */
672
- private readonly placeholder?;
673
- /** The owning part's relationships, threaded to each {@link Paragraph}/{@link Run} for hyperlink `@r:id` resolution; absent when reached without them. */
674
- private readonly relationships?;
675
- constructor(txBody: Element, part: Part,
676
- /** The owning slide's theme context (colour maps + `fontScheme`), threaded to each {@link Paragraph}/{@link Run} for the `resolved*` getters. */
677
- themeContext?: FlattenContext | undefined,
678
- /**
679
- * The placeholder this text body lives in, when any — enables
680
- * placeholder-inherited run colour/size/face resolution. Absent for ordinary
681
- * text boxes and table cells.
682
- */
683
- placeholder?: PlaceholderTextContext | undefined,
684
- /** The owning part's relationships, threaded to each {@link Paragraph}/{@link Run} for hyperlink `@r:id` resolution; absent when reached without them. */
685
- relationships?: Relationships | undefined);
686
- /** Paragraphs (`a:p`) in document order. */
687
- get paragraphs(): Paragraph[];
688
- /**
689
- * The frame's body properties (`a:bodyPr`: insets, anchor, vertical text), or
690
- * `null` when there is no `a:bodyPr`. Only explicitly-set insets are reported
691
- * (a missing side is the PowerPoint default — see {@link BodyProperties}).
692
- */
693
- get bodyProperties(): BodyProperties | null;
694
- /**
695
- * The effective vertical anchor (`t`/`ctr`/`b`): the frame's own
696
- * `a:bodyPr/@anchor` when set, else the anchor it inherits from its
697
- * layout → master placeholder `a:bodyPr`. `null` when nothing in the chain sets
698
- * one (PowerPoint then defaults to top). Unlike {@link bodyProperties}'s
699
- * `anchor` (own attribute only), this surfaces the inherited anchor a
700
- * placeholder title relies on — the difference between a top- and
701
- * centre-anchored title that own-attribute reads alone cannot see.
702
- */
703
- get resolvedAnchor(): string | null;
704
- /**
705
- * The frame's vertical-autofit mode (`a:bodyPr` autofit child), or `null` when
706
- * there is no `a:bodyPr`. A `bodyPr` with no autofit child — or an explicit
707
- * `a:noAutofit` — reads `'none'`. See {@link AutofitMode}. This is the deep-model
708
- * counterpart of `inspectPptx`'s per-shape `autofit`; unlike the shallow surface
709
- * it hangs off the navigable text frame.
710
- */
711
- get autofit(): AutofitMode | null;
712
- /**
713
- * The baked shrink scale of a `normAutofit` frame as a percent (62.5 = 62.5%),
714
- * or `null` when the frame has no `a:normAutofit` or bakes no scale. A bare
715
- * `<a:normAutofit/>` (write-side `fit: 'shrink'`) carries no scale — PowerPoint
716
- * computes it on edit and draws at 100% until then — so it too reads `null`; an
717
- * explicit scale comes from `fit: { type: 'shrink', fontScale }`.
718
- */
719
- get autofitFontScale(): number | null;
720
- /**
721
- * The baked line-spacing reduction of a `normAutofit` frame as a percent
722
- * (`a:normAutofit/@lnSpcReduction` ÷ 1000), or `null` when unset. The companion
723
- * to {@link autofitFontScale} (write-side `fit: { type: 'shrink', lnSpcReduction }`).
724
- */
725
- get autofitLineSpaceReduction(): number | null;
726
- /** All paragraph text joined by `\n` (mirrors python-pptx `TextFrame.text`). */
727
- get text(): string;
728
- /**
729
- * Replace the frame's text with a single paragraph and run, preserving the
730
- * character formatting (`a:rPr`) of the frame's first existing run when there
731
- * is one. For multiple runs or per-run formatting, edit
732
- * `paragraphs[].runs[]` directly.
733
- */
734
- set text(value: string);
735
- /** Escape hatch: the underlying `p:txBody` element. After mutating it call {@link markDirty}, or `save()` writes the original bytes. */
736
- get element_(): Element;
737
- /** Mark the owning part dirty so `save()` reserializes it. Call after mutating {@link element_}. */
738
- markDirty(): void;
739
- }
740
- //#endregion
741
- //#region src/read/api/pattern-fill.d.ts
742
- /**
743
- * A pattern fill (`a:pattFill`) — a two-colour preset hatch. The write-side
744
- * `fill: { type: 'pattern', pattern: { preset, fgColor, bgColor } }` emits the same element,
745
- * so the {@link preset} name and both colours round-trip. Colours resolve against the theme
746
- * (a scheme token → literal hex) the same way a solid fill does.
747
- */
748
- interface PatternFill {
749
- /** Preset pattern name (`@prst`, e.g. `pct50`/`diagCross`/`ltUpDiag`), or `null` when unset. */
750
- preset: string | null;
751
- /** Foreground colour (`a:fgClr`) resolved against the theme, or `null`. */
752
- foreground: ResolvedColor | null;
753
- /** Background colour (`a:bgClr`) resolved against the theme, or `null`. */
754
- background: ResolvedColor | null;
755
- }
756
- //#endregion
757
- //#region src/read/api/shapes/types.d.ts
758
- /** Discriminator for the concrete `Shape` subclass. */
759
- type ShapeType = 'autoShape' | 'picture' | 'connector' | 'graphicFrame' | 'group';
760
- /** One end of a connector/line (`a:ln/a:headEnd` or `a:tailEnd`), as read from a shape. */
761
- interface LineEnd {
762
- /** Arrowhead type (`@type`: `none`/`triangle`/`stealth`/`diamond`/`oval`/`arrow`). */
763
- type: string;
764
- /** Width class (`@w`: `sm`/`med`/`lg`), or `null` when unset. */
765
- width: string | null;
766
- /** Length class (`@len`: `sm`/`med`/`lg`), or `null` when unset. */
767
- length: string | null;
768
- }
769
- /** Both ends of a shape's line/border, when either carries an arrowhead. */
770
- interface LineEnds {
771
- head: LineEnd | null;
772
- tail: LineEnd | null;
773
- }
774
- /**
775
- * One bound end of a connector (`p:nvCxnSpPr/p:cNvCxnSpPr/a:stCxn` or `a:endCxn`),
776
- * as read. A connector authored with `startShape`/`endShape` attaches each end to
777
- * a shape by that shape's `p:cNvPr/@id` plus a connection-site index; an unbound
778
- * end (the writer emits a bare `p:cNvCxnSpPr`) reports no site at all — see
779
- * {@link Connector.startConnection}. This is the read counterpart of the write
780
- * API's `startShape`/`startShapeIdx` split, which binds by `objectName` and
781
- * resolves the name → id at serialize time.
782
- */
783
- interface ConnectionSite {
784
- /** The bound shape's drawing id (`@id`, i.e. its `p:cNvPr/@id`). */
785
- shapeId: number;
786
- /** Connection-site index on the bound shape (`@idx`; 0-based, preset-dependent). */
787
- siteIndex: number;
788
- /**
789
- * The bound shape resolved to a read-model shape via {@link Slide.shapeByIdDeep},
790
- * which descends into groups — so a connector bound to a shape nested in a group
791
- * resolves the same as one bound to a top-level shape. `null` only when no shape
792
- * anywhere on the slide carries that id (a genuinely dangling binding), which is
793
- * faithful degradation and does not throw.
794
- */
795
- boundShape: AnyShape | null;
796
- }
797
- /**
798
- * A shape's outer drop shadow (`spPr/a:effectLst/a:outerShdw`), as read from a
799
- * shape and resolved against the slide theme. Distances are in points (the EMU
800
- * source ÷ 12700) and the direction in degrees (the `60000`ths source ÷ 60000),
801
- * matching the write-side {@link ShadowProps} convention so it round-trips.
802
- */
803
- interface OuterShadow {
804
- /** Effective shadow colour as 6-hex (theme-resolved, transforms applied), or `null`. */
805
- color: string | null;
806
- /** Theme colour token when the shadow colour was a scheme colour (e.g. `accent1`), else `undefined`. */
807
- colorToken?: string;
808
- /** Shadow opacity 0–1 (from the colour's `a:alpha`), or `undefined` when fully opaque. */
809
- alpha?: number;
810
- /** Blur radius in points (`@blurRad` ÷ 12700), or `undefined` when unset. */
811
- blurPt?: number;
812
- /** Offset distance in points (`@dist` ÷ 12700), or `undefined` when unset. */
813
- offsetPt?: number;
814
- /** Offset direction in degrees, clockwise from 3 o'clock (`@dir` ÷ 60000), or `undefined` when unset. */
815
- angleDeg?: number;
816
- }
817
- /**
818
- * A shape's inner shadow (`spPr/a:effectLst/a:innerShdw`), resolved against the
819
- * slide theme. Identical fields to {@link OuterShadow} — CT_InnerShadowEffect
820
- * carries the same `blurRad`/`dist`/`dir` + colour — but a distinct type so a
821
- * consumer can tell an inset shadow from a drop shadow. Distances in points,
822
- * direction in degrees, matching the write-side `shadow: { type: 'inner' }`.
823
- */
824
- interface InnerShadow {
825
- /** Effective shadow colour as 6-hex (theme-resolved, transforms applied), or `null`. */
826
- color: string | null;
827
- /** Theme colour token when the shadow colour was a scheme colour (e.g. `accent1`), else `undefined`. */
828
- colorToken?: string;
829
- /** Shadow opacity 0–1 (from the colour's `a:alpha`), or `undefined` when fully opaque. */
830
- alpha?: number;
831
- /** Blur radius in points (`@blurRad` ÷ 12700), or `undefined` when unset. */
832
- blurPt?: number;
833
- /** Offset distance in points (`@dist` ÷ 12700), or `undefined` when unset. */
834
- offsetPt?: number;
835
- /** Offset direction in degrees, clockwise from 3 o'clock (`@dir` ÷ 60000), or `undefined` when unset. */
836
- angleDeg?: number;
837
- }
838
- /**
839
- * A shape's glow effect (`spPr/a:effectLst/a:glow`) — a coloured halo — resolved
840
- * against the slide theme. The write-side text glow (`glow: { size, color,
841
- * opacity }`) emits the same element, so {@link radiusPt} (`@rad` ÷ 12700) and the
842
- * colour round-trip.
843
- */
844
- interface Glow {
845
- /** Effective glow colour as 6-hex (theme-resolved, transforms applied), or `null`. */
846
- color: string | null;
847
- /** Theme colour token when the glow colour was a scheme colour (e.g. `accent1`), else `undefined`. */
848
- colorToken?: string;
849
- /** Glow opacity 0–1 (from the colour's `a:alpha`), or `undefined` when fully opaque. */
850
- alpha?: number;
851
- /** Glow radius in points (`@rad` ÷ 12700), or `undefined` when unset. */
852
- radiusPt?: number;
853
- }
854
- /**
855
- * A shape's reflection effect (`spPr/a:effectLst/a:reflection`) — a mirrored fade
856
- * beneath the shape. This library's writer authors none, so this is a **read-only**
857
- * surface: a consumer that finds one should carry the part verbatim rather than
858
- * regenerate it. Only the attributes a faithful replica needs are decoded —
859
- * distances in points (÷ 12700), directions in degrees (÷ 60000), and the start/end
860
- * alpha and position pairs as 0–1 fractions (the `1000`ths-of-a-percent source
861
- * ÷ 100000). All fields are optional; an attribute absent from the source is omitted.
862
- */
863
- interface Reflection {
864
- /** Blur radius in points (`@blurRad` ÷ 12700). */
865
- blurPt?: number;
866
- /** Start opacity 0–1 (`@stA` ÷ 100000). */
867
- startAlpha?: number;
868
- /** Start position along the reflection 0–1 (`@stPos` ÷ 100000). */
869
- startPos?: number;
870
- /** End opacity 0–1 (`@endA` ÷ 100000). */
871
- endAlpha?: number;
872
- /** End position along the reflection 0–1 (`@endPos` ÷ 100000). */
873
- endPos?: number;
874
- /** Offset distance in points (`@dist` ÷ 12700). */
875
- distPt?: number;
876
- /** Offset direction in degrees (`@dir` ÷ 60000). */
877
- angleDeg?: number;
878
- /** Fade direction in degrees (`@fadeDir` ÷ 60000). */
879
- fadeAngleDeg?: number;
880
- }
881
- /**
882
- * A shape's soft-edge effect (`spPr/a:effectLst/a:softEdge`) — a feathered border.
883
- * Like {@link Reflection}, the writer authors none, so carry it verbatim. `@rad`
884
- * (the feather radius) ÷ 12700 → points.
885
- */
886
- interface SoftEdge {
887
- /** Feather radius in points (`@rad` ÷ 12700). */
888
- radiusPt: number;
889
- }
890
- /**
891
- * One segment of a custom-geometry path (`a:path`), as read from a shape. The
892
- * command verbs mirror the write-side `GeometryPoint` DSL (`src/types/`)
893
- * so a consumer can map a `GeometryCommand[]` to `GeometryPoint[]` one-to-one.
894
- *
895
- * Coordinates (`x`/`y`/`x1`…) are raw path-unit integers in the path's own
896
- * `0..w` / `0..h` space (see {@link CustomGeometryPath.w}); they are not EMU and
897
- * must be scaled by the consumer against the shape's box. `arcTo` angles are in
898
- * **degrees** (the raw `60000`ths-of-a-degree values divided by 60000), matching
899
- * the write DSL's degree input.
900
- */
901
- type GeometryCommand = {
902
- cmd: 'moveTo';
903
- x: number;
904
- y: number;
905
- } | {
906
- cmd: 'lnTo';
907
- x: number;
908
- y: number;
909
- } | {
910
- cmd: 'cubicBezTo';
911
- x1: number;
912
- y1: number;
913
- x2: number;
914
- y2: number;
915
- x: number;
916
- y: number;
917
- } | {
918
- cmd: 'quadBezTo';
919
- x1: number;
920
- y1: number;
921
- x: number;
922
- y: number;
923
- } | {
924
- cmd: 'arcTo';
925
- wR: number;
926
- hR: number;
927
- stAng: number;
928
- swAng: number;
929
- } | {
930
- cmd: 'close';
931
- };
932
- /** One `<a:path>` of a custom geometry, with its path-unit viewport and render attrs. */
933
- interface CustomGeometryPath {
934
- /** Path-unit width (`a:path/@w`); the `x` denominator for this path's coords. Default `0`. */
935
- w: number;
936
- /** Path-unit height (`a:path/@h`); the `y` denominator for this path's coords. Default `0`. */
937
- h: number;
938
- /** Fill mode (`a:path/@fill`, `ST_PathFillMode`, e.g. `norm`/`none`/`lighten`). Default `norm`. */
939
- fill: string;
940
- /** Whether the path is stroked (`a:path/@stroke`). Default `true`. */
941
- stroke: boolean;
942
- /** The path's segments in document order — order *is* the geometry. */
943
- commands: GeometryCommand[];
944
- }
945
- /**
946
- * Custom freeform geometry (`spPr/a:custGeom/a:pathLst`), as read from a shape.
947
- * Faithfully exposes every `a:path` rather than flattening to a single command
948
- * list: the schema allows repeatable `a:path`, each with independent
949
- * `fill`/`stroke`. Desktop PowerPoint's own freeforms only ever emit one
950
- * `a:path` (a hole is one path with two `moveTo`…`close` contours), but
951
- * multi-`a:path` input is schema-legal (e.g. SVG import) and preserved here.
952
- */
953
- interface CustomGeometry {
954
- paths: CustomGeometryPath[];
864
+ * slide `a:lstStyle` → layout → master placeholder `a:lstStyle` → master
865
+ * `p:txStyles`). `null` when the run sets no size and inherits none — the
866
+ * resolved counterpart of {@link fontSizePt}, which reports only the run's own value.
867
+ */
868
+ get resolvedSizePt(): number | null;
869
+ /**
870
+ * The typeface this run effectively renders, resolved to a literal face name. It
871
+ * is the run's own `a:latin` ({@link fontName}) when set; otherwise the face named
872
+ * by the shape's `p:style/a:fontRef` (`idx` → theme major/minor font), then — for a
873
+ * run inside a placeholder — the face it inherits from the placeholder/list-style
874
+ * chain, then the presentation's `p:defaultTextStyle`. A `+mj-*`/`+mn-*`
875
+ * major/minor theme-font token — on the run itself or reached through the chain —
876
+ * is resolved through the theme `fontScheme` to its concrete face. `null` when the
877
+ * run names no face and inherits none, or a token cannot be resolved — the resolved
878
+ * counterpart of {@link fontName}, which reports the raw `@typeface` (possibly a token).
879
+ */
880
+ get resolvedFontFace(): string | null;
881
+ /**
882
+ * Whether this run effectively renders bold. It is the run's own `@b`
883
+ * ({@link bold}) when set; otherwise, for a run inside a placeholder, the bold
884
+ * state it inherits from the placeholder/list-style chain (paragraph `a:defRPr` →
885
+ * slide `a:lstStyle` → layout → master placeholder `a:lstStyle` → master
886
+ * `p:txStyles`). `null` when the run sets no `@b` and inherits none — the
887
+ * resolved counterpart of {@link bold}, which reports only the run's own value.
888
+ */
889
+ get resolvedBold(): boolean | null;
890
+ /** Escape hatch: the underlying `a:r` element. After mutating it call {@link markDirty}, or `save()` writes the original bytes. */
891
+ get element_(): Element;
892
+ /** Mark the owning part dirty so `save()` reserializes it. Call after mutating {@link element_}. */
893
+ markDirty(): void;
955
894
  }
956
- /** A shape's resolved position and size in slide-absolute EMU. */
957
- interface AbsoluteFrame {
958
- left: number;
959
- top: number;
960
- width: number;
961
- height: number;
962
- /** Effective clockwise rotation in degrees after composing enclosing group rotations. */
963
- rotation: number;
964
- /** Effective horizontal flip after XOR-composing enclosing group flips. */
965
- flipH: boolean;
966
- /** Effective vertical flip after XOR-composing enclosing group flips. */
967
- flipV: boolean;
895
+ /** One paragraph (`a:p`) of a text frame. */
896
+ declare class Paragraph {
897
+ #private;
898
+ private readonly element;
899
+ private readonly part;
900
+ /** The owning slide's theme context (colour maps + `fontScheme`), threaded to each {@link Run} for the `resolved*` getters. */
901
+ private readonly themeContext?;
902
+ /**
903
+ * Placeholder + slide-list-style context for resolving a placeholder-inherited
904
+ * run colour/size/face; absent for non-placeholder text. The owning
905
+ * {@link TextFrame} supplies the placeholder identity and the text body's
906
+ * `a:lstStyle`.
907
+ */
908
+ private readonly inherit?;
909
+ /** The owning part's relationships, threaded to each {@link Run} for hyperlink `@r:id` resolution; absent when reached without them. */
910
+ private readonly relationships?;
911
+ constructor(element: Element, part: Part,
912
+ /** The owning slide's theme context (colour maps + `fontScheme`), threaded to each {@link Run} for the `resolved*` getters. */
913
+ themeContext?: ThemeContext | undefined,
914
+ /**
915
+ * Placeholder + slide-list-style context for resolving a placeholder-inherited
916
+ * run colour/size/face; absent for non-placeholder text. The owning
917
+ * {@link TextFrame} supplies the placeholder identity and the text body's
918
+ * `a:lstStyle`.
919
+ */
920
+ inherit?: {
921
+ placeholder: PlaceholderTextContext;
922
+ slideLstStyle: Element | null;
923
+ } | undefined,
924
+ /** The owning part's relationships, threaded to each {@link Run} for hyperlink `@r:id` resolution; absent when reached without them. */
925
+ relationships?: Relationships | undefined);
926
+ /** The runs (`a:r`) in document order. Fields (`a:fld`) and breaks are not runs; see `text`. */
927
+ get runs(): Run[];
928
+ /** Indent level (`a:pPr/@lvl`), 0 when unset. */
929
+ get level(): number;
930
+ /**
931
+ * Horizontal alignment token (`a:pPr/@algn`: `l` | `ctr` | `r` | `just` |
932
+ * `dist` | `thaiDist`), or `null` when unset (inherited from the list style).
933
+ */
934
+ get align(): string | null;
935
+ /**
936
+ * Space before the paragraph in points (`a:pPr/a:spcBef/a:spcPts/@val` is
937
+ * hundredths of a point), or `null` when unset or expressed as a percentage
938
+ * (`a:spcPct`, which has no fixed point value).
939
+ */
940
+ get spaceBeforePt(): number | null;
941
+ /** Space after the paragraph in points; see {@link spaceBeforePt} for the percentage caveat. */
942
+ get spaceAfterPt(): number | null;
943
+ /**
944
+ * The paragraph's line spacing (`a:pPr/a:lnSpc`), as an exact point height
945
+ * (`a:spcPts`) or a percentage of the single-line height (`a:spcPct`), or
946
+ * `null` when unset (inherited from the list style). See {@link LineSpacing}.
947
+ */
948
+ get lineSpacing(): LineSpacing | null;
949
+ /** Left margin of the paragraph in points (`a:pPr/@marL` is EMU; 12700 EMU = 1pt), or `null` when unset. */
950
+ get marginLeftPt(): number | null;
951
+ /** First-line indent in points (`a:pPr/@indent` is EMU; negative for a hanging indent), or `null` when unset. */
952
+ get indentPt(): number | null;
953
+ /**
954
+ * This paragraph's bullet — its kind, and for a drawn bullet the glyph, the
955
+ * numbering start, and the bullet's own font/size/colour. `null` when the
956
+ * paragraph names no bullet at all and inherits one from the list style.
957
+ *
958
+ * Structured rather than a tagged string, which is not merely tidier. The
959
+ * previous `bullet` accessor reported `'none'` / `'char:•'` /
960
+ * `'autoNum:arabicPeriod'`, and that shape is ambiguous when the glyph is
961
+ * itself a colon; worse, it reads as a bare glyph, which is exactly how the
962
+ * script converter first consumed it — `'none'.codePointAt(0)` put a literal
963
+ * `n` bullet on every converted deck, silently. See {@link BulletDetail}.
964
+ */
965
+ get bulletDetail(): BulletDetail | null;
966
+ /**
967
+ * The paragraph's text: run (`a:r`) and field (`a:fld`) text concatenated in
968
+ * document order, with each line break (`a:br`) rendered as `\n`.
969
+ */
970
+ get text(): string;
971
+ /** Escape hatch: the underlying `a:p` element. After mutating it call {@link markDirty}, or `save()` writes the original bytes. */
972
+ get element_(): Element;
973
+ /** Mark the owning part dirty so `save()` reserializes it. Call after mutating {@link element_}. */
974
+ markDirty(): void;
968
975
  }
976
+ /** A shape's text frame (`p:txBody`): an ordered list of paragraphs. */
969
977
  /**
970
- * A colour reference inside a picture recolour effect, split by colour model
971
- * (mirrors {@link GradientStop}). At most one field is non-`null`.
978
+ * A text frame's body properties (`a:bodyPr`), as read from a shape. Carries the
979
+ * inset/anchor/vertical-text settings that govern where text sits inside its box
980
+ * — the difference between a label that clears a left rail and one that overlaps
981
+ * it. Only **explicitly set** attributes are reported; an absent inset means the
982
+ * PowerPoint default (`lIns`/`rIns` = 0.1", `tIns`/`bIns` = 0.05").
972
983
  */
973
- interface RecolorColor {
974
- /** Explicit RGB as 6-hex (`a:srgbClr/@val`), or `null`. */
975
- color: string | null;
976
- /** Theme colour token (`a:schemeClr/@val`, e.g. `accent1`), or `null`. */
977
- schemeColor: string | null;
978
- /** Preset colour name (`a:prstClr/@val`, e.g. `black`/`white` — the duotone icon-tint stops), or `null`. */
979
- presetColor: string | null;
984
+ interface BodyProperties {
985
+ /** Text direction (`@vert`: `horz`/`vert`/`vert270`/`eaVert`/`wordArtVert`…), or `null` when horizontal/unset. */
986
+ vert: string | null;
987
+ /** Vertical anchor (`@anchor`: `t`/`ctr`/`b`), or `null` when unset (defaults to top). */
988
+ anchor: string | null;
989
+ /** Wrap mode (`@wrap`: `square`/`none`), or `null` when unset. */
990
+ wrap: string | null;
991
+ /** Explicitly-set text insets in points (`@lIns`/`@rIns`/`@tIns`/`@bIns` ÷ 12700); a missing side uses the PowerPoint default. */
992
+ insetsPt: {
993
+ left?: number;
994
+ right?: number;
995
+ top?: number;
996
+ bottom?: number;
997
+ };
980
998
  }
981
999
  /**
982
- * A picture's blip recolour effect (`p:blipFill/a:blip` recolour child), as read.
983
- * A small discriminated union over the effects a faithful reader needs to
984
- * reproduce a recoloured image. Colours use the same `color`/`schemeColor`/
985
- * `presetColor` split as {@link GradientStop}, so theme tokens can resolve through
986
- * {@link Slide.themeContext}. `threshold`/`amount` are 0–1 fractions.
1000
+ * A text frame's vertical-autofit mode, read from its `a:bodyPr` autofit child:
1001
+ * - `'none'` — `a:noAutofit`, or no autofit child at all (the box has a fixed
1002
+ * size and text can overflow); write-side `fit: 'none'`.
1003
+ * - `'normAutofit'`— `a:normAutofit` (shrink text to fit); write-side `fit: 'shrink'`.
1004
+ * - `'spAutoFit'` — `a:spAutoFit` (resize the shape to fit text); write-side `fit: 'resize'`.
987
1005
  */
988
- type Recolor = {
989
- kind: 'duotone';
990
- stops: RecolorColor[];
991
- } | {
992
- kind: 'clrChange';
993
- from: RecolorColor | null;
994
- to: RecolorColor | null;
995
- } | {
996
- kind: 'grayscale';
997
- } | {
998
- kind: 'biLevel';
999
- threshold: number | null;
1000
- } | {
1001
- kind: 'alphaModFix';
1002
- amount: number;
1003
- };
1006
+ type AutofitMode = 'none' | 'normAutofit' | 'spAutoFit';
1007
+ declare class TextFrame {
1008
+ #private;
1009
+ private readonly txBody;
1010
+ private readonly part;
1011
+ /** The owning slide's theme context (colour maps + `fontScheme`), threaded to each {@link Paragraph}/{@link Run} for the `resolved*` getters. */
1012
+ private readonly themeContext?;
1013
+ /**
1014
+ * The placeholder this text body lives in, when any — enables
1015
+ * placeholder-inherited run colour/size/face resolution. Absent for ordinary
1016
+ * text boxes and table cells.
1017
+ */
1018
+ private readonly placeholder?;
1019
+ /** The owning part's relationships, threaded to each {@link Paragraph}/{@link Run} for hyperlink `@r:id` resolution; absent when reached without them. */
1020
+ private readonly relationships?;
1021
+ constructor(txBody: Element, part: Part,
1022
+ /** The owning slide's theme context (colour maps + `fontScheme`), threaded to each {@link Paragraph}/{@link Run} for the `resolved*` getters. */
1023
+ themeContext?: ThemeContext | undefined,
1024
+ /**
1025
+ * The placeholder this text body lives in, when any — enables
1026
+ * placeholder-inherited run colour/size/face resolution. Absent for ordinary
1027
+ * text boxes and table cells.
1028
+ */
1029
+ placeholder?: PlaceholderTextContext | undefined,
1030
+ /** The owning part's relationships, threaded to each {@link Paragraph}/{@link Run} for hyperlink `@r:id` resolution; absent when reached without them. */
1031
+ relationships?: Relationships | undefined);
1032
+ /** Paragraphs (`a:p`) in document order. */
1033
+ get paragraphs(): Paragraph[];
1034
+ /**
1035
+ * The frame's body properties (`a:bodyPr`: insets, anchor, vertical text), or
1036
+ * `null` when there is no `a:bodyPr`. Only explicitly-set insets are reported
1037
+ * (a missing side is the PowerPoint default — see {@link BodyProperties}).
1038
+ */
1039
+ get bodyProperties(): BodyProperties | null;
1040
+ /**
1041
+ * The effective vertical anchor (`t`/`ctr`/`b`): the frame's own
1042
+ * `a:bodyPr/@anchor` when set, else the anchor it inherits from its
1043
+ * layout → master placeholder `a:bodyPr`. `null` when nothing in the chain sets
1044
+ * one (PowerPoint then defaults to top). Unlike {@link bodyProperties}'s
1045
+ * `anchor` (own attribute only), this surfaces the inherited anchor a
1046
+ * placeholder title relies on — the difference between a top- and
1047
+ * centre-anchored title that own-attribute reads alone cannot see.
1048
+ */
1049
+ get resolvedAnchor(): string | null;
1050
+ /**
1051
+ * The frame's vertical-autofit mode (`a:bodyPr` autofit child), or `null` when
1052
+ * there is no `a:bodyPr`. A `bodyPr` with no autofit child — or an explicit
1053
+ * `a:noAutofit` — reads `'none'`. See {@link AutofitMode}. This is the deep-model
1054
+ * counterpart of `inspectPptx`'s per-shape `autofit`; unlike the shallow surface
1055
+ * it hangs off the navigable text frame.
1056
+ */
1057
+ get autofit(): AutofitMode | null;
1058
+ /**
1059
+ * The baked shrink scale of a `normAutofit` frame as a percent (62.5 = 62.5%),
1060
+ * or `null` when the frame has no `a:normAutofit` or bakes no scale. A bare
1061
+ * `<a:normAutofit/>` (write-side `fit: 'shrink'`) carries no scale — PowerPoint
1062
+ * computes it on edit and draws at 100% until then — so it too reads `null`; an
1063
+ * explicit scale comes from `fit: { type: 'shrink', fontScale }`.
1064
+ */
1065
+ get autofitFontScale(): number | null;
1066
+ /**
1067
+ * The baked line-spacing reduction of a `normAutofit` frame as a percent
1068
+ * (`a:normAutofit/@lnSpcReduction` ÷ 1000), or `null` when unset. The companion
1069
+ * to {@link autofitFontScale} (write-side `fit: { type: 'shrink', lnSpcReduction }`).
1070
+ */
1071
+ get autofitLineSpaceReduction(): number | null;
1072
+ /** All paragraph text joined by `\n` (mirrors python-pptx `TextFrame.text`). */
1073
+ get text(): string;
1074
+ /**
1075
+ * Replace the frame's text with a single paragraph and run, preserving the
1076
+ * character formatting (`a:rPr`) of the frame's first existing run when there
1077
+ * is one. For multiple runs or per-run formatting, edit
1078
+ * `paragraphs[].runs[]` directly.
1079
+ */
1080
+ set text(value: string);
1081
+ /** Escape hatch: the underlying `p:txBody` element. After mutating it call {@link markDirty}, or `save()` writes the original bytes. */
1082
+ get element_(): Element;
1083
+ /** Mark the owning part dirty so `save()` reserializes it. Call after mutating {@link element_}. */
1084
+ markDirty(): void;
1085
+ }
1004
1086
  //#endregion
1005
1087
  //#region src/read/api/shapes/base.d.ts
1006
1088
  /** Common base for every shape in a slide's shape tree. */
@@ -1149,10 +1231,23 @@ declare abstract class Shape {
1149
1231
  /** Theme colour token when the fill is a scheme colour (`a:solidFill/a:schemeClr/@val`, e.g. `accent2`), or `null`. */
1150
1232
  get fillSchemeColor(): string | null;
1151
1233
  set fillSchemeColor(value: string | null);
1234
+ /**
1235
+ * `true` when the shape sets an explicit no-fill (`spPr/a:noFill`) — a
1236
+ * deliberately transparent surface. The fill-side counterpart of
1237
+ * {@link lineNoFill}, and the only accessor that separates it from a shape
1238
+ * carrying no fill child at all (one inheriting through `p:style/a:fillRef`):
1239
+ * every other fill accessor — {@link fillColor}, {@link fillSchemeColor},
1240
+ * {@link resolvedFill}, {@link gradientFill}, {@link patternFill},
1241
+ * {@link pictureFill} — reports `null` for both. The two paint completely
1242
+ * differently, so a consumer that cannot tell them apart paints a transparent
1243
+ * shape in the theme's accent colour.
1244
+ */
1245
+ get fillNoFill(): boolean;
1152
1246
  /**
1153
1247
  * Set an explicit `<a:noFill/>` on the shape — a transparent surface. This is
1154
1248
  * distinct from clearing the fill (`fillColor = null`), which removes the
1155
1249
  * `a:solidFill` and lets the fill inherit from the shape's style/placeholder.
1250
+ * Read it back with {@link fillNoFill}.
1156
1251
  */
1157
1252
  noFill(): void;
1158
1253
  /** Explicit RGB line/border colour (`spPr/a:ln/a:solidFill/a:srgbClr/@val`), or `null`. */
@@ -1178,6 +1273,26 @@ declare abstract class Shape {
1178
1273
  * to know the border was explicitly suppressed.
1179
1274
  */
1180
1275
  get lineNoFill(): boolean;
1276
+ /**
1277
+ * The line end cap (`spPr/a:ln/@cap`) as the raw OOXML token — `'flat'`,
1278
+ * `'rnd'` (round) or `'sq'` (square) — or `null` when unset (PowerPoint's
1279
+ * default is `flat`). The write API authors this attribute through
1280
+ * `ShapeLineProps.cap`, so without the accessor a deck this library produced
1281
+ * could not be read back without losing it.
1282
+ *
1283
+ * Not cosmetic on a thick dashed rule: the cap decides whether each dash reads
1284
+ * as a rectangle or a lozenge, and it extends every dash by the stroke width.
1285
+ * SVG's `stroke-linecap` is the exact equivalent (`flat`→`butt`, `rnd`→`round`,
1286
+ * `sq`→`square`).
1287
+ */
1288
+ get lineCap(): string | null;
1289
+ /**
1290
+ * The line alignment (`spPr/a:ln/@algn`) as the raw OOXML token — `'ctr'`
1291
+ * (centred on the shape's outline) or `'in'` (inset, drawn wholly inside it) —
1292
+ * or `null` when unset. It shifts a thick outline by half its width, so it
1293
+ * changes where the border sits relative to the fill.
1294
+ */
1295
+ get lineAlign(): string | null;
1181
1296
  /**
1182
1297
  * Preset geometry name (`spPr/a:prstGeom/@prst`, e.g. `rect`), or `null` for
1183
1298
  * custom geometry or none. Not an auto-shape-only property: PowerPoint gives a
@@ -1329,7 +1444,7 @@ declare abstract class Shape {
1329
1444
  //#region src/read/api/shapes/autoshape.d.ts
1330
1445
  /** An auto shape, text box, or placeholder (`p:sp`). The only kind that holds text. */
1331
1446
  declare class AutoShape extends Shape {
1332
- readonly shapeType: "autoShape";
1447
+ readonly shapeType: 'autoShape';
1333
1448
  protected xfrm(): Element | null;
1334
1449
  protected getOrAddXfrm(): Element;
1335
1450
  get hasTextFrame(): boolean;
@@ -1355,7 +1470,7 @@ declare class AutoShape extends Shape {
1355
1470
  /** A picture (`p:pic`). */
1356
1471
  declare class Picture extends Shape {
1357
1472
  #private;
1358
- readonly shapeType: "picture";
1473
+ readonly shapeType: 'picture';
1359
1474
  protected xfrm(): Element | null;
1360
1475
  protected getOrAddXfrm(): Element;
1361
1476
  protected get supportsFill(): boolean;
@@ -1467,7 +1582,7 @@ declare class Picture extends Shape {
1467
1582
  /** A connector / line (`p:cxnSp`). */
1468
1583
  declare class Connector extends Shape {
1469
1584
  #private;
1470
- readonly shapeType: "connector";
1585
+ readonly shapeType: 'connector';
1471
1586
  protected xfrm(): Element | null;
1472
1587
  protected getOrAddXfrm(): Element;
1473
1588
  /**
@@ -1809,12 +1924,12 @@ declare class ChartExAxis {
1809
1924
  //#region src/read/api/table-edit.d.ts
1810
1925
  /** The four edges plus the two diagonals, keyed as {@link TableCellEdge} names them. */
1811
1926
  declare const EDGE_QNAMES: {
1812
- readonly left: "a:lnL";
1813
- readonly right: "a:lnR";
1814
- readonly top: "a:lnT";
1815
- readonly bottom: "a:lnB";
1816
- readonly tlToBr: "a:lnTlToBr";
1817
- readonly blToTr: "a:lnBlToTr";
1927
+ readonly left: 'a:lnL';
1928
+ readonly right: 'a:lnR';
1929
+ readonly top: 'a:lnT';
1930
+ readonly bottom: 'a:lnB';
1931
+ readonly tlToBr: 'a:lnTlToBr';
1932
+ readonly blToTr: 'a:lnBlToTr';
1818
1933
  };
1819
1934
  /** Which border of a cell an edit addresses. */
1820
1935
  type TableCellEdge = keyof typeof EDGE_QNAMES;
@@ -1882,7 +1997,7 @@ interface TableCellStyleContext {
1882
1997
  flags: TableConditionFlags;
1883
1998
  rowCount: number;
1884
1999
  colCount: number;
1885
- ctx: FlattenContext;
2000
+ ctx: ThemeContext;
1886
2001
  }
1887
2002
  /**
1888
2003
  * One edge border of a table cell (`a:tcPr/a:lnL|lnR|lnT|lnB|lnTlToBr|lnBlToTr`).
@@ -1953,7 +2068,7 @@ declare class Table {
1953
2068
  private readonly rels?;
1954
2069
  constructor(tbl: Element, part: Part,
1955
2070
  /** The owning slide's theme colour context, threaded to each cell's text for `Run.resolvedColor`. */
1956
- themeColors?: FlattenContext | undefined,
2071
+ themeColors?: ThemeContext | undefined,
1957
2072
  /** The deck package, for resolving `a:tableStyleId` against `tableStyles.xml` (style-graph cell fills). */
1958
2073
  opc?: OpcPackage | undefined,
1959
2074
  /** The owning slide's relationships, for resolving a cell picture fill's `r:embed` to a partname. */
@@ -2107,9 +2222,9 @@ declare class TableRow {
2107
2222
  private readonly rels?;
2108
2223
  constructor(tr: Element, part: Part,
2109
2224
  /** The owning slide's theme colour context, threaded to each {@link TableCell}. */
2110
- themeColors?: FlattenContext | undefined,
2225
+ themeColors?: ThemeContext | undefined,
2111
2226
  /** The table's style-resolution context, threaded to each cell for {@link TableCell.resolvedFill}. */
2112
- style?: (TableCellStyleContext | null) | undefined,
2227
+ style?: TableCellStyleContext | null | undefined,
2113
2228
  /** This row's zero-based index in the table, for style-graph banding/edge conditions. */
2114
2229
  rowIndex?: number,
2115
2230
  /** The owning slide's relationships, threaded to each cell for {@link TableCell.pictureFill}. */
@@ -2140,9 +2255,9 @@ declare class TableCell {
2140
2255
  private readonly rels?;
2141
2256
  constructor(tc: Element, part: Part,
2142
2257
  /** The owning slide's theme colour context, threaded to the cell's text for `Run.resolvedColor`. */
2143
- themeColors?: FlattenContext | undefined,
2258
+ themeColors?: ThemeContext | undefined,
2144
2259
  /** The table's style-resolution context, for the {@link resolvedFill} style-graph fallback. */
2145
- style?: (TableCellStyleContext | null) | undefined,
2260
+ style?: TableCellStyleContext | null | undefined,
2146
2261
  /** This cell's zero-based row index in the table. */
2147
2262
  rowIndex?: number,
2148
2263
  /** This cell's zero-based column index in its row. */
@@ -2269,6 +2384,24 @@ declare class TableCell {
2269
2384
  * `a:tcPr` is empty or absent, whatever the style graph would render it as.
2270
2385
  */
2271
2386
  get hasOwnFill(): boolean;
2387
+ /**
2388
+ * `true` when the cell sets an explicit no-fill (`a:tcPr/a:noFill`) — a deliberately
2389
+ * transparent cell showing the table background (or the slide) through. The cell-side
2390
+ * counterpart of {@link import('./shapes.js').AutoShape.fillNoFill}, and what
2391
+ * {@link noFill} writes.
2392
+ *
2393
+ * {@link hasOwnFill} is not this question: it is `true` for *any* `EG_FillProperties`
2394
+ * child, so on its own it cannot separate a suppressed fill from a gradient or an image
2395
+ * one — and every colour accessor ({@link resolvedFill}, {@link fillColor},
2396
+ * {@link fillSchemeColor}) reports `null` for a no-fill cell exactly as it does for a
2397
+ * cell that inherits its shading from the table style. Deriving it as "has a fill of its
2398
+ * own, and no accessor recognises it" instead of reading it has two failure modes: it
2399
+ * folds `a:grpFill` in with `a:noFill`, and its meaning changes silently the day a
2400
+ * further fill kind gets an accessor. The two paint completely differently — an
2401
+ * inherited banding colour versus nothing at all — so a consumer that cannot tell them
2402
+ * apart paints a transparent cell in the style's shading.
2403
+ */
2404
+ get fillNoFill(): boolean;
2272
2405
  /**
2273
2406
  * The cell's picture (image) fill (`a:tcPr/a:blipFill`), or `null` when the cell
2274
2407
  * is not image-filled. The cell counterpart of
@@ -2390,7 +2523,7 @@ declare class TableCell {
2390
2523
  /** A graphic frame (`p:graphicFrame`) — host for tables and charts. */
2391
2524
  declare class GraphicFrame extends Shape {
2392
2525
  #private;
2393
- readonly shapeType: "graphicFrame";
2526
+ readonly shapeType: 'graphicFrame';
2394
2527
  protected xfrm(): Element | null;
2395
2528
  protected getOrAddXfrm(): Element;
2396
2529
  protected getOrAddProperties(): ShapeProperties;
@@ -2422,11 +2555,25 @@ declare class GraphicFrame extends Shape {
2422
2555
  */
2423
2556
  declare class GroupShape extends Shape {
2424
2557
  #private;
2425
- readonly shapeType: "group";
2558
+ readonly shapeType: 'group';
2426
2559
  protected xfrm(): Element | null;
2427
2560
  protected getOrAddXfrm(): Element;
2428
2561
  protected properties(): Element | null;
2429
2562
  protected getOrAddProperties(): ShapeProperties;
2563
+ /**
2564
+ * The group's own child coordinate space (`p:grpSpPr/a:xfrm/a:chOff` and
2565
+ * `a:chExt`) in EMU, or `null` when the group has no transform or either
2566
+ * element is incomplete.
2567
+ *
2568
+ * Most consumers should not need this: {@link Shape.absoluteFrame} already
2569
+ * composes the whole ancestor chain — child space, group flips and rotations —
2570
+ * and doing that arithmetic per consumer is how a shape in a nested group ends
2571
+ * up subtly displaced. It is here for a *replica* consumer rather than a
2572
+ * *paint* one: rebuilding this group and its children as OOXML needs the
2573
+ * source child space to reproduce the scaling, and without it only groups whose
2574
+ * child space is the identity can be rebuilt.
2575
+ */
2576
+ get childFrame(): ChildFrame | null;
2430
2577
  /** The shapes nested directly inside this group, in document order. */
2431
2578
  get shapes(): AnyShape[];
2432
2579
  }
@@ -2470,7 +2617,7 @@ declare class NotesPlaceholder {
2470
2617
  private readonly relationships;
2471
2618
  constructor(sp: Element, part: Part,
2472
2619
  /** The notes theme context (notesMaster → `theme2.xml`), threaded to {@link textFrame}. */
2473
- themeContext: FlattenContext,
2620
+ themeContext: ThemeContext,
2474
2621
  /** The notes part's relationships, threaded to {@link textFrame} for hyperlink resolution. */
2475
2622
  relationships: Relationships);
2476
2623
  /** Placeholder type (`p:ph/@type`: `sldImg` | `body` | `sldNum`), or `null` when absent. */
@@ -2526,7 +2673,7 @@ declare class NotesSlide {
2526
2673
  * The notes theme context, resolved through the notesMaster → `theme2.xml` chain
2527
2674
  * and cached. Backs {@link NotesPlaceholder.textFrame}'s `Run.resolvedColor`.
2528
2675
  */
2529
- themeContext(): FlattenContext;
2676
+ themeContext(): ThemeContext;
2530
2677
  /** The placeholders (`p:sp`) in the notes shape tree, in document order. */
2531
2678
  get placeholders(): NotesPlaceholder[];
2532
2679
  /** The notes body placeholder (`p:ph type="body"`), or `null` when the notes slide has none. */
@@ -2708,7 +2855,7 @@ declare class Placeholder {
2708
2855
  private readonly relationships;
2709
2856
  constructor(sp: Element, part: Part,
2710
2857
  /** The owning master/layout theme context, threaded to {@link textFrame}. */
2711
- themeContext: FlattenContext,
2858
+ themeContext: ThemeContext,
2712
2859
  /** The owning part's relationships, threaded to {@link textFrame} for hyperlink resolution. */
2713
2860
  relationships: Relationships);
2714
2861
  /** Placeholder type (`p:ph/@type`: `title` | `body` | `sldNum` | …), or `null` when absent (a body placeholder). */
@@ -2780,7 +2927,7 @@ declare class SlideMaster {
2780
2927
  * The master's colour/font context (its `p:clrMap` + theme), resolved once and
2781
2928
  * cached. Backs each {@link Placeholder}'s text frame.
2782
2929
  */
2783
- themeContext(): FlattenContext;
2930
+ themeContext(): ThemeContext;
2784
2931
  }
2785
2932
  /**
2786
2933
  * A deck's slide layout (`slideLayoutN.xml`) as a modeled object — the gallery entry
@@ -2824,7 +2971,7 @@ declare class SlideLayout {
2824
2971
  * The layout's colour/font context (walked layout → master → theme), resolved once
2825
2972
  * and cached. Backs each {@link Placeholder}'s text frame.
2826
2973
  */
2827
- themeContext(): FlattenContext;
2974
+ themeContext(): ThemeContext;
2828
2975
  }
2829
2976
  //#endregion
2830
2977
  //#region src/read/api/transition.d.ts
@@ -2953,7 +3100,7 @@ declare class Slide {
2953
3100
  * font token included) resolves to a literal value. The maps/roots are empty when
2954
3101
  * the theme chain is incomplete, in which case tokens simply stay unresolved.
2955
3102
  */
2956
- themeContext(): FlattenContext;
3103
+ themeContext(): ThemeContext;
2957
3104
  /** Authoring name of the slide (`p:cSld/@name`), or `null` if unnamed. */
2958
3105
  get name(): string | null;
2959
3106
  /**
@@ -3543,5 +3690,5 @@ declare class Presentation {
3543
3690
  save(): Promise<Uint8Array>;
3544
3691
  }
3545
3692
  //#endregion
3546
- export { Chart as $, GroupShape as A, Run as At, Table as B, GradientStop as Bt, CommentAuthor as C, ShapeType as Ct, NotesPlaceholder as D, BodyProperties as Dt, ModernCommentAuthor as E, AutofitMode as Et, isPicture as F, SlideBackground as Ft, TableConditionFlags as G, TableCellBorderEdit as H, resolveColorElement as Ht, GraphicFrame as I, FillRect as It, ChartExAxis as J, TableCellEdge as K, CellBorder as L, PictureFill as Lt, isConnector as M, TextFrame as Mt, isGraphicFrame as N, BackgroundFill as Nt, NotesSlide as O, LineSpacing as Ot, isGroupShape as P, BackgroundSource as Pt, AxisNumberFormat as Q, CellBorders as R, PictureFillTile as Rt, Comment as S, Reflection as St, ModernComment as T, PatternFill as Tt, TableRow as U, ColorContext as Ut, TableCell as V, ResolvedColor as Vt, ResolvedTableStyle as W, ChartExLegend as X, ChartExDataLabels as Y, ChartExSeries as Z, ThemeColorSlot as _, LineEnd as _t, readCustomProperties as a, ChartSeries as at, Tag as b, Recolor as bt, Slide as c, AutoShape as ct, TransitionSpeed as d, ConnectionSite as dt, ChartAxis as et, ColorMapToken as f, CustomGeometry as ft, Theme as g, InnerShadow as gt, SlideMaster as h, Glow as ht, readCoreProperties as i, ChartLine as it, isAutoShape as j, RunHyperlink as jt, AnyShape as k, Paragraph as kt, TransitionInfo as l, Shape as lt, SlideLayout as m, GeometryCommand as mt, CoreProperties as n, ChartFill as nt, AddPictureOptions as o, Connector as ot, Placeholder as p, CustomGeometryPath as pt, ChartEx as q, CustomProperty as r, ChartLegend as rt, AddTextBoxOptions as s, Picture as st, Presentation as t, ChartDataLabels as tt, TransitionInput as u, AbsoluteFrame as ut, ThemeFontFace as v, LineEnds as vt, CommentSchema as w, SoftEdge as wt, readTagsForPart as x, RecolorColor as xt, ThemeFontScheme as y, OuterShadow as yt, CellThreeD as z, GradientFill as zt };
3547
- //# sourceMappingURL=presentation-CVaTZw1V.d.ts.map
3693
+ export { Chart as $, GroupShape as A, Recolor as At, Table as B, PictureFill as Bt, CommentAuthor as C, CustomGeometryPath as Ct, NotesPlaceholder as D, LineEnd as Dt, ModernCommentAuthor as E, InnerShadow as Et, isPicture as F, PatternFill as Ft, TableConditionFlags as G, resolveColorElement as Gt, TableCellBorderEdit as H, GradientFill as Ht, GraphicFrame as I, BackgroundFill as It, ChartExAxis as J, TableCellEdge as K, ColorContext as Kt, CellBorder as L, BackgroundSource as Lt, isConnector as M, Reflection as Mt, isGraphicFrame as N, ShapeType as Nt, NotesSlide as O, LineEnds as Ot, isGroupShape as P, SoftEdge as Pt, AxisNumberFormat as Q, CellBorders as R, SlideBackground as Rt, Comment as S, CustomGeometry as St, ModernComment as T, Glow as Tt, TableRow as U, GradientStop as Ut, TableCell as V, PictureFillTile as Vt, ResolvedTableStyle as W, ResolvedColor as Wt, ChartExLegend as X, ChartExDataLabels as Y, ChartExSeries as Z, ThemeColorSlot as _, RunHyperlink as _t, readCustomProperties as a, ChartSeries as at, Tag as b, ChildFrame as bt, Slide as c, AutoShape as ct, TransitionSpeed as d, BodyProperties as dt, ChartAxis as et, ColorMapToken as f, BulletDetail as ft, Theme as g, Run as gt, SlideMaster as h, Paragraph as ht, readCoreProperties as i, ChartLine as it, isAutoShape as j, RecolorColor as jt, AnyShape as k, OuterShadow as kt, TransitionInfo as l, Shape as lt, SlideLayout as m, LineSpacing as mt, CoreProperties as n, ChartFill as nt, AddPictureOptions as o, Connector as ot, Placeholder as p, BulletStyle as pt, ChartEx as q, CustomProperty as r, ChartLegend as rt, AddTextBoxOptions as s, Picture as st, Presentation as t, ChartDataLabels as tt, TransitionInput as u, AutofitMode as ut, ThemeFontFace as v, TextFrame as vt, CommentSchema as w, GeometryCommand as wt, readTagsForPart as x, ConnectionSite as xt, ThemeFontScheme as y, AbsoluteFrame as yt, CellThreeD as z, FillRect as zt };
3694
+ //# sourceMappingURL=presentation-DyIRDKkp.d.ts.map