pptx-kit 0.0.0 → 0.3.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.
- package/CHANGELOG.md +1657 -0
- package/LICENSE +21 -0
- package/README.md +405 -3
- package/dist/index.d.ts +5118 -0
- package/dist/index.js +13377 -0
- package/dist/index.js.map +1 -0
- package/dist/node.d.ts +14 -0
- package/dist/node.js +13389 -0
- package/dist/node.js.map +1 -0
- package/package.json +75 -5
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,1657 @@
|
|
|
1
|
+
# pptx-kit
|
|
2
|
+
|
|
3
|
+
## 0.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 3459aa5: `createPresentation()` now returns an immediately-authorable deck
|
|
8
|
+
|
|
9
|
+
Previously `createPresentation()` returned an OPC package with only the OPC
|
|
10
|
+
defaults — no slide master, layouts, theme, or slide size — so
|
|
11
|
+
`getSlideLayouts()` came back empty and `addSlide({ layout })` was
|
|
12
|
+
impossible. From-scratch authoring (a headline feature in the README) did
|
|
13
|
+
not actually work without loading a template file.
|
|
14
|
+
|
|
15
|
+
`createPresentation()` now ships a slide master, the Office theme, and three
|
|
16
|
+
layouts — `Blank`, `Title Slide`, and `Title and Content` — so you can go
|
|
17
|
+
straight to `addSlide` / `addTitleSlide` / `addContentSlide` and `savePresentation`.
|
|
18
|
+
Every emitted part is validated against the ECMA-376 XSDs in CI. The slide
|
|
19
|
+
size defaults to 16:9 and is selectable: `createPresentation({ size: '4:3' })`.
|
|
20
|
+
|
|
21
|
+
Also in this release (input-validation hardening at the authoring boundary):
|
|
22
|
+
|
|
23
|
+
- `addSlideChart` now rejects a series `color` (and `pointColors` /
|
|
24
|
+
`trendline.color` / plot- and chart-area fills / axis & gridline colors)
|
|
25
|
+
that isn't an sRGB hex (`#RRGGBB` or `RRGGBB`) with a clear error, instead
|
|
26
|
+
of silently emitting an invalid `<a:srgbClr val="…"/>` that PowerPoint
|
|
27
|
+
dropped or repaired. Bare `RRGGBB` (no `#`) is accepted and normalized;
|
|
28
|
+
scheme tokens like `accent1` are correctly rejected, since charts emit
|
|
29
|
+
`srgbClr`.
|
|
30
|
+
- `addSlideTable` with empty `rows: []` (or a row with no cells) now throws
|
|
31
|
+
an actionable `addSlideTable: …` error at the boundary rather than
|
|
32
|
+
producing a grid-less `<a:tbl>` that triggers PowerPoint's repair dialog.
|
|
33
|
+
(The error message previously named the old internal `addTable` path.)
|
|
34
|
+
- `findSlideLayout`'s case-sensitive, locale-dependent name matching is now
|
|
35
|
+
documented in its JSDoc and the README, pointing readers to the
|
|
36
|
+
locale-stable `findSlideLayoutByType` and to `RegExp`/`i` for
|
|
37
|
+
case-insensitive name lookups. No behavior change.
|
|
38
|
+
|
|
39
|
+
No breaking changes. `createPresentation()` keeps its zero-argument call
|
|
40
|
+
signature; the new `{ size }` options object is optional.
|
|
41
|
+
|
|
42
|
+
## 0.2.0
|
|
43
|
+
|
|
44
|
+
### Minor Changes
|
|
45
|
+
|
|
46
|
+
- b03e0cb: feat: fidelity calibration sweep — measured against LibreOffice ground truth,
|
|
47
|
+
mean fg-SSIM rose from ≈0.66 to ≈0.78 (≈0.81 excluding documented
|
|
48
|
+
divergences). Body placeholders now inherit the master `bodyStyle` bullet and
|
|
49
|
+
hanging indent through the paragraph cascade (new `bullet` field on
|
|
50
|
+
`ParagraphProperties` from `getParagraphPropertiesEffective`); charts no
|
|
51
|
+
longer invent a legend when the XML authors no `<c:legend>`, and the value
|
|
52
|
+
axis gets Excel-style headroom above the data max with the tick step
|
|
53
|
+
preserved; the chart builder writes `<c:smooth val="0"/>` explicitly on line
|
|
54
|
+
series (the schema default for an absent element is smooth=1, which made
|
|
55
|
+
LibreOffice draw unauthored lines as curves); and the pure-SVG text layer is
|
|
56
|
+
nudged 0.75px left to land on LibreOffice's pixel grid.
|
|
57
|
+
|
|
58
|
+
## 0.1.0
|
|
59
|
+
|
|
60
|
+
### Minor Changes
|
|
61
|
+
|
|
62
|
+
- 263bf52: feat: `getShapeAdjustValues(shape)` returns the `<a:prstGeom><a:avLst>
|
|
63
|
+
<a:gd name=… fmla="val N"/></a:avLst>` map (preset adjust-handle
|
|
64
|
+
values). Only literal `val` formulas are surfaced; computed formulas
|
|
65
|
+
(`pin`, `+-`, etc.) reference the preset's built-in guides and
|
|
66
|
+
aren't useful without them.
|
|
67
|
+
|
|
68
|
+
Playground reads `adj` on `roundRect` to project the authored corner
|
|
69
|
+
radius — previously every rounded rectangle painted at a hard-coded
|
|
70
|
+
18%. Other presets (callouts, arrows, etc.) can adopt the same getter
|
|
71
|
+
as their renderers grow.
|
|
72
|
+
|
|
73
|
+
- a944352: feat(site/playground): render auto-numbered bullets. Paragraphs with
|
|
74
|
+
`bulletStyle === 'number'` or `{ autoNum: '…' }` now emit the next
|
|
75
|
+
number in sequence (1., 2., 3., …; A., B., C., …; i., ii., iii., …)
|
|
76
|
+
rather than a generic dot. Counter resets on a non-numbered paragraph
|
|
77
|
+
or a level change, matching PowerPoint's behaviour.
|
|
78
|
+
|
|
79
|
+
Covers the common `ST_TextAutoNumberScheme` tokens — arabicPeriod /
|
|
80
|
+
ParenR / ParenBoth, romanUc / Lc with Period / ParenR / ParenBoth,
|
|
81
|
+
alphaUc / Lc with Period / ParenR / ParenBoth.
|
|
82
|
+
|
|
83
|
+
- 63c4453: feat: chart axis _tick labels_ honor authored `<c:txPr>` font / color.
|
|
84
|
+
`ChartSpec.categoryAxisLabelStyle` and `valueAxisLabelStyle` carry the
|
|
85
|
+
font / color extracted from `<c:catAx><c:txPr>` and `<c:valAx><c:txPr>`.
|
|
86
|
+
A shared `axisTickAttrs` helper composes the SVG `font-*` / `fill`
|
|
87
|
+
attributes; the value-axis renderer and category-axis renderer both
|
|
88
|
+
project it onto every tick label.
|
|
89
|
+
- e60dc26: feat: chart value-axis tick marks. `ChartSpec.valueAxisMajorTickMark`
|
|
90
|
+
and `categoryAxisMajorTickMark` carry `<c:majorTickMark val="in|out|
|
|
91
|
+
cross|none"/>`. The playground value-axis renderer draws short stubs
|
|
92
|
+
on the appropriate side of the plot edge (default `out` matches
|
|
93
|
+
PowerPoint's stock look); `none` suppresses them entirely.
|
|
94
|
+
- 3a2b974: feat: chart axis titles honor authored `<a:rPr>` font / color.
|
|
95
|
+
`ChartSpec.categoryAxisTitleStyle` and `valueAxisTitleStyle` carry the
|
|
96
|
+
same `ChartTextStyle` shape as `titleStyle`. The playground renderer
|
|
97
|
+
projects size / bold / italic / fill onto both axis title labels,
|
|
98
|
+
sharing the helper that drives the chart title.
|
|
99
|
+
- b8c676d: feat(site/playground): bar chart category-axis labels honor
|
|
100
|
+
`categoryAxisLabelRotationDeg`. The horizontal-value renderer used
|
|
101
|
+
the rotation field only for column charts (categories along the
|
|
102
|
+
x-axis); now the bar variant (categories down the y-axis) also
|
|
103
|
+
rotates each label around its anchor and widens its ellipsis budget
|
|
104
|
+
for tilted labels.
|
|
105
|
+
- 0b61a96: feat(site/playground): apply the 3-level gradient bg cascade. When
|
|
106
|
+
the slide reports `'gradient'` but doesn't author the actual stops,
|
|
107
|
+
the renderer walks slide → layout → master gradient-fill readers
|
|
108
|
+
to find the inherited gradient definition.
|
|
109
|
+
- 2896447: feat: `getSlideLayoutBackgroundImageBytes(pres, layout)` and
|
|
110
|
+
`getSlideMasterBackgroundImageBytes(pres, layout)` complete the
|
|
111
|
+
picture-background cascade. The slide reader already returned bytes
|
|
112
|
+
for slide-level `<a:blipFill>` backgrounds; the new readers resolve
|
|
113
|
+
the same shape on layouts and masters via their own rel lists. The
|
|
114
|
+
playground renderer threads slide → layout → master fallback, so
|
|
115
|
+
template-defined photo backgrounds finally show on inheriting slides.
|
|
116
|
+
- 8a4dafb: feat(site/playground): apply the 3-level pattern bg cascade. When the
|
|
117
|
+
slide reports `'pattern'` but doesn't author the actual pattern preset,
|
|
118
|
+
the renderer now walks slide → layout → master pattern-fill readers,
|
|
119
|
+
paralleling the gradient cascade.
|
|
120
|
+
- 4b1fd76: feat: `getSlideLayoutBackgroundPatternFill(pres, layout)` and
|
|
121
|
+
`getSlideMasterBackgroundPatternFill(pres, layout)` complete the
|
|
122
|
+
pattern-background cascade. Slides reporting `'pattern'` can now
|
|
123
|
+
resolve the actual preset / colors by walking slide → layout →
|
|
124
|
+
master, paralleling the gradient / solid / blip cascades.
|
|
125
|
+
- 63dee61: feat: `getShapeBodyPrEffective(pres, shape)` — `<a:bodyPr>` cascade
|
|
126
|
+
covering anchor, wrap, vertical-text direction, and inset margins.
|
|
127
|
+
Walks shape → layout placeholder → master placeholder bodyPr the same
|
|
128
|
+
way the rPr / pPr cascades do. Playground uses it so placeholders
|
|
129
|
+
inherit text alignment / margins from the layout / master without
|
|
130
|
+
each slide having to re-author them.
|
|
131
|
+
- 36bd14d: feat(site/playground): shape text honors `<a:bodyPr wrap="none"/>`.
|
|
132
|
+
The reader's effective wrap value was already threaded through; the
|
|
133
|
+
renderer now emits `white-space:nowrap` when wrap is `'none'`,
|
|
134
|
+
keeping single-line text frames (vertical labels, breadcrumbs,
|
|
135
|
+
fixed-width badges) from wrapping into multiple lines.
|
|
136
|
+
- e31b414: feat(site/playground): paragraphs with image bullets (`<a:pPr><a:buBlip>`)
|
|
137
|
+
render a filled-square glyph (■) instead of inheriting the default
|
|
138
|
+
round bullet. The reader already exposed `isParagraphBulletPicture`;
|
|
139
|
+
the playground now threads it through paragraph metadata so the
|
|
140
|
+
visual cue lands.
|
|
141
|
+
- e30c9f3: feat: `isParagraphBulletPicture(shape, p)` returns `true` when the
|
|
142
|
+
paragraph uses an image as its bullet (`<a:pPr><a:buBlip>`).
|
|
143
|
+
Renderers without image-bullet support can fall back to a generic
|
|
144
|
+
glyph; UIs that want to indicate the bullet is custom have a clean
|
|
145
|
+
yes/no signal.
|
|
146
|
+
- 263bf52: feat: `getParagraphBulletStyle(pres, shape, p)` returns the
|
|
147
|
+
paragraph-level bullet overrides — color (theme-resolved), percent
|
|
148
|
+
size, fixed-point size, font face — from `<a:buClr>` / `<a:buSzPct>`
|
|
149
|
+
/ `<a:buSzPts>` / `<a:buFont>`. Playground projects each onto the
|
|
150
|
+
bullet `<span>`, so decks that style bullets in an accent color or
|
|
151
|
+
sized-up font (a common branding move) render correctly instead of
|
|
152
|
+
falling back to the body's color.
|
|
153
|
+
- b53b420: feat: chart category-axis tick labels honor `<a:bodyPr rot="N"/>`.
|
|
154
|
+
`ChartSpec.categoryAxisLabelRotationDeg` carries the authored rotation
|
|
155
|
+
(converted from OOXML's 60000ths-of-a-degree to plain degrees). The
|
|
156
|
+
playground renderer rotates each tick label around its anchor and
|
|
157
|
+
shifts the text-anchor side based on the sign of the rotation so dense
|
|
158
|
+
charts with 45°/-45°/90° rotated labels render the way PowerPoint
|
|
159
|
+
shows them. Rotated labels also get a longer truncation budget before
|
|
160
|
+
ellipsization.
|
|
161
|
+
- 4f5cc4c: feat: round out gridline color round-trip with 3 more fields —
|
|
162
|
+
`valueAxisMinorGridlineColor`, `categoryAxisMajorGridlineColor`, and
|
|
163
|
+
`categoryAxisMinorGridlineColor`. Previously only the value-axis major
|
|
164
|
+
color was carried. All four now share a new chart-builder
|
|
165
|
+
`gridlinesElement(local, color?)` helper and a chart-reader
|
|
166
|
+
`readGridlineColor(gl)` helper; the existing major-gridline color
|
|
167
|
+
inline parse was replaced with a call to the shared reader for
|
|
168
|
+
consistency.
|
|
169
|
+
- 9fba547: feat(chart): `ChartSpec.chartAreaFill` and `plotAreaFill` read
|
|
170
|
+
`<c:chartSpace><c:spPr><a:solidFill>` and `<c:plotArea><c:spPr>
|
|
171
|
+
<a:solidFill>`. Playground paints the chart-area backdrop in the
|
|
172
|
+
authored color (replacing the hard-coded white) and adds a tinted
|
|
173
|
+
rect behind the plot area when `plotAreaFill` is authored. Common
|
|
174
|
+
on branded dashboards that paint a subtle background behind the
|
|
175
|
+
chart bars.
|
|
176
|
+
- 9d79d53: feat: chart-area / plot-area authored outline strokes.
|
|
177
|
+
`ChartSpec.chartAreaStrokeColor` reads `<c:chartSpace><c:spPr><a:ln>`;
|
|
178
|
+
`ChartSpec.plotAreaStrokeColor` reads `<c:plotArea><c:spPr><a:ln>`.
|
|
179
|
+
The playground renderer projects them onto the chart-area card
|
|
180
|
+
border and the plot-area inner rect — branded charts with thick / no
|
|
181
|
+
/ colored card borders finally render the way PowerPoint shows them.
|
|
182
|
+
- eb4159e: feat(chart): `ChartSpec.valueAxisHidden` and `categoryAxisHidden`
|
|
183
|
+
read `<c:valAx><c:delete val="1"/>` and `<c:catAx><c:delete val="1"/>`.
|
|
184
|
+
Playground skips rendering the axis when hidden — common on KPI tile
|
|
185
|
+
charts that show just the data points without axis labels.
|
|
186
|
+
- 2710f56: feat: `ChartSpec.categoryAxisLineColor` and `valueAxisLineColor` —
|
|
187
|
+
authored stroke color on the axis line itself
|
|
188
|
+
(`<c:catAx|valAx><c:spPr><a:ln><a:solidFill><a:srgbClr val=…/>`).
|
|
189
|
+
`undefined` falls back to the renderer's default. Read by chart-reader,
|
|
190
|
+
written by chart-builder in the correct CT_CatAx / CT_ValAx schema
|
|
191
|
+
order (after the tick-mark elements, before `<c:txPr>`).
|
|
192
|
+
- c5761f4: feat(chart): `ChartSpec.categoryAxisOrientation` and
|
|
193
|
+
`valueAxisOrientation` read `<c:catAx>/<c:valAx><c:scaling>
|
|
194
|
+
<c:orientation val="minMax|maxMin"/>`. Tools and renderers that
|
|
195
|
+
care about category render order (typically bar charts emit
|
|
196
|
+
`maxMin` so the first category sits at the top) can act on these
|
|
197
|
+
without dropping to XML.
|
|
198
|
+
- 45e889d: feat: `ChartSpec.valueAxis` reports the authored
|
|
199
|
+
`<c:valAx><c:scaling>` min / max. Playground respects them when
|
|
200
|
+
computing axis ranges, so charts with a fixed authored scale (e.g.
|
|
201
|
+
percentage charts pinned to 0..100) render with the same scale the
|
|
202
|
+
deck author saw instead of auto-fitting to the data.
|
|
203
|
+
|
|
204
|
+
Adds the `ChartAxisScaling` interface to the public type surface.
|
|
205
|
+
|
|
206
|
+
- 6dd7281: feat: `ChartSpec.categoryAxisTitleRotationDeg` and
|
|
207
|
+
`ChartSpec.valueAxisTitleRotationDeg` — rotation in plain degrees
|
|
208
|
+
(clockwise) on the per-axis title. Maps to
|
|
209
|
+
`<c:catAx|valAx><c:title><c:tx><c:rich><a:bodyPr rot="N"/>` (60000ths
|
|
210
|
+
of a degree on the wire). PowerPoint often emits `-90` on the value-
|
|
211
|
+
axis title; the field now survives round-trip. Read by chart-reader
|
|
212
|
+
via a new `readTitleRotationDeg` helper; written by chart-builder
|
|
213
|
+
through an extended `titleElement(title, style?, rotationDeg?)`
|
|
214
|
+
signature.
|
|
215
|
+
- 2bf32ca: feat(chart): `ChartSpec.categoryAxisTitle` and `valueAxisTitle` read
|
|
216
|
+
the per-axis `<c:title>` rich text on `<c:catAx>` (or `<c:dateAx>` /
|
|
217
|
+
`<c:serAx>`) and `<c:valAx>`. Playground paints the value-axis title
|
|
218
|
+
rotated -90° along the y-axis and the category-axis title centered
|
|
219
|
+
below the x-axis.
|
|
220
|
+
- db36287: feat: chart builder writes back plot-area / chart-area fill + stroke
|
|
221
|
+
colors. A new `spPrChildren(fill, stroke)` helper emits
|
|
222
|
+
`<c:spPr><a:solidFill><a:srgbClr/></a:solidFill><a:ln>…</a:ln>`. The
|
|
223
|
+
builder appends it under `<c:plotArea>` when `plotAreaFill` or
|
|
224
|
+
`plotAreaStrokeColor` is set, and under `<c:chartSpace>` (root) when
|
|
225
|
+
`chartAreaFill` or `chartAreaStrokeColor` is set. Round-trip test
|
|
226
|
+
verifies all four survive.
|
|
227
|
+
- 02434bb: feat: chart builder writes back value-axis extras and tick marks.
|
|
228
|
+
`<c:valAx>` now emits `<c:scaling><c:logBase>`, `<c:majorTickMark>`,
|
|
229
|
+
and `<c:dispUnits><c:builtInUnit>` when authored on `ChartSpec`;
|
|
230
|
+
`<c:catAx>` emits `<c:majorTickMark>`. Round-tripping a chart with
|
|
231
|
+
these fields no longer drops them. Covered by a new round-trip test
|
|
232
|
+
in `fn-chart-readback`.
|
|
233
|
+
- 0afa65b: feat: chart builder writes back full value-axis scaling. `<c:valAx>`
|
|
234
|
+
now emits `<c:scaling><c:min/>/<c:max/>`, `<c:numFmt formatCode>`,
|
|
235
|
+
`<c:majorUnit>`, and `<c:minorUnit>` when authored — completing the
|
|
236
|
+
read/write parity for `ChartSpec.valueAxis`. Round-trip test added.
|
|
237
|
+
- 7bee159: feat: chart builder writes back axis titles, hidden flags, and
|
|
238
|
+
category-axis tick-label config. `<c:valAx>` / `<c:catAx>` now emit:
|
|
239
|
+
|
|
240
|
+
- `<c:title>` with style (from `valueAxisTitleStyle` /
|
|
241
|
+
`categoryAxisTitleStyle`) when an axis title is authored
|
|
242
|
+
- `<c:delete val="1"/>` when `valueAxisHidden` / `categoryAxisHidden`
|
|
243
|
+
- `<c:tickLblPos>` and `<c:tickLblSkip>` when authored on the
|
|
244
|
+
category axis
|
|
245
|
+
|
|
246
|
+
Closes the read/write gap for these `ChartSpec` fields. Round-trip
|
|
247
|
+
test added.
|
|
248
|
+
|
|
249
|
+
- bddd838: feat: chart builder writes back chart-level data-label config. A new
|
|
250
|
+
`dLblsElement` helper builds `<c:dLbls>` with `showVal` / `showCatName`
|
|
251
|
+
/ `showSerName` / `showPercent` toggles plus optional `<c:numFmt>`,
|
|
252
|
+
`<c:dLblPos>`, and `<c:separator>`. Wired into every chart variant
|
|
253
|
+
(bar / column / line / pie / doughnut / area), so round-tripping a
|
|
254
|
+
chart with authored data labels preserves them.
|
|
255
|
+
- 3f6f848: feat: chart builder writes back per-data-point `<c:dPt>` overrides.
|
|
256
|
+
New `dPtElements(colors, explosions)` helper emits sparse
|
|
257
|
+
`<c:dPt><c:idx><c:bubble3D val="0"/>[<c:explosion>]
|
|
258
|
+
[<c:spPr><a:solidFill><a:srgbClr/>]</c:dPt>` entries from
|
|
259
|
+
`ChartSeries.pointColors` and `ChartSeries.pointExplosions`.
|
|
260
|
+
Round-trip test asserts both sparse arrays survive.
|
|
261
|
+
- 8a9bab4: feat: chart builder writes back a wide slate of optional chart fields.
|
|
262
|
+
The chart-builder now emits, when authored on `ChartSpec`:
|
|
263
|
+
|
|
264
|
+
- `<c:varyColors>` (per chart kind), `<c:gapWidth>`, `<c:overlap>`
|
|
265
|
+
on bar / column
|
|
266
|
+
- `<c:grouping>` honors `ChartSpec.grouping` (`'clustered' | 'stacked'
|
|
267
|
+
| 'percentStacked' | 'standard'`) on bar / column / line / area
|
|
268
|
+
- `<c:dropLines>`, `<c:hiLowLines>` on line
|
|
269
|
+
- `<c:firstSliceAng>` on pie / doughnut; `<c:holeSize>` on doughnut
|
|
270
|
+
honors `holeSizePct`
|
|
271
|
+
- `<c:majorGridlines>` (with optional `<c:spPr><a:ln><a:solidFill>`
|
|
272
|
+
color), `<c:minorGridlines>` on the value axis
|
|
273
|
+
- `<c:title><c:overlay>` honoring `titleOverlay`
|
|
274
|
+
|
|
275
|
+
Round-trip test asserts the additions all survive read → save →
|
|
276
|
+
reload.
|
|
277
|
+
|
|
278
|
+
- e7078d7: feat: chart builder writes back legend.textStyle + axis orientation
|
|
279
|
+
reversals. `<c:legend><c:txPr>` now carries the authored font / color
|
|
280
|
+
from `legend.textStyle` (via the existing `axisTxPrElement` helper);
|
|
281
|
+
`<c:scaling><c:orientation>` honors `categoryAxisOrientation` and
|
|
282
|
+
`valueAxisOrientation` (defaulting to `minMax`). Round-trip test
|
|
283
|
+
asserts all four survive read → save → reload.
|
|
284
|
+
- 034207d: feat: chart builder writes back `<c:legend>` and `<c:dispBlanksAs>`.
|
|
285
|
+
The chart-root previously emitted only the default legend / blanks
|
|
286
|
+
behavior; the builder now:
|
|
287
|
+
|
|
288
|
+
- emits `<c:legend>` with `legendPos`, `overlay`, and one
|
|
289
|
+
`<c:legendEntry><c:idx><c:delete val="1"/></c:legendEntry>` per
|
|
290
|
+
hidden series index — or skips the element when
|
|
291
|
+
`spec.legend.position === null` (author wants no legend)
|
|
292
|
+
- threads `spec.dispBlanksAs` (`'gap' | 'zero' | 'span'`) into
|
|
293
|
+
`<c:dispBlanksAs>`
|
|
294
|
+
|
|
295
|
+
Round-trip test added.
|
|
296
|
+
|
|
297
|
+
- f643b29: feat: chart builder writes back per-series `<c:dLbls>` overrides.
|
|
298
|
+
`dLblsElement` is refactored to take the labels arg directly via
|
|
299
|
+
`buildDLblsFromLabels(dl)`; `seriesElement` now emits per-series
|
|
300
|
+
`<c:dLbls>` when authored, so charts with per-series label toggles /
|
|
301
|
+
numberFormat / position survive round-trip. Round-trip test covers
|
|
302
|
+
all four fields plus the no-override case.
|
|
303
|
+
- cf2d02b: feat: chart builder writes back series-level optional fields. Each
|
|
304
|
+
`<c:ser>` now emits:
|
|
305
|
+
|
|
306
|
+
- richer `<c:spPr>` with `<a:ln w="…"><a:prstDash/>` when
|
|
307
|
+
`series.lineWidthEmu` or `lineDash` is authored
|
|
308
|
+
- `<c:invertIfNegative val="1"/>` when set
|
|
309
|
+
- `<c:marker><c:symbol/><c:size/></c:marker>` from `markerSymbol` /
|
|
310
|
+
`markerSizePt`
|
|
311
|
+
- `<c:smooth val="1"/>` when set
|
|
312
|
+
|
|
313
|
+
Round-trip test covers all five fields.
|
|
314
|
+
|
|
315
|
+
- 7f0b8ee: feat: chart builder writes back `ChartSpec.titleStyle`. Previously the
|
|
316
|
+
reader picked up authored `<a:rPr sz/b/i><a:solidFill>` on chart
|
|
317
|
+
titles but the builder dropped any incoming style, so round-tripping
|
|
318
|
+
(read → save → reload) lost the title font / color. The builder now
|
|
319
|
+
emits `<a:rPr>` attributes and an inner `<a:solidFill><a:srgbClr/>`
|
|
320
|
+
when a `titleStyle` is provided. New round-trip test
|
|
321
|
+
(`fn-chart-readback`) covers this; total tests 801.
|
|
322
|
+
- bf62577: feat: chart builder writes back per-series `<c:trendline>`. A new
|
|
323
|
+
`trendlineElement(tl)` helper emits `<c:trendlineType>`,
|
|
324
|
+
`<c:period>` (movingAvg), `<c:order>` (poly), `<c:forward>` /
|
|
325
|
+
`<c:backward>`, and `<c:spPr><a:ln><a:solidFill>` color when
|
|
326
|
+
authored. Closes the read/write gap for `ChartSeries.trendline`;
|
|
327
|
+
round-trip test covers type / period / forward / backward / color.
|
|
328
|
+
- 925fd6f: feat: chart builder writes back axis tick-label style + rotation via
|
|
329
|
+
`<c:txPr>`. New `axisTxPrElement(style, rotationDeg)` helper emits the
|
|
330
|
+
`<c:txPr><a:bodyPr rot/><a:lstStyle/><a:p><a:pPr><a:defRPr…/></a:pPr></a:p></c:txPr>`
|
|
331
|
+
payload from `categoryAxisLabelStyle` / `categoryAxisLabelRotationDeg`
|
|
332
|
+
and the value-axis counterparts. Closes the read/write gap for these
|
|
333
|
+
fields; round-trip test added.
|
|
334
|
+
- ba80399: feat: `ChartSpec.categoryAxisMajorGridlines` and
|
|
335
|
+
`ChartSpec.categoryAxisMinorGridlines` — companions to the existing
|
|
336
|
+
`valueAxis*` pair. Bar charts (where the category axis sits on the
|
|
337
|
+
vertical edge) actually use these as horizontal guide lines per
|
|
338
|
+
category band. Mapped to `<c:catAx><c:majorGridlines/>` /
|
|
339
|
+
`<c:minorGridlines/>`. Read by chart-reader, written by chart-builder
|
|
340
|
+
in the correct CT_CatAx schema order (right after `<c:axPos>`).
|
|
341
|
+
- 2d61d26: feat: `ChartSpec.categoryAxisLabelOffset` and
|
|
342
|
+
`ChartSpec.categoryAxisLabelAlign` — two more category-axis tuning
|
|
343
|
+
knobs from ECMA-376. `<c:catAx><c:lblOffset val="N"/>` (0..1000, default 100) controls the distance from the axis line to the labels as a
|
|
344
|
+
percent of text size; `<c:catAx><c:lblAlgn val="ctr|l|r"/>` controls
|
|
345
|
+
how multi-line category labels align relative to their tick mark. Both
|
|
346
|
+
are read by chart-reader and written by chart-builder in the correct
|
|
347
|
+
CT_CatAx schema order.
|
|
348
|
+
- 21f58cb: feat: `ChartSpec.categoryAxisNoMultiLevelLabel` — toggle multi-level
|
|
349
|
+
(hierarchical) category labels via `<c:catAx><c:noMultiLvlLbl val/>`.
|
|
350
|
+
PowerPoint defaults to `0` (multi-level labels stack); set to `true`
|
|
351
|
+
to flatten hierarchical categories into a single row. Read by
|
|
352
|
+
chart-reader, written by chart-builder at the schema-required last
|
|
353
|
+
position inside `<c:catAx>`.
|
|
354
|
+
- c561df4: feat: `ChartSpec.categoryAxisNumberFormat` — number-format code for the
|
|
355
|
+
category-axis tick labels (`<c:catAx><c:numFmt formatCode="…"/>`). Most
|
|
356
|
+
useful on date-style categories (`"mm/dd/yyyy"`, `"mmm-yyyy"`) but
|
|
357
|
+
accepts any Excel format string. Independent of `valueAxis.numberFormat`.
|
|
358
|
+
Read by chart-reader, written by chart-builder in the correct CT_CatAx
|
|
359
|
+
schema order (after `<c:title>`, before `<c:majorTickMark>`).
|
|
360
|
+
- 3ecc11b: feat(chart): category-axis label-skip + position. `ChartSpec.categoryAxisTickLabelSkip`
|
|
361
|
+
reads `<c:catAx><c:tickLblSkip val="N"/>` (render every Nth label),
|
|
362
|
+
and `categoryAxisTickLabelPos` reads `<c:tickLblPos val="…"/>`
|
|
363
|
+
(`'none'` hides labels but keeps the axis line; `'low'`/`'high'`/
|
|
364
|
+
`'nextTo'` are the other tokens). Playground honors both — dense
|
|
365
|
+
time-series charts with `tickLblSkip="5"` no longer overlap their
|
|
366
|
+
labels.
|
|
367
|
+
- e04ccff: feat: `ChartSpec.dataLabels` carries the chart-level `<c:dLbls>` toggles
|
|
368
|
+
— `showValue`, `showCategory`, `showSeriesName`, `showPercent` — read
|
|
369
|
+
from each plotted-kind element. Playground projects them onto bar /
|
|
370
|
+
column tops (numeric value above each bar) and pie / doughnut slices
|
|
371
|
+
(value, percent, and / or category text painted at the slice mid-arc).
|
|
372
|
+
|
|
373
|
+
Adds the `ChartDataLabels` interface to the public type surface.
|
|
374
|
+
|
|
375
|
+
- 199031b: feat: chart data labels honor `<c:dLbls><c:numFmt formatCode="…"/>`.
|
|
376
|
+
`ChartDataLabels.numberFormat` exposes the format code on both
|
|
377
|
+
chart-level and per-series toggle groups, and the playground renderer
|
|
378
|
+
projects value labels through the same Excel-format subset the value
|
|
379
|
+
axis already supports (`"0%"`, `"$#,##0"`, `"0.00"`, etc). Per-series
|
|
380
|
+
formats win over the chart-level default.
|
|
381
|
+
- b77c0ed: feat(chart): `ChartSpec.dispBlanksAs` reads `<c:dispBlanksAs>`
|
|
382
|
+
(`'gap' | 'zero' | 'span'`). Playground line / area renderer:
|
|
383
|
+
|
|
384
|
+
- `gap` (default): breaks the path on null values
|
|
385
|
+
- `zero`: substitutes 0 so the line dips to the baseline
|
|
386
|
+
- `span`: connects the surrounding points across the gap
|
|
387
|
+
|
|
388
|
+
Previously every null value was coerced to 0, which silently
|
|
389
|
+
flattened the chart whenever the deck had genuine missing data.
|
|
390
|
+
|
|
391
|
+
- 0eee0da: feat: `ChartDataLabels.textStyle` — the default-run text style for chart
|
|
392
|
+
data labels is now read and written. `<c:dLbls><c:txPr><a:defRPr/>`
|
|
393
|
+
is parsed into `ChartTextStyle` (sizePt / bold / italic / color) and
|
|
394
|
+
emitted in CT_DLbls schema order (after `<c:numFmt>`, before
|
|
395
|
+
`<c:dLblPos>`). Both the chart-level `dataLabels` and per-series
|
|
396
|
+
`series[i].dataLabels` honor the field.
|
|
397
|
+
- 17f57b3: feat: `ChartSeries.pointColors` — sparse map of per-data-point fill
|
|
398
|
+
overrides read from `<c:ser><c:dPt><c:spPr><a:solidFill>`. Pie /
|
|
399
|
+
doughnut decks almost always emit one of these per slice; the playground
|
|
400
|
+
now paints each slice in its authored color (and reflects it in the
|
|
401
|
+
legend swatches) rather than cycling through the accent palette.
|
|
402
|
+
- 4d2cecb: feat(chart): `ChartSpec.dropLines` and `hiLowLines` read
|
|
403
|
+
`<c:dropLines>` and `<c:hiLowLines>` on line / area / stock plots.
|
|
404
|
+
Playground renders drop lines from each first-series data point down
|
|
405
|
+
to the value axis (dashed gray) and hi-low lines as a vertical span
|
|
406
|
+
between the highest and lowest series value at each category
|
|
407
|
+
(solid darker gray). The latter is the canonical OHLC pattern.
|
|
408
|
+
- 263bf52: feat: chart reader now recognises scatter, bubble, radar, stock, and
|
|
409
|
+
(2D / 3D) surface charts and degrades them to the closest already-
|
|
410
|
+
modelled kind so renderers paint something useful instead of the
|
|
411
|
+
"unsupported chart kind" placeholder. Scatter / bubble series read
|
|
412
|
+
their `<c:yVal>` channel; their `<c:xVal>` / `<c:bubbleSize>` are
|
|
413
|
+
not yet surfaced.
|
|
414
|
+
- 0a9236f: feat(chart): `ChartSpec.gapWidthPct` and `overlapPct` read from
|
|
415
|
+
`<c:gapWidth>` and `<c:overlap>` on bar / column plots. Playground
|
|
416
|
+
sizes bars per ECMA-376 §21.2.2.75 — `barW = groupW / (clusterUnits +
|
|
417
|
+
gapWidth/100)` with `clusterUnits = 1 + (S - 1)(1 - overlap/100)` —
|
|
418
|
+
so authored bar spacing matches PowerPoint instead of the hard-coded
|
|
419
|
+
0.8 / 0.7 ratios.
|
|
420
|
+
- b88dbb8: feat(chart): `ChartSpec.valueAxisMajorGridlines` / `valueAxisMinorGridlines`
|
|
421
|
+
read the presence of `<c:majorGridlines/>` / `<c:minorGridlines/>`
|
|
422
|
+
under `<c:valAx>`. Playground hides gridlines when `majorGridlines`
|
|
423
|
+
is explicitly `false` (absent in the source XML) — common on KPI
|
|
424
|
+
charts that show clean bars / lines without horizontal rules behind
|
|
425
|
+
them. Tick labels still render.
|
|
426
|
+
- 4caa5ad: feat(chart): `ChartSeries.invertIfNegative` reads `<c:ser>
|
|
427
|
+
<c:invertIfNegative val="1"/>`. Playground's bar / column renderer
|
|
428
|
+
paints negative bars in a darker shade of the series color when the
|
|
429
|
+
flag is set — matching PowerPoint's profit/loss visualization.
|
|
430
|
+
- b603115: feat: `ChartSpec.language` (`<c:chartSpace><c:lang val=…/>`) and
|
|
431
|
+
`ChartSpec.date1904` (`<c:date1904 val=…/>`) — chartSpace-level Office
|
|
432
|
+
metadata round-tripped for parity. `language` is the Office UI
|
|
433
|
+
language code (e.g. `'en-US'`, `'ja-JP'`); `date1904` selects the
|
|
434
|
+
1904 date epoch (default `false` = Excel 1900 epoch, surface only
|
|
435
|
+
when explicitly true). pptx-kit's renderers don't act on either yet.
|
|
436
|
+
- 028e3b7: feat: chart `<c:legend><c:legendEntry><c:delete val="1"/>` honored.
|
|
437
|
+
`ChartSpec.legend.hiddenIndices` carries the series indices the
|
|
438
|
+
author wants suppressed from the legend (typically trendline series).
|
|
439
|
+
The playground filters the parallel legend arrays (names, colors,
|
|
440
|
+
marker glyphs) in lock-step so the remaining entries stay aligned,
|
|
441
|
+
without affecting plotted data.
|
|
442
|
+
- c141173: feat(chart): `ChartSpec.legend` carries the `<c:legend><c:legendPos>`
|
|
443
|
+
token — `'r' | 't' | 'b' | 'l' | 'tr'`. Playground projects each
|
|
444
|
+
onto the appropriate edge (horizontal row for top / bottom, vertical
|
|
445
|
+
stack for the side / corner positions). Charts whose `<c:legend>`
|
|
446
|
+
sets `position` to `null` paint without a legend.
|
|
447
|
+
- 9a49faf: feat(chart): `ChartAxisScaling.majorUnit` and `minorUnit` read
|
|
448
|
+
`<c:valAx><c:majorUnit>` / `<c:minorUnit>` tick spacing. Playground's
|
|
449
|
+
value-axis renderer emits ticks at each multiple of the authored
|
|
450
|
+
majorUnit instead of nice-rounded auto-ticks when present.
|
|
451
|
+
- f99d548: feat: `ChartSpec.valueAxisMinorTickMark` and `categoryAxisMinorTickMark`
|
|
452
|
+
— minor-tick-mark mode siblings of the existing `*MajorTickMark` pair.
|
|
453
|
+
Maps to `<c:catAx><c:minorTickMark val="in|out|cross|none"/>` and the
|
|
454
|
+
value-axis equivalent. Read by chart-reader, written by chart-builder
|
|
455
|
+
in the correct schema order (right after `<c:majorTickMark>`).
|
|
456
|
+
- 28d77ea: fix: chart categories accept `<c:cat><c:numRef>` (numeric / date
|
|
457
|
+
categories). Previously the category-axis dropped to an empty
|
|
458
|
+
labels array when the chart authored a numeric category channel
|
|
459
|
+
(common for date-axis line charts authored in Excel). Falls back
|
|
460
|
+
to formatting each cached numeric value as a string so date /
|
|
461
|
+
number cats appear on the axis instead of disappearing.
|
|
462
|
+
- 7b3ba0a: feat(chart): axis number formats now accept Excel's `"$"#,##0`
|
|
463
|
+
quoted-literal prefix / suffix syntax. PowerPoint typically emits
|
|
464
|
+
currency as `"$"#,##0` (or `"\$"#,##0`) rather than the bare `$`
|
|
465
|
+
form, so the previous detection missed it.
|
|
466
|
+
- d2f86d2: feat(chart): `ChartAxisScaling.numberFormat` reads `<c:valAx><c:numFmt
|
|
467
|
+
formatCode="…"/>`. Playground projects the most common Excel format
|
|
468
|
+
codes to axis labels — percent (`'0%'`, `'0.0%'`), thousand
|
|
469
|
+
separator (`'#,##0'`, `'#,##0.0'`), and currency prefixes
|
|
470
|
+
(`'$#,##0'`, `'¥#,##0'`). Other codes fall through to the generic
|
|
471
|
+
auto-formatted label.
|
|
472
|
+
- 3efdbeb: feat(chart): `ChartSpec.titleOverlay` and `ChartSpec.legend.overlay`
|
|
473
|
+
read `<c:title><c:overlay>` / `<c:legend><c:overlay>`. When `true`,
|
|
474
|
+
the title / legend sits on top of the plot area instead of taking a
|
|
475
|
+
horizontal strip. Playground sizes the plot area accordingly — gives
|
|
476
|
+
the chart back the extra vertical real estate when overlay is set.
|
|
477
|
+
- 4cde872: feat: `ChartSpec.plotVisibleCellsOnly` — toggle `<c:plotVisOnly val/>`.
|
|
478
|
+
PowerPoint's default is `true` (only plot visible cells); the field
|
|
479
|
+
exists to let authors opt into `false` (plot hidden rows / columns too).
|
|
480
|
+
The reader surfaces `false` only when the wire is explicitly `0` so
|
|
481
|
+
round-tripping the common default doesn't drag a redundant explicit
|
|
482
|
+
`true` into the spec.
|
|
483
|
+
- 693ba3e: feat: `ChartSpec.roundedCorners` — round-trip the chartSpace-level
|
|
484
|
+
`<c:roundedCorners val>` toggle. PowerPoint's default is `false`; the
|
|
485
|
+
reader surfaces `true` only when the wire is explicitly `1` and the
|
|
486
|
+
builder emits the element only when authored, so common defaults stay
|
|
487
|
+
clean. Schema position is BEFORE `<c:chart>` (per CT_ChartSpace).
|
|
488
|
+
- 733120a: feat(chart): `ChartSeries.smooth` reads `<c:smooth val="1"/>`. Playground
|
|
489
|
+
line / area renderer interpolates a cubic-Bézier curve through the
|
|
490
|
+
data points (Catmull-Rom-to-Bezier with 0.5 tension) when `smooth` is
|
|
491
|
+
true, matching PowerPoint's "smooth line" preset visually.
|
|
492
|
+
- d581121: feat(site/playground): bar (horizontal), line, and area charts now
|
|
493
|
+
honour `ChartSpec.grouping` for stacked / percentStacked layouts —
|
|
494
|
+
matching the column-chart treatment added previously. Data labels
|
|
495
|
+
render inside the stacked segments for bar (white bold), at the
|
|
496
|
+
appropriate cumulative position for line / area, and percent-stacked
|
|
497
|
+
versions normalize each category to 100%.
|
|
498
|
+
- 33c2c11: feat: `ChartSpec.grouping` carries the `<c:grouping>` token —
|
|
499
|
+
`'clustered' | 'stacked' | 'percentStacked' | 'standard'`. Playground
|
|
500
|
+
column chart renders stacked / percent-stacked layouts: series stack
|
|
501
|
+
within each category, and percent-stacked normalises to 0..100% per
|
|
502
|
+
column with in-bar value labels.
|
|
503
|
+
|
|
504
|
+
Adds the `ChartGrouping` type to the public surface.
|
|
505
|
+
|
|
506
|
+
- 53148e4: feat: `ChartSpec.chartStyle` — round-trip the chartSpace-level
|
|
507
|
+
`<c:style val="N"/>` PowerPoint chart-style preset (1..48). Encodes a
|
|
508
|
+
curated combo of theme accent colors, gradients, effects, and font
|
|
509
|
+
sizes from the PowerPoint "Chart Styles" gallery. Read and written for
|
|
510
|
+
round-trip parity; pptx-kit's renderers don't interpret the preset
|
|
511
|
+
yet, but the field survives save/reload.
|
|
512
|
+
- b1cfda3: feat: `ChartSpec.categoryAxisTickMarkSkip` — the second half of the
|
|
513
|
+
ECMA-376 `<c:catAx>` skip pair. `<c:tickLblSkip>` (already supported)
|
|
514
|
+
controls label-skip stride; `<c:tickMarkSkip val="N"/>` independently
|
|
515
|
+
draws every Nth tick mark. Useful when you want fewer label collisions
|
|
516
|
+
but the same dense tick lattice. Read by chart-reader and written by
|
|
517
|
+
chart-builder.
|
|
518
|
+
- 2599a46: feat: chart titles read `<c:tx><c:strRef>` workbook-cell references.
|
|
519
|
+
Previously only literal `<c:rich>` titles surfaced; titles authored
|
|
520
|
+
via Excel's "Link to source cell" wizard (which emits `<c:strRef>`
|
|
521
|
+
with a `<c:strCache>` of the resolved text) now flow through to
|
|
522
|
+
`ChartSpec.title` as the cached value. Affects the title shown above
|
|
523
|
+
the chart and, transitively, axis-title rendering.
|
|
524
|
+
- da1e50d: feat: chart titles honor `<a:rPr>` font / color overrides.
|
|
525
|
+
`ChartSpec.titleStyle` carries the authored size (in pt), bold, italic,
|
|
526
|
+
and fill color extracted from the title's first `<a:r><a:rPr>` (or
|
|
527
|
+
`<a:pPr><a:defRPr>` as fallback). The playground renderer projects
|
|
528
|
+
those through to the SVG `<text>`. Templates that brand their chart
|
|
529
|
+
titles to a non-default size / color finally render with the authored
|
|
530
|
+
look.
|
|
531
|
+
- 5f84cfc: feat: `ChartTrendline.displayEquation` and `ChartTrendline.displayRSquared`
|
|
532
|
+
— two booleans that toggle the regression-equation label and R²
|
|
533
|
+
coefficient overlay next to a trendline. Map to
|
|
534
|
+
`<c:trendline><c:dispEq val="1"/>` and `<c:dispRSqr val="1"/>`. Read by
|
|
535
|
+
chart-reader; written by chart-builder in the correct CT_Trendline
|
|
536
|
+
schema order (after `<c:backward>`, before any `<c:trendlineLbl>`).
|
|
537
|
+
- a978251: feat: `ChartTrendline.name` — round-trip a custom trendline label
|
|
538
|
+
(`<c:trendline><c:name>…`). PowerPoint auto-generates a label like
|
|
539
|
+
"Linear (X)" or "MA(5) (X)" when this element is omitted; authors who
|
|
540
|
+
want a different label (or who imported one from another tool) now
|
|
541
|
+
have the field. Read by chart-reader; written by chart-builder at the
|
|
542
|
+
CT_Trendline schema-required first position (before `<c:spPr>`).
|
|
543
|
+
- 57eeffa: feat(chart): `ChartSeries.trendline` reads `<c:trendline>` —
|
|
544
|
+
regression type (linear / exp / log / poly / power / movingAvg),
|
|
545
|
+
moving-average period, polynomial order, and the trendline's stroke
|
|
546
|
+
color. Playground overlays a dashed trendline on bar / column / line
|
|
547
|
+
charts; linear / log / exp use fitted regressions, movingAvg uses a
|
|
548
|
+
rolling mean.
|
|
549
|
+
|
|
550
|
+
Adds the `ChartTrendline` type to the public surface.
|
|
551
|
+
|
|
552
|
+
- 24b2794: feat: `ChartSpec.valueAxisCrossBetween` — controls whether the value
|
|
553
|
+
axis crosses the category axis _between_ tick marks (the default for
|
|
554
|
+
bar/column/area) or _at_ each tick mark (the default for line/scatter).
|
|
555
|
+
Maps to `<c:valAx><c:crossBetween val="between|midCat"/>`. Read by
|
|
556
|
+
chart-reader, written by chart-builder in the correct CT_ValAx schema
|
|
557
|
+
order (after `<c:crossesAt>`).
|
|
558
|
+
- 6a236be: feat: `ChartSpec.valueAxisCrosses` — controls where the category axis
|
|
559
|
+
crosses the value axis. Accepts either an enum keyword
|
|
560
|
+
(`'autoZero' | 'min' | 'max'` → `<c:valAx><c:crosses val=…/>`) or a
|
|
561
|
+
numeric tagged form (`{ at: N }` → `<c:valAx><c:crossesAt val=N/>`).
|
|
562
|
+
The two forms are mutually exclusive per the schema; `crossesAt` wins
|
|
563
|
+
when both are present on read. Read by chart-reader, written by
|
|
564
|
+
chart-builder in the correct CT_ValAx schema order (after `<c:crossAx>`).
|
|
565
|
+
- b2c1304: feat: chart `<c:varyColors>` for single-series bar / column.
|
|
566
|
+
`ChartSpec.varyColors` carries the `<c:plottedKind><c:varyColors val="1"/>`
|
|
567
|
+
flag. When set and the chart has exactly one series, the renderer
|
|
568
|
+
assigns each data point a distinct accent color (mirroring
|
|
569
|
+
PowerPoint's "Vary colors by point" toggle for column / bar). Pies
|
|
570
|
+
already varied colors implicitly.
|
|
571
|
+
- 69431a9: feat: `getSlideColorMapOverride(slide)` returns the slide's
|
|
572
|
+
`<p:clrMapOvr><a:overrideClrMapping/>` token-remap, or `null` when the
|
|
573
|
+
slide inherits the master's color map. Returned as a plain `Record`
|
|
574
|
+
with the eight stable tokens (`bg1`, `tx1`, `bg2`, `tx2`, `accent1`-
|
|
575
|
+
`accent6`, `hlink`, `folHlink`) keyed to their override targets.
|
|
576
|
+
Useful for renderers that need to know when a slide reinterprets the
|
|
577
|
+
theme's color story.
|
|
578
|
+
- 263bf52: feat: apply ECMA-376 §20.1.2.3.x color transforms when resolving colors.
|
|
579
|
+
|
|
580
|
+
- New `resolveDrawingColor(colorEl, theme)` resolves any DrawingML color
|
|
581
|
+
element (`<a:srgbClr>` / `<a:schemeClr>` / `<a:sysClr>` / `<a:prstClr>`)
|
|
582
|
+
with all transform children (`<a:lumMod>`, `<a:lumOff>`, `<a:shade>`,
|
|
583
|
+
`<a:tint>`, `<a:satMod>` / `Off`, `<a:hueMod>` / `Off`, `<a:gray>`,
|
|
584
|
+
`<a:inv>`, `<a:comp>`) applied. Scheme tokens are looked up against
|
|
585
|
+
the supplied theme.
|
|
586
|
+
- New `getShapeFillColorResolved(pres, shape)` and
|
|
587
|
+
`getShapeStrokeColorResolved(pres, shape)` return the exact `#RRGGBB`
|
|
588
|
+
PowerPoint paints — useful for renderers / exporters where the legacy
|
|
589
|
+
`getShapeFillColor` / `getShapeStrokeColor` strings (`#RRGGBB` or
|
|
590
|
+
`scheme:<token>`) miss both scheme resolution and color transforms.
|
|
591
|
+
- `getShapeRunFormatEffective` now applies the same pipeline at every
|
|
592
|
+
layer of the rPr cascade, so a run inheriting `accent1 lumMod=40000
|
|
593
|
+
lumOff=60000` (PowerPoint's "Accent 1, Lighter 60%") resolves to the
|
|
594
|
+
concrete tinted hex instead of leaking the raw token through.
|
|
595
|
+
|
|
596
|
+
- 263bf52: feat(site/playground): bent / curved connector routing.
|
|
597
|
+
|
|
598
|
+
`bentConnector{2,3,4,5}` render as the matching L / Z / two-step /
|
|
599
|
+
three-step paths, and `curvedConnector{2,3,4,5}` render as quadratic
|
|
600
|
+
/ cubic Bézier curves between the connector's bounding-box endpoints.
|
|
601
|
+
Previously every connector preset projected to a straight line; flow-
|
|
602
|
+
chart and diagram decks now show the right cadence.
|
|
603
|
+
|
|
604
|
+
- e65228f: feat: read custom geometry. New `getShapeCustomGeometry(shape)` returns a
|
|
605
|
+
shape's `<a:custGeom>` (ECMA-376 §20.1.9) as a fully-evaluated path list —
|
|
606
|
+
guide formulas (`avLst`/`gdLst`, all §20.1.9.11 operators) are resolved
|
|
607
|
+
against the shape extents so the returned `moveTo`/`lnTo`/`arcTo`/
|
|
608
|
+
`quadBezTo`/`cubicBezTo`/`close` commands carry only numbers. The preview
|
|
609
|
+
renderer now draws custom geometry as a real SVG path (arcs converted to
|
|
610
|
+
cubic Béziers) instead of a labelled rectangle placeholder; only a custGeom
|
|
611
|
+
that fails to evaluate still falls back, marked `data-pptx-fallback`.
|
|
612
|
+
- 1e774b8: feat(site/playground): pie / doughnut / line / area honor
|
|
613
|
+
`<c:dLblPos>` data-label positions. Pie supports `ctr` (default
|
|
614
|
+
midline), `inEnd` (just inside the rim), and `outEnd` (outside the
|
|
615
|
+
pie, with a darker fill so it shows on the chart-area backdrop). Line
|
|
616
|
+
and area chart per-point labels honor `ctr`, `t` (default), `b`, `l`,
|
|
617
|
+
`r`. Column / bar already shipped in the prior batch.
|
|
618
|
+
- fc019d1: feat: chart data label position. `ChartDataLabels.position` carries the
|
|
619
|
+
`<c:dLbls><c:dLblPos val="…"/>` token (typed as
|
|
620
|
+
`ChartDataLabelPosition`). The reader extracts it at both chart-level
|
|
621
|
+
and per-series scope. The playground renderer projects `ctr`, `inEnd`,
|
|
622
|
+
`outEnd`, `inBase` onto clustered column and bar labels — outside-end
|
|
623
|
+
remains the default, but authored positions now move labels inside the
|
|
624
|
+
bar or to the base as PowerPoint shows them.
|
|
625
|
+
- 3cfba8d: feat: chart data label separator. `ChartDataLabels.separator` carries
|
|
626
|
+
the `<c:dLbls><c:separator>…</c:separator>` text used to join
|
|
627
|
+
multiple label parts (value + percent + category etc.). The pie /
|
|
628
|
+
doughnut renderer threads the per-series override, falling back to
|
|
629
|
+
the chart-level separator and finally to a single space. Common
|
|
630
|
+
values: `", "`, `"\n"`, `"; "`.
|
|
631
|
+
- 003e7b5: feat: density-array companions for tables and images —
|
|
632
|
+
`getPresentationTableCountsBySlide(pres)` and
|
|
633
|
+
`getPresentationImageCountsBySlide(pres)`. Both return a dense
|
|
634
|
+
per-slide count array (0 for slides without that asset kind),
|
|
635
|
+
matching the shape / chart / comment / text-length counterparts.
|
|
636
|
+
Completes the deck-density family.
|
|
637
|
+
- fd1519a: feat(site/playground): `<c:dispUnits>` value-axis label. When the
|
|
638
|
+
chart authors a display-units token (`thousands`, `millions`, etc.)
|
|
639
|
+
the value-axis now emits an italic "Thousands" / "Millions" /
|
|
640
|
+
… label rotated alongside the axis (vertical orientation) or to
|
|
641
|
+
the right of the rightmost tick (horizontal). Completes the
|
|
642
|
+
display-units rendering — values are already divided, and now the
|
|
643
|
+
scale self-describes.
|
|
644
|
+
- c5f0b60: feat: chart value-axis honors `<c:dispUnits><c:builtInUnit/>`.
|
|
645
|
+
`ChartAxisScaling.displayUnits` carries the authored scale token
|
|
646
|
+
(`hundreds`, `thousands`, `millions`, etc.). The playground divides
|
|
647
|
+
each value-axis tick by the corresponding divisor before formatting,
|
|
648
|
+
so charts authored "in millions" finally render as `10` / `20` /
|
|
649
|
+
`30` instead of `10000000`.
|
|
650
|
+
- 263bf52: feat: add `getShapeRunFormatEffective(pres, shape, p, r)` — resolves a
|
|
651
|
+
run's character properties (font, size, color, bold, italic, underline)
|
|
652
|
+
through the full ECMA-376 §21.1.2.4.7 inheritance chain: run `<a:rPr>` →
|
|
653
|
+
`<a:endParaRPr>` → paragraph `<a:defRPr>` → text-body `<a:lstStyle>` →
|
|
654
|
+
matching layout placeholder → matching master placeholder → master
|
|
655
|
+
`<p:txStyles>` → theme `<a:fontScheme>`. Theme tokens like `+mj-lt` are
|
|
656
|
+
expanded to the deck's major/minor typefaces. The existing
|
|
657
|
+
`getShapeRunFormat` still returns the literal `<a:rPr>` only.
|
|
658
|
+
- 25654cf: feat: `getShapeEffectsEffective(pres, shape)` walks the layout →
|
|
659
|
+
master placeholder cascade for `<a:effectLst>`. Effect lists override
|
|
660
|
+
rather than compose (matching PowerPoint's behaviour), so the first
|
|
661
|
+
layer that supplies any effects wins. Playground uses it so
|
|
662
|
+
placeholder shadows / glows / soft edges inherited from the master
|
|
663
|
+
finally render on slides that don't repeat the effect list.
|
|
664
|
+
- acc9b15: feat: effects & fills polish. The reflection effect (`a:reflection`) now
|
|
665
|
+
renders as a vertically mirrored, gradient-masked copy honoring start/end
|
|
666
|
+
alpha, distance, and the signed `sy` scale; picture bullets (`a:buBlip`)
|
|
667
|
+
render as real inline images in both text layout modes via the new core
|
|
668
|
+
reader `getParagraphBulletImageBytes` (the "■" fallback remains only when
|
|
669
|
+
bullet bytes are genuinely unavailable); and gradient fills inherited
|
|
670
|
+
through the placeholder layout/master cascade resolve via the new
|
|
671
|
+
`getShapeGradientFillEffective` instead of painting a hardcoded orange
|
|
672
|
+
tint.
|
|
673
|
+
- 263bf52: feat: `getShapeEffects(pres, shape)` returns every effect on the
|
|
674
|
+
shape's `<a:effectLst>` (`outerShdw`, `innerShdw`, `glow`, `reflection`,
|
|
675
|
+
`softEdge`, `blur`) in document order, with each effect's color
|
|
676
|
+
(transform-resolved against the theme), opacity, blur radius, distance,
|
|
677
|
+
and angle. PowerPoint composes multiple effects in a single filter
|
|
678
|
+
stack — the existing `getShapeEffect` only surfaced the first one.
|
|
679
|
+
|
|
680
|
+
The playground renderer now emits an SVG `<filter>` chain that
|
|
681
|
+
composes the same effects, including a synthesized inner shadow
|
|
682
|
+
(SVG has no `feInnerShadow` primitive — built via offset + composite).
|
|
683
|
+
|
|
684
|
+
Also adds the `ShapeEffectAny` type union to the public surface.
|
|
685
|
+
|
|
686
|
+
- 18d3ceb: feat: `getShapeFillEffective(pres, shape)` walks the layout → master
|
|
687
|
+
placeholder cascade when the shape's own fill is `'inherit'`. Returns
|
|
688
|
+
the first non-inherit fill found. Playground reaches for it as its
|
|
689
|
+
primary fill source so placeholder fills authored on the master /
|
|
690
|
+
layout finally show through.
|
|
691
|
+
- 81ce680: feat: `findShapesByPreset(slide, preset)` returns every shape whose
|
|
692
|
+
`<a:prstGeom prst="…"/>` matches. Useful for diagram introspection:
|
|
693
|
+
find all `'leftArrow'`s for a workflow swap, replace every `'cloud'`
|
|
694
|
+
with `'rect'`, etc. Shapes without a preset (custGeom / pictures /
|
|
695
|
+
charts / tables / connectors / groups) are filtered out.
|
|
696
|
+
- 019a934: feat: `findChartsWithDataLabels(slide)` — slide-scoped auditor for
|
|
697
|
+
charts whose chart-level or per-series `dataLabels` enable at least
|
|
698
|
+
one of `showValue` / `showCategory` / `showSeriesName` / `showPercent`.
|
|
699
|
+
Purely presence-based; doesn't validate numberFormat or position.
|
|
700
|
+
Charts whose kind isn't modeled are skipped.
|
|
701
|
+
- cb5d037: feat: `findChartsWithTrendlines(slide)` — slide-scoped finder for
|
|
702
|
+
charts that carry at least one `<c:trendline>` on any of their
|
|
703
|
+
series. Useful for deck-audit reports — trendlines are easy to add
|
|
704
|
+
and easy to forget. Charts whose kind isn't modeled are skipped.
|
|
705
|
+
- 1653804: feat: `findCommentsByAuthor(pres, authorName)` and
|
|
706
|
+
`findSlidesWithCommentsByAuthor(pres, authorName)` now accept a
|
|
707
|
+
`RegExp` as well as a literal string. Useful for "every comment from
|
|
708
|
+
review bots" (`/^review-bot/`) or "every comment from anyone with a
|
|
709
|
+
given email domain" patterns. Backward compatible — string callers
|
|
710
|
+
still get exact-equality matching.
|
|
711
|
+
- b6d9ea4: feat: `findShapeByName(slide, name)` now accepts a `RegExp` as well
|
|
712
|
+
as a literal string. Mirrors the RegExp support just landed on
|
|
713
|
+
`findShapesByName` (multi-match). Returns the first match in document
|
|
714
|
+
order; backward compatible with existing string callers.
|
|
715
|
+
- 7e59ac4: feat: `findShapeInPresentation(pres, name)` now accepts a `RegExp` as
|
|
716
|
+
well as a literal string. Mirrors the RegExp support on the
|
|
717
|
+
slide-scoped `findShapeByName`. Backward compatible — string callers
|
|
718
|
+
still get exact-equality.
|
|
719
|
+
- 70a2327: feat: `findShapesByEffect(pres, slide, kind)` — returns every shape on
|
|
720
|
+
the slide whose `<a:effectLst>` carries an effect of the given `kind`
|
|
721
|
+
(`'outerShdw'`, `'innerShdw'`, `'glow'`, `'reflection'`, `'softEdge'`,
|
|
722
|
+
`'blur'`). Pure presence check; doesn't walk the layout / master
|
|
723
|
+
cascade. Useful for "which shapes have a shadow / glow on this
|
|
724
|
+
slide?" audits.
|
|
725
|
+
- 94c4480: feat: `findShapesByHyperlink(slide, url)` — slide-scoped finder that
|
|
726
|
+
returns every shape whose hyperlink target matches `url` (substring or
|
|
727
|
+
`RegExp`). Pairs the existing presentation-level
|
|
728
|
+
`findSlidesByHyperlink` for cases where the caller already has a
|
|
729
|
+
specific slide and wants the linking shapes inside it.
|
|
730
|
+
- e71664d: feat: `findShapesByName(slide, name)` now accepts a `RegExp` as well
|
|
731
|
+
as a literal string. Useful when template-cloned shapes share a
|
|
732
|
+
prefix (`'TextPlaceholder1'`, `'TextPlaceholder2'`, …). Backward
|
|
733
|
+
compatible — string callers still get exact-equality matching.
|
|
734
|
+
- f57a4ab: feat: `findShapesInRect(slide, x, y, w, h)` — marquee-style region
|
|
735
|
+
finder. Returns every shape whose bounds overlap the rectangle
|
|
736
|
+
(touching edges count). Shapes with no resolvable bounds are skipped.
|
|
737
|
+
Companion to `findShapesAtPoint(slide, x, y)` for cases where the
|
|
738
|
+
caller wants a region of the slide rather than a single point.
|
|
739
|
+
- a7c00cb: feat: `findShapesWithAnimation(slide)` — returns every shape on the
|
|
740
|
+
slide whose `getShapeAnimation` is not `null`. Pair to
|
|
741
|
+
`slideHasAnimations`. Useful for "which shapes on this slide actually
|
|
742
|
+
animate?" audits before exporting to a video pipeline that doesn't
|
|
743
|
+
honor PowerPoint's timing tree.
|
|
744
|
+
- 87d7fbb: feat: `findShapesWithHyperlinks(slide)` — every shape on the slide
|
|
745
|
+
that carries any hyperlink, regardless of target. Counterpart to
|
|
746
|
+
`findShapesByHyperlink(slide, url)` (which requires a matching URL)
|
|
747
|
+
for "audit every clickable shape on this slide" workflows.
|
|
748
|
+
- 5cc4f75: feat: `findSlideByTitle(pres, title)` now accepts a `RegExp` as well
|
|
749
|
+
as a literal string. Pairs the RegExp support on
|
|
750
|
+
`findSlidesByText` / `findShapeByName` / `findCommentsByAuthor`.
|
|
751
|
+
Backward compatible — string callers still get exact-equality.
|
|
752
|
+
- 134943d: feat: `findSlidesByLayoutPartName(pres, layoutPartName)` — finds every
|
|
753
|
+
slide whose resolved layout part name matches `layoutPartName` (e.g.
|
|
754
|
+
`'/ppt/slideLayouts/slideLayout3.xml'`). Pair to the existing
|
|
755
|
+
`findSlidesByLayoutName` / `findSlidesByLayoutType`. Keyed on the
|
|
756
|
+
actual package path, so it's stable across template-name collisions
|
|
757
|
+
and PowerPoint UI locales.
|
|
758
|
+
- 20613b5: feat: `findSlidesWithChartKind(pres, kind)` — kind-filtered variant of
|
|
759
|
+
the existing `getSlidesWithCharts`. Returns every slide carrying at
|
|
760
|
+
least one chart of the given `ChartKind` (`'bar'`, `'column'`,
|
|
761
|
+
`'line'`, `'pie'`, `'doughnut'`, `'area'`). Built on `getSlideCharts`
|
|
762
|
+
so the predicate respects the spec the renderers actually see.
|
|
763
|
+
- 7c545c9: feat: `findSlidesWithChartTrendlines(pres)` — deck-level variant of
|
|
764
|
+
the slide-scoped `findChartsWithTrendlines`. Returns every slide
|
|
765
|
+
carrying at least one chart with a trendline on any series. Useful
|
|
766
|
+
for "audit every trendline in this deck" workflows before publishing.
|
|
767
|
+
- 666343d: feat: `getEmptySlides(pres)` — returns every slide whose `<p:spTree>`
|
|
768
|
+
carries no shapes (per `getSlideShapes`). Useful as a pre-publish
|
|
769
|
+
"find the section dividers I forgot to fill in" check.
|
|
770
|
+
- b4dbcc0: feat: `getPresentationChartCountsBySlide(pres)` — dense per-slide chart
|
|
771
|
+
count array. Counts every chart returned by `getSlideCharts` regardless
|
|
772
|
+
of whether its spec parsed; pair with `getPresentationChartKindCounts`
|
|
773
|
+
for kind-level totals. Rounds out the density-array family alongside
|
|
774
|
+
`getPresentationCommentCountsBySlide`,
|
|
775
|
+
`getPresentationShapeCountsBySlide`, and
|
|
776
|
+
`getPresentationTextLengthsBySlide`.
|
|
777
|
+
- a4ca6ca: feat: `getPresentationChartKindCounts(pres)` — deck-wide histogram of
|
|
778
|
+
`ChartKind` → count. Returns a frozen `Record` with every kind
|
|
779
|
+
present (zeros for absent kinds), so destructuring and chart-style
|
|
780
|
+
audits stay typed without runtime checks. Charts whose spec doesn't
|
|
781
|
+
parse are skipped, matching `findChartByKind` / `findSlidesWithChartKind`.
|
|
782
|
+
- f7dbcc4: feat: `getPresentationCommentCountsByAuthor(pres)` — deck-wide
|
|
783
|
+
histogram of comment counts keyed by author display name. Useful for
|
|
784
|
+
"who reviewed this deck the most?" audits. Authors sharing a display
|
|
785
|
+
name get merged into the same bucket; pair with
|
|
786
|
+
`getPresentationCommenters` when authors with identical names need to
|
|
787
|
+
be kept separate by `id`.
|
|
788
|
+
- be1a608: feat: `getPresentationCommentCountsBySlide(pres)` — dense per-slide
|
|
789
|
+
comment count array. Every slide appears as an element (count `0`
|
|
790
|
+
when the slide has no comments), so callers can chart comment
|
|
791
|
+
density per slide without re-indexing.
|
|
792
|
+
- 2789bb3: feat: `getPresentationHyperlinkCountsBySlide(pres)` — dense per-slide
|
|
793
|
+
hyperlink count array. Counts shapes whose `getShapeHyperlink` is
|
|
794
|
+
non-null. Cheaper than `getAllHyperlinks` when the caller only wants
|
|
795
|
+
per-slide counts. Rounds out the deck-density family.
|
|
796
|
+
- 2f67bd7: feat: `getPresentationNotesLengthsBySlide(pres)` — dense per-slide
|
|
797
|
+
speaker-notes length array. Pair with
|
|
798
|
+
`getPresentationTextLengthsBySlide` for handout / talk-track audits —
|
|
799
|
+
slides with little on-screen text but heavy notes are usually the
|
|
800
|
+
slow part of a presentation.
|
|
801
|
+
- 1974b01: feat: `getPresentationShapeCountsBySlide(pres)` — dense per-slide
|
|
802
|
+
shape count array. Counts whatever `getSlideShapes` flattens (top-
|
|
803
|
+
level + group-children). Useful for charting shape density per slide
|
|
804
|
+
and identifying outliers for cleanup.
|
|
805
|
+
- 6569f9d: feat: `getPresentationTextLengthsBySlide(pres)` — dense per-slide
|
|
806
|
+
visible-text length array. Counts code points (surrogate pairs as 1)
|
|
807
|
+
per `getSlideTextLength`. Pair with `getPresentationShapeCountsBySlide`
|
|
808
|
+
for slide-density audits.
|
|
809
|
+
- b793c74: feat: `getSlideLayoutUsageCountsByType(pres)` — companion to
|
|
810
|
+
`getSlideLayoutUsageCounts`, but keyed on the OOXML layout-type enum
|
|
811
|
+
token (`title`, `obj`, `twoObj`, `blank`, …) instead of the user-
|
|
812
|
+
visible name. Stable across PowerPoint UI locales. Useful for "how
|
|
813
|
+
many content slides vs. dividers vs. title slides?" audits.
|
|
814
|
+
- 3891fa2: feat: `getSlideLayoutUsageCounts(pres)` — layout name → number-of-slides
|
|
815
|
+
histogram. Every layout enumerated by `getSlideLayouts` appears as a
|
|
816
|
+
key (count `0` for unreferenced layouts), so the function surfaces
|
|
817
|
+
unused layouts directly — useful for trimming template decks that
|
|
818
|
+
ship with placeholder layouts the working deck never picks up.
|
|
819
|
+
- aad46e4: feat: `getSlideMasterUsageCounts(pres)` — master part name → number of
|
|
820
|
+
slides chaining to that master. Every master in the package appears as
|
|
821
|
+
a key (count `0` for unreferenced masters), so it surfaces unused
|
|
822
|
+
masters directly. Pair with `getSlideLayoutUsageCounts` for the
|
|
823
|
+
layout layer in multi-master template decks.
|
|
824
|
+
- 02fe159: feat: `getSlideTables(slide)` — returns every table graphic-frame
|
|
825
|
+
shape on the slide, in document order. Pair to `getSlideCharts` for
|
|
826
|
+
cases where the caller wants just the tables; convenience over
|
|
827
|
+
`getSlideShapes(slide).filter(isTableShape)`.
|
|
828
|
+
- acf5880: feat: `getUnusedSlideLayouts(pres)` — returns the layouts in the
|
|
829
|
+
package that no slide references. Useful when trimming a template
|
|
830
|
+
deck — unused layouts contribute parts and rels without ever
|
|
831
|
+
rendering. Iteration order matches `getSlideLayouts`.
|
|
832
|
+
- eca84ce: feat: `getUnusedSlideMasters(pres)` — master part names that no slide
|
|
833
|
+
chains to (count of `0` in `getSlideMasterUsageCounts`). Pair to
|
|
834
|
+
`getUnusedSlideLayouts`. Useful when trimming multi-master template
|
|
835
|
+
decks of dead theme variants.
|
|
836
|
+
- 263bf52: feat: `getShapeGradientFill` now surfaces non-linear gradient paths
|
|
837
|
+
(`<a:path path="circle|rect|shape">`) and the `<a:fillToRect>` focus
|
|
838
|
+
rectangle. `GradientFillOptions` gains `path` and `focus` fields so
|
|
839
|
+
renderers can reproduce radial, rectangular, and shape-following
|
|
840
|
+
gradients instead of falling back to a linear approximation.
|
|
841
|
+
|
|
842
|
+
The playground renderer emits an SVG `<radialGradient>` for the
|
|
843
|
+
non-linear paths, with reversed stop offsets so the first ECMA-376
|
|
844
|
+
stop sits at the focus center (matching PowerPoint's outward
|
|
845
|
+
painting order).
|
|
846
|
+
|
|
847
|
+
- 855076d: feat: chart value-axis major gridlines honor authored stroke color.
|
|
848
|
+
`ChartSpec.valueAxisMajorGridlineColor` extracts the
|
|
849
|
+
`<c:majorGridlines><c:spPr><a:ln><a:solidFill><a:srgbClr/>` color and
|
|
850
|
+
the playground renderer paints gridlines with it (falls through to the
|
|
851
|
+
existing light-gray default when no color is authored). Branded
|
|
852
|
+
templates with custom gridline tints finally render correctly.
|
|
853
|
+
- 74b227e: feat(site/playground): hyperlink tooltips. Shape and per-run
|
|
854
|
+
hyperlinks now surface their `<a:hlinkClick tooltip="…"/>` text —
|
|
855
|
+
shapes get an SVG `<title>` child on the `<a>` wrapper, runs get a
|
|
856
|
+
`title=` attribute on the HTML anchor. PowerPoint shows these on
|
|
857
|
+
hover during the slideshow; the playground now does too.
|
|
858
|
+
- a610e82: feat: `getShapeHyperlinkTooltip(shape)` and
|
|
859
|
+
`getShapeRunHyperlinkTooltip(shape, p, r)` return the
|
|
860
|
+
`<a:hlinkClick tooltip="…"/>` text. Tooltips show up in PowerPoint
|
|
861
|
+
when the user hovers a linked shape in slide-show mode — useful for
|
|
862
|
+
accessibility and link-preview surfaces.
|
|
863
|
+
- cbdda7c: feat(site/playground): render `<a:duotone>` image recolor. The filter
|
|
864
|
+
pipeline desaturates the picture to luminance, then samples a
|
|
865
|
+
two-color gradient (firstColor → secondColor) via a 16-step
|
|
866
|
+
`feComponentTransfer` table. Pictures with PowerPoint's Color >
|
|
867
|
+
Recolor preset finally render in their authored two-color tint.
|
|
868
|
+
- c4a89c1: feat: `getShapeImageDuotone(pres, shape)` reads the picture's
|
|
869
|
+
`<a:blip><a:duotone>` two-color recolor effect — the typical
|
|
870
|
+
"Picture Tools > Recolor" output. Returns the two hex-resolved
|
|
871
|
+
colors (or `null` for each that the duotone didn't author). Lets
|
|
872
|
+
downstream renderers project the duotone via SVG `<filter>` or
|
|
873
|
+
inform consumers that the picture has a color-replacement applied.
|
|
874
|
+
- 99fcb65: feat: image color-effect readers — `isShapeImageGrayscale(shape)`
|
|
875
|
+
detects `<a:blip><a:grayscl/>` (Color > Grayscale), and
|
|
876
|
+
`getShapeImageBiLevelThreshold(shape)` returns the threshold percent
|
|
877
|
+
for `<a:blip><a:biLevel thresh="…"/>` (Color > Black and White).
|
|
878
|
+
Renderers can project these onto CSS / SVG filters.
|
|
879
|
+
- 263bf52: feat: `getShapeImageLinkUrl(shape)` returns the external URL of a
|
|
880
|
+
picture whose `<a:blip>` carries an `r:link` (Insert > "Link to file")
|
|
881
|
+
instead of `r:embed`. Bytes for these aren't in the package; the
|
|
882
|
+
playground now shows the linked URL in the placeholder rather than a
|
|
883
|
+
generic "no bytes" label.
|
|
884
|
+
- 508627a: feat(site/playground): grayscale + biLevel image filters in the
|
|
885
|
+
playground. The filter pipeline now composes:
|
|
886
|
+
|
|
887
|
+
1. brightness + contrast (linear feComponentTransfer)
|
|
888
|
+
2. grayscale (luminance-preserving feColorMatrix) when
|
|
889
|
+
`<a:blip><a:grayscl/>` is set
|
|
890
|
+
3. biLevel two-tone (discrete tableValues snapped at the authored
|
|
891
|
+
threshold) when `<a:blip><a:biLevel thresh="…"/>` is set
|
|
892
|
+
|
|
893
|
+
Pictures with Color > Grayscale or Color > Black and White now
|
|
894
|
+
render with the same visual treatment PowerPoint shows.
|
|
895
|
+
|
|
896
|
+
- 66edcbc: feat: add `isShapeTextBox(shape)` — `true` when a shape is a text box
|
|
897
|
+
(`<p:cNvSpPr txBox="1">`) rather than an autoshape. The two have different
|
|
898
|
+
default text formatting (text boxes left/top, autoshapes center/middle), so
|
|
899
|
+
renderers and layout code need to tell them apart.
|
|
900
|
+
- 263bf52: feat: `getSlideLayoutBackground(layout)` mirrors `getSlideBackground`
|
|
901
|
+
for slide layouts. Playground falls back to it when the slide's own
|
|
902
|
+
background reports `'inherit'`, so brand-color or template backgrounds
|
|
903
|
+
authored on the layout actually paint behind slides that don't override
|
|
904
|
+
the bg themselves.
|
|
905
|
+
- 2a1d712: feat: `getSlideLayoutBackgroundGradientFill(layout)` returns the
|
|
906
|
+
gradient definition when a layout's background is
|
|
907
|
+
`<p:bgPr><a:gradFill>`. Same shape as the slide-level variant —
|
|
908
|
+
renderers can reuse the same projection logic for layout gradient
|
|
909
|
+
backgrounds via the shared `gradientDef` helper.
|
|
910
|
+
- a1229d5: feat: `getSlideLayoutBackgroundShapes(pres, layout)` returns the
|
|
911
|
+
non-placeholder shapes on a layout as a render-ready view
|
|
912
|
+
(`SlideLayoutBackgroundShape` — bounds, preset, fillHex, strokeHex,
|
|
913
|
+
strokeWidthEmu, rotation, flip). Playground paints them behind the
|
|
914
|
+
slide's own shapes so brand-template decoration (corner bars, divider
|
|
915
|
+
lines, background rectangles) shows through on slides that don't
|
|
916
|
+
redefine the layout themselves.
|
|
917
|
+
|
|
918
|
+
Adds the `SlideLayoutBackgroundShape` type to the public surface.
|
|
919
|
+
|
|
920
|
+
- ba056db: feat: `getSlideLayoutBackground` now handles `<p:bgRef>` the same way
|
|
921
|
+
`getSlideBackground` does. Layouts in real brand templates almost
|
|
922
|
+
always reference the theme via `<p:bgRef>` rather than authoring an
|
|
923
|
+
explicit `<p:bgPr>` — picking up the inner color element as a solid
|
|
924
|
+
fill closes the cascade so the playground paints the right brand
|
|
925
|
+
color even when the slide's own background reports `inherit`.
|
|
926
|
+
- 3ea2ed5: feat(site/playground): line / area chart legend swatches use the
|
|
927
|
+
series marker glyph. The legend previously rendered every series as
|
|
928
|
+
a 9×9 square color rect. For `line` / `area` charts the renderer now
|
|
929
|
+
passes the per-series `markerSymbol` (circle / square / diamond /
|
|
930
|
+
triangle / star / x / plus / dash / dot) so legend entries match
|
|
931
|
+
the data points. Bar / column / pie keep the square swatch.
|
|
932
|
+
- b1073ff: feat(site/playground): right / left chart legend stack centers
|
|
933
|
+
vertically. Previously the `r` and `l` legend positions both
|
|
934
|
+
stacked from a fixed `f.y + 12` top, the same as `tr`. PowerPoint
|
|
935
|
+
vertically-centers right / left legends inside the chart area; the
|
|
936
|
+
renderer now matches by computing `yStart` from the legend's total
|
|
937
|
+
height. `tr` keeps the top-anchored stack.
|
|
938
|
+
- ee27024: feat: chart legend honors authored `<c:txPr>` font / color.
|
|
939
|
+
`ChartSpec.legend.textStyle` carries the same `ChartTextStyle` shape
|
|
940
|
+
used for the chart title and axis titles. The playground renderer
|
|
941
|
+
projects font-size, bold, italic, and fill color onto every legend
|
|
942
|
+
label across all four position layouts (right / left / top / bottom /
|
|
943
|
+
top-right).
|
|
944
|
+
- fca13ca: feat(site/playground): line and area charts paint per-point value labels
|
|
945
|
+
when `<c:dLbls><c:showVal val="1"/>` is set. Labels sit just above each
|
|
946
|
+
marker and route through the chart number-format projector (so
|
|
947
|
+
`<c:numFmt formatCode="0%"/>` etc. apply the same as on bar / pie).
|
|
948
|
+
Honors the per-series → chart-level cascade.
|
|
949
|
+
- 263bf52: feat: `getParagraphLineSpacing(shape, p)` returns the paragraph's
|
|
950
|
+
`<a:lnSpc>` as `{ kind: 'pct' | 'pts', value }`. Percent values come
|
|
951
|
+
through as a unit fraction (1.5 = 150%); point values are pt.
|
|
952
|
+
|
|
953
|
+
The playground projects both forms to CSS `line-height` per paragraph,
|
|
954
|
+
and uses the existing `getParagraphSpacing` to project spcBef / spcAft
|
|
955
|
+
to `margin-top` / `margin-bottom`. Text blocks now keep the vertical
|
|
956
|
+
rhythm the deck authored instead of falling back to a fixed line
|
|
957
|
+
height for everything.
|
|
958
|
+
|
|
959
|
+
- 5381e9d: feat(chart): line / area charts now overlay the per-series
|
|
960
|
+
`<c:trendline>` when authored. Same regression types as the
|
|
961
|
+
column-chart variant (linear / log / exp / movingAvg / poly+power
|
|
962
|
+
fallback). Only emitted on the clustered layout — stacked plots
|
|
963
|
+
already convey the cumulative shape.
|
|
964
|
+
- ef4d410: feat: `getSlideMasterBackground(pres, layout)` returns the master's
|
|
965
|
+
`<p:bg>` (both `<p:bgPr>` and `<p:bgRef>` forms). Playground extends
|
|
966
|
+
its background fallback chain to slide → layout → master so brand
|
|
967
|
+
backgrounds authored on the master alone finally render on inheriting
|
|
968
|
+
slides instead of falling through to the theme's `light1`.
|
|
969
|
+
- 9c7a852: feat: `getSlideMasterBackgroundGradientFill(pres, layout)` returns
|
|
970
|
+
the master's gradient background when `<p:bg><p:bgPr><a:gradFill>`
|
|
971
|
+
is authored. Completes the three-level bg cascade for gradient
|
|
972
|
+
backgrounds — slides can fall through slide → layout → master.
|
|
973
|
+
- 60df186: feat: more name-based finders now accept `RegExp` —
|
|
974
|
+
`findSlideLayout(pres, name)`,
|
|
975
|
+
`findCommentAuthorByName(pres, authorName)`, and
|
|
976
|
+
`findSlidesByLayoutName(pres, layoutName)`. Pairs the RegExp support
|
|
977
|
+
recently added to `findShapeByName` / `findShapesByName` /
|
|
978
|
+
`findCommentsByAuthor` / `findSlideByTitle`. String callers unchanged.
|
|
979
|
+
- 10a9d05: feat: `getParagraphPropertiesEffective(pres, shape, p)` — paragraph-property
|
|
980
|
+
cascade mirroring the rPr one. Resolves alignment, left / right / first-line
|
|
981
|
+
indents, line spacing, paragraph spacing (before / after), and rtl through
|
|
982
|
+
the paragraph → text-body lstStyle → layout placeholder lstStyle →
|
|
983
|
+
master placeholder lstStyle → master txStyles chain.
|
|
984
|
+
|
|
985
|
+
The playground uses it as the primary source of paragraph properties so
|
|
986
|
+
placeholders inherit their default alignment / line-spacing / indent from
|
|
987
|
+
the layout / master, with any per-slide override winning on top.
|
|
988
|
+
|
|
989
|
+
Adds the `ParagraphProperties` type to the public surface.
|
|
990
|
+
|
|
991
|
+
- 263bf52: feat: `getShapeParagraphElements(shape, paragraphIndex)` returns the
|
|
992
|
+
inline children of a paragraph (runs, field placeholders, and line
|
|
993
|
+
breaks) in document order. Renderers can walk this list to reproduce
|
|
994
|
+
the full visible content — footer / date / slide-number `<a:fld>`
|
|
995
|
+
text was previously dropped by the strict `<a:r>`-only run accessors.
|
|
996
|
+
|
|
997
|
+
The playground now uses it: footer text + slide numbers + datetime
|
|
998
|
+
fields show up in the preview, and `<a:br>` line breaks render as
|
|
999
|
+
real `<br/>` inside the foreignObject body.
|
|
1000
|
+
|
|
1001
|
+
Adds the `ShapeParagraphElement` discriminated union to the public
|
|
1002
|
+
type surface.
|
|
1003
|
+
|
|
1004
|
+
- 263bf52: feat: `getParagraphIndent(shape, p)` returns the paragraph's
|
|
1005
|
+
`<a:pPr marL marR indent>` values in EMU (`null` for sides the
|
|
1006
|
+
paragraph doesn't author). Playground projects each side to CSS
|
|
1007
|
+
`padding-left` / `padding-right` / `text-indent` and skips the
|
|
1008
|
+
level-based default when the paragraph carries an explicit `marL`.
|
|
1009
|
+
- 263bf52: feat: `getShapePatternFill(pres, shape)` returns the pattern preset
|
|
1010
|
+
token plus the foreground / background colors resolved against the
|
|
1011
|
+
deck's theme. Pairs with the existing `setShapePatternFill`. The
|
|
1012
|
+
playground renderer now paints real SVG `<pattern>` tiles for the
|
|
1013
|
+
common `ST_PresetPatternVal` tokens (pct5..pct90, light/dark diagonal
|
|
1014
|
+
and horizontal/vertical stripes, grids, weave, wave, sphere, diamonds)
|
|
1015
|
+
instead of substituting a flat tint.
|
|
1016
|
+
- 1b08908: feat(chart): per-series `<c:ser><c:dLbls>` overrides. `ChartSeries.dataLabels`
|
|
1017
|
+
mirrors the chart-level `ChartSpec.dataLabels`; the series-level
|
|
1018
|
+
override wins when present. Playground's bar / column renderers
|
|
1019
|
+
check the per-series flag first so one series can show labels while
|
|
1020
|
+
others stay clean — common in financial decks.
|
|
1021
|
+
- 263bf52: feat: playground now applies the picture corrections that already
|
|
1022
|
+
shipped on the API: source-rectangle crop (`<a:srcRect>`), brightness
|
|
1023
|
+
(`<a:lumOff>`), contrast (`<a:lumMod>`), and opacity (`<a:alphaModFix>`).
|
|
1024
|
+
|
|
1025
|
+
Crops project to an enlarged `<image>` element clipped to the shape's
|
|
1026
|
+
bounds (matching PowerPoint's "Crop" tool). Brightness + contrast
|
|
1027
|
+
compose into an SVG `<feComponentTransfer>` filter. Opacity drives
|
|
1028
|
+
the `opacity` attribute directly.
|
|
1029
|
+
|
|
1030
|
+
- 7303fa8: feat(chart): `ChartSpec.firstSliceAngleDeg` reads `<c:firstSliceAng>`
|
|
1031
|
+
and `ChartSpec.holeSizePct` reads `<c:holeSize>` for doughnut charts.
|
|
1032
|
+
Playground rotates the first slice's starting position clockwise from
|
|
1033
|
+
12 o'clock per the authored angle, and sizes the doughnut hole at the
|
|
1034
|
+
authored percent (10..90) of the outer radius instead of the
|
|
1035
|
+
hard-coded 55%.
|
|
1036
|
+
- 0ca34e1: feat: pie / doughnut slice explosion. `ChartSeries.pointExplosions`
|
|
1037
|
+
exposes the per-data-point pull-out percentage from `<c:dPt><c:explosion val="N"/>`,
|
|
1038
|
+
and the playground renderer offsets exploded slices (and their labels)
|
|
1039
|
+
outward along the slice mid-angle. Matches the "pulled-out" pie look
|
|
1040
|
+
authors get from Excel's "Vary colors by point" toggle.
|
|
1041
|
+
- 2e9776d: feat(site/playground): chart / media count badges on each slide.
|
|
1042
|
+
`getSlideCharts(slide)` and `getSlideMediaPartNames(pres, slide)`
|
|
1043
|
+
power two new badges (`N chart`, `N media`) showing how many chart
|
|
1044
|
+
shapes and how many media parts (images / audio / video) the slide
|
|
1045
|
+
references — useful for quick deck audits.
|
|
1046
|
+
- 997d507: feat(site/playground): comment badge tooltip carries the comment
|
|
1047
|
+
texts. The `N cmt` badge's `title=` attribute now joins each
|
|
1048
|
+
comment's body text so hovering surfaces the review remarks
|
|
1049
|
+
without opening PowerPoint.
|
|
1050
|
+
- 3ede588: feat(site/playground): additional slide badges — `hidden` (when
|
|
1051
|
+
`show="0"`) and `N cmt` (count of authored review comments). Threads
|
|
1052
|
+
`isSlideHidden` and `getSlideComments` through the slide-snapshot
|
|
1053
|
+
and surfaces both next to the existing `trans` / `anim` badges, so
|
|
1054
|
+
audit views see the full set of slide-level flags at a glance.
|
|
1055
|
+
- 7a489fa: feat(site/playground): layout-type badge tooltip carries the
|
|
1056
|
+
user-visible layout name. Hovering the small `obj` / `title` / etc.
|
|
1057
|
+
badge now reveals `layout: <Name> (type: <token>)` from
|
|
1058
|
+
`getSlideLayoutName(layout)`. Helps identify which authored layout
|
|
1059
|
+
each slide is bound to without leaving the playground.
|
|
1060
|
+
- d7d8571: feat(site/playground): show the slide's layout type (`title`, `obj`,
|
|
1061
|
+
`twoObj`, `blank`, …) as a badge next to the slide title. Reads
|
|
1062
|
+
`<p:sldLayout type="…">` via `getSlideLayout` + `getSlideLayoutType`
|
|
1063
|
+
so deck audits can spot which layout each slide is bound to without
|
|
1064
|
+
opening PowerPoint.
|
|
1065
|
+
- 5861d1e: feat(site/playground): include slide-master count in the
|
|
1066
|
+
"masters · layouts · sections" meta cell. `getPresentationSummary`
|
|
1067
|
+
already returned layout / section counts; the playground now also
|
|
1068
|
+
calls `getSlideMasterCount` so multi-master decks surface that fact
|
|
1069
|
+
in the audit panel.
|
|
1070
|
+
- 9a64bb4: feat(site/playground): expose `getPresentationSummary` data in the
|
|
1071
|
+
meta panel — theme name, layout / section counts, total shape count,
|
|
1072
|
+
and deck-wide flags (hidden slides, charts, comments, animations).
|
|
1073
|
+
Gives deck audits a one-glance overview without scrolling through
|
|
1074
|
+
every slide.
|
|
1075
|
+
- d9ba44d: feat(site/playground): render section dividers in the slide list.
|
|
1076
|
+
Reads `getSlideSections(pres)`, maps each section's first slide to
|
|
1077
|
+
the section's name, and renders a dashed divider above that slide
|
|
1078
|
+
in the slide list. Deck audits can now see the section grouping at
|
|
1079
|
+
a glance.
|
|
1080
|
+
- 62069f7: feat(site/playground): make the per-slide number an anchor link.
|
|
1081
|
+
Each slide's two-digit index in the head row is now an `<a
|
|
1082
|
+
href="#slide-N">` link, so users can right-click → "Copy link
|
|
1083
|
+
address" to share a deep link to a specific slide. Paired with the
|
|
1084
|
+
`id="slide-N"` already on each `<li>`, the link also scrolls the
|
|
1085
|
+
slide into view when clicked.
|
|
1086
|
+
- ffec23d: feat(site/playground): show speaker notes under each slide. The
|
|
1087
|
+
playground now calls `getSlideNotes` for every slide and renders a
|
|
1088
|
+
collapsible `<details>` block when notes exist, so users can
|
|
1089
|
+
inspect the deck author's notes without opening PowerPoint.
|
|
1090
|
+
- b90f1bc: feat(site/playground): show `validatePresentation` results. The
|
|
1091
|
+
playground now runs the validator after parsing and surfaces any
|
|
1092
|
+
issues in a dedicated panel (with severity tint and the offending
|
|
1093
|
+
part name when available). Lets users spot missing rels, dangling
|
|
1094
|
+
slide IDs, etc. without dropping into the test harness.
|
|
1095
|
+
- e078498: feat: `getShapeRunClickAction(shape, p, r)` returns the per-run
|
|
1096
|
+
hlinkClick action with the same `ShapeClickAction` discriminated
|
|
1097
|
+
union the shape-level `getShapeClickAction` uses. Recognises external
|
|
1098
|
+
URLs, slide-jump (`ppaction://hlinksldjump`), and the four
|
|
1099
|
+
nav-preset actions (next / prev / first / last slide). Lets callers
|
|
1100
|
+
treat per-run hyperlinks symmetrically with shape-level ones.
|
|
1101
|
+
- 5015413: feat(site/playground): per-run hyperlinks. Runs carrying `<a:hlinkClick>`
|
|
1102
|
+
now render in the theme's hyperlink color with an underline, and the
|
|
1103
|
+
span is wrapped in an `<a href>` so the preview is clickable. Per-run
|
|
1104
|
+
font / color / formatting overrides still apply on top — the link
|
|
1105
|
+
styling fills the gaps the run didn't author.
|
|
1106
|
+
- cc592d2: feat(site/playground): per-run slide-jump click actions render as
|
|
1107
|
+
in-page anchors. Mirrors the shape-level slide-jump support shipped
|
|
1108
|
+
in the prior batch — `getShapeRunClickAction` resolves to either a
|
|
1109
|
+
URL or `#slide-N` anchor, and the run-level `<a href>` wrapper
|
|
1110
|
+
respects whether the href is in-page (no `target=_blank`) or
|
|
1111
|
+
external.
|
|
1112
|
+
- 2207ed1: feat: scatter, radar, and bubble charts are now modeled as their own
|
|
1113
|
+
`ChartKind`s instead of being folded into `line`. `ChartSeries` gains
|
|
1114
|
+
`xValues` (`<c:xVal>`) and `bubbleSizes` (`<c:bubbleSize>`); `ChartSpec`
|
|
1115
|
+
gains `scatterStyle`, `radarStyle`, `bubbleScale`, and
|
|
1116
|
+
`bubbleSizeRepresents`. Read + render only: the preview draws real
|
|
1117
|
+
scatter (two value axes + markers), radar (polar spokes/rings), and
|
|
1118
|
+
bubble (area-proportional circles) plots, and the write path now rejects
|
|
1119
|
+
these kinds loudly — previously a read-modify-write silently corrupted a
|
|
1120
|
+
scatter chart into a line chart.
|
|
1121
|
+
- 08dc68b: feat(chart): `ChartSeries.lineWidthEmu` and `lineDash` read
|
|
1122
|
+
`<c:ser><c:spPr><a:ln>` per-series stroke width and preset dash.
|
|
1123
|
+
Playground line / area renderer uses the authored stroke width
|
|
1124
|
+
(scaled to px) and projects the preset dash to the same
|
|
1125
|
+
`stroke-dasharray` cadence shape strokes use.
|
|
1126
|
+
- e09e734: feat(chart): per-series marker symbol + size.
|
|
1127
|
+
`ChartSeries.markerSymbol` / `markerSizePt` read `<c:ser><c:marker>`
|
|
1128
|
+
(`<c:symbol val="…"/>` + `<c:size val="N"/>`). Playground line / area
|
|
1129
|
+
renderer emits the matching SVG glyph at each data point — circle /
|
|
1130
|
+
square / diamond / triangle / star / x / plus / dash / dot — sized
|
|
1131
|
+
per the authored point value. `none` hides the markers.
|
|
1132
|
+
- 995825f: feat: `setShapeHyperlink` and `setShapeRunHyperlink` now accept an
|
|
1133
|
+
optional `tooltip` argument that writes a `tooltip="…"` attribute on the
|
|
1134
|
+
emitted `<a:hlinkClick>`. Backwards compatible — calls that omit the new
|
|
1135
|
+
arg behave exactly as before.
|
|
1136
|
+
|
|
1137
|
+
fix: `getShapeHyperlinkTooltip` previously only looked at the shape's
|
|
1138
|
+
`<p:cNvPr><a:hlinkClick>`, missing the run-level tooltip that
|
|
1139
|
+
`setShapeHyperlink` writes. It now scans run-level `<a:rPr>` first
|
|
1140
|
+
(mirroring `getShapeHyperlink`'s read path) and falls back to the
|
|
1141
|
+
shape-click hyperlink — so the reader / writer pair is consistent.
|
|
1142
|
+
|
|
1143
|
+
- 051f4bb: feat: writers for the three stroke attributes that had readers but no
|
|
1144
|
+
setters — `setShapeStrokeCap(shape, 'rnd' | 'sq' | 'flat' | null)`,
|
|
1145
|
+
`setShapeStrokeJoin(shape, 'round' | 'bevel' | 'miter' | null)`, and
|
|
1146
|
+
`setShapeStrokeCompound(shape, 'sng' | 'dbl' | 'thickThin' | 'thinThick' | 'tri' | null)`.
|
|
1147
|
+
|
|
1148
|
+
Cap and compound map to `<a:ln cap=…/>` and `<a:ln cmpd=…/>` attributes;
|
|
1149
|
+
join writes one of the `<a:round/>` / `<a:bevel/>` / `<a:miter/>` child
|
|
1150
|
+
variants. Passing `null` clears the attribute / removes the child so the
|
|
1151
|
+
shape inherits the default. Creates `<a:ln>` if absent.
|
|
1152
|
+
|
|
1153
|
+
- 56da3ee: feat: `setShapeTextBodyRotationDeg(shape, rotationDeg | null)` — companion
|
|
1154
|
+
writer for the existing `getShapeTextBodyRotationDeg` reader. Sets
|
|
1155
|
+
`<a:bodyPr rot="N"/>` (in 60000ths of a degree, per OOXML) so the text
|
|
1156
|
+
body can rotate independently of the shape's own `<p:xfrm rot>`. Passing
|
|
1157
|
+
`null` or `0` clears the attribute so the shape inherits the default.
|
|
1158
|
+
- a65c05c: feat: `setShapeTextColumns(shape, { count, gapEmu? } | null)` — multi-
|
|
1159
|
+
column writer pairing the existing `getShapeTextColumns` reader. Writes
|
|
1160
|
+
`<a:bodyPr numCol="N" [spcCol="EMU"]/>`. Passing `null` clears both
|
|
1161
|
+
attributes so the text body falls back to PowerPoint's default single
|
|
1162
|
+
column. `count` must be `>= 2` (single column is the default — pass
|
|
1163
|
+
`null` instead); the function throws otherwise.
|
|
1164
|
+
- fea7725: feat: `setShapeTextDirection(shape, direction | null)` — companion
|
|
1165
|
+
writer for the existing `getShapeTextDirection` reader. Sets
|
|
1166
|
+
`<a:bodyPr vert="…"/>` with any of the six `ST_TextVerticalType`
|
|
1167
|
+
values (`vert`, `vert270`, `wordArtVert`, `eaVert`, `mongolianVert`,
|
|
1168
|
+
`wordArtVertRtl`); passing `null` or `'horz'` clears the attribute so
|
|
1169
|
+
the shape uses the default horizontal direction.
|
|
1170
|
+
- 4006813: feat: `setTableCellAnchor(cell, 'top' | 'center' | 'bottom' | null)` and
|
|
1171
|
+
`setTableCellMargins(cell, {left?, right?, top?, bottom?} | null)` —
|
|
1172
|
+
writers for two `<a:tcPr>` properties that already had readers
|
|
1173
|
+
(`getTableCellAnchor`, `getTableCellMargins`). The anchor setter maps
|
|
1174
|
+
`top`/`center`/`bottom` to the schema's `t`/`ctr`/`b` values and clears
|
|
1175
|
+
the attribute on `null`. The margins setter writes per-side EMU on
|
|
1176
|
+
`marL`/`marR`/`marT`/`marB`; sides set to `null`/`undefined` are
|
|
1177
|
+
stripped (PowerPoint falls back to its defaults); passing the whole
|
|
1178
|
+
arg as `null` clears every side. Both create `<a:tcPr>` if absent.
|
|
1179
|
+
- 3921802: feat: `setTableCellBorders(cell, sides | null)` — partial-update writer
|
|
1180
|
+
for all 6 cell-border slots (`left`, `right`, `top`, `bottom` + the
|
|
1181
|
+
`tlToBr` / `blToTr` diagonals). Pairs the existing
|
|
1182
|
+
`getTableCellBorders` reader. Sides listed with `null` are removed from
|
|
1183
|
+
`<a:tcPr>`; sides omitted are left untouched. Passing `null` as the
|
|
1184
|
+
whole `sides` arg clears every side. Creates `<a:tcPr>` if absent.
|
|
1185
|
+
|
|
1186
|
+
The diagonals are independent of the four cardinal sides — a
|
|
1187
|
+
strikethrough cell can have only `tlToBr`.
|
|
1188
|
+
|
|
1189
|
+
- c3e01b3: feat: `setTableCellTextDirection(cell, direction | null)` — vertical-
|
|
1190
|
+
text writer for table cells, paired with the existing
|
|
1191
|
+
`getTableCellTextDirection` reader. Same six `ST_TextVerticalType`
|
|
1192
|
+
values as `setShapeTextDirection`. Passing `null` (or `'horz'`) clears
|
|
1193
|
+
the `<a:tcPr vert="…"/>` attribute so the cell uses the default
|
|
1194
|
+
horizontal direction. Creates `<a:tcPr>` if absent.
|
|
1195
|
+
- 328f207: feat: `setTableStyleFlags(table, flags)` — partial-update writer for
|
|
1196
|
+
the six `<a:tblPr>` boolean style flags (`firstRow`, `lastRow`,
|
|
1197
|
+
`firstCol`, `lastCol`, `bandRow`, `bandCol`). Pairs the existing
|
|
1198
|
+
`getTableStyleFlags` reader. Only the keys present in `flags` are
|
|
1199
|
+
touched — omitted keys keep their current state. A flag set to `false`
|
|
1200
|
+
strips the attribute (matching how PowerPoint round-trips defaults).
|
|
1201
|
+
Creates `<a:tblPr>` if absent. Throws when the shape isn't a table
|
|
1202
|
+
graphic frame.
|
|
1203
|
+
- 1ea509b: feat: `setTableStyleId(table, styleId | null)` — writer for
|
|
1204
|
+
`<a:tbl><a:tblPr><a:tableStyleId>`. Pairs the existing `getTableStyleId`
|
|
1205
|
+
reader. Pass the curly-braced GUID (e.g.
|
|
1206
|
+
`'{5C22544A-7EE6-4342-B048-85BDC9FD1C3A}'` for PowerPoint's "Medium
|
|
1207
|
+
Style 2 - Accent 1") or `null` to remove the reference so the table
|
|
1208
|
+
uses the slide's default style. Creates `<a:tblPr>` if absent. Throws
|
|
1209
|
+
when the shape isn't a table graphic frame.
|
|
1210
|
+
- 2438696: feat(site/playground): shape `aria-label` from authored alt text.
|
|
1211
|
+
Each rendered shape with a non-empty alt title (or, as fallback,
|
|
1212
|
+
alt description) now exposes `role="img" aria-label="…"` on the
|
|
1213
|
+
root `<g>`. Screen readers announce decks the same way PowerPoint's
|
|
1214
|
+
Accessibility Inspector reports them, without affecting visuals.
|
|
1215
|
+
- b8e24d6: feat(site/playground): each shape's authored name surfaces as a
|
|
1216
|
+
`data-pptx-shape-name` attribute on its root `<g>` element. Lets
|
|
1217
|
+
DevTools, a11y inspectors, or test selectors target shapes by their
|
|
1218
|
+
PowerPoint name without parsing SVG geometry. Cheap to emit and has
|
|
1219
|
+
no visual impact.
|
|
1220
|
+
- fdd4770: feat: `getShapeTextBodyRotationDeg(shape)` returns the shape's text-body
|
|
1221
|
+
rotation from `<a:bodyPr rot="N"/>` (where N is in 60000ths of a
|
|
1222
|
+
degree). Distinct from the shape's geometry rotation (`<p:xfrm rot>`):
|
|
1223
|
+
this rotates the text body _inside_ the shape without rotating the
|
|
1224
|
+
geometry. The playground renderer pivots the text body around the
|
|
1225
|
+
inset midpoint when the angle is non-zero, matching PowerPoint's
|
|
1226
|
+
behaviour for vertical-label callouts and rotated text frames.
|
|
1227
|
+
- 263bf52: feat: `getSlideBackgroundGradientFill(slide)` returns the gradient
|
|
1228
|
+
stops + path for slides with a `<p:bgPr><a:gradFill>` background.
|
|
1229
|
+
Playground paints gradient slide backgrounds via the same projector
|
|
1230
|
+
that handles shape gradients (linear / radial / rect / shape).
|
|
1231
|
+
- 263bf52: feat: `getSlideBackgroundPatternFill(pres, slide)` returns the pattern
|
|
1232
|
+
preset + theme-resolved foreground / background for slides whose
|
|
1233
|
+
`<p:bgPr>` carries a `<a:pattFill>`. Playground now paints pattern
|
|
1234
|
+
slide backgrounds via the same SVG `<pattern>` tile generator that
|
|
1235
|
+
handles shape pattern fills.
|
|
1236
|
+
- c2bcc39: feat: `getSlideBackground` now handles `<p:bgRef>` (the theme-fill-
|
|
1237
|
+
reference variant of slide background, e.g. `<p:bgRef idx="1003">
|
|
1238
|
+
<a:schemeClr val="bg1"/></p:bgRef>`). Returns the inner color element
|
|
1239
|
+
as a solid fill so renderers paint the slide background even when
|
|
1240
|
+
the deck uses the theme-reference form instead of explicit `<p:bgPr>
|
|
1241
|
+
<a:solidFill>`.
|
|
1242
|
+
- 8b7cab6: feat: `slideHasAnimations(slide)` — per-slide animation predicate.
|
|
1243
|
+
Returns `true` when the slide carries a `<p:timing>` block (at least
|
|
1244
|
+
one authored animation effect). Complements the deck-wide
|
|
1245
|
+
`getPresentationSummary().hasAnimations`. The site playground uses
|
|
1246
|
+
it (plus `getSlideTransition`) to show small `anim` / `trans`
|
|
1247
|
+
badges next to each slide title so deck audits don't need to open
|
|
1248
|
+
PowerPoint.
|
|
1249
|
+
- c0e0dc2: feat(site/playground): shapes with slide-jump click actions
|
|
1250
|
+
(`<a:hlinkClick action="ppaction://hlinksldjump"/>`) render as
|
|
1251
|
+
in-page hash anchors. The renderer resolves the target via
|
|
1252
|
+
`getShapeClickAction` and emits `<a href="#slide-N">`; each slide's
|
|
1253
|
+
`<li>` carries `id="slide-N"` so clicks scroll to the target slide.
|
|
1254
|
+
Plain URL click actions render the same way as shape-level
|
|
1255
|
+
hyperlinks (with `target="_blank"`).
|
|
1256
|
+
- 7410df9: feat: `getSlideMasterPartName(slide)` returns the part-name of the
|
|
1257
|
+
slide master the slide inherits from. Useful for multi-master decks
|
|
1258
|
+
where different slides live under different brand templates and the
|
|
1259
|
+
caller needs to scope theme / fontScheme / clrMap lookups to the
|
|
1260
|
+
correct master.
|
|
1261
|
+
- 1f536ab: feat: `getShapeStrokeEffective(pres, shape)` walks the layout → master
|
|
1262
|
+
placeholder cascade when the shape's own stroke is `'inherit'`. Same
|
|
1263
|
+
discriminant types (solid / none / inherit) as `getShapeStroke`; first
|
|
1264
|
+
non-inherit layer wins. Playground uses it so placeholder outlines
|
|
1265
|
+
authored on the master / layout finally render.
|
|
1266
|
+
- 263bf52: feat: full stroke read-back surface — `getShapeStrokeCap`,
|
|
1267
|
+
`getShapeStrokeJoin`, `getShapeStrokeCompound` plus the existing
|
|
1268
|
+
`getShapeStrokeDash` / `getShapeStrokeArrow`. Renderers now have
|
|
1269
|
+
enough information to reproduce dashed outlines, rounded vs square
|
|
1270
|
+
caps, miter vs bevel joins, and per-end arrow heads.
|
|
1271
|
+
|
|
1272
|
+
The playground composes `stroke-dasharray` from the preset dash
|
|
1273
|
+
patterns (cadence multiplied by stroke width as PowerPoint does),
|
|
1274
|
+
emits SVG `<marker>` defs for triangle / stealth / diamond / oval
|
|
1275
|
+
arrowheads on connectors and shapes, and maps cap / join through.
|
|
1276
|
+
|
|
1277
|
+
- f68bd96: feat(site/playground): table cell borders honor `<a:prstDash>`. The
|
|
1278
|
+
reader already surfaced the dash token; the renderer now projects it
|
|
1279
|
+
to an SVG `stroke-dasharray` (scaled by the border's authored width).
|
|
1280
|
+
Applies to every side, the top-left → bottom-right diagonal, and the
|
|
1281
|
+
bottom-left → top-right diagonal.
|
|
1282
|
+
- a037fa7: feat: `getTableCellAnchor(cell)` returns the cell's vertical text
|
|
1283
|
+
anchor (`<a:tcPr anchor="t|ctr|b"/>`) as `'top' | 'center' |
|
|
1284
|
+
'bottom' | null`. Playground projects each onto a CSS
|
|
1285
|
+
`justify-content` so cell text sits at the authored vertical
|
|
1286
|
+
position instead of always centering.
|
|
1287
|
+
- e50f1d6: feat(site/playground): table cell text honors authored `<a:tcPr
|
|
1288
|
+
marL/marR/marT/marB>` insets. The renderer previously hard-coded a
|
|
1289
|
+
4-pixel pad on every side; it now converts each EMU-valued margin to
|
|
1290
|
+
px (falling back to 4px only when the side isn't authored) so cells
|
|
1291
|
+
with custom inner padding line up the way PowerPoint shows them.
|
|
1292
|
+
- 42cf575: feat: `getTableCellMargins(cell)` returns the cell's `<a:tcPr marL
|
|
1293
|
+
marR marT marB>` inset margins in EMU. Each side is `null` when the
|
|
1294
|
+
cell doesn't author it, so renderers know to fall back to
|
|
1295
|
+
PowerPoint's defaults (91440 EMU / 0.1 in horizontal, 45720 EMU /
|
|
1296
|
+
0.05 in vertical).
|
|
1297
|
+
- ba94f5e: feat: `getTableCellParagraphs(cell)` returns a table cell's text as structured
|
|
1298
|
+
paragraphs — each carrying its alignment and per-run format (`size`, `bold`,
|
|
1299
|
+
`italic`, `color`, `font`, …) — the rich counterpart to `getTableCellText`,
|
|
1300
|
+
which only returns the flat visible string.
|
|
1301
|
+
- f05aa62: feat: `getTableCellTextDirection(cell)` reads `<a:tcPr vert="…"/>` —
|
|
1302
|
+
the same token set as `getShapeTextDirection` (`vert`, `vert270`,
|
|
1303
|
+
`eaVert`, `mongolianVert`, `wordArtVert`, `wordArtVertRtl`).
|
|
1304
|
+
Vertical column headers in tables commonly use `vert270` / `eaVert`
|
|
1305
|
+
so the header label reads bottom-to-top alongside its column.
|
|
1306
|
+
- 263bf52: feat: table span + border read-back.
|
|
1307
|
+
|
|
1308
|
+
- `getTableCellSpan(cell)` returns `{ gridSpan, rowSpan, hMerge, vMerge }`
|
|
1309
|
+
so renderers know which cells own a merged region and which are
|
|
1310
|
+
absorbed into one.
|
|
1311
|
+
- `getTableCellBorders(pres, cell)` returns per-side borders (left,
|
|
1312
|
+
right, top, bottom, plus the two diagonals tlToBr / blToTr) with
|
|
1313
|
+
theme-resolved colors, widths, and dash style.
|
|
1314
|
+
|
|
1315
|
+
Playground table rendering now honours both: merged cells are skipped
|
|
1316
|
+
on their absorbed positions, and per-cell borders render at the
|
|
1317
|
+
authored color / width on top of the default thin grid.
|
|
1318
|
+
|
|
1319
|
+
- 263bf52: feat: `getTableStyleFlags(table)` returns the `<a:tblPr>` boolean
|
|
1320
|
+
toggles — `firstRow` / `lastRow` / `firstCol` / `lastCol` / `bandRow`
|
|
1321
|
+
/ `bandCol`. Playground projects each onto a theme-derived tint
|
|
1322
|
+
(accent1 for header / footer rows, 92%-white-mixed accent for bands)
|
|
1323
|
+
when the cell doesn't supply an explicit fill of its own. Header text
|
|
1324
|
+
rendered on the accent gets white text instead of the default body
|
|
1325
|
+
color, matching PowerPoint's built-in table styles.
|
|
1326
|
+
- 243e731: feat: `getTableStyleId(table)` returns the GUID string inside
|
|
1327
|
+
`<a:tbl><a:tblPr><a:tableStyleId>`. PowerPoint references built-in
|
|
1328
|
+
table styles (`{5C22544A-…}` = Medium Style 2 - Accent 1, etc.) and
|
|
1329
|
+
theme-local styles by GUID. Returns `null` when the table doesn't
|
|
1330
|
+
author one.
|
|
1331
|
+
- dfae64a: feat: add `getSlideLayoutShapes(pres, layout)` and `getSlideMasterShapes(pres,
|
|
1332
|
+
layout)` — the non-placeholder decorative shapes (corner bars, divider lines,
|
|
1333
|
+
logos, watermark text) on a slide layout and its master, as render-ready
|
|
1334
|
+
`SlideShapeData`. Unlike the older flat `getSlideLayoutBackgroundShapes`, these
|
|
1335
|
+
include pictures and groups and work with every `getShape*` reader, so a
|
|
1336
|
+
picture logo's bytes resolve (against the layout/master's own relationship
|
|
1337
|
+
table). For reading/rendering — the handles are bound to the layout/master
|
|
1338
|
+
part, not a slide.
|
|
1339
|
+
- 263bf52: feat: `getShapeTextColumns(shape)` returns `{ count, gapEmu? }` for
|
|
1340
|
+
text bodies that author `<a:bodyPr numCol="N" spcCol="EMU"/>`.
|
|
1341
|
+
Playground emits `column-count` / `column-gap` on the foreignObject,
|
|
1342
|
+
so newspaper-style multi-column placeholders flow correctly.
|
|
1343
|
+
- 263bf52: feat: extend `TextFormat` with the remaining commonly-authored
|
|
1344
|
+
`CT_TextCharacterProperties` (ECMA-376 §17.18.83) attributes:
|
|
1345
|
+
|
|
1346
|
+
- `strike` — `true` / `false` / `'sngStrike'` / `'dblStrike'`
|
|
1347
|
+
- `spc` — character spacing in 1/100 pt
|
|
1348
|
+
- `kern` — kerning threshold in half-points
|
|
1349
|
+
- `baseline` — superscript / subscript offset as a unit fraction
|
|
1350
|
+
- `cap` — `'none'` / `'small'` / `'all'`
|
|
1351
|
+
- `highlight` — per-run background color
|
|
1352
|
+
|
|
1353
|
+
All round-trip through `setShapeRunFormat` / `getShapeRunFormat` and
|
|
1354
|
+
flow through `getShapeRunFormatEffective`'s inheritance cascade. The
|
|
1355
|
+
playground renderer honours each of them in the rendered HTML.
|
|
1356
|
+
|
|
1357
|
+
- dc98eb1: feat(site/playground): default text body to the theme's font scheme.
|
|
1358
|
+
`<a:fontScheme><a:majorFont>` becomes the default face for title /
|
|
1359
|
+
ctrTitle placeholders; `<a:minorFont>` covers everything else. The
|
|
1360
|
+
existing per-run `<a:rPr typeface>` override still wins. Templates
|
|
1361
|
+
that brand-themselves to Aptos / Inter / etc. now render with their
|
|
1362
|
+
authored fonts instead of always falling back to Calibri.
|
|
1363
|
+
- 263bf52: feat: Tier B fidelity batch.
|
|
1364
|
+
|
|
1365
|
+
- `getShapeTextDirection(shape)` returns the `<a:bodyPr vert="…"/>`
|
|
1366
|
+
token (`vert`, `vert270`, `wordArtVert`, `eaVert`, `mongolianVert`,
|
|
1367
|
+
`wordArtVertRtl`). Playground projects each onto a CSS
|
|
1368
|
+
`writing-mode` / `text-orientation` declaration so Asian and
|
|
1369
|
+
Mongolian-style vertical text renders without manual transforms.
|
|
1370
|
+
- Playground wraps shapes carrying a `<a:hlinkClick>` in an SVG `<a>`
|
|
1371
|
+
element so the preview is clickable — matches PowerPoint's
|
|
1372
|
+
slide-show behaviour for shape-level hyperlinks.
|
|
1373
|
+
- Group shape rendering now applies the group's own `<a:xfrm rot
|
|
1374
|
+
flipH flipV>` to the whole subtree before the scale + translate
|
|
1375
|
+
that maps internal coords onto slide coords.
|
|
1376
|
+
|
|
1377
|
+
- 4688af3: feat: chart trendline `<c:forward>` / `<c:backward>` extensions.
|
|
1378
|
+
`ChartTrendline.forward` and `backward` carry the N-period
|
|
1379
|
+
extrapolation past the last / before the first data point. The
|
|
1380
|
+
playground renderer projects the linear fit further along the x-axis
|
|
1381
|
+
by `N * step` so projected-future trendlines render the way
|
|
1382
|
+
PowerPoint shows them. Moving-average / log / poly trendlines keep
|
|
1383
|
+
their data-range output since extrapolation isn't meaningful for
|
|
1384
|
+
them.
|
|
1385
|
+
- 57117a7: feat: chart value-axis tick labels honor `<c:valAx><c:txPr><a:bodyPr
|
|
1386
|
+
rot="N"/>`. `ChartSpec.valueAxisLabelRotationDeg` returns the rotation
|
|
1387
|
+
in degrees (converted from OOXML's 60000ths-of-a-degree). The
|
|
1388
|
+
playground renders each value-axis tick label with a
|
|
1389
|
+
`transform=rotate()` around its anchor, symmetric to the
|
|
1390
|
+
`categoryAxisLabelRotationDeg` we already projected.
|
|
1391
|
+
- 3e1c8a1: feat: chart value-axis exposes `<c:scaling><c:logBase val="N"/>`.
|
|
1392
|
+
`ChartAxisScaling.logBase` carries the authored log base (commonly
|
|
1393
|
+
`2`, `10`, or `Math.E`). The reader clamps to PowerPoint's `[2, 1000]`
|
|
1394
|
+
range. Callers that round-trip charts now preserve the log-scale
|
|
1395
|
+
flag; the playground renderer still draws linear (log-scale
|
|
1396
|
+
projection is a follow-up — exposing the field unblocks it).
|
|
1397
|
+
|
|
1398
|
+
### Patch Changes
|
|
1399
|
+
|
|
1400
|
+
- 499c590: fix: presentation handles now interoperate across the `pptx-kit` and
|
|
1401
|
+
`pptx-kit/node` entry points. The two entries ship as separate bundles,
|
|
1402
|
+
and the opaque handles (`PresentationData`, `SlideData`, …) were keyed by
|
|
1403
|
+
plain `Symbol`s minted per bundle. Loading a deck with
|
|
1404
|
+
`loadPresentationFile` (from `pptx-kit/node`) and then reading it with,
|
|
1405
|
+
say, `getSlides` (from `pptx-kit`) crashed with
|
|
1406
|
+
`Cannot read properties of undefined`. The handle keys now use the global
|
|
1407
|
+
symbol registry (`Symbol.for`), so a handle from either entry is readable
|
|
1408
|
+
by the other — and by companion packages that bundle their own reader copy.
|
|
1409
|
+
- 8fc8f12: fix(site): playground stopped rendering after `SlideCommentData` was made
|
|
1410
|
+
opaque and `getSlideMediaPartNames` lost its `(pres, slide)` two-arg
|
|
1411
|
+
form. The playground was still doing `comment.text` and
|
|
1412
|
+
`getSlideMediaPartNames(pres, slide)`, both of which threw at runtime.
|
|
1413
|
+
Switched to the public `getCommentText(comment)` accessor and the
|
|
1414
|
+
single-arg `getSlideMediaPartNames(slide)` signature.
|
|
1415
|
+
- 3fb5101: fix: `getShapeRunFormatEffective` / `getParagraphPropertiesEffective` no longer
|
|
1416
|
+
inherit the slide master's `bodyStyle` for plain text boxes. A shape without a
|
|
1417
|
+
`<p:ph>` is not a placeholder, so its unsized runs now resolve to no inherited
|
|
1418
|
+
size (consumers apply the ~18pt text-box default) instead of wrongly picking up
|
|
1419
|
+
the master body size (often much larger). Real placeholders — including ones
|
|
1420
|
+
whose `<p:ph>` omits a `type` — still inherit as before. This makes effective
|
|
1421
|
+
text formatting match what PowerPoint and LibreOffice render for text boxes.
|
|
1422
|
+
- cfe8b69: fix: placeholder inheritance now applies the OOXML `ctrTitle`↔`title` and
|
|
1423
|
+
`subTitle`→`body` type equivalence. A `ctrTitle` (centered title) now inherits
|
|
1424
|
+
its layout/master `title` placeholder's `bodyPr` (e.g. `anchor="ctr"`),
|
|
1425
|
+
`lstStyle`, and geometry instead of dropping them — fixing
|
|
1426
|
+
`getShapeBodyPrEffective`, `getShapeBoundsResolved`,
|
|
1427
|
+
`getShapeRunFormatEffective`, and `getParagraphPropertiesEffective` for
|
|
1428
|
+
centered titles and subtitles.
|
|
1429
|
+
- 610ecac: fix(validator): `validatePresentation` now flags duplicate
|
|
1430
|
+
`<p:cNvPr id="N">` values inside a single slide's `<p:spTree>` as
|
|
1431
|
+
errors. PowerPoint requires every shape's non-visual ID to be unique
|
|
1432
|
+
within its slide; duplicates often appear after pasting shapes from
|
|
1433
|
+
another slide without re-allocating IDs. The walk recurses into
|
|
1434
|
+
`<p:grpSp>` so duplicates nested in groups are also caught.
|
|
1435
|
+
|
|
1436
|
+
## 1.0.0
|
|
1437
|
+
|
|
1438
|
+
### Major Changes
|
|
1439
|
+
|
|
1440
|
+
- f47b78b: **1.0.0** — first stable release. The public API is now frozen under SemVer.
|
|
1441
|
+
|
|
1442
|
+
**What works at 1.0:**
|
|
1443
|
+
|
|
1444
|
+
- **Read** any `.pptx` produced by PowerPoint, Keynote, Google Slides, or
|
|
1445
|
+
LibreOffice Impress, and save it back without corruption. Unknown
|
|
1446
|
+
extensions are preserved verbatim on round-trip.
|
|
1447
|
+
- **Template editing**: token / text replace across slides and speaker
|
|
1448
|
+
notes, image swap with geometry preserved, slide CRUD with placeholder
|
|
1449
|
+
inheritance from layout / master.
|
|
1450
|
+
- **Authoring on top of an existing master**: 180+ preset shapes, custom
|
|
1451
|
+
text formatting, tables, embedded charts (column / line / bar / pie /
|
|
1452
|
+
doughnut / area) with auto-generated xlsx, solid / gradient / pattern /
|
|
1453
|
+
image fills, shadows and glows, rotation / flip / z-order, hyperlinks
|
|
1454
|
+
and click actions, notes and comments, slide transitions, simple
|
|
1455
|
+
entrance / exit animations.
|
|
1456
|
+
- **Diagnostics**: `validatePresentation` returns invariant violations;
|
|
1457
|
+
every XML part is validated against the ECMA-376 XSDs in CI.
|
|
1458
|
+
- **Bundling**: one ESM build runs in both Node ≥ 20 and modern browsers.
|
|
1459
|
+
Tree-shaking is enforced by a CI test — minimal `load → save` bundle
|
|
1460
|
+
is < 75 KB unminified, full fn-API bundle is ~120 KB.
|
|
1461
|
+
|
|
1462
|
+
**Deferred to post-1.0** (read pass-through preserved on round-trip):
|
|
1463
|
+
|
|
1464
|
+
- Constructing new themes / masters / layouts from scratch.
|
|
1465
|
+
- SmartArt authoring.
|
|
1466
|
+
- Complex animation timing-tree authoring.
|
|
1467
|
+
- OLE / ActiveX authoring.
|
|
1468
|
+
- Document encryption (read + write).
|
|
1469
|
+
|
|
1470
|
+
**Performance (M-series Node 20):** 100-slide synthetic deck saves in
|
|
1471
|
+
~25 ms, loads in ~20 ms. 100 MB templates fit comfortably under the 2 s
|
|
1472
|
+
load/save targets.
|
|
1473
|
+
|
|
1474
|
+
**Migration:** if you were on the pre-1.0 class API
|
|
1475
|
+
(`Presentation` / `Slide` / `SlideShape` / `SlideLayout`), see the
|
|
1476
|
+
preceding changeset for the rename table. There is no class API at 1.0.
|
|
1477
|
+
|
|
1478
|
+
- 665c979: **BREAKING**: the class-based API (`Presentation`, `Slide`, `SlideShape`,
|
|
1479
|
+
`SlideLayout`) has been removed. Use the free-function API for every
|
|
1480
|
+
capability — one canonical path per operation.
|
|
1481
|
+
|
|
1482
|
+
| Was | Now |
|
|
1483
|
+
| -------------------------------- | ---------------------------------------- |
|
|
1484
|
+
| `Presentation.load(bytes)` | `loadPresentation(bytes)` |
|
|
1485
|
+
| `Presentation.create()` | `createPresentation()` |
|
|
1486
|
+
| `pres.save()` | `savePresentation(pres)` |
|
|
1487
|
+
| `pres.slides` | `getSlides(pres)` |
|
|
1488
|
+
| `pres.slideLayouts` | `getSlideLayouts(pres)` |
|
|
1489
|
+
| `pres.addSlide({ layout })` | `addSlide(pres, { layout })` |
|
|
1490
|
+
| `pres.removeSlide(slide)` | `removeSlide(pres, slide)` |
|
|
1491
|
+
| `pres.moveSlide(slide, i)` | `moveSlide(pres, slide, i)` |
|
|
1492
|
+
| `pres.duplicateSlide(slide)` | `duplicateSlide(pres, slide)` |
|
|
1493
|
+
| `pres.replaceTokens(map)` | `replaceTokensInPresentation(pres, map)` |
|
|
1494
|
+
| `slide.shapes` | `getSlideShapes(slide)` |
|
|
1495
|
+
| `slide.findPlaceholder('title')` | `findSlidePlaceholder(slide, 'title')` |
|
|
1496
|
+
| `slide.addTextBox(opts)` | `addSlideTextBox(slide, opts)` |
|
|
1497
|
+
| `slide.addShape(opts)` | `addSlideShape(slide, opts)` |
|
|
1498
|
+
| `slide.addImage(bytes, opts)` | `addSlideImage(slide, bytes, opts)` |
|
|
1499
|
+
| `slide.addTable(opts)` | `addSlideTable(slide, opts)` |
|
|
1500
|
+
| `slide.addLine(opts)` | `addSlideLine(slide, opts)` |
|
|
1501
|
+
| `slide.setBackground(color)` | `setSlideBackground(slide, color)` |
|
|
1502
|
+
| `slide.setTransition(opts)` | `setSlideTransition(slide, opts)` |
|
|
1503
|
+
| `slide.setNotes(text)` | `setSlideNotes(slide, text)` |
|
|
1504
|
+
| `slide.layout` | `getSlideLayout(slide)` |
|
|
1505
|
+
| `slide.notes` | `getSlideNotes(slide)` |
|
|
1506
|
+
| `slide.text` | `getSlideText(slide)` |
|
|
1507
|
+
| `shape.text` | `getShapeText(shape)` |
|
|
1508
|
+
| `shape.setText(value)` | `setShapeText(shape, value)` |
|
|
1509
|
+
| `shape.position` | `getShapePosition(shape)` |
|
|
1510
|
+
| `shape.setPosition(x, y)` | `setShapePosition(shape, x, y)` |
|
|
1511
|
+
| `shape.setFill(color)` | `setShapeFill(shape, color)` |
|
|
1512
|
+
| `shape.setStroke(opts)` | `setShapeStroke(shape, opts)` |
|
|
1513
|
+
| `shape.setRotation(deg)` | `setShapeRotation(shape, deg)` |
|
|
1514
|
+
| `shape.setHyperlink(url)` | `setShapeHyperlink(shape, url)` |
|
|
1515
|
+
| `layout.name` | `getSlideLayoutName(layout)` |
|
|
1516
|
+
|
|
1517
|
+
Node entry (`pptx-kit/node`) drops the `Presentation` subclass; use
|
|
1518
|
+
`loadPresentationFile` / `savePresentationToFile` instead.
|
|
1519
|
+
|
|
1520
|
+
**Why**: every capability used to have two paths through the public API
|
|
1521
|
+
— a class method and a free function. The duplication hurt
|
|
1522
|
+
discoverability (which one should you use?), made the bundle larger
|
|
1523
|
+
(class consumers dragged the whole prototype in), and forced every
|
|
1524
|
+
breaking change to land in two places. The free-function API is the
|
|
1525
|
+
canonical surface from now on.
|
|
1526
|
+
|
|
1527
|
+
### Minor Changes
|
|
1528
|
+
|
|
1529
|
+
- b41c502: Comprehensive feature surface for PPTX authoring + editing. This is the
|
|
1530
|
+
first release that covers every L1–L4 capability in the foundation
|
|
1531
|
+
plan. Highlights:
|
|
1532
|
+
|
|
1533
|
+
**Round-trip + template editing (L1 / L2)**
|
|
1534
|
+
|
|
1535
|
+
- `loadPresentation` / `savePresentation` (`Uint8Array` / `ArrayBuffer` / `Blob`).
|
|
1536
|
+
- Node convenience: `loadPresentationFile`, `savePresentationToFile`.
|
|
1537
|
+
- Token replace: `replaceTokensInPresentation`, `replaceTokensInSlide`.
|
|
1538
|
+
- Free-text replace: `replaceTextInPresentation`, `replaceTextInSlide`.
|
|
1539
|
+
- Slide CRUD: `addSlide`, `removeSlide`, `moveSlide`, `duplicateSlide`,
|
|
1540
|
+
`getSlideAt`, `getSlideIndex`, `clearSlideShapes`, `sortSlides`.
|
|
1541
|
+
- Cross-deck: `importSlide` (with image-media propagation).
|
|
1542
|
+
- Cross-slide: `copyShape`.
|
|
1543
|
+
- Diagnostics: `validatePresentation`, `getPresentationSummary`,
|
|
1544
|
+
`listPackageParts`, `readPackagePart`, `getMediaParts`,
|
|
1545
|
+
`setMediaPartBytes`, `compactPackage`.
|
|
1546
|
+
|
|
1547
|
+
**Authoring (L3)**
|
|
1548
|
+
|
|
1549
|
+
- Shapes: `addSlideTextBox`, `addSlideShape` (180+ presets),
|
|
1550
|
+
`addSlideLine`, `addSlideTable`, `addSlideImage`, `addSlideChart`.
|
|
1551
|
+
- Charts: `bar` / `column` / `line` / `pie` / `doughnut` / `area` with
|
|
1552
|
+
embedded xlsx; read/update via `getSlideCharts` / `setChartSpec`.
|
|
1553
|
+
- Tables: per-cell access (`getTableCells`, `setTableCellText`,
|
|
1554
|
+
`setTableCellFill`, `setTableCellTextFormat`,
|
|
1555
|
+
`setTableCellAlignment`); row + column insert/remove.
|
|
1556
|
+
- Slide layout swap: `setSlideLayout`, `findSlideLayout`.
|
|
1557
|
+
|
|
1558
|
+
**Text**
|
|
1559
|
+
|
|
1560
|
+
- Per-shape: `setShapeText`, `setShapeBullets`, `setShapeAlignment`,
|
|
1561
|
+
`setShapeTextFormat`, `setShapeHyperlink`, `setShapeTextAnchor`,
|
|
1562
|
+
`setShapeTextMargins`, `setShapeTextWrap`, `setShapeTextAutoFit`.
|
|
1563
|
+
- Per-paragraph: `setParagraphAlignment`, `setParagraphBullet`,
|
|
1564
|
+
`setParagraphLevel`, `setParagraphSpacing` + read-back pairs.
|
|
1565
|
+
- Per-run: `setShapeRunFormat`, `setShapeRunText`,
|
|
1566
|
+
`getShapeRunFormat`, `getShapeParagraphCount`, `getShapeRunCount`,
|
|
1567
|
+
`getShapeRunText`.
|
|
1568
|
+
|
|
1569
|
+
**Geometry**
|
|
1570
|
+
|
|
1571
|
+
- Position / size / rotation / flip + combined `setShapeBounds` /
|
|
1572
|
+
`getShapeBounds`. Z-order: `bringShapeToFront`, `sendShapeToBack`,
|
|
1573
|
+
`bringShapeForward`, `sendShapeBackward`.
|
|
1574
|
+
|
|
1575
|
+
**Fill / stroke / effects**
|
|
1576
|
+
|
|
1577
|
+
- Fill kinds: solid, gradient, pattern, image, none + `getShapeFill`
|
|
1578
|
+
read-back.
|
|
1579
|
+
- Stroke: color + width + dash + arrowheads + `getShapeStroke` /
|
|
1580
|
+
`getShapeStrokeDash` / `getShapeStrokeArrow` read-back.
|
|
1581
|
+
- Effects: `setShapeShadow`, `setShapeGlow`, `clearShapeEffects` +
|
|
1582
|
+
`getShapeEffect` read-back.
|
|
1583
|
+
|
|
1584
|
+
**Pictures**
|
|
1585
|
+
|
|
1586
|
+
- Crop, opacity, brightness (`lumOff`), contrast (`lumMod`),
|
|
1587
|
+
image replacement, image-as-fill. Read-back pairs for every setter.
|
|
1588
|
+
|
|
1589
|
+
**Slide-level (L4)**
|
|
1590
|
+
|
|
1591
|
+
- Notes (`getSlideNotes` / `setSlideNotes`).
|
|
1592
|
+
- Transitions (every effect + read-back).
|
|
1593
|
+
- Animations (`fadeIn` / `fadeOut` / `appear` / `disappear`) +
|
|
1594
|
+
read-back.
|
|
1595
|
+
- Comments (legacy schema, author dedup, optional position + date).
|
|
1596
|
+
- Backgrounds: solid color or embedded picture; read-back.
|
|
1597
|
+
- Visibility: `setSlideHidden` / `isSlideHidden`.
|
|
1598
|
+
- Slide sections (p14:sectionLst).
|
|
1599
|
+
- Slide size + presets (`SLIDE_SIZE_4_3` / `16_9` / `16_10`).
|
|
1600
|
+
- Slide title shortcut (`getSlideTitle` / `setSlideTitle`).
|
|
1601
|
+
- Click actions: URL / slide jump / preset nav + read-back.
|
|
1602
|
+
|
|
1603
|
+
**Theme + package**
|
|
1604
|
+
|
|
1605
|
+
- `getPresentationTheme` — color scheme (`accent1`–`accent6`, `dark1`,
|
|
1606
|
+
`light1`, `hyperlink`, ...).
|
|
1607
|
+
- `getMediaParts`, `listPackageParts`, `readPackagePart` for audit /
|
|
1608
|
+
export workflows.
|
|
1609
|
+
|
|
1610
|
+
**Tree-shake**
|
|
1611
|
+
|
|
1612
|
+
- The minimal `load`+`save` import is ~60 KB; the full fn-API
|
|
1613
|
+
bundle ~123 KB. CI guard via `test/tree-shake.test.ts`.
|
|
1614
|
+
|
|
1615
|
+
All emitted XML validates against the ECMA-376 strict schemas
|
|
1616
|
+
(pml.xsd, dml-chart.xsd, opc-relationships.xsd, opc-contentTypes.xsd)
|
|
1617
|
+
via Layer-1 tests.
|
|
1618
|
+
|
|
1619
|
+
**Additional helpers** (all tree-shakeable free functions)
|
|
1620
|
+
|
|
1621
|
+
- Properties: `getCoreProperties` / `setCoreProperties`,
|
|
1622
|
+
`getExtendedProperties` / `setExtendedProperties`, plus convenience
|
|
1623
|
+
`getPresentationCreated`, `getPresentationModified`,
|
|
1624
|
+
`incrementRevision`, `touchModified`.
|
|
1625
|
+
- Thumbnail: `getThumbnail` / `setThumbnail` / `removeThumbnail`.
|
|
1626
|
+
- Theme: `getPresentationTheme`, `getPresentationFonts`.
|
|
1627
|
+
- Slide queries: `getSlideCount`, `getSlideLayoutCount`,
|
|
1628
|
+
`getVisibleSlides`, `getHiddenSlides`, `getSlidesWithNotes`,
|
|
1629
|
+
`getSlidesWithComments`, `getSlidesWithImages`,
|
|
1630
|
+
`getSlidesWithCharts`, `getSlidesWithTables`,
|
|
1631
|
+
`getSlidesByLayout`, `findSlideByTitle`, `findSlideByText`,
|
|
1632
|
+
`findSlidesByText`, `findSlideByPartName`,
|
|
1633
|
+
`findSlideLayoutByType`, `findSlideLayoutByPartName`.
|
|
1634
|
+
- Bulk inventories: `getAllNotes`, `getAllComments`, `getAllCharts`,
|
|
1635
|
+
`getAllTables`, `getAllImages`, `getPresentationText`,
|
|
1636
|
+
`getSlideOutline`.
|
|
1637
|
+
- Shape introspection: `getShapeAt`, `getShapeIndex`,
|
|
1638
|
+
`getShapeSlide`, `getShapeXmlString`, `getShapeChartKind`,
|
|
1639
|
+
`getShapeChartSpec`, `getShapeImageFillBytes`,
|
|
1640
|
+
`getShapeImageFormat`, `getShapeImagePartName`,
|
|
1641
|
+
`getShapeAltTitle` / `setShapeAltTitle`,
|
|
1642
|
+
`getShapeDescription` / `setShapeDescription`.
|
|
1643
|
+
- Shape predicates: `isChartShape`, `isTableShape`,
|
|
1644
|
+
`isShapeHidden` / `setShapeHidden`, `isShapePlaceholder`,
|
|
1645
|
+
`hasShapeImage`, `hasShapeText`.
|
|
1646
|
+
- Shape search: `findShapeByText`, `findShapesByText`,
|
|
1647
|
+
`findShapesByKind`, `findChartByKind`,
|
|
1648
|
+
`findChartsBySeriesName`, `findCommentsByAuthor`,
|
|
1649
|
+
`findSlidePlaceholders`, `findSlidePlaceholderByIdx`.
|
|
1650
|
+
- Mutation: `setShapeRunHyperlink`, `getShapeRunHyperlink`,
|
|
1651
|
+
`getSlideBody`, `appendShapeText`,
|
|
1652
|
+
`appendSlideNotes`, `removeSlideNotes`,
|
|
1653
|
+
`swapSlides`, `mergePresentations`, `slidesUsingMediaPart`,
|
|
1654
|
+
`setTableColumnWidth`, `setTableRowHeight`, `getTableColumnWidths`,
|
|
1655
|
+
`getTableRowHeights`, `getTableCellAlignment`, `getTableCellFill`.
|
|
1656
|
+
- Diagnostics: `getSlideXmlString`, `getSlidePartName`,
|
|
1657
|
+
`getSlideLayoutPartName`, `getSlidesByLayout`.
|