fix(editor): prevent Tab key propagation outside editor (#11531)

Closes: BS-2964
This commit is contained in:
Saul-Mirone
2025-04-08 10:03:06 +00:00
parent 280227fa5f
commit 780c35eabe
5 changed files with 75 additions and 16 deletions
@@ -42,6 +42,7 @@ import type { ExtensionType } from '@blocksuite/store';
import { RootBlockAdapterExtensions } from '../adapters/extension';
import { clipboardConfigs } from '../clipboard';
import { builtinToolbarConfig } from '../configs/toolbar';
import { fallbackKeymap } from '../keyboard/keymap';
import {
innerModalWidget,
linkedDocWidget,
@@ -94,6 +95,7 @@ export const CommonSpecs: ExtensionType[] = [
viewportOverlayWidget,
scrollAnchoringWidget,
toolbarWidget,
fallbackKeymap,
ToolbarModuleExtension({
id: BlockFlavourIdentifier(NoteBlockSchema.model.flavour),
@@ -0,0 +1,16 @@
import { KeymapExtension } from '@blocksuite/std';
export const fallbackKeymap = KeymapExtension(() => {
return {
Tab: ctx => {
const event = ctx.get('defaultState').event;
event.stopPropagation();
event.preventDefault();
},
'Shift-Tab': ctx => {
const event = ctx.get('defaultState').event;
event.stopPropagation();
event.preventDefault();
},
};
});
@@ -1,3 +1,4 @@
import { toolbarButtons } from '@affine-test/kit/bs/linked-toolbar';
import { test } from '@affine-test/kit/playwright';
import {
pressArrowUp,
@@ -7,6 +8,7 @@ import {
import { openHomePage } from '@affine-test/kit/utils/load-page';
import {
clickNewPageButton,
createLinkedPage,
type,
waitForEditorLoad,
} from '@affine-test/kit/utils/page-logic';
@@ -77,4 +79,41 @@ test.describe('split list', () => {
listLocator.nth(4).locator('.affine-list-block__numbered')
).toHaveText('4.');
});
test('tab in list should not propagate out of editor', async ({ page }) => {
await pressEnter(page);
await type(page, '1. aaa');
await page.keyboard.press('Enter');
await page.keyboard.press('Tab');
await createLinkedPage(page, 'Test Page');
const inlineLink = page.locator('affine-reference');
const { switchViewBtn, cardViewBtn } = toolbarButtons(page);
const list = page.locator('affine-list');
const card = page.locator('affine-embed-linked-doc-block');
const pressWithCount = async (key: string, count: number) => {
for (let i = 0; i < count; i++) {
await new Promise(resolve => setTimeout(resolve, 5));
await page.keyboard.press(key);
}
};
await inlineLink.hover();
await switchViewBtn.click();
await cardViewBtn.click();
await expect(list.filter({ has: card })).toHaveCount(1);
await page.keyboard.press('Shift+Tab');
await expect(list.filter({ hasNot: card })).toHaveCount(1);
await pressWithCount('Tab', 5);
await expect(list.filter({ has: card })).toHaveCount(1);
await pressWithCount('Shift+Tab', 5);
await expect(list.filter({ hasNot: card })).toHaveCount(1);
});
});
+1 -16
View File
@@ -1,3 +1,4 @@
import { toolbarButtons } from '@affine-test/kit/bs/linked-toolbar';
import { waitNextFrame } from '@affine-test/kit/bs/misc';
import { test } from '@affine-test/kit/playwright';
import { clickEdgelessModeButton } from '@affine-test/kit/utils/editor';
@@ -27,22 +28,6 @@ test.beforeEach(async ({ page }) => {
await waitForEmptyEditor(page);
});
function toolbarButtons(page: Page) {
const toolbar = page.locator('affine-toolbar-widget editor-toolbar');
const switchViewBtn = toolbar.getByLabel('Switch view');
const inlineViewBtn = toolbar.getByLabel('Inline view');
const cardViewBtn = toolbar.getByLabel('Card view');
const embedViewBtn = toolbar.getByLabel('Embed view');
return {
toolbar,
switchViewBtn,
inlineViewBtn,
cardViewBtn,
embedViewBtn,
};
}
async function enableEmojiDocIcon(page: Page) {
// Opens settings panel
await openEditorSetting(page);
+17
View File
@@ -0,0 +1,17 @@
import type { Page } from '@playwright/test';
export function toolbarButtons(page: Page) {
const toolbar = page.locator('affine-toolbar-widget editor-toolbar');
const switchViewBtn = toolbar.getByLabel('Switch view');
const inlineViewBtn = toolbar.getByLabel('Inline view');
const cardViewBtn = toolbar.getByLabel('Card view');
const embedViewBtn = toolbar.getByLabel('Embed view');
return {
toolbar,
switchViewBtn,
inlineViewBtn,
cardViewBtn,
embedViewBtn,
};
}