Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions .changeset/applyedits-lossless-surgical-edits.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
"@textcortex/slidewise": minor
---

feat(pptx): `applyEdits` — lossless surgical-edit API

Add `applyEdits(source, plan, options?)`: a patch on the original `.pptx` bytes
rather than a full re-serialize. The create flow can now emit an `EditPlan`
(subset/reorder/repeat of template slides, each with edits) and get back a valid
package where everything not named by an edit is byte-identical to the source —
masters, layouts, theme, embedded fonts, `ppt/tags/*`, notes, embeddings, and
any untouched element. This removes the lossy round-trip that produced the
`custGeom`/SVG-fallback/dangling-rel fidelity bugs and lets hosts drop their
defensive cleanup. `serializeDeck` stays for the live editor / from-scratch decks.

Edits address elements by the same stable ids `parsePptx` returns; slides by
1-based template index. Supported ops: `setText`/`clearText` (preserve the
template box + run styling, or rebuild from supplied runs), `setChartData`
(repopulate a native chart in place — type/colours kept, caches **and** the
embedded `xlsx` workbook updated so Edit-Data still works), `setTableData`,
`setImage`, `removeElement`, `addChart`, `addDiagram`, plus per-slide
`background` and deck `title`. Removed slides and any parts that become
exclusive to them are reclaimed by a package-wide reachability sweep, then
dangling relationships and content-types are reconciled. Unresolved element ids
and unsupported layout-instantiation are surfaced via `onWarning` instead of
throwing.
51 changes: 51 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,57 @@ editor only sees current-shape decks. It throws if the input was written by a
newer Slidewise than the host has installed — pin the version range you can
support.

### Lossless surgical edits with `applyEdits`

When you start from a branded template and only need to change a few things
(swap some text, fill a chart, drop a sample element), a full
`serializeDeck` round-trip is overkill — and re-rendering unedited elements is
where fidelity bugs come from. `applyEdits(source, plan)` instead **patches the
original bytes**: everything not named by an edit comes out byte-identical to
the source (masters, layouts, theme, embedded fonts, `ppt/tags/*`, notes,
embeddings, and any untouched element), and the result opens in PowerPoint with
no repair.

```ts
import { parsePptx, applyEdits, type EditPlan } from "@textcortex/slidewise";

const deck = await parsePptx(source); // address elements by deck ids
const plan: EditPlan = {
title: "Q3 Results",
// Output order = this list. Slides are the source's 1-based template index;
// a source slide may repeat for controlled reuse.
slides: [
{
source: { slideIndex: 1 },
edits: [{ op: "setText", elementId: titleId, text: "Q3 Results" }],
},
{
source: { slideIndex: 3 },
edits: [
// Repopulate a native chart in place — type/colours and the embedded
// workbook are preserved, so PowerPoint's Edit-Data still works.
{ op: "setChartData", elementId: chartId, categories: ["Jan", "Feb", "Mar"], series: [{ name: "Revenue", values: [10, 20, 30] }] },
{ op: "removeElement", elementId: sampleChartId },
],
},
{ source: { slideIndex: 4 }, edits: [] }, // kept byte-identical
],
};

const out: Uint8Array = await applyEdits(source, plan, {
onWarning: (w) => notifyHost(w.message), // unresolved id / unsupported op
});
```

Ops: `setText` / `clearText`, `setChartData`, `setTableData`, `setImage`,
`removeElement`, `addChart`, `addDiagram`, plus per-slide `background` and the
deck `title`. Elements are addressed by the same stable ids `parsePptx` returns,
so call `applyEdits` in the same process as the `parsePptx` that produced the
plan. Removed slides and any parts exclusive to them are reclaimed
automatically. `serializeDeck` remains the path for the live editor and
from-scratch decks; `applyEdits` is the lossless path for template-derived
output.

### Generating slides from the template's layouts

`parsePptx` exposes the source template's master layouts on `deck.layouts`.
Expand Down
9 changes: 8 additions & 1 deletion packages/slidewise/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,18 @@ export {
type SlideRailItemContextValue,
} from "./compound";

export { parsePptx, isPptxTemplate, serializeDeck } from "./lib/pptx";
export { parsePptx, isPptxTemplate, serializeDeck, applyEdits } from "./lib/pptx";
export type {
SerializeOptions,
SerializeWarning,
SvgRasterizer,
EditPlan,
PlannedSlide,
Edit,
Run,
Series,
Rect,
ApplyEditsOptions,
} from "./lib/pptx";
export type { ParseDiagnostics, ParseResult } from "./lib/pptx/types";

Expand Down
Loading
Loading