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
+ const require_vertical_orientation = require("./vertical-orientation.cjs");
2
+ let fabric = require("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 fabric.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 = require_vertical_orientation.orientationOf(line[index]);
53
+ kinds[index] = orientation === require_vertical_orientation.Orientation.Upright ? UPRIGHT : orientation === require_vertical_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 && !fabric.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(fabric.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 && !fabric.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 = fabric.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 = [...fabric.IText.textLayoutProperties, ...VERTICAL_PROPERTIES];
328
+ VerticalText.cacheProperties = [...fabric.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
+ exports.VerticalText = VerticalText;
@@ -0,0 +1,54 @@
1
+ import { IText, TPointerEvent } from "fabric";
2
+ //#region src/text/vertical-text.d.ts
3
+ export type TextOrientation = "mixed" | "upright";
4
+ export type CombineUpright = "none" | "digits2";
5
+ export interface VerticalTextProps {
6
+ textOrientation: TextOrientation;
7
+ combineUpright: CombineUpright;
8
+ }
9
+ type Box = {
10
+ left: number;
11
+ width: number;
12
+ kernedWidth: number;
13
+ height: number;
14
+ deltaY: number;
15
+ };
16
+ export declare class VerticalText extends IText {
17
+ static override type: string;
18
+ static override textLayoutProperties: string[];
19
+ static override cacheProperties: string[];
20
+ static verticalDefaults: VerticalTextProps & {
21
+ keysMap: Record<number, string>;
22
+ keysMapRtl: Record<number, string>;
23
+ };
24
+ static override getDefaults(): Record<string, unknown>;
25
+ textOrientation: TextOrientation;
26
+ combineUpright: CombineUpright;
27
+ private glyphKinds;
28
+ constructor(text: string, options?: Partial<VerticalTextProps> & ConstructorParameters<typeof IText>[1]);
29
+ private self;
30
+ private kindsOf;
31
+ private kindAt;
32
+ override _measureLine(lineIndex: number): {
33
+ width: number;
34
+ numOfSpaces: number;
35
+ };
36
+ override _getGraphemeBox(grapheme: string, lineIndex: number, charIndex: number, previous?: string, skipLeft?: boolean): Box;
37
+ override initDimensions(): void;
38
+ override _getLineLeftOffset(lineIndex: number): number;
39
+ private column;
40
+ override _render(ctx: CanvasRenderingContext2D): void;
41
+ private drawGlyphs;
42
+ private drawBackgroundAndLines;
43
+ private cursorPoint;
44
+ override _getCursorBoundaries(index?: number): ReturnType<IText["_getCursorBoundaries"]>;
45
+ override _renderCursor(ctx: CanvasRenderingContext2D, _boundaries: unknown, selectionStart: number): void;
46
+ override _renderSelection(ctx: CanvasRenderingContext2D, selection: {
47
+ selectionStart: number;
48
+ selectionEnd: number;
49
+ }): void;
50
+ override getSelectionStartFromPointer(event: TPointerEvent): number;
51
+ override _toSVG(): string[];
52
+ override toObject(propertiesToInclude?: PropertyKey[]): any;
53
+ }
54
+ //#endregion
@@ -0,0 +1,54 @@
1
+ import { IText, TPointerEvent } from "fabric";
2
+ //#region src/text/vertical-text.d.ts
3
+ export type TextOrientation = "mixed" | "upright";
4
+ export type CombineUpright = "none" | "digits2";
5
+ export interface VerticalTextProps {
6
+ textOrientation: TextOrientation;
7
+ combineUpright: CombineUpright;
8
+ }
9
+ type Box = {
10
+ left: number;
11
+ width: number;
12
+ kernedWidth: number;
13
+ height: number;
14
+ deltaY: number;
15
+ };
16
+ export declare class VerticalText extends IText {
17
+ static override type: string;
18
+ static override textLayoutProperties: string[];
19
+ static override cacheProperties: string[];
20
+ static verticalDefaults: VerticalTextProps & {
21
+ keysMap: Record<number, string>;
22
+ keysMapRtl: Record<number, string>;
23
+ };
24
+ static override getDefaults(): Record<string, unknown>;
25
+ textOrientation: TextOrientation;
26
+ combineUpright: CombineUpright;
27
+ private glyphKinds;
28
+ constructor(text: string, options?: Partial<VerticalTextProps> & ConstructorParameters<typeof IText>[1]);
29
+ private self;
30
+ private kindsOf;
31
+ private kindAt;
32
+ override _measureLine(lineIndex: number): {
33
+ width: number;
34
+ numOfSpaces: number;
35
+ };
36
+ override _getGraphemeBox(grapheme: string, lineIndex: number, charIndex: number, previous?: string, skipLeft?: boolean): Box;
37
+ override initDimensions(): void;
38
+ override _getLineLeftOffset(lineIndex: number): number;
39
+ private column;
40
+ override _render(ctx: CanvasRenderingContext2D): void;
41
+ private drawGlyphs;
42
+ private drawBackgroundAndLines;
43
+ private cursorPoint;
44
+ override _getCursorBoundaries(index?: number): ReturnType<IText["_getCursorBoundaries"]>;
45
+ override _renderCursor(ctx: CanvasRenderingContext2D, _boundaries: unknown, selectionStart: number): void;
46
+ override _renderSelection(ctx: CanvasRenderingContext2D, selection: {
47
+ selectionStart: number;
48
+ selectionEnd: number;
49
+ }): void;
50
+ override getSelectionStartFromPointer(event: TPointerEvent): number;
51
+ override _toSVG(): string[];
52
+ override toObject(propertiesToInclude?: PropertyKey[]): any;
53
+ }
54
+ //#endregion