diff --git a/blocksuite/affine/blocks/code/src/highlight/affine-code-unit.ts b/blocksuite/affine/blocks/code/src/highlight/affine-code-unit.ts index 684f7e4ae1..1fff01008c 100644 --- a/blocksuite/affine/blocks/code/src/highlight/affine-code-unit.ts +++ b/blocksuite/affine/blocks/code/src/highlight/affine-code-unit.ts @@ -1,7 +1,7 @@ import { affineTextStyles } from '@blocksuite/affine-shared/styles'; import type { AffineTextAttributes } from '@blocksuite/affine-shared/types'; import { ShadowlessElement } from '@blocksuite/std'; -import { ZERO_WIDTH_SPACE } from '@blocksuite/std/inline'; +import { ZERO_WIDTH_FOR_EMPTY_LINE } from '@blocksuite/std/inline'; import type { DeltaInsert } from '@blocksuite/store'; import { html } from 'lit'; import { property } from 'lit/decorators.js'; @@ -111,7 +111,7 @@ export class AffineCodeUnit extends ShadowlessElement { @property({ type: Object }) accessor delta: DeltaInsert = { - insert: ZERO_WIDTH_SPACE, + insert: ZERO_WIDTH_FOR_EMPTY_LINE, }; } diff --git a/blocksuite/affine/inlines/footnote/src/footnote-node/footnote-node.ts b/blocksuite/affine/inlines/footnote/src/footnote-node/footnote-node.ts index 7d0eadf958..9aa7a3394c 100644 --- a/blocksuite/affine/inlines/footnote/src/footnote-node/footnote-node.ts +++ b/blocksuite/affine/inlines/footnote/src/footnote-node/footnote-node.ts @@ -12,8 +12,8 @@ import { import { INLINE_ROOT_ATTR, type InlineRootElement, - ZERO_WIDTH_NON_JOINER, - ZERO_WIDTH_SPACE, + ZERO_WIDTH_FOR_EMBED_NODE, + ZERO_WIDTH_FOR_EMPTY_LINE, } from '@blocksuite/std/inline'; import type { DeltaInsert } from '@blocksuite/store'; import { shift } from '@floating-ui/dom'; @@ -186,7 +186,7 @@ export class AffineFootnoteNode extends WithDisposable(ShadowlessElement) { return html`${node}${node}`; } @@ -195,7 +195,7 @@ export class AffineFootnoteNode extends WithDisposable(ShadowlessElement) { @property({ type: Object }) accessor delta: DeltaInsert = { - insert: ZERO_WIDTH_SPACE, + insert: ZERO_WIDTH_FOR_EMPTY_LINE, attributes: {}, }; diff --git a/blocksuite/affine/inlines/latex/src/latex-node/latex-editor-unit.ts b/blocksuite/affine/inlines/latex/src/latex-node/latex-editor-unit.ts index ac0fce9d06..803dc84b41 100644 --- a/blocksuite/affine/inlines/latex/src/latex-node/latex-editor-unit.ts +++ b/blocksuite/affine/inlines/latex/src/latex-node/latex-editor-unit.ts @@ -1,6 +1,6 @@ import type { AffineTextAttributes } from '@blocksuite/affine-shared/types'; import { ShadowlessElement } from '@blocksuite/std'; -import { ZERO_WIDTH_SPACE } from '@blocksuite/std/inline'; +import { ZERO_WIDTH_FOR_EMPTY_LINE } from '@blocksuite/std/inline'; import type { DeltaInsert } from '@blocksuite/store'; import { html } from 'lit'; import { property } from 'lit/decorators.js'; @@ -50,6 +50,6 @@ export class LatexEditorUnit extends ShadowlessElement { @property({ attribute: false }) accessor delta: DeltaInsert = { - insert: ZERO_WIDTH_SPACE, + insert: ZERO_WIDTH_FOR_EMPTY_LINE, }; } diff --git a/blocksuite/affine/inlines/latex/src/latex-node/latex-node.ts b/blocksuite/affine/inlines/latex/src/latex-node/latex-node.ts index c1a5931219..1767bb3176 100644 --- a/blocksuite/affine/inlines/latex/src/latex-node/latex-node.ts +++ b/blocksuite/affine/inlines/latex/src/latex-node/latex-node.ts @@ -9,8 +9,8 @@ import { } from '@blocksuite/std'; import { type InlineEditor, - ZERO_WIDTH_NON_JOINER, - ZERO_WIDTH_SPACE, + ZERO_WIDTH_FOR_EMBED_NODE, + ZERO_WIDTH_FOR_EMPTY_LINE, } from '@blocksuite/std/inline'; import type { DeltaInsert } from '@blocksuite/store'; import { signal } from '@preact/signals-core'; @@ -178,7 +178,7 @@ export class AffineLatexNode extends SignalWatcher( override render() { return html`
-
`; } @@ -244,7 +244,7 @@ export class AffineLatexNode extends SignalWatcher( @property({ attribute: false }) accessor delta: DeltaInsert = { - insert: ZERO_WIDTH_SPACE, + insert: ZERO_WIDTH_FOR_EMPTY_LINE, }; @property({ attribute: false }) diff --git a/blocksuite/affine/inlines/link/src/link-node/affine-link.ts b/blocksuite/affine/inlines/link/src/link-node/affine-link.ts index 0fed7e1412..b78e1dd797 100644 --- a/blocksuite/affine/inlines/link/src/link-node/affine-link.ts +++ b/blocksuite/affine/inlines/link/src/link-node/affine-link.ts @@ -13,7 +13,7 @@ import { BLOCK_ID_ATTR, ShadowlessElement } from '@blocksuite/std'; import { INLINE_ROOT_ATTR, type InlineRootElement, - ZERO_WIDTH_SPACE, + ZERO_WIDTH_FOR_EMPTY_LINE, } from '@blocksuite/std/inline'; import type { DeltaInsert } from '@blocksuite/store'; import { css, html } from 'lit'; @@ -177,7 +177,7 @@ export class AffineLink extends WithDisposable(ShadowlessElement) { @property({ type: Object }) accessor delta: DeltaInsert = { - insert: ZERO_WIDTH_SPACE, + insert: ZERO_WIDTH_FOR_EMPTY_LINE, }; @property({ attribute: false }) diff --git a/blocksuite/affine/inlines/mention/src/affine-mention.ts b/blocksuite/affine/inlines/mention/src/affine-mention.ts index 0ae98fce2d..4e647c653d 100644 --- a/blocksuite/affine/inlines/mention/src/affine-mention.ts +++ b/blocksuite/affine/inlines/mention/src/affine-mention.ts @@ -5,8 +5,8 @@ import { SignalWatcher, WithDisposable } from '@blocksuite/global/lit'; import type { BlockStdScope } from '@blocksuite/std'; import { ShadowlessElement } from '@blocksuite/std'; import { - ZERO_WIDTH_NON_JOINER, - ZERO_WIDTH_SPACE, + ZERO_WIDTH_FOR_EMBED_NODE, + ZERO_WIDTH_FOR_EMPTY_LINE, } from '@blocksuite/std/inline'; import type { DeltaInsert } from '@blocksuite/store'; import { css, html } from 'lit'; @@ -88,7 +88,7 @@ export class AffineMention extends SignalWatcher( data-selected=${this.selected} data-type="error" class="affine-mention" - >@Unknown Member@Unknown Member`; const userService = this.std.getOptional(UserProvider); @@ -107,7 +107,7 @@ export class AffineMention extends SignalWatcher( data-selected=${this.selected} data-type="removed" class="affine-mention" - >@Inactive Member@Inactive Member`; } else { return html`@${userInfo$.value.name ?? 'Unknown'}`; } @@ -129,7 +129,7 @@ export class AffineMention extends SignalWatcher( >@loading...`; } @@ -138,7 +138,7 @@ export class AffineMention extends SignalWatcher( @property({ type: Object }) accessor delta: DeltaInsert = { - insert: ZERO_WIDTH_SPACE, + insert: ZERO_WIDTH_FOR_EMPTY_LINE, attributes: {}, }; diff --git a/blocksuite/affine/inlines/preset/src/nodes/affine-text.ts b/blocksuite/affine/inlines/preset/src/nodes/affine-text.ts index 8333e130e6..8bb104d00b 100644 --- a/blocksuite/affine/inlines/preset/src/nodes/affine-text.ts +++ b/blocksuite/affine/inlines/preset/src/nodes/affine-text.ts @@ -1,7 +1,7 @@ import { affineTextStyles } from '@blocksuite/affine-shared/styles'; import type { AffineTextAttributes } from '@blocksuite/affine-shared/types'; import { ShadowlessElement } from '@blocksuite/std'; -import { ZERO_WIDTH_SPACE } from '@blocksuite/std/inline'; +import { ZERO_WIDTH_FOR_EMPTY_LINE } from '@blocksuite/std/inline'; import type { DeltaInsert } from '@blocksuite/store'; import { html } from 'lit'; import { property } from 'lit/decorators.js'; @@ -30,6 +30,6 @@ export class AffineText extends ShadowlessElement { @property({ type: Object }) accessor delta: DeltaInsert = { - insert: ZERO_WIDTH_SPACE, + insert: ZERO_WIDTH_FOR_EMPTY_LINE, }; } diff --git a/blocksuite/affine/inlines/reference/src/reference-node/reference-node.ts b/blocksuite/affine/inlines/reference/src/reference-node/reference-node.ts index 923eb36c2c..619ddd6d1a 100644 --- a/blocksuite/affine/inlines/reference/src/reference-node/reference-node.ts +++ b/blocksuite/affine/inlines/reference/src/reference-node/reference-node.ts @@ -22,8 +22,8 @@ import { BLOCK_ID_ATTR, ShadowlessElement } from '@blocksuite/std'; import { INLINE_ROOT_ATTR, type InlineRootElement, - ZERO_WIDTH_NON_JOINER, - ZERO_WIDTH_SPACE, + ZERO_WIDTH_FOR_EMBED_NODE, + ZERO_WIDTH_FOR_EMPTY_LINE, } from '@blocksuite/std/inline'; import type { DeltaInsert, DocMeta, Store } from '@blocksuite/store'; import { css, html, nothing } from 'lit'; @@ -274,14 +274,14 @@ export class AffineReference extends WithDisposable(ShadowlessElement) { >${title}`; - // we need to add `` in an + // we need to add `` in an // embed element to make sure inline range calculation is correct return html` this.open({ event })} - >${content}${content}`; } @@ -299,7 +299,7 @@ export class AffineReference extends WithDisposable(ShadowlessElement) { @property({ type: Object }) accessor delta: DeltaInsert = { - insert: ZERO_WIDTH_SPACE, + insert: ZERO_WIDTH_FOR_EMPTY_LINE, attributes: {}, }; diff --git a/blocksuite/framework/std/src/inline/components/v-element.ts b/blocksuite/framework/std/src/inline/components/v-element.ts index 530913b413..5bd2a020be 100644 --- a/blocksuite/framework/std/src/inline/components/v-element.ts +++ b/blocksuite/framework/std/src/inline/components/v-element.ts @@ -7,7 +7,7 @@ import { html, LitElement } from 'lit'; import { property } from 'lit/decorators.js'; import { styleMap } from 'lit/directives/style-map.js'; -import { ZERO_WIDTH_SPACE } from '../consts.js'; +import { ZERO_WIDTH_FOR_EMPTY_LINE } from '../consts.js'; import type { InlineEditor } from '../inline-editor.js'; import { isInlineRangeIntersect } from '../utils/inline-range.js'; @@ -90,7 +90,7 @@ export class VElement< @property({ type: Object }) accessor delta: DeltaInsert = { - insert: ZERO_WIDTH_SPACE, + insert: ZERO_WIDTH_FOR_EMPTY_LINE, }; @property({ attribute: false }) diff --git a/blocksuite/framework/std/src/inline/components/v-line.ts b/blocksuite/framework/std/src/inline/components/v-line.ts index 1c9ec99e52..a2f6af6247 100644 --- a/blocksuite/framework/std/src/inline/components/v-line.ts +++ b/blocksuite/framework/std/src/inline/components/v-line.ts @@ -4,7 +4,7 @@ import { html, LitElement, type TemplateResult } from 'lit'; import { property } from 'lit/decorators.js'; import { styleMap } from 'lit/directives/style-map.js'; -import { INLINE_ROOT_ATTR, ZERO_WIDTH_SPACE } from '../consts.js'; +import { INLINE_ROOT_ATTR, ZERO_WIDTH_FOR_EMPTY_LINE } from '../consts.js'; import type { InlineRootElement } from '../inline-editor.js'; import { EmbedGap } from './embed-gap.js'; @@ -89,7 +89,9 @@ export class VLine extends LitElement { renderVElements() { if (this.elements.length === 0) { // don't use v-element because it not correspond to the actual delta - return html`
`; + return html` +
+ `; } const inlineEditor = this.inlineEditor; diff --git a/blocksuite/framework/std/src/inline/components/v-text.ts b/blocksuite/framework/std/src/inline/components/v-text.ts index 9e6b2586d1..4e0ce4ae02 100644 --- a/blocksuite/framework/std/src/inline/components/v-text.ts +++ b/blocksuite/framework/std/src/inline/components/v-text.ts @@ -2,7 +2,7 @@ import { html, LitElement } from 'lit'; import { property } from 'lit/decorators.js'; import { styleMap } from 'lit/directives/style-map.js'; -import { ZERO_WIDTH_SPACE } from '../consts.js'; +import { ZERO_WIDTH_FOR_EMPTY_LINE } from '../consts.js'; export class VText extends LitElement { override createRenderRoot() { @@ -24,7 +24,7 @@ export class VText extends LitElement { } @property({ attribute: false }) - accessor str: string = ZERO_WIDTH_SPACE; + accessor str: string = ZERO_WIDTH_FOR_EMPTY_LINE; } declare global { diff --git a/blocksuite/framework/std/src/inline/consts.ts b/blocksuite/framework/std/src/inline/consts.ts index 37057e1739..d626dea077 100644 --- a/blocksuite/framework/std/src/inline/consts.ts +++ b/blocksuite/framework/std/src/inline/consts.ts @@ -1,5 +1,6 @@ -export const ZERO_WIDTH_SPACE = '\u200C'; -// see https://en.wikipedia.org/wiki/Zero-width_non-joiner -export const ZERO_WIDTH_NON_JOINER = '\u200B'; +import { IS_SAFARI } from '@blocksuite/global/env'; + +export const ZERO_WIDTH_FOR_EMPTY_LINE = IS_SAFARI ? '\u200C' : '\u200B'; +export const ZERO_WIDTH_FOR_EMBED_NODE = IS_SAFARI ? '\u200B' : '\u200C'; export const INLINE_ROOT_ATTR = 'data-v-root'; diff --git a/blocksuite/framework/std/src/inline/utils/point-conversion.ts b/blocksuite/framework/std/src/inline/utils/point-conversion.ts index 7e891b289a..dd0a7bf659 100644 --- a/blocksuite/framework/std/src/inline/utils/point-conversion.ts +++ b/blocksuite/framework/std/src/inline/utils/point-conversion.ts @@ -1,7 +1,7 @@ import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions'; import type { VElement, VLine } from '../components/index.js'; -import { INLINE_ROOT_ATTR, ZERO_WIDTH_SPACE } from '../consts.js'; +import { INLINE_ROOT_ATTR, ZERO_WIDTH_FOR_EMPTY_LINE } from '../consts.js'; import type { DomPoint, TextPoint } from '../types.js'; import { isInlineRoot, @@ -76,7 +76,7 @@ export function textPointToDomPoint( index += calculateTextLength(text); } - if (text.wholeText !== ZERO_WIDTH_SPACE) { + if (text.wholeText !== ZERO_WIDTH_FOR_EMPTY_LINE) { index += offset; } diff --git a/blocksuite/framework/std/src/inline/utils/text.ts b/blocksuite/framework/std/src/inline/utils/text.ts index edbeedcc77..a9534c72d9 100644 --- a/blocksuite/framework/std/src/inline/utils/text.ts +++ b/blocksuite/framework/std/src/inline/utils/text.ts @@ -1,7 +1,7 @@ -import { ZERO_WIDTH_SPACE } from '../consts.js'; +import { ZERO_WIDTH_FOR_EMPTY_LINE } from '../consts.js'; export function calculateTextLength(text: Text): number { - if (text.wholeText === ZERO_WIDTH_SPACE) { + if (text.wholeText === ZERO_WIDTH_FOR_EMPTY_LINE) { return 0; } else { return text.wholeText.length; diff --git a/blocksuite/playground/examples/inline/test-page.ts b/blocksuite/playground/examples/inline/test-page.ts index 58bb4aef75..062730aa73 100644 --- a/blocksuite/playground/examples/inline/test-page.ts +++ b/blocksuite/playground/examples/inline/test-page.ts @@ -5,7 +5,7 @@ import { effects } from '@blocksuite/affine/std/effects'; import { type AttributeRenderer, InlineEditor, - ZERO_WIDTH_NON_JOINER, + ZERO_WIDTH_FOR_EMBED_NODE, } from '@blocksuite/affine/std/inline'; import { type BaseTextAttributes, @@ -62,7 +62,7 @@ const attributeRenderer: AttributeRenderer = ({ delta, selected }) => { border: selected ? '1px solid #eb763a' : '', background: 'rgba(135,131,120,0.15)', })} - >@flrande@flrande`; } diff --git a/tests/blocksuite/e2e/basic.spec.ts b/tests/blocksuite/e2e/basic.spec.ts index 1815c894c1..db4d8d80f6 100644 --- a/tests/blocksuite/e2e/basic.spec.ts +++ b/tests/blocksuite/e2e/basic.spec.ts @@ -394,7 +394,7 @@ test(scoped`delete emoji forward`, async ({ page }) => { }); test( - scoped`ZERO_WIDTH_SPACE should be counted by one cursor position`, + scoped`ZERO_WIDTH_FOR_EMPTY_LINE should be counted by one cursor position`, async ({ page }) => { await enterPlaygroundRoom(page); await initEmptyParagraphState(page); diff --git a/tests/blocksuite/e2e/database/actions.ts b/tests/blocksuite/e2e/database/actions.ts index 4b831becc5..209c3c913c 100644 --- a/tests/blocksuite/e2e/database/actions.ts +++ b/tests/blocksuite/e2e/database/actions.ts @@ -12,7 +12,7 @@ import { getEditorLocator, waitNextFrame, } from '../utils/actions/misc.js'; -import { ZERO_WIDTH_SPACE } from '../utils/inline-editor.js'; +import { ZERO_WIDTH_FOR_EMPTY_LINE } from '../utils/inline-editor.js'; export async function press(page: Page, content: string) { await page.keyboard.press(content, { delay: 50 }); @@ -95,7 +95,7 @@ export async function assertDatabaseTitleColumnText( const text = await selectCell1.innerText(); if (title === '') { - expect(text).toMatch(new RegExp(`^(|[${ZERO_WIDTH_SPACE}])$`)); + expect(text).toMatch(new RegExp(`^(|[${ZERO_WIDTH_FOR_EMPTY_LINE}])$`)); } else { expect(text).toBe(title); } diff --git a/tests/blocksuite/e2e/inline/inline-editor.spec.ts b/tests/blocksuite/e2e/inline/inline-editor.spec.ts index 2ea45ffc16..907d09db7d 100644 --- a/tests/blocksuite/e2e/inline/inline-editor.spec.ts +++ b/tests/blocksuite/e2e/inline/inline-editor.spec.ts @@ -15,7 +15,7 @@ import { initEmptyParagraphState, } from '../utils/actions/misc.js'; import { assertRichTextInlineDeltas } from '../utils/asserts.js'; -import { ZERO_WIDTH_SPACE } from '../utils/inline-editor.js'; +import { ZERO_WIDTH_FOR_EMPTY_LINE } from '../utils/inline-editor.js'; // FIXME(mirone): copy paste from framework/inline/__tests__/utils.ts const defaultPlaygroundURL = new URL( `http://localhost:${process.env.CI ? 4173 : 5173}/` @@ -165,8 +165,8 @@ test('basic input', async ({ page, browserName }) => { const editorAUndo = page.getByText('undo').nth(0); const editorARedo = page.getByText('redo').nth(0); - await expect(editorA).toHaveText(ZERO_WIDTH_SPACE); - await expect(editorB).toHaveText(ZERO_WIDTH_SPACE); + await expect(editorA).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE); + await expect(editorB).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE); await page.waitForTimeout(100); @@ -177,8 +177,8 @@ test('basic input', async ({ page, browserName }) => { await editorAUndo.click(); - await expect(editorA).toHaveText(ZERO_WIDTH_SPACE); - await expect(editorB).toHaveText(ZERO_WIDTH_SPACE); + await expect(editorA).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE); + await expect(editorB).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE); await editorARedo.click(); @@ -244,12 +244,18 @@ test('basic input', async ({ page, browserName }) => { await page.waitForTimeout(100); - await expect(editorA).toHaveText('abc\n' + ZERO_WIDTH_SPACE + '\nbbb', { - useInnerText: true, // for multi-line text - }); - await expect(editorB).toHaveText('abc\n' + ZERO_WIDTH_SPACE + '\nbbb', { - useInnerText: true, // for multi-line text - }); + await expect(editorA).toHaveText( + 'abc\n' + ZERO_WIDTH_FOR_EMPTY_LINE + '\nbbb', + { + useInnerText: true, // for multi-line text + } + ); + await expect(editorB).toHaveText( + 'abc\n' + ZERO_WIDTH_FOR_EMPTY_LINE + '\nbbb', + { + useInnerText: true, // for multi-line text + } + ); await editorAUndo.click(); @@ -258,12 +264,18 @@ test('basic input', async ({ page, browserName }) => { await editorARedo.click(); - await expect(editorA).toHaveText('abc\n' + ZERO_WIDTH_SPACE + '\nbbb', { - useInnerText: true, // for multi-line text - }); - await expect(editorB).toHaveText('abc\n' + ZERO_WIDTH_SPACE + '\nbbb', { - useInnerText: true, // for multi-line text - }); + await expect(editorA).toHaveText( + 'abc\n' + ZERO_WIDTH_FOR_EMPTY_LINE + '\nbbb', + { + useInnerText: true, // for multi-line text + } + ); + await expect(editorB).toHaveText( + 'abc\n' + ZERO_WIDTH_FOR_EMPTY_LINE + '\nbbb', + { + useInnerText: true, // for multi-line text + } + ); await focusInlineRichText(page); await page.waitForTimeout(100); @@ -274,12 +286,18 @@ test('basic input', async ({ page, browserName }) => { await editorAUndo.click(); - await expect(editorA).toHaveText('abc\n' + ZERO_WIDTH_SPACE + '\nbbb', { - useInnerText: true, // for multi-line text - }); - await expect(editorB).toHaveText('abc\n' + ZERO_WIDTH_SPACE + '\nbbb', { - useInnerText: true, // for multi-line text - }); + await expect(editorA).toHaveText( + 'abc\n' + ZERO_WIDTH_FOR_EMPTY_LINE + '\nbbb', + { + useInnerText: true, // for multi-line text + } + ); + await expect(editorB).toHaveText( + 'abc\n' + ZERO_WIDTH_FOR_EMPTY_LINE + '\nbbb', + { + useInnerText: true, // for multi-line text + } + ); await editorARedo.click(); @@ -314,12 +332,18 @@ test('basic input', async ({ page, browserName }) => { await press(page, 'Enter'); await press(page, 'Enter'); - await expect(editorA).toHaveText('abbbc\n' + ZERO_WIDTH_SPACE + '\ndd', { - useInnerText: true, // for multi-line text - }); - await expect(editorB).toHaveText('abbbc\n' + ZERO_WIDTH_SPACE + '\ndd', { - useInnerText: true, // for multi-line text - }); + await expect(editorA).toHaveText( + 'abbbc\n' + ZERO_WIDTH_FOR_EMPTY_LINE + '\ndd', + { + useInnerText: true, // for multi-line text + } + ); + await expect(editorB).toHaveText( + 'abbbc\n' + ZERO_WIDTH_FOR_EMPTY_LINE + '\ndd', + { + useInnerText: true, // for multi-line text + } + ); await editorAUndo.click(); @@ -328,12 +352,18 @@ test('basic input', async ({ page, browserName }) => { await editorARedo.click(); - await expect(editorA).toHaveText('abbbc\n' + ZERO_WIDTH_SPACE + '\ndd', { - useInnerText: true, // for multi-line text - }); - await expect(editorB).toHaveText('abbbc\n' + ZERO_WIDTH_SPACE + '\ndd', { - useInnerText: true, // for multi-line text - }); + await expect(editorA).toHaveText( + 'abbbc\n' + ZERO_WIDTH_FOR_EMPTY_LINE + '\ndd', + { + useInnerText: true, // for multi-line text + } + ); + await expect(editorB).toHaveText( + 'abbbc\n' + ZERO_WIDTH_FOR_EMPTY_LINE + '\ndd', + { + useInnerText: true, // for multi-line text + } + ); }); test('chinese input', async ({ page, browserName }) => { @@ -348,8 +378,8 @@ test('chinese input', async ({ page, browserName }) => { const editorA = page.locator('[data-v-root="true"]').nth(0); const editorB = page.locator('[data-v-root="true"]').nth(1); - await expect(editorA).toHaveText(ZERO_WIDTH_SPACE); - await expect(editorB).toHaveText(ZERO_WIDTH_SPACE); + await expect(editorA).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE); + await expect(editorB).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE); await page.waitForTimeout(100); const client = await page.context().newCDPSession(page); @@ -396,8 +426,8 @@ test('readonly mode', async ({ page }) => { const editorA = page.locator('[data-v-root="true"]').nth(0); const editorB = page.locator('[data-v-root="true"]').nth(1); - await expect(editorA).toHaveText(ZERO_WIDTH_SPACE); - await expect(editorB).toHaveText(ZERO_WIDTH_SPACE); + await expect(editorA).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE); + await expect(editorB).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE); await page.waitForTimeout(100); @@ -441,8 +471,8 @@ test('basic styles', async ({ page }) => { const editorAUndo = page.getByText('undo').nth(0); const editorARedo = page.getByText('redo').nth(0); - await expect(editorA).toHaveText(ZERO_WIDTH_SPACE); - await expect(editorB).toHaveText(ZERO_WIDTH_SPACE); + await expect(editorA).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE); + await expect(editorB).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE); await page.waitForTimeout(100); @@ -696,8 +726,8 @@ test('overlapping styles', async ({ page }) => { const editorAUndo = page.getByText('undo').nth(0); const editorARedo = page.getByText('redo').nth(0); - await expect(editorA).toHaveText(ZERO_WIDTH_SPACE); - await expect(editorB).toHaveText(ZERO_WIDTH_SPACE); + await expect(editorA).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE); + await expect(editorB).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE); await page.waitForTimeout(100); @@ -868,8 +898,8 @@ test('input continuous spaces', async ({ page }) => { const editorA = page.locator('[data-v-root="true"]').nth(0); const editorB = page.locator('[data-v-root="true"]').nth(1); - await expect(editorA).toHaveText(ZERO_WIDTH_SPACE); - await expect(editorB).toHaveText(ZERO_WIDTH_SPACE); + await expect(editorA).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE); + await expect(editorB).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE); await page.waitForTimeout(100); @@ -902,8 +932,8 @@ test('select from the start of line using shift+arrow', async ({ page }) => { const editorA = page.locator('[data-v-root="true"]').nth(0); const editorB = page.locator('[data-v-root="true"]').nth(1); - await expect(editorA).toHaveText(ZERO_WIDTH_SPACE); - await expect(editorB).toHaveText(ZERO_WIDTH_SPACE); + await expect(editorA).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE); + await expect(editorB).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE); await page.waitForTimeout(100); @@ -961,8 +991,8 @@ test('getLine', async ({ page }) => { const editorA = page.locator('[data-v-root="true"]').nth(0); const editorB = page.locator('[data-v-root="true"]').nth(1); - await expect(editorA).toHaveText(ZERO_WIDTH_SPACE); - await expect(editorB).toHaveText(ZERO_WIDTH_SPACE); + await expect(editorA).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE); + await expect(editorB).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE); await page.waitForTimeout(100); @@ -1032,7 +1062,7 @@ test('embed', async ({ page }) => { const editorA = page.locator('[data-v-root="true"]').nth(0); const editorAEmbed = page.getByText('embed').nth(0); - await expect(editorA).toHaveText(ZERO_WIDTH_SPACE); + await expect(editorA).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE); await page.waitForTimeout(100); @@ -1101,7 +1131,7 @@ test('delete embed when pressing backspace after embed', async ({ page }) => { const editorA = page.locator('[data-v-root="true"]').nth(0); const editorAEmbed = page.getByText('embed').nth(0); - await expect(editorA).toHaveText(ZERO_WIDTH_SPACE); + await expect(editorA).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE); await page.waitForTimeout(100); await type(page, 'ab'); await expect(editorA).toHaveText('ab'); @@ -1146,7 +1176,7 @@ test('triple click to select line', async ({ page }) => { const editorA = page.locator('[data-v-root="true"]').nth(0); - await expect(editorA).toHaveText(ZERO_WIDTH_SPACE); + await expect(editorA).toHaveText(ZERO_WIDTH_FOR_EMPTY_LINE); await page.waitForTimeout(100); await type(page, 'abc\nabc abc abc\nabc'); @@ -1161,9 +1191,12 @@ test('triple click to select line', async ({ page }) => { await assertSelection(page, 0, 4, 11); await pressBackspace(page); - await expect(editorA).toHaveText('abc\n' + ZERO_WIDTH_SPACE + '\nabc', { - useInnerText: true, // for multi-line text - }); + await expect(editorA).toHaveText( + 'abc\n' + ZERO_WIDTH_FOR_EMPTY_LINE + '\nabc', + { + useInnerText: true, // for multi-line text + } + ); }); test('caret should move correctly when inline elements are exist', async ({ diff --git a/tests/blocksuite/e2e/latex/inline.spec.ts b/tests/blocksuite/e2e/latex/inline.spec.ts index 46eca3a38a..4ea4e7f373 100644 --- a/tests/blocksuite/e2e/latex/inline.spec.ts +++ b/tests/blocksuite/e2e/latex/inline.spec.ts @@ -24,7 +24,7 @@ import { assertRichTextInlineDeltas, assertRichTextInlineRange, } from '../utils/asserts.js'; -import { ZERO_WIDTH_SPACE } from '../utils/inline-editor.js'; +import { ZERO_WIDTH_FOR_EMPTY_LINE } from '../utils/inline-editor.js'; import { test } from '../utils/playwright.js'; test('add inline latex at the start of line', async ({ page }) => { @@ -162,13 +162,13 @@ test('latex editor', async ({ page }) => { ); await pressBackspaceWithShortKey(page, 2); - expect(await latexEditorLine.innerText()).toBe(ZERO_WIDTH_SPACE); + expect(await latexEditorLine.innerText()).toBe(ZERO_WIDTH_FOR_EMPTY_LINE); await undoByKeyboard(page); expect(await latexEditorLine.innerText()).toBe( 'ababababababababababababababababababababababababab' ); await redoByKeyboard(page); - expect(await latexEditorLine.innerText()).toBe(ZERO_WIDTH_SPACE); + expect(await latexEditorLine.innerText()).toBe(ZERO_WIDTH_FOR_EMPTY_LINE); await undoByKeyboard(page); expect(await latexEditorLine.innerText()).toBe( 'ababababababababababababababababababababababababab' @@ -200,7 +200,7 @@ test('latex editor', async ({ page }) => { await selectAllByKeyboard(page); await pressBackspace(page); - expect(await latexEditorLine.innerText()).toBe(ZERO_WIDTH_SPACE); + expect(await latexEditorLine.innerText()).toBe(ZERO_WIDTH_FOR_EMPTY_LINE); // highlight await type( diff --git a/tests/blocksuite/e2e/utils/actions/misc.ts b/tests/blocksuite/e2e/utils/actions/misc.ts index 9b02a1df11..4b0646209b 100644 --- a/tests/blocksuite/e2e/utils/actions/misc.ts +++ b/tests/blocksuite/e2e/utils/actions/misc.ts @@ -14,7 +14,7 @@ import { expect } from '@playwright/test'; import stringify from 'json-stable-stringify'; import lz from 'lz-string'; -import { ZERO_WIDTH_SPACE } from '../inline-editor.js'; +import { ZERO_WIDTH_FOR_EMPTY_LINE } from '../inline-editor.js'; import { currentEditorIndex } from '../multiple-editor.js'; import { pressArrowRight, @@ -1054,7 +1054,7 @@ export async function getIndexCoordinate( } export function inlineEditorInnerTextToString(innerText: string): string { - return innerText.replace(ZERO_WIDTH_SPACE, '').trim(); + return innerText.replace(ZERO_WIDTH_FOR_EMPTY_LINE, '').trim(); } export async function focusTitle(page: Page) { diff --git a/tests/blocksuite/e2e/utils/inline-editor.ts b/tests/blocksuite/e2e/utils/inline-editor.ts index 93e84cb399..c27b9d9c70 100644 --- a/tests/blocksuite/e2e/utils/inline-editor.ts +++ b/tests/blocksuite/e2e/utils/inline-editor.ts @@ -22,4 +22,5 @@ export async function getStringFromRichText( } // Why? we can't import from `@blocksuite/affine/std/inline` because playwright will throw an error -export const ZERO_WIDTH_SPACE = '\u200C'; +export const ZERO_WIDTH_FOR_EMPTY_LINE = + process.env.BROWSER === 'webkit' ? '\u200C' : '\u200B'; diff --git a/tests/kit/src/utils/editor.ts b/tests/kit/src/utils/editor.ts index fb059281c0..c65db29407 100644 --- a/tests/kit/src/utils/editor.ts +++ b/tests/kit/src/utils/editor.ts @@ -8,10 +8,11 @@ import { expect, type Locator, type Page } from '@playwright/test'; declare type _GLOBAL_ = typeof BlocksuiteEffects; const EDGELESS_TOOLBAR_WIDGET = 'edgeless-toolbar-widget'; -export const ZERO_WIDTH_SPACE = '\u200C'; +export const ZERO_WIDTH_FOR_EMPTY_LINE = + process.env.BROWSER === 'webkit' ? '\u200C' : '\u200B'; export function inlineEditorInnerTextToString(innerText: string): string { - return innerText.replace(ZERO_WIDTH_SPACE, '').trim(); + return innerText.replace(ZERO_WIDTH_FOR_EMPTY_LINE, '').trim(); } const PARAGRAPH_BLOCK_LOCATOR = 'affine-paragraph';