@nasser-sw/fabric 7.0.0-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.
- package/0 +0 -0
- package/debug/{konva → konva-master}/CHANGELOG.md +2 -1
- package/debug/{konva → konva-master}/README.md +7 -3
- package/debug/{konva → konva-master}/package.json +1 -1
- package/debug/{konva → konva-master}/release.sh +1 -4
- package/debug/{konva → konva-master}/src/Canvas.ts +37 -0
- package/debug/{konva → konva-master}/src/shapes/Text.ts +2 -2
- package/dist/index.js +2198 -272
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/index.min.mjs +1 -1
- package/dist/index.min.mjs.map +1 -1
- package/dist/index.mjs +2198 -272
- package/dist/index.mjs.map +1 -1
- package/dist/index.node.cjs +2198 -272
- package/dist/index.node.cjs.map +1 -1
- package/dist/index.node.mjs +2198 -272
- package/dist/index.node.mjs.map +1 -1
- package/dist/package.json.min.mjs +1 -1
- package/dist/package.json.mjs +1 -1
- package/dist/src/shapes/Line.d.ts +33 -86
- package/dist/src/shapes/Line.d.ts.map +1 -1
- package/dist/src/shapes/Line.min.mjs +1 -1
- package/dist/src/shapes/Line.min.mjs.map +1 -1
- package/dist/src/shapes/Line.mjs +405 -159
- package/dist/src/shapes/Line.mjs.map +1 -1
- package/dist/src/shapes/Polyline.d.ts +7 -0
- package/dist/src/shapes/Polyline.d.ts.map +1 -1
- package/dist/src/shapes/Polyline.min.mjs +1 -1
- package/dist/src/shapes/Polyline.min.mjs.map +1 -1
- package/dist/src/shapes/Polyline.mjs +48 -16
- package/dist/src/shapes/Polyline.mjs.map +1 -1
- package/dist/src/shapes/Text/Text.d.ts +19 -0
- package/dist/src/shapes/Text/Text.d.ts.map +1 -1
- package/dist/src/shapes/Text/Text.min.mjs +1 -1
- package/dist/src/shapes/Text/Text.min.mjs.map +1 -1
- package/dist/src/shapes/Text/Text.mjs +302 -16
- package/dist/src/shapes/Text/Text.mjs.map +1 -1
- package/dist/src/shapes/Textbox.d.ts +56 -1
- package/dist/src/shapes/Textbox.d.ts.map +1 -1
- package/dist/src/shapes/Textbox.min.mjs +1 -1
- package/dist/src/shapes/Textbox.min.mjs.map +1 -1
- package/dist/src/shapes/Textbox.mjs +633 -11
- package/dist/src/shapes/Textbox.mjs.map +1 -1
- package/dist/src/shapes/Triangle.d.ts +27 -2
- package/dist/src/shapes/Triangle.d.ts.map +1 -1
- package/dist/src/shapes/Triangle.min.mjs +1 -1
- package/dist/src/shapes/Triangle.min.mjs.map +1 -1
- package/dist/src/shapes/Triangle.mjs +72 -12
- package/dist/src/shapes/Triangle.mjs.map +1 -1
- package/dist/src/text/examples/arabicTextExample.d.ts +60 -0
- package/dist/src/text/examples/arabicTextExample.d.ts.map +1 -0
- package/dist/src/text/measure.d.ts +9 -0
- package/dist/src/text/measure.d.ts.map +1 -1
- package/dist/src/text/measure.min.mjs +1 -1
- package/dist/src/text/measure.min.mjs.map +1 -1
- package/dist/src/text/measure.mjs +175 -4
- package/dist/src/text/measure.mjs.map +1 -1
- package/dist/src/text/overlayEditor.d.ts +8 -0
- package/dist/src/text/overlayEditor.d.ts.map +1 -1
- package/dist/src/text/overlayEditor.min.mjs +1 -1
- package/dist/src/text/overlayEditor.min.mjs.map +1 -1
- package/dist/src/text/overlayEditor.mjs +395 -56
- package/dist/src/text/overlayEditor.mjs.map +1 -1
- package/dist/src/text/scriptUtils.d.ts +142 -0
- package/dist/src/text/scriptUtils.d.ts.map +1 -0
- package/dist/src/text/scriptUtils.min.mjs +2 -0
- package/dist/src/text/scriptUtils.min.mjs.map +1 -0
- package/dist/src/text/scriptUtils.mjs +212 -0
- package/dist/src/text/scriptUtils.mjs.map +1 -0
- package/dist/src/util/misc/cornerRadius.d.ts +70 -0
- package/dist/src/util/misc/cornerRadius.d.ts.map +1 -0
- package/dist/src/util/misc/cornerRadius.min.mjs +2 -0
- package/dist/src/util/misc/cornerRadius.min.mjs.map +1 -0
- package/dist/src/util/misc/cornerRadius.mjs +181 -0
- package/dist/src/util/misc/cornerRadius.mjs.map +1 -0
- package/dist-extensions/src/shapes/CustomLine.d.ts +10 -0
- package/dist-extensions/src/shapes/CustomLine.d.ts.map +1 -0
- package/dist-extensions/src/shapes/Line.d.ts +33 -86
- package/dist-extensions/src/shapes/Line.d.ts.map +1 -1
- package/dist-extensions/src/shapes/Polyline.d.ts +7 -0
- package/dist-extensions/src/shapes/Polyline.d.ts.map +1 -1
- package/dist-extensions/src/shapes/Text/Text.d.ts +19 -0
- package/dist-extensions/src/shapes/Text/Text.d.ts.map +1 -1
- package/dist-extensions/src/shapes/Textbox.d.ts +56 -1
- package/dist-extensions/src/shapes/Textbox.d.ts.map +1 -1
- package/dist-extensions/src/shapes/Triangle.d.ts +27 -2
- package/dist-extensions/src/shapes/Triangle.d.ts.map +1 -1
- package/dist-extensions/src/text/measure.d.ts +9 -0
- package/dist-extensions/src/text/measure.d.ts.map +1 -1
- package/dist-extensions/src/text/overlayEditor.d.ts +8 -0
- package/dist-extensions/src/text/overlayEditor.d.ts.map +1 -1
- package/dist-extensions/src/text/scriptUtils.d.ts +142 -0
- package/dist-extensions/src/text/scriptUtils.d.ts.map +1 -0
- package/dist-extensions/src/util/misc/cornerRadius.d.ts +70 -0
- package/dist-extensions/src/util/misc/cornerRadius.d.ts.map +1 -0
- package/fabric-test-editor.html +3552 -0
- package/fabric-test2.html +647 -0
- package/fabric.ts +182 -182
- package/fonts/STV Bold.ttf +0 -0
- package/fonts/STV Light.ttf +0 -0
- package/fonts/STV Regular.ttf +0 -0
- package/package.json +164 -164
- package/src/shapes/Line.ts +484 -157
- package/src/shapes/Polyline.ts +70 -29
- package/src/shapes/Text/Text.ts +317 -19
- package/src/shapes/Textbox.ts +663 -12
- package/src/shapes/Triangle.spec.ts +76 -0
- package/src/shapes/Triangle.ts +85 -15
- package/src/text/measure.ts +200 -50
- package/src/text/overlayEditor.ts +504 -94
- package/src/util/misc/cornerRadius.spec.ts +141 -0
- package/src/util/misc/cornerRadius.ts +269 -0
- /package/debug/{konva → konva-master}/LICENSE +0 -0
- /package/debug/{konva → konva-master}/gulpfile.mjs +0 -0
- /package/debug/{konva → konva-master}/resources/doc-includes/ContainerParams.txt +0 -0
- /package/debug/{konva → konva-master}/resources/doc-includes/NodeParams.txt +0 -0
- /package/debug/{konva → konva-master}/resources/doc-includes/ShapeParams.txt +0 -0
- /package/debug/{konva → konva-master}/resources/jsdoc.conf.json +0 -0
- /package/debug/{konva → konva-master}/rollup.config.mjs +0 -0
- /package/debug/{konva → konva-master}/src/Animation.ts +0 -0
- /package/debug/{konva → konva-master}/src/BezierFunctions.ts +0 -0
- /package/debug/{konva → konva-master}/src/Container.ts +0 -0
- /package/debug/{konva → konva-master}/src/Context.ts +0 -0
- /package/debug/{konva → konva-master}/src/Core.ts +0 -0
- /package/debug/{konva → konva-master}/src/DragAndDrop.ts +0 -0
- /package/debug/{konva → konva-master}/src/Factory.ts +0 -0
- /package/debug/{konva → konva-master}/src/FastLayer.ts +0 -0
- /package/debug/{konva → konva-master}/src/Global.ts +0 -0
- /package/debug/{konva → konva-master}/src/Group.ts +0 -0
- /package/debug/{konva → konva-master}/src/Layer.ts +0 -0
- /package/debug/{konva → konva-master}/src/Node.ts +0 -0
- /package/debug/{konva → konva-master}/src/PointerEvents.ts +0 -0
- /package/debug/{konva → konva-master}/src/Shape.ts +0 -0
- /package/debug/{konva → konva-master}/src/Stage.ts +0 -0
- /package/debug/{konva → konva-master}/src/Tween.ts +0 -0
- /package/debug/{konva → konva-master}/src/Util.ts +0 -0
- /package/debug/{konva → konva-master}/src/Validators.ts +0 -0
- /package/debug/{konva → konva-master}/src/_CoreInternals.ts +0 -0
- /package/debug/{konva → konva-master}/src/_FullInternals.ts +0 -0
- /package/debug/{konva → konva-master}/src/canvas-backend.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/Blur.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/Brighten.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/Brightness.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/Contrast.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/Emboss.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/Enhance.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/Grayscale.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/HSL.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/HSV.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/Invert.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/Kaleidoscope.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/Mask.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/Noise.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/Pixelate.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/Posterize.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/RGB.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/RGBA.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/Sepia.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/Solarize.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/Threshold.ts +0 -0
- /package/debug/{konva → konva-master}/src/index.ts +0 -0
- /package/debug/{konva → konva-master}/src/shapes/Arc.ts +0 -0
- /package/debug/{konva → konva-master}/src/shapes/Arrow.ts +0 -0
- /package/debug/{konva → konva-master}/src/shapes/Circle.ts +0 -0
- /package/debug/{konva → konva-master}/src/shapes/Ellipse.ts +0 -0
- /package/debug/{konva → konva-master}/src/shapes/Image.ts +0 -0
- /package/debug/{konva → konva-master}/src/shapes/Label.ts +0 -0
- /package/debug/{konva → konva-master}/src/shapes/Line.ts +0 -0
- /package/debug/{konva → konva-master}/src/shapes/Path.ts +0 -0
- /package/debug/{konva → konva-master}/src/shapes/Rect.ts +0 -0
- /package/debug/{konva → konva-master}/src/shapes/RegularPolygon.ts +0 -0
- /package/debug/{konva → konva-master}/src/shapes/Ring.ts +0 -0
- /package/debug/{konva → konva-master}/src/shapes/Sprite.ts +0 -0
- /package/debug/{konva → konva-master}/src/shapes/Star.ts +0 -0
- /package/debug/{konva → konva-master}/src/shapes/TextPath.ts +0 -0
- /package/debug/{konva → konva-master}/src/shapes/Transformer.ts +0 -0
- /package/debug/{konva → konva-master}/src/shapes/Wedge.ts +0 -0
- /package/debug/{konva → konva-master}/src/skia-backend.ts +0 -0
- /package/debug/{konva → konva-master}/src/types.ts +0 -0
- /package/debug/{konva → konva-master}/tsconfig.json +0 -0
- /package/debug/{konva → konva-master}/tsconfig.test.json +0 -0
|
@@ -79,8 +79,12 @@ class OverlayEditor {
|
|
|
79
79
|
this.textarea.style.pointerEvents = 'auto';
|
|
80
80
|
// Set appropriate unicodeBidi based on content and direction
|
|
81
81
|
const hasArabicText = /[\u0600-\u06FF\u0750-\u077F\uFB50-\uFDFF\uFE70-\uFEFF]/.test(this.target.text || '');
|
|
82
|
+
const hasLatinText = /[a-zA-Z]/.test(this.target.text || '');
|
|
82
83
|
const isLTRDirection = this.target.direction === 'ltr';
|
|
83
|
-
if (hasArabicText && isLTRDirection) {
|
|
84
|
+
if (hasArabicText && hasLatinText && isLTRDirection) {
|
|
85
|
+
// For mixed Arabic/Latin text in LTR mode, use embed for consistent line wrapping
|
|
86
|
+
this.textarea.style.unicodeBidi = 'embed';
|
|
87
|
+
} else if (hasArabicText && isLTRDirection) {
|
|
84
88
|
// For Arabic text in LTR mode, use embed to preserve shaping while respecting direction
|
|
85
89
|
this.textarea.style.unicodeBidi = 'embed';
|
|
86
90
|
} else {
|
|
@@ -169,14 +173,26 @@ class OverlayEditor {
|
|
|
169
173
|
parseFloat(this.hostDiv.style.width) / zoom;
|
|
170
174
|
const currentHeight = parseFloat(this.hostDiv.style.height) / zoom;
|
|
171
175
|
|
|
172
|
-
//
|
|
176
|
+
// Always update height for responsive controls (especially important for line deletion)
|
|
173
177
|
const heightDiff = Math.abs(currentHeight - target.height);
|
|
174
|
-
const threshold =
|
|
178
|
+
const threshold = 0.5; // Lower threshold for better responsiveness to line changes
|
|
175
179
|
|
|
176
180
|
if (heightDiff > threshold) {
|
|
181
|
+
target.height;
|
|
177
182
|
target.height = currentHeight;
|
|
178
183
|
target.setCoords(); // Update control positions
|
|
184
|
+
|
|
185
|
+
// Force dirty to ensure proper re-rendering
|
|
186
|
+
target.dirty = true;
|
|
179
187
|
this.canvas.requestRenderAll(); // Re-render to show updated selection
|
|
188
|
+
|
|
189
|
+
// IMPORTANT: Reposition overlay after height change
|
|
190
|
+
requestAnimationFrame(() => {
|
|
191
|
+
if (!this.isDestroyed) {
|
|
192
|
+
this.applyOverlayStyle();
|
|
193
|
+
console.log('📐 Height changed - rechecking alignment after repositioning:');
|
|
194
|
+
}
|
|
195
|
+
});
|
|
180
196
|
}
|
|
181
197
|
}
|
|
182
198
|
|
|
@@ -204,14 +220,6 @@ class OverlayEditor {
|
|
|
204
220
|
target.setCoords();
|
|
205
221
|
const aCoords = target.aCoords;
|
|
206
222
|
|
|
207
|
-
// DEBUG: Log dimensions before edit
|
|
208
|
-
console.log('BEFORE EDIT:');
|
|
209
|
-
console.log(' target.width =', target.width);
|
|
210
|
-
console.log(' target.height =', target.height);
|
|
211
|
-
console.log(' target.getScaledWidth() =', target.getScaledWidth());
|
|
212
|
-
console.log(' target.getScaledHeight() =', target.getScaledHeight());
|
|
213
|
-
console.log(' target.padding =', target.padding);
|
|
214
|
-
|
|
215
223
|
// 2. Get canvas position and scroll offsets (like rtl-test.html)
|
|
216
224
|
const canvasEl = canvas.upperCanvasEl;
|
|
217
225
|
const canvasRect = canvasEl.getBoundingClientRect();
|
|
@@ -234,14 +242,12 @@ class OverlayEditor {
|
|
|
234
242
|
const left = canvasRect.left + scrollX + screenPoint.x;
|
|
235
243
|
const top = canvasRect.top + scrollY + screenPoint.y;
|
|
236
244
|
|
|
237
|
-
// 4.
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
console.log(' zoom =', zoom);
|
|
244
|
-
console.log(' final width =', width);
|
|
245
|
+
// 4. Calculate the precise width and height for the container
|
|
246
|
+
// **THE FIX:** Use getBoundingRect() for BOTH width and height.
|
|
247
|
+
// This is the most reliable measure of the object's final rendered dimensions.
|
|
248
|
+
const objectBounds = target.getBoundingRect();
|
|
249
|
+
const width = Math.round(objectBounds.width * zoom);
|
|
250
|
+
const height = Math.round(objectBounds.height * zoom);
|
|
245
251
|
|
|
246
252
|
// 5. Apply styles to host DIV - absolute positioning like rtl-test.html
|
|
247
253
|
this.hostDiv.style.position = 'absolute';
|
|
@@ -265,50 +271,333 @@ class OverlayEditor {
|
|
|
265
271
|
const scaleX = target.scaleX || 1;
|
|
266
272
|
const finalFontSize = baseFontSize * scaleX * zoom;
|
|
267
273
|
const fabricLineHeight = target.lineHeight || 1.16;
|
|
268
|
-
//
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
274
|
+
// **THE FIX:** Use 'border-box' so the width property includes padding.
|
|
275
|
+
// This makes alignment much easier and more reliable.
|
|
276
|
+
this.textarea.style.boxSizing = 'border-box';
|
|
277
|
+
|
|
278
|
+
// **THE FIX:** Set the textarea width to be IDENTICAL to the host div's width.
|
|
279
|
+
// The padding will now be correctly contained *inside* this width.
|
|
280
|
+
this.textarea.style.width = `${width}px`;
|
|
281
|
+
this.textarea.style.height = '100%'; // Let hostDiv control height
|
|
273
282
|
this.textarea.style.padding = `${paddingY}px ${paddingX}px`;
|
|
283
|
+
|
|
284
|
+
// Apply all other font and text styles to match Fabric
|
|
285
|
+
const letterSpacingPx = (target.charSpacing || 0) / 1000 * finalFontSize;
|
|
286
|
+
|
|
287
|
+
// Special handling for text objects loaded from JSON - ensure they're properly initialized
|
|
288
|
+
if (target.dirty !== false && target.initDimensions) {
|
|
289
|
+
console.log('🔧 Ensuring text object is properly initialized before overlay editing');
|
|
290
|
+
// Force re-initialization if the text object seems to be in a dirty state
|
|
291
|
+
target.initDimensions();
|
|
292
|
+
}
|
|
274
293
|
this.textarea.style.fontSize = `${finalFontSize}px`;
|
|
275
|
-
this.textarea.style.lineHeight = String(fabricLineHeight);
|
|
294
|
+
this.textarea.style.lineHeight = String(fabricLineHeight);
|
|
276
295
|
this.textarea.style.fontFamily = target.fontFamily || 'Arial';
|
|
277
296
|
this.textarea.style.fontWeight = String(target.fontWeight || 'normal');
|
|
278
297
|
this.textarea.style.fontStyle = target.fontStyle || 'normal';
|
|
279
|
-
|
|
298
|
+
// Handle text alignment and justification
|
|
299
|
+
const textAlign = target.textAlign || 'left';
|
|
300
|
+
let cssTextAlign = textAlign;
|
|
301
|
+
|
|
302
|
+
// Detect text direction from content for proper justify handling
|
|
303
|
+
const autoDetectedDirection = this.firstStrongDir(this.textarea.value || '');
|
|
304
|
+
|
|
305
|
+
// DEBUG: Log alignment details
|
|
306
|
+
console.log('🔍 ALIGNMENT DEBUG:');
|
|
307
|
+
console.log(' Fabric textAlign:', textAlign);
|
|
308
|
+
console.log(' Fabric direction:', target.direction);
|
|
309
|
+
console.log(' Text content:', JSON.stringify(target.text));
|
|
310
|
+
console.log(' Detected direction:', autoDetectedDirection);
|
|
311
|
+
|
|
312
|
+
// Map fabric.js justify to CSS
|
|
313
|
+
if (textAlign.includes('justify')) {
|
|
314
|
+
// Try to match fabric.js justify behavior more precisely
|
|
315
|
+
try {
|
|
316
|
+
// For justify, we need to replicate fabric.js space expansion
|
|
317
|
+
// Use CSS justify but with specific settings to match fabric.js better
|
|
318
|
+
cssTextAlign = 'justify';
|
|
319
|
+
|
|
320
|
+
// Set text-align-last based on justify type and detected direction
|
|
321
|
+
// Smart justify: respect detected direction even when fabric alignment doesn't match
|
|
322
|
+
if (textAlign === 'justify') {
|
|
323
|
+
this.textarea.style.textAlignLast = autoDetectedDirection === 'rtl' ? 'right' : 'left';
|
|
324
|
+
} else if (textAlign === 'justify-left') {
|
|
325
|
+
// If text is RTL but fabric says justify-left, override to justify-right for better UX
|
|
326
|
+
if (autoDetectedDirection === 'rtl') {
|
|
327
|
+
this.textarea.style.textAlignLast = 'right';
|
|
328
|
+
console.log(' → Overrode justify-left to justify-right for RTL text');
|
|
329
|
+
} else {
|
|
330
|
+
this.textarea.style.textAlignLast = 'left';
|
|
331
|
+
}
|
|
332
|
+
} else if (textAlign === 'justify-right') {
|
|
333
|
+
// If text is LTR but fabric says justify-right, override to justify-left for better UX
|
|
334
|
+
if (autoDetectedDirection === 'ltr') {
|
|
335
|
+
this.textarea.style.textAlignLast = 'left';
|
|
336
|
+
console.log(' → Overrode justify-right to justify-left for LTR text');
|
|
337
|
+
} else {
|
|
338
|
+
this.textarea.style.textAlignLast = 'right';
|
|
339
|
+
}
|
|
340
|
+
} else if (textAlign === 'justify-center') {
|
|
341
|
+
this.textarea.style.textAlignLast = 'center';
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// Enhanced justify settings for better fabric.js matching
|
|
345
|
+
this.textarea.style.textJustify = 'inter-word';
|
|
346
|
+
this.textarea.style.wordSpacing = 'normal';
|
|
347
|
+
|
|
348
|
+
// Additional CSS properties for better justify matching
|
|
349
|
+
this.textarea.style.textAlign = 'justify';
|
|
350
|
+
this.textarea.style.textAlignLast = this.textarea.style.textAlignLast;
|
|
351
|
+
|
|
352
|
+
// Try to force better justify behavior
|
|
353
|
+
this.textarea.style.textJustifyTrim = 'none';
|
|
354
|
+
this.textarea.style.textAutospace = 'none';
|
|
355
|
+
console.log(' → Applied justify alignment:', textAlign, 'with last-line:', this.textarea.style.textAlignLast);
|
|
356
|
+
} catch (error) {
|
|
357
|
+
console.warn(' → Justify setup failed, falling back to standard alignment:', error);
|
|
358
|
+
cssTextAlign = textAlign.replace('justify-', '').replace('justify', 'left');
|
|
359
|
+
}
|
|
360
|
+
} else {
|
|
361
|
+
this.textarea.style.textAlignLast = 'auto';
|
|
362
|
+
this.textarea.style.textJustify = 'auto';
|
|
363
|
+
this.textarea.style.wordSpacing = 'normal';
|
|
364
|
+
console.log(' → Applied standard alignment:', cssTextAlign);
|
|
365
|
+
}
|
|
366
|
+
this.textarea.style.textAlign = cssTextAlign;
|
|
280
367
|
this.textarea.style.color = ((_target$fill = target.fill) === null || _target$fill === void 0 ? void 0 : _target$fill.toString()) || '#000';
|
|
281
|
-
this.textarea.style.letterSpacing = `${
|
|
282
|
-
|
|
368
|
+
this.textarea.style.letterSpacing = `${letterSpacingPx}px`;
|
|
369
|
+
|
|
370
|
+
// Use the already detected direction from above
|
|
371
|
+
const fabricDirection = target.direction;
|
|
283
372
|
|
|
284
|
-
//
|
|
373
|
+
// Use auto-detected direction for better BiDi support, but respect fabric direction if it makes sense
|
|
374
|
+
this.textarea.style.direction = autoDetectedDirection || fabricDirection || 'ltr';
|
|
285
375
|
this.textarea.style.fontVariant = 'normal';
|
|
286
376
|
this.textarea.style.fontStretch = 'normal';
|
|
287
|
-
this.textarea.style.textRendering = 'auto';
|
|
288
|
-
this.textarea.style.fontKerning = '
|
|
289
|
-
this.textarea.style.
|
|
377
|
+
this.textarea.style.textRendering = 'auto'; // Changed from 'optimizeLegibility' to match canvas
|
|
378
|
+
this.textarea.style.fontKerning = 'normal';
|
|
379
|
+
this.textarea.style.fontFeatureSettings = 'normal';
|
|
380
|
+
this.textarea.style.fontVariationSettings = 'normal';
|
|
290
381
|
this.textarea.style.margin = '0';
|
|
291
382
|
this.textarea.style.border = 'none';
|
|
292
383
|
this.textarea.style.outline = 'none';
|
|
293
384
|
this.textarea.style.background = 'transparent';
|
|
294
|
-
this.textarea.style.
|
|
385
|
+
this.textarea.style.overflowWrap = 'break-word';
|
|
295
386
|
this.textarea.style.whiteSpace = 'pre-wrap';
|
|
387
|
+
this.textarea.style.hyphens = 'none';
|
|
388
|
+
|
|
389
|
+
// DEBUG: Log final CSS properties
|
|
390
|
+
console.log('🎨 FINAL TEXTAREA CSS:');
|
|
391
|
+
console.log(' textAlign:', this.textarea.style.textAlign);
|
|
392
|
+
console.log(' textAlignLast:', this.textarea.style.textAlignLast);
|
|
393
|
+
console.log(' direction:', this.textarea.style.direction);
|
|
394
|
+
console.log(' unicodeBidi:', this.textarea.style.unicodeBidi);
|
|
395
|
+
console.log(' width:', this.textarea.style.width);
|
|
396
|
+
console.log(' textJustify:', this.textarea.style.textJustify);
|
|
397
|
+
console.log(' wordSpacing:', this.textarea.style.wordSpacing);
|
|
398
|
+
console.log(' whiteSpace:', this.textarea.style.whiteSpace);
|
|
399
|
+
|
|
400
|
+
// If justify, log Fabric object dimensions for comparison
|
|
401
|
+
if (textAlign.includes('justify')) {
|
|
402
|
+
var _calcTextWidth, _ref;
|
|
403
|
+
console.log('🔧 FABRIC OBJECT JUSTIFY INFO:');
|
|
404
|
+
console.log(' Fabric width:', target.width);
|
|
405
|
+
console.log(' Fabric calcTextWidth:', (_calcTextWidth = (_ref = target).calcTextWidth) === null || _calcTextWidth === void 0 ? void 0 : _calcTextWidth.call(_ref));
|
|
406
|
+
console.log(' Fabric textAlign:', target.textAlign);
|
|
407
|
+
console.log(' Text lines:', target.textLines);
|
|
408
|
+
}
|
|
296
409
|
|
|
297
|
-
//
|
|
298
|
-
console.log('
|
|
299
|
-
console.log('
|
|
300
|
-
console.log('
|
|
301
|
-
console.log('
|
|
302
|
-
console.log('
|
|
303
|
-
console.log('
|
|
304
|
-
console.log('
|
|
305
|
-
console.log('
|
|
306
|
-
console.log('
|
|
307
|
-
console.log('
|
|
410
|
+
// Debug font properties matching
|
|
411
|
+
console.log('🔤 FONT PROPERTIES COMPARISON:');
|
|
412
|
+
console.log(' Fabric fontFamily:', target.fontFamily);
|
|
413
|
+
console.log(' Fabric fontWeight:', target.fontWeight);
|
|
414
|
+
console.log(' Fabric fontStyle:', target.fontStyle);
|
|
415
|
+
console.log(' Fabric fontSize:', target.fontSize);
|
|
416
|
+
console.log(' → Textarea fontFamily:', this.textarea.style.fontFamily);
|
|
417
|
+
console.log(' → Textarea fontWeight:', this.textarea.style.fontWeight);
|
|
418
|
+
console.log(' → Textarea fontStyle:', this.textarea.style.fontStyle);
|
|
419
|
+
console.log(' → Textarea fontSize:', this.textarea.style.fontSize);
|
|
420
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
421
|
+
|
|
422
|
+
// Enhanced font rendering to better match fabric.js canvas rendering
|
|
423
|
+
// Default to auto for more natural rendering
|
|
424
|
+
this.textarea.style.webkitFontSmoothing = 'auto';
|
|
425
|
+
this.textarea.style.mozOsxFontSmoothing = 'auto';
|
|
426
|
+
this.textarea.style.fontSmooth = 'auto';
|
|
427
|
+
this.textarea.style.textSizeAdjust = 'none';
|
|
428
|
+
|
|
429
|
+
// For bold fonts, use subpixel rendering to match canvas thickness better
|
|
430
|
+
const fontWeight = String(target.fontWeight || 'normal');
|
|
431
|
+
const isBold = fontWeight === 'bold' || fontWeight === '700' || parseInt(fontWeight) >= 600;
|
|
432
|
+
if (isBold) {
|
|
433
|
+
this.textarea.style.webkitFontSmoothing = 'subpixel-antialiased';
|
|
434
|
+
this.textarea.style.mozOsxFontSmoothing = 'unset';
|
|
435
|
+
console.log('🔤 Applied enhanced bold rendering for better thickness matching');
|
|
436
|
+
}
|
|
437
|
+
console.log('🎨 FONT SMOOTHING APPLIED:');
|
|
438
|
+
console.log(' webkitFontSmoothing:', this.textarea.style.webkitFontSmoothing);
|
|
439
|
+
console.log(' mozOsxFontSmoothing:', this.textarea.style.mozOsxFontSmoothing);
|
|
308
440
|
|
|
309
441
|
// Initial bounds are set correctly by Fabric.js - don't force update here
|
|
310
442
|
}
|
|
311
443
|
|
|
444
|
+
/**
|
|
445
|
+
* Debug method to compare textarea and canvas object bounding boxes
|
|
446
|
+
*/
|
|
447
|
+
debugBoundingBoxComparison() {
|
|
448
|
+
const target = this.target;
|
|
449
|
+
const canvas = this.canvas;
|
|
450
|
+
const zoom = canvas.getZoom();
|
|
451
|
+
|
|
452
|
+
// Get textarea bounding box (in screen coordinates)
|
|
453
|
+
const textareaRect = this.textarea.getBoundingClientRect();
|
|
454
|
+
const hostRect = this.hostDiv.getBoundingClientRect();
|
|
455
|
+
|
|
456
|
+
// Get canvas object bounding box (in screen coordinates)
|
|
457
|
+
const canvasBounds = target.getBoundingRect();
|
|
458
|
+
const canvasRect = canvas.upperCanvasEl.getBoundingClientRect();
|
|
459
|
+
|
|
460
|
+
// Convert canvas object bounds to screen coordinates
|
|
461
|
+
const vpt = canvas.viewportTransform;
|
|
462
|
+
const screenObjectBounds = {
|
|
463
|
+
left: canvasRect.left + canvasBounds.left * zoom + vpt[4],
|
|
464
|
+
top: canvasRect.top + canvasBounds.top * zoom + vpt[5],
|
|
465
|
+
width: canvasBounds.width * zoom,
|
|
466
|
+
height: canvasBounds.height * zoom
|
|
467
|
+
};
|
|
468
|
+
console.log('🔍 BOUNDING BOX COMPARISON:');
|
|
469
|
+
console.log('📦 Textarea Rect:', {
|
|
470
|
+
left: Math.round(textareaRect.left * 100) / 100,
|
|
471
|
+
top: Math.round(textareaRect.top * 100) / 100,
|
|
472
|
+
width: Math.round(textareaRect.width * 100) / 100,
|
|
473
|
+
height: Math.round(textareaRect.height * 100) / 100
|
|
474
|
+
});
|
|
475
|
+
console.log('📦 Host Div Rect:', {
|
|
476
|
+
left: Math.round(hostRect.left * 100) / 100,
|
|
477
|
+
top: Math.round(hostRect.top * 100) / 100,
|
|
478
|
+
width: Math.round(hostRect.width * 100) / 100,
|
|
479
|
+
height: Math.round(hostRect.height * 100) / 100
|
|
480
|
+
});
|
|
481
|
+
console.log('📦 Canvas Object Bounds (screen):', {
|
|
482
|
+
left: Math.round(screenObjectBounds.left * 100) / 100,
|
|
483
|
+
top: Math.round(screenObjectBounds.top * 100) / 100,
|
|
484
|
+
width: Math.round(screenObjectBounds.width * 100) / 100,
|
|
485
|
+
height: Math.round(screenObjectBounds.height * 100) / 100
|
|
486
|
+
});
|
|
487
|
+
console.log('📦 Canvas Object Bounds (canvas):', canvasBounds);
|
|
488
|
+
|
|
489
|
+
// Calculate differences
|
|
490
|
+
const hostVsObject = {
|
|
491
|
+
leftDiff: Math.round((hostRect.left - screenObjectBounds.left) * 100) / 100,
|
|
492
|
+
topDiff: Math.round((hostRect.top - screenObjectBounds.top) * 100) / 100,
|
|
493
|
+
widthDiff: Math.round((hostRect.width - screenObjectBounds.width) * 100) / 100,
|
|
494
|
+
heightDiff: Math.round((hostRect.height - screenObjectBounds.height) * 100) / 100
|
|
495
|
+
};
|
|
496
|
+
const textareaVsObject = {
|
|
497
|
+
leftDiff: Math.round((textareaRect.left - screenObjectBounds.left) * 100) / 100,
|
|
498
|
+
topDiff: Math.round((textareaRect.top - screenObjectBounds.top) * 100) / 100,
|
|
499
|
+
widthDiff: Math.round((textareaRect.width - screenObjectBounds.width) * 100) / 100,
|
|
500
|
+
heightDiff: Math.round((textareaRect.height - screenObjectBounds.height) * 100) / 100
|
|
501
|
+
};
|
|
502
|
+
console.log('📏 Host Div vs Canvas Object Diff:', hostVsObject);
|
|
503
|
+
console.log('📏 Textarea vs Canvas Object Diff:', textareaVsObject);
|
|
504
|
+
|
|
505
|
+
// Check if they're aligned (within 2px tolerance)
|
|
506
|
+
const tolerance = 2;
|
|
507
|
+
const hostAligned = Math.abs(hostVsObject.leftDiff) < tolerance && Math.abs(hostVsObject.topDiff) < tolerance && Math.abs(hostVsObject.widthDiff) < tolerance && Math.abs(hostVsObject.heightDiff) < tolerance;
|
|
508
|
+
const textareaAligned = Math.abs(textareaVsObject.leftDiff) < tolerance && Math.abs(textareaVsObject.topDiff) < tolerance && Math.abs(textareaVsObject.widthDiff) < tolerance && Math.abs(textareaVsObject.heightDiff) < tolerance;
|
|
509
|
+
console.log(hostAligned ? '✅ Host Div ALIGNED with canvas object' : '❌ Host Div MISALIGNED with canvas object');
|
|
510
|
+
console.log(textareaAligned ? '✅ Textarea ALIGNED with canvas object' : '❌ Textarea MISALIGNED with canvas object');
|
|
511
|
+
console.log('🔍 Zoom:', zoom, 'Viewport Transform:', vpt);
|
|
512
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/**
|
|
516
|
+
* Debug method to compare text wrapping between textarea and Fabric text object
|
|
517
|
+
*/
|
|
518
|
+
debugTextWrapping() {
|
|
519
|
+
const target = this.target;
|
|
520
|
+
const text = this.textarea.value;
|
|
521
|
+
console.log('📝 TEXT WRAPPING COMPARISON:');
|
|
522
|
+
console.log('📄 Text Content:', `"${text}"`);
|
|
523
|
+
console.log('📄 Text Length:', text.length);
|
|
524
|
+
|
|
525
|
+
// Analyze line breaks
|
|
526
|
+
const explicitLines = text.split('\n');
|
|
527
|
+
console.log('📄 Explicit Lines (\\n):', explicitLines.length);
|
|
528
|
+
explicitLines.forEach((line, i) => {
|
|
529
|
+
console.log(` Line ${i + 1}: "${line}" (${line.length} chars)`);
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
// Get textarea computed styles for wrapping analysis
|
|
533
|
+
const textareaStyles = window.getComputedStyle(this.textarea);
|
|
534
|
+
console.log('📐 Textarea Wrapping Styles:');
|
|
535
|
+
console.log(' width:', textareaStyles.width);
|
|
536
|
+
console.log(' fontSize:', textareaStyles.fontSize);
|
|
537
|
+
console.log(' fontFamily:', textareaStyles.fontFamily);
|
|
538
|
+
console.log(' fontWeight:', textareaStyles.fontWeight);
|
|
539
|
+
console.log(' letterSpacing:', textareaStyles.letterSpacing);
|
|
540
|
+
console.log(' lineHeight:', textareaStyles.lineHeight);
|
|
541
|
+
console.log(' whiteSpace:', textareaStyles.whiteSpace);
|
|
542
|
+
console.log(' wordWrap:', textareaStyles.wordWrap);
|
|
543
|
+
console.log(' overflowWrap:', textareaStyles.overflowWrap);
|
|
544
|
+
console.log(' direction:', textareaStyles.direction);
|
|
545
|
+
console.log(' textAlign:', textareaStyles.textAlign);
|
|
546
|
+
|
|
547
|
+
// Get Fabric text object properties for comparison
|
|
548
|
+
console.log('📐 Fabric Text Object Properties:');
|
|
549
|
+
console.log(' width:', target.width);
|
|
550
|
+
console.log(' fontSize:', target.fontSize);
|
|
551
|
+
console.log(' fontFamily:', target.fontFamily);
|
|
552
|
+
console.log(' fontWeight:', target.fontWeight);
|
|
553
|
+
console.log(' charSpacing:', target.charSpacing);
|
|
554
|
+
console.log(' lineHeight:', target.lineHeight);
|
|
555
|
+
console.log(' direction:', target.direction);
|
|
556
|
+
console.log(' textAlign:', target.textAlign);
|
|
557
|
+
console.log(' scaleX:', target.scaleX);
|
|
558
|
+
console.log(' scaleY:', target.scaleY);
|
|
559
|
+
|
|
560
|
+
// Calculate effective dimensions for comparison - use actual rendered width
|
|
561
|
+
// **THE FIX:** Use getBoundingRect to get the *actual rendered width* of the Fabric object.
|
|
562
|
+
const fabricEffectiveWidth = this.target.getBoundingRect().width;
|
|
563
|
+
// Use the exact width set on textarea for comparison
|
|
564
|
+
const textareaComputedWidth = parseFloat(window.getComputedStyle(this.textarea).width);
|
|
565
|
+
const textareaEffectiveWidth = textareaComputedWidth / this.canvas.getZoom();
|
|
566
|
+
const widthDiff = Math.abs(textareaEffectiveWidth - fabricEffectiveWidth);
|
|
567
|
+
console.log('📏 Effective Width Comparison:');
|
|
568
|
+
console.log(' Textarea Effective Width:', textareaEffectiveWidth);
|
|
569
|
+
console.log(' Fabric Effective Width:', fabricEffectiveWidth);
|
|
570
|
+
console.log(' Width Difference:', widthDiff.toFixed(2) + 'px');
|
|
571
|
+
console.log(widthDiff < 1 ? '✅ Widths MATCH for wrapping' : '❌ Width MISMATCH may cause different wrapping');
|
|
572
|
+
|
|
573
|
+
// Check text direction and bidi handling
|
|
574
|
+
const hasRTLText = /[\u0590-\u05FF\u0600-\u06FF\u0750-\u077F\uFB50-\uFDFF\uFE70-\uFEFF]/.test(text);
|
|
575
|
+
const hasBidiText = /[\u0590-\u06FF]/.test(text) && /[a-zA-Z]/.test(text);
|
|
576
|
+
console.log('🌍 Text Direction Analysis:');
|
|
577
|
+
console.log(' Has RTL characters:', hasRTLText);
|
|
578
|
+
console.log(' Has mixed Bidi text:', hasBidiText);
|
|
579
|
+
console.log(' Textarea direction:', textareaStyles.direction);
|
|
580
|
+
console.log(' Fabric direction:', target.direction || 'auto');
|
|
581
|
+
console.log(' Textarea unicodeBidi:', textareaStyles.unicodeBidi);
|
|
582
|
+
|
|
583
|
+
// Measure actual rendered line count
|
|
584
|
+
const textareaScrollHeight = this.textarea.scrollHeight;
|
|
585
|
+
const textareaLineHeight = parseFloat(textareaStyles.lineHeight) || parseFloat(textareaStyles.fontSize) * 1.2;
|
|
586
|
+
const estimatedTextareaLines = Math.round(textareaScrollHeight / textareaLineHeight);
|
|
587
|
+
console.log('📊 Line Count Analysis:');
|
|
588
|
+
console.log(' Textarea scrollHeight:', textareaScrollHeight);
|
|
589
|
+
console.log(' Textarea lineHeight:', textareaLineHeight);
|
|
590
|
+
console.log(' Estimated rendered lines:', estimatedTextareaLines);
|
|
591
|
+
console.log(' Explicit line breaks:', explicitLines.length);
|
|
592
|
+
if (estimatedTextareaLines > explicitLines.length) {
|
|
593
|
+
console.log('🔄 Text wrapping detected in textarea');
|
|
594
|
+
console.log(' Wrapped lines:', estimatedTextareaLines - explicitLines.length);
|
|
595
|
+
} else {
|
|
596
|
+
console.log('📏 No text wrapping in textarea');
|
|
597
|
+
}
|
|
598
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
599
|
+
}
|
|
600
|
+
|
|
312
601
|
/**
|
|
313
602
|
* Focus the textarea and position cursor at end
|
|
314
603
|
*/
|
|
@@ -337,6 +626,11 @@ class OverlayEditor {
|
|
|
337
626
|
this.canvas.requestRenderAll();
|
|
338
627
|
this.target.setCoords();
|
|
339
628
|
this.applyOverlayStyle();
|
|
629
|
+
|
|
630
|
+
// Fix character mapping issues after JSON loading for browser-wrapped fonts
|
|
631
|
+
if (this.target._fixCharacterMappingAfterJsonLoad) {
|
|
632
|
+
this.target._fixCharacterMappingAfterJsonLoad();
|
|
633
|
+
}
|
|
340
634
|
this.textarea.focus();
|
|
341
635
|
this.textarea.setSelectionRange(this.textarea.value.length, this.textarea.value.length);
|
|
342
636
|
|
|
@@ -382,6 +676,23 @@ class OverlayEditor {
|
|
|
382
676
|
// Handle commit/cancel after restoring visibility
|
|
383
677
|
if (commit && !this.isComposing) {
|
|
384
678
|
const finalText = this.textarea.value;
|
|
679
|
+
|
|
680
|
+
// Auto-detect text direction and update fabric object if needed
|
|
681
|
+
const detectedDirection = this.firstStrongDir(finalText);
|
|
682
|
+
const currentDirection = this.target.direction || 'ltr';
|
|
683
|
+
if (detectedDirection && detectedDirection !== currentDirection) {
|
|
684
|
+
console.log(`🔄 Overlay Exit: Auto-detected direction change from "${currentDirection}" to "${detectedDirection}"`);
|
|
685
|
+
console.log(` Text content: "${finalText.substring(0, 50)}..."`);
|
|
686
|
+
|
|
687
|
+
// Update the fabric object's direction
|
|
688
|
+
this.target.set('direction', detectedDirection);
|
|
689
|
+
|
|
690
|
+
// Force a re-render to apply the direction change
|
|
691
|
+
this.canvas.requestRenderAll();
|
|
692
|
+
console.log(`✅ Fabric object direction updated to: ${detectedDirection}`);
|
|
693
|
+
} else {
|
|
694
|
+
console.log(`📝 Overlay Exit: Direction unchanged (${currentDirection}), text: "${finalText.substring(0, 30)}..."`);
|
|
695
|
+
}
|
|
385
696
|
if (this.onCommit) {
|
|
386
697
|
this.onCommit(finalText);
|
|
387
698
|
}
|
|
@@ -421,25 +732,40 @@ class OverlayEditor {
|
|
|
421
732
|
}
|
|
422
733
|
}
|
|
423
734
|
autoResizeTextarea() {
|
|
424
|
-
//
|
|
425
|
-
const
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
735
|
+
// Store the scroll position and the container's old height for comparison.
|
|
736
|
+
const scrollTop = this.textarea.scrollTop;
|
|
737
|
+
const oldHeight = parseFloat(this.hostDiv.style.height || '0');
|
|
738
|
+
|
|
739
|
+
// 1. **Force a reliable reflow.**
|
|
740
|
+
// First, reset the textarea's height to a minimal value. This is the crucial step
|
|
741
|
+
// that forces the browser to recalculate the content's height from scratch,
|
|
742
|
+
// ignoring the hostDiv's larger, stale height.
|
|
743
|
+
this.textarea.style.height = '1px';
|
|
744
|
+
|
|
745
|
+
// 2. Read the now-accurate scrollHeight. This value reflects the minimum
|
|
746
|
+
// height required for the content, whether it's single or multi-line.
|
|
429
747
|
const scrollHeight = this.textarea.scrollHeight;
|
|
430
748
|
|
|
431
|
-
//
|
|
432
|
-
const
|
|
433
|
-
const newHeight =
|
|
434
|
-
const heightChanged = Math.abs(newHeight - oldHeight) > 2; // Only if meaningful change
|
|
749
|
+
// A small buffer for rendering consistency across browsers.
|
|
750
|
+
const buffer = 2;
|
|
751
|
+
const newHeight = scrollHeight + buffer;
|
|
435
752
|
|
|
436
|
-
|
|
437
|
-
|
|
753
|
+
// Check if the height has changed significantly.
|
|
754
|
+
const heightChanged = Math.abs(newHeight - oldHeight) > 1;
|
|
438
755
|
|
|
439
|
-
// Only update object bounds if
|
|
756
|
+
// 4. Only update heights and object bounds if there was a change.
|
|
440
757
|
if (heightChanged) {
|
|
758
|
+
this.textarea.style.height = `${newHeight}px`;
|
|
759
|
+
this.hostDiv.style.height = `${newHeight}px`;
|
|
441
760
|
this.updateObjectBounds();
|
|
761
|
+
} else {
|
|
762
|
+
// If no significant change, ensure the textarea's height matches the container
|
|
763
|
+
// to prevent any minor visual misalignment.
|
|
764
|
+
this.textarea.style.height = this.hostDiv.style.height;
|
|
442
765
|
}
|
|
766
|
+
|
|
767
|
+
// 5. Restore the original scroll position.
|
|
768
|
+
this.textarea.scrollTop = scrollTop;
|
|
443
769
|
}
|
|
444
770
|
handleKeyDown(e) {
|
|
445
771
|
if (e.key === 'Escape') {
|
|
@@ -448,6 +774,19 @@ class OverlayEditor {
|
|
|
448
774
|
} else if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {
|
|
449
775
|
e.preventDefault();
|
|
450
776
|
this.destroy(true); // Commit
|
|
777
|
+
} else if (e.key === 'Enter' || e.key === 'Backspace' || e.key === 'Delete') {
|
|
778
|
+
// For keys that might change the height, schedule a resize check
|
|
779
|
+
// Use both immediate and delayed checks to catch all scenarios
|
|
780
|
+
requestAnimationFrame(() => {
|
|
781
|
+
if (!this.isDestroyed) {
|
|
782
|
+
this.autoResizeTextarea();
|
|
783
|
+
}
|
|
784
|
+
});
|
|
785
|
+
setTimeout(() => {
|
|
786
|
+
if (!this.isDestroyed) {
|
|
787
|
+
this.autoResizeTextarea();
|
|
788
|
+
}
|
|
789
|
+
}, 10); // Small delay to ensure DOM is updated
|
|
451
790
|
}
|
|
452
791
|
}
|
|
453
792
|
handleFocus() {
|