@pptx-glimpse/editor 0.1.0 → 0.2.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/README.md +122 -44
- package/dist/index.cjs +344 -29
- package/dist/index.d.cts +43 -17
- package/dist/index.d.ts +43 -17
- package/dist/index.js +346 -29
- package/package.json +8 -4
package/README.md
CHANGED
|
@@ -1,66 +1,144 @@
|
|
|
1
1
|
# @pptx-glimpse/editor
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@pptx-glimpse/editor)
|
|
4
|
+
[](https://github.com/hirokisakabe/pptx-glimpse/actions/workflows/ci.yml)
|
|
5
|
+
[](https://github.com/hirokisakabe/pptx-glimpse/blob/main/LICENSE)
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
The public, headless editing layer for `PptxSourceModel`. It applies validated commands and manages
|
|
8
|
+
selection and undo/redo history without depending on a DOM, UI framework, or renderer.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
This package is published on npm. Install it together with its document-layer dependency so both
|
|
11
|
+
packages are direct dependencies of your application:
|
|
11
12
|
|
|
12
|
-
```
|
|
13
|
+
```bash
|
|
13
14
|
npm install @pptx-glimpse/document @pptx-glimpse/editor
|
|
14
15
|
```
|
|
15
16
|
|
|
16
|
-
##
|
|
17
|
+
## Quick start
|
|
17
18
|
|
|
18
19
|
```ts
|
|
20
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
19
21
|
import { readPptx, writePptx } from "@pptx-glimpse/document";
|
|
20
22
|
import { createEditorSession } from "@pptx-glimpse/editor";
|
|
21
23
|
|
|
22
|
-
const source = readPptx(input);
|
|
23
|
-
const run = source.slides[0]?.shapes
|
|
24
|
-
|
|
25
|
-
?.textBody?.paragraphs[0]?.runs[0];
|
|
24
|
+
const source = readPptx(await readFile("input.pptx"));
|
|
25
|
+
const run = source.slides[0]?.shapes.find((shape) => shape.kind === "shape")?.textBody
|
|
26
|
+
?.paragraphs[0]?.runs[0];
|
|
26
27
|
|
|
27
|
-
if (run
|
|
28
|
-
throw new Error("editable text run
|
|
28
|
+
if (run === undefined) {
|
|
29
|
+
throw new Error("No editable text run found");
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
const session = createEditorSession(source);
|
|
32
|
-
const result = session.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
33
|
+
const result = session.replaceTextRunPlainText(run, "Edited");
|
|
34
|
+
|
|
35
|
+
if (!result.ok) {
|
|
36
|
+
throw new Error(`${result.code}: ${result.message}`, { cause: result.cause });
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
for (const warning of result.warnings ?? []) {
|
|
40
|
+
console.warn(warning.code, warning.message);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
await writeFile("edited.pptx", writePptx(session.document));
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Source-node methods, commands, history, and selection
|
|
47
|
+
|
|
48
|
+
For ordinary edits, pass source nodes directly to the corresponding `EditorSession` convenience
|
|
49
|
+
method. Text-run and paragraph methods replace plain text or set/clear properties. Shape methods
|
|
50
|
+
move, resize, transform, style, or delete a `SourceShapeNode`; `replaceImage()` accepts a
|
|
51
|
+
`SourceImage`; slide topology methods accept a `SourceSlide`. `addTextBox()` and `addConnector()`
|
|
52
|
+
also accept the target `SourceSlide`, so application code does not need to extract source handles.
|
|
53
|
+
Nodes captured before earlier edits remain usable because the session resolves their stable handle
|
|
54
|
+
against its current document.
|
|
55
|
+
|
|
56
|
+
Every convenience method creates and applies the matching command through the same validation,
|
|
57
|
+
warning, selection-reconciliation, and undo/redo-history path. A successful convenience-method
|
|
58
|
+
call that changes the document creates one undo-history entry.
|
|
59
|
+
|
|
60
|
+
Use `session.apply(command)` when commands need to be stored, logged, transported by UI code, or
|
|
61
|
+
constructed independently of a source-node object. Use `session.applyAll(commands)` to apply
|
|
62
|
+
multiple operations atomically as one undo-history entry; convenience methods are single-operation
|
|
63
|
+
calls and cannot be grouped into one history entry by calling them sequentially. Failed validation
|
|
64
|
+
returns an `invalid-command` result without changing the document.
|
|
65
|
+
|
|
66
|
+
The released command set includes:
|
|
67
|
+
|
|
68
|
+
- Text: `replaceTextRunPlainText`, `replaceParagraphPlainText`, `setTextRunProperties`,
|
|
69
|
+
`clearTextRunProperties`, `setParagraphProperties`, and `clearParagraphProperties`.
|
|
70
|
+
- Shapes: `moveShape`, `resizeShape`, `setShapeTransform`, `setShapeFill`, `setShapeOutline`,
|
|
71
|
+
`addTextBox`, `addConnector`, and `deleteShape`.
|
|
72
|
+
- Media: `replaceImage`.
|
|
73
|
+
- Slides: `addEmptySlideFromLayout`, `duplicateSlide`, `moveSlide`, and `deleteSlide`.
|
|
74
|
+
|
|
75
|
+
Use `undo()`, `redo()`, `canUndo`, `canRedo`, `undoDepth`, and `redoDepth` to integrate history.
|
|
76
|
+
`selectShape(handle)` and `deselectShape()` manage a single shape selection. Selection is reconciled
|
|
77
|
+
after commands and history changes, and is cleared if its shape no longer exists.
|
|
78
|
+
|
|
79
|
+
## Operation failures and warnings
|
|
80
|
+
|
|
81
|
+
Expected failures do not throw. `apply()` / `applyAll()`, `selectShape()`, `undo()`, and `redo()`
|
|
82
|
+
return a discriminated result with the shared `EditorOperationFailure` shape:
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
const result = session.undo();
|
|
37
86
|
if (!result.ok) {
|
|
38
|
-
|
|
87
|
+
switch (result.code) {
|
|
88
|
+
case "empty-undo-stack":
|
|
89
|
+
// Disable or ignore the undo action.
|
|
90
|
+
break;
|
|
91
|
+
default:
|
|
92
|
+
console.error(result.message, result.cause);
|
|
93
|
+
}
|
|
39
94
|
}
|
|
95
|
+
```
|
|
40
96
|
|
|
41
|
-
|
|
97
|
+
The operation codes are `invalid-command`, `invalid-selection`, `empty-undo-stack`, and
|
|
98
|
+
`empty-redo-stack`. Unexpected programmer errors and invariant violations still throw.
|
|
99
|
+
|
|
100
|
+
Warnings describe successful operations and remain on the success result:
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
const result = session.apply(replaceImageCommand);
|
|
104
|
+
if (result.ok) {
|
|
105
|
+
for (const warning of result.warnings ?? []) {
|
|
106
|
+
if (warning.code === "shared-media-part") {
|
|
107
|
+
console.warn(warning.message);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
42
111
|
```
|
|
43
112
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
-
|
|
66
|
-
`
|
|
113
|
+
## Package boundary
|
|
114
|
+
|
|
115
|
+
Use [`pptx-glimpse`](https://github.com/hirokisakabe/pptx-glimpse/blob/main/packages/core/README.md)
|
|
116
|
+
when you want high-level rendering plus an edit/rerender/save session. Use
|
|
117
|
+
[`@pptx-glimpse/document`](https://github.com/hirokisakabe/pptx-glimpse/blob/main/packages/document/README.md)
|
|
118
|
+
directly for source/computed document semantics, authoring, immutable editing operations, and
|
|
119
|
+
writing without session state.
|
|
120
|
+
|
|
121
|
+
`@pptx-glimpse/editor` adds command validation, selection, warnings, and history to the document
|
|
122
|
+
model. It does not include React, ProseMirror, a DOM UI, SVG/PNG rendering, or file I/O. Import
|
|
123
|
+
supported APIs from the package root; deep source and `dist` paths are internal.
|
|
124
|
+
|
|
125
|
+
## Runtime support, stability, and limitations
|
|
126
|
+
|
|
127
|
+
- Node.js 22 or later is supported.
|
|
128
|
+
- Browser bundlers can use the same byte- and model-oriented APIs; the package has no DOM or
|
|
129
|
+
Node.js filesystem dependency.
|
|
130
|
+
- `@pptx-glimpse/editor` is a `0.x` package. Commands and result types may change before `1.0.0`.
|
|
131
|
+
- Elements without source handles, and edits the document layer cannot safely preserve, are
|
|
132
|
+
rejected as `invalid-command`.
|
|
133
|
+
- New table, chart, and SmartArt editing commands are not available.
|
|
134
|
+
- Replacing a shared media part can change multiple image references and returns a
|
|
135
|
+
`shared-media-part` warning.
|
|
136
|
+
- Expected operation rejection uses the exported `EditorOperationErrorCode` and
|
|
137
|
+
`EditorOperationFailure` contract.
|
|
138
|
+
|
|
139
|
+
See the [project README](https://github.com/hirokisakabe/pptx-glimpse#readme) for package selection
|
|
140
|
+
and the demo.
|
|
141
|
+
|
|
142
|
+
## License
|
|
143
|
+
|
|
144
|
+
MIT
|
package/dist/index.cjs
CHANGED
|
@@ -66,50 +66,198 @@ var EditorSession = class {
|
|
|
66
66
|
deselectShape() {
|
|
67
67
|
this.#selection = void 0;
|
|
68
68
|
}
|
|
69
|
+
replaceTextRunPlainText(run, text) {
|
|
70
|
+
return this.applyToSourceNode(
|
|
71
|
+
"replaceTextRunPlainText",
|
|
72
|
+
run,
|
|
73
|
+
isSourceTextRun,
|
|
74
|
+
import_document.findTextRunBySourceHandle,
|
|
75
|
+
(handle) => ({ kind: "replaceTextRunPlainText", handle, text })
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
replaceParagraphPlainText(paragraph, text) {
|
|
79
|
+
return this.applyToSourceNode(
|
|
80
|
+
"replaceParagraphPlainText",
|
|
81
|
+
paragraph,
|
|
82
|
+
isSourceParagraph,
|
|
83
|
+
import_document.findParagraphBySourceHandle,
|
|
84
|
+
(handle) => ({ kind: "replaceParagraphPlainText", handle, text })
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
setTextRunProperties(run, properties) {
|
|
88
|
+
return this.applyToSourceNode(
|
|
89
|
+
"setTextRunProperties",
|
|
90
|
+
run,
|
|
91
|
+
isSourceTextRun,
|
|
92
|
+
import_document.findTextRunBySourceHandle,
|
|
93
|
+
(handle) => ({ kind: "setTextRunProperties", handle, properties })
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
clearTextRunProperties(run, properties) {
|
|
97
|
+
return this.applyToSourceNode(
|
|
98
|
+
"clearTextRunProperties",
|
|
99
|
+
run,
|
|
100
|
+
isSourceTextRun,
|
|
101
|
+
import_document.findTextRunBySourceHandle,
|
|
102
|
+
(handle) => ({ kind: "clearTextRunProperties", handle, properties })
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
setParagraphProperties(paragraph, properties) {
|
|
106
|
+
return this.applyToSourceNode(
|
|
107
|
+
"setParagraphProperties",
|
|
108
|
+
paragraph,
|
|
109
|
+
isSourceParagraph,
|
|
110
|
+
import_document.findParagraphBySourceHandle,
|
|
111
|
+
(handle) => ({ kind: "setParagraphProperties", handle, properties })
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
clearParagraphProperties(paragraph, properties) {
|
|
115
|
+
return this.applyToSourceNode(
|
|
116
|
+
"clearParagraphProperties",
|
|
117
|
+
paragraph,
|
|
118
|
+
isSourceParagraph,
|
|
119
|
+
import_document.findParagraphBySourceHandle,
|
|
120
|
+
(handle) => ({ kind: "clearParagraphProperties", handle, properties })
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
moveShape(shape, offsetX, offsetY) {
|
|
124
|
+
return this.applyToShapeNode("moveShape", shape, (handle) => ({
|
|
125
|
+
kind: "moveShape",
|
|
126
|
+
handle,
|
|
127
|
+
offsetX,
|
|
128
|
+
offsetY
|
|
129
|
+
}));
|
|
130
|
+
}
|
|
131
|
+
resizeShape(shape, width, height) {
|
|
132
|
+
return this.applyToShapeNode("resizeShape", shape, (handle) => ({
|
|
133
|
+
kind: "resizeShape",
|
|
134
|
+
handle,
|
|
135
|
+
width,
|
|
136
|
+
height
|
|
137
|
+
}));
|
|
138
|
+
}
|
|
139
|
+
setShapeTransform(shape, transform) {
|
|
140
|
+
return this.applyToShapeNode("setShapeTransform", shape, (handle) => ({
|
|
141
|
+
kind: "setShapeTransform",
|
|
142
|
+
handle,
|
|
143
|
+
...transform
|
|
144
|
+
}));
|
|
145
|
+
}
|
|
146
|
+
setShapeFill(shape, fill) {
|
|
147
|
+
return this.applyToShapeNode("setShapeFill", shape, (handle) => ({
|
|
148
|
+
kind: "setShapeFill",
|
|
149
|
+
handle,
|
|
150
|
+
fill
|
|
151
|
+
}));
|
|
152
|
+
}
|
|
153
|
+
setShapeOutline(shape, outline) {
|
|
154
|
+
return this.applyToShapeNode("setShapeOutline", shape, (handle) => ({
|
|
155
|
+
kind: "setShapeOutline",
|
|
156
|
+
handle,
|
|
157
|
+
outline
|
|
158
|
+
}));
|
|
159
|
+
}
|
|
160
|
+
addTextBox(slide, input) {
|
|
161
|
+
return this.applyToSlide("addTextBox", slide, (slideHandle) => ({
|
|
162
|
+
kind: "addTextBox",
|
|
163
|
+
slideHandle,
|
|
164
|
+
...input
|
|
165
|
+
}));
|
|
166
|
+
}
|
|
167
|
+
addConnector(slide, input) {
|
|
168
|
+
return this.applyToSlide("addConnector", slide, (slideHandle) => ({
|
|
169
|
+
kind: "addConnector",
|
|
170
|
+
slideHandle,
|
|
171
|
+
...input
|
|
172
|
+
}));
|
|
173
|
+
}
|
|
174
|
+
deleteShape(shape) {
|
|
175
|
+
return this.applyToShapeNode("deleteShape", shape, (handle) => ({
|
|
176
|
+
kind: "deleteShape",
|
|
177
|
+
handle
|
|
178
|
+
}));
|
|
179
|
+
}
|
|
180
|
+
replaceImage(image, bytes) {
|
|
181
|
+
return this.applyToSourceNode(
|
|
182
|
+
"replaceImage",
|
|
183
|
+
image,
|
|
184
|
+
isSourceImage,
|
|
185
|
+
(document, handle) => {
|
|
186
|
+
const shape = (0, import_document.findShapeNodeBySourceHandle)(document, handle);
|
|
187
|
+
return shape?.kind === "image" ? shape : void 0;
|
|
188
|
+
},
|
|
189
|
+
(handle) => ({ kind: "replaceImage", handle, bytes })
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
addEmptySlideFromLayout(input) {
|
|
193
|
+
return this.apply({ kind: "addEmptySlideFromLayout", ...input });
|
|
194
|
+
}
|
|
195
|
+
duplicateSlide(slide) {
|
|
196
|
+
return this.applyToSlide("duplicateSlide", slide, (handle) => ({
|
|
197
|
+
kind: "duplicateSlide",
|
|
198
|
+
handle
|
|
199
|
+
}));
|
|
200
|
+
}
|
|
201
|
+
moveSlide(slide, input) {
|
|
202
|
+
return this.applyToSlide("moveSlide", slide, (handle) => ({
|
|
203
|
+
kind: "moveSlide",
|
|
204
|
+
handle,
|
|
205
|
+
...input
|
|
206
|
+
}));
|
|
207
|
+
}
|
|
208
|
+
deleteSlide(slide) {
|
|
209
|
+
return this.applyToSlide("deleteSlide", slide, (handle) => ({
|
|
210
|
+
kind: "deleteSlide",
|
|
211
|
+
handle
|
|
212
|
+
}));
|
|
213
|
+
}
|
|
69
214
|
apply(command) {
|
|
70
215
|
return this.applyAll([command]);
|
|
71
216
|
}
|
|
72
217
|
applyAll(commands) {
|
|
73
218
|
const before = this.#document;
|
|
74
219
|
if (commands.length === 0) return { ok: true, document: before };
|
|
220
|
+
let after = before;
|
|
221
|
+
const warnings = [];
|
|
222
|
+
for (const command of commands) {
|
|
223
|
+
const result = applyCommandToDocument(after, command);
|
|
224
|
+
if (!result.ok) return result;
|
|
225
|
+
after = result.document;
|
|
226
|
+
warnings.push(...collectCommandWarnings(after, [command]));
|
|
227
|
+
}
|
|
75
228
|
try {
|
|
76
|
-
let after = before;
|
|
77
|
-
const warnings = [];
|
|
78
|
-
for (const command of commands) {
|
|
79
|
-
after = applyCommandToDocument(after, command);
|
|
80
|
-
warnings.push(...collectCommandWarnings(after, [command]));
|
|
81
|
-
}
|
|
82
229
|
assertNoConflictingParagraphAndRunEdits(after.edits);
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
...dedupedWarnings.length > 0 ? { warnings: dedupedWarnings } : {}
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
this.#document = after;
|
|
93
|
-
this.reconcileSelectionAfterDocumentChange();
|
|
94
|
-
this.#undoStack.push({ before, after });
|
|
95
|
-
this.#redoStack.length = 0;
|
|
230
|
+
} catch (cause) {
|
|
231
|
+
return invalidCommandFailure(cause);
|
|
232
|
+
}
|
|
233
|
+
after = normalizeEditorEdits(after);
|
|
234
|
+
const dedupedWarnings = dedupeCommandWarnings(warnings);
|
|
235
|
+
if (after === before) {
|
|
96
236
|
return {
|
|
97
237
|
ok: true,
|
|
98
|
-
document:
|
|
238
|
+
document: before,
|
|
99
239
|
...dedupedWarnings.length > 0 ? { warnings: dedupedWarnings } : {}
|
|
100
240
|
};
|
|
101
|
-
} catch (error) {
|
|
102
|
-
return {
|
|
103
|
-
ok: false,
|
|
104
|
-
code: "invalid-command",
|
|
105
|
-
message: error instanceof Error ? error.message : "Editor command was rejected.",
|
|
106
|
-
cause: error
|
|
107
|
-
};
|
|
108
241
|
}
|
|
242
|
+
this.#document = after;
|
|
243
|
+
this.reconcileSelectionAfterDocumentChange();
|
|
244
|
+
this.#undoStack.push({ before, after });
|
|
245
|
+
this.#redoStack.length = 0;
|
|
246
|
+
return {
|
|
247
|
+
ok: true,
|
|
248
|
+
document: after,
|
|
249
|
+
...dedupedWarnings.length > 0 ? { warnings: dedupedWarnings } : {}
|
|
250
|
+
};
|
|
109
251
|
}
|
|
110
252
|
undo() {
|
|
111
253
|
const entry = this.#undoStack.pop();
|
|
112
|
-
if (entry === void 0)
|
|
254
|
+
if (entry === void 0) {
|
|
255
|
+
return {
|
|
256
|
+
ok: false,
|
|
257
|
+
code: "empty-undo-stack",
|
|
258
|
+
message: "undo: undo history is empty"
|
|
259
|
+
};
|
|
260
|
+
}
|
|
113
261
|
this.#document = entry.before;
|
|
114
262
|
this.reconcileSelectionAfterDocumentChange();
|
|
115
263
|
this.#redoStack.push(entry);
|
|
@@ -117,7 +265,13 @@ var EditorSession = class {
|
|
|
117
265
|
}
|
|
118
266
|
redo() {
|
|
119
267
|
const entry = this.#redoStack.pop();
|
|
120
|
-
if (entry === void 0)
|
|
268
|
+
if (entry === void 0) {
|
|
269
|
+
return {
|
|
270
|
+
ok: false,
|
|
271
|
+
code: "empty-redo-stack",
|
|
272
|
+
message: "redo: redo history is empty"
|
|
273
|
+
};
|
|
274
|
+
}
|
|
121
275
|
this.#document = entry.after;
|
|
122
276
|
this.reconcileSelectionAfterDocumentChange();
|
|
123
277
|
this.#undoStack.push(entry);
|
|
@@ -129,11 +283,172 @@ var EditorSession = class {
|
|
|
129
283
|
this.#selection = void 0;
|
|
130
284
|
}
|
|
131
285
|
}
|
|
286
|
+
applyToShapeNode(operation, shape, createCommand) {
|
|
287
|
+
return this.applyToSourceNode(
|
|
288
|
+
operation,
|
|
289
|
+
shape,
|
|
290
|
+
isSourceShapeNode,
|
|
291
|
+
import_document.findShapeNodeBySourceHandle,
|
|
292
|
+
createCommand
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
applyToSlide(operation, slide, createCommand) {
|
|
296
|
+
return this.applyToSourceNode(
|
|
297
|
+
operation,
|
|
298
|
+
slide,
|
|
299
|
+
isSourceSlide,
|
|
300
|
+
(document, handle) => document.slides.find((candidate) => sourceHandlesEqual(candidate.handle, handle)),
|
|
301
|
+
createCommand
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
applyToSourceNode(operation, node, isExpectedNode, findCurrentNode, createCommand) {
|
|
305
|
+
if (!isExpectedNode(node)) {
|
|
306
|
+
return invalidSourceNodeFailure(operation, "source node has the wrong target type");
|
|
307
|
+
}
|
|
308
|
+
if (node.handle === void 0) {
|
|
309
|
+
return invalidSourceNodeFailure(operation, "source node does not have a handle");
|
|
310
|
+
}
|
|
311
|
+
if (findCurrentNode(this.#document, node.handle) === void 0) {
|
|
312
|
+
return invalidSourceNodeFailure(
|
|
313
|
+
operation,
|
|
314
|
+
"source node handle was not found in the current EditorSession document"
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
return this.apply(createCommand(node.handle));
|
|
318
|
+
}
|
|
132
319
|
};
|
|
133
320
|
function createEditorSession(document) {
|
|
134
321
|
return new EditorSession(document);
|
|
135
322
|
}
|
|
323
|
+
var EDITOR_COMMAND_KINDS = /* @__PURE__ */ new Set([
|
|
324
|
+
"replaceTextRunPlainText",
|
|
325
|
+
"replaceParagraphPlainText",
|
|
326
|
+
"setTextRunProperties",
|
|
327
|
+
"clearTextRunProperties",
|
|
328
|
+
"setParagraphProperties",
|
|
329
|
+
"clearParagraphProperties",
|
|
330
|
+
"moveShape",
|
|
331
|
+
"resizeShape",
|
|
332
|
+
"setShapeTransform",
|
|
333
|
+
"setShapeFill",
|
|
334
|
+
"setShapeOutline",
|
|
335
|
+
"addTextBox",
|
|
336
|
+
"addConnector",
|
|
337
|
+
"deleteShape",
|
|
338
|
+
"replaceImage",
|
|
339
|
+
"addEmptySlideFromLayout",
|
|
340
|
+
"duplicateSlide",
|
|
341
|
+
"moveSlide",
|
|
342
|
+
"deleteSlide"
|
|
343
|
+
]);
|
|
344
|
+
var EXPECTED_COMMAND_REJECTION_PREFIXES = [
|
|
345
|
+
"replaceTextRunPlainText:",
|
|
346
|
+
"replaceParagraphPlainText:",
|
|
347
|
+
"setTextRunProperties:",
|
|
348
|
+
"clearTextRunProperties:",
|
|
349
|
+
"setParagraphProperties:",
|
|
350
|
+
"clearParagraphProperties:",
|
|
351
|
+
"moveShape:",
|
|
352
|
+
"resizeShape:",
|
|
353
|
+
"setShapeTransform:",
|
|
354
|
+
"setShapeFill:",
|
|
355
|
+
"setShapeOutline:",
|
|
356
|
+
"addTextBox:",
|
|
357
|
+
"addConnector:",
|
|
358
|
+
"deleteShape:",
|
|
359
|
+
"replaceImageBytes:",
|
|
360
|
+
"addEmptySlideFromLayout:",
|
|
361
|
+
"duplicateSlide:",
|
|
362
|
+
"moveSlide:",
|
|
363
|
+
"deleteSlide:",
|
|
364
|
+
"updateTextRunProperties:",
|
|
365
|
+
"updateParagraphProperties:",
|
|
366
|
+
"updateShapeTransform:"
|
|
367
|
+
];
|
|
136
368
|
function applyCommandToDocument(document, command) {
|
|
369
|
+
if (!EDITOR_COMMAND_KINDS.has(command.kind)) {
|
|
370
|
+
throw new TypeError(`EditorSession: unsupported command kind '${String(command.kind)}'`);
|
|
371
|
+
}
|
|
372
|
+
switch (command.kind) {
|
|
373
|
+
case "replaceTextRunPlainText":
|
|
374
|
+
case "replaceParagraphPlainText":
|
|
375
|
+
case "setTextRunProperties":
|
|
376
|
+
case "clearTextRunProperties":
|
|
377
|
+
case "setParagraphProperties":
|
|
378
|
+
case "clearParagraphProperties":
|
|
379
|
+
case "moveShape":
|
|
380
|
+
case "resizeShape":
|
|
381
|
+
case "setShapeTransform":
|
|
382
|
+
case "setShapeFill":
|
|
383
|
+
case "setShapeOutline":
|
|
384
|
+
case "addTextBox":
|
|
385
|
+
case "addConnector":
|
|
386
|
+
case "deleteShape":
|
|
387
|
+
case "replaceImage":
|
|
388
|
+
case "addEmptySlideFromLayout":
|
|
389
|
+
case "duplicateSlide":
|
|
390
|
+
case "moveSlide":
|
|
391
|
+
case "deleteSlide":
|
|
392
|
+
return attemptCommand(() => executeCommand(document, command));
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
function attemptCommand(operation) {
|
|
396
|
+
try {
|
|
397
|
+
return { ok: true, document: operation() };
|
|
398
|
+
} catch (cause) {
|
|
399
|
+
return invalidCommandFailure(cause);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
function invalidCommandFailure(cause) {
|
|
403
|
+
if (!(cause instanceof Error) || !EXPECTED_COMMAND_REJECTION_PREFIXES.some((prefix) => cause.message.startsWith(prefix))) {
|
|
404
|
+
throw cause;
|
|
405
|
+
}
|
|
406
|
+
return {
|
|
407
|
+
ok: false,
|
|
408
|
+
code: "invalid-command",
|
|
409
|
+
message: cause.message,
|
|
410
|
+
cause
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
function invalidSourceNodeFailure(operation, reason) {
|
|
414
|
+
return {
|
|
415
|
+
ok: false,
|
|
416
|
+
code: "invalid-command",
|
|
417
|
+
message: `${operation}: ${reason}`
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
function isSourceTextRun(value) {
|
|
421
|
+
return isObject(value) && value.kind === "textRun";
|
|
422
|
+
}
|
|
423
|
+
function isSourceParagraph(value) {
|
|
424
|
+
return isObject(value) && Array.isArray(value.runs);
|
|
425
|
+
}
|
|
426
|
+
var SOURCE_SHAPE_NODE_KINDS = /* @__PURE__ */ new Set([
|
|
427
|
+
"shape",
|
|
428
|
+
"connector",
|
|
429
|
+
"group",
|
|
430
|
+
"image",
|
|
431
|
+
"table",
|
|
432
|
+
"chart",
|
|
433
|
+
"smartArt",
|
|
434
|
+
"raw"
|
|
435
|
+
]);
|
|
436
|
+
function isSourceShapeNode(value) {
|
|
437
|
+
return isObject(value) && typeof value.kind === "string" && SOURCE_SHAPE_NODE_KINDS.has(value.kind);
|
|
438
|
+
}
|
|
439
|
+
function isSourceImage(value) {
|
|
440
|
+
return isObject(value) && value.kind === "image";
|
|
441
|
+
}
|
|
442
|
+
function isSourceSlide(value) {
|
|
443
|
+
return isObject(value) && typeof value.partPath === "string" && typeof value.layoutPartPath === "string" && Array.isArray(value.shapes);
|
|
444
|
+
}
|
|
445
|
+
function isObject(value) {
|
|
446
|
+
return typeof value === "object" && value !== null;
|
|
447
|
+
}
|
|
448
|
+
function sourceHandlesEqual(left, right) {
|
|
449
|
+
return left !== void 0 && left.partPath === right.partPath && left.nodeId === right.nodeId && left.relationshipId === right.relationshipId && left.orderingSlot === right.orderingSlot;
|
|
450
|
+
}
|
|
451
|
+
function executeCommand(document, command) {
|
|
137
452
|
switch (command.kind) {
|
|
138
453
|
case "replaceTextRunPlainText":
|
|
139
454
|
return replaceTextRunPlainTextCommand(document, command);
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
import { AddConnectorInput, SourceHandle, AddEmptySlideFromLayoutInput, AddTextBoxInput, EditableParagraphProperty, EditableTextRunProperty, PptxSourceModel, EditableTextRunProperties, EditableParagraphProperties, Emu, EditableShapeFill, EditableShapeOutline, MoveSlideInput } from '@pptx-glimpse/document';
|
|
1
|
+
import { AddConnectorInput, SourceHandle, AddEmptySlideFromLayoutInput, AddTextBoxInput, EditableParagraphProperty, EditableTextRunProperty, PptxSourceModel, EditableTextRunProperties, EditableParagraphProperties, Emu, EditableShapeFill, EditableShapeOutline, MoveSlideInput, SourceTextRun, SourceParagraph, SourceShapeNode, SourceTransform, SourceSlide, SourceImage } from '@pptx-glimpse/document';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Headless editor commands, selection, warnings, and history.
|
|
5
|
+
*
|
|
6
|
+
* Expected operation rejections use the shared discriminated failure contract exported
|
|
7
|
+
* by this module. Unexpected programmer errors and invariant violations must propagate.
|
|
8
|
+
* The repository-wide ownership, conversion, and catch rules are documented in
|
|
9
|
+
* [the editor error contract](../../../docs/editor-error-contract.md).
|
|
10
|
+
*/
|
|
2
11
|
|
|
3
12
|
interface ReplaceTextRunPlainTextCommand {
|
|
4
13
|
readonly kind: "replaceTextRunPlainText";
|
|
@@ -93,16 +102,18 @@ interface DeleteSlideCommand {
|
|
|
93
102
|
readonly handle: SourceHandle;
|
|
94
103
|
}
|
|
95
104
|
type EditorCommand = ReplaceTextRunPlainTextCommand | ReplaceParagraphPlainTextCommand | SetTextRunPropertiesCommand | ClearTextRunPropertiesCommand | SetParagraphPropertiesCommand | ClearParagraphPropertiesCommand | MoveShapeCommand | ResizeShapeCommand | SetShapeTransformCommand | SetShapeFillCommand | SetShapeOutlineCommand | AddTextBoxCommand | AddConnectorCommand | DeleteShapeCommand | ReplaceImageCommand | AddEmptySlideFromLayoutCommand | DuplicateSlideCommand | MoveSlideCommand | DeleteSlideCommand;
|
|
105
|
+
type EditorOperationErrorCode = "invalid-command" | "invalid-selection" | "empty-undo-stack" | "empty-redo-stack";
|
|
106
|
+
interface EditorOperationFailure<Code extends EditorOperationErrorCode = EditorOperationErrorCode> {
|
|
107
|
+
readonly ok: false;
|
|
108
|
+
readonly code: Code;
|
|
109
|
+
readonly message: string;
|
|
110
|
+
readonly cause?: unknown;
|
|
111
|
+
}
|
|
96
112
|
type EditorApplyCommandResult = {
|
|
97
113
|
readonly ok: true;
|
|
98
114
|
readonly document: PptxSourceModel;
|
|
99
115
|
readonly warnings?: readonly EditorCommandWarning[];
|
|
100
|
-
} |
|
|
101
|
-
readonly ok: false;
|
|
102
|
-
readonly code: "invalid-command";
|
|
103
|
-
readonly message: string;
|
|
104
|
-
readonly cause?: unknown;
|
|
105
|
-
};
|
|
116
|
+
} | EditorOperationFailure<"invalid-command">;
|
|
106
117
|
interface EditorCommandWarning {
|
|
107
118
|
readonly code: "shared-media-part";
|
|
108
119
|
readonly message: string;
|
|
@@ -112,21 +123,14 @@ interface EditorCommandWarning {
|
|
|
112
123
|
type EditorHistoryResult = {
|
|
113
124
|
readonly ok: true;
|
|
114
125
|
readonly document: PptxSourceModel;
|
|
115
|
-
} |
|
|
116
|
-
readonly ok: false;
|
|
117
|
-
readonly reason: "empty-undo-stack" | "empty-redo-stack";
|
|
118
|
-
};
|
|
126
|
+
} | EditorOperationFailure<"empty-undo-stack" | "empty-redo-stack">;
|
|
119
127
|
interface EditorSelection {
|
|
120
128
|
readonly shapeHandle: SourceHandle;
|
|
121
129
|
}
|
|
122
130
|
type EditorSelectShapeResult = {
|
|
123
131
|
readonly ok: true;
|
|
124
132
|
readonly selection: EditorSelection;
|
|
125
|
-
} |
|
|
126
|
-
readonly ok: false;
|
|
127
|
-
readonly code: "invalid-selection";
|
|
128
|
-
readonly message: string;
|
|
129
|
-
};
|
|
133
|
+
} | EditorOperationFailure<"invalid-selection">;
|
|
130
134
|
declare class EditorSession {
|
|
131
135
|
#private;
|
|
132
136
|
constructor(document: PptxSourceModel);
|
|
@@ -138,12 +142,34 @@ declare class EditorSession {
|
|
|
138
142
|
get redoDepth(): number;
|
|
139
143
|
selectShape(handle: SourceHandle): EditorSelectShapeResult;
|
|
140
144
|
deselectShape(): void;
|
|
145
|
+
replaceTextRunPlainText(run: SourceTextRun, text: string): EditorApplyCommandResult;
|
|
146
|
+
replaceParagraphPlainText(paragraph: SourceParagraph, text: string): EditorApplyCommandResult;
|
|
147
|
+
setTextRunProperties(run: SourceTextRun, properties: EditableTextRunProperties): EditorApplyCommandResult;
|
|
148
|
+
clearTextRunProperties(run: SourceTextRun, properties: readonly EditableTextRunProperty[]): EditorApplyCommandResult;
|
|
149
|
+
setParagraphProperties(paragraph: SourceParagraph, properties: EditableParagraphProperties): EditorApplyCommandResult;
|
|
150
|
+
clearParagraphProperties(paragraph: SourceParagraph, properties: readonly EditableParagraphProperty[]): EditorApplyCommandResult;
|
|
151
|
+
moveShape(shape: SourceShapeNode, offsetX: Emu, offsetY: Emu): EditorApplyCommandResult;
|
|
152
|
+
resizeShape(shape: SourceShapeNode, width: Emu, height: Emu): EditorApplyCommandResult;
|
|
153
|
+
setShapeTransform(shape: SourceShapeNode, transform: Pick<SourceTransform, "offsetX" | "offsetY" | "width" | "height">): EditorApplyCommandResult;
|
|
154
|
+
setShapeFill(shape: SourceShapeNode, fill: EditableShapeFill): EditorApplyCommandResult;
|
|
155
|
+
setShapeOutline(shape: SourceShapeNode, outline: EditableShapeOutline): EditorApplyCommandResult;
|
|
156
|
+
addTextBox(slide: SourceSlide, input: AddTextBoxInput): EditorApplyCommandResult;
|
|
157
|
+
addConnector(slide: SourceSlide, input: AddConnectorInput): EditorApplyCommandResult;
|
|
158
|
+
deleteShape(shape: SourceShapeNode): EditorApplyCommandResult;
|
|
159
|
+
replaceImage(image: SourceImage, bytes: Uint8Array): EditorApplyCommandResult;
|
|
160
|
+
addEmptySlideFromLayout(input: AddEmptySlideFromLayoutInput): EditorApplyCommandResult;
|
|
161
|
+
duplicateSlide(slide: SourceSlide): EditorApplyCommandResult;
|
|
162
|
+
moveSlide(slide: SourceSlide, input: MoveSlideInput): EditorApplyCommandResult;
|
|
163
|
+
deleteSlide(slide: SourceSlide): EditorApplyCommandResult;
|
|
141
164
|
apply(command: EditorCommand): EditorApplyCommandResult;
|
|
142
165
|
applyAll(commands: readonly EditorCommand[]): EditorApplyCommandResult;
|
|
143
166
|
undo(): EditorHistoryResult;
|
|
144
167
|
redo(): EditorHistoryResult;
|
|
145
168
|
private reconcileSelectionAfterDocumentChange;
|
|
169
|
+
private applyToShapeNode;
|
|
170
|
+
private applyToSlide;
|
|
171
|
+
private applyToSourceNode;
|
|
146
172
|
}
|
|
147
173
|
declare function createEditorSession(document: PptxSourceModel): EditorSession;
|
|
148
174
|
|
|
149
|
-
export { type AddConnectorCommand, type AddEmptySlideFromLayoutCommand, type AddTextBoxCommand, type ClearParagraphPropertiesCommand, type ClearTextRunPropertiesCommand, type DeleteShapeCommand, type DeleteSlideCommand, type DuplicateSlideCommand, type EditorApplyCommandResult, type EditorCommand, type EditorCommandWarning, type EditorHistoryResult, type EditorSelectShapeResult, type EditorSelection, EditorSession, type MoveShapeCommand, type MoveSlideCommand, type ReplaceImageCommand, type ReplaceParagraphPlainTextCommand, type ReplaceTextRunPlainTextCommand, type ResizeShapeCommand, type SetParagraphPropertiesCommand, type SetShapeFillCommand, type SetShapeOutlineCommand, type SetShapeTransformCommand, type SetTextRunPropertiesCommand, createEditorSession };
|
|
175
|
+
export { type AddConnectorCommand, type AddEmptySlideFromLayoutCommand, type AddTextBoxCommand, type ClearParagraphPropertiesCommand, type ClearTextRunPropertiesCommand, type DeleteShapeCommand, type DeleteSlideCommand, type DuplicateSlideCommand, type EditorApplyCommandResult, type EditorCommand, type EditorCommandWarning, type EditorHistoryResult, type EditorOperationErrorCode, type EditorOperationFailure, type EditorSelectShapeResult, type EditorSelection, EditorSession, type MoveShapeCommand, type MoveSlideCommand, type ReplaceImageCommand, type ReplaceParagraphPlainTextCommand, type ReplaceTextRunPlainTextCommand, type ResizeShapeCommand, type SetParagraphPropertiesCommand, type SetShapeFillCommand, type SetShapeOutlineCommand, type SetShapeTransformCommand, type SetTextRunPropertiesCommand, createEditorSession };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
import { AddConnectorInput, SourceHandle, AddEmptySlideFromLayoutInput, AddTextBoxInput, EditableParagraphProperty, EditableTextRunProperty, PptxSourceModel, EditableTextRunProperties, EditableParagraphProperties, Emu, EditableShapeFill, EditableShapeOutline, MoveSlideInput } from '@pptx-glimpse/document';
|
|
1
|
+
import { AddConnectorInput, SourceHandle, AddEmptySlideFromLayoutInput, AddTextBoxInput, EditableParagraphProperty, EditableTextRunProperty, PptxSourceModel, EditableTextRunProperties, EditableParagraphProperties, Emu, EditableShapeFill, EditableShapeOutline, MoveSlideInput, SourceTextRun, SourceParagraph, SourceShapeNode, SourceTransform, SourceSlide, SourceImage } from '@pptx-glimpse/document';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Headless editor commands, selection, warnings, and history.
|
|
5
|
+
*
|
|
6
|
+
* Expected operation rejections use the shared discriminated failure contract exported
|
|
7
|
+
* by this module. Unexpected programmer errors and invariant violations must propagate.
|
|
8
|
+
* The repository-wide ownership, conversion, and catch rules are documented in
|
|
9
|
+
* [the editor error contract](../../../docs/editor-error-contract.md).
|
|
10
|
+
*/
|
|
2
11
|
|
|
3
12
|
interface ReplaceTextRunPlainTextCommand {
|
|
4
13
|
readonly kind: "replaceTextRunPlainText";
|
|
@@ -93,16 +102,18 @@ interface DeleteSlideCommand {
|
|
|
93
102
|
readonly handle: SourceHandle;
|
|
94
103
|
}
|
|
95
104
|
type EditorCommand = ReplaceTextRunPlainTextCommand | ReplaceParagraphPlainTextCommand | SetTextRunPropertiesCommand | ClearTextRunPropertiesCommand | SetParagraphPropertiesCommand | ClearParagraphPropertiesCommand | MoveShapeCommand | ResizeShapeCommand | SetShapeTransformCommand | SetShapeFillCommand | SetShapeOutlineCommand | AddTextBoxCommand | AddConnectorCommand | DeleteShapeCommand | ReplaceImageCommand | AddEmptySlideFromLayoutCommand | DuplicateSlideCommand | MoveSlideCommand | DeleteSlideCommand;
|
|
105
|
+
type EditorOperationErrorCode = "invalid-command" | "invalid-selection" | "empty-undo-stack" | "empty-redo-stack";
|
|
106
|
+
interface EditorOperationFailure<Code extends EditorOperationErrorCode = EditorOperationErrorCode> {
|
|
107
|
+
readonly ok: false;
|
|
108
|
+
readonly code: Code;
|
|
109
|
+
readonly message: string;
|
|
110
|
+
readonly cause?: unknown;
|
|
111
|
+
}
|
|
96
112
|
type EditorApplyCommandResult = {
|
|
97
113
|
readonly ok: true;
|
|
98
114
|
readonly document: PptxSourceModel;
|
|
99
115
|
readonly warnings?: readonly EditorCommandWarning[];
|
|
100
|
-
} |
|
|
101
|
-
readonly ok: false;
|
|
102
|
-
readonly code: "invalid-command";
|
|
103
|
-
readonly message: string;
|
|
104
|
-
readonly cause?: unknown;
|
|
105
|
-
};
|
|
116
|
+
} | EditorOperationFailure<"invalid-command">;
|
|
106
117
|
interface EditorCommandWarning {
|
|
107
118
|
readonly code: "shared-media-part";
|
|
108
119
|
readonly message: string;
|
|
@@ -112,21 +123,14 @@ interface EditorCommandWarning {
|
|
|
112
123
|
type EditorHistoryResult = {
|
|
113
124
|
readonly ok: true;
|
|
114
125
|
readonly document: PptxSourceModel;
|
|
115
|
-
} |
|
|
116
|
-
readonly ok: false;
|
|
117
|
-
readonly reason: "empty-undo-stack" | "empty-redo-stack";
|
|
118
|
-
};
|
|
126
|
+
} | EditorOperationFailure<"empty-undo-stack" | "empty-redo-stack">;
|
|
119
127
|
interface EditorSelection {
|
|
120
128
|
readonly shapeHandle: SourceHandle;
|
|
121
129
|
}
|
|
122
130
|
type EditorSelectShapeResult = {
|
|
123
131
|
readonly ok: true;
|
|
124
132
|
readonly selection: EditorSelection;
|
|
125
|
-
} |
|
|
126
|
-
readonly ok: false;
|
|
127
|
-
readonly code: "invalid-selection";
|
|
128
|
-
readonly message: string;
|
|
129
|
-
};
|
|
133
|
+
} | EditorOperationFailure<"invalid-selection">;
|
|
130
134
|
declare class EditorSession {
|
|
131
135
|
#private;
|
|
132
136
|
constructor(document: PptxSourceModel);
|
|
@@ -138,12 +142,34 @@ declare class EditorSession {
|
|
|
138
142
|
get redoDepth(): number;
|
|
139
143
|
selectShape(handle: SourceHandle): EditorSelectShapeResult;
|
|
140
144
|
deselectShape(): void;
|
|
145
|
+
replaceTextRunPlainText(run: SourceTextRun, text: string): EditorApplyCommandResult;
|
|
146
|
+
replaceParagraphPlainText(paragraph: SourceParagraph, text: string): EditorApplyCommandResult;
|
|
147
|
+
setTextRunProperties(run: SourceTextRun, properties: EditableTextRunProperties): EditorApplyCommandResult;
|
|
148
|
+
clearTextRunProperties(run: SourceTextRun, properties: readonly EditableTextRunProperty[]): EditorApplyCommandResult;
|
|
149
|
+
setParagraphProperties(paragraph: SourceParagraph, properties: EditableParagraphProperties): EditorApplyCommandResult;
|
|
150
|
+
clearParagraphProperties(paragraph: SourceParagraph, properties: readonly EditableParagraphProperty[]): EditorApplyCommandResult;
|
|
151
|
+
moveShape(shape: SourceShapeNode, offsetX: Emu, offsetY: Emu): EditorApplyCommandResult;
|
|
152
|
+
resizeShape(shape: SourceShapeNode, width: Emu, height: Emu): EditorApplyCommandResult;
|
|
153
|
+
setShapeTransform(shape: SourceShapeNode, transform: Pick<SourceTransform, "offsetX" | "offsetY" | "width" | "height">): EditorApplyCommandResult;
|
|
154
|
+
setShapeFill(shape: SourceShapeNode, fill: EditableShapeFill): EditorApplyCommandResult;
|
|
155
|
+
setShapeOutline(shape: SourceShapeNode, outline: EditableShapeOutline): EditorApplyCommandResult;
|
|
156
|
+
addTextBox(slide: SourceSlide, input: AddTextBoxInput): EditorApplyCommandResult;
|
|
157
|
+
addConnector(slide: SourceSlide, input: AddConnectorInput): EditorApplyCommandResult;
|
|
158
|
+
deleteShape(shape: SourceShapeNode): EditorApplyCommandResult;
|
|
159
|
+
replaceImage(image: SourceImage, bytes: Uint8Array): EditorApplyCommandResult;
|
|
160
|
+
addEmptySlideFromLayout(input: AddEmptySlideFromLayoutInput): EditorApplyCommandResult;
|
|
161
|
+
duplicateSlide(slide: SourceSlide): EditorApplyCommandResult;
|
|
162
|
+
moveSlide(slide: SourceSlide, input: MoveSlideInput): EditorApplyCommandResult;
|
|
163
|
+
deleteSlide(slide: SourceSlide): EditorApplyCommandResult;
|
|
141
164
|
apply(command: EditorCommand): EditorApplyCommandResult;
|
|
142
165
|
applyAll(commands: readonly EditorCommand[]): EditorApplyCommandResult;
|
|
143
166
|
undo(): EditorHistoryResult;
|
|
144
167
|
redo(): EditorHistoryResult;
|
|
145
168
|
private reconcileSelectionAfterDocumentChange;
|
|
169
|
+
private applyToShapeNode;
|
|
170
|
+
private applyToSlide;
|
|
171
|
+
private applyToSourceNode;
|
|
146
172
|
}
|
|
147
173
|
declare function createEditorSession(document: PptxSourceModel): EditorSession;
|
|
148
174
|
|
|
149
|
-
export { type AddConnectorCommand, type AddEmptySlideFromLayoutCommand, type AddTextBoxCommand, type ClearParagraphPropertiesCommand, type ClearTextRunPropertiesCommand, type DeleteShapeCommand, type DeleteSlideCommand, type DuplicateSlideCommand, type EditorApplyCommandResult, type EditorCommand, type EditorCommandWarning, type EditorHistoryResult, type EditorSelectShapeResult, type EditorSelection, EditorSession, type MoveShapeCommand, type MoveSlideCommand, type ReplaceImageCommand, type ReplaceParagraphPlainTextCommand, type ReplaceTextRunPlainTextCommand, type ResizeShapeCommand, type SetParagraphPropertiesCommand, type SetShapeFillCommand, type SetShapeOutlineCommand, type SetShapeTransformCommand, type SetTextRunPropertiesCommand, createEditorSession };
|
|
175
|
+
export { type AddConnectorCommand, type AddEmptySlideFromLayoutCommand, type AddTextBoxCommand, type ClearParagraphPropertiesCommand, type ClearTextRunPropertiesCommand, type DeleteShapeCommand, type DeleteSlideCommand, type DuplicateSlideCommand, type EditorApplyCommandResult, type EditorCommand, type EditorCommandWarning, type EditorHistoryResult, type EditorOperationErrorCode, type EditorOperationFailure, type EditorSelectShapeResult, type EditorSelection, EditorSession, type MoveShapeCommand, type MoveSlideCommand, type ReplaceImageCommand, type ReplaceParagraphPlainTextCommand, type ReplaceTextRunPlainTextCommand, type ResizeShapeCommand, type SetParagraphPropertiesCommand, type SetShapeFillCommand, type SetShapeOutlineCommand, type SetShapeTransformCommand, type SetTextRunPropertiesCommand, createEditorSession };
|
package/dist/index.js
CHANGED
|
@@ -8,7 +8,9 @@ import {
|
|
|
8
8
|
deleteShape,
|
|
9
9
|
deleteSlide,
|
|
10
10
|
duplicateSlide,
|
|
11
|
+
findParagraphBySourceHandle,
|
|
11
12
|
findShapeNodeBySourceHandle,
|
|
13
|
+
findTextRunBySourceHandle,
|
|
12
14
|
moveSlide,
|
|
13
15
|
replaceImageBytes,
|
|
14
16
|
replaceParagraphPlainText,
|
|
@@ -60,50 +62,198 @@ var EditorSession = class {
|
|
|
60
62
|
deselectShape() {
|
|
61
63
|
this.#selection = void 0;
|
|
62
64
|
}
|
|
65
|
+
replaceTextRunPlainText(run, text) {
|
|
66
|
+
return this.applyToSourceNode(
|
|
67
|
+
"replaceTextRunPlainText",
|
|
68
|
+
run,
|
|
69
|
+
isSourceTextRun,
|
|
70
|
+
findTextRunBySourceHandle,
|
|
71
|
+
(handle) => ({ kind: "replaceTextRunPlainText", handle, text })
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
replaceParagraphPlainText(paragraph, text) {
|
|
75
|
+
return this.applyToSourceNode(
|
|
76
|
+
"replaceParagraphPlainText",
|
|
77
|
+
paragraph,
|
|
78
|
+
isSourceParagraph,
|
|
79
|
+
findParagraphBySourceHandle,
|
|
80
|
+
(handle) => ({ kind: "replaceParagraphPlainText", handle, text })
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
setTextRunProperties(run, properties) {
|
|
84
|
+
return this.applyToSourceNode(
|
|
85
|
+
"setTextRunProperties",
|
|
86
|
+
run,
|
|
87
|
+
isSourceTextRun,
|
|
88
|
+
findTextRunBySourceHandle,
|
|
89
|
+
(handle) => ({ kind: "setTextRunProperties", handle, properties })
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
clearTextRunProperties(run, properties) {
|
|
93
|
+
return this.applyToSourceNode(
|
|
94
|
+
"clearTextRunProperties",
|
|
95
|
+
run,
|
|
96
|
+
isSourceTextRun,
|
|
97
|
+
findTextRunBySourceHandle,
|
|
98
|
+
(handle) => ({ kind: "clearTextRunProperties", handle, properties })
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
setParagraphProperties(paragraph, properties) {
|
|
102
|
+
return this.applyToSourceNode(
|
|
103
|
+
"setParagraphProperties",
|
|
104
|
+
paragraph,
|
|
105
|
+
isSourceParagraph,
|
|
106
|
+
findParagraphBySourceHandle,
|
|
107
|
+
(handle) => ({ kind: "setParagraphProperties", handle, properties })
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
clearParagraphProperties(paragraph, properties) {
|
|
111
|
+
return this.applyToSourceNode(
|
|
112
|
+
"clearParagraphProperties",
|
|
113
|
+
paragraph,
|
|
114
|
+
isSourceParagraph,
|
|
115
|
+
findParagraphBySourceHandle,
|
|
116
|
+
(handle) => ({ kind: "clearParagraphProperties", handle, properties })
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
moveShape(shape, offsetX, offsetY) {
|
|
120
|
+
return this.applyToShapeNode("moveShape", shape, (handle) => ({
|
|
121
|
+
kind: "moveShape",
|
|
122
|
+
handle,
|
|
123
|
+
offsetX,
|
|
124
|
+
offsetY
|
|
125
|
+
}));
|
|
126
|
+
}
|
|
127
|
+
resizeShape(shape, width, height) {
|
|
128
|
+
return this.applyToShapeNode("resizeShape", shape, (handle) => ({
|
|
129
|
+
kind: "resizeShape",
|
|
130
|
+
handle,
|
|
131
|
+
width,
|
|
132
|
+
height
|
|
133
|
+
}));
|
|
134
|
+
}
|
|
135
|
+
setShapeTransform(shape, transform) {
|
|
136
|
+
return this.applyToShapeNode("setShapeTransform", shape, (handle) => ({
|
|
137
|
+
kind: "setShapeTransform",
|
|
138
|
+
handle,
|
|
139
|
+
...transform
|
|
140
|
+
}));
|
|
141
|
+
}
|
|
142
|
+
setShapeFill(shape, fill) {
|
|
143
|
+
return this.applyToShapeNode("setShapeFill", shape, (handle) => ({
|
|
144
|
+
kind: "setShapeFill",
|
|
145
|
+
handle,
|
|
146
|
+
fill
|
|
147
|
+
}));
|
|
148
|
+
}
|
|
149
|
+
setShapeOutline(shape, outline) {
|
|
150
|
+
return this.applyToShapeNode("setShapeOutline", shape, (handle) => ({
|
|
151
|
+
kind: "setShapeOutline",
|
|
152
|
+
handle,
|
|
153
|
+
outline
|
|
154
|
+
}));
|
|
155
|
+
}
|
|
156
|
+
addTextBox(slide, input) {
|
|
157
|
+
return this.applyToSlide("addTextBox", slide, (slideHandle) => ({
|
|
158
|
+
kind: "addTextBox",
|
|
159
|
+
slideHandle,
|
|
160
|
+
...input
|
|
161
|
+
}));
|
|
162
|
+
}
|
|
163
|
+
addConnector(slide, input) {
|
|
164
|
+
return this.applyToSlide("addConnector", slide, (slideHandle) => ({
|
|
165
|
+
kind: "addConnector",
|
|
166
|
+
slideHandle,
|
|
167
|
+
...input
|
|
168
|
+
}));
|
|
169
|
+
}
|
|
170
|
+
deleteShape(shape) {
|
|
171
|
+
return this.applyToShapeNode("deleteShape", shape, (handle) => ({
|
|
172
|
+
kind: "deleteShape",
|
|
173
|
+
handle
|
|
174
|
+
}));
|
|
175
|
+
}
|
|
176
|
+
replaceImage(image, bytes) {
|
|
177
|
+
return this.applyToSourceNode(
|
|
178
|
+
"replaceImage",
|
|
179
|
+
image,
|
|
180
|
+
isSourceImage,
|
|
181
|
+
(document, handle) => {
|
|
182
|
+
const shape = findShapeNodeBySourceHandle(document, handle);
|
|
183
|
+
return shape?.kind === "image" ? shape : void 0;
|
|
184
|
+
},
|
|
185
|
+
(handle) => ({ kind: "replaceImage", handle, bytes })
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
addEmptySlideFromLayout(input) {
|
|
189
|
+
return this.apply({ kind: "addEmptySlideFromLayout", ...input });
|
|
190
|
+
}
|
|
191
|
+
duplicateSlide(slide) {
|
|
192
|
+
return this.applyToSlide("duplicateSlide", slide, (handle) => ({
|
|
193
|
+
kind: "duplicateSlide",
|
|
194
|
+
handle
|
|
195
|
+
}));
|
|
196
|
+
}
|
|
197
|
+
moveSlide(slide, input) {
|
|
198
|
+
return this.applyToSlide("moveSlide", slide, (handle) => ({
|
|
199
|
+
kind: "moveSlide",
|
|
200
|
+
handle,
|
|
201
|
+
...input
|
|
202
|
+
}));
|
|
203
|
+
}
|
|
204
|
+
deleteSlide(slide) {
|
|
205
|
+
return this.applyToSlide("deleteSlide", slide, (handle) => ({
|
|
206
|
+
kind: "deleteSlide",
|
|
207
|
+
handle
|
|
208
|
+
}));
|
|
209
|
+
}
|
|
63
210
|
apply(command) {
|
|
64
211
|
return this.applyAll([command]);
|
|
65
212
|
}
|
|
66
213
|
applyAll(commands) {
|
|
67
214
|
const before = this.#document;
|
|
68
215
|
if (commands.length === 0) return { ok: true, document: before };
|
|
216
|
+
let after = before;
|
|
217
|
+
const warnings = [];
|
|
218
|
+
for (const command of commands) {
|
|
219
|
+
const result = applyCommandToDocument(after, command);
|
|
220
|
+
if (!result.ok) return result;
|
|
221
|
+
after = result.document;
|
|
222
|
+
warnings.push(...collectCommandWarnings(after, [command]));
|
|
223
|
+
}
|
|
69
224
|
try {
|
|
70
|
-
let after = before;
|
|
71
|
-
const warnings = [];
|
|
72
|
-
for (const command of commands) {
|
|
73
|
-
after = applyCommandToDocument(after, command);
|
|
74
|
-
warnings.push(...collectCommandWarnings(after, [command]));
|
|
75
|
-
}
|
|
76
225
|
assertNoConflictingParagraphAndRunEdits(after.edits);
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
...dedupedWarnings.length > 0 ? { warnings: dedupedWarnings } : {}
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
this.#document = after;
|
|
87
|
-
this.reconcileSelectionAfterDocumentChange();
|
|
88
|
-
this.#undoStack.push({ before, after });
|
|
89
|
-
this.#redoStack.length = 0;
|
|
226
|
+
} catch (cause) {
|
|
227
|
+
return invalidCommandFailure(cause);
|
|
228
|
+
}
|
|
229
|
+
after = normalizeEditorEdits(after);
|
|
230
|
+
const dedupedWarnings = dedupeCommandWarnings(warnings);
|
|
231
|
+
if (after === before) {
|
|
90
232
|
return {
|
|
91
233
|
ok: true,
|
|
92
|
-
document:
|
|
234
|
+
document: before,
|
|
93
235
|
...dedupedWarnings.length > 0 ? { warnings: dedupedWarnings } : {}
|
|
94
236
|
};
|
|
95
|
-
} catch (error) {
|
|
96
|
-
return {
|
|
97
|
-
ok: false,
|
|
98
|
-
code: "invalid-command",
|
|
99
|
-
message: error instanceof Error ? error.message : "Editor command was rejected.",
|
|
100
|
-
cause: error
|
|
101
|
-
};
|
|
102
237
|
}
|
|
238
|
+
this.#document = after;
|
|
239
|
+
this.reconcileSelectionAfterDocumentChange();
|
|
240
|
+
this.#undoStack.push({ before, after });
|
|
241
|
+
this.#redoStack.length = 0;
|
|
242
|
+
return {
|
|
243
|
+
ok: true,
|
|
244
|
+
document: after,
|
|
245
|
+
...dedupedWarnings.length > 0 ? { warnings: dedupedWarnings } : {}
|
|
246
|
+
};
|
|
103
247
|
}
|
|
104
248
|
undo() {
|
|
105
249
|
const entry = this.#undoStack.pop();
|
|
106
|
-
if (entry === void 0)
|
|
250
|
+
if (entry === void 0) {
|
|
251
|
+
return {
|
|
252
|
+
ok: false,
|
|
253
|
+
code: "empty-undo-stack",
|
|
254
|
+
message: "undo: undo history is empty"
|
|
255
|
+
};
|
|
256
|
+
}
|
|
107
257
|
this.#document = entry.before;
|
|
108
258
|
this.reconcileSelectionAfterDocumentChange();
|
|
109
259
|
this.#redoStack.push(entry);
|
|
@@ -111,7 +261,13 @@ var EditorSession = class {
|
|
|
111
261
|
}
|
|
112
262
|
redo() {
|
|
113
263
|
const entry = this.#redoStack.pop();
|
|
114
|
-
if (entry === void 0)
|
|
264
|
+
if (entry === void 0) {
|
|
265
|
+
return {
|
|
266
|
+
ok: false,
|
|
267
|
+
code: "empty-redo-stack",
|
|
268
|
+
message: "redo: redo history is empty"
|
|
269
|
+
};
|
|
270
|
+
}
|
|
115
271
|
this.#document = entry.after;
|
|
116
272
|
this.reconcileSelectionAfterDocumentChange();
|
|
117
273
|
this.#undoStack.push(entry);
|
|
@@ -123,11 +279,172 @@ var EditorSession = class {
|
|
|
123
279
|
this.#selection = void 0;
|
|
124
280
|
}
|
|
125
281
|
}
|
|
282
|
+
applyToShapeNode(operation, shape, createCommand) {
|
|
283
|
+
return this.applyToSourceNode(
|
|
284
|
+
operation,
|
|
285
|
+
shape,
|
|
286
|
+
isSourceShapeNode,
|
|
287
|
+
findShapeNodeBySourceHandle,
|
|
288
|
+
createCommand
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
applyToSlide(operation, slide, createCommand) {
|
|
292
|
+
return this.applyToSourceNode(
|
|
293
|
+
operation,
|
|
294
|
+
slide,
|
|
295
|
+
isSourceSlide,
|
|
296
|
+
(document, handle) => document.slides.find((candidate) => sourceHandlesEqual(candidate.handle, handle)),
|
|
297
|
+
createCommand
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
applyToSourceNode(operation, node, isExpectedNode, findCurrentNode, createCommand) {
|
|
301
|
+
if (!isExpectedNode(node)) {
|
|
302
|
+
return invalidSourceNodeFailure(operation, "source node has the wrong target type");
|
|
303
|
+
}
|
|
304
|
+
if (node.handle === void 0) {
|
|
305
|
+
return invalidSourceNodeFailure(operation, "source node does not have a handle");
|
|
306
|
+
}
|
|
307
|
+
if (findCurrentNode(this.#document, node.handle) === void 0) {
|
|
308
|
+
return invalidSourceNodeFailure(
|
|
309
|
+
operation,
|
|
310
|
+
"source node handle was not found in the current EditorSession document"
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
return this.apply(createCommand(node.handle));
|
|
314
|
+
}
|
|
126
315
|
};
|
|
127
316
|
function createEditorSession(document) {
|
|
128
317
|
return new EditorSession(document);
|
|
129
318
|
}
|
|
319
|
+
var EDITOR_COMMAND_KINDS = /* @__PURE__ */ new Set([
|
|
320
|
+
"replaceTextRunPlainText",
|
|
321
|
+
"replaceParagraphPlainText",
|
|
322
|
+
"setTextRunProperties",
|
|
323
|
+
"clearTextRunProperties",
|
|
324
|
+
"setParagraphProperties",
|
|
325
|
+
"clearParagraphProperties",
|
|
326
|
+
"moveShape",
|
|
327
|
+
"resizeShape",
|
|
328
|
+
"setShapeTransform",
|
|
329
|
+
"setShapeFill",
|
|
330
|
+
"setShapeOutline",
|
|
331
|
+
"addTextBox",
|
|
332
|
+
"addConnector",
|
|
333
|
+
"deleteShape",
|
|
334
|
+
"replaceImage",
|
|
335
|
+
"addEmptySlideFromLayout",
|
|
336
|
+
"duplicateSlide",
|
|
337
|
+
"moveSlide",
|
|
338
|
+
"deleteSlide"
|
|
339
|
+
]);
|
|
340
|
+
var EXPECTED_COMMAND_REJECTION_PREFIXES = [
|
|
341
|
+
"replaceTextRunPlainText:",
|
|
342
|
+
"replaceParagraphPlainText:",
|
|
343
|
+
"setTextRunProperties:",
|
|
344
|
+
"clearTextRunProperties:",
|
|
345
|
+
"setParagraphProperties:",
|
|
346
|
+
"clearParagraphProperties:",
|
|
347
|
+
"moveShape:",
|
|
348
|
+
"resizeShape:",
|
|
349
|
+
"setShapeTransform:",
|
|
350
|
+
"setShapeFill:",
|
|
351
|
+
"setShapeOutline:",
|
|
352
|
+
"addTextBox:",
|
|
353
|
+
"addConnector:",
|
|
354
|
+
"deleteShape:",
|
|
355
|
+
"replaceImageBytes:",
|
|
356
|
+
"addEmptySlideFromLayout:",
|
|
357
|
+
"duplicateSlide:",
|
|
358
|
+
"moveSlide:",
|
|
359
|
+
"deleteSlide:",
|
|
360
|
+
"updateTextRunProperties:",
|
|
361
|
+
"updateParagraphProperties:",
|
|
362
|
+
"updateShapeTransform:"
|
|
363
|
+
];
|
|
130
364
|
function applyCommandToDocument(document, command) {
|
|
365
|
+
if (!EDITOR_COMMAND_KINDS.has(command.kind)) {
|
|
366
|
+
throw new TypeError(`EditorSession: unsupported command kind '${String(command.kind)}'`);
|
|
367
|
+
}
|
|
368
|
+
switch (command.kind) {
|
|
369
|
+
case "replaceTextRunPlainText":
|
|
370
|
+
case "replaceParagraphPlainText":
|
|
371
|
+
case "setTextRunProperties":
|
|
372
|
+
case "clearTextRunProperties":
|
|
373
|
+
case "setParagraphProperties":
|
|
374
|
+
case "clearParagraphProperties":
|
|
375
|
+
case "moveShape":
|
|
376
|
+
case "resizeShape":
|
|
377
|
+
case "setShapeTransform":
|
|
378
|
+
case "setShapeFill":
|
|
379
|
+
case "setShapeOutline":
|
|
380
|
+
case "addTextBox":
|
|
381
|
+
case "addConnector":
|
|
382
|
+
case "deleteShape":
|
|
383
|
+
case "replaceImage":
|
|
384
|
+
case "addEmptySlideFromLayout":
|
|
385
|
+
case "duplicateSlide":
|
|
386
|
+
case "moveSlide":
|
|
387
|
+
case "deleteSlide":
|
|
388
|
+
return attemptCommand(() => executeCommand(document, command));
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
function attemptCommand(operation) {
|
|
392
|
+
try {
|
|
393
|
+
return { ok: true, document: operation() };
|
|
394
|
+
} catch (cause) {
|
|
395
|
+
return invalidCommandFailure(cause);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
function invalidCommandFailure(cause) {
|
|
399
|
+
if (!(cause instanceof Error) || !EXPECTED_COMMAND_REJECTION_PREFIXES.some((prefix) => cause.message.startsWith(prefix))) {
|
|
400
|
+
throw cause;
|
|
401
|
+
}
|
|
402
|
+
return {
|
|
403
|
+
ok: false,
|
|
404
|
+
code: "invalid-command",
|
|
405
|
+
message: cause.message,
|
|
406
|
+
cause
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
function invalidSourceNodeFailure(operation, reason) {
|
|
410
|
+
return {
|
|
411
|
+
ok: false,
|
|
412
|
+
code: "invalid-command",
|
|
413
|
+
message: `${operation}: ${reason}`
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
function isSourceTextRun(value) {
|
|
417
|
+
return isObject(value) && value.kind === "textRun";
|
|
418
|
+
}
|
|
419
|
+
function isSourceParagraph(value) {
|
|
420
|
+
return isObject(value) && Array.isArray(value.runs);
|
|
421
|
+
}
|
|
422
|
+
var SOURCE_SHAPE_NODE_KINDS = /* @__PURE__ */ new Set([
|
|
423
|
+
"shape",
|
|
424
|
+
"connector",
|
|
425
|
+
"group",
|
|
426
|
+
"image",
|
|
427
|
+
"table",
|
|
428
|
+
"chart",
|
|
429
|
+
"smartArt",
|
|
430
|
+
"raw"
|
|
431
|
+
]);
|
|
432
|
+
function isSourceShapeNode(value) {
|
|
433
|
+
return isObject(value) && typeof value.kind === "string" && SOURCE_SHAPE_NODE_KINDS.has(value.kind);
|
|
434
|
+
}
|
|
435
|
+
function isSourceImage(value) {
|
|
436
|
+
return isObject(value) && value.kind === "image";
|
|
437
|
+
}
|
|
438
|
+
function isSourceSlide(value) {
|
|
439
|
+
return isObject(value) && typeof value.partPath === "string" && typeof value.layoutPartPath === "string" && Array.isArray(value.shapes);
|
|
440
|
+
}
|
|
441
|
+
function isObject(value) {
|
|
442
|
+
return typeof value === "object" && value !== null;
|
|
443
|
+
}
|
|
444
|
+
function sourceHandlesEqual(left, right) {
|
|
445
|
+
return left !== void 0 && left.partPath === right.partPath && left.nodeId === right.nodeId && left.relationshipId === right.relationshipId && left.orderingSlot === right.orderingSlot;
|
|
446
|
+
}
|
|
447
|
+
function executeCommand(document, command) {
|
|
131
448
|
switch (command.kind) {
|
|
132
449
|
case "replaceTextRunPlainText":
|
|
133
450
|
return replaceTextRunPlainTextCommand(document, command);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pptx-glimpse/editor",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Headless PPTX editing commands, validation, selection, and undo/redo history for PptxSourceModel.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
7
7
|
"module": "./dist/index.js",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
}
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@pptx-glimpse/document": "^0.12.
|
|
22
|
+
"@pptx-glimpse/document": "^0.12.1"
|
|
23
23
|
},
|
|
24
24
|
"files": [
|
|
25
25
|
"dist",
|
|
@@ -32,7 +32,11 @@
|
|
|
32
32
|
"pptx",
|
|
33
33
|
"powerpoint",
|
|
34
34
|
"editor",
|
|
35
|
-
"headless"
|
|
35
|
+
"headless",
|
|
36
|
+
"commands",
|
|
37
|
+
"undo",
|
|
38
|
+
"redo",
|
|
39
|
+
"selection"
|
|
36
40
|
],
|
|
37
41
|
"repository": {
|
|
38
42
|
"type": "git",
|