mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-01 01:29:31 +08:00
fix(editor): can not move carte at the end of inline element (#11558)
Close [BS-2922](https://linear.app/affine-design/issue/BS-2922/【移动端-ios】文档添加linked-page后,无法删除)
This commit is contained in:
@@ -1,7 +1,5 @@
|
|||||||
import { IS_SAFARI } from '@blocksuite/global/env';
|
export const ZERO_WIDTH_SPACE = '\u200C';
|
||||||
|
|
||||||
export const ZERO_WIDTH_SPACE = IS_SAFARI ? '\u200C' : '\u200B';
|
|
||||||
// see https://en.wikipedia.org/wiki/Zero-width_non-joiner
|
// see https://en.wikipedia.org/wiki/Zero-width_non-joiner
|
||||||
export const ZERO_WIDTH_NON_JOINER = '\u200C';
|
export const ZERO_WIDTH_NON_JOINER = '\u200B';
|
||||||
|
|
||||||
export const INLINE_ROOT_ATTR = 'data-v-root';
|
export const INLINE_ROOT_ATTR = 'data-v-root';
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { test } from '@affine-test/kit/playwright';
|
import { test } from '@affine-test/kit/playwright';
|
||||||
import {
|
import {
|
||||||
|
assertTitle,
|
||||||
clickEdgelessModeButton,
|
clickEdgelessModeButton,
|
||||||
clickView,
|
clickView,
|
||||||
createEdgelessNoteBlock,
|
createEdgelessNoteBlock,
|
||||||
@@ -162,7 +163,7 @@ test.describe('edgeless page block', () => {
|
|||||||
const note = page.locator('affine-edgeless-note');
|
const note = page.locator('affine-edgeless-note');
|
||||||
const docTitle = note.locator('edgeless-page-block-title');
|
const docTitle = note.locator('edgeless-page-block-title');
|
||||||
await expect(docTitle).toBeVisible();
|
await expect(docTitle).toBeVisible();
|
||||||
await expect(docTitle).toHaveText(title);
|
await assertTitle(page, title);
|
||||||
|
|
||||||
await note.dblclick();
|
await note.dblclick();
|
||||||
await docTitle.click();
|
await docTitle.click();
|
||||||
@@ -170,11 +171,11 @@ test.describe('edgeless page block', () => {
|
|||||||
// clear the title
|
// clear the title
|
||||||
await selectAllByKeyboard(page);
|
await selectAllByKeyboard(page);
|
||||||
await pressBackspace(page);
|
await pressBackspace(page);
|
||||||
await expect(docTitle).toHaveText('');
|
await assertTitle(page, '');
|
||||||
|
|
||||||
// type new title
|
// type new title
|
||||||
await type(page, 'New Title');
|
await type(page, 'New Title');
|
||||||
await expect(docTitle).toHaveText('New Title');
|
await assertTitle(page, 'New Title');
|
||||||
|
|
||||||
// cursor could move between doc title and note content
|
// cursor could move between doc title and note content
|
||||||
await page.keyboard.press('ArrowDown');
|
await page.keyboard.press('ArrowDown');
|
||||||
@@ -186,10 +187,10 @@ test.describe('edgeless page block', () => {
|
|||||||
|
|
||||||
await page.keyboard.press('ArrowUp');
|
await page.keyboard.press('ArrowUp');
|
||||||
await type(page, 'yy');
|
await type(page, 'yy');
|
||||||
await expect(docTitle).toHaveText('yyNew Title');
|
await assertTitle(page, 'yyNew Title');
|
||||||
|
|
||||||
await pressEnter(page);
|
await pressEnter(page);
|
||||||
await expect(docTitle).toHaveText('yy');
|
await assertTitle(page, 'yy');
|
||||||
await expect(paragraphs).toHaveCount(numParagraphs + 1);
|
await expect(paragraphs).toHaveCount(numParagraphs + 1);
|
||||||
await expect(paragraphs.nth(0)).toHaveText('New Title');
|
await expect(paragraphs.nth(0)).toHaveText('New Title');
|
||||||
await expect(paragraphs.nth(1)).toHaveText('xxHello');
|
await expect(paragraphs.nth(1)).toHaveText('xxHello');
|
||||||
|
|||||||
@@ -2,6 +2,13 @@ import type { InlineEditor, InlineRange } from '@blocksuite/affine/std/inline';
|
|||||||
import type { DeltaInsert } from '@blocksuite/affine/store';
|
import type { DeltaInsert } from '@blocksuite/affine/store';
|
||||||
import { expect, type Page, test } from '@playwright/test';
|
import { expect, type Page, test } from '@playwright/test';
|
||||||
|
|
||||||
|
import { pressArrowLeft, pressEnter } from '../utils/actions/keyboard.js';
|
||||||
|
import {
|
||||||
|
enterPlaygroundRoom,
|
||||||
|
focusRichText,
|
||||||
|
initEmptyParagraphState,
|
||||||
|
} from '../utils/actions/misc.js';
|
||||||
|
import { assertRichTextInlineDeltas } from '../utils/asserts.js';
|
||||||
import { ZERO_WIDTH_SPACE } from '../utils/inline-editor.js';
|
import { ZERO_WIDTH_SPACE } from '../utils/inline-editor.js';
|
||||||
// FIXME(mirone): copy paste from framework/inline/__tests__/utils.ts
|
// FIXME(mirone): copy paste from framework/inline/__tests__/utils.ts
|
||||||
const defaultPlaygroundURL = new URL(
|
const defaultPlaygroundURL = new URL(
|
||||||
@@ -1124,3 +1131,41 @@ test('triple click to select line', async ({ page }) => {
|
|||||||
await press(page, 'Backspace');
|
await press(page, 'Backspace');
|
||||||
expect(await editorA.innerText()).toBe('abc\n' + ZERO_WIDTH_SPACE + '\nabc');
|
expect(await editorA.innerText()).toBe('abc\n' + ZERO_WIDTH_SPACE + '\nabc');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('caret should move correctly when inline elements are exist', async ({
|
||||||
|
page,
|
||||||
|
}) => {
|
||||||
|
await enterPlaygroundRoom(page);
|
||||||
|
await initEmptyParagraphState(page);
|
||||||
|
await focusRichText(page, 0);
|
||||||
|
|
||||||
|
// hello 'link doc' world
|
||||||
|
await type(page, 'hello ');
|
||||||
|
await press(page, '@');
|
||||||
|
await type(page, 'link doc');
|
||||||
|
await pressEnter(page);
|
||||||
|
await type(page, ' world');
|
||||||
|
|
||||||
|
await pressArrowLeft(page, ' world'.length);
|
||||||
|
await pressArrowLeft(page); // on 'linked doc'
|
||||||
|
await pressArrowLeft(page); // on the left side of 'linked doc'
|
||||||
|
await type(page, 'test');
|
||||||
|
|
||||||
|
await assertRichTextInlineDeltas(page, [
|
||||||
|
{
|
||||||
|
insert: 'hello test',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
attributes: {
|
||||||
|
reference: {
|
||||||
|
pageId: '3',
|
||||||
|
type: 'LinkedPage',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
insert: ' ',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
insert: ' world',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import { expect } from '@playwright/test';
|
|||||||
import stringify from 'json-stable-stringify';
|
import stringify from 'json-stable-stringify';
|
||||||
import lz from 'lz-string';
|
import lz from 'lz-string';
|
||||||
|
|
||||||
|
import { ZERO_WIDTH_SPACE } from '../inline-editor.js';
|
||||||
import { currentEditorIndex } from '../multiple-editor.js';
|
import { currentEditorIndex } from '../multiple-editor.js';
|
||||||
import {
|
import {
|
||||||
pressArrowRight,
|
pressArrowRight,
|
||||||
@@ -1053,7 +1054,7 @@ export async function getIndexCoordinate(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function inlineEditorInnerTextToString(innerText: string): string {
|
export function inlineEditorInnerTextToString(innerText: string): string {
|
||||||
return innerText.replace('\u200B', '').trim();
|
return innerText.replace(ZERO_WIDTH_SPACE, '').trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function focusTitle(page: Page) {
|
export async function focusTitle(page: Page) {
|
||||||
|
|||||||
@@ -22,8 +22,4 @@ export async function getStringFromRichText(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Why? we can't import from `@blocksuite/affine/std/inline` because playwright will throw an error
|
// Why? we can't import from `@blocksuite/affine/std/inline` because playwright will throw an error
|
||||||
export const ZERO_WIDTH_SPACE = /Apple Computer/.test(
|
export const ZERO_WIDTH_SPACE = '\u200C';
|
||||||
globalThis.navigator?.vendor
|
|
||||||
)
|
|
||||||
? '\u200C'
|
|
||||||
: '\u200B';
|
|
||||||
|
|||||||
@@ -5,6 +5,11 @@ import { expect, type Locator, type Page } from '@playwright/test';
|
|||||||
declare type _GLOBAL_ = typeof BlocksuiteEffects;
|
declare type _GLOBAL_ = typeof BlocksuiteEffects;
|
||||||
|
|
||||||
const EDGELESS_TOOLBAR_WIDGET = 'edgeless-toolbar-widget';
|
const EDGELESS_TOOLBAR_WIDGET = 'edgeless-toolbar-widget';
|
||||||
|
export const ZERO_WIDTH_SPACE = '\u200C';
|
||||||
|
|
||||||
|
export function inlineEditorInnerTextToString(innerText: string): string {
|
||||||
|
return innerText.replace(ZERO_WIDTH_SPACE, '').trim();
|
||||||
|
}
|
||||||
|
|
||||||
export function locateModeSwitchButton(
|
export function locateModeSwitchButton(
|
||||||
page: Page,
|
page: Page,
|
||||||
@@ -62,6 +67,13 @@ export async function focusDocTitle(page: Page, editorIndex = 0) {
|
|||||||
await locateDocTitle(page, editorIndex).locator('.inline-editor').focus();
|
await locateDocTitle(page, editorIndex).locator('.inline-editor').focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function assertTitle(page: Page, text: string) {
|
||||||
|
const title = locateDocTitle(page);
|
||||||
|
const inlineEditor = title.locator('.doc-title-container').first();
|
||||||
|
const vText = inlineEditorInnerTextToString(await inlineEditor.innerText());
|
||||||
|
expect(vText).toBe(text);
|
||||||
|
}
|
||||||
|
|
||||||
export function locateToolbar(page: Page, editorIndex = 0) {
|
export function locateToolbar(page: Page, editorIndex = 0) {
|
||||||
return locateEditorContainer(page, editorIndex).locator(
|
return locateEditorContainer(page, editorIndex).locator(
|
||||||
'affine-toolbar-widget editor-toolbar'
|
'affine-toolbar-widget editor-toolbar'
|
||||||
|
|||||||
Reference in New Issue
Block a user