@nasser-sw/fabric 7.0.1-beta1 → 7.0.1-beta10

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 (181) hide show
  1. package/0 +0 -0
  2. package/debug/{konva → konva-master}/CHANGELOG.md +2 -1
  3. package/debug/{konva → konva-master}/README.md +7 -3
  4. package/debug/{konva → konva-master}/package.json +1 -1
  5. package/debug/{konva → konva-master}/release.sh +1 -4
  6. package/debug/{konva → konva-master}/src/Canvas.ts +37 -0
  7. package/debug/{konva → konva-master}/src/shapes/Text.ts +2 -2
  8. package/dist/index.js +1853 -288
  9. package/dist/index.js.map +1 -1
  10. package/dist/index.min.js +1 -1
  11. package/dist/index.min.js.map +1 -1
  12. package/dist/index.min.mjs +1 -1
  13. package/dist/index.min.mjs.map +1 -1
  14. package/dist/index.mjs +1853 -288
  15. package/dist/index.mjs.map +1 -1
  16. package/dist/index.node.cjs +1853 -288
  17. package/dist/index.node.cjs.map +1 -1
  18. package/dist/index.node.mjs +1853 -288
  19. package/dist/index.node.mjs.map +1 -1
  20. package/dist/package.json.min.mjs +1 -1
  21. package/dist/package.json.mjs +1 -1
  22. package/dist/src/shapes/Line.d.ts +33 -86
  23. package/dist/src/shapes/Line.d.ts.map +1 -1
  24. package/dist/src/shapes/Line.min.mjs +1 -1
  25. package/dist/src/shapes/Line.min.mjs.map +1 -1
  26. package/dist/src/shapes/Line.mjs +405 -159
  27. package/dist/src/shapes/Line.mjs.map +1 -1
  28. package/dist/src/shapes/Polyline.d.ts +7 -0
  29. package/dist/src/shapes/Polyline.d.ts.map +1 -1
  30. package/dist/src/shapes/Polyline.min.mjs +1 -1
  31. package/dist/src/shapes/Polyline.min.mjs.map +1 -1
  32. package/dist/src/shapes/Polyline.mjs +48 -16
  33. package/dist/src/shapes/Polyline.mjs.map +1 -1
  34. package/dist/src/shapes/Text/Text.d.ts +19 -0
  35. package/dist/src/shapes/Text/Text.d.ts.map +1 -1
  36. package/dist/src/shapes/Text/Text.min.mjs +1 -1
  37. package/dist/src/shapes/Text/Text.min.mjs.map +1 -1
  38. package/dist/src/shapes/Text/Text.mjs +302 -16
  39. package/dist/src/shapes/Text/Text.mjs.map +1 -1
  40. package/dist/src/shapes/Textbox.d.ts +43 -1
  41. package/dist/src/shapes/Textbox.d.ts.map +1 -1
  42. package/dist/src/shapes/Textbox.min.mjs +1 -1
  43. package/dist/src/shapes/Textbox.min.mjs.map +1 -1
  44. package/dist/src/shapes/Textbox.mjs +521 -67
  45. package/dist/src/shapes/Textbox.mjs.map +1 -1
  46. package/dist/src/shapes/Triangle.d.ts +27 -2
  47. package/dist/src/shapes/Triangle.d.ts.map +1 -1
  48. package/dist/src/shapes/Triangle.min.mjs +1 -1
  49. package/dist/src/shapes/Triangle.min.mjs.map +1 -1
  50. package/dist/src/shapes/Triangle.mjs +72 -12
  51. package/dist/src/shapes/Triangle.mjs.map +1 -1
  52. package/dist/src/text/examples/arabicTextExample.d.ts +60 -0
  53. package/dist/src/text/examples/arabicTextExample.d.ts.map +1 -0
  54. package/dist/src/text/measure.d.ts +9 -0
  55. package/dist/src/text/measure.d.ts.map +1 -1
  56. package/dist/src/text/measure.min.mjs +1 -1
  57. package/dist/src/text/measure.min.mjs.map +1 -1
  58. package/dist/src/text/measure.mjs +175 -4
  59. package/dist/src/text/measure.mjs.map +1 -1
  60. package/dist/src/text/overlayEditor.d.ts.map +1 -1
  61. package/dist/src/text/overlayEditor.min.mjs +1 -1
  62. package/dist/src/text/overlayEditor.min.mjs.map +1 -1
  63. package/dist/src/text/overlayEditor.mjs +155 -9
  64. package/dist/src/text/overlayEditor.mjs.map +1 -1
  65. package/dist/src/text/scriptUtils.d.ts +142 -0
  66. package/dist/src/text/scriptUtils.d.ts.map +1 -0
  67. package/dist/src/text/scriptUtils.min.mjs +2 -0
  68. package/dist/src/text/scriptUtils.min.mjs.map +1 -0
  69. package/dist/src/text/scriptUtils.mjs +212 -0
  70. package/dist/src/text/scriptUtils.mjs.map +1 -0
  71. package/dist/src/util/misc/cornerRadius.d.ts +70 -0
  72. package/dist/src/util/misc/cornerRadius.d.ts.map +1 -0
  73. package/dist/src/util/misc/cornerRadius.min.mjs +2 -0
  74. package/dist/src/util/misc/cornerRadius.min.mjs.map +1 -0
  75. package/dist/src/util/misc/cornerRadius.mjs +181 -0
  76. package/dist/src/util/misc/cornerRadius.mjs.map +1 -0
  77. package/dist-extensions/src/shapes/CustomLine.d.ts +10 -0
  78. package/dist-extensions/src/shapes/CustomLine.d.ts.map +1 -0
  79. package/dist-extensions/src/shapes/Line.d.ts +33 -86
  80. package/dist-extensions/src/shapes/Line.d.ts.map +1 -1
  81. package/dist-extensions/src/shapes/Polyline.d.ts +7 -0
  82. package/dist-extensions/src/shapes/Polyline.d.ts.map +1 -1
  83. package/dist-extensions/src/shapes/Text/Text.d.ts +19 -0
  84. package/dist-extensions/src/shapes/Text/Text.d.ts.map +1 -1
  85. package/dist-extensions/src/shapes/Textbox.d.ts +43 -1
  86. package/dist-extensions/src/shapes/Textbox.d.ts.map +1 -1
  87. package/dist-extensions/src/shapes/Triangle.d.ts +27 -2
  88. package/dist-extensions/src/shapes/Triangle.d.ts.map +1 -1
  89. package/dist-extensions/src/text/measure.d.ts +9 -0
  90. package/dist-extensions/src/text/measure.d.ts.map +1 -1
  91. package/dist-extensions/src/text/overlayEditor.d.ts.map +1 -1
  92. package/dist-extensions/src/text/scriptUtils.d.ts +142 -0
  93. package/dist-extensions/src/text/scriptUtils.d.ts.map +1 -0
  94. package/dist-extensions/src/util/misc/cornerRadius.d.ts +70 -0
  95. package/dist-extensions/src/util/misc/cornerRadius.d.ts.map +1 -0
  96. package/fabric-test-editor.html +3552 -0
  97. package/fabric-test2.html +647 -0
  98. package/fabric.ts +182 -182
  99. package/fonts/STV Bold.ttf +0 -0
  100. package/fonts/STV Light.ttf +0 -0
  101. package/fonts/STV Regular.ttf +0 -0
  102. package/package.json +164 -164
  103. package/src/shapes/Line.ts +484 -157
  104. package/src/shapes/Polyline.ts +70 -29
  105. package/src/shapes/Text/Text.ts +317 -19
  106. package/src/shapes/Textbox.ts +544 -12
  107. package/src/shapes/Triangle.spec.ts +76 -0
  108. package/src/shapes/Triangle.ts +85 -15
  109. package/src/text/measure.ts +200 -50
  110. package/src/text/overlayEditor.ts +164 -12
  111. package/src/util/misc/cornerRadius.spec.ts +141 -0
  112. package/src/util/misc/cornerRadius.ts +269 -0
  113. /package/debug/{konva → konva-master}/LICENSE +0 -0
  114. /package/debug/{konva → konva-master}/gulpfile.mjs +0 -0
  115. /package/debug/{konva → konva-master}/resources/doc-includes/ContainerParams.txt +0 -0
  116. /package/debug/{konva → konva-master}/resources/doc-includes/NodeParams.txt +0 -0
  117. /package/debug/{konva → konva-master}/resources/doc-includes/ShapeParams.txt +0 -0
  118. /package/debug/{konva → konva-master}/resources/jsdoc.conf.json +0 -0
  119. /package/debug/{konva → konva-master}/rollup.config.mjs +0 -0
  120. /package/debug/{konva → konva-master}/src/Animation.ts +0 -0
  121. /package/debug/{konva → konva-master}/src/BezierFunctions.ts +0 -0
  122. /package/debug/{konva → konva-master}/src/Container.ts +0 -0
  123. /package/debug/{konva → konva-master}/src/Context.ts +0 -0
  124. /package/debug/{konva → konva-master}/src/Core.ts +0 -0
  125. /package/debug/{konva → konva-master}/src/DragAndDrop.ts +0 -0
  126. /package/debug/{konva → konva-master}/src/Factory.ts +0 -0
  127. /package/debug/{konva → konva-master}/src/FastLayer.ts +0 -0
  128. /package/debug/{konva → konva-master}/src/Global.ts +0 -0
  129. /package/debug/{konva → konva-master}/src/Group.ts +0 -0
  130. /package/debug/{konva → konva-master}/src/Layer.ts +0 -0
  131. /package/debug/{konva → konva-master}/src/Node.ts +0 -0
  132. /package/debug/{konva → konva-master}/src/PointerEvents.ts +0 -0
  133. /package/debug/{konva → konva-master}/src/Shape.ts +0 -0
  134. /package/debug/{konva → konva-master}/src/Stage.ts +0 -0
  135. /package/debug/{konva → konva-master}/src/Tween.ts +0 -0
  136. /package/debug/{konva → konva-master}/src/Util.ts +0 -0
  137. /package/debug/{konva → konva-master}/src/Validators.ts +0 -0
  138. /package/debug/{konva → konva-master}/src/_CoreInternals.ts +0 -0
  139. /package/debug/{konva → konva-master}/src/_FullInternals.ts +0 -0
  140. /package/debug/{konva → konva-master}/src/canvas-backend.ts +0 -0
  141. /package/debug/{konva → konva-master}/src/filters/Blur.ts +0 -0
  142. /package/debug/{konva → konva-master}/src/filters/Brighten.ts +0 -0
  143. /package/debug/{konva → konva-master}/src/filters/Brightness.ts +0 -0
  144. /package/debug/{konva → konva-master}/src/filters/Contrast.ts +0 -0
  145. /package/debug/{konva → konva-master}/src/filters/Emboss.ts +0 -0
  146. /package/debug/{konva → konva-master}/src/filters/Enhance.ts +0 -0
  147. /package/debug/{konva → konva-master}/src/filters/Grayscale.ts +0 -0
  148. /package/debug/{konva → konva-master}/src/filters/HSL.ts +0 -0
  149. /package/debug/{konva → konva-master}/src/filters/HSV.ts +0 -0
  150. /package/debug/{konva → konva-master}/src/filters/Invert.ts +0 -0
  151. /package/debug/{konva → konva-master}/src/filters/Kaleidoscope.ts +0 -0
  152. /package/debug/{konva → konva-master}/src/filters/Mask.ts +0 -0
  153. /package/debug/{konva → konva-master}/src/filters/Noise.ts +0 -0
  154. /package/debug/{konva → konva-master}/src/filters/Pixelate.ts +0 -0
  155. /package/debug/{konva → konva-master}/src/filters/Posterize.ts +0 -0
  156. /package/debug/{konva → konva-master}/src/filters/RGB.ts +0 -0
  157. /package/debug/{konva → konva-master}/src/filters/RGBA.ts +0 -0
  158. /package/debug/{konva → konva-master}/src/filters/Sepia.ts +0 -0
  159. /package/debug/{konva → konva-master}/src/filters/Solarize.ts +0 -0
  160. /package/debug/{konva → konva-master}/src/filters/Threshold.ts +0 -0
  161. /package/debug/{konva → konva-master}/src/index.ts +0 -0
  162. /package/debug/{konva → konva-master}/src/shapes/Arc.ts +0 -0
  163. /package/debug/{konva → konva-master}/src/shapes/Arrow.ts +0 -0
  164. /package/debug/{konva → konva-master}/src/shapes/Circle.ts +0 -0
  165. /package/debug/{konva → konva-master}/src/shapes/Ellipse.ts +0 -0
  166. /package/debug/{konva → konva-master}/src/shapes/Image.ts +0 -0
  167. /package/debug/{konva → konva-master}/src/shapes/Label.ts +0 -0
  168. /package/debug/{konva → konva-master}/src/shapes/Line.ts +0 -0
  169. /package/debug/{konva → konva-master}/src/shapes/Path.ts +0 -0
  170. /package/debug/{konva → konva-master}/src/shapes/Rect.ts +0 -0
  171. /package/debug/{konva → konva-master}/src/shapes/RegularPolygon.ts +0 -0
  172. /package/debug/{konva → konva-master}/src/shapes/Ring.ts +0 -0
  173. /package/debug/{konva → konva-master}/src/shapes/Sprite.ts +0 -0
  174. /package/debug/{konva → konva-master}/src/shapes/Star.ts +0 -0
  175. /package/debug/{konva → konva-master}/src/shapes/TextPath.ts +0 -0
  176. /package/debug/{konva → konva-master}/src/shapes/Transformer.ts +0 -0
  177. /package/debug/{konva → konva-master}/src/shapes/Wedge.ts +0 -0
  178. /package/debug/{konva → konva-master}/src/skia-backend.ts +0 -0
  179. /package/debug/{konva → konva-master}/src/types.ts +0 -0
  180. /package/debug/{konva → konva-master}/tsconfig.json +0 -0
  181. /package/debug/{konva → konva-master}/tsconfig.test.json +0 -0
@@ -3,6 +3,7 @@ import { IText } from './IText/IText.mjs';
3
3
  import { classRegistry } from '../ClassRegistry.mjs';
4
4
  import { createTextboxDefaultControls } from '../controls/commonControls.mjs';
5
5
  import { JUSTIFY } from './Text/constants.mjs';
6
+ import { fontLacksEnglishGlyphsCached } from '../text/measure.mjs';
6
7
  import { layoutText } from '../text/layout.mjs';
7
8
 
8
9
  // @TODO: Many things here are configuration related and shouldn't be on the class nor prototype
@@ -65,8 +66,27 @@ class Textbox extends IText {
65
66
  */
66
67
  initDimensions() {
67
68
  if (!this.initialized) {
69
+ this.initialized = true;
70
+ }
71
+
72
+ // Prevent rapid recalculations during moves
73
+ if (this._usingBrowserWrapping) {
74
+ const now = Date.now();
75
+ const lastCall = this._lastInitDimensionsTime || 0;
76
+ const isRapidCall = now - lastCall < 100;
77
+ const isDuringLoading = this._jsonLoading || !this._browserWrapInitialized;
78
+ if (isRapidCall && !isDuringLoading) {
79
+ return;
80
+ }
81
+ this._lastInitDimensionsTime = now;
82
+ }
83
+
84
+ // Skip if nothing changed
85
+ const currentState = `${this.text}|${this.width}|${this.fontSize}|${this.fontFamily}|${this.textAlign}`;
86
+ if (this._lastDimensionState === currentState && this._textLines && this._textLines.length > 0) {
68
87
  return;
69
88
  }
89
+ this._lastDimensionState = currentState;
70
90
 
71
91
  // Use advanced layout if enabled
72
92
  if (this.enableAdvancedLayout) {
@@ -77,17 +97,142 @@ class Textbox extends IText {
77
97
  // clear dynamicMinWidth as it will be different after we re-wrap line
78
98
  this.dynamicMinWidth = 0;
79
99
  // wrap lines
80
- this._styleMap = this._generateStyleMap(this._splitText());
81
- // if after wrapping, the width is smaller than dynamicMinWidth, change the width and re-wrap
82
- if (this.dynamicMinWidth > this.width) {
100
+ const splitTextResult = this._splitText();
101
+ this._styleMap = this._generateStyleMap(splitTextResult);
102
+
103
+ // For browser wrapping, ensure _textLines is set from browser results
104
+ if (this._usingBrowserWrapping && splitTextResult && splitTextResult.lines) {
105
+ this._textLines = splitTextResult.lines.map(line => line.split(''));
106
+
107
+ // Store justify measurements and browser height
108
+ const justifyMeasurements = splitTextResult.justifySpaceMeasurements;
109
+ if (justifyMeasurements) {
110
+ this._styleMap.justifySpaceMeasurements = justifyMeasurements;
111
+ }
112
+ const actualHeight = splitTextResult.actualBrowserHeight;
113
+ if (actualHeight) {
114
+ this._actualBrowserHeight = actualHeight;
115
+ }
116
+ }
117
+ // Don't auto-resize width when using browser wrapping to prevent width increases during moves
118
+ if (!this._usingBrowserWrapping && this.dynamicMinWidth > this.width) {
83
119
  this._set('width', this.dynamicMinWidth);
84
120
  }
121
+
122
+ // For browser wrapping fonts (like STV), ensure minimum width for new textboxes
123
+ // since these fonts can't measure English characters properly
124
+ if (this._usingBrowserWrapping && this.width < 50) {
125
+ console.log(`🔤 BROWSER WRAP: Font ${this.fontFamily} has width ${this.width}px, setting to 300px for usability`);
126
+ this.width = 300;
127
+ }
128
+
129
+ // Mark browser wrapping as initialized when complete
130
+ if (this._usingBrowserWrapping) {
131
+ this._browserWrapInitialized = true;
132
+ }
85
133
  if (this.textAlign.includes(JUSTIFY)) {
134
+ // For browser wrapping fonts, apply browser-calculated justify spaces
135
+ if (this._usingBrowserWrapping) {
136
+ console.log('🔤 BROWSER WRAP: Applying browser-calculated justify spaces');
137
+ this._applyBrowserJustifySpaces();
138
+ return;
139
+ }
140
+
141
+ // Don't apply justify alignment during drag operations to prevent snapping
142
+ const now = Date.now();
143
+ const lastDragTime = this._lastInitDimensionsTime || 0;
144
+ const isDuringDrag = now - lastDragTime < 200; // 200ms window for drag detection
145
+
146
+ if (isDuringDrag) {
147
+ console.log('🔤 Skipping justify during drag operation to prevent snapping');
148
+ return;
149
+ }
150
+
151
+ // For non-browser-wrapping fonts, use Fabric's justify system
86
152
  // once text is measured we need to make space fatter to make justified text.
87
- this.enlargeSpaces();
153
+ // Ensure __charBounds exists and fonts are ready before applying justify
154
+ if (this.__charBounds && this.__charBounds.length > 0) {
155
+ // Check if font is ready for accurate justify calculations
156
+ const fontReady = this._isFontReady ? this._isFontReady() : true;
157
+ if (fontReady) {
158
+ this.enlargeSpaces();
159
+ } else {
160
+ console.warn('⚠️ Textbox: Font not ready for justify, deferring enlargeSpaces');
161
+ // Defer justify calculation until font is ready
162
+ this._scheduleJustifyAfterFontLoad();
163
+ }
164
+ } else {
165
+ console.warn('⚠️ Textbox: __charBounds not ready for justify alignment, deferring enlargeSpaces');
166
+ // Defer the justify calculation until the next frame
167
+ setTimeout(() => {
168
+ if (this.__charBounds && this.__charBounds.length > 0 && this.enlargeSpaces) {
169
+ var _this$canvas;
170
+ console.log('🔧 Applying deferred Textbox justify alignment');
171
+ this.enlargeSpaces();
172
+ (_this$canvas = this.canvas) === null || _this$canvas === void 0 || _this$canvas.requestRenderAll();
173
+ }
174
+ }, 0);
175
+ }
176
+ }
177
+ // Calculate height - use Fabric's calculation for proper text rendering space
178
+ if (this._usingBrowserWrapping && this._textLines && this._textLines.length > 0) {
179
+ const actualBrowserHeight = this._actualBrowserHeight;
180
+ const oldHeight = this.height;
181
+ // Use Fabric's height calculation since it knows how much space text rendering needs
182
+ this.height = this.calcTextHeight();
183
+
184
+ // Force canvas refresh and control update if height changed significantly
185
+ if (Math.abs(this.height - oldHeight) > 1) {
186
+ var _this$canvas2, _this$_textLines;
187
+ this.setCoords();
188
+ (_this$canvas2 = this.canvas) === null || _this$canvas2 === void 0 || _this$canvas2.requestRenderAll();
189
+
190
+ // DEBUG: Log exact positioning details
191
+ console.log(`🎯 POSITIONING DEBUG:`);
192
+ console.log(` Textbox height: ${this.height}px`);
193
+ console.log(` Textbox top: ${this.top}px`);
194
+ console.log(` Textbox left: ${this.left}px`);
195
+ console.log(` Text lines: ${((_this$_textLines = this._textLines) === null || _this$_textLines === void 0 ? void 0 : _this$_textLines.length) || 0}`);
196
+ console.log(` Font size: ${this.fontSize}px`);
197
+ console.log(` Line height: ${this.lineHeight || 1.16}`);
198
+ console.log(` Calculated line height: ${this.fontSize * (this.lineHeight || 1.16)}px`);
199
+ console.log(` _getTopOffset(): ${this._getTopOffset()}px`);
200
+ console.log(` calcTextHeight(): ${this.calcTextHeight()}px`);
201
+ console.log(` Browser height: ${actualBrowserHeight}px`);
202
+ console.log(` Height difference: ${this.height - this.calcTextHeight()}px`);
203
+ }
204
+ } else {
205
+ this.height = this.calcTextHeight();
88
206
  }
89
- // clear cache and re-calculate height
90
- this.height = this.calcTextHeight();
207
+ }
208
+
209
+ /**
210
+ * Schedule justify calculation after font loads (Textbox-specific)
211
+ * @private
212
+ */
213
+ _scheduleJustifyAfterFontLoad() {
214
+ if (typeof document === 'undefined' || !('fonts' in document)) {
215
+ return;
216
+ }
217
+
218
+ // Only schedule if not already waiting
219
+ if (this._fontJustifyScheduled) {
220
+ return;
221
+ }
222
+ this._fontJustifyScheduled = true;
223
+ const fontSpec = `${this.fontSize}px ${this.fontFamily}`;
224
+ document.fonts.load(fontSpec).then(() => {
225
+ var _this$canvas3;
226
+ this._fontJustifyScheduled = false;
227
+ console.log('🔧 Textbox: Font loaded, applying justify alignment');
228
+
229
+ // Re-run initDimensions to ensure proper justify calculation
230
+ this.initDimensions();
231
+ (_this$canvas3 = this.canvas) === null || _this$canvas3 === void 0 || _this$canvas3.requestRenderAll();
232
+ }).catch(() => {
233
+ this._fontJustifyScheduled = false;
234
+ console.warn('⚠️ Textbox: Font loading failed, justify may be incorrect');
235
+ });
91
236
  }
92
237
 
93
238
  /**
@@ -454,19 +599,33 @@ class Textbox extends IText {
454
599
  width: wordWidth
455
600
  } = data[i];
456
601
  offset += word.length;
457
- lineWidth += infixWidth + wordWidth - additionalSpace;
458
- if (lineWidth > maxWidth && !lineJustStarted) {
602
+
603
+ // Predictive wrapping: check if adding this word would exceed the width
604
+ const potentialLineWidth = lineWidth + infixWidth + wordWidth - additionalSpace;
605
+ // Use exact width to match overlay editor behavior
606
+ const conservativeMaxWidth = maxWidth; // No artificial buffer
607
+
608
+ // Debug logging for wrapping decisions
609
+ const currentLineText = line.join('');
610
+ console.log(`🔧 FABRIC WRAP CHECK: "${data[i].word}" -> potential: ${potentialLineWidth.toFixed(1)}px vs limit: ${conservativeMaxWidth.toFixed(1)}px`);
611
+ if (potentialLineWidth > conservativeMaxWidth && !lineJustStarted) {
612
+ // This word would exceed the width, wrap before adding it
613
+ console.log(`🔧 FABRIC WRAP! Line: "${currentLineText}" (${lineWidth.toFixed(1)}px)`);
459
614
  graphemeLines.push(line);
460
615
  line = [];
461
- lineWidth = wordWidth;
616
+ lineWidth = wordWidth; // Start new line with just this word
462
617
  lineJustStarted = true;
463
618
  } else {
464
- lineWidth += additionalSpace;
619
+ // Word fits, add it to current line
620
+ lineWidth = potentialLineWidth + additionalSpace;
465
621
  }
466
622
  if (!lineJustStarted && !splitByGrapheme) {
467
623
  line.push(infix);
468
624
  }
469
625
  line = line.concat(word);
626
+
627
+ // Debug: show current line after adding word
628
+ console.log(`🔧 FABRIC AFTER ADD: Line now: "${line.join('')}" (${line.length} chars)`);
470
629
  infixWidth = splitByGrapheme ? 0 : this._measureWord([infix], lineIndex, offset);
471
630
  offset++;
472
631
  lineJustStarted = false;
@@ -476,9 +635,19 @@ class Textbox extends IText {
476
635
  // TODO: this code is probably not necessary anymore.
477
636
  // it can be moved out of this function since largestWordWidth is now
478
637
  // known in advance
479
- if (largestWordWidth + reservedSpace > this.dynamicMinWidth) {
638
+ // Don't modify dynamicMinWidth when using browser wrapping to prevent width increases
639
+ if (!this._usingBrowserWrapping && largestWordWidth + reservedSpace > this.dynamicMinWidth) {
640
+ console.log(`🔧 FABRIC updating dynamicMinWidth: ${this.dynamicMinWidth} -> ${largestWordWidth - additionalSpace + reservedSpace}`);
480
641
  this.dynamicMinWidth = largestWordWidth - additionalSpace + reservedSpace;
642
+ } else if (this._usingBrowserWrapping) {
643
+ console.log(`🔤 BROWSER WRAP: Skipping dynamicMinWidth update to prevent width increase`);
481
644
  }
645
+
646
+ // Debug: show final wrapped lines
647
+ console.log(`🔧 FABRIC FINAL LINES: ${graphemeLines.length} lines`);
648
+ graphemeLines.forEach((line, i) => {
649
+ console.log(` Line ${i + 1}: "${line.join('')}" (${line.length} chars)`);
650
+ });
482
651
  return graphemeLines;
483
652
  }
484
653
 
@@ -522,6 +691,260 @@ class Textbox extends IText {
522
691
  * @override
523
692
  */
524
693
  _splitTextIntoLines(text) {
694
+ // Check if we need browser wrapping using smart font detection
695
+ const needsBrowserWrapping = this.fontFamily && fontLacksEnglishGlyphsCached(this.fontFamily);
696
+ if (needsBrowserWrapping) {
697
+ // Cache key based on text content, width, font properties, AND text alignment
698
+ const textHash = text.length + text.slice(0, 50); // Include text content in cache key
699
+ const cacheKey = `${textHash}|${this.width}|${this.fontSize}|${this.fontFamily}|${this.textAlign}`;
700
+
701
+ // Check if we have a cached result and nothing has changed
702
+ if (this._browserWrapCache && this._browserWrapCache.key === cacheKey) {
703
+ const cachedResult = this._browserWrapCache.result;
704
+
705
+ // For justify alignment, ensure we have the measurements
706
+ if (this.textAlign.includes('justify') && !cachedResult.justifySpaceMeasurements) ; else {
707
+ return cachedResult;
708
+ }
709
+ }
710
+ const result = this._splitTextIntoLinesWithBrowser(text);
711
+
712
+ // Cache the result
713
+ this._browserWrapCache = {
714
+ key: cacheKey,
715
+ result
716
+ };
717
+
718
+ // Mark that we used browser wrapping to prevent dynamicMinWidth modifications
719
+ this._usingBrowserWrapping = true;
720
+ return result;
721
+ }
722
+
723
+ // Clear the browser wrapping flag when using regular wrapping
724
+ this._usingBrowserWrapping = false;
725
+
726
+ // Default Fabric wrapping for other fonts
727
+ const newText = super._splitTextIntoLines(text),
728
+ graphemeLines = this._wrapText(newText.lines, this.width),
729
+ lines = new Array(graphemeLines.length);
730
+ for (let i = 0; i < graphemeLines.length; i++) {
731
+ lines[i] = graphemeLines[i].join('');
732
+ }
733
+ newText.lines = lines;
734
+ newText.graphemeLines = graphemeLines;
735
+ return newText;
736
+ }
737
+
738
+ /**
739
+ * Use browser's native text wrapping for accurate handling of fonts without English glyphs
740
+ * @private
741
+ */
742
+ _splitTextIntoLinesWithBrowser(text) {
743
+ if (typeof document === 'undefined') {
744
+ // Fallback to regular wrapping in Node.js
745
+ return this._splitTextIntoLinesDefault(text);
746
+ }
747
+
748
+ // Create a hidden element that mimics the overlay editor
749
+ const testElement = document.createElement('div');
750
+ testElement.style.position = 'absolute';
751
+ testElement.style.left = '-9999px';
752
+ testElement.style.visibility = 'hidden';
753
+ testElement.style.fontSize = `${this.fontSize}px`;
754
+ testElement.style.fontFamily = `"${this.fontFamily}"`;
755
+ testElement.style.fontWeight = String(this.fontWeight || 'normal');
756
+ testElement.style.fontStyle = String(this.fontStyle || 'normal');
757
+ testElement.style.lineHeight = String(this.lineHeight || 1.16);
758
+ testElement.style.width = `${this.width}px`;
759
+ testElement.style.direction = this.direction || 'ltr';
760
+ testElement.style.whiteSpace = 'pre-wrap';
761
+ testElement.style.wordBreak = 'normal';
762
+ testElement.style.overflowWrap = 'break-word';
763
+
764
+ // Set browser-native text alignment (including justify)
765
+ if (this.textAlign.includes('justify')) {
766
+ testElement.style.textAlign = 'justify';
767
+ testElement.style.textAlignLast = 'auto'; // Let browser decide last line alignment
768
+ } else {
769
+ testElement.style.textAlign = this.textAlign;
770
+ }
771
+ testElement.textContent = text;
772
+ document.body.appendChild(testElement);
773
+
774
+ // Get the browser's natural line breaks
775
+ const range = document.createRange();
776
+ const lines = [];
777
+ const graphemeLines = [];
778
+ try {
779
+ // Simple approach: split by measuring character positions
780
+ const textNode = testElement.firstChild;
781
+ if (textNode && textNode.nodeType === Node.TEXT_NODE) {
782
+ let currentLineStart = 0;
783
+ const textLength = text.length;
784
+ let previousBottom = 0;
785
+ for (let i = 0; i <= textLength; i++) {
786
+ range.setStart(textNode, currentLineStart);
787
+ range.setEnd(textNode, i);
788
+ const rect = range.getBoundingClientRect();
789
+ if (i > currentLineStart && (rect.bottom > previousBottom + 5 || i === textLength)) {
790
+ // New line detected or end of text
791
+ const lineEnd = i === textLength ? i : i - 1;
792
+ const lineText = text.substring(currentLineStart, lineEnd).trim();
793
+ if (lineText) {
794
+ lines.push(lineText);
795
+ // Convert to graphemes for compatibility
796
+ const graphemeLine = lineText.split('');
797
+ graphemeLines.push(graphemeLine);
798
+ }
799
+ currentLineStart = lineEnd;
800
+ previousBottom = rect.bottom;
801
+ }
802
+ }
803
+ }
804
+ } catch (error) {
805
+ console.warn('Browser wrapping failed, using fallback:', error);
806
+ document.body.removeChild(testElement);
807
+ return this._splitTextIntoLinesDefault(text);
808
+ }
809
+
810
+ // Extract actual browser height BEFORE removing element
811
+ const actualBrowserHeight = testElement.scrollHeight;
812
+ const offsetHeight = testElement.offsetHeight;
813
+ const clientHeight = testElement.clientHeight;
814
+ const boundingRect = testElement.getBoundingClientRect();
815
+ console.log(`🔤 Browser element measurements:`);
816
+ console.log(` scrollHeight: ${actualBrowserHeight}px (content + padding + hidden overflow)`);
817
+ console.log(` offsetHeight: ${offsetHeight}px (content + padding + border)`);
818
+ console.log(` clientHeight: ${clientHeight}px (content + padding, no border/scrollbar)`);
819
+ console.log(` boundingRect.height: ${boundingRect.height}px (actual rendered height)`);
820
+ console.log(` Font size: ${this.fontSize}px, Line height: ${this.lineHeight || 1.16}, Lines: ${lines.length}`);
821
+
822
+ // For justify alignment, extract space measurements from browser BEFORE removing element
823
+ let justifySpaceMeasurements = null;
824
+ if (this.textAlign.includes('justify')) {
825
+ justifySpaceMeasurements = this._extractJustifySpaceMeasurements(testElement, lines);
826
+ }
827
+ document.body.removeChild(testElement);
828
+ console.log(`🔤 Browser wrapping result: ${lines.length} lines`);
829
+
830
+ // Try different height measurements to find the most accurate
831
+ let bestHeight = actualBrowserHeight;
832
+
833
+ // If scrollHeight and offsetHeight differ significantly, investigate
834
+ if (Math.abs(actualBrowserHeight - offsetHeight) > 2) {
835
+ console.log(`🔤 Height discrepancy detected: scrollHeight=${actualBrowserHeight}px vs offsetHeight=${offsetHeight}px`);
836
+ }
837
+
838
+ // Consider using boundingRect height if it's larger (sometimes more accurate for visible content)
839
+ if (boundingRect.height > bestHeight) {
840
+ console.log(`🔤 Using boundingRect height (${boundingRect.height}px) instead of scrollHeight (${bestHeight}px)`);
841
+ bestHeight = boundingRect.height;
842
+ }
843
+
844
+ // Font-specific height adjustments for accurate bounding box
845
+ let adjustedHeight = bestHeight;
846
+
847
+ // Fonts without English glyphs need additional height buffer due to different font metrics
848
+ const lacksEnglishGlyphs = fontLacksEnglishGlyphsCached(this.fontFamily);
849
+ if (lacksEnglishGlyphs) {
850
+ const glyphBuffer = this.fontSize * 0.25; // 25% of font size for non-English fonts
851
+ adjustedHeight = bestHeight + glyphBuffer;
852
+ console.log(`🔤 Non-English font detected (${this.fontFamily}): Adding ${glyphBuffer}px buffer (${bestHeight}px + ${glyphBuffer}px = ${adjustedHeight}px)`);
853
+ } else {
854
+ console.log(`🔤 Standard font (${this.fontFamily}): Using browser height directly (${bestHeight}px)`);
855
+ }
856
+ return {
857
+ _unwrappedLines: [text.split('')],
858
+ lines: lines,
859
+ graphemeText: text.split(''),
860
+ graphemeLines: graphemeLines,
861
+ justifySpaceMeasurements: justifySpaceMeasurements,
862
+ actualBrowserHeight: adjustedHeight
863
+ };
864
+ }
865
+
866
+ /**
867
+ * Extract justify space measurements from browser
868
+ * @private
869
+ */
870
+ _extractJustifySpaceMeasurements(element, lines) {
871
+ console.log(`🔤 Extracting browser justify space measurements for ${lines.length} lines`);
872
+
873
+ // For now, we'll use a simplified approach:
874
+ // Apply uniform space expansion to match the line width
875
+ const spaceWidths = [];
876
+ lines.forEach((line, lineIndex) => {
877
+ const lineSpaces = [];
878
+ const spaceCount = (line.match(/\s/g) || []).length;
879
+ if (spaceCount > 0 && lineIndex < lines.length - 1) {
880
+ // Don't justify last line
881
+ // Calculate how much space expansion is needed
882
+ const normalSpaceWidth = 6.4; // Default space width for STV font
883
+ const lineWidth = this.width;
884
+
885
+ // Estimate natural line width
886
+ const charCount = line.length - spaceCount;
887
+ const avgCharWidth = 12; // Approximate for STV font
888
+
889
+ // Calculate expanded space width
890
+ const remainingSpace = lineWidth - charCount * avgCharWidth;
891
+ const expandedSpaceWidth = remainingSpace / spaceCount;
892
+ console.log(`🔤 Line ${lineIndex}: ${spaceCount} spaces, natural: ${normalSpaceWidth}px -> justified: ${expandedSpaceWidth.toFixed(1)}px`);
893
+
894
+ // Fill array with expanded space widths for this line
895
+ for (let i = 0; i < spaceCount; i++) {
896
+ lineSpaces.push(expandedSpaceWidth);
897
+ }
898
+ }
899
+ spaceWidths.push(lineSpaces);
900
+ });
901
+ return spaceWidths;
902
+ }
903
+
904
+ /**
905
+ * Apply browser-calculated justify space measurements
906
+ * @private
907
+ */
908
+ _applyBrowserJustifySpaces() {
909
+ if (!this._textLines || !this.__charBounds) {
910
+ console.warn('🔤 BROWSER JUSTIFY: _textLines or __charBounds not ready');
911
+ return;
912
+ }
913
+
914
+ // Get space measurements from browser wrapping result
915
+ const styleMap = this._styleMap;
916
+ if (!styleMap || !styleMap.justifySpaceMeasurements) {
917
+ console.warn('🔤 BROWSER JUSTIFY: No justify space measurements available');
918
+ return;
919
+ }
920
+ const spaceWidths = styleMap.justifySpaceMeasurements;
921
+ console.log('🔤 BROWSER JUSTIFY: Applying space measurements to __charBounds');
922
+
923
+ // Apply space widths to character bounds
924
+ this._textLines.forEach((line, lineIndex) => {
925
+ if (!this.__charBounds || !this.__charBounds[lineIndex] || !spaceWidths[lineIndex]) return;
926
+ const lineBounds = this.__charBounds[lineIndex];
927
+ const lineSpaceWidths = spaceWidths[lineIndex];
928
+ let spaceIndex = 0;
929
+ for (let charIndex = 0; charIndex < line.length; charIndex++) {
930
+ if (/\s/.test(line[charIndex]) && spaceIndex < lineSpaceWidths.length) {
931
+ const expandedWidth = lineSpaceWidths[spaceIndex];
932
+ if (lineBounds[charIndex]) {
933
+ const oldWidth = lineBounds[charIndex].width;
934
+ lineBounds[charIndex].width = expandedWidth;
935
+ console.log(`🔤 Line ${lineIndex} space ${spaceIndex}: ${oldWidth.toFixed(1)}px -> ${expandedWidth.toFixed(1)}px`);
936
+ }
937
+ spaceIndex++;
938
+ }
939
+ }
940
+ });
941
+ }
942
+
943
+ /**
944
+ * Fallback to default Fabric wrapping
945
+ * @private
946
+ */
947
+ _splitTextIntoLinesDefault(text) {
525
948
  const newText = super._splitTextIntoLines(text),
526
949
  graphemeLines = this._wrapText(newText.lines, this.width),
527
950
  lines = new Array(graphemeLines.length);
@@ -556,37 +979,24 @@ class Textbox extends IText {
556
979
  * @private
557
980
  */
558
981
  initializeEventListeners() {
559
- var _this$canvas;
982
+ var _this$canvas4;
560
983
  // Track which side is being used for resize to handle position compensation
561
984
  let resizeOrigin = null;
562
985
 
563
986
  // Detect resize origin during resizing
564
987
  this.on('resizing', e => {
565
988
  // Check transform origin to determine which side is being resized
566
- console.log('🔍 Resize event data:', e);
567
989
  if (e.transform) {
568
990
  const {
569
- originX,
570
- originY
991
+ originX
571
992
  } = e.transform;
572
- console.log('🔍 Transform origins:', {
573
- originX,
574
- originY
575
- });
576
993
  // originX tells us which side is the anchor - opposite side is being dragged
577
994
  resizeOrigin = originX === 'right' ? 'left' : originX === 'left' ? 'right' : null;
578
- console.log('🎯 Setting resizeOrigin to:', resizeOrigin);
579
995
  } else if (e.originX) {
580
996
  const {
581
- originX,
582
- originY
997
+ originX
583
998
  } = e;
584
- console.log('🔍 Event origins:', {
585
- originX,
586
- originY
587
- });
588
999
  resizeOrigin = originX === 'right' ? 'left' : originX === 'left' ? 'right' : null;
589
- console.log('🎯 Setting resizeOrigin to:', resizeOrigin);
590
1000
  }
591
1001
  });
592
1002
 
@@ -594,19 +1004,15 @@ class Textbox extends IText {
594
1004
  // Use 'modified' event which fires after user releases the mouse
595
1005
  this.on('modified', () => {
596
1006
  const currentResizeOrigin = resizeOrigin; // Capture the value before reset
597
- console.log('✅ Modified event fired - resize complete, triggering safety snap', {
598
- resizeOrigin: currentResizeOrigin
599
- });
600
1007
  // Small delay to ensure text layout is updated
601
1008
  setTimeout(() => this.safetySnapWidth(currentResizeOrigin), 10);
602
1009
  resizeOrigin = null; // Reset after capturing
603
1010
  });
604
1011
 
605
1012
  // Also listen to canvas-level modified event as backup
606
- (_this$canvas = this.canvas) === null || _this$canvas === void 0 || _this$canvas.on('object:modified', e => {
1013
+ (_this$canvas4 = this.canvas) === null || _this$canvas4 === void 0 || _this$canvas4.on('object:modified', e => {
607
1014
  if (e.target === this) {
608
1015
  const currentResizeOrigin = resizeOrigin; // Capture the value before reset
609
- console.log('✅ Canvas object:modified fired for this textbox');
610
1016
  setTimeout(() => this.safetySnapWidth(currentResizeOrigin), 10);
611
1017
  resizeOrigin = null; // Reset after capturing
612
1018
  }
@@ -621,38 +1027,17 @@ class Textbox extends IText {
621
1027
  * @param resizeOrigin - Which side was used for resizing ('left' or 'right')
622
1028
  */
623
1029
  safetySnapWidth(resizeOrigin) {
624
- var _this$_textLines;
625
- console.log('🔍 safetySnapWidth called', {
626
- isWrapping: this.isWrapping,
627
- hasTextLines: !!this._textLines,
628
- lineCount: ((_this$_textLines = this._textLines) === null || _this$_textLines === void 0 ? void 0 : _this$_textLines.length) || 0,
629
- currentWidth: this.width,
630
- type: this.type,
631
- text: this.text
632
- });
633
-
634
1030
  // For Textbox objects, we always want to check for clipping regardless of isWrapping flag
635
1031
  if (!this._textLines || this.type.toLowerCase() !== 'textbox' || this._textLines.length === 0) {
636
- var _this$_textLines2;
637
- console.log('❌ Early return - missing requirements', {
638
- hasTextLines: !!this._textLines,
639
- typeMatch: this.type.toLowerCase() === 'textbox',
640
- actualType: this.type,
641
- hasLines: ((_this$_textLines2 = this._textLines) === null || _this$_textLines2 === void 0 ? void 0 : _this$_textLines2.length) > 0
642
- });
643
1032
  return;
644
1033
  }
645
1034
  const lineCount = this._textLines.length;
646
1035
  if (lineCount === 0) return;
647
-
648
- // Check all lines, not just the last one
649
- let maxActualLineWidth = 0; // Actual measured width without buffers
650
1036
  let maxRequiredWidth = 0; // Width including RTL buffer
651
1037
 
652
1038
  for (let i = 0; i < lineCount; i++) {
653
1039
  const lineText = this._textLines[i].join(''); // Convert grapheme array to string
654
1040
  const lineWidth = this.getLineWidth(i);
655
- maxActualLineWidth = Math.max(maxActualLineWidth, lineWidth);
656
1041
 
657
1042
  // RTL detection - regex for Arabic, Hebrew, and other RTL characters
658
1043
  const rtlRegex = /[\u0590-\u05FF\u0600-\u06FF\u0750-\u077F\uFB50-\uFDFF\uFE70-\uFEFF]/;
@@ -669,14 +1054,9 @@ class Textbox extends IText {
669
1054
  const safetyThreshold = 2; // px - very subtle trigger
670
1055
 
671
1056
  if (maxRequiredWidth > this.width - safetyThreshold) {
672
- var _this$canvas2;
1057
+ var _this$canvas5;
673
1058
  // Set width to exactly what's needed + minimal safety margin
674
1059
  const newWidth = maxRequiredWidth + 1; // Add just 1px safety margin
675
- console.log(`Safety snap: ${this.width.toFixed(0)}px -> ${newWidth.toFixed(0)}px`, {
676
- maxActualLineWidth: maxActualLineWidth.toFixed(1),
677
- maxRequiredWidth: maxRequiredWidth.toFixed(1),
678
- difference: (newWidth - this.width).toFixed(1)
679
- });
680
1060
 
681
1061
  // Store original position before width change
682
1062
  const originalLeft = this.left;
@@ -692,19 +1072,12 @@ class Textbox extends IText {
692
1072
  // Only compensate position when resizing from left handle
693
1073
  // Right handle resize doesn't shift the text position
694
1074
  if (resizeOrigin === 'left') {
695
- console.log('🔧 Compensating for left-side resize', {
696
- originalLeft,
697
- widthIncrease,
698
- newLeft: originalLeft - widthIncrease
699
- });
700
1075
  // When resizing from left, the expansion pushes text right
701
1076
  // Compensate by moving the textbox left by the width increase
702
1077
  this.set({
703
1078
  'left': originalLeft - widthIncrease,
704
1079
  'top': originalTop
705
1080
  });
706
- } else {
707
- console.log('✅ Right-side resize, no compensation needed');
708
1081
  }
709
1082
  this.setCoords();
710
1083
 
@@ -714,7 +1087,88 @@ class Textbox extends IText {
714
1087
  this.__overlayEditor.refresh();
715
1088
  }, 0);
716
1089
  }
717
- (_this$canvas2 = this.canvas) === null || _this$canvas2 === void 0 || _this$canvas2.requestRenderAll();
1090
+ (_this$canvas5 = this.canvas) === null || _this$canvas5 === void 0 || _this$canvas5.requestRenderAll();
1091
+ }
1092
+ }
1093
+
1094
+ /**
1095
+ * Fix character selection mismatch after JSON loading for browser-wrapped fonts
1096
+ * @private
1097
+ */
1098
+ _fixCharacterMappingAfterJsonLoad() {
1099
+ if (this._usingBrowserWrapping) {
1100
+ // Clear all cached states to force fresh text layout calculation
1101
+ this._browserWrapCache = null;
1102
+ this._lastDimensionState = null;
1103
+
1104
+ // Force complete re-initialization
1105
+ this.initDimensions();
1106
+ this._forceClearCache = true;
1107
+
1108
+ // Ensure canvas refresh
1109
+ this.setCoords();
1110
+ if (this.canvas) {
1111
+ this.canvas.requestRenderAll();
1112
+ }
1113
+ }
1114
+ }
1115
+
1116
+ /**
1117
+ * Force complete textbox re-initialization (useful after JSON loading)
1118
+ * Overrides Text version with Textbox-specific logic
1119
+ */
1120
+ forceTextReinitialization() {
1121
+ console.log('🔄 Force reinitializing Textbox object');
1122
+
1123
+ // CRITICAL: Ensure textbox is marked as initialized
1124
+ this.initialized = true;
1125
+
1126
+ // Clear all caches and force dirty state
1127
+ this._clearCache();
1128
+ this.dirty = true;
1129
+ this.dynamicMinWidth = 0;
1130
+
1131
+ // Force isEditing false to ensure clean state
1132
+ this.isEditing = false;
1133
+ console.log(' → Set initialized=true, dirty=true, cleared caches');
1134
+
1135
+ // Re-initialize dimensions (this will handle justify properly)
1136
+ this.initDimensions();
1137
+
1138
+ // Double-check that justify was applied by checking space widths
1139
+ if (this.textAlign.includes('justify') && this.__charBounds) {
1140
+ setTimeout(() => {
1141
+ var _this$canvas6;
1142
+ // Verify justify was applied by checking if space widths vary
1143
+ let hasVariableSpaces = false;
1144
+ this.__charBounds.forEach((lineBounds, i) => {
1145
+ if (lineBounds && this._textLines && this._textLines[i]) {
1146
+ const spaces = lineBounds.filter((bound, j) => /\s/.test(this._textLines[i][j]));
1147
+ if (spaces.length > 1) {
1148
+ const firstSpaceWidth = spaces[0].width;
1149
+ hasVariableSpaces = spaces.some(space => Math.abs(space.width - firstSpaceWidth) > 0.1);
1150
+ }
1151
+ }
1152
+ });
1153
+ if (!hasVariableSpaces && this.__charBounds.length > 0) {
1154
+ console.warn(' ⚠️ Justify spaces still uniform - forcing enlargeSpaces again');
1155
+ if (this.enlargeSpaces) {
1156
+ this.enlargeSpaces();
1157
+ }
1158
+ } else {
1159
+ console.log(' ✅ Justify spaces properly expanded');
1160
+ }
1161
+
1162
+ // Ensure height is recalculated - use browser height if available
1163
+ if (this._usingBrowserWrapping && this._actualBrowserHeight) {
1164
+ this.height = this._actualBrowserHeight;
1165
+ console.log(`🔤 JUSTIFY: Preserved browser height: ${this.height}px`);
1166
+ } else {
1167
+ this.height = this.calcTextHeight();
1168
+ console.log(`🔧 JUSTIFY: Used calcTextHeight: ${this.height}px`);
1169
+ }
1170
+ (_this$canvas6 = this.canvas) === null || _this$canvas6 === void 0 || _this$canvas6.requestRenderAll();
1171
+ }, 10);
718
1172
  }
719
1173
  }
720
1174