diff --git a/CHANGELOG.md b/CHANGELOG.md index b558fb957cc..8359f974884 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## [next] +- fix() Textbox inputs with new lines, regression from #9097 [#9192](https://github.com/fabricjs/fabric.js/pull/9192) - docs(): add link to contributing guide [#8393](https://github.com/fabricjs/fabric.js/pull/8393) - test(e2e): Drag&Drop tests [#9112](https://github.com/fabricjs/fabric.js/pull/9112) - fix(CanvasEvents): regression of `getPointer` usages + BREAKING: drop event data [#9186](https://github.com/fabricjs/fabric.js/pull/9186) diff --git a/e2e/tests/text/adding-text/index.spec.ts b/e2e/tests/text/adding-text/index.spec.ts new file mode 100644 index 00000000000..c62670b7a8c --- /dev/null +++ b/e2e/tests/text/adding-text/index.spec.ts @@ -0,0 +1,85 @@ +import { CanvasUtil } from '../../../utils/CanvasUtil'; +import { expect, test } from '@playwright/test'; +import { ObjectUtil } from '../../../utils/ObjectUtil'; +import type { Textbox } from 'fabric'; +import '../../../setup'; + +[false, true].forEach((splitByGrapheme) => { + test(`adding new lines and copy paste - splitByGrapheme: ${splitByGrapheme}`, async ({ + page, + context, + }) => { + await context.grantPermissions(['clipboard-read', 'clipboard-write']); + const canvasUtil = new CanvasUtil(page); + const textBoxutil = new ObjectUtil(page, 'text'); + + await textBoxutil.executeInBrowser( + (textbox: Textbox, context) => { + textbox.splitByGrapheme = context.splitByGrapheme; + textbox.set('dirty', true); + textbox.initDimensions(); + textbox.canvas.renderAll(); + }, + { splitByGrapheme } + ); + + await expect(await canvasUtil.screenshot()).toMatchSnapshot({ + name: `1-initial-splitByGrapheme-${splitByGrapheme}.png`, + }); + await canvasUtil.click({ + position: { + x: 50, + y: 65, + }, + delay: 200, + }); + await canvasUtil.click({ + position: { + x: 50, + y: 65, + }, + delay: 200, + }); + await page.mouse.down(); + await page.mouse.move(65, 120, { steps: 15 }); + await page.mouse.up(); + await canvasUtil.ctrlC(); + await canvasUtil.click({ + position: { + x: 176, + y: 65, + }, + delay: 200, + }); + await canvasUtil.press('Enter'); + await canvasUtil.press('Enter'); + await canvasUtil.press('a'); + await canvasUtil.press('b'); + await canvasUtil.press('c'); + await canvasUtil.press('Enter'); + await canvasUtil.press('Enter'); + await expect(await canvasUtil.screenshot()).toMatchSnapshot({ + name: `2-before-pasting-splitByGrapheme-${splitByGrapheme}.png`, + }); + await canvasUtil.ctrlV(); + await expect(await canvasUtil.screenshot()).toMatchSnapshot({ + name: `3-after-pasting-splitByGrapheme-${splitByGrapheme}.png`, + maxDiffPixelRatio: 0.03, + }); + // NOTE: Here is clear that there style bug of #9028 is visible splitbygrapheme true only + // to be triggered the copy paste has to happen across lines + await canvasUtil.click({ + position: { + x: 176, + y: 152, + }, + delay: 200, + }); + await canvasUtil.press('Enter'); + await canvasUtil.press('Enter'); + await expect(await canvasUtil.screenshot()).toMatchSnapshot({ + name: `4-after-adding-more-lines-splitByGrapheme-${splitByGrapheme}.png`, + maxDiffPixelRatio: 0.03, + }); + }); +}); diff --git a/e2e/tests/text/adding-text/index.spec.ts-snapshots/1-initial-splitByGrapheme-false.png b/e2e/tests/text/adding-text/index.spec.ts-snapshots/1-initial-splitByGrapheme-false.png new file mode 100644 index 00000000000..77797ff4e7b Binary files /dev/null and b/e2e/tests/text/adding-text/index.spec.ts-snapshots/1-initial-splitByGrapheme-false.png differ diff --git a/e2e/tests/text/adding-text/index.spec.ts-snapshots/1-initial-splitByGrapheme-true.png b/e2e/tests/text/adding-text/index.spec.ts-snapshots/1-initial-splitByGrapheme-true.png new file mode 100644 index 00000000000..d0fdb3b1b02 Binary files /dev/null and b/e2e/tests/text/adding-text/index.spec.ts-snapshots/1-initial-splitByGrapheme-true.png differ diff --git a/e2e/tests/text/adding-text/index.spec.ts-snapshots/2-before-pasting-splitByGrapheme-false.png b/e2e/tests/text/adding-text/index.spec.ts-snapshots/2-before-pasting-splitByGrapheme-false.png new file mode 100644 index 00000000000..da44f464151 Binary files /dev/null and b/e2e/tests/text/adding-text/index.spec.ts-snapshots/2-before-pasting-splitByGrapheme-false.png differ diff --git a/e2e/tests/text/adding-text/index.spec.ts-snapshots/2-before-pasting-splitByGrapheme-true.png b/e2e/tests/text/adding-text/index.spec.ts-snapshots/2-before-pasting-splitByGrapheme-true.png new file mode 100644 index 00000000000..9b1b6e6bf96 Binary files /dev/null and b/e2e/tests/text/adding-text/index.spec.ts-snapshots/2-before-pasting-splitByGrapheme-true.png differ diff --git a/e2e/tests/text/adding-text/index.spec.ts-snapshots/3-after-pasting-splitByGrapheme-false.png b/e2e/tests/text/adding-text/index.spec.ts-snapshots/3-after-pasting-splitByGrapheme-false.png new file mode 100644 index 00000000000..f1025356dc0 Binary files /dev/null and b/e2e/tests/text/adding-text/index.spec.ts-snapshots/3-after-pasting-splitByGrapheme-false.png differ diff --git a/e2e/tests/text/adding-text/index.spec.ts-snapshots/3-after-pasting-splitByGrapheme-true.png b/e2e/tests/text/adding-text/index.spec.ts-snapshots/3-after-pasting-splitByGrapheme-true.png new file mode 100644 index 00000000000..978d4c00afb Binary files /dev/null and b/e2e/tests/text/adding-text/index.spec.ts-snapshots/3-after-pasting-splitByGrapheme-true.png differ diff --git a/e2e/tests/text/adding-text/index.spec.ts-snapshots/4-after-adding-more-lines-splitByGrapheme-false.png b/e2e/tests/text/adding-text/index.spec.ts-snapshots/4-after-adding-more-lines-splitByGrapheme-false.png new file mode 100644 index 00000000000..be86f063323 Binary files /dev/null and b/e2e/tests/text/adding-text/index.spec.ts-snapshots/4-after-adding-more-lines-splitByGrapheme-false.png differ diff --git a/e2e/tests/text/adding-text/index.spec.ts-snapshots/4-after-adding-more-lines-splitByGrapheme-true.png b/e2e/tests/text/adding-text/index.spec.ts-snapshots/4-after-adding-more-lines-splitByGrapheme-true.png new file mode 100644 index 00000000000..21d686e612a Binary files /dev/null and b/e2e/tests/text/adding-text/index.spec.ts-snapshots/4-after-adding-more-lines-splitByGrapheme-true.png differ diff --git a/e2e/tests/text/adding-text/index.ts b/e2e/tests/text/adding-text/index.ts new file mode 100644 index 00000000000..ff9f9ed0a81 --- /dev/null +++ b/e2e/tests/text/adding-text/index.ts @@ -0,0 +1,32 @@ +import { Textbox, util } from 'fabric'; +import { beforeAll } from '../../test'; + +beforeAll( + (canvas) => { + const textValue = 'fabric.js sandbox'; + const text = new Textbox(textValue, { + originX: 'center', + objectCaching: false, + splitByGrapheme: true, + width: 200, + top: 20, + styles: util.stylesFromArray( + [ + { + style: { + fontWeight: 'bold', + fontSize: 64, + }, + start: 0, + end: 9, + }, + ], + textValue + ), + }); + canvas.add(text); + canvas.centerObjectH(text); + return { text }; + }, + { width: 300, height: 700 } +); diff --git a/e2e/utils/CanvasUtil.ts b/e2e/utils/CanvasUtil.ts index 691c84637ff..d5a67672d05 100644 --- a/e2e/utils/CanvasUtil.ts +++ b/e2e/utils/CanvasUtil.ts @@ -1,5 +1,6 @@ import { type LocatorScreenshotOptions, type Page } from '@playwright/test'; import type { Canvas } from 'fabric'; +import os from 'node:os'; export class CanvasUtil { constructor(readonly page: Page, readonly selector = '#canvas') {} @@ -8,6 +9,22 @@ export class CanvasUtil { return this.page.click(`canvas_top=${this.selector}`, clickProperties); } + press(keyPressed: Parameters[1]) { + return this.page.keyboard.press(keyPressed, { delay: 200 }); + } + + ctrlC(): Promise { + const isMac = os.platform() === 'darwin'; + const modifier = isMac ? 'Meta' : 'Control'; + return this.page.keyboard.press(`${modifier}+KeyC`); + } + + ctrlV(): Promise { + const isMac = os.platform() === 'darwin'; + const modifier = isMac ? 'Meta' : 'Control'; + return this.page.keyboard.press(`${modifier}+KeyV`); + } + screenshot(options: LocatorScreenshotOptions = {}) { return this.page .locator(`canvas_wrapper=${this.selector}`) diff --git a/src/shapes/Textbox.ts b/src/shapes/Textbox.ts index 6ad7a168b20..3714bc570ec 100644 --- a/src/shapes/Textbox.ts +++ b/src/shapes/Textbox.ts @@ -339,7 +339,7 @@ export class Textbox< : this.wordSplit(line); if (wordsOrGraphemes.length === 0) { - return []; + return [{ word: [], width: 0 }]; } return wordsOrGraphemes.map((word: string) => { @@ -349,7 +349,7 @@ export class Textbox< : this.graphemeSplit(word); const width = this._measureWord(graphemeArray, lineIndex, offset); largestWordWidth = Math.max(width, largestWordWidth); - offset += word.length + infix.length; + offset += graphemeArray.length + infix.length; return { word: graphemeArray, width }; }); });