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
@@ -0,0 +1,336 @@
1
+ import { Orientation, orientationOf } from "./vertical-orientation.js";
2
+ import { IText, util } from "fabric";
3
+ //#region src/text/vertical-text.ts
4
+ const VERTICAL_PROPERTIES = ["textOrientation", "combineUpright"];
5
+ const UPRIGHT = 0;
6
+ const ROTATED = 1;
7
+ const SHIFTED = 2;
8
+ const COMBINED = 3;
9
+ const COMBINED_REST = 4;
10
+ const VERTICAL_KEYS = {
11
+ 9: "exitEditing",
12
+ 27: "exitEditing",
13
+ 33: "moveCursorLeft",
14
+ 34: "moveCursorRight",
15
+ 35: "moveCursorRight",
16
+ 36: "moveCursorLeft",
17
+ 37: "moveCursorDown",
18
+ 38: "moveCursorLeft",
19
+ 39: "moveCursorUp",
20
+ 40: "moveCursorRight"
21
+ };
22
+ const escapeXml = (value) => value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
23
+ const isDigit = (grapheme) => grapheme !== void 0 && /^[0-9]$/.test(grapheme);
24
+ function paint(value, ctx) {
25
+ if (typeof value === "string") return value;
26
+ return value?.toLive?.(ctx) ?? "#000";
27
+ }
28
+ var VerticalText = class VerticalText extends IText {
29
+ static getDefaults() {
30
+ return {
31
+ ...super.getDefaults(),
32
+ ...VerticalText.verticalDefaults
33
+ };
34
+ }
35
+ constructor(text, options = {}) {
36
+ super(text, {
37
+ ...VerticalText.verticalDefaults,
38
+ ...options
39
+ });
40
+ }
41
+ self() {
42
+ return this;
43
+ }
44
+ kindsOf(lineIndex) {
45
+ const line = this.self()._textLines[lineIndex] ?? [];
46
+ const kinds = new Uint8Array(line.length);
47
+ for (let index = 0; index < line.length; index += 1) {
48
+ if (this.textOrientation === "upright") {
49
+ kinds[index] = UPRIGHT;
50
+ continue;
51
+ }
52
+ const orientation = orientationOf(line[index]);
53
+ kinds[index] = orientation === Orientation.Upright ? UPRIGHT : orientation === Orientation.UprightShifted ? SHIFTED : ROTATED;
54
+ }
55
+ if (this.combineUpright === "digits2") for (let index = 0; index < line.length;) {
56
+ if (!isDigit(line[index])) {
57
+ index += 1;
58
+ continue;
59
+ }
60
+ let end = index;
61
+ while (isDigit(line[end])) end += 1;
62
+ if (end - index <= 2) {
63
+ kinds[index] = COMBINED;
64
+ for (let rest = index + 1; rest < end; rest += 1) kinds[rest] = COMBINED_REST;
65
+ }
66
+ index = end;
67
+ }
68
+ return kinds;
69
+ }
70
+ kindAt(lineIndex, charIndex) {
71
+ return this.glyphKinds?.[lineIndex]?.[charIndex] ?? ROTATED;
72
+ }
73
+ _measureLine(lineIndex) {
74
+ this.glyphKinds ?? (this.glyphKinds = []);
75
+ this.glyphKinds[lineIndex] = this.kindsOf(lineIndex);
76
+ return super._measureLine(lineIndex);
77
+ }
78
+ _getGraphemeBox(grapheme, lineIndex, charIndex, previous, skipLeft) {
79
+ const kind = this.kindAt(lineIndex, charIndex);
80
+ const previousTurns = charIndex > 0 && this.kindAt(lineIndex, charIndex - 1) === ROTATED;
81
+ const box = super._getGraphemeBox(grapheme, lineIndex, charIndex, kind === ROTATED && previousTurns ? previous : void 0, true);
82
+ if (kind !== ROTATED) {
83
+ const spacing = this.self().charSpacing !== 0 ? this.self()._getWidthOfCharSpacing() : 0;
84
+ box.width = box.kernedWidth = kind === COMBINED_REST ? 0 : box.height + spacing;
85
+ }
86
+ if (!skipLeft && charIndex > 0) {
87
+ const before = this.self().__charBounds[lineIndex][charIndex - 1];
88
+ box.left = before.left + before.width + box.kernedWidth - box.width;
89
+ }
90
+ return box;
91
+ }
92
+ initDimensions() {
93
+ super.initDimensions();
94
+ const along = this.height;
95
+ this.height = this.width;
96
+ this.width = along;
97
+ }
98
+ _getLineLeftOffset(lineIndex) {
99
+ const free = this.height - this.getLineWidth(lineIndex);
100
+ if (this.textAlign.includes("center")) return free / 2;
101
+ if (this.textAlign.endsWith("right")) return free;
102
+ return 0;
103
+ }
104
+ column(lineIndex) {
105
+ let right = this.width / 2;
106
+ for (let index = 0; index < lineIndex; index += 1) right -= this.getHeightOfLine(index);
107
+ const thickness = this.getHeightOfLine(lineIndex);
108
+ return {
109
+ right,
110
+ em: thickness / this.lineHeight,
111
+ thickness,
112
+ top: -this.height / 2 + this._getLineLeftOffset(lineIndex)
113
+ };
114
+ }
115
+ _render(ctx) {
116
+ const self = this.self();
117
+ const fraction = self._fontSizeFraction;
118
+ ctx.save();
119
+ for (let line = 0; line < self._textLines.length; line += 1) {
120
+ const graphemes = self._textLines[line];
121
+ const bounds = self.__charBounds[line] ?? [];
122
+ const { right, em, top } = this.column(line);
123
+ const center = right - em / 2;
124
+ let index = 0;
125
+ while (index < graphemes.length) {
126
+ const kind = this.kindAt(line, index);
127
+ const style = this.getCompleteStyleDeclaration(line, index);
128
+ const y = top + bounds[index].left;
129
+ let end = index + 1;
130
+ if (kind === ROTATED) while (end < graphemes.length && this.kindAt(line, end) === ROTATED && !util.hasStyleChanged(style, this.getCompleteStyleDeclaration(line, end), false)) end += 1;
131
+ else if (kind === COMBINED) while (end < graphemes.length && this.kindAt(line, end) === COMBINED_REST) end += 1;
132
+ const text = graphemes.slice(index, end).join("");
133
+ const advance = top + bounds[end - 1].left + bounds[end - 1].width - y;
134
+ this.drawBackgroundAndLines(ctx, style, right, em, y, advance);
135
+ if (text.trim() !== "") {
136
+ ctx.font = self._getFontDeclaration(style);
137
+ ctx.fillStyle = paint(style.fill, ctx);
138
+ ctx.textBaseline = "alphabetic";
139
+ const baseline = (.5 - fraction) * style.fontSize;
140
+ ctx.save();
141
+ if (kind === ROTATED) {
142
+ ctx.textAlign = "left";
143
+ ctx.translate(center, y);
144
+ ctx.rotate(Math.PI / 2);
145
+ this.drawGlyphs(ctx, style, text, 0, baseline);
146
+ } else {
147
+ ctx.textAlign = "center";
148
+ let x = center;
149
+ let glyphY = y + style.fontSize / 2 + baseline;
150
+ if (kind === SHIFTED) {
151
+ x += style.fontSize / 2;
152
+ glyphY -= style.fontSize / 2;
153
+ }
154
+ if (kind === COMBINED) {
155
+ const width = ctx.measureText(text).width;
156
+ const squeeze = Math.min(1, style.fontSize * .95 / width);
157
+ ctx.translate(x, glyphY);
158
+ ctx.scale(squeeze, 1);
159
+ x = 0;
160
+ glyphY = 0;
161
+ }
162
+ this.drawGlyphs(ctx, style, text, x, glyphY);
163
+ }
164
+ ctx.restore();
165
+ }
166
+ index = end;
167
+ }
168
+ }
169
+ ctx.restore();
170
+ }
171
+ drawGlyphs(ctx, style, text, x, y) {
172
+ ctx.fillText(text, x, y);
173
+ if (style.stroke && style.strokeWidth) {
174
+ ctx.strokeStyle = paint(style.stroke, ctx);
175
+ ctx.lineWidth = style.strokeWidth;
176
+ ctx.strokeText(text, x, y);
177
+ }
178
+ }
179
+ drawBackgroundAndLines(ctx, style, right, em, y, advance) {
180
+ if (style.textBackgroundColor) {
181
+ ctx.fillStyle = paint(style.textBackgroundColor, ctx);
182
+ ctx.fillRect(right - em, y, em, advance);
183
+ }
184
+ const thickness = style.fontSize / 15;
185
+ ctx.fillStyle = paint(style.textDecorationColor || style.fill, ctx);
186
+ if (style.underline) ctx.fillRect(right - thickness, y, thickness, advance);
187
+ if (style.overline) ctx.fillRect(right - em, y, thickness, advance);
188
+ if (style.linethrough) ctx.fillRect(right - em / 2 - thickness / 2, y, thickness, advance);
189
+ }
190
+ cursorPoint(index) {
191
+ const { lineIndex, charIndex } = this.get2DCursorLocation(index);
192
+ const { right, em, top } = this.column(lineIndex);
193
+ const bounds = this.self().__charBounds[lineIndex] ?? [];
194
+ return {
195
+ x: right - em,
196
+ y: top + (bounds[charIndex]?.left ?? 0),
197
+ width: em,
198
+ line: lineIndex,
199
+ char: charIndex
200
+ };
201
+ }
202
+ _getCursorBoundaries(index = this.selectionStart) {
203
+ const point = this.cursorPoint(index);
204
+ const charHeight = this.getValueOfPropertyAt(point.line, Math.max(0, point.char - 1), "fontSize") * this.lineHeight;
205
+ return {
206
+ left: point.x,
207
+ top: point.y - charHeight,
208
+ leftOffset: 0,
209
+ topOffset: 0
210
+ };
211
+ }
212
+ _renderCursor(ctx, _boundaries, selectionStart) {
213
+ const point = this.cursorPoint(selectionStart);
214
+ const scale = this.getObjectScaling().y * (this.canvas?.getZoom() ?? 1);
215
+ const thickness = this.cursorWidth / scale;
216
+ ctx.fillStyle = this.cursorColor || this.getValueOfPropertyAt(point.line, Math.max(0, point.char - 1), "fill");
217
+ ctx.globalAlpha = this.self()._currentCursorOpacity;
218
+ ctx.fillRect(point.x, point.y - thickness / 2, point.width, thickness);
219
+ }
220
+ _renderSelection(ctx, selection) {
221
+ const start = this.get2DCursorLocation(selection.selectionStart);
222
+ const end = this.get2DCursorLocation(selection.selectionEnd);
223
+ const charBounds = this.self().__charBounds;
224
+ const composing = Boolean(this.inCompositionMode);
225
+ ctx.fillStyle = composing ? this.cursorColor || "#000" : this.selectionColor;
226
+ for (let line = start.lineIndex; line <= end.lineIndex; line += 1) {
227
+ const { right, em, thickness, top } = this.column(line);
228
+ const from = line === start.lineIndex ? charBounds[line]?.[start.charIndex]?.left ?? 0 : 0;
229
+ const to = line === end.lineIndex ? charBounds[line]?.[end.charIndex]?.left ?? 0 : this.getLineWidth(line) || em / 4;
230
+ if (composing) ctx.fillRect(right - 1, top + from, 1, to - from);
231
+ else ctx.fillRect(right - (line === end.lineIndex ? em : thickness), top + from, line === end.lineIndex ? em : thickness, to - from);
232
+ }
233
+ }
234
+ getSelectionStartFromPointer(event) {
235
+ const point = this.canvas.getScenePoint(event).transform(util.invertTransform(this.calcTransformMatrix()));
236
+ const lines = this.self()._textLines;
237
+ let fromRight = this.width / 2 - point.x;
238
+ let line = 0;
239
+ while (line < lines.length - 1 && fromRight > this.getHeightOfLine(line)) {
240
+ fromRight -= this.getHeightOfLine(line);
241
+ line += 1;
242
+ }
243
+ const bounds = this.self().__charBounds[line] ?? [];
244
+ const length = lines[line].length;
245
+ const y = point.y - this.column(line).top;
246
+ let low = 0;
247
+ let high = length;
248
+ while (low < high) {
249
+ const middle = low + high + 1 >> 1;
250
+ const box = bounds[middle - 1];
251
+ if (box.left + box.width / 2 <= y) low = middle;
252
+ else high = middle - 1;
253
+ }
254
+ let index = low;
255
+ for (let previous = 0; previous < line; previous += 1) index += lines[previous].length + 1;
256
+ return Math.min(index, this._text.length);
257
+ }
258
+ _toSVG() {
259
+ const self = this.self();
260
+ const fraction = self._fontSizeFraction;
261
+ const parts = [];
262
+ const number = (value) => String(Math.round(value * 1e3) / 1e3);
263
+ for (let line = 0; line < self._textLines.length; line += 1) {
264
+ const graphemes = self._textLines[line];
265
+ const bounds = self.__charBounds[line] ?? [];
266
+ const { right, em, top } = this.column(line);
267
+ const center = right - em / 2;
268
+ let index = 0;
269
+ while (index < graphemes.length) {
270
+ const kind = this.kindAt(line, index);
271
+ const style = this.getCompleteStyleDeclaration(line, index);
272
+ const y = top + bounds[index].left;
273
+ let end = index + 1;
274
+ if (kind === ROTATED) while (end < graphemes.length && this.kindAt(line, end) === ROTATED && !util.hasStyleChanged(style, this.getCompleteStyleDeclaration(line, end), false)) end += 1;
275
+ else if (kind === COMBINED) while (end < graphemes.length && this.kindAt(line, end) === COMBINED_REST) end += 1;
276
+ const text = graphemes.slice(index, end).join("");
277
+ const advance = top + bounds[end - 1].left + bounds[end - 1].width - y;
278
+ const fill = typeof style.fill === "string" ? style.fill : "#000";
279
+ if (typeof style.textBackgroundColor === "string" && style.textBackgroundColor) parts.push(`<rect x="${number(right - em)}" y="${number(y)}" width="${number(em)}" height="${number(advance)}" fill="${escapeXml(style.textBackgroundColor)}" />\n`);
280
+ const thickness = style.fontSize / 15;
281
+ const lineColor = typeof (style.textDecorationColor || style.fill) === "string" ? style.textDecorationColor || style.fill : "#000";
282
+ for (const [on, x] of [
283
+ [style.underline, right - thickness],
284
+ [style.overline, right - em],
285
+ [style.linethrough, right - em / 2 - thickness / 2]
286
+ ]) if (on) parts.push(`<rect x="${number(x)}" y="${number(y)}" width="${number(thickness)}" height="${number(advance)}" fill="${escapeXml(lineColor)}" />\n`);
287
+ if (text.trim() !== "") {
288
+ const family = String(style.fontFamily ?? this.fontFamily);
289
+ const quoted = /^['"]|,/.test(family) ? family : `'${family}'`;
290
+ const stroke = style.stroke && style.strokeWidth && typeof style.stroke === "string" ? ` stroke="${escapeXml(style.stroke)}" stroke-width="${style.strokeWidth}"` : "";
291
+ const font = `font-family="${escapeXml(quoted)}" font-size="${number(style.fontSize)}" font-style="${style.fontStyle ?? "normal"}" font-weight="${style.fontWeight ?? "normal"}" fill="${escapeXml(fill)}"${stroke}`;
292
+ const baseline = (.5 - fraction) * style.fontSize;
293
+ if (kind === ROTATED) parts.push(`<text xml:space="preserve" transform="translate(${number(center)} ${number(y)}) rotate(90)" x="0" y="${number(baseline)}" ${font}>${escapeXml(text)}</text>\n`);
294
+ else {
295
+ let x = center;
296
+ let glyphY = y + style.fontSize / 2 + baseline;
297
+ if (kind === SHIFTED) {
298
+ x += style.fontSize / 2;
299
+ glyphY -= style.fontSize / 2;
300
+ }
301
+ let transform = "";
302
+ if (kind === COMBINED) {
303
+ const context = util.createCanvasElement().getContext("2d");
304
+ context.font = self._getFontDeclaration(style);
305
+ const squeeze = Math.min(1, style.fontSize * .95 / context.measureText(text).width);
306
+ transform = ` transform="translate(${number(x)} ${number(glyphY)}) scale(${number(squeeze)} 1)"`;
307
+ x = 0;
308
+ glyphY = 0;
309
+ }
310
+ parts.push(`<text xml:space="preserve"${transform} x="${number(x)}" y="${number(glyphY)}" text-anchor="middle" ${font}>${escapeXml(text)}</text>\n`);
311
+ }
312
+ }
313
+ index = end;
314
+ }
315
+ }
316
+ return [
317
+ "<g>\n",
318
+ ...parts,
319
+ "</g>\n"
320
+ ];
321
+ }
322
+ toObject(propertiesToInclude = []) {
323
+ return super.toObject([...VERTICAL_PROPERTIES, ...propertiesToInclude]);
324
+ }
325
+ };
326
+ VerticalText.type = "VerticalText";
327
+ VerticalText.textLayoutProperties = [...IText.textLayoutProperties, ...VERTICAL_PROPERTIES];
328
+ VerticalText.cacheProperties = [...IText.cacheProperties, ...VERTICAL_PROPERTIES];
329
+ VerticalText.verticalDefaults = {
330
+ textOrientation: "mixed",
331
+ combineUpright: "none",
332
+ keysMap: VERTICAL_KEYS,
333
+ keysMapRtl: VERTICAL_KEYS
334
+ };
335
+ //#endregion
336
+ export { VerticalText };
package/dist/text.cjs ADDED
@@ -0,0 +1,21 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_shaping = require("./text/shaping.cjs");
3
+ const require_bounded_textbox = require("./text/bounded-textbox.cjs");
4
+ const require_vertical_orientation = require("./text/vertical-orientation.cjs");
5
+ const require_vertical_text = require("./text/vertical-text.cjs");
6
+ const require_register = require("./text/register.cjs");
7
+ const require_mobile_input = require("./text/mobile-input.cjs");
8
+ exports.BoundedTextbox = require_bounded_textbox.BoundedTextbox;
9
+ exports.Orientation = require_vertical_orientation.Orientation;
10
+ exports.ShapedIText = require_shaping.ShapedIText;
11
+ exports.ShapedTextbox = require_shaping.ShapedTextbox;
12
+ exports.VerticalText = require_vertical_text.VerticalText;
13
+ exports.attachMobileTextInput = require_mobile_input.attachMobileTextInput;
14
+ exports.drawsJoinedRuns = require_shaping.drawsJoinedRuns;
15
+ exports.findTextEdit = require_mobile_input.findTextEdit;
16
+ exports.orientationOf = require_vertical_orientation.orientationOf;
17
+ exports.orientationOfCodePoint = require_vertical_orientation.orientationOfCodePoint;
18
+ exports.registerTextObjects = require_register.registerTextObjects;
19
+ exports.shapeLine = require_shaping.shapeLine;
20
+ exports.shapeWord = require_shaping.shapeWord;
21
+ exports.textObjects = require_register.textObjects;
@@ -0,0 +1,7 @@
1
+ import { BoundedTextbox, BoundedTextboxProps, BreakWords, TextFit, TextOverflow } from "./text/bounded-textbox.cjs";
2
+ import { registerTextObjects, textObjects } from "./text/register.cjs";
3
+ import { AnyText, ShapedIText, ShapedTextbox, drawsJoinedRuns, shapeLine, shapeWord } from "./text/shaping.cjs";
4
+ import { MobileTextInput, MobileTextInputOptions, attachMobileTextInput, findTextEdit } from "./text/mobile-input.cjs";
5
+ import { CombineUpright, TextOrientation, VerticalText, VerticalTextProps } from "./text/vertical-text.cjs";
6
+ import { Orientation, orientationOf, orientationOfCodePoint } from "./text/vertical-orientation.cjs";
7
+ export { type AnyText, BoundedTextbox, type BoundedTextboxProps, type BreakWords, type CombineUpright, type MobileTextInput, type MobileTextInputOptions, Orientation, ShapedIText, ShapedTextbox, type TextFit, type TextOrientation, type TextOverflow, VerticalText, type VerticalTextProps, attachMobileTextInput, drawsJoinedRuns, findTextEdit, orientationOf, orientationOfCodePoint, registerTextObjects, shapeLine, shapeWord, textObjects };
package/dist/text.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ import { BoundedTextbox, BoundedTextboxProps, BreakWords, TextFit, TextOverflow } from "./text/bounded-textbox.js";
2
+ import { registerTextObjects, textObjects } from "./text/register.js";
3
+ import { AnyText, ShapedIText, ShapedTextbox, drawsJoinedRuns, shapeLine, shapeWord } from "./text/shaping.js";
4
+ import { MobileTextInput, MobileTextInputOptions, attachMobileTextInput, findTextEdit } from "./text/mobile-input.js";
5
+ import { CombineUpright, TextOrientation, VerticalText, VerticalTextProps } from "./text/vertical-text.js";
6
+ import { Orientation, orientationOf, orientationOfCodePoint } from "./text/vertical-orientation.js";
7
+ export { type AnyText, BoundedTextbox, type BoundedTextboxProps, type BreakWords, type CombineUpright, type MobileTextInput, type MobileTextInputOptions, Orientation, ShapedIText, ShapedTextbox, type TextFit, type TextOrientation, type TextOverflow, VerticalText, type VerticalTextProps, attachMobileTextInput, drawsJoinedRuns, findTextEdit, orientationOf, orientationOfCodePoint, registerTextObjects, shapeLine, shapeWord, textObjects };
package/dist/text.js ADDED
@@ -0,0 +1,7 @@
1
+ import { ShapedIText, ShapedTextbox, drawsJoinedRuns, shapeLine, shapeWord } from "./text/shaping.js";
2
+ import { BoundedTextbox } from "./text/bounded-textbox.js";
3
+ import { Orientation, orientationOf, orientationOfCodePoint } from "./text/vertical-orientation.js";
4
+ import { VerticalText } from "./text/vertical-text.js";
5
+ import { registerTextObjects, textObjects } from "./text/register.js";
6
+ import { attachMobileTextInput, findTextEdit } from "./text/mobile-input.js";
7
+ export { BoundedTextbox, Orientation, ShapedIText, ShapedTextbox, VerticalText, attachMobileTextInput, drawsJoinedRuns, findTextEdit, orientationOf, orientationOfCodePoint, registerTextObjects, shapeLine, shapeWord, textObjects };
@@ -17,10 +17,23 @@ async function mapWithConcurrency(items, limit, work) {
17
17
  await Promise.all(Array.from({ length: workers }, runWorker));
18
18
  return results;
19
19
  }
20
- /** Lets the browser paint and handle input before the next piece of work. */
20
+ /**
21
+ * Lets the browser paint, handle input and run other queued work, such as a
22
+ * framework's re-render after a progress update, before the next piece of
23
+ * work. A message-channel task runs after the tasks already queued and,
24
+ * unlike `setTimeout`, is not delayed by timer clamping. `scheduler.yield()`
25
+ * is not used: it resumes ahead of other queued tasks, so a UI waiting to
26
+ * show progress would not render until the work had finished.
27
+ */
21
28
  function yieldToEventLoop() {
22
- const scheduler = globalThis.scheduler;
23
- if (typeof scheduler?.yield === "function") return scheduler.yield();
29
+ if (typeof MessageChannel === "function") return new Promise((resolve) => {
30
+ const channel = new MessageChannel();
31
+ channel.port1.onmessage = () => {
32
+ channel.port1.close();
33
+ resolve();
34
+ };
35
+ channel.port2.postMessage(void 0);
36
+ });
24
37
  return new Promise((resolve) => setTimeout(resolve, 0));
25
38
  }
26
39
  //#endregion
@@ -17,10 +17,23 @@ async function mapWithConcurrency(items, limit, work) {
17
17
  await Promise.all(Array.from({ length: workers }, runWorker));
18
18
  return results;
19
19
  }
20
- /** Lets the browser paint and handle input before the next piece of work. */
20
+ /**
21
+ * Lets the browser paint, handle input and run other queued work, such as a
22
+ * framework's re-render after a progress update, before the next piece of
23
+ * work. A message-channel task runs after the tasks already queued and,
24
+ * unlike `setTimeout`, is not delayed by timer clamping. `scheduler.yield()`
25
+ * is not used: it resumes ahead of other queued tasks, so a UI waiting to
26
+ * show progress would not render until the work had finished.
27
+ */
21
28
  function yieldToEventLoop() {
22
- const scheduler = globalThis.scheduler;
23
- if (typeof scheduler?.yield === "function") return scheduler.yield();
29
+ if (typeof MessageChannel === "function") return new Promise((resolve) => {
30
+ const channel = new MessageChannel();
31
+ channel.port1.onmessage = () => {
32
+ channel.port1.close();
33
+ resolve();
34
+ };
35
+ channel.port2.postMessage(void 0);
36
+ });
24
37
  return new Promise((resolve) => setTimeout(resolve, 0));
25
38
  }
26
39
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fabricjs-document-engine",
3
- "version": "1.1.0",
3
+ "version": "1.3.0",
4
4
  "description": "Fabric.js save and load, undo and redo, and autosave for an existing canvas: stable object ids, custom objects, copy and paste, SVG import, PNG, SVG and PDF export, and recovery.",
5
5
  "keywords": [
6
6
  "fabricjs",
@@ -107,6 +107,36 @@
107
107
  "default": "./dist/pdf.cjs"
108
108
  }
109
109
  },
110
+ "./text": {
111
+ "import": {
112
+ "types": "./dist/text.d.ts",
113
+ "default": "./dist/text.js"
114
+ },
115
+ "require": {
116
+ "types": "./dist/text.d.cts",
117
+ "default": "./dist/text.cjs"
118
+ }
119
+ },
120
+ "./performance": {
121
+ "import": {
122
+ "types": "./dist/performance.d.ts",
123
+ "default": "./dist/performance.js"
124
+ },
125
+ "require": {
126
+ "types": "./dist/performance.d.cts",
127
+ "default": "./dist/performance.cjs"
128
+ }
129
+ },
130
+ "./filters": {
131
+ "import": {
132
+ "types": "./dist/filters.d.ts",
133
+ "default": "./dist/filters.js"
134
+ },
135
+ "require": {
136
+ "types": "./dist/filters.d.cts",
137
+ "default": "./dist/filters.cjs"
138
+ }
139
+ },
110
140
  "./schema/document-v1.json": "./schema/document-v1.schema.json",
111
141
  "./package.json": "./package.json"
112
142
  },
@@ -18,7 +18,11 @@
18
18
  "properties": {
19
19
  "width": { "type": "number", "exclusiveMinimum": 0 },
20
20
  "height": { "type": "number", "exclusiveMinimum": 0 },
21
- "background": {}
21
+ "background": {},
22
+ "backgroundImage": { "$ref": "#/$defs/fabricObject" },
23
+ "overlay": {},
24
+ "overlayImage": { "$ref": "#/$defs/fabricObject" },
25
+ "clipPath": { "$ref": "#/$defs/fabricObject" }
22
26
  }
23
27
  },
24
28
  "objects": { "type": "array", "items": { "$ref": "#/$defs/fabricObject" } },