fix(editor): improve backspace ux for callout block (#10696)

This commit is contained in:
Flrande
2025-03-07 08:50:31 +00:00
parent 8d9746e0cc
commit 264f0dd2be
5 changed files with 99 additions and 2 deletions
@@ -0,0 +1,34 @@
import { CalloutBlockModel } from '@blocksuite/affine-model';
import { matchModels } from '@blocksuite/affine-shared/utils';
import {
BlockSelection,
KeymapExtension,
TextSelection,
} from '@blocksuite/block-std';
export const CalloutKeymapExtension = KeymapExtension(std => {
return {
Backspace: ctx => {
const text = std.selection.find(TextSelection);
if (text && text.isCollapsed() && text.from.index === 0) {
const event = ctx.get('defaultState').event;
event.preventDefault();
const block = std.store.getBlock(text.from.blockId);
if (!block) return false;
const parent = std.store.getParent(block.model);
if (!parent) return false;
if (!matchModels(parent, [CalloutBlockModel])) return false;
std.selection.setGroup('note', [
std.selection.create(BlockSelection, {
blockId: parent.id,
}),
]);
return true;
}
return false;
},
};
});
@@ -3,10 +3,12 @@ import { BlockViewExtension, FlavourExtension } from '@blocksuite/block-std';
import type { ExtensionType } from '@blocksuite/store';
import { literal } from 'lit/static-html.js';
import { CalloutKeymapExtension } from './callout-keymap';
import { calloutSlashMenuConfig } from './configs/slash-menu';
export const CalloutBlockSpec: ExtensionType[] = [
FlavourExtension('affine:callout'),
BlockViewExtension('affine:callout', literal`affine-callout`),
CalloutKeymapExtension,
SlashMenuConfigExtension('affine:callout', calloutSlashMenuConfig),
];
@@ -1,6 +1,7 @@
import {
AttachmentBlockModel,
BookmarkBlockModel,
CalloutBlockModel,
CodeBlockModel,
DatabaseBlockModel,
DividerBlockModel,
@@ -53,8 +54,18 @@ export function mergeWithPrev(editorHost: EditorHost, model: BlockModel) {
return handleNoPreviousSibling(editorHost, model);
}
const modelIndex = parent.children.indexOf(model);
const prevSibling = doc.getPrev(model);
if (matchModels(prevSibling, [CalloutBlockModel])) {
editorHost.selection.setGroup('note', [
editorHost.selection.create(BlockSelection, {
blockId: prevSibling.id,
}),
]);
return true;
}
if (matchModels(prevBlock, [ParagraphBlockModel, ListBlockModel])) {
const modelIndex = parent.children.indexOf(model);
if (
(modelIndex === -1 || modelIndex === parent.children.length - 1) &&
parent.role === 'content'
@@ -1,4 +1,10 @@
import { undoByKeyboard } from '@affine-test/kit/utils/keyboard';
import {
pressArrowDown,
pressArrowUp,
pressBackspace,
pressEnter,
undoByKeyboard,
} from '@affine-test/kit/utils/keyboard';
import { openHomePage } from '@affine-test/kit/utils/load-page';
import { type } from '@affine-test/kit/utils/page-logic';
import { expect, test } from '@playwright/test';
@@ -60,3 +66,41 @@ test('disable slash menu in callout block', async ({ page }) => {
await type(page, '/');
await expect(slashMenu).toBeVisible();
});
test('press backspace after callout block', async ({ page }) => {
await pressEnter(page);
await pressArrowUp(page);
await type(page, '/callout\n');
await pressArrowDown(page);
const paragraph = page.locator('affine-paragraph');
const callout = page.locator('affine-callout');
expect(await paragraph.count()).toBe(3);
expect(await callout.count()).toBe(1);
await pressBackspace(page);
expect(await paragraph.count()).toBe(3);
expect(await callout.count()).toBe(1);
await pressBackspace(page);
await expect(paragraph).toHaveCount(2);
await expect(callout).toHaveCount(0);
});
test('press backspace in callout block', async ({ page }) => {
const paragraph = page.locator('affine-paragraph');
const callout = page.locator('affine-callout');
await type(page, '/callout\n');
expect(await paragraph.count()).toBe(2);
expect(await callout.count()).toBe(1);
await pressBackspace(page);
await expect(paragraph).toHaveCount(2);
await expect(callout).toHaveCount(1);
await pressBackspace(page);
await expect(paragraph).toHaveCount(1);
await expect(callout).toHaveCount(0);
});
+6
View File
@@ -38,6 +38,12 @@ export async function pressArrowUp(page: Page, count = 1) {
}
}
export async function pressArrowDown(page: Page, count = 1) {
for (let i = 0; i < count; i++) {
await page.keyboard.press('ArrowDown', { delay: 20 });
}
}
export async function pressTab(page: Page) {
await page.keyboard.press('Tab', { delay: 50 });
}