fabricjs-document-engine 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/README.md +70 -1
  2. package/README.zh-CN.md +71 -1
  3. package/dist/assets/asset-pipeline.cjs +10 -8
  4. package/dist/assets/asset-pipeline.d.cts +1 -1
  5. package/dist/assets/asset-pipeline.d.ts +1 -1
  6. package/dist/assets/asset-pipeline.js +10 -8
  7. package/dist/assets/image-check.cjs +4 -3
  8. package/dist/assets/image-check.d.cts +1 -1
  9. package/dist/assets/image-check.d.ts +1 -1
  10. package/dist/assets/image-check.js +4 -3
  11. package/dist/commands/clipboard.cjs +5 -0
  12. package/dist/commands/clipboard.js +5 -0
  13. package/dist/commands/text-edit.cjs +223 -0
  14. package/dist/commands/text-edit.d.cts +23 -0
  15. package/dist/commands/text-edit.d.ts +23 -0
  16. package/dist/commands/text-edit.js +218 -0
  17. package/dist/document/document-format.d.cts +15 -0
  18. package/dist/document/document-format.d.ts +15 -0
  19. package/dist/document/validate-document.cjs +8 -0
  20. package/dist/document/validate-document.js +8 -0
  21. package/dist/engine/create-document-engine.cjs +115 -21
  22. package/dist/engine/create-document-engine.d.cts +24 -6
  23. package/dist/engine/create-document-engine.d.ts +24 -6
  24. package/dist/engine/create-document-engine.js +116 -22
  25. package/dist/engine/errors.d.cts +1 -1
  26. package/dist/engine/errors.d.ts +1 -1
  27. package/dist/export/export-options.cjs +3 -0
  28. package/dist/export/export-options.d.cts +6 -0
  29. package/dist/export/export-options.d.ts +6 -0
  30. package/dist/export/export-options.js +3 -0
  31. package/dist/export/preflight-export.d.cts +1 -1
  32. package/dist/export/preflight-export.d.ts +1 -1
  33. package/dist/export/render-export.cjs +42 -4
  34. package/dist/export/render-export.js +43 -5
  35. package/dist/export/svg/clip-masks.cjs +39 -0
  36. package/dist/export/svg/clip-masks.js +37 -0
  37. package/dist/export/svg/embed-assets.cjs +1 -0
  38. package/dist/export/svg/embed-assets.js +1 -0
  39. package/dist/export/svg/raster-object.cjs +82 -0
  40. package/dist/export/svg/raster-object.js +81 -0
  41. package/dist/{pdf → export/svg}/text-decorations.cjs +3 -3
  42. package/dist/{pdf → export/svg}/text-decorations.js +3 -3
  43. package/dist/export/svg/text-on-path.cjs +0 -10
  44. package/dist/export/svg/text-on-path.js +1 -10
  45. package/dist/fabric/fabric-adapter.cjs +5 -3
  46. package/dist/fabric/fabric-adapter.js +5 -3
  47. package/dist/fabric/object-registry.cjs +7 -1
  48. package/dist/fabric/object-registry.js +7 -1
  49. package/dist/fabric/page-state.cjs +69 -0
  50. package/dist/fabric/page-state.js +64 -0
  51. package/dist/filters/filter-worker.cjs +281 -0
  52. package/dist/filters/filter-worker.d.cts +26 -0
  53. package/dist/filters/filter-worker.d.ts +26 -0
  54. package/dist/filters/filter-worker.js +281 -0
  55. package/dist/filters/pipeline.cjs +91 -0
  56. package/dist/filters/pipeline.d.cts +35 -0
  57. package/dist/filters/pipeline.d.ts +35 -0
  58. package/dist/filters/pipeline.js +87 -0
  59. package/dist/filters/worker-entry.cjs +78 -0
  60. package/dist/filters/worker-entry.d.cts +29 -0
  61. package/dist/filters/worker-entry.d.ts +29 -0
  62. package/dist/filters/worker-entry.js +78 -0
  63. package/dist/filters.cjs +9 -0
  64. package/dist/filters.d.cts +3 -0
  65. package/dist/filters.d.ts +3 -0
  66. package/dist/filters.js +3 -0
  67. package/dist/history/apply-state.cjs +19 -2
  68. package/dist/history/apply-state.js +19 -2
  69. package/dist/history/create-history.cjs +53 -13
  70. package/dist/history/create-history.d.cts +8 -0
  71. package/dist/history/create-history.d.ts +8 -0
  72. package/dist/history/create-history.js +53 -13
  73. package/dist/history/snapshot.cjs +10 -1
  74. package/dist/history/snapshot.js +10 -2
  75. package/dist/import/svg-import.cjs +102 -0
  76. package/dist/import/svg-import.d.cts +1 -0
  77. package/dist/import/svg-import.d.ts +1 -0
  78. package/dist/import/svg-import.js +103 -1
  79. package/dist/index.cjs +7 -0
  80. package/dist/index.d.cts +4 -3
  81. package/dist/index.d.ts +4 -3
  82. package/dist/index.js +2 -1
  83. package/dist/migrations/migrate-document.cjs +2 -1
  84. package/dist/migrations/migrate-document.js +2 -1
  85. package/dist/pdf/export-pdf.cjs +8 -67
  86. package/dist/pdf/export-pdf.js +8 -67
  87. package/dist/performance/batch.cjs +31 -0
  88. package/dist/performance/batch.d.cts +4 -0
  89. package/dist/performance/batch.d.ts +4 -0
  90. package/dist/performance/batch.js +31 -0
  91. package/dist/performance/dirty-regions.cjs +378 -0
  92. package/dist/performance/dirty-regions.d.cts +23 -0
  93. package/dist/performance/dirty-regions.d.ts +23 -0
  94. package/dist/performance/dirty-regions.js +378 -0
  95. package/dist/performance/monitor.cjs +60 -0
  96. package/dist/performance/monitor.d.cts +20 -0
  97. package/dist/performance/monitor.d.ts +20 -0
  98. package/dist/performance/monitor.js +60 -0
  99. package/dist/performance/spatial-index.cjs +78 -0
  100. package/dist/performance/spatial-index.d.cts +21 -0
  101. package/dist/performance/spatial-index.d.ts +21 -0
  102. package/dist/performance/spatial-index.js +78 -0
  103. package/dist/performance.cjs +9 -0
  104. package/dist/performance.d.cts +5 -0
  105. package/dist/performance.d.ts +5 -0
  106. package/dist/performance.js +5 -0
  107. package/dist/recovery/recovery-controller.cjs +148 -29
  108. package/dist/recovery/recovery-controller.d.cts +8 -0
  109. package/dist/recovery/recovery-controller.d.ts +8 -0
  110. package/dist/recovery/recovery-controller.js +148 -29
  111. package/dist/security/content-limits.cjs +43 -3
  112. package/dist/security/content-limits.d.cts +8 -0
  113. package/dist/security/content-limits.d.ts +8 -0
  114. package/dist/security/content-limits.js +39 -4
  115. package/dist/text/bounded-textbox.cjs +306 -0
  116. package/dist/text/bounded-textbox.d.cts +53 -0
  117. package/dist/text/bounded-textbox.d.ts +53 -0
  118. package/dist/text/bounded-textbox.js +306 -0
  119. package/dist/text/mobile-input.cjs +146 -0
  120. package/dist/text/mobile-input.d.cts +19 -0
  121. package/dist/text/mobile-input.d.ts +19 -0
  122. package/dist/text/mobile-input.js +145 -0
  123. package/dist/text/register.cjs +17 -0
  124. package/dist/text/register.d.cts +5 -0
  125. package/dist/text/register.d.ts +5 -0
  126. package/dist/text/register.js +16 -0
  127. package/dist/text/shaping.cjs +125 -0
  128. package/dist/text/shaping.d.cts +28 -0
  129. package/dist/text/shaping.d.ts +28 -0
  130. package/dist/text/shaping.js +121 -0
  131. package/dist/text/vertical-orientation.cjs +192 -0
  132. package/dist/text/vertical-orientation.d.cts +10 -0
  133. package/dist/text/vertical-orientation.d.ts +10 -0
  134. package/dist/text/vertical-orientation.js +190 -0
  135. package/dist/text/vertical-text.cjs +336 -0
  136. package/dist/text/vertical-text.d.cts +54 -0
  137. package/dist/text/vertical-text.d.ts +54 -0
  138. package/dist/text/vertical-text.js +336 -0
  139. package/dist/text.cjs +21 -0
  140. package/dist/text.d.cts +7 -0
  141. package/dist/text.d.ts +7 -0
  142. package/dist/text.js +7 -0
  143. package/dist/util/concurrency.cjs +16 -3
  144. package/dist/util/concurrency.js +16 -3
  145. package/package.json +31 -1
  146. package/schema/document-v1.schema.json +5 -1
@@ -1,6 +1,6 @@
1
+ import { createSnapshot, diffSnapshots } from "./snapshot.js";
1
2
  import { applyStateChange } from "./apply-state.js";
2
3
  import { createHistoryStack } from "./history-stack.js";
3
- import { createSnapshot, diffSnapshots } from "./snapshot.js";
4
4
  //#region src/history/create-history.ts
5
5
  const verbsByAction = {
6
6
  drag: "Move",
@@ -24,18 +24,23 @@ function describePendingChanges(changes) {
24
24
  return changes.length === 1 ? `${verb} ${changes[0].noun}` : `${verb} ${changes.length} objects`;
25
25
  }
26
26
  function createHistory(options) {
27
- const { canvas, serializeObjects, onChange, onContentChange } = options;
27
+ const { canvas, serializeState, onChange, onContentChange, onLiveChange } = options;
28
+ const takeSnapshot = () => {
29
+ const { objects, page } = serializeState();
30
+ return createSnapshot(objects, page);
31
+ };
28
32
  const stack = createHistoryStack({
29
33
  steps: Math.max(1, options.limit ?? 100),
30
34
  bytes: Math.max(0, options.maxBytes ?? 67108864)
31
35
  });
32
- let snapshot = createSnapshot(serializeObjects());
36
+ let snapshot = takeSnapshot();
33
37
  let pendingChanges = [];
34
38
  let flushScheduled = false;
35
39
  let transactionDepth = 0;
36
40
  let pausedDepth = 0;
37
41
  let applying = false;
38
42
  let queue = Promise.resolve();
43
+ let epoch = 0;
39
44
  function state() {
40
45
  const undoLabels = stack.undoLabels();
41
46
  const redoLabels = stack.redoLabels();
@@ -48,7 +53,7 @@ function createHistory(options) {
48
53
  }
49
54
  function commit(label) {
50
55
  pendingChanges = [];
51
- const nextSnapshot = createSnapshot(serializeObjects());
56
+ const nextSnapshot = takeSnapshot();
52
57
  const difference = diffSnapshots(snapshot, nextSnapshot);
53
58
  snapshot = nextSnapshot;
54
59
  if (difference === null) return false;
@@ -86,26 +91,56 @@ function createHistory(options) {
86
91
  notice(verbsByAction[action] ?? "Transform", event.target);
87
92
  };
88
93
  const handleTextEdited = ({ target }) => notice("Edit", target);
94
+ const handleTextChanged = () => {
95
+ if (!applying && pausedDepth === 0) onLiveChange?.();
96
+ };
89
97
  const listeners = [
90
98
  ["object:added", handleAdded],
91
99
  ["object:removed", handleRemoved],
92
100
  ["object:modified", handleModified],
93
- ["text:editing:exited", handleTextEdited]
101
+ ["text:editing:exited", handleTextEdited],
102
+ ["text:changed", handleTextChanged]
94
103
  ];
95
104
  const eventTarget = canvas;
96
105
  listeners.forEach(([name, handler]) => eventTarget.on(name, handler));
97
- function transaction(label, work) {
106
+ /**
107
+ * Puts the canvas back to the last recorded snapshot. The snapshot is the
108
+ * state before the transaction, so the difference to undo is exactly what
109
+ * the transaction changed: one serialization, then only the changed
110
+ * objects are rebuilt.
111
+ */
112
+ function rollBack() {
113
+ const difference = diffSnapshots(snapshot, takeSnapshot());
114
+ pendingChanges = [];
115
+ if (difference === null) return Promise.resolve();
116
+ applying = true;
117
+ return runInOrder(async () => {
118
+ try {
119
+ await applyStateChange(canvas, difference.before);
120
+ } finally {
121
+ applying = false;
122
+ }
123
+ });
124
+ }
125
+ function transaction(label, work, transactionOptions = {}) {
98
126
  if (transactionDepth === 0) commitPendingChanges();
127
+ const outermost = transactionDepth === 0;
99
128
  transactionDepth += 1;
100
129
  const finish = () => {
101
130
  transactionDepth -= 1;
102
131
  if (transactionDepth === 0) commit(label);
103
132
  };
133
+ const fail = () => {
134
+ transactionDepth -= 1;
135
+ if (transactionDepth > 0) return void 0;
136
+ if (outermost && transactionOptions.rollback) return rollBack();
137
+ commit(label);
138
+ };
104
139
  let result;
105
140
  try {
106
141
  result = work();
107
142
  } catch (error) {
108
- finish();
143
+ fail()?.catch(() => void 0);
109
144
  throw error;
110
145
  }
111
146
  if (!isPromiseLike(result)) {
@@ -115,8 +150,8 @@ function createHistory(options) {
115
150
  return Promise.resolve(result).then((value) => {
116
151
  finish();
117
152
  return value;
118
- }, (error) => {
119
- finish();
153
+ }, async (error) => {
154
+ await fail();
120
155
  throw error;
121
156
  });
122
157
  }
@@ -148,16 +183,19 @@ function createHistory(options) {
148
183
  commitPendingChanges();
149
184
  const step = takeStep();
150
185
  if (step === void 0) return false;
186
+ const startedIn = epoch;
151
187
  applying = true;
188
+ let applied;
152
189
  try {
153
- await applyStateChange(canvas, pickChange(step));
190
+ applied = await applyStateChange(canvas, pickChange(step), () => epoch !== startedIn);
154
191
  } catch (error) {
155
- putBack(step);
192
+ if (epoch === startedIn) putBack(step);
156
193
  throw error;
157
194
  } finally {
158
195
  applying = false;
159
196
  }
160
- snapshot = createSnapshot(serializeObjects());
197
+ if (!applied) return false;
198
+ snapshot = takeSnapshot();
161
199
  moveTo(step);
162
200
  onContentChange();
163
201
  onChange(state());
@@ -170,6 +208,7 @@ function createHistory(options) {
170
208
  return commit(label);
171
209
  },
172
210
  transaction,
211
+ settled: () => queue.then(() => void 0),
173
212
  undo: () => travel(() => stack.takeUndo(), (step) => step.before, (step) => stack.returnUndo(step), (step) => stack.returnRedo(step)),
174
213
  redo: () => travel(() => stack.takeRedo(), (step) => step.after, (step) => stack.returnRedo(step), (step) => stack.returnUndo(step)),
175
214
  state,
@@ -182,7 +221,8 @@ function createHistory(options) {
182
221
  reset() {
183
222
  pendingChanges = [];
184
223
  stack.clear();
185
- snapshot = createSnapshot(serializeObjects());
224
+ epoch += 1;
225
+ snapshot = takeSnapshot();
186
226
  onChange(state());
187
227
  },
188
228
  destroy() {
@@ -1,7 +1,15 @@
1
1
  //#region src/history/snapshot.ts
2
- function createSnapshot(objects) {
2
+ /**
3
+ * The page itself (size, background, overlay, mask) is one more entry in the
4
+ * same map under this reserved key. It never appears in `order`, so the
5
+ * diff stays proportional to what changed and object ordering is unaffected.
6
+ * Object ids come from `createId`, which never produces this value.
7
+ */
8
+ const PAGE_KEY = "__page__";
9
+ function createSnapshot(objects, page) {
3
10
  const objectsById = /* @__PURE__ */ new Map();
4
11
  const order = [];
12
+ if (page !== void 0) objectsById.set(PAGE_KEY, JSON.stringify(page));
5
13
  for (const object of objects) {
6
14
  const id = object.id ?? "";
7
15
  objectsById.set(id, JSON.stringify(object));
@@ -43,5 +51,6 @@ function diffSnapshots(previous, next) {
43
51
  };
44
52
  }
45
53
  //#endregion
54
+ exports.PAGE_KEY = PAGE_KEY;
46
55
  exports.createSnapshot = createSnapshot;
47
56
  exports.diffSnapshots = diffSnapshots;
@@ -1,7 +1,15 @@
1
1
  //#region src/history/snapshot.ts
2
- function createSnapshot(objects) {
2
+ /**
3
+ * The page itself (size, background, overlay, mask) is one more entry in the
4
+ * same map under this reserved key. It never appears in `order`, so the
5
+ * diff stays proportional to what changed and object ordering is unaffected.
6
+ * Object ids come from `createId`, which never produces this value.
7
+ */
8
+ const PAGE_KEY = "__page__";
9
+ function createSnapshot(objects, page) {
3
10
  const objectsById = /* @__PURE__ */ new Map();
4
11
  const order = [];
12
+ if (page !== void 0) objectsById.set(PAGE_KEY, JSON.stringify(page));
5
13
  for (const object of objects) {
6
14
  const id = object.id ?? "";
7
15
  objectsById.set(id, JSON.stringify(object));
@@ -43,4 +51,4 @@ function diffSnapshots(previous, next) {
43
51
  };
44
52
  }
45
53
  //#endregion
46
- export { createSnapshot, diffSnapshots };
54
+ export { PAGE_KEY, createSnapshot, diffSnapshots };
@@ -127,12 +127,110 @@ function contentBounds(objects) {
127
127
  height: 0
128
128
  };
129
129
  }
130
+ function dropBrokenUses(document) {
131
+ for (const use of Array.from(document.getElementsByTagName("use"))) {
132
+ const link = (use.getAttribute("href") ?? use.getAttributeNS(XLINK, "href") ?? "").trim();
133
+ if (!link.startsWith("#") || link.length === 1 || document.getElementById(link.slice(1)) === null) use.remove();
134
+ }
135
+ }
136
+ const GROUP_MARK = "data-fde-svg-group";
137
+ function markGroups(document) {
138
+ for (const name of ["g", "a"]) for (const element of Array.from(document.documentElement.getElementsByTagName(name))) element.setAttribute(GROUP_MARK, "");
139
+ }
140
+ function svgMetadata(element) {
141
+ const metadata = {};
142
+ const id = element.getAttribute("id");
143
+ if (id) metadata.svgId = id;
144
+ const className = element.getAttribute("class");
145
+ if (className) metadata.svgClass = className;
146
+ for (const attribute of Array.from(element.attributes)) {
147
+ if (!attribute.name.startsWith("data-") || attribute.name === GROUP_MARK) continue;
148
+ (metadata.svgData ?? (metadata.svgData = {}))[attribute.name.slice(5)] = attribute.value;
149
+ }
150
+ return metadata;
151
+ }
152
+ function ownOpacity(element) {
153
+ const fromStyle = /(?:^|;)\s*opacity\s*:\s*([0-9.]+)/.exec(element.getAttribute("style") ?? "")?.[1];
154
+ const value = Number.parseFloat(fromStyle ?? element.getAttribute("opacity") ?? "1");
155
+ return Number.isFinite(value) ? Math.min(1, Math.max(0, value)) : 1;
156
+ }
157
+ function rebuildGroups(objects, elements, root) {
158
+ const top = [];
159
+ const nodes = /* @__PURE__ */ new Map();
160
+ const groupNodes = /* @__PURE__ */ new Set();
161
+ const chains = /* @__PURE__ */ new Map();
162
+ const elementOf = /* @__PURE__ */ new Map();
163
+ objects.forEach((object, index) => {
164
+ const element = elements[index];
165
+ elementOf.set(object, element);
166
+ const chain = [];
167
+ for (let parent = element.parentElement; parent && parent !== root; parent = parent.parentElement) if (parent.hasAttribute(GROUP_MARK)) chain.push(parent);
168
+ chains.set(object, chain);
169
+ let children = top;
170
+ for (let level = chain.length - 1; level >= 0; level -= 1) {
171
+ const groupElement = chain[level];
172
+ let node = nodes.get(groupElement);
173
+ if (!node) {
174
+ node = {
175
+ element: groupElement,
176
+ children: []
177
+ };
178
+ nodes.set(groupElement, node);
179
+ groupNodes.add(node);
180
+ children.push(node);
181
+ }
182
+ children = node.children;
183
+ }
184
+ children.push(object);
185
+ const own = element.getAttribute("id");
186
+ const leaf = object;
187
+ if (!own && chain.length > 0 && leaf.id !== void 0) delete leaf.id;
188
+ const inherited = chain.reduce((product, groupElement) => product * ownOpacity(groupElement), 1);
189
+ if (inherited > 0) object.opacity = Math.min(1, object.opacity / inherited);
190
+ object.set(svgMetadata(element));
191
+ });
192
+ const hoistClip = (node, group) => {
193
+ if (!node.element.hasAttribute("clip-path")) return;
194
+ let clip;
195
+ for (const object of objects) {
196
+ const chain = chains.get(object);
197
+ const at = chain.indexOf(node.element);
198
+ if (at === -1) continue;
199
+ if (elementOf.get(object).hasAttribute("clip-path") || chain.slice(0, at).some((between) => between.hasAttribute("clip-path")) || !object.clipPath) continue;
200
+ if (!clip) {
201
+ const absolute = fabric.util.multiplyTransformMatrices(object.calcTransformMatrix(), object.clipPath.calcTransformMatrix());
202
+ clip = object.clipPath;
203
+ fabric.util.applyTransformToObject(clip, fabric.util.multiplyTransformMatrices(fabric.util.invertTransform(group.calcTransformMatrix()), absolute));
204
+ }
205
+ object.clipPath = void 0;
206
+ object.set("dirty", true);
207
+ }
208
+ if (clip) group.clipPath = clip;
209
+ };
210
+ const build = (item) => {
211
+ if (!groupNodes.has(item)) return item;
212
+ const node = item;
213
+ const group = new fabric.Group(node.children.map(build));
214
+ group.set({
215
+ opacity: ownOpacity(node.element),
216
+ ...svgMetadata(node.element)
217
+ });
218
+ const id = node.element.getAttribute("id");
219
+ if (id) group.id = id;
220
+ hoistClip(node, group);
221
+ group.setCoords();
222
+ return group;
223
+ };
224
+ return top.map(build);
225
+ }
130
226
  /** Parses and places an SVG. Adding the result to a canvas is up to the caller. */
131
227
  async function readSvg(svg, options = {}, limits = {}) {
132
228
  if (typeof svg !== "string" || svg.trim().length === 0) refuse("The SVG is empty");
133
229
  const warnings = [];
134
230
  const document = parse(svg);
135
231
  sanitize(document, limits, warnings);
232
+ dropBrokenUses(document);
233
+ if (options.preserveGroups) markGroups(document);
136
234
  let parsed;
137
235
  try {
138
236
  parsed = await (0, fabric.parseSVGDocument)(document, void 0, {
@@ -145,6 +243,10 @@ async function readSvg(svg, options = {}, limits = {}) {
145
243
  }
146
244
  if (options.signal?.aborted) throw new require_errors.DocumentEngineError("LOAD_ABORTED", "The SVG import was cancelled");
147
245
  let objects = parsed.objects.filter((object) => object !== null && object !== void 0);
246
+ if (options.preserveGroups) {
247
+ const elements = parsed.elements.filter((_, index) => parsed.objects[index] !== null && parsed.objects[index] !== void 0);
248
+ objects = rebuildGroups(objects, elements, document.documentElement);
249
+ }
148
250
  const declared = {
149
251
  width: parsed.options.width ?? 0,
150
252
  height: parsed.options.height ?? 0
@@ -19,6 +19,7 @@ export interface SvgImportOptions {
19
19
  offscreen?: "keep" | "drop" | "clip";
20
20
  /** One group (the default), or separate objects. */
21
21
  as?: "group" | "objects";
22
+ preserveGroups?: boolean;
22
23
  /** Where the viewport's top-left corner lands on the canvas. Default 0, 0. */
23
24
  left?: number;
24
25
  top?: number;
@@ -19,6 +19,7 @@ export interface SvgImportOptions {
19
19
  offscreen?: "keep" | "drop" | "clip";
20
20
  /** One group (the default), or separate objects. */
21
21
  as?: "group" | "objects";
22
+ preserveGroups?: boolean;
22
23
  /** Where the viewport's top-left corner lands on the canvas. Default 0, 0. */
23
24
  left?: number;
24
25
  top?: number;
@@ -1,6 +1,6 @@
1
1
  import { DocumentEngineError, isDocumentEngineError } from "../engine/errors.js";
2
2
  import { isSafeImageUrl } from "../security/content-limits.js";
3
- import { FixedLayout, Group, LayoutManager, Rect, parseSVGDocument } from "fabric";
3
+ import { FixedLayout, Group, LayoutManager, Rect, parseSVGDocument, util } from "fabric";
4
4
  //#region src/import/svg-import.ts
5
5
  const XLINK = "http://www.w3.org/1999/xlink";
6
6
  const REMOVED_ELEMENTS = [
@@ -127,12 +127,110 @@ function contentBounds(objects) {
127
127
  height: 0
128
128
  };
129
129
  }
130
+ function dropBrokenUses(document) {
131
+ for (const use of Array.from(document.getElementsByTagName("use"))) {
132
+ const link = (use.getAttribute("href") ?? use.getAttributeNS(XLINK, "href") ?? "").trim();
133
+ if (!link.startsWith("#") || link.length === 1 || document.getElementById(link.slice(1)) === null) use.remove();
134
+ }
135
+ }
136
+ const GROUP_MARK = "data-fde-svg-group";
137
+ function markGroups(document) {
138
+ for (const name of ["g", "a"]) for (const element of Array.from(document.documentElement.getElementsByTagName(name))) element.setAttribute(GROUP_MARK, "");
139
+ }
140
+ function svgMetadata(element) {
141
+ const metadata = {};
142
+ const id = element.getAttribute("id");
143
+ if (id) metadata.svgId = id;
144
+ const className = element.getAttribute("class");
145
+ if (className) metadata.svgClass = className;
146
+ for (const attribute of Array.from(element.attributes)) {
147
+ if (!attribute.name.startsWith("data-") || attribute.name === GROUP_MARK) continue;
148
+ (metadata.svgData ?? (metadata.svgData = {}))[attribute.name.slice(5)] = attribute.value;
149
+ }
150
+ return metadata;
151
+ }
152
+ function ownOpacity(element) {
153
+ const fromStyle = /(?:^|;)\s*opacity\s*:\s*([0-9.]+)/.exec(element.getAttribute("style") ?? "")?.[1];
154
+ const value = Number.parseFloat(fromStyle ?? element.getAttribute("opacity") ?? "1");
155
+ return Number.isFinite(value) ? Math.min(1, Math.max(0, value)) : 1;
156
+ }
157
+ function rebuildGroups(objects, elements, root) {
158
+ const top = [];
159
+ const nodes = /* @__PURE__ */ new Map();
160
+ const groupNodes = /* @__PURE__ */ new Set();
161
+ const chains = /* @__PURE__ */ new Map();
162
+ const elementOf = /* @__PURE__ */ new Map();
163
+ objects.forEach((object, index) => {
164
+ const element = elements[index];
165
+ elementOf.set(object, element);
166
+ const chain = [];
167
+ for (let parent = element.parentElement; parent && parent !== root; parent = parent.parentElement) if (parent.hasAttribute(GROUP_MARK)) chain.push(parent);
168
+ chains.set(object, chain);
169
+ let children = top;
170
+ for (let level = chain.length - 1; level >= 0; level -= 1) {
171
+ const groupElement = chain[level];
172
+ let node = nodes.get(groupElement);
173
+ if (!node) {
174
+ node = {
175
+ element: groupElement,
176
+ children: []
177
+ };
178
+ nodes.set(groupElement, node);
179
+ groupNodes.add(node);
180
+ children.push(node);
181
+ }
182
+ children = node.children;
183
+ }
184
+ children.push(object);
185
+ const own = element.getAttribute("id");
186
+ const leaf = object;
187
+ if (!own && chain.length > 0 && leaf.id !== void 0) delete leaf.id;
188
+ const inherited = chain.reduce((product, groupElement) => product * ownOpacity(groupElement), 1);
189
+ if (inherited > 0) object.opacity = Math.min(1, object.opacity / inherited);
190
+ object.set(svgMetadata(element));
191
+ });
192
+ const hoistClip = (node, group) => {
193
+ if (!node.element.hasAttribute("clip-path")) return;
194
+ let clip;
195
+ for (const object of objects) {
196
+ const chain = chains.get(object);
197
+ const at = chain.indexOf(node.element);
198
+ if (at === -1) continue;
199
+ if (elementOf.get(object).hasAttribute("clip-path") || chain.slice(0, at).some((between) => between.hasAttribute("clip-path")) || !object.clipPath) continue;
200
+ if (!clip) {
201
+ const absolute = util.multiplyTransformMatrices(object.calcTransformMatrix(), object.clipPath.calcTransformMatrix());
202
+ clip = object.clipPath;
203
+ util.applyTransformToObject(clip, util.multiplyTransformMatrices(util.invertTransform(group.calcTransformMatrix()), absolute));
204
+ }
205
+ object.clipPath = void 0;
206
+ object.set("dirty", true);
207
+ }
208
+ if (clip) group.clipPath = clip;
209
+ };
210
+ const build = (item) => {
211
+ if (!groupNodes.has(item)) return item;
212
+ const node = item;
213
+ const group = new Group(node.children.map(build));
214
+ group.set({
215
+ opacity: ownOpacity(node.element),
216
+ ...svgMetadata(node.element)
217
+ });
218
+ const id = node.element.getAttribute("id");
219
+ if (id) group.id = id;
220
+ hoistClip(node, group);
221
+ group.setCoords();
222
+ return group;
223
+ };
224
+ return top.map(build);
225
+ }
130
226
  /** Parses and places an SVG. Adding the result to a canvas is up to the caller. */
131
227
  async function readSvg(svg, options = {}, limits = {}) {
132
228
  if (typeof svg !== "string" || svg.trim().length === 0) refuse("The SVG is empty");
133
229
  const warnings = [];
134
230
  const document = parse(svg);
135
231
  sanitize(document, limits, warnings);
232
+ dropBrokenUses(document);
233
+ if (options.preserveGroups) markGroups(document);
136
234
  let parsed;
137
235
  try {
138
236
  parsed = await parseSVGDocument(document, void 0, {
@@ -145,6 +243,10 @@ async function readSvg(svg, options = {}, limits = {}) {
145
243
  }
146
244
  if (options.signal?.aborted) throw new DocumentEngineError("LOAD_ABORTED", "The SVG import was cancelled");
147
245
  let objects = parsed.objects.filter((object) => object !== null && object !== void 0);
246
+ if (options.preserveGroups) {
247
+ const elements = parsed.elements.filter((_, index) => parsed.objects[index] !== null && parsed.objects[index] !== void 0);
248
+ objects = rebuildGroups(objects, elements, document.documentElement);
249
+ }
148
250
  const declared = {
149
251
  width: parsed.options.width ?? 0,
150
252
  height: parsed.options.height ?? 0
package/dist/index.cjs CHANGED
@@ -12,6 +12,7 @@ const require_batch_render = require("./export/batch-render.cjs");
12
12
  const require_document_state_store = require("./state/document-state-store.cjs");
13
13
  const require_clipboard = require("./commands/clipboard.cjs");
14
14
  const require_layers = require("./commands/layers.cjs");
15
+ const require_text_edit = require("./commands/text-edit.cjs");
15
16
  exports.CLIPBOARD_FORMAT = require_clipboard.CLIPBOARD_FORMAT;
16
17
  exports.CURRENT_SCHEMA_VERSION = require_document_format.CURRENT_SCHEMA_VERSION;
17
18
  exports.DocumentEngineError = require_errors.DocumentEngineError;
@@ -23,6 +24,7 @@ exports.createClipboard = require_clipboard.createClipboard;
23
24
  exports.createConflictError = require_errors.createConflictError;
24
25
  exports.createDocumentEngine = require_create_document_engine.createDocumentEngine;
25
26
  exports.createDocumentStateStore = require_document_state_store.createDocumentStateStore;
27
+ exports.createTextCommands = require_text_edit.createTextCommands;
26
28
  exports.detectSchemaVersion = require_migrate_document.detectSchemaVersion;
27
29
  exports.downloadExport = require_download_export.downloadExport;
28
30
  exports.getLayers = require_layers.getLayers;
@@ -30,9 +32,14 @@ exports.isDocumentEngineError = require_errors.isDocumentEngineError;
30
32
  exports.isSafeImageUrl = require_content_limits.isSafeImageUrl;
31
33
  exports.migrateDocument = require_migrate_document.migrateDocument;
32
34
  exports.moveToIndex = require_layers.moveToIndex;
35
+ exports.readStyleRuns = require_text_edit.readStyleRuns;
33
36
  exports.refuseUnsafeImageUrls = require_content_limits.refuseUnsafeImageUrls;
34
37
  exports.renderDocuments = require_batch_render.renderDocuments;
38
+ exports.replaceTextRange = require_text_edit.replaceTextRange;
35
39
  exports.secureDocument = require_content_limits.secureDocument;
36
40
  exports.sendBackward = require_layers.sendBackward;
37
41
  exports.sendToBack = require_layers.sendToBack;
42
+ exports.setTextRangeStyle = require_text_edit.setTextRangeStyle;
43
+ exports.shiftStyleRuns = require_text_edit.shiftStyleRuns;
38
44
  exports.validateDocument = require_validate_document.validateDocument;
45
+ exports.writeStyleRuns = require_text_edit.writeStyleRuns;
package/dist/index.d.cts CHANGED
@@ -9,7 +9,7 @@ import { ContentLimits, isSafeImageUrl, refuseUnsafeImageUrls, secureDocument }
9
9
  import { SvgImportOptions, SvgImportResult, SvgImportWarning, SvgImportWarningCode } from "./import/svg-import.cjs";
10
10
  import { NewDocumentOptions } from "./document/create-document.cjs";
11
11
  import { CustomObjectDefinition } from "./fabric/object-registry.cjs";
12
- import { HistoryOptions, HistoryState } from "./history/create-history.cjs";
12
+ import { HistoryOptions, HistoryState, TransactionOptions } from "./history/create-history.cjs";
13
13
  import { DocumentVersion, VersionKind, VersionOptions, VersionStorage, VersionSummary } from "./versions/document-version.cjs";
14
14
  import { RecoveryStore } from "./recovery/recovery-store.cjs";
15
15
  import { InterruptedLoad, RecoveryOptions, RecoveryRecord } from "./recovery/recovery-controller.cjs";
@@ -19,7 +19,7 @@ import { DocumentEngineError, DocumentEngineErrorDetails, DocumentErrorCode, Doc
19
19
  import { DocumentStorage, SaveContext, SaveResult } from "./storage/storage-contract.cjs";
20
20
  import { SaveOptions, SaveRetryEvent, SaveState, SaveStatus } from "./save/save-controller.cjs";
21
21
  import { Unsubscribe } from "./engine/event-emitter.cjs";
22
- import { DocumentEngine, DocumentEngineEvents, DocumentEngineOptions, ExportResult, ImportOptions, LoadOptions, LoadProgress, LoadStage, NewDocumentRequest, createDocumentEngine } from "./engine/create-document-engine.cjs";
22
+ import { DocumentEngine, DocumentEngineEvents, DocumentEngineOptions, ExportResult, ImportOptions, LoadOptions, LoadProgress, LoadStage, NewDocumentRequest, PageChanges, RestoreRecoveryOptions, createDocumentEngine } from "./engine/create-document-engine.cjs";
23
23
  import { validateDocument } from "./document/validate-document.cjs";
24
24
  import { KeyboardShortcutOptions, UndoRedoTarget, bindKeyboardShortcuts } from "./history/keyboard-shortcuts.cjs";
25
25
  import { UnsavedChangesSource, bindUnsavedChangesWarning } from "./save/unsaved-changes-warning.cjs";
@@ -29,4 +29,5 @@ import { Migration, MigrationContext, MigrationResult, detectSchemaVersion, migr
29
29
  import { DocumentState, DocumentStateStore, createDocumentStateStore } from "./state/document-state-store.cjs";
30
30
  import { CLIPBOARD_FORMAT, Clipboard, ClipboardContent, ClipboardOptions, PasteOptions, createClipboard } from "./commands/clipboard.cjs";
31
31
  import { LayerInfo, LayerOptions, LayerPin, bringForward, bringToFront, getLayers, moveToIndex, sendBackward, sendToBack } from "./commands/layers.cjs";
32
- export { type AssetManifest, type AssetOptions, type AssetReport, type AssetWarning, type AssetWarningCode, type AutosaveOptions, CLIPBOARD_FORMAT, CURRENT_SCHEMA_VERSION, type Clipboard, type ClipboardContent, type ClipboardOptions, type ContentLimits, type CustomObjectDefinition, type DocumentCanvas, type DocumentEngine, DocumentEngineError, type DocumentEngineErrorDetails, type DocumentEngineEvents, type DocumentEngineOptions, type DocumentErrorCode, type DocumentInfo, type DocumentIssue, type DocumentState, type DocumentStateStore, type DocumentStorage, type DocumentVersion, type DownloadableExport, type ExportArea, type ExportBackground, type ExportFormat, type ExportOptions, type ExportPreflight, type ExportProblem, type ExportProblemCode, type ExportRect, type ExportResult, type FabricDocument, type FontAsset, type FontLoader, type FontSource, type HistoryOptions, type HistoryState, type ImageAsset, type ImageFailureReason, type ImageLoadFailure, type ImportOptions, type InterruptedLoad, type KeyboardShortcutOptions, type LayerInfo, type LayerOptions, type LayerPin, type LoadOptions, type LoadProgress, type LoadStage, type Migration, type MigrationContext, type MigrationResult, type NewDocumentOptions, type NewDocumentRequest, type PasteOptions, type RecoveryOptions, type RecoveryRecord, type RecoveryStore, type RenderDocumentsOptions, type RenderedDocument, type RetryOptions, type SaveContext, type SaveOptions, type SaveResult, type SaveRetryEvent, type SaveState, type SaveStatus, type SerializedFabricObject, type SvgExportOptions, type SvgImportOptions, type SvgImportResult, type SvgImportWarning, type SvgImportWarningCode, type UndoRedoTarget, type UnsavedChangesSource, type Unsubscribe, type UploadRequest, type VersionKind, type VersionOptions, type VersionStorage, type VersionSummary, bindKeyboardShortcuts, bindUnsavedChangesWarning, bringForward, bringToFront, createClipboard, createConflictError, createDocumentEngine, createDocumentStateStore, detectSchemaVersion, downloadExport, getLayers, isDocumentEngineError, isSafeImageUrl, migrateDocument, moveToIndex, refuseUnsafeImageUrls, renderDocuments, secureDocument, sendBackward, sendToBack, validateDocument };
32
+ import { EditableTextObject, InsertedStyle, StyleRun, TextCommands, createTextCommands, readStyleRuns, replaceTextRange, setTextRangeStyle, shiftStyleRuns, writeStyleRuns } from "./commands/text-edit.cjs";
33
+ export { type AssetManifest, type AssetOptions, type AssetReport, type AssetWarning, type AssetWarningCode, type AutosaveOptions, CLIPBOARD_FORMAT, CURRENT_SCHEMA_VERSION, type Clipboard, type ClipboardContent, type ClipboardOptions, type ContentLimits, type CustomObjectDefinition, type DocumentCanvas, type DocumentEngine, DocumentEngineError, type DocumentEngineErrorDetails, type DocumentEngineEvents, type DocumentEngineOptions, type DocumentErrorCode, type DocumentInfo, type DocumentIssue, type DocumentState, type DocumentStateStore, type DocumentStorage, type DocumentVersion, type DownloadableExport, type EditableTextObject, type ExportArea, type ExportBackground, type ExportFormat, type ExportOptions, type ExportPreflight, type ExportProblem, type ExportProblemCode, type ExportRect, type ExportResult, type FabricDocument, type FontAsset, type FontLoader, type FontSource, type HistoryOptions, type HistoryState, type ImageAsset, type ImageFailureReason, type ImageLoadFailure, type ImportOptions, type InsertedStyle, type InterruptedLoad, type KeyboardShortcutOptions, type LayerInfo, type LayerOptions, type LayerPin, type LoadOptions, type LoadProgress, type LoadStage, type Migration, type MigrationContext, type MigrationResult, type NewDocumentOptions, type NewDocumentRequest, type PageChanges, type PasteOptions, type RecoveryOptions, type RecoveryRecord, type RecoveryStore, type RenderDocumentsOptions, type RenderedDocument, type RestoreRecoveryOptions, type RetryOptions, type SaveContext, type SaveOptions, type SaveResult, type SaveRetryEvent, type SaveState, type SaveStatus, type SerializedFabricObject, type StyleRun, type SvgExportOptions, type SvgImportOptions, type SvgImportResult, type SvgImportWarning, type SvgImportWarningCode, type TextCommands, type TransactionOptions, type UndoRedoTarget, type UnsavedChangesSource, type Unsubscribe, type UploadRequest, type VersionKind, type VersionOptions, type VersionStorage, type VersionSummary, bindKeyboardShortcuts, bindUnsavedChangesWarning, bringForward, bringToFront, createClipboard, createConflictError, createDocumentEngine, createDocumentStateStore, createTextCommands, detectSchemaVersion, downloadExport, getLayers, isDocumentEngineError, isSafeImageUrl, migrateDocument, moveToIndex, readStyleRuns, refuseUnsafeImageUrls, renderDocuments, replaceTextRange, secureDocument, sendBackward, sendToBack, setTextRangeStyle, shiftStyleRuns, validateDocument, writeStyleRuns };
package/dist/index.d.ts CHANGED
@@ -9,7 +9,7 @@ import { ContentLimits, isSafeImageUrl, refuseUnsafeImageUrls, secureDocument }
9
9
  import { SvgImportOptions, SvgImportResult, SvgImportWarning, SvgImportWarningCode } from "./import/svg-import.js";
10
10
  import { NewDocumentOptions } from "./document/create-document.js";
11
11
  import { CustomObjectDefinition } from "./fabric/object-registry.js";
12
- import { HistoryOptions, HistoryState } from "./history/create-history.js";
12
+ import { HistoryOptions, HistoryState, TransactionOptions } from "./history/create-history.js";
13
13
  import { DocumentVersion, VersionKind, VersionOptions, VersionStorage, VersionSummary } from "./versions/document-version.js";
14
14
  import { RecoveryStore } from "./recovery/recovery-store.js";
15
15
  import { InterruptedLoad, RecoveryOptions, RecoveryRecord } from "./recovery/recovery-controller.js";
@@ -19,7 +19,7 @@ import { DocumentEngineError, DocumentEngineErrorDetails, DocumentErrorCode, Doc
19
19
  import { DocumentStorage, SaveContext, SaveResult } from "./storage/storage-contract.js";
20
20
  import { SaveOptions, SaveRetryEvent, SaveState, SaveStatus } from "./save/save-controller.js";
21
21
  import { Unsubscribe } from "./engine/event-emitter.js";
22
- import { DocumentEngine, DocumentEngineEvents, DocumentEngineOptions, ExportResult, ImportOptions, LoadOptions, LoadProgress, LoadStage, NewDocumentRequest, createDocumentEngine } from "./engine/create-document-engine.js";
22
+ import { DocumentEngine, DocumentEngineEvents, DocumentEngineOptions, ExportResult, ImportOptions, LoadOptions, LoadProgress, LoadStage, NewDocumentRequest, PageChanges, RestoreRecoveryOptions, createDocumentEngine } from "./engine/create-document-engine.js";
23
23
  import { validateDocument } from "./document/validate-document.js";
24
24
  import { KeyboardShortcutOptions, UndoRedoTarget, bindKeyboardShortcuts } from "./history/keyboard-shortcuts.js";
25
25
  import { UnsavedChangesSource, bindUnsavedChangesWarning } from "./save/unsaved-changes-warning.js";
@@ -29,4 +29,5 @@ import { Migration, MigrationContext, MigrationResult, detectSchemaVersion, migr
29
29
  import { DocumentState, DocumentStateStore, createDocumentStateStore } from "./state/document-state-store.js";
30
30
  import { CLIPBOARD_FORMAT, Clipboard, ClipboardContent, ClipboardOptions, PasteOptions, createClipboard } from "./commands/clipboard.js";
31
31
  import { LayerInfo, LayerOptions, LayerPin, bringForward, bringToFront, getLayers, moveToIndex, sendBackward, sendToBack } from "./commands/layers.js";
32
- export { type AssetManifest, type AssetOptions, type AssetReport, type AssetWarning, type AssetWarningCode, type AutosaveOptions, CLIPBOARD_FORMAT, CURRENT_SCHEMA_VERSION, type Clipboard, type ClipboardContent, type ClipboardOptions, type ContentLimits, type CustomObjectDefinition, type DocumentCanvas, type DocumentEngine, DocumentEngineError, type DocumentEngineErrorDetails, type DocumentEngineEvents, type DocumentEngineOptions, type DocumentErrorCode, type DocumentInfo, type DocumentIssue, type DocumentState, type DocumentStateStore, type DocumentStorage, type DocumentVersion, type DownloadableExport, type ExportArea, type ExportBackground, type ExportFormat, type ExportOptions, type ExportPreflight, type ExportProblem, type ExportProblemCode, type ExportRect, type ExportResult, type FabricDocument, type FontAsset, type FontLoader, type FontSource, type HistoryOptions, type HistoryState, type ImageAsset, type ImageFailureReason, type ImageLoadFailure, type ImportOptions, type InterruptedLoad, type KeyboardShortcutOptions, type LayerInfo, type LayerOptions, type LayerPin, type LoadOptions, type LoadProgress, type LoadStage, type Migration, type MigrationContext, type MigrationResult, type NewDocumentOptions, type NewDocumentRequest, type PasteOptions, type RecoveryOptions, type RecoveryRecord, type RecoveryStore, type RenderDocumentsOptions, type RenderedDocument, type RetryOptions, type SaveContext, type SaveOptions, type SaveResult, type SaveRetryEvent, type SaveState, type SaveStatus, type SerializedFabricObject, type SvgExportOptions, type SvgImportOptions, type SvgImportResult, type SvgImportWarning, type SvgImportWarningCode, type UndoRedoTarget, type UnsavedChangesSource, type Unsubscribe, type UploadRequest, type VersionKind, type VersionOptions, type VersionStorage, type VersionSummary, bindKeyboardShortcuts, bindUnsavedChangesWarning, bringForward, bringToFront, createClipboard, createConflictError, createDocumentEngine, createDocumentStateStore, detectSchemaVersion, downloadExport, getLayers, isDocumentEngineError, isSafeImageUrl, migrateDocument, moveToIndex, refuseUnsafeImageUrls, renderDocuments, secureDocument, sendBackward, sendToBack, validateDocument };
32
+ import { EditableTextObject, InsertedStyle, StyleRun, TextCommands, createTextCommands, readStyleRuns, replaceTextRange, setTextRangeStyle, shiftStyleRuns, writeStyleRuns } from "./commands/text-edit.js";
33
+ export { type AssetManifest, type AssetOptions, type AssetReport, type AssetWarning, type AssetWarningCode, type AutosaveOptions, CLIPBOARD_FORMAT, CURRENT_SCHEMA_VERSION, type Clipboard, type ClipboardContent, type ClipboardOptions, type ContentLimits, type CustomObjectDefinition, type DocumentCanvas, type DocumentEngine, DocumentEngineError, type DocumentEngineErrorDetails, type DocumentEngineEvents, type DocumentEngineOptions, type DocumentErrorCode, type DocumentInfo, type DocumentIssue, type DocumentState, type DocumentStateStore, type DocumentStorage, type DocumentVersion, type DownloadableExport, type EditableTextObject, type ExportArea, type ExportBackground, type ExportFormat, type ExportOptions, type ExportPreflight, type ExportProblem, type ExportProblemCode, type ExportRect, type ExportResult, type FabricDocument, type FontAsset, type FontLoader, type FontSource, type HistoryOptions, type HistoryState, type ImageAsset, type ImageFailureReason, type ImageLoadFailure, type ImportOptions, type InsertedStyle, type InterruptedLoad, type KeyboardShortcutOptions, type LayerInfo, type LayerOptions, type LayerPin, type LoadOptions, type LoadProgress, type LoadStage, type Migration, type MigrationContext, type MigrationResult, type NewDocumentOptions, type NewDocumentRequest, type PageChanges, type PasteOptions, type RecoveryOptions, type RecoveryRecord, type RecoveryStore, type RenderDocumentsOptions, type RenderedDocument, type RestoreRecoveryOptions, type RetryOptions, type SaveContext, type SaveOptions, type SaveResult, type SaveRetryEvent, type SaveState, type SaveStatus, type SerializedFabricObject, type StyleRun, type SvgExportOptions, type SvgImportOptions, type SvgImportResult, type SvgImportWarning, type SvgImportWarningCode, type TextCommands, type TransactionOptions, type UndoRedoTarget, type UnsavedChangesSource, type Unsubscribe, type UploadRequest, type VersionKind, type VersionOptions, type VersionStorage, type VersionSummary, bindKeyboardShortcuts, bindUnsavedChangesWarning, bringForward, bringToFront, createClipboard, createConflictError, createDocumentEngine, createDocumentStateStore, createTextCommands, detectSchemaVersion, downloadExport, getLayers, isDocumentEngineError, isSafeImageUrl, migrateDocument, moveToIndex, readStyleRuns, refuseUnsafeImageUrls, renderDocuments, replaceTextRange, secureDocument, sendBackward, sendToBack, setTextRangeStyle, shiftStyleRuns, validateDocument, writeStyleRuns };
package/dist/index.js CHANGED
@@ -11,4 +11,5 @@ import { renderDocuments } from "./export/batch-render.js";
11
11
  import { createDocumentStateStore } from "./state/document-state-store.js";
12
12
  import { CLIPBOARD_FORMAT, createClipboard } from "./commands/clipboard.js";
13
13
  import { bringForward, bringToFront, getLayers, moveToIndex, sendBackward, sendToBack } from "./commands/layers.js";
14
- export { CLIPBOARD_FORMAT, CURRENT_SCHEMA_VERSION, DocumentEngineError, bindKeyboardShortcuts, bindUnsavedChangesWarning, bringForward, bringToFront, createClipboard, createConflictError, createDocumentEngine, createDocumentStateStore, detectSchemaVersion, downloadExport, getLayers, isDocumentEngineError, isSafeImageUrl, migrateDocument, moveToIndex, refuseUnsafeImageUrls, renderDocuments, secureDocument, sendBackward, sendToBack, validateDocument };
14
+ import { createTextCommands, readStyleRuns, replaceTextRange, setTextRangeStyle, shiftStyleRuns, writeStyleRuns } from "./commands/text-edit.js";
15
+ export { CLIPBOARD_FORMAT, CURRENT_SCHEMA_VERSION, DocumentEngineError, bindKeyboardShortcuts, bindUnsavedChangesWarning, bringForward, bringToFront, createClipboard, createConflictError, createDocumentEngine, createDocumentStateStore, createTextCommands, detectSchemaVersion, downloadExport, getLayers, isDocumentEngineError, isSafeImageUrl, migrateDocument, moveToIndex, readStyleRuns, refuseUnsafeImageUrls, renderDocuments, replaceTextRange, secureDocument, sendBackward, sendToBack, setTextRangeStyle, shiftStyleRuns, validateDocument, writeStyleRuns };
@@ -1,3 +1,4 @@
1
+ const require_page_state = require("../fabric/page-state.cjs");
1
2
  const require_errors = require("../engine/errors.cjs");
2
3
  require("../document/document-format.cjs");
3
4
  const require_ids = require("../document/ids.cjs");
@@ -19,7 +20,7 @@ function fromFabricJson(json, context) {
19
20
  canvas: {
20
21
  width: positiveNumberOr(json.width, context.canvasWidth),
21
22
  height: positiveNumberOr(json.height, context.canvasHeight),
22
- ...json.background === void 0 ? {} : { background: json.background }
23
+ ...require_page_state.pickPageFields(json)
23
24
  },
24
25
  objects: json.objects,
25
26
  metadata: { ...context.metadata }
@@ -1,3 +1,4 @@
1
+ import { pickPageFields } from "../fabric/page-state.js";
1
2
  import { DocumentEngineError } from "../engine/errors.js";
2
3
  import "../document/document-format.js";
3
4
  import { createId } from "../document/ids.js";
@@ -19,7 +20,7 @@ function fromFabricJson(json, context) {
19
20
  canvas: {
20
21
  width: positiveNumberOr(json.width, context.canvasWidth),
21
22
  height: positiveNumberOr(json.height, context.canvasHeight),
22
- ...json.background === void 0 ? {} : { background: json.background }
23
+ ...pickPageFields(json)
23
24
  },
24
25
  objects: json.objects,
25
26
  metadata: { ...context.metadata }