diff --git a/CHANGELOG.md b/CHANGELOG.md index 0fa23cef..25b3c7ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## 9.3.18 (2024-12-17) (unreleased) + +- Fix emoji rendering with letterSpacing + ## 9.3.17 (2024-12-02) (unreleased) - Fix `Arrow.getClientRect()` diff --git a/src/shapes/Text.ts b/src/shapes/Text.ts index dbd3b948..ced0fd1f 100644 --- a/src/shapes/Text.ts +++ b/src/shapes/Text.ts @@ -16,13 +16,14 @@ import { GetSet } from '../types'; export function stringToArray(string: string): string[] { // Use Unicode-aware splitting return [...string].reduce((acc, char, index, array) => { - // Handle emoji sequences (including ZWJ sequences) - if ( - /\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?(?:\u200D\p{Emoji_Presentation})+/u.test( - char - ) - ) { - acc.push(char); + // Handle emoji with skin tone modifiers and ZWJ sequences + if (/\p{Emoji}/u.test(char)) { + if (acc.length > 0 && /\p{Emoji}/u.test(acc[acc.length - 1])) { + // Combine with previous emoji if it's part of a sequence + acc[acc.length - 1] += char; + } else { + acc.push(char); + } } // Handle regional indicator symbols (flags) else if ( @@ -310,7 +311,7 @@ export class Text extends Shape { spacesNumber = text.split(' ').length - 1; oneWord = spacesNumber === 0; lineWidth = - align === JUSTIFY && !lastLine ? totalWidth - padding * 2 : width; + align === JUSTIFY && !lastLine ? totalWidth - padding * 2 : width; context.lineTo( lineTranslateX + Math.round(lineWidth), translateY + lineTranslateY + yOffset @@ -383,7 +384,8 @@ export class Text extends Shape { return isAuto ? this.getTextWidth() + this.padding() * 2 : this.attrs.width; } getHeight() { - const isAuto = this.attrs.height === AUTO || this.attrs.height === undefined; + const isAuto = + this.attrs.height === AUTO || this.attrs.height === undefined; return isAuto ? this.fontSize() * this.textArr.length * this.lineHeight() + this.padding() * 2 @@ -501,7 +503,9 @@ export class Text extends Shape { this.textArr = []; getDummyContext().font = this._getContextFont(); - const additionalWidth = shouldAddEllipsis ? this._getTextWidth(ELLIPSIS) : 0; + const additionalWidth = shouldAddEllipsis + ? this._getTextWidth(ELLIPSIS) + : 0; for (let i = 0, max = lines.length; i < max; ++i) { let line = lines[i]; diff --git a/test/unit/Text-test.ts b/test/unit/Text-test.ts index 6f5ae001..25897e98 100644 --- a/test/unit/Text-test.ts +++ b/test/unit/Text-test.ts @@ -146,7 +146,7 @@ describe('Text', function () { var text = new Konva.Text({ x: 10, y: 10, - text: '😬', + text: '😬👧🏿', fontSize: 50, letterSpacing: 1, }); @@ -159,7 +159,7 @@ describe('Text', function () { context.textBaseline = 'middle'; context.font = 'normal normal 50px Arial'; context.fillStyle = 'darkgrey'; - context.fillText('😬', 10, 10 + 25); + context.fillText('😬👧🏿', 10, 10 + 25); compareLayerAndCanvas(layer, canvas, 254); });