fabricjs-document-engine 1.1.0 → 1.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 +39 -1
- package/README.zh-CN.md +39 -1
- package/dist/assets/asset-pipeline.cjs +10 -8
- package/dist/assets/asset-pipeline.d.cts +1 -1
- package/dist/assets/asset-pipeline.d.ts +1 -1
- package/dist/assets/asset-pipeline.js +10 -8
- package/dist/assets/image-check.cjs +4 -3
- package/dist/assets/image-check.d.cts +1 -1
- package/dist/assets/image-check.d.ts +1 -1
- package/dist/assets/image-check.js +4 -3
- package/dist/commands/clipboard.cjs +5 -0
- package/dist/commands/clipboard.js +5 -0
- package/dist/document/document-format.d.cts +15 -0
- package/dist/document/document-format.d.ts +15 -0
- package/dist/document/validate-document.cjs +8 -0
- package/dist/document/validate-document.js +8 -0
- package/dist/engine/create-document-engine.cjs +115 -21
- package/dist/engine/create-document-engine.d.cts +24 -6
- package/dist/engine/create-document-engine.d.ts +24 -6
- package/dist/engine/create-document-engine.js +116 -22
- package/dist/engine/errors.d.cts +1 -1
- package/dist/engine/errors.d.ts +1 -1
- package/dist/export/export-options.cjs +3 -0
- package/dist/export/export-options.d.cts +6 -0
- package/dist/export/export-options.d.ts +6 -0
- package/dist/export/export-options.js +3 -0
- package/dist/export/preflight-export.d.cts +1 -1
- package/dist/export/preflight-export.d.ts +1 -1
- package/dist/export/render-export.cjs +42 -4
- package/dist/export/render-export.js +43 -5
- package/dist/export/svg/clip-masks.cjs +39 -0
- package/dist/export/svg/clip-masks.js +37 -0
- package/dist/export/svg/embed-assets.cjs +1 -0
- package/dist/export/svg/embed-assets.js +1 -0
- package/dist/export/svg/raster-object.cjs +82 -0
- package/dist/export/svg/raster-object.js +81 -0
- package/dist/{pdf → export/svg}/text-decorations.cjs +3 -3
- package/dist/{pdf → export/svg}/text-decorations.js +3 -3
- package/dist/export/svg/text-on-path.cjs +0 -10
- package/dist/export/svg/text-on-path.js +1 -10
- package/dist/fabric/fabric-adapter.cjs +5 -3
- package/dist/fabric/fabric-adapter.js +5 -3
- package/dist/fabric/page-state.cjs +69 -0
- package/dist/fabric/page-state.js +64 -0
- package/dist/history/apply-state.cjs +19 -2
- package/dist/history/apply-state.js +19 -2
- package/dist/history/create-history.cjs +53 -13
- package/dist/history/create-history.d.cts +8 -0
- package/dist/history/create-history.d.ts +8 -0
- package/dist/history/create-history.js +53 -13
- package/dist/history/snapshot.cjs +10 -1
- package/dist/history/snapshot.js +10 -2
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/migrations/migrate-document.cjs +2 -1
- package/dist/migrations/migrate-document.js +2 -1
- package/dist/pdf/export-pdf.cjs +8 -67
- package/dist/pdf/export-pdf.js +8 -67
- package/dist/recovery/recovery-controller.cjs +148 -29
- package/dist/recovery/recovery-controller.d.cts +8 -0
- package/dist/recovery/recovery-controller.d.ts +8 -0
- package/dist/recovery/recovery-controller.js +148 -29
- package/dist/security/content-limits.cjs +43 -3
- package/dist/security/content-limits.d.cts +8 -0
- package/dist/security/content-limits.d.ts +8 -0
- package/dist/security/content-limits.js +39 -4
- package/dist/util/concurrency.cjs +16 -3
- package/dist/util/concurrency.js +16 -3
- package/package.json +1 -1
- package/schema/document-v1.schema.json +5 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const require_asset_manifest = require("../assets/asset-manifest.cjs");
|
|
2
|
+
const require_page_state = require("../fabric/page-state.cjs");
|
|
2
3
|
const require_errors = require("./errors.cjs");
|
|
3
4
|
const require_content_limits = require("../security/content-limits.cjs");
|
|
4
5
|
const require_image_check = require("../assets/image-check.cjs");
|
|
@@ -38,11 +39,21 @@ function createDocumentEngine(options) {
|
|
|
38
39
|
const registry = require_object_registry.createObjectRegistry(options.customObjects);
|
|
39
40
|
const events = require_event_emitter.createEventEmitter();
|
|
40
41
|
const objectsById = /* @__PURE__ */ new Map();
|
|
41
|
-
const assetOptions =
|
|
42
|
+
const assetOptions = {
|
|
43
|
+
...options.assets,
|
|
44
|
+
maxImagePixels: options.limits?.maxImagePixels ?? 67108864
|
|
45
|
+
};
|
|
42
46
|
const uploadedUrls = /* @__PURE__ */ new Map();
|
|
43
47
|
let documentInfo = require_create_document.createDocumentInfo(options.document);
|
|
44
48
|
let activeLoad = null;
|
|
45
49
|
let destroyed = false;
|
|
50
|
+
let mutations = 0;
|
|
51
|
+
let session = 0;
|
|
52
|
+
/** Throws when async work started under `startedIn` would now change another document. */
|
|
53
|
+
function ensureSameSession(startedIn, what) {
|
|
54
|
+
ensureUsable();
|
|
55
|
+
if (session !== startedIn) throw new require_errors.DocumentEngineError("DOCUMENT_CHANGED", `${what} was dropped because another document was opened while it ran`);
|
|
56
|
+
}
|
|
46
57
|
function ensureUsable() {
|
|
47
58
|
if (destroyed) throw new require_errors.DocumentEngineError("ENGINE_DESTROYED", "This document engine was destroyed");
|
|
48
59
|
}
|
|
@@ -67,21 +78,41 @@ function createDocumentEngine(options) {
|
|
|
67
78
|
objectsById.clear();
|
|
68
79
|
canvas.getObjects().forEach(indexObjectTree);
|
|
69
80
|
}
|
|
70
|
-
const handleObjectAdded = ({ target }) =>
|
|
71
|
-
|
|
81
|
+
const handleObjectAdded = ({ target }) => {
|
|
82
|
+
mutations += 1;
|
|
83
|
+
indexObjectTree(target);
|
|
84
|
+
};
|
|
85
|
+
const handleObjectRemoved = ({ target }) => {
|
|
86
|
+
mutations += 1;
|
|
87
|
+
removeObjectTreeFromIndex(target);
|
|
88
|
+
};
|
|
89
|
+
const countMutation = () => {
|
|
90
|
+
mutations += 1;
|
|
91
|
+
};
|
|
72
92
|
canvas.on("object:added", handleObjectAdded);
|
|
73
93
|
canvas.on("object:removed", handleObjectRemoved);
|
|
94
|
+
canvas.on("object:modified", countMutation);
|
|
95
|
+
canvas.on("text:changed", countMutation);
|
|
74
96
|
rebuildIndex();
|
|
75
97
|
const history = require_create_history.createHistory({
|
|
76
98
|
canvas,
|
|
77
99
|
limit: options.history?.limit,
|
|
78
100
|
maxBytes: options.history?.maxBytes,
|
|
79
|
-
|
|
101
|
+
serializeState: () => {
|
|
80
102
|
rebuildIndex();
|
|
81
|
-
|
|
103
|
+
const serialized = require_fabric_adapter.serializeCanvas(canvas, registry.propertiesToInclude());
|
|
104
|
+
return {
|
|
105
|
+
objects: serialized.objects,
|
|
106
|
+
page: {
|
|
107
|
+
width: canvas.getWidth(),
|
|
108
|
+
height: canvas.getHeight(),
|
|
109
|
+
...require_page_state.pickPageFields(serialized)
|
|
110
|
+
}
|
|
111
|
+
};
|
|
82
112
|
},
|
|
83
113
|
onChange: (state) => events.emit("history:change", state),
|
|
84
|
-
onContentChange: () => noteContentChange()
|
|
114
|
+
onContentChange: () => noteContentChange(),
|
|
115
|
+
onLiveChange: () => noteContentChange()
|
|
85
116
|
});
|
|
86
117
|
const saving = require_save_controller.createSaveController({
|
|
87
118
|
getStorage: () => requireStorage(),
|
|
@@ -116,6 +147,7 @@ function createDocumentEngine(options) {
|
|
|
116
147
|
}
|
|
117
148
|
}) : void 0;
|
|
118
149
|
function noteContentChange() {
|
|
150
|
+
mutations += 1;
|
|
119
151
|
saving.noteContentChange();
|
|
120
152
|
recovery?.schedule();
|
|
121
153
|
}
|
|
@@ -138,11 +170,14 @@ function createDocumentEngine(options) {
|
|
|
138
170
|
height: canvas.getHeight()
|
|
139
171
|
},
|
|
140
172
|
objects: serialized.objects,
|
|
141
|
-
assets: require_asset_manifest.buildAssetManifest(
|
|
173
|
+
assets: require_asset_manifest.buildAssetManifest(require_page_state.documentObjects({
|
|
174
|
+
objects: serialized.objects,
|
|
175
|
+
canvas: serialized
|
|
176
|
+
})),
|
|
142
177
|
metadata: { ...documentInfo.metadata }
|
|
143
178
|
};
|
|
144
179
|
if (serialized.version !== void 0) document.fabricVersion = serialized.version;
|
|
145
|
-
|
|
180
|
+
Object.assign(document.canvas, require_page_state.pickPageFields(serialized));
|
|
146
181
|
return document;
|
|
147
182
|
}
|
|
148
183
|
function toLoadError(error, controller) {
|
|
@@ -161,7 +196,7 @@ function createDocumentEngine(options) {
|
|
|
161
196
|
throw new require_errors.DocumentEngineError(issues[0].code, `The document is not valid: ${summary}`, { issues });
|
|
162
197
|
}
|
|
163
198
|
const document = input;
|
|
164
|
-
const unknownTypes = registry.findUnknownTypes(require_walk_objects.collectSerializedTypes(document
|
|
199
|
+
const unknownTypes = registry.findUnknownTypes(require_walk_objects.collectSerializedTypes(require_page_state.documentObjects(document)));
|
|
165
200
|
if (unknownTypes.length > 0) throw new require_errors.DocumentEngineError("UNKNOWN_OBJECT_TYPE", `The document uses object types that are not registered: ${unknownTypes.join(", ")}. Register them with customObjects or engine.registerObject before loading.`, { unknownTypes });
|
|
166
201
|
return document;
|
|
167
202
|
}
|
|
@@ -199,6 +234,7 @@ function createDocumentEngine(options) {
|
|
|
199
234
|
ensureUsable();
|
|
200
235
|
protectUnsavedChanges(loadOptions.discardUnsavedChanges);
|
|
201
236
|
const controller = startedLoad ?? startLoad(loadOptions.signal);
|
|
237
|
+
const mutationsAtStart = mutations;
|
|
202
238
|
const documentId = describeDocumentId(input);
|
|
203
239
|
const report = (stage, done, total) => {
|
|
204
240
|
if (controller.signal.aborted) return;
|
|
@@ -228,11 +264,15 @@ function createDocumentEngine(options) {
|
|
|
228
264
|
if (controller.signal.aborted) throw new Error("aborted");
|
|
229
265
|
await history.withoutRecording(() => require_fabric_adapter.loadIntoCanvas(canvas, {
|
|
230
266
|
version: document.fabricVersion,
|
|
231
|
-
|
|
267
|
+
...require_page_state.pickPageFields(document.canvas),
|
|
232
268
|
objects: document.objects
|
|
233
269
|
}, {
|
|
234
270
|
signal: controller.signal,
|
|
235
|
-
onObjects: (done, total) => report("objects", done, total)
|
|
271
|
+
onObjects: (done, total) => report("objects", done, total),
|
|
272
|
+
beforeSwap: () => {
|
|
273
|
+
if (mutations !== mutationsAtStart && !loadOptions.discardUnsavedChanges) throw new require_errors.DocumentEngineError("LOAD_CONFLICT", "The canvas was edited while the document loaded, so the load was stopped to keep the edits. Pass { discardUnsavedChanges: true } to replace them.");
|
|
274
|
+
session += 1;
|
|
275
|
+
}
|
|
236
276
|
}));
|
|
237
277
|
if (controller.signal.aborted) throw new Error("aborted");
|
|
238
278
|
if (loadOptions.restoreCanvasSize ?? true) canvas.setDimensions({
|
|
@@ -285,10 +325,37 @@ function createDocumentEngine(options) {
|
|
|
285
325
|
metadata
|
|
286
326
|
});
|
|
287
327
|
}
|
|
328
|
+
function setPage(changes, label = "Change page") {
|
|
329
|
+
ensureUsable();
|
|
330
|
+
const problem = require_content_limits.canvasSizeProblem(changes.width ?? canvas.getWidth(), changes.height ?? canvas.getHeight(), options.limits);
|
|
331
|
+
if (problem) throw new require_errors.DocumentEngineError("UNSAFE_DOCUMENT", `The page was not resized: it would be ${problem}`);
|
|
332
|
+
history.transaction(label, () => {
|
|
333
|
+
const width = changes.width ?? canvas.getWidth();
|
|
334
|
+
const height = changes.height ?? canvas.getHeight();
|
|
335
|
+
if (width !== canvas.getWidth() || height !== canvas.getHeight()) canvas.setDimensions({
|
|
336
|
+
width,
|
|
337
|
+
height
|
|
338
|
+
});
|
|
339
|
+
const live = {};
|
|
340
|
+
if (changes.background !== void 0) live.backgroundColor = changes.background ?? "";
|
|
341
|
+
if (changes.backgroundImage !== void 0) live.backgroundImage = changes.backgroundImage ?? void 0;
|
|
342
|
+
if (changes.overlay !== void 0) live.overlayColor = changes.overlay ?? "";
|
|
343
|
+
if (changes.overlayImage !== void 0) live.overlayImage = changes.overlayImage ?? void 0;
|
|
344
|
+
if (changes.clipPath !== void 0) live.clipPath = changes.clipPath ?? void 0;
|
|
345
|
+
canvas.set(live);
|
|
346
|
+
});
|
|
347
|
+
canvas.requestRenderAll();
|
|
348
|
+
}
|
|
288
349
|
async function importSvg(svg, importOptions = {}) {
|
|
289
350
|
ensureUsable();
|
|
351
|
+
const startedIn = session;
|
|
290
352
|
const result = await require_svg_import.readSvg(svg, importOptions, options.limits);
|
|
291
|
-
|
|
353
|
+
try {
|
|
354
|
+
ensureSameSession(startedIn, "The SVG import");
|
|
355
|
+
} catch (error) {
|
|
356
|
+
result.objects.forEach((object) => object.dispose?.());
|
|
357
|
+
throw error;
|
|
358
|
+
}
|
|
292
359
|
if (result.objects.length > 0) {
|
|
293
360
|
history.transaction("Import SVG", () => canvas.add(...result.objects));
|
|
294
361
|
canvas.requestRenderAll();
|
|
@@ -408,6 +475,7 @@ function createDocumentEngine(options) {
|
|
|
408
475
|
protectUnsavedChanges(newOptions.discardUnsavedChanges);
|
|
409
476
|
activeLoad?.abort();
|
|
410
477
|
history.withoutRecording(() => canvas.clear());
|
|
478
|
+
session += 1;
|
|
411
479
|
objectsById.clear();
|
|
412
480
|
documentInfo = require_create_document.createDocumentInfo(newOptions);
|
|
413
481
|
uploadedUrls.clear();
|
|
@@ -434,10 +502,12 @@ function createDocumentEngine(options) {
|
|
|
434
502
|
if (isReplaceableImage(object) && require_image_check.isSameUrl(object.getSrc(), oldUrl)) images.push(object);
|
|
435
503
|
});
|
|
436
504
|
if (images.length === 0) return 0;
|
|
505
|
+
const startedIn = session;
|
|
437
506
|
await history.transaction("Replace image", () => Promise.all(images.map(async (image) => {
|
|
438
507
|
const displayedWidth = image.width * image.scaleX;
|
|
439
508
|
const displayedHeight = image.height * image.scaleY;
|
|
440
509
|
await image.setSrc(newUrl, { crossOrigin: image.crossOrigin ?? null });
|
|
510
|
+
ensureSameSession(startedIn, "Replacing the image");
|
|
441
511
|
image.set({
|
|
442
512
|
scaleX: displayedWidth / image.width,
|
|
443
513
|
scaleY: displayedHeight / image.height
|
|
@@ -486,14 +556,31 @@ function createDocumentEngine(options) {
|
|
|
486
556
|
const warnings = [...check.warnings];
|
|
487
557
|
const rendered = require_render_export.withExportView(canvas, settings.background, format, () => {
|
|
488
558
|
const area = require_export_area.resolveExportArea(canvas, settings.area, settings.padding);
|
|
559
|
+
if (format !== "svg") {
|
|
560
|
+
const problem = require_content_limits.canvasSizeProblem(area.width * settings.scale, area.height * settings.scale, options.limits);
|
|
561
|
+
if (problem) {
|
|
562
|
+
const message = `The export would be ${problem}. Lower the scale or export a smaller area.`;
|
|
563
|
+
throw new require_errors.DocumentEngineError("EXPORT_BLOCKED", message, { problems: [{
|
|
564
|
+
code: "TOO_LARGE",
|
|
565
|
+
message,
|
|
566
|
+
objectIds: []
|
|
567
|
+
}] });
|
|
568
|
+
}
|
|
569
|
+
}
|
|
489
570
|
return {
|
|
490
571
|
area,
|
|
491
|
-
content: format === "svg" ? Promise.resolve(require_render_export.renderSvg(canvas, area, settings.scale, settings.svg)) : require_render_export.renderRaster(canvas, area, format, settings.scale, settings.quality)
|
|
572
|
+
content: format === "svg" ? Promise.resolve(require_render_export.renderSvg(canvas, area, settings.scale, settings.svg, options.limits)) : require_render_export.renderRaster(canvas, area, format, settings.scale, settings.quality)
|
|
492
573
|
};
|
|
493
574
|
});
|
|
494
575
|
let blob;
|
|
495
576
|
if (format === "svg") {
|
|
496
|
-
const
|
|
577
|
+
const { svg, rasterizedObjectIds } = await rendered.content;
|
|
578
|
+
if (rasterizedObjectIds.length > 0) warnings.push({
|
|
579
|
+
code: "CLIP_PATH_RASTERIZED",
|
|
580
|
+
message: "Objects whose clip path has a clip path of its own were drawn as pictures: Fabric cannot write nested clip paths as SVG.",
|
|
581
|
+
objectIds: rasterizedObjectIds
|
|
582
|
+
});
|
|
583
|
+
const embedded = await require_embed_assets.embedSvgAssets(svg, canvas, settings.svg, settings.signal, options.limits?.isAllowedUrl ?? require_content_limits.isSafeImageUrl);
|
|
497
584
|
stopIfCancelled();
|
|
498
585
|
if (settings.svg.embedImages === "require" && embedded.problems.length > 0) {
|
|
499
586
|
const problems = embedded.warnings.filter((warning) => warning.code === "IMAGE_NOT_EMBEDDED").map((warning) => ({
|
|
@@ -555,12 +642,14 @@ function createDocumentEngine(options) {
|
|
|
555
642
|
if (!recovery) throw new require_errors.DocumentEngineError("RECOVERY_MISSING", "Pass recovery: { store } to createDocumentEngine to use recovery");
|
|
556
643
|
return recovery;
|
|
557
644
|
}
|
|
558
|
-
async function restoreRecovery(documentId,
|
|
645
|
+
async function restoreRecovery(documentId, restoreOptions = {}) {
|
|
559
646
|
const source = requireRecovery();
|
|
560
647
|
const id = documentId ?? documentInfo.id;
|
|
561
|
-
const
|
|
648
|
+
const { sessionId: branch, ...loadOptions } = restoreOptions;
|
|
649
|
+
const record = await source.read(id, branch);
|
|
562
650
|
if (!record) throw new require_errors.DocumentEngineError("RECOVERY_NOT_FOUND", `There is no recovery copy for document "${id}"`);
|
|
563
651
|
const loaded = await loadDocument(await require_recovery_controller.restoreRecordedFiles(record), loadOptions);
|
|
652
|
+
source.adopt(loaded.id, record.sessionId);
|
|
564
653
|
noteContentChange();
|
|
565
654
|
events.emit("recovery:restored", { document: loaded });
|
|
566
655
|
return loaded;
|
|
@@ -581,12 +670,15 @@ function createDocumentEngine(options) {
|
|
|
581
670
|
const { disposed } = canvas;
|
|
582
671
|
if (recovery && saving.state().isDirty && !disposed) recovery.writeNow();
|
|
583
672
|
destroyed = true;
|
|
673
|
+
session += 1;
|
|
584
674
|
activeLoad?.abort();
|
|
585
675
|
history.destroy();
|
|
586
676
|
saving.destroy();
|
|
587
677
|
recovery?.destroy();
|
|
588
678
|
canvas.off("object:added", handleObjectAdded);
|
|
589
679
|
canvas.off("object:removed", handleObjectRemoved);
|
|
680
|
+
canvas.off("object:modified", countMutation);
|
|
681
|
+
canvas.off("text:changed", countMutation);
|
|
590
682
|
objectsById.clear();
|
|
591
683
|
events.clear();
|
|
592
684
|
}
|
|
@@ -594,7 +686,8 @@ function createDocumentEngine(options) {
|
|
|
594
686
|
canvas,
|
|
595
687
|
getDocumentInfo: () => ({
|
|
596
688
|
...documentInfo,
|
|
597
|
-
metadata: { ...documentInfo.metadata }
|
|
689
|
+
metadata: { ...documentInfo.metadata },
|
|
690
|
+
session
|
|
598
691
|
}),
|
|
599
692
|
updateMetadata(changes) {
|
|
600
693
|
ensureUsable();
|
|
@@ -635,14 +728,15 @@ function createDocumentEngine(options) {
|
|
|
635
728
|
preflightExport: checkBeforeExport,
|
|
636
729
|
flushRecovery: async () => requireRecovery().flush(),
|
|
637
730
|
getRecoverableDocuments: async () => requireRecovery().list(),
|
|
638
|
-
getRecovery: async (documentId) => requireRecovery().read(documentId ?? documentInfo.id),
|
|
731
|
+
getRecovery: async (documentId, sessionId) => requireRecovery().read(documentId ?? documentInfo.id, sessionId),
|
|
639
732
|
restoreRecovery,
|
|
640
|
-
discardRecovery: async (documentId) => requireRecovery().
|
|
733
|
+
discardRecovery: async (documentId, sessionId) => requireRecovery().discard(documentId ?? documentInfo.id, sessionId),
|
|
641
734
|
getInterruptedLoad: async () => requireRecovery().interruptedLoad(),
|
|
642
|
-
transaction(label, work) {
|
|
735
|
+
transaction(label, work, transactionOptions) {
|
|
643
736
|
ensureUsable();
|
|
644
|
-
return history.transaction(label, work);
|
|
737
|
+
return history.transaction(label, work, transactionOptions);
|
|
645
738
|
},
|
|
739
|
+
setPage,
|
|
646
740
|
commit(label = "Edit") {
|
|
647
741
|
ensureUsable();
|
|
648
742
|
return history.commit(label);
|
|
@@ -7,7 +7,7 @@ import { ContentLimits } from "../security/content-limits.cjs";
|
|
|
7
7
|
import { SvgImportOptions, SvgImportResult } from "../import/svg-import.cjs";
|
|
8
8
|
import { NewDocumentOptions } from "../document/create-document.cjs";
|
|
9
9
|
import { CustomObjectDefinition } from "../fabric/object-registry.cjs";
|
|
10
|
-
import { HistoryOptions, HistoryState } from "../history/create-history.cjs";
|
|
10
|
+
import { HistoryOptions, HistoryState, TransactionOptions } from "../history/create-history.cjs";
|
|
11
11
|
import { VersionOptions, VersionSummary } from "../versions/document-version.cjs";
|
|
12
12
|
import { InterruptedLoad, RecoveryOptions, RecoveryRecord } from "../recovery/recovery-controller.cjs";
|
|
13
13
|
import { AutosaveOptions } from "../save/autosave-scheduler.cjs";
|
|
@@ -16,7 +16,7 @@ import { DocumentEngineError } from "./errors.cjs";
|
|
|
16
16
|
import { DocumentStorage } from "../storage/storage-contract.cjs";
|
|
17
17
|
import { SaveOptions, SaveRetryEvent, SaveState } from "../save/save-controller.cjs";
|
|
18
18
|
import { Unsubscribe } from "./event-emitter.cjs";
|
|
19
|
-
import { FabricObject, StaticCanvas } from "fabric";
|
|
19
|
+
import { FabricObject, StaticCanvas, TFiller } from "fabric";
|
|
20
20
|
//#region src/engine/create-document-engine.d.ts
|
|
21
21
|
export interface DocumentEngineOptions {
|
|
22
22
|
canvas: StaticCanvas;
|
|
@@ -51,6 +51,23 @@ export interface LoadProgress {
|
|
|
51
51
|
done: number;
|
|
52
52
|
total: number;
|
|
53
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* Page settings for `setPage`. Images and the mask are live Fabric objects;
|
|
56
|
+
* `null` removes one.
|
|
57
|
+
*/
|
|
58
|
+
export interface PageChanges {
|
|
59
|
+
width?: number;
|
|
60
|
+
height?: number;
|
|
61
|
+
background?: string | TFiller | null;
|
|
62
|
+
backgroundImage?: FabricObject | null;
|
|
63
|
+
overlay?: string | TFiller | null;
|
|
64
|
+
overlayImage?: FabricObject | null;
|
|
65
|
+
clipPath?: FabricObject | null;
|
|
66
|
+
}
|
|
67
|
+
export interface RestoreRecoveryOptions extends LoadOptions {
|
|
68
|
+
/** Restore the copy one session wrote. By default the newest copy of the document is used. */
|
|
69
|
+
sessionId?: string;
|
|
70
|
+
}
|
|
54
71
|
export interface NewDocumentRequest extends NewDocumentOptions {
|
|
55
72
|
discardUnsavedChanges?: boolean;
|
|
56
73
|
}
|
|
@@ -147,7 +164,8 @@ export interface DocumentEngine {
|
|
|
147
164
|
isDirty(): boolean;
|
|
148
165
|
getSaveState(): SaveState;
|
|
149
166
|
registerObject(definition: CustomObjectDefinition): void;
|
|
150
|
-
transaction<Result>(label: string, work: () => Result): Result;
|
|
167
|
+
transaction<Result>(label: string, work: () => Result, options?: TransactionOptions): Result;
|
|
168
|
+
setPage(changes: PageChanges, label?: string): void;
|
|
151
169
|
commit(label?: string): boolean;
|
|
152
170
|
undo(): Promise<boolean>;
|
|
153
171
|
redo(): Promise<boolean>;
|
|
@@ -166,9 +184,9 @@ export interface DocumentEngine {
|
|
|
166
184
|
preflightExport(options: ExportOptions): Promise<ExportPreflight>;
|
|
167
185
|
flushRecovery(): Promise<void>;
|
|
168
186
|
getRecoverableDocuments(): Promise<RecoveryRecord[]>;
|
|
169
|
-
getRecovery(documentId?: string): Promise<RecoveryRecord | undefined>;
|
|
170
|
-
restoreRecovery(documentId?: string, options?:
|
|
171
|
-
discardRecovery(documentId?: string): Promise<void>;
|
|
187
|
+
getRecovery(documentId?: string, sessionId?: string): Promise<RecoveryRecord | undefined>;
|
|
188
|
+
restoreRecovery(documentId?: string, options?: RestoreRecoveryOptions): Promise<FabricDocument>;
|
|
189
|
+
discardRecovery(documentId?: string, sessionId?: string): Promise<void>;
|
|
172
190
|
getInterruptedLoad(): Promise<InterruptedLoad | undefined>;
|
|
173
191
|
on<Name extends keyof DocumentEngineEvents>(name: Name, handler: (payload: DocumentEngineEvents[Name]) => void): Unsubscribe;
|
|
174
192
|
destroy(): void;
|
|
@@ -7,7 +7,7 @@ import { ContentLimits } from "../security/content-limits.js";
|
|
|
7
7
|
import { SvgImportOptions, SvgImportResult } from "../import/svg-import.js";
|
|
8
8
|
import { NewDocumentOptions } from "../document/create-document.js";
|
|
9
9
|
import { CustomObjectDefinition } from "../fabric/object-registry.js";
|
|
10
|
-
import { HistoryOptions, HistoryState } from "../history/create-history.js";
|
|
10
|
+
import { HistoryOptions, HistoryState, TransactionOptions } from "../history/create-history.js";
|
|
11
11
|
import { VersionOptions, VersionSummary } from "../versions/document-version.js";
|
|
12
12
|
import { InterruptedLoad, RecoveryOptions, RecoveryRecord } from "../recovery/recovery-controller.js";
|
|
13
13
|
import { AutosaveOptions } from "../save/autosave-scheduler.js";
|
|
@@ -16,7 +16,7 @@ import { DocumentEngineError } from "./errors.js";
|
|
|
16
16
|
import { DocumentStorage } from "../storage/storage-contract.js";
|
|
17
17
|
import { SaveOptions, SaveRetryEvent, SaveState } from "../save/save-controller.js";
|
|
18
18
|
import { Unsubscribe } from "./event-emitter.js";
|
|
19
|
-
import { FabricObject, StaticCanvas } from "fabric";
|
|
19
|
+
import { FabricObject, StaticCanvas, TFiller } from "fabric";
|
|
20
20
|
//#region src/engine/create-document-engine.d.ts
|
|
21
21
|
export interface DocumentEngineOptions {
|
|
22
22
|
canvas: StaticCanvas;
|
|
@@ -51,6 +51,23 @@ export interface LoadProgress {
|
|
|
51
51
|
done: number;
|
|
52
52
|
total: number;
|
|
53
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* Page settings for `setPage`. Images and the mask are live Fabric objects;
|
|
56
|
+
* `null` removes one.
|
|
57
|
+
*/
|
|
58
|
+
export interface PageChanges {
|
|
59
|
+
width?: number;
|
|
60
|
+
height?: number;
|
|
61
|
+
background?: string | TFiller | null;
|
|
62
|
+
backgroundImage?: FabricObject | null;
|
|
63
|
+
overlay?: string | TFiller | null;
|
|
64
|
+
overlayImage?: FabricObject | null;
|
|
65
|
+
clipPath?: FabricObject | null;
|
|
66
|
+
}
|
|
67
|
+
export interface RestoreRecoveryOptions extends LoadOptions {
|
|
68
|
+
/** Restore the copy one session wrote. By default the newest copy of the document is used. */
|
|
69
|
+
sessionId?: string;
|
|
70
|
+
}
|
|
54
71
|
export interface NewDocumentRequest extends NewDocumentOptions {
|
|
55
72
|
discardUnsavedChanges?: boolean;
|
|
56
73
|
}
|
|
@@ -147,7 +164,8 @@ export interface DocumentEngine {
|
|
|
147
164
|
isDirty(): boolean;
|
|
148
165
|
getSaveState(): SaveState;
|
|
149
166
|
registerObject(definition: CustomObjectDefinition): void;
|
|
150
|
-
transaction<Result>(label: string, work: () => Result): Result;
|
|
167
|
+
transaction<Result>(label: string, work: () => Result, options?: TransactionOptions): Result;
|
|
168
|
+
setPage(changes: PageChanges, label?: string): void;
|
|
151
169
|
commit(label?: string): boolean;
|
|
152
170
|
undo(): Promise<boolean>;
|
|
153
171
|
redo(): Promise<boolean>;
|
|
@@ -166,9 +184,9 @@ export interface DocumentEngine {
|
|
|
166
184
|
preflightExport(options: ExportOptions): Promise<ExportPreflight>;
|
|
167
185
|
flushRecovery(): Promise<void>;
|
|
168
186
|
getRecoverableDocuments(): Promise<RecoveryRecord[]>;
|
|
169
|
-
getRecovery(documentId?: string): Promise<RecoveryRecord | undefined>;
|
|
170
|
-
restoreRecovery(documentId?: string, options?:
|
|
171
|
-
discardRecovery(documentId?: string): Promise<void>;
|
|
187
|
+
getRecovery(documentId?: string, sessionId?: string): Promise<RecoveryRecord | undefined>;
|
|
188
|
+
restoreRecovery(documentId?: string, options?: RestoreRecoveryOptions): Promise<FabricDocument>;
|
|
189
|
+
discardRecovery(documentId?: string, sessionId?: string): Promise<void>;
|
|
172
190
|
getInterruptedLoad(): Promise<InterruptedLoad | undefined>;
|
|
173
191
|
on<Name extends keyof DocumentEngineEvents>(name: Name, handler: (payload: DocumentEngineEvents[Name]) => void): Unsubscribe;
|
|
174
192
|
destroy(): void;
|