web-doc 0.6.2 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (188) hide show
  1. package/THIRD_PARTY_NOTICES.md +26 -1
  2. package/dist/adapters/docx-images.d.ts +13 -4
  3. package/dist/adapters/docx-images.js +3 -0
  4. package/dist/adapters/docx-paragraphs.d.ts +65 -0
  5. package/dist/adapters/docx-paragraphs.js +165 -0
  6. package/dist/adapters/docx-prepass.d.ts +17 -0
  7. package/dist/adapters/docx-prepass.js +230 -0
  8. package/dist/adapters/office.d.ts +31 -5
  9. package/dist/adapters/office.js +60 -29
  10. package/dist/adapters/pdf.d.ts +9 -0
  11. package/dist/adapters/pdf.js +10 -0
  12. package/dist/assets/pdfium/pdfium.wasm +0 -0
  13. package/dist/contracts.d.ts +47 -2
  14. package/dist/edit/assets.d.ts +23 -0
  15. package/dist/edit/assets.js +75 -0
  16. package/dist/edit/docx/elements.d.ts +6 -0
  17. package/dist/edit/docx/elements.js +90 -0
  18. package/dist/edit/docx/engine.d.ts +51 -0
  19. package/dist/edit/docx/engine.js +473 -0
  20. package/dist/edit/docx/handlers.d.ts +3 -0
  21. package/dist/edit/docx/handlers.js +15 -0
  22. package/dist/edit/docx/ids.d.ts +45 -0
  23. package/dist/edit/docx/ids.js +101 -0
  24. package/dist/edit/docx/model.d.ts +92 -0
  25. package/dist/edit/docx/model.js +339 -0
  26. package/dist/edit/docx/operations.d.ts +37 -0
  27. package/dist/edit/docx/operations.js +3 -0
  28. package/dist/edit/docx/provider.d.ts +13 -0
  29. package/dist/edit/docx/provider.js +34 -0
  30. package/dist/edit/docx/schemas.d.ts +6 -0
  31. package/dist/edit/docx/schemas.js +192 -0
  32. package/dist/edit/docx/session.d.ts +37 -0
  33. package/dist/edit/docx/session.js +426 -0
  34. package/dist/edit/docx/structure-ops.d.ts +6 -0
  35. package/dist/edit/docx/structure-ops.js +494 -0
  36. package/dist/edit/docx/style.d.ts +45 -0
  37. package/dist/edit/docx/style.js +375 -0
  38. package/dist/edit/docx/table-ops.d.ts +4 -0
  39. package/dist/edit/docx/table-ops.js +219 -0
  40. package/dist/edit/docx/text-ops.d.ts +18 -0
  41. package/dist/edit/docx/text-ops.js +458 -0
  42. package/dist/edit/docx/text.d.ts +34 -0
  43. package/dist/edit/docx/text.js +263 -0
  44. package/dist/edit/docx/types.d.ts +191 -0
  45. package/dist/edit/docx/types.js +1 -0
  46. package/dist/edit/docx/write.d.ts +50 -0
  47. package/dist/edit/docx/write.js +352 -0
  48. package/dist/edit/engine.d.ts +117 -0
  49. package/dist/edit/engine.js +1 -0
  50. package/dist/edit/history.d.ts +53 -0
  51. package/dist/edit/history.js +101 -0
  52. package/dist/edit/ooxml/names.d.ts +20 -0
  53. package/dist/edit/ooxml/names.js +61 -0
  54. package/dist/edit/ooxml/opc.d.ts +50 -0
  55. package/dist/edit/ooxml/opc.js +150 -0
  56. package/dist/edit/ooxml/package.d.ts +82 -0
  57. package/dist/edit/ooxml/package.js +233 -0
  58. package/dist/edit/ooxml/patch.d.ts +51 -0
  59. package/dist/edit/ooxml/patch.js +250 -0
  60. package/dist/edit/ooxml/transaction.d.ts +39 -0
  61. package/dist/edit/ooxml/transaction.js +316 -0
  62. package/dist/edit/ooxml/worker.d.ts +8 -0
  63. package/dist/edit/ooxml/worker.js +12 -0
  64. package/dist/edit/ooxml/writer.d.ts +21 -0
  65. package/dist/edit/ooxml/writer.js +187 -0
  66. package/dist/edit/ooxml/xml.d.ts +74 -0
  67. package/dist/edit/ooxml/xml.js +451 -0
  68. package/dist/edit/ooxml/zip.d.ts +54 -0
  69. package/dist/edit/ooxml/zip.js +280 -0
  70. package/dist/edit/operations.d.ts +19 -0
  71. package/dist/edit/operations.js +137 -0
  72. package/dist/edit/pdf/engine/compact.d.ts +6 -0
  73. package/dist/edit/pdf/engine/compact.js +442 -0
  74. package/dist/edit/pdf/engine/document.d.ts +95 -0
  75. package/dist/edit/pdf/engine/document.js +868 -0
  76. package/dist/edit/pdf/engine/elements.d.ts +45 -0
  77. package/dist/edit/pdf/engine/elements.js +313 -0
  78. package/dist/edit/pdf/engine/existing-text.d.ts +4 -0
  79. package/dist/edit/pdf/engine/existing-text.js +424 -0
  80. package/dist/edit/pdf/engine/fonts.d.ts +78 -0
  81. package/dist/edit/pdf/engine/fonts.js +466 -0
  82. package/dist/edit/pdf/engine/geometry.d.ts +36 -0
  83. package/dist/edit/pdf/engine/geometry.js +97 -0
  84. package/dist/edit/pdf/engine/handler.d.ts +21 -0
  85. package/dist/edit/pdf/engine/handler.js +108 -0
  86. package/dist/edit/pdf/engine/images.d.ts +33 -0
  87. package/dist/edit/pdf/engine/images.js +188 -0
  88. package/dist/edit/pdf/engine/layout.d.ts +23 -0
  89. package/dist/edit/pdf/engine/layout.js +177 -0
  90. package/dist/edit/pdf/engine/operations.d.ts +67 -0
  91. package/dist/edit/pdf/engine/operations.js +3 -0
  92. package/dist/edit/pdf/engine/pages.d.ts +6 -0
  93. package/dist/edit/pdf/engine/pages.js +98 -0
  94. package/dist/edit/pdf/engine/pdfium.d.ts +195 -0
  95. package/dist/edit/pdf/engine/pdfium.js +249 -0
  96. package/dist/edit/pdf/engine/shapes.d.ts +4 -0
  97. package/dist/edit/pdf/engine/shapes.js +183 -0
  98. package/dist/edit/pdf/engine/tables.d.ts +44 -0
  99. package/dist/edit/pdf/engine/tables.js +315 -0
  100. package/dist/edit/pdf/engine/text-box.d.ts +71 -0
  101. package/dist/edit/pdf/engine/text-box.js +317 -0
  102. package/dist/edit/pdf/engine/text-layout.d.ts +28 -0
  103. package/dist/edit/pdf/engine/text-layout.js +67 -0
  104. package/dist/edit/pdf/engine/transform.d.ts +5 -0
  105. package/dist/edit/pdf/engine/transform.js +137 -0
  106. package/dist/edit/pdf/provider.d.ts +35 -0
  107. package/dist/edit/pdf/provider.js +92 -0
  108. package/dist/edit/pdf/range-map.d.ts +14 -0
  109. package/dist/edit/pdf/range-map.js +107 -0
  110. package/dist/edit/pdf/schemas.d.ts +11 -0
  111. package/dist/edit/pdf/schemas.js +291 -0
  112. package/dist/edit/pdf/selection.d.ts +5 -0
  113. package/dist/edit/pdf/selection.js +152 -0
  114. package/dist/edit/pdf/session.d.ts +53 -0
  115. package/dist/edit/pdf/session.js +273 -0
  116. package/dist/edit/pdf/types.d.ts +336 -0
  117. package/dist/edit/pdf/types.js +1 -0
  118. package/dist/edit/pptx/elements.d.ts +74 -0
  119. package/dist/edit/pptx/elements.js +301 -0
  120. package/dist/edit/pptx/engine.d.ts +37 -0
  121. package/dist/edit/pptx/engine.js +466 -0
  122. package/dist/edit/pptx/geometry.d.ts +72 -0
  123. package/dist/edit/pptx/geometry.js +193 -0
  124. package/dist/edit/pptx/handler.d.ts +7 -0
  125. package/dist/edit/pptx/handler.js +91 -0
  126. package/dist/edit/pptx/handlers.d.ts +3 -0
  127. package/dist/edit/pptx/handlers.js +21 -0
  128. package/dist/edit/pptx/image-table-ops.d.ts +5 -0
  129. package/dist/edit/pptx/image-table-ops.js +233 -0
  130. package/dist/edit/pptx/model.d.ts +69 -0
  131. package/dist/edit/pptx/model.js +170 -0
  132. package/dist/edit/pptx/operations.d.ts +50 -0
  133. package/dist/edit/pptx/operations.js +11 -0
  134. package/dist/edit/pptx/provider.d.ts +17 -0
  135. package/dist/edit/pptx/provider.js +40 -0
  136. package/dist/edit/pptx/schemas.d.ts +6 -0
  137. package/dist/edit/pptx/schemas.js +220 -0
  138. package/dist/edit/pptx/session.d.ts +44 -0
  139. package/dist/edit/pptx/session.js +114 -0
  140. package/dist/edit/pptx/shape-ops.d.ts +10 -0
  141. package/dist/edit/pptx/shape-ops.js +486 -0
  142. package/dist/edit/pptx/slide-ops.d.ts +6 -0
  143. package/dist/edit/pptx/slide-ops.js +353 -0
  144. package/dist/edit/pptx/style.d.ts +31 -0
  145. package/dist/edit/pptx/style.js +181 -0
  146. package/dist/edit/pptx/text-ops.d.ts +13 -0
  147. package/dist/edit/pptx/text-ops.js +267 -0
  148. package/dist/edit/pptx/text-write.d.ts +67 -0
  149. package/dist/edit/pptx/text-write.js +293 -0
  150. package/dist/edit/pptx/text.d.ts +41 -0
  151. package/dist/edit/pptx/text.js +99 -0
  152. package/dist/edit/pptx/types.d.ts +232 -0
  153. package/dist/edit/pptx/types.js +1 -0
  154. package/dist/edit/schema.d.ts +11 -0
  155. package/dist/edit/schema.js +275 -0
  156. package/dist/edit/session.d.ts +66 -0
  157. package/dist/edit/session.js +701 -0
  158. package/dist/edit/sessions.d.ts +8 -0
  159. package/dist/edit/sessions.js +1 -0
  160. package/dist/edit/types.d.ts +276 -0
  161. package/dist/edit/types.js +1 -0
  162. package/dist/edit/worker-engine.d.ts +31 -0
  163. package/dist/edit/worker-engine.js +91 -0
  164. package/dist/fonts/THIRD_PARTY_NOTICES.md +3 -0
  165. package/dist/fonts/manifest.json +6 -1
  166. package/dist/fonts/noto-sans-latin-cyrillic.ttf +0 -0
  167. package/dist/fonts.d.ts +2 -0
  168. package/dist/fonts.js +4 -0
  169. package/dist/headless.d.ts +4 -0
  170. package/dist/headless.js +4 -0
  171. package/dist/index.d.ts +5 -0
  172. package/dist/index.js +5 -0
  173. package/dist/limits.js +3 -0
  174. package/dist/ooxml-edit-worker.d.ts +1 -0
  175. package/dist/ooxml-edit-worker.js +8 -0
  176. package/dist/pdf-edit-worker.d.ts +1 -0
  177. package/dist/pdf-edit-worker.js +35 -0
  178. package/dist/spreadsheet-viewport.d.ts +5 -0
  179. package/dist/spreadsheet-viewport.js +11 -0
  180. package/dist/ui.js +7 -0
  181. package/dist/viewer.d.ts +6 -0
  182. package/dist/viewer.js +293 -19
  183. package/dist/viewport.d.ts +13 -0
  184. package/dist/viewport.js +126 -1
  185. package/dist/worker-protocol.d.ts +39 -2
  186. package/dist/workers/ooxml-edit-worker.js +8671 -0
  187. package/dist/workers/pdf-edit-worker.js +10844 -0
  188. package/package.json +3 -3
@@ -0,0 +1,273 @@
1
+ import { ViewerError } from "../../errors.js";
2
+ import { reportError } from "../session.js";
3
+ import { rectContains } from "./engine/geometry.js";
4
+ import { mapRangeThrough } from "./range-map.js";
5
+ import { resolveSelection } from "./selection.js";
6
+ /**
7
+ * The PDF session: the core session narrowed to PDF operations and elements.
8
+ * Typed methods are added here as their operations ship; each is `apply()`
9
+ * with a single operation.
10
+ */
11
+ export class PdfSession {
12
+ format = "pdf";
13
+ #core;
14
+ /** Committed calls, oldest first, for `mapRange`; bounded by `LOG_LIMIT`. */
15
+ #log = [];
16
+ /** Batches applied and not undone, and those undone and not redone. */
17
+ #applied = [];
18
+ #undone = [];
19
+ /** The last elements read per page, with the revision they describe. */
20
+ #geometry = new Map();
21
+ constructor(core) {
22
+ this.#core = core;
23
+ }
24
+ get sessionId() {
25
+ return this.#core.sessionId;
26
+ }
27
+ get state() {
28
+ return this.#core.state;
29
+ }
30
+ get schemas() {
31
+ return this.#core.schemas;
32
+ }
33
+ async apply(operations, options) {
34
+ const receipt = await this.#core.apply(operations, options);
35
+ this.#record("apply", operations, receipt);
36
+ return receipt;
37
+ }
38
+ async applyJson(operations, options) {
39
+ const receipt = await this.#core.applyJson(operations, options);
40
+ this.#record("apply", operations, receipt);
41
+ return receipt;
42
+ }
43
+ async undo(options) {
44
+ const receipt = await this.#core.undo(options);
45
+ this.#record("undo", [], receipt);
46
+ return receipt;
47
+ }
48
+ async redo(options) {
49
+ const receipt = await this.#core.redo(options);
50
+ this.#record("redo", [], receipt);
51
+ return receipt;
52
+ }
53
+ async reset(options) {
54
+ const receipt = await this.#core.reset(options);
55
+ this.#record("reset", [], receipt);
56
+ return receipt;
57
+ }
58
+ /** Keeps the mutation log in step with the core after a committed call. */
59
+ #record(kind, operations, receipt) {
60
+ const last = this.#log.at(-1)?.revision ?? 0;
61
+ // A dry run or a no-op leaves the revision alone and changes nothing.
62
+ if (receipt.dryRun || receipt.revision === last)
63
+ return;
64
+ this.#refreshGeometry(receipt);
65
+ let involved = operations;
66
+ switch (kind) {
67
+ case "apply":
68
+ this.#applied.push(operations);
69
+ this.#undone = [];
70
+ break;
71
+ case "undo":
72
+ involved = this.#applied.pop() ?? [];
73
+ this.#undone.push(involved);
74
+ break;
75
+ case "redo":
76
+ involved = this.#undone.pop() ?? [];
77
+ this.#applied.push(involved);
78
+ break;
79
+ case "reset":
80
+ involved = this.#applied.flat();
81
+ this.#applied = [];
82
+ this.#undone = [];
83
+ break;
84
+ }
85
+ this.#log.push({
86
+ revision: receipt.revision,
87
+ kind,
88
+ operations: involved,
89
+ receipt,
90
+ });
91
+ if (this.#log.length > LOG_LIMIT)
92
+ this.#log.splice(0, 1);
93
+ }
94
+ save(options) {
95
+ return this.#core.save(options);
96
+ }
97
+ markSaved(stateToken) {
98
+ this.#core.markSaved(stateToken);
99
+ }
100
+ addAsset(data, options) {
101
+ return this.#core.addAsset(data, options);
102
+ }
103
+ async getElements(query, options) {
104
+ const result = (await this.#core.getElements(query, options));
105
+ // A whole page's elements feed the geometry cache.
106
+ if (query?.pageIndex !== undefined &&
107
+ query.kinds === undefined &&
108
+ query.intersects === undefined)
109
+ this.#remember(query.pageIndex, result);
110
+ return result;
111
+ }
112
+ elementsAtSync(pageIndex, point) {
113
+ const cached = this.#geometry.get(pageIndex);
114
+ return Object.freeze({
115
+ sessionId: this.sessionId,
116
+ revision: cached?.revision ?? this.state.revision,
117
+ items: Object.freeze((cached?.elements ?? [])
118
+ .filter((element) => rectContains(element.bounds, point))
119
+ .reverse()),
120
+ });
121
+ }
122
+ get cachedPages() {
123
+ return [...this.#geometry.keys()].sort((a, b) => a - b);
124
+ }
125
+ #remember(pageIndex, result) {
126
+ const cached = this.#geometry.get(pageIndex);
127
+ if (cached && cached.revision > result.revision)
128
+ return;
129
+ this.#geometry.set(pageIndex, {
130
+ revision: result.revision,
131
+ elements: result.items,
132
+ });
133
+ }
134
+ /**
135
+ * After a committed change the changed pages' entries are stale: they are
136
+ * dropped and, while the page still exists, read again in the background
137
+ * so the next hover answers from the new revision.
138
+ */
139
+ #refreshGeometry(receipt) {
140
+ for (const pageIndex of [...this.#geometry.keys()]) {
141
+ const changed = pageIndex >= receipt.pageCount ||
142
+ receipt.changedPages.includes(pageIndex);
143
+ if (!changed)
144
+ continue;
145
+ this.#geometry.delete(pageIndex);
146
+ if (pageIndex < receipt.pageCount)
147
+ this.getElements({ pageIndex }).catch(reportError);
148
+ }
149
+ }
150
+ getElement(id, options) {
151
+ return this.#core.getElement(id, options);
152
+ }
153
+ elementsAt(pageIndex, point, options) {
154
+ return this.#core.elementsAt(pageIndex, point, options);
155
+ }
156
+ findText(query, options) {
157
+ return this.#core.findText(query, options);
158
+ }
159
+ getTextLayout(elementId, options) {
160
+ return this.#core.readItem(options, (engine, signal) => pdfReads(engine).textLayout(elementId, signal));
161
+ }
162
+ positionAt(pageIndex, point, options) {
163
+ return this.#core.readItem(options, (engine, signal) => pdfReads(engine).positionAt(pageIndex, point, signal));
164
+ }
165
+ rangeRects(range, options) {
166
+ return this.#core.readItems(options, (engine, signal) => pdfReads(engine).rangeRects(range, signal));
167
+ }
168
+ getPageLayout(pageIndex, options) {
169
+ return this.#core.readItem(options, (engine, signal) => pdfReads(engine).pageLayout(pageIndex, signal));
170
+ }
171
+ elementsForSelection(selection, options) {
172
+ return this.#core.readItems(options, async (engine, signal) => {
173
+ const first = selection.pageIndex;
174
+ const last = selection.endPageIndex ?? first;
175
+ const pages = [];
176
+ for (let pageIndex = first; pageIndex <= last; pageIndex += 1) {
177
+ const layout = await pdfReads(engine).pageLayout(pageIndex, signal);
178
+ if (layout)
179
+ pages.push(layout);
180
+ }
181
+ return resolveSelection(selection, pages);
182
+ });
183
+ }
184
+ mapRange(range, fromRevision, options) {
185
+ // Queued like any read, so every call committed before it is in the log.
186
+ return this.#core.readItem(options, async (engine, signal) => {
187
+ const current = this.state.revision;
188
+ if (fromRevision > current || fromRevision < 0)
189
+ return undefined;
190
+ const records = this.#log.filter((record) => record.revision > fromRevision);
191
+ // A gap means the log no longer reaches back that far.
192
+ if (records.length !== current - fromRevision)
193
+ return undefined;
194
+ const mapped = mapRangeThrough(range, records);
195
+ if (!mapped)
196
+ return undefined;
197
+ // The element as it is now bounds the offsets; a missing one ends it.
198
+ const clamp = async (position) => {
199
+ const element = engine.getElement
200
+ ? await engine.getElement(position.elementId, signal)
201
+ : (await engine.getElements({}, signal)).find((entry) => entry.id === position.elementId);
202
+ if (!element)
203
+ return undefined;
204
+ const length = element.text?.length ?? 0;
205
+ return { ...position, offset: Math.min(position.offset, length) };
206
+ };
207
+ const start = await clamp(mapped.start);
208
+ const end = await clamp(mapped.end);
209
+ return start && end ? { start, end } : undefined;
210
+ });
211
+ }
212
+ renderPageWithout(pageIndex, elementIds, options = {}) {
213
+ return this.#core.readItem(options, (engine, signal) => pdfReads(engine).renderWithout(pageIndex, [...elementIds], options.scale ?? 1, signal));
214
+ }
215
+ insertTextBox(fields, options) {
216
+ return this.apply([{ op: "insertTextBox", ...fields }], options);
217
+ }
218
+ replaceText(fields, options) {
219
+ return this.apply([{ op: "replaceText", ...fields }], options);
220
+ }
221
+ setTextStyle(fields, options) {
222
+ return this.apply([{ op: "setTextStyle", ...fields }], options);
223
+ }
224
+ resizeElement(fields, options) {
225
+ return this.apply([{ op: "resizeElement", ...fields }], options);
226
+ }
227
+ moveElement(fields, options) {
228
+ return this.apply([{ op: "moveElement", ...fields }], options);
229
+ }
230
+ deleteElement(fields, options) {
231
+ return this.apply([{ op: "deleteElement", ...fields }], options);
232
+ }
233
+ insertPage(fields, options) {
234
+ return this.apply([{ op: "insertPage", ...fields }], options);
235
+ }
236
+ deletePage(fields, options) {
237
+ return this.apply([{ op: "deletePage", ...fields }], options);
238
+ }
239
+ movePage(fields, options) {
240
+ return this.apply([{ op: "movePage", ...fields }], options);
241
+ }
242
+ rotatePage(fields, options) {
243
+ return this.apply([{ op: "rotatePage", ...fields }], options);
244
+ }
245
+ insertShape(fields, options) {
246
+ return this.apply([{ op: "insertShape", ...fields }], options);
247
+ }
248
+ setShapeStyle(fields, options) {
249
+ return this.apply([{ op: "setShapeStyle", ...fields }], options);
250
+ }
251
+ insertImage(fields, options) {
252
+ return this.apply([{ op: "insertImage", ...fields }], options);
253
+ }
254
+ insertTable(fields, options) {
255
+ return this.apply([{ op: "insertTable", ...fields }], options);
256
+ }
257
+ setTableCell(fields, options) {
258
+ return this.apply([{ op: "setTableCell", ...fields }], options);
259
+ }
260
+ }
261
+ /** How many committed calls `mapRange` can look back over. */
262
+ const LOG_LIMIT = 512;
263
+ /** The engine behind a PDF session answers the overlay reads; a stand-in may not. */
264
+ function pdfReads(engine) {
265
+ const reads = engine;
266
+ if (!reads.textLayout ||
267
+ !reads.positionAt ||
268
+ !reads.rangeRects ||
269
+ !reads.renderWithout ||
270
+ !reads.pageLayout)
271
+ throw new ViewerError("edit-unsupported", "This engine does not implement the PDF overlay primitives", { details: { format: "pdf", reason: "no-overlay-primitives" } });
272
+ return reads;
273
+ }
@@ -0,0 +1,336 @@
1
+ import type { TextSelection } from "../../contracts.js";
2
+ import type { ApplyOptions, BinaryData, EditElement, EditReceipt, EditSessionBase, PagePoint, PageRect, ReadItem, ReadOptions, ReadResult, SavedDocument, SaveOptions, TextPosition, TextRange } from "../types.js";
3
+ export type PdfElementKind = "text" | "image" | "shape" | "textBox" | "table" | "other";
4
+ export type PdfTextAlign = "left" | "center" | "right";
5
+ export interface PdfTextStyle {
6
+ readonly fontFamily: string;
7
+ /** Points. */
8
+ readonly fontSize: number;
9
+ readonly bold: boolean;
10
+ readonly italic: boolean;
11
+ /** `#RRGGBB`. */
12
+ readonly color: string;
13
+ /** Text boxes only. */
14
+ readonly align?: PdfTextAlign;
15
+ /** Text boxes only; a multiple of the font size. */
16
+ readonly lineHeight?: number;
17
+ }
18
+ export interface PdfShapeStyle {
19
+ readonly stroke?: {
20
+ readonly color: string;
21
+ readonly width: number;
22
+ };
23
+ readonly fill?: {
24
+ readonly color: string;
25
+ };
26
+ }
27
+ export interface PdfElement extends EditElement {
28
+ readonly kind: PdfElementKind;
29
+ /** Present for `text` and `textBox`. */
30
+ readonly textStyle?: PdfTextStyle;
31
+ /** Present for `shape` and `table`. */
32
+ readonly shapeStyle?: PdfShapeStyle;
33
+ /** Present for `table`. */
34
+ readonly table?: {
35
+ readonly rows: readonly (readonly string[])[];
36
+ };
37
+ }
38
+ export interface PdfTextBoxStyle {
39
+ /** "Helvetica" (default), "Times" or "Courier"; registered families follow. */
40
+ readonly fontFamily?: string;
41
+ /** 1–500 points, default 12. */
42
+ readonly fontSize?: number;
43
+ readonly bold?: boolean;
44
+ readonly italic?: boolean;
45
+ /** `#RRGGBB`, default "#000000". */
46
+ readonly color?: string;
47
+ readonly align?: PdfTextAlign;
48
+ /** Multiple of the font size, 0.5–5, default 1.2. */
49
+ readonly lineHeight?: number;
50
+ }
51
+ export interface InsertTextBoxOperation {
52
+ readonly op: "insertTextBox";
53
+ readonly pageIndex: number;
54
+ readonly rect: PageRect;
55
+ readonly text: string;
56
+ readonly style?: PdfTextBoxStyle;
57
+ }
58
+ export interface ReplaceTextOperation {
59
+ readonly op: "replaceText";
60
+ /** A `textBox` or `text` element. */
61
+ readonly target: string;
62
+ readonly text: string;
63
+ /**
64
+ * The part of the target's text to replace, both ends on the target;
65
+ * absent, the whole text. A text object is split around the range only
66
+ * when its font cannot draw the new text; the parts keep their font, size,
67
+ * colour and baseline and the first part keeps the id.
68
+ */
69
+ readonly range?: TextRange;
70
+ }
71
+ export interface SetTextStyleOperation {
72
+ readonly op: "setTextStyle";
73
+ /** A `textBox` or `text` element. */
74
+ readonly target: string;
75
+ readonly style: PdfTextBoxStyle;
76
+ }
77
+ export interface ResizeElementOperation {
78
+ readonly op: "resizeElement";
79
+ readonly target: string;
80
+ /** New bounds in page space; a text box is laid out again inside them. */
81
+ readonly rect: PageRect;
82
+ }
83
+ export interface MoveElementOperation {
84
+ readonly op: "moveElement";
85
+ readonly target: string;
86
+ /** New top-left corner of the element's bounds, in page space. */
87
+ readonly to?: PagePoint;
88
+ /** Offset in page space. Exactly one of `to` and `by` is given. */
89
+ readonly by?: {
90
+ readonly dx: number;
91
+ readonly dy: number;
92
+ };
93
+ }
94
+ export interface DeleteElementOperation {
95
+ readonly op: "deleteElement";
96
+ readonly target: string;
97
+ }
98
+ export interface InsertPageOperation {
99
+ readonly op: "insertPage";
100
+ /** Position of the new page, 0 to the current page count. */
101
+ readonly index: number;
102
+ /** Points; defaults to the size of the page before, else after, the position. */
103
+ readonly size?: {
104
+ readonly width: number;
105
+ readonly height: number;
106
+ };
107
+ }
108
+ export interface DeletePageOperation {
109
+ readonly op: "deletePage";
110
+ readonly pageIndex: number;
111
+ }
112
+ export interface MovePageOperation {
113
+ readonly op: "movePage";
114
+ readonly from: number;
115
+ /** The page's index after the move. */
116
+ readonly to: number;
117
+ }
118
+ export interface PdfStroke {
119
+ readonly color: string;
120
+ /** Points; 0 draws the thinnest line the device can. */
121
+ readonly width: number;
122
+ }
123
+ export interface PdfFill {
124
+ readonly color: string;
125
+ }
126
+ export type InsertShapeOperation = {
127
+ readonly op: "insertShape";
128
+ readonly pageIndex: number;
129
+ readonly shape: "rectangle" | "ellipse";
130
+ readonly rect: PageRect;
131
+ readonly stroke?: PdfStroke;
132
+ readonly fill?: PdfFill;
133
+ } | {
134
+ readonly op: "insertShape";
135
+ readonly pageIndex: number;
136
+ readonly shape: "line";
137
+ readonly from: PagePoint;
138
+ readonly to: PagePoint;
139
+ readonly stroke?: PdfStroke;
140
+ };
141
+ export interface InsertImageOperation {
142
+ readonly op: "insertImage";
143
+ readonly pageIndex: number;
144
+ readonly rect: PageRect;
145
+ /** PNG or JPEG bytes; base64 over pure-JSON transports. */
146
+ readonly data: BinaryData;
147
+ readonly mimeType: "image/png" | "image/jpeg";
148
+ }
149
+ export interface PdfTableStyle {
150
+ /** "Helvetica" (default), "Times", "Courier" or a registered family. */
151
+ readonly fontFamily?: string;
152
+ /** 1–500 points, default 10. */
153
+ readonly fontSize?: number;
154
+ /** Text colour, `#RRGGBB`, default "#000000". */
155
+ readonly color?: string;
156
+ /** Grid colour, default "#000000". */
157
+ readonly borderColor?: string;
158
+ /** Grid stroke in points, 0–20, default 0.75. */
159
+ readonly borderWidth?: number;
160
+ /** Space between a cell's edges and its text, 0–100, default 4. */
161
+ readonly cellPadding?: number;
162
+ /** Fill of the first row; none by default. */
163
+ readonly headerFill?: string;
164
+ }
165
+ export interface InsertTableOperation {
166
+ readonly op: "insertTable";
167
+ readonly pageIndex: number;
168
+ /** Top-left corner in page space. */
169
+ readonly at: PagePoint;
170
+ /** Total width in points; the height follows the wrapped cell text. */
171
+ readonly width: number;
172
+ /** Cell text by row; every row has the same number of cells. 1–100 rows, 1–20 columns. */
173
+ readonly rows: readonly (readonly string[])[];
174
+ /** Relative column weights, one per column; equal when omitted. */
175
+ readonly columnWidths?: readonly number[];
176
+ readonly style?: PdfTableStyle;
177
+ }
178
+ export interface SetTableCellOperation {
179
+ readonly op: "setTableCell";
180
+ /** A `table` element. */
181
+ readonly target: string;
182
+ readonly row: number;
183
+ readonly column: number;
184
+ /** The cell's new text; empty clears the cell. */
185
+ readonly text: string;
186
+ }
187
+ export interface SetShapeStyleOperation {
188
+ readonly op: "setShapeStyle";
189
+ readonly target: string;
190
+ /** A new stroke, `null` to remove it, or absent to keep it. */
191
+ readonly stroke?: PdfStroke | null;
192
+ /** A new fill, `null` to remove it, or absent to keep it. */
193
+ readonly fill?: PdfFill | null;
194
+ }
195
+ export interface RotatePageOperation {
196
+ readonly op: "rotatePage";
197
+ readonly pageIndex: number;
198
+ /** Absolute clockwise rotation in degrees. */
199
+ readonly rotation: 0 | 90 | 180 | 270;
200
+ }
201
+ /** The PDF operation union; operations are added as they ship. */
202
+ export type PdfOperation = InsertTextBoxOperation | ReplaceTextOperation | SetTextStyleOperation | ResizeElementOperation | MoveElementOperation | DeleteElementOperation | InsertPageOperation | DeletePageOperation | MovePageOperation | RotatePageOperation | InsertShapeOperation | SetShapeStyleOperation | InsertImageOperation | InsertTableOperation | SetTableCellOperation;
203
+ export interface PdfSaveOptions extends SaveOptions {
204
+ /**
205
+ * `full` rewrites the file, so deleted content is gone and the bytes do not
206
+ * depend on which pages were read; `incremental` appends to the original
207
+ * bytes and keeps earlier signed revisions intact. The default is `full`
208
+ * for a document without signature fields and `incremental` for a signed one.
209
+ */
210
+ readonly mode?: "full" | "incremental";
211
+ }
212
+ /** One drawn character of a layout line. */
213
+ export interface TextLayoutGlyph {
214
+ /** Offset of the character in `EditElement.text`. */
215
+ readonly offset: number;
216
+ /** Tight box of the glyph in page space; a space takes its advance box. */
217
+ readonly box: PageRect;
218
+ /** Advance width along the baseline, in points. */
219
+ readonly advance: number;
220
+ }
221
+ /** One line of a text element: one PDFium text object, as the file stores it. */
222
+ export interface TextLayoutLine {
223
+ /** The part of the element's text the line draws, half-open. */
224
+ readonly range: TextRange;
225
+ readonly text: string;
226
+ /** Union of the glyph boxes, in page space. */
227
+ readonly bounds: PageRect;
228
+ /** Start of the baseline, in page space. */
229
+ readonly baseline: PagePoint;
230
+ readonly glyphs: readonly TextLayoutGlyph[];
231
+ readonly fontFamily: string;
232
+ readonly fontSize: number;
233
+ readonly color: string;
234
+ }
235
+ /** The drawn geometry of a `text`, `textBox` or `table` element. */
236
+ export interface TextLayout {
237
+ readonly elementId: string;
238
+ readonly pageIndex: number;
239
+ /** Lines in reading order: a text box's lines, a table's cells. */
240
+ readonly lines: readonly TextLayoutLine[];
241
+ }
242
+ /** Every text element of a page with its layout, plus the page's displayed size in points. */
243
+ export interface PageLayout {
244
+ readonly pageIndex: number;
245
+ readonly width: number;
246
+ readonly height: number;
247
+ /** In reading order. */
248
+ readonly layouts: readonly TextLayout[];
249
+ }
250
+ /** A page rendered by PDFium in the worker: RGBA pixels, row-major, unpremultiplied over white. */
251
+ export interface PageBitmap {
252
+ readonly pageIndex: number;
253
+ /** Device pixels per point the page was rendered at. */
254
+ readonly scale: number;
255
+ readonly width: number;
256
+ readonly height: number;
257
+ readonly data: Uint8Array;
258
+ }
259
+ export interface RenderOptions extends ReadOptions {
260
+ /** Device pixels per point, default 1; bounded by `maxDecodedPixels`. */
261
+ readonly scale?: number;
262
+ }
263
+ /**
264
+ * An operation's fields without its `op`, as the typed methods take them.
265
+ * Distributes over unions so `insertShape` keeps its per-shape fields.
266
+ */
267
+ export type Fields<T extends PdfOperation> = T extends unknown ? Omit<T, "op"> : never;
268
+ export interface PdfEditSession extends EditSessionBase<PdfOperation, PdfElement> {
269
+ readonly format: "pdf";
270
+ save(options?: PdfSaveOptions): Promise<SavedDocument>;
271
+ /** Lines, glyph boxes and styles of a `text`, `textBox` or `table` element. */
272
+ getTextLayout(elementId: string, options?: ReadOptions): Promise<ReadItem<TextLayout>>;
273
+ /** The text position nearest to a page-space point; none on a page without text. */
274
+ positionAt(pageIndex: number, point: PagePoint, options?: ReadOptions): Promise<ReadItem<TextPosition>>;
275
+ /** The rectangles a range covers, one per line fragment, in reading order. */
276
+ rangeRects(range: TextRange, options?: ReadOptions): Promise<ReadResult<PageRect>>;
277
+ /**
278
+ * The page rendered by PDFium with the listed elements left out, so a host's
279
+ * input surface can stand in for them on screen. Nothing is reopened and the
280
+ * session's bytes stay as they are; unknown ids are ignored.
281
+ */
282
+ renderPageWithout(pageIndex: number, elementIds: readonly string[], options?: RenderOptions): Promise<ReadItem<PageBitmap>>;
283
+ /** The layouts of every text element on a page, in one read. */
284
+ getPageLayout(pageIndex: number, options?: ReadOptions): Promise<ReadItem<PageLayout>>;
285
+ /**
286
+ * Maps the viewer's text selection (PDF.js runs in page space) to elements
287
+ * and ranges: a line whose box the run covers by half, else the one line
288
+ * that contains the run, else a line whose folded text contains the run's.
289
+ */
290
+ elementsForSelection(selection: TextSelection, options?: ReadOptions): Promise<ReadResult<TextRange>>;
291
+ /**
292
+ * Elements under a point from the session's main-thread geometry cache,
293
+ * without waiting: the last `getElements({ pageIndex })` result of the
294
+ * page, refreshed after every committed change. A page never read answers
295
+ * no items; `cachedPages` says which pages answer.
296
+ */
297
+ elementsAtSync(pageIndex: number, point: PagePoint): ReadResult<PdfElement>;
298
+ /** Pages whose geometry the cache holds. */
299
+ readonly cachedPages: readonly number[];
300
+ /**
301
+ * Where a range taken at `fromRevision` is now, after the batches, undos,
302
+ * redos and resets of this session since then; none when its element is
303
+ * gone or the revision is older than the session remembers.
304
+ */
305
+ mapRange(range: TextRange, fromRevision: number, options?: ReadOptions): Promise<ReadItem<TextRange>>;
306
+ /** Lays `text` out inside `rect` as new text objects; the box's id is in `createdIds`. */
307
+ insertTextBox(fields: Fields<InsertTextBoxOperation>, options?: ApplyOptions): Promise<EditReceipt>;
308
+ /** Replaces the text of a text box (laid out again) or of a text object. */
309
+ replaceText(fields: Fields<ReplaceTextOperation>, options?: ApplyOptions): Promise<EditReceipt>;
310
+ /** Changes style fields; unspecified fields keep their value. */
311
+ setTextStyle(fields: Fields<SetTextStyleOperation>, options?: ApplyOptions): Promise<EditReceipt>;
312
+ /** Gives an element new bounds; text boxes reflow, other elements stretch. */
313
+ resizeElement(fields: Fields<ResizeElementOperation>, options?: ApplyOptions): Promise<EditReceipt>;
314
+ /** Moves an element to a point or by an offset, in page space. */
315
+ moveElement(fields: Fields<MoveElementOperation>, options?: ApplyOptions): Promise<EditReceipt>;
316
+ /** Removes an element and, for a group, every object in it. */
317
+ deleteElement(fields: Fields<DeleteElementOperation>, options?: ApplyOptions): Promise<EditReceipt>;
318
+ /** Adds a blank page. */
319
+ insertPage(fields: Fields<InsertPageOperation>, options?: ApplyOptions): Promise<EditReceipt>;
320
+ /** Removes a page; the last page cannot be removed. */
321
+ deletePage(fields: Fields<DeletePageOperation>, options?: ApplyOptions): Promise<EditReceipt>;
322
+ /** Reorders pages. */
323
+ movePage(fields: Fields<MovePageOperation>, options?: ApplyOptions): Promise<EditReceipt>;
324
+ /** Sets a page's rotation. */
325
+ rotatePage(fields: Fields<RotatePageOperation>, options?: ApplyOptions): Promise<EditReceipt>;
326
+ /** Draws a rectangle, ellipse or line as a path object. */
327
+ insertShape(fields: Fields<InsertShapeOperation>, options?: ApplyOptions): Promise<EditReceipt>;
328
+ /** Changes or removes a shape's stroke and fill. */
329
+ setShapeStyle(fields: Fields<SetShapeStyleOperation>, options?: ApplyOptions): Promise<EditReceipt>;
330
+ /** Places a PNG or JPEG inside `rect`; JPEG data is embedded as it is. */
331
+ insertImage(fields: Fields<InsertImageOperation>, options?: ApplyOptions): Promise<EditReceipt>;
332
+ /** Draws a grid with wrapped cell text; rows grow to fit their tallest cell. */
333
+ insertTable(fields: Fields<InsertTableOperation>, options?: ApplyOptions): Promise<EditReceipt>;
334
+ /** Changes one cell's text and lays the table out again. */
335
+ setTableCell(fields: Fields<SetTableCellOperation>, options?: ApplyOptions): Promise<EditReceipt>;
336
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,74 @@
1
+ import type { OoxmlPackage } from "../ooxml/package.js";
2
+ import type { XmlElement, XmlPart } from "../ooxml/xml.js";
3
+ import { type Matrix, type PlacedFrame, type Xfrm } from "./geometry.js";
4
+ import type { DeckModel, SlideRecord } from "./model.js";
5
+ import { type StyleSource } from "./style.js";
6
+ import { type TextModel } from "./text.js";
7
+ import type { PptxElement, PptxPlaceholder } from "./types.js";
8
+ /** What the engine knows about one element beyond what it reports. */
9
+ export interface ShapeRecord {
10
+ readonly element: PptxElement;
11
+ readonly slide: SlideRecord;
12
+ readonly part: XmlPart;
13
+ /** The element node in the slide part (`p:sp`, `p:pic`, …). */
14
+ readonly node: XmlElement;
15
+ readonly cNvPr: XmlElement;
16
+ readonly cNvPrId: number;
17
+ /** The element's own `a:xfrm` or `p:xfrm` node, when it has one. */
18
+ readonly xfrmNode?: XmlElement;
19
+ /** The frame in the element's own space (EMU), inherited when `inherited` is true. */
20
+ readonly xfrm?: Xfrm;
21
+ readonly inherited: boolean;
22
+ /** Transform from the element's space to slide space. */
23
+ readonly parents: Matrix;
24
+ readonly placed?: PlacedFrame;
25
+ readonly txBody?: XmlElement;
26
+ readonly spPr?: XmlElement;
27
+ readonly text?: TextModel;
28
+ /** Inside the fallback branch of `mc:AlternateContent`. */
29
+ readonly readOnly: boolean;
30
+ readonly parent?: ShapeRecord;
31
+ }
32
+ export interface SlideElements {
33
+ readonly slide: SlideRecord;
34
+ readonly pageIndex: number;
35
+ readonly part: XmlPart;
36
+ /** Document order, groups before their children. */
37
+ readonly records: readonly ShapeRecord[];
38
+ byId(id: string): ShapeRecord | undefined;
39
+ }
40
+ /** A placeholder of a layout or master, for inheritance. */
41
+ export interface PlaceholderRecord {
42
+ readonly part: XmlPart;
43
+ readonly node: XmlElement;
44
+ readonly type: string;
45
+ readonly idx?: number;
46
+ readonly xfrm?: Xfrm;
47
+ readonly lstStyle?: XmlElement;
48
+ }
49
+ export interface PlaceholderTable {
50
+ readonly part: XmlPart;
51
+ readonly placeholders: readonly PlaceholderRecord[];
52
+ /** `p:txStyles` of a master. */
53
+ readonly txStyles?: XmlElement;
54
+ }
55
+ /** The placeholders of a layout or master part. */
56
+ export declare function readPlaceholders(pkg: OoxmlPackage, partName: string, signal?: AbortSignal): Promise<PlaceholderTable>;
57
+ export declare function placeholderOf(part: XmlPart, node: XmlElement): PptxPlaceholder | undefined;
58
+ /** Placeholder types that share position and style: titles, and body-like content. */
59
+ export declare function placeholderFamily(type: string): string;
60
+ /** The placeholder a slide placeholder inherits from: same idx first, then the same family. */
61
+ export declare function matchPlaceholder(table: PlaceholderTable | undefined, ph: PptxPlaceholder): PlaceholderRecord | undefined;
62
+ export interface InheritanceSources {
63
+ layout?: PlaceholderTable;
64
+ master?: PlaceholderTable;
65
+ /** `p:defaultTextStyle` of the presentation. */
66
+ defaults?: StyleSource;
67
+ }
68
+ /** Reads every element of a slide. */
69
+ export declare function readSlideElements(pkg: OoxmlPackage, model: DeckModel, slide: SlideRecord, pageIndex: number, sources: InheritanceSources, signal?: AbortSignal): Promise<SlideElements>;
70
+ /** The list-style chain of a shape, in priority order. */
71
+ export declare function listStylesOf(context: {
72
+ readonly part: XmlPart;
73
+ readonly sources: InheritanceSources;
74
+ }, txBody: XmlElement, placeholder: PptxPlaceholder | undefined): StyleSource[];