From 0902b2b9c923936b722d45411b8d726dec6b677e Mon Sep 17 00:00:00 2001 From: L-Sun Date: Fri, 23 May 2025 07:28:30 +0000 Subject: [PATCH] fix(editor): can not select the block after undo the drag from canvas to note (#12473) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Close [BS-3509](https://linear.app/affine-design/issue/BS-3509/embed拖入note,然后撤销,形成的block刷新后才可选中,且只能进行有限交互) ### Before https://github.com/user-attachments/assets/4c83f9ba-1a99-427f-824d-7e946e55e737 ### After https://github.com/user-attachments/assets/e6a28478-0af4-4358-a353-e0c2e8edb0f9 ## Summary by CodeRabbit - **Bug Fixes** - Improved block selection reliability after dragging a block into a note and performing an undo action, ensuring the block remains selectable. - **Tests** - Added an end-to-end test to verify block selection after dragging and undo operations in edgeless mode. --- .../src/watchers/drag-event-watcher.ts | 1 + .../framework/std/src/gfx/controller.ts | 1 - blocksuite/framework/std/src/gfx/grid.ts | 34 +++++++++---------- .../e2e/edgeless/selection/selection.spec.ts | 26 ++++++++++++++ 4 files changed, 43 insertions(+), 19 deletions(-) diff --git a/blocksuite/affine/widgets/drag-handle/src/watchers/drag-event-watcher.ts b/blocksuite/affine/widgets/drag-handle/src/watchers/drag-event-watcher.ts index d52018eaf..b22d58c11 100644 --- a/blocksuite/affine/widgets/drag-handle/src/watchers/drag-event-watcher.ts +++ b/blocksuite/affine/widgets/drag-handle/src/watchers/drag-event-watcher.ts @@ -710,6 +710,7 @@ export class DragEventWatcher { dropPayload: DropPayload, point: Point ) => { + this.std.store.captureSync(); if (this.mode === 'edgeless') { this._onEdgelessDrop(dropBlock, dragPayload, dropPayload, point); } else { diff --git a/blocksuite/framework/std/src/gfx/controller.ts b/blocksuite/framework/std/src/gfx/controller.ts index a5f3f3419..2285e1d17 100644 --- a/blocksuite/framework/std/src/gfx/controller.ts +++ b/blocksuite/framework/std/src/gfx/controller.ts @@ -200,7 +200,6 @@ export class GfxController extends LifeCycleWatcher { ...options, all: true, }); - let picked = last(results) ?? null; const { activeGroup } = selectionManager; const first = picked; diff --git a/blocksuite/framework/std/src/gfx/grid.ts b/blocksuite/framework/std/src/gfx/grid.ts index 6a07e824a..327a9e849 100644 --- a/blocksuite/framework/std/src/gfx/grid.ts +++ b/blocksuite/framework/std/src/gfx/grid.ts @@ -397,22 +397,14 @@ export class GridManager extends GfxExtension { if (payload.type === 'add' && canBeRenderedAsGfxBlock(payload.model)) { this.add(payload.model); } - if (payload.type === 'update') { - const model = store.getBlock(payload.id) - ?.model as GfxBlockElementModel; - - if (!model) { - return; - } + const model = store.getModelById(payload.id); + if (!model) return; if (payload.props.key === 'xywh' && canBeRenderedAsGfxBlock(model)) { - this.update( - store.getBlock(payload.id)?.model as GfxBlockElementModel - ); + this.update(model); } } - if ( payload.type === 'delete' && payload.model instanceof GfxBlockElementModel @@ -429,22 +421,28 @@ export class GridManager extends GfxExtension { }); const watchSurface = (surface: SurfaceBlockModel) => { - let lastChildMap = new Map(surface.childMap.peek()); + let lastChildMap = new Map(surface.childMap.peek()); disposables.add( - surface.childMap.subscribe(val => { - val.forEach((_, id) => { + surface.childMap.subscribe(currentChildMap => { + currentChildMap.forEach((_, id) => { if (lastChildMap.has(id)) { lastChildMap.delete(id); return; } }); lastChildMap.forEach((_, id) => { - const block = store.getBlock(id); - if (block?.model) { - this.remove(block.model as GfxBlockElementModel); + const model = store.getModelById(id); + if (model) { + this.remove(model as GfxBlockElementModel); } }); - lastChildMap = new Map(val); + currentChildMap.forEach((_, id) => { + const model = store.getModelById(id); + if (model) { + this.add(model as GfxBlockElementModel); + } + }); + lastChildMap = new Map(currentChildMap); }) ); diff --git a/tests/blocksuite/e2e/edgeless/selection/selection.spec.ts b/tests/blocksuite/e2e/edgeless/selection/selection.spec.ts index 0ab289f2a..5834be639 100644 --- a/tests/blocksuite/e2e/edgeless/selection/selection.spec.ts +++ b/tests/blocksuite/e2e/edgeless/selection/selection.spec.ts @@ -11,6 +11,7 @@ import { addBasicRectShapeElement, click, clickInCenter, + clickView, dragBetweenCoords, enterPlaygroundRoom, getBoundingRect, @@ -18,6 +19,7 @@ import { initThreeParagraphs, pressEnter, pressEscape, + undoByKeyboard, waitNextFrame, } from '../../utils/actions/index.js'; import { @@ -517,3 +519,27 @@ test('should the selected rect be below the edgeless element toolbar', async ({ expect(topElement).toBe('EDGELESS-TOOLBAR-WIDGET'); }); + +test('should the block selectable after undo drag a block from canvas to note', async ({ + page, +}) => { + await enterPlaygroundRoom(page); + await initEmptyEdgelessState(page); + await switchEditorMode(page); + + await actions.createNote(page, [0, 200], 'hello\nworld'); + await pressEscape(page, 3); + await clickView(page, [0, 200]); + const toolbar = actions.locatorComponentToolbar(page); + await toolbar.getByLabel('More menu').click(); + await toolbar.getByTestId('turn-into-linked-doc').click(); + + await page.dragAndDrop( + '.affine-drag-handle-grabber.dots', + 'affine-edgeless-note[data-block-id="2"]' + ); + await waitNextFrame(page); + await undoByKeyboard(page); + await page.locator('affine-embed-edgeless-synced-doc-block').click(); + expect(await actions.getSelectedBoundCount(page)).toBe(1); +});